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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.ruby-version +1 -1
- data/.yardopts +3 -0
- data/CHANGELOG.md +34 -14
- data/Guardfile +1 -0
- data/README.md +64 -257
- data/lib/aixm.rb +16 -7
- data/lib/aixm/component.rb +6 -0
- data/lib/aixm/component/frequency.rb +135 -0
- data/lib/aixm/component/geometry.rb +34 -23
- data/lib/aixm/component/geometry/arc.rb +37 -22
- data/lib/aixm/component/geometry/border.rb +29 -20
- data/lib/aixm/component/geometry/circle.rb +39 -22
- data/lib/aixm/component/geometry/point.rb +29 -13
- data/lib/aixm/component/helipad.rb +154 -0
- data/lib/aixm/component/layer.rb +91 -0
- data/lib/aixm/component/runway.rb +294 -0
- data/lib/aixm/component/service.rb +170 -0
- data/lib/aixm/component/timetable.rb +65 -0
- data/lib/aixm/component/vertical_limits.rb +65 -29
- data/lib/aixm/config.rb +87 -0
- data/lib/aixm/document.rb +66 -42
- data/lib/aixm/errors.rb +11 -0
- data/lib/aixm/f.rb +34 -20
- data/lib/aixm/feature.rb +38 -0
- data/lib/aixm/feature/airport.rb +473 -0
- data/lib/aixm/feature/airspace.rb +145 -92
- data/lib/aixm/feature/navigational_aid.rb +94 -0
- data/lib/aixm/feature/navigational_aid/designated_point.rb +50 -54
- data/lib/aixm/feature/navigational_aid/dme.rb +48 -40
- data/lib/aixm/feature/navigational_aid/marker.rb +55 -45
- data/lib/aixm/feature/navigational_aid/ndb.rb +54 -50
- data/lib/aixm/feature/navigational_aid/tacan.rb +38 -31
- data/lib/aixm/feature/navigational_aid/vor.rb +84 -76
- data/lib/aixm/feature/organisation.rb +97 -0
- data/lib/aixm/feature/unit.rb +152 -0
- data/lib/aixm/refinements.rb +132 -47
- data/lib/aixm/shortcuts.rb +11 -6
- data/lib/aixm/version.rb +1 -1
- data/lib/aixm/xy.rb +64 -20
- data/lib/aixm/z.rb +51 -22
- data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-DataTypes.xsd +0 -0
- data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Features.xsd +0 -0
- data/{lib/aixm/schemas → schemas/aixm}/4.5/AIXM-Snapshot.xsd +0 -0
- data/schemas/ofmx/0/OFMX-DataTypes.xsd +5077 -0
- data/schemas/ofmx/0/OFMX-Features.xsd +9955 -0
- data/schemas/ofmx/0/OFMX-Snapshot.xsd +217 -0
- data/spec/factory.rb +209 -33
- data/spec/lib/aixm/component/frequency_spec.rb +75 -0
- data/spec/lib/aixm/component/geometry/arc_spec.rb +28 -22
- data/spec/lib/aixm/component/geometry/border_spec.rb +23 -20
- data/spec/lib/aixm/component/geometry/circle_spec.rb +31 -22
- data/spec/lib/aixm/component/geometry/point_spec.rb +11 -14
- data/spec/lib/aixm/component/geometry_spec.rb +150 -69
- data/spec/lib/aixm/component/helipad_spec.rb +136 -0
- data/spec/lib/aixm/component/layer_spec.rb +110 -0
- data/spec/lib/aixm/component/runway_spec.rb +402 -0
- data/spec/lib/aixm/component/service_spec.rb +61 -0
- data/spec/lib/aixm/component/timetable_spec.rb +49 -0
- data/spec/lib/aixm/component/vertical_limits_spec.rb +39 -20
- data/spec/lib/aixm/config_spec.rb +41 -0
- data/spec/lib/aixm/document_spec.rb +637 -147
- data/spec/lib/aixm/errors_spec.rb +14 -0
- data/spec/lib/aixm/f_spec.rb +17 -10
- data/spec/lib/aixm/feature/airport_spec.rb +546 -0
- data/spec/lib/aixm/feature/airspace_spec.rb +349 -226
- data/spec/lib/aixm/feature/navigational_aid/designated_point_spec.rb +47 -36
- data/spec/lib/aixm/feature/navigational_aid/dme_spec.rb +61 -36
- data/spec/lib/aixm/feature/navigational_aid/marker_spec.rb +61 -113
- data/spec/lib/aixm/feature/navigational_aid/ndb_spec.rb +65 -79
- data/spec/lib/aixm/feature/navigational_aid/tacan_spec.rb +57 -36
- data/spec/lib/aixm/feature/navigational_aid/vor_spec.rb +86 -112
- data/spec/lib/aixm/feature/navigational_aid_spec.rb +52 -0
- data/spec/lib/aixm/feature/organisation_spec.rb +77 -0
- data/spec/lib/aixm/feature/unit_spec.rb +227 -0
- data/spec/lib/aixm/feature_spec.rb +58 -0
- data/spec/lib/aixm/refinements_spec.rb +187 -178
- data/spec/lib/aixm/xy_spec.rb +45 -34
- data/spec/lib/aixm/z_spec.rb +19 -21
- data/spec/macros/organisation.rb +11 -0
- data/spec/macros/remarks.rb +12 -0
- data/spec/macros/timetable.rb +11 -0
- data/spec/macros/xy.rb +11 -0
- data/spec/macros/z_qnh.rb +11 -0
- data/spec/spec_helper.rb +26 -0
- metadata +60 -19
- data/lib/aixm/base.rb +0 -10
- data/lib/aixm/component/base.rb +0 -6
- data/lib/aixm/component/class_layer.rb +0 -46
- data/lib/aixm/component/geometry/base.rb +0 -8
- data/lib/aixm/component/schedule.rb +0 -43
- data/lib/aixm/feature/base.rb +0 -6
- data/lib/aixm/feature/navigational_aid/base.rb +0 -79
- data/spec/lib/aixm/component/class_layer_spec.rb +0 -74
- data/spec/lib/aixm/component/schedule_spec.rb +0 -33
- data/spec/lib/aixm/feature/navigational_aid/base_spec.rb +0 -41
data/lib/aixm.rb
CHANGED
|
@@ -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
|
|
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/
|
|
27
|
+
require_relative 'aixm/component/layer'
|
|
24
28
|
require_relative 'aixm/component/vertical_limits'
|
|
25
|
-
require_relative 'aixm/component/
|
|
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
|
|
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/
|
|
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,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
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
25
|
+
# @example Built by adding elements
|
|
16
26
|
# geometry = AIXM.geometry
|
|
17
27
|
# geometry << AIXM.point(...)
|
|
18
28
|
# geometry << AIXM.point(...)
|
|
19
|
-
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
@result_array
|
|
41
|
+
# @return [String]
|
|
42
|
+
def inspect
|
|
43
|
+
%Q(#<#{self.class} segments=#{segments.count.inspect}>)
|
|
34
44
|
end
|
|
35
45
|
|
|
36
|
-
|
|
37
|
-
#
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
44
|
-
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
@result_array.map { |h| h.
|
|
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
|
|
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
|
-
|
|
4
|
+
class Component
|
|
3
5
|
class Geometry
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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(
|
|
39
|
-
avx.geoLong(xy.long(
|
|
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(
|
|
42
|
-
avx.geoLongArc(center_xy.long(
|
|
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
|
-
|
|
4
|
+
class Component
|
|
3
5
|
class Geometry
|
|
4
6
|
|
|
5
|
-
##
|
|
6
7
|
# Borders are following natural or artifical border lines referenced by
|
|
7
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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(
|
|
31
|
-
avx.geoLong(xy.long(
|
|
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
|
-
|
|
4
|
+
class Component
|
|
3
5
|
class Geometry
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
#
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
20
|
+
# @return [Integer] circle radius
|
|
21
|
+
attr_reader :radius
|
|
11
22
|
|
|
12
23
|
def initialize(center_xy:, radius:)
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
|
|
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(
|
|
30
|
-
avx.geoLong(north_xy.long(
|
|
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(
|
|
33
|
-
avx.geoLongArc(center_xy.long(
|
|
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 /
|
|
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
|