MKOverlay Custom Stroke - CGPath

时间:2016-02-20 00:00:42

标签: swift dictionary overlay cgpath

我需要一个自定义的MKOverlay描边样式。 我需要在覆盖层内部使用更宽的浅色,就像这个笔触一样。

This is what I want

我知道怎么画它,

This is what I get

class PolygonRenderer:MKPolygonRenderer {

    override func drawMapRect(mapRect: MKMapRect, zoomScale: MKZoomScale, inContext context: CGContext) {

        let fullPath = CGPathCreateMutable()

        for i in 0 ..< self.polygon.pointCount {

            let point = self.pointForMapPoint(self.polygon.points()[i])

            print(point)

            if i == 0 {

                CGPathMoveToPoint(fullPath, nil, point.x, point.y)

            } else {

                CGPathAddLineToPoint(fullPath, nil, point.x, point.y)
            }
        }

        let baseWidth = 10 / zoomScale

        CGContextAddPath(context, self.path)

        CGContextSetStrokeColorWithColor(context, UIColor.blueColor().colorWithAlphaComponent(0.3).CGColor)

        CGContextSetLineWidth(context, baseWidth * 2)

        CGContextSetLineCap(context, self.lineCap)

        CGContextStrokePath(context);

        CGContextAddPath(context, self.path)

        CGContextSetStrokeColorWithColor(context, UIColor.blueColor().CGColor)

        CGContextSetLineWidth(context, baseWidth)

        CGContextSetLineCap(context, self.lineCap)

        CGContextStrokePath(context)
    }
}

是否可以像第一张图像一样绘制路径?

1 个答案:

答案 0 :(得分:1)

对于那些可能会发现这个问题有用的人,我找到了一种方法来做到这一点。此过程适用于仅包含点的CGPath,即它不包含弧。所以这里是我创建的MKPolygonRender子类。

这些扩展来自here,感谢 Logan

import UIKit
import MapKit


extension CGPoint {
  func angleToPoint(comparisonPoint: CGPoint) -> CGFloat {
    let originX = comparisonPoint.x - self.x
    let originY = comparisonPoint.y - self.y
    let bearingRadians = atan2f(Float(originY), Float(originX))
    var bearingDegrees = CGFloat(bearingRadians).degrees
    while bearingDegrees < 0 {
        bearingDegrees += 360
    }
    return (bearingDegrees + 270).truncatingRemainder(dividingBy: 360)
  }
}

extension CGFloat {
 var degrees: CGFloat {
    return self * CGFloat(180.0 / M_PI)
 }
}

class PolygonRenderer: MKPolygonRenderer {

override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) {

    let strokeWidth = MKRoadWidthAtZoomScale(zoomScale) * self.lineWidth

    let outerPath = CGMutablePath()
    let innerPath = CGMutablePath()

    var previousPoint = point(for: self.polygon.points()[self.polygon.pointCount - 1])

    for i in 0 ..< self.polygon.pointCount {

        let currentPoint = point(for: self.polygon.points()[i])

        let nextPoint:CGPoint = point(for: self.polygon.points()[(i + 1) % self.polygon.pointCount])

        let a : CGFloat = {

            let lengthA = distance(currentPoint, b: nextPoint)
            let lengthB = distance(previousPoint, b: currentPoint)
            let lengthC = distance(nextPoint, b: previousPoint)

            return CGFloat(Int(round(Double(angle(lengthA, b: lengthB, c: lengthC)))))

        }()

        let degrees = previousPoint.angleToPoint(comparisonPoint: currentPoint)

        let strokeHyp: CGFloat = CGFloat(strokeWidth) / CGFloat(sind(Double(a) / 2))

        var newPoint = CGPoint()

        newPoint.x = CGFloat(Double(strokeHyp) * cos(degreesToRadians(Double(degrees + (360 - (a / 2))).truncatingRemainder(dividingBy: 360)))) + currentPoint.x
        newPoint.y = CGFloat(Double(strokeHyp) * sin(degreesToRadians(Double(degrees + (360 - (a / 2))).truncatingRemainder(dividingBy: 360)))) + currentPoint.y

        print("stroke width: ", strokeWidth, "stroke hyp: ", strokeHyp)

        print("pointIndex: ", i,"dir: ", degrees)

        if i == 0 {
            outerPath.move(to: currentPoint)
            innerPath.move(to: newPoint)
        } else {
            outerPath.addLine(to: currentPoint)
            innerPath.addLine(to: newPoint)
        }

        previousPoint = currentPoint
    }

    outerPath.closeSubpath()

    context.addPath(outerPath)

    context.setLineWidth(strokeWidth)

    context.setStrokeColor(self.strokeColor?.cgColor ?? UIColor.black.cgColor)

    context.strokePath()


    innerPath.closeSubpath()

    context.addPath(innerPath)

    context.setLineWidth(strokeWidth)

    context.setStrokeColor(self.strokeColor?.withAlphaComponent(0.3).cgColor ?? UIColor.black.withAlphaComponent(0.3).cgColor)

    context.strokePath()

}

func angle(_ a:CGFloat, b:CGFloat, c:CGFloat) -> CGFloat {

    var angle = (a * a) + (b * b) - (c * c)

    angle = angle / (2 * a * b)

    return CGFloat(radiansToDegrees(acos(Double(angle))))
}

func distance(_ a:CGPoint,b:CGPoint)->CGFloat{
    return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));
}

func direction(_ center:CGPoint,point:CGPoint)->CGFloat{

    let hyp = Double(distance(center, b: point))
    let adj = Double(center.y - point.y)
    var angle = CGFloat(radiansToDegrees(asin(adj/hyp)))

    if point.x < center.x {
        angle += 180
    } else {
        angle = 360 - angle
    }
    return round(angle)
}

func radiansToDegrees(_ radians:Double)->Double{
    return (radians * 180.0 / Double.pi)
}

func degreesToRadians(_ degrees:Double)->Double{
    return ((degrees - 90) * Double.pi / 180.0)
}

func sind(_ degrees: Double) -> Double {
    return __sinpi(degrees/180.0)
}
}

This is an example of this PolygonRenderer