ffi-geos 1.2.2 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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