【问题标题】:MKOverlay Custom Stroke - CGPathMKOverlay 自定义描边 - CGPath
【发布时间】:2016-02-20 00:00:41
【问题描述】:

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

我知道怎么画成这样,

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)
    }
}

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

【问题讨论】:

  • 是的,只需并排画两笔即可。
  • 你会如何使用 MKOverlay 来做到这一点?
  • 子类 MKOverlayRenderer 并自己绘制...喜欢吗?在绘制较暗的线之前将上下文向下移动 lineWidth ?
  • 你打算怎么做?我似乎无法让它与 CGAfflineTransform 或 CGAfflineScale 一起使用。有没有别的办法。
  • CGAffineTransform 应该可以正常工作,我只是不确定参数,因为我有一段时间没有做 Core Graphics 的事情了。

标签: swift dictionary overlay cgpath


【解决方案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)
}
}

【讨论】:

    猜你喜欢
    • 2023-03-18
    • 1970-01-01
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    相关资源
    最近更新 更多