ffi-geos 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- if respond_to?(:unary_union)
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 do |pattern|
316
+ }.detect { |pattern|
306
317
  relate_pattern(geom, pattern)
307
- end
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 do |pattern|
338
+ }.detect { |pattern|
328
339
  relate_pattern(geom, pattern)
329
- end
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
- ary = FFI::MemoryPointer.new(:pointer)
534
- ary.write_array_of_pointer([ ptr ])
554
+ def polygonize(*geoms)
555
+ geoms.each do |geom|
556
+ raise ArgumentError unless geom.is_a?(Geos::Geometry)
557
+ end
535
558
 
536
- cast_geometry_ptr(FFIGeos.GEOSPolygonize_r(Geos.current_handle_pointer, ary, 1), srid_copy: srid).to_a
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([ ptr ])
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
- 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,7 +81,7 @@ module Geos
67
81
  trans_scale
68
82
  translate
69
83
  }.each do |m|
70
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
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
- 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
@@ -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(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)
@@ -79,13 +82,13 @@ module Geos
79
82
  end
80
83
 
81
84
  def snap_to_grid!(*args)
82
- if !self.empty?
83
- cs = self.coord_seq.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
@@ -95,41 +98,39 @@ module Geos
95
98
  end
96
99
 
97
100
  def snap_to_grid(*args)
98
- ret = self.dup.snap_to_grid!(*args)
99
- ret.srid = pick_srid_according_to_policy(self.srid)
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,7 +192,7 @@ module Geos
177
192
  trans_scale
178
193
  translate
179
194
  }.each do |m|
180
- self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
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
- EOF
209
+ RUBY
195
210
  end
196
211
  end
197
212
  end
@@ -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)
120
+ class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
121
121
  def #{m}!(*args)
122
- unless self.empty?
123
- self.coord_seq.#{m}!(*args)
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 = self.dup.#{m}!(*args)
131
- ret.srid = pick_srid_according_to_policy(self.srid)
130
+ ret = dup.#{m}!(*args)
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