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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +49 -0
  3. data/.rubocop.yml +5117 -4
  4. data/FUNDING.yml +2 -0
  5. data/Gemfile +9 -16
  6. data/Guardfile +3 -4
  7. data/MIT-LICENSE +1 -1
  8. data/README.rdoc +2 -20
  9. data/Rakefile +3 -2
  10. data/ffi-geos.gemspec +7 -2
  11. data/lib/ffi-geos/buffer_params.rb +1 -1
  12. data/lib/ffi-geos/coordinate_sequence.rb +179 -177
  13. data/lib/ffi-geos/geometry.rb +118 -31
  14. data/lib/ffi-geos/geometry_collection.rb +26 -12
  15. data/lib/ffi-geos/interrupt.rb +11 -14
  16. data/lib/ffi-geos/line_string.rb +64 -49
  17. data/lib/ffi-geos/multi_line_string.rb +1 -1
  18. data/lib/ffi-geos/point.rb +18 -18
  19. data/lib/ffi-geos/polygon.rb +44 -30
  20. data/lib/ffi-geos/prepared_geometry.rb +1 -1
  21. data/lib/ffi-geos/strtree.rb +28 -30
  22. data/lib/ffi-geos/tools.rb +1 -1
  23. data/lib/ffi-geos/utils.rb +16 -23
  24. data/lib/ffi-geos/version.rb +1 -1
  25. data/lib/ffi-geos/wkb_reader.rb +1 -1
  26. data/lib/ffi-geos/wkb_writer.rb +4 -5
  27. data/lib/ffi-geos/wkt_reader.rb +1 -1
  28. data/lib/ffi-geos/wkt_writer.rb +7 -13
  29. data/lib/ffi-geos.rb +134 -48
  30. data/sonar-project.properties +16 -0
  31. data/test/coordinate_sequence_tests.rb +148 -126
  32. data/test/geometry_collection_tests.rb +41 -67
  33. data/test/geometry_tests.rb +341 -40
  34. data/test/interrupt_tests.rb +7 -7
  35. data/test/line_string_tests.rb +23 -15
  36. data/test/point_tests.rb +5 -5
  37. data/test/polygon_tests.rb +6 -7
  38. data/test/prepared_geometry_tests.rb +8 -8
  39. data/test/strtree_tests.rb +13 -12
  40. data/test/test_helper.rb +74 -56
  41. data/test/utils_tests.rb +69 -59
  42. data/test/wkb_reader_tests.rb +9 -9
  43. data/test/wkb_writer_tests.rb +14 -12
  44. data/test/wkt_reader_tests.rb +0 -1
  45. data/test/wkt_writer_tests.rb +2 -5
  46. metadata +12 -10
  47. data/.travis.yml +0 -21
@@ -38,7 +38,7 @@ module Geos
38
38
  self.srid = source.srid
39
39
  end
40
40
 
41
- def self.release(ptr) #:nodoc:
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
- cast_geometry_ptr(FFIGeos.GEOSIntersection_r(Geos.current_handle_pointer, ptr, geom.ptr), srid_copy: pick_srid_from_geoms(srid, geom.srid))
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
- cast_geometry_ptr(FFIGeos.GEOSDifference_r(Geos.current_handle_pointer, ptr, geom.ptr), srid_copy: pick_srid_from_geoms(srid, geom.srid))
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
- cast_geometry_ptr(FFIGeos.GEOSSymDifference_r(Geos.current_handle_pointer, ptr, geom.ptr), srid_copy: pick_srid_from_geoms(srid, geom.srid))
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
- cast_geometry_ptr(FFIGeos.GEOSUnion_r(Geos.current_handle_pointer, ptr, geom.ptr), srid_copy: pick_srid_from_geoms(srid, geom.srid))
166
- else
167
- if respond_to?(:unary_union)
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
- union_cascaded
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
- cast_geometry_ptr(FFIGeos.GEOSUnaryUnion_r(Geos.current_handle_pointer, ptr), srid_copy: srid)
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) #:nodoc:
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 do |pattern|
340
+ }.detect { |pattern|
306
341
  relate_pattern(geom, pattern)
307
- end
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) #:nodoc:
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 do |pattern|
362
+ }.detect { |pattern|
328
363
  relate_pattern(geom, pattern)
329
- end
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::GEOS_VERSION >= '3.3.0'
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
- ary = FFI::MemoryPointer.new(:pointer)
534
- ary.write_array_of_pointer([ ptr ])
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
- cast_geometry_ptr(FFIGeos.GEOSPolygonize_r(Geos.current_handle_pointer, ary, 1), srid_copy: srid).to_a
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([ ptr ])
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
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
50
- def #{dimension}_#{op}
51
- unless self.empty?
52
- self.collect(&:#{dimension}_#{op}).#{op}
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
- end
55
- EOF
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
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
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
- EOF
100
+ RUBY
87
101
  end
88
102
  end
89
103
  end
@@ -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
- raise ArgumentError, 'Expected either a method or a block for Geos::Interrupt.register'
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
- @current_interrupt_callback = if method_or_block
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
- retval
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
@@ -28,7 +28,7 @@ module Geos
28
28
  end
29
29
 
30
30
  def point_n(n)
31
- raise Geos::IndexBoundsError if n < 0 || n >= num_points
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(FFIGeos.GEOSOffsetCurve_r(
49
- Geos.current_handle_pointer,
50
- ptr,
51
- width,
52
- options[:quad_segs],
53
- options[:join],
54
- options[:mitre_limit]
55
- ), srid_copy: srid)
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
- if !self.empty?
83
- cs = self.coord_seq.snap_to_grid!(*args)
84
+ def snap_to_grid!(*args, **)
85
+ unless empty?
86
+ cs = coord_seq.snap_to_grid!(*args)
84
87
 
85
- if cs.length == 0
86
- @ptr = Geos.create_empty_line_string(:srid => self.srid).ptr
88
+ if cs.empty?
89
+ @ptr = Geos.create_empty_line_string(srid: srid).ptr
87
90
  elsif cs.length <= 1
88
- raise Geos::InvalidGeometryError.new("snap_to_grid! produced an invalid number of points in for a LineString - found #{cs.length} - must be 0 or > 1")
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 = self.dup.snap_to_grid!(*args)
99
- ret.srid = pick_srid_according_to_policy(self.srid)
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
- if !fraction.between?(0, 1)
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
- self.start_point
111
+ start_point
111
112
  when 1
112
- self.end_point
113
+ end_point
113
114
  else
114
115
  length = self.length
115
116
  total_length = 0
116
- segs = self.num_points - 1
117
+ segs = num_points - 1
117
118
 
118
119
  segs.times do |i|
119
- p1 = self[i]
120
- p2 = self[i + 1]
120
+ p_1 = self[i]
121
+ p_2 = self[i + 1]
121
122
 
122
- seg_length = p1.distance(p2) / 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 << p1.x + ((p2.x - p1.x) * dseg)
129
- args << p1.y + ((p2.y - p1.y) * dseg)
130
- args << p1.z + ((p2.z - p1.z) * dseg) if self.has_z?
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 << { :srid => pick_srid_according_to_policy(self.srid) } unless self.srid == 0
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
- self.end_point
142
+ end_point
142
143
  end
143
144
  end
144
- alias_method :interpolate_point, :line_interpolate_point
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
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
149
- def #{dimension}_#{op}
150
- unless self.empty?
151
- self.coord_seq.#{dimension}_#{op}
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
- end
154
- EOF
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
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
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
- EOF
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
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
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
- EOF
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::GEOS_VERSION >= '3.5.0'
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))
@@ -79,31 +79,31 @@ module Geos
79
79
  end
80
80
 
81
81
  def dump_points(cur_path = [])
82
- cur_path.push(self.dup)
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
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
87
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
88
88
  def #{dimension}_#{op}
89
- unless self.empty?
90
- self.#{dimension}
89
+ unless empty?
90
+ #{dimension}
91
91
  end
92
92
  end
93
- EOF
93
+ RUBY
94
94
  end
95
95
 
96
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
96
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
97
97
  def z_#{op}
98
- unless self.empty?
99
- if self.has_z?
100
- self.z
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
- EOF
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
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
121
- def #{m}!(*args)
122
- unless self.empty?
123
- self.coord_seq.#{m}!(*args)
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 = self.dup.#{m}!(*args)
131
- ret.srid = pick_srid_according_to_policy(self.srid)
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
- EOF
134
+ RUBY
135
135
  end
136
136
  end
137
137
  end