aipp 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +9 -0
- data/README.md +47 -13
- data/TODO.md +5 -2
- data/aipp.gemspec +1 -1
- data/lib/aipp.rb +2 -0
- data/lib/aipp/aip.rb +4 -3
- data/lib/aipp/border.rb +146 -0
- data/lib/aipp/downloader.rb +1 -1
- data/lib/aipp/executable.rb +2 -2
- data/lib/aipp/parser.rb +12 -1
- data/lib/aipp/patcher.rb +1 -1
- data/lib/aipp/pdf.rb +5 -5
- data/lib/aipp/regions/LF/AD-1.3.rb +4 -4
- data/lib/aipp/regions/LF/AD-1.6.rb +1 -1
- data/lib/aipp/regions/LF/AD-2.rb +7 -7
- data/lib/aipp/regions/LF/ENR-2.1.rb +9 -7
- data/lib/aipp/regions/LF/ENR-4.1.rb +2 -7
- data/lib/aipp/regions/LF/ENR-4.3.rb +1 -1
- data/lib/aipp/regions/LF/ENR-5.1.rb +2 -2
- data/lib/aipp/regions/LF/ENR-5.5.rb +53 -0
- data/lib/aipp/regions/LF/borders/france_atlantic_coast.geojson +2546 -0
- data/lib/aipp/regions/LF/borders/france_atlantic_territorial_sea.geojson +1663 -0
- data/lib/aipp/regions/LF/borders/france_ecrins_national_park.geojson +5861 -0
- data/lib/aipp/regions/LF/borders/france_mediterranean_coast.geojson +6203 -0
- data/lib/aipp/regions/LF/helpers/common.rb +26 -16
- data/lib/aipp/version.rb +1 -1
- data/lib/core_ext/integer.rb +16 -0
- data/lib/core_ext/object.rb +4 -4
- data/spec/fixtures/border.geojson +201 -0
- data/spec/lib/aipp/border_spec.rb +135 -0
- data/spec/lib/core_ext/integer_spec.rb +15 -0
- metadata +17 -5
- data/lib/aipp/regions/LF/ENR-5.5.rb-NEW +0 -11
@@ -15,10 +15,10 @@ module AIPP
|
|
15
15
|
'franco-belge' => 'BELGIUM_FRANCE',
|
16
16
|
'germano-suisse' => 'GERMANY_SWITZERLAND',
|
17
17
|
'hispano-andorrane' => 'ANDORRA_SPAIN',
|
18
|
-
'la côte atlantique française' => 'FRANCE_ATLANTIC_COAST',
|
19
|
-
'côte méditérrannéenne' => 'FRANCE_MEDITERRANEAN_COAST',
|
20
|
-
'limite des eaux territoriales atlantique françaises' => 'FRANCE_ATLANTIC_TERRITORIAL_SEA',
|
21
|
-
'parc national des écrins' => 'FRANCE_ECRINS_NATIONAL_PARK'
|
18
|
+
'la côte atlantique française' => 'FRANCE_ATLANTIC_COAST',
|
19
|
+
'côte méditérrannéenne' => 'FRANCE_MEDITERRANEAN_COAST',
|
20
|
+
'limite des eaux territoriales atlantique françaises' => 'FRANCE_ATLANTIC_TERRITORIAL_SEA',
|
21
|
+
'parc national des écrins' => 'FRANCE_ECRINS_NATIONAL_PARK'
|
22
22
|
}.freeze
|
23
23
|
|
24
24
|
# Intersection points between three countries
|
@@ -127,12 +127,11 @@ module AIPP
|
|
127
127
|
|
128
128
|
def layer_from(text_for_limits, text_for_class=nil)
|
129
129
|
above, below = text_for_limits.gsub(/ /, '').split(/\n+/).select(&:blank_to_nil).split { |e| e.match? '---+' }
|
130
|
-
above.reverse!
|
131
130
|
AIXM.layer(
|
132
131
|
class: text_for_class,
|
133
132
|
vertical_limits: AIXM.vertical_limits(
|
134
|
-
max_z: z_from(above[1]),
|
135
133
|
upper_z: z_from(above[0]),
|
134
|
+
max_z: z_from(above[1]),
|
136
135
|
lower_z: z_from(below[0]),
|
137
136
|
min_z: z_from(below[1])
|
138
137
|
)
|
@@ -158,17 +157,26 @@ module AIPP
|
|
158
157
|
when /end|(\S+) , (\S+)/
|
159
158
|
geometry << AIXM.point(xy: buffer[:xy]) if buffer.has_key?(:xy)
|
160
159
|
buffer[:xy] = AIXM.xy(lat: $1, long: $2) if $1
|
160
|
+
if border = buffer.delete(:border)
|
161
|
+
from = border.nearest(xy: geometry.segments.last.xy)
|
162
|
+
to = border.nearest(xy: buffer[:xy], geometry_index: from.geometry_index)
|
163
|
+
geometry.concat border.segment(from_position: from, to_position: to).map(&:to_point)
|
164
|
+
end
|
161
165
|
when /^frontière ([\w-]+)/i, /^(\D[^(]+)/i
|
162
166
|
border_name = BORDERS.fetch($1.downcase.strip)
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
+
if borders.has_key? border_name # border from GeoJSON
|
168
|
+
buffer[:border] = borders[border_name]
|
169
|
+
else # named border
|
170
|
+
buffer[:xy] ||= INTERSECTIONS.fetch("#{buffer[:border_name]}|#{border_name}")
|
171
|
+
buffer[:border_name] = border_name
|
172
|
+
if border_name == 'FRANCE_SPAIN' # specify which part of this split border
|
173
|
+
border_name += buffer[:xy].lat < 42.55 ? '_EAST' : '_WEST'
|
174
|
+
end
|
175
|
+
geometry << AIXM.border(
|
176
|
+
xy: buffer.delete(:xy),
|
177
|
+
name: border_name
|
178
|
+
)
|
167
179
|
end
|
168
|
-
geometry << AIXM.border(
|
169
|
-
xy: buffer.delete(:xy),
|
170
|
-
name: border_name
|
171
|
-
)
|
172
180
|
else
|
173
181
|
fail "geometry `#{element}' not recognized"
|
174
182
|
end
|
@@ -176,8 +184,10 @@ module AIPP
|
|
176
184
|
end
|
177
185
|
end
|
178
186
|
|
179
|
-
def timetable_from(text)
|
180
|
-
|
187
|
+
def timetable_from!(text)
|
188
|
+
if text.gsub!(/^\s*#{AIXM::H_RE}\s*$/, '')
|
189
|
+
AIXM.timetable(code: Regexp.last_match&.to_s&.strip)
|
190
|
+
end
|
181
191
|
end
|
182
192
|
|
183
193
|
end
|
data/lib/aipp/version.rb
CHANGED
@@ -0,0 +1,16 @@
|
|
1
|
+
class Integer
|
2
|
+
|
3
|
+
# Iterates the given block, passing in increasing or decreasing values to and
|
4
|
+
# including limit
|
5
|
+
#
|
6
|
+
# If no block is given, an Enumerator is returned instead.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# 10.up_or_downto(12).to_a # => [10, 11, 12]
|
10
|
+
# 10.upto(12).to_a # => [10, 11, 12]
|
11
|
+
# 10.up_or_downto(8).to_a # => [10, 9, 8]
|
12
|
+
# 10.downto(8).to_a # => [10, 9, 8]
|
13
|
+
def up_or_downto(limit)
|
14
|
+
self > limit ? self.downto(limit) : self.upto(limit)
|
15
|
+
end
|
16
|
+
end
|
data/lib/core_ext/object.rb
CHANGED
@@ -32,11 +32,11 @@ class Object
|
|
32
32
|
puts message.send(color)
|
33
33
|
end
|
34
34
|
|
35
|
-
# Issue a
|
35
|
+
# Issue a verbose informational message.
|
36
36
|
#
|
37
|
-
# @param message [String]
|
38
|
-
def
|
39
|
-
info(message, color: color) if $
|
37
|
+
# @param message [String] verbose informational message
|
38
|
+
def verbose_info(message, color: :blue)
|
39
|
+
info(message, color: color) if $VERBOSE_INFO
|
40
40
|
end
|
41
41
|
|
42
42
|
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
{
|
2
|
+
"type": "GeometryCollection",
|
3
|
+
"geometries": [
|
4
|
+
{
|
5
|
+
"type": "LineString",
|
6
|
+
"coordinates": [
|
7
|
+
[
|
8
|
+
4.757294654846191,
|
9
|
+
43.989202079482276
|
10
|
+
],
|
11
|
+
[
|
12
|
+
4.764375686645508,
|
13
|
+
43.99701327763528
|
14
|
+
],
|
15
|
+
[
|
16
|
+
4.7519731521606445,
|
17
|
+
44.00269350325321
|
18
|
+
],
|
19
|
+
[
|
20
|
+
4.745192527770996,
|
21
|
+
43.99506829280446
|
22
|
+
],
|
23
|
+
[
|
24
|
+
4.751286506652832,
|
25
|
+
43.99235138187902
|
26
|
+
],
|
27
|
+
[
|
28
|
+
4.750943183898926,
|
29
|
+
43.99198088438825
|
30
|
+
],
|
31
|
+
[
|
32
|
+
4.757294654846191,
|
33
|
+
43.989202079482276
|
34
|
+
]
|
35
|
+
]
|
36
|
+
},
|
37
|
+
{
|
38
|
+
"type": "LineString",
|
39
|
+
"coordinates": [
|
40
|
+
[
|
41
|
+
4.777421951293944,
|
42
|
+
44.00115001749186
|
43
|
+
],
|
44
|
+
[
|
45
|
+
4.78205680847168,
|
46
|
+
43.994111213373934
|
47
|
+
],
|
48
|
+
[
|
49
|
+
4.784030914306641,
|
50
|
+
43.99818641226534
|
51
|
+
],
|
52
|
+
[
|
53
|
+
4.787635803222656,
|
54
|
+
44.00077957493397
|
55
|
+
],
|
56
|
+
[
|
57
|
+
4.785747528076171,
|
58
|
+
44.00448389642906
|
59
|
+
],
|
60
|
+
[
|
61
|
+
4.790983200073242,
|
62
|
+
44.004669106432225
|
63
|
+
],
|
64
|
+
[
|
65
|
+
4.798364639282227,
|
66
|
+
44.008373185063874
|
67
|
+
],
|
68
|
+
[
|
69
|
+
4.793901443481445,
|
70
|
+
44.01528684632061
|
71
|
+
],
|
72
|
+
[
|
73
|
+
4.787378311157227,
|
74
|
+
44.01584237340163
|
75
|
+
],
|
76
|
+
[
|
77
|
+
4.785575866699219,
|
78
|
+
44.01960747533136
|
79
|
+
],
|
80
|
+
[
|
81
|
+
4.768667221069335,
|
82
|
+
44.01831131968508
|
83
|
+
],
|
84
|
+
[
|
85
|
+
4.763689041137695,
|
86
|
+
44.01460786170962
|
87
|
+
],
|
88
|
+
[
|
89
|
+
4.760427474975586,
|
90
|
+
44.01065725159039
|
91
|
+
],
|
92
|
+
[
|
93
|
+
4.770212173461914,
|
94
|
+
44.002940457248556
|
95
|
+
],
|
96
|
+
[
|
97
|
+
4.777421951293944,
|
98
|
+
44.00115001749186
|
99
|
+
]
|
100
|
+
]
|
101
|
+
},
|
102
|
+
{
|
103
|
+
"type": "LineString",
|
104
|
+
"coordinates": [
|
105
|
+
[
|
106
|
+
4.752960205078125,
|
107
|
+
43.93721446391471
|
108
|
+
],
|
109
|
+
[
|
110
|
+
4.744377136230469,
|
111
|
+
43.950068873803815
|
112
|
+
],
|
113
|
+
[
|
114
|
+
4.737510681152343,
|
115
|
+
43.97033364196856
|
116
|
+
],
|
117
|
+
[
|
118
|
+
4.7344207763671875,
|
119
|
+
43.98713332912919
|
120
|
+
],
|
121
|
+
[
|
122
|
+
4.7371673583984375,
|
123
|
+
44.00516299694704
|
124
|
+
],
|
125
|
+
[
|
126
|
+
4.743347167968749,
|
127
|
+
44.02195282780904
|
128
|
+
],
|
129
|
+
[
|
130
|
+
4.749870300292969,
|
131
|
+
44.037503870182896
|
132
|
+
],
|
133
|
+
[
|
134
|
+
4.755706787109375,
|
135
|
+
44.05379106204314
|
136
|
+
],
|
137
|
+
[
|
138
|
+
4.7646331787109375,
|
139
|
+
44.070073775703484
|
140
|
+
]
|
141
|
+
]
|
142
|
+
},
|
143
|
+
{
|
144
|
+
"type": "LineString",
|
145
|
+
"coordinates": [
|
146
|
+
[
|
147
|
+
4.7948455810546875,
|
148
|
+
43.95328204198018
|
149
|
+
],
|
150
|
+
[
|
151
|
+
4.801368713378906,
|
152
|
+
43.956989327857265
|
153
|
+
],
|
154
|
+
[
|
155
|
+
4.815788269042969,
|
156
|
+
43.9646503190861
|
157
|
+
],
|
158
|
+
[
|
159
|
+
4.82025146484375,
|
160
|
+
43.98614524381678
|
161
|
+
],
|
162
|
+
[
|
163
|
+
4.840850830078125,
|
164
|
+
43.98491011404692
|
165
|
+
],
|
166
|
+
[
|
167
|
+
4.845314025878906,
|
168
|
+
43.99479043262446
|
169
|
+
],
|
170
|
+
[
|
171
|
+
4.8538970947265625,
|
172
|
+
43.98367495857784
|
173
|
+
],
|
174
|
+
[
|
175
|
+
4.851493835449218,
|
176
|
+
43.967121395851485
|
177
|
+
],
|
178
|
+
[
|
179
|
+
4.8442840576171875,
|
180
|
+
43.96069638244953
|
181
|
+
],
|
182
|
+
[
|
183
|
+
4.829521179199219,
|
184
|
+
43.96069638244953
|
185
|
+
],
|
186
|
+
[
|
187
|
+
4.819221496582031,
|
188
|
+
43.95501213750488
|
189
|
+
],
|
190
|
+
[
|
191
|
+
4.805145263671875,
|
192
|
+
43.955506441260546
|
193
|
+
],
|
194
|
+
[
|
195
|
+
4.799995422363281,
|
196
|
+
43.952046228624724
|
197
|
+
]
|
198
|
+
]
|
199
|
+
}
|
200
|
+
]
|
201
|
+
}
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe AIPP::Border::Position do
|
4
|
+
subject do
|
5
|
+
AIPP::Border::Position.new(
|
6
|
+
geometries: [
|
7
|
+
[AIXM.xy(long: 0, lat: 0), AIXM.xy(long: 1, lat: 1), AIXM.xy(long: 2, lat: 2)],
|
8
|
+
[AIXM.xy(long: 10, lat: 10), AIXM.xy(long: 11, lat: 11), AIXM.xy(long: 12, lat: 12)]
|
9
|
+
],
|
10
|
+
geometry_index: 0,
|
11
|
+
coordinates_index: 0
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe :xy do
|
16
|
+
it "returns the coordinates" do
|
17
|
+
subject.xy.must_equal AIXM.xy(long: 0, lat: 0)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "returns nil if the geometry index is out of bounds" do
|
21
|
+
subject.tap { |s| s.geometry_index = 2 }.xy.must_be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "returns nil if the coordinates index is out of bounds" do
|
25
|
+
subject.tap { |s| s.coordinates_index = 3 }.xy.must_be_nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe AIPP::Border do
|
31
|
+
let :fixtures_dir do
|
32
|
+
Pathname(__FILE__).join('..', '..', '..', 'fixtures')
|
33
|
+
end
|
34
|
+
|
35
|
+
# The border.geojson fixture defines three geometries:
|
36
|
+
# * index 0: closed geometry circumventing the airfield of Pujaut
|
37
|
+
# * index 1: closed geometry circumventing the village of Pujaut
|
38
|
+
# * index 2: unclosed I-shaped geometry following the TGV from the S to N bridges over the Rhône
|
39
|
+
# * index 3: unclosed U-shaped geometry around Île de Bartelasse from N to S end of Pont Daladier
|
40
|
+
subject do
|
41
|
+
AIPP::Border.new(fixtures_dir.join('border.geojson'))
|
42
|
+
end
|
43
|
+
|
44
|
+
describe :initialize do
|
45
|
+
it "fails for files unless the extension is .geojson" do
|
46
|
+
-> { AIPP::Border.new("/path/to/another.txt") }.must_raise ArgumentError
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe :name do
|
51
|
+
it "returns the upcased file name" do
|
52
|
+
subject.name.must_equal 'BORDER'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe :closed? do
|
57
|
+
it "returns true for closed geometries" do
|
58
|
+
subject.closed?(geometry_index: 0).must_equal true
|
59
|
+
subject.closed?(geometry_index: 1).must_equal true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns false for unclosed geometries" do
|
63
|
+
subject.closed?(geometry_index: 2).must_equal false
|
64
|
+
subject.closed?(geometry_index: 3).must_equal false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe :nearest do
|
69
|
+
let :point do
|
70
|
+
AIXM.xy(lat: 44.008187986625636, long: 4.759397506713866)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "finds the nearest position on any geometry" do
|
74
|
+
position = subject.nearest(xy: point)
|
75
|
+
position.geometry_index.must_equal 1
|
76
|
+
position.coordinates_index.must_equal 12
|
77
|
+
position.xy.must_equal AIXM.xy(lat: 44.01065725159039, long: 4.760427474975586)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "finds the nearest postition on a given geometry" do
|
81
|
+
position = subject.nearest(xy: point, geometry_index: 0)
|
82
|
+
position.geometry_index.must_equal 0
|
83
|
+
position.coordinates_index.must_equal 2
|
84
|
+
position.xy.must_equal AIXM.xy(lat: 44.00269350325321, long: 4.7519731521606445)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe :segment do
|
89
|
+
it "fails if positions are not on the same geometry" do
|
90
|
+
from_position = AIPP::Border::Position.new(geometries: subject.geometries, geometry_index: 0, coordinates_index: 0)
|
91
|
+
to_position = AIPP::Border::Position.new(geometries: subject.geometries, geometry_index: 1, coordinates_index: 0)
|
92
|
+
-> { subject.segment(from_position: from_position, to_position: to_position) }.must_raise ArgumentError
|
93
|
+
end
|
94
|
+
|
95
|
+
it "returns shortest segment on an unclosed I-shaped geometry" do
|
96
|
+
from_position = subject.nearest(xy: AIXM.xy(lat: 44.002940457248556, long: 4.734249114990234))
|
97
|
+
to_position = subject.nearest(xy: AIXM.xy(lat: 44.07155380033749, long: 4.7687530517578125), geometry_index: from_position.geometry_index)
|
98
|
+
subject.segment(from_position: from_position, to_position: to_position).must_equal [
|
99
|
+
AIXM.xy(lat: 44.00516299694704, long: 4.7371673583984375),
|
100
|
+
AIXM.xy(lat: 44.02195282780904, long: 4.743347167968749),
|
101
|
+
AIXM.xy(lat: 44.037503870182896, long: 4.749870300292969),
|
102
|
+
AIXM.xy(lat: 44.05379106204314, long: 4.755706787109375),
|
103
|
+
AIXM.xy(lat: 44.070073775703484, long: 4.7646331787109375)
|
104
|
+
]
|
105
|
+
end
|
106
|
+
|
107
|
+
it "returns shortest segment on an unclosed U-shaped geometry" do
|
108
|
+
from_position = subject.nearest(xy: AIXM.xy(lat: 43.96563876212758, long: 4.8126983642578125))
|
109
|
+
to_position = subject.nearest(xy: AIXM.xy(lat: 43.956989327857265, long: 4.83123779296875), geometry_index: from_position.geometry_index)
|
110
|
+
subject.segment(from_position: from_position, to_position: to_position).must_equal [
|
111
|
+
AIXM.xy(lat: 43.9646503190861, long: 4.815788269042969),
|
112
|
+
AIXM.xy(lat: 43.98614524381678, long: 4.82025146484375),
|
113
|
+
AIXM.xy(lat: 43.98491011404692, long: 4.840850830078125),
|
114
|
+
AIXM.xy(lat: 43.99479043262446, long: 4.845314025878906),
|
115
|
+
AIXM.xy(lat: 43.98367495857784, long: 4.8538970947265625),
|
116
|
+
AIXM.xy(lat: 43.967121395851485, long: 4.851493835449218),
|
117
|
+
AIXM.xy(lat: 43.96069638244953, long: 4.8442840576171875),
|
118
|
+
AIXM.xy(lat: 43.96069638244953, long: 4.829521179199219)
|
119
|
+
]
|
120
|
+
end
|
121
|
+
|
122
|
+
it "returns shortest segment ignoring endings on a closed geometry" do
|
123
|
+
from_position = subject.nearest(xy: AIXM.xy(lat: 44.00022390676026, long: 4.789009094238281))
|
124
|
+
to_position = subject.nearest(xy: AIXM.xy(lat: 43.99800118202362, long: 4.765834808349609), geometry_index: from_position.geometry_index)
|
125
|
+
subject.segment(from_position: from_position, to_position: to_position).must_equal [
|
126
|
+
AIXM.xy(lat: 44.00077957493397, long: 4.787635803222656),
|
127
|
+
AIXM.xy(lat: 43.99818641226534, long: 4.784030914306641),
|
128
|
+
AIXM.xy(lat: 43.994111213373934, long: 4.78205680847168),
|
129
|
+
AIXM.xy(lat: 44.00115001749186, long: 4.777421951293944),
|
130
|
+
AIXM.xy(lat: 44.002940457248556, long: 4.770212173461914)
|
131
|
+
]
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|