aipp 0.2.6 → 1.0.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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +21 -0
- data/README.md +147 -91
- data/exe/aip2aixm +2 -2
- data/exe/aip2ofmx +2 -2
- data/lib/aipp/aip.rb +96 -11
- data/lib/aipp/border.rb +77 -46
- data/lib/aipp/debugger.rb +101 -0
- data/lib/aipp/downloader.rb +18 -5
- data/lib/aipp/executable.rb +33 -20
- data/lib/aipp/parser.rb +42 -37
- data/lib/aipp/patcher.rb +5 -2
- data/lib/aipp/regions/LF/README.md +49 -0
- data/lib/aipp/regions/LF/aerodromes.rb +223 -0
- data/lib/aipp/regions/LF/d_p_r_airspaces.rb +56 -0
- data/lib/aipp/regions/LF/dangerous_activities.rb +49 -0
- data/lib/aipp/regions/LF/designated_points.rb +47 -0
- data/lib/aipp/regions/LF/fixtures/aerodromes.yml +608 -0
- data/lib/aipp/regions/LF/helipads.rb +122 -0
- data/lib/aipp/regions/LF/helpers/base.rb +167 -174
- data/lib/aipp/regions/LF/helpers/surface.rb +49 -0
- data/lib/aipp/regions/LF/helpers/usage_limitation.rb +20 -0
- data/lib/aipp/regions/LF/navigational_aids.rb +85 -0
- data/lib/aipp/regions/LF/obstacles.rb +153 -0
- data/lib/aipp/regions/LF/serviced_airspaces.rb +70 -0
- data/lib/aipp/regions/LF/services.rb +172 -0
- data/lib/aipp/t_hash.rb +3 -4
- data/lib/aipp/version.rb +1 -1
- data/lib/aipp.rb +7 -5
- data/lib/core_ext/enumerable.rb +2 -2
- data/lib/core_ext/hash.rb +21 -5
- data/lib/core_ext/nokogiri.rb +54 -0
- data/lib/core_ext/string.rb +32 -65
- data.tar.gz.sig +0 -0
- metadata +70 -81
- metadata.gz.sig +0 -0
- data/lib/aipp/airac.rb +0 -55
- data/lib/aipp/regions/LF/AD-1.3.rb +0 -177
- data/lib/aipp/regions/LF/AD-1.6.rb +0 -33
- data/lib/aipp/regions/LF/AD-2.rb +0 -344
- data/lib/aipp/regions/LF/AD-3.1.rb +0 -185
- data/lib/aipp/regions/LF/ENR-2.1.rb +0 -167
- data/lib/aipp/regions/LF/ENR-4.1.rb +0 -41
- data/lib/aipp/regions/LF/ENR-4.3.rb +0 -27
- data/lib/aipp/regions/LF/ENR-5.1.rb +0 -106
- data/lib/aipp/regions/LF/ENR-5.4.rb +0 -90
- data/lib/aipp/regions/LF/ENR-5.5.rb +0 -55
- data/lib/aipp/regions/LF/fixtures/AD-1.3.yml +0 -511
- data/lib/aipp/regions/LF/fixtures/AD-2.yml +0 -185
- data/lib/aipp/regions/LF/fixtures/AD-3.1.yml +0 -10
- data/lib/aipp/regions/LF/helpers/URL.rb +0 -26
- data/lib/aipp/regions/LF/helpers/navigational_aid.rb +0 -104
- data/lib/aipp/regions/LF/helpers/radio_AD.rb +0 -110
- data/lib/core_ext/object.rb +0 -43
@@ -0,0 +1,223 @@
|
|
1
|
+
module AIPP
|
2
|
+
module LF
|
3
|
+
|
4
|
+
class Aerodromes < AIP
|
5
|
+
|
6
|
+
include AIPP::LF::Helpers::Base
|
7
|
+
include AIPP::LF::Helpers::UsageLimitation
|
8
|
+
include AIPP::LF::Helpers::Surface
|
9
|
+
|
10
|
+
APPROACH_LIGHTING_TYPES = {
|
11
|
+
'CAT I' => :cat_1,
|
12
|
+
'CAT II' => :cat_2,
|
13
|
+
'CAT III' => :cat_3,
|
14
|
+
'CAT II-III' => :cat_2_and_3
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
LIGHTING_POSITIONS = {
|
18
|
+
threshold: 'Thr',
|
19
|
+
touch_down_zone: 'Tdz',
|
20
|
+
center_line: 'Axe',
|
21
|
+
edge: 'Bord',
|
22
|
+
runway_end: 'Fin',
|
23
|
+
stopway_center_line: 'Swy'
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
LIGHTING_COLORS = {
|
27
|
+
'W' => :white,
|
28
|
+
'R' => :red,
|
29
|
+
'G' => :green,
|
30
|
+
'B' => :blue,
|
31
|
+
'Y' => :yellow
|
32
|
+
}.freeze
|
33
|
+
|
34
|
+
ICAO_LIGHTING_COLORS = {
|
35
|
+
center_line: :white,
|
36
|
+
edge: :white
|
37
|
+
}.freeze
|
38
|
+
|
39
|
+
def parse
|
40
|
+
cache.ad.css(%Q(Ad[lk^="[LF]"])).each do |ad_node|
|
41
|
+
# Build airport
|
42
|
+
next unless limitation_type = LIMITATION_TYPES.fetch(ad_node.(:AdStatut))
|
43
|
+
airport = AIXM.airport(
|
44
|
+
source: source(section: 'AD', position: ad_node.line),
|
45
|
+
organisation: organisation_lf,
|
46
|
+
id: id_from(ad_node.(:AdCode)),
|
47
|
+
name: ad_node.(:AdNomComplet),
|
48
|
+
xy: xy_from(ad_node.(:Geometrie))
|
49
|
+
).tap do |airport|
|
50
|
+
airport.meta = ad_node.attr('pk')
|
51
|
+
airport.z = given(ad_node.(:AdRefAltFt)) { AIXM.z(_1.to_i, :qnh) }
|
52
|
+
airport.declination = ad_node.(:AdMagVar)&.to_f
|
53
|
+
airport.add_usage_limitation(type: limitation_type.fetch(:limitation)) do |limitation|
|
54
|
+
limitation.remarks = limitation_type[:remarks]
|
55
|
+
[
|
56
|
+
(:scheduled if ad_node.(:TfcRegulier?)),
|
57
|
+
(:not_scheduled if ad_node.(:TfcNonRegulier?)),
|
58
|
+
(:private if ad_node.(:TfcPrive?)),
|
59
|
+
(:other unless ad_node.(:TfcRegulier?) || ad_node.(:TfcNonRegulier?) || ad_node.(:TfcPrive?))
|
60
|
+
].compact.each do |purpose|
|
61
|
+
limitation.add_condition do |condition|
|
62
|
+
condition.realm = limitation_type.fetch(:realm)
|
63
|
+
condition.origin = case
|
64
|
+
when ad_node.(:TfcIntl?) && ad_node.(:TfcNtl?) then :any
|
65
|
+
when ad_node.(:TfcIntl?) then :international
|
66
|
+
when ad_node.(:TfcNtl?) then :national
|
67
|
+
else :other
|
68
|
+
end
|
69
|
+
condition.rule = case
|
70
|
+
when ad_node.(:TfcIfr?) && ad_node.(:TfcVfr?) then :ifr_and_vfr
|
71
|
+
when ad_node.(:TfcIfr?) then :ifr
|
72
|
+
when ad_node.(:TfcVfr?) then :vfr
|
73
|
+
else
|
74
|
+
warn("falling back to VFR rule for `#{airport.id}'", severe: false)
|
75
|
+
:vfr
|
76
|
+
end
|
77
|
+
condition.purpose = purpose
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
# TODO: link to VAC once supported downstream
|
82
|
+
# # Link to VAC
|
83
|
+
# airport.remarks = [
|
84
|
+
# airport.remarks.to_s,
|
85
|
+
# link_to('VAC-AD', url_for("VAC-#{airport.id}"))
|
86
|
+
# ].join("\n")
|
87
|
+
cache.rwy.css(%Q(Rwy:has(Ad[pk="#{ad_node.attr(:pk)}"]))).each do |rwy_node|
|
88
|
+
add_runway_to(airport, rwy_node)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
add airport
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def id_from(content)
|
98
|
+
case content
|
99
|
+
when /^\d{2}$/ then 'LF00' + content # private aerodromes without official ID
|
100
|
+
else 'LF' + content
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_runway_to(airport, rwy_node)
|
105
|
+
AIXM.runway(
|
106
|
+
name: rwy_node.(:Rwy)
|
107
|
+
).tap do |runway|
|
108
|
+
rwylgt_nodes = cache.rwylgt.css(%Q(RwyLgt:has(Rwy[pk="#{rwy_node.attr(:pk)}"])))
|
109
|
+
airport.add_runway(runway)
|
110
|
+
runway.dimensions = AIXM.r(AIXM.d(rwy_node.(:Longueur)&.to_i, :m), AIXM.d(rwy_node.(:Largeur)&.to_i, :m))
|
111
|
+
runway.surface = surface_from(rwy_node)
|
112
|
+
runway.forth.geographic_bearing = given(rwy_node.(:OrientationGeo)) { AIXM.a(_1.to_f) }
|
113
|
+
runway.forth.xy = given(rwy_node.(:LatThr1), rwy_node.(:LongThr1)) { AIXM.xy(lat: _1.to_f, long: _2.to_f) }
|
114
|
+
runway.forth.displaced_threshold = given(rwy_node.(:LatDThr1), rwy_node.(:LongDThr1)) { AIXM.xy(lat: _1.to_f, long: _2.to_f) }
|
115
|
+
runway.forth.z = given(rwy_node.(:AltFtDThr1)) { AIXM.z(_1.to_i, :qnh) }
|
116
|
+
runway.forth.z ||= given(rwy_node.(:AltFtThr1)) { AIXM.z(_1.to_i, :qnh) }
|
117
|
+
if rwylgt_node = rwylgt_nodes[0]
|
118
|
+
runway.forth.vasis = vasis_from(rwylgt_node)
|
119
|
+
given(approach_lighting_from(rwylgt_node)) { runway.forth.add_approach_lighting(_1) }
|
120
|
+
LIGHTING_POSITIONS.each_key do |position|
|
121
|
+
given(lighting_from(rwylgt_node, position)) { runway.forth.add_lighting(_1) }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
if rwy_node.(:Rwy).match? '/'
|
125
|
+
runway.back.xy = given(rwy_node.(:LatThr2), rwy_node.(:LongThr2)) { AIXM.xy(lat: _1.to_f, long: _2.to_f) }
|
126
|
+
runway.back.displaced_threshold = given(rwy_node.(:LatDThr2), rwy_node.(:LongDThr2)) { AIXM.xy(lat: _1.to_f, long: _2.to_f) }
|
127
|
+
runway.back.z = given(rwy_node.(:AltFtDThr2)) { AIXM.z(_1.to_i, :qnh) }
|
128
|
+
runway.back.z ||= given(rwy_node.(:AltFtThr2)) { AIXM.z(_1.to_i, :qnh) }
|
129
|
+
if rwylgt_node = rwylgt_nodes[1]
|
130
|
+
runway.back.vasis = vasis_from(rwylgt_node)
|
131
|
+
given(approach_lighting_from(rwylgt_node)) { runway.back.add_approach_lighting(_1) }
|
132
|
+
LIGHTING_POSITIONS.each_key do |position|
|
133
|
+
given(lighting_from(rwylgt_node, position)) { runway.back.add_lighting(_1) }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def vasis_from(rwylgt_node)
|
141
|
+
if rwylgt_node.(:PapiVasis)
|
142
|
+
AIXM.vasis.tap do |vasis|
|
143
|
+
vasis.type = rwylgt_node.(:PapiVasis)
|
144
|
+
vasis.slope_angle = AIXM.a(rwylgt_node.(:PapiVasisPente).to_f)
|
145
|
+
vasis.meht = AIXM.z(rwylgt_node.(:MehtFt).to_i, :qfe)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def approach_lighting_from(rwylgt_node)
|
151
|
+
if rwylgt_node.(:LgtApchCat)
|
152
|
+
AIXM.approach_lighting(
|
153
|
+
type: APPROACH_LIGHTING_TYPES.fetch(rwylgt_node.(:LgtApchCat) , :other)
|
154
|
+
).tap do |approach_lighting|
|
155
|
+
approach_lighting.length = AIXM.d(rwylgt_node.(:LgtApchLongueur).to_i, :m) if rwylgt_node.(:LgtApchLongueur)
|
156
|
+
approach_lighting.intensity = rwylgt_node.(:LgtApchIntensite)&.first_match(/LIH/, /LIM/, /LIL/, default: :other)
|
157
|
+
approach_lighting.remarks = {
|
158
|
+
'type' => (rwylgt_node.(:LgtApchCat) if approach_lighting.type == :other),
|
159
|
+
'intensité/intensity' => (rwylgt_node.(:LgtApchIntensite) if approach_lighting.intensity == :other)
|
160
|
+
}.to_remarks
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def lighting_from(rwylgt_node, position)
|
166
|
+
prefix = "Lgt" + LIGHTING_POSITIONS.fetch(position)
|
167
|
+
if rwylgt_node.(:"#{prefix}Couleur") || rwylgt_node.(:"#{prefix}Longueur")
|
168
|
+
AIXM.lighting(position: position).tap do |lighting|
|
169
|
+
couleur, intensite = rwylgt_node.(:"#{prefix}Couleur"), rwylgt_node.(:"#{prefix}Intensite")
|
170
|
+
lighting.intensity = if intensite
|
171
|
+
intensite.first_match(/LIH/, /LIM/, /LIL/, default: :other)
|
172
|
+
elsif couleur
|
173
|
+
couleur.first_match(/LIH/, /LIM/, /LIL/).tap { couleur.remove!(/LIH|LIM|LIL/) }
|
174
|
+
end
|
175
|
+
lighting.color = if couleur
|
176
|
+
if couleur.match? /ICAO|EASA|OACI|AESA/
|
177
|
+
ICAO_LIGHTING_COLORS[position]
|
178
|
+
else
|
179
|
+
couleur.remove(/[^#{LIGHTING_COLORS.keys.join}]/).compact
|
180
|
+
LIGHTING_COLORS.fetch(couleur, :other)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
lighting.description = {
|
184
|
+
'couleur/color' => (rwylgt_node.(:"#{prefix}Couleur") if [nil, :other].include?(lighting.color)),
|
185
|
+
'longueur/length' => rwylgt_node.(:"#{prefix}Longueur"),
|
186
|
+
'espace/spacing' => rwylgt_node.(:"#{prefix}Espace")
|
187
|
+
}.to_remarks
|
188
|
+
lighting.remarks = rwylgt_node.(:LgtRem)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
patch AIXM::Feature::Airport, :xy do |parser, object, value|
|
194
|
+
throw(:abort) unless coordinate = parser.fixture.dig(object.id, 'xy')
|
195
|
+
lat, long = coordinate.split(/\s+/)
|
196
|
+
AIXM.xy(lat: lat, long: long)
|
197
|
+
end
|
198
|
+
|
199
|
+
patch AIXM::Feature::Airport, :z do |parser, object, value|
|
200
|
+
throw(:abort) unless value.nil?
|
201
|
+
throw(:abort, 'fixture missing') unless elevation = parser.fixture.dig(object.id, 'z')
|
202
|
+
AIXM.z(elevation, :qnh)
|
203
|
+
end
|
204
|
+
|
205
|
+
patch AIXM::Component::Runway, :dimensions do |parser, object, value|
|
206
|
+
throw(:abort) unless value.surface.zero?
|
207
|
+
throw(:abort, 'fixture missing') unless dimensions = parser.fixture.dig(object.airport.id, object.name, 'dimensions')
|
208
|
+
length, width = dimensions.split(/\D+/)
|
209
|
+
length = length&.match?(/^\d+$/) ? AIXM.d(length.to_i, :m) : value.length
|
210
|
+
width = width&.match?(/^\d+$/) ? AIXM.d(width.to_i, :m) : value.width
|
211
|
+
AIXM.r(length, width).tap { |r| throw(:abort, 'fixture incomplete') if r.surface.zero? }
|
212
|
+
end
|
213
|
+
|
214
|
+
patch AIXM::Component::Runway::Direction, :xy do |parser, object, value|
|
215
|
+
throw(:abort) unless value.nil?
|
216
|
+
throw(:abort, 'fixture missing') unless coordinate = parser.fixture.dig(object.runway.airport.id, object.name.to_s(:runway), 'xy')
|
217
|
+
lat, long = coordinate.split(/\s+/)
|
218
|
+
AIXM.xy(lat: lat, long: long)
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module AIPP
|
2
|
+
module LF
|
3
|
+
|
4
|
+
class DPRAirspaces < AIP
|
5
|
+
|
6
|
+
include AIPP::LF::Helpers::Base
|
7
|
+
|
8
|
+
# Map source types to type and optional local type
|
9
|
+
SOURCE_TYPES = {
|
10
|
+
'D' => { type: 'D' },
|
11
|
+
'P' => { type: 'P' },
|
12
|
+
'R' => { type: 'R' },
|
13
|
+
'ZIT' => { type: 'P', local_type: 'ZIT' }
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
# Radius to use for zones consisting of one point only
|
17
|
+
POINT_RADIUS = AIXM.d(1, :km).freeze
|
18
|
+
|
19
|
+
def parse
|
20
|
+
SOURCE_TYPES.each do |source_type, target|
|
21
|
+
verbose_info("processing #{source_type}")
|
22
|
+
cache.espace.css(%Q(Espace[lk^="[LF][#{source_type} "])).each do |espace_node|
|
23
|
+
# UPSTREAM: Espace[pk=300343] has no Partie/Volume (reported)
|
24
|
+
next if espace_node['pk'] == '300343'
|
25
|
+
partie_node = cache.partie.at_css(%Q(Partie:has(Espace[pk="#{espace_node['pk']}"])))
|
26
|
+
volume_node = cache.volume.at_css(%Q(Volume:has(Partie[pk="#{partie_node['pk']}"])))
|
27
|
+
name = "#{options[:region]}-#{source_type}#{espace_node.(:Nom)}".remove(/\s/)
|
28
|
+
add(
|
29
|
+
AIXM.airspace(
|
30
|
+
source: source(section: 'ENR', position: espace_node.line),
|
31
|
+
name: "#{name} #{partie_node.(:NomUsuel)}".strip,
|
32
|
+
type: target[:type],
|
33
|
+
local_type: target[:local_type]
|
34
|
+
).tap do |airspace|
|
35
|
+
airspace.geometry = geometry_from(partie_node.(:Contour))
|
36
|
+
if airspace.geometry.point? # convert point to circle
|
37
|
+
airspace.geometry = AIXM.geometry(
|
38
|
+
AIXM.circle(
|
39
|
+
center_xy: airspace.geometry.segments.first.xy,
|
40
|
+
radius: POINT_RADIUS
|
41
|
+
)
|
42
|
+
)
|
43
|
+
end
|
44
|
+
fail("geometry is not closed") unless airspace.geometry.closed?
|
45
|
+
airspace.add_layer layer_from(volume_node)
|
46
|
+
airspace.layers.first.timetable = timetable_from(volume_node.(:HorCode))
|
47
|
+
airspace.layers.first.remarks = volume_node.(:Activite)
|
48
|
+
end
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module AIPP
|
2
|
+
module LF
|
3
|
+
|
4
|
+
class DangerousActivities < AIP
|
5
|
+
|
6
|
+
include AIPP::LF::Helpers::Base
|
7
|
+
|
8
|
+
# Map raw activities to type of activity airspace
|
9
|
+
ACTIVITIES = {
|
10
|
+
'AP' => { activity: :other, airspace: :dangerous_activities_area },
|
11
|
+
'Aer' => { activity: :aeromodelling, airspace: :dangerous_activities_area },
|
12
|
+
'Bal' => { activity: :balloon, airspace: :dangerous_activities_area },
|
13
|
+
'Pje' => { activity: :parachuting, airspace: :dangerous_activities_area },
|
14
|
+
'TrPVL' => { activity: :glider_winch, airspace: :dangerous_activities_area },
|
15
|
+
'TrPla' => { activity: :glider_winch, airspace: :dangerous_activities_area },
|
16
|
+
'TrVL' => { activity: :glider_winch, airspace: :dangerous_activities_area },
|
17
|
+
'Vol' => { activity: :acrobatics, airspace: :dangerous_activities_area }
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
def parse
|
21
|
+
ACTIVITIES.each do |code, type|
|
22
|
+
verbose_info("processing #{code}")
|
23
|
+
cache.espace.css(%Q(Espace[lk^="[LF][#{code} "])).each do |espace_node|
|
24
|
+
partie_node = cache.partie.at_css(%Q(Partie:has(Espace[pk="#{espace_node['pk']}"])))
|
25
|
+
volume_node = cache.volume.at_css(%Q(Volume:has(Partie[pk="#{partie_node['pk']}"])))
|
26
|
+
add(
|
27
|
+
AIXM.airspace(
|
28
|
+
source: source(section: 'ENR', position: espace_node.line),
|
29
|
+
id: espace_node.(:Nom),
|
30
|
+
type: type[:airspace],
|
31
|
+
local_type: code.upcase,
|
32
|
+
name: [espace_node.(:Nom), partie_node.(:NomUsuel)].join(' ')
|
33
|
+
).tap do |airspace|
|
34
|
+
airspace.geometry = geometry_from partie_node.(:Contour)
|
35
|
+
layer_from(volume_node).then do |layer|
|
36
|
+
layer.activity = type[:activity]
|
37
|
+
airspace.add_layer layer
|
38
|
+
end
|
39
|
+
airspace.layers.first.timetable = timetable_from(volume_node.(:HorCode))
|
40
|
+
airspace.layers.first.remarks = volume_node.(:Remarque)
|
41
|
+
end
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module AIPP
|
2
|
+
module LF
|
3
|
+
|
4
|
+
class DesignatedPoints < AIP
|
5
|
+
|
6
|
+
include AIPP::LF::Helpers::Base
|
7
|
+
|
8
|
+
DEPENDS = %w(aerodromes)
|
9
|
+
|
10
|
+
SOURCE_TYPES = {
|
11
|
+
'VFR' => :vfr_reporting_point,
|
12
|
+
'WPT' => :icao
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
def parse
|
16
|
+
SOURCE_TYPES.each do |source_type, type|
|
17
|
+
verbose_info("processing #{source_type}")
|
18
|
+
cache.navfix.css(%Q(NavFix[lk^="[LF][#{source_type} "])).each do |navfix_node|
|
19
|
+
ident = navfix_node.(:Ident)
|
20
|
+
add(
|
21
|
+
AIXM.designated_point(
|
22
|
+
source: source(section: 'ENR', position: navfix_node.line),
|
23
|
+
type: type,
|
24
|
+
id: ident.split('-').last.remove(/[^a-z\d]/i), # only use last segment of ID
|
25
|
+
name: ident,
|
26
|
+
xy: xy_from(navfix_node.(:Geometrie))
|
27
|
+
).tap do |designated_point|
|
28
|
+
designated_point.remarks = navfix_node.(:Description)
|
29
|
+
if ident.match? /-/
|
30
|
+
airport = find_by(:airport, id: "LF#{ident.split('-').first}").first
|
31
|
+
designated_point.airport = airport
|
32
|
+
end
|
33
|
+
end
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
AIXM::Memoize.method :to_uid do
|
38
|
+
aixm.features.find_by(:designated_point).duplicates.each do |duplicates|
|
39
|
+
duplicates.first.name += '/' + duplicates[1..].map(&:name).join('/')
|
40
|
+
aixm.remove_features(duplicates[1..])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|