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/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/geometry/qgsabstractgeometryv2.h b/src/core/geometry/qgsabstractgeometryv2.h index 47c46b86381..7c33db6ed9a 100644 --- a/src/core/geometry/qgsabstractgeometryv2.h +++ b/src/core/geometry/qgsabstractgeometryv2.h @@ -291,6 +291,12 @@ 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 + @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 * 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/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(); } } diff --git a/src/core/geometry/qgsgeometry.cpp b/src/core/geometry/qgsgeometry.cpp index 930e0eba663..98a5d545122 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..76e250d3b45 100644 --- a/src/core/geometry/qgslinestringv2.h +++ b/src/core/geometry/qgslinestringv2.h @@ -132,6 +132,10 @@ class CORE_EXPORT 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 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..1516893d34a 100644 --- a/src/core/geometry/qgsmultilinestringv2.h +++ b/src/core/geometry/qgsmultilinestringv2.h @@ -42,6 +42,10 @@ 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 the more generic curve type QgsMultiCurveV2 + @return the converted geometry. Caller takes ownership*/ + 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..e6bb7585083 100644 --- a/src/core/geometry/qgsmultipolygonv2.h +++ b/src/core/geometry/qgsmultipolygonv2.h @@ -43,6 +43,10 @@ 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 the more generic curve type QgsMultiSurfaceV2 + @return the converted geometry. Caller takes ownership*/ + 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..031a0428a28 100644 --- a/src/core/geometry/qgspolygonv2.h +++ b/src/core/geometry/qgspolygonv2.h @@ -50,6 +50,10 @@ class CORE_EXPORT QgsPolygonV2: public QgsCurvePolygonV2 QgsPolygonV2* surfaceToPolygon() const override; + /** 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; //overridden to handle LineString25D rings virtual void setExteriorRing( QgsCurveV2* ring ) override; 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 c1a8ed06db8..0a4edf11b90 100644 --- a/src/core/qgsvectordataprovider.h +++ b/src/core/qgsvectordataprovider.h @@ -436,6 +436,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 99d82d30a12..714e0bfd663 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" diff --git a/src/core/qgsvectorlayereditbuffer.h b/src/core/qgsvectorlayereditbuffer.h index f629b12d87a..6c95fc24fe3 100644 --- a/src/core/qgsvectorlayereditbuffer.h +++ b/src/core/qgsvectorlayereditbuffer.h @@ -188,7 +188,6 @@ class CORE_EXPORT QgsVectorLayerEditBuffer : public QObject /** Changed geometries which are not commited. */ QgsGeometryMap mChangedGeometries; - }; #endif // QGSVECTORLAYEREDITBUFFER_H diff --git a/src/providers/postgres/qgspostgresprovider.cpp b/src/providers/postgres/qgspostgresprovider.cpp index 637ff1c7d57..dbb355c9d02 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 ( size_t 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; }