aixm 0.2.3 → 0.3.0

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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/.yardopts +3 -0
  5. data/CHANGELOG.md +34 -14
  6. data/Guardfile +1 -0
  7. data/README.md +64 -257
  8. data/lib/aixm.rb +16 -7
  9. data/lib/aixm/component.rb +6 -0
  10. data/lib/aixm/component/frequency.rb +135 -0
  11. data/lib/aixm/component/geometry.rb +34 -23
  12. data/lib/aixm/component/geometry/arc.rb +37 -22
  13. data/lib/aixm/component/geometry/border.rb +29 -20
  14. data/lib/aixm/component/geometry/circle.rb +39 -22
  15. data/lib/aixm/component/geometry/point.rb +29 -13
  16. data/lib/aixm/component/helipad.rb +154 -0
  17. data/lib/aixm/component/layer.rb +91 -0
  18. data/lib/aixm/component/runway.rb +294 -0
  19. data/lib/aixm/component/service.rb +170 -0
  20. data/lib/aixm/component/timetable.rb +65 -0
  21. data/lib/aixm/component/vertical_limits.rb +65 -29
  22. data/lib/aixm/config.rb +87 -0
  23. data/lib/aixm/document.rb +66 -42
  24. data/lib/aixm/errors.rb +11 -0
  25. data/lib/aixm/f.rb +34 -20
  26. data/lib/aixm/feature.rb +38 -0
  27. data/lib/aixm/feature/airport.rb +473 -0
  28. data/lib/aixm/feature/airspace.rb +145 -92
  29. data/lib/aixm/feature/navigational_aid.rb +94 -0
  30. data/lib/aixm/feature/navigational_aid/designated_point.rb +50 -54
  31. data/lib/aixm/feature/navigational_aid/dme.rb +48 -40
  32. data/lib/aixm/feature/navigational_aid/marker.rb +55 -45
  33. data/lib/aixm/feature/navigational_aid/ndb.rb +54 -50
  34. data/lib/aixm/feature/navigational_aid/tacan.rb +38 -31
  35. data/lib/aixm/feature/navigational_aid/vor.rb +84 -76
  36. data/lib/aixm/feature/organisation.rb +97 -0
  37. data/lib/aixm/feature/unit.rb +152 -0
  38. data/lib/aixm/refinements.rb +132 -47
  39. data/lib/aixm/shortcuts.rb +11 -6
  40. data/lib/aixm/version.rb +1 -1
  41. data/lib/aixm/xy.rb +64 -20
  42. data/lib/aixm/z.rb +51 -22
  43. data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-DataTypes.xsd +0 -0
  44. data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Features.xsd +0 -0
  45. data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Snapshot.xsd +0 -0
  46. data/schemas/ofmx/0/OFMX-DataTypes.xsd +5077 -0
  47. data/schemas/ofmx/0/OFMX-Features.xsd +9955 -0
  48. data/schemas/ofmx/0/OFMX-Snapshot.xsd +217 -0
  49. data/spec/factory.rb +209 -33
  50. data/spec/lib/aixm/component/frequency_spec.rb +75 -0
  51. data/spec/lib/aixm/component/geometry/arc_spec.rb +28 -22
  52. data/spec/lib/aixm/component/geometry/border_spec.rb +23 -20
  53. data/spec/lib/aixm/component/geometry/circle_spec.rb +31 -22
  54. data/spec/lib/aixm/component/geometry/point_spec.rb +11 -14
  55. data/spec/lib/aixm/component/geometry_spec.rb +150 -69
  56. data/spec/lib/aixm/component/helipad_spec.rb +136 -0
  57. data/spec/lib/aixm/component/layer_spec.rb +110 -0
  58. data/spec/lib/aixm/component/runway_spec.rb +402 -0
  59. data/spec/lib/aixm/component/service_spec.rb +61 -0
  60. data/spec/lib/aixm/component/timetable_spec.rb +49 -0
  61. data/spec/lib/aixm/component/vertical_limits_spec.rb +39 -20
  62. data/spec/lib/aixm/config_spec.rb +41 -0
  63. data/spec/lib/aixm/document_spec.rb +637 -147
  64. data/spec/lib/aixm/errors_spec.rb +14 -0
  65. data/spec/lib/aixm/f_spec.rb +17 -10
  66. data/spec/lib/aixm/feature/airport_spec.rb +546 -0
  67. data/spec/lib/aixm/feature/airspace_spec.rb +349 -226
  68. data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +47 -36
  69. data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +61 -36
  70. data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +61 -113
  71. data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +65 -79
  72. data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +57 -36
  73. data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +86 -112
  74. data/spec/lib/aixm/feature/navigational_aid_spec.rb +52 -0
  75. data/spec/lib/aixm/feature/organisation_spec.rb +77 -0
  76. data/spec/lib/aixm/feature/unit_spec.rb +227 -0
  77. data/spec/lib/aixm/feature_spec.rb +58 -0
  78. data/spec/lib/aixm/refinements_spec.rb +187 -178
  79. data/spec/lib/aixm/xy_spec.rb +45 -34
  80. data/spec/lib/aixm/z_spec.rb +19 -21
  81. data/spec/macros/organisation.rb +11 -0
  82. data/spec/macros/remarks.rb +12 -0
  83. data/spec/macros/timetable.rb +11 -0
  84. data/spec/macros/xy.rb +11 -0
  85. data/spec/macros/z_qnh.rb +11 -0
  86. data/spec/spec_helper.rb +26 -0
  87. metadata +60 -19
  88. data/lib/aixm/base.rb +0 -10
  89. data/lib/aixm/component/base.rb +0 -6
  90. data/lib/aixm/component/class_layer.rb +0 -46
  91. data/lib/aixm/component/geometry/base.rb +0 -8
  92. data/lib/aixm/component/schedule.rb +0 -43
  93. data/lib/aixm/feature/base.rb +0 -6
  94. data/lib/aixm/feature/navigational_aid/base.rb +0 -79
  95. data/spec/lib/aixm/component/class_layer_spec.rb +0 -74
  96. data/spec/lib/aixm/component/schedule_spec.rb +0 -33
  97. data/spec/lib/aixm/feature/navigational_aid/base_spec.rb +0 -41
@@ -1,259 +1,382 @@
1
1
  require_relative '../../../spec_helper'
2
2
 
3
3
  describe AIXM::Feature::Airspace do
4
- context "incomplete" do
4
+
5
+ context "only required attributes set" do
5
6
  subject do
6
- AIXM.airspace(name: 'foobar', type: 'D')
7
+ AIXM.airspace(type: "TMA", name: "Test TMA")
7
8
  end
8
9
 
9
- describe :complete? do
10
- it "must fail validation" do
11
- subject.wont_be :complete?
10
+ describe :initialize do
11
+ it "sets defaults" do
12
+ subject.id.must_equal '22E2F734'
13
+ subject.layers.must_equal []
14
+ subject.geometry.must_be_instance_of AIXM::Component::Geometry
12
15
  end
13
16
  end
14
- end
15
17
 
16
- context "complete" do
17
- context "with one class layer" do
18
- subject do
19
- AIXM::Factory.polygon_airspace
18
+ describe :id= do
19
+ it "fails on invalid values" do
20
+ [:foobar, 123].wont_be_written_to subject, :id
20
21
  end
21
22
 
22
- describe :complete? do
23
- it "must pass validation" do
24
- subject.must_be :complete?
25
- end
23
+ it "falls back to id derived from digest of id, name and short_name" do
24
+ subject.tap { |s| s.id = nil }.id.must_equal '22E2F734'
26
25
  end
27
26
 
28
- describe :to_digest do
29
- it "must return digest of payload" do
30
- subject.to_digest.must_equal 367297292
31
- end
27
+ it "upcases value" do
28
+ subject.tap { |s| s.id = 'löl' }.id.must_equal 'LOEL'
32
29
  end
30
+ end
33
31
 
34
- describe :to_aixm do
35
- it "must build correct XML with OFM extensions" do
36
- digest = subject.to_digest
37
- subject.to_aixm(:ofm).must_equal <<~"END"
38
- <!-- Airspace: [D] POLYGON AIRSPACE -->
39
- <Ase xt_classLayersAvail="false">
40
- <AseUid mid="#{digest}" newEntity="true">
41
- <codeType>D</codeType>
42
- <codeId>#{digest}</codeId>
43
- </AseUid>
44
- <txtLocalType>POLYGON</txtLocalType>
45
- <txtName>POLYGON AIRSPACE</txtName>
46
- <codeClass>C</codeClass>
47
- <codeDistVerUpper>STD</codeDistVerUpper>
48
- <valDistVerUpper>65</valDistVerUpper>
49
- <uomDistVerUpper>FL</uomDistVerUpper>
50
- <codeDistVerLower>STD</codeDistVerLower>
51
- <valDistVerLower>45</valDistVerLower>
52
- <uomDistVerLower>FL</uomDistVerLower>
53
- <codeDistVerMax>ALT</codeDistVerMax>
54
- <valDistVerMax>6000</valDistVerMax>
55
- <uomDistVerMax>FT</uomDistVerMax>
56
- <codeDistVerMnm>HEI</codeDistVerMnm>
57
- <valDistVerMnm>3000</valDistVerMnm>
58
- <uomDistVerMnm>FT</uomDistVerMnm>
59
- <Att>
60
- <codeWorkHr>H24</codeWorkHr>
61
- </Att>
62
- <txtRmk>polygon airspace</txtRmk>
63
- <xt_selAvail>false</xt_selAvail>
64
- </Ase>
65
- <Abd>
66
- <AbdUid>
67
- <AseUid mid="#{digest}" newEntity="true">
68
- <codeType>D</codeType>
69
- <codeId>#{digest}</codeId>
70
- </AseUid>
71
- </AbdUid>
72
- <Avx>
73
- <codeType>CWA</codeType>
74
- <geoLat>47.85916667N</geoLat>
75
- <geoLong>7.56000000E</geoLong>
76
- <codeDatum>WGE</codeDatum>
77
- <geoLatArc>47.90416667N</geoLatArc>
78
- <geoLongArc>7.56333333E</geoLongArc>
79
- </Avx>
80
- <Avx>
81
- <codeType>FNT</codeType>
82
- <geoLat>47.94361111N</geoLat>
83
- <geoLong>7.59583333E</geoLong>
84
- <codeDatum>WGE</codeDatum>
85
- <GbrUid>
86
- <txtName>FRANCE_GERMANY</txtName>
87
- </GbrUid>
88
- </Avx>
89
- <Avx>
90
- <codeType>GRC</codeType>
91
- <geoLat>47.85916667N</geoLat>
92
- <geoLong>7.56000000E</geoLong>
93
- <codeDatum>WGE</codeDatum>
94
- </Avx>
95
- </Abd>
96
- END
97
- end
32
+ describe :type= do
33
+ it "fails on invalid values" do
34
+ [nil, :foobar, 123].wont_be_written_to subject, :type
98
35
  end
99
36
 
100
- context "with two class layers" do
101
- subject do
102
- AIXM::Factory.polygon_airspace.tap do |airspace|
103
- airspace.class_layers << AIXM::Factory.class_layer
104
- end
105
- end
37
+ it "looks up valid values" do
38
+ subject.tap { |s| s.type = :danger_area }.type.must_equal :danger_area
39
+ subject.tap { |s| s.type = :P }.type.must_equal :prohibited_area
40
+ end
41
+ end
106
42
 
107
- describe :complete? do
108
- it "must pass validation" do
109
- subject.must_be :complete?
110
- end
111
- end
43
+ describe :name= do
44
+ it "fails on invalid values" do
45
+ [:foobar, 123].wont_be_written_to subject, :name
46
+ end
112
47
 
113
- describe :to_digest do
114
- it "must return digest of payload" do
115
- subject.to_digest.must_equal 481196243
116
- end
117
- end
48
+ it "accepts nil value" do
49
+ [nil].must_be_written_to subject, :name
50
+ end
118
51
 
119
- describe :to_aixm do
120
- it "must build correct XML with OFM extensions" do
121
- digest = subject.to_digest
122
- subject.to_aixm(:ofm).must_equal <<~"END"
123
- <!-- Airspace: [D] POLYGON AIRSPACE -->
124
- <Ase xt_classLayersAvail="true">
125
- <AseUid mid="#{digest}" newEntity="true">
126
- <codeType>D</codeType>
127
- <codeId>#{digest}</codeId>
128
- </AseUid>
129
- <txtLocalType>POLYGON</txtLocalType>
130
- <txtName>POLYGON AIRSPACE</txtName>
131
- <codeClass>C</codeClass>
132
- <codeDistVerUpper>STD</codeDistVerUpper>
133
- <valDistVerUpper>65</valDistVerUpper>
134
- <uomDistVerUpper>FL</uomDistVerUpper>
135
- <codeDistVerLower>STD</codeDistVerLower>
136
- <valDistVerLower>45</valDistVerLower>
137
- <uomDistVerLower>FL</uomDistVerLower>
138
- <codeDistVerMax>ALT</codeDistVerMax>
139
- <valDistVerMax>6000</valDistVerMax>
140
- <uomDistVerMax>FT</uomDistVerMax>
141
- <codeDistVerMnm>HEI</codeDistVerMnm>
142
- <valDistVerMnm>3000</valDistVerMnm>
143
- <uomDistVerMnm>FT</uomDistVerMnm>
144
- <Att>
145
- <codeWorkHr>H24</codeWorkHr>
146
- </Att>
147
- <txtRmk>polygon airspace</txtRmk>
148
- <xt_selAvail>false</xt_selAvail>
149
- </Ase>
150
- <Abd>
151
- <AbdUid>
152
- <AseUid mid="#{digest}" newEntity="true">
153
- <codeType>D</codeType>
154
- <codeId>#{digest}</codeId>
155
- </AseUid>
156
- </AbdUid>
157
- <Avx>
158
- <codeType>CWA</codeType>
159
- <geoLat>47.85916667N</geoLat>
160
- <geoLong>7.56000000E</geoLong>
161
- <codeDatum>WGE</codeDatum>
162
- <geoLatArc>47.90416667N</geoLatArc>
163
- <geoLongArc>7.56333333E</geoLongArc>
164
- </Avx>
165
- <Avx>
166
- <codeType>FNT</codeType>
167
- <geoLat>47.94361111N</geoLat>
168
- <geoLong>7.59583333E</geoLong>
169
- <codeDatum>WGE</codeDatum>
170
- <GbrUid>
171
- <txtName>FRANCE_GERMANY</txtName>
172
- </GbrUid>
173
- </Avx>
174
- <Avx>
175
- <codeType>GRC</codeType>
176
- <geoLat>47.85916667N</geoLat>
177
- <geoLong>7.56000000E</geoLong>
178
- <codeDatum>WGE</codeDatum>
179
- </Avx>
180
- </Abd>
181
- <Adg>
182
- <AdgUid>
183
- <AseUid mid="#{digest}.1">
184
- <codeType>CLASS</codeType>
185
- </AseUid>
186
- </AdgUid>
187
- <AdgUid>
188
- <AseUid mid="#{digest}.2">
189
- <codeType>CLASS</codeType>
190
- </AseUid>
191
- </AdgUid>
192
- <AseUidSameExtent mid="#{digest}"/>
193
- </Adg>
194
- <Ase>
195
- <AseUid mid="#{digest}.1">
196
- <codeType>CLASS</codeType>
197
- </AseUid>
198
- <txtName>POLYGON AIRSPACE</txtName>
199
- <codeClass>C</codeClass>
200
- <codeDistVerUpper>STD</codeDistVerUpper>
201
- <valDistVerUpper>65</valDistVerUpper>
202
- <uomDistVerUpper>FL</uomDistVerUpper>
203
- <codeDistVerLower>STD</codeDistVerLower>
204
- <valDistVerLower>45</valDistVerLower>
205
- <uomDistVerLower>FL</uomDistVerLower>
206
- <codeDistVerMax>ALT</codeDistVerMax>
207
- <valDistVerMax>6000</valDistVerMax>
208
- <uomDistVerMax>FT</uomDistVerMax>
209
- <codeDistVerMnm>HEI</codeDistVerMnm>
210
- <valDistVerMnm>3000</valDistVerMnm>
211
- <uomDistVerMnm>FT</uomDistVerMnm>
212
- </Ase>
213
- <Ase>
214
- <AseUid mid="#{digest}.2">
215
- <codeType>CLASS</codeType>
216
- </AseUid>
217
- <txtName>POLYGON AIRSPACE</txtName>
218
- <codeClass>C</codeClass>
219
- <codeDistVerUpper>STD</codeDistVerUpper>
220
- <valDistVerUpper>65</valDistVerUpper>
221
- <uomDistVerUpper>FL</uomDistVerUpper>
222
- <codeDistVerLower>STD</codeDistVerLower>
223
- <valDistVerLower>45</valDistVerLower>
224
- <uomDistVerLower>FL</uomDistVerLower>
225
- <codeDistVerMax>ALT</codeDistVerMax>
226
- <valDistVerMax>6000</valDistVerMax>
227
- <uomDistVerMax>FT</uomDistVerMax>
228
- <codeDistVerMnm>HEI</codeDistVerMnm>
229
- <valDistVerMnm>3000</valDistVerMnm>
230
- <uomDistVerMnm>FT</uomDistVerMnm>
231
- </Ase>
232
- END
233
- end
234
- end
52
+ it "upcases value" do
53
+ subject.tap { |s| s.name = 'löl' }.name.must_equal 'LOEL'
235
54
  end
236
55
  end
237
56
 
238
- context "partially complete" do
239
- subject do
240
- AIXM::Factory.polygon_airspace
57
+ describe :short_name= do
58
+ it "fails on invalid values" do
59
+ [:foobar, 123].wont_be_written_to subject, :short_name
60
+ end
61
+
62
+ it "accepts nil value" do
63
+ [nil].must_be_written_to subject, :short_name
241
64
  end
242
65
 
243
- it "must build correct XML without short name" do
244
- subject.short_name = nil
245
- subject.to_aixm.wont_match(/txtLocalType/)
66
+ it "upcases value" do
67
+ subject.tap { |s| s.short_name = 'löl' }.short_name.must_equal 'LOEL'
68
+ end
69
+ end
70
+
71
+ describe :to_uid do
72
+ it "builds with arbitrary tag" do
73
+ subject.to_uid.must_match(/<AseUid>/)
74
+ subject.to_uid(as: :FooBar).must_match(/<FooBar>/)
75
+ end
76
+ end
77
+
78
+ describe :to_xml do
79
+ it "fails to build AIXM since geometry is not closed" do
80
+ subject.layers << AIXM::Factory.layer
81
+ -> { subject.to_xml }.must_raise AIXM::GeometryError
82
+ end
83
+
84
+ it "fails to build AIXM since layers are not defined" do
85
+ subject.geometry = AIXM::Factory.circle_geometry
86
+ -> { subject.to_xml }.must_raise AIXM::LayerError
87
+ end
88
+ end
89
+ end
90
+
91
+ context "only required attributes, geometry and layers set" do
92
+ subject do
93
+ AIXM.airspace(type: "TMA", name: "Test TMA").tap do |airspace|
94
+ airspace.geometry = AIXM::Factory.circle_geometry
95
+ airspace.layers << AIXM::Factory.layer
96
+ end
97
+ end
98
+
99
+ describe :to_xml do
100
+ it "builds correct AIXM without id" do
101
+ AIXM.aixm!
102
+ subject.to_xml.must_match(%r{<codeId>22E2F734</codeId>})
246
103
  end
247
104
 
248
- it "must build correct XML with identical name and short name" do
249
- subject.short_name = 'POLYGON AIRSPACE'
250
- subject.to_aixm.wont_match(/txtLocalType/)
105
+ it "builds correct AIXM without short name" do
106
+ AIXM.aixm!
107
+ subject.to_xml.wont_match(/<txtLocalType>/)
251
108
  end
252
109
 
253
- it "must build correct XML without schedule" do
254
- subject.schedule = nil
255
- subject.to_aixm.wont_match(/codeWorkHr/)
110
+ it "builds correct AIXM with identical name and short name" do
111
+ AIXM.aixm!
112
+ subject.to_xml.wont_match(/<txtLocalType>/)
256
113
  end
257
114
  end
258
115
  end
116
+
117
+ context "with one layer" do
118
+ subject do
119
+ AIXM::Factory.polygon_airspace
120
+ end
121
+
122
+ describe :to_xml do
123
+ it "builds correct complete OFMX" do
124
+ AIXM.ofmx!
125
+ subject.to_xml.must_equal <<~"END"
126
+ <!-- Airspace: [D] POLYGON AIRSPACE -->
127
+ <Ase source="LF|GEN|0.0 FACTORY|0|0">
128
+ <AseUid region="LF">
129
+ <codeType>D</codeType>
130
+ <codeId>PA</codeId>
131
+ </AseUid>
132
+ <txtLocalType>POLYGON</txtLocalType>
133
+ <txtName>POLYGON AIRSPACE</txtName>
134
+ <codeClass>C</codeClass>
135
+ <codeDistVerUpper>STD</codeDistVerUpper>
136
+ <valDistVerUpper>65</valDistVerUpper>
137
+ <uomDistVerUpper>FL</uomDistVerUpper>
138
+ <codeDistVerLower>STD</codeDistVerLower>
139
+ <valDistVerLower>45</valDistVerLower>
140
+ <uomDistVerLower>FL</uomDistVerLower>
141
+ <codeDistVerMax>ALT</codeDistVerMax>
142
+ <valDistVerMax>6000</valDistVerMax>
143
+ <uomDistVerMax>FT</uomDistVerMax>
144
+ <codeDistVerMnm>HEI</codeDistVerMnm>
145
+ <valDistVerMnm>3000</valDistVerMnm>
146
+ <uomDistVerMnm>FT</uomDistVerMnm>
147
+ <Att>
148
+ <codeWorkHr>H24</codeWorkHr>
149
+ </Att>
150
+ <codeSelAvbl>Y</codeSelAvbl>
151
+ <txtRmk>airspace layer</txtRmk>
152
+ </Ase>
153
+ <Abd>
154
+ <AbdUid>
155
+ <AseUid region="LF">
156
+ <codeType>D</codeType>
157
+ <codeId>PA</codeId>
158
+ </AseUid>
159
+ </AbdUid>
160
+ <Avx>
161
+ <codeType>CWA</codeType>
162
+ <geoLat>47.85916667N</geoLat>
163
+ <geoLong>007.56000000E</geoLong>
164
+ <codeDatum>WGE</codeDatum>
165
+ <geoLatArc>47.90416667N</geoLatArc>
166
+ <geoLongArc>007.56333333E</geoLongArc>
167
+ </Avx>
168
+ <Avx>
169
+ <GbrUid>
170
+ <txtName>FRANCE_GERMANY</txtName>
171
+ </GbrUid>
172
+ <codeType>FNT</codeType>
173
+ <geoLat>47.94361111N</geoLat>
174
+ <geoLong>007.59583333E</geoLong>
175
+ <codeDatum>WGE</codeDatum>
176
+ </Avx>
177
+ <Avx>
178
+ <codeType>GRC</codeType>
179
+ <geoLat>47.85916667N</geoLat>
180
+ <geoLong>007.56000000E</geoLong>
181
+ <codeDatum>WGE</codeDatum>
182
+ </Avx>
183
+ </Abd>
184
+ END
185
+ end
186
+
187
+ it "builds correct minimal OFMX" do
188
+ AIXM.ofmx!
189
+ subject.short_name = subject.name = nil
190
+ subject.to_xml.must_equal <<~"END"
191
+ <!-- Airspace: [D] UNNAMED -->
192
+ <Ase source="LF|GEN|0.0 FACTORY|0|0">
193
+ <AseUid region="LF">
194
+ <codeType>D</codeType>
195
+ <codeId>PA</codeId>
196
+ </AseUid>
197
+ <codeClass>C</codeClass>
198
+ <codeDistVerUpper>STD</codeDistVerUpper>
199
+ <valDistVerUpper>65</valDistVerUpper>
200
+ <uomDistVerUpper>FL</uomDistVerUpper>
201
+ <codeDistVerLower>STD</codeDistVerLower>
202
+ <valDistVerLower>45</valDistVerLower>
203
+ <uomDistVerLower>FL</uomDistVerLower>
204
+ <codeDistVerMax>ALT</codeDistVerMax>
205
+ <valDistVerMax>6000</valDistVerMax>
206
+ <uomDistVerMax>FT</uomDistVerMax>
207
+ <codeDistVerMnm>HEI</codeDistVerMnm>
208
+ <valDistVerMnm>3000</valDistVerMnm>
209
+ <uomDistVerMnm>FT</uomDistVerMnm>
210
+ <Att>
211
+ <codeWorkHr>H24</codeWorkHr>
212
+ </Att>
213
+ <codeSelAvbl>Y</codeSelAvbl>
214
+ <txtRmk>airspace layer</txtRmk>
215
+ </Ase>
216
+ <Abd>
217
+ <AbdUid>
218
+ <AseUid region="LF">
219
+ <codeType>D</codeType>
220
+ <codeId>PA</codeId>
221
+ </AseUid>
222
+ </AbdUid>
223
+ <Avx>
224
+ <codeType>CWA</codeType>
225
+ <geoLat>47.85916667N</geoLat>
226
+ <geoLong>007.56000000E</geoLong>
227
+ <codeDatum>WGE</codeDatum>
228
+ <geoLatArc>47.90416667N</geoLatArc>
229
+ <geoLongArc>007.56333333E</geoLongArc>
230
+ </Avx>
231
+ <Avx>
232
+ <GbrUid>
233
+ <txtName>FRANCE_GERMANY</txtName>
234
+ </GbrUid>
235
+ <codeType>FNT</codeType>
236
+ <geoLat>47.94361111N</geoLat>
237
+ <geoLong>007.59583333E</geoLong>
238
+ <codeDatum>WGE</codeDatum>
239
+ </Avx>
240
+ <Avx>
241
+ <codeType>GRC</codeType>
242
+ <geoLat>47.85916667N</geoLat>
243
+ <geoLong>007.56000000E</geoLong>
244
+ <codeDatum>WGE</codeDatum>
245
+ </Avx>
246
+ </Abd>
247
+ END
248
+ end
249
+ end
250
+ end
251
+
252
+ context "with two layers" do
253
+ subject do
254
+ AIXM::Factory.polygon_airspace.tap do |airspace|
255
+ airspace.layers << AIXM::Factory.layer
256
+ end
257
+ end
258
+
259
+ describe :to_xml do
260
+ it "builds correct OFMX" do
261
+ AIXM.ofmx!
262
+ subject.to_xml.must_equal <<~"END"
263
+ <!-- Airspace: [D] POLYGON AIRSPACE -->
264
+ <Ase source="LF|GEN|0.0 FACTORY|0|0" classLayers="2">
265
+ <AseUid region="LF">
266
+ <codeType>D</codeType>
267
+ <codeId>PA</codeId>
268
+ </AseUid>
269
+ <txtLocalType>POLYGON</txtLocalType>
270
+ <txtName>POLYGON AIRSPACE</txtName>
271
+ </Ase>
272
+ <Abd>
273
+ <AbdUid>
274
+ <AseUid region="LF">
275
+ <codeType>D</codeType>
276
+ <codeId>PA</codeId>
277
+ </AseUid>
278
+ </AbdUid>
279
+ <Avx>
280
+ <codeType>CWA</codeType>
281
+ <geoLat>47.85916667N</geoLat>
282
+ <geoLong>007.56000000E</geoLong>
283
+ <codeDatum>WGE</codeDatum>
284
+ <geoLatArc>47.90416667N</geoLatArc>
285
+ <geoLongArc>007.56333333E</geoLongArc>
286
+ </Avx>
287
+ <Avx>
288
+ <GbrUid>
289
+ <txtName>FRANCE_GERMANY</txtName>
290
+ </GbrUid>
291
+ <codeType>FNT</codeType>
292
+ <geoLat>47.94361111N</geoLat>
293
+ <geoLong>007.59583333E</geoLong>
294
+ <codeDatum>WGE</codeDatum>
295
+ </Avx>
296
+ <Avx>
297
+ <codeType>GRC</codeType>
298
+ <geoLat>47.85916667N</geoLat>
299
+ <geoLong>007.56000000E</geoLong>
300
+ <codeDatum>WGE</codeDatum>
301
+ </Avx>
302
+ </Abd>
303
+ <Ase>
304
+ <AseUid region="LF">
305
+ <codeType>CLASS</codeType>
306
+ <codeId>522496D6</codeId>
307
+ </AseUid>
308
+ <txtName>POLYGON AIRSPACE LAYER 1</txtName>
309
+ <codeClass>C</codeClass>
310
+ <codeDistVerUpper>STD</codeDistVerUpper>
311
+ <valDistVerUpper>65</valDistVerUpper>
312
+ <uomDistVerUpper>FL</uomDistVerUpper>
313
+ <codeDistVerLower>STD</codeDistVerLower>
314
+ <valDistVerLower>45</valDistVerLower>
315
+ <uomDistVerLower>FL</uomDistVerLower>
316
+ <codeDistVerMax>ALT</codeDistVerMax>
317
+ <valDistVerMax>6000</valDistVerMax>
318
+ <uomDistVerMax>FT</uomDistVerMax>
319
+ <codeDistVerMnm>HEI</codeDistVerMnm>
320
+ <valDistVerMnm>3000</valDistVerMnm>
321
+ <uomDistVerMnm>FT</uomDistVerMnm>
322
+ <Att>
323
+ <codeWorkHr>H24</codeWorkHr>
324
+ </Att>
325
+ <codeSelAvbl>Y</codeSelAvbl>
326
+ <txtRmk>airspace layer</txtRmk>
327
+ </Ase>
328
+ <Adg>
329
+ <AdgUid>
330
+ <AseUid region="LF">
331
+ <codeType>CLASS</codeType>
332
+ <codeId>522496D6</codeId>
333
+ </AseUid>
334
+ </AdgUid>
335
+ <AseUidSameExtent region="LF">
336
+ <codeType>D</codeType>
337
+ <codeId>PA</codeId>
338
+ </AseUidSameExtent>
339
+ </Adg>
340
+ <Ase>
341
+ <AseUid region="LF">
342
+ <codeType>CLASS</codeType>
343
+ <codeId>CAA85949</codeId>
344
+ </AseUid>
345
+ <txtName>POLYGON AIRSPACE LAYER 2</txtName>
346
+ <codeClass>C</codeClass>
347
+ <codeDistVerUpper>STD</codeDistVerUpper>
348
+ <valDistVerUpper>65</valDistVerUpper>
349
+ <uomDistVerUpper>FL</uomDistVerUpper>
350
+ <codeDistVerLower>STD</codeDistVerLower>
351
+ <valDistVerLower>45</valDistVerLower>
352
+ <uomDistVerLower>FL</uomDistVerLower>
353
+ <codeDistVerMax>ALT</codeDistVerMax>
354
+ <valDistVerMax>6000</valDistVerMax>
355
+ <uomDistVerMax>FT</uomDistVerMax>
356
+ <codeDistVerMnm>HEI</codeDistVerMnm>
357
+ <valDistVerMnm>3000</valDistVerMnm>
358
+ <uomDistVerMnm>FT</uomDistVerMnm>
359
+ <Att>
360
+ <codeWorkHr>H24</codeWorkHr>
361
+ </Att>
362
+ <codeSelAvbl>Y</codeSelAvbl>
363
+ <txtRmk>airspace layer</txtRmk>
364
+ </Ase>
365
+ <Adg>
366
+ <AdgUid>
367
+ <AseUid region="LF">
368
+ <codeType>CLASS</codeType>
369
+ <codeId>CAA85949</codeId>
370
+ </AseUid>
371
+ </AdgUid>
372
+ <AseUidSameExtent region="LF">
373
+ <codeType>D</codeType>
374
+ <codeId>PA</codeId>
375
+ </AseUidSameExtent>
376
+ </Adg>
377
+ END
378
+ end
379
+ end
380
+ end
381
+
259
382
  end