ffi-geos 1.2.2 → 2.3.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/.github/workflows/main.yml +49 -0
- data/.rubocop.yml +5117 -4
- data/FUNDING.yml +2 -0
- data/Gemfile +9 -16
- data/Guardfile +3 -4
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -20
- data/Rakefile +3 -2
- data/ffi-geos.gemspec +7 -2
- data/lib/ffi-geos/buffer_params.rb +1 -1
- data/lib/ffi-geos/coordinate_sequence.rb +179 -177
- data/lib/ffi-geos/geometry.rb +118 -31
- data/lib/ffi-geos/geometry_collection.rb +26 -12
- data/lib/ffi-geos/interrupt.rb +11 -14
- data/lib/ffi-geos/line_string.rb +64 -49
- data/lib/ffi-geos/multi_line_string.rb +1 -1
- data/lib/ffi-geos/point.rb +18 -18
- data/lib/ffi-geos/polygon.rb +44 -30
- data/lib/ffi-geos/prepared_geometry.rb +1 -1
- data/lib/ffi-geos/strtree.rb +28 -30
- data/lib/ffi-geos/tools.rb +1 -1
- data/lib/ffi-geos/utils.rb +16 -23
- data/lib/ffi-geos/version.rb +1 -1
- data/lib/ffi-geos/wkb_reader.rb +1 -1
- data/lib/ffi-geos/wkb_writer.rb +4 -5
- data/lib/ffi-geos/wkt_reader.rb +1 -1
- data/lib/ffi-geos/wkt_writer.rb +7 -13
- data/lib/ffi-geos.rb +134 -48
- data/sonar-project.properties +16 -0
- data/test/coordinate_sequence_tests.rb +148 -126
- data/test/geometry_collection_tests.rb +41 -67
- data/test/geometry_tests.rb +341 -40
- data/test/interrupt_tests.rb +7 -7
- data/test/line_string_tests.rb +23 -15
- data/test/point_tests.rb +5 -5
- data/test/polygon_tests.rb +6 -7
- data/test/prepared_geometry_tests.rb +8 -8
- data/test/strtree_tests.rb +13 -12
- data/test/test_helper.rb +74 -56
- 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 +12 -10
- data/.travis.yml +0 -21
data/lib/ffi-geos/geometry.rb
CHANGED
@@ -38,7 +38,7 @@ module Geos
|
|
38
38
|
self.srid = source.srid
|
39
39
|
end
|
40
40
|
|
41
|
-
def self.release(ptr)
|
41
|
+
def self.release(ptr) # :nodoc:
|
42
42
|
FFIGeos.GEOSGeom_destroy_r(Geos.current_handle_pointer, ptr)
|
43
43
|
end
|
44
44
|
|
@@ -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
|
@@ -85,9 +83,14 @@ module Geos
|
|
85
83
|
CoordinateSequence.new(FFIGeos.GEOSGeom_getCoordSeq_r(Geos.current_handle_pointer, ptr), false, self)
|
86
84
|
end
|
87
85
|
|
88
|
-
def intersection(geom)
|
86
|
+
def intersection(geom, precision: nil)
|
89
87
|
check_geometry(geom)
|
90
|
-
|
88
|
+
|
89
|
+
if precision
|
90
|
+
cast_geometry_ptr(FFIGeos.GEOSIntersectionPrec_r(Geos.current_handle_pointer, ptr, geom.ptr, precision), srid_copy: pick_srid_from_geoms(srid, geom.srid))
|
91
|
+
else
|
92
|
+
cast_geometry_ptr(FFIGeos.GEOSIntersection_r(Geos.current_handle_pointer, ptr, geom.ptr), srid_copy: pick_srid_from_geoms(srid, geom.srid))
|
93
|
+
end
|
91
94
|
end
|
92
95
|
|
93
96
|
if FFIGeos.respond_to?(:GEOSBufferWithParams_r)
|
@@ -141,14 +144,24 @@ module Geos
|
|
141
144
|
cast_geometry_ptr(FFIGeos.GEOSConvexHull_r(Geos.current_handle_pointer, ptr), srid_copy: srid)
|
142
145
|
end
|
143
146
|
|
144
|
-
def difference(geom)
|
147
|
+
def difference(geom, precision: nil)
|
145
148
|
check_geometry(geom)
|
146
|
-
|
149
|
+
|
150
|
+
if precision
|
151
|
+
cast_geometry_ptr(FFIGeos.GEOSDifferencePrec_r(Geos.current_handle_pointer, ptr, geom.ptr, precision), srid_copy: pick_srid_from_geoms(srid, geom.srid))
|
152
|
+
else
|
153
|
+
cast_geometry_ptr(FFIGeos.GEOSDifference_r(Geos.current_handle_pointer, ptr, geom.ptr), srid_copy: pick_srid_from_geoms(srid, geom.srid))
|
154
|
+
end
|
147
155
|
end
|
148
156
|
|
149
|
-
def sym_difference(geom)
|
157
|
+
def sym_difference(geom, precision: nil)
|
150
158
|
check_geometry(geom)
|
151
|
-
|
159
|
+
|
160
|
+
if precision
|
161
|
+
cast_geometry_ptr(FFIGeos.GEOSSymDifferencePrec_r(Geos.current_handle_pointer, ptr, geom.ptr, precision), srid_copy: pick_srid_from_geoms(srid, geom.srid))
|
162
|
+
else
|
163
|
+
cast_geometry_ptr(FFIGeos.GEOSSymDifference_r(Geos.current_handle_pointer, ptr, geom.ptr), srid_copy: pick_srid_from_geoms(srid, geom.srid))
|
164
|
+
end
|
152
165
|
end
|
153
166
|
alias symmetric_difference sym_difference
|
154
167
|
|
@@ -159,16 +172,19 @@ module Geos
|
|
159
172
|
# Calling without a geom argument is equivalent to calling unary_union when
|
160
173
|
# using GEOS 3.3+ and is equivalent to calling union_cascaded in older
|
161
174
|
# versions.
|
162
|
-
def union(geom = nil)
|
175
|
+
def union(geom = nil, precision: nil)
|
163
176
|
if geom
|
164
177
|
check_geometry(geom)
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
unary_union
|
178
|
+
|
179
|
+
if precision
|
180
|
+
cast_geometry_ptr(FFIGeos.GEOSUnionPrec_r(Geos.current_handle_pointer, ptr, geom.ptr, precision), srid_copy: pick_srid_from_geoms(srid, geom.srid))
|
169
181
|
else
|
170
|
-
|
182
|
+
cast_geometry_ptr(FFIGeos.GEOSUnion_r(Geos.current_handle_pointer, ptr, geom.ptr), srid_copy: pick_srid_from_geoms(srid, geom.srid))
|
171
183
|
end
|
184
|
+
elsif respond_to?(:unary_union)
|
185
|
+
unary_union
|
186
|
+
else
|
187
|
+
union_cascaded
|
172
188
|
end
|
173
189
|
end
|
174
190
|
|
@@ -176,10 +192,21 @@ module Geos
|
|
176
192
|
cast_geometry_ptr(FFIGeos.GEOSUnionCascaded_r(Geos.current_handle_pointer, ptr), srid_copy: srid)
|
177
193
|
end
|
178
194
|
|
195
|
+
if FFIGeos.respond_to?(:GEOSCoverageUnion_r)
|
196
|
+
# Added in GEOS 3.8+
|
197
|
+
def coverage_union
|
198
|
+
cast_geometry_ptr(FFIGeos.GEOSCoverageUnion_r(Geos.current_handle_pointer, ptr), srid_copy: srid)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
179
202
|
if FFIGeos.respond_to?(:GEOSUnaryUnion_r)
|
180
203
|
# Available in GEOS 3.3+
|
181
|
-
def unary_union
|
182
|
-
|
204
|
+
def unary_union(precision = nil)
|
205
|
+
if precision
|
206
|
+
cast_geometry_ptr(FFIGeos.GEOSUnaryUnionPrec_r(Geos.current_handle_pointer, ptr, precision), srid_copy: srid)
|
207
|
+
else
|
208
|
+
cast_geometry_ptr(FFIGeos.GEOSUnaryUnion_r(Geos.current_handle_pointer, ptr), srid_copy: srid)
|
209
|
+
end
|
183
210
|
end
|
184
211
|
end
|
185
212
|
|
@@ -208,6 +235,14 @@ module Geos
|
|
208
235
|
end
|
209
236
|
alias center centroid
|
210
237
|
|
238
|
+
if FFIGeos.respond_to?(:GEOSMinimumBoundingCircle_r)
|
239
|
+
# Added in GEOS 3.8+. Does not yet support the radius or center
|
240
|
+
# arguments.
|
241
|
+
def minimum_bounding_circle
|
242
|
+
cast_geometry_ptr(FFIGeos.GEOSMinimumBoundingCircle_r(Geos.current_handle_pointer, ptr, nil, nil), srid_copy: srid)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
211
246
|
def envelope
|
212
247
|
cast_geometry_ptr(FFIGeos.GEOSEnvelope_r(Geos.current_handle_pointer, ptr), srid_copy: srid)
|
213
248
|
end
|
@@ -295,16 +330,16 @@ module Geos
|
|
295
330
|
bool_result(FFIGeos.GEOSCovers_r(Geos.current_handle_pointer, ptr, geom.ptr))
|
296
331
|
end
|
297
332
|
else
|
298
|
-
def covers?(geom)
|
333
|
+
def covers?(geom) # :nodoc:
|
299
334
|
check_geometry(geom)
|
300
335
|
!!%w{
|
301
336
|
T*****FF*
|
302
337
|
*T****FF*
|
303
338
|
***T**FF*
|
304
339
|
****T*FF*
|
305
|
-
}.detect
|
340
|
+
}.detect { |pattern|
|
306
341
|
relate_pattern(geom, pattern)
|
307
|
-
|
342
|
+
}
|
308
343
|
end
|
309
344
|
end
|
310
345
|
|
@@ -317,16 +352,16 @@ module Geos
|
|
317
352
|
bool_result(FFIGeos.GEOSCoveredBy_r(Geos.current_handle_pointer, ptr, geom.ptr))
|
318
353
|
end
|
319
354
|
else
|
320
|
-
def covered_by?(geom)
|
355
|
+
def covered_by?(geom) # :nodoc:
|
321
356
|
check_geometry(geom)
|
322
357
|
!!%w{
|
323
358
|
T*F**F***
|
324
359
|
*TF**F***
|
325
360
|
**FT*F***
|
326
361
|
**F*TF***
|
327
|
-
}.detect
|
362
|
+
}.detect { |pattern|
|
328
363
|
relate_pattern(geom, pattern)
|
329
|
-
|
364
|
+
}
|
330
365
|
end
|
331
366
|
end
|
332
367
|
|
@@ -351,7 +386,7 @@ module Geos
|
|
351
386
|
|
352
387
|
def eql_almost?(other, decimal = 6)
|
353
388
|
check_geometry(other)
|
354
|
-
bool_result(FFIGeos.GEOSEqualsExact_r(Geos.current_handle_pointer, ptr, other.ptr, 0.5 * 10 ** -decimal))
|
389
|
+
bool_result(FFIGeos.GEOSEqualsExact_r(Geos.current_handle_pointer, ptr, other.ptr, 0.5 * (10 ** -decimal)))
|
355
390
|
end
|
356
391
|
alias equals_almost? eql_almost?
|
357
392
|
alias almost_equals? eql_almost?
|
@@ -406,7 +441,7 @@ module Geos
|
|
406
441
|
|
407
442
|
# GEOS versions prior to 3.3.0 didn't handle exceptions and can crash on
|
408
443
|
# bad input.
|
409
|
-
if FFIGeos.respond_to?(:GEOSProject_r) && Geos::
|
444
|
+
if FFIGeos.respond_to?(:GEOSProject_r) && Geos::GEOS_NICE_VERSION >= '030300'
|
410
445
|
def project(geom, normalized = false)
|
411
446
|
raise TypeError, 'Expected Geos::Point type' unless geom.is_a?(Geos::Point)
|
412
447
|
|
@@ -467,6 +502,17 @@ module Geos
|
|
467
502
|
double_ptr.read_double
|
468
503
|
end
|
469
504
|
|
505
|
+
if FFIGeos.respond_to?(:GEOSDistanceIndexed_r)
|
506
|
+
# Available in GEOS 3.7+.
|
507
|
+
def distance_indexed(geom)
|
508
|
+
check_geometry(geom)
|
509
|
+
double_ptr = FFI::MemoryPointer.new(:double)
|
510
|
+
FFIGeos.GEOSDistanceIndexed_r(Geos.current_handle_pointer, ptr, geom.ptr, double_ptr)
|
511
|
+
double_ptr.read_double
|
512
|
+
end
|
513
|
+
alias indexed_distance distance_indexed
|
514
|
+
end
|
515
|
+
|
470
516
|
def hausdorff_distance(geom, densify_frac = nil)
|
471
517
|
check_geometry(geom)
|
472
518
|
|
@@ -529,20 +575,49 @@ module Geos
|
|
529
575
|
}
|
530
576
|
end
|
531
577
|
|
532
|
-
def polygonize
|
533
|
-
|
534
|
-
|
578
|
+
def polygonize(*geoms)
|
579
|
+
geoms.each do |geom|
|
580
|
+
raise ArgumentError unless geom.is_a?(Geos::Geometry)
|
581
|
+
end
|
582
|
+
|
583
|
+
ary = [ptr].concat(geoms.collect(&:ptr))
|
584
|
+
ary_ptr = FFI::MemoryPointer.new(:pointer, ary.length)
|
585
|
+
ary_ptr.write_array_of_pointer(ary)
|
586
|
+
|
587
|
+
cast_geometry_ptr(FFIGeos.GEOSPolygonize_r(Geos.current_handle_pointer, ary_ptr, ary.length), srid_copy: srid).to_a
|
588
|
+
end
|
589
|
+
|
590
|
+
if FFIGeos.respond_to?(:GEOSPolygonize_valid_r)
|
591
|
+
# Added in GEOS 3.8+
|
592
|
+
def polygonize_valid
|
593
|
+
ary = FFI::MemoryPointer.new(:pointer)
|
594
|
+
ary.write_array_of_pointer([ptr])
|
535
595
|
|
536
|
-
|
596
|
+
cast_geometry_ptr(FFIGeos.GEOSPolygonize_valid_r(Geos.current_handle_pointer, ary, 1), srid_copy: srid)
|
597
|
+
end
|
537
598
|
end
|
538
599
|
|
539
600
|
def polygonize_cut_edges
|
540
601
|
ary = FFI::MemoryPointer.new(:pointer)
|
541
|
-
ary.write_array_of_pointer([
|
602
|
+
ary.write_array_of_pointer([ptr])
|
542
603
|
|
543
604
|
cast_geometry_ptr(FFIGeos.GEOSPolygonizer_getCutEdges_r(Geos.current_handle_pointer, ary, 1), srid_copy: srid).to_a
|
544
605
|
end
|
545
606
|
|
607
|
+
if FFIGeos.respond_to?(:GEOSBuildArea_r)
|
608
|
+
# Added in GEOS 3.8+
|
609
|
+
def build_area
|
610
|
+
cast_geometry_ptr(FFIGeos.GEOSBuildArea_r(Geos.current_handle_pointer, ptr))
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
if FFIGeos.respond_to?(:GEOSMakeValid_r)
|
615
|
+
# Added in GEOS 3.8+
|
616
|
+
def make_valid
|
617
|
+
cast_geometry_ptr(FFIGeos.GEOSMakeValid_r(Geos.current_handle_pointer, ptr))
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
546
621
|
if FFIGeos.respond_to?(:GEOSDelaunayTriangulation_r)
|
547
622
|
# :call-seq:
|
548
623
|
# delaunay_triangulation(options = {})
|
@@ -644,6 +719,18 @@ module Geos
|
|
644
719
|
end
|
645
720
|
end
|
646
721
|
|
722
|
+
if FFIGeos.respond_to?(:GEOSMaximumInscribedCircle_r)
|
723
|
+
def maximum_inscribed_circle(precision)
|
724
|
+
cast_geometry_ptr(FFIGeos.GEOSMaximumInscribedCircle_r(Geos.current_handle_pointer, ptr, precision))
|
725
|
+
end
|
726
|
+
end
|
727
|
+
|
728
|
+
if FFIGeos.respond_to?(:GEOSLargestEmptyCircle_r)
|
729
|
+
def largest_empty_circle(precision, boundary: nil)
|
730
|
+
cast_geometry_ptr(FFIGeos.GEOSLargestEmptyCircle_r(Geos.current_handle_pointer, ptr, boundary ? boundary.ptr : nil, precision))
|
731
|
+
end
|
732
|
+
end
|
733
|
+
|
647
734
|
if FFIGeos.respond_to?(:GEOSMinimumWidth_r)
|
648
735
|
def minimum_width
|
649
736
|
cast_geometry_ptr(FFIGeos.GEOSMinimumWidth_r(Geos.current_handle_pointer, ptr))
|
@@ -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,23 +81,23 @@ module Geos
|
|
67
81
|
trans_scale
|
68
82
|
translate
|
69
83
|
}.each do |m|
|
70
|
-
|
71
|
-
def #{m}!(*args)
|
84
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
85
|
+
def #{m}!(*args, **kwargs)
|
72
86
|
unless self.empty?
|
73
87
|
self.num_geometries.times do |i|
|
74
|
-
self[i].#{m}!(*args)
|
88
|
+
self[i].#{m}!(*args, **kwargs)
|
75
89
|
end
|
76
90
|
end
|
77
91
|
|
78
92
|
self
|
79
93
|
end
|
80
94
|
|
81
|
-
def #{m}(*args)
|
82
|
-
ret = self.dup.#{m}!(*args)
|
95
|
+
def #{m}(*args, **kwargs)
|
96
|
+
ret = self.dup.#{m}!(*args, **kwargs)
|
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
|
@@ -42,17 +42,20 @@ module Geos
|
|
42
42
|
end
|
43
43
|
alias slice []
|
44
44
|
|
45
|
-
def offset_curve(width, options
|
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)
|
@@ -78,14 +81,14 @@ module Geos
|
|
78
81
|
cur_path.concat(to_a)
|
79
82
|
end
|
80
83
|
|
81
|
-
def snap_to_grid!(*args)
|
82
|
-
|
83
|
-
cs =
|
84
|
+
def snap_to_grid!(*args, **)
|
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
|
@@ -94,42 +97,40 @@ module Geos
|
|
94
97
|
self
|
95
98
|
end
|
96
99
|
|
97
|
-
def snap_to_grid(*args)
|
98
|
-
ret =
|
99
|
-
ret.srid = pick_srid_according_to_policy(
|
100
|
+
def snap_to_grid(*args, **)
|
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,21 +192,21 @@ module Geos
|
|
177
192
|
trans_scale
|
178
193
|
translate
|
179
194
|
}.each do |m|
|
180
|
-
|
181
|
-
def #{m}!(*args)
|
195
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
196
|
+
def #{m}!(*args, **kwargs)
|
182
197
|
unless self.empty?
|
183
|
-
self.coord_seq.#{m}!(*args)
|
198
|
+
self.coord_seq.#{m}!(*args, **kwargs)
|
184
199
|
end
|
185
200
|
|
186
201
|
self
|
187
202
|
end
|
188
203
|
|
189
|
-
def #{m}(*args)
|
190
|
-
ret = self.dup.#{m}!(*args)
|
204
|
+
def #{m}(*args, **kwargs)
|
205
|
+
ret = self.dup.#{m}!(*args, **kwargs)
|
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
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Geos
|
4
4
|
class MultiLineString < GeometryCollection
|
5
|
-
if FFIGeos.respond_to?(:GEOSisClosed_r) && Geos::
|
5
|
+
if FFIGeos.respond_to?(:GEOSisClosed_r) && Geos::GEOS_NICE_VERSION >= '030500'
|
6
6
|
# Available in GEOS 3.5.0+.
|
7
7
|
def closed?
|
8
8
|
bool_result(FFIGeos.GEOSisClosed_r(Geos.current_handle_pointer, ptr))
|
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
|
-
|
121
|
-
def #{m}!(*args)
|
122
|
-
unless
|
123
|
-
|
120
|
+
class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
|
121
|
+
def #{m}!(*args, **kwargs)
|
122
|
+
unless empty?
|
123
|
+
coord_seq.#{m}!(*args, **kwargs)
|
124
124
|
end
|
125
125
|
|
126
126
|
self
|
127
127
|
end
|
128
128
|
|
129
|
-
def #{m}(*args)
|
130
|
-
ret =
|
131
|
-
ret.srid = pick_srid_according_to_policy(
|
129
|
+
def #{m}(*args, **kwargs)
|
130
|
+
ret = dup.#{m}!(*args, **kwargs)
|
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
|