我正在使用 MKOverlayPathRenderer 和 UIBezierPath(画线)来创建弧线。我不使用addArc
方法,因为第一个和最后一个半径可能不同。
import Foundation
import UIKit
import MapKit
class IGAArcRenderer: MKOverlayPathRenderer {
var polyline: MKPolyline
var arcCentreMapPoint: MKMapPoint
var initialBearing : Double
var finalBearing : Double
init(polylineIn: MKPolyline,centreCoordinates: CLLocationCoordinate2D,initBearing: Double,finalBearing: Double) {
polyline = polylineIn
self.arcCentreMapPoint = MKMapPoint(centreCoordinates)
self.initialBearing = initBearing
self.finalBearing = finalBearing
super.init(overlay: polyline)
setup()
}
override func createPath() {
let points = polyline.points()
let startPoint = point(for: points[0])
let endPoint = point(for: points[1])
// Defining our new curved path using Bezier path
let myPath = UIBezierPath()
myPath.move(to: startPoint)
let arcCentre = point(for: arcCentreMapPoint)
let startAngle = deg2rad(Deg: CGFloat(self.initialBearing+90))
let endAngle = deg2rad(Deg: CGFloat(self.finalBearing+90))
// Radius to Start and End Points
let radiusStart = CGPointDistance(from: arcCentre, to: startPoint)
let radiusEnd = CGPointDistance(from: arcCentre, to: endPoint)
// Calculate which direction the arc should go when is drawn.
// If the following value is greater than 0, go clockwise
//let c = (startPoint.x-arcCentre.x)*(endPoint.y-arcCentre.y)-(startPoint.y-arcCentre.y)*(endPoint.x-arcCentre.x)
//let direction = c<0 ? false : true
/* NOTE: This code is working and draws an arc, which is not always perfect due to differences in radius
myPath.addArc(withCenter: arcCentre,
radius: radius,
startAngle: startAngle,
endAngle: endAngle,
clockwise: direction)
myPath.addLine(to: endPoint)
*/
// Draw an arc by adding a number of lines determined by delta radius and delta angle
let numpoints = 100
let stepRadius = (radiusEnd-radiusStart)/CGFloat(numpoints)
var stepAngle : CGFloat = 0.0
if startAngle>=0 && endAngle>=0 {
stepAngle = (endAngle-startAngle)/CGFloat(numpoints)
}
else if startAngle<0 && endAngle>=0 {
stepAngle = (endAngle+startAngle)/CGFloat(numpoints)
}
else if startAngle>=0 && endAngle<0 {
stepAngle = (endAngle+startAngle)/CGFloat(numpoints)
}
else if startAngle<0 && endAngle<0 {
stepAngle = (endAngle-startAngle)/CGFloat(numpoints)
}
print("........ C \(c)")
print("........ START ANGLE \(startAngle)")
print("........ END ANGLE \(endAngle)")
print("........ STEP ANGLE 11 \(endAngle-startAngle)")
print("........ STEP ANGLE 22 \(stepAngle)")
// For each point, calculate the CGPoint based on the radius and angle
// and draw a line to this point
for i in 0..<numpoints {
var angleCurrent : CGFloat = 0.0
// Trying to play here to get the right direction
if startAngle>=0 && startAngle>endAngle {
angleCurrent = startAngle+CGFloat(i)*stepAngle // ORIGINAL
}
else if startAngle<0 && startAngle>endAngle {
angleCurrent = startAngle-CGFloat(i)*stepAngle // ORIGINAL
}
if startAngle>=0 && startAngle<endAngle {
angleCurrent = startAngle-CGFloat(i)*stepAngle // ORIGINAL
}
else {
angleCurrent = startAngle+CGFloat(i)*stepAngle // ORIGINAL
}
// Next radius
let radiusCurrent = radiusStart+CGFloat(i)*stepRadius
// Find the CGPoint
let pi_x = cos(angleCurrent)*((arcCentre.x-radiusCurrent)-arcCentre.x)-sin(angleCurrent)*((arcCentre.y)-arcCentre.y)+arcCentre.x
let pi_y = sin(angleCurrent)*((arcCentre.x-radiusCurrent)-arcCentre.x)+cos(angleCurrent)*((arcCentre.y)-arcCentre.y)+arcCentre.y;
let newLocation = CGPoint(x: pi_x, y: pi_y)
myPath.addLine(to: newLocation)
}
myPath.addLine(to: endPoint)
path = myPath.cgPath
}
func CGPointDistanceSquared(from: CGPoint, to: CGPoint) -> CGFloat {
return (from.x - to.x) * (from.x - to.x) + (from.y - to.y) * (from.y - to.y)
}
func CGPointDistance(from: CGPoint, to: CGPoint) -> CGFloat {
return sqrt(CGPointDistanceSquared(from: from, to: to))
}
func deg2rad(Deg deg: CGFloat) -> CGFloat {
return (deg * .pi / 180.0);
}
func rad2deg(Rad rad: CGFloat) -> CGFloat {
return (rad * 180 / .pi);
}
}
有时,弧线绘制得很好,有时方向和角度步长值的计算存在问题。以下是我使用键值得到的一些示例。对于第一张图像,计算第一条弧线的正确角度步长存在问题(应该在 0.017 左右),但第二条弧线绘制得非常完美。对于最后一张图像,弧线的方向是错误的,而在所有其他情况下,方向是好的。
如果这里有人对几何有很好的了解,将不胜感激!