在 google 路径中的坐标之间插入点的最佳方法是什么?这种方法正确吗?

What is the best way to interpolate points between coordinates in google path? Is this approach correct?

我正在尝试在 Google 地图上绘制折线,以像 Uber 中那样向用户显示 driver/delivery 男孩的位置。

我使用 google directions API 获取概览折线并将其绘制在地图上。现在我从我们自己的服务器获取 driver 位置,为了更新地图上的用户位置,我遍历 GMSPath 中的 co-ordinates,这是我通过解码 over-view 获得的折线为

            if let jsonArray = jsonResult["routes"].array, jsonArray.count > 0 {
                for json in jsonArray {
                    if let polyline = json["overview_polyline"]["points"].string {
                        self.possibleOverViewPolylines.append(polyline)
                    }
                }
            }
            self.currentPolyline =  self.possibleOverViewPolylines[0]
            self.path = GMSMutablePath.init(fromEncodedPath: self.currentPolyline)
            self.polyline = GMSPolyline(path: self.path)

Google 通常 returns 发送时有多个路由 alternative=true 所以我缓存所有 overview_polyline 并使用第一个作为当前线路。

现在通过阅读和 trial-error 我发现捕获的 driver 的 lat-long 中可能存在错误,范围可能在 5-50 米之间。因此,一旦我获得 driver 位置,我将遍历路径中的整个坐标以找到地图中最近的点并将 driver 捕捉到该位置

           var overallDistance: CLLocationDistance = 50
           for index in 0 ..< strongSelf.path.count() {
                let coordinate = strongSelf.path.coordinate(at: UInt(index))
                let distance = location.distance(to: coordinate)
                if distance < overallDistance {
                    foundIndex = Int(index)
                    overallDistance = distance
                }
            }
            if overallDistance >= 50 {
                debugPrint("\(location)")
                evaluateAlternativeRoutes()
            }
            else {
                updatepolyline(location: strongSelf.path.coordinate(at: UInt(foundIndex)))
            }

将折线更新为

            self?.polyline.map = nil
            while strongSelf.path.coordinate(at: UInt(0)).latitude != location.latitude &&  strongSelf.path.coordinate(at: UInt(0)).longitude != location.longitude {
                self?.path.removeCoordinate(at: 0)
            }
            if strongSelf.path.coordinate(at: 0).latitude == location.latitude && strongSelf.path.coordinate(at: UInt(0)).longitude == location.longitude {
                self?.path.removeCoordinate(at: 0)
            }
            self?.polyline = GMSPolyline(path: strongSelf.path)

最终替代路线被评估为

        var overallDistance: CLLocationDistance = 50
        var foundIndex = -1

        for (polylineIndex,polyline) in strongSelf.possibleOverViewPolylines.enumerated() {
            if let path = GMSMutablePath.init(fromEncodedPath: polyline) {
                for index in 0 ..< path.count() {
                    let coordinate = path.coordinate(at: UInt(index))
                    let distance = location.distance(to: coordinate)
                    if distance < overallDistance {
                        foundIndex = polylineIndex
                        overallDistance = distance
                    }
                }
            }
        }
        if foundIndex != -1 {
             self?.path = GMSMutablePath.init(fromEncodedPath: strongSelf.possibleOverViewPolylines[foundIndex])
        }
        else {
             //make routes API call again
        }

如果 none 可用的替代路线与 driver 位置匹配,driver 可能会采用完全不同的路线,因此我再次调用路线 API driver 地点

为什么要优化这么多?

Google 的路由 API 成本高昂,不必要地调用 google 路由 API 会增加经济负担并破坏整个用户体验,因此想在本地进行大部分计算

但上面的代码有效 sub-optimally :( 它有效但不是很好 :|

此方法存在问题

问题 1: 方法假设 drivers 位置的可能错误率最大为 50m,当我评估到路径中所有点的距离时,都会根据这个 50 检查,但不幸的是 google 路径中的坐标分布不均,在一条漫长的直路上,路径坐标中两个后续点之间的距离可达 200 米。我用

测试了它
           for i in 0 ..< self.path.count() {
                if i == 0 {
                    debugPrint(self.path.coordinate(at: i))
                }
                else {
                    debugPrint("distance between \(self.path.coordinate(at: (i - 1))) and \(self.path.coordinate(at: (i))) is \(self.path.coordinate(at: (i - 1)).distance(to: self.path.coordinate(at: (i))))")
                }
            }

因此,将 driver 的位置与 50m 路径中的所有点进行比较的逻辑作为上限逻辑在那里失败。

我能想到的方案

如果我可以在 google 路径中任意两个坐标之间以 50m 的规则间隔插入点,并将上限提高到 100m(路径中两点之间的距离为 50m,[= 中的误差为 50m 91=]) 这应该给我更好的机会来减少 API 调用的次数

我试过什么?

我尝试使用

通过线性插值来解决它

不用说结果是灾难性的,因为等式假设笛卡尔平面和地球不是平的:|

最后 你到底在问什么?

  1. 在 google 路径的两个坐标之间插入点以实现我想要实现的目标是否是正确的方法?

  2. 如果是,我应该使用哪种更好的插值算法?显然线性没有多大意义:(

请帮忙,提前致谢

Google 本身在 GMSGeometryUtils 模块中提供了各种插值方法。我认为您需要进行插值的可能是: https://developers.google.com/maps/documentation/ios-sdk/reference/group___geometry_utils.html#gad0c5870bd9d182d22310f84a77888124

GMSGeometryInterpolate 使用您在给定分数处提供的 'from' 和 'to' 坐标之间的最短路径,并且 GMSPath 确实连接了您提供的每个子序列坐标之间的最短路径,因此它应该足够了。