Skip to content

Commit

Permalink
Remove maybe_valid, stricter is_empty
Browse files Browse the repository at this point in the history
  • Loading branch information
cleder committed Feb 4, 2024
1 parent 4e22a36 commit 29094d3
Show file tree
Hide file tree
Showing 5 changed files with 4 additions and 203 deletions.
69 changes: 3 additions & 66 deletions pygeoif/geometry.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (C) 2012 -2023 Christian Ledermann
# Copyright (C) 2012 -2024 Christian Ledermann
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -383,26 +383,15 @@ def is_empty(self) -> bool:
"""
Return if this geometry is empty.
A Linestring is considered empty when it has less than 2 points.
A Linestring is considered empty when it has no points.
"""
return len(self._geoms) < 2 # noqa: PLR2004
return len(self._geoms) == 0

@property
def has_z(self) -> Optional[bool]:
"""Return True if the geometry's coordinate sequence(s) have z values."""
return self._geoms[0].has_z if self.geoms else None

@property
def maybe_valid(self) -> bool:
"""
Check validity of the coordinates.
Returns False if the coordinates collapse to a single Point.
This only highlights obvious problems with this geometry.
Even if this test passes the geometry may still be invalid.
"""
return len({p.coords[0] for p in self._geoms}) > 1

@property
def _wkt_coords(self) -> str:
return ", ".join(point._wkt_coords for point in self.geoms) # noqa: SLF001
Expand Down Expand Up @@ -506,26 +495,6 @@ def is_ccw(self) -> bool:
"""Return True if the ring is oriented counter clock-wise."""
return signed_area(self.coords) >= 0

@property
def maybe_valid(self) -> bool:
"""
Check validity of the coordinates.
This only highlights obvious problems with this geometry.
Even if this test passes the geometry may still be invalid.
"""
if self.has_z:
msg = "Validation is only implemented for 2D coordinates"
raise DimensionError(msg)
min_x, min_y, max_x, max_y = self.bounds # type: ignore [misc]
if min_x == max_x or min_y == max_y:
return False
try:
_, area = centroid(self.coords)
except ZeroDivisionError:
return False
return math.isclose(a=area, b=signed_area(self.coords))


class Polygon(_Geometry):
"""
Expand Down Expand Up @@ -619,22 +588,6 @@ def has_z(self) -> Optional[bool]:
"""Return True if the geometry's coordinate sequence(s) have z values."""
return self._geoms[0].has_z

@property
def maybe_valid(self) -> bool:
"""
Check validity of the coordinates.
This only highlights obvious problems with this geometry.
Even if this test passes the geometry may still be invalid.
"""
if not self._check_interior_bounds():
return False
return (
all(interior.maybe_valid for interior in self.interiors)
if self.exterior.maybe_valid
else False
)

@property
def _wkt_coords(self) -> str:
ec = self.exterior._wkt_coords # noqa: SLF001
Expand Down Expand Up @@ -672,22 +625,6 @@ def _from_dict(cls, geo_interface: GeoInterface) -> "Polygon":
holes=cast(Tuple[LineType], geo_interface["coordinates"][1:]),
)

def _check_interior_bounds(self) -> bool:
"""Check that the bounding boxes of holes are inside the bounds of the shell."""
bounds = self.bounds
if not bounds:
return False
for interior in self.interiors:
i_box = cast(Bounds, interior.bounds)
if (
bounds[0] > i_box[0]
or bounds[1] > i_box[1]
or bounds[2] < i_box[2]
or bounds[3] < i_box[3]
):
return False
return True

def _get_bounds(self) -> Bounds:
return self.exterior._get_bounds() # noqa: SLF001

Expand Down
1 change: 0 additions & 1 deletion tests/test_factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,6 @@ def test_force_2d_polygon() -> None:
((0.5, 0.5), (0.5, 1.5), (1.5, 1.5), (1.5, 0.5), (0.5, 0.5)),
)
assert not p2d.has_z
assert p.maybe_valid == p2d.maybe_valid

# 3d to 2d
external = [(0, 0, 1), (0, 2, 1), (2, 2, 1), (2, 0, 1), (0, 0, 1)]
Expand Down
20 changes: 1 addition & 19 deletions tests/test_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,24 +191,6 @@ def test_from_coordinates() -> None:
assert geometry.LineString.from_coordinates(line.coords) == line


def test_maybe_valid() -> None:
line = geometry.LineString([(0, 0), (1, 0)])

assert line.maybe_valid


def test_maybe_valid_point() -> None:
line = geometry.LineString([(0, 0), (0, 0)])

assert not line.maybe_valid


def test_maybe_empty() -> None:
line = geometry.LineString([])

assert not line.maybe_valid


def test_empty() -> None:
line = geometry.LineString([])

Expand All @@ -218,7 +200,7 @@ def test_empty() -> None:
def test_empty_1_pt() -> None:
line = geometry.LineString([(0, 0)])

assert line.is_empty
assert not line.is_empty


def test_repr_empty() -> None:
Expand Down
40 changes: 0 additions & 40 deletions tests/test_linear_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,46 +151,6 @@ def test_convex_hull_linear_ring() -> None:
assert line.convex_hull == geometry.Polygon([(0, 0), (1, 0), (2, 2), (0, 0)])


def test_maybe_valid_crossing() -> None:
line = geometry.LinearRing([(0, 0), (1, 0), (1, 1), (0, -1)])

assert not line.maybe_valid


def test_maybe_valid_no_area() -> None:
line = geometry.LinearRing([(0, 0), (1, 1)])

assert not line.maybe_valid


def test_maybe_valid_x_line() -> None:
line = geometry.LinearRing([(0, 2), (1, 2)])

assert not line.maybe_valid


def test_maybe_valid_y_line() -> None:
line = geometry.LinearRing([(3, 0), (3, 1)])

assert not line.maybe_valid


def test_maybe_valid_happy() -> None:
line = geometry.LinearRing([(0, 0), (1, 0), (1, 1), (0, 0)])

assert line.maybe_valid


def test_valid_3d() -> None:
line = geometry.LinearRing([(0, 0, 1), (2, 0, 2), (2, 2, 0), (0, 2, 0)])

with pytest.raises(
exceptions.DimensionError,
match="^Validation is only implemented for 2D coordinates$",
):
assert line.maybe_valid


def test_is_ccw() -> None:
line = geometry.LinearRing([(0, 0), (1, 0), (1, 1), (0, 0)])

Expand Down
77 changes: 0 additions & 77 deletions tests/test_polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,77 +250,6 @@ def test_from_coordinates_with_holes() -> None:
assert geometry.Polygon.from_coordinates(polygon.coords) == polygon


def test_maybe_valid() -> None:
e = [(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)]
i = [(0.5, 0.5), (1, 1), (0.5, 1)]
polygon = geometry.Polygon(e, [i])

assert polygon.maybe_valid


def test_maybe_valid_touching_hole() -> None:
"""A Hole may touch an exterior at one point."""
e = [(0, 0), (0, 4), (4, 4), (4, 0)]
interiors_gen = (((1, 1), (2, 3), e[pt]) for pt in range(len(e)))
for polygon in (geometry.Polygon(e, [interior]) for interior in interiors_gen):
assert polygon.maybe_valid


def test_is_invalid_hole_too_big_y() -> None:
"""A Hole may not cross an exterior."""
e = [(0, 0), (0, 4), (4, 4), (4, 0)]
outside = (
(-1, -1),
(-1, 5),
(5, 5),
(5, -1),
(-1, 0),
(-1, 4),
(5, 4),
(5, 0),
(0, -1),
(0, 5),
(4, 5),
(4, -1),
)
interiors_gen = (
((1 + (i & 1), 1), (3, 3 - (i & 1)), outside[i]) for i in range(len(e))
)
for polygon in (geometry.Polygon(e, [interior]) for interior in interiors_gen):
assert not polygon.maybe_valid


def test_is_invalid_hole_too_big_x() -> None:
e = [(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)]
i = [(0.5, 0.5), (3, 1), (0.5, 1)]
polygon = geometry.Polygon(e, [i])

assert not polygon.maybe_valid


def test_is_invalid_hole_too_big_min() -> None:
e = [(0, 0), (0, 2), (2, 2), (2, 0), (0, 0)]
i = [(-0.5, -0.5), (3, 1), (0.5, 1)]
polygon = geometry.Polygon(e, [i])

assert not polygon.maybe_valid


def test_is_invalid_exterior() -> None:
e = [(0, 0), (1, 0), (1, 1), (0, -1), (0, 0)]
polygon = geometry.Polygon(e)

assert not polygon.maybe_valid


def test_is_invalid_interior() -> None:
e = [(-2, -2), (-2, 2), (2, 2), (2, -2), (-2, -2)]
i = [(0, 0), (1, 0), (1, 1), (0, -1), (0, 0)]
polygon = geometry.Polygon(e, [i])

assert not polygon.maybe_valid


def test_empty() -> None:
polygon = geometry.Polygon([])

Expand All @@ -343,9 +272,3 @@ def test_empty_bounds() -> None:
polygon = geometry.Polygon([])

assert polygon.bounds == ()


def test_maybe_valid_empty() -> None:
polygon = geometry.Polygon([])

assert not polygon.maybe_valid

0 comments on commit 29094d3

Please sign in to comment.