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

Если здесь есть кто-нибудь с хорошим знанием геометрии, буду очень признателен!

0 ответов

Другие вопросы по тегам