Skip to content

Commit

Permalink
change QgsAbstractGeometryV2::coordinateSequence() to return a
Browse files Browse the repository at this point in the history
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 e503c70
Show file tree
Hide file tree
Showing 54 changed files with 365 additions and 346 deletions.
4 changes: 2 additions & 2 deletions python/core/geometry/qgsabstractgeometryv2.sip
Expand Up @@ -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
*/
Expand Down
2 changes: 1 addition & 1 deletion python/core/geometry/qgscircularstringv2.sip
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion python/core/geometry/qgscurvepolygonv2.sip
Expand Up @@ -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;

Expand Down
6 changes: 3 additions & 3 deletions python/core/geometry/qgscurvev2.sip
Expand Up @@ -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.
Expand All @@ -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;

Expand Down
8 changes: 8 additions & 0 deletions python/core/geometry/qgsgeometry.sip
Expand Up @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion python/core/geometry/qgsgeometrycollectionv2.sip
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion python/core/geometry/qgspointv2.sip
Expand Up @@ -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 );
Expand Down
7 changes: 7 additions & 0 deletions python/core/qgsvectorlayereditutils.sip
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions src/app/qgsmaptooladdcircularstring.cpp
Expand Up @@ -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 );
Expand Down Expand Up @@ -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 );
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsmaptooladdcircularstring.h
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsmaptooladdpart.cpp
Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions src/app/qgsmaptoolcircularstringcurvepoint.cpp
Expand Up @@ -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 );
Expand All @@ -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 );
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsmaptoolcircularstringradius.cpp
Expand Up @@ -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
Expand Down
11 changes: 3 additions & 8 deletions src/core/geometry/qgsabstractgeometryv2.cpp
Expand Up @@ -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();
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/core/geometry/qgsabstractgeometryv2.h
Expand Up @@ -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
Expand Down Expand Up @@ -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
*/
Expand Down
24 changes: 12 additions & 12 deletions src/core/geometry/qgscircularstringv2.cpp
Expand Up @@ -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 );
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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" );
Expand Down Expand Up @@ -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 )
Expand Down Expand Up @@ -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();
Expand All @@ -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();

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 )
{
Expand Down

0 comments on commit e503c70

Please sign in to comment.