From 7e20fe4cdcc75624d16db211abccaa6cd4e17a65 Mon Sep 17 00:00:00 2001 From: "Juergen E. Fischer" Date: Sat, 27 Jan 2018 17:07:33 +0100 Subject: [PATCH] make converting to multi geometries to fullfil provider geometry constraints the last step and use earlier conversions (fixes #17643) --- src/core/geometry/qgsgeometrycollection.cpp | 2 ++ src/core/qgsvectordataprovider.cpp | 30 ++++++++++++--------- tests/src/python/test_provider_postgres.py | 27 ++++++++++++++++--- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/core/geometry/qgsgeometrycollection.cpp b/src/core/geometry/qgsgeometrycollection.cpp index e1c0bdc7db2f..577aa9f17022 100644 --- a/src/core/geometry/qgsgeometrycollection.cpp +++ b/src/core/geometry/qgsgeometrycollection.cpp @@ -852,5 +852,7 @@ int QgsGeometryCollection::childCount() const QgsAbstractGeometry *QgsGeometryCollection::childGeometry( int index ) const { + if ( index < 0 || index > mGeometries.count() ) + return nullptr; return mGeometries.at( index ); } diff --git a/src/core/qgsvectordataprovider.cpp b/src/core/qgsvectordataprovider.cpp index 66f58bf135e7..8498bbb902bf 100644 --- a/src/core/qgsvectordataprovider.cpp +++ b/src/core/qgsvectordataprovider.cpp @@ -725,17 +725,6 @@ QgsGeometry QgsVectorDataProvider::convertToProviderType( const QgsGeometry &geo } } - //convert to multitype if necessary - if ( QgsWkbTypes::isMultiType( providerGeomType ) && !QgsWkbTypes::isMultiType( geometry->wkbType() ) ) - { - outputGeom = QgsGeometryFactory::geomFromWkbType( providerGeomType ); - QgsGeometryCollection *geomCollection = qgsgeometry_cast( outputGeom.get() ); - if ( geomCollection ) - { - geomCollection->addGeometry( geometry->clone() ); - } - } - //convert to curved type if necessary if ( !QgsWkbTypes::isCurvedType( geometry->wkbType() ) && QgsWkbTypes::isCurvedType( providerGeomType ) ) { @@ -749,14 +738,27 @@ QgsGeometry QgsVectorDataProvider::convertToProviderType( const QgsGeometry &geo //convert to linear type from curved type if ( QgsWkbTypes::isCurvedType( geometry->wkbType() ) && !QgsWkbTypes::isCurvedType( providerGeomType ) ) { - QgsAbstractGeometry *segmentizedGeom = nullptr; - segmentizedGeom = outputGeom ? outputGeom->segmentize() : geometry->segmentize(); + QgsAbstractGeometry *segmentizedGeom = outputGeom ? outputGeom->segmentize() : geometry->segmentize(); if ( segmentizedGeom ) { outputGeom.reset( segmentizedGeom ); } } + //convert to multitype if necessary + if ( QgsWkbTypes::isMultiType( providerGeomType ) && !QgsWkbTypes::isMultiType( geometry->wkbType() ) ) + { + std::unique_ptr< QgsAbstractGeometry > collGeom( QgsGeometryFactory::geomFromWkbType( providerGeomType ) ); + QgsGeometryCollection *geomCollection = qgsgeometry_cast( collGeom.get() ); + if ( geomCollection ) + { + if ( geomCollection->addGeometry( outputGeom ? outputGeom->clone() : geometry->clone() ) ) + { + outputGeom.reset( collGeom.release() ); + } + } + } + //set z/m types if ( QgsWkbTypes::hasZ( providerGeomType ) ) { @@ -766,6 +768,7 @@ QgsGeometry QgsVectorDataProvider::convertToProviderType( const QgsGeometry &geo } outputGeom->addZValue(); } + if ( QgsWkbTypes::hasM( providerGeomType ) ) { if ( !outputGeom ) @@ -779,6 +782,7 @@ QgsGeometry QgsVectorDataProvider::convertToProviderType( const QgsGeometry &geo { return QgsGeometry( outputGeom.release() ); } + return QgsGeometry(); } diff --git a/tests/src/python/test_provider_postgres.py b/tests/src/python/test_provider_postgres.py index 39bd0906f81e..7031ac9a556f 100644 --- a/tests/src/python/test_provider_postgres.py +++ b/tests/src/python/test_provider_postgres.py @@ -37,8 +37,9 @@ QgsReadWriteContext, QgsRectangle, QgsDefaultValue, - QgsDataSourceUri, - QgsProject + QgsProject, + QgsWkbTypes, + QgsGeometry ) from qgis.gui import QgsGui from qgis.PyQt.QtCore import QDate, QTime, QDateTime, QVariant, QDir, QObject @@ -807,7 +808,7 @@ def _test(table, schema=None): table = ("%s" % table) if schema is None else ("\"%s\".\"%s\"" % (schema, table)) dest_uri = "%s sslmode=disable table=%s (geom) sql" % (self.dbconn, table) - err = QgsVectorLayerExporter.exportLayer(lyr, dest_uri, "postgres", lyr.crs()) + QgsVectorLayerExporter.exportLayer(lyr, dest_uri, "postgres", lyr.crs()) olyr = QgsVectorLayer(dest_uri, "y", "postgres") self.assertTrue(olyr.isValid(), "Failed URI: %s" % dest_uri) @@ -1035,6 +1036,26 @@ def testStyleDatabaseWithService(self): ids = styles[1] self.assertEqual(len(ids), 0) + def testCurveToMultipolygon(self): + self.execSQLCommand('CREATE TABLE IF NOT EXISTS multicurve(pk SERIAL NOT NULL PRIMARY KEY, geom public.geometry(MultiPolygon, 4326))') + self.execSQLCommand('TRUNCATE multicurve') + + vl = QgsVectorLayer(self.dbconn + ' sslmode=disable key=\'pk\' srid=4326 type=MULTIPOLYGON table="multicurve" (geom) sql=', 'test', 'postgres') + + f = QgsFeature(vl.fields()) + f.setGeometry(QgsGeometry.fromWkt('CurvePolygon(CircularString (20 30, 50 30, 50 90, 10 50, 20 30))')) + self.assertTrue(vl.startEditing()) + self.assertTrue(vl.addFeatures([f])) + self.assertTrue(vl.commitChanges()) + + f = next(vl.getFeatures(QgsFeatureRequest())) + + g = f.geometry().constGet() + self.assertTrue(g) + self.assertEqual(g.wkbType(), QgsWkbTypes.MultiPolygon) + self.assertEqual(g.childCount(), 1) + self.assertTrue(g.childGeometry(0).vertexCount() > 3) + class TestPyQgsPostgresProviderCompoundKey(unittest.TestCase, ProviderTestCase):