aixm 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -6
- data/README.md +2 -0
- data/lib/aixm.rb +3 -0
- data/lib/aixm/component/geometry/circle.rb +6 -6
- data/lib/aixm/component/helipad.rb +19 -12
- data/lib/aixm/component/runway.rb +34 -22
- data/lib/aixm/d.rb +66 -0
- data/lib/aixm/document.rb +2 -14
- data/lib/aixm/feature/airport.rb +1 -0
- data/lib/aixm/feature/obstacle.rb +288 -0
- data/lib/aixm/feature/obstacle_group.rb +104 -0
- data/lib/aixm/refinements.rb +105 -102
- data/lib/aixm/shortcuts.rb +3 -0
- data/lib/aixm/version.rb +1 -1
- data/lib/aixm/xy.rb +5 -4
- data/lib/aixm/z.rb +3 -3
- data/spec/factory.rb +108 -5
- data/spec/lib/aixm/component/geometry/circle_spec.rb +4 -8
- data/spec/lib/aixm/component/geometry_spec.rb +2 -2
- data/spec/lib/aixm/component/helipad_spec.rb +2 -10
- data/spec/lib/aixm/component/runway_spec.rb +4 -16
- data/spec/lib/aixm/d_spec.rb +130 -0
- data/spec/lib/aixm/document_spec.rb +215 -2
- data/spec/lib/aixm/feature/obstacle_group_spec.rb +284 -0
- data/spec/lib/aixm/feature/obstacle_spec.rb +285 -0
- data/spec/lib/aixm/refinements_spec.rb +100 -76
- data/spec/lib/aixm/xy_spec.rb +3 -3
- metadata +11 -2
@@ -0,0 +1,104 @@
|
|
1
|
+
using AIXM::Refinements
|
2
|
+
|
3
|
+
module AIXM
|
4
|
+
class Feature
|
5
|
+
|
6
|
+
# Groups of obstacles which consist of either linked (e.g. power line
|
7
|
+
# towers) or unlinked (e.g. wind turbines) members.
|
8
|
+
#
|
9
|
+
# ===Cheat Sheet in Pseudo Code:
|
10
|
+
# obstacle_group = AIXM.obstacle_group(
|
11
|
+
# source: String or nil # see remarks below
|
12
|
+
# name: String or nil
|
13
|
+
# )
|
14
|
+
# obstacle_group.add_obstacle( # add an obstacle to the group
|
15
|
+
# AIXM.obstacle
|
16
|
+
# )
|
17
|
+
# obstacle_group.add_obstacle( # add an obstacle to the group and link
|
18
|
+
# AIXM.obstacle, # it to the obstacle last added to the group
|
19
|
+
# linked_to: :previous,
|
20
|
+
# link_type: LINK_TYPES
|
21
|
+
# )
|
22
|
+
# obstacle_group.add_obstacle( # add an obstacle to the group and link
|
23
|
+
# AIXM.obstacle, # it to any obstacle already in the group
|
24
|
+
# linked_to: AIXM.obstacle,
|
25
|
+
# link_type: LINK_TYPES
|
26
|
+
# )
|
27
|
+
# obstacle_group.id # UUID v3 calculated from the group payload
|
28
|
+
#
|
29
|
+
# As soon as an obstacle is added to a group, it's extended with new the
|
30
|
+
# following attributes:
|
31
|
+
# * group - the group this object belongs to
|
32
|
+
# * linked_to - obstacle this one is linked to (if any)
|
33
|
+
# * link_type - type of link between the two obstacles (if any)
|
34
|
+
#
|
35
|
+
# The source set on the group is handed down to each of it's obstacles and
|
36
|
+
# will be used there unless the individual obstacle overrides it with a
|
37
|
+
# different source of it's own.
|
38
|
+
#
|
39
|
+
# @see https://github.com/openflightmaps/ofmx/wiki/Obstacle
|
40
|
+
class ObstacleGroup < Feature
|
41
|
+
public_class_method :new
|
42
|
+
|
43
|
+
LINK_TYPES = {
|
44
|
+
CABLE: :cable,
|
45
|
+
SOLID: :solid,
|
46
|
+
OTHER: :other
|
47
|
+
}.freeze
|
48
|
+
|
49
|
+
# @return [String] group name
|
50
|
+
attr_reader :name
|
51
|
+
|
52
|
+
# @return [Array<AIXM::Feature::Obstacle>] obstacles in this group
|
53
|
+
attr_reader :obstacles
|
54
|
+
|
55
|
+
def initialize(source: nil, name: nil)
|
56
|
+
super(source: source)
|
57
|
+
self.name = name
|
58
|
+
@obstacles = []
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [String]
|
62
|
+
def inspect
|
63
|
+
%Q(#<#{self.class} #{@obstacles.count} obstacle(s)>)
|
64
|
+
end
|
65
|
+
|
66
|
+
def name=(value)
|
67
|
+
fail(ArgumentError, "invalid name") unless value.nil? || value.is_a?(String)
|
68
|
+
@name = value&.uptrans
|
69
|
+
end
|
70
|
+
|
71
|
+
# Add an obstacle to the group and optionally link it to another obstacle
|
72
|
+
# from the group.
|
73
|
+
#
|
74
|
+
# @param obstacle [AIXM::Feature::Obstacle] obstacle instance
|
75
|
+
# @param linked_to [Symbol, AIXM::Feature::Obstacle, nil] Either:
|
76
|
+
# * :previous - link to the obstacle last added to the group
|
77
|
+
# * AIXM::Feature::Obstacle - link to this specific obstacle
|
78
|
+
# @param link_type [Symbol, nil] type of link (see {LINK_TYPES})
|
79
|
+
# @return [self]
|
80
|
+
def add_obstacle(obstacle, linked_to: nil, link_type: :other)
|
81
|
+
obstacle.extend AIXM::Feature::Obstacle::Grouped
|
82
|
+
obstacle.send(:group=, self)
|
83
|
+
if linked_to && link_type
|
84
|
+
obstacle.send(:linked_to=, linked_to == :previous ? @obstacles.last : linked_to)
|
85
|
+
obstacle.send(:link_type=, link_type)
|
86
|
+
end
|
87
|
+
@obstacles << obstacle
|
88
|
+
self
|
89
|
+
end
|
90
|
+
|
91
|
+
# @return [String] UUID version 3 group identifier
|
92
|
+
def id
|
93
|
+
([name] + @obstacles.map { |o| o.xy.to_s }).to_uuid
|
94
|
+
end
|
95
|
+
alias_method :to_uid, :id # features need "to_uid" for "==" to work
|
96
|
+
|
97
|
+
# @return [String] AIXM or OFMX markup
|
98
|
+
def to_xml
|
99
|
+
@obstacles.map { |o| o.to_xml }.join
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
data/lib/aixm/refinements.rb
CHANGED
@@ -13,13 +13,6 @@ module AIXM
|
|
13
13
|
"Ø" => "Oe"
|
14
14
|
}.freeze
|
15
15
|
|
16
|
-
KM_FACTORS = {
|
17
|
-
km: 1,
|
18
|
-
m: 0.001,
|
19
|
-
nm: 1.852,
|
20
|
-
ft: 0.0003048
|
21
|
-
}.freeze
|
22
|
-
|
23
16
|
# @!method to_digest
|
24
17
|
# Builds a 4 byte hex digest from the Array payload.
|
25
18
|
#
|
@@ -35,6 +28,83 @@ module AIXM
|
|
35
28
|
end
|
36
29
|
end
|
37
30
|
|
31
|
+
# @!method to_uuid
|
32
|
+
# Builds a UUID version 3 digest from the Array payload.
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# ['foo', :bar, nil, [123]].to_uuid
|
36
|
+
# # => "f3920098"
|
37
|
+
#
|
38
|
+
# @note This is a refinement for +Array+
|
39
|
+
# @return [String] UUID version 3
|
40
|
+
refine Array do
|
41
|
+
def to_uuid
|
42
|
+
::Digest::MD5.hexdigest(flatten.map(&:to_s).join('|')).unpack("a8a4a4a4a12").join("-")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# @!method to_dms(padding=3)
|
48
|
+
# Convert DD angle to DMS with the degrees zero padded to +padding+
|
49
|
+
# length.
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# 43.22164444444445.to_dms(2)
|
53
|
+
# # => "43°12'77.92\""
|
54
|
+
# 43.22164444444445.to_dms
|
55
|
+
# # => "043°12'77.92\""
|
56
|
+
#
|
57
|
+
# @note This is a refinement for +Float+
|
58
|
+
# @param padding [Integer] number of digits for the degree part
|
59
|
+
# @return [String] angle in DMS notation +{-}D°MM'SS.SS"+
|
60
|
+
refine Float do
|
61
|
+
def to_dms(padding=3)
|
62
|
+
degrees = self.abs.floor
|
63
|
+
minutes = ((self.abs - degrees) * 60).floor
|
64
|
+
seconds = (self.abs - degrees - minutes.to_f / 60) * 3600
|
65
|
+
minutes, seconds = minutes + 1, 0 if seconds.round(2) == 60
|
66
|
+
degrees, minutes = degrees + 1, 0 if minutes == 60
|
67
|
+
%Q(%s%0#{padding}d°%02d'%05.2f") % [
|
68
|
+
('-' if self.negative?),
|
69
|
+
self.abs.truncate,
|
70
|
+
minutes.abs.truncate,
|
71
|
+
seconds.abs
|
72
|
+
]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# @!method to_rad
|
77
|
+
# Convert an angle from degree to radian.
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# 45.to_rad
|
81
|
+
# # => 0.7853981633974483
|
82
|
+
#
|
83
|
+
# @note This is a refinement for +Float+
|
84
|
+
# @return [Float] radian angle
|
85
|
+
refine Float do
|
86
|
+
def to_rad
|
87
|
+
self * Math::PI / 180
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# @!method trim
|
92
|
+
# Convert whole numbers to Integer and leave all other untouched.
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# 3.0.trim
|
96
|
+
# # => 3
|
97
|
+
# 3.3.trim
|
98
|
+
# # => 3.3
|
99
|
+
#
|
100
|
+
# @note This is a refinement for +Float+
|
101
|
+
# @return [Integer, Float] converted Float
|
102
|
+
refine Float do
|
103
|
+
def trim
|
104
|
+
(self % 1).zero? ? self.to_i : self
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
38
108
|
# @!method lookup(key_or_value, fallback=omitted=true)
|
39
109
|
# Fetch a value from the hash, but unlike +Hash#fetch+, if +key_or_value+
|
40
110
|
# is no hash key, check whether +key_or_value+ is a hash value and if so
|
@@ -79,32 +149,6 @@ module AIXM
|
|
79
149
|
end
|
80
150
|
end
|
81
151
|
|
82
|
-
# @!method uptrans
|
83
|
-
# Upcase and transliterate to match the reduced character set for
|
84
|
-
# AIXM names and titles.
|
85
|
-
#
|
86
|
-
# See {UPTRANS_MAP} for supported diacryts and {UPTRANS_FILTER} for the
|
87
|
-
# list of allowed characters in the returned value.
|
88
|
-
#
|
89
|
-
# @example
|
90
|
-
# "Nîmes-Alès".uptrans
|
91
|
-
# # => "NIMES-ALES"
|
92
|
-
# "Zürich".uptrans
|
93
|
-
# # => "ZUERICH"
|
94
|
-
#
|
95
|
-
# @note This is a refinement for +String+
|
96
|
-
# @return [String] upcased and transliterated String
|
97
|
-
refine String do
|
98
|
-
def uptrans
|
99
|
-
self.dup.tap do |string|
|
100
|
-
string.upcase!
|
101
|
-
string.gsub!(/(#{UPTRANS_MAP.keys.join('|')})/, UPTRANS_MAP)
|
102
|
-
string.unicode_normalize!(:nfd)
|
103
|
-
string.gsub!(UPTRANS_FILTER, '')
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
152
|
# @!method to_dd
|
109
153
|
# Convert DMS angle to DD or +nil+ if the notation is not recognized.
|
110
154
|
#
|
@@ -129,85 +173,44 @@ module AIXM
|
|
129
173
|
end
|
130
174
|
end
|
131
175
|
|
132
|
-
# @!method
|
133
|
-
#
|
134
|
-
#
|
135
|
-
# @example
|
136
|
-
# 3.0.trim
|
137
|
-
# # => 3
|
138
|
-
# 3.3.trim
|
139
|
-
# # => 3.3
|
140
|
-
#
|
141
|
-
# @note This is a refinement for +Float+
|
142
|
-
# @return [Integer, Float] converted Float
|
143
|
-
refine Float do
|
144
|
-
def trim
|
145
|
-
(self % 1).zero? ? self.to_i : self
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
# @!method to_rad
|
150
|
-
# Convert an angle from degree to radian.
|
176
|
+
# @!method to_time
|
177
|
+
# Parse string to date and time.
|
151
178
|
#
|
152
179
|
# @example
|
153
|
-
#
|
154
|
-
# # =>
|
180
|
+
# '2018-01-01 15:00'.to_time
|
181
|
+
# # => 2018-01-01 15:00:00 +0100
|
155
182
|
#
|
156
|
-
# @note This is a refinement for +
|
157
|
-
# @return [
|
158
|
-
refine
|
159
|
-
def
|
160
|
-
self
|
183
|
+
# @note This is a refinement for +String+
|
184
|
+
# @return [Time] date and time
|
185
|
+
refine String do
|
186
|
+
def to_time
|
187
|
+
Time.parse(self)
|
161
188
|
end
|
162
189
|
end
|
163
190
|
|
164
|
-
# @!method
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
168
|
-
# @example
|
169
|
-
# 43.22164444444445.to_dms(2)
|
170
|
-
# # => "43°12'77.92\""
|
171
|
-
# 43.22164444444445.to_dms
|
172
|
-
# # => "043°12'77.92\""
|
191
|
+
# @!method uptrans
|
192
|
+
# Upcase and transliterate to match the reduced character set for
|
193
|
+
# AIXM names and titles.
|
173
194
|
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
# @return [String] angle in DMS notation +{-}D°MM'SS.SS"+
|
177
|
-
refine Float do
|
178
|
-
def to_dms(padding=3)
|
179
|
-
degrees = self.abs.floor
|
180
|
-
minutes = ((self.abs - degrees) * 60).floor
|
181
|
-
seconds = (self.abs - degrees - minutes.to_f / 60) * 3600
|
182
|
-
minutes, seconds = minutes + 1, 0 if seconds.round(2) == 60
|
183
|
-
degrees, minutes = degrees + 1, 0 if minutes == 60
|
184
|
-
%Q(%s%0#{padding}d°%02d'%05.2f") % [
|
185
|
-
('-' if self.negative?),
|
186
|
-
self.abs.truncate,
|
187
|
-
minutes.abs.truncate,
|
188
|
-
seconds.abs
|
189
|
-
]
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
# @!method to_km(from:)
|
194
|
-
# Convert a distance from the source unit +from+ to kilometers.
|
195
|
+
# See {UPTRANS_MAP} for supported diacryts and {UPTRANS_FILTER} for the
|
196
|
+
# list of allowed characters in the returned value.
|
195
197
|
#
|
196
198
|
# @example
|
197
|
-
#
|
198
|
-
# # =>
|
199
|
-
#
|
200
|
-
# # =>
|
199
|
+
# "Nîmes-Alès".uptrans
|
200
|
+
# # => "NIMES-ALES"
|
201
|
+
# "Zürich".uptrans
|
202
|
+
# # => "ZUERICH"
|
201
203
|
#
|
202
|
-
# @note This is a refinement for +
|
203
|
-
# @
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
204
|
+
# @note This is a refinement for +String+
|
205
|
+
# @return [String] upcased and transliterated String
|
206
|
+
refine String do
|
207
|
+
def uptrans
|
208
|
+
self.dup.tap do |string|
|
209
|
+
string.upcase!
|
210
|
+
string.gsub!(/(#{UPTRANS_MAP.keys.join('|')})/, UPTRANS_MAP)
|
211
|
+
string.unicode_normalize!(:nfd)
|
212
|
+
string.gsub!(UPTRANS_FILTER, '')
|
213
|
+
end
|
211
214
|
end
|
212
215
|
end
|
213
216
|
end
|
data/lib/aixm/shortcuts.rb
CHANGED
@@ -4,6 +4,7 @@ module AIXM
|
|
4
4
|
document: Document,
|
5
5
|
xy: XY,
|
6
6
|
z: Z,
|
7
|
+
d: D,
|
7
8
|
f: F,
|
8
9
|
organisation: Feature::Organisation,
|
9
10
|
unit: Feature::Unit,
|
@@ -26,6 +27,8 @@ module AIXM
|
|
26
27
|
tacan: Feature::NavigationalAid::TACAN,
|
27
28
|
ndb: Feature::NavigationalAid::NDB,
|
28
29
|
vor: Feature::NavigationalAid::VOR,
|
30
|
+
obstacle: Feature::Obstacle,
|
31
|
+
obstacle_group: Feature::ObstacleGroup,
|
29
32
|
timetable: Component::Timetable
|
30
33
|
}.freeze
|
31
34
|
|
data/lib/aixm/version.rb
CHANGED
data/lib/aixm/xy.rb
CHANGED
@@ -68,19 +68,20 @@ module AIXM
|
|
68
68
|
other.is_a?(self.class) && lat == other.lat && long == other.long
|
69
69
|
end
|
70
70
|
|
71
|
-
# @return [
|
71
|
+
# @return [AIXM::D] distance as calculated by use of the Haversine formula
|
72
72
|
def distance(other)
|
73
73
|
if self == other
|
74
|
-
0
|
74
|
+
AIXM.d(0, :m)
|
75
75
|
else
|
76
|
-
2 * EARTH_RADIUS * Math.asin(
|
76
|
+
value = 2 * EARTH_RADIUS * Math.asin(
|
77
77
|
Math.sqrt(
|
78
78
|
Math.sin((other.lat.to_rad - lat.to_rad) / 2) ** 2 +
|
79
79
|
Math.cos(lat.to_rad) * Math.cos(other.lat.to_rad) *
|
80
80
|
Math.sin((other.long.to_rad - long.to_rad) / 2) ** 2
|
81
81
|
)
|
82
82
|
)
|
83
|
-
|
83
|
+
AIXM.d(value.round, :m)
|
84
|
+
end
|
84
85
|
end
|
85
86
|
|
86
87
|
private
|
data/lib/aixm/z.rb
CHANGED
@@ -5,8 +5,8 @@ module AIXM
|
|
5
5
|
# Height, elevation or altitude
|
6
6
|
#
|
7
7
|
# @example
|
8
|
-
# AIXM.z(1000, :qfe) # height: 1000 ft above ground
|
9
|
-
# AIXM.z(2000, :qnh) # elevation or altitude: 2000 ft above mean sea level
|
8
|
+
# AIXM.z(1000, :qfe) # height (ft): 1000 ft above ground
|
9
|
+
# AIXM.z(2000, :qnh) # elevation or altitude (ft): 2000 ft above mean sea level
|
10
10
|
# AIXM.z(45, :qne) # altitude: flight level 45
|
11
11
|
#
|
12
12
|
# ===Shortcuts:
|
@@ -15,7 +15,7 @@ module AIXM
|
|
15
15
|
class Z
|
16
16
|
CODES = %i(qfe qnh qne).freeze
|
17
17
|
|
18
|
-
# @return [Integer]
|
18
|
+
# @return [Integer] altitude or elevation value
|
19
19
|
attr_reader :alt
|
20
20
|
|
21
21
|
# @return [Symbol] Q code - either +:qfe+ (height in feet), +:qnh+ (altitude in feet or +:qne+ (altitude as flight level)
|
data/spec/factory.rb
CHANGED
@@ -12,6 +12,10 @@ module AIXM
|
|
12
12
|
AIXM.z(1000, :qnh)
|
13
13
|
end
|
14
14
|
|
15
|
+
def d
|
16
|
+
AIXM.d(123, :m)
|
17
|
+
end
|
18
|
+
|
15
19
|
def f
|
16
20
|
AIXM.f(123.35, :mhz)
|
17
21
|
end
|
@@ -69,7 +73,7 @@ module AIXM
|
|
69
73
|
AIXM.geometry.tap do |geometry|
|
70
74
|
geometry << AIXM.circle(
|
71
75
|
center_xy: AIXM.xy(lat: %q(47°35'00"N), long: %q(004°53'00"E)),
|
72
|
-
radius: 10
|
76
|
+
radius: AIXM.d(10, :km)
|
73
77
|
)
|
74
78
|
end
|
75
79
|
end
|
@@ -313,8 +317,8 @@ module AIXM
|
|
313
317
|
|
314
318
|
def runway
|
315
319
|
AIXM.runway(name: '16L/34R').tap do |runway|
|
316
|
-
runway.length = 650
|
317
|
-
runway.width = 80
|
320
|
+
runway.length = AIXM.d(650, :m)
|
321
|
+
runway.width = AIXM.d(80, :m)
|
318
322
|
runway.composition = :graded_earth
|
319
323
|
runway.status = :closed
|
320
324
|
runway.remarks = "Markings eroded"
|
@@ -335,14 +339,110 @@ module AIXM
|
|
335
339
|
AIXM.helipad(name: 'H1').tap do |helipad|
|
336
340
|
helipad.xy = AIXM.xy(lat: %q(43°59'56.94"N), long: %q(004°45'05.56"E))
|
337
341
|
helipad.z = AIXM.z(141, :qnh)
|
338
|
-
helipad.length = 20
|
339
|
-
helipad.width = 20
|
342
|
+
helipad.length = AIXM.d(20, :m)
|
343
|
+
helipad.width = AIXM.d(20, :m)
|
340
344
|
helipad.composition = :grass
|
341
345
|
helipad.status = :other
|
342
346
|
helipad.remarks = "Authorizaton by AD operator required"
|
343
347
|
end
|
344
348
|
end
|
345
349
|
|
350
|
+
# Obstacle
|
351
|
+
|
352
|
+
def obstacle
|
353
|
+
AIXM.obstacle(
|
354
|
+
name: "Eiffel Tower",
|
355
|
+
type: :tower,
|
356
|
+
xy: AIXM.xy(lat: %q(48°51'29.7"N), long: %q(002°17'40.52"E)),
|
357
|
+
radius: AIXM.d(88, :m),
|
358
|
+
z: AIXM.z(1187 , :qnh)
|
359
|
+
).tap do |obstacle|
|
360
|
+
obstacle.lighting = true
|
361
|
+
obstacle.lighting_remarks = "red strobes"
|
362
|
+
obstacle.marking = nil
|
363
|
+
obstacle.marking_remarks = nil
|
364
|
+
obstacle.height = AIXM.d(324, :m)
|
365
|
+
obstacle.xy_accuracy = AIXM.d(2, :m)
|
366
|
+
obstacle.z_accuracy = AIXM.d(1, :m)
|
367
|
+
obstacle.height_accurate = true
|
368
|
+
obstacle.valid_from = Time.parse('2018-01-01 12:00:00 +0100')
|
369
|
+
obstacle.valid_until = Time.parse('2019-01-01 12:00:00 +0100')
|
370
|
+
obstacle.remarks = "Temporary light installations (white strobes, gyro light etc)"
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
def unlinked_obstacle_group
|
375
|
+
AIXM.obstacle_group(
|
376
|
+
name: "Mirmande éoliennes"
|
377
|
+
).tap do |obstacle_group|
|
378
|
+
obstacle_group.add_obstacle(
|
379
|
+
AIXM.obstacle(
|
380
|
+
name: "La Teissonière 1",
|
381
|
+
type: :wind_turbine,
|
382
|
+
xy: AIXM.xy(lat: %q(44°40'30.05"N), long: %q(004°52'21.24"E)),
|
383
|
+
radius: AIXM.d(80, :m),
|
384
|
+
z: AIXM.z(1764, :qnh)
|
385
|
+
).tap do |obstacle|
|
386
|
+
obstacle.height = AIXM.d(80, :m)
|
387
|
+
obstacle.xy_accuracy = AIXM.d(50, :m)
|
388
|
+
obstacle.z_accuracy = AIXM.d(10, :m)
|
389
|
+
obstacle.height_accurate = false
|
390
|
+
end
|
391
|
+
)
|
392
|
+
obstacle_group.add_obstacle(
|
393
|
+
AIXM.obstacle(
|
394
|
+
name: "La Teissonière 2",
|
395
|
+
type: :wind_turbine,
|
396
|
+
xy: AIXM.xy(lat: %q(44°40'46.08"N), long: %q(004°52'25.72"E)),
|
397
|
+
radius: AIXM.d(80, :m),
|
398
|
+
z: AIXM.z(1738 , :qnh)
|
399
|
+
).tap do |obstacle|
|
400
|
+
obstacle.height = AIXM.d(80, :m)
|
401
|
+
obstacle.xy_accuracy = AIXM.d(50, :m)
|
402
|
+
obstacle.z_accuracy = AIXM.d(10, :m)
|
403
|
+
obstacle.height_accurate = false
|
404
|
+
end
|
405
|
+
)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
def linked_obstacle_group
|
410
|
+
AIXM.obstacle_group(
|
411
|
+
name: "Droitwich longwave antenna"
|
412
|
+
).tap do |obstacle_group|
|
413
|
+
obstacle_group.add_obstacle(
|
414
|
+
AIXM.obstacle(
|
415
|
+
name: "Droitwich LW north",
|
416
|
+
type: :mast,
|
417
|
+
xy: AIXM.xy(lat: %q(52°17'47.03"N), long: %q(002°06'24.31"W)),
|
418
|
+
radius: AIXM.d(200, :m),
|
419
|
+
z: AIXM.z(848 , :qnh)
|
420
|
+
).tap do |obstacle|
|
421
|
+
obstacle.height = AIXM.d(700, :ft)
|
422
|
+
obstacle.xy_accuracy = AIXM.d(0, :m)
|
423
|
+
obstacle.z_accuracy = AIXM.d(0, :ft)
|
424
|
+
obstacle.height_accurate = true
|
425
|
+
end
|
426
|
+
)
|
427
|
+
obstacle_group.add_obstacle(
|
428
|
+
AIXM.obstacle(
|
429
|
+
name: "Droitwich LW north",
|
430
|
+
type: :mast,
|
431
|
+
xy: AIXM.xy(lat: %q(52°17'40.48"N), long: %q(002°06'20.47"W)),
|
432
|
+
radius: AIXM.d(200, :m),
|
433
|
+
z: AIXM.z(848 , :qnh)
|
434
|
+
).tap do |obstacle|
|
435
|
+
obstacle.height = AIXM.d(700, :ft)
|
436
|
+
obstacle.xy_accuracy = AIXM.d(0, :m)
|
437
|
+
obstacle.z_accuracy = AIXM.d(0, :ft)
|
438
|
+
obstacle.height_accurate = true
|
439
|
+
end,
|
440
|
+
linked_to: :previous,
|
441
|
+
link_type: :cable
|
442
|
+
)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
346
446
|
# Document
|
347
447
|
|
348
448
|
def document
|
@@ -366,6 +466,9 @@ module AIXM
|
|
366
466
|
document.features << vor
|
367
467
|
document.features << vordme
|
368
468
|
document.features << vortac
|
469
|
+
document.features << obstacle
|
470
|
+
document.features << unlinked_obstacle_group
|
471
|
+
document.features << linked_obstacle_group
|
369
472
|
end
|
370
473
|
end
|
371
474
|
|