terraformer 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,6 +2,21 @@ module Terraformer
2
2
 
3
3
  class Polygon < Geometry
4
4
 
5
+ def initialize *args
6
+ case
7
+ when Coordinate === args[0] # each arg is a position of the polygon
8
+ self.coordinates = [Coordinate.from_array(args)]
9
+ when Array === args[0] # each arg is an array of positions; first is polygon, rest are "holes"
10
+ self.coordinates = Coordinate.from args
11
+ else
12
+ super *args
13
+ end
14
+
15
+ if line_strings.map(&:linear_ring?).include? false
16
+ raise ArgumentError.new 'not linear ring'
17
+ end
18
+ end
19
+
5
20
  def has_holes?
6
21
  coordinates.length > 1
7
22
  end
@@ -10,6 +25,97 @@ module Terraformer
10
25
  coordinates[0][0]
11
26
  end
12
27
 
28
+ def == obj
29
+ super obj do |o|
30
+
31
+ equal = true
32
+
33
+ # first check outer polygon
34
+ equal = self.coordinates[0].polygonally_equal_to? obj.coordinates[0]
35
+
36
+
37
+ # then inner polygons (holes)
38
+ #
39
+ if equal and obj.coordinates.length > 1
40
+ 1.upto(obj.coordinates.length - 1) do |i|
41
+ equal = self.coordinates[i].polygonally_equal_to? obj.coordinates[i]
42
+ break unless equal
43
+ end
44
+ end
45
+
46
+ equal
47
+ end
48
+ end
49
+
50
+ def line_strings
51
+ coordinates.map {|lr| LineString.new lr}
52
+ end
53
+
54
+ def holes
55
+ return nil unless has_holes?
56
+ coordinates[1..-1].map {|hole| Polygon.new hole}
57
+ end
58
+
59
+ def contains? obj
60
+ obj = Coordinate.new obj if Array === obj and Numeric === obj[0]
61
+ obj = obj.to_point if Coordinate === obj
62
+ contained = false
63
+ case obj
64
+ when Point
65
+ contained = Geometry.coordinates_contain_point? coordinates[0], obj.coordinates
66
+ contained = !holes.any? {|h| h.contains? obj} if contained and has_holes?
67
+ when MultiPoint
68
+ contained = obj.points.all? {|p| contains? p}
69
+ when LineString
70
+ contained = contains?(obj.first_coordinate) && !Geometry.array_intersects_multi_array?(obj.coordinates, coordinates)
71
+ when MultiLineString
72
+ contained = obj.line_strings.all? {|ls| contains? ls}
73
+ when Polygon
74
+ contained = obj.within? self
75
+ when MultiPolygon
76
+ contained = obj.polygons.all? {|p| p.within? self}
77
+ else
78
+ raise ArgumentError.new "unsupported type: #{obj.type rescue obj.class}"
79
+ end
80
+ contained
81
+ end
82
+
83
+ def within? obj
84
+ case obj
85
+ when Polygon
86
+ if self == obj
87
+ true
88
+ elsif obj.contains? first_coordinate
89
+ !Geometry.arrays_intersect_arrays?(coordinates, obj.coordinates)
90
+ end
91
+ when MultiPolygon
92
+ obj.polygons.any? {|p| p.contains? self}
93
+ else
94
+ raise ArgumentError.new "unsupported type: #{obj.type rescue obj.class}"
95
+ end
96
+ end
97
+
98
+ def add_vertex p
99
+ insert_vertex coordinates[0].length - 2, p
100
+ end
101
+ alias_method :<<, :add_vertex
102
+
103
+ def insert_vertex idx, p
104
+ p = p.coordinates if Point === p
105
+ raise ArgumentError unless Coordinate === p
106
+ coordinates[0].insert idx, p
107
+ end
108
+
109
+ def remove_vertex p
110
+ p = p.coordinates if Point === p
111
+ raise ArgumentError unless Coordinate === p
112
+ coordinates[0].delete p
113
+ end
114
+
115
+ def remove_vertex_at idx
116
+ coordinates[0].delete_at idx
117
+ end
118
+
13
119
  end
14
120
 
15
121
  end
@@ -1,3 +1,3 @@
1
1
  module Terraformer
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
data/lib/terraformer.rb CHANGED
@@ -2,10 +2,17 @@ require 'json'
2
2
  require 'bigdecimal'
3
3
  require 'bigdecimal/math'
4
4
  require 'bigdecimal/util'
5
+ require 'ext/array'
6
+ require 'ext/big_decimal'
7
+ require 'ext/big_math'
8
+ require 'ext/enumerable'
9
+ require 'ext/hash'
10
+ require 'forwardable'
5
11
 
6
12
  module Terraformer
7
13
 
8
- PRECISION = 8
14
+ PRECISION = BigDecimal.double_fig
15
+ BigDecimal.limit PRECISION
9
16
  PI = BigMath.PI PRECISION
10
17
  DEFAULT_BUFFER_RESOLUTION = 64
11
18
 
@@ -28,7 +35,10 @@ module Terraformer
28
35
  }
29
36
 
30
37
  def self.parse geojson
31
- geojson = JSON.parse geojson if String === geojson
38
+ if String === geojson
39
+ geojson = File.read geojson if File.readable? geojson
40
+ geojson = JSON.parse geojson
41
+ end
32
42
  raise ArgumentError.new "invalid arg: #{geojson}" unless Hash === geojson
33
43
 
34
44
  if klass = Terraformer.const_get(geojson['type'])
@@ -60,69 +70,26 @@ module Terraformer
60
70
  end
61
71
 
62
72
  def to_json *args
63
- self.to_hash.to_json *args
64
- end
65
-
66
- def [] prop
67
- self.__send__ prop.to_sym
73
+ h = self.to_hash
74
+ h[:bbox] = bbox if Hash === args.last and args.pop[:include_bbox]
75
+ h.to_json *args
68
76
  end
69
77
 
70
78
  end
71
79
 
72
- end
73
-
74
- module Enumerable
75
-
76
- def each_coordinate opts = {}, &block
77
- iter_coordinate :each, opts, &block
78
- end
79
-
80
- def map_coordinate opts = {}, &block
81
- iter_coordinate :map, opts, &block
82
- end
83
- alias_method :collect_coordinate, :map_coordinate
84
-
85
- def map_coordinate! opts = {}, &block
86
- iter_coordinate :map!, opts, &block
87
- end
88
- alias_method :collect_coordinate!, :map_coordinate!
80
+ # yikes!
81
+ module BBox
89
82
 
90
- def iter_coordinate meth, opts = {}, &block
91
- opts[:recurse] = true if opts[:recurse].nil?
92
-
93
- if Array === self and Numeric === self[0]
94
- yield self
95
- else
96
-
97
- self.__send__ meth do |pair|
98
- raise IndexError unless Array === pair
99
- case pair[0]
100
- when Numeric
101
- yield pair
102
- when Array
103
- pair.iter_coordinate meth, opts, &block if opts[:recurse]
104
- else
105
- raise IndexError.new "#{pair[0]} is not a Numeric or Array type"
106
- end
107
- end
83
+ def to_json *args
84
+ map {|e| e.to_f if e}.to_json *args
108
85
  end
109
- end
110
-
111
- end
112
-
113
- class BigDecimal
114
-
115
- def to_deg
116
- self * Terraformer::DEGREES_PER_RADIAN
117
- end
118
86
 
119
- def to_rad
120
- self * Terraformer::RADIANS_PER_DEGREE
121
87
  end
122
88
 
123
89
  end
124
90
 
125
91
  require 'terraformer/coordinate'
92
+ require 'terraformer/geodesic'
126
93
  require 'terraformer/bounds'
127
94
  require 'terraformer/geometry'
128
95
  require 'terraformer/feature'
@@ -132,3 +99,5 @@ require 'terraformer/line_string'
132
99
  require 'terraformer/multi_line_string'
133
100
  require 'terraformer/polygon'
134
101
  require 'terraformer/multi_polygon'
102
+ require 'terraformer/convex_hull'
103
+ require 'terraformer/circle'
@@ -0,0 +1,26 @@
1
+ require_relative './helper'
2
+
3
+ describe Terraformer::ConvexHull do
4
+
5
+ EXAMPLES.not(:multi_line_string).each do |key, geo|
6
+ it "works on #{key}" do
7
+ ch = Terraformer.parse(geo).convex_hull
8
+ ch.dont_be_terrible_ok
9
+ ch.must_be_valid_geojson
10
+ end
11
+ end
12
+
13
+ it 'raises without enough points' do
14
+ ->{ Terraformer.parse(EXAMPLES[:multi_line_string]).convex_hull }.must_raise ArgumentError
15
+ end
16
+
17
+ it 'works on feature collections' do
18
+ fc = Terraformer::FeatureCollection.new
19
+ fc << Terraformer.parse(EXAMPLES[:waldocanyon])
20
+ fc << Terraformer.parse(EXAMPLES[:sf_county]).to_feature
21
+ ch = fc.convex_hull
22
+ ch.dont_be_terrible_ok
23
+ ch.must_be_valid_geojson
24
+ end
25
+
26
+ end
@@ -3,264 +3,264 @@
3
3
  "coordinates": [
4
4
  [
5
5
  [
6
- 100.00089398965049,
7
- 8.82355685852279e-05
6
+ 100.0008939896505,
7
+ 8.80502953952e-05
8
8
  ],
9
9
  [
10
- 100.00088105440783,
11
- 0.00017532535375140864
10
+ 100.0008810544078,
11
+ 0.0001752526182957
12
12
  ],
13
13
  [
14
- 100.00085963412958,
15
- 0.0002606963900620961
14
+ 100.0008596341295,
15
+ 0.0002607671625167
16
16
  ],
17
17
  [
18
- 100.00082993510475,
19
- 0.0003437757085983607
18
+ 100.0008299351047,
19
+ 0.0003437703763427
20
20
  ],
21
21
  [
22
- 100.00079224335116,
23
- 0.00042341737532065687
22
+ 100.000792243351,
23
+ 0.000423462893695
24
24
  ],
25
25
  [
26
- 100.00074692186101,
27
- 0.0004990484131054821
26
+ 100.000746921861,
27
+ 0.0004990772318774
28
28
  ],
29
29
  [
30
- 100.00069440710504,
31
- 0.0005700958425710862
30
+ 100.000694407105,
31
+ 0.0005698851833621
32
32
  ],
33
33
  [
34
- 100.00063520482904,
35
- 0.0006354137183563783
34
+ 100.000635204829,
35
+ 0.0006352048291938
36
36
  ],
37
37
  [
38
- 100.00056988518331,
39
- 0.0006944290561239309
38
+ 100.0005698851833,
39
+ 0.0006944071051437
40
40
  ],
41
41
  [
42
- 100.00049907723172,
43
- 0.0007471418363985708
42
+ 100.0004990772316,
43
+ 0.0007469218611963
44
44
  ],
45
45
  [
46
- 100.00042346289358,
47
- 0.0007924061103353283
46
+ 100.0004234628935,
47
+ 0.0007922433512302
48
48
  ],
49
49
  [
50
- 100.00034377037628,
51
- 0.0008296488941866115
50
+ 100.0003437703763,
51
+ 0.0008299351049923
52
52
  ],
53
53
  [
54
- 100.00026076716232,
55
- 0.0008594431386974881
54
+ 100.0002607671623,
55
+ 0.0008596341297125
56
56
  ],
57
57
  [
58
- 100.00017525261805,
59
- 0.0008812158656376033
58
+ 100.000175252618,
59
+ 0.0008810544079536
60
60
  ],
61
61
  [
62
- 100.00008805029526,
63
- 0.000893821132384516
62
+ 100.0000880502952,
63
+ 0.0008939896506158
64
64
  ],
65
65
  [
66
- 100.0,
67
- 0.0008984048664345436
66
+ 99.99999999999993,
67
+ 0.0008983152842413
68
68
  ],
69
69
  [
70
- 99.99991194970474,
71
- 0.000893821132384516
70
+ 99.9999119497047,
71
+ 0.0008939896506158
72
72
  ],
73
73
  [
74
- 99.99982474738195,
75
- 0.0008812158656376033
74
+ 99.99982474738192,
75
+ 0.0008810544079536
76
76
  ],
77
77
  [
78
- 99.99973923283768,
79
- 0.0008594431386974881
78
+ 99.99973923283758,
79
+ 0.0008596341297125
80
80
  ],
81
81
  [
82
- 99.99965622962372,
83
- 0.0008296488941866115
82
+ 99.99965622962364,
83
+ 0.0008299351049923
84
84
  ],
85
85
  [
86
- 99.99957653710642,
87
- 0.0007924061103353283
86
+ 99.9995765371064,
87
+ 0.0007922433512302
88
88
  ],
89
89
  [
90
- 99.99950092276828,
91
- 0.0007471418363985708
90
+ 99.99950092276822,
91
+ 0.0007469218611963
92
92
  ],
93
93
  [
94
- 99.99943011481669,
95
- 0.0006944290561239309
94
+ 99.99943011481662,
95
+ 0.0006944071051437
96
96
  ],
97
97
  [
98
- 99.99936479517096,
99
- 0.0006354137183563783
98
+ 99.9993647951709,
99
+ 0.0006352048291938
100
100
  ],
101
101
  [
102
- 99.99930559289496,
103
- 0.0005700958425710862
102
+ 99.9993055928949,
103
+ 0.0005698851833621
104
104
  ],
105
105
  [
106
- 99.99925307813899,
107
- 0.0004990484131054821
106
+ 99.99925307813896,
107
+ 0.0004990772318774
108
108
  ],
109
109
  [
110
- 99.99920775664884,
111
- 0.00042341737532065687
110
+ 99.99920775664887,
111
+ 0.000423462893695
112
112
  ],
113
113
  [
114
- 99.99917006489525,
115
- 0.0003437757085983607
114
+ 99.99917006489522,
115
+ 0.0003437703763427
116
116
  ],
117
117
  [
118
- 99.99914036587042,
119
- 0.0002606963900620961
118
+ 99.99914036587037,
119
+ 0.0002607671625167
120
120
  ],
121
121
  [
122
- 99.99911894559217,
123
- 0.00017532535375140864
122
+ 99.99911894559214,
123
+ 0.0001752526182957
124
124
  ],
125
125
  [
126
- 99.99910601034951,
127
- 8.82355685852279e-05
126
+ 99.99910601034942,
127
+ 8.80502953952e-05
128
128
  ],
129
129
  [
130
- 99.99910168471588,
131
- 1.9370377676740394e-13
130
+ 99.99910168471585,
131
+ 1.719e-13
132
132
  ],
133
133
  [
134
- 99.99910601034951,
135
- -8.594373353370475e-05
134
+ 99.99910601034942,
135
+ -8.80502950514e-05
136
136
  ],
137
137
  [
138
- 99.99911894559217,
139
- -0.00017761719160345075
138
+ 99.99911894559214,
139
+ -0.0001752526179519
140
140
  ],
141
141
  [
142
- 99.99914036587042,
143
- -0.0002635611917568658
142
+ 99.99914036587037,
143
+ -0.000260767162173
144
144
  ],
145
145
  [
146
- 99.99917006489525,
147
- -0.00034377570821095315
146
+ 99.99917006489522,
147
+ -0.0003437703759989
148
148
  ],
149
149
  [
150
- 99.99920775664884,
151
- -0.0004239903369654551
150
+ 99.99920775664887,
151
+ -0.0004234628933512
152
152
  ],
153
153
  [
154
- 99.99925307813899,
155
- -0.0004984754499351452
154
+ 99.99925307813896,
155
+ -0.0004990772315336
156
156
  ],
157
157
  [
158
- 99.99930559289496,
159
- -0.0005672310247747656
158
+ 99.9993055928949,
159
+ -0.0005698851830183
160
160
  ],
161
161
  [
162
- 99.99936479517096,
163
- -0.0006359866821211351
162
+ 99.9993647951709,
163
+ -0.00063520482885
164
164
  ],
165
165
  [
166
- 99.99943011481669,
167
- -0.0006932831262689893
166
+ 99.99943011481662,
167
+ -0.0006944071047999
168
168
  ],
169
169
  [
170
- 99.99950092276828,
171
- -0.000744849974990818
170
+ 99.99950092276822,
171
+ -0.0007469218608526
172
172
  ],
173
173
  [
174
- 99.99957653710642,
175
- -0.0007906872128161134
174
+ 99.9995765371064,
175
+ -0.0007922433508864
176
176
  ],
177
177
  [
178
- 99.99965622962372,
179
- -0.0008307948259940207
178
+ 99.99965622962364,
179
+ -0.0008299351046485
180
180
  ],
181
181
  [
182
- 99.99973923283768,
183
- -0.0008594431383100805
182
+ 99.99973923283758,
183
+ -0.0008596341293688
184
184
  ],
185
185
  [
186
- 99.99982474738195,
187
- -0.0008823617984762712
186
+ 99.99982474738192,
187
+ -0.0008810544076098
188
188
  ],
189
189
  [
190
- 99.99991194970474,
191
- -0.0008938211319971085
190
+ 99.9999119497047,
191
+ -0.0008939896502721
192
192
  ],
193
193
  [
194
- 100.0,
195
- -0.0008995507996170583
194
+ 99.99999999999993,
195
+ -0.0008983152838976
196
196
  ],
197
197
  [
198
- 100.00008805029526,
199
- -0.0008938211319971085
198
+ 100.0000880502952,
199
+ -0.0008939896502721
200
200
  ],
201
201
  [
202
- 100.00017525261805,
203
- -0.0008823617984762712
202
+ 100.000175252618,
203
+ -0.0008810544076098
204
204
  ],
205
205
  [
206
- 100.00026076716232,
207
- -0.0008594431383100805
206
+ 100.0002607671623,
207
+ -0.0008596341293688
208
208
  ],
209
209
  [
210
- 100.00034377037628,
211
- -0.0008307948259940207
210
+ 100.0003437703763,
211
+ -0.0008299351046485
212
212
  ],
213
213
  [
214
- 100.00042346289358,
215
- -0.0007906872128161134
214
+ 100.0004234628935,
215
+ -0.0007922433508864
216
216
  ],
217
217
  [
218
- 100.00049907723172,
219
- -0.000744849974990818
218
+ 100.0004990772316,
219
+ -0.0007469218608526
220
220
  ],
221
221
  [
222
- 100.00056988518331,
223
- -0.0006932831262689893
222
+ 100.0005698851833,
223
+ -0.0006944071047999
224
224
  ],
225
225
  [
226
- 100.00063520482904,
227
- -0.0006359866821211351
226
+ 100.000635204829,
227
+ -0.00063520482885
228
228
  ],
229
229
  [
230
- 100.00069440710504,
231
- -0.0005672310247747656
230
+ 100.000694407105,
231
+ -0.0005698851830183
232
232
  ],
233
233
  [
234
- 100.00074692186101,
235
- -0.0004984754499351452
234
+ 100.000746921861,
235
+ -0.0004990772315336
236
236
  ],
237
237
  [
238
- 100.00079224335116,
239
- -0.0004239903369654551
238
+ 100.000792243351,
239
+ -0.0004234628933512
240
240
  ],
241
241
  [
242
- 100.00082993510475,
243
- -0.00034377570821095315
242
+ 100.0008299351047,
243
+ -0.0003437703759989
244
244
  ],
245
245
  [
246
- 100.00085963412958,
247
- -0.0002635611917568658
246
+ 100.0008596341295,
247
+ -0.000260767162173
248
248
  ],
249
249
  [
250
- 100.00088105440783,
251
- -0.00017761719160345075
250
+ 100.0008810544078,
251
+ -0.0001752526179519
252
252
  ],
253
253
  [
254
- 100.00089398965049,
255
- -8.594373353370475e-05
254
+ 100.0008939896505,
255
+ -8.80502950514e-05
256
256
  ],
257
257
  [
258
- 100.00089831528412,
259
- 1.9370377676740394e-13
258
+ 100.0008983152841,
259
+ 1.719e-13
260
260
  ],
261
261
  [
262
- 100.00089398965049,
263
- 8.82355685852279e-05
262
+ 100.0008939896505,
263
+ 8.80502953952e-05
264
264
  ]
265
265
  ]
266
266
  ]
@@ -1,3 +1,3 @@
1
1
  { "type": "LineString",
2
- "coordinates": [ [100.0, 0.0], [101.0, 1.0] ]
2
+ "coordinates": [ [100.0, 0.0], [101.0, 1.0], [100.0, 1.0], [99.0,0.0] ]
3
3
  }
@@ -1,3 +1,3 @@
1
1
  { "type": "MultiPoint",
2
- "coordinates": [ [100.0, 0.0], [101.0, 1.0] ]
2
+ "coordinates": [ [100.0, 0.0], [101.0, 1.0], [100.0, 1.0], [99.0,0.0] ]
3
3
  }