Рисование дуг с помощью UIBezierPath addLine на MKMap
Я использую 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), но вторая дуга рисуется идеально. Для последнего изображения дуга идет в неправильном направлении, тогда как во всех остальных случаях направление правильное.
Если здесь есть кто-нибудь с хорошим знанием геометрии, буду очень признателен!