diff --git a/doc/api_break.dox b/doc/api_break.dox index 4ca7cc494a4..4b91bbc8db9 100644 --- a/doc/api_break.dox +++ b/doc/api_break.dox @@ -966,6 +966,7 @@ method to determine if a geometry is valid. - static bool compare( const QgsPolygon& p1, const QgsPolygon& p2, double epsilon ) has been renamed to comparePolygons - static bool compare( const QgsMultiPolygon& p1, const QgsMultiPolygon& p2, double epsilon ) has been renamed to compareMultiPolygons - smoothLine and smoothPolygon are no longer public API (use smooth() instead) +- avoidIntersections() got an extra argument: list of layers to include in the operation (previously read from active QgsProject) QgsGeometryAnalyzer {#qgis_api_break_3_0_QgsGeometryAnalyzer} diff --git a/python/core/geometry/qgsgeometry.sip b/python/core/geometry/qgsgeometry.sip index 3abf88a3d4a..40eb6ce543f 100644 --- a/python/core/geometry/qgsgeometry.sip +++ b/python/core/geometry/qgsgeometry.sip @@ -741,10 +741,11 @@ class QgsGeometry * 1 if geometry is not of polygon type, * 2 if avoid intersection would change the geometry type, * 3 other error during intersection removal + * @param avoidIntersectionsLayers list of layers to check for intersections * @param ignoreFeatures possibility to give a list of features where intersections should be ignored (not available in python bindings) * @note added in 1.5 */ - int avoidIntersections(); + int avoidIntersections( const QList& avoidIntersectionsLayers ); class Error { diff --git a/python/core/qgsproject.sip b/python/core/qgsproject.sip index 0c8790d3c1b..324275cd0a6 100644 --- a/python/core/qgsproject.sip +++ b/python/core/qgsproject.sip @@ -396,14 +396,14 @@ class QgsProject : QObject, QgsExpressionContextGenerator * * @note Added in QGIS 3.0 */ - QStringList avoidIntersectionsList() const; + QList avoidIntersectionsLayers() const; /** * A list of layers with which intersections should be avoided. * * @note Added in QGIS 3.0 */ - void setAvoidIntersectionsList( const QStringList& avoidIntersectionsList ); + void setAvoidIntersectionsLayers( const QList& layers ); QVariantMap customVariables() const; void setCustomVariables( const QVariantMap& customVariables ); int count() const; @@ -646,11 +646,11 @@ class QgsProject : QObject, QgsExpressionContextGenerator void topologicalEditingChanged(); /** - * Emitted whenever avoidIntersectionsList has changed. + * Emitted whenever avoidIntersectionsLayers has changed. * * @note Added in QGIS 3.0 */ - void avoidIntersectionsListChanged(); + void avoidIntersectionsLayersChanged(); /** * Emitted when the map theme collection changes. diff --git a/src/app/gps/qgsgpsinformationwidget.cpp b/src/app/gps/qgsgpsinformationwidget.cpp index 5b6a2bc3617..4525fd64bbe 100644 --- a/src/app/gps/qgsgpsinformationwidget.cpp +++ b/src/app/gps/qgsgpsinformationwidget.cpp @@ -909,7 +909,7 @@ void QgsGPSInformationWidget::on_mBtnCloseFeature_clicked() f->setGeometry( g ); QgsGeometry featGeom = f->geometry(); - int avoidIntersectionsReturn = featGeom.avoidIntersections(); + int avoidIntersectionsReturn = featGeom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() ); f->setGeometry( featGeom ); if ( avoidIntersectionsReturn == 1 ) { diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index bd3e436a326..4510f05480b 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -7656,7 +7656,7 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer ) geom = newGeometry; } // avoid intersection if enabled in digitize settings - geom.avoidIntersections(); + geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() ); } // now create new feature using pasted feature as a template. This automatically handles default diff --git a/src/app/qgsmaptooladdfeature.cpp b/src/app/qgsmaptooladdfeature.cpp index 636b0ffed14..d053fac47a4 100644 --- a/src/app/qgsmaptooladdfeature.cpp +++ b/src/app/qgsmaptooladdfeature.cpp @@ -273,7 +273,7 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e ) delete g; QgsGeometry featGeom = f->geometry(); - int avoidIntersectionsReturn = featGeom.avoidIntersections(); + int avoidIntersectionsReturn = featGeom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() ); f->setGeometry( featGeom ); if ( avoidIntersectionsReturn == 1 ) { @@ -295,17 +295,14 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e ) //use always topological editing for avoidIntersection. //Otherwise, no way to guarantee the geometries don't have a small gap in between. - QStringList intersectionLayers = QgsProject::instance()->avoidIntersectionsList(); + QList intersectionLayers = QgsProject::instance()->avoidIntersectionsLayers(); bool avoidIntersection = !intersectionLayers.isEmpty(); if ( avoidIntersection ) //try to add topological points also to background layers { - QStringList::const_iterator lIt = intersectionLayers.constBegin(); - for ( ; lIt != intersectionLayers.constEnd(); ++lIt ) + Q_FOREACH ( QgsVectorLayer* vl, intersectionLayers ) { - QgsMapLayer* ml = QgsProject::instance()->mapLayer( *lIt ); - QgsVectorLayer* vl = qobject_cast( ml ); //can only add topological points if background layer is editable... - if ( vl && vl->geometryType() == QgsWkbTypes::PolygonGeometry && vl->isEditable() ) + if ( vl->geometryType() == QgsWkbTypes::PolygonGeometry && vl->isEditable() ) { vl->addTopologicalPoints( f->geometry() ); } diff --git a/src/app/qgsmaptooladdpart.cpp b/src/app/qgsmaptooladdpart.cpp index 7b65e40bdb5..adeb79da0d8 100644 --- a/src/app/qgsmaptooladdpart.cpp +++ b/src/app/qgsmaptooladdpart.cpp @@ -149,7 +149,7 @@ void QgsMapToolAddPart::cadCanvasReleaseEvent( QgsMapMouseEvent * e ) QgsCurvePolygon* cp = new QgsCurvePolygon(); cp->setExteriorRing( curveToAdd ); QgsGeometry* geom = new QgsGeometry( cp ); - geom->avoidIntersections(); + geom->avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() ); const QgsCurvePolygon* cpGeom = dynamic_cast( geom->geometry() ); if ( !cpGeom ) diff --git a/src/app/qgsmaptoolreshape.cpp b/src/app/qgsmaptoolreshape.cpp index af02b8bce62..ca1733868d6 100644 --- a/src/app/qgsmaptoolreshape.cpp +++ b/src/app/qgsmaptoolreshape.cpp @@ -17,6 +17,7 @@ #include "qgsfeatureiterator.h" #include "qgsgeometry.h" #include "qgsmapcanvas.h" +#include "qgsproject.h" #include "qgsvectorlayer.h" #include "qgisapp.h" @@ -108,7 +109,7 @@ void QgsMapToolReshape::cadCanvasReleaseEvent( QgsMapMouseEvent * e ) QHash > ignoreFeatures; ignoreFeatures.insert( vlayer, vlayer->allFeatureIds() ); - if ( geom.avoidIntersections( ignoreFeatures ) != 0 ) + if ( geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers(), ignoreFeatures ) != 0 ) { emit messageEmitted( tr( "An error was reported during intersection removal" ), QgsMessageBar::CRITICAL ); vlayer->destroyEditCommand(); diff --git a/src/app/qgssnappinglayertreemodel.cpp b/src/app/qgssnappinglayertreemodel.cpp index 3a55cebd771..6b38d523cf5 100644 --- a/src/app/qgssnappinglayertreemodel.cpp +++ b/src/app/qgssnappinglayertreemodel.cpp @@ -144,7 +144,7 @@ QgsSnappingLayerTreeModel::QgsSnappingLayerTreeModel( QgsProject* project, QObje , mLayerTreeModel( nullptr ) { connect( project, &QgsProject::snappingConfigChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged ); - connect( project, &QgsProject::avoidIntersectionsListChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged ); + connect( project, &QgsProject::avoidIntersectionsLayersChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged ); } QgsSnappingLayerTreeModel::~QgsSnappingLayerTreeModel() @@ -494,7 +494,7 @@ QVariant QgsSnappingLayerTreeModel::data( const QModelIndex& idx, int role ) con { if ( role == Qt::CheckStateRole && vl->geometryType() == QgsWkbTypes::PolygonGeometry ) { - if ( mProject->avoidIntersectionsList().contains( vl->id() ) ) + if ( mProject->avoidIntersectionsLayers().contains( vl ) ) { return Qt::Checked; } @@ -620,14 +620,14 @@ bool QgsSnappingLayerTreeModel::setData( const QModelIndex& index, const QVarian if ( !mIndividualLayerSettings.contains( vl ) ) return false; - QStringList avoidIntersectionsList = mProject->avoidIntersectionsList(); + QList avoidIntersectionsList = mProject->avoidIntersectionsLayers(); - if ( value.toInt() == Qt::Checked && !avoidIntersectionsList.contains( vl->id() ) ) - avoidIntersectionsList.append( vl->id() ); + if ( value.toInt() == Qt::Checked && !avoidIntersectionsList.contains( vl ) ) + avoidIntersectionsList.append( vl ); else - avoidIntersectionsList.removeAll( vl->id() ); + avoidIntersectionsList.removeAll( vl ); - mProject->setAvoidIntersectionsList( avoidIntersectionsList ); + mProject->setAvoidIntersectionsLayers( avoidIntersectionsList ); return true; } } diff --git a/src/core/geometry/qgsgeometry.cpp b/src/core/geometry/qgsgeometry.cpp index c2a17053638..4312c91f567 100644 --- a/src/core/geometry/qgsgeometry.cpp +++ b/src/core/geometry/qgsgeometry.cpp @@ -1871,14 +1871,14 @@ bool QgsGeometry::deletePart( int partNum ) return ok; } -int QgsGeometry::avoidIntersections( const QHash > &ignoreFeatures ) +int QgsGeometry::avoidIntersections( const QList& avoidIntersectionsLayers, const QHash > &ignoreFeatures ) { if ( !d->geometry ) { return 1; } - QgsAbstractGeometry* diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), ignoreFeatures ); + QgsAbstractGeometry* diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, ignoreFeatures ); if ( diffGeom ) { detach( false ); diff --git a/src/core/geometry/qgsgeometry.h b/src/core/geometry/qgsgeometry.h index fbdeb6d91f5..bfac1768fb9 100644 --- a/src/core/geometry/qgsgeometry.h +++ b/src/core/geometry/qgsgeometry.h @@ -795,10 +795,12 @@ class CORE_EXPORT QgsGeometry * 1 if geometry is not of polygon type, * 2 if avoid intersection would change the geometry type, * 3 other error during intersection removal + * @param avoidIntersectionsLayers list of layers to check for intersections * @param ignoreFeatures possibility to give a list of features where intersections should be ignored (not available in python bindings) * @note added in 1.5 */ - int avoidIntersections( const QHash >& ignoreFeatures = ( QHash >() ) ); + int avoidIntersections( const QList& avoidIntersectionsLayers, + const QHash >& ignoreFeatures = ( QHash >() ) ); /** \ingroup core */ diff --git a/src/core/geometry/qgsgeometryeditutils.cpp b/src/core/geometry/qgsgeometryeditutils.cpp index a77ec629914..c2e1b376b07 100644 --- a/src/core/geometry/qgsgeometryeditutils.cpp +++ b/src/core/geometry/qgsgeometryeditutils.cpp @@ -224,7 +224,9 @@ bool QgsGeometryEditUtils::deletePart( QgsAbstractGeometry* geom, int partNum ) return c->removeGeometry( partNum ); } -QgsAbstractGeometry* QgsGeometryEditUtils::avoidIntersections( const QgsAbstractGeometry& geom, QHash > ignoreFeatures ) +QgsAbstractGeometry* QgsGeometryEditUtils::avoidIntersections( const QgsAbstractGeometry& geom, + const QList& avoidIntersectionsLayers, + QHash > ignoreFeatures ) { QScopedPointer geomEngine( QgsGeometry::createGeometryEngine( &geom ) ); if ( geomEngine.isNull() ) @@ -240,39 +242,32 @@ QgsAbstractGeometry* QgsGeometryEditUtils::avoidIntersections( const QgsAbstract return nullptr; } - QStringList avoidIntersectionsList = QgsProject::instance()->avoidIntersectionsList(); - if ( avoidIntersectionsList.isEmpty() ) + if ( avoidIntersectionsLayers.isEmpty() ) return nullptr; //no intersections stored in project does not mean error QList< QgsAbstractGeometry* > nearGeometries; //go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each - QgsVectorLayer* currentLayer = nullptr; - QStringList::const_iterator aIt = avoidIntersectionsList.constBegin(); - for ( ; aIt != avoidIntersectionsList.constEnd(); ++aIt ) + Q_FOREACH ( QgsVectorLayer* currentLayer, avoidIntersectionsLayers ) { - currentLayer = dynamic_cast( QgsProject::instance()->mapLayer( *aIt ) ); - if ( currentLayer ) + QgsFeatureIds ignoreIds; + QHash >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer ); + if ( ignoreIt != ignoreFeatures.constEnd() ) + ignoreIds = ignoreIt.value(); + + QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() ) + .setFlags( QgsFeatureRequest::ExactIntersect ) + .setSubsetOfAttributes( QgsAttributeList() ) ); + QgsFeature f; + while ( fi.nextFeature( f ) ) { - QgsFeatureIds ignoreIds; - QHash >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer ); - if ( ignoreIt != ignoreFeatures.constEnd() ) - ignoreIds = ignoreIt.value(); + if ( ignoreIds.contains( f.id() ) ) + continue; - QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() ) - .setFlags( QgsFeatureRequest::ExactIntersect ) - .setSubsetOfAttributes( QgsAttributeList() ) ); - QgsFeature f; - while ( fi.nextFeature( f ) ) - { - if ( ignoreIds.contains( f.id() ) ) - continue; + if ( !f.hasGeometry() ) + continue; - if ( !f.hasGeometry() ) - continue; - - nearGeometries << f.geometry().geometry()->clone(); - } + nearGeometries << f.geometry().geometry()->clone(); } } diff --git a/src/core/geometry/qgsgeometryeditutils.h b/src/core/geometry/qgsgeometryeditutils.h index 36f3b9b0001..42084b72d90 100644 --- a/src/core/geometry/qgsgeometryeditutils.h +++ b/src/core/geometry/qgsgeometryeditutils.h @@ -59,9 +59,12 @@ class QgsGeometryEditUtils /** Alters a geometry so that it avoids intersections with features from all open vector layers. * @param geom geometry to alter + * @param avoidIntersectionsLayers list of layers to check for intersections * @param ignoreFeatures map of layer to feature id of features to ignore */ - static QgsAbstractGeometry* avoidIntersections( const QgsAbstractGeometry& geom, QHash > ignoreFeatures = ( QHash >() ) ); + static QgsAbstractGeometry* avoidIntersections( const QgsAbstractGeometry& geom, + const QList& avoidIntersectionsLayers, + QHash > ignoreFeatures = ( QHash >() ) ); }; #endif // QGSGEOMETRYEDITUTILS_H diff --git a/src/core/qgsproject.cpp b/src/core/qgsproject.cpp index 3eddcbca812..620bb4c3000 100644 --- a/src/core/qgsproject.cpp +++ b/src/core/qgsproject.cpp @@ -1023,15 +1023,25 @@ void QgsProject::setCustomVariables( const QVariantMap& variables ) emit customVariablesChanged(); } -QStringList QgsProject::avoidIntersectionsList() const +QList QgsProject::avoidIntersectionsLayers() const { - return readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), QStringList() ); + QList layers; + QStringList layerIds = readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), QStringList() ); + Q_FOREACH ( const QString& layerId, layerIds ) + { + if ( QgsVectorLayer* vlayer = qobject_cast( mapLayer( layerId ) ) ) + layers << vlayer; + } + return layers; } -void QgsProject::setAvoidIntersectionsList( const QStringList& avoidIntersectionsList ) +void QgsProject::setAvoidIntersectionsLayers( const QList& layers ) { - writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), avoidIntersectionsList ); - emit avoidIntersectionsListChanged(); + QStringList list; + Q_FOREACH ( QgsVectorLayer* layer, layers ) + list << layer->id(); + writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), list ); + emit avoidIntersectionsLayersChanged(); } QgsExpressionContext QgsProject::createExpressionContext() const diff --git a/src/core/qgsproject.h b/src/core/qgsproject.h index 2fb0b500cc1..3017e572d65 100644 --- a/src/core/qgsproject.h +++ b/src/core/qgsproject.h @@ -78,7 +78,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera Q_PROPERTY( QgsCoordinateReferenceSystem crs READ crs WRITE setCrs ) Q_PROPERTY( QgsMapThemeCollection* mapThemeCollection READ mapThemeCollection NOTIFY mapThemeCollectionChanged ) Q_PROPERTY( QgsSnappingConfig snappingConfig READ snappingConfig WRITE setSnappingConfig NOTIFY snappingConfigChanged ) - Q_PROPERTY( QStringList avoidIntersectionsList READ avoidIntersectionsList WRITE setAvoidIntersectionsList NOTIFY avoidIntersectionsListChanged ) + Q_PROPERTY( QList avoidIntersectionsLayers READ avoidIntersectionsLayers WRITE setAvoidIntersectionsLayers NOTIFY avoidIntersectionsLayersChanged ) public: //! Returns the QgsProject singleton instance @@ -465,14 +465,14 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera * * @note Added in QGIS 3.0 */ - QStringList avoidIntersectionsList() const; + QList avoidIntersectionsLayers() const; /** * A list of layers with which intersections should be avoided. * * @note Added in QGIS 3.0 */ - void setAvoidIntersectionsList( const QStringList& avoidIntersectionsList ); + void setAvoidIntersectionsLayers( const QList& layers ); /** * A map of custom project variables. @@ -760,11 +760,11 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera void topologicalEditingChanged(); /** - * Emitted whenever avoidIntersectionsList has changed. + * Emitted whenever avoidIntersectionsLayers has changed. * * @note Added in QGIS 3.0 */ - void avoidIntersectionsListChanged(); + void avoidIntersectionsLayersChanged(); /** * Emitted when the map theme collection changes.