Skip to content

Instantly share code, notes, and snippets.

@zirinisp
Created April 27, 2018 08:30
Show Gist options
  • Save zirinisp/e5cf5d9c33cb0bd815993900618eafe0 to your computer and use it in GitHub Desktop.
Save zirinisp/e5cf5d9c33cb0bd815993900618eafe0 to your computer and use it in GitHub Desktop.
Firecloud Nearby GeoQuery
import CoreLocation
extension CLLocationCoordinate2D {
func boundingBox(radius: CLLocationDistance) -> (max: CLLocationCoordinate2D, min: CLLocationCoordinate2D) {
// 0.0000089982311916 ~= 1m
let offset = 0.0000089982311916 * radius
let latMax = self.latitude + offset
let latMin = self.latitude - offset
// 1 degree of longitude = 111km only at equator
// (gradually shrinks to zero at the poles)
// So need to take into account latitude too
let lngOffset = offset * cos(self.latitude * .pi / 180.0);
let lngMax = self.longitude + lngOffset;
let lngMin = self.longitude - lngOffset;
let max = CLLocationCoordinate2D(latitude: latMax, longitude: lngMax)
let min = CLLocationCoordinate2D(latitude: latMin, longitude: lngMin)
return (max, min)
}
func isWithin(min: CLLocationCoordinate2D, max: CLLocationCoordinate2D) -> Bool {
return
self.latitude > min.latitude &&
self.latitude < max.latitude &&
self.longitude > min.longitude &&
self.longitude < max.longitude
}
}
private func convertFirestoreSpots(_ firestoreSpots: [FirestoreSpot]?,
currentLocation: CLLocationCoordinate2D) -> [(Spot, CLLocationDistance)] {
guard let firestoreSpots = firestoreSpots else {
return []
}
let spotsWithDistance: [(Spot, CLLocationDistance)] = firestoreSpots.flatMap { firestoreSpot in
guard let spot = Spot(firestoreSpot) else {
return nil
}
return (
spot,
currentLocation.distance(to: firestoreSpot.location.coordinate)
)
}
return spotsWithDistance.sorted { $0.1 < $1.1 }
}
let location = CLLocationCoordinate2D(latitude: 10.0, longitude: 20.0)
let (maxCoord, minCoord) = location.boundingBox(radius: 100)
let maxPoint = GeoPoint(
latitude: maxCoord.latitude,
longitude: maxCoord.longitude
)
let minPoint = GeoPoint(
latitude: minCoord.latitude,
longitude: minCoord.longitude
)
let locationField = "location"
let query = self.collectionReference
.whereField(locationField, isGreaterThan: minPoint)
.whereField(locationField, isLessThan: maxPoint)
.limit(to: 20)
// getModels will run the query and return the results.
return query.getModels(FirestoreSpot.self).then({ (firestoreSpots) -> [(Spot, CLLocationDistance)] in
guard let firestoreSpots = firestoreSpots else {
return [(Spot, CLLocationDistance)]()
}
// As the results are only filterd by latitude, we will have to filter them again
let filtered = firestoreSpots.filter { firestoreSpot in
return firestoreSpot.location.coordinate.isWithin(
min: minCoord,
max: maxCoord
)
}
let sorted = self.convertFirestoreSpots(
filtered,
currentLocation: location
)
let limited = Array(sorted.prefix(maxSpotsNumber))
return limited
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment