I have a 200mb geojson file containing the speed limits of a country. In short the file has polygons that encompass different areas with each polygon having a given speed limit value.
I am creating a naviagation app that needs to query this geojson file to get the speed limit the user is in. My current approach is somwhat of a linear search so whilst working induces lag and massive peformance hits to the program.
My current implementation:
func findSpeedLimit(location: CLLocationCoordinate2D, geoJSON: GeoJSON) -> Int? {
// Decode the GeoJSON data into a FeatureCollection object
guard case let .featureCollection(featureCollection) = geoJSON else {
print("Error: GeoJSON data is not a FeatureCollection")
return nil
}
// Create a Point object from the location coordinates
let point = Point(x: location.longitude, y: location.latitude)
//print("Looking for speed limit at location: \(location.latitude), \(location.longitude)")
// Loop through the features in the feature collection
for (index, feature) in featureCollection.features.enumerated() {
// Check if the feature has a geometry and properties
guard let geometry = feature.geometry,
let properties = feature.properties else {
print("Feature \(index) has no geometry or properties")
continue
}
do {
// Check if the geometry contains the point
if try geometry.contains(point) {
// Check if the properties have a speedLimitZoneValue key
if let speedLimit = properties["speedLimitZoneValue"] {
let speedLimitString = String(describing: speedLimit)
if let number = Int(speedLimitString.components(separatedBy: CharacterSet.decimalDigits.inverted).joined()) {
//print (number)
//print("Speed limit found for feature \(index): \(number) km/h")
return number
}
} else {
print("Feature \(index) has no 'speedLimitZoneValue' property")
}
} else {
//print("Feature \(index) does not contain the point")
}
} catch {
print("Error checking if geometry contains point: \(error)")
}
}
return nil
}
I tried using a GKRtree but wasent able to get it to work in this context. Any ideas?
Update, communicated with the people at the geoswift library to implement the "prepared geometry" function of geos into the library.
Implementation:
-
Map the geometry of each of your features to a PreparedGeometry by calling the new makePrepared() method, and store those values somewhere alongside the original features/properties.
-
At each location update use one of the new contains methods on PreparedGeometry to test for containment.