Skip to content

Commit

Permalink
style changes
Browse files Browse the repository at this point in the history
  • Loading branch information
ekurutepe committed Mar 1, 2020
1 parent 5f58fc6 commit a82ad84
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 66 deletions.
124 changes: 66 additions & 58 deletions Iguazu/AirSpace/Airspace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ public extension Collection where Iterator.Element == String {
let idx = Double(n)
guard let value = Double(c.trimmingCharacters(in: CharacterSet.whitespaces)) else { fatalError("not convertible to degrees: '\(c)'") }
return value * pow(60.0, -idx)
}
.reduce(0.0, +)
}
.reduce(0.0, +)
}
}

Expand All @@ -46,41 +46,41 @@ public enum AirspaceAltitude: Equatable {
case agl(Altitude)
case msl(Altitude)
case fl(Int)

init?(_ string: String) {
let lowercase = string.lowercased()
if lowercase == "gnd" || lowercase == "sfc" {
self = .surface
return
}

let impliedMSLString: String
if let mslRange = lowercase.range(of: "msl") {
impliedMSLString = lowercase.replacingCharacters(in: mslRange, with: "")
} else {
impliedMSLString = lowercase
}

guard let value = Int(impliedMSLString.trimmingCharacters(in: CharacterSet.decimalDigits.inverted).trimmingCharacters(in: .whitespaces)) else { return nil }

if impliedMSLString.hasPrefix("fl") {
self = .fl(value)
return
}

let unit: UnitLength

if impliedMSLString.contains("m") {
unit = .meters
} else {
unit = .feet
}

if impliedMSLString.hasSuffix("agl") {
self = .agl(Altitude(value: Double(value), unit: unit))
return
}

self = .msl(Altitude(value: Double(value), unit: unit))
return
}
Expand All @@ -104,6 +104,10 @@ extension AirspaceAltitude: Comparable {
return msl.converted(to: .feet).value < Double(fl * 100)
case (.fl(let fl), .msl(let msl)):
return Double(fl*100) < msl.converted(to: .feet).value
case (.agl(_), .fl(_)):
return true
case (.fl(_), .agl(_)):
return false
default:
fatalError("Compare only makes sense for comparing FL and MSL. Comparisons with surface and AGL are programmer error!!!")
}
Expand Down Expand Up @@ -132,35 +136,36 @@ public final class OpenAirParser {
public init() {

}

public func airSpacesByClass(from openAirString: String) -> AirspacesByClassDictionary? {
let lines = openAirString.components(separatedBy: .newlines)

var airSpaces = AirspacesByClassDictionary()

var currentAirspace: AirspaceInProgress? = nil

var state = ParserState()

for line in lines {
guard line.utf8.count > 1 else { continue }

guard let firstWhiteSpace = line.rangeOfCharacter(from: .whitespaces) else { continue }

let prefix = line[line.startIndex ..< firstWhiteSpace.lowerBound]
let value = line[firstWhiteSpace.upperBound ..< line.endIndex]
.trimmingCharacters(in: .whitespacesAndNewlines)

switch prefix {
case "AC":
currentAirspace.flatMap {
$0.validAirspace.flatMap { asp in
guard asp.floor < .fl(100) else { return }
var list = airSpaces[asp.airspaceClass] ?? [Airspace]()
list.append(asp)
airSpaces[asp.airspaceClass] = list
}
}

state = ParserState()
currentAirspace = AirspaceInProgress()
currentAirspace?.class = AirspaceClass(rawValue: value)
Expand Down Expand Up @@ -221,101 +226,104 @@ public final class OpenAirParser {
continue
}
}

currentAirspace.flatMap {
$0.validAirspace.flatMap { asp in
guard asp.floor < .fl(100) else { return }
var list = airSpaces[asp.airspaceClass] ?? [Airspace]()
list.append(asp)
airSpaces[asp.airspaceClass] = list
}
}

return airSpaces
}

public func airSpaces(from openAirString: String) -> [Airspace]? {
guard let airspaces = self.airSpacesByClass(from: openAirString) else { return nil }
let flatAirspaces = airspaces.reduce([Airspace]()) { (res, tuple) -> [Airspace] in
return res + tuple.value
}
return flatAirspaces
}

public func airSpacesByClass(withContentsOf url: URL) -> AirspacesByClassDictionary? {
var openAirString = ""
do {
openAirString = try String(contentsOf: url, encoding: .ascii)
openAirString = try String(contentsOf: url, encoding: .utf8)
}
catch _ {
catch {
assertionFailure("failed opening \(url): \(error.localizedDescription)")
return nil
}

return self.airSpacesByClass(from: openAirString)
}

public func airSpaces(withContentsOf url: URL) -> [Airspace]? {
var openAirString = ""
do {
openAirString = try String(contentsOf: url, encoding: .ascii)
openAirString = try String(contentsOf: url, encoding: .utf8)
}
catch _ {
catch {
assertionFailure("failed opening \(url): \(error.localizedDescription)")
return nil
}

return self.airSpaces(from: openAirString)
}

private func coordinate<S: StringProtocol>(from string: S) -> CLLocationCoordinate2D? {
let scanner = Scanner(string: string.uppercased())
guard let latString = scanner.scanUpToCharacters(from: .northSouth) else { fatalError("could not find N/S in coordinate string") }

let latComponents = latString.components(separatedBy: ":")

var latitude = latComponents.degree
guard latitude <= 90.0 else { fatalError("latitude \(latitude) for \"\(string)\"; \(dump(latComponents))") }

guard let latHemisphere = scanner.scanCharacters(from: .northSouth) else { fatalError("could not find N/S hemisphere")}

if latHemisphere == "S" { latitude = -1.0 * latitude }

guard let lngString = scanner.scanUpToCharacters(from: .eastWest) else { fatalError("could not find EW in coordinate string") }

guard let lngHemisphere = scanner.scanCharacters(from: .eastWest) else { fatalError("could not find E/W hemisphere")}

let lngComponents = lngString.components(separatedBy: ":")

var longitude = lngComponents.degree
guard longitude <= 180.0 else { fatalError("longitude \(longitude) for \"\(string)\"; \(dump(lngComponents))") }

if lngHemisphere == "W" { longitude = -1.0 * longitude }

return CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}

private func polygonArc(around center: CLLocationCoordinate2D, radius: CLLocationDistance, from: CLLocationDegrees, to: CLLocationDegrees, clockwise: Bool) -> [CLLocationCoordinate2D] {
let resolution = 5.0

let sign = clockwise ? 1.0 : -1.0

let start = from

var end = (to == from) ? from+360.0 : to

if (clockwise && to < from ) {
end += 360.0
}

if (!clockwise && to > from) {
end -= 360.0
}

let range = fabs(end - start)
let count = ceil(range/resolution)
let step = sign*range/count

let coordinates = stride(from: start, through: end, by: step)
.map { degree in center.coordinate(at: radius, direction: degree) }

return coordinates
}

Expand All @@ -331,7 +339,7 @@ public final class OpenAirParser {
var name: String? = nil
var labelCoordinates: [CLLocationCoordinate2D]? = nil
var polygonCoordinates = [CLLocationCoordinate2D]()

var validAirspace: Airspace? {
guard let klass = self.class,
let ceiling = self.ceiling,
Expand All @@ -340,10 +348,10 @@ public final class OpenAirParser {
polygonCoordinates.count > 2,
let first = polygonCoordinates.first,
let last = polygonCoordinates.last else { return nil }

var coords = polygonCoordinates
if first.distance(from: last) < 50.0 {
coords = coords.dropLast()
if first != last {
coords.append(first)
}
return Airspace(name: name, class: klass, floor: floor, ceiling: ceiling, polygon: coords, labelCoordinates: self.labelCoordinates)
}
Expand Down Expand Up @@ -372,25 +380,25 @@ extension AirspaceAltitude {
extension Airspace: GeoJsonEncodable {
public var geoJsonString: String? {
let coordinatesArray: [[Double]] = (self.polygonCoordinates+[self.polygonCoordinates[0]]).reversed().map { [$0.longitude, $0.latitude] }

let dict: NSDictionary = [
"type": "Feature",
"properties": [
"name": self.name as NSString,
"type": self.airspaceClass.rawValue as NSString,
"floor": self.floor.geoJsonAltitude,
"ceiling": self.ceiling.geoJsonAltitude,
] as NSDictionary,
] as NSDictionary,
"geometry": [
"type": "Polygon" as NSString,
"coordinates": [ coordinatesArray as NSArray ] as NSArray,
] as NSDictionary
] as NSDictionary
]

guard JSONSerialization.isValidJSONObject(dict) else { return nil }
guard let data = try? JSONSerialization.data(withJSONObject: dict, options: []) else { return nil }
return String(data: data, encoding: .utf8)

}
}

14 changes: 6 additions & 8 deletions Iguazu/AirSpace/AirspaceMapDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,14 @@ public extension AirspaceClass {
#elseif os(iOS)
var color: UIColor {
switch self {
case .Danger:
return .black
case .CTR, .GliderProhibited, .Prohibited, .Restricted:
case .Danger, .GliderProhibited, .Prohibited, .Restricted:
return .red
case .Delta:
return .green
case .Bravo, .Charlie, .RadioMandatoryZone:
return UIColor(red: 0.0, green: 0.6, blue: 1.0, alpha: 1.0)
case .Delta, .CTR, .Bravo, .Charlie, .RadioMandatoryZone:
return UIColor(red: 0.0, green: 0.12, blue: 0.67, alpha: 1.0)
case .TransponderMandatoryZone:
return .gray
return .darkGray
case .WaveWindow:
return .green
default:
return .purple
}
Expand Down

0 comments on commit a82ad84

Please sign in to comment.