rgeo 3.0.0.pre.rc.3 → 3.0.1

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -3
  3. data/ext/geos_c_impl/extconf.rb +1 -0
  4. data/ext/geos_c_impl/factory.c +43 -5
  5. data/ext/geos_c_impl/factory.h +13 -2
  6. data/ext/geos_c_impl/geometry.c +178 -122
  7. data/ext/geos_c_impl/geometry_collection.c +17 -19
  8. data/ext/geos_c_impl/line_string.c +46 -36
  9. data/ext/geos_c_impl/point.c +0 -2
  10. data/ext/geos_c_impl/polygon.c +10 -11
  11. data/ext/geos_c_impl/polygon.h +1 -1
  12. data/ext/geos_c_impl/preface.h +3 -0
  13. data/ext/geos_c_impl/ruby_more.c +7 -0
  14. data/ext/geos_c_impl/ruby_more.h +8 -0
  15. data/lib/rgeo/cartesian/analysis.rb +5 -3
  16. data/lib/rgeo/cartesian/bounding_box.rb +74 -79
  17. data/lib/rgeo/cartesian/calculations.rb +20 -26
  18. data/lib/rgeo/cartesian/factory.rb +47 -49
  19. data/lib/rgeo/cartesian/planar_graph.rb +10 -16
  20. data/lib/rgeo/cartesian/sweepline_intersector.rb +1 -3
  21. data/lib/rgeo/cartesian/valid_op.rb +1 -3
  22. data/lib/rgeo/coord_sys/cs/entities.rb +91 -101
  23. data/lib/rgeo/coord_sys/cs/factories.rb +0 -2
  24. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +70 -29
  25. data/lib/rgeo/feature/curve.rb +0 -1
  26. data/lib/rgeo/feature/factory.rb +25 -27
  27. data/lib/rgeo/feature/factory_generator.rb +3 -4
  28. data/lib/rgeo/feature/geometry.rb +41 -30
  29. data/lib/rgeo/feature/geometry_collection.rb +3 -4
  30. data/lib/rgeo/feature/line_string.rb +1 -2
  31. data/lib/rgeo/feature/linear_ring.rb +0 -1
  32. data/lib/rgeo/feature/multi_curve.rb +0 -1
  33. data/lib/rgeo/feature/multi_surface.rb +0 -1
  34. data/lib/rgeo/feature/point.rb +0 -1
  35. data/lib/rgeo/feature/polygon.rb +1 -2
  36. data/lib/rgeo/feature/surface.rb +0 -1
  37. data/lib/rgeo/feature/types.rb +69 -85
  38. data/lib/rgeo/geographic/factory.rb +87 -80
  39. data/lib/rgeo/geographic/interface.rb +44 -27
  40. data/lib/rgeo/geographic/projected_feature_methods.rb +2 -6
  41. data/lib/rgeo/geographic/projected_window.rb +35 -21
  42. data/lib/rgeo/geographic/simple_mercator_projector.rb +27 -15
  43. data/lib/rgeo/geographic/spherical_feature_methods.rb +8 -3
  44. data/lib/rgeo/geographic/spherical_math.rb +17 -20
  45. data/lib/rgeo/geos/capi_factory.rb +50 -50
  46. data/lib/rgeo/geos/ffi_factory.rb +50 -49
  47. data/lib/rgeo/geos/ffi_feature_methods.rb +72 -98
  48. data/lib/rgeo/geos/interface.rb +16 -16
  49. data/lib/rgeo/geos/utils.rb +5 -5
  50. data/lib/rgeo/geos/zm_factory.rb +50 -42
  51. data/lib/rgeo/geos/zm_feature_methods.rb +15 -9
  52. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +4 -4
  53. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -2
  54. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +18 -24
  55. data/lib/rgeo/impl_helper/basic_point_methods.rb +1 -3
  56. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +15 -16
  57. data/lib/rgeo/impl_helper/utils.rb +3 -9
  58. data/lib/rgeo/impl_helper/valid_op.rb +12 -16
  59. data/lib/rgeo/version.rb +1 -1
  60. data/lib/rgeo/wkrep/wkb_generator.rb +42 -47
  61. data/lib/rgeo/wkrep/wkb_parser.rb +17 -18
  62. data/lib/rgeo/wkrep/wkt_generator.rb +23 -16
  63. data/lib/rgeo/wkrep/wkt_parser.rb +23 -13
  64. metadata +6 -6
@@ -9,11 +9,22 @@
9
9
  module RGeo
10
10
  module Geos
11
11
  # This the FFI-GEOS implementation of RGeo::Feature::Factory.
12
-
13
12
  class FFIFactory
14
13
  include Feature::Factory::Instance
15
14
  include ImplHelper::Utils
16
15
 
16
+ attr_reader :coordinate_dimension, :spatial_dimension, :_has_3d, :_auto_prepare
17
+
18
+ # Returns the SRID of geometries created by this factory.
19
+ attr_reader :srid
20
+
21
+ # Returns the resolution used by buffer calculations on geometries
22
+ # created by this factory
23
+ attr_reader :buffer_resolution
24
+
25
+ # See RGeo::Feature::Factory#coord_sys
26
+ attr_reader :coord_sys
27
+
17
28
  # Create a new factory. Returns nil if the FFI-GEOS implementation
18
29
  # is not supported.
19
30
  #
@@ -22,9 +33,11 @@ module RGeo
22
33
  def initialize(opts = {})
23
34
  @has_z = opts[:has_z_coordinate] ? true : false
24
35
  @has_m = opts[:has_m_coordinate] ? true : false
36
+
25
37
  if @has_z && @has_m
26
38
  raise Error::UnsupportedOperation, "GEOS cannot support both Z and M coordinates at the same time."
27
39
  end
40
+
28
41
  @coordinate_dimension = 2
29
42
  @coordinate_dimension += 1 if @has_z
30
43
  @coordinate_dimension += 1 if @has_m
@@ -43,6 +56,7 @@ module RGeo
43
56
  @wkt_writer = nil
44
57
  else
45
58
  @wkt_writer = ::Geos::WktWriter.new
59
+ @wkt_writer.output_dimensions = 2
46
60
  @wkt_writer.trim = true
47
61
  @wkt_generator = nil
48
62
  end
@@ -53,6 +67,7 @@ module RGeo
53
67
  @wkb_writer = nil
54
68
  else
55
69
  @wkb_writer = ::Geos::WkbWriter.new
70
+ @wkb_writer.output_dimensions = 2
56
71
  @wkb_generator = nil
57
72
  end
58
73
 
@@ -81,7 +96,6 @@ module RGeo
81
96
  @wkb_parser = nil
82
97
  end
83
98
  end
84
- attr_reader :coordinate_dimension, :spatial_dimension
85
99
 
86
100
  # Standard object inspection output
87
101
 
@@ -91,12 +105,12 @@ module RGeo
91
105
 
92
106
  # Factory equivalence test.
93
107
 
94
- def eql?(rhs)
95
- rhs.is_a?(self.class) && @srid == rhs.srid &&
96
- @has_z == rhs.property(:has_z_coordinate) &&
97
- @has_m == rhs.property(:has_m_coordinate) &&
98
- @buffer_resolution == rhs.property(:buffer_resolution) &&
99
- @coord_sys.eql?(rhs.coord_sys)
108
+ def eql?(other)
109
+ other.is_a?(self.class) && @srid == other.srid &&
110
+ @has_z == other.property(:has_z_coordinate) &&
111
+ @has_m == other.property(:has_m_coordinate) &&
112
+ @buffer_resolution == other.property(:buffer_resolution) &&
113
+ @coord_sys.eql?(other.coord_sys)
100
114
  end
101
115
  alias == eql?
102
116
 
@@ -125,11 +139,9 @@ module RGeo
125
139
  end
126
140
 
127
141
  def marshal_load(data) # :nodoc:
128
- if (coord_sys_data = data["cs"])
129
- coord_sys = CoordSys::CONFIG.default_coord_sys_class.create_from_wkt(coord_sys_data)
130
- else
131
- coord_sys = nil
132
- end
142
+ cs_class = CoordSys::CONFIG.default_coord_sys_class
143
+ coord_sys = data["cs"]&.then { |cs| cs_class.create_from_wkt(cs) }
144
+
133
145
  initialize(
134
146
  has_z_coordinate: data["hasz"],
135
147
  has_m_coordinate: data["hasm"],
@@ -160,11 +172,9 @@ module RGeo
160
172
  end
161
173
 
162
174
  def init_with(coder) # :nodoc:
163
- if (coord_sys_data = coder["cs"])
164
- coord_sys = CoordSys::CONFIG.default_coord_sys_class.create_from_wkt(coord_sys_data.to_s)
165
- else
166
- coord_sys = nil
167
- end
175
+ cs_class = CoordSys::CONFIG.default_coord_sys_class
176
+ coord_sys = coder["cs"]&.then { |cs| cs_class.create_from_wkt(cs) }
177
+
168
178
  initialize(
169
179
  has_z_coordinate: coder["has_z_coordinate"],
170
180
  has_m_coordinate: coder["has_m_coordinate"],
@@ -179,15 +189,6 @@ module RGeo
179
189
  )
180
190
  end
181
191
 
182
- # Returns the SRID of geometries created by this factory.
183
-
184
- attr_reader :srid
185
-
186
- # Returns the resolution used by buffer calculations on geometries
187
- # created by this factory
188
-
189
- attr_reader :buffer_resolution
190
-
191
192
  # See RGeo::Feature::Factory#property
192
193
  def property(name_)
193
194
  case name_
@@ -296,10 +297,8 @@ module RGeo
296
297
  inner_rings = inner_rings.to_a unless inner_rings.is_a?(Array)
297
298
  return unless RGeo::Feature::LineString.check_type(outer_ring)
298
299
  outer_ring = create_fg_linear_ring(outer_ring.points)
299
- inner_rings = inner_rings.map do |r|
300
- return unless RGeo::Feature::LineString.check_type(r)
301
- create_fg_linear_ring(r.points)
302
- end
300
+ return unless inner_rings.all? { |r| RGeo::Feature::LineString.check_type(r) }
301
+ inner_rings = inner_rings.map { |r| create_fg_linear_ring(r.points) }
303
302
  inner_rings.compact!
304
303
  fg_geom = ::Geos::Utils.create_polygon(outer_ring, *inner_rings)
305
304
  FFIPolygonImpl.new(self, fg_geom, nil)
@@ -328,11 +327,16 @@ module RGeo
328
327
  def multi_point(elems)
329
328
  elems = elems.to_a unless elems.is_a?(Array)
330
329
  elems = elems.map do |elem|
331
- elem = RGeo::Feature.cast(elem, self, RGeo::Feature::Point,
332
- :force_new, :keep_subtype)
333
- return unless elem
334
- elem.detach_fg_geom
330
+ RGeo::Feature.cast(
331
+ elem,
332
+ self,
333
+ RGeo::Feature::Point,
334
+ :force_new,
335
+ :keep_subtype
336
+ )
335
337
  end
338
+ return unless elems.all?
339
+ elems = elems.map(&:detach_fg_geom)
336
340
  klasses = Array.new(elems.size, FFIPointImpl)
337
341
  fg_geom = ::Geos::Utils.create_collection(::Geos::GeomTypes::GEOS_MULTIPOINT, elems)
338
342
  FFIMultiPointImpl.new(self, fg_geom, klasses)
@@ -367,13 +371,9 @@ module RGeo
367
371
  FFIMultiPolygonImpl.new(self, fg_geom, klasses)
368
372
  end
369
373
 
370
- # See RGeo::Feature::Factory#coord_sys
371
-
372
- attr_reader :coord_sys
373
-
374
374
  # See RGeo::Feature::Factory#override_cast
375
375
 
376
- def override_cast(original, ntype, flags)
376
+ def override_cast(_original, _ntype, _flags)
377
377
  false
378
378
  # TODO
379
379
  end
@@ -421,14 +421,13 @@ module RGeo
421
421
  klass.new(self, fg_geom, klasses)
422
422
  end
423
423
 
424
- attr_reader :_has_3d # :nodoc:
425
- attr_reader :_auto_prepare # :nodoc:
426
-
427
424
  def convert_to_fg_geometry(obj, type = nil)
428
- if type && obj.factory != self
429
- obj = Feature.cast(obj, self, type)
430
- end
431
- obj&.fg_geom
425
+ obj = Feature.cast(obj, self, type) if type && obj.factory != self
426
+
427
+ geom = obj&.fg_geom
428
+ raise RGeo::Error::InvalidGeometry, "Unable to cast the geometry to the FFI Factory" if geom.nil?
429
+
430
+ geom
432
431
  end
433
432
 
434
433
  def generate_wkt(geom)
@@ -450,6 +449,7 @@ module RGeo
450
449
  def write_for_marshal(geom)
451
450
  if Utils.ffi_supports_set_output_dimension || !@_has_3d
452
451
  wkb_writer = ::Geos::WkbWriter.new
452
+ wkb_writer.output_dimensions = 2
453
453
  wkb_writer.output_dimensions = 3 if @_has_3d
454
454
  wkb_writer.write(geom.fg_geom)
455
455
  else
@@ -464,6 +464,7 @@ module RGeo
464
464
  def write_for_psych(geom)
465
465
  if Utils.ffi_supports_set_output_dimension || !@_has_3d
466
466
  wkt_writer = ::Geos::WktWriter.new
467
+ wkt_writer.output_dimensions = 2
467
468
  wkt_writer.trim = true
468
469
  wkt_writer.output_dimensions = 3 if @_has_3d
469
470
  wkt_writer.write(geom.fg_geom)
@@ -480,14 +481,14 @@ module RGeo
480
481
 
481
482
  def create_fg_linear_ring(points)
482
483
  size = points.size
483
- return if size == 1 || size == 2
484
+ return if size.between?(1, 2)
484
485
  if size > 0 && points.first != points.last
485
486
  points += [points.first]
486
487
  size += 1
487
488
  end
488
489
  cs = ::Geos::CoordinateSequence.new(size, 3)
490
+ return unless points.all? { |p| RGeo::Feature::Point.check_type(p) }
489
491
  points.each_with_index do |p, i|
490
- return unless RGeo::Feature::Point.check_type(p)
491
492
  cs.set_x(i, p.x)
492
493
  cs.set_y(i, p.y)
493
494
  if @has_z
@@ -13,6 +13,8 @@ module RGeo
13
13
  module FFIGeometryMethods # :nodoc:
14
14
  include Feature::Instance
15
15
 
16
+ attr_reader :factory, :fg_geom, :_klasses
17
+
16
18
  def initialize(factory, fg_geom, klasses)
17
19
  @factory = factory
18
20
  @fg_geom = fg_geom
@@ -56,11 +58,6 @@ module RGeo
56
58
  @_klasses = nil
57
59
  end
58
60
 
59
- attr_reader :factory
60
- attr_reader :fg_geom
61
-
62
- attr_reader :_klasses # :nodoc:
63
-
64
61
  def initialize_copy(orig)
65
62
  @factory = orig.factory
66
63
  @fg_geom = orig.fg_geom.clone
@@ -94,9 +91,7 @@ module RGeo
94
91
  end
95
92
 
96
93
  def prepare!
97
- if @_fg_prep.is_a?(Integer)
98
- @_fg_prep = ::Geos::PreparedGeometry.new(@fg_geom)
99
- end
94
+ @_fg_prep = ::Geos::PreparedGeometry.new(@fg_geom) if @_fg_prep.is_a?(Integer)
100
95
  self
101
96
  end
102
97
 
@@ -149,20 +144,21 @@ module RGeo
149
144
 
150
145
  # (see RGeo::ImplHelper::ValidityCheck#make_valid)
151
146
  # Only available since GEOS 3.8+
152
- def make_valid
153
- @factory.wrap_fg_geom(@fg_geom.make_valid, nil)
154
- rescue ::Geos::GEOSException
155
- raise Error::UnsupportedOperation
156
- end if ::Geos::FFIGeos.respond_to?(:GEOSMakeValid_r)
147
+ if ::Geos::FFIGeos.respond_to?(:GEOSMakeValid_r)
148
+ def make_valid
149
+ @factory.wrap_fg_geom(@fg_geom.make_valid, nil)
150
+ rescue ::Geos::GEOSException
151
+ raise Error::UnsupportedOperation
152
+ end
153
+ end
157
154
 
158
155
  def equals?(rhs)
159
156
  return false unless rhs.is_a?(RGeo::Feature::Instance)
160
157
  fg = factory.convert_to_fg_geometry(rhs)
161
- if !fg
162
- false
158
+
163
159
  # GEOS has a bug where empty geometries are not spatially equal
164
160
  # to each other. Work around this case first.
165
- elsif fg.empty? && @fg_geom.empty?
161
+ if fg.empty? && @fg_geom.empty?
166
162
  true
167
163
  else
168
164
  @fg_geom.eql?(fg)
@@ -172,83 +168,54 @@ module RGeo
172
168
 
173
169
  def disjoint?(rhs)
174
170
  fg = factory.convert_to_fg_geometry(rhs)
175
- if fg
176
- prep = request_prepared if Utils.ffi_supports_prepared_level_2
177
- prep ? prep.disjoint?(fg) : @fg_geom.disjoint?(fg)
178
- else
179
- false
180
- end
171
+ prep = request_prepared if Utils.ffi_supports_prepared_level2
172
+ prep ? prep.disjoint?(fg) : @fg_geom.disjoint?(fg)
181
173
  end
182
174
 
183
175
  def intersects?(rhs)
184
176
  fg = factory.convert_to_fg_geometry(rhs)
185
- if fg
186
- prep = request_prepared if Utils.ffi_supports_prepared_level_1
187
- prep ? prep.intersects?(fg) : @fg_geom.intersects?(fg)
188
- else
189
- false
190
- end
177
+ prep = request_prepared if Utils.ffi_supports_prepared_level1
178
+ prep ? prep.intersects?(fg) : @fg_geom.intersects?(fg)
191
179
  end
192
180
 
193
181
  def touches?(rhs)
194
182
  fg = factory.convert_to_fg_geometry(rhs)
195
- if fg
196
- prep = request_prepared if Utils.ffi_supports_prepared_level_2
197
- prep ? prep.touches?(fg) : @fg_geom.touches?(fg)
198
- else
199
- false
200
- end
183
+ prep = request_prepared if Utils.ffi_supports_prepared_level2
184
+ prep ? prep.touches?(fg) : @fg_geom.touches?(fg)
201
185
  end
202
186
 
203
187
  def crosses?(rhs)
204
188
  fg = factory.convert_to_fg_geometry(rhs)
205
- if fg
206
- prep = request_prepared if Utils.ffi_supports_prepared_level_2
207
- prep ? prep.crosses?(fg) : @fg_geom.crosses?(fg)
208
- else
209
- false
210
- end
189
+ prep = request_prepared if Utils.ffi_supports_prepared_level2
190
+ prep ? prep.crosses?(fg) : @fg_geom.crosses?(fg)
211
191
  end
212
192
 
213
193
  def within?(rhs)
214
194
  fg = factory.convert_to_fg_geometry(rhs)
215
- if fg
216
- prep = request_prepared if Utils.ffi_supports_prepared_level_2
217
- prep ? prep.within?(fg) : @fg_geom.within?(fg)
218
- else
219
- false
220
- end
195
+ prep = request_prepared if Utils.ffi_supports_prepared_level2
196
+ prep ? prep.within?(fg) : @fg_geom.within?(fg)
221
197
  end
222
198
 
223
199
  def contains?(rhs)
224
200
  fg = factory.convert_to_fg_geometry(rhs)
225
- if fg
226
- prep = request_prepared if Utils.ffi_supports_prepared_level_1
227
- prep ? prep.contains?(fg) : @fg_geom.contains?(fg)
228
- else
229
- false
230
- end
201
+ prep = request_prepared if Utils.ffi_supports_prepared_level1
202
+ prep ? prep.contains?(fg) : @fg_geom.contains?(fg)
231
203
  end
232
204
 
233
205
  def overlaps?(rhs)
234
206
  fg = factory.convert_to_fg_geometry(rhs)
235
- if fg
236
- prep = request_prepared if Utils.ffi_supports_prepared_level_2
237
- prep ? prep.overlaps?(fg) : @fg_geom.overlaps?(fg)
238
- else
239
- false
240
- end
207
+ prep = request_prepared if Utils.ffi_supports_prepared_level2
208
+ prep ? prep.overlaps?(fg) : @fg_geom.overlaps?(fg)
241
209
  end
242
210
 
243
211
  def relate?(rhs, pattern)
244
212
  fg = factory.convert_to_fg_geometry(rhs)
245
- fg ? @fg_geom.relate_pattern(fg, pattern) : nil
213
+ @fg_geom.relate_pattern(fg, pattern)
246
214
  end
247
- alias relate relate? # DEPRECATED
248
215
 
249
216
  def distance(rhs)
250
217
  fg = factory.convert_to_fg_geometry(rhs)
251
- fg ? @fg_geom.distance(fg) : nil
218
+ @fg_geom.distance(fg)
252
219
  end
253
220
 
254
221
  def buffer(distance)
@@ -261,14 +228,14 @@ module RGeo
261
228
 
262
229
  def intersection(rhs)
263
230
  fg = factory.convert_to_fg_geometry(rhs)
264
- fg ? @factory.wrap_fg_geom(@fg_geom.intersection(fg), nil) : nil
231
+ @factory.wrap_fg_geom(@fg_geom.intersection(fg), nil)
265
232
  end
266
233
 
267
234
  alias * intersection
268
235
 
269
236
  def union(rhs)
270
237
  fg = factory.convert_to_fg_geometry(rhs)
271
- fg ? @factory.wrap_fg_geom(@fg_geom.union(fg), nil) : nil
238
+ @factory.wrap_fg_geom(@fg_geom.union(fg), nil)
272
239
  end
273
240
 
274
241
  alias + union
@@ -280,18 +247,18 @@ module RGeo
280
247
 
281
248
  def difference(rhs)
282
249
  fg = factory.convert_to_fg_geometry(rhs)
283
- fg ? @factory.wrap_fg_geom(@fg_geom.difference(fg), nil) : nil
250
+ @factory.wrap_fg_geom(@fg_geom.difference(fg), nil)
284
251
  end
285
252
 
286
253
  alias - difference
287
254
 
288
255
  def sym_difference(rhs)
289
256
  fg = factory.convert_to_fg_geometry(rhs)
290
- fg ? @factory.wrap_fg_geom(@fg_geom.sym_difference(fg), nil) : nil
257
+ @factory.wrap_fg_geom(@fg_geom.sym_difference(fg), nil)
291
258
  end
292
259
 
293
- def eql?(rhs)
294
- rep_equals?(rhs)
260
+ def eql?(other)
261
+ rep_equals?(other)
295
262
  end
296
263
 
297
264
  def detach_fg_geom
@@ -343,7 +310,7 @@ module RGeo
343
310
  end
344
311
 
345
312
  def rep_equals?(rhs)
346
- rhs.class == self.class && rhs.factory.eql?(@factory) &&
313
+ rhs.instance_of?(self.class) && rhs.factory.eql?(@factory) &&
347
314
  Utils.ffi_coord_seqs_equal?(rhs.fg_geom.coord_seq, @fg_geom.coord_seq, @factory._has_3d)
348
315
  end
349
316
 
@@ -372,14 +339,15 @@ module RGeo
372
339
  @fg_geom.num_points
373
340
  end
374
341
 
375
- def point_n(n)
376
- if n >= 0 && n < @fg_geom.num_points
377
- coord_seq = @fg_geom.coord_seq
378
- x = coord_seq.get_x(n)
379
- y = coord_seq.get_y(n)
380
- extra = @factory._has_3d ? [coord_seq.get_z(n)] : []
381
- @factory.point(x, y, *extra)
382
- end
342
+ def point_n(idx)
343
+ return unless idx >= 0 && idx < @fg_geom.num_points
344
+
345
+ coord_seq = @fg_geom.coord_seq
346
+ x = coord_seq.get_x(idx)
347
+ y = coord_seq.get_y(idx)
348
+ extra = @factory._has_3d ? [coord_seq.get_z(idx)] : []
349
+
350
+ @factory.point(x, y, *extra)
383
351
  end
384
352
 
385
353
  def start_point
@@ -410,7 +378,7 @@ module RGeo
410
378
  end
411
379
 
412
380
  def rep_equals?(rhs)
413
- rhs.class == self.class && rhs.factory.eql?(@factory) &&
381
+ rhs.instance_of?(self.class) && rhs.factory.eql?(@factory) &&
414
382
  Utils.ffi_coord_seqs_equal?(rhs.fg_geom.coord_seq, @fg_geom.coord_seq, @factory._has_3d)
415
383
  end
416
384
 
@@ -464,10 +432,10 @@ module RGeo
464
432
  @fg_geom.num_interior_rings
465
433
  end
466
434
 
467
- def interior_ring_n(n)
468
- if n >= 0 && n < @fg_geom.num_interior_rings
469
- @factory.wrap_fg_geom(@fg_geom.interior_ring_n(n), FFILinearRingImpl)
470
- end
435
+ def interior_ring_n(idx)
436
+ return unless idx >= 0 && idx < @fg_geom.num_interior_rings
437
+
438
+ @factory.wrap_fg_geom(@fg_geom.interior_ring_n(idx), FFILinearRingImpl)
471
439
  end
472
440
 
473
441
  def interior_rings
@@ -477,7 +445,7 @@ module RGeo
477
445
  end
478
446
 
479
447
  def rep_equals?(rhs)
480
- if rhs.class == self.class && rhs.factory.eql?(@factory) &&
448
+ if rhs.instance_of?(self.class) && rhs.factory.eql?(@factory) &&
481
449
  rhs.exterior_ring.rep_equals?(exterior_ring)
482
450
  sn = @fg_geom.num_interior_rings
483
451
  rn = rhs.num_interior_rings
@@ -493,8 +461,10 @@ module RGeo
493
461
 
494
462
  def hash
495
463
  @hash ||= begin
496
- hash = Utils.ffi_coord_seq_hash(@fg_geom.exterior_ring.coord_seq,
497
- [@factory, geometry_type].hash)
464
+ hash = Utils.ffi_coord_seq_hash(
465
+ @fg_geom.exterior_ring.coord_seq,
466
+ [@factory, geometry_type].hash
467
+ )
498
468
  @fg_geom.interior_rings.inject(hash) do |h, r|
499
469
  Utils.ffi_coord_seq_hash(r.coord_seq, h)
500
470
  end
@@ -512,7 +482,7 @@ module RGeo
512
482
  end
513
483
 
514
484
  def rep_equals?(rhs)
515
- if rhs.class == self.class && rhs.factory.eql?(@factory)
485
+ if rhs.instance_of?(self.class) && rhs.factory.eql?(@factory)
516
486
  size = @fg_geom.num_geometries
517
487
  if size == rhs.num_geometries
518
488
  size.times do |n|
@@ -529,19 +499,24 @@ module RGeo
529
499
  end
530
500
  alias size num_geometries
531
501
 
532
- def geometry_n(n)
533
- if n >= 0 && n < @fg_geom.num_geometries
534
- @factory.wrap_fg_geom(@fg_geom.get_geometry_n(n),
535
- @_klasses ? @_klasses[n] : nil)
536
- end
502
+ def geometry_n(idx)
503
+ return unless idx >= 0 && idx < @fg_geom.num_geometries
504
+
505
+ @factory.wrap_fg_geom(
506
+ @fg_geom.get_geometry_n(idx),
507
+ @_klasses ? @_klasses[idx] : nil
508
+ )
537
509
  end
538
510
 
539
- def [](n)
540
- n += @fg_geom.num_geometries if n < 0
541
- if n >= 0 && n < @fg_geom.num_geometries
542
- @factory.wrap_fg_geom(@fg_geom.get_geometry_n(n),
543
- @_klasses ? @_klasses[n] : nil)
544
- end
511
+ def [](idx)
512
+ idx += @fg_geom.num_geometries if idx < 0
513
+
514
+ return unless idx >= 0 && idx < @fg_geom.num_geometries
515
+
516
+ @factory.wrap_fg_geom(
517
+ @fg_geom.get_geometry_n(idx),
518
+ @_klasses ? @_klasses[idx] : nil
519
+ )
545
520
  end
546
521
 
547
522
  def hash
@@ -551,8 +526,7 @@ module RGeo
551
526
  def each
552
527
  if block_given?
553
528
  @fg_geom.num_geometries.times do |n|
554
- yield @factory.wrap_fg_geom(@fg_geom.get_geometry_n(n),
555
- @_klasses ? @_klasses[n] : nil)
529
+ yield @factory.wrap_fg_geom(@fg_geom.get_geometry_n(n), @_klasses ? @_klasses[n] : nil)
556
530
  end
557
531
  self
558
532
  else
@@ -62,13 +62,12 @@ module RGeo
62
62
 
63
63
  def version
64
64
  unless defined?(@version)
65
- if RGeo::Geos::CAPI_SUPPORTED
66
- @version = RGeo::Geos::CAPIFactory._geos_version.freeze
67
- elsif RGeo::Geos::FFI_SUPPORTED
68
- @version = ::Geos::FFIGeos.GEOSversion.sub(/-CAPI-.*$/, "").freeze
69
- else
70
- @version = nil
71
- end
65
+ @version =
66
+ if RGeo::Geos::CAPI_SUPPORTED
67
+ RGeo::Geos::CAPIFactory._geos_version.freeze
68
+ elsif RGeo::Geos::FFI_SUPPORTED
69
+ ::Geos::FFIGeos.GEOSversion.sub(/-CAPI-.*$/, "").freeze
70
+ end
72
71
  end
73
72
  @version
74
73
  end
@@ -163,15 +162,16 @@ module RGeo
163
162
  # never automatically generates a prepared geometry (unless you
164
163
  # generate one explicitly using the <tt>prepare!</tt> method).
165
164
  def factory(opts = {})
166
- if supported?
167
- native_interface = opts[:native_interface] || Geos.preferred_native_interface
168
- if opts[:has_z_coordinate] && opts[:has_m_coordinate]
169
- ZMFactory.new(opts)
170
- elsif native_interface == :ffi
171
- FFIFactory.new(opts)
172
- else
173
- CAPIFactory.create(opts)
174
- end
165
+ return unless supported?
166
+
167
+ native_interface = opts[:native_interface] || Geos.preferred_native_interface
168
+
169
+ if opts[:has_z_coordinate] && opts[:has_m_coordinate]
170
+ ZMFactory.new(opts)
171
+ elsif native_interface == :ffi
172
+ FFIFactory.new(opts)
173
+ else
174
+ CAPIFactory.create(opts)
175
175
  end
176
176
  end
177
177
  end
@@ -49,17 +49,17 @@ module RGeo
49
49
  result
50
50
  end
51
51
 
52
- def ffi_coord_seq_hash(cs, hash = 0)
53
- (0...cs.length).inject(hash) do |h, i|
54
- [hash, cs.get_x(i), cs.get_y(i), cs.get_z(i)].hash
52
+ def ffi_coord_seq_hash(coord_seq, init_hash = 0)
53
+ (0...coord_seq.length).inject(init_hash) do |hash, i|
54
+ [hash, coord_seq.get_x(i), coord_seq.get_y(i), coord_seq.get_z(i)].hash
55
55
  end
56
56
  end
57
57
 
58
- def ffi_supports_prepared_level_1
58
+ def ffi_supports_prepared_level1
59
59
  FFI_SUPPORTED && ::Geos::FFIGeos.respond_to?(:GEOSPreparedContains_r)
60
60
  end
61
61
 
62
- def ffi_supports_prepared_level_2
62
+ def ffi_supports_prepared_level2
63
63
  FFI_SUPPORTED && ::Geos::FFIGeos.respond_to?(:GEOSPreparedDisjoint_r)
64
64
  end
65
65