aixm 0.3.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +72 -6
  4. data/README.md +191 -53
  5. data/exe/ckmid +11 -0
  6. data/exe/mkmid +11 -0
  7. data/lib/aixm/association.rb +367 -0
  8. data/lib/aixm/classes.rb +44 -0
  9. data/lib/aixm/component/fato.rb +44 -52
  10. data/lib/aixm/component/frequency.rb +13 -14
  11. data/lib/aixm/component/geometry/arc.rb +2 -2
  12. data/lib/aixm/component/geometry/border.rb +14 -5
  13. data/lib/aixm/component/geometry/circle.rb +8 -2
  14. data/lib/aixm/component/geometry/point.rb +10 -3
  15. data/lib/aixm/component/geometry/rhumb_line.rb +54 -0
  16. data/lib/aixm/component/geometry.rb +38 -38
  17. data/lib/aixm/component/helipad.rb +29 -37
  18. data/lib/aixm/component/layer.rb +28 -19
  19. data/lib/aixm/component/lighting.rb +11 -12
  20. data/lib/aixm/component/runway.rb +46 -53
  21. data/lib/aixm/{feature → component}/service.rb +36 -35
  22. data/lib/aixm/component/surface.rb +3 -3
  23. data/lib/aixm/component/timetable.rb +5 -3
  24. data/lib/aixm/component/{vertical_limits.rb → vertical_limit.rb} +12 -6
  25. data/lib/aixm/config.rb +6 -3
  26. data/lib/aixm/document.rb +31 -49
  27. data/lib/aixm/executables.rb +85 -0
  28. data/lib/aixm/f.rb +28 -0
  29. data/lib/aixm/feature/address.rb +20 -15
  30. data/lib/aixm/feature/airport.rb +113 -129
  31. data/lib/aixm/feature/airspace.rb +54 -23
  32. data/lib/aixm/feature/navigational_aid/designated_point.rb +12 -14
  33. data/lib/aixm/feature/navigational_aid/dme.rb +10 -11
  34. data/lib/aixm/feature/navigational_aid/marker.rb +6 -2
  35. data/lib/aixm/feature/navigational_aid/ndb.rb +6 -2
  36. data/lib/aixm/feature/navigational_aid/tacan.rb +6 -2
  37. data/lib/aixm/feature/navigational_aid/vor.rb +22 -14
  38. data/lib/aixm/feature/navigational_aid.rb +7 -9
  39. data/lib/aixm/feature/obstacle.rb +22 -20
  40. data/lib/aixm/feature/obstacle_group.rb +30 -30
  41. data/lib/aixm/feature/organisation.rb +20 -4
  42. data/lib/aixm/feature/unit.rb +35 -45
  43. data/lib/aixm/feature.rb +13 -3
  44. data/lib/aixm/memoize.rb +89 -0
  45. data/lib/aixm/object.rb +9 -0
  46. data/lib/aixm/payload_hash.rb +114 -0
  47. data/lib/aixm/refinements.rb +34 -50
  48. data/lib/aixm/shortcuts.rb +6 -43
  49. data/lib/aixm/version.rb +1 -1
  50. data/lib/aixm/xy.rb +9 -1
  51. data/lib/aixm.rb +18 -7
  52. data/schemas/ofmx/{0 → 0.1}/OFMX-CSV-Obstacle.json +0 -0
  53. data/schemas/ofmx/{0 → 0.1}/OFMX-CSV.json +0 -0
  54. data/schemas/ofmx/{0 → 0.1}/OFMX-DataTypes.xsd +52 -2
  55. data/schemas/ofmx/{0 → 0.1}/OFMX-Features.xsd +225 -14
  56. data/schemas/ofmx/{0 → 0.1}/OFMX-Snapshot.xsd +0 -5
  57. data.tar.gz.sig +0 -0
  58. metadata +116 -164
  59. metadata.gz.sig +0 -0
  60. data/.gitignore +0 -6
  61. data/.ruby-version +0 -1
  62. data/.travis.yml +0 -8
  63. data/.yardopts +0 -3
  64. data/Guardfile +0 -8
  65. data/aixm.gemspec +0 -35
  66. data/gems.rb +0 -3
  67. data/lib/aixm/component.rb +0 -6
  68. data/rakefile.rb +0 -22
  69. data/spec/factory.rb +0 -559
  70. data/spec/lib/aixm/a_spec.rb +0 -203
  71. data/spec/lib/aixm/component/fato_spec.rb +0 -260
  72. data/spec/lib/aixm/component/frequency_spec.rb +0 -75
  73. data/spec/lib/aixm/component/geometry/arc_spec.rb +0 -75
  74. data/spec/lib/aixm/component/geometry/border_spec.rb +0 -33
  75. data/spec/lib/aixm/component/geometry/circle_spec.rb +0 -70
  76. data/spec/lib/aixm/component/geometry/point_spec.rb +0 -39
  77. data/spec/lib/aixm/component/geometry_spec.rb +0 -321
  78. data/spec/lib/aixm/component/helipad_spec.rb +0 -187
  79. data/spec/lib/aixm/component/layer_spec.rb +0 -137
  80. data/spec/lib/aixm/component/lighting_spec.rb +0 -88
  81. data/spec/lib/aixm/component/runway_spec.rb +0 -472
  82. data/spec/lib/aixm/component/surface_spec.rb +0 -124
  83. data/spec/lib/aixm/component/timetable_spec.rb +0 -49
  84. data/spec/lib/aixm/component/vertical_limits_spec.rb +0 -97
  85. data/spec/lib/aixm/config_spec.rb +0 -41
  86. data/spec/lib/aixm/d_spec.rb +0 -150
  87. data/spec/lib/aixm/document_spec.rb +0 -1875
  88. data/spec/lib/aixm/errors_spec.rb +0 -14
  89. data/spec/lib/aixm/f_spec.rb +0 -85
  90. data/spec/lib/aixm/feature/address_spec.rb +0 -55
  91. data/spec/lib/aixm/feature/airport_spec.rb +0 -770
  92. data/spec/lib/aixm/feature/airspace_spec.rb +0 -390
  93. data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +0 -98
  94. data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +0 -92
  95. data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +0 -79
  96. data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +0 -89
  97. data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +0 -88
  98. data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +0 -245
  99. data/spec/lib/aixm/feature/navigational_aid_spec.rb +0 -52
  100. data/spec/lib/aixm/feature/obstacle_group_spec.rb +0 -326
  101. data/spec/lib/aixm/feature/obstacle_spec.rb +0 -279
  102. data/spec/lib/aixm/feature/organisation_spec.rb +0 -77
  103. data/spec/lib/aixm/feature/service_spec.rb +0 -59
  104. data/spec/lib/aixm/feature/unit_spec.rb +0 -230
  105. data/spec/lib/aixm/feature_spec.rb +0 -38
  106. data/spec/lib/aixm/p_spec.rb +0 -189
  107. data/spec/lib/aixm/refinements_spec.rb +0 -381
  108. data/spec/lib/aixm/version_spec.rb +0 -7
  109. data/spec/lib/aixm/w_spec.rb +0 -150
  110. data/spec/lib/aixm/xy_spec.rb +0 -180
  111. data/spec/lib/aixm/z_spec.rb +0 -94
  112. data/spec/macros/marking.rb +0 -12
  113. data/spec/macros/organisation.rb +0 -11
  114. data/spec/macros/remarks.rb +0 -12
  115. data/spec/macros/timetable.rb +0 -11
  116. data/spec/macros/xy.rb +0 -11
  117. data/spec/macros/z_qnh.rb +0 -11
  118. data/spec/sounds/failure.mp3 +0 -0
  119. data/spec/sounds/success.mp3 +0 -0
  120. data/spec/spec_helper.rb +0 -55
@@ -8,13 +8,14 @@ module AIXM
8
8
  # ===Cheat Sheet in Pseudo Code:
9
9
  # airspace = AIXM.airspace(
10
10
  # source: String or nil
11
+ # region: String or nil
11
12
  # id: String or nil # nil is converted to an 8 character digest
12
13
  # type: String or Symbol
13
14
  # local_type: String or nil
14
15
  # name: String or nil
15
16
  # )
16
- # airspace.geometry << AIXM.point or AIXM.arc or AIXM.border or AIXM.circle
17
- # airspace.layers << AIXM.layer
17
+ # airspace.add_layer(AIXM.layer)
18
+ # airspace.geometry.add_segment(AIXM.point or AIXM.arc or AIXM.border or AIXM.circle)
18
19
  #
19
20
  # The +id+ is mandatory, however, you may omit it when initializing a new
20
21
  # airspace or assign +nil+ to an existing airspace which will generate a 8
@@ -27,8 +28,11 @@ module AIXM
27
28
  #
28
29
  # airspace= AIXM.airspace(type: :regulated_airspace, local_type: "RMZ")
29
30
  #
30
- # @see https://github.com/openflightmaps/ofmx/wiki/Airspace#ase-airspace
31
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Airspace#ase-airspace
31
32
  class Airspace < Feature
33
+ include AIXM::Association
34
+ include AIXM::Memoize
35
+
32
36
  public_class_method :new
33
37
 
34
38
  TYPES = {
@@ -74,6 +78,18 @@ module AIXM
74
78
  PART: :part_of_airspace
75
79
  }.freeze
76
80
 
81
+ # @!method geometry
82
+ # @return [AIXM::Component::Geometry] horizontal geometry shape
83
+ # @!method geometry=(geometry)
84
+ # @param geometry [AIXM::Component::Geometry]
85
+ has_one :geometry
86
+
87
+ # @!method layers
88
+ # @return [Array<AIXM::Compoment::Layer>] vertical layers
89
+ # @!method add_layer(layer)
90
+ # @param layer [AIXM::Compoment::Layer]
91
+ has_many :layers
92
+
77
93
  # @note When assigning +nil+, a 4 byte hex derived from {#type}, {#name}
78
94
  # and {#local_type} is written instead.
79
95
  # @return [String] published identifier (e.g. "LFP81")
@@ -90,18 +106,11 @@ module AIXM
90
106
  # @return [String, nil] full name (e.g. "LF P 81 CHERBOURG")
91
107
  attr_reader :name
92
108
 
93
- # @return [AIXM::Component::Geometry] horizontal geometrical shape
94
- attr_accessor :geometry
95
-
96
- # @return [Array<AIXM::Compoment::Layer>] vertical layers
97
- attr_accessor :layers
98
-
99
- def initialize(source: nil, id: nil, type:, local_type: nil, name: nil)
100
- super(source: source)
109
+ def initialize(source: nil, region: nil, id: nil, type:, local_type: nil, name: nil)
110
+ super(source: source, region: region)
101
111
  self.type, self.local_type, self.name = type, local_type, name
102
112
  self.id = id
103
- @geometry = AIXM.geometry
104
- @layers = []
113
+ self.geometry = AIXM.geometry
105
114
  end
106
115
 
107
116
  # @return [String]
@@ -133,9 +142,19 @@ module AIXM
133
142
  # @return [String] UID markup
134
143
  def to_uid(as: :AseUid)
135
144
  builder = Builder::XmlMarkup.new(indent: 2)
136
- builder.tag!(as) do |tag|
145
+ builder.tag!(as, ({ region: (region if AIXM.ofmx?) }.compact)) do |tag|
137
146
  tag.codeType(TYPES.key(type).to_s)
138
147
  tag.codeId(id)
148
+ tag.txtLocalType(local_type) if AIXM.ofmx? && local_type && local_type != name
149
+ end
150
+ end
151
+ memoize :to_uid
152
+
153
+ # @return [String] UID markup
154
+ def to_wrapped_uid(as: :AseUid, with:)
155
+ builder = Builder::XmlMarkup.new(indent: 2)
156
+ builder.tag!(with) do |tag|
157
+ tag << to_uid(as: as).indent(2)
139
158
  end
140
159
  end
141
160
 
@@ -148,32 +167,45 @@ module AIXM
148
167
  builder.comment! "Airspace: [#{TYPES.key(type)}] #{name || :UNNAMED}"
149
168
  builder.Ase({ source: (source if AIXM.ofmx?) }.compact) do |ase|
150
169
  ase << to_uid.indent(2)
151
- ase.txtLocalType(local_type) if local_type && local_type != name
170
+ ase.txtLocalType(local_type) if AIXM.aixm? && local_type && local_type != name
152
171
  ase.txtName(name) if name
153
172
  unless layered?
154
173
  ase << layers.first.to_xml.indent(2)
155
174
  end
156
175
  end
157
176
  builder.Abd do |abd|
158
- abd.AbdUid do |abd_uid|
159
- abd_uid << to_uid.indent(4)
160
- end
177
+ abd << to_wrapped_uid(with: :AbdUid).indent(2)
161
178
  abd << geometry.to_xml.indent(2)
162
179
  end
163
180
  if layered?
164
181
  layers.each.with_index do |layer, index|
165
- layer_airspace = AIXM.airspace(type: 'CLASS', name: "#{name} LAYER #{index + 1}")
182
+ layer_airspace = AIXM.airspace(region: region, type: 'CLASS', name: "#{name} LAYER #{index + 1}")
166
183
  builder.Ase do |ase|
167
184
  ase << layer_airspace.to_uid.indent(2)
168
185
  ase.txtName(layer_airspace.name)
169
186
  ase << layers[index].to_xml.indent(2)
170
187
  end
171
188
  builder.Adg do |adg|
172
- adg.AdgUid do |adg_uid|
173
- adg_uid << layer_airspace.to_uid.indent(4)
174
- end
189
+ adg << layer_airspace.to_wrapped_uid(with: :AdgUid).indent(2)
175
190
  adg << to_uid(as: :AseUidSameExtent).indent(2)
176
191
  end
192
+ layer.services.each do |service|
193
+ builder.Sae do |sae|
194
+ sae.SaeUid do |sae_uid|
195
+ sae_uid << service.to_uid.indent(4)
196
+ sae_uid << layer_airspace.to_uid.indent(4)
197
+ end
198
+ end
199
+ end
200
+ end
201
+ else
202
+ layers.first.services.each do |service|
203
+ builder.Sae do |sae|
204
+ sae.SaeUid do |sae_uid|
205
+ sae_uid << service.to_uid.indent(4)
206
+ sae_uid << to_uid.indent(4)
207
+ end
208
+ end
177
209
  end
178
210
  end
179
211
  builder.target!
@@ -184,7 +216,6 @@ module AIXM
184
216
  def layered?
185
217
  layers.count > 1
186
218
  end
187
-
188
219
  end
189
220
  end
190
221
  end
@@ -10,6 +10,7 @@ module AIXM
10
10
  # ===Cheat Sheet in Pseudo Code:
11
11
  # designated_point = AIXM.designated_point(
12
12
  # source: String or nil
13
+ # region: String or nil
13
14
  # id: String
14
15
  # name: String or nil
15
16
  # xy: AIXM.xy
@@ -18,11 +19,12 @@ module AIXM
18
19
  # designated_point.airport = AIXM.airport or nil
19
20
  # designated_point.remarks = String or nil
20
21
  #
21
- # @see https://github.com/openflightmaps/ofmx/wiki/Navigational-aid#dpn-designated-point
22
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Navigational-aid#dpn-designated-point
22
23
  class DesignatedPoint < NavigationalAid
24
+ include AIXM::Association
25
+ include AIXM::Memoize
26
+
23
27
  public_class_method :new
24
- private :organisation=
25
- private :organisation
26
28
 
27
29
  TYPES = {
28
30
  ICAO: :icao, # five-letter ICAO id
@@ -35,15 +37,15 @@ module AIXM
35
37
  OTHER: :other # specify in remarks
36
38
  }.freeze
37
39
 
38
- # @return [Symbol] type of designated point
39
- attr_reader :type
40
-
41
40
  # @return [AIXM::Feature::Airport] airport this designated point is
42
41
  # associated with
43
- attr_reader :airport
42
+ belongs_to :airport
43
+
44
+ # @return [Symbol] type of designated point
45
+ attr_reader :type
44
46
 
45
47
  def initialize(type:, **arguments)
46
- super(organisation: false, z: nil, **arguments)
48
+ super(organisation: nil, z: nil, **arguments)
47
49
  self.type = type
48
50
  end
49
51
 
@@ -51,20 +53,16 @@ module AIXM
51
53
  @type = TYPES.lookup(value&.to_s&.to_sym, nil) || fail(ArgumentError, "invalid type")
52
54
  end
53
55
 
54
- def airport=(value)
55
- fail(ArgumentError, "invalid airport") unless value.nil? || value.is_a?(AIXM::Feature::Airport)
56
- @airport = value
57
- end
58
-
59
56
  # @return [String] UID markup
60
57
  def to_uid
61
58
  builder = Builder::XmlMarkup.new(indent: 2)
62
- builder.DpnUid do |dpn_uid|
59
+ builder.DpnUid({ region: (region if AIXM.ofmx?) }.compact) do |dpn_uid|
63
60
  dpn_uid.codeId(id)
64
61
  dpn_uid.geoLat(xy.lat(AIXM.schema))
65
62
  dpn_uid.geoLong(xy.long(AIXM.schema))
66
63
  end
67
64
  end
65
+ memoize :to_uid
68
66
 
69
67
  # @return [String] AIXM or OFMX markup
70
68
  def to_xml
@@ -12,6 +12,7 @@ module AIXM
12
12
  # ===Cheat Sheet in Pseudo Code:
13
13
  # dme = AIXM.dme(
14
14
  # source: String or nil
15
+ # region: String or nil
15
16
  # organisation: AIXM.organisation
16
17
  # id: String
17
18
  # name: String
@@ -22,18 +23,21 @@ module AIXM
22
23
  # dme.timetable = AIXM.timetable or nil
23
24
  # dme.remarks = String or nil
24
25
  #
25
- # @see https://github.com/openflightmaps/ofmx/wiki/Navigational-aid#dme-dme
26
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Navigational-aid#dme-dme
26
27
  class DME < NavigationalAid
28
+ include AIXM::Memoize
29
+
27
30
  public_class_method :new
28
31
 
29
32
  CHANNEL_RE = /\A([1-9]|[1-9]\d|1[0-1]\d|12[0-6])[XY]\z/.freeze
30
33
 
34
+ # @!method vor
35
+ # @return [AIXM::Feature::NavigationalAid::VOR, nil] associated VOR
36
+ belongs_to :vor, readonly: true
37
+
31
38
  # @return [String] radio channel
32
39
  attr_reader :channel
33
40
 
34
- # @return [AIXM::Feature::NavigationalAid::VOR, nil] associated VOR
35
- attr_reader :vor
36
-
37
41
  def initialize(channel:, **arguments)
38
42
  super(**arguments)
39
43
  self.channel = channel
@@ -60,21 +64,16 @@ module AIXM
60
64
  end
61
65
  end
62
66
 
63
- def vor=(value)
64
- fail(ArgumentError, "invalid VOR") unless value.is_a? VOR
65
- @vor = value
66
- end
67
- private :vor=
68
-
69
67
  # @return [String] UID markup
70
68
  def to_uid
71
69
  builder = Builder::XmlMarkup.new(indent: 2)
72
- builder.DmeUid do |dme_uid|
70
+ builder.DmeUid({ region: (region if AIXM.ofmx?) }.compact) do |dme_uid|
73
71
  dme_uid.codeId(id)
74
72
  dme_uid.geoLat(xy.lat(AIXM.schema))
75
73
  dme_uid.geoLong(xy.long(AIXM.schema))
76
74
  end
77
75
  end
76
+ memoize :to_uid
78
77
 
79
78
  # @return [String] AIXM or OFMX markup
80
79
  def to_xml
@@ -11,6 +11,7 @@ module AIXM
11
11
  # ===Cheat Sheet in Pseudo Code:
12
12
  # marker = AIXM.marker(
13
13
  # source: String or nil
14
+ # region: String or nil
14
15
  # organisation: AIXM.organisation
15
16
  # id: String
16
17
  # name: String
@@ -24,8 +25,10 @@ module AIXM
24
25
  # @note Marker are not fully implemented because they usually have to be
25
26
  # associated with an ILS which are not implemented as of now.
26
27
  #
27
- # @see https://github.com/openflightmaps/ofmx/wiki/Navigational-aid#mkr-marker-beacon
28
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Navigational-aid#mkr-marker-beacon
28
29
  class Marker < NavigationalAid
30
+ include AIXM::Memoize
31
+
29
32
  public_class_method :new
30
33
 
31
34
  TYPES = {
@@ -53,12 +56,13 @@ module AIXM
53
56
  # @return [String] UID markup
54
57
  def to_uid
55
58
  builder = Builder::XmlMarkup.new(indent: 2)
56
- builder.MkrUid do |mkr_uid|
59
+ builder.MkrUid({ region: (region if AIXM.ofmx?) }.compact) do |mkr_uid|
57
60
  mkr_uid.codeId(id)
58
61
  mkr_uid.geoLat(xy.lat(AIXM.schema))
59
62
  mkr_uid.geoLong(xy.long(AIXM.schema))
60
63
  end
61
64
  end
65
+ memoize :to_uid
62
66
 
63
67
  # @return [String] AIXM or OFMX markup
64
68
  def to_xml
@@ -10,6 +10,7 @@ module AIXM
10
10
  # ===Cheat Sheet in Pseudo Code:
11
11
  # ndb = AIXM.ndb(
12
12
  # source: String or nil
13
+ # region: String or nil
13
14
  # organisation: AIXM.organisation
14
15
  # id: String
15
16
  # name: String
@@ -21,8 +22,10 @@ module AIXM
21
22
  # ndb.timetable = AIXM.timetable or nil
22
23
  # ndb.remarks = String or nil
23
24
  #
24
- # @see https://github.com/openflightmaps/ofmx/wiki/Navigational-aid#ndb-ndb
25
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Navigational-aid#ndb-ndb
25
26
  class NDB < NavigationalAid
27
+ include AIXM::Memoize
28
+
26
29
  public_class_method :new
27
30
 
28
31
  TYPES = {
@@ -55,12 +58,13 @@ module AIXM
55
58
  # @return [String] UID markup
56
59
  def to_uid
57
60
  builder = Builder::XmlMarkup.new(indent: 2)
58
- builder.NdbUid do |ndb_uid|
61
+ builder.NdbUid({ region: (region if AIXM.ofmx?) }.compact) do |ndb_uid|
59
62
  ndb_uid.codeId(id)
60
63
  ndb_uid.geoLat(xy.lat(AIXM.schema))
61
64
  ndb_uid.geoLong(xy.long(AIXM.schema))
62
65
  end
63
66
  end
67
+ memoize :to_uid
64
68
 
65
69
  # @return [String] AIXM or OFMX markup
66
70
  def to_xml
@@ -11,6 +11,7 @@ module AIXM
11
11
  # ===Cheat Sheet in Pseudo Code:
12
12
  # tacan = AIXM.tacan(
13
13
  # source: String or nil
14
+ # region: String or nil
14
15
  # organisation: AIXM.organisation
15
16
  # id: String
16
17
  # name: String
@@ -21,19 +22,22 @@ module AIXM
21
22
  # tacan.timetable = AIXM.timetable or nil
22
23
  # tacan.remarks = String or nil
23
24
  #
24
- # @see https://github.com/openflightmaps/ofmx/wiki/Navigational-aid#tcn-tacan
25
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Navigational-aid#tcn-tacan
25
26
  class TACAN < DME
27
+ include AIXM::Memoize
28
+
26
29
  public_class_method :new
27
30
 
28
31
  # @return [String] UID markup
29
32
  def to_uid
30
33
  builder = Builder::XmlMarkup.new(indent: 2)
31
- builder.TcnUid do |tcn_uid|
34
+ builder.TcnUid({ region: (region if AIXM.ofmx?) }.compact) do |tcn_uid|
32
35
  tcn_uid.codeId(id)
33
36
  tcn_uid.geoLat(xy.lat(AIXM.schema))
34
37
  tcn_uid.geoLong(xy.long(AIXM.schema))
35
38
  end
36
39
  end
40
+ memoize :to_uid
37
41
 
38
42
  # @return [String] AIXM or OFMX markup
39
43
  def to_xml
@@ -11,6 +11,7 @@ module AIXM
11
11
  # ===Cheat Sheet in Pseudo Code:
12
12
  # vor = AIXM.vor(
13
13
  # source: String or nil
14
+ # region: String or nil
14
15
  # organisation: AIXM.organisation
15
16
  # id: String
16
17
  # name: String
@@ -25,8 +26,10 @@ module AIXM
25
26
  # vor.associate_dme(channel: String) # turns the VOR into a VOR/DME
26
27
  # vor.associate_tacan(channel: String) # turns the VOR into a VORTAC
27
28
  #
28
- # @see https://github.com/openflightmaps/ofmx/wiki/Navigational-aid#vor-vor
29
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Navigational-aid#vor-vor
29
30
  class VOR < NavigationalAid
31
+ include AIXM::Memoize
32
+
30
33
  public_class_method :new
31
34
 
32
35
  TYPES = {
@@ -42,6 +45,18 @@ module AIXM
42
45
  OTHER: :other # specify in remarks
43
46
  }.freeze
44
47
 
48
+ # @!method dme
49
+ # @return [AIXM::Feature::NavigationalAid::DME, nil] associated DME
50
+ # @!method dme=(dme)
51
+ # @param dme [AIXM::Feature::NavigationalAid::DME, nil]
52
+ has_one :dme, allow_nil: true
53
+
54
+ # @!method tacan
55
+ # @return [AIXM::Feature::NavigationalAid::TACAN, nil] associated TACAN
56
+ # @!method tacan=(tacan)
57
+ # @param tacan [AIXM::Feature::NavigationalAid::TACAN, nil]
58
+ has_one :tacan, allow_nil: true
59
+
45
60
  # @return [Symbol] type of VOR (see {TYPES})
46
61
  attr_reader :type
47
62
 
@@ -51,12 +66,6 @@ module AIXM
51
66
  # @return [Symbol] north indication (see {NORTHS})
52
67
  attr_reader :north
53
68
 
54
- # @return [AIXM::Feature::NavigationalAid::DME, nil] associated DME
55
- attr_reader :dme
56
-
57
- # @return [AIXM::Feature::NavigationalAid::TACAN, nil] associated TACAN
58
- attr_reader :tacan
59
-
60
69
  def initialize(type:, f:, north:, **arguments)
61
70
  super(**arguments)
62
71
  self.type, self.f, self.north = type, f, north
@@ -77,27 +86,26 @@ module AIXM
77
86
 
78
87
  # Associate a DME which turns the VOR into a VOR/DME
79
88
  def associate_dme(channel:)
80
- @dme = AIXM.dme(organisation: organisation, id: id, name: name, xy: xy, z: z, channel: channel)
81
- @dme.timetable, @dme.remarks = timetable, remarks
82
- @dme.send(:vor=, self)
89
+ self.dme = AIXM.dme(region: region, organisation: organisation, id: id, name: name, xy: xy, z: z, channel: channel)
90
+ dme.timetable, @dme.remarks = timetable, remarks
83
91
  end
84
92
 
85
93
  # Associate a TACAN which turns the VOR into a VORTAC
86
94
  def associate_tacan(channel:)
87
- @tacan = AIXM.tacan(organisation: organisation, id: id, name: name, xy: xy, z: z, channel: channel)
88
- @tacan.timetable, @tacan.remarks = timetable, remarks
89
- @tacan.send(:vor=, self)
95
+ self.tacan = AIXM.tacan(region: region, organisation: organisation, id: id, name: name, xy: xy, z: z, channel: channel)
96
+ tacan.timetable, @tacan.remarks = timetable, remarks
90
97
  end
91
98
 
92
99
  # @return [String] UID markup
93
100
  def to_uid
94
101
  builder = Builder::XmlMarkup.new(indent: 2)
95
- builder.VorUid do |vor_uid|
102
+ builder.VorUid({ region: (region if AIXM.ofmx?) }.compact) do |vor_uid|
96
103
  vor_uid.codeId(id)
97
104
  vor_uid.geoLat(xy.lat(AIXM.schema))
98
105
  vor_uid.geoLong(xy.long(AIXM.schema))
99
106
  end
100
107
  end
108
+ memoize :to_uid
101
109
 
102
110
  # @return [String] AIXM or OFMX markup
103
111
  def to_xml
@@ -5,10 +5,13 @@ module AIXM
5
5
 
6
6
  # @abstract
7
7
  class NavigationalAid < Feature
8
+ include AIXM::Association
9
+
8
10
  private_class_method :new
9
11
 
10
- # @return [AIXM::Feature::Organisation] superior organisation
11
- attr_reader :organisation
12
+ # @!method organisation
13
+ # @return [AIXM::Feature::Organisation] superior organisation
14
+ belongs_to :organisation, as: :member
12
15
 
13
16
  # @return [String] published identifier
14
17
  attr_reader :id
@@ -28,8 +31,8 @@ module AIXM
28
31
  # @return [String, nil] free text remarks
29
32
  attr_reader :remarks
30
33
 
31
- def initialize(source: nil, organisation:, id:, name: nil, xy:, z: nil)
32
- super(source: source)
34
+ def initialize(source: nil, region: nil, organisation:, id:, name: nil, xy:, z: nil)
35
+ super(source: source, region: region)
33
36
  self.organisation, self.id, self.name, self.xy, self.z = organisation, id, name, xy, z
34
37
  end
35
38
 
@@ -38,11 +41,6 @@ module AIXM
38
41
  %Q(#<#{self.class} id=#{id.inspect} name=#{name.inspect}>)
39
42
  end
40
43
 
41
- def organisation=(value)
42
- fail(ArgumentError, "invalid organisation") unless value == false || value.is_a?(AIXM::Feature::Organisation)
43
- @organisation = value
44
- end
45
-
46
44
  def id=(value)
47
45
  fail(ArgumentError, "invalid id") unless value.is_a? String
48
46
  @id = value.upcase
@@ -9,11 +9,12 @@ module AIXM
9
9
  # ===Cheat Sheet in Pseudo Code:
10
10
  # obstacle = AIXM.obstacle(
11
11
  # source: String or nil
12
+ # region: String or nil
12
13
  # name: String or nil
13
14
  # type: TYPES
14
15
  # xy: AIXM.xy
15
16
  # z: AIXM.z
16
- # radius: AIXM.d
17
+ # radius: AIXM.d or nil
17
18
  # )
18
19
  # obstacle.lighting = true or false (default for AIXM) or nil (means: unknown, default for OFMX)
19
20
  # obstacle.lighting_remarks = String or nil
@@ -34,10 +35,15 @@ module AIXM
34
35
  #
35
36
  # Please note: As soon as an obstacle is added to an obstacle group, the
36
37
  # +xy_accuracy+ and +z_accuracy+ of the obstacle group overwrite whatever
37
- # is set on the individual obstacles!
38
+ # is set on the individual obstacles. On the other hand, if the obstacle
39
+ # group has no +source+ set, it will inherit this value from the first
40
+ # obstacle in the group.
38
41
  #
39
- # @see https://github.com/openflightmaps/ofmx/wiki/Obstacle
42
+ # @see https://gitlab.com/openflightmaps/ofmx/wikis/Obstacle
40
43
  class Obstacle < Feature
44
+ include AIXM::Association
45
+ include AIXM::Memoize
46
+
41
47
  public_class_method :new
42
48
 
43
49
  TYPES = {
@@ -57,6 +63,10 @@ module AIXM
57
63
  OTHER: :other
58
64
  }.freeze
59
65
 
66
+ # @!method obstacle_group
67
+ # @return [AIXM::Feature::ObstacleGroup] group this obstacle belongs to
68
+ belongs_to :obstacle_group
69
+
60
70
  # @return [String] full name
61
71
  attr_reader :name
62
72
 
@@ -108,24 +118,21 @@ module AIXM
108
118
  # @return [String, nil] free text remarks
109
119
  attr_reader :remarks
110
120
 
111
- # @return [AIXM::Feature::ObstacleGroup] group this obstacle belongs to
112
- attr_reader :obstacle_group
113
-
114
121
  # @return [Symbol, nil] another obstacle to which a physical link exists
115
122
  attr_reader :linked_to
116
123
 
117
124
  # @return [Symbol, nil] type of physical link between this and another obstacle
118
125
  attr_reader :link_type
119
126
 
120
- def initialize(source: nil, name: nil, type:, xy:, z:, radius:)
121
- super(source: source)
127
+ def initialize(source: nil, region: nil, name: nil, type:, xy:, z:, radius: nil)
128
+ super(source: source, region: region)
122
129
  self.name, self.type, self.xy, self.z, self.radius = name, type, xy, z, radius
123
- @lighting = @marking = @height_accurate = false
130
+ @lighting = @marking = false
124
131
  end
125
132
 
126
133
  # @return [String]
127
134
  def inspect
128
- %Q(#<#{self.class} xy="#{xy.to_s}" type=#{type.inspect}>)
135
+ %Q(#<#{self.class} xy="#{xy.to_s}" type=#{type.inspect} name=#{name.inspect}>)
129
136
  end
130
137
 
131
138
  def name=(value)
@@ -202,12 +209,6 @@ module AIXM
202
209
  @remarks = value&.to_s
203
210
  end
204
211
 
205
- def obstacle_group=(value)
206
- fail(ArgumentError, "invalid obstacle group") unless value.is_a?(AIXM::Feature::ObstacleGroup)
207
- @obstacle_group = value
208
- end
209
- private :obstacle_group=
210
-
211
212
  def linked_to=(value)
212
213
  fail(ArgumentError, "invalid linked to") unless value.is_a?(AIXM::Feature::Obstacle)
213
214
  @linked_to = value
@@ -231,7 +232,7 @@ module AIXM
231
232
 
232
233
  # @return [String] UID markup
233
234
  def to_uid(as: :ObsUid)
234
- self.obstacle_group ||= singleton_obstacle_group
235
+ obstacle_group = self.obstacle_group || singleton_obstacle_group
235
236
  builder = Builder::XmlMarkup.new(indent: 2)
236
237
  builder.tag!(as) do |tag|
237
238
  tag << obstacle_group.to_uid.indent(2) if AIXM.ofmx?
@@ -239,14 +240,15 @@ module AIXM
239
240
  tag.geoLong((xy.long(AIXM.schema)))
240
241
  end
241
242
  end
243
+ memoize :to_uid
242
244
 
243
245
  # @return [String] AIXM or OFMX markup
244
246
  def to_xml(delegate: true)
245
- self.obstacle_group ||= singleton_obstacle_group
247
+ obstacle_group = self.obstacle_group || singleton_obstacle_group
246
248
  return obstacle_group.to_xml if delegate && AIXM.ofmx?
247
249
  builder = Builder::XmlMarkup.new(indent: 2)
248
250
  builder.comment! "Obstacle: [#{type}] #{xy.to_s} #{name}".strip
249
- builder.Obs do |obs|
251
+ builder.Obs({ source: (source if AIXM.ofmx?) }.compact) do |obs|
250
252
  obs << to_uid.indent(2)
251
253
  obs.txtName(name) if name
252
254
  if AIXM.ofmx?
@@ -298,7 +300,7 @@ module AIXM
298
300
  # OFMX requires single, ungrouped obstacles to be the only member of a
299
301
  # singleton obstacle group.
300
302
  def singleton_obstacle_group
301
- AIXM.obstacle_group.add_obstacle self
303
+ AIXM.obstacle_group(region: region).add_obstacle self
302
304
  end
303
305
 
304
306
  end