1
0
mirror of https://github.com/django/django.git synced 2025-05-07 15:36:29 +00:00

Refs #34406 -- Added support for GDAL curved geometries.

Co-authored-by: Fabien Le Frapper <contact@fabienlefrapper.me>
This commit is contained in:
David Smith 2024-10-22 21:24:36 +01:00 committed by GitHub
parent dd0a116b93
commit 04adff9f98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 292 additions and 23 deletions

View File

@ -64,6 +64,7 @@ class OGRGeometry(GDALBase):
"""Encapsulate an OGR geometry.""" """Encapsulate an OGR geometry."""
destructor = capi.destroy_geom destructor = capi.destroy_geom
geos_support = True
def __init__(self, geom_input, srs=None): def __init__(self, geom_input, srs=None):
"""Initialize Geometry on either WKT or an OGR pointer as input.""" """Initialize Geometry on either WKT or an OGR pointer as input."""
@ -304,6 +305,19 @@ class OGRGeometry(GDALBase):
f"Input to 'set_measured' must be a boolean, got '{value!r}'." f"Input to 'set_measured' must be a boolean, got '{value!r}'."
) )
@property
def has_curve(self):
"""Return True if the geometry is or has curve geometry."""
return capi.has_curve_geom(self.ptr, 0)
def get_linear_geometry(self):
"""Return a linear version of this geometry."""
return OGRGeometry(capi.get_linear_geom(self.ptr, 0, None))
def get_curve_geometry(self):
"""Return a curve version of this geometry."""
return OGRGeometry(capi.get_curve_geom(self.ptr, None))
# #### SpatialReference-related Properties #### # #### SpatialReference-related Properties ####
# The SRS property # The SRS property
@ -360,9 +374,14 @@ class OGRGeometry(GDALBase):
@property @property
def geos(self): def geos(self):
"Return a GEOSGeometry object from this OGRGeometry." "Return a GEOSGeometry object from this OGRGeometry."
if self.geos_support:
from django.contrib.gis.geos import GEOSGeometry from django.contrib.gis.geos import GEOSGeometry
return GEOSGeometry(self._geos_ptr(), self.srid) return GEOSGeometry(self._geos_ptr(), self.srid)
else:
from django.contrib.gis.geos import GEOSException
raise GEOSException(f"GEOS does not support {self.__class__.__qualname__}.")
@property @property
def gml(self): def gml(self):
@ -727,6 +746,18 @@ class Polygon(OGRGeometry):
return sum(self[i].point_count for i in range(self.geom_count)) return sum(self[i].point_count for i in range(self.geom_count))
class CircularString(LineString):
geos_support = False
class CurvePolygon(Polygon):
geos_support = False
class CompoundCurve(OGRGeometry):
geos_support = False
# Geometry Collection base class. # Geometry Collection base class.
class GeometryCollection(OGRGeometry): class GeometryCollection(OGRGeometry):
"The Geometry Collection class." "The Geometry Collection class."
@ -788,6 +819,14 @@ class MultiPolygon(GeometryCollection):
pass pass
class MultiSurface(GeometryCollection):
geos_support = False
class MultiCurve(GeometryCollection):
geos_support = False
# Class mapping dictionary (using the OGRwkbGeometryType as the key) # Class mapping dictionary (using the OGRwkbGeometryType as the key)
GEO_CLASSES = { GEO_CLASSES = {
1: Point, 1: Point,
@ -797,7 +836,17 @@ GEO_CLASSES = {
5: MultiLineString, 5: MultiLineString,
6: MultiPolygon, 6: MultiPolygon,
7: GeometryCollection, 7: GeometryCollection,
8: CircularString,
9: CompoundCurve,
10: CurvePolygon,
11: MultiCurve,
12: MultiSurface,
101: LinearRing, 101: LinearRing,
1008: CircularString, # CIRCULARSTRING Z
1009: CompoundCurve, # COMPOUNDCURVE Z
1010: CurvePolygon, # CURVEPOLYGON Z
1011: MultiCurve, # MULTICURVE Z
1012: MultiSurface, # MULTICURVE Z
2001: Point, # POINT M 2001: Point, # POINT M
2002: LineString, # LINESTRING M 2002: LineString, # LINESTRING M
2003: Polygon, # POLYGON M 2003: Polygon, # POLYGON M
@ -805,6 +854,11 @@ GEO_CLASSES = {
2005: MultiLineString, # MULTILINESTRING M 2005: MultiLineString, # MULTILINESTRING M
2006: MultiPolygon, # MULTIPOLYGON M 2006: MultiPolygon, # MULTIPOLYGON M
2007: GeometryCollection, # GEOMETRYCOLLECTION M 2007: GeometryCollection, # GEOMETRYCOLLECTION M
2008: CircularString, # CIRCULARSTRING M
2009: CompoundCurve, # COMPOUNDCURVE M
2010: CurvePolygon, # CURVEPOLYGON M
2011: MultiCurve, # MULTICURVE M
2012: MultiSurface, # MULTICURVE M
3001: Point, # POINT ZM 3001: Point, # POINT ZM
3002: LineString, # LINESTRING ZM 3002: LineString, # LINESTRING ZM
3003: Polygon, # POLYGON ZM 3003: Polygon, # POLYGON ZM
@ -812,6 +866,11 @@ GEO_CLASSES = {
3005: MultiLineString, # MULTILINESTRING ZM 3005: MultiLineString, # MULTILINESTRING ZM
3006: MultiPolygon, # MULTIPOLYGON ZM 3006: MultiPolygon, # MULTIPOLYGON ZM
3007: GeometryCollection, # GEOMETRYCOLLECTION ZM 3007: GeometryCollection, # GEOMETRYCOLLECTION ZM
3008: CircularString, # CIRCULARSTRING ZM
3009: CompoundCurve, # COMPOUNDCURVE ZM
3010: CurvePolygon, # CURVEPOLYGON ZM
3011: MultiCurve, # MULTICURVE ZM
3012: MultiSurface, # MULTISURFACE ZM
1 + OGRGeomType.wkb25bit: Point, # POINT Z 1 + OGRGeomType.wkb25bit: Point, # POINT Z
2 + OGRGeomType.wkb25bit: LineString, # LINESTRING Z 2 + OGRGeomType.wkb25bit: LineString, # LINESTRING Z
3 + OGRGeomType.wkb25bit: Polygon, # POLYGON Z 3 + OGRGeomType.wkb25bit: Polygon, # POLYGON Z

View File

@ -85,6 +85,13 @@ is_3d = bool_output(lgdal.OGR_G_Is3D, [c_void_p])
set_3d = void_output(lgdal.OGR_G_Set3D, [c_void_p, c_int], errcheck=False) set_3d = void_output(lgdal.OGR_G_Set3D, [c_void_p, c_int], errcheck=False)
is_measured = bool_output(lgdal.OGR_G_IsMeasured, [c_void_p]) is_measured = bool_output(lgdal.OGR_G_IsMeasured, [c_void_p])
set_measured = void_output(lgdal.OGR_G_SetMeasured, [c_void_p, c_int], errcheck=False) set_measured = void_output(lgdal.OGR_G_SetMeasured, [c_void_p, c_int], errcheck=False)
has_curve_geom = bool_output(lgdal.OGR_G_HasCurveGeometry, [c_void_p, c_int])
get_linear_geom = geom_output(
lgdal.OGR_G_GetLinearGeometry, [c_void_p, c_double, POINTER(c_char_p)]
)
get_curve_geom = geom_output(
lgdal.OGR_G_GetCurveGeometry, [c_void_p, POINTER(c_char_p)]
)
# Geometry modification routines. # Geometry modification routines.
add_geom = void_output(lgdal.OGR_G_AddGeometry, [c_void_p, c_void_p]) add_geom = void_output(lgdal.OGR_G_AddGeometry, [c_void_p, c_void_p])

View File

@ -611,6 +611,26 @@ coordinate transformation:
>>> polygon.geom_count >>> polygon.geom_count
1 1
.. attribute:: has_curve
.. versionadded:: 5.2
A boolean indicating if this geometry is or contains a curve geometry.
.. method:: get_linear_geometry
.. versionadded:: 5.2
Returns a linear version of the geometry. If no conversion can be made, the
original geometry is returned.
.. method:: get_curve_geometry
.. versionadded:: 5.2
Returns a curved version of the geometry. If no conversion can be made, the
original geometry is returned.
.. attribute:: point_count .. attribute:: point_count
Returns the number of points used to describe this geometry: Returns the number of points used to describe this geometry:

View File

@ -94,7 +94,11 @@ Minor features
:mod:`django.contrib.gis` :mod:`django.contrib.gis`
~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
* ... * GDAL now supports curved geometries ``CurvePolygon``, ``CompoundCurve``,
``CircularString``, ``MultiSurface``, and ``MultiCurve`` via the new
:attr:`.OGRGeometry.has_curve` property, and the
:meth:`.OGRGeometry.get_linear_geometry` and
:meth:`.OGRGeometry.get_curve_geometry` methods.
:mod:`django.contrib.messages` :mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -137,5 +137,87 @@
"union_geoms": [ "union_geoms": [
{"wkt": "POLYGON ((-5 0,-5 10,5 10,5 5,10 5,10 -5,0 -5,0 0,-5 0))"}, {"wkt": "POLYGON ((-5 0,-5 10,5 10,5 5,10 5,10 -5,0 -5,0 0,-5 0))"},
{"wkt": "POLYGON ((2 0, 2 15, 18 15, 18 0, 2 0))"} {"wkt": "POLYGON ((2 0, 2 15, 18 15, 18 0, 2 0))"}
],
"curved_geoms": [
{"wkt": "CIRCULARSTRING(1 5, 6 2, 7 3)",
"name": "CircularString",
"num": 8
},
{"wkt": "COMPOUNDCURVE((5 3, 5 13), CIRCULARSTRING(5 13, 7 15, 9 13), (9 13, 9 3), CIRCULARSTRING(9 3, 7 1, 5 3))",
"name": "CompoundCurve",
"num": 9
},
{"wkt": "CURVEPOLYGON(CIRCULARSTRING(0 0, 4 0, 4 4, 0 4, 0 0),(1 1, 3 3, 3 1, 1 1))",
"name": "CurvePolygon",
"num": 10
},
{"wkt": "MULTICURVE((0 0, 5 5), CIRCULARSTRING(4 0, 4 4, 8 4))",
"name": "MultiCurve",
"num": 11
},
{"wkt": "MULTISURFACE(((0 0, 0 1, 1 1, 1 0, 0 0)), ((1 1, 1 2, 2 2, 2 1, 1 1)))",
"name": "MultiSurface",
"num": 12
},
{"wkt": "CIRCULARSTRING Z (1 5 1, 6 2 2, 7 3 3)",
"name": "CircularStringZ",
"num": 1008
},
{"wkt": "COMPOUNDCURVE Z ((5 3 0, 5 13 0), CIRCULARSTRING Z (5 13 0, 7 15 0, 9 13 0), (9 13 0 , 9 3 0), CIRCULARSTRING(9 3 0, 7 1 0, 5 3 0))",
"name": "CompoundCurveZ",
"num": 1009
},
{"wkt": "CURVEPOLYGON Z(CIRCULARSTRING Z (0 0 0, 4 0 0, 4 4 0, 0 4 0, 0 0 0),(1 1 0, 3 3 0, 3 1 0, 1 1 0))",
"name": "CurvePolygonZ",
"num": 1010
},
{"wkt": "MULTICURVE Z ((0 0 1, 5 5 2), CIRCULARSTRING Z (4 0 0, 4 4 0, 8 4 0))",
"name": "MultiCurveZ",
"num": 1011
},
{"wkt": "MULTISURFACE Z (((0 0 1, 0 1 2, 1 1 3, 1 0 4, 0 0 5)), ((1 1 0, 1 2 0, 2 2 0, 2 1 0, 1 1 0)))",
"name": "MultiSurfaceZ",
"num": 1012
},
{"wkt": "CIRCULARSTRING M (1 5 1, 6 2 2, 7 3 3)",
"name": "CircularStringM",
"num": 2008
},
{"wkt": "COMPOUNDCURVE M ((5 3 0, 5 13 0), CIRCULARSTRING M (5 13 0, 7 15 0, 9 13 0), (9 13 0 , 9 3 0), CIRCULARSTRING M (9 3 0, 7 1 0, 5 3 0))",
"name": "CompoundCurveM",
"num": 2009
},
{"wkt": "CURVEPOLYGON M (CIRCULARSTRING M (0 0 0, 4 0 0, 4 4 0, 0 4 0, 0 0 0),(1 1 0, 3 3 1, 3 1 1, 1 1 2))",
"name": "CurvePolygonM",
"num": 2010
},
{"wkt": "MULTICURVE M ((0 0 1, 5 5 2), CIRCULARSTRING M (4 0 0, 4 4 0, 8 4 0))",
"name": "MultiCurveM",
"num": 2011
},
{"wkt": "MULTISURFACE M (((0 0 1, 0 1 2, 1 1 3, 1 0 4, 0 0 5)), ((1 1 0, 1 2 0, 2 2 0, 2 1 0, 1 1 0)))",
"name": "MultiSurfaceM",
"num": 2012
},
{"wkt": "CIRCULARSTRING ZM (1 5 0 1, 6 2 0 2, 7 3 0 3)",
"name": "CircularStringZM",
"num": 3008
},
{"wkt": "COMPOUNDCURVE ZM ((5 3 0 0, 5 13 0 0), CIRCULARSTRING ZM (5 13 0 0, 7 15 0 0, 9 13 0 0), (9 13 0 0, 9 3 0 0), CIRCULARSTRING ZM (9 3 0 0, 7 1 0 0, 5 3 0 0))",
"name": "CompoundCurveZM",
"num": 3009
},
{"wkt": "CURVEPOLYGON ZM (CIRCULARSTRING ZM (0 0 0 0, 4 0 0 0, 4 4 0 0, 0 4 0 0, 0 0 0 0), (1 1 0 0, 3 3 0 0, 3 1 0 0, 1 1 0 0))",
"name": "CurvePolygonZM",
"num": 3010
},
{"wkt": "MULTICURVE ZM ((0 0 0 1, 5 5 0 2), CIRCULARSTRING ZM (4 0 0 0, 4 4 0 0, 8 4 0 0))",
"name": "MultiCurveZM",
"num": 3011
},
{"wkt": "MULTISURFACE ZM (((0 0 0 1, 0 1 0 2, 1 1 0 3, 1 0 0 4, 0 0 0 5)), ((1 1 0 0, 1 2 0 0, 2 2 0 0, 2 1 0 0, 1 1 0 0)))",
"name": "MultiSurfaceZM",
"num": 3012
}
] ]
} }

View File

@ -8,6 +8,8 @@ from django.contrib.gis.gdal import (
OGRGeomType, OGRGeomType,
SpatialReference, SpatialReference,
) )
from django.contrib.gis.gdal.geometries import CircularString, CurvePolygon
from django.contrib.gis.geos import GEOSException
from django.template import Context from django.template import Context
from django.template.engine import Engine from django.template.engine import Engine
from django.test import SimpleTestCase from django.test import SimpleTestCase
@ -646,11 +648,11 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
("Multilinestring", 5, True), ("Multilinestring", 5, True),
("MultiPolygon", 6, True), ("MultiPolygon", 6, True),
("GeometryCollection", 7, True), ("GeometryCollection", 7, True),
("CircularString", 8, False), ("CircularString", 8, True),
("CompoundCurve", 9, False), ("CompoundCurve", 9, True),
("CurvePolygon", 10, False), ("CurvePolygon", 10, True),
("MultiCurve", 11, False), ("MultiCurve", 11, True),
("MultiSurface", 12, False), ("MultiSurface", 12, True),
# 13 (Curve) and 14 (Surface) are abstract types. # 13 (Curve) and 14 (Surface) are abstract types.
("PolyhedralSurface", 15, False), ("PolyhedralSurface", 15, False),
("TIN", 16, False), ("TIN", 16, False),
@ -664,11 +666,11 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
("Multilinestring Z", -2147483643, True), # 1005 ("Multilinestring Z", -2147483643, True), # 1005
("MultiPolygon Z", -2147483642, True), # 1006 ("MultiPolygon Z", -2147483642, True), # 1006
("GeometryCollection Z", -2147483641, True), # 1007 ("GeometryCollection Z", -2147483641, True), # 1007
("CircularString Z", 1008, False), ("CircularString Z", 1008, True),
("CompoundCurve Z", 1009, False), ("CompoundCurve Z", 1009, True),
("CurvePolygon Z", 1010, False), ("CurvePolygon Z", 1010, True),
("MultiCurve Z", 1011, False), ("MultiCurve Z", 1011, True),
("MultiSurface Z", 1012, False), ("MultiSurface Z", 1012, True),
("PolyhedralSurface Z", 1015, False), ("PolyhedralSurface Z", 1015, False),
("TIN Z", 1016, False), ("TIN Z", 1016, False),
("Triangle Z", 1017, False), ("Triangle Z", 1017, False),
@ -679,11 +681,11 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
("MultiLineString M", 2005, True), ("MultiLineString M", 2005, True),
("MultiPolygon M", 2006, True), ("MultiPolygon M", 2006, True),
("GeometryCollection M", 2007, True), ("GeometryCollection M", 2007, True),
("CircularString M", 2008, False), ("CircularString M", 2008, True),
("CompoundCurve M", 2009, False), ("CompoundCurve M", 2009, True),
("CurvePolygon M", 2010, False), ("CurvePolygon M", 2010, True),
("MultiCurve M", 2011, False), ("MultiCurve M", 2011, True),
("MultiSurface M", 2012, False), ("MultiSurface M", 2012, True),
("PolyhedralSurface M", 2015, False), ("PolyhedralSurface M", 2015, False),
("TIN M", 2016, False), ("TIN M", 2016, False),
("Triangle M", 2017, False), ("Triangle M", 2017, False),
@ -694,11 +696,11 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
("MultiLineString ZM", 3005, True), ("MultiLineString ZM", 3005, True),
("MultiPolygon ZM", 3006, True), ("MultiPolygon ZM", 3006, True),
("GeometryCollection ZM", 3007, True), ("GeometryCollection ZM", 3007, True),
("CircularString ZM", 3008, False), ("CircularString ZM", 3008, True),
("CompoundCurve ZM", 3009, False), ("CompoundCurve ZM", 3009, True),
("CurvePolygon ZM", 3010, False), ("CurvePolygon ZM", 3010, True),
("MultiCurve ZM", 3011, False), ("MultiCurve ZM", 3011, True),
("MultiSurface ZM", 3012, False), ("MultiSurface ZM", 3012, True),
("PolyhedralSurface ZM", 3015, False), ("PolyhedralSurface ZM", 3015, False),
("TIN ZM", 3016, False), ("TIN ZM", 3016, False),
("Triangle ZM", 3017, False), ("Triangle ZM", 3017, False),
@ -967,6 +969,101 @@ class OGRGeomTest(SimpleTestCase, TestDataMixin):
geom = OGRGeometry(geom_input) geom = OGRGeometry(geom_input)
self.assertIs(geom.is_measured, True) self.assertIs(geom.is_measured, True)
def test_has_curve(self):
for geom in self.geometries.curved_geoms:
with self.subTest(wkt=geom.wkt):
geom = OGRGeometry(geom.wkt)
self.assertIs(geom.has_curve, True)
msg = f"GEOS does not support {geom.__class__.__qualname__}."
with self.assertRaisesMessage(GEOSException, msg):
geom.geos
geom = OGRGeometry("POINT (0 1)")
self.assertIs(geom.has_curve, False)
def test_get_linear_geometry(self):
geom = OGRGeometry("CIRCULARSTRING (-0.797 0.466,-0.481 0.62,-0.419 0.473)")
linear = geom.get_linear_geometry()
self.assertEqual(linear.geom_name, "LINESTRING")
self.assertIs(linear.has_curve, False)
def test_get_linear_geometry_no_conversion_possible(self):
wkt = "POINT (0 0)"
geom = OGRGeometry(wkt)
geom2 = geom.get_linear_geometry()
self.assertEqual(geom2.wkt, wkt)
def test_get_curve_geometry(self):
linear_string = OGRGeometry(
"LINESTRING (-0.797 0.466,-0.797500910583869 0.479079607685707,"
"-0.797096828208069 0.49216256476959,-0.795789684575482 0.505186328593822,"
"-0.793585728444384 0.518088639471983,-0.79049549575663 0.530807818319715,"
"-0.786533759270668 0.543283061509385,-0.781719457941079 0.555454731539925,"
"-0.776075606381369 0.567264642132187,-0.769629184843353 0.578656336386302,"
"-0.76241101023902 0.589575356672327,-0.754455588821145 0.599969504963013,"
"-0.745800951227352 0.609789092364991,-0.736488470675795 0.618987176654798,"
"-0.726562665181888 0.627519786684672,-0.716070984741265 0.635346132585369,"
"-0.705063584496685 0.642428800760598,-0.693593084972889 0.648733932741749,"
"-0.681714320525941 0.654231387047048,-0.669484077209319 0.658894883272069,"
"-0.656960821309923 0.662702127722269,-0.644204419852031 0.665634919987354,"
"-0.631275854404748 0.667679239947688,-0.618236929561618 0.668825314797118,"
"-0.60514997748578 0.669067665761503,-0.592077559933017 0.66840513428977,"
"-0.579082169177269 0.666840887592428,-0.566225929268313 0.664382403500809,"
"-0.553570299049824 0.661041434719465,-0.541175778357228 0.656833952642756,"
"-0.529101618800212 0.651780071004197,-0.5174055405123 0.645903949723276,"
"-0.506143456221622 0.639233679409784,-0.495369203961872 0.631801147077652,"
"-0.485134289701335 0.623641883709865,-0.475487641120239 0.614794894404014,"
"-0.46647537371355 0.605302471909454,-0.458140570337321 0.595209994448282,"
"-0.450523075252448 0.58456570878613,-0.443659303650563 0.573420499590156,"
"-0.437582067572208 0.561827646176397,-0.432320419050072 0.549842567809747,"
"-0.427899511226613 0.537522558773986,-0.424340478110267 0.524926514478182,"
"-0.421660333544978 0.512114649909193,-0.419871889876113 0.499148211775737,"
"-0.418983696701434 0.486089185720561,-0.419 0.473)"
)
curve = linear_string.get_curve_geometry()
self.assertEqual(curve.geom_name, "CIRCULARSTRING")
self.assertEqual(
curve.wkt,
"CIRCULARSTRING (-0.797 0.466,-0.618236929561618 "
"0.668825314797118,-0.419 0.473)",
)
def test_get_curve_geometry_no_conversion_possible(self):
geom = OGRGeometry("LINESTRING (0 0, 1 0, 2 0)")
geom2 = geom.get_curve_geometry()
self.assertEqual(geom2.wkt, geom.wkt)
def test_curved_geometries(self):
for geom in self.geometries.curved_geoms:
with self.subTest(wkt=geom.wkt, geom_name=geom.name):
g = OGRGeometry(geom.wkt)
self.assertEqual(geom.name, g.geom_type.name)
self.assertEqual(geom.num, g.geom_type.num)
msg = f"GEOS does not support {g.__class__.__qualname__}."
with self.assertRaisesMessage(GEOSException, msg):
g.geos
def test_circularstring_has_linestring_features(self):
geom = OGRGeometry("CIRCULARSTRING ZM (1 5 0 1, 6 2 0 2, 7 3 0 3)")
self.assertIsInstance(geom, CircularString)
self.assertEqual(geom.x, [1, 6, 7])
self.assertEqual(geom.y, [5, 2, 3])
self.assertEqual(geom.z, [0, 0, 0])
self.assertEqual(geom.m, [1, 2, 3])
self.assertEqual(
geom.tuple,
((1.0, 5.0, 0.0, 1.0), (6.0, 2.0, 0.0, 2.0), (7.0, 3.0, 0.0, 3.0)),
)
self.assertEqual(geom[0], (1, 5, 0, 1))
self.assertEqual(len(geom), 3)
def test_curvepolygon_has_polygon_features(self):
geom = OGRGeometry(
"CURVEPOLYGON ZM (CIRCULARSTRING ZM (0 0 0 0, 4 0 0 0, 4 4 0 0, 0 4 0 0, "
"0 0 0 0), (1 1 0 0, 3 3 0 0, 3 1 0 0, 1 1 0 0))"
)
self.assertIsInstance(geom, CurvePolygon)
self.assertIsInstance(geom.shell, CircularString)
class DeprecationTests(SimpleTestCase): class DeprecationTests(SimpleTestCase):
def test_coord_setter_deprecation(self): def test_coord_setter_deprecation(self):