From 21b0b23a67ee1aa1a35f7f64cd8fe997e4de89d7 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 22 Dec 2023 17:21:08 +0000 Subject: [PATCH] Refs #35058 -- Made OGRGeomType aware of additional WKB geometry types. This commit increases OGRGeomType's knowledge of WKB types and allows for improved error messages when Django doesn't yet have a corresponding class to wrap a given type. --- django/contrib/gis/gdal/geometries.py | 4 +- django/contrib/gis/gdal/geomtype.py | 48 +++++++++++++++ django/contrib/gis/geometry.py | 4 +- tests/gis_tests/gdal_tests/test_geom.py | 81 ++++++++++++++++++++++++- 4 files changed, 134 insertions(+), 3 deletions(-) diff --git a/django/contrib/gis/gdal/geometries.py b/django/contrib/gis/gdal/geometries.py index f74dc688b3..5094413642 100644 --- a/django/contrib/gis/gdal/geometries.py +++ b/django/contrib/gis/gdal/geometries.py @@ -123,7 +123,9 @@ class OGRGeometry(GDALBase): self.srs = srs # Setting the class depending upon the OGR Geometry Type - self.__class__ = GEO_CLASSES[self.geom_type.num] + if (geo_class := GEO_CLASSES.get(self.geom_type.num)) is None: + raise TypeError(f"Unsupported geometry type: {self.geom_type}") + self.__class__ = geo_class # Pickle routines def __getstate__(self): diff --git a/django/contrib/gis/gdal/geomtype.py b/django/contrib/gis/gdal/geomtype.py index 6f342b3c96..c8c4703a82 100644 --- a/django/contrib/gis/gdal/geomtype.py +++ b/django/contrib/gis/gdal/geomtype.py @@ -16,9 +16,57 @@ class OGRGeomType: 5: "MultiLineString", 6: "MultiPolygon", 7: "GeometryCollection", + 8: "CircularString", + 9: "CompoundCurve", + 10: "CurvePolygon", + 11: "MultiCurve", + 12: "MultiSurface", + 15: "PolyhedralSurface", + 16: "TIN", + 17: "Triangle", 100: "None", 101: "LinearRing", 102: "PointZ", + 1008: "CircularStringZ", + 1009: "CompoundCurveZ", + 1010: "CurvePolygonZ", + 1011: "MultiCurveZ", + 1012: "MultiSurfaceZ", + 1013: "CurveZ", + 1014: "SurfaceZ", + 1015: "PolyhedralSurfaceZ", + 1016: "TINZ", + 1017: "TriangleZ", + 2001: "PointM", + 2002: "LineStringM", + 2003: "PolygonM", + 2004: "MultiPointM", + 2005: "MultiLineStringM", + 2006: "MultiPolygonM", + 2007: "GeometryCollectionM", + 2008: "CircularStringM", + 2009: "CompoundCurveM", + 2010: "CurvePolygonM", + 2011: "MultiCurveM", + 2012: "MultiSurfaceM", + 2015: "PolyhedralSurfaceM", + 2016: "TINM", + 2017: "TriangleM", + 3001: "PointZM", + 3002: "LineStringZM", + 3003: "PolygonZM", + 3004: "MultiPointZM", + 3005: "MultiLineStringZM", + 3006: "MultiPolygonZM", + 3007: "GeometryCollectionZM", + 3008: "CircularStringZM", + 3009: "CompoundCurveZM", + 3010: "CurvePolygonZM", + 3011: "MultiCurveZM", + 3012: "MultiSurfaceZM", + 3015: "PolyhedralSurfaceZM", + 3016: "TINZM", + 3017: "TriangleZM", 1 + wkb25bit: "Point25D", 2 + wkb25bit: "LineString25D", 3 + wkb25bit: "Polygon25D", diff --git a/django/contrib/gis/geometry.py b/django/contrib/gis/geometry.py index b5caf04be4..7aac8644ee 100644 --- a/django/contrib/gis/geometry.py +++ b/django/contrib/gis/geometry.py @@ -10,7 +10,9 @@ wkt_regex = _lazy_re_compile( r"^(SRID=(?P\-?[0-9]+);)?" r"(?P" r"(?PPOINT|LINESTRING|LINEARRING|POLYGON|MULTIPOINT|" - r"MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION)" + r"MULTILINESTRING|MULTIPOLYGON|GEOMETRYCOLLECTION|CIRCULARSTRING|COMPOUNDCURVE|" + r"CURVEPOLYGON|MULTICURVE|MULTISURFACE|CURVE|SURFACE|POLYHEDRALSURFACE|TIN|" + r"TRIANGLE)" r"[ACEGIMLONPSRUTYZ0-9,.+() -]+)$", re.I, ) diff --git a/tests/gis_tests/gdal_tests/test_geom.py b/tests/gis_tests/gdal_tests/test_geom.py index 913e465ef1..372a385443 100644 --- a/tests/gis_tests/gdal_tests/test_geom.py +++ b/tests/gis_tests/gdal_tests/test_geom.py @@ -35,7 +35,7 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin): with self.assertRaises(GDALException): OGRGeomType("fooD") with self.assertRaises(GDALException): - OGRGeomType(9) + OGRGeomType(4001) # Equivalence can take strings, ints, and other OGRGeomTypes self.assertEqual(OGRGeomType(1), OGRGeomType(1)) @@ -635,3 +635,82 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin): def test_empty_point_to_geos(self): p = OGRGeometry("POINT EMPTY", srs=4326) self.assertEqual(p.geos.ewkt, p.ewkt) + + def test_geometry_types(self): + tests = [ + ("Point", 1, True), + ("LineString", 2, True), + ("Polygon", 3, True), + ("MultiPoint", 4, True), + ("Multilinestring", 5, True), + ("MultiPolygon", 6, True), + ("GeometryCollection", 7, True), + ("CircularString", 8, False), + ("CompoundCurve", 9, False), + ("CurvePolygon", 10, False), + ("MultiCurve", 11, False), + ("MultiSurface", 12, False), + # 13 (Curve) and 14 (Surface) are abstract types. + ("PolyhedralSurface", 15, False), + ("TIN", 16, False), + ("Triangle", 17, False), + ("Linearring", 2, True), + # Types 1 - 7 with Z dimension have 2.5D enums. + ("Point Z", -2147483647, True), # 1001 + ("LineString Z", -2147483646, True), # 1002 + ("Polygon Z", -2147483645, True), # 1003 + ("MultiPoint Z", -2147483644, True), # 1004 + ("Multilinestring Z", -2147483643, True), # 1005 + ("MultiPolygon Z", -2147483642, True), # 1006 + ("GeometryCollection Z", -2147483641, True), # 1007 + ("CircularString Z", 1008, False), + ("CompoundCurve Z", 1009, False), + ("CurvePolygon Z", 1010, False), + ("MultiCurve Z", 1011, False), + ("MultiSurface Z", 1012, False), + ("PolyhedralSurface Z", 1015, False), + ("TIN Z", 1016, False), + ("Triangle Z", 1017, False), + ("Point M", 2001, False), + ("LineString M", 2002, False), + ("Polygon M", 2003, False), + ("MultiPoint M", 2004, False), + ("MultiLineString M", 2005, False), + ("MultiPolygon M", 2006, False), + ("GeometryCollection M", 2007, False), + ("CircularString M", 2008, False), + ("CompoundCurve M", 2009, False), + ("CurvePolygon M", 2010, False), + ("MultiCurve M", 2011, False), + ("MultiSurface M", 2012, False), + ("PolyhedralSurface M", 2015, False), + ("TIN M", 2016, False), + ("Triangle M", 2017, False), + ("Point ZM", 3001, False), + ("LineString ZM", 3002, False), + ("Polygon ZM", 3003, False), + ("MultiPoint ZM", 3004, False), + ("MultiLineString ZM", 3005, False), + ("MultiPolygon ZM", 3006, False), + ("GeometryCollection ZM", 3007, False), + ("CircularString ZM", 3008, False), + ("CompoundCurve ZM", 3009, False), + ("CurvePolygon ZM", 3010, False), + ("MultiCurve ZM", 3011, False), + ("MultiSurface ZM", 3012, False), + ("PolyhedralSurface ZM", 3015, False), + ("TIN ZM", 3016, False), + ("Triangle ZM", 3017, False), + ] + + for test in tests: + geom_type, num, supported = test + with self.subTest(geom_type=geom_type, num=num, supported=supported): + if supported: + g = OGRGeometry(f"{geom_type} EMPTY") + self.assertEqual(g.geom_type.num, num) + else: + type_ = geom_type.replace(" ", "") + msg = f"Unsupported geometry type: {type_}" + with self.assertRaisesMessage(TypeError, msg): + OGRGeometry(f"{geom_type} EMPTY")