rgeo 2.3.0 → 3.0.0.pre.rc.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -0
  3. data/README.md +1 -0
  4. data/ext/geos_c_impl/analysis.c +8 -6
  5. data/ext/geos_c_impl/analysis.h +1 -3
  6. data/ext/geos_c_impl/errors.c +10 -8
  7. data/ext/geos_c_impl/errors.h +7 -3
  8. data/ext/geos_c_impl/extconf.rb +3 -0
  9. data/ext/geos_c_impl/factory.c +251 -182
  10. data/ext/geos_c_impl/factory.h +43 -62
  11. data/ext/geos_c_impl/geometry.c +56 -24
  12. data/ext/geos_c_impl/geometry.h +8 -3
  13. data/ext/geos_c_impl/geometry_collection.c +41 -148
  14. data/ext/geos_c_impl/geometry_collection.h +1 -14
  15. data/ext/geos_c_impl/globals.c +91 -0
  16. data/ext/geos_c_impl/globals.h +45 -0
  17. data/ext/geos_c_impl/line_string.c +28 -29
  18. data/ext/geos_c_impl/line_string.h +1 -3
  19. data/ext/geos_c_impl/main.c +10 -9
  20. data/ext/geos_c_impl/point.c +9 -8
  21. data/ext/geos_c_impl/point.h +1 -3
  22. data/ext/geos_c_impl/polygon.c +15 -51
  23. data/ext/geos_c_impl/polygon.h +1 -3
  24. data/ext/geos_c_impl/preface.h +8 -0
  25. data/lib/rgeo/cartesian/analysis.rb +2 -2
  26. data/lib/rgeo/cartesian/calculations.rb +54 -17
  27. data/lib/rgeo/cartesian/factory.rb +0 -7
  28. data/lib/rgeo/cartesian/feature_classes.rb +66 -46
  29. data/lib/rgeo/cartesian/feature_methods.rb +56 -20
  30. data/lib/rgeo/cartesian/interface.rb +0 -6
  31. data/lib/rgeo/cartesian/planar_graph.rb +379 -0
  32. data/lib/rgeo/cartesian/sweepline_intersector.rb +149 -0
  33. data/lib/rgeo/cartesian/valid_op.rb +71 -0
  34. data/lib/rgeo/cartesian.rb +3 -0
  35. data/lib/rgeo/coord_sys/cs/wkt_parser.rb +6 -6
  36. data/lib/rgeo/error.rb +15 -0
  37. data/lib/rgeo/feature/curve.rb +12 -2
  38. data/lib/rgeo/feature/geometry.rb +38 -28
  39. data/lib/rgeo/feature/geometry_collection.rb +13 -5
  40. data/lib/rgeo/feature/line_string.rb +3 -3
  41. data/lib/rgeo/feature/multi_curve.rb +6 -1
  42. data/lib/rgeo/feature/multi_surface.rb +3 -3
  43. data/lib/rgeo/feature/point.rb +4 -4
  44. data/lib/rgeo/feature/surface.rb +3 -3
  45. data/lib/rgeo/geographic/factory.rb +0 -7
  46. data/lib/rgeo/geographic/interface.rb +4 -18
  47. data/lib/rgeo/geographic/proj4_projector.rb +0 -2
  48. data/lib/rgeo/geographic/projected_feature_classes.rb +21 -9
  49. data/lib/rgeo/geographic/projected_feature_methods.rb +63 -30
  50. data/lib/rgeo/geographic/simple_mercator_projector.rb +0 -2
  51. data/lib/rgeo/geographic/spherical_feature_classes.rb +29 -9
  52. data/lib/rgeo/geographic/spherical_feature_methods.rb +68 -2
  53. data/lib/rgeo/geos/capi_factory.rb +21 -31
  54. data/lib/rgeo/geos/capi_feature_classes.rb +64 -11
  55. data/lib/rgeo/geos/ffi_factory.rb +0 -28
  56. data/lib/rgeo/geos/ffi_feature_classes.rb +34 -10
  57. data/lib/rgeo/geos/ffi_feature_methods.rb +53 -10
  58. data/lib/rgeo/geos/interface.rb +18 -10
  59. data/lib/rgeo/geos/zm_factory.rb +0 -12
  60. data/lib/rgeo/geos/zm_feature_methods.rb +30 -5
  61. data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +18 -8
  62. data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -1
  63. data/lib/rgeo/impl_helper/basic_line_string_methods.rb +37 -26
  64. data/lib/rgeo/impl_helper/basic_point_methods.rb +13 -3
  65. data/lib/rgeo/impl_helper/basic_polygon_methods.rb +8 -3
  66. data/lib/rgeo/impl_helper/valid_op.rb +354 -0
  67. data/lib/rgeo/impl_helper/validity_check.rb +138 -0
  68. data/lib/rgeo/impl_helper.rb +1 -0
  69. data/lib/rgeo/version.rb +1 -1
  70. data/lib/rgeo/wkrep/wkb_generator.rb +1 -1
  71. data/lib/rgeo/wkrep/wkt_generator.rb +6 -6
  72. metadata +30 -7
@@ -79,7 +79,8 @@ module RGeo
79
79
 
80
80
  private
81
81
 
82
- def validate_geometry
82
+ # Ensure coordinates fall within a valid range.
83
+ def init_geometry
83
84
  if @x < -180.0 || @x > 180.0
84
85
  @x = @x % 360.0
85
86
  @x -= 360.0 if @x > 180.0
@@ -97,7 +98,7 @@ module RGeo
97
98
  end
98
99
  end
99
100
 
100
- def is_simple?
101
+ def simple?
101
102
  len = arcs.length
102
103
  return false if arcs.any?(&:degenerate?)
103
104
  return true if len == 1
@@ -120,9 +121,74 @@ module RGeo
120
121
  true
121
122
  end
122
123
 
124
+ def is_simple?
125
+ warn "The is_simple? method is deprecated, please use the simple? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
126
+ simple?
127
+ end
128
+
123
129
  def length
124
130
  arcs.inject(0.0) { |sum, arc| sum + arc.length } * SphericalMath::RADIUS
125
131
  end
132
+
133
+ def intersects?(rhs)
134
+ case rhs
135
+ when Feature::LineString
136
+ intersects_line_string?(rhs)
137
+ else
138
+ super
139
+ end
140
+ end
141
+
142
+ def crosses?(rhs)
143
+ case rhs
144
+ when Feature::LineString
145
+ crosses_line_string?(rhs)
146
+ else
147
+ super
148
+ end
149
+ end
150
+
151
+ private
152
+
153
+ # TODO: replace with better algorithm (https://github.com/rgeo/rgeo/issues/274)
154
+ # Very simple algorithm to determine if 2 LineStrings intersect.
155
+ # Uses a nested for loop to look at each arc in the LineStrings and
156
+ # check if each arc intersects.
157
+ #
158
+ # @param [RGeo::Geographic::SphericalLineStringImpl] rhs
159
+ #
160
+ # @return [Boolean]
161
+ def intersects_line_string?(rhs)
162
+ arcs.each do |arc|
163
+ rhs.arcs.each do |rhs_arc|
164
+ return true if arc.intersects_arc?(rhs_arc)
165
+ end
166
+ end
167
+
168
+ false
169
+ end
170
+
171
+ # TODO: replace with better algorithm (https://github.com/rgeo/rgeo/issues/274)
172
+ # Very simple algorithm to determine if 2 LineStrings cross.
173
+ # Uses a nested for loop to look at each arc in the LineStrings and
174
+ # check if each arc crosses.
175
+ #
176
+ # @param [RGeo::Geographic::SphericalLineStringImpl] rhs
177
+ #
178
+ # @return [Boolean]
179
+ def crosses_line_string?(rhs)
180
+ arcs.each do |arc|
181
+ rhs.arcs.each do |rhs_arc|
182
+ next unless arc.intersects_arc?(rhs_arc)
183
+
184
+ # check that endpoints aren't the intersection point
185
+ is_endpoint = arc.contains_point?(rhs_arc.s) || arc.contains_point?(rhs_arc.e) || rhs_arc.contains_point?(arc.s) || rhs_arc.contains_point?(arc.e)
186
+ return true unless is_endpoint
187
+ end
188
+ end
189
+
190
+ false
191
+ end
126
192
  end
127
193
 
128
194
  module SphericalMultiLineStringMethods # :nodoc:
@@ -26,7 +26,6 @@ module RGeo
26
26
 
27
27
  # Get flags to pass to the C extension
28
28
  flags = 0
29
- flags |= 1 if opts_[:uses_lenient_assertions] || opts_[:lenient_multi_polygon_assertions] || opts_[:uses_lenient_multi_polygon_assertions]
30
29
  flags |= 2 if opts_[:has_z_coordinate]
31
30
  flags |= 4 if opts_[:has_m_coordinate]
32
31
  if flags & 6 == 6
@@ -137,16 +136,15 @@ module RGeo
137
136
 
138
137
  def marshal_dump # :nodoc:
139
138
  hash_ = {
140
- "hasz" => (_flags & 0x2 != 0),
141
- "hasm" => (_flags & 0x4 != 0),
139
+ "hasz" => supports_z?,
140
+ "hasm" => supports_m?,
142
141
  "srid" => _srid,
143
142
  "bufr" => _buffer_resolution,
144
143
  "wktg" => _wkt_generator ? _wkt_generator.properties : {},
145
144
  "wkbg" => _wkb_generator ? _wkb_generator.properties : {},
146
145
  "wktp" => _wkt_parser ? _wkt_parser.properties : {},
147
146
  "wkbp" => _wkb_parser ? _wkb_parser.properties : {},
148
- "lmpa" => (_flags & 0x1 != 0),
149
- "apre" => ((_flags & 0x8) >> 3)
147
+ "apre" => auto_prepare
150
148
  }
151
149
  if (proj4_ = _proj4)
152
150
  hash_["proj4"] = proj4_.marshal_dump
@@ -179,8 +177,7 @@ module RGeo
179
177
  wkb_generator: symbolize_hash(data_["wkbg"]),
180
178
  wkt_parser: symbolize_hash(data_["wktp"]),
181
179
  wkb_parser: symbolize_hash(data_["wkbp"]),
182
- uses_lenient_multi_polygon_assertions: data_["lmpa"],
183
- auto_prepare: (data_["apre"] == 0 ? :disabled : :simple),
180
+ auto_prepare: data_["apre"],
184
181
  proj4: proj4_,
185
182
  coord_sys: coord_sys_
186
183
  )
@@ -190,16 +187,15 @@ module RGeo
190
187
  # Psych support
191
188
 
192
189
  def encode_with(coder_) # :nodoc:
193
- coder_["has_z_coordinate"] = (_flags & 0x2 != 0)
194
- coder_["has_m_coordinate"] = (_flags & 0x4 != 0)
190
+ coder_["has_z_coordinate"] = supports_z?
191
+ coder_["has_m_coordinate"] = supports_m?
195
192
  coder_["srid"] = _srid
196
193
  coder_["buffer_resolution"] = _buffer_resolution
197
- coder_["lenient_multi_polygon_assertions"] = (_flags & 0x1 != 0)
198
194
  coder_["wkt_generator"] = _wkt_generator ? _wkt_generator.properties : {}
199
195
  coder_["wkb_generator"] = _wkb_generator ? _wkb_generator.properties : {}
200
196
  coder_["wkt_parser"] = _wkt_parser ? _wkt_parser.properties : {}
201
197
  coder_["wkb_parser"] = _wkb_parser ? _wkb_parser.properties : {}
202
- coder_["auto_prepare"] = ((_flags & 0x8) == 0 ? "disabled" : "simple")
198
+ coder_["auto_prepare"] = auto_prepare
203
199
  if (proj4_ = _proj4)
204
200
  str_ = proj4_.original_str || proj4_.canonical_str
205
201
  coder_["proj4"] = proj4_.radians? ? { "proj4" => str_, "radians" => true } : str_
@@ -236,7 +232,6 @@ module RGeo
236
232
  wkt_parser: symbolize_hash(coder_["wkt_parser"]),
237
233
  wkb_parser: symbolize_hash(coder_["wkb_parser"]),
238
234
  auto_prepare: coder_["auto_prepare"] == "disabled" ? :disabled : :simple,
239
- uses_lenient_multi_polygon_assertions: coder_["lenient_multi_polygon_assertions"],
240
235
  proj4: proj4_,
241
236
  coord_sys: coord_sys_
242
237
  )
@@ -256,28 +251,19 @@ module RGeo
256
251
  _buffer_resolution
257
252
  end
258
253
 
259
- # Returns true if this factory is lenient with MultiPolygon assertions
260
-
261
- def lenient_multi_polygon_assertions?
262
- _flags & 0x1 != 0
263
- end
264
-
265
254
  # See RGeo::Feature::Factory#property
266
-
267
255
  def property(name_)
268
256
  case name_
269
257
  when :has_z_coordinate
270
- _flags & 0x2 != 0
258
+ supports_z?
271
259
  when :has_m_coordinate
272
- _flags & 0x4 != 0
260
+ supports_m?
273
261
  when :is_cartesian
274
262
  true
275
- when :uses_lenient_multi_polygon_assertions
276
- _flags & 0x1 != 0
277
263
  when :buffer_resolution
278
264
  _buffer_resolution
279
265
  when :auto_prepare
280
- _flags & 0x8 != 0 ? :simple : :disabled
266
+ prepare_heuristic? ? :simple : :disabled
281
267
  end
282
268
  end
283
269
 
@@ -307,11 +293,11 @@ module RGeo
307
293
 
308
294
  # See RGeo::Feature::Factory#point
309
295
 
310
- def point(x_, y_, *extra_)
311
- if extra_.length > (_flags & 6 == 0 ? 0 : 1)
296
+ def point(x, y, *extra)
297
+ if extra.length > (supports_z_or_m? ? 1 : 0)
312
298
  raise(RGeo::Error::InvalidGeometry, "Parse error")
313
299
  else
314
- CAPIPointImpl.create(self, x_, y_, extra_[0].to_f)
300
+ CAPIPointImpl.create(self, x, y, extra[0].to_f)
315
301
  end
316
302
  end
317
303
 
@@ -398,7 +384,7 @@ module RGeo
398
384
  # Optimization if we're just changing factories, but the
399
385
  # factories are zm-compatible and proj4-compatible.
400
386
  if original.factory != self && ntype == type &&
401
- original.factory._flags & 0x6 == _flags & 0x6 &&
387
+ original.factory._flags & FLAG_SUPPORTS_Z_OR_M == _flags & FLAG_SUPPORTS_Z_OR_M &&
402
388
  (!project || original.factory.proj4 == _proj4)
403
389
  result = original.dup
404
390
  result.factory = self
@@ -406,7 +392,7 @@ module RGeo
406
392
  end
407
393
  # LineString conversion optimization.
408
394
  if (original.factory != self || ntype != type) &&
409
- original.factory._flags & 0x6 == _flags & 0x6 &&
395
+ original.factory._flags & FLAG_SUPPORTS_Z_OR_M == _flags & FLAG_SUPPORTS_Z_OR_M &&
410
396
  (!project || original.factory.proj4 == _proj4) &&
411
397
  type.subtype_of?(Feature::LineString) && ntype.subtype_of?(Feature::LineString)
412
398
  return IMPL_CLASSES[ntype]._copy_from(self, original)
@@ -414,15 +400,19 @@ module RGeo
414
400
  when ZMGeometryMethods
415
401
  # Optimization for just removing a coordinate from an otherwise
416
402
  # compatible factory
417
- if _flags & 0x6 == 0x2 && self == original.factory.z_factory
403
+ if supports_z? && !supports_m? && self == original.factory.z_factory
418
404
  return Feature.cast(original.z_geometry, ntype, flags)
419
- elsif _flags & 0x6 == 0x4 && self == original.factory.m_factory
405
+ elsif supports_m? && !supports_z? && self == original.factory.m_factory
420
406
  return Feature.cast(original.m_geometry, ntype, flags)
421
407
  end
422
408
  end
423
409
  false
424
410
  end
425
411
 
412
+ def auto_prepare # :nodoc:
413
+ prepare_heuristic? ? :simple : :disabled
414
+ end
415
+
426
416
  # :stopdoc:
427
417
 
428
418
  IMPL_CLASSES = {
@@ -6,11 +6,23 @@
6
6
  #
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
+ require_relative "../impl_helper/validity_check"
10
+
9
11
  module RGeo
10
12
  module Geos
11
- module CAPIGeometryMethods # :nodoc:
13
+ module CAPIGeometryMethods
12
14
  include Feature::Instance
13
15
 
16
+ def is_empty? # rubocop:disable Naming/PredicateName
17
+ warn "The is_empty? method is deprecated, please use the empty? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
18
+ empty?
19
+ end
20
+
21
+ def is_simple? # rubocop:disable Naming/PredicateName
22
+ warn "The is_simple? method is deprecated, please use the simple? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
23
+ simple?
24
+ end
25
+
14
26
  def inspect
15
27
  "#<#{self.class}:0x#{object_id.to_s(16)} #{as_text.inspect}>"
16
28
  end
@@ -50,25 +62,52 @@ module RGeo
50
62
  alias to_s as_text
51
63
  end
52
64
 
65
+ module CAPIMultiLineStringMethods # :nodoc:
66
+ def is_closed? # rubocop:disable Naming/PredicateName
67
+ warn "The is_closed? method is deprecated, please use the closed? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
68
+ closed?
69
+ end
70
+ end
71
+
72
+ module CAPILineStringMethods # :nodoc:
73
+ def is_closed? # rubocop:disable Naming/PredicateName
74
+ warn "The is_closed? method is deprecated, please use the closed? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
75
+ closed?
76
+ end
77
+
78
+ def is_ring? # rubocop:disable Naming/PredicateName
79
+ warn "The is_ring? method is deprecated, please use the ring? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
80
+ ring?
81
+ end
82
+ end
83
+
53
84
  module CAPIGeometryCollectionMethods # :nodoc:
54
85
  include Enumerable
55
86
  end
56
87
 
57
- class CAPIGeometryImpl # :nodoc:
88
+ class CAPIGeometryImpl
89
+ include Feature::Geometry
90
+ include ImplHelper::ValidityCheck
58
91
  include CAPIGeometryMethods
59
92
  end
60
93
 
61
- class CAPIPointImpl # :nodoc:
94
+ class CAPIPointImpl
95
+ include Feature::Point
96
+ include ImplHelper::ValidityCheck
62
97
  include CAPIGeometryMethods
63
98
  include CAPIPointMethods
64
99
  end
65
100
 
66
- class CAPILineStringImpl # :nodoc:
101
+ class CAPILineStringImpl
102
+ include Feature::LineString
103
+ include ImplHelper::ValidityCheck
67
104
  include CAPIGeometryMethods
68
105
  include CAPILineStringMethods
69
106
  end
70
107
 
71
- class CAPILinearRingImpl # :nodoc:
108
+ class CAPILinearRingImpl
109
+ include Feature::LinearRing
110
+ include ImplHelper::ValidityCheck
72
111
  include CAPIGeometryMethods
73
112
  include CAPILineStringMethods
74
113
  include CAPILinearRingMethods
@@ -78,38 +117,52 @@ module RGeo
78
117
  end
79
118
  end
80
119
 
81
- class CAPILineImpl # :nodoc:
120
+ class CAPILineImpl
121
+ include Feature::Line
122
+ include ImplHelper::ValidityCheck
82
123
  include CAPIGeometryMethods
83
124
  include CAPILineStringMethods
84
125
  include CAPILineMethods
85
126
  end
86
127
 
87
- class CAPIPolygonImpl # :nodoc:
128
+ class CAPIPolygonImpl
129
+ include Feature::Polygon
130
+ include ImplHelper::ValidityCheck
88
131
  include CAPIGeometryMethods
89
132
  include CAPIPolygonMethods
90
133
  end
91
134
 
92
- class CAPIGeometryCollectionImpl # :nodoc:
135
+ class CAPIGeometryCollectionImpl
136
+ include Feature::GeometryCollection
137
+ include ImplHelper::ValidityCheck
93
138
  include CAPIGeometryMethods
94
139
  include CAPIGeometryCollectionMethods
95
140
  end
96
141
 
97
- class CAPIMultiPointImpl # :nodoc:
142
+ class CAPIMultiPointImpl
143
+ include Feature::MultiPoint
144
+ include ImplHelper::ValidityCheck
98
145
  include CAPIGeometryMethods
99
146
  include CAPIGeometryCollectionMethods
100
147
  include CAPIMultiPointMethods
101
148
  end
102
149
 
103
- class CAPIMultiLineStringImpl # :nodoc:
150
+ class CAPIMultiLineStringImpl
151
+ include Feature::MultiLineString
152
+ include ImplHelper::ValidityCheck
104
153
  include CAPIGeometryMethods
105
154
  include CAPIGeometryCollectionMethods
106
155
  include CAPIMultiLineStringMethods
107
156
  end
108
157
 
109
- class CAPIMultiPolygonImpl # :nodoc:
158
+ class CAPIMultiPolygonImpl
159
+ include Feature::MultiPolygon
160
+ include ImplHelper::ValidityCheck
110
161
  include CAPIGeometryMethods
111
162
  include CAPIGeometryCollectionMethods
112
163
  include CAPIMultiPolygonMethods
113
164
  end
165
+
166
+ ImplHelper::ValidityCheck.override_classes
114
167
  end
115
168
  end
@@ -20,9 +20,6 @@ module RGeo
20
20
  # See RGeo::Geos.factory for a list of supported options.
21
21
 
22
22
  def initialize(opts = {})
23
- # Main flags
24
- @uses_lenient_multi_polygon_assertions = opts[:uses_lenient_assertions] ||
25
- opts[:lenient_multi_polygon_assertions] || opts[:uses_lenient_multi_polygon_assertions]
26
23
  @has_z = opts[:has_z_coordinate] ? true : false
27
24
  @has_m = opts[:has_m_coordinate] ? true : false
28
25
  if @has_z && @has_m
@@ -145,7 +142,6 @@ module RGeo
145
142
  "wkbg" => @wkb_generator.properties,
146
143
  "wktp" => @wkt_parser.properties,
147
144
  "wkbp" => @wkb_parser.properties,
148
- "lmpa" => @uses_lenient_multi_polygon_assertions,
149
145
  "apre" => @_auto_prepare
150
146
  }
151
147
  hash["proj4"] = @proj4.marshal_dump if @proj4
@@ -174,7 +170,6 @@ module RGeo
174
170
  wkb_generator: symbolize_hash(data["wkbg"]),
175
171
  wkt_parser: symbolize_hash(data["wktp"]),
176
172
  wkb_parser: symbolize_hash(data["wkbp"]),
177
- uses_lenient_multi_polygon_assertions: data["lmpa"],
178
173
  auto_prepare: (data["apre"] ? :simple : :disabled),
179
174
  proj4: proj4,
180
175
  coord_sys: coord_sys
@@ -188,7 +183,6 @@ module RGeo
188
183
  coder["has_m_coordinate"] = @has_m
189
184
  coder["srid"] = @srid
190
185
  coder["buffer_resolution"] = @buffer_resolution
191
- coder["lenient_multi_polygon_assertions"] = @uses_lenient_multi_polygon_assertions
192
186
  coder["wkt_generator"] = @wkt_generator.properties
193
187
  coder["wkb_generator"] = @wkb_generator.properties
194
188
  coder["wkt_parser"] = @wkt_parser.properties
@@ -227,7 +221,6 @@ module RGeo
227
221
  wkt_parser: symbolize_hash(coder["wkt_parser"]),
228
222
  wkb_parser: symbolize_hash(coder["wkb_parser"]),
229
223
  auto_prepare: coder["auto_prepare"] == "disabled" ? :disabled : :simple,
230
- uses_lenient_multi_polygon_assertions: coder["lenient_multi_polygon_assertions"],
231
224
  proj4: proj4,
232
225
  coord_sys: coord_sys
233
226
  )
@@ -242,14 +235,7 @@ module RGeo
242
235
 
243
236
  attr_reader :buffer_resolution
244
237
 
245
- # Returns true if this factory is lenient with MultiPolygon assertions
246
-
247
- def lenient_multi_polygon_assertions?
248
- @uses_lenient_multi_polygon_assertions
249
- end
250
-
251
238
  # See RGeo::Feature::Factory#property
252
-
253
239
  def property(name_)
254
240
  case name_
255
241
  when :has_z_coordinate
@@ -260,15 +246,12 @@ module RGeo
260
246
  true
261
247
  when :buffer_resolution
262
248
  @buffer_resolution
263
- when :uses_lenient_multi_polygon_assertions
264
- @uses_lenient_multi_polygon_assertions
265
249
  when :auto_prepare
266
250
  @_auto_prepare ? :simple : :disabled
267
251
  end
268
252
  end
269
253
 
270
254
  # See RGeo::Feature::Factory#parse_wkt
271
-
272
255
  def parse_wkt(str)
273
256
  if @wkt_reader
274
257
  wrap_fg_geom(@wkt_reader.read(str), nil)
@@ -417,17 +400,6 @@ module RGeo
417
400
  raise(RGeo::Error::InvalidGeometry, "Could not cast to polygon: #{elem}") unless elem
418
401
  elem.detach_fg_geom
419
402
  end
420
- unless @uses_lenient_multi_polygon_assertions
421
- (1...elems.size).each do |i|
422
- (0...i).each do |j|
423
- igeom = elems[i]
424
- jgeom = elems[j]
425
- if igeom.relate_pattern(jgeom, "2********") || igeom.relate_pattern(jgeom, "****1****")
426
- raise(RGeo::Error::InvalidGeometry, "Invalid relate pattern: #{jgeom}")
427
- end
428
- end
429
- end
430
- end
431
403
  klasses = Array.new(elems.size, FFIPolygonImpl)
432
404
  fg_geom = ::Geos::Utils.create_collection(::Geos::GeomTypes::GEOS_MULTIPOLYGON, elems)
433
405
  FFIMultiPolygonImpl.new(self, fg_geom, klasses)
@@ -6,60 +6,84 @@
6
6
  #
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
+ require_relative "../impl_helper/validity_check"
10
+
9
11
  module RGeo
10
12
  module Geos
11
- class FFIGeometryImpl # :nodoc:
13
+ class FFIGeometryImpl
14
+ include Feature::Geometry
15
+ include ImplHelper::ValidityCheck
12
16
  include FFIGeometryMethods
13
17
  end
14
18
 
15
- class FFIPointImpl # :nodoc:
19
+ class FFIPointImpl
20
+ include Feature::Point
21
+ include ImplHelper::ValidityCheck
16
22
  include FFIGeometryMethods
17
23
  include FFIPointMethods
18
24
  end
19
25
 
20
- class FFILineStringImpl # :nodoc:
26
+ class FFILineStringImpl
27
+ include Feature::LineString
28
+ include ImplHelper::ValidityCheck
21
29
  include FFIGeometryMethods
22
30
  include FFILineStringMethods
23
31
  end
24
32
 
25
- class FFILinearRingImpl # :nodoc:
33
+ class FFILinearRingImpl
34
+ include Feature::LinearRing
35
+ include ImplHelper::ValidityCheck
26
36
  include FFIGeometryMethods
27
37
  include FFILineStringMethods
28
38
  include FFILinearRingMethods
29
39
  end
30
40
 
31
- class FFILineImpl # :nodoc:
41
+ class FFILineImpl
42
+ include Feature::Line
43
+ include ImplHelper::ValidityCheck
32
44
  include FFIGeometryMethods
33
45
  include FFILineStringMethods
34
46
  include FFILineMethods
35
47
  end
36
48
 
37
- class FFIPolygonImpl # :nodoc:
49
+ class FFIPolygonImpl
50
+ include Feature::Polygon
51
+ include ImplHelper::ValidityCheck
38
52
  include FFIGeometryMethods
39
53
  include FFIPolygonMethods
40
54
  end
41
55
 
42
- class FFIGeometryCollectionImpl # :nodoc:
56
+ class FFIGeometryCollectionImpl
57
+ include Feature::GeometryCollection
58
+ include ImplHelper::ValidityCheck
43
59
  include FFIGeometryMethods
44
60
  include FFIGeometryCollectionMethods
45
61
  end
46
62
 
47
- class FFIMultiPointImpl # :nodoc:
63
+ class FFIMultiPointImpl
64
+ include Feature::MultiPoint
65
+ include ImplHelper::ValidityCheck
48
66
  include FFIGeometryMethods
49
67
  include FFIGeometryCollectionMethods
50
68
  include FFIMultiPointMethods
51
69
  end
52
70
 
53
- class FFIMultiLineStringImpl # :nodoc:
71
+ class FFIMultiLineStringImpl
72
+ include Feature::MultiLineString
73
+ include ImplHelper::ValidityCheck
54
74
  include FFIGeometryMethods
55
75
  include FFIGeometryCollectionMethods
56
76
  include FFIMultiLineStringMethods
57
77
  end
58
78
 
59
- class FFIMultiPolygonImpl # :nodoc:
79
+ class FFIMultiPolygonImpl
80
+ include Feature::MultiPolygon
81
+ include ImplHelper::ValidityCheck
60
82
  include FFIGeometryMethods
61
83
  include FFIGeometryCollectionMethods
62
84
  include FFIMultiPolygonMethods
63
85
  end
86
+
87
+ ImplHelper::ValidityCheck.override_classes
64
88
  end
65
89
  end
@@ -6,6 +6,8 @@
6
6
  #
7
7
  # -----------------------------------------------------------------------------
8
8
 
9
+ require "ffi-geos"
10
+
9
11
  module RGeo
10
12
  module Geos
11
13
  module FFIGeometryMethods # :nodoc:
@@ -95,11 +97,9 @@ module RGeo
95
97
  end
96
98
 
97
99
  def boundary
98
- if self.class == FFIGeometryCollectionImpl
99
- nil
100
- else
101
- @factory.wrap_fg_geom(@fg_geom.boundary, nil)
102
- end
100
+ @factory.wrap_fg_geom(@fg_geom.boundary, nil)
101
+ rescue ::Geos::GEOSException
102
+ raise Error::InvalidGeometry, "Operation not supported by GeometryCollection"
103
103
  end
104
104
 
105
105
  def as_text
@@ -113,14 +113,42 @@ module RGeo
113
113
  @factory.generate_wkb(self)
114
114
  end
115
115
 
116
- def is_empty?
116
+ def empty?
117
117
  @fg_geom.empty?
118
118
  end
119
119
 
120
- def is_simple?
120
+ def is_empty?
121
+ warn "The is_empty? method is deprecated, please use the empty? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
122
+ empty?
123
+ end
124
+
125
+ def simple?
121
126
  @fg_geom.simple?
122
127
  end
123
128
 
129
+ def is_simple?
130
+ warn "The is_simple? method is deprecated, please use the simple? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
131
+ simple?
132
+ end
133
+
134
+ def valid?
135
+ @fg_geom.valid?
136
+ end
137
+
138
+ def invalid_reason
139
+ # valid_detail gives solely the reason, or nil if valid, which is
140
+ # what we want.
141
+ fg_geom.valid_detail&.dig(:detail)&.force_encoding(Encoding::UTF_8)
142
+ end
143
+
144
+ # (see RGeo::ImplHelper::ValidityCheck#make_valid)
145
+ # Only available since GEOS 3.8+
146
+ def make_valid
147
+ @factory.wrap_fg_geom(@fg_geom.make_valid, nil)
148
+ rescue ::Geos::GEOSException
149
+ raise Error::UnsupportedOperation
150
+ end if ::Geos::FFIGeos.respond_to?(:GEOSMakeValid_r)
151
+
124
152
  def equals?(rhs)
125
153
  return false unless rhs.is_a?(RGeo::Feature::Instance)
126
154
  fg = factory.convert_to_fg_geometry(rhs)
@@ -367,14 +395,24 @@ module RGeo
367
395
  end
368
396
  end
369
397
 
370
- def is_closed?
398
+ def closed?
371
399
  @fg_geom.closed?
372
400
  end
373
401
 
374
- def is_ring?
402
+ def is_closed?
403
+ warn "The is_closed? method is deprecated, please use the closed? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
404
+ closed?
405
+ end
406
+
407
+ def ring?
375
408
  @fg_geom.ring?
376
409
  end
377
410
 
411
+ def is_ring?
412
+ warn "The is_ring? method is deprecated, please use the ring? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
413
+ ring?
414
+ end
415
+
378
416
  def rep_equals?(rhs)
379
417
  rhs.class == self.class && rhs.factory.eql?(@factory) &&
380
418
  Utils.ffi_coord_seqs_equal?(rhs.fg_geom.coord_seq, @fg_geom.coord_seq, @factory._has_3d)
@@ -553,7 +591,7 @@ module RGeo
553
591
  @fg_geom.length
554
592
  end
555
593
 
556
- def is_closed?
594
+ def closed?
557
595
  size = num_geometries
558
596
  size.times do |n|
559
597
  return false unless @fg_geom.get_geometry_n(n).closed?
@@ -561,6 +599,11 @@ module RGeo
561
599
  true
562
600
  end
563
601
 
602
+ def is_closed?
603
+ warn "The is_closed? method is deprecated, please use the closed? counterpart, will be removed in v3" unless ENV["RGEO_SILENCE_DEPRECATION"]
604
+ closed?
605
+ end
606
+
564
607
  def coordinates
565
608
  each.map(&:coordinates)
566
609
  end