Skip to content
Permalink
Browse files

change QgsAbstractGeometryV2::coordinateSequence() to return a

implicitly shared copy of an internal cache instead of recreating the
coordinate sequence again and again.

Improves performance of the nodetool on large features a lot (refs #13963)

Also introduce Qgs(Coordinate|Ring|Point)SequenceV2 typedefs.
  • Loading branch information
jef-n committed Feb 21, 2016
1 parent 4485d3a commit e503c705a1c4dba07617f6beaf0a58360c857bcf
Showing with 365 additions and 346 deletions.
  1. +2 −2 python/core/geometry/qgsabstractgeometryv2.sip
  2. +1 −1 python/core/geometry/qgscircularstringv2.sip
  3. +1 −1 python/core/geometry/qgscurvepolygonv2.sip
  4. +3 −3 python/core/geometry/qgscurvev2.sip
  5. +8 −0 python/core/geometry/qgsgeometry.sip
  6. +1 −1 python/core/geometry/qgsgeometrycollectionv2.sip
  7. +1 −1 python/core/geometry/qgspointv2.sip
  8. +7 −0 python/core/qgsvectorlayereditutils.sip
  9. +2 −2 src/app/qgsmaptooladdcircularstring.cpp
  10. +1 −1 src/app/qgsmaptooladdcircularstring.h
  11. +1 −1 src/app/qgsmaptooladdpart.cpp
  12. +2 −2 src/app/qgsmaptoolcircularstringcurvepoint.cpp
  13. +1 −1 src/app/qgsmaptoolcircularstringradius.cpp
  14. +3 −8 src/core/geometry/qgsabstractgeometryv2.cpp
  15. +5 −2 src/core/geometry/qgsabstractgeometryv2.h
  16. +12 −12 src/core/geometry/qgscircularstringv2.cpp
  17. +4 −4 src/core/geometry/qgscircularstringv2.h
  18. +4 −4 src/core/geometry/qgscompoundcurvev2.cpp
  19. +1 −1 src/core/geometry/qgscompoundcurvev2.h
  20. +15 −12 src/core/geometry/qgscurvepolygonv2.cpp
  21. +1 −1 src/core/geometry/qgscurvepolygonv2.h
  22. +9 −7 src/core/geometry/qgscurvev2.cpp
  23. +6 −5 src/core/geometry/qgscurvev2.h
  24. +22 −25 src/core/geometry/qgsgeometry.cpp
  25. +4 −4 src/core/geometry/qgsgeometry.h
  26. +10 −6 src/core/geometry/qgsgeometrycollectionv2.cpp
  27. +3 −2 src/core/geometry/qgsgeometrycollectionv2.h
  28. +1 −1 src/core/geometry/qgsgeometryengine.h
  29. +1 −1 src/core/geometry/qgsgeometryfactory.cpp
  30. +12 −11 src/core/geometry/qgsgeometryutils.cpp
  31. +6 −6 src/core/geometry/qgsgeometryutils.h
  32. +3 −3 src/core/geometry/qgsgeos.cpp
  33. +2 −2 src/core/geometry/qgsgeos.h
  34. +7 −7 src/core/geometry/qgslinestringv2.cpp
  35. +2 −2 src/core/geometry/qgslinestringv2.h
  36. +1 −1 src/core/geometry/qgsmulticurvev2.cpp
  37. +1 −1 src/core/geometry/qgsmultilinestringv2.cpp
  38. +1 −1 src/core/geometry/qgsmultipointv2.cpp
  39. +2 −2 src/core/geometry/qgsmultipolygonv2.cpp
  40. +2 −2 src/core/geometry/qgsmultisurfacev2.cpp
  41. +7 −5 src/core/geometry/qgspointv2.cpp
  42. +1 −1 src/core/geometry/qgspointv2.h
  43. +2 −2 src/core/geometry/qgspolygonv2.cpp
  44. +2 −3 src/core/geometry/qgssurfacev2.h
  45. +2 −2 src/core/qgsdistancearea.cpp
  46. +3 −6 src/core/qgsexpression.cpp
  47. +1 −1 src/core/qgsvectorlayer.cpp
  48. +2 −1 src/core/qgsvectorlayer.h
  49. +3 −3 src/core/qgsvectorlayereditutils.cpp
  50. +1 −1 src/core/qgsvectorlayereditutils.h
  51. +5 −5 src/gui/qgsmaptoolcapture.cpp
  52. +1 −1 src/plugins/geometry_checker/checks/qgsgeometryselfintersectioncheck.cpp
  53. +2 −2 src/providers/grass/qgsgrassvectormap.cpp
  54. +162 −164 tests/src/core/testqgsgeometry.cpp
@@ -221,9 +221,9 @@ class QgsAbstractGeometryV2
virtual bool nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const = 0;

/** Retrieves the sequence of geometries, rings and nodes.
* @param coord destination for coordinate sequence.
* @return coordinate sequence
*/
virtual void coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord /Out/ ) const = 0;
virtual QList< QList< QList< QgsPointV2 > > > coordinateSequence() const = 0;

/** Returns the number of nodes contained in the geometry
*/
@@ -82,7 +82,7 @@ class QgsCircularStringV2: public QgsCurveV2
/**
* @copydoc QgsCurveV2::pointAt()
*/
bool pointAt( int i, QgsPointV2& vertex, QgsVertexId::VertexType& type ) const;
bool pointAt( int node, QgsPointV2& point, QgsVertexId::VertexType& type ) const;

/**
* @copydoc QgsCurveV2::sumUpArea()
@@ -64,7 +64,7 @@ class QgsCurvePolygonV2: public QgsSurfaceV2
virtual bool moveVertex( QgsVertexId position, const QgsPointV2& newPos );
virtual bool deleteVertex( QgsVertexId position );

virtual void coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord /Out/ ) const;
virtual QList< QList< QList< QgsPointV2 > > > coordinateSequence() const;
double closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const;
bool nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const;

@@ -57,7 +57,7 @@ class QgsCurveV2: public QgsAbstractGeometryV2
*/
virtual void sumUpArea( double& sum ) const = 0;

virtual void coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord /Out/ ) const;
virtual QList< QList< QList< QgsPointV2 > > > coordinateSequence() const;
virtual bool nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const;

/** Returns the point and vertex id of a point within the curve.
@@ -76,8 +76,8 @@ class QgsCurveV2: public QgsAbstractGeometryV2
/** Returns a geometry without curves. Caller takes ownership*/
virtual QgsCurveV2* segmentize() const /Factory/;

virtual int vertexCount(int part = 0, int ring = 0) const;
virtual int ringCount(int part = 0) const;
virtual int vertexCount( int part = 0, int ring = 0 ) const;
virtual int ringCount( int part = 0 ) const;
virtual int partCount() const;
virtual QgsPointV2 vertexAt( QgsVertexId id ) const;

@@ -279,11 +279,13 @@ class QgsGeometry
/** Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
@return 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
3 ring is not valid geometry, 4 ring not disjoint with existing rings, 5 no polygon found which contained the ring*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addRing( const QList<QgsPoint>& ring );

/** Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
@return 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
3 ring is not valid geometry, 4 ring not disjoint with existing rings, 5 no polygon found which contained the ring*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addRing( QgsCurveV2* ring );

/** Adds a new part to a the geometry.
@@ -292,6 +294,7 @@ class QgsGeometry
* @returns 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
* not disjoint with existing polygons of the feature
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addPart( const QList<QgsPoint> &points, QGis::GeometryType geomType = QGis::UnknownGeometry );

/** Adds a new part to a the geometry.
@@ -300,6 +303,7 @@ class QgsGeometry
* @returns 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
* not disjoint with existing polygons of the feature
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addPart( const QList<QgsPointV2> &points, QGis::GeometryType geomType = QGis::UnknownGeometry );

/** Adds a new part to this geometry.
@@ -308,6 +312,7 @@ class QgsGeometry
* @returns 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
* not disjoint with existing polygons of the feature
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addPart( QgsAbstractGeometryV2* part /Transfer/, QGis::GeometryType geomType = QGis::UnknownGeometry );

/** Adds a new island polygon to a multipolygon feature
@@ -316,13 +321,15 @@ class QgsGeometry
* not disjoint with existing polygons of the feature
* @note not available in python bindings
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
// int addPart( GEOSGeometry *newPart );

/** Adds a new island polygon to a multipolygon feature
@return 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
not disjoint with existing polygons of the feature
@note available in python bindings as addPartGeometry (added in 2.2)
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addPart( const QgsGeometry *newPart /Transfer/ ) /PyName=addPartGeometry/;

/** Translate this geometry by dx, dy
@@ -351,6 +358,7 @@ class QgsGeometry
@param topological true if topological editing is enabled
@param[out] topologyTestPoints points that need to be tested for topological completeness in the dataset
@return 0 in case of success, 1 if geometry has not been split, error else*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int splitGeometry( const QList<QgsPoint>& splitLine,
QList<QgsGeometry*>&newGeometries /Out/,
bool topological,
@@ -68,7 +68,7 @@ class QgsGeometryCollectionV2: public QgsAbstractGeometryV2

virtual QgsRectangle boundingBox() const;

virtual void coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord /Out/ ) const;
virtual QList< QList< QList< QgsPointV2 > > > coordinateSequence() const;
virtual double closestSegment( const QgsPointV2& pt, QgsPointV2& segmentPt, QgsVertexId& vertexAfter, bool* leftOf, double epsilon ) const;
bool nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const;

@@ -155,7 +155,7 @@ class QgsPointV2: public QgsAbstractGeometryV2
void draw( QPainter& p ) const;
void transform( const QgsCoordinateTransform& ct, QgsCoordinateTransform::TransformDirection d = QgsCoordinateTransform::ForwardTransform );
void transform( const QTransform& t );
virtual void coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord /Out/ ) const;
virtual QList< QList< QList< QgsPointV2 > > > coordinateSequence() const;

//low-level editing
virtual bool insertVertex( QgsVertexId position, const QgsPointV2& vertex );
@@ -54,6 +54,7 @@ class QgsVectorLayerEditUtils
* 4 ring crosses existing rings,
* 5 no feature found where ring can be inserted
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addRing( const QList<QgsPoint>& ring, const QgsFeatureIds& targetFeatureIds = QgsFeatureIds(), QgsFeatureId* modifiedFeatureId = 0 );

/** Adds a ring to polygon/multipolygon features
@@ -70,6 +71,7 @@ class QgsVectorLayerEditUtils
* 5 no feature found where ring can be inserted
* @note available in python bindings as addCurvedRing
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addRing( QgsCurveV2* ring, const QgsFeatureIds& targetFeatureIds = QgsFeatureIds(), QgsFeatureId* modifiedFeatureId = nullptr ) /PyName=addCurvedRing/;

/** Adds a new part polygon to a multipart feature
@@ -82,6 +84,7 @@ class QgsVectorLayerEditUtils
* 5 if several features are selected,
* 6 if selected geometry not found
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addPart( const QList<QgsPoint>& ring, QgsFeatureId featureId );

/** Adds a new part polygon to a multipart feature
@@ -95,9 +98,11 @@ class QgsVectorLayerEditUtils
* 6 if selected geometry not found
* @note available in python bindings as addPartV2
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addPart( const QList<QgsPointV2>& ring, QgsFeatureId featureId ) /PyName=addPartV2/;

// @note available in python bindings as addCurvedPart
// TODO QGIS 3.0 returns an enum instead of a magic constant
int addPart( QgsCurveV2* ring, QgsFeatureId featureId ) /PyName=addCurvedPart/;

/** Translates feature by dx, dy
@@ -115,6 +120,7 @@ class QgsVectorLayerEditUtils
* 0 in case of success,
* 4 if there is a selection but no feature split
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int splitParts( const QList<QgsPoint>& splitLine, bool topologicalEditing = false );

/** Splits features cut by the given line
@@ -124,6 +130,7 @@ class QgsVectorLayerEditUtils
* 0 in case of success,
* 4 if there is a selection but no feature split
*/
// TODO QGIS 3.0 returns an enum instead of a magic constant
int splitFeatures( const QList<QgsPoint>& splitLine, bool topologicalEditing = false );

/** Adds topological points for every vertex of the geometry.
@@ -161,7 +161,7 @@ void QgsMapToolAddCircularString::activate()
mTempRubberBand->show();
}
QgsCircularStringV2* c = new QgsCircularStringV2();
QList< QgsPointV2 > rubberBandPoints = mPoints;
QgsPointSequenceV2 rubberBandPoints = mPoints;
rubberBandPoints.append( QgsPointV2( mapPoint ) );
c->setPoints( rubberBandPoints );
mTempRubberBand->setGeometry( c );
@@ -208,7 +208,7 @@ void QgsMapToolAddCircularString::updateCenterPointRubberBand( const QgsPointV2&

//create circular string
QgsCircularStringV2* cs = new QgsCircularStringV2();
QList< QgsPointV2 > csPoints;
QgsPointSequenceV2 csPoints;
csPoints.append( mPoints.at( mPoints.size() - 2 ) );
csPoints.append( mPoints.at( mPoints.size() - 1 ) );
csPoints.append( pt );
@@ -45,7 +45,7 @@ class QgsMapToolAddCircularString: public QgsMapToolCapture
* */
QgsMapToolCapture* mParentTool;
/** Circular string points (in map coordinates)*/
QList< QgsPointV2 > mPoints;
QgsPointSequenceV2 mPoints;
//! The rubberband to show the already completed circular strings
QgsGeometryRubberBand* mRubberBand;
//! The rubberband to show the circular string currently working on
@@ -85,7 +85,7 @@ void QgsMapToolAddPart::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
}

vlayer->beginEditCommand( tr( "Part added" ) );
errorCode = vlayer->addPart( QList<QgsPointV2>() << layerPoint );
errorCode = vlayer->addPart( QgsPointSequenceV2() << layerPoint );
}
break;

@@ -52,7 +52,7 @@ void QgsMapToolCircularStringCurvePoint::cadCanvasReleaseEvent( QgsMapMouseEvent
}

QgsCircularStringV2* c = new QgsCircularStringV2();
QList< QgsPointV2 > rubberBandPoints = mPoints.mid( mPoints.size() - 1 - ( mPoints.size() + 1 ) % 2 );
QgsPointSequenceV2 rubberBandPoints = mPoints.mid( mPoints.size() - 1 - ( mPoints.size() + 1 ) % 2 );
rubberBandPoints.append( mapPoint );
c->setPoints( rubberBandPoints );
mTempRubberBand->setGeometry( c );
@@ -66,7 +66,7 @@ void QgsMapToolCircularStringCurvePoint::cadCanvasReleaseEvent( QgsMapMouseEvent
}

QgsCircularStringV2* c = new QgsCircularStringV2();
QList< QgsPointV2 > rubberBandPoints = mPoints;
QgsPointSequenceV2 rubberBandPoints = mPoints;
rubberBandPoints.append( mapPoint );
c->setPoints( rubberBandPoints );
mRubberBand->setGeometry( c );
@@ -122,7 +122,7 @@ void QgsMapToolCircularStringRadius::recalculateRubberBand()

void QgsMapToolCircularStringRadius::recalculateTempRubberBand( const QgsPoint& mousePosition )
{
QList<QgsPointV2> rubberBandPoints;
QgsPointSequenceV2 rubberBandPoints;
if ( !( mPoints.size() % 2 ) )
{
//recalculate midpoint on circle segment
@@ -137,18 +137,13 @@ QgsRectangle QgsAbstractGeometryV2::calculateBoundingBox() const

int QgsAbstractGeometryV2::nCoordinates() const
{
QList< QList< QList< QgsPointV2 > > > coordinates;
coordinateSequence( coordinates );
int nCoords = 0;

QList< QList< QList< QgsPointV2 > > >::const_iterator partIt = coordinates.constBegin();
for ( ; partIt != coordinates.constEnd(); ++partIt )
Q_FOREACH ( const QgsRingSequenceV2 &r, coordinateSequence() )
{
const QList< QList< QgsPointV2 > >& part = *partIt;
QList< QList< QgsPointV2 > >::const_iterator ringIt = part.constBegin();
for ( ; ringIt != part.constEnd(); ++ringIt )
Q_FOREACH ( const QgsPointSequenceV2 &p, r )
{
nCoords += ringIt->size();
nCoords += p.size();
}
}

@@ -32,6 +32,9 @@ class QgsPointV2;
struct QgsVertexId;
class QPainter;

typedef QList< QgsPointV2 > QgsPointSequenceV2;
typedef QList< QgsPointSequenceV2 > QgsRingSequenceV2;
typedef QList< QgsRingSequenceV2 > QgsCoordinateSequenceV2;

/** \ingroup core
* \class QgsAbstractGeometryV2
@@ -204,9 +207,9 @@ class CORE_EXPORT QgsAbstractGeometryV2
virtual bool nextVertex( QgsVertexId& id, QgsPointV2& vertex ) const = 0;

/** Retrieves the sequence of geometries, rings and nodes.
* @param coord destination for coordinate sequence.
* @return coordinate sequence
*/
virtual void coordinateSequence( QList< QList< QList< QgsPointV2 > > >& coord ) const = 0;
virtual QgsCoordinateSequenceV2 coordinateSequence() const = 0;

/** Returns the number of nodes contained in the geometry
*/
@@ -118,18 +118,18 @@ QgsRectangle QgsCircularStringV2::segmentBoundingBox( const QgsPointV2& pt1, con
QgsRectangle bbox( pt1.x(), pt1.y(), pt1.x(), pt1.y() );
bbox.combineExtentWith( pt3.x(), pt3.y() );

QList<QgsPointV2> compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
QList<QgsPointV2>::const_iterator cpIt = compassPoints.constBegin();
QgsPointSequenceV2 compassPoints = compassPointsOnSegment( p1Angle, p2Angle, p3Angle, centerX, centerY, radius );
QgsPointSequenceV2::const_iterator cpIt = compassPoints.constBegin();
for ( ; cpIt != compassPoints.constEnd(); ++cpIt )
{
bbox.combineExtentWith( cpIt->x(), cpIt->y() );
}
return bbox;
}

QList<QgsPointV2> QgsCircularStringV2::compassPointsOnSegment( double p1Angle, double p2Angle, double p3Angle, double centerX, double centerY, double radius )
QgsPointSequenceV2 QgsCircularStringV2::compassPointsOnSegment( double p1Angle, double p2Angle, double p3Angle, double centerX, double centerY, double radius )
{
QList<QgsPointV2> pointList;
QgsPointSequenceV2 pointList;

QgsPointV2 nPoint( centerX, centerY + radius );
QgsPointV2 ePoint( centerX + radius, centerY );
@@ -274,7 +274,7 @@ unsigned char* QgsCircularStringV2::asWkb( int& binarySize ) const
QgsWkbPtr wkb( geomPtr, binarySize );
wkb << static_cast<char>( QgsApplication::endian() );
wkb << static_cast<quint32>( wkbType() );
QList<QgsPointV2> pts;
QgsPointSequenceV2 pts;
points( pts );
QgsGeometryUtils::pointsToWKB( wkb, pts, is3D(), isMeasure() );
return geomPtr;
@@ -283,7 +283,7 @@ unsigned char* QgsCircularStringV2::asWkb( int& binarySize ) const
QString QgsCircularStringV2::asWkt( int precision ) const
{
QString wkt = wktTypeStr() + ' ';
QList<QgsPointV2> pts;
QgsPointSequenceV2 pts;
points( pts );
wkt += QgsGeometryUtils::pointsToWKT( pts, precision, is3D(), isMeasure() );
return wkt;
@@ -300,7 +300,7 @@ QDomElement QgsCircularStringV2::asGML2( QDomDocument& doc, int precision, const

QDomElement QgsCircularStringV2::asGML3( QDomDocument& doc, int precision, const QString& ns ) const
{
QList<QgsPointV2> pts;
QgsPointSequenceV2 pts;
points( pts );

QDomElement elemCurve = doc.createElementNS( ns, "Curve" );
@@ -354,7 +354,7 @@ QgsPointV2 QgsCircularStringV2::endPoint() const
QgsLineStringV2* QgsCircularStringV2::curveToLine() const
{
QgsLineStringV2* line = new QgsLineStringV2();
QList<QgsPointV2> points;
QgsPointSequenceV2 points;
int nPoints = numPoints();

for ( int i = 0; i < ( nPoints - 2 ) ; i += 2 )
@@ -408,7 +408,7 @@ QgsPointV2 QgsCircularStringV2::pointN( int i ) const
return QgsPointV2( t, x, y, z, m );
}

void QgsCircularStringV2::points( QList<QgsPointV2>& pts ) const
void QgsCircularStringV2::points( QgsPointSequenceV2 &pts ) const
{
pts.clear();
int nPts = numPoints();
@@ -418,7 +418,7 @@ void QgsCircularStringV2::points( QList<QgsPointV2>& pts ) const
}
}

void QgsCircularStringV2::setPoints( const QList<QgsPointV2>& points )
void QgsCircularStringV2::setPoints( const QgsPointSequenceV2 &points )
{
clearCache();

@@ -473,7 +473,7 @@ void QgsCircularStringV2::setPoints( const QList<QgsPointV2>& points )
}
}

void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QList<QgsPointV2>& points ) const
void QgsCircularStringV2::segmentize( const QgsPointV2& p1, const QgsPointV2& p2, const QgsPointV2& p3, QgsPointSequenceV2 &points ) const
{
//adapted code from postgis
double radius = 0;
@@ -670,7 +670,7 @@ void QgsCircularStringV2::addToPainterPath( QPainterPath& path ) const

for ( int i = 0; i < ( nPoints - 2 ) ; i += 2 )
{
QList<QgsPointV2> pt;
QgsPointSequenceV2 pt;
segmentize( QgsPointV2( mX[i], mY[i] ), QgsPointV2( mX[i + 1], mY[i + 1] ), QgsPointV2( mX[i + 2], mY[i + 2] ), pt );
for ( int j = 1; j < pt.size(); ++j )
{

0 comments on commit e503c70

Please sign in to comment.
You can’t perform that action at this time.