我在我的 Swift 项目中使用 Mapbox SDK,并为一些火车路径添加了自定义轨道。暂时,我正在办公室周围测试应用程序,因此,我创建了办公室周围的自定义路线。
这些自定义路线不是 Mapbox 或 Google 地图中存在的可路由轨道或道路。
我必须只在我的自定义轨道上显示任何 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
上面的这个功能工作得很好,我的位置正在更新,说明我站在哪里。
以下是此功能的结果,您可以在其中看到我站立的位置(偏离路线),
在这里,我的位置将在我移动时不断更新,并精确显示我的位置,有时在轨道上,但大部分时间不在轨道上。
但是,我的目标不是始终显示偏离轨道的位置,而是显示在轨道上的位置。
以下是我添加的用于显示我在赛道上的位置的代码,但这有点吓人:(。
我们在setAnnotation
这里更新相同的功能,
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 获取特征点
- 过滤所有坐标并通过检查与新位置的距离来找到最近的坐标
- 找到最近坐标后,在始终在轨道上的最近坐标上显示注释,或者如果距离太远,则在原始位置显示注释
这基本上显示了我在赛道上的位置,但我还没有测试整个赛道(我很快就会这样做)。
上述函数的结果,它可能会给出断断续续的响应,
但是,我想重构这个函数,并且如果我能够从 Mapbox 的样式 URL 中提取 geoJSON 文件,我还想要一些指针(我已经在 Mapbox 地图中添加了样式)。