aixm 1.0.0 → 1.1.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 (58) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +43 -13
  4. data/README.md +31 -20
  5. data/lib/aixm/a.rb +89 -71
  6. data/lib/aixm/association.rb +37 -27
  7. data/lib/aixm/classes.rb +5 -2
  8. data/lib/aixm/{feature → component}/address.rb +12 -9
  9. data/lib/aixm/component/approach_lighting.rb +136 -0
  10. data/lib/aixm/component/fato.rb +58 -42
  11. data/lib/aixm/component/frequency.rb +2 -2
  12. data/lib/aixm/component/geometry/arc.rb +1 -1
  13. data/lib/aixm/component/geometry/border.rb +1 -1
  14. data/lib/aixm/component/geometry/circle.rb +3 -3
  15. data/lib/aixm/component/geometry/point.rb +1 -1
  16. data/lib/aixm/component/geometry/rhumb_line.rb +1 -1
  17. data/lib/aixm/component/geometry.rb +3 -2
  18. data/lib/aixm/component/helipad.rb +26 -36
  19. data/lib/aixm/component/layer.rb +5 -3
  20. data/lib/aixm/component/lighting.rb +5 -5
  21. data/lib/aixm/component/runway.rb +81 -52
  22. data/lib/aixm/component/service.rb +12 -3
  23. data/lib/aixm/component/surface.rb +12 -12
  24. data/lib/aixm/component/timetable.rb +2 -2
  25. data/lib/aixm/component/vasis.rb +105 -0
  26. data/lib/aixm/component/vertical_limit.rb +3 -3
  27. data/lib/aixm/component.rb +10 -0
  28. data/lib/aixm/config.rb +2 -0
  29. data/lib/aixm/d.rb +16 -15
  30. data/lib/aixm/document.rb +10 -1
  31. data/lib/aixm/f.rb +1 -1
  32. data/lib/aixm/feature/airport.rb +34 -10
  33. data/lib/aixm/feature/airspace.rb +3 -0
  34. data/lib/aixm/feature/navigational_aid/dme.rb +29 -10
  35. data/lib/aixm/feature/navigational_aid/marker.rb +2 -2
  36. data/lib/aixm/feature/navigational_aid/tacan.rb +3 -2
  37. data/lib/aixm/feature/navigational_aid/vor.rb +32 -13
  38. data/lib/aixm/feature/navigational_aid.rb +1 -1
  39. data/lib/aixm/feature/obstacle.rb +6 -6
  40. data/lib/aixm/feature/obstacle_group.rb +6 -2
  41. data/lib/aixm/feature/organisation.rb +1 -0
  42. data/lib/aixm/feature/unit.rb +2 -1
  43. data/lib/aixm/feature.rb +3 -0
  44. data/lib/aixm/memoize.rb +27 -11
  45. data/lib/aixm/p.rb +3 -2
  46. data/lib/aixm/payload_hash.rb +1 -1
  47. data/lib/aixm/r.rb +62 -0
  48. data/lib/aixm/refinements.rb +4 -4
  49. data/lib/aixm/version.rb +1 -1
  50. data/lib/aixm/w.rb +2 -1
  51. data/lib/aixm/xy.rb +1 -1
  52. data/lib/aixm/z.rb +5 -4
  53. data/lib/aixm.rb +10 -5
  54. data/schemas/ofmx/0.1/OFMX-DataTypes.xsd +6 -0
  55. data/schemas/ofmx/0.1/OFMX-Snapshot.xsd +5 -0
  56. data.tar.gz.sig +0 -0
  57. metadata +8 -4
  58. metadata.gz.sig +0 -0
@@ -1,7 +1,7 @@
1
1
  using AIXM::Refinements
2
2
 
3
3
  module AIXM
4
- module Component
4
+ class Component
5
5
 
6
6
  # Runways are landing and takeoff strips for forward propelled aircraft.
7
7
  #
@@ -16,16 +16,19 @@ module AIXM
16
16
  # runway = AIXM.runway(
17
17
  # name: String
18
18
  # )
19
- # runway.length = AIXM.d or nil # must use same unit as width
20
- # runway.width = AIXM.d or nil # must use same unit as length
19
+ # runway.dimensions = AIXM.r or nil
21
20
  # runway.surface = AIXM.surface
21
+ # runway.marking = String or nil
22
22
  # runway.status = STATUSES or nil
23
23
  # runway.remarks = String or nil
24
- # runway.forth.name = AIXM.a[precision=2] # preset based on the runway name
25
- # runway.forth.geographic_orientation = AIXM.a[precision=3] or nil
24
+ # runway.forth.name = AIXM.a # preset based on the runway name
25
+ # runway.forth.geographic_bearing = AIXM.a or nil
26
26
  # runway.forth.xy = AIXM.xy
27
- # runway.forth.z = AIXM.z or nil
27
+ # runway.forth.z = AIXM.z or nil # highest point of the TDZ
28
28
  # runway.forth.displaced_threshold = AIXM.xy or AIXM.d or nil
29
+ # runway.forth.vasis = AIXM.vasis or nil (default: unspecified VASIS)
30
+ # runway.forth.add_lighting = AIXM.lighting
31
+ # runway.forth.add_approach_lighting = AIXM.approach_lighting
29
32
  # runway.forth.vfr_pattern = VFR_PATTERNS or nil
30
33
  # runway.forth.remarks = String or nil
31
34
  #
@@ -33,19 +36,19 @@ module AIXM
33
36
  # runway = AIXM.runway(name: '16L/34R')
34
37
  # runway.name # => '16L/34R'
35
38
  # runway.forth.name.to_s = '16L'
36
- # runway.forth.geographic_orientation = 165
39
+ # runway.forth.geographic_bearing = 165
37
40
  # runway.back.name.to_s = '34R'
38
- # runway.back.geographic_orientation = 345
41
+ # runway.back.geographic_bearing = 345
39
42
  #
40
43
  # @example Unidirectional runway:
41
44
  # runway = AIXM.runway(name: '16L')
42
45
  # runway.name # => '16L'
43
46
  # runway.forth.name.to_s = '16L'
44
- # runway.forth.geographic_orientation = 165
47
+ # runway.forth.geographic_bearing = 165
45
48
  # runway.back = nil
46
49
  #
47
50
  # @see https://gitlab.com/openflightmaps/ofmx/wikis/Airport#rwy-runway
48
- class Runway
51
+ class Runway < Component
49
52
  include AIXM::Association
50
53
  include AIXM::Memoize
51
54
 
@@ -56,20 +59,29 @@ module AIXM
56
59
  FAILAID: :visual_aids_failure, # failure or irregular operation of visual aids
57
60
  SPOWER: :secondary_power, # secondary power supply in operation
58
61
  OTHER: :other # specify in remarks
59
- }
62
+ }.freeze
60
63
 
61
64
  # @!method forth
62
65
  # @return [AIXM::Component::Runway::Direction] main direction
66
+ #
63
67
  # @!method forth=(forth)
64
68
  # @param forth [AIXM::Component::Runway::Direction]
65
69
  has_one :forth, accept: 'AIXM::Component::Runway::Direction'
66
70
 
67
71
  # @!method back
68
72
  # @return [AIXM::Component::Runway::Direction, nil] reverse direction
73
+ #
69
74
  # @!method back=(back)
70
75
  # @param back [AIXM::Component::Runway::Direction, nil]
71
76
  has_one :back, accept: 'AIXM::Component::Runway::Direction', allow_nil: true
72
77
 
78
+ # @!method surface
79
+ # @return [AIXM::Component::Surface] surface of the runway
80
+ #
81
+ # @!method surface=(surface)
82
+ # @param surface [AIXM::Component::Surface]
83
+ has_one :surface, accept: 'AIXM::Component::Surface'
84
+
73
85
  # @!method airport
74
86
  # @return [AIXM::Feature::Airport] airport the runway belongs to
75
87
  belongs_to :airport
@@ -77,14 +89,11 @@ module AIXM
77
89
  # @return [String] full name of runway (e.g. "12/30" or "16L/34R")
78
90
  attr_reader :name
79
91
 
80
- # @return [AIXM::D, nil] length
81
- attr_reader :length
92
+ # @return [AIXM::R, nil] dimensions
93
+ attr_reader :dimensions
82
94
 
83
- # @return [AIXM::D, nil] width
84
- attr_reader :width
85
-
86
- # @return [AIXM::Component::Surface] surface of the runway
87
- attr_reader :surface
95
+ # @return [String, nil] markings
96
+ attr_reader :marking
88
97
 
89
98
  # @return [Symbol, nil] status of the runway (see {STATUSES}) or +nil+ for normal operation
90
99
  attr_reader :status
@@ -99,7 +108,7 @@ module AIXM
99
108
  self.back = Direction.new(name: AIXM.a(back_name)) if back_name
100
109
  fail(ArgumentError, "invalid name") unless !back || back.name.inverse_of?(@forth.name)
101
110
  end
102
- @surface = AIXM.surface
111
+ self.surface = AIXM.surface
103
112
  end
104
113
 
105
114
  # @return [String]
@@ -112,20 +121,13 @@ module AIXM
112
121
  @name = value.uptrans
113
122
  end
114
123
 
115
- def length=(value)
116
- @length = if value
117
- fail(ArgumentError, "invalid length") unless value.is_a?(AIXM::D) && value.dist > 0
118
- fail(ArgumentError, "invalid length unit") if width && width.unit != value.unit
119
- value
120
- end
124
+ def dimensions=(value)
125
+ fail(ArgumentError, "invalid dimensions") unless value.nil? || value.is_a?(AIXM::R)
126
+ @dimensions = value
121
127
  end
122
128
 
123
- def width=(value)
124
- @width = if value
125
- fail(ArgumentError, "invalid width") unless value.is_a?(AIXM::D) && value.dist > 0
126
- fail(ArgumentError, "invalid width unit") if length && length.unit != value.unit
127
- value
128
- end
129
+ def marking=(value)
130
+ @marking = value&.to_s
129
131
  end
130
132
 
131
133
  def status=(value)
@@ -151,14 +153,16 @@ module AIXM
151
153
  builder = Builder::XmlMarkup.new(indent: 2)
152
154
  builder.Rwy do |rwy|
153
155
  rwy << to_uid.indent(2)
154
- rwy.valLen(length.dist.trim) if length
155
- rwy.valWid(width.dist.trim) if width
156
- rwy.uomDimRwy(length.unit.to_s.upcase) if length
157
- rwy.uomDimRwy(width.unit.to_s.upcase) if width && !length
156
+ if dimensions
157
+ rwy.valLen(dimensions.length.to_m.dim.trim)
158
+ rwy.valWid(dimensions.width.to_m.dim.trim)
159
+ rwy.uomDimRwy('M')
160
+ end
158
161
  unless (xml = surface.to_xml).empty?
159
162
  rwy << xml.indent(2)
160
163
  end
161
164
  rwy.codeSts(STATUSES.key(status).to_s) if status
165
+ rwy.txtMarking(marking) if marking
162
166
  rwy.txtRmk(remarks) if remarks
163
167
  end
164
168
  %i(@forth @back).each do |direction|
@@ -181,15 +185,24 @@ module AIXM
181
185
  L: :left,
182
186
  R: :right,
183
187
  E: :left_or_right
184
- }
188
+ }.freeze
185
189
 
186
190
  # @!method lightings
187
191
  # @return [Array<AIXM::Component::Lighting>] installed lighting systems
192
+ #
188
193
  # @!method add_lighting(lighting)
189
194
  # @param lighting [AIXM::Component::Lighting]
190
195
  # @return [self]
191
196
  has_many :lightings, as: :lightable
192
197
 
198
+ # @!method approach_lightings
199
+ # @return [Array<AIXM::Component::ApproachLighting>] installed approach lighting systems
200
+ #
201
+ # @!method add_approach_lighting(approach_lighting)
202
+ # @param approach_lighting [AIXM::Component::ApproachLighting]
203
+ # @return [self]
204
+ has_many :approach_lightings, as: :approach_lightable
205
+
193
206
  # @!method runway
194
207
  # @return [AIXM::Component::Runway] runway the runway direction is further describing
195
208
  belongs_to :runway, readonly: true
@@ -197,8 +210,8 @@ module AIXM
197
210
  # @return [AIXM::A] partial name of runway (e.g. "12" or "16L")
198
211
  attr_reader :name
199
212
 
200
- # @return [AIXM::A, nil] geographic orientation (true bearing) in degrees
201
- attr_reader :geographic_orientation
213
+ # @return [AIXM::A, nil] (true) geographic bearing in degrees
214
+ attr_reader :geographic_bearing
202
215
 
203
216
  # @return [AIXM::XY] beginning point (middle of the runway width)
204
217
  attr_reader :xy
@@ -211,6 +224,10 @@ module AIXM
211
224
  # point
212
225
  attr_reader :displaced_threshold
213
226
 
227
+ # @return [AIXM::Component::VASIS, nil] visual approach slope indicator
228
+ # system
229
+ attr_reader :vasis
230
+
214
231
  # @return [Symbol, nil] direction of the VFR flight pattern (see {VFR_PATTERNS})
215
232
  attr_reader :vfr_pattern
216
233
 
@@ -219,11 +236,12 @@ module AIXM
219
236
 
220
237
  def initialize(name:)
221
238
  self.name = name
239
+ self.vasis = AIXM.vasis
222
240
  end
223
241
 
224
242
  # @return [String]
225
243
  def inspect
226
- %Q(#<#{self.class} airport=#{runway&.airport&.id.inspect} name=#{name.inspect}>)
244
+ %Q(#<#{self.class} airport=#{runway&.airport&.id.inspect} name=#{name.to_s(:runway).inspect}>)
227
245
  end
228
246
 
229
247
  def name=(value)
@@ -231,10 +249,10 @@ module AIXM
231
249
  @name = value
232
250
  end
233
251
 
234
- def geographic_orientation=(value)
235
- return @geographic_orientation = nil if value.nil?
236
- fail(ArgumentError, "invalid geographic orientation") unless value.is_a? AIXM::A
237
- @geographic_orientation = value
252
+ def geographic_bearing=(value)
253
+ return @geographic_bearing = nil if value.nil?
254
+ fail(ArgumentError, "invalid geographic bearing") unless value.is_a? AIXM::A
255
+ @geographic_bearing = value
238
256
  end
239
257
 
240
258
  def xy=(value)
@@ -252,7 +270,7 @@ module AIXM
252
270
  when AIXM::XY
253
271
  @displaced_threshold = @xy.distance(value)
254
272
  when AIXM::D
255
- fail(ArgumentError, "invalid displaced threshold") unless value.dist > 0
273
+ fail(ArgumentError, "invalid displaced threshold") unless value.dim > 0
256
274
  @displaced_threshold = value
257
275
  when NilClass
258
276
  @displaced_threshold = nil
@@ -261,6 +279,11 @@ module AIXM
261
279
  end
262
280
  end
263
281
 
282
+ def vasis=(value)
283
+ fail(ArgumentError, "invalid vasis") unless value.nil? || value.is_a?(AIXM::Component::VASIS)
284
+ @vasis = value
285
+ end
286
+
264
287
  def vfr_pattern=(value)
265
288
  @vfr_pattern = value.nil? ? nil : (VFR_PATTERNS.lookup(value.to_s.to_sym, nil) || fail(ArgumentError, "invalid VFR pattern"))
266
289
  end
@@ -269,10 +292,10 @@ module AIXM
269
292
  @remarks = value&.to_s
270
293
  end
271
294
 
272
- # @return [AIXM::A] magnetic orientation (magnetic bearing) in degrees
273
- def magnetic_orientation
274
- if geographic_orientation && runway.airport.declination
275
- geographic_orientation - runway.airport.declination
295
+ # @return [AIXM::A] magnetic bearing in degrees
296
+ def magnetic_bearing
297
+ if geographic_bearing && runway.airport.declination
298
+ geographic_bearing - runway.airport.declination
276
299
  end
277
300
  end
278
301
 
@@ -281,7 +304,7 @@ module AIXM
281
304
  builder = Builder::XmlMarkup.new(indent: 2)
282
305
  builder.RdnUid do |rdn_uid|
283
306
  rdn_uid << runway.to_uid.indent(2)
284
- rdn_uid.txtDesig(name)
307
+ rdn_uid.txtDesig(name.to_s(:runway))
285
308
  end
286
309
  end
287
310
  memoize :to_uid
@@ -293,12 +316,15 @@ module AIXM
293
316
  rdn << to_uid.indent(2)
294
317
  rdn.geoLat(xy.lat(AIXM.schema))
295
318
  rdn.geoLong(xy.long(AIXM.schema))
296
- rdn.valTrueBrg(geographic_orientation) if geographic_orientation
297
- rdn.valMagBrg(magnetic_orientation) if magnetic_orientation
319
+ rdn.valTrueBrg(geographic_bearing.to_s(:bearing)) if geographic_bearing
320
+ rdn.valMagBrg(magnetic_bearing.to_s(:bearing)) if magnetic_bearing
298
321
  if z
299
322
  rdn.valElevTdz(z.alt)
300
323
  rdn.uomElevTdz(z.unit.upcase.to_s)
301
324
  end
325
+ if vasis
326
+ rdn << vasis.to_xml.indent(2)
327
+ end
302
328
  rdn.codeVfrPattern(VFR_PATTERNS.key(vfr_pattern).to_s) if vfr_pattern
303
329
  rdn.txtRmk(remarks) if remarks
304
330
  end
@@ -309,7 +335,7 @@ module AIXM
309
335
  rdd_uid.codeType('DPLM')
310
336
  rdd_uid.codeDayPeriod('A')
311
337
  end
312
- rdd.valDist(displaced_threshold.dist.trim)
338
+ rdd.valDist(displaced_threshold.dim.trim)
313
339
  rdd.uomDist(displaced_threshold.unit.to_s.upcase)
314
340
  rdd.txtRmk(remarks) if remarks
315
341
  end
@@ -317,6 +343,9 @@ module AIXM
317
343
  lightings.each do |lighting|
318
344
  builder << lighting.to_xml(as: :Rls)
319
345
  end
346
+ approach_lightings.each do |approach_lighting|
347
+ builder << approach_lighting.to_xml(as: :Rda)
348
+ end
320
349
  builder.target!
321
350
  end
322
351
  end
@@ -1,7 +1,7 @@
1
1
  using AIXM::Refinements
2
2
 
3
3
  module AIXM
4
- module Component
4
+ class Component
5
5
 
6
6
  # Service provided by a unit.
7
7
  #
@@ -14,7 +14,7 @@ module AIXM
14
14
  # service.add_frequency(AIXM.frequency)
15
15
  #
16
16
  # @see https://gitlab.com/openflightmaps/ofmx/wikis/Organisation#ser-service
17
- class Service
17
+ class Service < Component
18
18
  include AIXM::Association
19
19
  include AIXM::Memoize
20
20
 
@@ -73,7 +73,7 @@ module AIXM
73
73
  TWR: :aerodrome_control_tower_service,
74
74
  UAC: :upper_area_control_service,
75
75
  UDF: :uhf_direction_finding_service,
76
- VDF: :vhf_direction_finding_service,
76
+ VDF: :vdf_direction_finding_service,
77
77
  VOLMET: :volmet_service,
78
78
  VOT: :vor_test_facility,
79
79
  OTHER: :other # specify in remarks
@@ -129,6 +129,7 @@ module AIXM
129
129
 
130
130
  # @!method frequencies
131
131
  # @return [Array<AIXM::Component::Frequency>] frequencies used by this service
132
+ #
132
133
  # @!method add_frequency(frequency)
133
134
  # @param frequency [AIXM::Component::Frequency]
134
135
  has_many :frequencies
@@ -137,6 +138,14 @@ module AIXM
137
138
  # @return [AIXM::Feature::Unit] unit providing this service
138
139
  belongs_to :unit
139
140
 
141
+ # @!method airport
142
+ # @return [AIXM::Feature::Airport] airport this service is provided at
143
+ belongs_to :airport
144
+
145
+ # @!method airspace
146
+ # @return [AIXM::Feature::Airspace] airspace this service is provided in
147
+ belongs_to :airspace
148
+
140
149
  # @!method layer
141
150
  # @return [AIXM::Component::Layer] airspace layer this service is provided within
142
151
  belongs_to :layer
@@ -1,16 +1,15 @@
1
1
  using AIXM::Refinements
2
2
 
3
3
  module AIXM
4
- module Component
4
+ class Component
5
5
 
6
6
  # Surface of a runway, helipad etc
7
7
  #
8
8
  # ===Cheat Sheet in Pseudo Code:
9
- # surface = AIXM.surface(
10
- # composition: COMPOSITIONS or nil
11
- # preparation: PREPARATIONS or nil
12
- # condition: CONDITIONS or nil
13
- # )
9
+ # surface = AIXM.surface
10
+ # surface.composition: COMPOSITIONS or nil
11
+ # surface.preparation: PREPARATIONS or nil
12
+ # surface.condition: CONDITIONS or nil
14
13
  # surface.pcn = String or nil
15
14
  # surface.siwl_weight = AIXM.w
16
15
  # surface.siwl_tire_pressure = AIXM.p
@@ -20,9 +19,10 @@ module AIXM
20
19
  # ===Constants:
21
20
  # * +AIXM::PCN_RE+ - regular expression to match PCN notations
22
21
  #
23
- #
24
22
  # @see https://gitlab.com/openflightmaps/ofmx/wikis/Airport#rwy-runway
25
- class Surface
23
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Airport#tla-helipad-tlof
24
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Airport#fto-fato
25
+ class Surface < Component
26
26
  COMPOSITIONS = {
27
27
  ASPH: :asphalt,
28
28
  BITUM: :bitumen, # dug up, bound and rolled ground
@@ -38,7 +38,7 @@ module AIXM
38
38
  SNOW: :snow,
39
39
  WATER: :water,
40
40
  OTHER: :other # specify in remarks
41
- }
41
+ }.freeze
42
42
 
43
43
  PREPARATIONS = {
44
44
  AFSC: :aggregate_friction_seal_coat,
@@ -50,14 +50,14 @@ module AIXM
50
50
  RFSC: :rubberized_friction_seal_coat,
51
51
  ROLLED: :rolled,
52
52
  OTHER: :other
53
- }
53
+ }.freeze
54
54
 
55
55
  CONDITIONS = {
56
56
  GOOD: :good,
57
57
  FAIR: :fair,
58
58
  POOR: :poor,
59
59
  OTHER: :other
60
- }
60
+ }.freeze
61
61
 
62
62
  # @return [Symbol, nil] composition of the surface (see {COMPOSITIONS})
63
63
  attr_reader :composition
@@ -103,7 +103,7 @@ module AIXM
103
103
 
104
104
  # @return [String, nil] pavement classification number (e.g. "59/F/A/W/T")
105
105
  def pcn
106
- @pcn.none? ? nil : @pcn.values.join("/")
106
+ @pcn.none? ? nil : @pcn.values.join("/".freeze)
107
107
  end
108
108
 
109
109
  def pcn=(value)
@@ -1,7 +1,7 @@
1
1
  using AIXM::Refinements
2
2
 
3
3
  module AIXM
4
- module Component
4
+ class Component
5
5
 
6
6
  # Timetables define activity time windows.
7
7
  #
@@ -18,7 +18,7 @@ module AIXM
18
18
  # * +AIXM::H_RE+ - pattern matching working hour codes
19
19
  #
20
20
  # @see https://gitlab.com/openflightmaps/ofmx/wikis/Timetable#predefined-timetable
21
- class Timetable
21
+ class Timetable < Component
22
22
  CODES = {
23
23
  H24: :continuous, # all day and all night
24
24
  HJ: :sunrise_to_sunset, # all day
@@ -0,0 +1,105 @@
1
+ using AIXM::Refinements
2
+
3
+ module AIXM
4
+ class Component
5
+
6
+ # Visual approach slope indicator system
7
+ #
8
+ # ===Cheat Sheet in Pseudo Code:
9
+ # vasis = AIXM.vasis
10
+ # vasis.type = TYPES or nil
11
+ # vasis.position = POSITIONS or nil
12
+ # vasis.boxes = Integer or nil
13
+ # vasis.portable = true or false or nil (means: unknown, default)
14
+ # vasis.slope_angle = AIXM.a or nil
15
+ # vasis.meht = AIXM.d or nil
16
+ #
17
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Airport#rdn-runway-direction
18
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Airport#fdn-fato-direction
19
+ class VASIS < Component
20
+ TYPES = {
21
+ PAPI: :precision_api,
22
+ APAPI: :abbreviated_precision_api,
23
+ HAPI: :helicopter_api,
24
+ VASIS: :vasis,
25
+ AVASIS: :abbreviated_vasis,
26
+ TVASIS: :t_shaped_vasis,
27
+ ATVASIS: :abbreviated_t_shaped_vasis,
28
+ OTHER: :other # specify in remarks
29
+ }.freeze
30
+
31
+ POSITIONS = {
32
+ LEFT: :left,
33
+ RIGHT: :right,
34
+ BOTH: :left_and_right,
35
+ OTHER: :other # specify in remarks
36
+ }.freeze
37
+
38
+ # @return [Symbol, nil] type of VASIS (see {TYPES})
39
+ attr_reader :type
40
+
41
+ # @return [Symbol, nil] position relative to the runway (see {POSITIONS})
42
+ attr_reader :position
43
+
44
+ # @return [Integer, nil] number of boxes
45
+ attr_reader :boxes
46
+
47
+ # @return [Boolean, nil] whether the VASIS is portable
48
+ attr_reader :portable
49
+
50
+ # @return [AIXM::A, nil] appropriate approach slope angle
51
+ attr_reader :slope_angle
52
+
53
+ # @return [AIXM::Z, nil] minimum eye height over threshold (MEHT)
54
+ attr_reader :meht
55
+
56
+ # @return [String]
57
+ def inspect
58
+ %Q(#<#{self.class} type=#{type.inspect}>)
59
+ end
60
+
61
+ def type=(value)
62
+ @type = value.nil? ? nil : TYPES.lookup(value.to_s.to_sym, nil) || fail(ArgumentError, "invalid type")
63
+ end
64
+
65
+ def position=(value)
66
+ @position = value.nil? ? nil : POSITIONS.lookup(value.to_s.to_sym, nil) || fail(ArgumentError, "invalid position")
67
+ end
68
+
69
+ def boxes=(value)
70
+ fail(ArgumentError, "invalid boxes count") unless value.nil? || (value.is_a?(Integer) && value > 0)
71
+ @boxes = value
72
+ end
73
+
74
+ def portable=(value)
75
+ fail(ArgumentError, "invalid portable") unless [true, false, nil].include? value
76
+ @portable = value
77
+ end
78
+
79
+ def slope_angle=(value)
80
+ fail(ArgumentError, "invalid slope angle") unless value.nil? || (value.is_a?(AIXM::A) && value.deg <= 90)
81
+ @slope_angle = value
82
+ end
83
+
84
+ def meht=(value)
85
+ fail(ArgumentError, "invalid MEHT") unless value.nil? || (value.is_a?(AIXM::Z) && value.qfe?)
86
+ @meht = value
87
+ end
88
+
89
+ # @return [String] AIXM or OFMX markup
90
+ def to_xml
91
+ builder = Builder::XmlMarkup.new(indent: true)
92
+ builder.codeTypeVasis(TYPES.key(type).to_s) if type
93
+ builder.codePsnVasis(POSITIONS.key(position).to_s) if position
94
+ builder.noBoxVasis(boxes.to_s) if boxes
95
+ builder.codePortableVasis(portable ? 'Y' : 'N') unless portable.nil?
96
+ builder.valSlopeAngleGpVasis(slope_angle.to_f) if slope_angle
97
+ if meht
98
+ builder.valMeht(meht.alt.to_s)
99
+ builder.uomMeht('FT')
100
+ end
101
+ builder.target!
102
+ end
103
+ end
104
+ end
105
+ end
@@ -1,7 +1,7 @@
1
1
  using AIXM::Refinements
2
2
 
3
3
  module AIXM
4
- module Component
4
+ class Component
5
5
 
6
6
  # Vertical limit defines a 3D airspace vertically. It is often noted in
7
7
  # AIP as follows:
@@ -25,7 +25,7 @@ module AIXM
25
25
  # * +AIXM::UNLIMITED+ - no upper limit expressed as "FL 999"
26
26
  #
27
27
  # @see https://gitlab.com/openflightmaps/ofmx/wikis/Airspace#ase-airspace
28
- class VerticalLimit
28
+ class VerticalLimit < Component
29
29
  include AIXM::Association
30
30
 
31
31
  # @api private
@@ -57,7 +57,7 @@ module AIXM
57
57
  # @return [String]
58
58
  def inspect
59
59
  payload = %i(upper_z max_z lower_z min_z).map { %Q(#{_1}="#{send(_1)}") if send(_1) }.compact
60
- %Q(#<#{self.class} #{payload.join(' ')}>)
60
+ %Q(#<#{self.class} #{payload.join(' '.freeze)}>)
61
61
  end
62
62
 
63
63
  def upper_z=(value)
@@ -0,0 +1,10 @@
1
+ module AIXM
2
+
3
+ # @abstract
4
+ class Component
5
+
6
+ # @return [Object] freely usable e.g. to find_by foreign keys
7
+ attr_accessor :meta
8
+
9
+ end
10
+ end
data/lib/aixm/config.rb CHANGED
@@ -48,6 +48,7 @@ module AIXM
48
48
  #
49
49
  # @!method aixm!
50
50
  # @!method ofmx!
51
+ #
51
52
  # @return [Symbol] schema key
52
53
  SCHEMAS.each_key do |schema|
53
54
  define_method("#{schema}!") { @@config.schema = schema }
@@ -63,6 +64,7 @@ module AIXM
63
64
  #
64
65
  # @!method aixm?
65
66
  # @!method ofmx?
67
+ #
66
68
  # @return [Boolean]
67
69
  SCHEMAS.each_key do |schema|
68
70
  define_method("#{schema}?") { @@config.schema == schema }
data/lib/aixm/d.rb CHANGED
@@ -2,7 +2,7 @@ using AIXM::Refinements
2
2
 
3
3
  module AIXM
4
4
 
5
- # Distance or length
5
+ # Dimension, distance or length
6
6
  #
7
7
  # @example
8
8
  # AIXM.d(123, :m)
@@ -18,17 +18,17 @@ module AIXM
18
18
  }.freeze
19
19
 
20
20
  # @!method zero?
21
- # @return [Boolean] whether distance is zero
22
- def_delegator :@dist, :zero?
21
+ # @return [Boolean] whether dimension is zero
22
+ def_delegator :@dim, :zero?
23
23
 
24
- # @return [Float] distance
25
- attr_reader :dist
24
+ # @return [Float] dimension
25
+ attr_reader :dim
26
26
 
27
27
  # @return [Symbol] unit (see {UNITS})
28
28
  attr_reader :unit
29
29
 
30
- def initialize(dist, unit)
31
- self.dist, self.unit = dist, unit
30
+ def initialize(dim, unit)
31
+ self.dim, self.unit = dim, unit
32
32
  end
33
33
 
34
34
  # @return [String]
@@ -36,14 +36,14 @@ module AIXM
36
36
  %Q(#<#{self.class} #{to_s}>)
37
37
  end
38
38
 
39
- # @return [String] human readable representation (e.g. "123 m")
39
+ # @return [String] human readable representation (e.g. "123.0 m")
40
40
  def to_s
41
- [dist, unit].join(' ')
41
+ [dim, unit].join(' '.freeze)
42
42
  end
43
43
 
44
- def dist=(value)
45
- fail(ArgumentError, "invalid dist") unless value.is_a?(Numeric) && value >= 0
46
- @dist = value.to_f
44
+ def dim=(value)
45
+ fail(ArgumentError, "invalid dim") unless value.is_a?(Numeric) && value >= 0
46
+ @dim = value.to_f
47
47
  end
48
48
 
49
49
  def unit=(value)
@@ -56,18 +56,19 @@ module AIXM
56
56
  # @!method to_km
57
57
  # @!method to_m
58
58
  # @!method to_nm
59
- # @return [AIXM::D] convert distance
59
+ #
60
+ # @return [AIXM::D] convert dimension
60
61
  UNITS.each_key do |target_unit|
61
62
  define_method "to_#{target_unit}" do
62
63
  return self if unit == target_unit
63
- self.class.new((dist * UNITS[unit][target_unit]).round(8), target_unit)
64
+ self.class.new((dim * UNITS[unit][target_unit]).round(8), target_unit)
64
65
  end
65
66
  end
66
67
 
67
68
  # @see Object#<=>
68
69
  # @return [Integer]
69
70
  def <=>(other)
70
- dist <=> other.send(:"to_#{unit}").dist
71
+ dim <=> other.send(:"to_#{unit}").dim
71
72
  end
72
73
 
73
74
  # @see Object#==