How to draw an arc on Google Maps in iOS?

后端 未结 5 497
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-11 07:26

How to draw an arc between two coordinate points in Google Maps like in this image and same like facebook post in iOS ?

5条回答
  •  情书的邮戳
    2020-12-11 07:59

    None of the answers mentioned is a full proof solution. For a few locations, it draws a circle instead of a polyline. To resolve this we will calculate bearing(degrees clockwise from true north) and if it is less than zero, swap the start and end location.

    func createArc(
        startLocation: CLLocationCoordinate2D,
        endLocation: CLLocationCoordinate2D) -> GMSPolyline {
    
        var start = startLocation
        var end = endLocation
    
        if start.bearing(to: end) < 0.0 {
            start = endLocation
            end = startLocation
        }
    
        let angle = start.bearing(to: end) * Double.pi / 180.0
        let k = abs(0.3 * sin(angle))
    
        let path = GMSMutablePath()
        let d = GMSGeometryDistance(start, end)
        let h = GMSGeometryHeading(start, end)
        let p = GMSGeometryOffset(start, d * 0.5, h)
        let x = (1 - k * k) * d * 0.5 / (2 * k)
        let r = (1 + k * k) * d * 0.5 / (2 * k)
        let c = GMSGeometryOffset(p, x, h + 90.0)
        var h1 =  GMSGeometryHeading(c, start)
        var h2 = GMSGeometryHeading(c, end)
    
        if (h1 > 180) {
          h1 = h1 - 360
        }
    
        if (h2 > 180) {
          h2 = h2 - 360
        }
    
        let numpoints = 100.0
        let step = ((h2 - h1) / Double(numpoints))
        for i in stride(from: 0.0, to: numpoints, by: 1) {
          let pi = GMSGeometryOffset(c, r, h1 + i * step)
          path.add(pi)
        }
        path.add(end)
    
        let polyline = GMSPolyline(path: path)
        polyline.strokeWidth = 3.0
        polyline.spans = GMSStyleSpans(
          polyline.path!,
          [GMSStrokeStyle.solidColor(UIColor(hex: "#2962ff"))],
          [20, 20], .rhumb
        )
        return polyline
      }
    

    The bearing is the direction in which a vertical line on the map points, measured in degrees clockwise from north.

    func bearing(to point: CLLocationCoordinate2D) -> Double {
        func degreesToRadians(_ degrees: Double) -> Double { return degrees * Double.pi / 180.0 }
        func radiansToDegrees(_ radians: Double) -> Double { return radians * 180.0 / Double.pi }
    
        let lat1 = degreesToRadians(latitude)
        let lon1 = degreesToRadians(longitude)
    
        let lat2 = degreesToRadians(point.latitude);
        let lon2 = degreesToRadians(point.longitude);
    
        let dLon = lon2 - lon1;
    
        let y = sin(dLon) * cos(lat2);
        let x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
        let radiansBearing = atan2(y, x);
    
        return radiansToDegrees(radiansBearing)
      }
    

提交回复
热议问题