Skip to content

Instantly share code, notes, and snippets.

@olejorgensen
Last active January 13, 2024 16:28
Show Gist options
  • Save olejorgensen/f587f70cb96aefe7a61fde629117181e to your computer and use it in GitHub Desktop.
Save olejorgensen/f587f70cb96aefe7a61fde629117181e to your computer and use it in GitHub Desktop.
MapKit and CoreLocation extensions
import Foundation
extension Array where Element: Hashable {
var uniques: Array {
return Array(Set<Element>(self))
}
}
import Foundation
import CoreLocation
extension CLLocationCoordinate2D {
func distance(from: CLLocationCoordinate2D) -> Double {
let aLocation = CLLocation(latitude: self.latitude, longitude: self.longitude)
let bLocation = CLLocation(latitude: from.latitude, longitude: from.longitude)
return aLocation.distance(from: bLocation)
}
}
import Foundation
extension DateFormatter {
static let iso8601Full: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
formatter.calendar = Calendar(identifier: .iso8601)
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
}
import Foundation
import MapKit
import CoreLocation
extension MKCoordinateRegion {
init?(coordinates: [CLLocationCoordinate2D]) {
// first create a region centered around the prime meridian
let primeRegion = MKCoordinateRegion.region(for: coordinates, transform: { $0 }, inverseTransform: { $0 })
// next create a region centered around the 180th meridian
let transformedRegion = MKCoordinateRegion.region(for: coordinates, transform: MKCoordinateRegion.transform, inverseTransform: MKCoordinateRegion.inverseTransform)
// return the region that has the smallest longitude delta
if let a = primeRegion,
let b = transformedRegion,
let min = [a, b].min(by: { $0.span.longitudeDelta < $1.span.longitudeDelta }) {
self = min
} else if let a = primeRegion {
self = a
} else if let b = transformedRegion {
self = b
} else {
return nil
}
}
public static func makeSpan(latDelta: Double, longDelta: Double) -> MKCoordinateSpan? {
if let latDegrees = CLLocationDegrees(exactly: latDelta), let longDegrees = CLLocationDegrees(exactly: longDelta) {
let span = MKCoordinateSpan(latitudeDelta: latDegrees, longitudeDelta: longDegrees)
return span
}
return nil
}
// Latitude -180...180 -> 0...360
private static func transform(c: CLLocationCoordinate2D) -> CLLocationCoordinate2D {
if c.longitude < 0 { return CLLocationCoordinate2DMake(c.latitude, 360 + c.longitude) }
return c
}
// Latitude 0...360 -> -180...180
private static func inverseTransform(c: CLLocationCoordinate2D) -> CLLocationCoordinate2D {
if c.longitude > 180 { return CLLocationCoordinate2DMake(c.latitude, -360 + c.longitude) }
return c
}
private typealias Transform = (CLLocationCoordinate2D) -> (CLLocationCoordinate2D)
private static func region(for coordinates: [CLLocationCoordinate2D], transform: Transform, inverseTransform: Transform) -> MKCoordinateRegion? {
// handle empty array
if coordinates.isEmpty { return nil }
// handle single coordinate
guard coordinates.count > 1 else {
guard let span = makeSpan(latDelta: 0.0125, longDelta: 0.0125) else { return nil }
return MKCoordinateRegion(center: coordinates[0], span: span)
}
let transformed = coordinates.map(transform)
// find the span
let buffer = 0.00125
let minLat = transformed.min { $0.latitude < $1.latitude }!.latitude - buffer
let maxLat = transformed.max { $0.latitude < $1.latitude }!.latitude + buffer
let minLon = transformed.min { $0.longitude < $1.longitude }!.longitude - buffer
let maxLon = transformed.max { $0.longitude < $1.longitude }!.longitude + buffer
guard let span = makeSpan(latDelta: maxLat - minLat, longDelta: maxLon - minLon) else { return nil }
// find the center of the span
let center = inverseTransform(CLLocationCoordinate2DMake((maxLat - span.latitudeDelta / 2), maxLon - span.longitudeDelta / 2))
return MKCoordinateRegion(center: center, span: span)
}
}
import Foundation
import MapKit
import CoreLocation
extension MKMapRect {
static func distance(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) -> Double {
let aLocation = CLLocation(latitude: from.latitude, longitude: from.longitude)
let bLocation = CLLocation(latitude: to.latitude, longitude: to.longitude)
return aLocation.distance(from: bLocation)
}
var minCoordinate: CLLocationCoordinate2D {
get {
let point = MKMapPoint.init(x: self.minX, y: self.minY)
return point.coordinate
}
}
var maxCoordinate: CLLocationCoordinate2D {
get {
let point = MKMapPoint.init(x: self.maxX, y: self.maxY)
return point.coordinate
}
}
static func makeRegion(center: CLLocationCoordinate2D, rect: MKMapRect) -> CLCircularRegion {
let ne = MKMapPoint(x: rect.maxY, y: rect.origin.y).coordinate
let sw = MKMapPoint(x: rect.origin.x, y: rect.maxY).coordinate
let diameter = MKMapRect.distance(from: ne, to: sw)
let region = CLCircularRegion(center: center, radius: diameter / 2.0, identifier: "mapWindow")
return region
}
}
import Foundation
public extension String {
func stringByAppendingPathComponent(path: String) -> String {
let nsSt = self as NSString
return nsSt.appendingPathComponent(path)
}
static let alfaNumInsensitiveCompareOptions: NSString.CompareOptions = NSString.CompareOptions.caseInsensitive.union(NSString.CompareOptions.numeric)
func alfaNumInsensitiveCompare(other: String) -> ComparisonResult {
return compare(other, options: String.alfaNumInsensitiveCompareOptions)
}
/**
Trim using CharacterSet.whitespacesAndNewlines
*/
var trimmed: String {
get {
return self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
}
/**
Trim using CharacterSet.whitespacesAndNewlines
*/
var trimmedOrNil: String? {
get {
let trimmed = self.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
return trimmed.isEmpty ? nil : trimmed
}
}
/**
Encode using CharacterSet.urlQueryAllowed
*/
var toQueryValue: String? {
get {
return self.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
}
}
func firstDigits(options: NSRegularExpression.Options = NSRegularExpression.Options.caseInsensitive) -> String? {
return firstMatch("(\\d+)", options: options)
}
func firstMatch(_ pattern: String, options: NSRegularExpression.Options = NSRegularExpression.Options.caseInsensitive) -> String? {
let re = try? NSRegularExpression(pattern: pattern, options: options)
if let match = re?.firstMatch(in: self, options: [], range: NSRange(location: 0, length: self.count)) {
let range = match.range(at: 1)
if range.location < Int.max {
let substring = (self as NSString).substring(with: range)
return substring
}
}
return nil
}
func isMatchedByAny(regexes: [NSRegularExpression]) -> Bool {
for regex in regexes {
if isMatchedBy(regex: regex) {
return true
}
}
return false
}
func isMatchedBy(regex: NSRegularExpression) -> Bool {
return regex.firstMatch(in: self, range: NSRange(location: 0, length: self.count)) != nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment