aixm 0.1.0 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -1
- data/Guardfile +1 -1
- data/README.md +146 -17
- data/aixm.gemspec +3 -1
- data/lib/aixm.rb +12 -10
- data/lib/aixm/component/base.rb +6 -0
- data/lib/aixm/component/class_layer.rb +49 -0
- data/lib/aixm/component/geometry.rb +73 -0
- data/lib/aixm/component/geometry/arc.rb +53 -0
- data/lib/aixm/component/geometry/border.rb +49 -0
- data/lib/aixm/component/geometry/circle.rb +56 -0
- data/lib/aixm/component/geometry/point.rb +42 -0
- data/lib/aixm/component/schedule.rb +45 -0
- data/lib/aixm/{vertical/limits.rb → component/vertical_limits.rb} +9 -14
- data/lib/aixm/document.rb +30 -19
- data/lib/aixm/feature/airspace.rb +60 -29
- data/lib/aixm/refinements.rb +49 -2
- data/lib/aixm/shortcuts.rb +30 -0
- data/lib/aixm/version.rb +1 -1
- data/spec/factory.rb +42 -25
- data/spec/lib/aixm/component/class_layer_spec.rb +74 -0
- data/spec/lib/aixm/{horizontal → component/geometry}/arc_spec.rb +11 -11
- data/spec/lib/aixm/component/geometry/border_spec.rb +30 -0
- data/spec/lib/aixm/{horizontal → component/geometry}/circle_spec.rb +8 -8
- data/spec/lib/aixm/{horizontal → component/geometry}/point_spec.rb +7 -7
- data/spec/lib/aixm/{geometry_spec.rb → component/geometry_spec.rb} +39 -40
- data/spec/lib/aixm/component/schedule_spec.rb +33 -0
- data/spec/lib/aixm/{vertical/limits_spec.rb → component/vertical_limits_spec.rb} +10 -10
- data/spec/lib/aixm/document_spec.rb +97 -36
- data/spec/lib/aixm/feature/airspace_spec.rb +230 -71
- data/spec/lib/aixm/refinements_spec.rb +52 -12
- metadata +30 -23
- data/lib/aixm/constants.rb +0 -6
- data/lib/aixm/geometry.rb +0 -71
- data/lib/aixm/horizontal/arc.rb +0 -50
- data/lib/aixm/horizontal/border.rb +0 -45
- data/lib/aixm/horizontal/circle.rb +0 -53
- data/lib/aixm/horizontal/point.rb +0 -39
- data/spec/lib/aixm/horizontal/border_spec.rb +0 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c00283d4f8eeb7bc39a916e5d71778bcb9398ccd27d8bd0dd118b452f4d897b6
|
4
|
+
data.tar.gz: 3d8c7cdf302994e590add9864ac684e98147fdc546e5ca3983bd5f68d498e3ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0adb07ef827f44488bb89739155ee4c038a300f18590ba652d1a06771fefb4b8b72d50a203c4790d3d8a551f4c5992fcca8d73de68c50cd6c1d4732505ffeb1f
|
7
|
+
data.tar.gz: a3f7cc1facbbae82eddf970e0eb240753c46f0cc4194c477ff44a0537ff5724764179a09ab9366cdf37665b5df7e2dfb2dae9431f4c8d0500aa1144a4a4b6437
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,33 @@
|
|
1
|
+
## 0.1.3
|
2
|
+
|
3
|
+
* Breaking major changes:
|
4
|
+
* Re-organization of classes in features and components
|
5
|
+
* Additions:
|
6
|
+
* Shortcut initializers e.g. `AIXM.airspace(...)`
|
7
|
+
|
8
|
+
## 0.1.2
|
9
|
+
|
10
|
+
* Breaking additions:
|
11
|
+
* Class layers
|
12
|
+
* Breaking minor changes:
|
13
|
+
* Use `document.features << (feature)` instead of `document << (feature)`
|
14
|
+
|
15
|
+
## 0.1.1
|
16
|
+
|
17
|
+
* Additions:
|
18
|
+
* Schedule (all but `TIMSH`)
|
19
|
+
* Refinement `Float#to_km` and `String#uptrans`
|
20
|
+
* Shortcut constants `AIXM::UNLIMITED` and `AIXM::H24`
|
21
|
+
* `Airspace#short_name`
|
22
|
+
* Minor changes:
|
23
|
+
* `Document#created_at` and `#effective_at` accept Time, Date, String or *nil*
|
24
|
+
* Separate `AIXM::Document#valid?` from `#complete?`
|
25
|
+
* Write coordinates in DD if extension `:OFM` is set
|
26
|
+
* `Array#to_digest` returns Integer which fits in signed 32bit
|
27
|
+
|
1
28
|
## 0.1.0
|
2
29
|
|
3
|
-
* Initial implementation to import D/R/P zones to OFM
|
30
|
+
* Initial implementation to import D/R/P zones to OFM:
|
4
31
|
* XY Coordinate
|
5
32
|
* Z Altitude
|
6
33
|
* AIXM-Snapshot 4.5 Document
|
@@ -11,4 +38,5 @@
|
|
11
38
|
* Arc
|
12
39
|
* Border
|
13
40
|
* Circle
|
41
|
+
* Shortcut constant `AIXM::GROUND`
|
14
42
|
* Refinements
|
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
[![Continuous Integration](https://img.shields.io/travis/svoop/aixm/master.svg?style=flat)](https://travis-ci.org/svoop/aixm)
|
3
3
|
[![Code Climate](https://img.shields.io/codeclimate/github/svoop/aixm.svg?style=flat)](https://codeclimate.com/github/svoop/aixm)
|
4
4
|
[![Gitter](https://img.shields.io/gitter/room/svoop/aixm.svg?style=flat)](https://gitter.im/svoop/aixm)
|
5
|
-
[![Donorbox](https://img.shields.io/badge/donate-on_donorbox-yellow.svg)](https://donorbox.org/bitcetera
|
5
|
+
[![Donorbox](https://img.shields.io/badge/donate-on_donorbox-yellow.svg)](https://donorbox.org/bitcetera)
|
6
6
|
|
7
7
|
# AIXM
|
8
8
|
|
@@ -14,11 +14,12 @@ are part of this gem. Most notably, the gem is only a builder of AIXM 4.5
|
|
14
14
|
snapshot files and does not parse them.
|
15
15
|
|
16
16
|
* [Homepage](https://github.com/svoop/aixm)
|
17
|
+
* [API](http://www.rubydoc.info/gems/aixm)
|
17
18
|
* Author: [Sven Schwyn - Bitcetera](http://www.bitcetera.com)
|
18
19
|
|
19
20
|
## Install
|
20
21
|
|
21
|
-
Add this to your
|
22
|
+
Add this to your `Gemfile`:
|
22
23
|
|
23
24
|
```ruby
|
24
25
|
gem aixm
|
@@ -26,29 +27,131 @@ gem aixm
|
|
26
27
|
|
27
28
|
## Usage
|
28
29
|
|
29
|
-
|
30
|
+
You can initialize all elements either traditionally or by use of shorter
|
31
|
+
AIXM class methods:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
AIXM::Feature::Airspace.new(...)
|
35
|
+
AIXM.airspace(...)
|
36
|
+
```
|
37
|
+
|
38
|
+
### Fundamentals
|
39
|
+
|
40
|
+
All fundamentals are bundled at the root of the module `AIXM`.
|
41
|
+
|
42
|
+
### Document
|
43
|
+
|
44
|
+
The document is the root container of the AIXM snapshot file to be generated.
|
45
|
+
It's essentially a collection of features:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
document = AIXM.document(created_at: Time.now, effective_at: Time.now)
|
49
|
+
document.features << AIXM.airspace(...)
|
50
|
+
```
|
51
|
+
|
52
|
+
To give an overview of the AIXM building blocks, the remainder of this guide
|
53
|
+
will list initializer arguments with colons (`name: class`) and attribute
|
54
|
+
writers with equal or push signs (`name = class` or `name << class`):
|
55
|
+
|
56
|
+
* AIXM.document
|
57
|
+
* created_at: Time, Date or String
|
58
|
+
* effective_at: Time, Date or String
|
59
|
+
* features << AIXM::Feature
|
60
|
+
|
61
|
+
See [the API documentation](http://www.rubydoc.info/gems/aixm) for details and
|
62
|
+
[spec/factory.rb](https://github.com/svoop/aixm/blob/master/spec/factory.rb) for
|
63
|
+
examples.
|
30
64
|
|
31
65
|
#### Coordinate
|
32
66
|
|
33
67
|
All of the below are equivalent:
|
34
68
|
|
35
69
|
```ruby
|
36
|
-
AIXM
|
37
|
-
AIXM
|
38
|
-
AIXM
|
70
|
+
AIXM.xy(lat: %q(11°22'33.44"), long: %q(-111°22'33.44"))
|
71
|
+
AIXM.xy(lat: '112233.44N', long: '1112233.44W')
|
72
|
+
AIXM.xy(lat: 11.375955555555556, long: -111.37595555555555)
|
39
73
|
```
|
40
74
|
|
41
|
-
#### Altitude
|
75
|
+
#### Altitude and Heights
|
76
|
+
|
77
|
+
Altitudes and heights exist in three different forms:
|
42
78
|
|
43
79
|
```ruby
|
44
|
-
AIXM
|
45
|
-
AIXM
|
46
|
-
AIXM
|
80
|
+
AIXM.z(alt: 1000, code: :QFE) # height: 1000ft above ground
|
81
|
+
AIXM.z(alt: 2000, code: :QNH) # altitude: of 2000ft above mean sea level
|
82
|
+
AIXM.z(alt: 45, code: :QNE) # altitude: flight level 45
|
47
83
|
```
|
48
84
|
|
49
|
-
###
|
85
|
+
### Features
|
86
|
+
|
87
|
+
All features are subclasses of `AIXM::Feature`.
|
88
|
+
|
89
|
+
#### Airspace
|
90
|
+
|
91
|
+
* AIXM.airspace
|
92
|
+
* name: String
|
93
|
+
* short_name: String or *nil*
|
94
|
+
* type: String or Symbol
|
95
|
+
* schedule = AIXM.schedule
|
96
|
+
* geometry << AIXM.point, AIXM.arc, AIXM.border or AIXM.circle
|
97
|
+
* class_layers << AIXM.class_layer
|
98
|
+
* remarks = String
|
99
|
+
|
100
|
+
### Components
|
101
|
+
|
102
|
+
All components are subclasses of `AIXM::Component`.
|
103
|
+
|
104
|
+
#### Schedule
|
50
105
|
|
51
|
-
|
106
|
+
* AIXM.schedule
|
107
|
+
* code: String or Symbol
|
108
|
+
|
109
|
+
#### Class Layer
|
110
|
+
|
111
|
+
* AIXM.class_layer
|
112
|
+
* class: String or *nil*
|
113
|
+
* vertical_limits: AIXM.vertical_limits
|
114
|
+
|
115
|
+
#### Vertical Limits
|
116
|
+
|
117
|
+
* AIXM.vertical_limits
|
118
|
+
* max_z: AIXM.z or *nil*
|
119
|
+
* upper_z: AIXM.z
|
120
|
+
* lower_z: AIXM.z
|
121
|
+
* min_z: AIXM.z or *nil*
|
122
|
+
|
123
|
+
#### Point, Arc, Border and Circle
|
124
|
+
|
125
|
+
* AIXM.point
|
126
|
+
* xy: AIXM.xy
|
127
|
+
* AIXM.arc
|
128
|
+
* xy: AIXM.xy
|
129
|
+
* center_xy: AIXM.xy
|
130
|
+
* cloclwise: *true* or *false*
|
131
|
+
* AIXM.border
|
132
|
+
* xy: AIXM.xy
|
133
|
+
* name: String
|
134
|
+
* AIXM.circle
|
135
|
+
* center_xy: AIXM.xy
|
136
|
+
* radius: Numeric
|
137
|
+
|
138
|
+
#### Geometry
|
139
|
+
|
140
|
+
* AIXM.geometry
|
141
|
+
* << AIXM.point, AIXM.arc, AIXM.border or AIXM.circle
|
142
|
+
|
143
|
+
For a geometry to be complete, it must be comprised of either:
|
144
|
+
|
145
|
+
* exactly one circle
|
146
|
+
* at least three points, arcs or borders (the last of which a point with
|
147
|
+
identical coordinates as the first)
|
148
|
+
|
149
|
+
## Validation
|
150
|
+
|
151
|
+
* Use `AIXM::Document#complete?` to check whether all mandatory information is
|
152
|
+
present. Airspaces, geometries etc have `complete?` methods as well.
|
153
|
+
* Use `AIXM::Document#valid?` to validate the resulting AIXM against the XSD
|
154
|
+
schema. If any, you find the errors in `AIXM::Document#errors`.
|
52
155
|
|
53
156
|
## Rendering
|
54
157
|
|
@@ -59,16 +162,33 @@ document.to_xml(:OFM) # render AIXM 4.5 + OFM extensions XML
|
|
59
162
|
|
60
163
|
## Constants
|
61
164
|
|
62
|
-
*
|
165
|
+
* `AIXM::GROUND` - height: 0ft above ground
|
166
|
+
* `AIXM::UNLIMITED` - altitude: FL 999
|
167
|
+
* `AIXM::H24` - continuous schedule
|
63
168
|
|
64
169
|
## Refinements
|
65
170
|
|
66
171
|
By `using AIXM::Refinements` you get the following general purpose methods:
|
67
172
|
|
68
|
-
*
|
69
|
-
*
|
70
|
-
*
|
71
|
-
*
|
173
|
+
* `String#indent(number)`<br>Indent every line of a string with *number* spaces
|
174
|
+
* `String#uptrans`<br>upcase and transliterate to match the reduced character set for names
|
175
|
+
* `String#to_dd`<br>Convert DMS angle to DD or `nil` if the format is not recognized
|
176
|
+
* `Float#to_dms(padding)`<br>Convert DD angle to DMS with the degrees zero padded to *padding* length
|
177
|
+
* `Float#trim`<br>Convert whole numbers to Integer and leave all other untouched
|
178
|
+
* `Float#to_km(from: unit)`<br>Convert a distance from *unit* (:km, :m, :nm or :ft) to km
|
179
|
+
|
180
|
+
## Extensions
|
181
|
+
|
182
|
+
### OFM
|
183
|
+
|
184
|
+
This extension adds proprietary tags and attributes (most of which are prefixed
|
185
|
+
with `xt_`) aiming to improve importing the resulting AIXM into the OFM
|
186
|
+
originative suite:
|
187
|
+
|
188
|
+
* `<AIXM-Snapshot version="4.5 + OFM extensions of version 0.1" (...) />`<br>root node with extended version string
|
189
|
+
* `<Ase xt_classLayersAvail="(true|false)">`<br>true when multiple class layers and therefore an Adg-node is present
|
190
|
+
* `<xt_selAvail>(true|false)</xt_selAvail>`<br>enables conditional airspaces feature
|
191
|
+
* `<AseUid newEntity="(true|false)">`<br>tell the importer whether adding a new or updating an existing entity
|
72
192
|
|
73
193
|
## References
|
74
194
|
|
@@ -76,6 +196,15 @@ By `using AIXM::Refinements` you get the following general purpose methods:
|
|
76
196
|
* [AIXM on Wikipedia](https://en.wikipedia.org/wiki/AIXM)
|
77
197
|
* [Open Flightmaps](https://openflightmaps.org)
|
78
198
|
|
199
|
+
## Tests
|
200
|
+
|
201
|
+
Some tests are very time consuming and therefore skipped by default. To run the
|
202
|
+
full test suite, set the environment variable:
|
203
|
+
|
204
|
+
```
|
205
|
+
export SPEC_SCOPE=all
|
206
|
+
```
|
207
|
+
|
79
208
|
## Development
|
80
209
|
|
81
210
|
To install the development dependencies and then run the test suite:
|
data/aixm.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ['ruby@bitcetera.com']
|
11
11
|
spec.description = %q(Aeronautical Information Exchange Model (AIXM 4.5).)
|
12
12
|
spec.summary = %q(Aeronautical Information Exchange Model (AIXM 4.5).)
|
13
|
-
spec.homepage = '
|
13
|
+
spec.homepage = 'https://github.com/svoop/aixm'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
+
spec.required_ruby_version = '>= 2.5'
|
22
|
+
|
21
23
|
spec.add_development_dependency 'bundler'
|
22
24
|
spec.add_development_dependency 'rake'
|
23
25
|
spec.add_development_dependency 'minitest'
|
data/lib/aixm.rb
CHANGED
@@ -6,20 +6,22 @@ require 'digest'
|
|
6
6
|
require 'time'
|
7
7
|
|
8
8
|
require_relative 'aixm/version'
|
9
|
-
|
10
9
|
require_relative 'aixm/refinements'
|
11
10
|
|
11
|
+
require_relative 'aixm/document'
|
12
12
|
require_relative 'aixm/xy'
|
13
13
|
require_relative 'aixm/z'
|
14
|
-
require_relative 'aixm/geometry'
|
15
14
|
|
16
|
-
require_relative 'aixm/
|
17
|
-
require_relative 'aixm/
|
18
|
-
require_relative 'aixm/
|
19
|
-
require_relative 'aixm/
|
20
|
-
require_relative 'aixm/
|
21
|
-
|
22
|
-
require_relative 'aixm/
|
23
|
-
require_relative 'aixm/
|
15
|
+
require_relative 'aixm/component/base'
|
16
|
+
require_relative 'aixm/component/geometry'
|
17
|
+
require_relative 'aixm/component/geometry/point'
|
18
|
+
require_relative 'aixm/component/geometry/arc'
|
19
|
+
require_relative 'aixm/component/geometry/border'
|
20
|
+
require_relative 'aixm/component/geometry/circle'
|
21
|
+
require_relative 'aixm/component/class_layer'
|
22
|
+
require_relative 'aixm/component/vertical_limits'
|
23
|
+
require_relative 'aixm/component/schedule'
|
24
24
|
|
25
25
|
require_relative 'aixm/feature/airspace'
|
26
|
+
|
27
|
+
require_relative 'aixm/shortcuts'
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module AIXM
|
2
|
+
module Component
|
3
|
+
|
4
|
+
##
|
5
|
+
# Class layers consists of an optional airspace class and mandatory
|
6
|
+
# vertical limits.
|
7
|
+
class ClassLayer < Base
|
8
|
+
using AIXM::Refinements
|
9
|
+
|
10
|
+
CLASSES = %i(A B C D E F G)
|
11
|
+
|
12
|
+
attr_reader :vertical_limits
|
13
|
+
|
14
|
+
def initialize(class: nil, vertical_limits:)
|
15
|
+
@klass, @vertical_limits = binding.local_variable_get(:class)&.to_sym, vertical_limits
|
16
|
+
fail(ArgumentError, "invalid class `#{@klass}'") unless @klass.nil? || CLASSES.include?(@klass)
|
17
|
+
fail(ArgumentError, "invalid vertical limits") unless @vertical_limits.is_a? AIXM::Component::VerticalLimits
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Read the airspace class
|
22
|
+
#
|
23
|
+
# This and other workarounds in the initializer are necessary due to "class"
|
24
|
+
# being a reserved keyword in Ruby.
|
25
|
+
def class
|
26
|
+
@klass
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Digest to identify the payload
|
31
|
+
def to_digest
|
32
|
+
[self.class, vertical_limits.to_digest].to_digest
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Render AIXM
|
37
|
+
#
|
38
|
+
# Extensions:
|
39
|
+
# * +:OFM+ - Open Flightmaps
|
40
|
+
def to_xml(*extensions)
|
41
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
42
|
+
builder.codeClass(self.class.to_s) if self.class
|
43
|
+
builder << vertical_limits.to_xml(*extensions)
|
44
|
+
builder.target! # see https://github.com/jimweirich/builder/issues/42
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module AIXM
|
2
|
+
module Component
|
3
|
+
|
4
|
+
##
|
5
|
+
# Geometries define a 3D airspace horizontally. It's either exactly one
|
6
|
+
# circle or at least three points, arcs and borders (the last of which
|
7
|
+
# has to be a point with the same coordinates as the first).
|
8
|
+
#
|
9
|
+
# Example 1:
|
10
|
+
# geometry = AIXM.geometry(
|
11
|
+
# AIXM.point(...),
|
12
|
+
# AIXM.point(...)
|
13
|
+
# )
|
14
|
+
#
|
15
|
+
# Example 2:
|
16
|
+
# geometry = AIXM.geometry
|
17
|
+
# geometry << AIXM.point(...)
|
18
|
+
# geometry << AIXM.point(...)
|
19
|
+
class Geometry < Base
|
20
|
+
include Enumerable
|
21
|
+
extend Forwardable
|
22
|
+
using AIXM::Refinements
|
23
|
+
|
24
|
+
def_delegators :@result_array, :each, :<<
|
25
|
+
|
26
|
+
def initialize(*segments)
|
27
|
+
@result_array = segments
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Array of +AIXM::Component::Geometry::...+ objects
|
32
|
+
def segments
|
33
|
+
@result_array
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Check whether the geometry is complete
|
38
|
+
def complete?
|
39
|
+
circle? || closed_shape?
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Digest to identify the payload
|
44
|
+
def to_digest
|
45
|
+
segments.map(&:to_digest).to_digest
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Render AIXM
|
50
|
+
#
|
51
|
+
# Extensions:
|
52
|
+
# * +:OFM+ - Open Flightmaps
|
53
|
+
def to_xml(*extensions)
|
54
|
+
@result_array.map { |h| h.to_xml(*extensions) }.join
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def circle?
|
60
|
+
@result_array.size == 1 &&
|
61
|
+
@result_array.first.is_a?(AIXM::Component::Geometry::Circle)
|
62
|
+
end
|
63
|
+
|
64
|
+
def closed_shape?
|
65
|
+
@result_array.size >= 3 &&
|
66
|
+
!@result_array.any? { |h| h.is_a?(AIXM::Component::Geometry::Circle) } &&
|
67
|
+
@result_array.last.is_a?(AIXM::Component::Geometry::Point) &&
|
68
|
+
@result_array.first.xy == @result_array.last.xy
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|