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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/README.md +149 -116
  4. data/lib/aixm/component/class_layer.rb +3 -3
  5. data/lib/aixm/component/geometry.rb +3 -3
  6. data/lib/aixm/component/geometry/arc.rb +2 -2
  7. data/lib/aixm/component/geometry/border.rb +2 -2
  8. data/lib/aixm/component/geometry/circle.rb +2 -2
  9. data/lib/aixm/component/geometry/point.rb +2 -2
  10. data/lib/aixm/component/schedule.rb +2 -2
  11. data/lib/aixm/component/vertical_limits.rb +2 -2
  12. data/lib/aixm/document.rb +4 -4
  13. data/lib/aixm/feature/airspace.rb +42 -17
  14. data/lib/aixm/feature/navigational_aid/base.rb +41 -8
  15. data/lib/aixm/feature/navigational_aid/designated_point.rb +29 -15
  16. data/lib/aixm/feature/navigational_aid/dme.rb +32 -9
  17. data/lib/aixm/feature/navigational_aid/marker.rb +25 -7
  18. data/lib/aixm/feature/navigational_aid/ndb.rb +25 -9
  19. data/lib/aixm/feature/navigational_aid/tacan.rb +21 -20
  20. data/lib/aixm/feature/navigational_aid/vor.rb +66 -26
  21. data/lib/aixm/version.rb +1 -1
  22. data/spec/factory.rb +69 -13
  23. data/spec/lib/aixm/component/class_layer_spec.rb +4 -4
  24. data/spec/lib/aixm/component/geometry/arc_spec.rb +3 -3
  25. data/spec/lib/aixm/component/geometry/border_spec.rb +2 -2
  26. data/spec/lib/aixm/component/geometry/circle_spec.rb +3 -3
  27. data/spec/lib/aixm/component/geometry/point_spec.rb +3 -3
  28. data/spec/lib/aixm/component/geometry_spec.rb +4 -4
  29. data/spec/lib/aixm/component/schedule_spec.rb +2 -2
  30. data/spec/lib/aixm/component/vertical_limits_spec.rb +4 -4
  31. data/spec/lib/aixm/document_spec.rb +282 -28
  32. data/spec/lib/aixm/feature/airspace_spec.rb +14 -10
  33. data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +9 -6
  34. data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +9 -6
  35. data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +7 -4
  36. data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +9 -6
  37. data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +9 -6
  38. data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +156 -7
  39. metadata +2 -2
@@ -21,8 +21,8 @@ module AIXM
21
21
  end
22
22
 
23
23
  ##
24
- # Render AIXM
25
- def to_xml(*extensions)
24
+ # Render AIXM markup
25
+ def to_aixm(*extensions)
26
26
  builder = Builder::XmlMarkup.new(indent: 2)
27
27
  builder.Avx do |avx|
28
28
  avx.codeType('CWA')
@@ -18,8 +18,8 @@ module AIXM
18
18
  end
19
19
 
20
20
  ##
21
- # Render AIXM
22
- def to_xml(*extensions)
21
+ # Render AIXM markup
22
+ def to_aixm(*extensions)
23
23
  builder = Builder::XmlMarkup.new(indent: 2)
24
24
  builder.Avx do |avx|
25
25
  avx.codeType('GRC')
@@ -33,8 +33,8 @@ module AIXM
33
33
  end
34
34
 
35
35
  ##
36
- # Render AIXM
37
- def to_xml(*extensions)
36
+ # Render AIXM markup
37
+ def to_aixm(*extensions)
38
38
  Builder::XmlMarkup.new(indent: 2).codeWorkHr(CODES.key(code).to_s)
39
39
  end
40
40
  end
@@ -35,8 +35,8 @@ module AIXM
35
35
  end
36
36
 
37
37
  ##
38
- # Render AIXM
39
- def to_xml(*extensions)
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(to_xml)).reject do |error|
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 to_xml(*extensions)
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.to_xml(*extensions) }.join.indent(2)
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
- attr_reader :schedule
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
- @name, @short_name, @type = name.uptrans, short_name&.uptrans, type
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
- # Assign a +Schedule+ object or +nil+
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 AIXM
47
- def to_xml(*extensions)
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.AseUid({ mid: mid, newEntity: (true if extensions >> :ofm) }.compact) do |aseuid|
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.to_xml(*extensions).indent(2)
83
+ ase << class_layers.first.to_aixm(*extensions).indent(2)
59
84
  if schedule
60
85
  ase.Att do |att|
61
- att << schedule.to_xml(*extensions).indent(4)
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.to_s)
95
+ aseuid.codeType(type)
71
96
  aseuid.codeId(mid)
72
97
  end
73
98
  end
74
- abd << geometry.to_xml(*extensions).indent(2)
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].to_xml(*extensions).indent(2)
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
- @id, @name, @xy, @z = id&.upcase, name&.upcase, xy, z
19
- fail(ArgumentError, "invalid xy") unless xy.is_a? AIXM::XY
20
- fail(ArgumentError, "invalid z") unless z.nil? || (z.is_a?(AIXM::Z) && z.qnh?)
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 either the +type_key+ or +class+
51
+ # Return a fully descriptive combination of +class+ and +type_key+
25
52
  def kind
26
- respond_to?(:type_key) ? type_key : self.class.name.split('::').last.to_sym
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! "Navigational aid: [#{kind}] #{name}"
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
- @type = TYPES.lookup(type&.to_sym, nil) || fail(ArgumentError, "invalid type")
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 AIXM
41
- def to_xml(*extensions)
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.DpnUid({ newEntity: (true if extensions >> :ofm) }.compact) do |dpnuid|
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
- @channel = channel&.upcase
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 AIXM
30
- def to_xml(*extensions)
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.DmeUid({ newEntity: (true if extensions >> :ofm) }.compact) do |dmeuid|
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 to_xml(*extensions)
32
+ # Render AIXM markup
33
+ def to_aixm(*extensions)
17
34
  builder = to_builder(*extensions)
18
35
  builder.Mkr do |mkr|
19
- mkr.MkrUid({ newEntity: (true if extensions >> :ofm) }.compact) do |mkruid|
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