aixm 0.1.0 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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