aixm 0.3.5 → 0.3.6

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