aipp 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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', # TODO: handle internally
19
- 'côte méditérrannéenne' => 'FRANCE_MEDITERRANEAN_COAST', # TODO: handle internally
20
- 'limite des eaux territoriales atlantique françaises' => 'FRANCE_ATLANTIC_TERRITORIAL_SEA', # TODO: handle internally
21
- 'parc national des écrins' => 'FRANCE_ECRINS_NATIONAL_PARK' # TODO: handle internally
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
- buffer[:xy] ||= INTERSECTIONS.fetch("#{buffer[:border_name]}|#{border_name}")
164
- buffer[:border_name] = border_name
165
- if border_name == 'FRANCE_SPAIN' # specify which part of this split border
166
- border_name += buffer[:xy].lat < 42.55 ? '_EAST' : '_WEST'
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
- AIXM::H24 if text.gsub(/\W/, '') == 'H24'
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
@@ -1,3 +1,3 @@
1
1
  module AIPP
2
- VERSION = "0.2.2".freeze
2
+ VERSION = "0.2.3".freeze
3
3
  end
@@ -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
@@ -32,11 +32,11 @@ class Object
32
32
  puts message.send(color)
33
33
  end
34
34
 
35
- # Issue a debug message.
35
+ # Issue a verbose informational message.
36
36
  #
37
- # @param message [String] debug message
38
- def debug(message, color: :blue)
39
- info(message, color: color) if $DEBUG
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