如何在MKMapView上使用MKOverlayView绘制圆弧/曲线

发布于 2024-11-01 03:16:11 字数 92 浏览 1 评论 0原文

现在需要帮助。 我可以使用 MKPolyline 和 MKPolylineView 绘制线条,但是如何在 MKMapView 上的两个坐标之间绘制圆弧或曲线? 非常感谢。

Help needed now.
I can draw lines with MKPolyline and MKPolylineView, but how to draw an arc or curve lines between two coordinates on the MKMapView?
Great thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

筱果果 2024-11-08 03:16:11

在回答问题之前,重要的是要提到 MKOverlayView 已弃用,并且从 iOS7 及更高版本开始我们应该使用 MKOverlayRenderer

在 iOS 7 及更高版本中,请使用 MKOverlayRenderer 类来显示叠加层。

现在我们可以分解如何实现圆弧/曲线:

  1. 首先,我们需要定义并添加折线。让我们创建一个具有 2 个坐标的折线:
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
mapView.addOverlay(polyline)
  1. 添加折线后,MKMapView 将要求我们提供一个与我们已经创建的 MKPolyline 相对应的适当的 MKOverlayRenderer在第 1 节中创建。我们需要的 方法 是:

mapView(_mapView: MKMapView, rendererFor 覆盖: MKOverlay) -> MKOverlayRenderer

基本上:

向委托请求渲染器对象以在绘制指定叠加层时使用。

  1. 那么让我们提供该对象。我们希望将 MKOverlayPathRenderer 子类化,它显然继承自 MKOverlayRenderer 并且如文档所述:

当叠加层的形状由 CGPath 对象定义时,请使用此渲染器。默认情况下,此渲染器填充叠加层的形状并使用其当前属性表示路径的笔划。

因此,如果我们按原样使用新的子类对象,我们将得到一个开箱即用的解决方案,它是从第一个坐标到我们在第 1 节中定义的第二个坐标的实线,但由于我们想要一个曲线我们必须重写一个方法:

您可以按原样使用此类或子类来定义其他绘图行为。如果您创建子类,请重写 createPath() 方法并使用该方法构建适当的路径对象。要更改路径,请将其无效并使用子类获得的任何新数据重新创建路径。

这意味着在我们的 CustomObject: MKOverlayPathRenderer 中,我们将重写 createPath

override func createPath() {
 let polyline = overlay as! MKPolyline
 // Getting the coordinates from the polyline
 let points = polyline.points()
 // Taking the center of the polyline (between the 2 coordiantes) and converting to CGPoint
 let centerMapPoint = MKMapPoint(polyline.coordinate)
 // Converting coordinates to CGPoint corresponding to the specified point on the map
 let startPoint = point(for: points[0])
 let endPoint = point(for: points[1])
 let centerPoint = point(for: centerMapPoint)

 // I would like to thank a co-worker of mine for the controlPoint formula :)
 let controlPoint = CGPoint(x: centerPoint.x + (startPoint.y - endPoint.y) / 3,
                            y: centerPoint.y + (endPoint.x - startPoint.x) / 3)

 // Defining our new curved path using Bezier path
 let myPath = UIBezierPath()
 myPath.move(to: startPoint)
 myPath.addQuadCurve(to: endPoint,
                     controlPoint: controlPoint)
 // Mutates the solid line with our curved one
 path = myPath.cgPath
}

我们基本上完成了。您可能需要考虑添加宽度/描边/颜色等,以便您可以看到曲线

  1. (可选)如果您对渐变曲线感兴趣,有一个非常好的解决方案 此处,但您必须在代码中进行 2 处更改才能使其正常工作:

4.1。重写 override func draw(_ mapRect: MKMapRect, ZoomScale: MKZoomScale, in context: CGContext) 后,在添加渐变之前,您必须添加第 3 节中的相同代码,但不要更改在内部 path 中,您必须将其添加到提供的上下文中:

context.move(to: startPoint)
context.addQuadCurve(to: endPoint,
                     control: controlPoint)

这基本上为我们提供了一条关于渐变着色所需的曲线。

4.2.我们需要使用 path.boundingBox 而不是使用 path.boundingBoxOfPath ,因为:

...包括贝塞尔曲线和二次曲线的控制点。

boundingBoxOfPath 不同:

...包括贝塞尔曲线和二次曲线的控制点。

希望有帮助:)

Before answering the question it is important to mention that MKOverlayView is deprecated and from iOS7 and later we should use MKOverlayRenderer:

In iOS 7 and later, use the MKOverlayRenderer class to display overlays instead.

We can now break it down on how to implement the arc/curve line:

  1. First, we need to define and add our poly line. Let's create one with 2 coordinates:
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
mapView.addOverlay(polyline)
  1. After adding the polyline, MKMapView will want us to provide a proper MKOverlayRenderer in corresponding to the MKPolyline we've created at section 1. The method we need is:

mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer

Which basically:

Asks the delegate for a renderer object to use when drawing the specified overlay.

  1. So let's provide that object. We will want to subclass MKOverlayPathRenderer which obviously inherits from MKOverlayRenderer and as documentation states:

Use this renderer when your overlay's shape is defined by a CGPath object. By default, this renderer fills the overlay's shape and represents the strokes of the path using its current attributes.

So if we will use our newly subclass object as is, we will get an out-of-the-box solution which is a solid line from the 1st coordinate to the 2nd one we've defined in section 1, but since we want a curved line we will have to override a method for that:

You can use this class as-is or subclass to define additional drawing behaviors. If you subclass, override the createPath() method and use that method to build the appropriate path object. To change the path, invalidate it and recreate the path using whatever new data your subclass has obtained.

It means that inside our CustomObject: MKOverlayPathRenderer we will override createPath:

override func createPath() {
 let polyline = overlay as! MKPolyline
 // Getting the coordinates from the polyline
 let points = polyline.points()
 // Taking the center of the polyline (between the 2 coordiantes) and converting to CGPoint
 let centerMapPoint = MKMapPoint(polyline.coordinate)
 // Converting coordinates to CGPoint corresponding to the specified point on the map
 let startPoint = point(for: points[0])
 let endPoint = point(for: points[1])
 let centerPoint = point(for: centerMapPoint)

 // I would like to thank a co-worker of mine for the controlPoint formula :)
 let controlPoint = CGPoint(x: centerPoint.x + (startPoint.y - endPoint.y) / 3,
                            y: centerPoint.y + (endPoint.x - startPoint.x) / 3)

 // Defining our new curved path using Bezier path
 let myPath = UIBezierPath()
 myPath.move(to: startPoint)
 myPath.addQuadCurve(to: endPoint,
                     controlPoint: controlPoint)
 // Mutates the solid line with our curved one
 path = myPath.cgPath
}

We are basically done. You might want to consider adding width/stroke/color etc so you could see the curved line.

  1. (Optional) If you are interested in a gradient curved line, there is a really great solution here but there are 2 changes you will have to make in the code in order for this to work:

4.1. After overriding override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext), just before adding the gradient, you will have to add the same code from section 3 but instead of changing the inner path you will have to add it to the provided context:

context.move(to: startPoint)
context.addQuadCurve(to: endPoint,
                     control: controlPoint)

This basically gives us a curved line we need regarding the gradient coloring.

4.2. Instead of using path.boundingBoxOfPath we will need to use path.boundingBox because:

... including control points for Bézier and quadratic curves.

Unlike boundingBoxOfPath:

... not including control points for Bézier and quadratic curves.

Hope that helps :)

少钕鈤記 2024-11-08 03:16:11

阅读文档后,您似乎可以创建 MKOverlayPathView 实例并将任意 CGPathRef 对象分配给其 path 属性。该路径可以包含直线和圆弧。

我不知道(并且文档没有提到)路径的坐标应该采用什么格式(MKMapPointCLLocationCooperative2D 浮现在脑海中),但你可能可以通过尝试一下就能找到答案。

Reading the documentation, it seems that you can create an instance of MKOverlayPathView and assign an arbitrary CGPathRef object to its path property. This path can contain both straight lines and arcs.

I don't know (and the documentation doesn't mention) in what format the coordinates of the path should be (MKMapPoint or CLLocationCoordinate2D come to mind) but you can probably find that out by experimenting a bit.

甜嗑 2024-11-08 03:16:11

您已经在评论中回答了自己,但我想向大家指出优秀的 AIMapViewWrapper 项目GitHub,其中包含用于绘制圆弧的示例代码一组坐标上的路径。在该项目中,它用于绘制飞机所采用的路径,包括其下方的阴影路径(以及其他内容,例如沿该路径制作飞机动画)。对于任何对此感兴趣的人来说应该派上用场。

You answered yourself in your comment already, but I'd like to point everyone at the excellent AIMapViewWrapper project on GitHub which includes sample code for plotting an arc path over a set of coordinates. In that project it's being used to draw the path a plane takes including a shadow path underneath it (and other stuff such as animating a plane along that path). Should come in handy for anyone taking a stab at this.

万劫不复 2024-11-08 03:16:11

如果你想:

  1. 只在地图上绘制圆弧路径
  2. 只在地图上绘制图像
  3. 将圆弧路径和图像叠加在地图上

所以解决方案是:

  1. MKPolylineMKPolylineView绘制直线,MKPolygonMKPolygonView绘制多边形,MKCircleMKCircleView绘制圆形。没人适合吗?哪里有弧线?哦是的。现在真正的解决方案:您创建一个从 MKOverlayPathView 派生的自定义类并覆盖 -createPath 方法,在 -createPath 中创建一个弧线使用CGContextAddArcToPoint或者其他你喜欢的函数,将刚刚创建的路径关联到MKOverlayPathView的path属性,自定义工作就完成了。然后在地图中添加 MKPolyline(是的!只是 MKPolyline!),然后在 -mapView:viewForOverlay: 方法中创建自定义类,采用该折线。然后,运行它,一切都会如你所愿地运行。魔法?您可以将 MKPolyline 绘制为圆弧!
  2. 只是一个图像?使用MKAnnotationView。这样就完成了!你能做到的!我相信!
  3. 在我的问题中,我想在叠加层中绘制带有图像的圆弧。因此,我创建了一个符合 MKOverlay 协议的自定义类,以及一个从 MKOverlayView 派生的自定义类来绘制该叠加层。一切正常,但我无法在地图上绘制任何路径!我已将 lineWidth 设置为 1,2,3,4...但它不起作用!啊..解决办法是用MKRoadWidthAtZoomScale(zoomScale)函数设置线宽,就可以看到路径了!大功告成……

这里还有一些提示:

  1. 使用Core Graphic来绘制路径,而不是MapKit坐标或UIView坐标!
  2. 在 CG 函数中,请记住线宽应通过此函数转换:MKRoadWidthAtZoomScale(zoomScale)
  3. 希望有所帮助

If you want to:

  1. just draw arc path on map
  2. just draw an image on map
  3. combine arc path and image as overlay on map

So the solutions are:

  1. There are MKPolyline and MKPolylineView to draw lines, MKPolygon and MKPolygonView to draw polygons, MKCircle and MKCircleView to draw circles. No one fit? Where is an arc? Oh, yes. Now the really solution: You create a custom class derived from MKOverlayPathView and override the -createPath method, in the -createPath you create an arc use CGContextAddArcToPoint or others functions you like, and associate the path you just create to the path property of MKOverlayPathView and the custom works are done. Then you add MKPolyline in the map(Yes! just MKPolyline!), Then in the -mapView:viewForOverlay: method you create the custom class take that polyline. Then, just run it, everything is runs as you wish. Magic? you can draw a MKPolyline as an arc!
  2. Just an image? Use MKAnnotationView. That's done! you can do it! I believe that!
  3. In my problem, I want to draw an arc with an image in the overlay. So I create a custom class conforms to the MKOverlay protocol, and a custom class derived from MKOverlayView to draw that overlay. Everything works fine but I can't draw any path on the map! I've set the lineWidth to 1,2,3,4... but it wasn't work! Ah..the solution is set the line width with MKRoadWidthAtZoomScale(zoomScale) function and you can see the path! That's done......

And some tips here:

  1. Use Core Graphic to draw paths, not MapKit coordinates nor UIView coordinates!
  2. In the CG functions just keep in mind the line width should be converted by this function:MKRoadWidthAtZoomScale(zoomScale)
  3. Hope to help
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文