Mapbox Swift SDK - показывать аннотации на определенном треке (привязка к маршруту)
Я использую Mapbox SDK с моим проектом Swift и добавляю собственные треки для некоторых путей поездов. Временно я тестирую приложение в офисе, поэтому я создал собственный маршрут по офису.
Эти настраиваемые маршруты не являются маршрутами или дорогами, существующими в Mapbox или Google Maps.
Я должен показывать любые местоположения GPS только на моем собственном треке, а не вне его.
Давайте возьмем пример кода, у меня есть следующий код, который показывает мое местоположение по GPS, где я нахожусь.
func setAnnotation(atLocation location: CLLocation, forDevice device: String, andUser userId: Int) {
var locationMarker = LSTPointAnnotation()
// Check from list of annotations if the annotation exists or not
// as I am showing multiple annotations at a time for different people
// and all annotations update their individual locations in async fashion
if let userMarker = self.markerAnnotations[device] {
locationMarker = userMarker
} else {
markerAnnotations[device] = locationMarker
userDevices[userId] = device
self.mapView?.addAnnotation(locationMarker)
}
// We are creating annotation from Mapbox's 'viewForAnnotation' method
if let annotationView = self.mapView?.view(for: locationMarker) as? LSTLocoAnnotationView {
// I am changing color of annotation view after some processing
// Here only UI customisation is done
}
// Updating location of the annotation
locationMarker.coordinate = location.coordinate
}
В основном то, что делает вышеуказанная функция,
- Получить маркер пользователя из списка доступных маркеров аннотации или создать новую аннотацию
- Обновите местоположение этого маркера с новым местоположением, которое у нас есть
location
Эта функция выше работает отлично, и мое местоположение обновляется с указанием того, где я нахожусь.
Ниже приведен результат этой функции, где вы сможете увидеть место, где я стою (вне маршрута).
Здесь мое местоположение будет постоянно обновляться, когда я двигаюсь, и точно показывает мое местоположение когда-то на трассе, но в основном вне трассы.
Однако моя цель - не показывать локацию вне трассы, а всегда на трассе.
Ниже приведен код, который я добавил, чтобы показать свое местоположение на трассе, но это немного пугает :(.
Мы обновляем то же самое
func setAnnotation(atLocation location: CLLocation, forDevice device: String, andUser userId: Int) {
var locationMarker = LSTPointAnnotation()
// Check from list of annotations if the annotation exists or not
// as I am showing multiple annotations at a time for different people
// and all annotations update their individual locations in async fashion
if let userMarker = self.markerAnnotations[device] {
locationMarker = userMarker
} else {
markerAnnotations[device] = locationMarker
userDevices[userId] = device
self.mapView?.addAnnotation(locationMarker)
}
// Now I have geoJson file for custom route
// as I have stylised that route with dash lines
// Accessing all features with dash-lines
let features = self.mapView?.visibleFeatures(in: map.bounds, styleLayerIdentifiers: Set(arrayLiteral: "polyline-dash"))
// Will mark nearest-coordinates and nearest distance with new location of that coordinate
var nearestCoord: CLLocationCoordinate2D?
var nearest: Double?
// Sorting all feature points based on nearest location distance (Assumption)
if let json = features?.sorted(by: { firstFeature, secondFeature in
let firstDistance = firstFeature.coordinate.distance(to: location.coordinate)
let secondDistance = secondFeature.coordinate.distance(to: location.coordinate)
return firstDistance < secondDistance
}).first?.geoJSONDictionary(),
let geometry = json["geometry"] as? Dictionary<String, Any>,
let coords = geometry["coordinates"] as? Array<Array<Any>> {
// Have to take geoJSONDictionary as without it
// I would not be able to access underlying coordinates of the feature
// feature.coordinate gives centre of Mapbox View (It always keep annotation at centre of the screen which is not required)
// Loop through all coordinates and finding nearest coord with new location
for coord in coords {
if let inners = coord as? Array<Any> {
for inner in inners {
guard let t1 = inner as? Array<Double> else { return }
let c1 = CLLocationCoordinate2D(latitude: t1[1], longitude: t1[0])
let firstDistance = c1.distance(to: location.coordinate)
// Save nearest location and nearest distance
if let dist = nearest {
if firstDistance < dist {
nearest = firstDistance
nearestCoord = c1
}
} else {
nearest = firstDistance
nearestCoord = c1
}
}
}
}
}
// We are creating annotation from Mapbox's 'viewForAnnotation' method
if let annotationView = self.mapView?.view(for: locationMarker) as? LSTLocoAnnotationView {
// I am changing color of annotation view after some processing
// Here only UI customisation is done
}
// Updating location of the annotation with nearest coordinate from route
// But if distance is too large then we are showing original location
if let near = nearestCoord, (nearest ?? 0) <= 100 {
locationMarker.coordinate = near
} else {
locationMarker.coordinate = location.coordinate
}
}
Что делает функция выше,
- Взять характерные точки из geoJson
- Отфильтруйте все координаты и найдите ближайшую координату, проверив расстояние с новым местоположением
- Как только ближайшая координата найдена, покажите аннотацию к ближайшей координате, которая всегда соответствует заданному маршруту, или, если расстояние слишком велико, затем покажите аннотацию в исходном местоположении
Это в основном показывает мое местоположение на трассе, но я не тестировал всю трассу (что я скоро сделаю).
Результат вышеуказанной функции, он может давать прерывистый ответ,
Однако я хочу реорганизовать эту функцию, а также мне нужны указатели, могу ли я извлечь файл geoJSON из URL-адреса стиля Mapbox или нет (я уже добавил стили в карту Mapbox).