aixm 0.2.3 → 0.3.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
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.yardopts +3 -0
- data/CHANGELOG.md +34 -14
- data/Guardfile +1 -0
- data/README.md +64 -257
- data/lib/aixm.rb +16 -7
- data/lib/aixm/component.rb +6 -0
- data/lib/aixm/component/frequency.rb +135 -0
- data/lib/aixm/component/geometry.rb +34 -23
- data/lib/aixm/component/geometry/arc.rb +37 -22
- data/lib/aixm/component/geometry/border.rb +29 -20
- data/lib/aixm/component/geometry/circle.rb +39 -22
- data/lib/aixm/component/geometry/point.rb +29 -13
- data/lib/aixm/component/helipad.rb +154 -0
- data/lib/aixm/component/layer.rb +91 -0
- data/lib/aixm/component/runway.rb +294 -0
- data/lib/aixm/component/service.rb +170 -0
- data/lib/aixm/component/timetable.rb +65 -0
- data/lib/aixm/component/vertical_limits.rb +65 -29
- data/lib/aixm/config.rb +87 -0
- data/lib/aixm/document.rb +66 -42
- data/lib/aixm/errors.rb +11 -0
- data/lib/aixm/f.rb +34 -20
- data/lib/aixm/feature.rb +38 -0
- data/lib/aixm/feature/airport.rb +473 -0
- data/lib/aixm/feature/airspace.rb +145 -92
- data/lib/aixm/feature/navigational_aid.rb +94 -0
- data/lib/aixm/feature/navigational_aid/designated_point.rb +50 -54
- data/lib/aixm/feature/navigational_aid/dme.rb +48 -40
- data/lib/aixm/feature/navigational_aid/marker.rb +55 -45
- data/lib/aixm/feature/navigational_aid/ndb.rb +54 -50
- data/lib/aixm/feature/navigational_aid/tacan.rb +38 -31
- data/lib/aixm/feature/navigational_aid/vor.rb +84 -76
- data/lib/aixm/feature/organisation.rb +97 -0
- data/lib/aixm/feature/unit.rb +152 -0
- data/lib/aixm/refinements.rb +132 -47
- data/lib/aixm/shortcuts.rb +11 -6
- data/lib/aixm/version.rb +1 -1
- data/lib/aixm/xy.rb +64 -20
- data/lib/aixm/z.rb +51 -22
- data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-DataTypes.xsd +0 -0
- data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Features.xsd +0 -0
- data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Snapshot.xsd +0 -0
- data/schemas/ofmx/0/OFMX-DataTypes.xsd +5077 -0
- data/schemas/ofmx/0/OFMX-Features.xsd +9955 -0
- data/schemas/ofmx/0/OFMX-Snapshot.xsd +217 -0
- data/spec/factory.rb +209 -33
- data/spec/lib/aixm/component/frequency_spec.rb +75 -0
- data/spec/lib/aixm/component/geometry/arc_spec.rb +28 -22
- data/spec/lib/aixm/component/geometry/border_spec.rb +23 -20
- data/spec/lib/aixm/component/geometry/circle_spec.rb +31 -22
- data/spec/lib/aixm/component/geometry/point_spec.rb +11 -14
- data/spec/lib/aixm/component/geometry_spec.rb +150 -69
- data/spec/lib/aixm/component/helipad_spec.rb +136 -0
- data/spec/lib/aixm/component/layer_spec.rb +110 -0
- data/spec/lib/aixm/component/runway_spec.rb +402 -0
- data/spec/lib/aixm/component/service_spec.rb +61 -0
- data/spec/lib/aixm/component/timetable_spec.rb +49 -0
- data/spec/lib/aixm/component/vertical_limits_spec.rb +39 -20
- data/spec/lib/aixm/config_spec.rb +41 -0
- data/spec/lib/aixm/document_spec.rb +637 -147
- data/spec/lib/aixm/errors_spec.rb +14 -0
- data/spec/lib/aixm/f_spec.rb +17 -10
- data/spec/lib/aixm/feature/airport_spec.rb +546 -0
- data/spec/lib/aixm/feature/airspace_spec.rb +349 -226
- data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +47 -36
- data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +61 -36
- data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +61 -113
- data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +65 -79
- data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +57 -36
- data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +86 -112
- data/spec/lib/aixm/feature/navigational_aid_spec.rb +52 -0
- data/spec/lib/aixm/feature/organisation_spec.rb +77 -0
- data/spec/lib/aixm/feature/unit_spec.rb +227 -0
- data/spec/lib/aixm/feature_spec.rb +58 -0
- data/spec/lib/aixm/refinements_spec.rb +187 -178
- data/spec/lib/aixm/xy_spec.rb +45 -34
- data/spec/lib/aixm/z_spec.rb +19 -21
- data/spec/macros/organisation.rb +11 -0
- data/spec/macros/remarks.rb +12 -0
- data/spec/macros/timetable.rb +11 -0
- data/spec/macros/xy.rb +11 -0
- data/spec/macros/z_qnh.rb +11 -0
- data/spec/spec_helper.rb +26 -0
- metadata +60 -19
- data/lib/aixm/base.rb +0 -10
- data/lib/aixm/component/base.rb +0 -6
- data/lib/aixm/component/class_layer.rb +0 -46
- data/lib/aixm/component/geometry/base.rb +0 -8
- data/lib/aixm/component/schedule.rb +0 -43
- data/lib/aixm/feature/base.rb +0 -6
- data/lib/aixm/feature/navigational_aid/base.rb +0 -79
- data/spec/lib/aixm/component/class_layer_spec.rb +0 -74
- data/spec/lib/aixm/component/schedule_spec.rb +0 -33
- data/spec/lib/aixm/feature/navigational_aid/base_spec.rb +0 -41
|
@@ -1,126 +1,179 @@
|
|
|
1
|
+
using AIXM::Refinements
|
|
2
|
+
|
|
1
3
|
module AIXM
|
|
2
|
-
|
|
3
|
-
class Airspace < Base
|
|
4
|
-
using AIXM::Refinements
|
|
5
|
-
|
|
6
|
-
attr_reader :name, :short_name, :type, :schedule, :remarks
|
|
7
|
-
attr_accessor :geometry, :class_layers
|
|
8
|
-
|
|
9
|
-
##
|
|
10
|
-
# Airspace feature
|
|
11
|
-
#
|
|
12
|
-
# Options:
|
|
13
|
-
# * +name+ - full name of the airspace (will be converted to uppercase,
|
|
14
|
-
# e.g. +LF P 81+)
|
|
15
|
-
# * +short_name+ - short name of the airspace (will be converted to
|
|
16
|
-
# uppercase, e.g. +LF P 81 CHERBOURG+)
|
|
17
|
-
# * +type+ - airspace type (e.g. +TMA+ or +P+)
|
|
18
|
-
def initialize(name:, short_name: nil, type:)
|
|
19
|
-
self.name, self.short_name, self.type = name, short_name, type
|
|
20
|
-
@schedule = nil
|
|
21
|
-
@geometry = AIXM.geometry
|
|
22
|
-
@class_layers = []
|
|
23
|
-
end
|
|
4
|
+
class Feature
|
|
24
5
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
6
|
+
# Three-dimensional volume most notably defining flight zones.
|
|
7
|
+
#
|
|
8
|
+
# ===Cheat Sheet in Pseudo Code:
|
|
9
|
+
# airspace = AIXM.airspace(
|
|
10
|
+
# source: String or nil
|
|
11
|
+
# region: String or nil (falls back to AIXM.config.region)
|
|
12
|
+
# id: String
|
|
13
|
+
# type: String or Symbol
|
|
14
|
+
# name: String or nil
|
|
15
|
+
# short_name: String or nil
|
|
16
|
+
# )
|
|
17
|
+
# airspace.geometry << AIXM.point or AIXM.arc or AIXM.border or AIXM.circle
|
|
18
|
+
# airspace.layers << AIXM.layer
|
|
19
|
+
#
|
|
20
|
+
# @see https://github.com/openflightmaps/ofmx/wiki/Airspace#ase-airspace
|
|
21
|
+
class Airspace < Feature
|
|
22
|
+
public_class_method :new
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
TYPES = {
|
|
25
|
+
NAS: :national_airspace_system,
|
|
26
|
+
FIR: :flight_information_region,
|
|
27
|
+
'FIR-P': :part_of_flight_information_region,
|
|
28
|
+
UIR: :upper_flight_information_region,
|
|
29
|
+
'UIR-P': :part_of_upper_flight_information_region,
|
|
30
|
+
CTA: :control_area,
|
|
31
|
+
'CTA-P': :part_of_control_area,
|
|
32
|
+
OCA: :oceanic_control_area,
|
|
33
|
+
'OCA-P': :part_of_oceanic_control_area,
|
|
34
|
+
UTA: :upper_control_area,
|
|
35
|
+
'UTA-P': :part_of_upper_control_area,
|
|
36
|
+
TMA: :terminal_control_area,
|
|
37
|
+
'TMA-P': :part_of_terminal_control_area,
|
|
38
|
+
CTR: :control_zone,
|
|
39
|
+
'CTR-P': :part_of_control_zone,
|
|
40
|
+
CLASS: :airspace_with_class,
|
|
41
|
+
OTA: :oceanic_transition_area,
|
|
42
|
+
SECTOR: :control_sector,
|
|
43
|
+
'SECTOR-C': :temporarily_consolidated_sector,
|
|
44
|
+
TSA: :temporary_segregated_area,
|
|
45
|
+
TRA: :temporary_reserved_area,
|
|
46
|
+
CBA: :cross_border_area,
|
|
47
|
+
RCA: :reduced_coordination_airspace_procedure,
|
|
48
|
+
RAS: :regulated_airspace,
|
|
49
|
+
AWY: :airway,
|
|
50
|
+
P: :prohibited_area,
|
|
51
|
+
R: :restricted_area,
|
|
52
|
+
'R-AMC': :amc_manageable_restricted_area,
|
|
53
|
+
D: :danger_area,
|
|
54
|
+
'D-AMC': :amc_manageable_danger_area,
|
|
55
|
+
'D-OTHER': :dangerous_activities_area,
|
|
56
|
+
ADIZ: :air_defense_identification_zone,
|
|
57
|
+
A: :alert_area,
|
|
58
|
+
W: :warning_area,
|
|
59
|
+
PROTECT: :protected_from_specific_air_traffic,
|
|
60
|
+
AMA: :minimum_altitude_area,
|
|
61
|
+
ASR: :altimeter_setting_region,
|
|
62
|
+
'NO-FIR': :airspace_outside_any_flight_information_region,
|
|
63
|
+
POLITICAL: :political_area,
|
|
64
|
+
PART: :part_of_airspace
|
|
65
|
+
}.freeze
|
|
66
|
+
|
|
67
|
+
# @note When assigning +nil+, a 4 byte hex derived from {#type}, {#name}
|
|
68
|
+
# and {#short_name} is written instead.
|
|
69
|
+
# @return [String] published identifier (e.g. "LFP81")
|
|
70
|
+
attr_reader :id
|
|
71
|
+
|
|
72
|
+
# @return [Symbol] type of airspace (see {TYPES})
|
|
73
|
+
attr_reader :type
|
|
74
|
+
|
|
75
|
+
# @return [String, nil] full name (e.g. "LF P 81 CHERBOURG")
|
|
76
|
+
attr_reader :name
|
|
77
|
+
|
|
78
|
+
# @return [String, nil] short name (e.g. "LF P 81")
|
|
79
|
+
attr_reader :short_name
|
|
80
|
+
|
|
81
|
+
# @return [AIXM::Component::Geometry] horizontal geometrical shape
|
|
82
|
+
attr_accessor :geometry
|
|
83
|
+
|
|
84
|
+
# @return [Array<AIXM::Compoment::Layer>] vertical layers
|
|
85
|
+
attr_accessor :layers
|
|
86
|
+
|
|
87
|
+
def initialize(source: nil, region: nil, id: nil, type:, name: nil, short_name: nil)
|
|
88
|
+
super(source: source, region: region)
|
|
89
|
+
self.type, self.name, self.short_name = type, name, short_name
|
|
90
|
+
self.id = id
|
|
91
|
+
@geometry = AIXM.geometry
|
|
92
|
+
@layers = []
|
|
33
93
|
end
|
|
34
94
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
95
|
+
# @return [String]
|
|
96
|
+
def inspect
|
|
97
|
+
%Q(#<#{self.class} type=#{type.inspect} name=#{name.inspect}>)
|
|
38
98
|
end
|
|
39
99
|
|
|
40
|
-
def
|
|
41
|
-
fail(ArgumentError, "invalid
|
|
42
|
-
@
|
|
100
|
+
def id=(value)
|
|
101
|
+
fail(ArgumentError, "invalid id") unless value.nil? || value.is_a?(String)
|
|
102
|
+
@id = value&.uptrans || [type, name, short_name].to_digest.upcase
|
|
43
103
|
end
|
|
44
104
|
|
|
45
|
-
def
|
|
46
|
-
fail(ArgumentError, "invalid
|
|
47
|
-
@remarks = value
|
|
105
|
+
def type=(value)
|
|
106
|
+
@type = TYPES.lookup(value&.to_s&.to_sym, nil) || fail(ArgumentError, "invalid type")
|
|
48
107
|
end
|
|
49
108
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
!!name && !!type && class_layers.any? && geometry.complete?
|
|
109
|
+
def name=(value)
|
|
110
|
+
fail(ArgumentError, "invalid name") unless value.nil? || value.is_a?(String)
|
|
111
|
+
@name = value&.uptrans
|
|
54
112
|
end
|
|
55
113
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
[name, short_name, type, schedule&.to_digest, class_layers.map(&:to_digest), geometry.to_digest, remarks].to_digest
|
|
114
|
+
def short_name=(value)
|
|
115
|
+
fail(ArgumentError, "invalid short name") unless value.nil? || value.is_a?(String)
|
|
116
|
+
@short_name = value&.uptrans
|
|
60
117
|
end
|
|
61
118
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def to_uid(*extensions)
|
|
65
|
-
mid = to_digest
|
|
119
|
+
# @return [String] UID markup
|
|
120
|
+
def to_uid(as: :AseUid)
|
|
66
121
|
builder = Builder::XmlMarkup.new(indent: 2)
|
|
67
|
-
builder.
|
|
68
|
-
|
|
69
|
-
|
|
122
|
+
builder.tag!(as, { region: (region if AIXM.ofmx?) }.compact) do |tag|
|
|
123
|
+
tag.codeType(TYPES.key(type).to_s)
|
|
124
|
+
tag.codeId(id)
|
|
70
125
|
end
|
|
71
126
|
end
|
|
72
127
|
|
|
73
|
-
|
|
74
|
-
#
|
|
75
|
-
|
|
76
|
-
|
|
128
|
+
# @raise [AIXM::GeometryError] if the geometry is not closed
|
|
129
|
+
# @raise [AIXM::LayerError] if no layers are defined
|
|
130
|
+
# @return [String] AIXM or OFMX markup
|
|
131
|
+
def to_xml
|
|
132
|
+
fail(LayerError, "no layers defined") unless layers.any?
|
|
77
133
|
builder = Builder::XmlMarkup.new(indent: 2)
|
|
78
|
-
builder.comment! "Airspace: [#{type}] #{name}"
|
|
79
|
-
builder.Ase({
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
ase <<
|
|
84
|
-
if
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
134
|
+
builder.comment! "Airspace: [#{TYPES.key(type)}] #{name || :UNNAMED}"
|
|
135
|
+
builder.Ase({
|
|
136
|
+
source: (source if AIXM.ofmx?),
|
|
137
|
+
classLayers: (layers.count if AIXM.ofmx? && layered?)
|
|
138
|
+
}.compact) do |ase|
|
|
139
|
+
ase << to_uid.indent(2)
|
|
140
|
+
ase.txtLocalType(short_name) if short_name && short_name != name
|
|
141
|
+
ase.txtName(name) if name
|
|
142
|
+
unless layered?
|
|
143
|
+
ase << layers.first.to_xml.indent(2)
|
|
88
144
|
end
|
|
89
|
-
ase.txtRmk(remarks.to_s) if remarks
|
|
90
|
-
ase.xt_selAvail(false) if extensions >> :ofm
|
|
91
145
|
end
|
|
92
146
|
builder.Abd do |abd|
|
|
93
|
-
abd.AbdUid do |
|
|
94
|
-
|
|
95
|
-
aseuid.codeType(type)
|
|
96
|
-
aseuid.codeId(mid)
|
|
97
|
-
end
|
|
147
|
+
abd.AbdUid do |abd_uid|
|
|
148
|
+
abd_uid << to_uid.indent(4)
|
|
98
149
|
end
|
|
99
|
-
abd << geometry.
|
|
150
|
+
abd << geometry.to_xml.indent(2)
|
|
100
151
|
end
|
|
101
|
-
if
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
adg.AdgUid do |adguid|
|
|
105
|
-
adguid.AseUid(mid: "#{mid}.#{index + 1}") do |aseuid|
|
|
106
|
-
aseuid.codeType("CLASS")
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
adg.AseUidSameExtent(mid: mid)
|
|
111
|
-
end
|
|
112
|
-
class_layers.each.with_index do |class_layer, index|
|
|
152
|
+
if layered?
|
|
153
|
+
layers.each.with_index do |layer, index|
|
|
154
|
+
layer_airspace = AIXM.airspace(region: region, type: 'CLASS', name: "#{name} LAYER #{index + 1}")
|
|
113
155
|
builder.Ase do |ase|
|
|
114
|
-
ase.
|
|
115
|
-
|
|
156
|
+
ase << layer_airspace.to_uid.indent(2)
|
|
157
|
+
ase.txtName(layer_airspace.name)
|
|
158
|
+
ase << layers[index].to_xml.indent(2)
|
|
159
|
+
end
|
|
160
|
+
builder.Adg do |adg|
|
|
161
|
+
adg.AdgUid do |adg_uid|
|
|
162
|
+
adg_uid << layer_airspace.to_uid.indent(4)
|
|
116
163
|
end
|
|
117
|
-
|
|
118
|
-
ase << class_layers[index].to_aixm(*extensions).indent(2)
|
|
164
|
+
adg << to_uid(as: :AseUidSameExtent).indent(2)
|
|
119
165
|
end
|
|
120
166
|
end
|
|
121
167
|
end
|
|
122
|
-
builder.target!
|
|
168
|
+
builder.target!
|
|
123
169
|
end
|
|
170
|
+
|
|
171
|
+
private
|
|
172
|
+
|
|
173
|
+
def layered?
|
|
174
|
+
layers.count > 1
|
|
175
|
+
end
|
|
176
|
+
|
|
124
177
|
end
|
|
125
178
|
end
|
|
126
179
|
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
using AIXM::Refinements
|
|
2
|
+
|
|
3
|
+
module AIXM
|
|
4
|
+
class Feature
|
|
5
|
+
|
|
6
|
+
# @abstract
|
|
7
|
+
class NavigationalAid < Feature
|
|
8
|
+
private_class_method :new
|
|
9
|
+
|
|
10
|
+
# @return [AIXM::Feature::Organisation] superior organisation
|
|
11
|
+
attr_reader :organisation
|
|
12
|
+
|
|
13
|
+
# @return [String] published identifier
|
|
14
|
+
attr_reader :id
|
|
15
|
+
|
|
16
|
+
# @return [String, nil] name of the navigational aid
|
|
17
|
+
attr_reader :name
|
|
18
|
+
|
|
19
|
+
# @return [AIXM::XY] geographic position
|
|
20
|
+
attr_reader :xy
|
|
21
|
+
|
|
22
|
+
# @return [AIXM::Z, nil] elevation in +:qnh+
|
|
23
|
+
attr_reader :z
|
|
24
|
+
|
|
25
|
+
# @return [AIXM::Component::Timetable, nil] operating hours
|
|
26
|
+
attr_reader :timetable
|
|
27
|
+
|
|
28
|
+
# @return [String, nil] free text remarks
|
|
29
|
+
attr_reader :remarks
|
|
30
|
+
|
|
31
|
+
def initialize(source: nil, region: nil, organisation:, id:, name: nil, xy:, z: nil)
|
|
32
|
+
super(source: source, region: region)
|
|
33
|
+
self.organisation, self.id, self.name, self.xy, self.z = organisation, id, name, xy, z
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @return [String]
|
|
37
|
+
def inspect
|
|
38
|
+
%Q(#<#{self.class} id=#{id.inspect} name=#{name.inspect}>)
|
|
39
|
+
end
|
|
40
|
+
|
|
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
|
+
def id=(value)
|
|
47
|
+
fail(ArgumentError, "invalid id") unless value.is_a? String
|
|
48
|
+
@id = value.upcase
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def name=(value)
|
|
52
|
+
fail(ArgumentError, "invalid name") unless value.nil? || value.is_a?(String)
|
|
53
|
+
@name = value&.uptrans
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def xy=(value)
|
|
57
|
+
fail(ArgumentError, "invalid xy") unless value.is_a? AIXM::XY
|
|
58
|
+
@xy = value
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def z=(value)
|
|
62
|
+
fail(ArgumentError, "invalid z") unless value.nil? || (value.is_a?(AIXM::Z) && value.qnh?)
|
|
63
|
+
@z = value
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def timetable=(value)
|
|
67
|
+
fail(ArgumentError, "invalid timetable") unless value.nil? || value.is_a?(AIXM::Component::Timetable)
|
|
68
|
+
@timetable = value
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def remarks=(value)
|
|
72
|
+
@remarks = value&.to_s
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @return [String] fully descriptive combination of {#class} and {#type} key
|
|
76
|
+
def kind
|
|
77
|
+
[self.class.name.split('::').last, type_key].compact.join(':')
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def type_key
|
|
83
|
+
nil
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def to_builder
|
|
87
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
|
88
|
+
builder.comment! "NavigationalAid: [#{kind}] #{name || :UNNAMED}"
|
|
89
|
+
builder
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -1,81 +1,77 @@
|
|
|
1
|
+
using AIXM::Refinements
|
|
2
|
+
|
|
1
3
|
module AIXM
|
|
2
|
-
|
|
3
|
-
|
|
4
|
+
class Feature
|
|
5
|
+
class NavigationalAid
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
+
# Named geographical location used in defining an ATS route, aircraft
|
|
8
|
+
# flight paths or for other navigation purposes.
|
|
9
|
+
#
|
|
10
|
+
# ===Cheat Sheet in Pseudo Code:
|
|
11
|
+
# designated_point = AIXM.designated_point(
|
|
12
|
+
# source: String or nil
|
|
13
|
+
# region: String or nil (falls back to AIXM.config.region)
|
|
14
|
+
# id: String
|
|
15
|
+
# name: String or nil
|
|
16
|
+
# xy: AIXM.xy
|
|
17
|
+
# type: TYPES
|
|
18
|
+
# )
|
|
19
|
+
# designated_point.remarks = String or nil
|
|
7
20
|
#
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class DesignatedPoint < Base
|
|
14
|
-
using AIXM::Refinements
|
|
21
|
+
# @see https://github.com/openflightmaps/ofmx/wiki/Navigational-aid#dpn-designated-point
|
|
22
|
+
class DesignatedPoint < NavigationalAid
|
|
23
|
+
public_class_method :new
|
|
24
|
+
private :organisation=
|
|
25
|
+
private :organisation
|
|
15
26
|
|
|
16
27
|
TYPES = {
|
|
17
|
-
ICAO: :icao,
|
|
18
|
-
ADHP: :adhp,
|
|
19
|
-
COORD: :coordinates
|
|
28
|
+
ICAO: :icao, # five-letter ICAO name
|
|
29
|
+
ADHP: :adhp, # airport related name
|
|
30
|
+
COORD: :coordinates, # derived from geographical coordinates
|
|
31
|
+
OTHER: :other # specify in remarks
|
|
20
32
|
}.freeze
|
|
21
33
|
|
|
34
|
+
# @return [Symbol] type of designated point
|
|
22
35
|
attr_reader :type
|
|
23
36
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def initialize(id:, name: nil, xy:, z: nil, type:)
|
|
27
|
-
super(id: id, name: name, xy: xy, z: z)
|
|
37
|
+
def initialize(type:, **arguments)
|
|
38
|
+
super(organisation: false, z: nil, **arguments)
|
|
28
39
|
self.type = type
|
|
29
40
|
end
|
|
30
41
|
|
|
31
42
|
def type=(value)
|
|
32
|
-
@type = TYPES.lookup(value&.to_sym, nil) || fail(ArgumentError, "invalid type")
|
|
43
|
+
@type = TYPES.lookup(value&.to_s&.to_sym, nil) || fail(ArgumentError, "invalid type")
|
|
33
44
|
end
|
|
34
45
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
##
|
|
40
|
-
# Digest to identify the payload
|
|
41
|
-
def to_digest
|
|
42
|
-
[super, type].to_digest
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
##
|
|
46
|
-
# Render UID markup
|
|
47
|
-
def to_uid(*extensions)
|
|
46
|
+
# @return [String] UID markup
|
|
47
|
+
def to_uid
|
|
48
48
|
builder = Builder::XmlMarkup.new(indent: 2)
|
|
49
|
-
builder.DpnUid({
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
builder.DpnUid({ region: (region if AIXM.ofmx?) }.compact) do |dpn_uid|
|
|
50
|
+
dpn_uid.codeId(id)
|
|
51
|
+
dpn_uid.geoLat(xy.lat(AIXM.schema))
|
|
52
|
+
dpn_uid.geoLong(xy.long(AIXM.schema))
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
builder
|
|
60
|
-
|
|
61
|
-
dpn << to_uid(*extensions).indent(2)
|
|
62
|
-
dpn.OrgUid
|
|
63
|
-
dpn.txtName(name) if name
|
|
56
|
+
# @return [String] AIXM or OFMX markup
|
|
57
|
+
def to_xml
|
|
58
|
+
builder = to_builder
|
|
59
|
+
builder.Dpn({ source: (source if AIXM.ofmx?) }.compact) do |dpn|
|
|
60
|
+
dpn << to_uid.indent(2)
|
|
64
61
|
dpn.codeDatum('WGE')
|
|
65
62
|
dpn.codeType(type_key.to_s)
|
|
66
|
-
if
|
|
67
|
-
dpn.valElev(z.alt)
|
|
68
|
-
dpn.uomDistVer(z.unit.to_s)
|
|
69
|
-
end
|
|
70
|
-
if schedule
|
|
71
|
-
dpn.Dtt do |dtt|
|
|
72
|
-
dtt << schedule.to_aixm(*extensions).indent(4)
|
|
73
|
-
end
|
|
74
|
-
end
|
|
63
|
+
dpn.txtName(name) if name
|
|
75
64
|
dpn.txtRmk(remarks) if remarks
|
|
76
|
-
dpn.target!
|
|
65
|
+
dpn.target!
|
|
77
66
|
end
|
|
78
67
|
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def type_key
|
|
72
|
+
TYPES.key(type)
|
|
73
|
+
end
|
|
74
|
+
|
|
79
75
|
end
|
|
80
76
|
|
|
81
77
|
end
|