Add QgsGeometry.from_shapely() conversion method

This commit is contained in:
Till Frankenbach 2025-04-23 09:27:40 +02:00 committed by Nyall Dawson
parent 49e4c089cd
commit 01ed5b5c0e
5 changed files with 151 additions and 1 deletions

View File

@ -112,6 +112,7 @@ RUN apt-get update \
requests \
six \
hdbcli \
shapely \
&& apt-get clean
# Node.js and Yarn for server landingpage webapp

View File

@ -112,6 +112,7 @@ RUN dnf -y install \
python3-gdal \
python3-nose2 \
python3-psycopg2 \
python3-pyyaml
python3-pyyaml \
python3-shapely
FROM binary-only

View File

@ -742,12 +742,25 @@ try:
QgsGeometry.as_shapely = _geometry_as_shapely
def _geometry_from_shapely(shapely_geom) -> QgsGeometry:
geom = QgsGeometry()
geom.fromWkb(shapely_geom.wkb)
return geom
QgsGeometry.from_shapely = _geometry_from_shapely
except ModuleNotFoundError:
def _geometry_as_shapely(self):
raise QgsNotSupportedException('QgsGeometry.as_shapely is not available, shapely is not installed on the system')
QgsGeometry.as_shapely = _geometry_as_shapely
def _geometry_from_shapely(self):
raise QgsNotSupportedException('QgsGeometry.from_shapely is not available, shapely is not installed on the system')
QgsGeometry.from_shapely = _geometry_from_shapely
QgsRasterBlock.as_numpy.__doc__ = """
Returns the block data as a numpy array.
@ -786,3 +799,11 @@ Returns the geometry data as a shapely object.
.. versionadded:: 3.40
"""
QgsGeometry.from_shapely.__doc__ = """
Creates a new geometry from a shapely object.
:raises QgsNotSupportedException: if shapely is not available on the system
.. versionadded:: 3.42
"""

View File

@ -753,12 +753,25 @@ try:
QgsGeometry.as_shapely = _geometry_as_shapely
def _geometry_from_shapely(shapely_geom) -> QgsGeometry:
geom = QgsGeometry()
geom.fromWkb(shapely_geom.wkb)
return geom
QgsGeometry.from_shapely = _geometry_from_shapely
except ModuleNotFoundError:
def _geometry_as_shapely(self):
raise QgsNotSupportedException('QgsGeometry.as_shapely is not available, shapely is not installed on the system')
QgsGeometry.as_shapely = _geometry_as_shapely
def _geometry_from_shapely(self):
raise QgsNotSupportedException('QgsGeometry.from_shapely is not available, shapely is not installed on the system')
QgsGeometry.from_shapely = _geometry_from_shapely
QgsRasterBlock.as_numpy.__doc__ = """
Returns the block data as a numpy array.
@ -796,3 +809,11 @@ Returns the geometry data as a shapely object.
.. versionadded:: 3.40
"""
QgsGeometry.from_shapely.__doc__ = """
Creates a new geometry from a shapely object.
:raises QgsNotSupportedException: if shapely is not available on the system
.. versionadded:: 3.42
"""

View File

@ -57,6 +57,7 @@ from qgis.core import (
)
import unittest
import numpy
import shapely
from qgis.testing import start_app, QgisTestCase
from utilities import compareWkt, unitTestDataPath, writeShape
@ -14335,6 +14336,111 @@ class TestQgsGeometry(QgisTestCase):
)
)
def testFromShapely(self):
"""Test geometry creation from a shapely object."""
shapely_point = shapely.Point(1.0, 2.0)
qgs_point = QgsGeometry.from_shapely(shapely_point)
self.assertTrue(isinstance(qgs_point, QgsGeometry))
self.assertEqual(qgs_point.asWkt(), "Point (1 2)")
shapely_point_z = shapely.Point(1.0, 2.0, 3.0)
qgs_point_z = QgsGeometry.from_shapely(shapely_point_z)
self.assertTrue(isinstance(qgs_point_z, QgsGeometry))
self.assertEqual(qgs_point_z.asWkt(), "Point Z (1 2 3)")
shapely_multipoint = shapely.MultiPoint([(1.0, 2.0), (3.0, 4.0)])
qgs_multipoint = QgsGeometry.from_shapely(shapely_multipoint)
self.assertTrue(isinstance(qgs_multipoint, QgsGeometry))
self.assertEqual(qgs_multipoint.asWkt(), "MultiPoint ((1 2),(3 4))")
shapely_multipoint_z = shapely.MultiPoint([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)])
qgs_multipoint_z = QgsGeometry.from_shapely(shapely_multipoint_z)
self.assertTrue(isinstance(qgs_multipoint_z, QgsGeometry))
self.assertEqual(qgs_multipoint_z.asWkt(), "MultiPoint Z ((1 2 3),(4 5 6))")
shapely_linestring = shapely.LineString([(1.0, 2.0), (3.0, 4.0)])
qgs_linestring = QgsGeometry.from_shapely(shapely_linestring)
self.assertTrue(isinstance(qgs_linestring, QgsGeometry))
self.assertEqual(qgs_linestring.asWkt(), "LineString (1 2, 3 4)")
shapely_linestring_z = shapely.LineString([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)])
qgs_linestring_z = QgsGeometry.from_shapely(shapely_linestring_z)
self.assertEqual(qgs_linestring_z.asWkt(), "LineString Z (1 2 3, 4 5 6)")
shapely_multilinestring = shapely.MultiLineString(
[[(1.0, 2.0), (3.0, 4.0)], [(5.0, 6.0), (7.0, 8.0)]]
)
qgs_multilinestring = QgsGeometry.from_shapely(shapely_multilinestring)
self.assertEqual(
qgs_multilinestring.asWkt(), "MultiLineString ((1 2, 3 4),(5 6, 7 8))"
)
shapely_multilinestring_z = shapely.MultiLineString(
[[(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)], [(7.0, 8.0, 9.0), (10.0, 11.0, 12.0)]]
)
qgs_multilinestring_z = QgsGeometry.from_shapely(shapely_multilinestring_z)
self.assertEqual(
qgs_multilinestring_z.asWkt(),
"MultiLineString Z ((1 2 3, 4 5 6),(7 8 9, 10 11 12))",
)
shapely_polygon = shapely.Polygon([(0, 0), (4, 0), (4, 4), (0, 4), (0, 0)])
qgs_polygon = QgsGeometry.from_shapely(shapely_polygon)
self.assertEqual(qgs_polygon.asWkt(), "Polygon ((0 0, 4 0, 4 4, 0 4, 0 0))")
# 3D Polygon
shapely_polygon_z = shapely.Polygon(
[(0, 0, 1), (4, 0, 2), (4, 4, 3), (0, 4, 4), (0, 0, 1)]
)
qgs_polygon_z = QgsGeometry.from_shapely(shapely_polygon_z)
self.assertEqual(
qgs_polygon_z.asWkt(), "Polygon Z ((0 0 1, 4 0 2, 4 4 3, 0 4 4, 0 0 1))"
)
poly1 = shapely.Polygon([(0, 0), (2, 0), (2, 2), (0, 2), (0, 0)])
poly2 = shapely.Polygon([(3, 3), (5, 3), (5, 5), (3, 5), (3, 3)])
shapely_multipolygon = shapely.MultiPolygon([poly1, poly2])
qgs_multipolygon = QgsGeometry.from_shapely(shapely_multipolygon)
self.assertEqual(
qgs_multipolygon.asWkt(),
"MultiPolygon (((0 0, 2 0, 2 2, 0 2, 0 0)),((3 3, 5 3, 5 5, 3 5, 3 3)))",
)
poly1_z = shapely.Polygon(
[(0, 0, 1), (2, 0, 2), (2, 2, 3), (0, 2, 4), (0, 0, 1)]
)
poly2_z = shapely.Polygon(
[(3, 3, 5), (5, 3, 6), (5, 5, 7), (3, 5, 8), (3, 3, 5)]
)
shapely_multipolygon_z = shapely.MultiPolygon([poly1_z, poly2_z])
qgs_multipolygon_z = QgsGeometry.from_shapely(shapely_multipolygon_z)
self.assertEqual(
qgs_multipolygon_z.asWkt(),
(
"MultiPolygon Z (((0 0 1, 2 0 2, 2 2 3, 0 2 4, 0 0 1)),((3 3 5, 5 3 6, 5 5 7, "
"3 5 8, 3 3 5)))"
),
)
shapely_gc = shapely.GeometryCollection(
[
shapely.Point(1, 2),
shapely.LineString([(3, 4), (5, 6)]),
shapely.Polygon([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]),
]
)
qgs_gc = QgsGeometry.from_shapely(shapely_gc)
self.assertIsInstance(qgs_gc, QgsGeometry)
self.assertTrue(qgs_gc.isGeosValid())
self.assertTrue(qgs_gc.isMultipart())
self.assertEqual(
qgs_gc.asWkt(),
"GeometryCollection (Point (1 2),LineString (3 4, 5 6),Polygon ((0 0, 1 0, 1 1, 0 1, 0 0)))",
)
if __name__ == "__main__":
unittest.main()