aixm 0.3.5 → 0.3.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: efe8ab0dda077e481484589c0e2943b6417cefb5386e16d872692161b46add3f
4
- data.tar.gz: f7fb02c428760481b9159d81c93baec8e4e2d1ef1267e1884f02422d44af7b9b
3
+ metadata.gz: d13df653e543e46983fa5d15d841afae85142eb249e0272ecfa9e440047f8998
4
+ data.tar.gz: 988b5d2736771137ba4764b320c886d456576ecdea0c1115d3dde4d9ab33dbb4
5
5
  SHA512:
6
- metadata.gz: 1dcee1f3e19c58ada30b66bfa48201bae02a382bb6a8746b6f144de6c3280ef58ce2e6b6dc25ba5343ff9cfc9589e81e2217573bdfce642623f73530bf626e56
7
- data.tar.gz: 1cf3f783adfa14e2af626d97810c8bfbd3e776718a207e70343ed1bf1f2f5ccbaa52142aa5ab32727af99a8c07733d056817536f3157b171878c0d03b9363208
6
+ metadata.gz: 86b872de155b94fd83a331b7935e4496a8558fdff94e60d64fcceb9973e1ce21acf7f08a52e5955f03352990f0a818b3844fda3ad598e394bcf83aabb7b5dd0e
7
+ data.tar.gz: da0e8ab2566abb6530085c632a4e84bc7628ec2aa42cc93566c0b35c2768657f7c42764848b9a0b5149d15617aa25990bb0c5a7a368f39f67cc19f17d702ebc4
data/.gitignore CHANGED
@@ -1,5 +1,5 @@
1
1
  .DS_Store
2
- Gemfile.lock
2
+ gems.locked
3
3
  pkg/*
4
4
  *.gem
5
5
  .bundle
@@ -2,3 +2,7 @@
2
2
  language: ruby
3
3
  rvm:
4
4
  - 2.6.3
5
+ before_install:
6
+ - gem update --system
7
+ - gem install bundler
8
+ - bundle install
@@ -1,3 +1,18 @@
1
+ ## 0.3.6
2
+
3
+ #### Additions
4
+ * `AIXM::Component::FATO`
5
+ * `AIXM::Component::Helipad#helicopter_class` and `AIXM::Component::Helipad#marking`
6
+ * `AIXM::XY#seconds?` to detect possibly rounded or estimated coordinates
7
+ * `AIXM::Features::Airport#operator`
8
+ * `AIXM::W` (weight)
9
+ * `AIXM::P` (pressure)
10
+ * `AIXM::Component::Lighting` for use with runways, helipads and FATOs
11
+ * Surface details `siwl_weight`, `siwl_tire_pressure` and `auw_weight`
12
+
13
+ #### Changes
14
+ * Generate `Airport#id` from region and `Airport#name`
15
+
1
16
  ## 0.3.5
2
17
 
3
18
  #### Additions
data/README.md CHANGED
@@ -1,14 +1,13 @@
1
1
  [![Version](https://img.shields.io/gem/v/aixm.svg?style=flat)](https://rubygems.org/gems/aixm)
2
2
  [![Continuous Integration](https://img.shields.io/travis/svoop/aixm/master.svg?style=flat)](https://travis-ci.org/svoop/aixm)
3
- [![Code Climate](https://img.shields.io/codeclimate/github/svoop/aixm.svg?style=flat)](https://codeclimate.com/github/svoop/aixm)
4
- [![Gitter](https://img.shields.io/gitter/room/svoop/aixm.svg?style=flat)](https://gitter.im/svoop/aixm)
3
+ [![Code Climate](https://img.shields.io/codeclimate/maintainability/svoop/aixm.svg?style=flat)](https://codeclimate.com/github/svoop/aixm/)
5
4
  [![Donorbox](https://img.shields.io/badge/donate-on_donorbox-yellow.svg)](https://donorbox.org/bitcetera)
6
5
 
7
6
  # AIXM
8
7
 
9
8
  Partial implementation of the [Aeronautical Information Exchange Model (AIXM 4.5)](http://aixm.aero) and it's dialect [Open FlightMaps eXchange format (OFMX 0)](https://github.com/openflightmaps/ofmx) for Ruby.
10
9
 
11
- For now, only the parts needed to automize the AIP import of [Open Flightmaps](https://openflightmaps.org) are part of this gem. Most notably, the gem is only a builder for snapshot files and does not parse them.
10
+ For now, only the parts needed to automize the AIP import of [open flightmaps](https://openflightmaps.org) are part of this gem. Most notably, the gem is only a builder for snapshot files and does not parse them.
12
11
 
13
12
  * [Homepage](https://github.com/svoop/aixm)
14
13
  * [API](http://www.rubydoc.info/gems/aixm)
@@ -105,6 +104,7 @@ AIXM.schema(:version) # => 0
105
104
  * [Circle](http://www.rubydoc.info/gems/aixm/AIXM/Component/Circle.html)
106
105
  * [Runway](http://www.rubydoc.info/gems/aixm/AIXM/Component/Runway.html)
107
106
  * [Helipad](http://www.rubydoc.info/gems/aixm/AIXM/Component/Helipad.html)
107
+ * [FATO](http://www.rubydoc.info/gems/aixm/AIXM/Component/FATO.html)
108
108
  * [Surface](http://www.rubydoc.info/gems/aixm/AIXM/Component/Surface.html)
109
109
  * [Layer](http://www.rubydoc.info/gems/aixm/AIXM/Component/Layer.html)
110
110
  * [Vertical limits](http://www.rubydoc.info/gems/aixm/AIXM/Component/VerticalLimits.html)
@@ -118,13 +118,13 @@ By `using AIXM::Refinements` you get a few handy [extensions to Ruby core classe
118
118
 
119
119
  ### AIXM
120
120
  * [AIXM](http://aixm.aero)
121
- * [AICM 4.5 Documentation](https://openflightmaps.github.io/ofmx/aixm/4.5/manual/aicm/)
122
- * [AIXM 4.5 Specification](http://aixm.aero/document/aixm-45-specification)
121
+ * [AICM 4.5 documentation](https://openflightmaps.github.io/ofmx/aixm/4.5/manual/aicm/)
122
+ * [AIXM 4.5 specification](http://aixm.aero/document/aixm-45-specification)
123
123
 
124
124
  ### OFMX
125
125
  * [OFMX](https://github.com/openflightmaps/ofmx)
126
- * [OFMX Documentation](https://github.com/openflightmaps/ofmx/wiki)
127
- * [Open Flightmaps](https://openflightmaps.org)
126
+ * [OFMX documentation](https://github.com/openflightmaps/ofmx/wiki)
127
+ * [open flightmaps](https://openflightmaps.org)
128
128
 
129
129
  ## Tests
130
130
 
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.add_development_dependency 'minitest-matchers'
28
28
  spec.add_development_dependency 'guard'
29
29
  spec.add_development_dependency 'guard-minitest'
30
+ spec.add_development_dependency 'yard'
30
31
 
31
32
  spec.add_runtime_dependency 'builder', '~> 3'
32
33
  spec.add_runtime_dependency 'nokogiri', '~> 1'
File without changes
@@ -19,6 +19,8 @@ require_relative 'aixm/z'
19
19
  require_relative 'aixm/d'
20
20
  require_relative 'aixm/f'
21
21
  require_relative 'aixm/a'
22
+ require_relative 'aixm/w'
23
+ require_relative 'aixm/p'
22
24
 
23
25
  require_relative 'aixm/component'
24
26
  require_relative 'aixm/component/frequency'
@@ -31,8 +33,10 @@ require_relative 'aixm/component/layer'
31
33
  require_relative 'aixm/component/vertical_limits'
32
34
  require_relative 'aixm/component/timetable'
33
35
  require_relative 'aixm/component/runway'
36
+ require_relative 'aixm/component/fato'
34
37
  require_relative 'aixm/component/helipad'
35
38
  require_relative 'aixm/component/surface'
39
+ require_relative 'aixm/component/lighting'
36
40
 
37
41
  require_relative 'aixm/feature'
38
42
  require_relative 'aixm/feature/address'
@@ -0,0 +1,255 @@
1
+ using AIXM::Refinements
2
+
3
+ module AIXM
4
+ class Component
5
+
6
+ # FATO (final approach and take-off area) for vertical take-off aircraft
7
+ # such as helicopters.
8
+ #
9
+ # ===Cheat Sheet in Pseudo Code:
10
+ # fato = AIXM.fato(
11
+ # name: String
12
+ # )
13
+ # fato.length = AIXM.d or nil # must use same unit as width
14
+ # fato.width = AIXM.d or nil # must use same unit as length
15
+ # fato.surface = AIXM.surface
16
+ # fato.marking = String or nil
17
+ # fato.profile = String or nil
18
+ # fato.status = STATUSES or nil
19
+ # fato.remarks = String or nil
20
+ # fato.add_direction(
21
+ # name: String
22
+ # ) do |direction|
23
+ # direction.geographic_orientation = AIXM.a[precision=3] or nil
24
+ # direction.remarks = String or nil
25
+ # end
26
+ #
27
+ # @see https://github.com/openflightmaps/ofmx/wiki/Airport#fto-fato
28
+ class FATO
29
+ STATUSES = {
30
+ CLSD: :closed,
31
+ WIP: :work_in_progress, # e.g. construction work
32
+ PARKED: :parked_aircraft, # parked or disabled aircraft on FATO
33
+ FAILAID: :visual_aids_failure, # failure or irregular operation of visual aids
34
+ SPOWER: :secondary_power, # secondary power supply in operation
35
+ OTHER: :other # specify in remarks
36
+ }.freeze
37
+
38
+ # @return [AIXM::Feature::Airport] airport this FATO belongs to
39
+ attr_reader :airport
40
+
41
+ # @return [String] full name (e.g. "H1")
42
+ attr_reader :name
43
+
44
+ # @return [AIXM::D, nil] length
45
+ attr_reader :length
46
+
47
+ # @return [AIXM::D, nil] width
48
+ attr_reader :width
49
+
50
+ # @return [AIXM::Component::Surface] surface of the FATO
51
+ attr_reader :surface
52
+
53
+ # @return [String, nil] markings
54
+ attr_reader :marking
55
+
56
+ # @return [String, nil] profile description
57
+ attr_reader :profile
58
+
59
+ # @return [Symbol, nil] status of the FATO (see {STATUSES}) or +nil+ for normal operation
60
+ attr_reader :status
61
+
62
+ # @return [String, nil] free text remarks
63
+ attr_reader :remarks
64
+
65
+ # @return [Hash{String => AIXM::Component::FATO::Direction}] maps added direction names to full FATO directions
66
+ attr_reader :directions
67
+
68
+ def initialize(name:)
69
+ self.name = name
70
+ @surface = AIXM.surface
71
+ @directions = {}
72
+ end
73
+
74
+ # @return [String]
75
+ def inspect
76
+ %Q(#<#{self.class} airport=#{airport&.id.inspect} name=#{name.inspect}>)
77
+ end
78
+
79
+ def airport=(value)
80
+ fail(ArgumentError, "invalid airport") unless value.is_a? AIXM::Feature::Airport
81
+ @airport = value
82
+ end
83
+ private :airport=
84
+
85
+ def name=(value)
86
+ fail(ArgumentError, "invalid name") unless value.is_a? String
87
+ @name = value.uptrans
88
+ end
89
+
90
+ def length=(value)
91
+ @length = if value
92
+ fail(ArgumentError, "invalid length") unless value.is_a?(AIXM::D) && value.dist > 0
93
+ fail(ArgumentError, "invalid length unit") if width && width.unit != value.unit
94
+ @length = value
95
+ end
96
+ end
97
+
98
+ def width=(value)
99
+ @width = if value
100
+ fail(ArgumentError, "invalid width") unless value.is_a?(AIXM::D) && value.dist > 0
101
+ fail(ArgumentError, "invalid width unit") if length && length.unit != value.unit
102
+ @width = value
103
+ end
104
+ end
105
+
106
+ def marking=(value)
107
+ @marking = value&.to_s
108
+ end
109
+
110
+ def profile=(value)
111
+ @profile = value&.to_s
112
+ end
113
+
114
+ def status=(value)
115
+ @status = value.nil? ? nil : (STATUSES.lookup(value.to_s.to_sym, nil) || fail(ArgumentError, "invalid status"))
116
+ end
117
+
118
+ def remarks=(value)
119
+ @remarks = value&.to_s
120
+ end
121
+
122
+ def add_direction(name:)
123
+ direction = Direction.new(fato: self, name: name)
124
+ yield direction
125
+ @directions[name] = direction
126
+ end
127
+
128
+ # @return [String] UID markup
129
+ def to_uid
130
+ builder = Builder::XmlMarkup.new(indent: 2)
131
+ builder.FtoUid do |fto_uid|
132
+ fto_uid << airport.to_uid.indent(2)
133
+ fto_uid.txtDesig(name)
134
+ end
135
+ end
136
+
137
+ # @return [String] AIXM or OFMX markup
138
+ def to_xml
139
+ builder = Builder::XmlMarkup.new(indent: 2)
140
+ builder.Fto do |fto|
141
+ fto << to_uid.indent(2)
142
+ fto.valLen(length.dist.trim) if length
143
+ fto.valWid(width.dist.trim) if width
144
+ fto.uomDim(length.unit.to_s.upcase) if length
145
+ fto.uomDim(width.unit.to_s.upcase) if width && !length
146
+ unless (xml = surface.to_xml).empty?
147
+ fto << xml.indent(2)
148
+ end
149
+ fto.txtProfile(profile) if profile
150
+ fto.txtMarking(marking) if marking
151
+ fto.codeSts(STATUSES.key(status).to_s) if status
152
+ fto.txtRmk(remarks) if remarks
153
+ end
154
+ directions.values.each do |direction|
155
+ builder << direction.to_xml
156
+ end
157
+ builder.target!
158
+ end
159
+
160
+ # FATO directions further describe each direction to and from the FATO.
161
+ #
162
+ # @see https://github.com/openflightmaps/ofmx/wiki/Airport#fdn-fato-direction
163
+ class Direction
164
+
165
+ # @return [AIXM::Component::FATO] FATO the FATO direction is further describing
166
+ attr_reader :fato
167
+
168
+ # @return [AIXM::A] name of the FATO direction (e.g. "12" or "16L")
169
+ attr_reader :name
170
+
171
+ # @return [AIXM::A, nil] geographic orientation (true bearing) in degrees
172
+ attr_reader :geographic_orientation
173
+
174
+ # @return [String, nil] free text remarks
175
+ attr_reader :remarks
176
+
177
+ # @return [Array<AIXM::Component::Lighting>] installed lighting systems
178
+ attr_reader :lightings
179
+
180
+ def initialize(fato:, name:)
181
+ self.fato, self.name = fato, name
182
+ @lightings = []
183
+ end
184
+
185
+ # @return [String]
186
+ def inspect
187
+ %Q(#<#{self.class} airport=#{fato&.airport&.id.inspect} name=#{name.inspect}>)
188
+ end
189
+
190
+ def fato=(value)
191
+ fail(ArgumentError, "invalid FATO") unless value.is_a? AIXM::Component::FATO
192
+ @fato = value
193
+ end
194
+ private :fato
195
+
196
+ def name=(value)
197
+ fail(ArgumentError, "invalid name") unless value.is_a? String
198
+ @name = AIXM.a(value)
199
+ end
200
+
201
+ def geographic_orientation=(value)
202
+ return @geographic_orientation = nil if value.nil?
203
+ fail(ArgumentError, "invalid geographic orientation") unless value.is_a? AIXM::A
204
+ @geographic_orientation = value
205
+ end
206
+
207
+ def remarks=(value)
208
+ @remarks = value&.to_s
209
+ end
210
+
211
+ # Add a lighting system to the FATO direction.
212
+ #
213
+ # @param lighting [AIXM::Component::Lighting] lighting instance
214
+ # @return [self]
215
+ def add_lighting(lighting)
216
+ fail(ArgumentError, "invalid lighting") unless lighting.is_a? AIXM::Component::Lighting
217
+ lighting.send(:lightable=, self)
218
+ @lightings << lighting
219
+ self
220
+ end
221
+
222
+ # @return [AIXM::A] magnetic orientation (magnetic bearing) in degrees
223
+ def magnetic_orientation
224
+ if geographic_orientation && fato.airport.declination
225
+ geographic_orientation + fato.airport.declination
226
+ end
227
+ end
228
+
229
+ # @return [String] UID markup
230
+ def to_uid
231
+ builder = Builder::XmlMarkup.new(indent: 2)
232
+ builder.FdnUid do |fdn_uid|
233
+ fdn_uid << fato.to_uid.indent(2)
234
+ fdn_uid.txtDesig(name)
235
+ end
236
+ end
237
+
238
+ # @return [String] AIXM or OFMX markup
239
+ def to_xml
240
+ builder = Builder::XmlMarkup.new(indent: 2)
241
+ builder.Fdn do |fdn|
242
+ fdn << to_uid.indent(2)
243
+ fdn.valTrueBrg(geographic_orientation) if geographic_orientation
244
+ fdn.valMagBrg(magnetic_orientation) if magnetic_orientation
245
+ fdn.txtRmk(remarks) if remarks
246
+ end
247
+ lightings.each do |lighting|
248
+ builder << lighting.to_xml(as: :Fls)
249
+ end
250
+ builder.target!
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
@@ -3,22 +3,33 @@ using AIXM::Refinements
3
3
  module AIXM
4
4
  class Component
5
5
 
6
- # Helipads are TLOF (touch-down and lift-off areas) e.g. for helicopters.
6
+ # Helipads are TLOF (touch-down and lift-off areas) for vertical take-off
7
+ # aircraft such as helicopters.
7
8
  #
8
9
  # ===Cheat Sheet in Pseudo Code:
9
10
  # helipad = AIXM.helipad(
10
11
  # name: String
12
+ # xy = AIXM.xy
11
13
  # )
12
- # helipad.xy = AIXM.xy
13
14
  # helipad.z = AIXM.z or nil
14
15
  # helipad.length = AIXM.d or nil # must use same unit as width
15
16
  # helipad.width = AIXM.d or nil # must use same unit as length
16
17
  # helipad.surface = AIXM.surface
18
+ # helipad.marking = String or nil
19
+ # helipad.fato = AIXM.fato or nil
20
+ # helipad.helicopter_class = HELICOPTER_CLASSES or nil
17
21
  # helipad.status = STATUSES or nil
18
22
  # helipad.remarks = String or nil
19
23
  #
20
24
  # @see https://github.com/openflightmaps/ofmx/wiki/Airport#tla-helipad-tlof
21
25
  class Helipad
26
+ HELICOPTER_CLASSES = {
27
+ '1': :'1',
28
+ '2': :'2',
29
+ '3': :'3',
30
+ OTHER: :other # specify in remarks
31
+ }.freeze
32
+
22
33
  STATUSES = {
23
34
  CLSD: :closed,
24
35
  WIP: :work_in_progress, # e.g. construction work
@@ -49,15 +60,28 @@ module AIXM
49
60
  # @return [AIXM::Component::Surface] surface of the helipad
50
61
  attr_reader :surface
51
62
 
63
+ # @return [String, nil] markings
64
+ attr_reader :marking
65
+
66
+ # @return [AIXM::Component::FATO, nil] FATO the helipad is situated on
67
+ attr_reader :fato
68
+
69
+ # @return [Integer, Symbol, nil] suitable helicopter class
70
+ attr_reader :helicopter_class
71
+
52
72
  # @return [Symbol, nil] status of the helipad (see {STATUSES}) or +nil+ for normal operation
53
73
  attr_reader :status
54
74
 
55
75
  # @return [String, nil] free text remarks
56
76
  attr_reader :remarks
57
77
 
58
- def initialize(name:)
59
- self.name = name
78
+ # @return [Array<AIXM::Component::Lighting>] installed lighting systems
79
+ attr_reader :lightings
80
+
81
+ def initialize(name:, xy:)
82
+ self.name, self.xy = name, xy
60
83
  @surface = AIXM.surface
84
+ @lightings = []
61
85
  end
62
86
 
63
87
  # @return [String]
@@ -102,6 +126,19 @@ module AIXM
102
126
  end
103
127
  end
104
128
 
129
+ def marking=(value)
130
+ @marking = value&.to_s
131
+ end
132
+
133
+ def fato=(value)
134
+ fail(ArgumentError, "invalid FATO") unless value.nil? || value.is_a?(AIXM::Component::FATO)
135
+ @fato = value
136
+ end
137
+
138
+ def helicopter_class=(value)
139
+ @helicopter_class = value.nil? ? nil : (HELICOPTER_CLASSES.lookup(value.to_s.to_sym, nil) || fail(ArgumentError, "invalid helicopter class"))
140
+ end
141
+
105
142
  def status=(value)
106
143
  @status = value.nil? ? nil : (STATUSES.lookup(value.to_s.to_sym, nil) || fail(ArgumentError, "invalid status"))
107
144
  end
@@ -110,6 +147,17 @@ module AIXM
110
147
  @remarks = value&.to_s
111
148
  end
112
149
 
150
+ # Add a lighting system to the runway direction.
151
+ #
152
+ # @param lighting [AIXM::Component::Lighting] lighting instance
153
+ # @return [self]
154
+ def add_lighting(lighting)
155
+ fail(ArgumentError, "invalid lighting") unless lighting.is_a? AIXM::Component::Lighting
156
+ lighting.send(:lightable=, self)
157
+ @lightings << lighting
158
+ self
159
+ end
160
+
113
161
  # @return [String] UID markup
114
162
  def to_uid
115
163
  builder = Builder::XmlMarkup.new(indent: 2)
@@ -124,6 +172,7 @@ module AIXM
124
172
  builder = Builder::XmlMarkup.new(indent: 2)
125
173
  builder.Tla do |tla|
126
174
  tla << to_uid.indent(2)
175
+ tla << fato.to_uid.indent(2) if fato
127
176
  tla.geoLat(xy.lat(AIXM.schema))
128
177
  tla.geoLong(xy.long(AIXM.schema))
129
178
  tla.codeDatum('WGE')
@@ -138,9 +187,15 @@ module AIXM
138
187
  unless (xml = surface.to_xml).empty?
139
188
  tla << xml.indent(2)
140
189
  end
190
+ tla.codeClassHel(HELICOPTER_CLASSES.key(helicopter_class).to_s) if helicopter_class
191
+ tla.txtMarking(marking) if marking
141
192
  tla.codeSts(STATUSES.key(status).to_s) if status
142
193
  tla.txtRmk(remarks) if remarks
143
194
  end
195
+ lightings.each do |lighting|
196
+ builder << lighting.to_xml(as: :Tls)
197
+ end
198
+ builder.target!
144
199
  end
145
200
  end
146
201
  end