Module: RGeo::ImplHelper::ValidOpHelpers
- Included in:
- Cartesian::ValidOpHelpers
- Defined in:
- lib/rgeo/impl_helper/valid_op.rb
Overview
Helper functions for specific validity checks
Class Method Summary collapse
-
.check_connected_interiors(poly) ⇒ String
Checks that the interior of the polygon is connected.
-
.check_consistent_area(poly) ⇒ String
Checks that the edges in the polygon form a consistent area.
-
.check_consistent_area_mp(mpoly) ⇒ String
Checks that polygons do not intersect in a multipolygon.
-
.check_holes_in_shell(poly) ⇒ String
Checks holes are contained inside the exterior of a polygon.
-
.check_holes_not_nested(poly) ⇒ String
Checks that holes are not nested within each other.
-
.check_invalid_coordinate(point) ⇒ String
Checks that the given point has valid coordinates.
-
.check_no_self_intersecting_rings(poly) ⇒ String
Check that rings do not self intersect in a polygon.
-
.check_no_self_intersections(ring) ⇒ String
Checks that the ring does not self-intersect.
-
.check_shells_not_nested(mpoly) ⇒ String
Checks that individual polygons within a multipolygon are not nested.
Class Method Details
.check_connected_interiors(poly) ⇒ String
Checks that the interior of the polygon is connected. A disconnected interior can be described by this polygon for example POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (5 0, 10 5, 5 10, 0 5, 5 0))
Which is a square with a diamond inside of it.
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/rgeo/impl_helper/valid_op.rb', line 304 def check_connected_interiors(poly) # This is not proper and will flag valid geometries as invalid, but # is an ok approximation. # Idea is to check if a single hole has multiple points on the # exterior ring. poly.interior_rings.each do |ring| touches = Set.new ring.points.each do |pt| touches.add(pt) if poly.exterior_ring.contains?(pt) end return Error::DISCONNECTED_INTERIOR if touches.size > 1 end nil end |
.check_consistent_area(poly) ⇒ String
Checks that the edges in the polygon form a consistent area.
Specifically, checks that there are intersections no between the holes and the shell.
Also checks that there are no duplicate rings.
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/rgeo/impl_helper/valid_op.rb', line 205 def check_consistent_area(poly) # Holes don't cross exterior check. exterior = poly.exterior_ring poly.interior_rings.each do |ring| return Error::SELF_INTERSECTION if ring.crosses?(exterior) end # check interiors do not cross poly.interior_rings.combination(2).each do |ring1, ring2| return Error::SELF_INTERSECTION if ring1.crosses?(ring2) end # Duplicate rings check rings = [exterior] + poly.interior_rings return Error::SELF_INTERSECTION if rings.uniq.size != rings.size nil end |
.check_consistent_area_mp(mpoly) ⇒ String
Checks that polygons do not intersect in a multipolygon.
326 327 328 329 330 331 |
# File 'lib/rgeo/impl_helper/valid_op.rb', line 326 def check_consistent_area_mp(mpoly) mpoly.geometries.combination(2) do |p1, p2| return Error::SELF_INTERSECTION if p1.exterior_ring.crosses?(p2.exterior_ring) end nil end |
.check_holes_in_shell(poly) ⇒ String
Checks holes are contained inside the exterior of a polygon. Assuming check_consistent_area has already passed on the polygon, a simple point in polygon check can be done on one of the points in each hole to verify (since we know none of them intersect).
261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/rgeo/impl_helper/valid_op.rb', line 261 def check_holes_in_shell(poly) # get hole-less shell as test polygon shell = poly.exterior_ring shell = shell.factory.polygon(shell) poly.interior_rings.each do |interior| test_pt = interior.start_point return Error::HOLE_OUTSIDE_SHELL unless shell.contains?(test_pt) || poly.exterior_ring.contains?(test_pt) end nil end |
.check_holes_not_nested(poly) ⇒ String
Checks that holes are not nested within each other.
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/rgeo/impl_helper/valid_op.rb', line 279 def check_holes_not_nested(poly) # convert holes from linear_rings to polygons # Same logic that applies to check_holes_in_shell applies here # since we've already passed the consistent area test, we just # have to check if one point from each hole is contained in the other. holes = poly.interior_rings holes = holes.map { |v| v.factory.polygon(v) } holes.combination(2).each do |p1, p2| if p1.contains?(p2.exterior_ring.start_point) || p2.contains?(p1.exterior_ring.start_point) return Error::NESTED_HOLES end end nil end |
.check_invalid_coordinate(point) ⇒ String
Checks that the given point has valid coordinates.
187 188 189 190 191 192 193 |
# File 'lib/rgeo/impl_helper/valid_op.rb', line 187 def check_invalid_coordinate(point) x = point.x y = point.y return if x.finite? && y.finite? && x.real? && y.real? Error::INVALID_COORDINATE end |
.check_no_self_intersecting_rings(poly) ⇒ String
Check that rings do not self intersect in a polygon
239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/rgeo/impl_helper/valid_op.rb', line 239 def check_no_self_intersecting_rings(poly) exterior = poly.exterior_ring check = check_no_self_intersections(exterior) return check unless check.nil? poly.interior_rings.each do |ring| check = check_no_self_intersections(ring) return check unless check.nil? end nil end |
.check_no_self_intersections(ring) ⇒ String
Checks that the ring does not self-intersect. This is just a simplicity check on the ring.
230 231 232 |
# File 'lib/rgeo/impl_helper/valid_op.rb', line 230 def check_no_self_intersections(ring) return Error::SELF_INTERSECTION unless ring.simple? end |
.check_shells_not_nested(mpoly) ⇒ String
Checks that individual polygons within a multipolygon are not nested.
338 339 340 341 342 343 344 345 346 347 |
# File 'lib/rgeo/impl_helper/valid_op.rb', line 338 def check_shells_not_nested(mpoly) # Since we've passed the consistent area test, we can just check # that one point lies in the other. mpoly.geometries.combination(2) do |p1, p2| if p1.contains?(p2.exterior_ring.start_point) || p2.contains?(p1.exterior_ring.start_point) return Error::NESTED_SHELLS end end nil end |