ffi-geos 2.0.0 → 2.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3954 -4
- data/.travis.yml +23 -11
- data/Gemfile +7 -9
- data/Guardfile +3 -4
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -20
- data/Rakefile +3 -2
- data/ffi-geos.gemspec +2 -2
- data/lib/ffi-geos.rb +93 -44
- data/lib/ffi-geos/coordinate_sequence.rb +147 -145
- data/lib/ffi-geos/geometry.rb +68 -17
- data/lib/ffi-geos/geometry_collection.rb +22 -8
- data/lib/ffi-geos/interrupt.rb +11 -14
- data/lib/ffi-geos/line_string.rb +57 -42
- data/lib/ffi-geos/point.rb +16 -16
- data/lib/ffi-geos/polygon.rb +42 -28
- data/lib/ffi-geos/strtree.rb +3 -5
- data/lib/ffi-geos/tools.rb +1 -1
- data/lib/ffi-geos/utils.rb +4 -12
- data/lib/ffi-geos/version.rb +1 -1
- data/lib/ffi-geos/wkb_writer.rb +2 -3
- data/lib/ffi-geos/wkt_writer.rb +4 -7
- data/sonar-project.properties +16 -0
- data/test/coordinate_sequence_tests.rb +144 -122
- data/test/geometry_collection_tests.rb +38 -65
- data/test/geometry_tests.rb +106 -17
- data/test/interrupt_tests.rb +7 -7
- data/test/line_string_tests.rb +10 -10
- data/test/point_tests.rb +2 -2
- data/test/polygon_tests.rb +3 -4
- data/test/prepared_geometry_tests.rb +8 -8
- data/test/strtree_tests.rb +5 -5
- data/test/test_helper.rb +20 -35
- data/test/utils_tests.rb +69 -59
- data/test/wkb_reader_tests.rb +9 -9
- data/test/wkb_writer_tests.rb +14 -12
- data/test/wkt_reader_tests.rb +0 -1
- data/test/wkt_writer_tests.rb +2 -5
- metadata +4 -4
data/lib/ffi-geos/geometry.rb
CHANGED
@@ -53,9 +53,7 @@ module Geos
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def normalize!
|
56
|
-
if FFIGeos.GEOSNormalize_r(Geos.current_handle_pointer, ptr) == -1
|
57
|
-
raise Geos::Geometry::CouldntNormalizeError, self.class
|
58
|
-
end
|
56
|
+
raise Geos::Geometry::CouldntNormalizeError, self.class if FFIGeos.GEOSNormalize_r(Geos.current_handle_pointer, ptr) == -1
|
59
57
|
|
60
58
|
self
|
61
59
|
end
|
@@ -163,12 +161,10 @@ module Geos
|
|
163
161
|
if geom
|
164
162
|
check_geometry(geom)
|
165
163
|
cast_geometry_ptr(FFIGeos.GEOSUnion_r(Geos.current_handle_pointer, ptr, geom.ptr), srid_copy: pick_srid_from_geoms(srid, geom.srid))
|
164
|
+
elsif respond_to?(:unary_union)
|
165
|
+
unary_union
|
166
166
|
else
|
167
|
-
|
168
|
-
unary_union
|
169
|
-
else
|
170
|
-
union_cascaded
|
171
|
-
end
|
167
|
+
union_cascaded
|
172
168
|
end
|
173
169
|
end
|
174
170
|
|
@@ -176,6 +172,13 @@ module Geos
|
|
176
172
|
cast_geometry_ptr(FFIGeos.GEOSUnionCascaded_r(Geos.current_handle_pointer, ptr), srid_copy: srid)
|
177
173
|
end
|
178
174
|
|
175
|
+
if FFIGeos.respond_to?(:GEOSCoverageUnion_r)
|
176
|
+
# Added in GEOS 3.8+
|
177
|
+
def coverage_union
|
178
|
+
cast_geometry_ptr(FFIGeos.GEOSCoverageUnion_r(Geos.current_handle_pointer, ptr), srid_copy: srid)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
179
182
|
if FFIGeos.respond_to?(:GEOSUnaryUnion_r)
|
180
183
|
# Available in GEOS 3.3+
|
181
184
|
def unary_union
|
@@ -208,6 +211,14 @@ module Geos
|
|
208
211
|
end
|
209
212
|
alias center centroid
|
210
213
|
|
214
|
+
if FFIGeos.respond_to?(:GEOSMinimumBoundingCircle_r)
|
215
|
+
# Added in GEOS 3.8+. Does not yet support the radius or center
|
216
|
+
# arguments.
|
217
|
+
def minimum_bounding_circle
|
218
|
+
cast_geometry_ptr(FFIGeos.GEOSMinimumBoundingCircle_r(Geos.current_handle_pointer, ptr, nil, nil), srid_copy: srid)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
211
222
|
def envelope
|
212
223
|
cast_geometry_ptr(FFIGeos.GEOSEnvelope_r(Geos.current_handle_pointer, ptr), srid_copy: srid)
|
213
224
|
end
|
@@ -302,9 +313,9 @@ module Geos
|
|
302
313
|
*T****FF*
|
303
314
|
***T**FF*
|
304
315
|
****T*FF*
|
305
|
-
}.detect
|
316
|
+
}.detect { |pattern|
|
306
317
|
relate_pattern(geom, pattern)
|
307
|
-
|
318
|
+
}
|
308
319
|
end
|
309
320
|
end
|
310
321
|
|
@@ -324,9 +335,9 @@ module Geos
|
|
324
335
|
*TF**F***
|
325
336
|
**FT*F***
|
326
337
|
**F*TF***
|
327
|
-
}.detect
|
338
|
+
}.detect { |pattern|
|
328
339
|
relate_pattern(geom, pattern)
|
329
|
-
|
340
|
+
}
|
330
341
|
end
|
331
342
|
end
|
332
343
|
|
@@ -467,6 +478,17 @@ module Geos
|
|
467
478
|
double_ptr.read_double
|
468
479
|
end
|
469
480
|
|
481
|
+
if FFIGeos.respond_to?(:GEOSDistanceIndexed_r)
|
482
|
+
# Available in GEOS 3.7+.
|
483
|
+
def distance_indexed(geom)
|
484
|
+
check_geometry(geom)
|
485
|
+
double_ptr = FFI::MemoryPointer.new(:double)
|
486
|
+
FFIGeos.GEOSDistanceIndexed_r(Geos.current_handle_pointer, ptr, geom.ptr, double_ptr)
|
487
|
+
double_ptr.read_double
|
488
|
+
end
|
489
|
+
alias indexed_distance distance_indexed
|
490
|
+
end
|
491
|
+
|
470
492
|
def hausdorff_distance(geom, densify_frac = nil)
|
471
493
|
check_geometry(geom)
|
472
494
|
|
@@ -529,20 +551,49 @@ module Geos
|
|
529
551
|
}
|
530
552
|
end
|
531
553
|
|
532
|
-
def polygonize
|
533
|
-
|
534
|
-
|
554
|
+
def polygonize(*geoms)
|
555
|
+
geoms.each do |geom|
|
556
|
+
raise ArgumentError unless geom.is_a?(Geos::Geometry)
|
557
|
+
end
|
535
558
|
|
536
|
-
|
559
|
+
ary = [ptr].concat(geoms.collect(&:ptr))
|
560
|
+
ary_ptr = FFI::MemoryPointer.new(:pointer, ary.length)
|
561
|
+
ary_ptr.write_array_of_pointer(ary)
|
562
|
+
|
563
|
+
cast_geometry_ptr(FFIGeos.GEOSPolygonize_r(Geos.current_handle_pointer, ary_ptr, ary.length), srid_copy: srid).to_a
|
564
|
+
end
|
565
|
+
|
566
|
+
if FFIGeos.respond_to?(:GEOSPolygonize_valid_r)
|
567
|
+
# Added in GEOS 3.8+
|
568
|
+
def polygonize_valid
|
569
|
+
ary = FFI::MemoryPointer.new(:pointer)
|
570
|
+
ary.write_array_of_pointer([ptr])
|
571
|
+
|
572
|
+
cast_geometry_ptr(FFIGeos.GEOSPolygonize_valid_r(Geos.current_handle_pointer, ary, 1), srid_copy: srid)
|
573
|
+
end
|
537
574
|
end
|
538
575
|
|
539
576
|
def polygonize_cut_edges
|
540
577
|
ary = FFI::MemoryPointer.new(:pointer)
|
541
|
-
ary.write_array_of_pointer([
|
578
|
+
ary.write_array_of_pointer([ptr])
|
542
579
|
|
543
580
|
cast_geometry_ptr(FFIGeos.GEOSPolygonizer_getCutEdges_r(Geos.current_handle_pointer, ary, 1), srid_copy: srid).to_a
|
544
581
|
end
|
545
582
|
|
583
|
+
if FFIGeos.respond_to?(:GEOSBuildArea_r)
|
584
|
+
# Added in GEOS 3.8+
|
585
|
+
def build_area
|
586
|
+
cast_geometry_ptr(FFIGeos.GEOSBuildArea_r(Geos.current_handle_pointer, ptr))
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
if FFIGeos.respond_to?(:GEOSMakeValid_r)
|
591
|
+
# Added in GEOS 3.8+
|
592
|
+
def make_valid
|
593
|
+
cast_geometry_ptr(FFIGeos.GEOSMakeValid_r(Geos.current_handle_pointer, ptr))
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
546
597
|
if FFIGeos.respond_to?(:GEOSDelaunayTriangulation_r)
|
547
598
|
# :call-seq:
|
548
599
|
# delaunay_triangulation(options = {})
|
@@ -46,13 +46,27 @@ module Geos
|
|
46
46
|
|
47
47
|
%w{ x y z }.each do |dimension|
|
48
48
|
%w{ max min }.each do |op|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
native_method = "GEOSGeom_get#{dimension.upcase}#{op[0].upcase}#{op[1..-1]}_r"
|
50
|
+
|
51
|
+
if FFIGeos.respond_to?(native_method)
|
52
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
53
|
+
def #{dimension}_#{op}
|
54
|
+
return if empty?
|
55
|
+
|
56
|
+
double_ptr = FFI::MemoryPointer.new(:double)
|
57
|
+
FFIGeos.#{native_method}(Geos.current_handle_pointer, ptr, double_ptr)
|
58
|
+
double_ptr.read_double
|
53
59
|
end
|
54
|
-
|
55
|
-
|
60
|
+
RUBY
|
61
|
+
else
|
62
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
63
|
+
def #{dimension}_#{op}
|
64
|
+
unless self.empty?
|
65
|
+
self.collect(&:#{dimension}_#{op}).#{op}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
RUBY
|
69
|
+
end
|
56
70
|
end
|
57
71
|
end
|
58
72
|
|
@@ -67,7 +81,7 @@ module Geos
|
|
67
81
|
trans_scale
|
68
82
|
translate
|
69
83
|
}.each do |m|
|
70
|
-
|
84
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
71
85
|
def #{m}!(*args)
|
72
86
|
unless self.empty?
|
73
87
|
self.num_geometries.times do |i|
|
@@ -83,7 +97,7 @@ module Geos
|
|
83
97
|
ret.srid = pick_srid_according_to_policy(self.srid)
|
84
98
|
ret
|
85
99
|
end
|
86
|
-
|
100
|
+
RUBY
|
87
101
|
end
|
88
102
|
end
|
89
103
|
end
|
data/lib/ffi-geos/interrupt.rb
CHANGED
@@ -25,23 +25,20 @@ module Geos
|
|
25
25
|
# collector may not play nicely with GEOS and objects may get cleaned
|
26
26
|
# up in unexpected ways while interrupts are firing.
|
27
27
|
def register(method_or_block = nil, &block)
|
28
|
-
if method_or_block.nil? && !block_given?
|
29
|
-
|
30
|
-
elsif !method_or_block.nil? && block_given?
|
31
|
-
raise ArgumentError, 'Cannot use both a method and a block for Geos::Interrupt.register'
|
32
|
-
else
|
33
|
-
retval = @current_interrupt_callback
|
28
|
+
raise ArgumentError, 'Expected either a method or a block for Geos::Interrupt.register' if method_or_block.nil? && !block_given?
|
29
|
+
raise ArgumentError, 'Cannot use both a method and a block for Geos::Interrupt.register' if !method_or_block.nil? && block_given?
|
34
30
|
|
35
|
-
|
36
|
-
FFIGeos.GEOS_interruptRegisterCallback(method_or_block)
|
37
|
-
method_or_block
|
38
|
-
elsif block_given?
|
39
|
-
FFIGeos.GEOS_interruptRegisterCallback(block)
|
40
|
-
block
|
41
|
-
end
|
31
|
+
retval = @current_interrupt_callback
|
42
32
|
|
43
|
-
|
33
|
+
@current_interrupt_callback = if method_or_block
|
34
|
+
FFIGeos.GEOS_interruptRegisterCallback(method_or_block)
|
35
|
+
method_or_block
|
36
|
+
elsif block_given?
|
37
|
+
FFIGeos.GEOS_interruptRegisterCallback(block)
|
38
|
+
block
|
44
39
|
end
|
40
|
+
|
41
|
+
retval
|
45
42
|
end
|
46
43
|
|
47
44
|
# Interrupt the current operation. This method should generally be
|
data/lib/ffi-geos/line_string.rb
CHANGED
@@ -28,7 +28,7 @@ module Geos
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def point_n(n)
|
31
|
-
raise Geos::IndexBoundsError if n
|
31
|
+
raise Geos::IndexBoundsError if n.negative? || n >= num_points
|
32
32
|
|
33
33
|
cast_geometry_ptr(FFIGeos.GEOSGeomGetPointN_r(Geos.current_handle_pointer, ptr, n), srid_copy: srid)
|
34
34
|
end
|
@@ -45,14 +45,17 @@ module Geos
|
|
45
45
|
def offset_curve(width, options = {})
|
46
46
|
options = Constants::BUFFER_PARAM_DEFAULTS.merge(options)
|
47
47
|
|
48
|
-
cast_geometry_ptr(
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
48
|
+
cast_geometry_ptr(
|
49
|
+
FFIGeos.GEOSOffsetCurve_r(
|
50
|
+
Geos.current_handle_pointer,
|
51
|
+
ptr,
|
52
|
+
width,
|
53
|
+
options[:quad_segs],
|
54
|
+
options[:join],
|
55
|
+
options[:mitre_limit]
|
56
|
+
),
|
57
|
+
srid_copy: srid
|
58
|
+
)
|
56
59
|
end
|
57
60
|
|
58
61
|
if FFIGeos.respond_to?(:GEOSisClosed_r)
|
@@ -79,13 +82,13 @@ module Geos
|
|
79
82
|
end
|
80
83
|
|
81
84
|
def snap_to_grid!(*args)
|
82
|
-
|
83
|
-
cs =
|
85
|
+
unless empty?
|
86
|
+
cs = coord_seq.snap_to_grid!(*args)
|
84
87
|
|
85
|
-
if cs.
|
86
|
-
@ptr = Geos.create_empty_line_string(:
|
88
|
+
if cs.empty?
|
89
|
+
@ptr = Geos.create_empty_line_string(srid: srid).ptr
|
87
90
|
elsif cs.length <= 1
|
88
|
-
raise Geos::InvalidGeometryError
|
91
|
+
raise Geos::InvalidGeometryError, "snap_to_grid! produced an invalid number of points in for a LineString - found #{cs.length} - must be 0 or > 1"
|
89
92
|
else
|
90
93
|
@ptr = Geos.create_line_string(cs).ptr
|
91
94
|
end
|
@@ -95,41 +98,39 @@ module Geos
|
|
95
98
|
end
|
96
99
|
|
97
100
|
def snap_to_grid(*args)
|
98
|
-
ret =
|
99
|
-
ret.srid = pick_srid_according_to_policy(
|
101
|
+
ret = dup.snap_to_grid!(*args)
|
102
|
+
ret.srid = pick_srid_according_to_policy(srid)
|
100
103
|
ret
|
101
104
|
end
|
102
105
|
|
103
106
|
def line_interpolate_point(fraction)
|
104
|
-
|
105
|
-
raise ArgumentError.new("fraction must be between 0 and 1")
|
106
|
-
end
|
107
|
+
raise ArgumentError, 'fraction must be between 0 and 1' unless fraction.between?(0, 1)
|
107
108
|
|
108
109
|
case fraction
|
109
110
|
when 0
|
110
|
-
|
111
|
+
start_point
|
111
112
|
when 1
|
112
|
-
|
113
|
+
end_point
|
113
114
|
else
|
114
115
|
length = self.length
|
115
116
|
total_length = 0
|
116
|
-
segs =
|
117
|
+
segs = num_points - 1
|
117
118
|
|
118
119
|
segs.times do |i|
|
119
|
-
|
120
|
-
|
120
|
+
p_1 = self[i]
|
121
|
+
p_2 = self[i + 1]
|
121
122
|
|
122
|
-
seg_length =
|
123
|
+
seg_length = p_1.distance(p_2) / length
|
123
124
|
|
124
125
|
if fraction < total_length + seg_length
|
125
|
-
dseg = (fraction - total_length) / seg_length
|
126
|
+
dseg = (fraction - total_length) / seg_length
|
126
127
|
|
127
128
|
args = []
|
128
|
-
args <<
|
129
|
-
args <<
|
130
|
-
args <<
|
129
|
+
args << p_1.x + ((p_2.x - p_1.x) * dseg)
|
130
|
+
args << p_1.y + ((p_2.y - p_1.y) * dseg)
|
131
|
+
args << p_1.z + ((p_2.z - p_1.z) * dseg) if has_z?
|
131
132
|
|
132
|
-
args << { :
|
133
|
+
args << { srid: pick_srid_according_to_policy(srid) } unless srid.zero?
|
133
134
|
|
134
135
|
return Geos.create_point(*args)
|
135
136
|
end
|
@@ -138,23 +139,37 @@ module Geos
|
|
138
139
|
end
|
139
140
|
|
140
141
|
# if all else fails...
|
141
|
-
|
142
|
+
end_point
|
142
143
|
end
|
143
144
|
end
|
144
|
-
|
145
|
+
alias interpolate_point line_interpolate_point
|
145
146
|
|
146
147
|
%w{ max min }.each do |op|
|
147
148
|
%w{ x y }.each do |dimension|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
149
|
+
native_method = "GEOSGeom_get#{dimension.upcase}#{op[0].upcase}#{op[1..-1]}_r"
|
150
|
+
|
151
|
+
if FFIGeos.respond_to?(native_method)
|
152
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
153
|
+
def #{dimension}_#{op}
|
154
|
+
return if empty?
|
155
|
+
|
156
|
+
double_ptr = FFI::MemoryPointer.new(:double)
|
157
|
+
FFIGeos.#{native_method}(Geos.current_handle_pointer, ptr, double_ptr)
|
158
|
+
double_ptr.read_double
|
152
159
|
end
|
153
|
-
|
154
|
-
|
160
|
+
RUBY
|
161
|
+
else
|
162
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
163
|
+
def #{dimension}_#{op}
|
164
|
+
unless self.empty?
|
165
|
+
self.coord_seq.#{dimension}_#{op}
|
166
|
+
end
|
167
|
+
end
|
168
|
+
RUBY
|
169
|
+
end
|
155
170
|
end
|
156
171
|
|
157
|
-
|
172
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
158
173
|
def z_#{op}
|
159
174
|
unless self.empty?
|
160
175
|
if self.has_z?
|
@@ -164,7 +179,7 @@ module Geos
|
|
164
179
|
end
|
165
180
|
end
|
166
181
|
end
|
167
|
-
|
182
|
+
RUBY
|
168
183
|
end
|
169
184
|
|
170
185
|
%w{
|
@@ -177,7 +192,7 @@ module Geos
|
|
177
192
|
trans_scale
|
178
193
|
translate
|
179
194
|
}.each do |m|
|
180
|
-
|
195
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
181
196
|
def #{m}!(*args)
|
182
197
|
unless self.empty?
|
183
198
|
self.coord_seq.#{m}!(*args)
|
@@ -191,7 +206,7 @@ module Geos
|
|
191
206
|
ret.srid = pick_srid_according_to_policy(self.srid)
|
192
207
|
ret
|
193
208
|
end
|
194
|
-
|
209
|
+
RUBY
|
195
210
|
end
|
196
211
|
end
|
197
212
|
end
|
data/lib/ffi-geos/point.rb
CHANGED
@@ -79,31 +79,31 @@ module Geos
|
|
79
79
|
end
|
80
80
|
|
81
81
|
def dump_points(cur_path = [])
|
82
|
-
cur_path.push(
|
82
|
+
cur_path.push(dup)
|
83
83
|
end
|
84
84
|
|
85
85
|
%w{ max min }.each do |op|
|
86
86
|
%w{ x y }.each do |dimension|
|
87
|
-
|
87
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
88
88
|
def #{dimension}_#{op}
|
89
|
-
unless
|
90
|
-
|
89
|
+
unless empty?
|
90
|
+
#{dimension}
|
91
91
|
end
|
92
92
|
end
|
93
|
-
|
93
|
+
RUBY
|
94
94
|
end
|
95
95
|
|
96
|
-
|
96
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
97
97
|
def z_#{op}
|
98
|
-
unless
|
99
|
-
if
|
100
|
-
|
98
|
+
unless empty?
|
99
|
+
if has_z?
|
100
|
+
z
|
101
101
|
else
|
102
102
|
0
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
106
|
+
RUBY
|
107
107
|
end
|
108
108
|
|
109
109
|
%w{
|
@@ -117,21 +117,21 @@ module Geos
|
|
117
117
|
trans_scale
|
118
118
|
translate
|
119
119
|
}.each do |m|
|
120
|
-
|
120
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
121
121
|
def #{m}!(*args)
|
122
|
-
unless
|
123
|
-
|
122
|
+
unless empty?
|
123
|
+
coord_seq.#{m}!(*args)
|
124
124
|
end
|
125
125
|
|
126
126
|
self
|
127
127
|
end
|
128
128
|
|
129
129
|
def #{m}(*args)
|
130
|
-
ret =
|
131
|
-
ret.srid = pick_srid_according_to_policy(
|
130
|
+
ret = dup.#{m}!(*args)
|
131
|
+
ret.srid = pick_srid_according_to_policy(srid)
|
132
132
|
ret
|
133
133
|
end
|
134
|
-
|
134
|
+
RUBY
|
135
135
|
end
|
136
136
|
end
|
137
137
|
end
|