aixm 0.2.0 → 0.2.1
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/CHANGELOG.md +10 -0
- data/README.md +149 -116
- data/lib/aixm/component/class_layer.rb +3 -3
- data/lib/aixm/component/geometry.rb +3 -3
- data/lib/aixm/component/geometry/arc.rb +2 -2
- data/lib/aixm/component/geometry/border.rb +2 -2
- data/lib/aixm/component/geometry/circle.rb +2 -2
- data/lib/aixm/component/geometry/point.rb +2 -2
- data/lib/aixm/component/schedule.rb +2 -2
- data/lib/aixm/component/vertical_limits.rb +2 -2
- data/lib/aixm/document.rb +4 -4
- data/lib/aixm/feature/airspace.rb +42 -17
- data/lib/aixm/feature/navigational_aid/base.rb +41 -8
- data/lib/aixm/feature/navigational_aid/designated_point.rb +29 -15
- data/lib/aixm/feature/navigational_aid/dme.rb +32 -9
- data/lib/aixm/feature/navigational_aid/marker.rb +25 -7
- data/lib/aixm/feature/navigational_aid/ndb.rb +25 -9
- data/lib/aixm/feature/navigational_aid/tacan.rb +21 -20
- data/lib/aixm/feature/navigational_aid/vor.rb +66 -26
- data/lib/aixm/version.rb +1 -1
- data/spec/factory.rb +69 -13
- data/spec/lib/aixm/component/class_layer_spec.rb +4 -4
- data/spec/lib/aixm/component/geometry/arc_spec.rb +3 -3
- data/spec/lib/aixm/component/geometry/border_spec.rb +2 -2
- data/spec/lib/aixm/component/geometry/circle_spec.rb +3 -3
- data/spec/lib/aixm/component/geometry/point_spec.rb +3 -3
- data/spec/lib/aixm/component/geometry_spec.rb +4 -4
- data/spec/lib/aixm/component/schedule_spec.rb +2 -2
- data/spec/lib/aixm/component/vertical_limits_spec.rb +4 -4
- data/spec/lib/aixm/document_spec.rb +282 -28
- data/spec/lib/aixm/feature/airspace_spec.rb +14 -10
- data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +9 -6
- data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +9 -6
- data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +7 -4
- data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +9 -6
- data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +9 -6
- data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +156 -7
- metadata +2 -2
@@ -35,8 +35,8 @@ module AIXM
|
|
35
35
|
end
|
36
36
|
|
37
37
|
##
|
38
|
-
# Render AIXM
|
39
|
-
def
|
38
|
+
# Render AIXM markup
|
39
|
+
def to_aixm(*extensions)
|
40
40
|
%i(upper lower max min).each_with_object(Builder::XmlMarkup.new(indent: 2)) do |limit, builder|
|
41
41
|
if z = send(:"#{limit}_z")
|
42
42
|
builder.tag!(:"codeDistVer#{TAGS[limit]}", CODES[z.code].to_s)
|
data/lib/aixm/document.rb
CHANGED
@@ -34,17 +34,17 @@ module AIXM
|
|
34
34
|
# Validate against the XSD and return an array of errors
|
35
35
|
def errors
|
36
36
|
xsd = Nokogiri::XML::Schema(File.open(AIXM::SCHEMA))
|
37
|
-
xsd.validate(Nokogiri::XML(
|
37
|
+
xsd.validate(Nokogiri::XML(to_aixm)).reject do |error|
|
38
38
|
error.message =~ IGNORE_ERROR_PATTERN
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
42
|
##
|
43
|
-
# Render AIXM
|
43
|
+
# Render AIXM markup
|
44
44
|
#
|
45
45
|
# Extensions:
|
46
46
|
# * +:ofm+ - Open Flightmaps
|
47
|
-
def
|
47
|
+
def to_aixm(*extensions)
|
48
48
|
now = Time.now.xmlschema
|
49
49
|
meta = {
|
50
50
|
'xmlns:xsi': 'http://www.aixm.aero/schema/4.5/AIXM-Snapshot.xsd',
|
@@ -57,7 +57,7 @@ module AIXM
|
|
57
57
|
builder = Builder::XmlMarkup.new(indent: 2)
|
58
58
|
builder.instruct!
|
59
59
|
builder.tag!('AIXM-Snapshot', meta) do |aixm_snapshot|
|
60
|
-
aixm_snapshot << features.map { |f| f.
|
60
|
+
aixm_snapshot << features.map { |f| f.to_aixm(*extensions) }.join.indent(2)
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
@@ -3,9 +3,8 @@ module AIXM
|
|
3
3
|
class Airspace < Base
|
4
4
|
using AIXM::Refinements
|
5
5
|
|
6
|
-
attr_reader :name, :short_name, :type
|
7
|
-
|
8
|
-
attr_accessor :geometry, :class_layers, :remarks
|
6
|
+
attr_reader :name, :short_name, :type, :schedule, :remarks
|
7
|
+
attr_accessor :geometry, :class_layers
|
9
8
|
|
10
9
|
##
|
11
10
|
# Airspace feature
|
@@ -17,19 +16,37 @@ module AIXM
|
|
17
16
|
# uppercase, e.g. +LF P 81 CHERBOURG+)
|
18
17
|
# * +type+ - airspace type (e.g. +TMA+ or +P+)
|
19
18
|
def initialize(name:, short_name: nil, type:)
|
20
|
-
|
19
|
+
self.name, self.short_name, self.type = name, short_name, type
|
21
20
|
@schedule = nil
|
22
21
|
@geometry = AIXM.geometry
|
23
22
|
@class_layers = []
|
24
23
|
end
|
25
24
|
|
26
|
-
|
27
|
-
|
25
|
+
def name=(value)
|
26
|
+
fail(AttributeError, "invalid name") unless value.is_a? String
|
27
|
+
@name = value.uptrans
|
28
|
+
end
|
29
|
+
|
30
|
+
def short_name=(value)
|
31
|
+
fail(AttributeError, "invalid short name") unless value.nil? || value.is_a?(String)
|
32
|
+
@short_name = value&.uptrans
|
33
|
+
end
|
34
|
+
|
35
|
+
def type=(value)
|
36
|
+
fail(AttributeError, "invalid type") unless value.is_a?(String)
|
37
|
+
@type = value.upcase
|
38
|
+
end
|
39
|
+
|
28
40
|
def schedule=(value)
|
29
41
|
fail(ArgumentError, "invalid schedule") unless value.nil? || value.is_a?(AIXM::Component::Schedule)
|
30
42
|
@schedule = value
|
31
43
|
end
|
32
44
|
|
45
|
+
def remarks=(value)
|
46
|
+
fail(AttributeError, "invalid remarks") unless value.is_a?(String)
|
47
|
+
@remarks = value
|
48
|
+
end
|
49
|
+
|
33
50
|
##
|
34
51
|
# Check whether the airspace is complete
|
35
52
|
def complete?
|
@@ -43,22 +60,30 @@ module AIXM
|
|
43
60
|
end
|
44
61
|
|
45
62
|
##
|
46
|
-
# Render
|
47
|
-
def
|
63
|
+
# Render UID markup
|
64
|
+
def to_uid(*extensions)
|
65
|
+
mid = to_digest
|
66
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
67
|
+
builder.AseUid({ mid: mid, newEntity: (true if extensions >> :ofm) }.compact) do |aseuid|
|
68
|
+
aseuid.codeType(type)
|
69
|
+
aseuid.codeId(mid)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
##
|
74
|
+
# Render AIXM markup
|
75
|
+
def to_aixm(*extensions)
|
48
76
|
mid = to_digest
|
49
77
|
builder = Builder::XmlMarkup.new(indent: 2)
|
50
78
|
builder.comment! "Airspace: [#{type}] #{name}"
|
51
79
|
builder.Ase({ xt_classLayersAvail: ((class_layers.count > 1) if extensions >> :ofm) }.compact) do |ase|
|
52
|
-
ase
|
53
|
-
aseuid.codeType(type.to_s)
|
54
|
-
aseuid.codeId(mid)
|
55
|
-
end
|
80
|
+
ase << to_uid(*extensions).indent(2)
|
56
81
|
ase.txtLocalType(short_name.to_s) if short_name && short_name != name
|
57
82
|
ase.txtName(name.to_s)
|
58
|
-
ase << class_layers.first.
|
83
|
+
ase << class_layers.first.to_aixm(*extensions).indent(2)
|
59
84
|
if schedule
|
60
85
|
ase.Att do |att|
|
61
|
-
att << schedule.
|
86
|
+
att << schedule.to_aixm(*extensions).indent(4)
|
62
87
|
end
|
63
88
|
end
|
64
89
|
ase.txtRmk(remarks.to_s) if remarks
|
@@ -67,11 +92,11 @@ module AIXM
|
|
67
92
|
builder.Abd do |abd|
|
68
93
|
abd.AbdUid do |abduid|
|
69
94
|
abduid.AseUid({ mid: mid, newEntity: (true if extensions >> :ofm) }.compact) do |aseuid|
|
70
|
-
aseuid.codeType(type
|
95
|
+
aseuid.codeType(type)
|
71
96
|
aseuid.codeId(mid)
|
72
97
|
end
|
73
98
|
end
|
74
|
-
abd << geometry.
|
99
|
+
abd << geometry.to_aixm(*extensions).indent(2)
|
75
100
|
end
|
76
101
|
if class_layers.count > 1
|
77
102
|
builder.Adg do |adg|
|
@@ -90,7 +115,7 @@ module AIXM
|
|
90
115
|
aseuid.codeType("CLASS")
|
91
116
|
end
|
92
117
|
ase.txtName(name.to_s)
|
93
|
-
ase << class_layers[index].
|
118
|
+
ase << class_layers[index].to_aixm(*extensions).indent(2)
|
94
119
|
end
|
95
120
|
end
|
96
121
|
end
|
@@ -9,21 +9,48 @@ module AIXM
|
|
9
9
|
class Base < AIXM::Feature::Base
|
10
10
|
using AIXM::Refinements
|
11
11
|
|
12
|
-
attr_reader :id, :name, :xy, :z
|
13
|
-
attr_accessor :remarks
|
12
|
+
attr_reader :id, :name, :xy, :z, :schedule, :remarks
|
14
13
|
|
15
14
|
private_class_method :new
|
16
15
|
|
17
16
|
def initialize(id:, name:, xy:, z: nil)
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
self.id, self.name, self.xy, self.z = id, name, xy, z
|
18
|
+
end
|
19
|
+
|
20
|
+
def id=(value)
|
21
|
+
fail(ArgumentError, "invalid id") unless value.is_a? String
|
22
|
+
@id = value.upcase
|
23
|
+
end
|
24
|
+
|
25
|
+
def name=(value)
|
26
|
+
fail(ArgumentError, "invalid name") unless value.is_a? String
|
27
|
+
@name = value.upcase
|
28
|
+
end
|
29
|
+
|
30
|
+
def xy=(value)
|
31
|
+
fail(ArgumentError, "invalid xy") unless value.is_a? AIXM::XY
|
32
|
+
@xy = value
|
33
|
+
end
|
34
|
+
|
35
|
+
def z=(value)
|
36
|
+
fail(ArgumentError, "invalid z") unless value.nil? || (value.is_a?(AIXM::Z) && value.qnh?)
|
37
|
+
@z = value
|
38
|
+
end
|
39
|
+
|
40
|
+
def schedule=(value)
|
41
|
+
fail(ArgumentError, "invalid schedule") unless value.nil? || value.is_a?(AIXM::Component::Schedule)
|
42
|
+
@schedule = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def remarks=(value)
|
46
|
+
fail(ArgumentError, "invalid remarks") unless value.nil? || value.is_a?(String)
|
47
|
+
@remarks = value
|
21
48
|
end
|
22
49
|
|
23
50
|
##
|
24
|
-
# Return
|
51
|
+
# Return a fully descriptive combination of +class+ and +type_key+
|
25
52
|
def kind
|
26
|
-
|
53
|
+
[self.class.name.split('::').last, type_key].compact.join(':')
|
27
54
|
end
|
28
55
|
|
29
56
|
##
|
@@ -36,9 +63,15 @@ module AIXM
|
|
36
63
|
# Create builder to render AIXM in subclasses
|
37
64
|
def to_builder(*extensions)
|
38
65
|
builder = Builder::XmlMarkup.new(indent: 2)
|
39
|
-
builder.comment! "
|
66
|
+
builder.comment! "NavigationalAid: [#{kind}] #{name}"
|
40
67
|
builder
|
41
68
|
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Fallback type key
|
72
|
+
def type_key
|
73
|
+
nil
|
74
|
+
end
|
42
75
|
end
|
43
76
|
|
44
77
|
end
|
@@ -10,15 +10,13 @@ module AIXM
|
|
10
10
|
# * +:adhp+ (+:ADHP+) - aerodrome/heliport related name code designator
|
11
11
|
# * +:coordinates+ (+:COORD+) - point with identifier derived from its
|
12
12
|
# geographical coordinates
|
13
|
-
# * +:other+ (+:OTHER+) - other type
|
14
13
|
class DesignatedPoint < Base
|
15
14
|
using AIXM::Refinements
|
16
15
|
|
17
16
|
TYPES = {
|
18
17
|
ICAO: :icao,
|
19
18
|
ADHP: :adhp,
|
20
|
-
COORD: :coordinates
|
21
|
-
OTHER: :other
|
19
|
+
COORD: :coordinates
|
22
20
|
}.freeze
|
23
21
|
|
24
22
|
attr_reader :type
|
@@ -27,7 +25,15 @@ module AIXM
|
|
27
25
|
|
28
26
|
def initialize(id:, name:, xy:, z: nil, type:)
|
29
27
|
super(id: id, name: name, xy: xy, z: z)
|
30
|
-
|
28
|
+
self.type = type
|
29
|
+
end
|
30
|
+
|
31
|
+
def type=(value)
|
32
|
+
@type = TYPES.lookup(value&.to_sym, nil) || fail(ArgumentError, "invalid type")
|
33
|
+
end
|
34
|
+
|
35
|
+
def type_key
|
36
|
+
TYPES.key(type)
|
31
37
|
end
|
32
38
|
|
33
39
|
##
|
@@ -37,15 +43,22 @@ module AIXM
|
|
37
43
|
end
|
38
44
|
|
39
45
|
##
|
40
|
-
# Render
|
41
|
-
def
|
46
|
+
# Render UID markup
|
47
|
+
def to_uid(*extensions)
|
48
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
49
|
+
builder.DpnUid({ newEntity: (true if extensions >> :ofm) }.compact) do |dpnuid|
|
50
|
+
dpnuid.codeId(id)
|
51
|
+
dpnuid.geoLat(xy.lat(format_for(*extensions)))
|
52
|
+
dpnuid.geoLong(xy.long(format_for(*extensions)))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Render AIXM markup
|
58
|
+
def to_aixm(*extensions)
|
42
59
|
builder = to_builder(*extensions)
|
43
60
|
builder.Dpn do |dpn|
|
44
|
-
dpn
|
45
|
-
dpnuid.codeId(id)
|
46
|
-
dpnuid.geoLat(xy.lat(format_for(*extensions)))
|
47
|
-
dpnuid.geoLong(xy.long(format_for(*extensions)))
|
48
|
-
end
|
61
|
+
dpn << to_uid(*extensions).indent(2)
|
49
62
|
dpn.OrgUid
|
50
63
|
dpn.txtName(name)
|
51
64
|
dpn.codeDatum('WGE')
|
@@ -54,14 +67,15 @@ module AIXM
|
|
54
67
|
dpn.valElev(z.alt)
|
55
68
|
dpn.uomDistVer(z.unit.to_s)
|
56
69
|
end
|
70
|
+
if schedule
|
71
|
+
dpn.Dtt do |dtt|
|
72
|
+
dtt << schedule.to_aixm(*extensions).indent(4)
|
73
|
+
end
|
74
|
+
end
|
57
75
|
dpn.txtRmk(remarks) if remarks
|
58
76
|
dpn.target! # see https://github.com/jimweirich/builder/issues/42
|
59
77
|
end
|
60
78
|
end
|
61
|
-
|
62
|
-
def type_key
|
63
|
-
TYPES.key(type)
|
64
|
-
end
|
65
79
|
end
|
66
80
|
|
67
81
|
end
|
@@ -10,13 +10,23 @@ module AIXM
|
|
10
10
|
class DME < Base
|
11
11
|
using AIXM::Refinements
|
12
12
|
|
13
|
-
attr_reader :channel
|
13
|
+
attr_reader :channel, :vor
|
14
14
|
|
15
15
|
public_class_method :new
|
16
16
|
|
17
17
|
def initialize(id:, name:, xy:, z: nil, channel:)
|
18
18
|
super(id: id, name: name, xy: xy, z: z)
|
19
|
-
|
19
|
+
self.channel = channel
|
20
|
+
end
|
21
|
+
|
22
|
+
def channel=(value)
|
23
|
+
fail(ArgumentError, "invalid channel") unless value.is_a? String
|
24
|
+
@channel = value.upcase
|
25
|
+
end
|
26
|
+
|
27
|
+
def vor=(value)
|
28
|
+
fail(ArgumentError, "invalid VOR") unless value.is_a? VOR
|
29
|
+
@vor = value
|
20
30
|
end
|
21
31
|
|
22
32
|
##
|
@@ -26,16 +36,24 @@ module AIXM
|
|
26
36
|
end
|
27
37
|
|
28
38
|
##
|
29
|
-
# Render
|
30
|
-
def
|
39
|
+
# Render UID markup
|
40
|
+
def to_uid(*extensions)
|
41
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
42
|
+
builder.DmeUid({ newEntity: (true if extensions >> :ofm) }.compact) do |dmeuid|
|
43
|
+
dmeuid.codeId(id)
|
44
|
+
dmeuid.geoLat(xy.lat(format_for(*extensions)))
|
45
|
+
dmeuid.geoLong(xy.long(format_for(*extensions)))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Render AIXM markup
|
51
|
+
def to_aixm(*extensions)
|
31
52
|
builder = to_builder(*extensions)
|
32
53
|
builder.Dme do |dme|
|
33
|
-
dme
|
34
|
-
dmeuid.codeId(id)
|
35
|
-
dmeuid.geoLat(xy.lat(format_for(*extensions)))
|
36
|
-
dmeuid.geoLong(xy.long(format_for(*extensions)))
|
37
|
-
end
|
54
|
+
dme << to_uid(*extensions).indent(2)
|
38
55
|
dme.OrgUid
|
56
|
+
dme << vor.to_uid(*extensions).indent(2) if vor
|
39
57
|
dme.txtName(name)
|
40
58
|
dme.codeChannel(channel)
|
41
59
|
dme.codeDatum('WGE')
|
@@ -43,6 +61,11 @@ module AIXM
|
|
43
61
|
dme.valElev(z.alt)
|
44
62
|
dme.uomDistVer(z.unit.to_s)
|
45
63
|
end
|
64
|
+
if schedule
|
65
|
+
dme.Dtt do |dtt|
|
66
|
+
dtt << schedule.to_aixm(*extensions).indent(4)
|
67
|
+
end
|
68
|
+
end
|
46
69
|
dme.txtRmk(remarks) if remarks
|
47
70
|
dme.target! # see https://github.com/jimweirich/builder/issues/42
|
48
71
|
end
|
@@ -11,16 +11,29 @@ module AIXM
|
|
11
11
|
|
12
12
|
public_class_method :new
|
13
13
|
|
14
|
+
# TODO: Marker require an associated ILS
|
15
|
+
def initialize(**args)
|
16
|
+
warn("WARNING: Maker is not fully implemented yet due to the lack of ILS")
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Render UID markup
|
22
|
+
def to_uid(*extensions)
|
23
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
24
|
+
builder.MkrUid({ newEntity: (true if extensions >> :ofm) }.compact) do |mkruid|
|
25
|
+
mkruid.codeId(id)
|
26
|
+
mkruid.geoLat(xy.lat(format_for(*extensions)))
|
27
|
+
mkruid.geoLong(xy.long(format_for(*extensions)))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
14
31
|
##
|
15
|
-
# Render AIXM
|
16
|
-
def
|
32
|
+
# Render AIXM markup
|
33
|
+
def to_aixm(*extensions)
|
17
34
|
builder = to_builder(*extensions)
|
18
35
|
builder.Mkr do |mkr|
|
19
|
-
mkr
|
20
|
-
mkruid.codeId(id)
|
21
|
-
mkruid.geoLat(xy.lat(format_for(*extensions)))
|
22
|
-
mkruid.geoLong(xy.long(format_for(*extensions)))
|
23
|
-
end
|
36
|
+
mkr << to_uid(*extensions).indent(2)
|
24
37
|
mkr.OrgUid
|
25
38
|
mkr.valFreq(75)
|
26
39
|
mkr.uomFreq('MHZ')
|
@@ -30,6 +43,11 @@ module AIXM
|
|
30
43
|
mkr.valElev(z.alt)
|
31
44
|
mkr.uomDistVer(z.unit.to_s)
|
32
45
|
end
|
46
|
+
if schedule
|
47
|
+
mkr.Mtt do |mtt|
|
48
|
+
mtt << schedule.to_aixm(*extensions).indent(4)
|
49
|
+
end
|
50
|
+
end
|
33
51
|
mkr.txtRmk(remarks) if remarks
|
34
52
|
mkr.target! # see https://github.com/jimweirich/builder/issues/42
|
35
53
|
end
|