From 50f01a2ac8e760f940f572b94739bdc17145511e Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Sun, 21 Feb 2016 16:26:45 +1100 Subject: [PATCH 1/2] Optimise storage/calculation of geometry bounding boxes - removes storage of bounding box from QgsPointV2 (gives significant decrease in size of object) - more efficient calculation of bounding box for linestrings Additionally, this commit moves the bounding box invalidation to a virtual QgsAbstractGeometryV2::clearCache() method, so that other non-bounding box caches can also be cleared when the geometry is modified. --- .../core/geometry/qgsabstractgeometryv2.sip | 16 ++++--- python/core/geometry/qgscircularstringv2.sip | 6 ++- python/core/geometry/qgscompoundcurvev2.sip | 6 ++- python/core/geometry/qgscurvepolygonv2.sip | 6 ++- python/core/geometry/qgscurvev2.sip | 7 +++ .../core/geometry/qgsgeometrycollectionv2.sip | 5 +- python/core/geometry/qgslinestringv2.sip | 4 ++ python/core/geometry/qgspointv2.sip | 2 +- python/core/geometry/qgssurfacev2.sip | 7 +++ src/core/geometry/qgsabstractgeometryv2.cpp | 9 ---- src/core/geometry/qgsabstractgeometryv2.h | 18 ++++--- src/core/geometry/qgscircularstringv2.cpp | 6 +-- src/core/geometry/qgscircularstringv2.h | 7 ++- src/core/geometry/qgscompoundcurvev2.cpp | 10 ++-- src/core/geometry/qgscompoundcurvev2.h | 7 ++- src/core/geometry/qgscurvepolygonv2.cpp | 10 ++-- src/core/geometry/qgscurvepolygonv2.h | 3 +- src/core/geometry/qgscurvev2.cpp | 10 ++++ src/core/geometry/qgscurvev2.h | 9 ++++ src/core/geometry/qgsgeometrycollectionv2.cpp | 33 ++++++++----- src/core/geometry/qgsgeometrycollectionv2.h | 8 +++- src/core/geometry/qgslinestringv2.cpp | 48 ++++++++++++++----- src/core/geometry/qgslinestringv2.h | 4 ++ src/core/geometry/qgspointv2.cpp | 10 ++-- src/core/geometry/qgspointv2.h | 10 ++-- src/core/geometry/qgssurfacev2.h | 19 ++++++++ 26 files changed, 196 insertions(+), 84 deletions(-) diff --git a/python/core/geometry/qgsabstractgeometryv2.sip b/python/core/geometry/qgsabstractgeometryv2.sip index c96be1c42a64..fafa9bc5a347 100644 --- a/python/core/geometry/qgsabstractgeometryv2.sip +++ b/python/core/geometry/qgsabstractgeometryv2.sip @@ -85,12 +85,7 @@ class QgsAbstractGeometryV2 /** Returns the minimal bounding box for the geometry */ - QgsRectangle boundingBox() const; - - /** Calculates the minimal bounding box for the geometry. Derived classes should override this method - * to return the correct bounding box. - */ - virtual QgsRectangle calculateBoundingBox() const; + virtual QgsRectangle boundingBox() const = 0; //mm-sql interface /** Returns the inherent dimension of the geometry. For example, this is 0 for a point geometry, @@ -373,4 +368,13 @@ class QgsAbstractGeometryV2 /** Updates the geometry type based on whether sub geometries contain z or m values. */ void setZMTypeFromSubGeometry( const QgsAbstractGeometryV2* subggeom, QgsWKBTypes::Type baseGeomType ); + + /** Default calculator for the minimal bounding box for the geometry. Derived classes should override this method + * if a more efficient bounding box calculation is available. + */ + virtual QgsRectangle calculateBoundingBox() const; + + /** Clears any cached parameters associated with the geometry, eg bounding boxes + */ + virtual void clearCache() const; }; diff --git a/python/core/geometry/qgscircularstringv2.sip b/python/core/geometry/qgscircularstringv2.sip index a72980595251..054cec077e9b 100644 --- a/python/core/geometry/qgscircularstringv2.sip +++ b/python/core/geometry/qgscircularstringv2.sip @@ -16,8 +16,6 @@ class QgsCircularStringV2: public QgsCurveV2 virtual QgsCircularStringV2* clone() const; virtual void clear(); - virtual QgsRectangle calculateBoundingBox() const; - virtual bool fromWkb( QgsConstWkbPtr wkb ); virtual bool fromWkt( const QString& wkt ); @@ -109,6 +107,10 @@ class QgsCircularStringV2: public QgsCurveV2 virtual bool dropZValue(); virtual bool dropMValue(); + protected: + + virtual QgsRectangle calculateBoundingBox() const; + private: //helper methods for curveToLine void segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QList& points ) const; diff --git a/python/core/geometry/qgscompoundcurvev2.sip b/python/core/geometry/qgscompoundcurvev2.sip index fe6563b357da..aaa6423efc09 100644 --- a/python/core/geometry/qgscompoundcurvev2.sip +++ b/python/core/geometry/qgscompoundcurvev2.sip @@ -18,8 +18,6 @@ class QgsCompoundCurveV2: public QgsCurveV2 virtual QgsCompoundCurveV2* clone() const; virtual void clear(); - virtual QgsRectangle calculateBoundingBox() const; - virtual bool fromWkb( QgsConstWkbPtr wkb ); virtual bool fromWkt( const QString& wkt ); @@ -96,4 +94,8 @@ class QgsCompoundCurveV2: public QgsCurveV2 virtual bool dropZValue(); virtual bool dropMValue(); + protected: + + virtual QgsRectangle calculateBoundingBox() const; + }; diff --git a/python/core/geometry/qgscurvepolygonv2.sip b/python/core/geometry/qgscurvepolygonv2.sip index 95d3bbc3948b..2876a0d1032b 100644 --- a/python/core/geometry/qgscurvepolygonv2.sip +++ b/python/core/geometry/qgscurvepolygonv2.sip @@ -15,8 +15,6 @@ class QgsCurvePolygonV2: public QgsSurfaceV2 virtual QgsCurvePolygonV2* clone() const; void clear(); - - virtual QgsRectangle calculateBoundingBox() const; virtual bool fromWkb( QgsConstWkbPtr wkb ); virtual bool fromWkt( const QString& wkt ); @@ -88,4 +86,8 @@ class QgsCurvePolygonV2: public QgsSurfaceV2 virtual bool addMValue( double mValue = 0 ); virtual bool dropZValue(); virtual bool dropMValue(); + + protected: + + virtual QgsRectangle calculateBoundingBox() const; }; diff --git a/python/core/geometry/qgscurvev2.sip b/python/core/geometry/qgscurvev2.sip index 0dc88563f49a..7873953bc84e 100644 --- a/python/core/geometry/qgscurvev2.sip +++ b/python/core/geometry/qgscurvev2.sip @@ -81,6 +81,8 @@ class QgsCurveV2: public QgsAbstractGeometryV2 virtual int partCount() const; virtual QgsPointV2 vertexAt( QgsVertexId id ) const; + virtual QgsRectangle boundingBox() const; + /** Drops any Z dimensions which exist in the geometry. * @returns true if Z values were present and have been removed * @see dropMValue() @@ -94,4 +96,9 @@ class QgsCurveV2: public QgsAbstractGeometryV2 * @note added in QGIS 2.14 */ virtual bool dropMValue() = 0; + + protected: + + virtual void clearCache() const; + }; diff --git a/python/core/geometry/qgsgeometrycollectionv2.sip b/python/core/geometry/qgsgeometrycollectionv2.sip index bb1c9288e68e..c47a9cc0186b 100644 --- a/python/core/geometry/qgsgeometrycollectionv2.sip +++ b/python/core/geometry/qgsgeometrycollectionv2.sip @@ -66,7 +66,7 @@ class QgsGeometryCollectionV2: public QgsAbstractGeometryV2 QDomElement asGML3( QDomDocument& doc, int precision = 17, const QString& ns = "gml" ) const; QString asJSON( int precision = 17 ) const; - virtual QgsRectangle calculateBoundingBox() const; + virtual QgsRectangle boundingBox() const; virtual void coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord /Out/ ) const; virtual double closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const; @@ -113,4 +113,7 @@ class QgsGeometryCollectionV2: public QgsAbstractGeometryV2 */ bool fromCollectionWkt( const QString &wkt, const QList& subtypes, const QString& defaultChildWkbType = QString() ); + virtual QgsRectangle calculateBoundingBox() const; + virtual void clearCache() const; + }; diff --git a/python/core/geometry/qgslinestringv2.sip b/python/core/geometry/qgslinestringv2.sip index 376d49df80f8..fad5fca934ce 100644 --- a/python/core/geometry/qgslinestringv2.sip +++ b/python/core/geometry/qgslinestringv2.sip @@ -162,4 +162,8 @@ class QgsLineStringV2: public QgsCurveV2 virtual bool convertTo( QgsWKBTypes::Type type ); + protected: + + virtual QgsRectangle calculateBoundingBox() const; + }; diff --git a/python/core/geometry/qgspointv2.sip b/python/core/geometry/qgspointv2.sip index 8127b4f7e369..e87be599f69c 100644 --- a/python/core/geometry/qgspointv2.sip +++ b/python/core/geometry/qgspointv2.sip @@ -139,6 +139,7 @@ class QgsPointV2: public QgsAbstractGeometryV2 QPointF toQPointF() const; //implementation of inherited methods + virtual QgsRectangle boundingBox() const; virtual QString geometryType() const; virtual int dimension() const; virtual QgsPointV2* clone() const /Factory/; @@ -151,7 +152,6 @@ class QgsPointV2: public QgsAbstractGeometryV2 QDomElement asGML2( QDomDocument& doc, int precision = 17, const QString& ns = "gml" ) const; QDomElement asGML3( QDomDocument& doc, int precision = 17, const QString& ns = "gml" ) const; QString asJSON( int precision = 17 ) const; - virtual QgsRectangle calculateBoundingBox() const; void draw( QPainter& p ) const; void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ); void transform( const QTransform& t ); diff --git a/python/core/geometry/qgssurfacev2.sip b/python/core/geometry/qgssurfacev2.sip index b6ec824d560a..571d337e9dba 100644 --- a/python/core/geometry/qgssurfacev2.sip +++ b/python/core/geometry/qgssurfacev2.sip @@ -7,4 +7,11 @@ class QgsSurfaceV2: public QgsAbstractGeometryV2 public: virtual QgsPolygonV2* surfaceToPolygon() const = 0; + + virtual QgsRectangle boundingBox() const; + + protected: + + virtual void clearCache() const; + }; diff --git a/src/core/geometry/qgsabstractgeometryv2.cpp b/src/core/geometry/qgsabstractgeometryv2.cpp index 4fb85e905b4e..d8b60ff260a1 100644 --- a/src/core/geometry/qgsabstractgeometryv2.cpp +++ b/src/core/geometry/qgsabstractgeometryv2.cpp @@ -45,15 +45,6 @@ QgsAbstractGeometryV2& QgsAbstractGeometryV2::operator=( const QgsAbstractGeomet return *this; } -QgsRectangle QgsAbstractGeometryV2::boundingBox() const -{ - if ( mBoundingBox.isNull() ) - { - mBoundingBox = calculateBoundingBox(); - } - return mBoundingBox; -} - bool QgsAbstractGeometryV2::is3D() const { return QgsWKBTypes::hasZ( mWkbType ); diff --git a/src/core/geometry/qgsabstractgeometryv2.h b/src/core/geometry/qgsabstractgeometryv2.h index 63c38fe19f7b..a3db7645dbde 100644 --- a/src/core/geometry/qgsabstractgeometryv2.h +++ b/src/core/geometry/qgsabstractgeometryv2.h @@ -56,12 +56,7 @@ class CORE_EXPORT QgsAbstractGeometryV2 /** Returns the minimal bounding box for the geometry */ - QgsRectangle boundingBox() const; - - /** Calculates the minimal bounding box for the geometry. Derived classes should override this method - * to return the correct bounding box. - */ - virtual QgsRectangle calculateBoundingBox() const; + virtual QgsRectangle boundingBox() const = 0; //mm-sql interface /** Returns the inherent dimension of the geometry. For example, this is 0 for a point geometry, @@ -353,11 +348,20 @@ class CORE_EXPORT QgsAbstractGeometryV2 protected: QgsWKBTypes::Type mWkbType; - mutable QgsRectangle mBoundingBox; /** Updates the geometry type based on whether sub geometries contain z or m values. */ void setZMTypeFromSubGeometry( const QgsAbstractGeometryV2* subggeom, QgsWKBTypes::Type baseGeomType ); + + /** Default calculator for the minimal bounding box for the geometry. Derived classes should override this method + * if a more efficient bounding box calculation is available. + */ + virtual QgsRectangle calculateBoundingBox() const; + + /** Clears any cached parameters associated with the geometry, eg bounding boxes + */ + virtual void clearCache() const {} + }; diff --git a/src/core/geometry/qgscircularstringv2.cpp b/src/core/geometry/qgscircularstringv2.cpp index d6b6ebfe5a0f..5164ff9fc3f2 100644 --- a/src/core/geometry/qgscircularstringv2.cpp +++ b/src/core/geometry/qgscircularstringv2.cpp @@ -723,7 +723,7 @@ bool QgsCircularStringV2::insertVertex( QgsVertexId position, const QgsPointV2& { insertVertexBetween( position.vertex, position.vertex + 1, position.vertex - 1 ); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } @@ -744,7 +744,7 @@ bool QgsCircularStringV2::moveVertex( QgsVertexId position, const QgsPointV2& ne { mM[position.vertex] = newPos.m(); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } @@ -772,7 +772,7 @@ bool QgsCircularStringV2::deleteVertex( QgsVertexId position ) deleteVertex( position.vertex - 1 ); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } diff --git a/src/core/geometry/qgscircularstringv2.h b/src/core/geometry/qgscircularstringv2.h index 0e78c3877aa5..1da7f5eabbc8 100644 --- a/src/core/geometry/qgscircularstringv2.h +++ b/src/core/geometry/qgscircularstringv2.h @@ -41,8 +41,6 @@ class CORE_EXPORT QgsCircularStringV2: public QgsCurveV2 virtual QgsCircularStringV2* clone() const override; virtual void clear() override; - virtual QgsRectangle calculateBoundingBox() const override; - virtual bool fromWkb( QgsConstWkbPtr wkb ) override; virtual bool fromWkt( const QString& wkt ) override; @@ -134,6 +132,10 @@ class CORE_EXPORT QgsCircularStringV2: public QgsCurveV2 virtual bool dropZValue() override; virtual bool dropMValue() override; + protected: + + virtual QgsRectangle calculateBoundingBox() const override; + private: QVector mX; QVector mY; @@ -152,6 +154,7 @@ class CORE_EXPORT QgsCircularStringV2: public QgsCurveV2 const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ); void insertVertexBetween( int after, int before, int pointOnCircle ); void deleteVertex( int i ); + }; #endif // QGSCIRCULARSTRING_H diff --git a/src/core/geometry/qgscompoundcurvev2.cpp b/src/core/geometry/qgscompoundcurvev2.cpp index 1e334d460f98..d9e50c94e587 100644 --- a/src/core/geometry/qgscompoundcurvev2.cpp +++ b/src/core/geometry/qgscompoundcurvev2.cpp @@ -89,10 +89,10 @@ QgsRectangle QgsCompoundCurveV2::calculateBoundingBox() const return QgsRectangle(); } - QgsRectangle bbox = mCurves.at( 0 )->calculateBoundingBox(); + QgsRectangle bbox = mCurves.at( 0 )->boundingBox(); for ( int i = 1; i < mCurves.size(); ++i ) { - QgsRectangle curveBox = mCurves.at( i )->calculateBoundingBox(); + QgsRectangle curveBox = mCurves.at( i )->boundingBox(); bbox.combineExtentWith( &curveBox ); } return bbox; @@ -497,7 +497,7 @@ bool QgsCompoundCurveV2::insertVertex( QgsVertexId position, const QgsPointV2& v bool success = mCurves.at( curveId )->insertVertex( curveIds.at( 0 ).second, vertex ); if ( success ) { - mBoundingBox = QgsRectangle(); //bbox changed + clearCache(); //bbox changed } return success; } @@ -514,7 +514,7 @@ bool QgsCompoundCurveV2::moveVertex( QgsVertexId position, const QgsPointV2& new bool success = !curveIds.isEmpty(); if ( success ) { - mBoundingBox = QgsRectangle(); //bbox changed + clearCache(); //bbox changed } return success; } @@ -531,7 +531,7 @@ bool QgsCompoundCurveV2::deleteVertex( QgsVertexId position ) bool success = !curveIds.isEmpty(); if ( success ) { - mBoundingBox = QgsRectangle(); //bbox changed + clearCache(); //bbox changed } return success; } diff --git a/src/core/geometry/qgscompoundcurvev2.h b/src/core/geometry/qgscompoundcurvev2.h index 89cf51885d2e..6c7dea3e7dad 100644 --- a/src/core/geometry/qgscompoundcurvev2.h +++ b/src/core/geometry/qgscompoundcurvev2.h @@ -42,8 +42,6 @@ class CORE_EXPORT QgsCompoundCurveV2: public QgsCurveV2 virtual QgsCompoundCurveV2* clone() const override; virtual void clear() override; - virtual QgsRectangle calculateBoundingBox() const override; - virtual bool fromWkb( QgsConstWkbPtr wkb ) override; virtual bool fromWkt( const QString& wkt ) override; @@ -120,11 +118,16 @@ class CORE_EXPORT QgsCompoundCurveV2: public QgsCurveV2 virtual bool dropZValue() override; virtual bool dropMValue() override; + protected: + + virtual QgsRectangle calculateBoundingBox() const override; + private: QList< QgsCurveV2* > mCurves; /** Turns a vertex id for the compound curve into one or more ids for the subcurves @return the index of the subcurve or -1 in case of error*/ QList< QPair > curveVertexId( QgsVertexId id ) const; + }; #endif // QGSCOMPOUNDCURVEV2_H diff --git a/src/core/geometry/qgscurvepolygonv2.cpp b/src/core/geometry/qgscurvepolygonv2.cpp index 0c2b084e321f..6efde56d5543 100644 --- a/src/core/geometry/qgscurvepolygonv2.cpp +++ b/src/core/geometry/qgscurvepolygonv2.cpp @@ -209,7 +209,7 @@ QgsRectangle QgsCurvePolygonV2::calculateBoundingBox() const { if ( mExteriorRing ) { - return mExteriorRing->calculateBoundingBox(); + return mExteriorRing->boundingBox(); } return QgsRectangle(); } @@ -666,7 +666,7 @@ bool QgsCurvePolygonV2::insertVertex( QgsVertexId vId, const QgsPointV2& vertex else if ( vId.vertex == n ) ring->moveVertex( QgsVertexId( 0, 0, 0 ), vertex ); - mBoundingBox = QgsRectangle(); + clearCache(); return true; } @@ -687,7 +687,7 @@ bool QgsCurvePolygonV2::moveVertex( QgsVertexId vId, const QgsPointV2& newPos ) ring->moveVertex( QgsVertexId( vId.part, vId.ring, n - 1 ), newPos ); else if ( vId.vertex == n - 1 ) ring->moveVertex( QgsVertexId( vId.part, vId.ring, 0 ), newPos ); - mBoundingBox = QgsRectangle(); + clearCache(); } return success; } @@ -717,7 +717,7 @@ bool QgsCurvePolygonV2::deleteVertex( QgsVertexId vId ) { removeInteriorRing( vId.ring - 1 ); } - mBoundingBox = QgsRectangle(); + clearCache(); return true; } @@ -729,7 +729,7 @@ bool QgsCurvePolygonV2::deleteVertex( QgsVertexId vId ) ring->moveVertex( QgsVertexId( 0, 0, n - 2 ), ring->vertexAt( QgsVertexId( 0, 0, 0 ) ) ); else if ( vId.vertex == n - 1 ) ring->moveVertex( QgsVertexId( 0, 0, 0 ), ring->vertexAt( QgsVertexId( 0, 0, n - 2 ) ) ); - mBoundingBox = QgsRectangle(); + clearCache(); } return success; } diff --git a/src/core/geometry/qgscurvepolygonv2.h b/src/core/geometry/qgscurvepolygonv2.h index ac1f69340699..58a08aa028af 100644 --- a/src/core/geometry/qgscurvepolygonv2.h +++ b/src/core/geometry/qgscurvepolygonv2.h @@ -41,8 +41,6 @@ class CORE_EXPORT QgsCurvePolygonV2: public QgsSurfaceV2 virtual QgsCurvePolygonV2* clone() const override; void clear() override; - - virtual QgsRectangle calculateBoundingBox() const override; virtual bool fromWkb( QgsConstWkbPtr wkb ) override; virtual bool fromWkt( const QString& wkt ) override; @@ -120,6 +118,7 @@ class CORE_EXPORT QgsCurvePolygonV2: public QgsSurfaceV2 QgsCurveV2* mExteriorRing; QList mInteriorRings; + virtual QgsRectangle calculateBoundingBox() const override; }; #endif // QGSCURVEPOLYGONV2_H diff --git a/src/core/geometry/qgscurvev2.cpp b/src/core/geometry/qgscurvev2.cpp index 15d78d9ce440..7b4c043250ca 100644 --- a/src/core/geometry/qgscurvev2.cpp +++ b/src/core/geometry/qgscurvev2.cpp @@ -89,3 +89,13 @@ QgsPointV2 QgsCurveV2::vertexAt( QgsVertexId id ) const pointAt( id.vertex, v, type ); return v; } + +QgsRectangle QgsCurveV2::boundingBox() const +{ + if ( mBoundingBox.isNull() ) + { + mBoundingBox = calculateBoundingBox(); + } + return mBoundingBox; +} + diff --git a/src/core/geometry/qgscurvev2.h b/src/core/geometry/qgscurvev2.h index 71a52b098f6d..26cc52863ee0 100644 --- a/src/core/geometry/qgscurvev2.h +++ b/src/core/geometry/qgscurvev2.h @@ -109,6 +109,15 @@ class CORE_EXPORT QgsCurveV2: public QgsAbstractGeometryV2 virtual int partCount() const override { return numPoints() > 0 ? 1 : 0; } virtual QgsPointV2 vertexAt( QgsVertexId id ) const override; + virtual QgsRectangle boundingBox() const override; + + protected: + + virtual void clearCache() const override { mBoundingBox = QgsRectangle(); } + + private: + + mutable QgsRectangle mBoundingBox; }; #endif // QGSCURVEV2_H diff --git a/src/core/geometry/qgsgeometrycollectionv2.cpp b/src/core/geometry/qgsgeometrycollectionv2.cpp index 2ea846bc2bbc..52228e6a6356 100644 --- a/src/core/geometry/qgsgeometrycollectionv2.cpp +++ b/src/core/geometry/qgsgeometrycollectionv2.cpp @@ -72,7 +72,7 @@ void QgsGeometryCollectionV2::clear() qDeleteAll( mGeometries ); mGeometries.clear(); mWkbType = QgsWKBTypes::Unknown; - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid } int QgsGeometryCollectionV2::numGeometries() const @@ -98,7 +98,7 @@ bool QgsGeometryCollectionV2::addGeometry( QgsAbstractGeometryV2* g ) } mGeometries.append( g ); - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } @@ -110,7 +110,7 @@ bool QgsGeometryCollectionV2::insertGeometry( QgsAbstractGeometryV2 *g, int inde } mGeometries.insert( index, g ); - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } @@ -122,7 +122,7 @@ bool QgsGeometryCollectionV2::removeGeometry( int nr ) } delete mGeometries.at( nr ); mGeometries.remove( nr ); - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } @@ -147,7 +147,7 @@ void QgsGeometryCollectionV2::transform( const QgsCoordinateTransform& ct, QgsCo { g->transform( ct, d ); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid } void QgsGeometryCollectionV2::transform( const QTransform& t ) @@ -156,7 +156,7 @@ void QgsGeometryCollectionV2::transform( const QTransform& t ) { g->transform( t ); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid } #if 0 @@ -207,7 +207,7 @@ bool QgsGeometryCollectionV2::fromWkb( QgsConstWkbPtr wkbPtr ) { mGeometries[i] = geometryList.at( i ); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } @@ -314,6 +314,15 @@ QString QgsGeometryCollectionV2::asJSON( int precision ) const return json; } +QgsRectangle QgsGeometryCollectionV2::boundingBox() const +{ + if ( mBoundingBox.isNull() ) + { + mBoundingBox = calculateBoundingBox(); + } + return mBoundingBox; +} + QgsRectangle QgsGeometryCollectionV2::calculateBoundingBox() const { if ( mGeometries.size() < 1 ) @@ -321,10 +330,10 @@ QgsRectangle QgsGeometryCollectionV2::calculateBoundingBox() const return QgsRectangle(); } - QgsRectangle bbox = mGeometries.at( 0 )->calculateBoundingBox(); + QgsRectangle bbox = mGeometries.at( 0 )->boundingBox(); for ( int i = 1; i < mGeometries.size(); ++i ) { - QgsRectangle geomBox = mGeometries.at( i )->calculateBoundingBox(); + QgsRectangle geomBox = mGeometries.at( i )->boundingBox(); bbox.combineExtentWith( &geomBox ); } return bbox; @@ -385,7 +394,7 @@ bool QgsGeometryCollectionV2::insertVertex( QgsVertexId position, const QgsPoint bool success = mGeometries.at( position.part )->insertVertex( position, vertex ); if ( success ) { - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid } return success; } @@ -400,7 +409,7 @@ bool QgsGeometryCollectionV2::moveVertex( QgsVertexId position, const QgsPointV2 bool success = mGeometries.at( position.part )->moveVertex( position, newPos ); if ( success ) { - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid } return success; } @@ -428,7 +437,7 @@ bool QgsGeometryCollectionV2::deleteVertex( QgsVertexId position ) if ( success ) { - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid } return success; } diff --git a/src/core/geometry/qgsgeometrycollectionv2.h b/src/core/geometry/qgsgeometrycollectionv2.h index 568f0a7be355..85565ae69617 100644 --- a/src/core/geometry/qgsgeometrycollectionv2.h +++ b/src/core/geometry/qgsgeometrycollectionv2.h @@ -90,7 +90,7 @@ class CORE_EXPORT QgsGeometryCollectionV2: public QgsAbstractGeometryV2 QDomElement asGML3( QDomDocument& doc, int precision = 17, const QString& ns = "gml" ) const override; QString asJSON( int precision = 17 ) const override; - virtual QgsRectangle calculateBoundingBox() const override; + virtual QgsRectangle boundingBox() const override; virtual void coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord ) const override; virtual double closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const override; @@ -138,6 +138,12 @@ class CORE_EXPORT QgsGeometryCollectionV2: public QgsAbstractGeometryV2 */ bool fromCollectionWkt( const QString &wkt, const QList& subtypes, const QString& defaultChildWkbType = QString() ); + virtual QgsRectangle calculateBoundingBox() const override; + virtual void clearCache() const override { mBoundingBox = QgsRectangle(); } + + private: + + mutable QgsRectangle mBoundingBox; }; #endif // QGSGEOMETRYCOLLECTIONV2_H diff --git a/src/core/geometry/qgslinestringv2.cpp b/src/core/geometry/qgslinestringv2.cpp index 0530af4d62ec..5205022c8ecf 100644 --- a/src/core/geometry/qgslinestringv2.cpp +++ b/src/core/geometry/qgslinestringv2.cpp @@ -87,7 +87,7 @@ void QgsLineStringV2::clear() mZ.clear(); mM.clear(); mWkbType = QgsWKBTypes::Unknown; - mBoundingBox = QgsRectangle(); + clearCache(); } bool QgsLineStringV2::fromWkb( QgsConstWkbPtr wkbPtr ) @@ -113,6 +113,30 @@ void QgsLineStringV2::fromWkbPoints( QgsWKBTypes::Type type, const QgsConstWkbPt importVerticesFromWkb( wkb ); } +QgsRectangle QgsLineStringV2::calculateBoundingBox() const +{ + double xmin = std::numeric_limits::max(); + double ymin = std::numeric_limits::max(); + double xmax = -std::numeric_limits::max(); + double ymax = -std::numeric_limits::max(); + + Q_FOREACH ( double x, mX ) + { + if ( x < xmin ) + xmin = x; + if ( x > xmax ) + xmax = x; + } + Q_FOREACH ( double y, mY ) + { + if ( y < ymin ) + ymin = y; + if ( y > ymax ) + ymax = y; + } + return QgsRectangle( xmin, ymin, xmax, ymax ); +} + /*************************************************************************** * This class is considered CRITICAL and any change MUST be accompanied with * full unit tests. @@ -341,14 +365,14 @@ void QgsLineStringV2::setXAt( int index, double x ) { if ( index >= 0 && index < mX.size() ) mX[ index ] = x; - mBoundingBox = QgsRectangle(); + clearCache(); } void QgsLineStringV2::setYAt( int index, double y ) { if ( index >= 0 && index < mY.size() ) mY[ index ] = y; - mBoundingBox = QgsRectangle(); + clearCache(); } void QgsLineStringV2::setZAt( int index, double z ) @@ -381,7 +405,7 @@ void QgsLineStringV2::points( QList& pts ) const void QgsLineStringV2::setPoints( const QList& points ) { - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid if ( points.isEmpty() ) { @@ -495,7 +519,7 @@ void QgsLineStringV2::append( const QgsLineStringV2* line ) } } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid } QgsLineStringV2* QgsLineStringV2::reversed() const @@ -584,7 +608,7 @@ void QgsLineStringV2::transform( const QgsCoordinateTransform& ct, QgsCoordinate { delete[] zArray; } - mBoundingBox = QgsRectangle(); + clearCache(); } void QgsLineStringV2::transform( const QTransform& t ) @@ -597,7 +621,7 @@ void QgsLineStringV2::transform( const QTransform& t ) mX[i] = x; mY[i] = y; } - mBoundingBox = QgsRectangle(); + clearCache(); } /*************************************************************************** @@ -628,7 +652,7 @@ bool QgsLineStringV2::insertVertex( QgsVertexId position, const QgsPointV2& vert { mM.insert( position.vertex, vertex.m() ); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } @@ -648,7 +672,7 @@ bool QgsLineStringV2::moveVertex( QgsVertexId position, const QgsPointV2& newPos { mM[position.vertex] = newPos.m(); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } @@ -675,7 +699,7 @@ bool QgsLineStringV2::deleteVertex( QgsVertexId position ) clear(); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid return true; } @@ -702,7 +726,7 @@ void QgsLineStringV2::addVertex( const QgsPointV2& pt ) { mM.append( pt.m() ); } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid } double QgsLineStringV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const @@ -843,7 +867,7 @@ void QgsLineStringV2::importVerticesFromWkb( const QgsConstWkbPtr& wkb ) wkb >> mM[i]; } } - mBoundingBox = QgsRectangle(); //set bounding box invalid + clearCache(); //set bounding box invalid } /*************************************************************************** diff --git a/src/core/geometry/qgslinestringv2.h b/src/core/geometry/qgslinestringv2.h index 99fce524d655..dc7da12b35cd 100644 --- a/src/core/geometry/qgslinestringv2.h +++ b/src/core/geometry/qgslinestringv2.h @@ -188,6 +188,10 @@ class CORE_EXPORT QgsLineStringV2: public QgsCurveV2 bool convertTo( QgsWKBTypes::Type type ) override; + protected: + + virtual QgsRectangle calculateBoundingBox() const override; + private: QVector mX; QVector mY; diff --git a/src/core/geometry/qgspointv2.cpp b/src/core/geometry/qgspointv2.cpp index ababbbdb5e53..4bb9200be707 100644 --- a/src/core/geometry/qgspointv2.cpp +++ b/src/core/geometry/qgspointv2.cpp @@ -113,7 +113,7 @@ bool QgsPointV2::fromWkb( QgsConstWkbPtr wkbPtr ) if ( isMeasure() ) wkbPtr >> mM; - mBoundingBox = QgsRectangle(); + clearCache(); return true; } @@ -255,12 +255,12 @@ void QgsPointV2::clear() { mWkbType = QgsWKBTypes::Unknown; mX = mY = mZ = mM = 0.; - mBoundingBox = QgsRectangle(); + clearCache(); } void QgsPointV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { - mBoundingBox = QgsRectangle(); + clearCache(); ct.transformInPlace( mX, mY, mZ, d ); } @@ -281,7 +281,7 @@ void QgsPointV2::coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coor bool QgsPointV2::moveVertex( QgsVertexId position, const QgsPointV2& newPos ) { Q_UNUSED( position ); - mBoundingBox = QgsRectangle(); + clearCache(); mX = newPos.mX; mY = newPos.mY; if ( is3D() && newPos.is3D() ) @@ -354,7 +354,7 @@ bool QgsPointV2::addMValue( double mValue ) void QgsPointV2::transform( const QTransform& t ) { - mBoundingBox = QgsRectangle(); + clearCache(); qreal x, y; t.map( mX, mY, &x, &y ); mX = x; diff --git a/src/core/geometry/qgspointv2.h b/src/core/geometry/qgspointv2.h index 08d349dc1cc5..ffcb1b45521a 100644 --- a/src/core/geometry/qgspointv2.h +++ b/src/core/geometry/qgspointv2.h @@ -91,7 +91,7 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 * @see setX() * @note not available in Python bindings */ - double &rx() { mBoundingBox = QgsRectangle(); return mX; } + double &rx() { clearCache(); return mX; } /** Returns a reference to the y-coordinate of this point. * Using a reference makes it possible to directly manipulate y in place. @@ -99,7 +99,7 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 * @see setY() * @note not available in Python bindings */ - double &ry() { mBoundingBox = QgsRectangle(); return mY; } + double &ry() { clearCache(); return mY; } /** Returns a reference to the z-coordinate of this point. * Using a reference makes it possible to directly manipulate z in place. @@ -121,13 +121,13 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 * @see x() * @see rx() */ - void setX( double x ) { mX = x; mBoundingBox = QgsRectangle(); } + void setX( double x ) { clearCache(); mX = x; } /** Sets the point's y-coordinate. * @see y() * @see ry() */ - void setY( double y ) { mY = y; mBoundingBox = QgsRectangle(); } + void setY( double y ) { clearCache(); mY = y; } /** Sets the point's z-coordinate. * @note calling this will have no effect if the point does not contain a z-dimension. Use addZValue() to @@ -151,6 +151,7 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 QPointF toQPointF() const; //implementation of inherited methods + virtual QgsRectangle boundingBox() const override { return QgsRectangle( mX, mY, mX, mY ); } virtual QString geometryType() const override { return "Point"; } virtual int dimension() const override { return 0; } virtual QgsPointV2* clone() const override; @@ -163,7 +164,6 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 QDomElement asGML2( QDomDocument& doc, int precision = 17, const QString& ns = "gml" ) const override; QDomElement asGML3( QDomDocument& doc, int precision = 17, const QString& ns = "gml" ) const override; QString asJSON( int precision = 17 ) const override; - virtual QgsRectangle calculateBoundingBox() const override { return QgsRectangle( mX, mY, mX, mY );} void draw( QPainter& p ) const override; void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform ) override; void transform( const QTransform& t ) override; diff --git a/src/core/geometry/qgssurfacev2.h b/src/core/geometry/qgssurfacev2.h index 5696f6c2dac4..a4bb129d8e27 100644 --- a/src/core/geometry/qgssurfacev2.h +++ b/src/core/geometry/qgssurfacev2.h @@ -28,6 +28,25 @@ class CORE_EXPORT QgsSurfaceV2: public QgsAbstractGeometryV2 public: virtual QgsPolygonV2* surfaceToPolygon() const = 0; + + /** Returns the minimal bounding box for the geometry + */ + virtual QgsRectangle boundingBox() const override + { + if ( mBoundingBox.isNull() ) + { + mBoundingBox = calculateBoundingBox(); + } + return mBoundingBox; + } + + protected: + + virtual void clearCache() const override { mBoundingBox = QgsRectangle(); } + + private: + + mutable QgsRectangle mBoundingBox; }; #endif // QGSSURFACEV2_H From 6116fdcdb4f9cb8a95ab6429944a977d52b3c9fc Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Sun, 21 Feb 2016 19:55:15 +1100 Subject: [PATCH 2/2] Add a bunch of missing geometry cache clears --- python/core/geometry/qgscurvepolygonv2.sip | 4 ++-- src/core/geometry/qgscircularstringv2.cpp | 16 ++++++++++++++++ src/core/geometry/qgscompoundcurvev2.cpp | 11 +++++++++++ src/core/geometry/qgscurvepolygonv2.cpp | 16 ++++++++++++++-- src/core/geometry/qgscurvepolygonv2.h | 4 ++-- src/core/geometry/qgscurvev2.h | 2 +- src/core/geometry/qgsgeometrycollectionv2.cpp | 6 ++++++ src/core/geometry/qgsgeometrycollectionv2.h | 2 +- src/core/geometry/qgslinestringv2.cpp | 5 +++++ src/core/geometry/qgspointv2.cpp | 6 ++++++ src/core/geometry/qgspointv2.h | 8 ++++---- src/core/geometry/qgspolygonv2.cpp | 3 +++ src/core/geometry/qgssurfacev2.h | 2 +- tests/src/core/testqgsgeometry.cpp | 10 +++++----- 14 files changed, 77 insertions(+), 18 deletions(-) diff --git a/python/core/geometry/qgscurvepolygonv2.sip b/python/core/geometry/qgscurvepolygonv2.sip index 2876a0d1032b..e69c87f685f9 100644 --- a/python/core/geometry/qgscurvepolygonv2.sip +++ b/python/core/geometry/qgscurvepolygonv2.sip @@ -32,8 +32,8 @@ class QgsCurvePolygonV2: public QgsSurfaceV2 //curve polygon interface int numInteriorRings() const; - QgsCurveV2* exteriorRing() const; - QgsCurveV2* interiorRing( int i ) const; + const QgsCurveV2* exteriorRing() const; + const QgsCurveV2* interiorRing( int i ) const; virtual QgsPolygonV2* toPolygon() const; /** Sets the exterior ring of the polygon. The CurvePolygon type will be updated to match the dimensionality diff --git a/src/core/geometry/qgscircularstringv2.cpp b/src/core/geometry/qgscircularstringv2.cpp index 5164ff9fc3f2..327d7dc3699f 100644 --- a/src/core/geometry/qgscircularstringv2.cpp +++ b/src/core/geometry/qgscircularstringv2.cpp @@ -62,6 +62,7 @@ void QgsCircularStringV2::clear() mZ.clear(); mM.clear(); mWkbType = QgsWKBTypes::Unknown; + clearCache(); } QgsRectangle QgsCircularStringV2::calculateBoundingBox() const @@ -216,6 +217,7 @@ bool QgsCircularStringV2::fromWkb( QgsConstWkbPtr wkbPtr ) { return false; } + clearCache(); mWkbType = type; //type @@ -418,6 +420,8 @@ void QgsCircularStringV2::points( QList& pts ) const void QgsCircularStringV2::setPoints( const QList& points ) { + clearCache(); + if ( points.size() < 1 ) { mWkbType = QgsWKBTypes::Unknown; @@ -609,6 +613,8 @@ void QgsCircularStringV2::draw( QPainter& p ) const void QgsCircularStringV2::transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d ) { + clearCache(); + double* zArray = mZ.data(); bool hasZ = is3D(); @@ -630,6 +636,8 @@ void QgsCircularStringV2::transform( const QgsCoordinateTransform& ct, QgsCoordi void QgsCircularStringV2::transform( const QTransform& t ) { + clearCache(); + int nPoints = numPoints(); for ( int i = 0; i < nPoints; ++i ) { @@ -788,6 +796,7 @@ void QgsCircularStringV2::deleteVertex( int i ) { mM.remove( i ); } + clearCache(); } double QgsCircularStringV2::closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const @@ -975,6 +984,7 @@ void QgsCircularStringV2::insertVertexBetween( int after, int before, int pointO { mM.insert( before, ( mM[after] + mM[before] ) / 2.0 ); } + clearCache(); } double QgsCircularStringV2::vertexAngle( QgsVertexId vId ) const @@ -1053,6 +1063,7 @@ bool QgsCircularStringV2::addZValue( double zValue ) if ( QgsWKBTypes::hasZ( mWkbType ) ) return false; + clearCache(); mWkbType = QgsWKBTypes::addZ( mWkbType ); int nPoints = numPoints(); @@ -1070,6 +1081,7 @@ bool QgsCircularStringV2::addMValue( double mValue ) if ( QgsWKBTypes::hasM( mWkbType ) ) return false; + clearCache(); mWkbType = QgsWKBTypes::addM( mWkbType ); int nPoints = numPoints(); @@ -1087,6 +1099,8 @@ bool QgsCircularStringV2::dropZValue() if ( !QgsWKBTypes::hasZ( mWkbType ) ) return false; + clearCache(); + mWkbType = QgsWKBTypes::dropZ( mWkbType ); mZ.clear(); return true; @@ -1097,6 +1111,8 @@ bool QgsCircularStringV2::dropMValue() if ( !QgsWKBTypes::hasM( mWkbType ) ) return false; + clearCache(); + mWkbType = QgsWKBTypes::dropM( mWkbType ); mM.clear(); return true; diff --git a/src/core/geometry/qgscompoundcurvev2.cpp b/src/core/geometry/qgscompoundcurvev2.cpp index d9e50c94e587..6563084f1a49 100644 --- a/src/core/geometry/qgscompoundcurvev2.cpp +++ b/src/core/geometry/qgscompoundcurvev2.cpp @@ -61,6 +61,7 @@ QgsCompoundCurveV2& QgsCompoundCurveV2::operator=( const QgsCompoundCurveV2 & cu { if ( &curve != this ) { + clearCache(); QgsCurveV2::operator=( curve ); Q_FOREACH ( const QgsCurveV2* c, curve.mCurves ) { @@ -80,6 +81,7 @@ void QgsCompoundCurveV2::clear() qDeleteAll( mCurves ); mCurves.clear(); mWkbType = QgsWKBTypes::Unknown; + clearCache(); } QgsRectangle QgsCompoundCurveV2::calculateBoundingBox() const @@ -388,6 +390,7 @@ void QgsCompoundCurveV2::addCurve( QgsCurveV2* c ) { setZMTypeFromSubGeometry( c, QgsWKBTypes::CompoundCurve ); } + clearCache(); } } @@ -400,6 +403,7 @@ void QgsCompoundCurveV2::removeCurve( int i ) delete( mCurves.at( i ) ); mCurves.removeAt( i ); + clearCache(); } void QgsCompoundCurveV2::addVertex( const QgsPointV2& pt ) @@ -432,6 +436,7 @@ void QgsCompoundCurveV2::addVertex( const QgsPointV2& pt ) line = static_cast( lastCurve ); } line->addVertex( pt ); + clearCache(); } void QgsCompoundCurveV2::draw( QPainter& p ) const @@ -449,6 +454,7 @@ void QgsCompoundCurveV2::transform( const QgsCoordinateTransform& ct, QgsCoordin { curve->transform( ct, d ); } + clearCache(); } void QgsCompoundCurveV2::transform( const QTransform& t ) @@ -457,6 +463,7 @@ void QgsCompoundCurveV2::transform( const QTransform& t ) { curve->transform( t ); } + clearCache(); } void QgsCompoundCurveV2::addToPainterPath( QPainterPath& path ) const @@ -659,6 +666,7 @@ bool QgsCompoundCurveV2::addZValue( double zValue ) { curve->addZValue( zValue ); } + clearCache(); return true; } @@ -673,6 +681,7 @@ bool QgsCompoundCurveV2::addMValue( double mValue ) { curve->addMValue( mValue ); } + clearCache(); return true; } @@ -686,6 +695,7 @@ bool QgsCompoundCurveV2::dropZValue() { curve->dropZValue(); } + clearCache(); return true; } @@ -699,6 +709,7 @@ bool QgsCompoundCurveV2::dropMValue() { curve->dropMValue(); } + clearCache(); return true; } diff --git a/src/core/geometry/qgscurvepolygonv2.cpp b/src/core/geometry/qgscurvepolygonv2.cpp index 6efde56d5543..6bc3e8ecd84e 100644 --- a/src/core/geometry/qgscurvepolygonv2.cpp +++ b/src/core/geometry/qgscurvepolygonv2.cpp @@ -53,6 +53,7 @@ QgsCurvePolygonV2& QgsCurvePolygonV2::operator=( const QgsCurvePolygonV2 & p ) { if ( &p != this ) { + clearCache(); QgsSurfaceV2::operator=( p ); if ( p.mExteriorRing ) { @@ -79,6 +80,7 @@ void QgsCurvePolygonV2::clear() qDeleteAll( mInteriorRings ); mInteriorRings.clear(); mWkbType = QgsWKBTypes::Unknown; + clearCache(); } @@ -438,12 +440,12 @@ int QgsCurvePolygonV2::numInteriorRings() const return mInteriorRings.size(); } -QgsCurveV2* QgsCurvePolygonV2::exteriorRing() const +const QgsCurveV2* QgsCurvePolygonV2::exteriorRing() const { return mExteriorRing; } -QgsCurveV2* QgsCurvePolygonV2::interiorRing( int i ) const +const QgsCurveV2* QgsCurvePolygonV2::interiorRing( int i ) const { if ( i < 0 || i >= mInteriorRings.size() ) { @@ -484,6 +486,7 @@ void QgsCurvePolygonV2::setExteriorRing( QgsCurveV2* ring ) else ring->dropMValue(); } + clearCache(); } void QgsCurvePolygonV2::setInteriorRings( const QList& rings ) @@ -496,6 +499,7 @@ void QgsCurvePolygonV2::setInteriorRings( const QList& rings ) { addInteriorRing( ring ); } + clearCache(); } void QgsCurvePolygonV2::addInteriorRing( QgsCurveV2* ring ) @@ -515,6 +519,7 @@ void QgsCurvePolygonV2::addInteriorRing( QgsCurveV2* ring ) ring->addMValue(); mInteriorRings.append( ring ); + clearCache(); } bool QgsCurvePolygonV2::removeInteriorRing( int nr ) @@ -524,6 +529,7 @@ bool QgsCurvePolygonV2::removeInteriorRing( int nr ) return false; } delete mInteriorRings.takeAt( nr ); + clearCache(); return true; } @@ -561,6 +567,7 @@ void QgsCurvePolygonV2::transform( const QgsCoordinateTransform& ct, QgsCoordina { curve->transform( ct, d ); } + clearCache(); } void QgsCurvePolygonV2::transform( const QTransform& t ) @@ -574,6 +581,7 @@ void QgsCurvePolygonV2::transform( const QTransform& t ) { curve->transform( t ); } + clearCache(); } void QgsCurvePolygonV2::coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord ) const @@ -792,6 +800,7 @@ bool QgsCurvePolygonV2::addZValue( double zValue ) { curve->addZValue( zValue ); } + clearCache(); return true; } @@ -808,6 +817,7 @@ bool QgsCurvePolygonV2::addMValue( double mValue ) { curve->addMValue( mValue ); } + clearCache(); return true; } @@ -823,6 +833,7 @@ bool QgsCurvePolygonV2::dropZValue() { curve->dropZValue(); } + clearCache(); return true; } @@ -838,5 +849,6 @@ bool QgsCurvePolygonV2::dropMValue() { curve->dropMValue(); } + clearCache(); return true; } diff --git a/src/core/geometry/qgscurvepolygonv2.h b/src/core/geometry/qgscurvepolygonv2.h index 58a08aa028af..440bbffb8ac6 100644 --- a/src/core/geometry/qgscurvepolygonv2.h +++ b/src/core/geometry/qgscurvepolygonv2.h @@ -58,8 +58,8 @@ class CORE_EXPORT QgsCurvePolygonV2: public QgsSurfaceV2 //curve polygon interface int numInteriorRings() const; - QgsCurveV2* exteriorRing() const; - QgsCurveV2* interiorRing( int i ) const; + const QgsCurveV2* exteriorRing() const; + const QgsCurveV2* interiorRing( int i ) const; virtual QgsPolygonV2* toPolygon() const; /** Sets the exterior ring of the polygon. The CurvePolygon type will be updated to match the dimensionality diff --git a/src/core/geometry/qgscurvev2.h b/src/core/geometry/qgscurvev2.h index 26cc52863ee0..852cc60c590e 100644 --- a/src/core/geometry/qgscurvev2.h +++ b/src/core/geometry/qgscurvev2.h @@ -113,7 +113,7 @@ class CORE_EXPORT QgsCurveV2: public QgsAbstractGeometryV2 protected: - virtual void clearCache() const override { mBoundingBox = QgsRectangle(); } + virtual void clearCache() const override { mBoundingBox = QgsRectangle(); QgsAbstractGeometryV2::clearCache(); } private: diff --git a/src/core/geometry/qgsgeometrycollectionv2.cpp b/src/core/geometry/qgsgeometrycollectionv2.cpp index 52228e6a6356..bdc93df3dafa 100644 --- a/src/core/geometry/qgsgeometrycollectionv2.cpp +++ b/src/core/geometry/qgsgeometrycollectionv2.cpp @@ -46,6 +46,7 @@ QgsGeometryCollectionV2& QgsGeometryCollectionV2::operator=( const QgsGeometryCo { if ( &c != this ) { + clearCache(); QgsAbstractGeometryV2::operator=( c ); int nGeoms = c.mGeometries.size(); mGeometries.resize( nGeoms ); @@ -87,6 +88,7 @@ const QgsAbstractGeometryV2* QgsGeometryCollectionV2::geometryN( int n ) const QgsAbstractGeometryV2* QgsGeometryCollectionV2::geometryN( int n ) { + clearCache(); return mGeometries.value( n ); } @@ -590,6 +592,7 @@ bool QgsGeometryCollectionV2::addZValue( double zValue ) { geom->addZValue( zValue ); } + clearCache(); return true; } @@ -604,6 +607,7 @@ bool QgsGeometryCollectionV2::addMValue( double mValue ) { geom->addMValue( mValue ); } + clearCache(); return true; } @@ -618,6 +622,7 @@ bool QgsGeometryCollectionV2::dropZValue() { geom->dropZValue(); } + clearCache(); return true; } @@ -631,5 +636,6 @@ bool QgsGeometryCollectionV2::dropMValue() { geom->dropMValue(); } + clearCache(); return true; } diff --git a/src/core/geometry/qgsgeometrycollectionv2.h b/src/core/geometry/qgsgeometrycollectionv2.h index 85565ae69617..cdac442a02d0 100644 --- a/src/core/geometry/qgsgeometrycollectionv2.h +++ b/src/core/geometry/qgsgeometrycollectionv2.h @@ -139,7 +139,7 @@ class CORE_EXPORT QgsGeometryCollectionV2: public QgsAbstractGeometryV2 bool fromCollectionWkt( const QString &wkt, const QList& subtypes, const QString& defaultChildWkbType = QString() ); virtual QgsRectangle calculateBoundingBox() const override; - virtual void clearCache() const override { mBoundingBox = QgsRectangle(); } + virtual void clearCache() const override { mBoundingBox = QgsRectangle(); QgsAbstractGeometryV2::clearCache(); } private: diff --git a/src/core/geometry/qgslinestringv2.cpp b/src/core/geometry/qgslinestringv2.cpp index 5205022c8ecf..8ad4f4f5adc2 100644 --- a/src/core/geometry/qgslinestringv2.cpp +++ b/src/core/geometry/qgslinestringv2.cpp @@ -939,6 +939,7 @@ bool QgsLineStringV2::addZValue( double zValue ) if ( QgsWKBTypes::hasZ( mWkbType ) ) return false; + clearCache(); if ( mWkbType == QgsWKBTypes::Unknown ) { mWkbType = QgsWKBTypes::LineStringZ; @@ -962,6 +963,7 @@ bool QgsLineStringV2::addMValue( double mValue ) if ( QgsWKBTypes::hasM( mWkbType ) ) return false; + clearCache(); if ( mWkbType == QgsWKBTypes::Unknown ) { mWkbType = QgsWKBTypes::LineStringM; @@ -992,6 +994,7 @@ bool QgsLineStringV2::dropZValue() if ( !is3D() ) return false; + clearCache(); mWkbType = QgsWKBTypes::dropZ( mWkbType ); mZ.clear(); return true; @@ -1002,6 +1005,7 @@ bool QgsLineStringV2::dropMValue() if ( !isMeasure() ) return false; + clearCache(); mWkbType = QgsWKBTypes::dropM( mWkbType ); mM.clear(); return true; @@ -1012,6 +1016,7 @@ bool QgsLineStringV2::convertTo( QgsWKBTypes::Type type ) if ( type == mWkbType ) return true; + clearCache(); if ( type == QgsWKBTypes::LineString25D ) { //special handling required for conversion to LineString25D diff --git a/src/core/geometry/qgspointv2.cpp b/src/core/geometry/qgspointv2.cpp index 4bb9200be707..ba9c8e52f09f 100644 --- a/src/core/geometry/qgspointv2.cpp +++ b/src/core/geometry/qgspointv2.cpp @@ -339,6 +339,7 @@ bool QgsPointV2::addZValue( double zValue ) mWkbType = QgsWKBTypes::addZ( mWkbType ); mZ = zValue; + clearCache(); return true; } @@ -349,6 +350,7 @@ bool QgsPointV2::addMValue( double mValue ) mWkbType = QgsWKBTypes::addM( mWkbType ); mM = mValue; + clearCache(); return true; } @@ -369,6 +371,7 @@ bool QgsPointV2::dropZValue() mWkbType = QgsWKBTypes::dropZ( mWkbType ); mZ = 0.0; + clearCache(); return true; } @@ -379,6 +382,7 @@ bool QgsPointV2::dropMValue() mWkbType = QgsWKBTypes::dropM( mWkbType ); mM = 0.0; + clearCache(); return true; } @@ -387,6 +391,8 @@ bool QgsPointV2::convertTo( QgsWKBTypes::Type type ) if ( type == mWkbType ) return true; + clearCache(); + switch ( type ) { case QgsWKBTypes::Point: diff --git a/src/core/geometry/qgspointv2.h b/src/core/geometry/qgspointv2.h index ffcb1b45521a..0869e7c42fd1 100644 --- a/src/core/geometry/qgspointv2.h +++ b/src/core/geometry/qgspointv2.h @@ -107,7 +107,7 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 * @see setZ() * @note not available in Python bindings */ - double &rz() { return mZ; } + double &rz() { clearCache(); return mZ; } /** Returns a reference to the m value of this point. * Using a reference makes it possible to directly manipulate m in place. @@ -115,7 +115,7 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 * @see setM() * @note not available in Python bindings */ - double &rm() { return mM; } + double &rm() { clearCache(); return mM; } /** Sets the point's x-coordinate. * @see x() @@ -135,7 +135,7 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 * @see z() * @see rz() */ - void setZ( double z ) { mZ = z; } + void setZ( double z ) { clearCache(); mZ = z; } /** Sets the point's m-value. * @note calling this will have no effect if the point does not contain a m-dimension. Use addMValue() to @@ -143,7 +143,7 @@ class CORE_EXPORT QgsPointV2: public QgsAbstractGeometryV2 * @see m() * @see rm() */ - void setM( double m ) { mM = m; } + void setM( double m ) { clearCache(); mM = m; } /** Returns the point as a QPointF. * @note added in QGIS 2.14 diff --git a/src/core/geometry/qgspolygonv2.cpp b/src/core/geometry/qgspolygonv2.cpp index 48997f2dd438..9dc34b2da10f 100644 --- a/src/core/geometry/qgspolygonv2.cpp +++ b/src/core/geometry/qgspolygonv2.cpp @@ -197,6 +197,7 @@ void QgsPolygonV2::addInteriorRing( QgsCurveV2* ring ) { QgsCurvePolygonV2::addInteriorRing( ring ); } + clearCache(); } void QgsPolygonV2::setExteriorRing( QgsCurveV2* ring ) @@ -231,6 +232,8 @@ void QgsPolygonV2::setExteriorRing( QgsCurveV2* ring ) { ring->convertTo( mExteriorRing->wkbType() ); } + + clearCache(); } QgsPolygonV2* QgsPolygonV2::surfaceToPolygon() const diff --git a/src/core/geometry/qgssurfacev2.h b/src/core/geometry/qgssurfacev2.h index a4bb129d8e27..aabf7885f48d 100644 --- a/src/core/geometry/qgssurfacev2.h +++ b/src/core/geometry/qgssurfacev2.h @@ -42,7 +42,7 @@ class CORE_EXPORT QgsSurfaceV2: public QgsAbstractGeometryV2 protected: - virtual void clearCache() const override { mBoundingBox = QgsRectangle(); } + virtual void clearCache() const override { mBoundingBox = QgsRectangle(); QgsAbstractGeometryV2::clearCache(); } private: diff --git a/tests/src/core/testqgsgeometry.cpp b/tests/src/core/testqgsgeometry.cpp index b5376e28f262..e814048d4a82 100644 --- a/tests/src/core/testqgsgeometry.cpp +++ b/tests/src/core/testqgsgeometry.cpp @@ -2195,7 +2195,7 @@ void TestQgsGeometry::polygonV2() QVERIFY( !p1.interiorRing( 0 ) ); //retrieve exterior ring and check - QCOMPARE( *( static_cast< QgsLineStringV2* >( p1.exteriorRing() ) ), *ext ); + QCOMPARE( *( static_cast< const QgsLineStringV2* >( p1.exteriorRing() ) ), *ext ); //test that a non closed exterior ring will be automatically closed ext = new QgsLineStringV2(); @@ -2219,7 +2219,7 @@ void TestQgsGeometry::polygonV2() QCOMPARE( p2.wkbType(), QgsWKBTypes::PolygonZ ); QCOMPARE( p2.wktTypeStr(), QString( "PolygonZ" ) ); QCOMPARE( p2.geometryType(), QString( "Polygon" ) ); - QCOMPARE( *( static_cast< QgsLineStringV2* >( p2.exteriorRing() ) ), *ext ); + QCOMPARE( *( static_cast< const QgsLineStringV2* >( p2.exteriorRing() ) ), *ext ); QgsPolygonV2 p3; ext = new QgsLineStringV2(); ext->setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointM, 0, 0, 0, 1 ) @@ -2230,7 +2230,7 @@ void TestQgsGeometry::polygonV2() QVERIFY( p3.isMeasure() ); QCOMPARE( p3.wkbType(), QgsWKBTypes::PolygonM ); QCOMPARE( p3.wktTypeStr(), QString( "PolygonM" ) ); - QCOMPARE( *( static_cast< QgsLineStringV2* >( p3.exteriorRing() ) ), *ext ); + QCOMPARE( *( static_cast< const QgsLineStringV2* >( p3.exteriorRing() ) ), *ext ); QgsPolygonV2 p4; ext = new QgsLineStringV2(); ext->setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::PointZM, 0, 0, 2, 1 ) @@ -2241,7 +2241,7 @@ void TestQgsGeometry::polygonV2() QVERIFY( p4.isMeasure() ); QCOMPARE( p4.wkbType(), QgsWKBTypes::PolygonZM ); QCOMPARE( p4.wktTypeStr(), QString( "PolygonZM" ) ); - QCOMPARE( *( static_cast< QgsLineStringV2* >( p4.exteriorRing() ) ), *ext ); + QCOMPARE( *( static_cast< const QgsLineStringV2* >( p4.exteriorRing() ) ), *ext ); QgsPolygonV2 p5; ext = new QgsLineStringV2(); ext->setPoints( QList< QgsPointV2 >() << QgsPointV2( QgsWKBTypes::Point25D, 0, 0, 1 ) @@ -2252,7 +2252,7 @@ void TestQgsGeometry::polygonV2() QVERIFY( !p5.isMeasure() ); QCOMPARE( p5.wkbType(), QgsWKBTypes::Polygon25D ); QCOMPARE( p5.wktTypeStr(), QString( "PolygonZ" ) ); - QCOMPARE( *( static_cast< QgsLineStringV2* >( p5.exteriorRing() ) ), *ext ); + QCOMPARE( *( static_cast< const QgsLineStringV2* >( p5.exteriorRing() ) ), *ext ); //setting curved exterior ring should be segmentized QgsCircularStringV2* circularRing = new QgsCircularStringV2();