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

Commit

Permalink
2.0 Redesign (#11)
Browse files Browse the repository at this point in the history
  • Loading branch information
JonathanDowning committed Dec 6, 2020
1 parent bb70b43 commit 698f394
Show file tree
Hide file tree
Showing 19 changed files with 1,447 additions and 975 deletions.
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
# METAR
# METAR Parser for Swift

This is a simple regular expression based METAR parser.
SwiftMETAR provides a simple way to parse METARs into Swift types.

## Usage Example

``` swift
let metar = METAR(rawMETAR: "EGLL 290420Z AUTO 05005KT 020V090 7000 R04/1300VP2000U OVC005 09/08 Q1024 TEMPO BKN004")
import METAR

let metar = METAR("EGLL 290420Z AUTO 05005KT 020V090 7000 R04/1300VP2000U OVC005 09/08 Q1024 TEMPO BKN004")
print(metar?.visibility?.measurement) // Prints: Optional(7000.0 m)
print(metar?.temperature?.measurement) // Prints: Optional(9.0 °C)
print(metar?.qnh?.measurement) // Prints: Optional(1024.0 hPa)
print(metar?.wind?.speed.measurement) // Prints: Optional(5.0 kn)
print(metar?.runwayVisualRanges) // Prints: Optional([Runway 04: 1300.0 m – >2000.0 m Increasing])
```

## Contribution

If you'd like to contribute, please feel free to create a PR.

## License

SwiftMETAR is available under the MIT license. See the LICENSE file for more info.
30 changes: 30 additions & 0 deletions Sources/METAR/CloudLayer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// CloudLayer.swift
//
//
// Created by Jonathan Downing on 12/4/20.
//

import Foundation

public struct CloudLayer: Hashable {

public enum Coverage {
case few
case scattered
case broken
case overcast
case skyObscured
case notReported
}

public enum SignificantCloudType {
case cumulonimbus
case toweringCumulus
}

public var coverage: Coverage
public var height: Measurement<UnitLength>?
public var significantCloudType: SignificantCloudType?

}
24 changes: 24 additions & 0 deletions Sources/METAR/DirectionalVisibility.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// DirectionalVisibility.swift
//
//
// Created by Jonathan Downing on 12/5/20.
//

public struct DirectionalVisibility: Hashable {

public enum Direction {
case north
case northEast
case east
case southEast
case south
case southWest
case west
case northWest
}

public var visibility: Visibility
public var direction: Direction

}
56 changes: 56 additions & 0 deletions Sources/METAR/FlightRules.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// NOAAFlightRules.swift
//
//
// Created by Jonathan Downing on 12/4/20.
//

public enum ICAOFlightRules {

/// Visual Meteorlogical Conditions
///
/// Applicable when either are true:
/// - Ceiling is greater than or equal to 1,500 feet.
/// - Visibility is greater than or equal to 5,000 meters.
case vmc

/// Instrument Meteorlogical Conditions
///
/// Applicable when either are true:
/// - Ceiling is less than 1,500 feet.
/// - Visibility is less than 5,000 meters.
case imc

}

public enum NOAAFlightRules {

/// Visual Flight Rules
///
/// Applicable when both are true:
/// - Ceiling is greater than 3,000 feet
/// - Visibility is greater than 5 miles
case vfr

/// Marginal Visual Flight Rules
///
/// Applicable when either are true:
/// - Ceiling is greater than or equal to 1,000 feet and less than or equal to 3,000 feet
/// - Visibility is greater than or equal to 3 miles and less than or equal to 5 miles.
case mvfr

/// Instrument Flight Rules
///
/// Applicable when either are true:
/// - Ceiling is greater than or equal to 500 feet and less than 1,000 feet
/// - Visibility is greater than or equal to 1 mile and less than 3 miles.
case ifr

/// Low Instrument Flight Rules
///
/// Applicable when either are true:
/// - Ceiling is less than 500 feet
/// - Visibility is less than 1 mile
case lifr

}
28 changes: 28 additions & 0 deletions Sources/METAR/METAR+Ceiling.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// METAR+Ceiling.swift
//
//
// Created by Jonathan Downing on 07/01/2017.
//

import Foundation

extension METAR {

var ceiling: Measurement<UnitLength> {
var ceiling: Double = .greatestFiniteMagnitude
for layer in cloudLayers {
guard layer.coverage == .overcast || layer.coverage == .skyObscured || layer.coverage == .broken else {
continue
}
guard let height = layer.height?.converted(to: .feet).value else {
continue
}
if ceiling > height {
ceiling = height
}
}
return .init(value: ceiling, unit: .feet)
}

}
38 changes: 38 additions & 0 deletions Sources/METAR/METAR+Date.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// METAR+Date.swift
//
//
// Created by Jonathan Downing on 12/6/20.
//

import Foundation

extension METAR {

/// The date the report was issued.
///
/// Since METARs only encode day, hour, and minute information—the date from this property is the
/// most recent date in the past matching those date components. If the METAR is recent, this should
/// not be a problem.
public var date: Date {
date(relativeTo: Date())
}

func date(relativeTo referenceDate: Date) -> Date {
let calendar = Calendar(identifier: .gregorian)

var dateComponents = self.dateComponents
dateComponents.year = calendar.component(.year, from: referenceDate)
dateComponents.month = calendar.component(.month, from: referenceDate)

guard var date = calendar.date(from: dateComponents) else { return .distantPast }

if date > referenceDate {
dateComponents.month! -= 1
date = calendar.date(from: dateComponents) ?? .distantPast
}

return date
}

}
50 changes: 50 additions & 0 deletions Sources/METAR/METAR+FlightRules.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// File.swift
//
//
// Created by Jonathan Downing on 12/6/20.
//

import Foundation

extension METAR {

public var icaoFlightRules: ICAOFlightRules? {
if ceiling.converted(to: .feet).value < 1500 {
return .imc
}
if let visibility = visibility?.measurement.converted(to: .meters).value {
return visibility < 5000 ? .imc : .vmc
}
return .vmc
}

public var noaaFlightRules: NOAAFlightRules? {
if ceiling.converted(to: .feet).value < 500 {
return .lifr
}
if let visibility = visibility?.measurement.converted(to: .miles).value, visibility < 1 {
return .lifr
}
if ceiling.converted(to: .feet).value < 1000 {
return .ifr
}
if let visibility = visibility?.measurement.converted(to: .miles).value, visibility < 3 {
return .ifr
}
if ceiling.converted(to: .feet).value <= 3000 {
return .mvfr
}
if let visibility = visibility?.measurement.converted(to: .miles).value, visibility <= 5 {
return .mvfr
}
if let visibility = visibility?.measurement.converted(to: .miles).value, visibility > 5, ceiling.converted(to: .feet).value > 3000 {
return .vfr
}
if isCeilingAndVisibilityOK {
return .vfr
}
return nil
}

}
Loading

0 comments on commit 698f394

Please sign in to comment.