aixm 0.2.3 → 0.3.0

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 (97) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.ruby-version +1 -1
  4. data/.yardopts +3 -0
  5. data/CHANGELOG.md +34 -14
  6. data/Guardfile +1 -0
  7. data/README.md +64 -257
  8. data/lib/aixm.rb +16 -7
  9. data/lib/aixm/component.rb +6 -0
  10. data/lib/aixm/component/frequency.rb +135 -0
  11. data/lib/aixm/component/geometry.rb +34 -23
  12. data/lib/aixm/component/geometry/arc.rb +37 -22
  13. data/lib/aixm/component/geometry/border.rb +29 -20
  14. data/lib/aixm/component/geometry/circle.rb +39 -22
  15. data/lib/aixm/component/geometry/point.rb +29 -13
  16. data/lib/aixm/component/helipad.rb +154 -0
  17. data/lib/aixm/component/layer.rb +91 -0
  18. data/lib/aixm/component/runway.rb +294 -0
  19. data/lib/aixm/component/service.rb +170 -0
  20. data/lib/aixm/component/timetable.rb +65 -0
  21. data/lib/aixm/component/vertical_limits.rb +65 -29
  22. data/lib/aixm/config.rb +87 -0
  23. data/lib/aixm/document.rb +66 -42
  24. data/lib/aixm/errors.rb +11 -0
  25. data/lib/aixm/f.rb +34 -20
  26. data/lib/aixm/feature.rb +38 -0
  27. data/lib/aixm/feature/airport.rb +473 -0
  28. data/lib/aixm/feature/airspace.rb +145 -92
  29. data/lib/aixm/feature/navigational_aid.rb +94 -0
  30. data/lib/aixm/feature/navigational_aid/designated_point.rb +50 -54
  31. data/lib/aixm/feature/navigational_aid/dme.rb +48 -40
  32. data/lib/aixm/feature/navigational_aid/marker.rb +55 -45
  33. data/lib/aixm/feature/navigational_aid/ndb.rb +54 -50
  34. data/lib/aixm/feature/navigational_aid/tacan.rb +38 -31
  35. data/lib/aixm/feature/navigational_aid/vor.rb +84 -76
  36. data/lib/aixm/feature/organisation.rb +97 -0
  37. data/lib/aixm/feature/unit.rb +152 -0
  38. data/lib/aixm/refinements.rb +132 -47
  39. data/lib/aixm/shortcuts.rb +11 -6
  40. data/lib/aixm/version.rb +1 -1
  41. data/lib/aixm/xy.rb +64 -20
  42. data/lib/aixm/z.rb +51 -22
  43. data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-DataTypes.xsd +0 -0
  44. data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Features.xsd +0 -0
  45. data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Snapshot.xsd +0 -0
  46. data/schemas/ofmx/0/OFMX-DataTypes.xsd +5077 -0
  47. data/schemas/ofmx/0/OFMX-Features.xsd +9955 -0
  48. data/schemas/ofmx/0/OFMX-Snapshot.xsd +217 -0
  49. data/spec/factory.rb +209 -33
  50. data/spec/lib/aixm/component/frequency_spec.rb +75 -0
  51. data/spec/lib/aixm/component/geometry/arc_spec.rb +28 -22
  52. data/spec/lib/aixm/component/geometry/border_spec.rb +23 -20
  53. data/spec/lib/aixm/component/geometry/circle_spec.rb +31 -22
  54. data/spec/lib/aixm/component/geometry/point_spec.rb +11 -14
  55. data/spec/lib/aixm/component/geometry_spec.rb +150 -69
  56. data/spec/lib/aixm/component/helipad_spec.rb +136 -0
  57. data/spec/lib/aixm/component/layer_spec.rb +110 -0
  58. data/spec/lib/aixm/component/runway_spec.rb +402 -0
  59. data/spec/lib/aixm/component/service_spec.rb +61 -0
  60. data/spec/lib/aixm/component/timetable_spec.rb +49 -0
  61. data/spec/lib/aixm/component/vertical_limits_spec.rb +39 -20
  62. data/spec/lib/aixm/config_spec.rb +41 -0
  63. data/spec/lib/aixm/document_spec.rb +637 -147
  64. data/spec/lib/aixm/errors_spec.rb +14 -0
  65. data/spec/lib/aixm/f_spec.rb +17 -10
  66. data/spec/lib/aixm/feature/airport_spec.rb +546 -0
  67. data/spec/lib/aixm/feature/airspace_spec.rb +349 -226
  68. data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +47 -36
  69. data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +61 -36
  70. data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +61 -113
  71. data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +65 -79
  72. data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +57 -36
  73. data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +86 -112
  74. data/spec/lib/aixm/feature/navigational_aid_spec.rb +52 -0
  75. data/spec/lib/aixm/feature/organisation_spec.rb +77 -0
  76. data/spec/lib/aixm/feature/unit_spec.rb +227 -0
  77. data/spec/lib/aixm/feature_spec.rb +58 -0
  78. data/spec/lib/aixm/refinements_spec.rb +187 -178
  79. data/spec/lib/aixm/xy_spec.rb +45 -34
  80. data/spec/lib/aixm/z_spec.rb +19 -21
  81. data/spec/macros/organisation.rb +11 -0
  82. data/spec/macros/remarks.rb +12 -0
  83. data/spec/macros/timetable.rb +11 -0
  84. data/spec/macros/xy.rb +11 -0
  85. data/spec/macros/z_qnh.rb +11 -0
  86. data/spec/spec_helper.rb +26 -0
  87. metadata +60 -19
  88. data/lib/aixm/base.rb +0 -10
  89. data/lib/aixm/component/base.rb +0 -6
  90. data/lib/aixm/component/class_layer.rb +0 -46
  91. data/lib/aixm/component/geometry/base.rb +0 -8
  92. data/lib/aixm/component/schedule.rb +0 -43
  93. data/lib/aixm/feature/base.rb +0 -6
  94. data/lib/aixm/feature/navigational_aid/base.rb +0 -79
  95. data/spec/lib/aixm/component/class_layer_spec.rb +0 -74
  96. data/spec/lib/aixm/component/schedule_spec.rb +0 -33
  97. data/spec/lib/aixm/feature/navigational_aid/base_spec.rb +0 -41
@@ -1,32 +1,41 @@
1
1
  require 'builder'
2
+ require 'ostruct'
3
+ require 'securerandom'
2
4
  require 'nokogiri'
3
5
  require 'forwardable'
4
- require 'ostruct'
5
6
  require 'digest'
6
7
  require 'time'
7
8
 
8
9
  require_relative 'aixm/version'
9
10
  require_relative 'aixm/refinements'
11
+ require_relative 'aixm/config'
12
+ require_relative 'aixm/errors'
10
13
 
11
- require_relative 'aixm/base'
12
14
  require_relative 'aixm/document'
13
15
  require_relative 'aixm/xy'
14
16
  require_relative 'aixm/z'
15
17
  require_relative 'aixm/f'
16
18
 
17
- require_relative 'aixm/component/base'
19
+ require_relative 'aixm/component'
20
+ require_relative 'aixm/component/service'
21
+ require_relative 'aixm/component/frequency'
18
22
  require_relative 'aixm/component/geometry'
19
23
  require_relative 'aixm/component/geometry/point'
20
24
  require_relative 'aixm/component/geometry/arc'
21
25
  require_relative 'aixm/component/geometry/border'
22
26
  require_relative 'aixm/component/geometry/circle'
23
- require_relative 'aixm/component/class_layer'
27
+ require_relative 'aixm/component/layer'
24
28
  require_relative 'aixm/component/vertical_limits'
25
- require_relative 'aixm/component/schedule'
29
+ require_relative 'aixm/component/timetable'
30
+ require_relative 'aixm/component/runway'
31
+ require_relative 'aixm/component/helipad'
26
32
 
27
- require_relative 'aixm/feature/base'
33
+ require_relative 'aixm/feature'
34
+ require_relative 'aixm/feature/organisation'
35
+ require_relative 'aixm/feature/unit'
28
36
  require_relative 'aixm/feature/airspace'
29
- require_relative 'aixm/feature/navigational_aid/base'
37
+ require_relative 'aixm/feature/airport'
38
+ require_relative 'aixm/feature/navigational_aid'
30
39
  require_relative 'aixm/feature/navigational_aid/designated_point'
31
40
  require_relative 'aixm/feature/navigational_aid/dme'
32
41
  require_relative 'aixm/feature/navigational_aid/marker'
@@ -0,0 +1,6 @@
1
+ module AIXM
2
+
3
+ # @abstract
4
+ class Component; end
5
+
6
+ end
@@ -0,0 +1,135 @@
1
+ using AIXM::Refinements
2
+
3
+ module AIXM
4
+ class Component
5
+
6
+ # Frequencies used by a service.
7
+ #
8
+ # By default, {#reception_f} is set to the same value as {#transmission_f}
9
+ # since most services rely on simplex (aka: non-duplex) two-way
10
+ # communication. For services with one-way communication only such as ATIS,
11
+ # the {#reception_f} has to be set to +nil+ explicitly!
12
+ #
13
+ # ===Cheat Sheet in Pseudo Code:
14
+ # frequency = AIXM.frequency(
15
+ # transmission_f: AIXM.f
16
+ # callsigns: Hash
17
+ # )
18
+ # frequency.reception_f = AIXM.f or nil
19
+ # frequency.type = TYPES or nil
20
+ # frequency.timetable = AIXM.timetable or nil
21
+ # frequency.remarks = String or nil
22
+ #
23
+ # @see https://github.com/openflightmaps/ofmx/wiki/Organisation#fqy-frequency
24
+ class Frequency
25
+ TYPES = {
26
+ STD: :standard,
27
+ ALT: :alternative,
28
+ EMRG: :emergency,
29
+ GUARD: :guard,
30
+ MIL: :military,
31
+ CIV: :civilian,
32
+ OTHER: :other # specify in remarks
33
+ }.freeze
34
+
35
+ # @return [AIXM::Component::Service] service the frequency belongs to
36
+ attr_reader :service
37
+
38
+ # @return [AIXM::F] frequency for transmission (outgoing)
39
+ attr_reader :transmission_f
40
+
41
+ # @example
42
+ # { en: "STRASBOURG CONTROL", fr: "STRASBOURG CONTROLE" }
43
+ #
44
+ # @return [Hash] map from languages (ISO 639-1) to callsigns
45
+ attr_reader :callsigns
46
+
47
+ # @note One-way services such as ATIS should set this to +nil+ and simplex
48
+ # (aka: non-duplex) communication should set this to {#transmission_f}.
49
+ # @return [AIXM::F, nil] frequency for reception (incoming)
50
+ attr_reader :reception_f
51
+
52
+ # @return [Symbol, nil] type of frequency (see {TYPES})
53
+ attr_reader :type
54
+
55
+ # @return [AIXM::Component::Timetable, nil] operating hours
56
+ attr_reader :timetable
57
+
58
+ # @return [String, nil] free text remarks
59
+ attr_reader :remarks
60
+
61
+ def initialize(transmission_f:, callsigns:)
62
+ self.transmission_f, self.callsigns = transmission_f, callsigns
63
+ self.reception_f = transmission_f
64
+ end
65
+
66
+ # @return [String]
67
+ def inspect
68
+ %Q(#<#{self.class} transmission_f=#{transmission_f.inspect} callsigns=#{callsigns.inspect}>)
69
+ end
70
+
71
+ def service=(value)
72
+ fail(ArgumentError, "invalid service") unless value.is_a? AIXM::Component::Service
73
+ @service = value
74
+ end
75
+ private :service=
76
+
77
+ def transmission_f=(value)
78
+ fail(ArgumentError, "invalid transmission_f") unless value.is_a? AIXM::F
79
+ @transmission_f = value
80
+ end
81
+
82
+ def callsigns=(value)
83
+ fail(ArgumentError, "invalid callsigns") unless value.is_a?(Hash)
84
+ @callsigns = value.transform_keys { |k| k.to_sym.downcase }.transform_values { |v| v.to_s.uptrans }
85
+ end
86
+
87
+ def reception_f=(value)
88
+ fail(ArgumentError, "invalid reception_f") unless value.nil? || value.is_a?(AIXM::F)
89
+ @reception_f = value
90
+ end
91
+
92
+ def type=(value)
93
+ @type = value.nil? ? nil : TYPES.lookup(value.to_s.to_sym, nil) || fail(ArgumentError, "invalid type")
94
+ end
95
+
96
+ def timetable=(value)
97
+ fail(ArgumentError, "invalid timetable") unless value.nil? || value.is_a?(AIXM::Component::Timetable)
98
+ @timetable = value
99
+ end
100
+
101
+ def remarks=(value)
102
+ @remarks = value&.to_s
103
+ end
104
+
105
+ # @return [String] UID markup
106
+ def to_uid
107
+ builder = Builder::XmlMarkup.new(indent: 2)
108
+ builder.FqyUid do |fqy_uid|
109
+ fqy_uid << service.to_uid.indent(2)
110
+ fqy_uid.valFreqTrans(transmission_f.freq)
111
+ end
112
+ end
113
+
114
+ # @return [String] AIXM or OFMX markup
115
+ def to_xml
116
+ builder = Builder::XmlMarkup.new(indent: 2)
117
+ builder.Fqy do |fqy|
118
+ fqy << to_uid.indent(2)
119
+ fqy.valFreqRec(reception_f.freq) if reception_f
120
+ fqy.uomFreq(transmission_f.unit.upcase.to_s)
121
+ fqy << timetable.to_xml(as: :Ftt).indent(2) if timetable
122
+ fqy.txtRmk(remarks) if remarks
123
+ callsigns.each do |language, callsign|
124
+ fqy.Cdl do |cdl|
125
+ cdl.txtCallSign(callsign)
126
+ cdl.codeLang(language.upcase.to_s)
127
+ end
128
+ end
129
+ fqy.target!
130
+ end
131
+ end
132
+ end
133
+
134
+ end
135
+ end
@@ -1,25 +1,36 @@
1
+ using AIXM::Refinements
2
+
1
3
  module AIXM
2
- module Component
4
+ class Component
3
5
 
4
- ##
5
6
  # Geometries define a 3D airspace horizontally. It's either exactly one
6
7
  # circle or at least three points, arcs and borders (the last of which
7
8
  # has to be a point with the same coordinates as the first).
8
9
  #
9
- # Example 1:
10
+ # For a geometry to be valid, it must be comprised of either:
11
+ # * exactly one circle
12
+ # * at least three points, arcs or borders (the last of which a point with
13
+ # identical coordinates as the first)
14
+ #
15
+ # ===Cheat Sheet in Pseudo Code:
16
+ # geometry = AIXM.geometry
17
+ # geometry << AIXM.point or AIXM.arc or AIXM.border or AIXM.circle
18
+ #
19
+ # @example Built by passing elements to the initializer
10
20
  # geometry = AIXM.geometry(
11
21
  # AIXM.point(...),
12
22
  # AIXM.point(...)
13
23
  # )
14
24
  #
15
- # Example 2:
25
+ # @example Built by adding elements
16
26
  # geometry = AIXM.geometry
17
27
  # geometry << AIXM.point(...)
18
28
  # geometry << AIXM.point(...)
19
- class Geometry < Base
29
+ #
30
+ # @see https://github.com/openflightmaps/ofmx/wiki/Airspace#avx-border-vertex
31
+ class Geometry
20
32
  include Enumerable
21
33
  extend Forwardable
22
- using AIXM::Refinements
23
34
 
24
35
  def_delegators :@result_array, :each, :<<
25
36
 
@@ -27,28 +38,28 @@ module AIXM
27
38
  @result_array = segments
28
39
  end
29
40
 
30
- ##
31
- # Array of +AIXM::Component::Geometry::...+ objects
32
- def segments
33
- @result_array
41
+ # @return [String]
42
+ def inspect
43
+ %Q(#<#{self.class} segments=#{segments.count.inspect}>)
34
44
  end
35
45
 
36
- ##
37
- # Check whether the geometry is complete
38
- def complete?
39
- circle? || closed_shape?
46
+ # @return [Array<AIXM::Component::Geometry::Point,
47
+ # AIXM::Component::Geometry::Arc,
48
+ # AIXM::Component::Geometry::Border,
49
+ # AIXM::Component::Geometry::Circle>] points, arcs, borders or circle
50
+ def segments
51
+ @result_array
40
52
  end
41
53
 
42
- ##
43
- # Digest to identify the payload
44
- def to_digest
45
- segments.map(&:to_digest).to_digest
54
+ # @return [Boolean] whether the geometry is closed
55
+ def closed?
56
+ circle? || polygon?
46
57
  end
47
58
 
48
- ##
49
- # Render AIXM markup
50
- def to_aixm(*extensions)
51
- @result_array.map { |h| h.to_aixm(*extensions) }.join
59
+ # @return [String] AIXM or OFMX markup
60
+ def to_xml
61
+ fail(GeometryError, "geometry is not closed") unless closed?
62
+ @result_array.map { |h| h.to_xml }.join
52
63
  end
53
64
 
54
65
  private
@@ -58,7 +69,7 @@ module AIXM
58
69
  @result_array.first.is_a?(AIXM::Component::Geometry::Circle)
59
70
  end
60
71
 
61
- def closed_shape?
72
+ def polygon?
62
73
  @result_array.size >= 3 &&
63
74
  !@result_array.any? { |h| h.is_a?(AIXM::Component::Geometry::Circle) } &&
64
75
  @result_array.last.is_a?(AIXM::Component::Geometry::Point) &&
@@ -1,45 +1,60 @@
1
+ using AIXM::Refinements
2
+
1
3
  module AIXM
2
- module Component
4
+ class Component
3
5
  class Geometry
4
6
 
5
- ##
6
- # Arcs are +clockwise+ (true/false) circle sectors around +center_xy+ and
7
- # starting at +xy+.
7
+ # Arcs are clockwise or counter clockwise circle segments around a
8
+ # {#center_xy} and starting at {#xy}.
9
+ #
10
+ # ===Cheat Sheet in Pseudo Code:
11
+ # arc = AIXM.arc(
12
+ # xy: AIXM.xy
13
+ # center_xy: AIXM.xy
14
+ # clockwise: true or false
15
+ # )
16
+ #
17
+ # @see https://github.com/openflightmaps/ofmx/wiki/Airspace#arc
8
18
  class Arc < Point
9
- using AIXM::Refinements
10
-
19
+ # @return [AIXM::XY] center point
11
20
  attr_reader :center_xy
12
21
 
13
22
  def initialize(xy:, center_xy:, clockwise:)
14
23
  super(xy: xy)
15
- fail(ArgumentError, "invalid center xy") unless center_xy.is_a? AIXM::XY
16
- fail(ArgumentError, "clockwise must be true or false") unless [true, false].include? clockwise
17
- @center_xy, @clockwise = center_xy, clockwise
24
+ self.center_xy, self.clockwise = center_xy, clockwise
25
+ end
26
+
27
+ # @return [String]
28
+ def inspect
29
+ %Q(#<#{self.class} xy="#{xy.to_s}">)
30
+ end
31
+
32
+ def center_xy=(value)
33
+ fail(ArgumentError, "invalid center xy") unless value.is_a? AIXM::XY
34
+ @center_xy = value
18
35
  end
19
36
 
20
- ##
21
- # Whether the arc is going clockwise (true) or not (false)
37
+ # @!attribute [w] clockwise
38
+ # @return [Boolean] wheter the arc is going clockwise (true) or not (false)
22
39
  def clockwise?
23
40
  @clockwise
24
41
  end
25
42
 
26
- ##
27
- # Digest to identify the payload
28
- def to_digest
29
- [xy.lat, xy.long, center_xy.lat, center_xy.long, clockwise?].to_digest
43
+ def clockwise=(value)
44
+ fail(ArgumentError, "clockwise must be true or false") unless [true, false].include? value
45
+ @clockwise = value
30
46
  end
31
47
 
32
- ##
33
- # Render AIXM markup
34
- def to_aixm(*extensions)
48
+ # @return [String] AIXM or OFMX markup
49
+ def to_xml
35
50
  builder = Builder::XmlMarkup.new(indent: 2)
36
51
  builder.Avx do |avx|
37
52
  avx.codeType(clockwise? ? 'CWA' : 'CCA')
38
- avx.geoLat(xy.lat(format_for(*extensions)))
39
- avx.geoLong(xy.long(format_for(*extensions)))
53
+ avx.geoLat(xy.lat(AIXM.schema))
54
+ avx.geoLong(xy.long(AIXM.schema))
40
55
  avx.codeDatum('WGE')
41
- avx.geoLatArc(center_xy.lat(format_for(*extensions)))
42
- avx.geoLongArc(center_xy.long(format_for(*extensions)))
56
+ avx.geoLatArc(center_xy.lat(AIXM.schema))
57
+ avx.geoLongArc(center_xy.long(AIXM.schema))
43
58
  end
44
59
  end
45
60
  end
@@ -1,40 +1,49 @@
1
+ using AIXM::Refinements
2
+
1
3
  module AIXM
2
- module Component
4
+ class Component
3
5
  class Geometry
4
6
 
5
- ##
6
7
  # Borders are following natural or artifical border lines referenced by
7
- # +name+ and starting at +xy+.
8
+ # {#name} and starting at {#xy}.
9
+ #
10
+ # ===Cheat Sheet in Pseudo Code:
11
+ # border = AIXM.border(
12
+ # xy: AIXM.xy
13
+ # name: String
14
+ # )
15
+ #
16
+ # @see https://github.com/openflightmaps/ofmx/wiki/Airspace#frontier
8
17
  class Border < Point
9
- using AIXM::Refinements
10
-
18
+ # @return [String] name of the border
11
19
  attr_reader :name
12
20
 
13
21
  def initialize(xy:, name:)
14
22
  super(xy: xy)
15
- @name = name
23
+ self.name = name
24
+ end
25
+
26
+ # @return [String]
27
+ def inspect
28
+ %Q(#<#{self.class} xy="#{xy.to_s}">)
16
29
  end
17
30
 
18
- ##
19
- # Digest to identify the payload
20
- def to_digest
21
- [xy.lat, xy.long, name].to_digest
31
+ def name=(value)
32
+ fail(ArgumentError, "invalid name") unless value.is_a? String
33
+ @name = value
22
34
  end
23
35
 
24
- ##
25
- # Render AIXM markup
26
- def to_aixm(*extensions)
36
+ # @return [String] AIXM or OFMX markup
37
+ def to_xml
27
38
  builder = Builder::XmlMarkup.new(indent: 2)
28
39
  builder.Avx do |avx|
40
+ avx.GbrUid do |gbr_uid|
41
+ gbr_uid.txtName(name.to_s)
42
+ end
29
43
  avx.codeType('FNT')
30
- avx.geoLat(xy.lat(format_for(*extensions)))
31
- avx.geoLong(xy.long(format_for(*extensions)))
44
+ avx.geoLat(xy.lat(AIXM.schema))
45
+ avx.geoLong(xy.long(AIXM.schema))
32
46
  avx.codeDatum('WGE')
33
- if extensions >> :ofm
34
- avx.GbrUid do |gbruid|
35
- gbruid.txtName(name.to_s)
36
- end
37
- end
38
47
  end
39
48
  end
40
49
  end
@@ -1,47 +1,64 @@
1
+ using AIXM::Refinements
2
+
1
3
  module AIXM
2
- module Component
4
+ class Component
3
5
  class Geometry
4
6
 
5
- ##
6
- # Circles are defined by a +center_xy+ and a +radius+ in kilometers.
7
- class Circle < Base
8
- using AIXM::Refinements
7
+ # Circles are defined by a {#center_xy} and a {#radius} in kilometers.
8
+ #
9
+ # ===Cheat Sheet in Pseudo Code:
10
+ # circle = AIXM.circle(
11
+ # center_xy: AIXM.xy
12
+ # radius: Numeric # kilometers
13
+ # )
14
+ #
15
+ # @see https://github.com/openflightmaps/ofmx/wiki/Airspace#circle
16
+ class Circle
17
+ # @return [AIXM::XY] center point
18
+ attr_reader :center_xy
9
19
 
10
- attr_reader :center_xy, :radius
20
+ # @return [Integer] circle radius
21
+ attr_reader :radius
11
22
 
12
23
  def initialize(center_xy:, radius:)
13
- fail(ArgumentError, "invalid center xy") unless center_xy.is_a? AIXM::XY
14
- @center_xy, @radius = center_xy, radius
24
+ self.center_xy, self.radius = center_xy, radius
25
+ end
26
+
27
+ # @return [String]
28
+ def inspect
29
+ %Q(#<#{self.class} xy="#{xy.to_s}">)
30
+ end
31
+
32
+ def center_xy=(value)
33
+ fail(ArgumentError, "invalid center xy") unless value.is_a? AIXM::XY
34
+ @center_xy = value
15
35
  end
16
36
 
17
- ##
18
- # Digest to identify the payload
19
- def to_digest
20
- [center_xy.lat, center_xy.long, radius].to_digest
37
+ def radius=(value)
38
+ fail(ArgumentError, "invalid radius") unless value.is_a?(Numeric) && value > 0
39
+ @radius = value.to_f
21
40
  end
22
41
 
23
- ##
24
- # Render AIXM markup
25
- def to_aixm(*extensions)
42
+ # @return [String] AIXM or OFMX markup
43
+ def to_xml
26
44
  builder = Builder::XmlMarkup.new(indent: 2)
27
45
  builder.Avx do |avx|
28
46
  avx.codeType('CWA')
29
- avx.geoLat(north_xy.lat(format_for(*extensions)))
30
- avx.geoLong(north_xy.long(format_for(*extensions)))
47
+ avx.geoLat(north_xy.lat(AIXM.schema))
48
+ avx.geoLong(north_xy.long(AIXM.schema))
31
49
  avx.codeDatum('WGE')
32
- avx.geoLatArc(center_xy.lat(format_for(*extensions)))
33
- avx.geoLongArc(center_xy.long(format_for(*extensions)))
50
+ avx.geoLatArc(center_xy.lat(AIXM.schema))
51
+ avx.geoLongArc(center_xy.long(AIXM.schema))
34
52
  end
35
53
  end
36
54
 
37
55
  private
38
56
 
39
- ##
40
57
  # Coordinates of the point which is both strictly north of the center
41
- # and on the circumference of the circle
58
+ # and on the circumference of the circle.
42
59
  def north_xy
43
60
  AIXM.xy(
44
- lat: center_xy.lat + radius.to_f / 6371 * 180 / Math::PI,
61
+ lat: center_xy.lat + radius.to_f / (AIXM::XY::EARTH_RADIUS / 1000) * 180 / Math::PI,
45
62
  long: center_xy.long
46
63
  )
47
64
  end