aixm 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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