rgeo 2.4.0 → 3.0.0.pre.rc.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +6 -0
- data/README.md +1 -0
- data/ext/geos_c_impl/analysis.c +4 -4
- data/ext/geos_c_impl/errors.c +8 -6
- data/ext/geos_c_impl/errors.h +7 -3
- data/ext/geos_c_impl/extconf.rb +2 -0
- data/ext/geos_c_impl/factory.c +80 -7
- data/ext/geos_c_impl/factory.h +28 -14
- data/ext/geos_c_impl/geometry.c +46 -14
- data/ext/geos_c_impl/geometry.h +7 -0
- data/ext/geos_c_impl/geometry_collection.c +2 -104
- data/ext/geos_c_impl/geometry_collection.h +0 -11
- data/ext/geos_c_impl/line_string.c +1 -1
- data/ext/geos_c_impl/point.c +1 -1
- data/ext/geos_c_impl/polygon.c +1 -37
- data/ext/geos_c_impl/preface.h +3 -0
- data/lib/rgeo/cartesian/calculations.rb +54 -17
- data/lib/rgeo/cartesian/factory.rb +0 -7
- data/lib/rgeo/cartesian/feature_classes.rb +66 -46
- data/lib/rgeo/cartesian/feature_methods.rb +51 -20
- data/lib/rgeo/cartesian/interface.rb +0 -6
- data/lib/rgeo/cartesian/planar_graph.rb +379 -0
- data/lib/rgeo/cartesian/sweepline_intersector.rb +149 -0
- data/lib/rgeo/cartesian/valid_op.rb +71 -0
- data/lib/rgeo/cartesian.rb +3 -0
- data/lib/rgeo/coord_sys/cs/wkt_parser.rb +6 -6
- data/lib/rgeo/error.rb +15 -0
- data/lib/rgeo/feature/geometry.rb +28 -28
- data/lib/rgeo/feature/geometry_collection.rb +13 -5
- data/lib/rgeo/feature/line_string.rb +3 -3
- data/lib/rgeo/feature/multi_surface.rb +3 -3
- data/lib/rgeo/feature/point.rb +4 -4
- data/lib/rgeo/feature/surface.rb +3 -3
- data/lib/rgeo/geographic/factory.rb +0 -7
- data/lib/rgeo/geographic/interface.rb +5 -20
- data/lib/rgeo/geographic/proj4_projector.rb +0 -2
- data/lib/rgeo/geographic/projected_feature_classes.rb +21 -9
- data/lib/rgeo/geographic/projected_feature_methods.rb +51 -28
- data/lib/rgeo/geographic/simple_mercator_projector.rb +0 -2
- data/lib/rgeo/geographic/spherical_feature_classes.rb +29 -9
- data/lib/rgeo/geographic/spherical_feature_methods.rb +62 -1
- data/lib/rgeo/geos/capi_factory.rb +21 -31
- data/lib/rgeo/geos/capi_feature_classes.rb +35 -11
- data/lib/rgeo/geos/ffi_factory.rb +0 -28
- data/lib/rgeo/geos/ffi_feature_classes.rb +34 -10
- data/lib/rgeo/geos/ffi_feature_methods.rb +23 -5
- data/lib/rgeo/geos/interface.rb +0 -7
- data/lib/rgeo/geos/zm_factory.rb +0 -12
- data/lib/rgeo/impl_helper/basic_geometry_collection_methods.rb +4 -4
- data/lib/rgeo/impl_helper/basic_geometry_methods.rb +1 -1
- data/lib/rgeo/impl_helper/basic_line_string_methods.rb +15 -19
- data/lib/rgeo/impl_helper/basic_point_methods.rb +1 -1
- data/lib/rgeo/impl_helper/basic_polygon_methods.rb +1 -1
- data/lib/rgeo/impl_helper/valid_op.rb +354 -0
- data/lib/rgeo/impl_helper/validity_check.rb +138 -0
- data/lib/rgeo/impl_helper.rb +1 -0
- data/lib/rgeo/version.rb +1 -1
- metadata +31 -10
@@ -0,0 +1,354 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
|
5
|
+
module RGeo
|
6
|
+
module ImplHelper
|
7
|
+
# Mixin based off of the JTS/GEOS IsValidOp class.
|
8
|
+
# Implements #valid? and #invalid_reason on Features that include this.
|
9
|
+
#
|
10
|
+
# @see https://github.com/locationtech/jts/blob/master/modules/core/src/main/java/org/locationtech/jts/operation/valid/IsValidOp.java
|
11
|
+
module ValidOp
|
12
|
+
# Validity of geometry
|
13
|
+
#
|
14
|
+
# @return Boolean
|
15
|
+
def valid?
|
16
|
+
invalid_reason.nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
# Reason for invalidity or nil if valid
|
20
|
+
#
|
21
|
+
# @return String
|
22
|
+
def invalid_reason
|
23
|
+
return @invalid_reason if defined?(@invalid_reason)
|
24
|
+
@invalid_reason = check_valid
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def validity_helper
|
30
|
+
ValidOpHelpers
|
31
|
+
end
|
32
|
+
|
33
|
+
# Method that performs validity checking. Just checks the type of geometry
|
34
|
+
# and delegates to the proper validity checker.
|
35
|
+
#
|
36
|
+
# Returns a string describing the error or nil if it's a valid geometry.
|
37
|
+
# In some cases, "Unkown Validity" is returned if a dependent method has
|
38
|
+
# not been implemented.
|
39
|
+
#
|
40
|
+
# @return String
|
41
|
+
def check_valid
|
42
|
+
case self
|
43
|
+
when Feature::Point
|
44
|
+
check_valid_point
|
45
|
+
when Feature::LinearRing
|
46
|
+
check_valid_linear_ring
|
47
|
+
when Feature::LineString
|
48
|
+
check_valid_line_string
|
49
|
+
when Feature::Polygon
|
50
|
+
check_valid_polygon
|
51
|
+
when Feature::MultiPoint
|
52
|
+
check_valid_multi_point
|
53
|
+
when Feature::MultiPolygon
|
54
|
+
check_valid_multi_polygon
|
55
|
+
when Feature::GeometryCollection
|
56
|
+
check_valid_geometry_collection
|
57
|
+
else
|
58
|
+
raise NotImplementedError, "check_valid is not implemented for #{self}"
|
59
|
+
end
|
60
|
+
rescue RGeo::Error::UnsupportedOperation, NoMethodError
|
61
|
+
"Unkown Validity"
|
62
|
+
end
|
63
|
+
|
64
|
+
def check_valid_point
|
65
|
+
validity_helper.check_invalid_coordinate(self)
|
66
|
+
end
|
67
|
+
|
68
|
+
def check_valid_line_string
|
69
|
+
# check coordinates are all valid
|
70
|
+
points.each do |pt|
|
71
|
+
check = validity_helper.check_invalid_coordinate(pt)
|
72
|
+
return check unless check.nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
# check more than 1 point
|
76
|
+
return Error::TOO_FEW_POINTS unless num_points > 1
|
77
|
+
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def check_valid_linear_ring
|
82
|
+
# check coordinates are all valid
|
83
|
+
points.each do |pt|
|
84
|
+
check = validity_helper.check_invalid_coordinate(pt)
|
85
|
+
return check unless check.nil?
|
86
|
+
end
|
87
|
+
|
88
|
+
# check closed
|
89
|
+
return Error::UNCLOSED_RING unless closed?
|
90
|
+
|
91
|
+
# check more than 3 points
|
92
|
+
return Error::TOO_FEW_POINTS unless num_points > 3
|
93
|
+
|
94
|
+
# check no self-intersections
|
95
|
+
validity_helper.check_no_self_intersections(self)
|
96
|
+
end
|
97
|
+
|
98
|
+
def check_valid_polygon
|
99
|
+
# check coordinates are all valid
|
100
|
+
exterior_ring.points.each do |pt|
|
101
|
+
check = validity_helper.check_invalid_coordinate(pt)
|
102
|
+
return check unless check.nil?
|
103
|
+
end
|
104
|
+
interior_rings.each do |ring|
|
105
|
+
ring.points.each do |pt|
|
106
|
+
check = validity_helper.check_invalid_coordinate(pt)
|
107
|
+
return check unless check.nil?
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# check closed
|
112
|
+
return Error::UNCLOSED_RING unless exterior_ring.closed?
|
113
|
+
return Error::UNCLOSED_RING unless interior_rings.all?(&:closed?)
|
114
|
+
|
115
|
+
# check more than 3 points in each ring
|
116
|
+
return Error::TOO_FEW_POINTS unless exterior_ring.num_points > 3
|
117
|
+
return Error::TOO_FEW_POINTS unless interior_rings.all? { |r| r.num_points > 3 }
|
118
|
+
|
119
|
+
# can skip this check if there's no holes
|
120
|
+
unless interior_rings.empty?
|
121
|
+
check = validity_helper.check_consistent_area(self)
|
122
|
+
return check unless check.nil?
|
123
|
+
end
|
124
|
+
|
125
|
+
# check that there are no self-intersections
|
126
|
+
check = validity_helper.check_no_self_intersecting_rings(self)
|
127
|
+
return check unless check.nil?
|
128
|
+
|
129
|
+
# can skip these checks if there's no holes
|
130
|
+
unless interior_rings.empty?
|
131
|
+
check = validity_helper.check_holes_in_shell(self)
|
132
|
+
return check unless check.nil?
|
133
|
+
|
134
|
+
check = validity_helper.check_holes_not_nested(self)
|
135
|
+
return check unless check.nil?
|
136
|
+
|
137
|
+
check = validity_helper.check_connected_interiors(self)
|
138
|
+
return check unless check.nil?
|
139
|
+
end
|
140
|
+
|
141
|
+
nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def check_valid_multi_point
|
145
|
+
geometries.each do |pt|
|
146
|
+
check = validity_helper.check_invalid_coordinate(pt)
|
147
|
+
return check unless check.nil?
|
148
|
+
end
|
149
|
+
nil
|
150
|
+
end
|
151
|
+
|
152
|
+
def check_valid_multi_polygon
|
153
|
+
geometries.each do |poly|
|
154
|
+
return poly.invalid_reason unless poly.invalid_reason.nil?
|
155
|
+
end
|
156
|
+
|
157
|
+
check = validity_helper.check_consistent_area_mp(self)
|
158
|
+
return check unless check.nil?
|
159
|
+
|
160
|
+
# check no shells are nested
|
161
|
+
check = validity_helper.check_shells_not_nested(self)
|
162
|
+
return check unless check.nil?
|
163
|
+
|
164
|
+
nil
|
165
|
+
end
|
166
|
+
|
167
|
+
def check_valid_geometry_collection
|
168
|
+
geometries.each do |geom|
|
169
|
+
return geom.invalid_reason unless geom.invalid_reason.nil?
|
170
|
+
end
|
171
|
+
|
172
|
+
nil
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
##
|
177
|
+
# Helper functions for specific validity checks
|
178
|
+
##
|
179
|
+
module ValidOpHelpers
|
180
|
+
module_function
|
181
|
+
|
182
|
+
# Checks that the given point has valid coordinates.
|
183
|
+
#
|
184
|
+
# @param pt [RGeo::Feature::Point]
|
185
|
+
#
|
186
|
+
# @return [String] invalid_reason
|
187
|
+
def check_invalid_coordinate(pt)
|
188
|
+
x = pt.x
|
189
|
+
y = pt.y
|
190
|
+
return if x.finite? && y.finite? && x.real? && y.real?
|
191
|
+
|
192
|
+
Error::INVALID_COORDINATE
|
193
|
+
end
|
194
|
+
|
195
|
+
# Checks that the edges in the polygon form a consistent area.
|
196
|
+
#
|
197
|
+
# Specifically, checks that there are intersections no between the
|
198
|
+
# holes and the shell.
|
199
|
+
#
|
200
|
+
# Also checks that there are no duplicate rings.
|
201
|
+
#
|
202
|
+
# @param poly [RGeo::Feature::Polygon]
|
203
|
+
#
|
204
|
+
# @return [String] invalid_reason
|
205
|
+
def check_consistent_area(poly)
|
206
|
+
# Holes don't cross exterior check.
|
207
|
+
exterior = poly.exterior_ring
|
208
|
+
poly.interior_rings.each do |ring|
|
209
|
+
return Error::SELF_INTERSECTION if ring.crosses?(exterior)
|
210
|
+
end
|
211
|
+
|
212
|
+
# check interiors do not cross
|
213
|
+
poly.interior_rings.combination(2).each do |ring1, ring2|
|
214
|
+
return Error::SELF_INTERSECTION if ring1.crosses?(ring2)
|
215
|
+
end
|
216
|
+
|
217
|
+
# Duplicate rings check
|
218
|
+
rings = [exterior] + poly.interior_rings
|
219
|
+
return Error::SELF_INTERSECTION if rings.uniq.size != rings.size
|
220
|
+
|
221
|
+
nil
|
222
|
+
end
|
223
|
+
|
224
|
+
# Checks that the ring does not self-intersect. This is just a simplicity
|
225
|
+
# check on the ring.
|
226
|
+
#
|
227
|
+
# @param ring [RGeo::Feature::LinearRing]
|
228
|
+
#
|
229
|
+
# @return [String] invalid_reason
|
230
|
+
def check_no_self_intersections(ring)
|
231
|
+
return Error::SELF_INTERSECTION unless ring.simple?
|
232
|
+
end
|
233
|
+
|
234
|
+
# Check that rings do not self intersect in a polygon
|
235
|
+
#
|
236
|
+
# @param poly [RGeo::Feature::Polygon]
|
237
|
+
#
|
238
|
+
# @return [String] invalid_reason
|
239
|
+
def check_no_self_intersecting_rings(poly)
|
240
|
+
exterior = poly.exterior_ring
|
241
|
+
|
242
|
+
check = check_no_self_intersections(exterior)
|
243
|
+
return check unless check.nil?
|
244
|
+
|
245
|
+
poly.interior_rings.each do |ring|
|
246
|
+
check = check_no_self_intersections(ring)
|
247
|
+
return check unless check.nil?
|
248
|
+
end
|
249
|
+
|
250
|
+
nil
|
251
|
+
end
|
252
|
+
|
253
|
+
# Checks holes are contained inside the exterior of a polygon.
|
254
|
+
# Assuming check_consistent_area has already passed on the polygon,
|
255
|
+
# a simple point in polygon check can be done on one of the points
|
256
|
+
# in each hole to verify (since we know none of them intersect).
|
257
|
+
#
|
258
|
+
# @param poly [RGeo::Feature::Polygon]
|
259
|
+
#
|
260
|
+
# @return [String] invalid_reason
|
261
|
+
def check_holes_in_shell(poly)
|
262
|
+
# get hole-less shell as test polygon
|
263
|
+
shell = poly.exterior_ring
|
264
|
+
shell = shell.factory.polygon(shell)
|
265
|
+
|
266
|
+
poly.interior_rings.each do |interior|
|
267
|
+
test_pt = interior.start_point
|
268
|
+
unless shell.contains?(test_pt) || poly.exterior_ring.contains?(test_pt)
|
269
|
+
return Error::HOLE_OUTSIDE_SHELL
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
nil
|
274
|
+
end
|
275
|
+
|
276
|
+
# Checks that holes are not nested within each other.
|
277
|
+
#
|
278
|
+
# @param poly [RGeo::Feature::Polygon]
|
279
|
+
#
|
280
|
+
# @return [String] invalid_reason
|
281
|
+
def check_holes_not_nested(poly)
|
282
|
+
# convert holes from linear_rings to polygons
|
283
|
+
# Same logic that applies to check_holes_in_shell applies here
|
284
|
+
# since we've already passed the consistent area test, we just
|
285
|
+
# have to check if one point from each hole is contained in the other.
|
286
|
+
holes = poly.interior_rings
|
287
|
+
holes = holes.map { |v| v.factory.polygon(v) }
|
288
|
+
holes.combination(2).each do |p1, p2|
|
289
|
+
if p1.contains?(p2.exterior_ring.start_point) || p2.contains?(p1.exterior_ring.start_point)
|
290
|
+
return Error::NESTED_HOLES
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
nil
|
295
|
+
end
|
296
|
+
|
297
|
+
# Checks that the interior of the polygon is connected.
|
298
|
+
# A disconnected interior can be described by this polygon for example
|
299
|
+
# POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (5 0, 10 5, 5 10, 0 5, 5 0))
|
300
|
+
#
|
301
|
+
# Which is a square with a diamond inside of it.
|
302
|
+
#
|
303
|
+
# @param poly [RGeo::Feature::Polygon]
|
304
|
+
#
|
305
|
+
# @return [String] invalid_reason
|
306
|
+
def check_connected_interiors(poly)
|
307
|
+
# This is not proper and will flag valid geometries as invalid, but
|
308
|
+
# is an ok approximation.
|
309
|
+
# Idea is to check if a single hole has multiple points on the
|
310
|
+
# exterior ring.
|
311
|
+
poly.interior_rings.each do |ring|
|
312
|
+
touches = Set.new
|
313
|
+
ring.points.each do |pt|
|
314
|
+
touches.add(pt) if poly.exterior_ring.contains?(pt)
|
315
|
+
end
|
316
|
+
|
317
|
+
return Error::DISCONNECTED_INTERIOR if touches.size > 1
|
318
|
+
end
|
319
|
+
|
320
|
+
nil
|
321
|
+
end
|
322
|
+
|
323
|
+
# Checks that polygons do not intersect in a multipolygon.
|
324
|
+
#
|
325
|
+
# @param mp [RGeo::Feature::MultiPolygon]
|
326
|
+
#
|
327
|
+
# @return [String] invalid_reason
|
328
|
+
def check_consistent_area_mp(mp)
|
329
|
+
mp.geometries.combination(2) do |p1, p2|
|
330
|
+
if p1.exterior_ring.crosses?(p2.exterior_ring)
|
331
|
+
return Error::SELF_INTERSECTION
|
332
|
+
end
|
333
|
+
end
|
334
|
+
nil
|
335
|
+
end
|
336
|
+
|
337
|
+
# Checks that individual polygons within a multipolygon are not nested.
|
338
|
+
#
|
339
|
+
# @param mp [RGeo::Feature::MultiPolygon]
|
340
|
+
#
|
341
|
+
# @return [String] invalid_reason
|
342
|
+
def check_shells_not_nested(mp)
|
343
|
+
# Since we've passed the consistent area test, we can just check
|
344
|
+
# that one point lies in the other.
|
345
|
+
mp.geometries.combination(2) do |p1, p2|
|
346
|
+
if p1.contains?(p2.exterior_ring.start_point) || p2.contains?(p1.exterior_ring.start_point)
|
347
|
+
return Error::NESTED_SHELLS
|
348
|
+
end
|
349
|
+
end
|
350
|
+
nil
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RGeo
|
4
|
+
module ImplHelper
|
5
|
+
# This helper enforces valid geometry computation, avoiding results such
|
6
|
+
# as a 0 area for a bowtie shaped polygon. Implementations that are part
|
7
|
+
# of RGeo core should all include this.
|
8
|
+
#
|
9
|
+
# You can play around validity checks if needed:
|
10
|
+
#
|
11
|
+
# - {check_validity!} is the method that will raise if your geometry is
|
12
|
+
# not valid. Its message will be the same as {invalid_reason}.
|
13
|
+
# - {make_valid} is the method you can call to get a valid copy of the
|
14
|
+
# current geometry.
|
15
|
+
# - finally, you can bypass any checked method by prepending `unsafe_` to
|
16
|
+
# it. At your own risk.
|
17
|
+
module ValidityCheck
|
18
|
+
# Every method that should not be overriden by the validity check.
|
19
|
+
# Those methods are either accessors or very basic methods not related
|
20
|
+
# to validity checks, or are used to check validity, in which case the
|
21
|
+
# `true/false` gives a correct information, no need to raise).
|
22
|
+
UNCHECKED_METHODS = [
|
23
|
+
# Basic methods
|
24
|
+
:factory, :geometry_type, :as_text, :as_binary, :srid,
|
25
|
+
# Tests
|
26
|
+
:simple?, :closed?, :empty?,
|
27
|
+
# Accessors
|
28
|
+
:exterior_ring, :interior_rings, :[], :num_geometries, :num_interior_rings,
|
29
|
+
:geometry_n, :each, :points, :point_n, :start_point, :end_point, :x, :y, :z, :m,
|
30
|
+
# Trivial methods
|
31
|
+
:num_points,
|
32
|
+
# Comparison
|
33
|
+
:equals?, :rep_equals?, :eql?, :==, :'!='
|
34
|
+
].freeze
|
35
|
+
private_constant :UNCHECKED_METHODS
|
36
|
+
|
37
|
+
# Since methods have their unsafe_ counter part, it means that the `+`
|
38
|
+
# method would lead to having an `unsafe_+` method that is not simply
|
39
|
+
# callable. Here's a simple fallback:
|
40
|
+
SYMBOL2NAME = {
|
41
|
+
:+ => "add",
|
42
|
+
:- => "remove",
|
43
|
+
:* => "multiply"
|
44
|
+
}.tap { |h| h.default_proc = ->(_, key) { key.to_s } }.freeze
|
45
|
+
private_constant :SYMBOL2NAME
|
46
|
+
|
47
|
+
class << self
|
48
|
+
# Note for contributors: this should be called after all methods
|
49
|
+
# are loaded for a given feature classe. No worries though, this
|
50
|
+
# is tested.
|
51
|
+
def override_classes # :nodoc:
|
52
|
+
# Using pop here to be thread safe.
|
53
|
+
while (klass = classes.pop)
|
54
|
+
override(klass)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def included(klass) # :nodoc:
|
59
|
+
classes << klass
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def classes
|
65
|
+
@classes ||= []
|
66
|
+
end
|
67
|
+
|
68
|
+
def override(klass)
|
69
|
+
methods_to_check = feature_methods(klass)
|
70
|
+
|
71
|
+
klass.class_eval do
|
72
|
+
methods_to_check.each do |method_sym|
|
73
|
+
copy = "unsafe_#{SYMBOL2NAME[method_sym]}".to_sym
|
74
|
+
alias_method copy, method_sym
|
75
|
+
undef_method method_sym
|
76
|
+
define_method(method_sym) do |*args|
|
77
|
+
check_validity!
|
78
|
+
args.each do |arg|
|
79
|
+
arg.check_validity! if RGeo::Feature::Geometry.check_type(arg)
|
80
|
+
end
|
81
|
+
method(copy).call(*args)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def feature_methods(klass)
|
88
|
+
feature_defs = Set.new
|
89
|
+
klass
|
90
|
+
.ancestors
|
91
|
+
.select { |ancestor| ancestor <= RGeo::Feature::Geometry }
|
92
|
+
.each { |ancestor| feature_defs.merge(ancestor.instance_methods(false)) }
|
93
|
+
feature_defs & klass.instance_methods - UNCHECKED_METHODS
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Raises {invalid_reason} if the polygon is not valid, does nothing
|
98
|
+
# otherwise.
|
99
|
+
def check_validity!
|
100
|
+
# This method will use a cached invalid_reason for performance purposes.
|
101
|
+
# DO NOT MUTATE GEOMETRIES.
|
102
|
+
return unless invalid_reason_memo
|
103
|
+
|
104
|
+
raise Error::InvalidGeometry, invalid_reason_memo
|
105
|
+
end
|
106
|
+
|
107
|
+
# Tell why the geometry is not valid, `nil` means it is valid.
|
108
|
+
def invalid_reason
|
109
|
+
if defined?(super) == "super"
|
110
|
+
raise Error::RGeoError, "ValidityCheck MUST be loaded before " \
|
111
|
+
"definition of #{self.class}##{__method__}."
|
112
|
+
end
|
113
|
+
|
114
|
+
raise Error::UnsupportedOperation, "Method #{self.class}##{__method__} not defined."
|
115
|
+
end
|
116
|
+
|
117
|
+
# Try and make the geometry valid, this may change its shape.
|
118
|
+
# Returns a valid copy of the geometry.
|
119
|
+
def make_valid
|
120
|
+
if defined?(super) == "super"
|
121
|
+
raise Error::RGeoError, "ValidityCheck MUST be loaded before " \
|
122
|
+
"definition of #{self.class}##{__method__}."
|
123
|
+
end
|
124
|
+
|
125
|
+
raise Error::UnsupportedOperation, "Method #{self.class}##{__method__} not defined."
|
126
|
+
end
|
127
|
+
|
128
|
+
private
|
129
|
+
|
130
|
+
def invalid_reason_memo
|
131
|
+
# `defined?` is a bit faster than `instance_variable_defined?`.
|
132
|
+
return @invalid_reason_memo if defined?(@invalid_reason_memo)
|
133
|
+
|
134
|
+
@invalid_reason_memo = invalid_reason
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/rgeo/impl_helper.rb
CHANGED
data/lib/rgeo/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgeo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0.pre.rc.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Azuma
|
8
8
|
- Tee Parham
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-03-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi-geos
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '2.2'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '
|
27
|
+
version: '2.2'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: minitest
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,6 +81,20 @@ dependencies:
|
|
81
81
|
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: 1.8.1
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: yard
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0.9'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0.9'
|
84
98
|
description: RGeo is a geospatial data library for Ruby. It provides an implementation
|
85
99
|
of the Open Geospatial Consortium's Simple Features Specification, used by most
|
86
100
|
standard spatial/geographic data storage systems such as PostGIS. A number of add-on
|
@@ -90,11 +104,13 @@ email:
|
|
90
104
|
- dazuma@gmail.com
|
91
105
|
- parhameter@gmail.com
|
92
106
|
- kfdoggett@gmail.com
|
107
|
+
- buonomo.ulysse@gmail.com
|
93
108
|
executables: []
|
94
109
|
extensions:
|
95
110
|
- ext/geos_c_impl/extconf.rb
|
96
111
|
extra_rdoc_files: []
|
97
112
|
files:
|
113
|
+
- ".yardopts"
|
98
114
|
- LICENSE.txt
|
99
115
|
- README.md
|
100
116
|
- ext/geos_c_impl/analysis.c
|
@@ -129,6 +145,9 @@ files:
|
|
129
145
|
- lib/rgeo/cartesian/feature_classes.rb
|
130
146
|
- lib/rgeo/cartesian/feature_methods.rb
|
131
147
|
- lib/rgeo/cartesian/interface.rb
|
148
|
+
- lib/rgeo/cartesian/planar_graph.rb
|
149
|
+
- lib/rgeo/cartesian/sweepline_intersector.rb
|
150
|
+
- lib/rgeo/cartesian/valid_op.rb
|
132
151
|
- lib/rgeo/coord_sys.rb
|
133
152
|
- lib/rgeo/coord_sys/cs/entities.rb
|
134
153
|
- lib/rgeo/coord_sys/cs/factories.rb
|
@@ -185,6 +204,8 @@ files:
|
|
185
204
|
- lib/rgeo/impl_helper/basic_polygon_methods.rb
|
186
205
|
- lib/rgeo/impl_helper/math.rb
|
187
206
|
- lib/rgeo/impl_helper/utils.rb
|
207
|
+
- lib/rgeo/impl_helper/valid_op.rb
|
208
|
+
- lib/rgeo/impl_helper/validity_check.rb
|
188
209
|
- lib/rgeo/version.rb
|
189
210
|
- lib/rgeo/wkrep.rb
|
190
211
|
- lib/rgeo/wkrep/wkb_generator.rb
|
@@ -195,7 +216,7 @@ homepage: https://github.com/rgeo/rgeo
|
|
195
216
|
licenses:
|
196
217
|
- BSD-3-Clause
|
197
218
|
metadata: {}
|
198
|
-
post_install_message:
|
219
|
+
post_install_message:
|
199
220
|
rdoc_options: []
|
200
221
|
require_paths:
|
201
222
|
- lib
|
@@ -206,12 +227,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
206
227
|
version: 2.5.0
|
207
228
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
208
229
|
requirements:
|
209
|
-
- - "
|
230
|
+
- - ">"
|
210
231
|
- !ruby/object:Gem::Version
|
211
|
-
version:
|
232
|
+
version: 1.3.1
|
212
233
|
requirements: []
|
213
|
-
rubygems_version: 3.1.
|
214
|
-
signing_key:
|
234
|
+
rubygems_version: 3.1.4
|
235
|
+
signing_key:
|
215
236
|
specification_version: 4
|
216
237
|
summary: RGeo is a geospatial data library for Ruby.
|
217
238
|
test_files: []
|