0

我正在使用 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 左右),但第二条弧线绘制得非常完美。对于最后一张图像,弧线的方向是错误的,而在所有其他情况下,方向是好的。

如果这里有人对几何有很好的了解,将不胜感激!

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

在此处输入图像描述

4

0 回答 0