Merge pull request #60130 from Joonalai/fix-topological-slowness

Fix topological slowness with spatial filtering
This commit is contained in:
Julien Cabieces 2025-01-16 17:23:09 +01:00 committed by GitHub
commit d2aaa9c6e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 68 additions and 16 deletions

View File

@ -332,6 +332,7 @@ Merge features into a single one.
.. versionadded:: 3.30
%End
};
/************************************************************************

View File

@ -332,6 +332,7 @@ Merge features into a single one.
.. versionadded:: 3.30
%End
};
/************************************************************************

View File

@ -28,6 +28,7 @@
#include "qgisapp.h"
#include "qgsexpressioncontextutils.h"
#include "qgsrubberband.h"
#include "qgsvectorlayereditutils.h"
#include <QSettings>
@ -143,11 +144,16 @@ void QgsMapToolAddFeature::featureDigitized( const QgsFeature &feature )
}
if ( topologicalEditing )
{
QgsFeatureRequest request = QgsFeatureRequest().setNoAttributes().setFlags( Qgis::FeatureRequestFlag::NoGeometry ).setLimit( 1 );
const QgsRectangle bbox = feature.geometry().boundingBox();
const QList<QgsMapLayer *> layers = canvas()->layers( true );
for ( QgsMapLayer *layer : layers )
{
QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
QgsRectangle searchRect;
QgsFeature f;
QgsCoordinateTransform transform;
if ( !vectorLayer || !vectorLayer->isEditable() )
continue;
@ -155,6 +161,23 @@ void QgsMapToolAddFeature::featureDigitized( const QgsFeature &feature )
if ( !( vectorLayer->geometryType() == Qgis::GeometryType::Polygon || vectorLayer->geometryType() == Qgis::GeometryType::Line ) )
continue;
if ( vectorLayer->crs() == vlayer->crs() )
{
searchRect = QgsRectangle( bbox );
}
else
{
transform = QgsCoordinateTransform( vlayer->crs(), vectorLayer->crs(), vectorLayer->transformContext() );
searchRect = transform.transformBoundingBox( bbox );
}
searchRect.grow( QgsVectorLayerEditUtils::getTopologicalSearchRadius( vectorLayer ) );
request.setFilterRect( searchRect );
// We check that there is actually at least one feature intersecting our geometry in the layer to avoid creating an empty edit command and calling costly addTopologicalPoint
if ( !vectorLayer->getFeatures( request ).nextFeature( f ) )
continue;
vectorLayer->beginEditCommand( tr( "Topological points added by 'Add Feature'" ) );
int res = 2;
@ -164,7 +187,7 @@ void QgsMapToolAddFeature::featureDigitized( const QgsFeature &feature )
try
{
// transform digitized geometry from vlayer crs to vectorLayer crs and add topological points
transformedGeom.transform( QgsCoordinateTransform( vlayer->crs(), vectorLayer->crs(), vectorLayer->transformContext() ) );
transformedGeom.transform( transform );
res = vectorLayer->addTopologicalPoints( transformedGeom );
}
catch ( QgsCsException &cse )

View File

@ -43,6 +43,7 @@
#include "qgsexpressioncontextutils.h"
#include "qgsmessagebar.h"
#include "qgssettingsentryimpl.h"
#include "qgsvectorlayereditutils.h"
#include <QMenu>
@ -2204,6 +2205,10 @@ void QgsVertexTool::moveVertex( const QgsPointXY &mapPoint, const QgsPointLocato
{
// topo editing: add vertex to existing segments when moving/adding a vertex to such segment.
QgsFeatureRequest request = QgsFeatureRequest().setNoAttributes().setFlags( Qgis::FeatureRequestFlag::NoGeometry ).setLimit( 1 );
const QgsRectangle bbox = layerPoint.boundingBox();
const QList<QgsMapLayer *> targetLayers = canvas()->layers( true );
for ( auto itLayerEdits = edits.begin(); itLayerEdits != edits.end(); ++itLayerEdits )
@ -2211,6 +2216,8 @@ void QgsVertexTool::moveVertex( const QgsPointXY &mapPoint, const QgsPointLocato
for ( QgsMapLayer *targetLayer : targetLayers )
{
QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( targetLayer );
QgsRectangle searchRect;
QgsFeature f;
if ( !vectorLayer || !vectorLayer->isEditable() )
continue;
@ -2222,6 +2229,14 @@ void QgsVertexTool::moveVertex( const QgsPointXY &mapPoint, const QgsPointLocato
if ( vectorLayer->crs() != itLayerEdits.key()->crs() )
continue;
searchRect = QgsRectangle( bbox );
searchRect.grow( QgsVectorLayerEditUtils::getTopologicalSearchRadius( vectorLayer ) );
request.setFilterRect( searchRect );
// We check that there is actually at least one feature intersecting our geometry in the layer to avoid creating an empty edit command and calling costly addTopologicalPoint
if ( !vectorLayer->getFeatures( request ).nextFeature( f ) )
continue;
vectorLayer->beginEditCommand( tr( "Topological points added by 'Vertex Tool'" ) );
bool topoPointsAdded = false;

View File

@ -211,6 +211,28 @@ Qgis::GeometryOperationResult staticAddRing( QgsVectorLayer *layer, std::unique_
return success ? Qgis::GeometryOperationResult::Success : addRingReturnCode;
}
///@cond PRIVATE
double QgsVectorLayerEditUtils::getTopologicalSearchRadius( const QgsVectorLayer *layer )
{
double threshold = layer->geometryOptions()->geometryPrecision();
if ( qgsDoubleNear( threshold, 0.0 ) )
{
threshold = 1e-8;
if ( layer->crs().mapUnits() == Qgis::DistanceUnit::Meters )
{
threshold = 0.001;
}
else if ( layer->crs().mapUnits() == Qgis::DistanceUnit::Feet )
{
threshold = 0.0001;
}
}
return threshold;
}
///@endcond
Qgis::GeometryOperationResult QgsVectorLayerEditUtils::addRing( const QVector<QgsPointXY> &ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureId *modifiedFeatureId )
{
QgsPointSequence l;
@ -801,21 +823,7 @@ int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPoint &p )
double segmentSearchEpsilon = mLayer->crs().isGeographic() ? 1e-12 : 1e-8;
//work with a tolerance because coordinate projection may introduce some rounding
double threshold = mLayer->geometryOptions()->geometryPrecision();
if ( qgsDoubleNear( threshold, 0.0 ) )
{
threshold = 1e-8;
if ( mLayer->crs().mapUnits() == Qgis::DistanceUnit::Meters )
{
threshold = 0.001;
}
else if ( mLayer->crs().mapUnits() == Qgis::DistanceUnit::Feet )
{
threshold = 0.0001;
}
}
double threshold = getTopologicalSearchRadius( mLayer );
QgsRectangle searchRect( p, p, false );
searchRect.grow( threshold );

View File

@ -282,6 +282,10 @@ class CORE_EXPORT QgsVectorLayerEditUtils
*/
bool mergeFeatures( const QgsFeatureId &targetFeatureId, const QgsFeatureIds &mergeFeatureIds, const QgsAttributes &mergeAttributes, const QgsGeometry &unionGeometry, QString &errorMessage SIP_OUT );
///@cond PRIVATE
static double getTopologicalSearchRadius( const QgsVectorLayer *layer ) SIP_SKIP;
///@endcond
private:
/**