aixm 0.3.10 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +3 -1
- data/CHANGELOG.md +67 -14
- data/README.md +45 -24
- data/exe/ckmid +1 -4
- data/exe/mkmid +1 -4
- data/lib/aixm/a.rb +89 -71
- data/lib/aixm/association.rb +40 -32
- data/lib/aixm/classes.rb +8 -4
- data/lib/aixm/{feature → component}/address.rb +21 -12
- data/lib/aixm/component/approach_lighting.rb +136 -0
- data/lib/aixm/component/fato.rb +58 -42
- data/lib/aixm/component/frequency.rb +5 -5
- data/lib/aixm/component/geometry/arc.rb +1 -1
- data/lib/aixm/component/geometry/border.rb +1 -1
- data/lib/aixm/component/geometry/circle.rb +4 -4
- data/lib/aixm/component/geometry/point.rb +4 -3
- data/lib/aixm/component/geometry/rhumb_line.rb +54 -0
- data/lib/aixm/component/geometry.rb +10 -7
- data/lib/aixm/component/helipad.rb +26 -36
- data/lib/aixm/component/layer.rb +5 -3
- data/lib/aixm/component/lighting.rb +5 -5
- data/lib/aixm/component/runway.rb +81 -52
- data/lib/aixm/component/service.rb +12 -3
- data/lib/aixm/component/surface.rb +12 -12
- data/lib/aixm/component/timetable.rb +5 -3
- data/lib/aixm/component/vasis.rb +105 -0
- data/lib/aixm/component/vertical_limit.rb +3 -3
- data/lib/aixm/component.rb +10 -0
- data/lib/aixm/config.rb +5 -2
- data/lib/aixm/d.rb +16 -15
- data/lib/aixm/document.rb +14 -1
- data/lib/aixm/f.rb +29 -1
- data/lib/aixm/feature/airport.rb +34 -10
- data/lib/aixm/feature/airspace.rb +5 -1
- data/lib/aixm/feature/navigational_aid/dme.rb +29 -10
- data/lib/aixm/feature/navigational_aid/marker.rb +2 -2
- data/lib/aixm/feature/navigational_aid/tacan.rb +3 -2
- data/lib/aixm/feature/navigational_aid/vor.rb +32 -13
- data/lib/aixm/feature/navigational_aid.rb +1 -1
- data/lib/aixm/feature/obstacle.rb +36 -20
- data/lib/aixm/feature/obstacle_group.rb +12 -11
- data/lib/aixm/feature/organisation.rb +1 -0
- data/lib/aixm/feature/unit.rb +2 -1
- data/lib/aixm/feature.rb +3 -0
- data/lib/aixm/memoize.rb +27 -11
- data/lib/aixm/p.rb +3 -2
- data/lib/aixm/payload_hash.rb +1 -1
- data/lib/aixm/r.rb +62 -0
- data/lib/aixm/refinements.rb +4 -4
- data/lib/aixm/shortcuts.rb +2 -2
- data/lib/aixm/version.rb +1 -1
- data/lib/aixm/w.rb +2 -1
- data/lib/aixm/xy.rb +9 -1
- data/lib/aixm/z.rb +5 -4
- data/lib/aixm.rb +12 -6
- data/schemas/ofmx/{0 → 0.1}/OFMX-CSV-Obstacle.json +0 -0
- data/schemas/ofmx/{0 → 0.1}/OFMX-CSV.json +0 -0
- data/schemas/ofmx/{0 → 0.1}/OFMX-DataTypes.xsd +58 -2
- data/schemas/ofmx/{0 → 0.1}/OFMX-Features.xsd +119 -40
- data/schemas/ofmx/{0 → 0.1}/OFMX-Snapshot.xsd +5 -0
- data.tar.gz.sig +0 -0
- metadata +34 -29
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 33661b6ab9022c54a9d41dad531b0f1c53f39eaf053a6c4b8361c50543b9ae01
|
4
|
+
data.tar.gz: add22919257222a6f06dae9de21f0f71c2b941a67e6bc52dba14bde5fbae6c9a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1fb317e1791098f127c769e5f680bbf0c30ab823c73c48f392d6ea918f1ba4c6396d4e5cb43357ef1c867bad73e475d25be95b274bad7fd9ee17ce297dbbb6f
|
7
|
+
data.tar.gz: 904a2fa5c84b80bf14a67536fa2c0f2ab26b6d34dc3dc789e272116812994f86b9c3aff92b08d1cda9b3d3495abfe990eb922f0579fd779a1602963ba28ded59
|
checksums.yaml.gz.sig
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,18 +1,71 @@
|
|
1
|
+
## 1.1.0
|
2
|
+
|
3
|
+
#### Breaking Changes
|
4
|
+
* `AIXM::Association:Array#duplicates` now returns an array of arrays which
|
5
|
+
group all duplicates together.
|
6
|
+
* `VOR#associate_dme` and `VOR#associate_tacan` no longer take the channel
|
7
|
+
as argument but calculate it from the (ghost) frequency of the VOR.
|
8
|
+
* Replaced `#length`/`#width` with `#dimensions` on `Runway`, `Helipad` and `FATO`
|
9
|
+
* Renamed `AIXM::D#dist` to `AIXM::D#dim`
|
10
|
+
* Renamed `TLOF#helicopter_class` to `TLOF#performance_class`
|
11
|
+
* Renamed `#geographic_orientation` and `#magnetic_orientation` to more familiar
|
12
|
+
`#geographic_bearing` and `#magnetic_bearing` on `Runway` and `FATO`
|
13
|
+
* Re-implementation of `AIXM::A` without precision
|
14
|
+
* Demoted `Address` to component
|
15
|
+
* Fixed typo in `Service` type `:vdf_direction_finding_service`
|
16
|
+
|
17
|
+
#### Additions
|
18
|
+
* Associations from `Service` to `Airport` and `Airspace`
|
19
|
+
* `AIXM::R` (rectangle)
|
20
|
+
* `Runway#marking`
|
21
|
+
* `ApproachLighting` on `Runway::Direction` and `FATO::Direction`
|
22
|
+
* `VASIS` on `Runway::Direction` and `FATO::Direction`
|
23
|
+
* `#meta` on every feature and component
|
24
|
+
* `Document#regions` which is added to the root element for OFMX
|
25
|
+
|
26
|
+
#### Changes
|
27
|
+
* Nested memoization of the same method is now allowed and won't reset the
|
28
|
+
memoization cache anymore.
|
29
|
+
* Remove unit "mhz" from `Address` of type `:radio_frequency`.
|
30
|
+
|
31
|
+
## 1.0.0
|
32
|
+
|
33
|
+
#### Breaking Changes
|
34
|
+
* Move `Ase->txtLocalType` up into `AseUid` for OFMX
|
35
|
+
|
36
|
+
#### Additions
|
37
|
+
* Add rhumb line geometry
|
38
|
+
|
39
|
+
## 0.3.11
|
40
|
+
|
41
|
+
#### Breaking Changes
|
42
|
+
* Renamed default git branch to `main`
|
43
|
+
* Require Ruby 3.0
|
44
|
+
* `Address#address` requires and returns `AIXM::F` for type `:radio_frequency`
|
45
|
+
|
46
|
+
#### Changes
|
47
|
+
* Fix `Obstacle#source` for OFMX
|
48
|
+
|
49
|
+
#### Additions
|
50
|
+
* Add `f#voice?` and `AIXM.config.voice_channel_separation` to check whether a
|
51
|
+
frequency belongs to the voice communication airband and use it to validate
|
52
|
+
`Frequency`
|
53
|
+
|
1
54
|
## 0.3.10
|
2
55
|
|
3
|
-
|
56
|
+
#### Additions
|
4
57
|
* Proper `has_many` and `has_one` associations
|
5
|
-
* `AIXM::Association:Array#find_by|find|
|
58
|
+
* `AIXM::Association:Array#find_by|find|duplicates` on `has_many` associations
|
6
59
|
* `AIXM.config.mid` now defines whether `mid` attributes are inserted or not
|
7
60
|
provided the selected schema is OFMX
|
8
61
|
* `AIXM::Memoize` module
|
9
62
|
* `AIXM::PayloadHash` class
|
10
63
|
* `mkmid` executable to insert `mid` attributes into valid OFMX file
|
11
64
|
* `ckmid` executable to check `mid` attributes in an OFMX file
|
12
|
-
*
|
13
|
-
* `
|
65
|
+
* Geometries respond to `#point?`, `#circle?` and `#polygon?`
|
66
|
+
* `Layer#services`
|
14
67
|
|
15
|
-
|
68
|
+
#### Breaking Changes
|
16
69
|
* Require Ruby 2.7
|
17
70
|
* Moved `region` attribute from `Document` back to features again
|
18
71
|
* Use `Document#add_feature` instead of `Document@features#<<`
|
@@ -25,7 +78,7 @@
|
|
25
78
|
* Refinement `String#payload_hash` removed in favor of `AIXM::PayloadHash` class
|
26
79
|
* Refinements `Array#find|duplicates` removed
|
27
80
|
|
28
|
-
|
81
|
+
#### Changes
|
29
82
|
* Renamed `AIXM.config.mid_region` to `AIXM.config.region`
|
30
83
|
|
31
84
|
## 0.3.8
|
@@ -40,20 +93,20 @@
|
|
40
93
|
## 0.3.7
|
41
94
|
|
42
95
|
#### Additions
|
43
|
-
* `
|
44
|
-
* `
|
96
|
+
* `Document#select_features`
|
97
|
+
* `Document#group_obstacles!`
|
45
98
|
|
46
99
|
## 0.3.6
|
47
100
|
|
48
101
|
#### Additions
|
49
|
-
* `
|
50
|
-
* `
|
102
|
+
* `FATO`
|
103
|
+
* `Helipad#helicopter_class` and `Helipad#marking`
|
51
104
|
* `AIXM::XY#seconds?` to detect possibly rounded or estimated coordinates
|
52
|
-
* `
|
105
|
+
* `Airport#operator`
|
53
106
|
* `AIXM::W` (weight)
|
54
107
|
* `AIXM::P` (pressure)
|
55
|
-
* `
|
56
|
-
* Surface details
|
108
|
+
* `Lighting` for use with runways, helipads and FATOs
|
109
|
+
* Surface details `#siwl_weight`, `#siwl_tire_pressure` and `#auw_weight`
|
57
110
|
|
58
111
|
#### Changes
|
59
112
|
* Generate `Airport#id` from region and `Airport#name`
|
@@ -219,7 +272,7 @@
|
|
219
272
|
|
220
273
|
#### Changes
|
221
274
|
* `Document#created_at` and `#effective_at` accept Time, Date, String or *nil*
|
222
|
-
* Separate `
|
275
|
+
* Separate `Document#valid?` from `#complete?`
|
223
276
|
* Write coordinates in DD if extension `:OFM` is set
|
224
277
|
* `Array#to_digest` returns Integer which fits in signed 32bit
|
225
278
|
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@ For now, only the parts needed to automize the AIP import of [open flightmaps](h
|
|
20
20
|
This gem is [cryptographically signed](https://guides.rubygems.org/security/#using-gems) in order to assure it hasn't been tampered with. Unless already done, please add the author's public key as a trusted certificate now:
|
21
21
|
|
22
22
|
```
|
23
|
-
gem cert --add <(curl -Ls https://raw.github.com/svoop/aixm/
|
23
|
+
gem cert --add <(curl -Ls https://raw.github.com/svoop/aixm/main/certs/svoop.pem)
|
24
24
|
```
|
25
25
|
|
26
26
|
### Bundler
|
@@ -47,7 +47,7 @@ gem install aixm --trust-policy MediumSecurity
|
|
47
47
|
|
48
48
|
## Usage
|
49
49
|
|
50
|
-
Here's how to build a document object, populate it with a simple feature and then render it as AIXM:
|
50
|
+
Here's how to build a document object, populate it with a simple feature and then render it as AIXM or OFMX:
|
51
51
|
|
52
52
|
```ruby
|
53
53
|
document = AIXM.document(
|
@@ -100,19 +100,29 @@ The `:ofmx` schema requires the [region to be set on all core features](https://
|
|
100
100
|
|
101
101
|
```ruby
|
102
102
|
AIXM.ofmx!
|
103
|
-
AIXM.region = 'LF'
|
103
|
+
AIXM.config.region = 'LF'
|
104
104
|
```
|
105
105
|
|
106
106
|
:warning: This setting has no effect when using the `:aixm` schema.
|
107
107
|
|
108
|
+
### AIXM.voice_channel_separation
|
109
|
+
|
110
|
+
Define which voice channel separation should be used to validate voice communication frequencies.
|
111
|
+
|
112
|
+
```ruby
|
113
|
+
AIXM.voice_channel_separation = :any # both 25 and 8.33 kHz (default)
|
114
|
+
AIXM.voice_channel_separation = 25 # 25 kHz only
|
115
|
+
AIXM.voice_channel_separation = 833 # 8.33 kHz only
|
116
|
+
```
|
117
|
+
|
108
118
|
### AIXM.config.mid
|
109
119
|
|
110
120
|
In order to insert [OFMX-compliant `mid` attributes](https://gitlab.com/openflightmaps/ofmx/wikis/Features#mid) into all `*Uid` elements, you have set the mid configuration option to `true`.
|
111
121
|
|
112
122
|
```ruby
|
113
123
|
AIXM.ofmx!
|
114
|
-
AIXM.config.mid
|
115
|
-
AIXM.config.mid = true
|
124
|
+
AIXM.config.mid = false # don't insert mid attributes (default)
|
125
|
+
AIXM.config.mid = true # insert mid attributes
|
116
126
|
```
|
117
127
|
|
118
128
|
:warning: This setting has no effect when using the `:aixm` schema.
|
@@ -129,17 +139,16 @@ AIXM.config.ignored_errors = /invalid date/i
|
|
129
139
|
|
130
140
|
### Fundamentals
|
131
141
|
* [Document](https://www.rubydoc.info/gems/aixm/AIXM/Document.html)
|
142
|
+
* [A (angle)](https://www.rubydoc.info/gems/aixm/AIXM/A.html)
|
143
|
+
* [D (dimension, distance or length)](https://www.rubydoc.info/gems/aixm/AIXM/D.html)
|
144
|
+
* [F (frequency)](https://www.rubydoc.info/gems/aixm/AIXM/F.html)
|
145
|
+
* [P (pressure)](https://www.rubydoc.info/gems/aixm/AIXM/P.html)
|
146
|
+
* [R (rectangle)](https://www.rubydoc.info/gems/aixm/AIXM/R.html)
|
132
147
|
* [XY (longitude and latitude)](https://www.rubydoc.info/gems/aixm/AIXM/XY.html)
|
133
148
|
* [Z (height, elevation or altitude)](https://www.rubydoc.info/gems/aixm/AIXM/Z.html)
|
134
|
-
* [D (distance or length)](https://www.rubydoc.info/gems/aixm/AIXM/D.html)
|
135
|
-
* [F (frequency)](https://www.rubydoc.info/gems/aixm/AIXM/F.html)
|
136
|
-
* [A (angle)](https://www.rubydoc.info/gems/aixm/AIXM/A.html)
|
137
149
|
|
138
150
|
### Features
|
139
151
|
* [Address](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Address.html)
|
140
|
-
* [Organisation](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Organisation.html)
|
141
|
-
* [Unit](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Unit.html)
|
142
|
-
* [Service](https://www.rubydoc.info/gems/aixm/AIXM/Component/Service.html)
|
143
152
|
* [Airport](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Airport.html)
|
144
153
|
* [Airspace](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Airspace.html)
|
145
154
|
* [Navigational aid](https://www.rubydoc.info/gems/aixm/AIXM/NavigationalAid.html)
|
@@ -149,22 +158,32 @@ AIXM.config.ignored_errors = /invalid date/i
|
|
149
158
|
* [NDB](https://www.rubydoc.info/gems/aixm/AIXM/Feature/NDB.html)
|
150
159
|
* [TACAN](https://www.rubydoc.info/gems/aixm/AIXM/Feature/TACAN.html)
|
151
160
|
* [VOR](https://www.rubydoc.info/gems/aixm/AIXM/Feature/VOR.html)
|
152
|
-
* [Obstacle
|
161
|
+
* [Obstacle](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Obstacle.html)
|
162
|
+
* [Obstacle group](https://www.rubydoc.info/gems/aixm/AIXM/Feature/ObstacleGroup.html)
|
163
|
+
* [Organisation](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Organisation.html)
|
164
|
+
* [Service](https://www.rubydoc.info/gems/aixm/AIXM/Component/Service.html)
|
165
|
+
* [Unit](https://www.rubydoc.info/gems/aixm/AIXM/Feature/Unit.html)
|
153
166
|
|
154
167
|
### Components
|
168
|
+
|
169
|
+
* [ApproachLighting](https://www.rubydoc.info/gems/aixm/AIXM/Component/ApproachLighting.html)
|
170
|
+
* [FATO](https://www.rubydoc.info/gems/aixm/AIXM/Component/FATO.html)
|
155
171
|
* [Frequency](https://www.rubydoc.info/gems/aixm/AIXM/Component/Frequency.html)
|
156
172
|
* [Geometry](https://www.rubydoc.info/gems/aixm/AIXM/Component/Geometry.html)
|
157
|
-
* [Point](https://www.rubydoc.info/gems/aixm/AIXM/Component/Point.html)
|
158
173
|
* [Arc](https://www.rubydoc.info/gems/aixm/AIXM/Component/Arc.html)
|
159
174
|
* [Border](https://www.rubydoc.info/gems/aixm/AIXM/Component/Border.html)
|
160
175
|
* [Circle](https://www.rubydoc.info/gems/aixm/AIXM/Component/Circle.html)
|
161
|
-
* [
|
176
|
+
* [Point](https://www.rubydoc.info/gems/aixm/AIXM/Component/Point.html)
|
177
|
+
* [RhumbLine](https://www.rubydoc.info/gems/aixm/AIXM/Component/RhumbLine.html)
|
162
178
|
* [Helipad](https://www.rubydoc.info/gems/aixm/AIXM/Component/Helipad.html)
|
163
|
-
* [FATO](https://www.rubydoc.info/gems/aixm/AIXM/Component/FATO.html)
|
164
|
-
* [Surface](https://www.rubydoc.info/gems/aixm/AIXM/Component/Surface.html)
|
165
179
|
* [Layer](https://www.rubydoc.info/gems/aixm/AIXM/Component/Layer.html)
|
166
|
-
* [
|
180
|
+
* [Lighting](https://www.rubydoc.info/gems/aixm/AIXM/Component/Lighting.html)
|
181
|
+
* [Runway](https://www.rubydoc.info/gems/aixm/AIXM/Component/Runway.html)
|
182
|
+
* [Service](https://www.rubydoc.info/gems/aixm/AIXM/Component/Service.html)
|
183
|
+
* [Surface](https://www.rubydoc.info/gems/aixm/AIXM/Component/Surface.html)
|
167
184
|
* [Timetable](https://www.rubydoc.info/gems/aixm/AIXM/Component/Timetable.html)
|
185
|
+
* [VASIS](https://www.rubydoc.info/gems/aixm/AIXM/Component/VASIS.html)
|
186
|
+
* [Vertical limit](https://www.rubydoc.info/gems/aixm/AIXM/Component/VerticalLimit.html)
|
168
187
|
|
169
188
|
## Associations
|
170
189
|
|
@@ -194,6 +213,14 @@ document.features.find(airport) # => [#<AIXM::Feature::Airport>]
|
|
194
213
|
|
195
214
|
This may seem redundant at first, but keep in mind that two instances of +AIXM::CLASSES+ which implement `#to_uid` are considered equal if they are instances of the same class and both their UIDs as calculated by `#to_uid` are equal. Attributes which are not part of the `#to_uid` calculation are irrelevant!
|
196
215
|
|
216
|
+
### meta
|
217
|
+
|
218
|
+
You can write arbitrary meta information to any feature or component. It won't be used when building the AIXM or OFMX document, in fact, it is not used by this gem at all. But you can store e.g. foreign keys and then later use them to find a feature or component like so:
|
219
|
+
|
220
|
+
```ruby
|
221
|
+
document.features.find_by(:airport, meta: 1234) # 1234 is the foreign key
|
222
|
+
```
|
223
|
+
|
197
224
|
### duplicates
|
198
225
|
|
199
226
|
Equally on `has_many` associations, use `duplicates` to find identical or equal associations:
|
@@ -272,13 +299,7 @@ bundle exec rake # run tests once
|
|
272
299
|
bundle exec guard # run tests whenever files are modified
|
273
300
|
```
|
274
301
|
|
275
|
-
|
276
|
-
|
277
|
-
https://github.com/svoop/aixm/issues
|
278
|
-
|
279
|
-
To contribute code, fork the project on Github, add your code and submit a pull request:
|
280
|
-
|
281
|
-
https://help.github.com/articles/fork-a-repo
|
302
|
+
You're welcome to [submit issues](https://github.com/svoop/aixm/issues) and contribute code by [forking the project and submitting pull requests](https://docs.github.com/en/get-started/quickstart/fork-a-repo).
|
282
303
|
|
283
304
|
## License
|
284
305
|
|
data/exe/ckmid
CHANGED
@@ -1,13 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
# TODO: hide deprecations unless in gem root until fully complying with Ruby 2.7
|
4
|
-
Warning[:deprecated] = Dir.pwd.match? /aixm$/
|
5
|
-
|
6
3
|
require 'bundler/inline'
|
7
4
|
|
8
5
|
gemfile do
|
9
6
|
source 'https://rubygems.org'
|
10
|
-
ruby '>=
|
7
|
+
ruby '>= 3.0'
|
11
8
|
gem 'aixm', '~> 0'
|
12
9
|
end
|
13
10
|
|
data/exe/mkmid
CHANGED
@@ -1,13 +1,10 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
# TODO: hide deprecations unless in gem root until fully complying with Ruby 2.7
|
4
|
-
Warning[:deprecated] = Dir.pwd.match? /aixm$/
|
5
|
-
|
6
3
|
require 'bundler/inline'
|
7
4
|
|
8
5
|
gemfile do
|
9
6
|
source 'https://rubygems.org'
|
10
|
-
ruby '>=
|
7
|
+
ruby '>= 3.0'
|
11
8
|
gem 'aixm', '~> 0'
|
12
9
|
end
|
13
10
|
|
data/lib/aixm/a.rb
CHANGED
@@ -2,53 +2,48 @@ using AIXM::Refinements
|
|
2
2
|
|
3
3
|
module AIXM
|
4
4
|
|
5
|
-
# Angle
|
6
|
-
#
|
5
|
+
# Angle in the range of -360 < angle < 360 degrees (used for azimuths or
|
6
|
+
# courses) and with an optional one-letter suffix (used for runways).
|
7
7
|
#
|
8
|
-
# @example
|
9
|
-
#
|
10
|
-
# a
|
11
|
-
# a
|
12
|
-
# a
|
13
|
-
# a
|
14
|
-
# a.deg += 7 # => 19
|
15
|
-
# a.deg += 341 # => 0 - deg is always within (0..359)
|
16
|
-
# a.to_s # => "000" - to_s is always within ("000".."359")
|
8
|
+
# @example Initialization
|
9
|
+
# AIXM.a(-36.9) # => #<AIXM::A -36.9° "32">
|
10
|
+
# AIXM.a(12) # => #<AIXM::A 12° "01">
|
11
|
+
# AIXM.a("12L") # => #<AIXM::A 120° "12L">
|
12
|
+
# AIXM.a(360) # => #<AIXM::A 0° "36">
|
13
|
+
# AIXM.a(-400) # => #<AIXM::A -40° "32">
|
17
14
|
#
|
18
|
-
# @example
|
19
|
-
# a = AIXM.a(
|
20
|
-
# a
|
21
|
-
# a.
|
22
|
-
# a.
|
23
|
-
# a.
|
24
|
-
# a.
|
25
|
-
# a.
|
26
|
-
# a.
|
15
|
+
# @example Calculations
|
16
|
+
# a = AIXM.a("02L")
|
17
|
+
# a += 5 # => #<AIXM::A 25° "03L">
|
18
|
+
# a -= AIXM.a(342.8) # => #<AIXM::A -317.8° "04L">
|
19
|
+
# a.to_s # => "-317.8°"
|
20
|
+
# a.to_s(:runway) # => "04L"
|
21
|
+
# a.to_s(:bearing) # => "042.2000"
|
22
|
+
# a.to_f # => 42.2
|
23
|
+
# a.to_i # => 42
|
24
|
+
# a.invert # => #<AIXM::A -137.8° "22R">
|
25
|
+
# a.to_s(:runway) # => "22R"
|
27
26
|
class A
|
28
27
|
SUFFIX_INVERSIONS = {
|
29
28
|
R: :L,
|
30
29
|
L: :R
|
31
30
|
}.freeze
|
32
31
|
|
33
|
-
|
34
|
-
attr_reader :deg
|
32
|
+
RUNWAY_RE = /\A(0[1-9]|[12]\d|3[0-6])([A-Z])?\z/
|
35
33
|
|
36
|
-
# @return [Integer]
|
37
|
-
attr_reader :
|
34
|
+
# @return [Integer] angle in the range of -360 < angle < 360
|
35
|
+
attr_reader :deg
|
38
36
|
|
39
|
-
# @return [Symbol, nil] suffix
|
37
|
+
# @return [Symbol, nil] one-letter suffix
|
40
38
|
attr_reader :suffix
|
41
39
|
|
42
|
-
def initialize(
|
43
|
-
case
|
44
|
-
when Numeric
|
45
|
-
self.deg, @precision = deg_and_suffix, 3
|
40
|
+
def initialize(value)
|
41
|
+
case value
|
46
42
|
when String
|
47
|
-
fail(ArgumentError, "invalid angle") unless
|
48
|
-
self.deg,
|
49
|
-
when
|
50
|
-
|
51
|
-
@deg, @precision = 0, deg_and_suffix.to_s.to_i
|
43
|
+
fail(ArgumentError, "invalid angle") unless value =~ RUNWAY_RE
|
44
|
+
self.deg, self.suffix = $1.to_i * 10, $2
|
45
|
+
when Numeric
|
46
|
+
self.deg = value
|
52
47
|
else
|
53
48
|
fail(ArgumentError, "invalid angle")
|
54
49
|
end
|
@@ -56,39 +51,62 @@ module AIXM
|
|
56
51
|
|
57
52
|
# @return [String]
|
58
53
|
def inspect
|
59
|
-
%Q(#<#{self.class}
|
54
|
+
%Q(#<#{self.class} #{to_s} #{to_s(:runway).inspect}>)
|
60
55
|
end
|
61
56
|
|
62
|
-
# @return [
|
63
|
-
def
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
57
|
+
# @return [Integer] within 0..359
|
58
|
+
def to_i
|
59
|
+
(deg.round + 360) % 360
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Float] within 0.0..359.9~
|
63
|
+
def to_f
|
64
|
+
((deg + 360) % 360).to_f
|
65
|
+
end
|
66
|
+
|
67
|
+
# Degrees as formatted string
|
68
|
+
#
|
69
|
+
# Types are:
|
70
|
+
# * :human - degrees within -359.9~..359.9~ as D.D° (default)
|
71
|
+
# * :bearing - degrees within 0.0..359.9~ as DDD.DDDD
|
72
|
+
# * :runway - degrees within "01".."36" plus optional suffix
|
73
|
+
#
|
74
|
+
# @param type [Symbol, nil] either :runway, :bearing or nil
|
75
|
+
# @param unit [String] unit to postfix
|
76
|
+
# @return [String]
|
77
|
+
def to_s(type=:human)
|
78
|
+
return '' unless deg
|
79
|
+
case type
|
80
|
+
when :runway then [('%02d' % (((deg / 10).round + 35) % 36 + 1)), suffix].join
|
81
|
+
when :bearing then '%08.4f' % to_f.round(4)
|
82
|
+
when :human then [deg.to_s('F').sub(/\.0$/, ''), '°'].join
|
83
|
+
else fail ArgumentError
|
68
84
|
end
|
69
85
|
end
|
70
86
|
|
71
87
|
def deg=(value)
|
72
|
-
fail(ArgumentError, "invalid deg `#{value}'") unless value.is_a?
|
73
|
-
|
88
|
+
fail(ArgumentError, "invalid deg `#{value}'") unless value.is_a? Numeric
|
89
|
+
normalized_value = value.abs % 360
|
90
|
+
sign = '-' if value.negative? && normalized_value.nonzero?
|
91
|
+
@deg = BigDecimal("#{sign}#{normalized_value}")
|
74
92
|
end
|
75
93
|
|
76
94
|
def suffix=(value)
|
77
|
-
fail(
|
78
|
-
fail(ArgumentError, "invalid suffix") unless value.nil? || value.to_s =~ /\A[A-Z]+\z/
|
95
|
+
fail(ArgumentError, "invalid suffix") unless value.nil? || value.to_s =~ /\A[A-Z]\z/
|
79
96
|
@suffix = value&.to_s&.to_sym
|
80
97
|
end
|
81
98
|
|
82
99
|
# Invert an angle by 180 degrees
|
83
100
|
#
|
84
101
|
# @example
|
85
|
-
# AIXM.a(120).invert #
|
86
|
-
# AIXM.a("34L").invert #
|
87
|
-
# AIXM.a("33X").invert # => AIXM.a("33X")
|
102
|
+
# AIXM.a(120).invert # (300°)
|
103
|
+
# AIXM.a("34L").invert # (160° suffix "R")
|
88
104
|
#
|
89
105
|
# @return [AIXM::A] inverted angle
|
90
106
|
def invert
|
91
|
-
|
107
|
+
self.class.new(deg.negative? ? deg - 180 : deg + 180).tap do |angle|
|
108
|
+
angle.suffix = SUFFIX_INVERSIONS.fetch(suffix, suffix)
|
109
|
+
end
|
92
110
|
end
|
93
111
|
|
94
112
|
# Check whether +other+ angle is the inverse
|
@@ -104,47 +122,47 @@ module AIXM
|
|
104
122
|
invert == other
|
105
123
|
end
|
106
124
|
|
107
|
-
#
|
125
|
+
# Negate degrees
|
108
126
|
#
|
109
127
|
# @return [AIXM::A]
|
110
|
-
def
|
111
|
-
|
112
|
-
build(precision: precision, deg: (deg + numeric_or_angle.round) % 360, suffix: suffix)
|
128
|
+
def -@
|
129
|
+
deg.zero? ? self : self.class.new(-deg).tap { _1.suffix = suffix }
|
113
130
|
end
|
114
131
|
|
115
|
-
#
|
132
|
+
# Add degrees
|
116
133
|
#
|
134
|
+
# @param value [Numeric, AIXM::A]
|
117
135
|
# @return [AIXM::A]
|
118
|
-
def
|
119
|
-
|
120
|
-
|
136
|
+
def +(value)
|
137
|
+
case value
|
138
|
+
when Numeric
|
139
|
+
value.zero? ? self : self.class.new(deg + value).tap { _1.suffix = suffix }
|
140
|
+
when AIXM::A
|
141
|
+
value.deg.zero? ? self : self.class.new(deg + value.deg).tap { _1.suffix = suffix }
|
142
|
+
else
|
143
|
+
fail ArgumentError
|
144
|
+
end
|
121
145
|
end
|
122
146
|
|
123
|
-
#
|
124
|
-
|
125
|
-
|
147
|
+
# Subtract degrees
|
148
|
+
#
|
149
|
+
# @param value [Numeric, AIXM::A]
|
150
|
+
# @return [AIXM::A]
|
151
|
+
def -(value)
|
152
|
+
self + -value
|
126
153
|
end
|
127
154
|
|
128
155
|
# @see Object#==
|
129
156
|
# @return [Boolean]
|
130
157
|
def ==(other)
|
131
|
-
self.class === other && deg == other.deg &&
|
158
|
+
self.class === other && deg == other.deg && suffix == other.suffix
|
132
159
|
end
|
133
160
|
alias_method :eql?, :==
|
134
161
|
|
135
162
|
# @see Object#hash
|
136
163
|
# @return [Integer]
|
137
164
|
def hash
|
138
|
-
|
139
|
-
end
|
140
|
-
|
141
|
-
private
|
142
|
-
|
143
|
-
def build(precision:, deg:, suffix: nil)
|
144
|
-
self.class.new(precision.to_s.to_sym).tap do |a|
|
145
|
-
a.deg = deg
|
146
|
-
a.suffix = suffix
|
147
|
-
end
|
165
|
+
[deg, suffix].join.hash
|
148
166
|
end
|
149
167
|
end
|
150
168
|
|