简体   繁体   English

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

[英]How to draw arc/curve line with MKOverlayView on 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?我可以用 MKPolyline 和 MKPolylineView 画线,但是如何在 MKMapView 上的两个坐标之间画弧线或曲线? Great thanks.万分感谢。

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.您已经在评论中回答了自己,但我想向大家指出 GitHub 上优秀的AIMapViewWrapper项目,其中包括用于在一组坐标上绘制圆弧路径的示例代码 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.任何人都应该派上用场。

Reading the documentation, it seems that you can create an instance of MKOverlayPathView and assign an arbitrary CGPathRef object to its path property.阅读文档,似乎您可以创建MKOverlayPathView的实例并将任意CGPathRef对象分配给其path属性。 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.我不知道(并且文档没有提到)路径的坐标应该是什么格式( MKMapPointCLLocationCoordinate2D ),但您可能可以通过一些试验找到MKMapPoint

Before answering the question it is important to mention that MKOverlayView is deprecated and from iOS7 and later we should use MKOverlayRenderer :在回答这个问题之前,重要的是要提到MKOverlayView已被弃用,并且从 iOS7 和更高版本开始,我们应该使用MKOverlayRenderer

In iOS 7 and later, use the MKOverlayRenderer class to display overlays instead.在 iOS 7 及更高版本中,请改用 MKOverlayRenderer 类来显示叠加层。

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:让我们用 2 个坐标创建一个:
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:添加折线后, MKMapView会要求我们提供一个合适的MKOverlayRenderer对应于我们在第 1 部分创建的MKPolyline 。我们需要的方法是:

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:我们将要继承MKOverlayPathRenderer这显然继承自MKOverlayRenderer和文档状态:

Use this renderer when your overlay's shape is defined by a CGPath object.当您的叠加层的形状由 CGPath 对象定义时,请使用此渲染器。 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:因此,如果我们按原样使用我们新的子类对象,我们将得到一个开箱即用的解决方案,它是从第 1 节中定义的第一个坐标到第二个坐标的实线,但由于我们想要一个曲线,我们将不得不为此重写一个方法:

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.如果是子类,则覆盖 createPath() 方法并使用该方法构建适当的路径对象。 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 :这意味着在我们的CustomObject: MKOverlayPathRenderer我们将覆盖createPath

override func createPath() {
 // 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: (可选)如果您对渐变曲线感兴趣,这里有一个非常好的解决方案但您必须在代码中进行 2 处更改才能使其正常工作:

4.1. 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:在覆盖override func draw(_ mapRect: MKMapRect, zoomScale: MKZoomScale, in context: CGContext) ,就在添加渐变之前,您必须添加第 3 节中的相同代码,但不是更改内部path而是必须添加它提供的上下文:

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. 4.2. Instead of using path.boundingBoxOfPath we will need to use path.boundingBox because:而不是使用的path.boundingBoxOfPath我们将需要使用path.boundingBox因为:

... including control points for Bézier and quadratic curves. ...包括贝塞尔曲线和二次曲线的控制点。

Unlike boundingBoxOfPath :boundingBoxOfPath不同:

... not including control points for Bézier and quadratic curves. ...包括贝塞尔曲线和二次曲线的控制点。

Hope that helps :)希望有帮助:)

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.MKPolylineMKPolylineView画线, MKPolygonMKPolygonView画多边形, MKCircleMKCircleView 画圆 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.现在真正的解决方案是:您创建一个从MKOverlayPathView派生的自定义类并覆盖-createPath方法,在-createPath 中创建一个弧,使用CGContextAddArcToPoint或其他您喜欢的函数,并将您刚刚创建的路径关联到MKOverlayPathView的路径属性和定制工作完成。 Then you add MKPolyline in the map(Yes! just MKPolyline !), Then in the -mapView:viewForOverlay: method you create the custom class take that polyline.然后在地图中添加 MKPolyline(是的!只是MKPolyline !),然后在-mapView:viewForOverlay:方法中创建自定义类,采用该折线。 Then, just run it, everything is runs as you wish.然后,运行它,一切都如你所愿。 Magic?魔法? you can draw a MKPolyline as an arc!您可以将MKPolyline绘制为圆弧!
  2. Just an image?就一张图? Use MKAnnotationView .使用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.所以我创建了一个符合MKOverlay协议的自定义类,以及一个从MKOverlayView派生的自定义类来绘制该叠加层。 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!我已经将 lineWidth 设置为 1,2,3,4 ......但它不起作用! Ah..the solution is set the line width with MKRoadWidthAtZoomScale(zoomScale) function and you can see the path!啊..解决方案是用MKRoadWidthAtZoomScale(zoomScale)函数设置线宽,你可以看到路径! That's done......就这样了……

And some tips here:还有一些提示:

  1. Use Core Graphic to draw paths, not MapKit coordinates nor UIView coordinates!使用 Core Graphic 绘制路径,而不是 MapKit 坐标或 UIView 坐标!
  2. In the CG functions just keep in mind the line width should be converted by this function: MKRoadWidthAtZoomScale(zoomScale)在 CG 函数中,请记住应通过此函数转换线宽: MKRoadWidthAtZoomScale(zoomScale)
  3. Hope to help希望有所帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM