Meshtastic-Apple/Meshtastic/Extensions/CLLocationCoordinate2D.swift
Blake McAnally 4d547e48db This change fixes several lint errors throughout the project, and moves the SwiftLint build phase to before compilation.
After this change, a developer can now clone the project and run without the build failing due to lint errors! 😃

* I ran `swiftlint --fix` to resolve many auto-correctable issues (mostly whitespace)
* Excluded the `Meshtastic/Protobufs` directory from lint, since that code is automatically generated.
* Converted some single letter method parameters to lowercase.
* Converted several instances `force_cast` to instead use `guard` or `if let` to unwrap optional values. During this change, some of the SwiftUI views became "too complex to be solved in a reasonable time", so I broke up the views into distinct sub-expressions.

I was able to build and run the app on an iOS simulator.
2024-05-31 21:48:50 -05:00

62 lines
2.2 KiB
Swift

//
// CLLocationCoordinate2D.swift
// Meshtastic
//
// Copyright(c) Garth Vander Houwen 4/25/23.
//
import Foundation
import MapKit
extension CLLocationCoordinate2D {
/// Returns distance from coordianate in meters.
/// - Parameter from: coordinate which will be used as end point.
/// - Returns: distance in meters.
func distance(from: CLLocationCoordinate2D) -> CLLocationDistance {
let from = CLLocation(latitude: from.latitude, longitude: from.longitude)
let to = CLLocation(latitude: self.latitude, longitude: self.longitude)
return from.distance(from: to)
}
}
extension [CLLocationCoordinate2D] {
/// Get Convex Hull For an array of CLLocationCoordinate2D positions
/// - Returns: A smaller CLLocationCoordinate2D array containing only the points necessary to create a convex hull polygon
func getConvexHull() -> [CLLocationCoordinate2D] {
/// X = longitude
/// Y = latitude
/// 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
/// Returns a positive value, if OAB makes a counter-clockwise turn,
/// negative for clockwise turn, and zero if the points are collinear.
func cross(p: CLLocationCoordinate2D, a: CLLocationCoordinate2D, b: CLLocationCoordinate2D) -> Double {
let part1 = (a.longitude - p.longitude) * (b.latitude - p.latitude)
let part2 = (a.latitude - p.latitude) * (b.longitude - p.longitude)
return part1 - part2
}
// Sort points lexicographically
let points = self.sorted {
$0.longitude == $1.longitude ? $0.latitude < $1.latitude : $0.longitude < $1.longitude
}
// Build the lower hull
var lower: [CLLocationCoordinate2D] = []
for p in points {
while lower.count >= 2 && cross(p: lower[lower.count - 2], a: lower[lower.count - 1], b: p) <= 0 {
lower.removeLast()
}
lower.append(p)
}
// Build upper hull
var upper: [CLLocationCoordinate2D] = []
for p in points.reversed() {
while upper.count >= 2 && cross(p: upper[upper.count-2], a: upper[upper.count-1], b: p) <= 0 {
upper.removeLast()
}
upper.append(p)
}
// Last point of upper list is omitted because it is repeated at the
// beginning of the lower list.
upper.removeLast()
// Concatenation of the lower and upper hulls gives the convex hull.
return (upper + lower)
}
}