aixm 0.1.0 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/Guardfile +1 -1
  4. data/README.md +146 -17
  5. data/aixm.gemspec +3 -1
  6. data/lib/aixm.rb +12 -10
  7. data/lib/aixm/component/base.rb +6 -0
  8. data/lib/aixm/component/class_layer.rb +49 -0
  9. data/lib/aixm/component/geometry.rb +73 -0
  10. data/lib/aixm/component/geometry/arc.rb +53 -0
  11. data/lib/aixm/component/geometry/border.rb +49 -0
  12. data/lib/aixm/component/geometry/circle.rb +56 -0
  13. data/lib/aixm/component/geometry/point.rb +42 -0
  14. data/lib/aixm/component/schedule.rb +45 -0
  15. data/lib/aixm/{vertical/limits.rb → component/vertical_limits.rb} +9 -14
  16. data/lib/aixm/document.rb +30 -19
  17. data/lib/aixm/feature/airspace.rb +60 -29
  18. data/lib/aixm/refinements.rb +49 -2
  19. data/lib/aixm/shortcuts.rb +30 -0
  20. data/lib/aixm/version.rb +1 -1
  21. data/spec/factory.rb +42 -25
  22. data/spec/lib/aixm/component/class_layer_spec.rb +74 -0
  23. data/spec/lib/aixm/{horizontal → component/geometry}/arc_spec.rb +11 -11
  24. data/spec/lib/aixm/component/geometry/border_spec.rb +30 -0
  25. data/spec/lib/aixm/{horizontal → component/geometry}/circle_spec.rb +8 -8
  26. data/spec/lib/aixm/{horizontal → component/geometry}/point_spec.rb +7 -7
  27. data/spec/lib/aixm/{geometry_spec.rb → component/geometry_spec.rb} +39 -40
  28. data/spec/lib/aixm/component/schedule_spec.rb +33 -0
  29. data/spec/lib/aixm/{vertical/limits_spec.rb → component/vertical_limits_spec.rb} +10 -10
  30. data/spec/lib/aixm/document_spec.rb +97 -36
  31. data/spec/lib/aixm/feature/airspace_spec.rb +230 -71
  32. data/spec/lib/aixm/refinements_spec.rb +52 -12
  33. metadata +30 -23
  34. data/lib/aixm/constants.rb +0 -6
  35. data/lib/aixm/geometry.rb +0 -71
  36. data/lib/aixm/horizontal/arc.rb +0 -50
  37. data/lib/aixm/horizontal/border.rb +0 -45
  38. data/lib/aixm/horizontal/circle.rb +0 -53
  39. data/lib/aixm/horizontal/point.rb +0 -39
  40. 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: 153468c1338fc26792178d856c438511fa10ac58988ef0e938980fd590338164
4
- data.tar.gz: b04ae1dcbe0ef0d90beea492c08d08aeab943a156127c70cdc94c5ec69b4995b
3
+ metadata.gz: c00283d4f8eeb7bc39a916e5d71778bcb9398ccd27d8bd0dd118b452f4d897b6
4
+ data.tar.gz: 3d8c7cdf302994e590add9864ac684e98147fdc546e5ca3983bd5f68d498e3ea
5
5
  SHA512:
6
- metadata.gz: 45a95906e65595273f9e5667a7aee0498f5390a6d9c86500f00dafbc080376316fa4b8d062deefda840ec9a0d403ab941762c59f4b4d413eed17868102e86196
7
- data.tar.gz: efe2127226e7a3e3d5b25f69bb29688fa12c59b1af579a272291aa200b5b2447c24b4093e248eb671ca0cb915a0aa31a50f757c8dcb5770f3b7d28139ab78396
6
+ metadata.gz: 0adb07ef827f44488bb89739155ee4c038a300f18590ba652d1a06771fefb4b8b72d50a203c4790d3d8a551f4c5992fcca8d73de68c50cd6c1d4732505ffeb1f
7
+ data.tar.gz: a3f7cc1facbbae82eddf970e0eb240753c46f0cc4194c477ff44a0537ff5724764179a09ab9366cdf37665b5df7e2dfb2dae9431f4c8d0500aa1144a4a4b6437
@@ -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
@@ -3,5 +3,5 @@ clearing :on
3
3
  guard :minitest do
4
4
  watch(%r{^spec/(.+)_spec\.rb})
5
5
  watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
- watch(%r{^spec/spec_helper\.rb}) { 'spec' }
6
+ watch(%r{^spec/(spec_helper|factory)\.rb}) { 'spec' }
7
7
  end
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-aixm)
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 <tt>Gemfile</tt>:
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
- ### Types
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::XY.new(lat: %q(11°22'33.44"), long: %q(-111°22'33.44"))
37
- AIXM::XY.new(lat: '112233.44N', long: '1112233.44W')
38
- AIXM::XY.new(lat: 11.375955555555556, long: -111.37595555555555)
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::Z.new(alt: 1000, code: :QFE) # height: 1000ft above ground
45
- AIXM::Z.new(alt: 2000, code: :QNH) # altitude: of 2000ft above mean sea level
46
- AIXM::Z.new(alt: 45, code: :QNE) # altitude: flight level 45
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
- ### Document
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
- See <tt>spec/factory.rb</tt> for examples.
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
- * <tt>AIXM::GROUND</tt> - height: 0ft above ground
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
- * <tt>String#indent(number)</tt><br>Indent every line of a string with *number* spaces
69
- * <tt>String#to_dd</tt><br>Convert DMS angle to DD or <tt>nil</tt> if the format is not recognized
70
- * <tt>Float#to_dms(padding)</tt><br>Convert DD angle to DMS with the degrees zero padded to *padding* length
71
- * <tt>Float#trim</tt><br>Convert whole numbers to Integer and leave all other untouched
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:
@@ -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 = 'http://www.bitcetera.com/products/aixm'
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'
@@ -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/horizontal/point'
17
- require_relative 'aixm/horizontal/arc'
18
- require_relative 'aixm/horizontal/border'
19
- require_relative 'aixm/horizontal/circle'
20
- require_relative 'aixm/vertical/limits'
21
-
22
- require_relative 'aixm/constants'
23
- require_relative 'aixm/document'
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,6 @@
1
+ module AIXM
2
+ module Component
3
+ class Base
4
+ end
5
+ end
6
+ end
@@ -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