如何在 IOS 中弯曲折线(谷歌地图)?
Posted
技术标签:
【中文标题】如何在 IOS 中弯曲折线(谷歌地图)?【英文标题】:How to Curve a polyline (Google Maps) in IOS? 【发布时间】:2018-09-11 11:27:39 【问题描述】:我想在两点之间弯曲折线。
android 在 SphericalUtil 类的帮助下做到这一点。 但在 ios 中我不知道该怎么做。
对于 Android ,这是一个参考链接: Draw ARC Polyline in Google Map
我希望 iOS 也一样。
【问题讨论】:
UIBezierPath
?!
您可以使用UIBezierPath
或第三方如github.com/ivan114/IVBezierPathRenderer..
我可以使用 UIBezierPath 绘制路径,但它可以在地图上的两个纬度经度点之间使用吗?
【参考方案1】:
聚会迟到了,但为将来遇到此问题的其他人添加解决方案:
首先:使用UIBezierPath
绘制曲线
关注UIBezierPath
的扩展。使用在CGPoint.controlpoint(_, _)
中计算的垂直控制点将每对点绘制为四边形曲线。
使用tension
值来改变曲线的锐度。 tension
或 2
生成接近四分之一圆的东西。
extension UIBezierPath
static func from(_ points: [CGPoint], tension: CGFloat) -> UIBezierPath
let path = UIBezierPath()
guard let first = points.first, points.count > 1 else
return path
path.move(to: first)
points
.pairwise()
.dropFirst()
.forEach a, b in
path.addQuadCurve(
to: b,
controlPoint: .controlpoint(a!, b, tension: tension)
)
return path
extension CGPoint
static func controlpoint(_ l: CGPoint, _ r: CGPoint, tension: CGFloat = 2) -> CGPoint
midpoint(l, r) + (perpendicular(l, r) / tension)
static func midpoint(_ l: CGPoint, _ r: CGPoint) -> CGPoint
(l + r) / 2
static func perpendicular(_ l: CGPoint, _ r: CGPoint) -> CGPoint
let d = l - r
return CGPoint(x: -d.y, y: d.x)
static func + (l: CGPoint, r: CGPoint) -> CGPoint
CGPoint(
x: l.x + r.x,
y: l.y + r.y
)
static func - (l: CGPoint, r: CGPoint) -> CGPoint
CGPoint(
x: l.x - r.x,
y: l.y - r.y
)
static func / (point: CGPoint, divisor: CGFloat) -> CGPoint
CGPoint(
x: point.x / divisor,
y: point.y / divisor
)
extension Sequence
func pairwise() -> Zip2Sequence<[Element?], Self>
zip([nil] + map(Optional.some), self)
显然,这只涉及CGPoints
,而不是CLLocationCoordinate2D
或任何其他与地图相关的数据。不过,可以在视图中绘制:
下一步:定义一个自定义MKOverlayPathRenderer
final class BezierPolylineRenderer: MKOverlayPathRenderer
var tension: CGFloat = 2.5
override func createPath()
guard let multiPoint = overlay as? MKMultiPoint else
assertionFailure("Expected MKMultiPoint")
return
let points = (0 ..< multiPoint.pointCount)
.map multiPoint.points()[$0]
.map point(for: $0)
path = UIBezierPath.from(points, tension: tension).cgPath
override func draw(
_: MKMapRect,
zoomScale: MKZoomScale,
in context: CGContext
)
context.addPath(path)
applyStrokeProperties(to: context, atZoomScale: zoomScale)
context.setStrokeColor((strokeColor ?? .gray).cgColor)
context.setLineWidth(lineWidth / zoomScale)
context.strokePath()
最后:为您的地图添加一个委托以使用自定义渲染器
final class Delegate: NSObject, MKMapViewDelegate
func mapView(_: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer
if let polyline = overlay as? MKPolyline
let renderer = BezierPolylineRenderer(overlay: polyline)
renderer.strokeColor = .blue
renderer.lineWidth = 10
return renderer
else
fatalError("Unexpected overlay type: \(overlay)")
let delegate = Delegate()
let map = MKMapView()
map.delegate = delegate
map.addOverlay(MKPolyline(coordinates: coordinates, count: coordinates.count))
把它们放在一起,它看起来像这样:
如果您不喜欢兔子跳路径:
...还有其他方法可以计算贝塞尔曲线的控制点:
extension UIBezierPath
static func from(_ points: [CGPoint], tension: CGFloat) -> UIBezierPath
let path = UIBezierPath()
guard let first = points.first, points.count > 1 else
return UIBezierPath()
var derivatives: [CGPoint] = []
for j in 0 ..< points.count
let prev = points[max(j - 1, 0)]
let next = points[min(j + 1, points.count - 1)]
derivatives.append((next - prev) / tension)
path.move(to: first)
for i in 1 ..< points.count
let cp1 = points[i - 1] + (derivatives[i - 1] / tension)
let cp2 = points[i] - (derivatives[i] / tension)
path.addCurve(to: points[i], controlPoint1: cp1, controlPoint2: cp2)
return path
上述方法在当前点前后扫描,得到两个控制点,路径更平滑:
【讨论】:
以上是关于如何在 IOS 中弯曲折线(谷歌地图)?的主要内容,如果未能解决你的问题,请参考以下文章