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
@@ -16,8 +16,12 @@ module AIXM
16
16
 
17
17
  def initialize(id:, name:, xy:, z: nil, f:)
18
18
  super(id: id, name: name, xy: xy, z: z)
19
- @f = f
20
- fail(ArgumentError, "invalid frequency") unless f.is_a?(F) && f.between?(190, 1750, :khz)
19
+ self.f = f
20
+ end
21
+
22
+ def f=(value)
23
+ fail(ArgumentError, "invalid f") unless value.is_a?(F) && value.between?(190, 1750, :khz)
24
+ @f = value
21
25
  end
22
26
 
23
27
  ##
@@ -27,15 +31,22 @@ module AIXM
27
31
  end
28
32
 
29
33
  ##
30
- # Render AIXM
31
- def to_xml(*extensions)
34
+ # Render UID markup
35
+ def to_uid(*extensions)
36
+ builder = Builder::XmlMarkup.new(indent: 2)
37
+ builder.NdbUid({ newEntity: (true if extensions >> :ofm) }.compact) do |ndbuid|
38
+ ndbuid.codeId(id)
39
+ ndbuid.geoLat(xy.lat(format_for(*extensions)))
40
+ ndbuid.geoLong(xy.long(format_for(*extensions)))
41
+ end
42
+ end
43
+
44
+ ##
45
+ # Render AIXM markup
46
+ def to_aixm(*extensions)
32
47
  builder = to_builder(*extensions)
33
48
  builder.Ndb do |ndb|
34
- ndb.NdbUid({ newEntity: (true if extensions >> :ofm) }.compact) do |ndbuid|
35
- ndbuid.codeId(id)
36
- ndbuid.geoLat(xy.lat(format_for(*extensions)))
37
- ndbuid.geoLong(xy.long(format_for(*extensions)))
38
- end
49
+ ndb << to_uid(*extensions).indent(2)
39
50
  ndb.OrgUid
40
51
  ndb.txtName(name)
41
52
  ndb.valFreq(f.freq.trim)
@@ -45,6 +56,11 @@ module AIXM
45
56
  ndb.valElev(z.alt)
46
57
  ndb.uomDistVer(z.unit.to_s)
47
58
  end
59
+ if schedule
60
+ ndb.Ntt do |ntt|
61
+ ntt << schedule.to_aixm(*extensions).indent(4)
62
+ end
63
+ end
48
64
  ndb.txtRmk(remarks) if remarks
49
65
  ndb.target! # see https://github.com/jimweirich/builder/issues/42
50
66
  end
@@ -3,39 +3,35 @@ module AIXM
3
3
  module NavigationalAid
4
4
 
5
5
  ##
6
- # TACAN (tactical air navigation system) operate in the frequency band
7
- # between 960 MHz and 1215 MHz.
6
+ # TACAN (tactical air navigation system) can be used as a DME by civilian
7
+ # aircraft and therefore operate in the frequency band between 960 MHz
8
+ # and 1215 MHz.
8
9
  #
9
10
  # https://en.wikipedia.org/wiki/Tactical_air_navigation_system
10
- class TACAN < Base
11
+ class TACAN < DME
11
12
  using AIXM::Refinements
12
13
 
13
- attr_reader :channel
14
-
15
14
  public_class_method :new
16
15
 
17
- def initialize(id:, name:, xy:, z: nil, channel:)
18
- super(id: id, name: name, xy: xy, z: z)
19
- @channel = channel&.upcase
20
- end
21
-
22
16
  ##
23
- # Digest to identify the payload
24
- def to_digest
25
- [super, channel].to_digest
17
+ # Render UID markup
18
+ def to_uid(*extensions)
19
+ builder = Builder::XmlMarkup.new(indent: 2)
20
+ builder.TcnUid({ newEntity: (true if extensions >> :ofm) }.compact) do |tcnuid|
21
+ tcnuid.codeId(id)
22
+ tcnuid.geoLat(xy.lat(format_for(*extensions)))
23
+ tcnuid.geoLong(xy.long(format_for(*extensions)))
24
+ end
26
25
  end
27
26
 
28
27
  ##
29
- # Render AIXM
30
- def to_xml(*extensions)
28
+ # Render AIXM markup
29
+ def to_aixm(*extensions)
31
30
  builder = to_builder(*extensions)
32
31
  builder.Tcn do |tcn|
33
- tcn.TcnUid({ newEntity: (true if extensions >> :ofm) }.compact) do |tcnuid|
34
- tcnuid.codeId(id)
35
- tcnuid.geoLat(xy.lat(format_for(*extensions)))
36
- tcnuid.geoLong(xy.long(format_for(*extensions)))
37
- end
32
+ tcn << to_uid(*extensions).indent(2)
38
33
  tcn.OrgUid
34
+ tcn << vor.to_uid(*extensions).indent(2) if vor
39
35
  tcn.txtName(name)
40
36
  tcn.codeChannel(channel)
41
37
  tcn.codeDatum('WGE')
@@ -43,6 +39,11 @@ module AIXM
43
39
  tcn.valElev(z.alt)
44
40
  tcn.uomDistVer(z.unit.to_s)
45
41
  end
42
+ if schedule
43
+ tcn.Ttt do |ttt|
44
+ ttt << schedule.to_aixm(*extensions).indent(4)
45
+ end
46
+ end
46
47
  tcn.txtRmk(remarks) if remarks
47
48
  tcn.target! # see https://github.com/jimweirich/builder/issues/42
48
49
  end
@@ -8,7 +8,7 @@ module AIXM
8
8
  #
9
9
  # Types:
10
10
  # * +:vor+ (+:VOR+) - standard VOR
11
- # * +:vordme+ (+:DVOR+) - VOR/DME
11
+ # * +:doppler_vor+ (+:DVOR+) - Doppler VOR
12
12
  #
13
13
  # North types:
14
14
  # * +:geographic+ (+:TRUE+) - VOR aligned towards geographic north
@@ -16,7 +16,6 @@ module AIXM
16
16
  # universal transverse mercator grid imposed on
17
17
  # topographic maps by the USA and NATO
18
18
  # * +:magnetic+ (+:MAG+) - VOR aligned towards magnetic north
19
- # * +:other+ (+:OTHER+) - other north type
20
19
  #
21
20
  # https://en.wikipedia.org/wiki/VHF_omnidirectional_range
22
21
  class VOR < Base
@@ -24,26 +23,61 @@ module AIXM
24
23
 
25
24
  TYPES = {
26
25
  VOR: :vor,
27
- DVOR: :vordme
26
+ DVOR: :doppler_vor
28
27
  }.freeze
29
28
 
30
29
  NORTHS = {
31
30
  TRUE: :geographic,
32
31
  GRID: :grid,
33
- MAG: :magnetic,
34
- OTHER: :other
32
+ MAG: :magnetic
35
33
  }.freeze
36
34
 
37
- attr_reader :type, :f, :north
35
+ attr_reader :type, :f, :north, :dme, :tacan
38
36
 
39
37
  public_class_method :new
40
38
 
41
39
  def initialize(id:, name:, xy:, z: nil, type:, f:, north:)
42
40
  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)
41
+ self.type, self.f, self.north = type, f, north
42
+ end
43
+
44
+ def type=(value)
45
+ @type = TYPES.lookup(value&.to_sym, nil) || fail(ArgumentError, "invalid type")
46
+ end
47
+
48
+ def type_key
49
+ TYPES.key(type)
50
+ end
51
+
52
+ def f=(value)
53
+ fail(ArgumentError, "invalid f") unless value.is_a?(F) && value.between?(108, 117.95, :mhz)
54
+ @f = value
55
+ end
56
+
57
+ def north=(value)
58
+ @north = NORTHS.lookup(value&.to_sym, nil) || fail(ArgumentError, "invalid north")
59
+ end
60
+
61
+ def north_key
62
+ NORTHS.key(north)
63
+ end
64
+
65
+ ##
66
+ # Associate a DME (also known as VOR/DME)
67
+ def associate_dme(channel:)
68
+ @dme = AIXM.dme(id: id, name: name, xy: xy, z: z, channel: channel)
69
+ @dme.schedule = schedule
70
+ @dme.remarks = remarks
71
+ @dme.vor = self
72
+ end
73
+
74
+ ##
75
+ # Associate a TACAN (also known as VORTAC)
76
+ def associate_tacan(channel:)
77
+ @tacan = AIXM.tacan(id: id, name: name, xy: xy, z: z, channel: channel)
78
+ @tacan.schedule = schedule
79
+ @tacan.remarks = remarks
80
+ @tacan.vor = self
47
81
  end
48
82
 
49
83
  ##
@@ -53,15 +87,22 @@ module AIXM
53
87
  end
54
88
 
55
89
  ##
56
- # Render AIXM
57
- def to_xml(*extensions)
90
+ # Render UID markup
91
+ def to_uid(*extensions)
92
+ builder = Builder::XmlMarkup.new(indent: 2)
93
+ builder.VorUid({ newEntity: (true if extensions >> :ofm) }.compact) do |voruid|
94
+ voruid.codeId(id)
95
+ voruid.geoLat(xy.lat(format_for(*extensions)))
96
+ voruid.geoLong(xy.long(format_for(*extensions)))
97
+ end
98
+ end
99
+
100
+ ##
101
+ # Render AIXM markup
102
+ def to_aixm(*extensions)
58
103
  builder = to_builder(*extensions)
59
104
  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
105
+ vor << to_uid(*extensions).indent(2)
65
106
  vor.OrgUid
66
107
  vor.txtName(name)
67
108
  vor.codeType(type_key.to_s)
@@ -73,17 +114,16 @@ module AIXM
73
114
  vor.valElev(z.alt)
74
115
  vor.uomDistVer(z.unit.to_s)
75
116
  end
117
+ if schedule
118
+ vor.Vtt do |vtt|
119
+ vtt << schedule.to_aixm(*extensions).indent(4)
120
+ end
121
+ end
76
122
  vor.txtRmk(remarks) if remarks
77
- vor.target! # see https://github.com/jimweirich/builder/issues/42
78
123
  end
79
- end
80
-
81
- def type_key
82
- TYPES.key(type)
83
- end
84
-
85
- def north_key
86
- NORTHS.key(north)
124
+ builder << @dme.to_aixm(*extensions) if @dme
125
+ builder << @tacan.to_aixm(*extensions) if @tacan
126
+ builder.target! # see https://github.com/jimweirich/builder/issues/42
87
127
  end
88
128
  end
89
129
 
data/lib/aixm/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module AIXM
2
- VERSION = "0.2.0".freeze
2
+ VERSION = "0.2.1".freeze
3
3
  end
data/spec/factory.rb CHANGED
@@ -48,26 +48,26 @@ module AIXM
48
48
  end
49
49
  end
50
50
 
51
- def polygon_airspace(short_name: 'POLYGON', schedule: :H24)
51
+ def polygon_airspace
52
52
  AIXM.airspace(
53
53
  name: 'POLYGON AIRSPACE',
54
- short_name: short_name,
54
+ short_name: 'POLYGON',
55
55
  type: 'D'
56
56
  ).tap do |airspace|
57
- airspace.schedule = AIXM.schedule(code: schedule) if schedule
57
+ airspace.schedule = AIXM::H24
58
58
  airspace.class_layers << class_layer
59
59
  airspace.geometry = polygon_geometry
60
60
  airspace.remarks = 'polygon airspace'
61
61
  end
62
62
  end
63
63
 
64
- def circle_airspace(short_name: 'CIRCLE', schedule: :H24)
64
+ def circle_airspace
65
65
  AIXM.airspace(
66
66
  name: 'CIRCLE AIRSPACE',
67
- short_name: short_name,
67
+ short_name: 'CIRCLE',
68
68
  type: 'D'
69
69
  ).tap do |airspace|
70
- airspace.schedule = AIXM.schedule(code: schedule) if schedule
70
+ airspace.schedule = AIXM::H24
71
71
  airspace.class_layers << class_layer
72
72
  airspace.geometry = circle_geometry
73
73
  airspace.remarks = 'circle airspace'
@@ -76,24 +76,26 @@ module AIXM
76
76
 
77
77
  def designated_point
78
78
  AIXM.designated_point(
79
- id: 'DPN',
79
+ id: 'DDD',
80
80
  name: 'DESIGNATED POINT NAVAID',
81
81
  xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
82
82
  z: AIXM.z(500, :qnh),
83
83
  type: :ICAO
84
84
  ).tap do |designated_point|
85
+ designated_point.schedule = AIXM::H24
85
86
  designated_point.remarks = 'designated point navaid'
86
87
  end
87
88
  end
88
89
 
89
90
  def dme
90
91
  AIXM.dme(
91
- id: 'DME',
92
+ id: 'MMM',
92
93
  name: 'DME NAVAID',
93
94
  xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
94
95
  z: AIXM.z(500, :qnh),
95
96
  channel: '95X'
96
97
  ).tap do |dme|
98
+ dme.schedule = AIXM::H24
97
99
  dme.remarks = 'dme navaid'
98
100
  end
99
101
  end
@@ -105,48 +107,99 @@ module AIXM
105
107
  xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
106
108
  z: AIXM.z(500, :qnh)
107
109
  ).tap do |marker|
110
+ marker.schedule = AIXM::H24
108
111
  marker.remarks = 'marker navaid'
109
112
  end
110
113
  end
111
114
 
112
115
  def ndb
113
116
  AIXM.ndb(
114
- id: 'NDB',
117
+ id: 'NNN',
115
118
  name: 'NDB NAVAID',
116
119
  xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
117
120
  z: AIXM.z(500, :qnh),
118
121
  f: AIXM.f(555, :khz)
119
122
  ).tap do |ndb|
123
+ ndb.schedule = AIXM::H24
120
124
  ndb.remarks = 'ndb navaid'
121
125
  end
122
126
  end
123
127
 
124
128
  def tacan
125
129
  AIXM.tacan(
126
- id: 'TCN',
130
+ id: 'TTT',
127
131
  name: 'TACAN NAVAID',
128
132
  xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
129
133
  z: AIXM.z(500, :qnh),
130
134
  channel: '29X'
131
135
  ).tap do |tacan|
136
+ tacan.schedule = AIXM::H24
132
137
  tacan.remarks = 'tacan navaid'
133
138
  end
134
139
  end
135
140
 
136
141
  def vor
137
142
  AIXM.vor(
138
- id: 'VOR',
143
+ id: 'VVV',
139
144
  name: 'VOR NAVAID',
140
145
  xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
141
146
  z: AIXM.z(500, :qnh),
142
- type: :VOR,
147
+ type: :vor,
143
148
  f: AIXM.f(111, :mhz),
144
149
  north: :geographic
145
150
  ).tap do |vor|
151
+ vor.schedule = AIXM::H24
146
152
  vor.remarks = 'vor navaid'
147
153
  end
148
154
  end
149
155
 
156
+ def dvor
157
+ AIXM.vor(
158
+ id: 'DVV',
159
+ name: 'DOPPLER-VOR NAVAID',
160
+ xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
161
+ z: AIXM.z(500, :qnh),
162
+ type: :doppler_vor,
163
+ f: AIXM.f(111, :mhz),
164
+ north: :geographic
165
+ ).tap do |doppler_vor|
166
+ doppler_vor.schedule = AIXM::H24
167
+ doppler_vor.remarks = 'doppler-vor navaid'
168
+ end
169
+ end
170
+
171
+ def vordme
172
+ AIXM.vor(
173
+ id: 'VDD',
174
+ name: 'VOR/DME NAVAID',
175
+ xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
176
+ z: AIXM.z(500, :qnh),
177
+ type: :vor,
178
+ f: AIXM.f(111, :mhz),
179
+ north: :geographic
180
+ ).tap do |vordme|
181
+ vordme.schedule = AIXM::H24
182
+ vordme.remarks = 'vor/dme navaid'
183
+ vordme.associate_dme(channel: '95X')
184
+ end
185
+ end
186
+
187
+ def vortac
188
+ AIXM.vor(
189
+ id: 'VTT',
190
+ name: 'VORTAC NAVAID',
191
+ xy: AIXM.xy(lat: %q(47°51'33"N), long: %q(007°33'36"E)),
192
+ z: AIXM.z(500, :qnh),
193
+ type: :vor,
194
+ f: AIXM.f(111, :mhz),
195
+ north: :geographic
196
+ ).tap do |vortac|
197
+ vortac.schedule = AIXM::H24
198
+ vortac.remarks = 'vortac navaid'
199
+ vortac.associate_tacan(channel: '29X')
200
+ end
201
+ end
202
+
150
203
  def document
151
204
  time = Time.parse('2018-01-18 12:00:00 +0100')
152
205
  AIXM.document(created_at: time, effective_at: time).tap do |document|
@@ -156,8 +209,11 @@ module AIXM
156
209
  document.features << AIXM::Factory.dme
157
210
  document.features << AIXM::Factory.marker
158
211
  document.features << AIXM::Factory.ndb
159
- document.features << AIXM::Factory.vor
160
212
  document.features << AIXM::Factory.tacan
213
+ document.features << AIXM::Factory.vor
214
+ document.features << AIXM::Factory.dvor
215
+ document.features << AIXM::Factory.vordme
216
+ document.features << AIXM::Factory.vortac
161
217
  end
162
218
  end
163
219