diff --git a/fastkml/geometry.py b/fastkml/geometry.py index c7dfb10b..a6e63892 100644 --- a/fastkml/geometry.py +++ b/fastkml/geometry.py @@ -980,6 +980,55 @@ def etree_element( ) return element + @classmethod + def _get_polygon_kwargs( + cls, + *, + ns: str, + element: Element, + strict: bool, + ) -> Dict[str, Any]: + outer_boundary = element.find(f"{ns}outerBoundaryIs") + if outer_boundary is None: + error = config.etree.tostring( # type: ignore[attr-defined] + element, + encoding="UTF-8", + ).decode("UTF-8") + raise KMLParseError(f"Missing outerBoundaryIs in {error}") + outer_ring = outer_boundary.find(f"{ns}LinearRing") + if outer_ring is None: + error = config.etree.tostring( # type: ignore[attr-defined] + element, + encoding="UTF-8", + ).decode("UTF-8") + raise KMLParseError(f"Missing LinearRing in {error}") + exterior = cls._get_geometry(ns=ns, element=outer_ring, strict=strict) + interiors = [] + for inner_boundary in element.findall(f"{ns}innerBoundaryIs"): + inner_ring = inner_boundary.find(f"{ns}LinearRing") + if inner_ring is None: + error = config.etree.tostring( # type: ignore[attr-defined] + element, + encoding="UTF-8", + ).decode("UTF-8") + raise KMLParseError(f"Missing LinearRing in {error}") + interiors.append( + cls._get_geometry(ns=ns, element=inner_ring, strict=strict) + ) + return {"geometry": geo.Polygon.from_linear_rings(exterior, *interiors)} + + @classmethod + def _get_kwargs( + cls, + *, + ns: str, + element: Element, + strict: bool, + ) -> Dict[str, Any]: + kwargs = super()._get_kwargs(ns=ns, element=element, strict=strict) + kwargs.update(cls._get_polygon_kwargs(ns=ns, element=element, strict=strict)) + return kwargs + class MultiGeometry(_Geometry): ... diff --git a/tests/geometries/polygon_test.py b/tests/geometries/polygon_test.py index db7be840..6003870f 100644 --- a/tests/geometries/polygon_test.py +++ b/tests/geometries/polygon_test.py @@ -15,6 +15,8 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA """Test the geometry classes.""" +from typing import cast + import pygeoif.geometry as geo from fastkml.geometry import Polygon @@ -60,6 +62,45 @@ def test_exterior_interior(self): "0.900000,0.100000 0.100000,0.100000" ) in polygon.to_string() + def test_from_string_exterior_only(self): + """Test exterior only.""" + doc = """ + + + 0.000000,0.000000 1.000000,0.000000 1.000000,1.000000 + 0.000000,0.000000 + + + """ + + polygon2 = cast(Polygon, Polygon.class_from_string(doc)) + + assert polygon2.geometry == geo.Polygon([(0, 0), (1, 0), (1, 1), (0, 0)]) + + def test_from_string_exterior_interior(self): + doc = """ + + + -1.000000,-1.000000 2.000000,-1.000000 2.000000,2.000000 + -1.000000,-1.000000 + + + + + 0.000000,0.000000 1.000000,0.000000 1.000000,1.000000 + 0.000000,0.000000 + + + + """ + + polygon2 = cast(Polygon, Polygon.class_from_string(doc)) + + assert polygon2.geometry == geo.Polygon( + [(-1, -1), (2, -1), (2, 2), (-1, -1)], + [[(0, 0), (1, 0), (1, 1), (0, 0)]], + ) + class TestLxml(Lxml, TestStdLibrary): """Test with lxml."""