代码之家  ›  专栏  ›  技术社区  ›  Sandeep Bhandari

在谷歌路径的坐标之间插值点的最佳方式是什么?这种方法正确吗?

  •  0
  • Sandeep Bhandari  · 技术社区  · 7 年前

    我试图在谷歌地图上绘制多段线,向用户显示司机/送货员的位置,就像在Uber中一样。

    enter image description here

    我用谷歌 directions API 获取概览多段线并在地图上绘制。现在我从我们自己的服务器上获取驱动程序的位置,为了更新用户在地图上的位置,我在 GMSPath 我通过将俯视多段线解码为

                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)
    

    谷歌通常会在发送时返回多条路由 alternative=true 所以我缓存了所有的overview_折线,并使用第一条作为当前的over line。

    现在,通过阅读和试错,我发现捕获的驱动程序的横向长度可能存在误差,误差范围可能在5-50米之间。所以,一旦我得到了驱动程序的位置,我就遍历路径中的整个坐标,找到地图上最近的点,并将驱动程序捕捉到那个位置

               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
            }
    

    如果没有一条可用的替代路线与驾驶员位置匹配,驾驶员可能会选择完全不同的路线,因此我使用驾驶员位置再次调用routes API

    为什么会有这么多优化?

    Google的routes API成本高昂,不必要地调用Google routes API将增加财务负担,并破坏整个用户体验,因此希望在本地进行大部分计算

    但上面的代码工作得不太理想:(它工作得很好,但不是很好:|

    这种方法的问题

    问题1: 该方法假设驾驶员位置的可能错误率最大为50米,当我评估路径中所有点的距离时,会对照这50米进行检查,但不幸的是,谷歌路径中的坐标分布不均匀,在一条长直道路上,路径坐标中的两个后续点之间的距离可能高达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))))")
                    }
                }
    

    所以,当cap逻辑失败时,将驱动器位置与路径中的所有点进行比较的逻辑是50m。

    我能想到的解决办法

    如果我能以50m的规则间隔在google path的任意两个坐标之间插入点,并将上限提高到100m(路径中两点之间的距离为50m,lat-long中的误差为50m),那么我应该有更好的机会减少API调用的数量

    我试过什么?

    我试着用线性插值法解决这个问题

    enter image description here

    不必说结果是灾难性的,因为方程假设一个笛卡尔平面,地球不是平的:|

    所以最后 你到底在问什么?

    1. 在谷歌路径的两个坐标之间插值点,以实现我试图实现的目标,这是正确的方法吗?

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

    请帮忙,提前谢谢

    0 回复  |  直到 7 年前
        1
  •  1
  •   DarkoS    6 年前

    谷歌本身也提供了各种在GMSGeometryTils模块中插值的方法。我认为插值所需的可能是: https://developers.google.com/maps/documentation/ios-sdk/reference/group___geometry_utils.html#gad0c5870bd9d182d22310f84a77888124

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