aixm 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +91 -11
  4. data/lib/aixm.rb +10 -0
  5. data/lib/aixm/base.rb +10 -0
  6. data/lib/aixm/component/base.rb +1 -1
  7. data/lib/aixm/component/class_layer.rb +0 -3
  8. data/lib/aixm/component/geometry.rb +0 -3
  9. data/lib/aixm/component/geometry/arc.rb +4 -8
  10. data/lib/aixm/component/geometry/base.rb +8 -0
  11. data/lib/aixm/component/geometry/border.rb +3 -8
  12. data/lib/aixm/component/geometry/circle.rb +5 -9
  13. data/lib/aixm/component/geometry/point.rb +6 -13
  14. data/lib/aixm/component/schedule.rb +8 -10
  15. data/lib/aixm/component/vertical_limits.rb +1 -4
  16. data/lib/aixm/document.rb +9 -6
  17. data/lib/aixm/f.rb +41 -0
  18. data/lib/aixm/feature/airspace.rb +5 -9
  19. data/lib/aixm/feature/base.rb +6 -0
  20. data/lib/aixm/feature/navigational_aid/base.rb +46 -0
  21. data/lib/aixm/feature/navigational_aid/designated_point.rb +69 -0
  22. data/lib/aixm/feature/navigational_aid/dme.rb +54 -0
  23. data/lib/aixm/feature/navigational_aid/marker.rb +41 -0
  24. data/lib/aixm/feature/navigational_aid/ndb.rb +56 -0
  25. data/lib/aixm/feature/navigational_aid/tacan.rb +54 -0
  26. data/lib/aixm/feature/navigational_aid/vor.rb +92 -0
  27. data/lib/aixm/refinements.rb +23 -2
  28. data/lib/aixm/shortcuts.rb +12 -5
  29. data/lib/aixm/version.rb +1 -1
  30. data/lib/aixm/xy.rb +9 -6
  31. data/lib/aixm/z.rb +22 -11
  32. data/spec/factory.rb +87 -4
  33. data/spec/lib/aixm/component/class_layer_spec.rb +6 -6
  34. data/spec/lib/aixm/component/geometry/arc_spec.rb +16 -16
  35. data/spec/lib/aixm/component/geometry/border_spec.rb +4 -4
  36. data/spec/lib/aixm/component/geometry/circle_spec.rb +10 -10
  37. data/spec/lib/aixm/component/geometry/point_spec.rb +4 -4
  38. data/spec/lib/aixm/component/geometry_spec.rb +21 -21
  39. data/spec/lib/aixm/component/schedule_spec.rb +6 -6
  40. data/spec/lib/aixm/component/vertical_limits_spec.rb +18 -18
  41. data/spec/lib/aixm/document_spec.rb +220 -30
  42. data/spec/lib/aixm/f_spec.rb +58 -0
  43. data/spec/lib/aixm/feature/airspace_spec.rb +5 -5
  44. data/spec/lib/aixm/feature/navigational_aid/base_spec.rb +37 -0
  45. data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +43 -0
  46. data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +43 -0
  47. data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +44 -0
  48. data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +54 -0
  49. data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +43 -0
  50. data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +58 -0
  51. data/spec/lib/aixm/refinements_spec.rb +27 -0
  52. data/spec/lib/aixm/xy_spec.rb +29 -23
  53. data/spec/lib/aixm/z_spec.rb +33 -17
  54. metadata +29 -2
@@ -0,0 +1,92 @@
1
+ module AIXM
2
+ module Feature
3
+ module NavigationalAid
4
+
5
+ ##
6
+ # VOR (VHF omnidirectional range) operate in the frequency band between
7
+ # 108.00 Mhz to 117.95 MHz. Two type of VORs exist:
8
+ #
9
+ # Types:
10
+ # * +:vor+ (+:VOR+) - standard VOR
11
+ # * +:vordme+ (+:DVOR+) - VOR/DME
12
+ #
13
+ # North types:
14
+ # * +:geographic+ (+:TRUE+) - VOR aligned towards geographic north
15
+ # * +:grid+ (+:GRID+) - VOR aligned along north-south lines of the
16
+ # universal transverse mercator grid imposed on
17
+ # topographic maps by the USA and NATO
18
+ # * +:magnetic+ (+:MAG+) - VOR aligned towards magnetic north
19
+ # * +:other+ (+:OTHER+) - other north type
20
+ #
21
+ # https://en.wikipedia.org/wiki/VHF_omnidirectional_range
22
+ class VOR < Base
23
+ using AIXM::Refinements
24
+
25
+ TYPES = {
26
+ VOR: :vor,
27
+ DVOR: :vordme
28
+ }.freeze
29
+
30
+ NORTHS = {
31
+ TRUE: :geographic,
32
+ GRID: :grid,
33
+ MAG: :magnetic,
34
+ OTHER: :other
35
+ }.freeze
36
+
37
+ attr_reader :type, :f, :north
38
+
39
+ public_class_method :new
40
+
41
+ def initialize(id:, name:, xy:, z: nil, type:, f:, north:)
42
+ super(id: id, name: name, xy: xy, z: z)
43
+ @type = TYPES.lookup(type&.to_sym, nil) || fail(ArgumentError, "invalid type")
44
+ @north = NORTHS.lookup(north&.to_sym, nil) || fail(ArgumentError, "invalid north")
45
+ @f = f
46
+ fail(ArgumentError, "invalid frequency") unless f.is_a?(F) && f.between?(108, 117.95, :mhz)
47
+ end
48
+
49
+ ##
50
+ # Digest to identify the payload
51
+ def to_digest
52
+ [super, type, f.to_digest, north].to_digest
53
+ end
54
+
55
+ ##
56
+ # Render AIXM
57
+ def to_xml(*extensions)
58
+ builder = to_builder(*extensions)
59
+ builder.Vor do |vor|
60
+ vor.VorUid({ newEntity: (true if extensions >> :ofm) }.compact) do |voruid|
61
+ voruid.codeId(id)
62
+ voruid.geoLat(xy.lat(format_for(*extensions)))
63
+ voruid.geoLong(xy.long(format_for(*extensions)))
64
+ end
65
+ vor.OrgUid
66
+ vor.txtName(name)
67
+ vor.codeType(type_key.to_s)
68
+ vor.valFreq(f.freq.trim)
69
+ vor.uomFreq(f.unit.upcase.to_s)
70
+ vor.codeTypeNorth(north_key.to_s)
71
+ vor.codeDatum('WGE')
72
+ if z
73
+ vor.valElev(z.alt)
74
+ vor.uomDistVer(z.unit.to_s)
75
+ end
76
+ vor.txtRmk(remarks) if remarks
77
+ vor.target! # see https://github.com/jimweirich/builder/issues/42
78
+ end
79
+ end
80
+
81
+ def type_key
82
+ TYPES.key(type)
83
+ end
84
+
85
+ def north_key
86
+ NORTHS.key(north)
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -25,8 +25,8 @@ module AIXM
25
25
  # Shortcut for +include?+
26
26
  #
27
27
  # Example:
28
- # extensions.include?(:OFM) # => true
29
- # extensions >> :OFM # => true
28
+ # extensions.include?(:ofm) # => true
29
+ # extensions >> :ofm # => true
30
30
  alias_method :>>, :include?
31
31
 
32
32
  ##
@@ -36,6 +36,27 @@ module AIXM
36
36
  end
37
37
  end
38
38
 
39
+ refine Hash do
40
+ ##
41
+ # Fetch a value from the hash, but unlike +fetch+, if +key_or_value+ is
42
+ # no hash key, check whether +key_or_value+ is a hash value and if so
43
+ # return it.
44
+ #
45
+ # Examples:
46
+ # h = { one: 1, two: 2, three: 3, four: :three }
47
+ # h.lookup(:one) # => 1
48
+ # h.lookup(1) # => 1
49
+ # h.lookup(:three) # => 3 (key has priority over value)
50
+ # h.lookup(:foo) # => KeyError
51
+ # h.lookup(:foo, :default) # => :default
52
+ # h.lookup(:foo, nil) # => nil
53
+ def lookup(key_or_value, default = omitted = true)
54
+ self[key_or_value] ||
55
+ (key_or_value if has_value?(key_or_value)) ||
56
+ (omitted ? fail(KeyError, "key or value `#{key_or_value}' not found") : default)
57
+ end
58
+ end
59
+
39
60
  refine String do
40
61
  ##
41
62
  # Indent every line of a string with +number+ spaces
@@ -2,14 +2,11 @@ module AIXM
2
2
 
3
3
  SCHEMA = Pathname(__dir__).join('schemas', '4.5', 'AIXM-Snapshot.xsd').freeze
4
4
 
5
- GROUND = Z.new(alt: 0, code: :QFE).freeze
6
- UNLIMITED = Z.new(alt: 999, code: :QNE).freeze
7
- H24 = Component::Schedule.new(code: :H24).freeze
8
-
9
5
  ELEMENTS = {
10
6
  document: Document,
11
7
  xy: XY,
12
8
  z: Z,
9
+ f: F,
13
10
  airspace: Feature::Airspace,
14
11
  class_layer: Component::ClassLayer,
15
12
  geometry: Component::Geometry,
@@ -18,7 +15,13 @@ module AIXM
18
15
  arc: Component::Geometry::Arc,
19
16
  border: Component::Geometry::Border,
20
17
  circle: Component::Geometry::Circle,
21
- point: Component::Geometry::Point
18
+ point: Component::Geometry::Point,
19
+ dme: Feature::NavigationalAid::DME,
20
+ designated_point: Feature::NavigationalAid::DesignatedPoint,
21
+ marker: Feature::NavigationalAid::Marker,
22
+ tacan: Feature::NavigationalAid::TACAN,
23
+ ndb: Feature::NavigationalAid::NDB,
24
+ vor: Feature::NavigationalAid::VOR
22
25
  }.freeze
23
26
 
24
27
  ELEMENTS.each do |element, klass|
@@ -27,4 +30,8 @@ module AIXM
27
30
  end
28
31
  end
29
32
 
33
+ GROUND = z(0, :qfe).freeze
34
+ UNLIMITED = z(999, :qne).freeze
35
+ H24 = schedule(code: :H24).freeze
36
+
30
37
  end
@@ -1,3 +1,3 @@
1
1
  module AIXM
2
- VERSION = "0.1.3".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
@@ -6,8 +6,7 @@ module AIXM
6
6
  # The following notations for longitude and latitude are recognized:
7
7
  # * DD - examples: 12.12345678 (north or east), -12.12345678 (south or west)
8
8
  # * DMS - examples: 11°22'33.44"N, 1112233.44W
9
- class XY
10
-
9
+ class XY < Base
11
10
  using AIXM::Refinements
12
11
 
13
12
  def initialize(lat:, long:)
@@ -18,20 +17,24 @@ module AIXM
18
17
 
19
18
  def lat(format=nil)
20
19
  case format
21
- when :OFM then ("%.8f" % @lat.abs.round(8)) + (@lat.negative? ? 'S' : 'N')
22
- when :AIXM then @lat.to_dms(2).gsub(/[^\d.]/, '') + (@lat.negative? ? 'S' : 'N')
20
+ when :ofm then ("%.8f" % @lat.abs.round(8)) + (@lat.negative? ? 'S' : 'N')
21
+ when :aixm then @lat.to_dms(2).gsub(/[^\d.]/, '') + (@lat.negative? ? 'S' : 'N')
23
22
  else @lat.round(8)
24
23
  end
25
24
  end
26
25
 
27
26
  def long(format=nil)
28
27
  case format
29
- when :OFM then ("%.8f" % @long.abs.round(8)) + (@long.negative? ? 'W' : 'E')
30
- when :AIXM then @long.to_dms(3).gsub(/[^\d.]/, '') + (@long.negative? ? 'W' : 'E')
28
+ when :ofm then ("%.8f" % @long.abs.round(8)) + (@long.negative? ? 'W' : 'E')
29
+ when :aixm then @long.to_dms(3).gsub(/[^\d.]/, '') + (@long.negative? ? 'W' : 'E')
31
30
  else @long.round(8)
32
31
  end
33
32
  end
34
33
 
34
+ def to_digest
35
+ [lat, long].to_digest
36
+ end
37
+
35
38
  def ==(other)
36
39
  other.is_a?(XY) && lat == other.lat && long == other.long
37
40
  end
@@ -4,34 +4,45 @@ module AIXM
4
4
  # Elevation or altitude
5
5
  #
6
6
  # The following Q codes are recognized:
7
- # * QFE - height in feet
8
- # * QNH - altitude in feet
9
- # * QNE - altitude as flight level
10
- class Z
7
+ # * +:qfe+ - height in feet
8
+ # * +:qnh+ - altitude in feet
9
+ # * +:qne+ - altitude as flight level
10
+ class Z < Base
11
+ using AIXM::Refinements
11
12
 
12
- CODES = %i(QFE QNH QNE).freeze
13
+ CODES = %i(qfe qnh qne).freeze
13
14
 
14
15
  attr_reader :alt, :code
15
16
 
16
- def initialize(alt:, code:)
17
- fail(ArgumentError, "unrecognized Q code `#{code}'") unless CODES.include? code
18
- @alt, @code = alt, code
17
+ def initialize(alt, code)
18
+ @alt, @code = alt, code&.to_sym&.downcase
19
+ fail(ArgumentError, "unrecognized Q code `#{code}'") unless CODES.include? @code
20
+ end
21
+
22
+ ##
23
+ # Digest to identify the payload
24
+ def to_digest
25
+ [alt, code].to_digest
19
26
  end
20
27
 
21
28
  def ==(other)
22
29
  other.is_a?(Z) && alt == other.alt && code == other.code
23
30
  end
24
31
 
32
+ CODES.each do |code|
33
+ define_method(:"#{code}?") { @code == code }
34
+ end
35
+
25
36
  def ground?
26
- @code == :QFE && @alt == 0
37
+ qfe? && @alt == 0
27
38
  end
28
39
 
29
40
  def base
30
- @code == :QFE ? :ASFC : :AMSL
41
+ qfe? ? :ASFC : :AMSL
31
42
  end
32
43
 
33
44
  def unit
34
- @code == :QNE ? :FL : :FT
45
+ qne? ? :FL : :FT
35
46
  end
36
47
 
37
48
  end
@@ -2,12 +2,16 @@ module AIXM
2
2
  class Factory
3
3
  class << self
4
4
 
5
+ def xy
6
+ AIXM.xy(lat: 10, long: 20)
7
+ end
8
+
5
9
  def vertical_limits
6
10
  AIXM.vertical_limits(
7
- upper_z: AIXM.z(alt: 65, code: :QNE),
8
- lower_z: AIXM.z(alt: 45, code: :QNE),
9
- max_z: AIXM.z(alt: 6000, code: :QNH),
10
- min_z: AIXM.z(alt: 3000, code: :QFE)
11
+ upper_z: AIXM.z(65, :qne),
12
+ lower_z: AIXM.z(45, :qne),
13
+ max_z: AIXM.z(6000, :qnh),
14
+ min_z: AIXM.z(3000, :qfe)
11
15
  )
12
16
  end
13
17
 
@@ -70,11 +74,90 @@ module AIXM
70
74
  end
71
75
  end
72
76
 
77
+ def designated_point
78
+ AIXM.designated_point(
79
+ id: 'DPN',
80
+ name: 'DESIGNATED POINT NAVAID',
81
+ xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
82
+ z: AIXM.z(500, :qnh),
83
+ type: :ICAO
84
+ ).tap do |designated_point|
85
+ designated_point.remarks = 'designated point navaid'
86
+ end
87
+ end
88
+
89
+ def dme
90
+ AIXM.dme(
91
+ id: 'DME',
92
+ name: 'DME NAVAID',
93
+ xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
94
+ z: AIXM.z(500, :qnh),
95
+ channel: '95X'
96
+ ).tap do |dme|
97
+ dme.remarks = 'dme navaid'
98
+ end
99
+ end
100
+
101
+ def marker
102
+ AIXM.marker(
103
+ id: '---',
104
+ name: 'MARKER NAVAID',
105
+ xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
106
+ z: AIXM.z(500, :qnh)
107
+ ).tap do |marker|
108
+ marker.remarks = 'marker navaid'
109
+ end
110
+ end
111
+
112
+ def ndb
113
+ AIXM.ndb(
114
+ id: 'NDB',
115
+ name: 'NDB NAVAID',
116
+ xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
117
+ z: AIXM.z(500, :qnh),
118
+ f: AIXM.f(555, :khz)
119
+ ).tap do |ndb|
120
+ ndb.remarks = 'ndb navaid'
121
+ end
122
+ end
123
+
124
+ def tacan
125
+ AIXM.tacan(
126
+ id: 'TCN',
127
+ name: 'TACAN NAVAID',
128
+ xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
129
+ z: AIXM.z(500, :qnh),
130
+ channel: '29X'
131
+ ).tap do |tacan|
132
+ tacan.remarks = 'tacan navaid'
133
+ end
134
+ end
135
+
136
+ def vor
137
+ AIXM.vor(
138
+ id: 'VOR',
139
+ name: 'VOR NAVAID',
140
+ xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
141
+ z: AIXM.z(500, :qnh),
142
+ type: :VOR,
143
+ f: AIXM.f(111, :mhz),
144
+ north: :geographic
145
+ ).tap do |vor|
146
+ vor.remarks = 'vor navaid'
147
+ end
148
+ end
149
+
73
150
  def document
74
151
  time = Time.parse('2018-01-18 12:00:00 +0100')
75
152
  AIXM.document(created_at: time, effective_at: time).tap do |document|
76
153
  document.features << AIXM::Factory.polygon_airspace
77
154
  document.features << AIXM::Factory.circle_airspace
155
+ document.features << AIXM::Factory.designated_point
156
+ document.features << AIXM::Factory.dme
157
+ document.features << AIXM::Factory.marker
158
+ document.features << AIXM::Factory.ndb
159
+ document.features << AIXM::Factory.vor
160
+ document.features << AIXM::Factory.tacan
78
161
  end
79
162
  end
80
163
 
@@ -3,19 +3,19 @@ require_relative '../../../spec_helper'
3
3
  describe AIXM::Component::ClassLayer do
4
4
  describe :initialize do
5
5
  it "won't accept invalid arguments" do
6
- -> { AIXM::Component::ClassLayer.new(class: 'X', vertical_limits: AIXM::Factory.vertical_limits ) }.must_raise ArgumentError
7
- -> { AIXM::Component::ClassLayer.new(class: 'A', vertical_limits: 'foobar') }.must_raise ArgumentError
6
+ -> { AIXM.class_layer(class: 'X', vertical_limits: AIXM::Factory.vertical_limits ) }.must_raise ArgumentError
7
+ -> { AIXM.class_layer(class: 'A', vertical_limits: 'foobar') }.must_raise ArgumentError
8
8
  end
9
9
  end
10
10
 
11
11
  context "with class" do
12
12
  subject do
13
- AIXM::Component::ClassLayer.new(class: :C, vertical_limits: AIXM::Factory.vertical_limits)
13
+ AIXM.class_layer(class: :C, vertical_limits: AIXM::Factory.vertical_limits)
14
14
  end
15
15
 
16
16
  describe :to_digest do
17
17
  it "must return digest of payload" do
18
- subject.to_digest.must_equal 612555203
18
+ subject.to_digest.must_equal 385936206
19
19
  end
20
20
  end
21
21
 
@@ -42,12 +42,12 @@ describe AIXM::Component::ClassLayer do
42
42
 
43
43
  context "without class" do
44
44
  subject do
45
- AIXM::Component::ClassLayer.new(vertical_limits: AIXM::Factory.vertical_limits)
45
+ AIXM.class_layer(vertical_limits: AIXM::Factory.vertical_limits)
46
46
  end
47
47
 
48
48
  describe :to_digest do
49
49
  it "must return digest of payload" do
50
- subject.to_digest.must_equal 486148039
50
+ subject.to_digest.must_equal 5930767
51
51
  end
52
52
  end
53
53
 
@@ -3,26 +3,26 @@ require_relative '../../../../spec_helper'
3
3
  describe AIXM::Component::Geometry::Arc do
4
4
  describe :initialize do
5
5
  it "won't accept invalid arguments" do
6
- xy = AIXM::XY.new(lat: 11.1, long: 22.2)
7
- -> { AIXM::Component::Geometry::Arc.new(xy: 0, center_xy: xy, clockwise: true) }.must_raise ArgumentError
8
- -> { AIXM::Component::Geometry::Arc.new(xy: xy, center_xy: 0, clockwise: true) }.must_raise ArgumentError
9
- -> { AIXM::Component::Geometry::Arc.new(xy: xy, center_xy: xy, clockwise: 0) }.must_raise ArgumentError
6
+ xy = AIXM.xy(lat: 11.1, long: 22.2)
7
+ -> { AIXM.arc(xy: 0, center_xy: xy, clockwise: true) }.must_raise ArgumentError
8
+ -> { AIXM.arc(xy: xy, center_xy: 0, clockwise: true) }.must_raise ArgumentError
9
+ -> { AIXM.arc(xy: xy, center_xy: xy, clockwise: 0) }.must_raise ArgumentError
10
10
  end
11
11
  end
12
12
 
13
13
  describe :clockwise? do
14
14
  it "must return true or false" do
15
- xy = AIXM::XY.new(lat: 11.1, long: 22.2)
16
- AIXM::Component::Geometry::Arc.new(xy: xy, center_xy: xy, clockwise: true).must_be :clockwise?
17
- AIXM::Component::Geometry::Arc.new(xy: xy, center_xy: xy, clockwise: false).wont_be :clockwise?
15
+ xy = AIXM.xy(lat: 11.1, long: 22.2)
16
+ AIXM.arc(xy: xy, center_xy: xy, clockwise: true).must_be :clockwise?
17
+ AIXM.arc(xy: xy, center_xy: xy, clockwise: false).wont_be :clockwise?
18
18
  end
19
19
  end
20
20
 
21
21
  describe :to_digest do
22
22
  it "must return digest of payload" do
23
- subject = AIXM::Component::Geometry::Arc.new(
24
- xy: AIXM::XY.new(lat: 11.1, long: 33.3),
25
- center_xy: AIXM::XY.new(lat: 22.2, long: 33.3),
23
+ subject = AIXM.arc(
24
+ xy: AIXM.xy(lat: 11.1, long: 33.3),
25
+ center_xy: AIXM.xy(lat: 22.2, long: 33.3),
26
26
  clockwise: true
27
27
  )
28
28
  subject.to_digest.must_equal 712900173
@@ -31,9 +31,9 @@ describe AIXM::Component::Geometry::Arc do
31
31
 
32
32
  describe :to_xml do
33
33
  it "must build correct XML for clockwise arcs" do
34
- subject = AIXM::Component::Geometry::Arc.new(
35
- xy: AIXM::XY.new(lat: 11.1, long: 33.3),
36
- center_xy: AIXM::XY.new(lat: 22.2, long: 33.3),
34
+ subject = AIXM.arc(
35
+ xy: AIXM.xy(lat: 11.1, long: 33.3),
36
+ center_xy: AIXM.xy(lat: 22.2, long: 33.3),
37
37
  clockwise: true
38
38
  )
39
39
  subject.to_xml.must_equal <<~END
@@ -49,9 +49,9 @@ describe AIXM::Component::Geometry::Arc do
49
49
  end
50
50
 
51
51
  it "must build correct XML for counter-clockwise arcs" do
52
- subject = AIXM::Component::Geometry::Arc.new(
53
- xy: AIXM::XY.new(lat: 11.1, long: 33.3),
54
- center_xy: AIXM::XY.new(lat: 22.2, long: 33.3),
52
+ subject = AIXM.arc(
53
+ xy: AIXM.xy(lat: 11.1, long: 33.3),
54
+ center_xy: AIXM.xy(lat: 22.2, long: 33.3),
55
55
  clockwise: false
56
56
  )
57
57
  subject.to_xml.must_equal <<~END