import Foundation
import MapKit
class GradientPolyLineRender: MKOverlayPathRenderer {
var hues: [CGFloat] = []
var polyline: GSGradientPolyline?
var rwLock: pthread_rwlock_t = pthread_rwlock_t()
var maxVelocity: CGFloat
var minVelocity: CGFloat
var maxHue: CGFloat
var minHue: CGFloat
init(overlay: MKOverlay, maxVelocity: CGFloat = 5, minVelocity: CGFloat = 2, maxHue: CGFloat = 0.3, minHue: CGFloat = 0.03) {
self.maxVelocity = maxVelocity
self.minVelocity = minVelocity
self.maxHue = maxHue
self.minHue = minHue
super.init(overlay: overlay)
pthread_rwlock_init(&rwLock, nil)
polyline = self.overlay as? GSGradientPolyline
createPath()
}
override func createPath() {
guard var points = polyline?.points() else { return }
let path = CGMutablePath()
var pathIsEmpty: Bool = true
let pointCount = polyline?.pointCount ?? 0
for _ in 0 ..< pointCount {
let point = self.point(for: points.pointee)
if (pathIsEmpty){
path.move(to: CGPoint(x: point.x, y: point.y))
pathIsEmpty = false
} else {
path.addLine(to: CGPoint(x: point.x, y: point.y))
}
points = points.successor()
}
pthread_rwlock_wrlock(&rwLock)
self.path = path
pthread_rwlock_unlock(&rwLock)
}
override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {
let pointsRect = self.path.boundingBox
let mapCGRect = self.rect(for: mapRect)
if !pointsRect.intersects(mapCGRect) {
return
}
guard var points = polyline?.points() else {
return
}
var preColor = UIColor.white
var currentColor = UIColor.white
let pointsCount: Int = polyline?.colors?.count ?? 0
for index in 0 ..< pointsCount {
let currentPoint = self.point(for: points.pointee)
let path = CGMutablePath()
currentColor = (polyline?.colors?[index]) ?? UIColor.red
if index == 0 {
path.move(to: currentPoint)
} else {
let prevPoint = self.point(for: points.predecessor().pointee)
path.move(to: prevPoint)
path.addLine(to: currentPoint)
var pc_r: CGFloat = 0
var pc_g: CGFloat = 0
var pc_b: CGFloat = 0
var pc_a: CGFloat = 0
var cc_r: CGFloat = 0
var cc_g: CGFloat = 0
var cc_b: CGFloat = 0
var cc_a: CGFloat = 0
preColor.getRed(&pc_r, green: &pc_g, blue: &pc_b, alpha: &pc_a)
currentColor.getRed(&cc_r, green: &cc_g, blue: &cc_b, alpha: &cc_a)
let gradientColors = [pc_r, pc_g, pc_b, pc_a, cc_r, cc_g, cc_b, cc_a]
context.saveGState()
let lineWidth = context.convertToUserSpace(CGSize(width: self.lineWidth, height: self.lineWidth)).width
let pathToFill = path.copy(strokingWithWidth: lineWidth, lineCap: self.lineCap, lineJoin: self.lineJoin, miterLimit: self.miterLimit)
context.addPath(pathToFill)
context.clip()
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient.init(colorSpace: colorSpace, colorComponents: gradientColors, locations: [0, 1], count: 2)
let gardientStart = prevPoint
let gardientEnd = currentPoint
context.drawLinearGradient(gradient!, start: gardientStart, end: gardientEnd, options: CGGradientDrawingOptions.drawsAfterEndLocation)
context.restoreGState()
}
preColor = UIColor.init(cgColor: currentColor.cgColor)
points = points.successor()
}
}
}