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