[![Version](https://img.shields.io/gem/v/aixm.svg?style=flat)](https://rubygems.org/gems/aixm)
[![Continuous Integration](https://img.shields.io/travis/svoop/aixm/master.svg?style=flat)](https://travis-ci.org/svoop/aixm)
[![Code Climate](https://img.shields.io/codeclimate/github/svoop/aixm.svg?style=flat)](https://codeclimate.com/github/svoop/aixm)
[![Gitter](https://img.shields.io/gitter/room/svoop/aixm.svg?style=flat)](https://gitter.im/svoop/aixm)
[![Donorbox](https://img.shields.io/badge/donate-on_donorbox-yellow.svg)](https://donorbox.org/bitcetera)
# AIXM
Partial implementation of the [Aeronautical Information Exchange Model (AIXM 4.5)](http://aixm.aero) for Ruby.
For now, only the parts needed to automize the AIP import of [Open Flightmaps](https://openflightmaps.org) are part of this gem. Most notably, the gem is only a builder of AIXM 4.5 snapshot files and does not parse them.
* [Homepage](https://github.com/svoop/aixm)
* [API](http://www.rubydoc.info/gems/aixm)
* Author: [Sven Schwyn - Bitcetera](http://www.bitcetera.com)
## Install
Add this to your `Gemfile`:
```ruby
gem aixm
```
## Usage
You can initialize all elements either traditionally or by use of shorter AIXM class methods:
```ruby
AIXM.airspace(...)
AIXM.airspace(...)
```
### Fundamentals
All fundamentals are subclasses of `AIXM::Base`.
### Document
The document is the root container of the AIXM snapshot file to be generated. It's essentially a collection of features:
```ruby
document = AIXM.document(created_at: Time.now, effective_at: Time.now)
document.features << AIXM.airspace(...)
```
To give you an overview of the AIXM building blocks, the remainder of this guide will use pseudo code to describe the initializer arguments, writer methods etc:
```ruby
document = AIXM.document(
created_at: Time or Date or String
effective_at: Time or Date or String
)
document.features << AIXM::Feature
```
See [the API documentation](http://www.rubydoc.info/gems/aixm) for details and [spec/factory.rb](https://github.com/svoop/aixm/blob/master/spec/factory.rb) for examples.
#### Coordinate
All of the below are equivalent:
```ruby
AIXM.xy(lat: %q(11°22'33.44"), long: %q(-111°22'33.44"))
AIXM.xy(lat: '112233.44N', long: '1112233.44W')
AIXM.xy(lat: 11.375955555555556, long: -111.37595555555555)
```
#### Altitude and Heights
Altitudes and heights exist in three different forms:
```ruby
AIXM.z(1000, :qfe) # height: 1000ft above ground
AIXM.z(2000, :qnh) # altitude: of 2000ft above mean sea level
AIXM.z(45, :qne) # altitude: flight level 45
```
#### Frequency
```ruby
AIXM.f(123.35, :mhz)
```
### Features
All features are subclasses of `AIXM::Feature::Base`.
#### Airspace
```ruby
airspace = AIXM.airspace(
name: String
short_name: String or nil
type: String or Symbol
)
airspace.schedule = AIXM.schedule
airspace.geometry << AIXM.point or AIXM.arc or AIXM.border or AIXM.circle
airspace.class_layers << AIXM.class_layer
airspace.remarks = String
```
#### Navigational Aids
##### Designated Point
```ruby
designated_point = AIXM.designated_point(
id: String
name: String or nil
xy: AIXM.xy
z: AIXM.z or nil
type: :icao or :adhp, or :coordinates
)
designated_point.schedule = AIXM.schedule
designated_point.remarks = String
```
##### DME
```ruby
dme = AIXM.dme(
id: String
name: String
xy: AIXM.xy
z: AIXM.z or nil
channel: String
)
dme.schedule = AIXM.schedule
dme.remarks = String
```
##### NDB
```ruby
ndb = AIXM.ndb(
id: String
name: String
xy: AIXM.xy
z: AIXM.z or nil
type: :en_route, :locator or :marine
f: AIXM.f
)
ndb.schedule = AIXM.schedule
ndb.remarks = String
```
##### Marker
WARNING: Marker are not fully implemented because they usually have to be
associated with ILS which are not yet implemented.
```ruby
marker = AIXM.marker(
id: String
name: String
xy: AIXM.xy
z: AIXM.z or nil
type: :outer, :middle, :inner or :backcourse
)
marker.schedule = AIXM.schedule
marker.remarks = String
```
##### TACAN
```ruby
tacan = AIXM.tacan(
id: String
name: String
xy: AIXM.xy
z: AIXM.z or nil
channel: String
)
tacan.schedule = AIXM.schedule
tacan.remarks = String
```
##### VOR
```ruby
vor = AIXM.vor(
id: String
name: String
xy: AIXM.xy
z: AIXM.z or nil
type: :conventional or :doppler
f: AIXM.f
north: :geographic or :grid or :magnetic
)
vor.schedule = AIXM.schedule
vor.remarks = String
vor.associate_dme(channel: String) # turns the VOR into a VOR/DME
vor.associate_tacan(channel: String) # turns the VOR into a VORTAC
```
### Components
All components are subclasses of `AIXM::Component::Base`.
#### Schedule
```ruby
schedule = AIXM.schedule(
code: String or Symbol
)
```
#### Class Layer
```ruby
class_layer = AIXM.class_layer(
class: String or nil
vertical_limits: AIXM.vertical_limits
)
```
#### Vertical Limits
```ruby
vertical_limits = AIXM.vertical_limits(
max_z: AIXM.z or nil
upper_z: AIXM.z
lower_z: AIXM.z
min_z: AIXM.z or nil
)
```
#### Point, Arc, Border and Circle
```ruby
point = AIXM.point(
xy: AIXM.xy
)
arc = AIXM.arc(
xy: AIXM.xy
center_xy: AIXM.xy
cloclwise: true or false
)
border = AIXM.border(
xy: AIXM.xy
name: String
)
circle = AIXM.circle(
center_xy: AIXM.xy
radius: Numeric
)
```
#### Geometry
```ruby
geometry = AIXM.geometry
geometry << AIXM.point or AIXM.arc or AIXM.border or AIXM.circle
```
For a geometry to be complete, it must be comprised of either:
* exactly one circle
* at least three points, arcs or borders (the last of which a point with identical coordinates as the first)
## Validation
Use `AIXM::Document#complete?` to check whether all mandatory information is present. Airspaces, geometries etc have `complete?` methods as well.
Use `AIXM::Document#valid?` to validate the resulting AIXM against the XSD schema. If any, you find the errors in `AIXM::Document#errors`. Since the data model is not fully implemented, some associations cannot be assigned and have to be left empty. The resulting validation errors are silently ignored:
* OrgUid - organizations may be empty tags
## Rendering
```ruby
document.to_aixm # render AIXM 4.5 compliant XML
document.to_aixm(:ofm) # render AIXM 4.5 + OFM extensions XML
```
## Constants
* `AIXM::GROUND` - height: 0ft above ground
* `AIXM::UNLIMITED` - altitude: FL 999
* `AIXM::H24` - continuous schedule
## Refinements
By `using AIXM::Refinements` you get the following general purpose methods:
* `Hash#lookup(key, default)`
Similar to `fetch` but falls back to values
* `String#indent(number)`
Indent every line of a string with *number* spaces
* `String#uptrans`
upcase and transliterate to match the reduced character set for names
* `String#to_dd`
Convert DMS angle to DD or `nil` if the format is not recognized
* `Float#to_dms(padding)`
Convert DD angle to DMS with the degrees zero padded to *padding* length
* `Float#trim`
Convert whole numbers to Integer and leave all other untouched
* `Float#to_km(from: unit)`
Convert a distance from *unit* (:km, :m, :nm or :ft) to km
See the [source code](https://github.com/svoop/aixm/blob/master/lib/aixm/refinements.rb) for more explicit descriptions and examples.
## Extensions
### OFM
This extension adds proprietary tags and attributes (most of which are prefixed with `xt_`) aiming to improve importing the resulting AIXM into the OFM originative suite:
* ``
root node with extended version string
* ``
true when multiple class layers and therefore an Adg-node is present
* `(true|false)`
enables conditional airspaces feature
* ``
tell the importer whether adding a new or updating an existing entity
## References
* [AIXM](http://aixm.aero)
* [AIXM on Wikipedia](https://en.wikipedia.org/wiki/AIXM)
* [AIXM 4.5 Specification](http://aixm.aero/document/aixm-45-specification)
* [AICM 4.5 Entity-Relationship](https://www.ead.eurocontrol.int/SystemHelp/mergedProjects/SDO/aixm/)
* [Open Flightmaps](https://openflightmaps.org)
## Tests
Some tests are very time consuming and therefore skipped by default. To run the full test suite, set the environment variable:
```
export SPEC_SCOPE=all
```
## Development
To install the development dependencies and then run the test suite:
```
bundle install
bundle exec rake # run tests once
bundle exec guard # run tests whenever files are modified
```
Please submit issues on:
https://github.com/svoop/aixm/issues
To contribute code, fork the project on Github, add your code and submit a pull request:
https://help.github.com/articles/fork-a-repo
## License
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).