aixm 0.2.0 → 0.2.1

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