|
| 1 | +# SwiftDOF |
| 2 | + |
| 3 | +[](https://github.com/RISCfuture/SwiftDOF/actions/workflows/ci.yml) |
| 4 | +[](https://riscfuture.github.io/SwiftDOF/) |
| 5 | +[](https://swift.org) |
| 6 | +[](https://swift.org) |
| 7 | + |
| 8 | +A parser for FAA Digital Obstacle File (DOF) data. |
| 9 | + |
| 10 | +## Overview |
| 11 | + |
| 12 | +SwiftDOF parses FAA Digital Obstacle File (DOF) data, which can be downloaded |
| 13 | +from <https://www.faa.gov/air_traffic/flight_info/aeronav/digital_products/dof/>. |
| 14 | + |
| 15 | +The data is parsed into Codable structs that can be used in your Swift project. |
| 16 | + |
| 17 | +The design philosophy of SwiftDOF is _domain restricted data_ wherever |
| 18 | +possible. This means favoring restrictive enums over open types like Strings. |
| 19 | +It also takes advantage of `Foundation` types wherever possible, such as |
| 20 | +`Measurement`s instead of raw numeric types for physical values. |
| 21 | + |
| 22 | +The DOF format is documented at <https://www.faa.gov/air_traffic/flight_info/aeronav/digital_products/dof/media/DOF_README_09-03-2019.pdf>. |
| 23 | + |
| 24 | +## Requirements |
| 25 | + |
| 26 | +- Swift 6.2+ |
| 27 | +- macOS 26+, iOS 26+, watchOS 26+, tvOS 26+, or visionOS 26+ |
| 28 | + |
| 29 | +## Installation |
| 30 | + |
| 31 | +Add SwiftDOF to your `Package.swift`: |
| 32 | + |
| 33 | +```swift |
| 34 | +dependencies: [ |
| 35 | + .package(url: "https://github.com/RISCfuture/SwiftDOF", from: "1.0.0") |
| 36 | +] |
| 37 | +``` |
| 38 | + |
| 39 | +Then add it to your target: |
| 40 | + |
| 41 | +```swift |
| 42 | +.target( |
| 43 | + name: "YourTarget", |
| 44 | + dependencies: ["SwiftDOF"] |
| 45 | +) |
| 46 | +``` |
| 47 | + |
| 48 | +## Usage |
| 49 | + |
| 50 | +### Loading DOF Data |
| 51 | + |
| 52 | +```swift |
| 53 | +import SwiftDOF |
| 54 | + |
| 55 | +// Load from a local file |
| 56 | +let dof = try DOF(data: Data(contentsOf: fileURL)) |
| 57 | + |
| 58 | +// Or load asynchronously from a URL |
| 59 | +let dof = try await DOF(url: fileURL) |
| 60 | +``` |
| 61 | + |
| 62 | +### Querying Obstacles |
| 63 | + |
| 64 | +```swift |
| 65 | +// Get total count |
| 66 | +print("Total obstacles: \(dof.count)") |
| 67 | + |
| 68 | +// Look up by OAS number |
| 69 | +if let obstacle = dof.obstacle(for: "01-001307") { |
| 70 | + print("\(obstacle.type) at \(obstacle.city), \(obstacle.state ?? "")") |
| 71 | + print("Height: \(obstacle.heightFtAGL) ft AGL") |
| 72 | +} |
| 73 | + |
| 74 | +// Filter by state |
| 75 | +let texasObstacles = dof.obstacles(in: "TX") |
| 76 | + |
| 77 | +// Iterate over all obstacles |
| 78 | +for obstacle in dof { |
| 79 | + // ... |
| 80 | +} |
| 81 | +``` |
| 82 | + |
| 83 | +### Using Measurement Types |
| 84 | + |
| 85 | +```swift |
| 86 | +// Heights as Measurement<UnitLength> |
| 87 | +let heightAGL = obstacle.heightAGL // e.g., 500 ft |
| 88 | +let heightMeters = heightAGL.converted(to: .meters) |
| 89 | + |
| 90 | +// Coordinates as Measurement<UnitAngle> |
| 91 | +let lat = obstacle.latitude |
| 92 | +let lon = obstacle.longitude |
| 93 | + |
| 94 | +// Or as CoreLocation coordinate |
| 95 | +let coordinate = obstacle.coreLocation |
| 96 | +``` |
| 97 | + |
| 98 | +## Documentation |
| 99 | + |
| 100 | +Online API documentation and tutorials are available at |
| 101 | +<https://riscfuture.github.io/SwiftDOF/documentation/swiftdof/>. |
| 102 | + |
| 103 | +DocC documentation is available, including tutorials and API documentation. For |
| 104 | +Xcode documentation, you can run |
| 105 | + |
| 106 | +```sh |
| 107 | +swift package generate-documentation --target SwiftDOF |
| 108 | +``` |
| 109 | + |
| 110 | +to generate a docarchive at |
| 111 | +`.build/plugins/Swift-DocC/outputs/SwiftDOF.doccarchive`. You can open this |
| 112 | +docarchive file in Xcode for browseable API documentation. Or, within Xcode, |
| 113 | +open the SwiftDOF package in Xcode and choose **Build Documentation** from the |
| 114 | +**Product** menu. |
| 115 | + |
| 116 | +## Testing |
| 117 | + |
| 118 | +SwiftDOF has comprehensive unit tests, which can be run with `swift test`. |
| 119 | + |
| 120 | +### E2E Testing Tool |
| 121 | + |
| 122 | +The `SwiftDOF_E2E` target is a command-line tool for testing DOF parsing: |
| 123 | + |
| 124 | +```sh |
| 125 | +# Download and parse current FAA DOF cycle |
| 126 | +swift run SwiftDOF_E2E |
| 127 | + |
| 128 | +# Parse a local file |
| 129 | +swift run SwiftDOF_E2E -i /path/to/DOF.DAT |
| 130 | + |
| 131 | +# Parse from a URL |
| 132 | +swift run SwiftDOF_E2E -i https://aeronav.faa.gov/Obst_Data/DOF_251221.zip |
| 133 | + |
| 134 | +# Output as JSON |
| 135 | +swift run SwiftDOF_E2E -f json > obstacles.json |
| 136 | +``` |
| 137 | + |
| 138 | +Options: |
| 139 | +- `-i, --input <path|url>`: Path or URL to DOF file (.dat or .zip). Defaults to current FAA cycle. |
| 140 | +- `-f, --format <summary|json>`: Output format. Defaults to summary. |
0 commit comments