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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +5 -0
  5. data/CHANGELOG.md +14 -0
  6. data/Gemfile +3 -0
  7. data/Guardfile +7 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +100 -0
  10. data/Rakefile +12 -0
  11. data/aixm.gemspec +32 -0
  12. data/lib/aixm.rb +25 -0
  13. data/lib/aixm/constants.rb +6 -0
  14. data/lib/aixm/document.rb +65 -0
  15. data/lib/aixm/feature/airspace.rb +74 -0
  16. data/lib/aixm/geometry.rb +71 -0
  17. data/lib/aixm/horizontal/arc.rb +50 -0
  18. data/lib/aixm/horizontal/border.rb +45 -0
  19. data/lib/aixm/horizontal/circle.rb +53 -0
  20. data/lib/aixm/horizontal/point.rb +39 -0
  21. data/lib/aixm/refinements.rb +61 -0
  22. data/lib/aixm/schemas/4.5/AIXM-DataTypes.xsd +5231 -0
  23. data/lib/aixm/schemas/4.5/AIXM-Features.xsd +10066 -0
  24. data/lib/aixm/schemas/4.5/AIXM-Snapshot.xsd +352 -0
  25. data/lib/aixm/version.rb +3 -0
  26. data/lib/aixm/vertical/limits.rb +59 -0
  27. data/lib/aixm/xy.rb +52 -0
  28. data/lib/aixm/z.rb +39 -0
  29. data/spec/factory.rb +66 -0
  30. data/spec/lib/aixm/document_spec.rb +211 -0
  31. data/spec/lib/aixm/feature/airspace_spec.rb +96 -0
  32. data/spec/lib/aixm/geometry_spec.rb +218 -0
  33. data/spec/lib/aixm/horizontal/arc_spec.rb +69 -0
  34. data/spec/lib/aixm/horizontal/border_spec.rb +47 -0
  35. data/spec/lib/aixm/horizontal/circle_spec.rb +65 -0
  36. data/spec/lib/aixm/horizontal/point_spec.rb +42 -0
  37. data/spec/lib/aixm/refinements_spec.rb +180 -0
  38. data/spec/lib/aixm/version_spec.rb +7 -0
  39. data/spec/lib/aixm/vertical/limits_spec.rb +78 -0
  40. data/spec/lib/aixm/xy_spec.rb +131 -0
  41. data/spec/lib/aixm/z_spec.rb +59 -0
  42. data/spec/sounds/failure.mp3 +0 -0
  43. data/spec/sounds/success.mp3 +0 -0
  44. data/spec/spec_helper.rb +28 -0
  45. 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
@@ -0,0 +1,5 @@
1
+ .DS_Store
2
+ Gemfile.lock
3
+ pkg/*
4
+ *.gem
5
+ .bundle
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.5.0
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.0
5
+ before_install: gem install bundler -v 1.16.1
data/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ ## 0.1.0
2
+
3
+ * Initial implementation to import D/R/P zones to OFM
4
+ * XY Coordinate
5
+ * Z Altitude
6
+ * AIXM-Snapshot 4.5 Document
7
+ * Airspace
8
+ * Vertical Limits
9
+ * Geometry
10
+ * Point
11
+ * Arc
12
+ * Border
13
+ * Circle
14
+ * Refinements
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,7 @@
1
+ clearing :on
2
+
3
+ guard :minitest do
4
+ watch(%r{^spec/(.+)_spec\.rb})
5
+ watch(%r{^lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch(%r{^spec/spec_helper\.rb}) { 'spec' }
7
+ end
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
+ [![Version](https://img.shields.io/gem/v/aixm.svg?style=flat)](https://rubygems.org/gems/aixm)
2
+ [![Continuous Integration](https://img.shields.io/travis/svoop/aixm/master.svg?style=flat)](https://travis-ci.org/svoop/aixm)
3
+ [![Code Climate](https://img.shields.io/codeclimate/github/svoop/aixm.svg?style=flat)](https://codeclimate.com/github/svoop/aixm)
4
+ [![Gitter](https://img.shields.io/gitter/room/svoop/aixm.svg?style=flat)](https://gitter.im/svoop/aixm)
5
+ [![Donorbox](https://img.shields.io/badge/donate-on_donorbox-yellow.svg)](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
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['spec/lib/**/*_spec.rb']
8
+ t.verbose = false
9
+ t.warning = true
10
+ end
11
+
12
+ task default: :test
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,6 @@
1
+ module AIXM
2
+
3
+ SCHEMA = Pathname(__dir__).join('schemas', '4.5', 'AIXM-Snapshot.xsd').freeze
4
+ GROUND = AIXM::Z.new(alt: 0, code: :QFE).freeze
5
+
6
+ end
@@ -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