Я пытаюсь нанести Полилинию на Googlemap, чтобы показать положение водителя / курьера для пользователя, как в Uber.
Я использую Google направления 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)
Google обычно возвращает несколько маршрутов при отправке alternative=true
, поэтому я кеширую всю review_polyline и использую первый в качестве текущей надстрочной линии.
Теперь из чтения и пробной ошибки я выяснил, что может быть ошибка в lat-long перехваченного драйвера, и она может варьироваться от 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)))
}
, обновляя Polyline как
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
}
Если ни один из доступных альтернативных маршрутов не соответствует местоположению водителя, возможно, водитель выбирает совершенно другой маршрут, поэтому я снова выполняю вызов API-маршрутов с местоположением водителя
Почему так много оптимизации?
API-интерфейсы Google-маршрутов являются дорогостоящими, а вызов API-интерфейсов Google-маршрутов излишне увеличит финансовую нагрузку, а также испортит весь пользовательский опыт и, следовательно, позволит выполнять большинство расчетов локально.
Но приведенный выше код работает неоптимально :( Он работает, но не очень хорошо: |
Проблемы с этим подходом
Проблема 1: Метод предполагает, что возможная частота ошибок в местоположении водителей не должна превышать 50 м, и когда я оцениваю все расстояния до точек пути,Получите эти 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))))")
}
}
Таким образом, логика сравнения местоположения драйверов со всеми точками на пути с 50 м, так как там нет логики ограничения.
Решение, которое я могу придумать
Если я смогу интерполировать точки между любыми двумя координатами в пути Google с регулярным интервалом 50 м и поднять ограничение до 100 м (расстояние между двумя точками в пути 50 м, ошибка по длине 50 м), что должнодать мне гораздо больше шансов уменьшить количество вызовов API
Что я пробовал?
Я пытался решить эту проблему с помощью линейной интерполяции с использованием
Нет необходимости говорить, что результат катастрофичен, поскольку в уравнении предполагается, что декартова плоскость и земля не плоская: |
Итак, наконец Какого черта вы спрашиваете?
Правильный ли подход для интерполяции точек между двумя координатами пути Google для достижениячто я пытаюсь достичь?
Если да, то какой алгоритм интерполяции лучше использовать?Очевидно, что линейность не имеет большого смысла: (
Пожалуйста, помогите, заранее спасибо