Skip to content

Instantly share code, notes, and snippets.

@kayoslab
Last active March 4, 2017 19:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kayoslab/90ffed97919e6413ae95df5cf86aa2f7 to your computer and use it in GitHub Desktop.
Save kayoslab/90ffed97919e6413ae95df5cf86aa2f7 to your computer and use it in GitHub Desktop.
CLLocationCoordinate2D Extension to get a CoordinateRange struct within a given maximum Distance in Swift 3.0
/*
* Copyright (C) kayoslabs - All Rights Reserved
* Description from Jan Philip Matuschek
* (http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates)
* Written by kayoslabs, March 2017
*/
import Foundation
import MapKit
extension CLLocationCoordinate2D {
internal func range(maxDist:Double) -> (latitude: CoordinateRange, longitude: CoordinateRange)? {
if maxDist > 0.0 {
let latRad:Double = self.latitude * (Double.pi / 180.0)
let lonRad:Double = self.longitude * (Double.pi / 180.0)
// Minimum
let kLatMin:Double = -90.0
let kLatMax:Double = 90.0
let kLonMin:Double = -180.0
let kLonMax:Double = 180.0
// Assuming a spherical approximationa of the Earth with radius:
// R = 6371 km
let R:Double = 6371.0
// We can define r as the angular radius of the query circle:
// r = d/R = (1000 km)/(6371 km) = 0.1570
// angular distance in radians on a great circle
let radDist:Double = maxDist / R
// latmin = lat - r = 1.2393 rad
// latmax = lat + r = 1.5532 rad
var latMin:Double = latRad - radDist
var latMax:Double = latRad + radDist
// If latmax is greater than π/2, then the North Pole is within the query circle
var lonMin:Double = 0.0
var lonMax:Double = 0.0
if latMin > kLatMin && latMax < kLatMax {
// Computing the Minimum and Maximum Longitude
// latT = arcsin(sin(lat)/cos(r)) = 1.4942 rad
// lonmin = lonT1 = lon - Δlon = -1.8184 rad
// lonmax = lonT2 = lon + Δlon = 0.4221 rad
// Δlon = arccos( ( cos(r) - sin(latT) · sin(lat) ) / ( cos(latT) · cos(lat) ) )
// = arcsin(sin(r)/cos(lat)) = 1.1202 rad
let deltaLon:Double = asin(sin(radDist)/cos(latRad))
lonMin = lonRad - deltaLon
lonMax = lonRad + deltaLon
// If one of lonmin/max is outside the range of valid longitude values [-π, π],
// the 180th meridian is within the query circle.
if lonMin < kLonMin {
lonMin += 2.0 * Double.pi
}
if lonMax > kLonMax {
lonMax -= 2.0 * Double.pi
}
} else {
// a pole is within the distance
latMin = max(latMin, kLatMin)
latMax = min(latMax, kLatMax)
lonMin = kLonMin
lonMax = kLonMax
}
let range = (latitude:CoordinateRange(minimum: latMin * (180.0 / Double.pi), maximum: latMax * (180.0 / Double.pi)),
longitude:CoordinateRange(minimum: lonMin * (180.0 / Double.pi), maximum: lonMax * (180.0 / Double.pi)))
return range
} else {
return nil
}
}
}
struct CoordinateRange {
internal var minimum:Double
internal var maximum:Double
init(minimum:Double, maximum:Double) {
self.minimum = minimum
self.maximum = maximum
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment