我试图在谷歌地图上绘制多段线,向用户显示司机/送货员的位置,就像在Uber中一样。
我用谷歌
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调用的数量
我试过什么?
我试着用线性插值法解决这个问题
不必说结果是灾难性的,因为方程假设一个笛卡尔平面,地球不是平的:|
所以最后
你到底在问什么?
-
在谷歌路径的两个坐标之间插值点,以实现我试图实现的目标,这是正确的方法吗?
-
如果是,我应该使用哪种更好的插值算法?显然,线性没有多大意义:(
请帮忙,提前谢谢