From 679e8f2e8d096cd149034a71d933e33463994ffa Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Wed, 27 Apr 2016 16:26:07 +0200 Subject: [PATCH 1/6] Convert added/changed geometries into the right before sending back to provider --- src/core/geometry/qgsabstractgeometryv2.h | 5 ++ src/core/geometry/qgsgeometry.cpp | 5 ++ src/core/geometry/qgslinestringv2.cpp | 8 +++ src/core/geometry/qgslinestringv2.h | 3 + src/core/geometry/qgsmultilinestringv2.cpp | 11 +++ src/core/geometry/qgsmultilinestringv2.h | 3 + src/core/geometry/qgsmultipolygonv2.cpp | 10 +++ src/core/geometry/qgsmultipolygonv2.h | 3 + src/core/geometry/qgspolygonv2.cpp | 12 ++++ src/core/geometry/qgspolygonv2.h | 3 + src/core/qgsvectorlayereditbuffer.cpp | 83 ++++++++++++++++++++++ src/core/qgsvectorlayereditbuffer.h | 2 + 12 files changed, 148 insertions(+) diff --git a/src/core/geometry/qgsabstractgeometryv2.h b/src/core/geometry/qgsabstractgeometryv2.h index e6f72d6a555..9057cebadd1 100644 --- a/src/core/geometry/qgsabstractgeometryv2.h +++ b/src/core/geometry/qgsabstractgeometryv2.h @@ -292,6 +292,11 @@ class CORE_EXPORT QgsAbstractGeometryV2 */ virtual QgsAbstractGeometryV2* segmentize() const { return clone(); } + /** Returns the geometry converted to the more generic curve type. + E.g. QgsLineStringV2 -> QgsCompoundCurveV2, QgsPolygonV2 -> QgsCurvePolygonV2, + QgsMultiLineStringV2 -> QgsMultiCurveV2, QgsMultiPolygonV2 -> QgsMultiSurfaceV2*/ + virtual QgsAbstractGeometryV2* toCurveType() const { return 0; } + /** Returns approximate angle at a vertex. This is usually the average angle between adjacent * segments, and can be pictured as the orientation of a line following the curvature of the * geometry at the specified vertex. diff --git a/src/core/geometry/qgsgeometry.cpp b/src/core/geometry/qgsgeometry.cpp index 3bffeea23a5..48179956169 100644 --- a/src/core/geometry/qgsgeometry.cpp +++ b/src/core/geometry/qgsgeometry.cpp @@ -132,6 +132,11 @@ QgsAbstractGeometryV2* QgsGeometry::geometry() const void QgsGeometry::setGeometry( QgsAbstractGeometryV2* geometry ) { + if ( d->geometry == geometry ) + { + return; + } + detach( false ); if ( d->geometry ) { diff --git a/src/core/geometry/qgslinestringv2.cpp b/src/core/geometry/qgslinestringv2.cpp index a6d2cd124f4..13534a88550 100644 --- a/src/core/geometry/qgslinestringv2.cpp +++ b/src/core/geometry/qgslinestringv2.cpp @@ -17,6 +17,7 @@ #include "qgslinestringv2.h" #include "qgsapplication.h" +#include "qgscompoundcurvev2.h" #include "qgscoordinatetransform.h" #include "qgsgeometryutils.h" #include "qgsmaptopixel.h" @@ -583,6 +584,13 @@ QPolygonF QgsLineStringV2::asQPolygonF() const return points; } +QgsAbstractGeometryV2* QgsLineStringV2::toCurveType() const +{ + QgsCompoundCurveV2* compoundCurve = new QgsCompoundCurveV2(); + compoundCurve->addCurve( clone() ); + return compoundCurve; +} + /*************************************************************************** * This class is considered CRITICAL and any change MUST be accompanied with * full unit tests. diff --git a/src/core/geometry/qgslinestringv2.h b/src/core/geometry/qgslinestringv2.h index 3ebfff2424c..16677d56287 100644 --- a/src/core/geometry/qgslinestringv2.h +++ b/src/core/geometry/qgslinestringv2.h @@ -132,6 +132,9 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2 */ QPolygonF asQPolygonF() const; + /** Returns the geometry converted to QgsCompoundCurveV2*/ + QgsAbstractGeometryV2* toCurveType() const override; + //reimplemented methods virtual QString geometryType() const override { return "LineString"; } diff --git a/src/core/geometry/qgsmultilinestringv2.cpp b/src/core/geometry/qgsmultilinestringv2.cpp index fc1a9e6b137..a83bdc6d24f 100644 --- a/src/core/geometry/qgsmultilinestringv2.cpp +++ b/src/core/geometry/qgsmultilinestringv2.cpp @@ -20,6 +20,7 @@ email : marco.hugentobler at sourcepole dot com #include "qgscompoundcurvev2.h" #include "qgsgeometryutils.h" #include "qgslinestringv2.h" +#include "qgsmulticurvev2.h" QgsMultiLineStringV2* QgsMultiLineStringV2::clone() const { @@ -101,3 +102,13 @@ bool QgsMultiLineStringV2::addGeometry( QgsAbstractGeometryV2* g ) setZMTypeFromSubGeometry( g, QgsWKBTypes::MultiLineString ); return QgsGeometryCollectionV2::addGeometry( g ); } + +QgsAbstractGeometryV2* QgsMultiLineStringV2::toCurveType() const +{ + QgsMultiCurveV2* multiCurve = new QgsMultiCurveV2(); + for ( int i = 0; i < mGeometries.size(); ++i ) + { + multiCurve->addGeometry( mGeometries.at( i )->clone() ); + } + return multiCurve; +} diff --git a/src/core/geometry/qgsmultilinestringv2.h b/src/core/geometry/qgsmultilinestringv2.h index f3de42044a8..6e28ad4728d 100644 --- a/src/core/geometry/qgsmultilinestringv2.h +++ b/src/core/geometry/qgsmultilinestringv2.h @@ -42,6 +42,9 @@ class CORE_EXPORT QgsMultiLineStringV2: public QgsMultiCurveV2 /** Adds a geometry and takes ownership. Returns true in case of success*/ virtual bool addGeometry( QgsAbstractGeometryV2* g ) override; + /** Returns the geometry converted to QgsMultiCurveV2*/ + QgsAbstractGeometryV2* toCurveType() const override; + protected: virtual bool wktOmitChildType() const override { return true; } diff --git a/src/core/geometry/qgsmultipolygonv2.cpp b/src/core/geometry/qgsmultipolygonv2.cpp index 80e9ca0a286..8277989f326 100644 --- a/src/core/geometry/qgsmultipolygonv2.cpp +++ b/src/core/geometry/qgsmultipolygonv2.cpp @@ -117,3 +117,13 @@ bool QgsMultiPolygonV2::addGeometry( QgsAbstractGeometryV2* g ) setZMTypeFromSubGeometry( g, QgsWKBTypes::MultiPolygon ); return QgsGeometryCollectionV2::addGeometry( g ); } + +QgsAbstractGeometryV2* QgsMultiPolygonV2::toCurveType() const +{ + QgsMultiSurfaceV2* multiSurface = new QgsMultiSurfaceV2(); + for ( int i = 0; i < mGeometries.size(); ++i ) + { + multiSurface->addGeometry( mGeometries.at( i )->clone() ); + } + return multiSurface; +} diff --git a/src/core/geometry/qgsmultipolygonv2.h b/src/core/geometry/qgsmultipolygonv2.h index d59a71e78f2..176dfd14e47 100644 --- a/src/core/geometry/qgsmultipolygonv2.h +++ b/src/core/geometry/qgsmultipolygonv2.h @@ -43,6 +43,9 @@ class CORE_EXPORT QgsMultiPolygonV2: public QgsMultiSurfaceV2 /** Adds a geometry and takes ownership. Returns true in case of success*/ virtual bool addGeometry( QgsAbstractGeometryV2* g ) override; + /** Returns the geometry converted to QgsMultiSurfaceV2*/ + QgsAbstractGeometryV2* toCurveType() const override; + protected: virtual bool wktOmitChildType() const override { return true; } diff --git a/src/core/geometry/qgspolygonv2.cpp b/src/core/geometry/qgspolygonv2.cpp index 3521df01554..9fecf25e93b 100644 --- a/src/core/geometry/qgspolygonv2.cpp +++ b/src/core/geometry/qgspolygonv2.cpp @@ -240,3 +240,15 @@ QgsPolygonV2* QgsPolygonV2::surfaceToPolygon() const { return clone(); } + +QgsAbstractGeometryV2* QgsPolygonV2::toCurveType() const +{ + QgsCurvePolygonV2* curvePolygon = new QgsCurvePolygonV2(); + curvePolygon->setExteriorRing( mExteriorRing->clone() ); + int nInteriorRings = mInteriorRings.size(); + for ( int i = 0; i < nInteriorRings; ++i ) + { + curvePolygon->addInteriorRing( mInteriorRings.at( i )->clone() ); + } + return curvePolygon; +} diff --git a/src/core/geometry/qgspolygonv2.h b/src/core/geometry/qgspolygonv2.h index c645a8d35b6..1f0c125f270 100644 --- a/src/core/geometry/qgspolygonv2.h +++ b/src/core/geometry/qgspolygonv2.h @@ -50,6 +50,9 @@ class CORE_EXPORT QgsPolygonV2: public QgsCurvePolygonV2 QgsPolygonV2* surfaceToPolygon() const override; + /** Returns the geometry converted to QgsCurvePolygonV2*/ + QgsAbstractGeometryV2* toCurveType() const override; + void addInteriorRing( QgsCurveV2* ring ) override; //overridden to handle LineString25D rings virtual void setExteriorRing( QgsCurveV2* ring ) override; diff --git a/src/core/qgsvectorlayereditbuffer.cpp b/src/core/qgsvectorlayereditbuffer.cpp index 99d82d30a12..aa55662372b 100644 --- a/src/core/qgsvectorlayereditbuffer.cpp +++ b/src/core/qgsvectorlayereditbuffer.cpp @@ -15,7 +15,13 @@ #include "qgsvectorlayereditbuffer.h" #include "qgsgeometry.h" +#include "qgscurvepolygonv2.h" +#include "qgscurvev2.h" +#include "qgsgeometrycollectionv2.h" +#include "qgsgeometryfactory.h" +#include "qgsgeometryutils.h" #include "qgslogger.h" +#include "qgspolygonv2.h" #include "qgsvectorlayerundocommand.h" #include "qgsvectordataprovider.h" #include "qgsvectorlayer.h" @@ -270,6 +276,23 @@ bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors ) int cap = provider->capabilities(); bool success = true; + //convert added features to a type accepted by the backend + QgsFeatureMap::iterator addedIt = mAddedFeatures.begin(); + for ( ; addedIt != mAddedFeatures.end(); ++addedIt ) + { + QgsGeometry* geom = addedIt.value().geometry(); + if ( geom ) + { + geom->setGeometry( outputGeometry( geom->geometry() ) ); + } + } + + QgsGeometryMap::iterator changedIt = mChangedGeometries.begin(); + for ( ; changedIt != mChangedGeometries.end(); ++changedIt ) + { + changedIt.value().setGeometry( outputGeometry( changedIt.value().geometry() ) ); + } + // geometry updates attribute updates // yes no => changeGeometryValues // no yes => changeAttributeValues @@ -666,3 +689,63 @@ void QgsVectorLayerEditBuffer::updateLayerFields() { L->updateFields(); } + +QgsAbstractGeometryV2* QgsVectorLayerEditBuffer::outputGeometry( QgsAbstractGeometryV2* geom ) const +{ + if ( !geom || !L ) + { + delete geom; + return nullptr; + } + + QgsWKBTypes::Type providerGeomType = QGis::fromOldWkbType( L->dataProvider()->geometryType() ); + + if ( geom->wkbType() == providerGeomType ) + { + return geom; + } + + QgsAbstractGeometryV2* outputGeom = geom; + + //convert to multitype if necessary + if ( QgsWKBTypes::isMultiType( providerGeomType ) && !QgsWKBTypes::isMultiType( geom->wkbType() ) ) + { + outputGeom = QgsGeometryFactory::geomFromWkbType( providerGeomType ); + QgsGeometryCollectionV2* geomCollection = dynamic_cast( outputGeom ); + if ( geomCollection ) + { + geomCollection->addGeometry( geom ); + } + } + + //convert to curved type if necessary + if ( !QgsWKBTypes::isCurvedType( outputGeom->wkbType() ) && QgsWKBTypes::isCurvedType( providerGeomType ) ) + { + QgsAbstractGeometryV2* curveGeom = outputGeom->toCurveType(); + if ( curveGeom ) + { + outputGeom = curveGeom; + } + } + + //convert to linear type from curved type + if ( QgsWKBTypes::isCurvedType( outputGeom->wkbType() ) && !QgsWKBTypes::isCurvedType( providerGeomType ) ) + { + QgsAbstractGeometryV2* segmentizedGeom = outputGeom->segmentize(); + if ( segmentizedGeom ) + { + outputGeom = segmentizedGeom; + } + } + + //set z/m types + if ( QgsWKBTypes::hasZ( providerGeomType ) ) + { + outputGeom->addZValue(); + } + if ( QgsWKBTypes::hasM( providerGeomType ) ) + { + outputGeom->addMValue(); + } + return outputGeom; +} diff --git a/src/core/qgsvectorlayereditbuffer.h b/src/core/qgsvectorlayereditbuffer.h index f629b12d87a..8f2abb8e2bf 100644 --- a/src/core/qgsvectorlayereditbuffer.h +++ b/src/core/qgsvectorlayereditbuffer.h @@ -156,6 +156,8 @@ class CORE_EXPORT QgsVectorLayerEditBuffer : public QObject void updateLayerFields(); + QgsAbstractGeometryV2* outputGeometry( QgsAbstractGeometryV2* geom ) const; + protected: QgsVectorLayer* L; friend class QgsVectorLayer; From 381895fd6252e43e7beafff440d26dc2fa151ead Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Thu, 28 Apr 2016 09:26:59 +0200 Subject: [PATCH 2/6] Fix crash --- src/core/qgsvectorlayereditbuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/qgsvectorlayereditbuffer.cpp b/src/core/qgsvectorlayereditbuffer.cpp index aa55662372b..641dbd6221a 100644 --- a/src/core/qgsvectorlayereditbuffer.cpp +++ b/src/core/qgsvectorlayereditbuffer.cpp @@ -714,7 +714,7 @@ QgsAbstractGeometryV2* QgsVectorLayerEditBuffer::outputGeometry( QgsAbstractGeom QgsGeometryCollectionV2* geomCollection = dynamic_cast( outputGeom ); if ( geomCollection ) { - geomCollection->addGeometry( geom ); + geomCollection->addGeometry( geom->clone() ); } } From caad9897f496ecc1aa0df6fcf5f7028a680abc66 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Thu, 28 Apr 2016 15:01:41 +0200 Subject: [PATCH 3/6] Add z/m values to new curves of compound curve --- src/core/geometry/qgscompoundcurvev2.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/geometry/qgscompoundcurvev2.cpp b/src/core/geometry/qgscompoundcurvev2.cpp index 819b2bfa6a5..0fbd87146c2 100644 --- a/src/core/geometry/qgscompoundcurvev2.cpp +++ b/src/core/geometry/qgscompoundcurvev2.cpp @@ -390,6 +390,15 @@ void QgsCompoundCurveV2::addCurve( QgsCurveV2* c ) { setZMTypeFromSubGeometry( c, QgsWKBTypes::CompoundCurve ); } + + if ( QgsWKBTypes::hasZ( mWkbType ) && !QgsWKBTypes::hasZ( c->wkbType() ) ) + { + c->addZValue(); + } + if ( QgsWKBTypes::hasM( mWkbType ) && !QgsWKBTypes::hasM( c->wkbType() ) ) + { + c->addMValue(); + } clearCache(); } } From bd6d22d8b6da5a8d81eac27687c29bdc908f1aa8 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Fri, 29 Apr 2016 11:53:34 +0200 Subject: [PATCH 4/6] Update sip bindings --- python/core/geometry/qgsabstractgeometryv2.sip | 6 ++++++ python/core/geometry/qgslinestringv2.sip | 4 ++++ python/core/geometry/qgsmultilinestringv2.sip | 4 ++++ python/core/geometry/qgsmultipolygonv2.sip | 4 ++++ python/core/geometry/qgspolygonv2.sip | 4 ++++ src/core/geometry/qgsabstractgeometryv2.h | 3 ++- src/core/geometry/qgslinestringv2.h | 3 ++- src/core/geometry/qgsmultilinestringv2.h | 3 ++- src/core/geometry/qgsmultipolygonv2.h | 3 ++- src/core/geometry/qgspolygonv2.h | 3 ++- src/core/qgsvectorlayereditbuffer.h | 4 ++-- 11 files changed, 34 insertions(+), 7 deletions(-) diff --git a/python/core/geometry/qgsabstractgeometryv2.sip b/python/core/geometry/qgsabstractgeometryv2.sip index 3cd3ab502c1..aa66e56d2f1 100644 --- a/python/core/geometry/qgsabstractgeometryv2.sip +++ b/python/core/geometry/qgsabstractgeometryv2.sip @@ -306,6 +306,12 @@ class QgsAbstractGeometryV2 */ virtual QgsAbstractGeometryV2* segmentize() const /Factory/; + /** Returns the geometry converted to the more generic curve type. + E.g. QgsLineStringV2 -> QgsCompoundCurveV2, QgsPolygonV2 -> QgsCurvePolygonV2, + QgsMultiLineStringV2 -> QgsMultiCurveV2, QgsMultiPolygonV2 -> QgsMultiSurfaceV2 + @return the converted geometry. Caller takes ownership*/ + virtual QgsAbstractGeometryV2* toCurveType() const /Factory/; + /** Returns approximate angle at a vertex. This is usually the average angle between adjacent * segments, and can be pictured as the orientation of a line following the curvature of the * geometry at the specified vertex. diff --git a/python/core/geometry/qgslinestringv2.sip b/python/core/geometry/qgslinestringv2.sip index fad5fca934c..dc5ead486bb 100644 --- a/python/core/geometry/qgslinestringv2.sip +++ b/python/core/geometry/qgslinestringv2.sip @@ -106,6 +106,10 @@ class QgsLineStringV2: public QgsCurveV2 */ QPolygonF asQPolygonF() const; + /** Returns the geometry converted to the more generic curve type QgsCompoundCurveV2 + @return the converted geometry. Caller takes ownership*/ + QgsAbstractGeometryV2* toCurveType() const /Factory/; + //reimplemented methods virtual QString geometryType() const; diff --git a/python/core/geometry/qgsmultilinestringv2.sip b/python/core/geometry/qgsmultilinestringv2.sip index c1833e74975..f42c39ec53c 100644 --- a/python/core/geometry/qgsmultilinestringv2.sip +++ b/python/core/geometry/qgsmultilinestringv2.sip @@ -20,6 +20,10 @@ class QgsMultiLineStringV2: public QgsMultiCurveV2 /** Adds a geometry and takes ownership. Returns true in case of success*/ virtual bool addGeometry( QgsAbstractGeometryV2* g ); + /** Returns the geometry converted to the more generic curve type QgsMultiCurveV2 + @return the converted geometry. Caller takes ownership*/ + QgsAbstractGeometryV2* toCurveType() const /Factory/; + protected: virtual bool wktOmitChildType() const; diff --git a/python/core/geometry/qgsmultipolygonv2.sip b/python/core/geometry/qgsmultipolygonv2.sip index 26392e2e1e7..f5d5ebd4e31 100644 --- a/python/core/geometry/qgsmultipolygonv2.sip +++ b/python/core/geometry/qgsmultipolygonv2.sip @@ -20,6 +20,10 @@ class QgsMultiPolygonV2: public QgsMultiSurfaceV2 /** Adds a geometry and takes ownership. Returns true in case of success*/ virtual bool addGeometry( QgsAbstractGeometryV2* g ); + /** Returns the geometry converted to the more generic curve type QgsMultiSurfaceV2 + @return the converted geometry. Caller takes ownership*/ + QgsAbstractGeometryV2* toCurveType() const /Factory/; + protected: virtual bool wktOmitChildType() const; diff --git a/python/core/geometry/qgspolygonv2.sip b/python/core/geometry/qgspolygonv2.sip index f52273e6589..fb38cd87372 100644 --- a/python/core/geometry/qgspolygonv2.sip +++ b/python/core/geometry/qgspolygonv2.sip @@ -26,6 +26,10 @@ class QgsPolygonV2: public QgsCurvePolygonV2 QgsPolygonV2* surfaceToPolygon() const; + /** Returns the geometry converted to the more generic curve type QgsCurvePolygonV2 + @return the converted geometry. Caller takes ownership*/ + QgsAbstractGeometryV2* toCurveType() const /Factory/; + void addInteriorRing( QgsCurveV2* ring /Transfer/ ); //overridden to handle LineString25D rings virtual void setExteriorRing( QgsCurveV2* ring /Transfer/ ); diff --git a/src/core/geometry/qgsabstractgeometryv2.h b/src/core/geometry/qgsabstractgeometryv2.h index 9057cebadd1..5863a97cc8e 100644 --- a/src/core/geometry/qgsabstractgeometryv2.h +++ b/src/core/geometry/qgsabstractgeometryv2.h @@ -294,7 +294,8 @@ class CORE_EXPORT QgsAbstractGeometryV2 /** Returns the geometry converted to the more generic curve type. E.g. QgsLineStringV2 -> QgsCompoundCurveV2, QgsPolygonV2 -> QgsCurvePolygonV2, - QgsMultiLineStringV2 -> QgsMultiCurveV2, QgsMultiPolygonV2 -> QgsMultiSurfaceV2*/ + QgsMultiLineStringV2 -> QgsMultiCurveV2, QgsMultiPolygonV2 -> QgsMultiSurfaceV2 + @return the converted geometry. Caller takes ownership*/ virtual QgsAbstractGeometryV2* toCurveType() const { return 0; } /** Returns approximate angle at a vertex. This is usually the average angle between adjacent diff --git a/src/core/geometry/qgslinestringv2.h b/src/core/geometry/qgslinestringv2.h index 16677d56287..76e250d3b45 100644 --- a/src/core/geometry/qgslinestringv2.h +++ b/src/core/geometry/qgslinestringv2.h @@ -132,7 +132,8 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2 */ QPolygonF asQPolygonF() const; - /** Returns the geometry converted to QgsCompoundCurveV2*/ + /** Returns the geometry converted to the more generic curve type QgsCompoundCurveV2 + @return the converted geometry. Caller takes ownership*/ QgsAbstractGeometryV2* toCurveType() const override; //reimplemented methods diff --git a/src/core/geometry/qgsmultilinestringv2.h b/src/core/geometry/qgsmultilinestringv2.h index 6e28ad4728d..1516893d34a 100644 --- a/src/core/geometry/qgsmultilinestringv2.h +++ b/src/core/geometry/qgsmultilinestringv2.h @@ -42,7 +42,8 @@ class CORE_EXPORT QgsMultiLineStringV2: public QgsMultiCurveV2 /** Adds a geometry and takes ownership. Returns true in case of success*/ virtual bool addGeometry( QgsAbstractGeometryV2* g ) override; - /** Returns the geometry converted to QgsMultiCurveV2*/ + /** Returns the geometry converted to the more generic curve type QgsMultiCurveV2 + @return the converted geometry. Caller takes ownership*/ QgsAbstractGeometryV2* toCurveType() const override; protected: diff --git a/src/core/geometry/qgsmultipolygonv2.h b/src/core/geometry/qgsmultipolygonv2.h index 176dfd14e47..e6bb7585083 100644 --- a/src/core/geometry/qgsmultipolygonv2.h +++ b/src/core/geometry/qgsmultipolygonv2.h @@ -43,7 +43,8 @@ class CORE_EXPORT QgsMultiPolygonV2: public QgsMultiSurfaceV2 /** Adds a geometry and takes ownership. Returns true in case of success*/ virtual bool addGeometry( QgsAbstractGeometryV2* g ) override; - /** Returns the geometry converted to QgsMultiSurfaceV2*/ + /** Returns the geometry converted to the more generic curve type QgsMultiSurfaceV2 + @return the converted geometry. Caller takes ownership*/ QgsAbstractGeometryV2* toCurveType() const override; protected: diff --git a/src/core/geometry/qgspolygonv2.h b/src/core/geometry/qgspolygonv2.h index 1f0c125f270..031a0428a28 100644 --- a/src/core/geometry/qgspolygonv2.h +++ b/src/core/geometry/qgspolygonv2.h @@ -50,7 +50,8 @@ class CORE_EXPORT QgsPolygonV2: public QgsCurvePolygonV2 QgsPolygonV2* surfaceToPolygon() const override; - /** Returns the geometry converted to QgsCurvePolygonV2*/ + /** Returns the geometry converted to the more generic curve type QgsCurvePolygonV2 + @return the converted geometry. Caller takes ownership*/ QgsAbstractGeometryV2* toCurveType() const override; void addInteriorRing( QgsCurveV2* ring ) override; diff --git a/src/core/qgsvectorlayereditbuffer.h b/src/core/qgsvectorlayereditbuffer.h index 8f2abb8e2bf..8f52849b6ca 100644 --- a/src/core/qgsvectorlayereditbuffer.h +++ b/src/core/qgsvectorlayereditbuffer.h @@ -156,8 +156,6 @@ class CORE_EXPORT QgsVectorLayerEditBuffer : public QObject void updateLayerFields(); - QgsAbstractGeometryV2* outputGeometry( QgsAbstractGeometryV2* geom ) const; - protected: QgsVectorLayer* L; friend class QgsVectorLayer; @@ -191,6 +189,8 @@ class CORE_EXPORT QgsVectorLayerEditBuffer : public QObject /** Changed geometries which are not commited. */ QgsGeometryMap mChangedGeometries; + private: + QgsAbstractGeometryV2* outputGeometry( QgsAbstractGeometryV2* geom ) const; }; #endif // QGSVECTORLAYEREDITBUFFER_H From 11b7a2702ce6f553cf7bb2f121688683f7e72833 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Fri, 6 May 2016 15:26:13 +0200 Subject: [PATCH 5/6] Move conversion of added/changed geometry to vector data provider --- python/core/qgsvectordataprovider.sip | 4 + src/core/qgsvectordataprovider.cpp | 104 ++++++++++++++++++ src/core/qgsvectordataprovider.h | 4 + src/core/qgsvectorlayereditbuffer.cpp | 77 ------------- src/core/qgsvectorlayereditbuffer.h | 3 - .../postgres/qgspostgresprovider.cpp | 9 +- 6 files changed, 119 insertions(+), 82 deletions(-) diff --git a/python/core/qgsvectordataprovider.sip b/python/core/qgsvectordataprovider.sip index 3755723f35b..eece46b0cfc 100644 --- a/python/core/qgsvectordataprovider.sip +++ b/python/core/qgsvectordataprovider.sip @@ -361,4 +361,8 @@ class QgsVectorDataProvider : QgsDataProvider void fillMinMaxCache(); void pushError( const QString& msg ); + + /** Converts the geometry to the provider type if possible / necessary + @return the converted geometry or 0 if no conversion was necessary or possible*/ + QgsGeometry* convertToProviderType( const QgsGeometry* geom ) const /Factory/; }; diff --git a/src/core/qgsvectordataprovider.cpp b/src/core/qgsvectordataprovider.cpp index 7cabcdc68cd..00aa94d12f4 100644 --- a/src/core/qgsvectordataprovider.cpp +++ b/src/core/qgsvectordataprovider.cpp @@ -21,10 +21,15 @@ #include #include "qgsvectordataprovider.h" +#include "qgscircularstringv2.h" +#include "qgscompoundcurvev2.h" #include "qgsfeature.h" #include "qgsfeatureiterator.h" #include "qgsfeaturerequest.h" #include "qgsfield.h" +#include "qgsgeometry.h" +#include "qgsgeometrycollectionv2.h" +#include "qgsgeometryfactory.h" #include "qgslogger.h" #include "qgsmessagelog.h" @@ -572,4 +577,103 @@ QSet QgsVectorDataProvider::layerDependencies() const return QSet(); } +QgsGeometry* QgsVectorDataProvider::convertToProviderType( const QgsGeometry* geom ) const +{ + if ( !geom ) + { + return 0; + } + + QgsAbstractGeometryV2* geometry = geom->geometry(); + if ( !geometry ) + { + return 0; + } + + QgsWKBTypes::Type providerGeomType = QgsWKBTypes::Type( geometryType() ); + + //geom is already in the provider geometry type + if ( geometry->wkbType() == providerGeomType ) + { + return 0; + } + + QgsAbstractGeometryV2* outputGeom = 0; + + //convert compoundcurve to circularstring (possible if compoundcurve consists of one circular string) + if ( QgsWKBTypes::flatType( providerGeomType ) == QgsWKBTypes::CircularString && QgsWKBTypes::flatType( geometry->wkbType() ) == QgsWKBTypes::CompoundCurve ) + { + QgsCompoundCurveV2* compoundCurve = static_cast( geometry ); + if ( compoundCurve ) + { + if ( compoundCurve->nCurves() == 1 ) + { + const QgsCircularStringV2* circularString = dynamic_cast( compoundCurve->curveAt( 0 ) ); + if ( circularString ) + { + outputGeom = circularString->clone(); + } + } + } + } + + //convert to multitype if necessary + if ( QgsWKBTypes::isMultiType( providerGeomType ) && !QgsWKBTypes::isMultiType( geometry->wkbType() ) ) + { + outputGeom = QgsGeometryFactory::geomFromWkbType( providerGeomType ); + QgsGeometryCollectionV2* geomCollection = dynamic_cast( outputGeom ); + if ( geomCollection ) + { + geomCollection->addGeometry( geometry->clone() ); + } + } + + //convert to curved type if necessary + if ( !QgsWKBTypes::isCurvedType( geometry->wkbType() ) && QgsWKBTypes::isCurvedType( providerGeomType ) ) + { + QgsAbstractGeometryV2* curveGeom = outputGeom ? outputGeom->toCurveType() : geometry->toCurveType(); + if ( curveGeom ) + { + delete outputGeom; + outputGeom = curveGeom; + } + } + + //convert to linear type from curved type + if ( QgsWKBTypes::isCurvedType( geometry->wkbType() ) && !QgsWKBTypes::isCurvedType( providerGeomType ) ) + { + QgsAbstractGeometryV2* segmentizedGeom = 0; + segmentizedGeom = outputGeom ? outputGeom->segmentize() : geometry->segmentize(); + if ( segmentizedGeom ) + { + delete outputGeom; + outputGeom = segmentizedGeom; + } + } + + //set z/m types + if ( QgsWKBTypes::hasZ( providerGeomType ) ) + { + if ( !outputGeom ) + { + outputGeom = geometry->clone(); + } + outputGeom->addZValue(); + } + if ( QgsWKBTypes::hasM( providerGeomType ) ) + { + if ( !outputGeom ) + { + outputGeom = geometry->clone(); + } + outputGeom->addMValue(); + } + + if ( outputGeom ) + { + return new QgsGeometry( outputGeom ); + } + return 0; +} + QStringList QgsVectorDataProvider::smEncodings; diff --git a/src/core/qgsvectordataprovider.h b/src/core/qgsvectordataprovider.h index a6012875bbc..254242b624d 100644 --- a/src/core/qgsvectordataprovider.h +++ b/src/core/qgsvectordataprovider.h @@ -429,6 +429,10 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider /** Old-style mapping of index to name for QgsPalLabeling fix */ QgsAttrPalIndexNameHash mAttrPalIndexName; + /** Converts the geometry to the provider type if possible / necessary + @return the converted geometry or 0 if no conversion was necessary or possible*/ + QgsGeometry* convertToProviderType( const QgsGeometry* geom ) const; + private: /** Old notation **/ QMap mOldTypeList; diff --git a/src/core/qgsvectorlayereditbuffer.cpp b/src/core/qgsvectorlayereditbuffer.cpp index 641dbd6221a..714e0bfd663 100644 --- a/src/core/qgsvectorlayereditbuffer.cpp +++ b/src/core/qgsvectorlayereditbuffer.cpp @@ -276,23 +276,6 @@ bool QgsVectorLayerEditBuffer::commitChanges( QStringList& commitErrors ) int cap = provider->capabilities(); bool success = true; - //convert added features to a type accepted by the backend - QgsFeatureMap::iterator addedIt = mAddedFeatures.begin(); - for ( ; addedIt != mAddedFeatures.end(); ++addedIt ) - { - QgsGeometry* geom = addedIt.value().geometry(); - if ( geom ) - { - geom->setGeometry( outputGeometry( geom->geometry() ) ); - } - } - - QgsGeometryMap::iterator changedIt = mChangedGeometries.begin(); - for ( ; changedIt != mChangedGeometries.end(); ++changedIt ) - { - changedIt.value().setGeometry( outputGeometry( changedIt.value().geometry() ) ); - } - // geometry updates attribute updates // yes no => changeGeometryValues // no yes => changeAttributeValues @@ -689,63 +672,3 @@ void QgsVectorLayerEditBuffer::updateLayerFields() { L->updateFields(); } - -QgsAbstractGeometryV2* QgsVectorLayerEditBuffer::outputGeometry( QgsAbstractGeometryV2* geom ) const -{ - if ( !geom || !L ) - { - delete geom; - return nullptr; - } - - QgsWKBTypes::Type providerGeomType = QGis::fromOldWkbType( L->dataProvider()->geometryType() ); - - if ( geom->wkbType() == providerGeomType ) - { - return geom; - } - - QgsAbstractGeometryV2* outputGeom = geom; - - //convert to multitype if necessary - if ( QgsWKBTypes::isMultiType( providerGeomType ) && !QgsWKBTypes::isMultiType( geom->wkbType() ) ) - { - outputGeom = QgsGeometryFactory::geomFromWkbType( providerGeomType ); - QgsGeometryCollectionV2* geomCollection = dynamic_cast( outputGeom ); - if ( geomCollection ) - { - geomCollection->addGeometry( geom->clone() ); - } - } - - //convert to curved type if necessary - if ( !QgsWKBTypes::isCurvedType( outputGeom->wkbType() ) && QgsWKBTypes::isCurvedType( providerGeomType ) ) - { - QgsAbstractGeometryV2* curveGeom = outputGeom->toCurveType(); - if ( curveGeom ) - { - outputGeom = curveGeom; - } - } - - //convert to linear type from curved type - if ( QgsWKBTypes::isCurvedType( outputGeom->wkbType() ) && !QgsWKBTypes::isCurvedType( providerGeomType ) ) - { - QgsAbstractGeometryV2* segmentizedGeom = outputGeom->segmentize(); - if ( segmentizedGeom ) - { - outputGeom = segmentizedGeom; - } - } - - //set z/m types - if ( QgsWKBTypes::hasZ( providerGeomType ) ) - { - outputGeom->addZValue(); - } - if ( QgsWKBTypes::hasM( providerGeomType ) ) - { - outputGeom->addMValue(); - } - return outputGeom; -} diff --git a/src/core/qgsvectorlayereditbuffer.h b/src/core/qgsvectorlayereditbuffer.h index 8f52849b6ca..6c95fc24fe3 100644 --- a/src/core/qgsvectorlayereditbuffer.h +++ b/src/core/qgsvectorlayereditbuffer.h @@ -188,9 +188,6 @@ class CORE_EXPORT QgsVectorLayerEditBuffer : public QObject /** Changed geometries which are not commited. */ QgsGeometryMap mChangedGeometries; - - private: - QgsAbstractGeometryV2* outputGeometry( QgsAbstractGeometryV2* geom ) const; }; #endif // QGSVECTORLAYEREDITBUFFER_H diff --git a/src/providers/postgres/qgspostgresprovider.cpp b/src/providers/postgres/qgspostgresprovider.cpp index 637ff1c7d57..30c19f9a2ea 100644 --- a/src/providers/postgres/qgspostgresprovider.cpp +++ b/src/providers/postgres/qgspostgresprovider.cpp @@ -2371,14 +2371,19 @@ void QgsPostgresProvider::appendGeomParam( const QgsGeometry *geom, QStringList } QString param; - const unsigned char *buf = geom->asWkb(); - for ( int i = 0; i < geom->wkbSize(); ++i ) + + QgsGeometry* convertedGeom = convertToProviderType( geom ); + const unsigned char *buf = convertedGeom ? convertedGeom->asWkb() : geom->asWkb(); + size_t wkbSize = convertedGeom ? convertedGeom->wkbSize() : geom->wkbSize(); + + for ( int i = 0; i < wkbSize; ++i ) { if ( connectionRO()->useWkbHex() ) param += QString( "%1" ).arg(( int ) buf[i], 2, 16, QChar( '0' ) ); else param += QString( "\\%1" ).arg(( int ) buf[i], 3, 8, QChar( '0' ) ); } + delete convertedGeom; params << param; } From 0b4961c2248300fbc8917024fd470ef9cea44d52 Mon Sep 17 00:00:00 2001 From: Marco Hugentobler Date: Fri, 6 May 2016 16:51:41 +0200 Subject: [PATCH 6/6] Fix warning --- src/providers/postgres/qgspostgresprovider.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/providers/postgres/qgspostgresprovider.cpp b/src/providers/postgres/qgspostgresprovider.cpp index 30c19f9a2ea..dbb355c9d02 100644 --- a/src/providers/postgres/qgspostgresprovider.cpp +++ b/src/providers/postgres/qgspostgresprovider.cpp @@ -2376,7 +2376,7 @@ void QgsPostgresProvider::appendGeomParam( const QgsGeometry *geom, QStringList const unsigned char *buf = convertedGeom ? convertedGeom->asWkb() : geom->asWkb(); size_t wkbSize = convertedGeom ? convertedGeom->wkbSize() : geom->wkbSize(); - for ( int i = 0; i < wkbSize; ++i ) + for ( size_t i = 0; i < wkbSize; ++i ) { if ( connectionRO()->useWkbHex() ) param += QString( "%1" ).arg(( int ) buf[i], 2, 16, QChar( '0' ) );