Skip to content

Commit

Permalink
Add mechanism to defer updates of rubber bands when adding multiple
Browse files Browse the repository at this point in the history
geometries

GREATLY speeds up rubber band creation for many geometries, resulting
in consequent speed ups to the move features tool, rotate features tool,
....
  • Loading branch information
nyalldawson committed Feb 22, 2021
1 parent 67c2263 commit 7b37f32
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 13 deletions.
11 changes: 9 additions & 2 deletions python/gui/auto_generated/qgsrubberband.sip.in
Expand Up @@ -273,26 +273,33 @@ Sets this rubber band to a map canvas rectangle
:param rect: rectangle in canvas coordinates
%End

void addGeometry( const QgsGeometry &geometry, QgsVectorLayer *layer );
void addGeometry( const QgsGeometry &geometry, QgsVectorLayer *layer, bool doUpdate = true );
%Docstring
Adds the geometry of an existing feature to a rubberband
This is useful for multi feature highlighting.
As of 2.0, this method does not change the GeometryType any more. You need to set the GeometryType
of the rubberband explicitly by calling :py:func:`~QgsRubberBand.reset` or :py:func:`~QgsRubberBand.setToGeometry` with appropriate arguments.
:py:func:`~QgsRubberBand.setToGeometry` is also to be preferred for backwards-compatibility.

If additional geometries are to be added then set ``doUpdate`` to ``False`` to defer costly repaint and bounding rectangle calculations for better performance.
After adding the final geometry :py:func:`~QgsRubberBand.updatePosition` should be called.

:param geometry: the geometry object. Will be treated as a collection of vertices.
:param layer: the layer containing the feature, used for coord transformation to map
crs. If ``layer`` is ``None``, the coordinates are not going to be transformed.
:param doUpdate: set to ``False`` to defer updates of the rubber band.
%End

void addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
void addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem(), bool doUpdate = true );
%Docstring
Adds a ``geometry`` to the rubberband.

If ``crs`` is specified, the geometry will be automatically reprojected from ``crs``
to the canvas CRS.

If additional geometries are to be added then set ``doUpdate`` to ``False`` to defer costly repaint and bounding rectangle calculations for better performance.
After adding the final geometry :py:func:`~QgsRubberBand.updatePosition` should be called.

.. versionadded:: 3.0
%End

Expand Down
4 changes: 3 additions & 1 deletion src/app/qgsmaptoolmovefeature.cpp
Expand Up @@ -138,11 +138,13 @@ void QgsMapToolMoveFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )

while ( it.nextFeature( feat ) )
{
mRubberBand->addGeometry( feat.geometry(), vlayer );
mRubberBand->addGeometry( feat.geometry(), vlayer, false );

if ( allFeaturesInView && !viewRect.intersects( feat.geometry().boundingBox() ) )
allFeaturesInView = false;
}
mRubberBand->updatePosition();
mRubberBand->update();

if ( !allFeaturesInView )
{
Expand Down
4 changes: 3 additions & 1 deletion src/app/qgsmaptoolrotatefeature.cpp
Expand Up @@ -304,8 +304,10 @@ void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
QgsFeatureIterator it = vlayer->getSelectedFeatures();
while ( it.nextFeature( feat ) )
{
mRubberBand->addGeometry( feat.geometry(), vlayer );
mRubberBand->addGeometry( feat.geometry(), vlayer, false );
}
mRubberBand->updatePosition();
mRubberBand->update();
}

mRubberBand->show();
Expand Down
4 changes: 3 additions & 1 deletion src/app/qgsmaptoolscalefeature.cpp
Expand Up @@ -266,9 +266,11 @@ void QgsMapToolScaleFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
QgsFeatureIterator it = vlayer->getSelectedFeatures();
while ( it.nextFeature( feat ) )
{
mRubberBand->addGeometry( feat.geometry(), vlayer );
mRubberBand->addGeometry( feat.geometry(), vlayer, false );
mOriginalGeometries << feat.geometry();
}
mRubberBand->updatePosition();
mRubberBand->update();
}

mScalingActive = true;
Expand Down
4 changes: 3 additions & 1 deletion src/gui/qgsmapcanvas.cpp
Expand Up @@ -1624,7 +1624,9 @@ void QgsMapCanvas::flashGeometries( const QList<QgsGeometry> &geometries, const
QgsWkbTypes::GeometryType geomType = QgsWkbTypes::geometryType( geometries.at( 0 ).wkbType() );
QgsRubberBand *rb = new QgsRubberBand( this, geomType );
for ( const QgsGeometry &geom : geometries )
rb->addGeometry( geom, crs );
rb->addGeometry( geom, crs, false );
rb->updatePosition();
rb->update();

if ( geomType == QgsWkbTypes::LineGeometry || geomType == QgsWkbTypes::PointGeometry )
{
Expand Down
13 changes: 8 additions & 5 deletions src/gui/qgsrubberband.cpp
Expand Up @@ -276,7 +276,7 @@ void QgsRubberBand::setToGeometry( const QgsGeometry &geom, const QgsCoordinateR
addGeometry( geom, crs );
}

void QgsRubberBand::addGeometry( const QgsGeometry &geometry, QgsVectorLayer *layer )
void QgsRubberBand::addGeometry( const QgsGeometry &geometry, QgsVectorLayer *layer, bool doUpdate )
{
QgsGeometry geom = geometry;
if ( layer )
Expand All @@ -292,10 +292,10 @@ void QgsRubberBand::addGeometry( const QgsGeometry &geometry, QgsVectorLayer *la
}
}

addGeometry( geom );
addGeometry( geom, QgsCoordinateReferenceSystem(), doUpdate );
}

void QgsRubberBand::addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs )
void QgsRubberBand::addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs, bool doUpdate )
{
if ( geometry.isEmpty() )
{
Expand Down Expand Up @@ -394,8 +394,11 @@ void QgsRubberBand::addGeometry( const QgsGeometry &geometry, const QgsCoordinat
}

setVisible( true );
updateRect();
update();
if ( doUpdate )
{
updateRect();
update();
}
}

void QgsRubberBand::setToCanvasRectangle( QRect rect )
Expand Down
11 changes: 9 additions & 2 deletions src/gui/qgsrubberband.h
Expand Up @@ -324,21 +324,28 @@ class GUI_EXPORT QgsRubberBand : public QgsMapCanvasItem
* of the rubberband explicitly by calling reset() or setToGeometry() with appropriate arguments.
* setToGeometry() is also to be preferred for backwards-compatibility.
*
* If additional geometries are to be added then set \a doUpdate to FALSE to defer costly repaint and bounding rectangle calculations for better performance.
* After adding the final geometry updatePosition() should be called.
*
* \param geometry the geometry object. Will be treated as a collection of vertices.
* \param layer the layer containing the feature, used for coord transformation to map
* crs. If \a layer is NULLPTR, the coordinates are not going to be transformed.
* \param doUpdate set to FALSE to defer updates of the rubber band.
*/
void addGeometry( const QgsGeometry &geometry, QgsVectorLayer *layer );
void addGeometry( const QgsGeometry &geometry, QgsVectorLayer *layer, bool doUpdate = true );

/**
* Adds a \a geometry to the rubberband.
*
* If \a crs is specified, the geometry will be automatically reprojected from \a crs
* to the canvas CRS.
*
* If additional geometries are to be added then set \a doUpdate to FALSE to defer costly repaint and bounding rectangle calculations for better performance.
* After adding the final geometry updatePosition() should be called.
*
* \since QGIS 3.0
*/
void addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
void addGeometry( const QgsGeometry &geometry, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem(), bool doUpdate = true );

/**
* Adds translation to original coordinates (all in map coordinates)
Expand Down

0 comments on commit 7b37f32

Please sign in to comment.