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
@@ -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