Skip to content
This repository has been archived by the owner on Apr 2, 2023. It is now read-only.

Commit

Permalink
Improve flight rules calculation (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanDowning committed Nov 29, 2020
1 parent 706c4c6 commit cb9c2f6
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 145 deletions.
12 changes: 5 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
name: Swift

name: Run Tests
on: [push]

jobs:
build:

test:
name: Run Tests
runs-on: macOS-latest

steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v2
- name: Build
run: swift build -v
- name: Run tests
- name: Run Tests
run: swift test -v
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// swift-tools-version:5.0

import PackageDescription

let package = Package(
Expand Down
97 changes: 57 additions & 40 deletions Sources/METAR/METAR.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,37 @@ public struct METAR: Codable, Equatable {
public var wind: Wind?
public var qnh: QNH?
public var skyCondition: SkyCondition?
public var cloudLayers: [CloudLayer]
public var cloudLayers: [CloudLayer] = []
public var visibility: Visibility?
public var weather: [Weather]
public var trends: [Forecast]
public var weather: [Weather] = []
public var trends: [Forecast] = []
public var militaryColourCode: MilitaryColourCode?
public var temperature: Temperature?
public var dewPoint: Temperature?
public var relativeHumidity: Double?
public var ceilingAndVisibilityOK: Bool
public var automaticStation: Bool
public var correction: Bool
public var noSignificantChangesExpected: Bool
public var ceilingAndVisibilityOK = false
public var automaticStation = false
public var correction = false
public var noSignificantChangesExpected = false
public var remarks: String?
public var metarString: String
public var flightRules: NOAAFlightRules?

}

extension METAR {

public var relativeHumidity: Double? {
guard
let temperature = temperature?.measurement.converted(to: .celsius).value,
let dewPoint = dewPoint?.measurement.converted(to: .celsius).value
else {
return nil
}
return exp((17.625 * dewPoint) / (243.04 + dewPoint)) / exp((17.625 * temperature) / (243.04 + temperature))
}

}

@available(iOS 10.0, macOS 10.12, tvOS 10.0, watchOS 3.0, *)
extension METAR {

Expand All @@ -40,11 +53,21 @@ extension METAR {
return .vfr
}

let ceiling = cloudLayers
.filter { $0.coverage == .overcast || $0.coverage == .skyObscured || $0.coverage == .broken }
.compactMap { $0.height?.measurement.converted(to: .feet).value }
.sorted()
.first ?? .greatestFiniteMagnitude
var ceiling = Double.greatestFiniteMagnitude
for layer in cloudLayers {
if layer.coverage == .notReported, let height = layer.height?.measurement.converted(to: .feet).value, height <= 3000 {
return nil
}
guard layer.coverage == .overcast || layer.coverage == .skyObscured || layer.coverage == .broken else {
continue
}
guard let height = layer.height?.measurement.converted(to: .feet).value else {
return nil
}
if ceiling > height {
ceiling = height
}
}

if ceiling > 3000, let visibilityValue = visibility?.converted(to: .miles).value, visibilityValue > 5 {
return .vfr
Expand Down Expand Up @@ -83,7 +106,7 @@ public extension METAR {
private init?(metar: String, fullMETAR: Bool = true) {
var metar = metar

guard let loneSlashesRegularExpression = try? NSRegularExpression(pattern: "(^|\\s)(/)+") else { return nil }
guard let loneSlashesRegularExpression = try? NSRegularExpression(pattern: "^(/)+") else { return nil }
guard let icaoRegularExpression = try? NSRegularExpression(pattern: "(.*?)([A-Z]{4})\\b") else { return nil }
guard let dateRegularExpression = try? NSRegularExpression(pattern: "(?<!\\S)([0-9]{2})([0-9]{2})([0-9]{2})Z\\b") else { return nil }
guard let remarksRegularExpression = try? NSRegularExpression(pattern: "(?<!\\S)RMK(.*)") else { return nil }
Expand Down Expand Up @@ -509,12 +532,6 @@ public extension METAR {
qnh = nil
}

if let temperature = temperature?.measurement.converted(to: .celsius).value, let dewPoint = dewPoint?.measurement.converted(to: .celsius).value {
relativeHumidity = exp((17.625 * dewPoint) / (243.04 + dewPoint)) / exp((17.625 * temperature) / (243.04 + temperature))
} else {
relativeHumidity = nil
}

self.flightRules = METAR.noaaFlightRules(ceilingAndVisibilityOK: self.ceilingAndVisibilityOK, cloudLayers: self.cloudLayers, visibility: self.visibility?.measurement)
}

Expand Down Expand Up @@ -570,9 +587,9 @@ public struct Visibility: Equatable, Codable {
case miles
}

public let value: Double
public let unit: Unit
public let greaterThanOrEqual: Bool
public var value: Double
public var unit: Unit
public var greaterThanOrEqual = false

public var measurement: Measurement<UnitLength> {
switch unit {
Expand All @@ -598,8 +615,8 @@ public struct Wind: Codable, Equatable {
case kilometersPerHour
}

public let value: Double
public let unit: Unit
public var value: Double
public var unit: Unit

public var measurement: Measurement<UnitSpeed> {
switch unit {
Expand All @@ -616,14 +633,14 @@ public struct Wind: Codable, Equatable {

public typealias Degrees = Double

public let direction: Degrees?
public let speed: Speed
public let gustSpeed: Speed?
public let variation: Variation?
public var direction: Degrees?
public var speed: Speed
public var gustSpeed: Speed?
public var variation: Variation?

public struct Variation: Equatable, Codable {
public let from: Degrees
public let to: Degrees
public var from: Degrees
public var to: Degrees
}

}
Expand All @@ -644,8 +661,8 @@ public struct CloudLayer: Equatable, Codable {
case feet
}

let value: Double
let unit: Unit
var value: Double
var unit: Unit

public var measurement: Measurement<UnitLength> {
switch unit {
Expand All @@ -656,9 +673,9 @@ public struct CloudLayer: Equatable, Codable {

}

public let coverage: Coverage
public let height: Height?
public let significantCloudType: SignificantCloudType?
public var coverage: Coverage
public var height: Height?
public var significantCloudType: SignificantCloudType?

public enum Coverage: String, Codable {
case few, scattered, broken, overcast, skyObscured, notReported
Expand All @@ -672,8 +689,8 @@ public struct CloudLayer: Equatable, Codable {

public struct Weather: Equatable, Codable {

public let modifier: Modifier
public let phenomena: [Phenomena]
public var modifier: Modifier
public var phenomena: [Phenomena] = []

public enum Modifier: String, Codable {
case light = "-"
Expand Down Expand Up @@ -735,8 +752,8 @@ public struct Forecast: Codable, Equatable {
case becoming = "BECMG", temporaryForecast = "TEMPO"
}

public let metarRepresentation: METAR
public let type: Type
public var metarRepresentation: METAR
public var type: Type

}

Expand Down
Loading

0 comments on commit cb9c2f6

Please sign in to comment.