aixm 0.1.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 +7 -0
- data/.gitignore +5 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +3 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +100 -0
- data/Rakefile +12 -0
- data/aixm.gemspec +32 -0
- data/lib/aixm.rb +25 -0
- data/lib/aixm/constants.rb +6 -0
- data/lib/aixm/document.rb +65 -0
- data/lib/aixm/feature/airspace.rb +74 -0
- data/lib/aixm/geometry.rb +71 -0
- data/lib/aixm/horizontal/arc.rb +50 -0
- data/lib/aixm/horizontal/border.rb +45 -0
- data/lib/aixm/horizontal/circle.rb +53 -0
- data/lib/aixm/horizontal/point.rb +39 -0
- data/lib/aixm/refinements.rb +61 -0
- data/lib/aixm/schemas/4.5/AIXM-DataTypes.xsd +5231 -0
- data/lib/aixm/schemas/4.5/AIXM-Features.xsd +10066 -0
- data/lib/aixm/schemas/4.5/AIXM-Snapshot.xsd +352 -0
- data/lib/aixm/version.rb +3 -0
- data/lib/aixm/vertical/limits.rb +59 -0
- data/lib/aixm/xy.rb +52 -0
- data/lib/aixm/z.rb +39 -0
- data/spec/factory.rb +66 -0
- data/spec/lib/aixm/document_spec.rb +211 -0
- data/spec/lib/aixm/feature/airspace_spec.rb +96 -0
- data/spec/lib/aixm/geometry_spec.rb +218 -0
- data/spec/lib/aixm/horizontal/arc_spec.rb +69 -0
- data/spec/lib/aixm/horizontal/border_spec.rb +47 -0
- data/spec/lib/aixm/horizontal/circle_spec.rb +65 -0
- data/spec/lib/aixm/horizontal/point_spec.rb +42 -0
- data/spec/lib/aixm/refinements_spec.rb +180 -0
- data/spec/lib/aixm/version_spec.rb +7 -0
- data/spec/lib/aixm/vertical/limits_spec.rb +78 -0
- data/spec/lib/aixm/xy_spec.rb +131 -0
- data/spec/lib/aixm/z_spec.rb +59 -0
- data/spec/sounds/failure.mp3 +0 -0
- data/spec/sounds/success.mp3 +0 -0
- data/spec/spec_helper.rb +28 -0
- metadata +243 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 153468c1338fc26792178d856c438511fa10ac58988ef0e938980fd590338164
|
4
|
+
data.tar.gz: b04ae1dcbe0ef0d90beea492c08d08aeab943a156127c70cdc94c5ec69b4995b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 45a95906e65595273f9e5667a7aee0498f5390a6d9c86500f00dafbc080376316fa4b8d062deefda840ec9a0d403ab941762c59f4b4d413eed17868102e86196
|
7
|
+
data.tar.gz: efe2127226e7a3e3d5b25f69bb29688fa12c59b1af579a272291aa200b5b2447c24b4093e248eb671ca0cb915a0aa31a50f757c8dcb5770f3b7d28139ab78396
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.5.0
|
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Sven Schwyn
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
[](https://rubygems.org/gems/aixm)
|
2
|
+
[](https://travis-ci.org/svoop/aixm)
|
3
|
+
[](https://codeclimate.com/github/svoop/aixm)
|
4
|
+
[](https://gitter.im/svoop/aixm)
|
5
|
+
[](https://donorbox.org/bitcetera-aixm)
|
6
|
+
|
7
|
+
# AIXM
|
8
|
+
|
9
|
+
Partial implementation of the [Aeronautical Information Exchange Model (AIXM 4.5)](http://aixm.aero)
|
10
|
+
for Ruby.
|
11
|
+
|
12
|
+
For now, only the parts needed to automize the AIP import of [Open Flightmaps](https://openflightmaps.org)
|
13
|
+
are part of this gem. Most notably, the gem is only a builder of AIXM 4.5
|
14
|
+
snapshot files and does not parse them.
|
15
|
+
|
16
|
+
* [Homepage](https://github.com/svoop/aixm)
|
17
|
+
* Author: [Sven Schwyn - Bitcetera](http://www.bitcetera.com)
|
18
|
+
|
19
|
+
## Install
|
20
|
+
|
21
|
+
Add this to your <tt>Gemfile</tt>:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem aixm
|
25
|
+
```
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
### Types
|
30
|
+
|
31
|
+
#### Coordinate
|
32
|
+
|
33
|
+
All of the below are equivalent:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
AIXM::XY.new(lat: %q(11°22'33.44"), long: %q(-111°22'33.44"))
|
37
|
+
AIXM::XY.new(lat: '112233.44N', long: '1112233.44W')
|
38
|
+
AIXM::XY.new(lat: 11.375955555555556, long: -111.37595555555555)
|
39
|
+
```
|
40
|
+
|
41
|
+
#### Altitude
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
AIXM::Z.new(alt: 1000, code: :QFE) # height: 1000ft above ground
|
45
|
+
AIXM::Z.new(alt: 2000, code: :QNH) # altitude: of 2000ft above mean sea level
|
46
|
+
AIXM::Z.new(alt: 45, code: :QNE) # altitude: flight level 45
|
47
|
+
```
|
48
|
+
|
49
|
+
### Document
|
50
|
+
|
51
|
+
See <tt>spec/factory.rb</tt> for examples.
|
52
|
+
|
53
|
+
## Rendering
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
document.to_xml # render AIXM 4.5 compliant XML
|
57
|
+
document.to_xml(:OFM) # render AIXM 4.5 + OFM extensions XML
|
58
|
+
```
|
59
|
+
|
60
|
+
## Constants
|
61
|
+
|
62
|
+
* <tt>AIXM::GROUND</tt> - height: 0ft above ground
|
63
|
+
|
64
|
+
## Refinements
|
65
|
+
|
66
|
+
By `using AIXM::Refinements` you get the following general purpose methods:
|
67
|
+
|
68
|
+
* <tt>String#indent(number)</tt><br>Indent every line of a string with *number* spaces
|
69
|
+
* <tt>String#to_dd</tt><br>Convert DMS angle to DD or <tt>nil</tt> if the format is not recognized
|
70
|
+
* <tt>Float#to_dms(padding)</tt><br>Convert DD angle to DMS with the degrees zero padded to *padding* length
|
71
|
+
* <tt>Float#trim</tt><br>Convert whole numbers to Integer and leave all other untouched
|
72
|
+
|
73
|
+
## References
|
74
|
+
|
75
|
+
* [AIXM](http://aixm.aero)
|
76
|
+
* [AIXM on Wikipedia](https://en.wikipedia.org/wiki/AIXM)
|
77
|
+
* [Open Flightmaps](https://openflightmaps.org)
|
78
|
+
|
79
|
+
## Development
|
80
|
+
|
81
|
+
To install the development dependencies and then run the test suite:
|
82
|
+
|
83
|
+
```
|
84
|
+
bundle install
|
85
|
+
bundle exec rake # run tests once
|
86
|
+
bundle exec guard # run tests whenever files are modified
|
87
|
+
```
|
88
|
+
|
89
|
+
Please submit issues on:
|
90
|
+
|
91
|
+
https://github.com/svoop/aixm/issues
|
92
|
+
|
93
|
+
To contribute code, fork the project on Github, add your code and submit a
|
94
|
+
pull request:
|
95
|
+
|
96
|
+
https://help.github.com/articles/fork-a-repo
|
97
|
+
|
98
|
+
## License
|
99
|
+
|
100
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/aixm.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'aixm/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'aixm'
|
8
|
+
spec.version = AIXM::VERSION
|
9
|
+
spec.authors = ['Sven Schwyn']
|
10
|
+
spec.email = ['ruby@bitcetera.com']
|
11
|
+
spec.description = %q(Aeronautical Information Exchange Model (AIXM 4.5).)
|
12
|
+
spec.summary = %q(Aeronautical Information Exchange Model (AIXM 4.5).)
|
13
|
+
spec.homepage = 'http://www.bitcetera.com/products/aixm'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'minitest'
|
24
|
+
spec.add_development_dependency 'minitest-reporters'
|
25
|
+
spec.add_development_dependency 'minitest-sound'
|
26
|
+
spec.add_development_dependency 'minitest-matchers'
|
27
|
+
spec.add_development_dependency 'guard'
|
28
|
+
spec.add_development_dependency 'guard-minitest'
|
29
|
+
|
30
|
+
spec.add_runtime_dependency 'builder', '~> 3'
|
31
|
+
spec.add_runtime_dependency 'nokogiri', '~> 1'
|
32
|
+
end
|
data/lib/aixm.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'forwardable'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'digest'
|
6
|
+
require 'time'
|
7
|
+
|
8
|
+
require_relative 'aixm/version'
|
9
|
+
|
10
|
+
require_relative 'aixm/refinements'
|
11
|
+
|
12
|
+
require_relative 'aixm/xy'
|
13
|
+
require_relative 'aixm/z'
|
14
|
+
require_relative 'aixm/geometry'
|
15
|
+
|
16
|
+
require_relative 'aixm/horizontal/point'
|
17
|
+
require_relative 'aixm/horizontal/arc'
|
18
|
+
require_relative 'aixm/horizontal/border'
|
19
|
+
require_relative 'aixm/horizontal/circle'
|
20
|
+
require_relative 'aixm/vertical/limits'
|
21
|
+
|
22
|
+
require_relative 'aixm/constants'
|
23
|
+
require_relative 'aixm/document'
|
24
|
+
|
25
|
+
require_relative 'aixm/feature/airspace'
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module AIXM
|
2
|
+
class Document
|
3
|
+
|
4
|
+
include Enumerable
|
5
|
+
extend Forwardable
|
6
|
+
using AIXM::Refinements
|
7
|
+
|
8
|
+
def_delegators :@result_array, :each, :<<
|
9
|
+
|
10
|
+
attr_reader :created_at, :effective_at
|
11
|
+
|
12
|
+
##
|
13
|
+
# Define a AIXM-Snapshot document
|
14
|
+
#
|
15
|
+
# Options:
|
16
|
+
# * +created_at+ - creation date (default: now)
|
17
|
+
# * +effective_at+ - snapshot effective after date (default: now)
|
18
|
+
def initialize(created_at: nil, effective_at: nil)
|
19
|
+
@created_at, @effective_at = created_at, effective_at
|
20
|
+
@result_array = []
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# Array of features defined by this document
|
25
|
+
def features
|
26
|
+
@result_array
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Validate against the XSD and return an array of errors
|
31
|
+
def errors
|
32
|
+
xsd = Nokogiri::XML::Schema(File.open(AIXM::SCHEMA))
|
33
|
+
xsd.validate(Nokogiri::XML(to_xml))
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Check whether the document is valid (extensions excluded)
|
38
|
+
def valid?
|
39
|
+
any? && reduce(true) { |b, f| b && f.valid? } && errors.none?
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Render AIXM
|
44
|
+
#
|
45
|
+
# Extensions:
|
46
|
+
# * +:OFM+ - Open Flightmaps
|
47
|
+
def to_xml(*extensions)
|
48
|
+
now = Time.now.xmlschema
|
49
|
+
meta = {
|
50
|
+
'xmlns:xsi': 'http://www.aixm.aero/schema/4.5/AIXM-Snapshot.xsd',
|
51
|
+
version: '4.5',
|
52
|
+
origin: "AIXM #{AIXM::VERSION} Ruby gem",
|
53
|
+
created: @created_at&.xmlschema || now,
|
54
|
+
effective: @effective_at&.xmlschema || now
|
55
|
+
}
|
56
|
+
meta[:version] += ' + OFM extensions of version 0.1' if extensions.include?(:OFM)
|
57
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
58
|
+
builder.instruct!
|
59
|
+
builder.tag!('AIXM-Snapshot', meta) do |aixm_snapshot|
|
60
|
+
aixm_snapshot << @result_array.map { |f| f.to_xml(extensions) }.join.indent(2)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module AIXM
|
2
|
+
module Feature
|
3
|
+
class Airspace
|
4
|
+
|
5
|
+
using AIXM::Refinements
|
6
|
+
|
7
|
+
attr_reader :name, :type
|
8
|
+
attr_reader :vertical_limits
|
9
|
+
attr_accessor :geometry, :remarks
|
10
|
+
|
11
|
+
##
|
12
|
+
# Airspace feature
|
13
|
+
#
|
14
|
+
# Options:
|
15
|
+
# * +name+ - name of the airspace (will be converted to uppercase)
|
16
|
+
# * +type+ - airspace type (e.g. +TMA+ or +P+)
|
17
|
+
def initialize(name:, type:)
|
18
|
+
@geometry = AIXM::Geometry.new
|
19
|
+
@name, @type = name.upcase, type
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Assign a +Vertical::Limits+ object
|
24
|
+
def vertical_limits=(value)
|
25
|
+
fail(ArgumentError, "invalid vertical limit") unless value.is_a?(AIXM::Vertical::Limits)
|
26
|
+
@vertical_limits = value
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Check whether the airspace is valid
|
31
|
+
def valid?
|
32
|
+
name && type && vertical_limits && geometry.valid?
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Digest to identify the payload
|
37
|
+
def to_digest
|
38
|
+
[name, type, vertical_limits.to_digest, geometry.to_digest, remarks].to_digest
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Render AIXM
|
43
|
+
#
|
44
|
+
# Extensions:
|
45
|
+
# * +:OFM+ - Open Flightmaps
|
46
|
+
def to_xml(*extensions)
|
47
|
+
mid = to_digest
|
48
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
49
|
+
builder.Ase(extensions.include?(:OFM) ? { xt_classLayersAvail: false } : {}) do |ase|
|
50
|
+
ase.AseUid(extensions.include?(:OFM) ? { mid: mid, newEntity: true } : { mid: mid }) do |aseuid|
|
51
|
+
aseuid.codeType(type)
|
52
|
+
aseuid.codeId(mid) # TODO: verify
|
53
|
+
end
|
54
|
+
ase.txtName(name)
|
55
|
+
ase << vertical_limits.to_xml(extensions).indent(2)
|
56
|
+
ase.txtRmk(remarks) if remarks
|
57
|
+
if extensions.include?(:OFM)
|
58
|
+
ase.xt_txtRmk(remarks)
|
59
|
+
ase.xt_selAvail(false)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
builder.Abd do |abd|
|
63
|
+
abd.AbdUid do |abduid|
|
64
|
+
abduid.AseUid(extensions.include?(:OFM) ? { mid: mid, newEntity: true } : { mid: mid }) do |aseuid|
|
65
|
+
aseuid.codeType(type)
|
66
|
+
aseuid.codeId(mid) # TODO: verify
|
67
|
+
end
|
68
|
+
end
|
69
|
+
abd << geometry.to_xml(extensions).indent(2)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module AIXM
|
2
|
+
class Geometry
|
3
|
+
|
4
|
+
include Enumerable
|
5
|
+
extend Forwardable
|
6
|
+
using AIXM::Refinements
|
7
|
+
|
8
|
+
def_delegators :@result_array, :each, :<<
|
9
|
+
|
10
|
+
##
|
11
|
+
# Define a shape (horizontal geometry) which is either exactly one
|
12
|
+
# +AIXM::Horizontals::Circle+ or any number of +AIXM::Horizontals::Point+,
|
13
|
+
# +::Arc+ and +::Border+.
|
14
|
+
#
|
15
|
+
# Example 1:
|
16
|
+
# geometry = AIXM::Geometry.new(
|
17
|
+
# AIXM::Horizontals::Point(...),
|
18
|
+
# AIXM::Horizontals::Point(...)
|
19
|
+
# )
|
20
|
+
#
|
21
|
+
# Example 2:
|
22
|
+
# geometry = AIXM::Geometry.new
|
23
|
+
# geometry << AIXM::Horizontals::Point(...)
|
24
|
+
# geometry << AIXM::Horizontals::Point(...)
|
25
|
+
def initialize(*horizontals)
|
26
|
+
@result_array = horizontals
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Array of +AIXM::Horizontal::...+ objects
|
31
|
+
def horizontals
|
32
|
+
@result_array
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Check whether the geometry is valid
|
37
|
+
def valid?
|
38
|
+
circle? || closed_shape?
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Digest to identify the payload
|
43
|
+
def to_digest
|
44
|
+
horizontals.map(&:to_digest).to_digest
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Render AIXM
|
49
|
+
#
|
50
|
+
# Extensions:
|
51
|
+
# * +:OFM+ - Open Flightmaps
|
52
|
+
def to_xml(*extensions)
|
53
|
+
@result_array.map { |h| h.to_xml(extensions) }.join
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def circle?
|
59
|
+
@result_array.size == 1 &&
|
60
|
+
@result_array.first.is_a?(AIXM::Horizontal::Circle)
|
61
|
+
end
|
62
|
+
|
63
|
+
def closed_shape?
|
64
|
+
@result_array.size >= 3 &&
|
65
|
+
!@result_array.any? { |h| h.is_a?(AIXM::Horizontal::Circle) } &&
|
66
|
+
@result_array.last.is_a?(AIXM::Horizontal::Point) &&
|
67
|
+
@result_array.first.xy == @result_array.last.xy
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|