Skip to content

Commit 0513bb3

Browse files
committed
Make QgsGeometry independent from QgsProject + better avoid intersections API
1 parent 8c340f7 commit 0513bb3

15 files changed

+72
-62
lines changed

doc/api_break.dox

+1
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,7 @@ method to determine if a geometry is valid.
966966
- static bool compare( const QgsPolygon& p1, const QgsPolygon& p2, double epsilon ) has been renamed to comparePolygons
967967
- static bool compare( const QgsMultiPolygon& p1, const QgsMultiPolygon& p2, double epsilon ) has been renamed to compareMultiPolygons
968968
- smoothLine and smoothPolygon are no longer public API (use smooth() instead)
969+
- avoidIntersections() got an extra argument: list of layers to include in the operation (previously read from active QgsProject)
969970

970971

971972
QgsGeometryAnalyzer {#qgis_api_break_3_0_QgsGeometryAnalyzer}

python/core/geometry/qgsgeometry.sip

+2-1
Original file line numberDiff line numberDiff line change
@@ -741,10 +741,11 @@ class QgsGeometry
741741
* 1 if geometry is not of polygon type,
742742
* 2 if avoid intersection would change the geometry type,
743743
* 3 other error during intersection removal
744+
* @param avoidIntersectionsLayers list of layers to check for intersections
744745
* @param ignoreFeatures possibility to give a list of features where intersections should be ignored (not available in python bindings)
745746
* @note added in 1.5
746747
*/
747-
int avoidIntersections();
748+
int avoidIntersections( const QList<QgsVectorLayer*>& avoidIntersectionsLayers );
748749

749750
class Error
750751
{

python/core/qgsproject.sip

+4-4
Original file line numberDiff line numberDiff line change
@@ -396,14 +396,14 @@ class QgsProject : QObject, QgsExpressionContextGenerator
396396
*
397397
* @note Added in QGIS 3.0
398398
*/
399-
QStringList avoidIntersectionsList() const;
399+
QList<QgsVectorLayer*> avoidIntersectionsLayers() const;
400400

401401
/**
402402
* A list of layers with which intersections should be avoided.
403403
*
404404
* @note Added in QGIS 3.0
405405
*/
406-
void setAvoidIntersectionsList( const QStringList& avoidIntersectionsList );
406+
void setAvoidIntersectionsLayers( const QList<QgsVectorLayer*>& layers );
407407
QVariantMap customVariables() const;
408408
void setCustomVariables( const QVariantMap& customVariables );
409409
int count() const;
@@ -646,11 +646,11 @@ class QgsProject : QObject, QgsExpressionContextGenerator
646646
void topologicalEditingChanged();
647647

648648
/**
649-
* Emitted whenever avoidIntersectionsList has changed.
649+
* Emitted whenever avoidIntersectionsLayers has changed.
650650
*
651651
* @note Added in QGIS 3.0
652652
*/
653-
void avoidIntersectionsListChanged();
653+
void avoidIntersectionsLayersChanged();
654654

655655
/**
656656
* Emitted when the map theme collection changes.

src/app/gps/qgsgpsinformationwidget.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -909,7 +909,7 @@ void QgsGPSInformationWidget::on_mBtnCloseFeature_clicked()
909909
f->setGeometry( g );
910910

911911
QgsGeometry featGeom = f->geometry();
912-
int avoidIntersectionsReturn = featGeom.avoidIntersections();
912+
int avoidIntersectionsReturn = featGeom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
913913
f->setGeometry( featGeom );
914914
if ( avoidIntersectionsReturn == 1 )
915915
{

src/app/qgisapp.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -7656,7 +7656,7 @@ void QgisApp::editPaste( QgsMapLayer *destinationLayer )
76567656
geom = newGeometry;
76577657
}
76587658
// avoid intersection if enabled in digitize settings
7659-
geom.avoidIntersections();
7659+
geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
76607660
}
76617661

76627662
// now create new feature using pasted feature as a template. This automatically handles default

src/app/qgsmaptooladdfeature.cpp

+4-7
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e )
273273
delete g;
274274

275275
QgsGeometry featGeom = f->geometry();
276-
int avoidIntersectionsReturn = featGeom.avoidIntersections();
276+
int avoidIntersectionsReturn = featGeom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
277277
f->setGeometry( featGeom );
278278
if ( avoidIntersectionsReturn == 1 )
279279
{
@@ -295,17 +295,14 @@ void QgsMapToolAddFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e )
295295

296296
//use always topological editing for avoidIntersection.
297297
//Otherwise, no way to guarantee the geometries don't have a small gap in between.
298-
QStringList intersectionLayers = QgsProject::instance()->avoidIntersectionsList();
298+
QList<QgsVectorLayer*> intersectionLayers = QgsProject::instance()->avoidIntersectionsLayers();
299299
bool avoidIntersection = !intersectionLayers.isEmpty();
300300
if ( avoidIntersection ) //try to add topological points also to background layers
301301
{
302-
QStringList::const_iterator lIt = intersectionLayers.constBegin();
303-
for ( ; lIt != intersectionLayers.constEnd(); ++lIt )
302+
Q_FOREACH ( QgsVectorLayer* vl, intersectionLayers )
304303
{
305-
QgsMapLayer* ml = QgsProject::instance()->mapLayer( *lIt );
306-
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( ml );
307304
//can only add topological points if background layer is editable...
308-
if ( vl && vl->geometryType() == QgsWkbTypes::PolygonGeometry && vl->isEditable() )
305+
if ( vl->geometryType() == QgsWkbTypes::PolygonGeometry && vl->isEditable() )
309306
{
310307
vl->addTopologicalPoints( f->geometry() );
311308
}

src/app/qgsmaptooladdpart.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ void QgsMapToolAddPart::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
149149
QgsCurvePolygon* cp = new QgsCurvePolygon();
150150
cp->setExteriorRing( curveToAdd );
151151
QgsGeometry* geom = new QgsGeometry( cp );
152-
geom->avoidIntersections();
152+
geom->avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
153153

154154
const QgsCurvePolygon* cpGeom = dynamic_cast<const QgsCurvePolygon*>( geom->geometry() );
155155
if ( !cpGeom )

src/app/qgsmaptoolreshape.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "qgsfeatureiterator.h"
1818
#include "qgsgeometry.h"
1919
#include "qgsmapcanvas.h"
20+
#include "qgsproject.h"
2021
#include "qgsvectorlayer.h"
2122
#include "qgisapp.h"
2223

@@ -108,7 +109,7 @@ void QgsMapToolReshape::cadCanvasReleaseEvent( QgsMapMouseEvent * e )
108109
QHash<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures;
109110
ignoreFeatures.insert( vlayer, vlayer->allFeatureIds() );
110111

111-
if ( geom.avoidIntersections( ignoreFeatures ) != 0 )
112+
if ( geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers(), ignoreFeatures ) != 0 )
112113
{
113114
emit messageEmitted( tr( "An error was reported during intersection removal" ), QgsMessageBar::CRITICAL );
114115
vlayer->destroyEditCommand();

src/app/qgssnappinglayertreemodel.cpp

+7-7
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ QgsSnappingLayerTreeModel::QgsSnappingLayerTreeModel( QgsProject* project, QObje
144144
, mLayerTreeModel( nullptr )
145145
{
146146
connect( project, &QgsProject::snappingConfigChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged );
147-
connect( project, &QgsProject::avoidIntersectionsListChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged );
147+
connect( project, &QgsProject::avoidIntersectionsLayersChanged, this, &QgsSnappingLayerTreeModel::onSnappingSettingsChanged );
148148
}
149149

150150
QgsSnappingLayerTreeModel::~QgsSnappingLayerTreeModel()
@@ -494,7 +494,7 @@ QVariant QgsSnappingLayerTreeModel::data( const QModelIndex& idx, int role ) con
494494
{
495495
if ( role == Qt::CheckStateRole && vl->geometryType() == QgsWkbTypes::PolygonGeometry )
496496
{
497-
if ( mProject->avoidIntersectionsList().contains( vl->id() ) )
497+
if ( mProject->avoidIntersectionsLayers().contains( vl ) )
498498
{
499499
return Qt::Checked;
500500
}
@@ -620,14 +620,14 @@ bool QgsSnappingLayerTreeModel::setData( const QModelIndex& index, const QVarian
620620
if ( !mIndividualLayerSettings.contains( vl ) )
621621
return false;
622622

623-
QStringList avoidIntersectionsList = mProject->avoidIntersectionsList();
623+
QList<QgsVectorLayer*> avoidIntersectionsList = mProject->avoidIntersectionsLayers();
624624

625-
if ( value.toInt() == Qt::Checked && !avoidIntersectionsList.contains( vl->id() ) )
626-
avoidIntersectionsList.append( vl->id() );
625+
if ( value.toInt() == Qt::Checked && !avoidIntersectionsList.contains( vl ) )
626+
avoidIntersectionsList.append( vl );
627627
else
628-
avoidIntersectionsList.removeAll( vl->id() );
628+
avoidIntersectionsList.removeAll( vl );
629629

630-
mProject->setAvoidIntersectionsList( avoidIntersectionsList );
630+
mProject->setAvoidIntersectionsLayers( avoidIntersectionsList );
631631
return true;
632632
}
633633
}

src/core/geometry/qgsgeometry.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1871,14 +1871,14 @@ bool QgsGeometry::deletePart( int partNum )
18711871
return ok;
18721872
}
18731873

1874-
int QgsGeometry::avoidIntersections( const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
1874+
int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer*>& avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
18751875
{
18761876
if ( !d->geometry )
18771877
{
18781878
return 1;
18791879
}
18801880

1881-
QgsAbstractGeometry* diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), ignoreFeatures );
1881+
QgsAbstractGeometry* diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, ignoreFeatures );
18821882
if ( diffGeom )
18831883
{
18841884
detach( false );

src/core/geometry/qgsgeometry.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -795,10 +795,12 @@ class CORE_EXPORT QgsGeometry
795795
* 1 if geometry is not of polygon type,
796796
* 2 if avoid intersection would change the geometry type,
797797
* 3 other error during intersection removal
798+
* @param avoidIntersectionsLayers list of layers to check for intersections
798799
* @param ignoreFeatures possibility to give a list of features where intersections should be ignored (not available in python bindings)
799800
* @note added in 1.5
800801
*/
801-
int avoidIntersections( const QHash<QgsVectorLayer*, QSet<QgsFeatureId> >& ignoreFeatures = ( QHash<QgsVectorLayer*, QSet<QgsFeatureId> >() ) );
802+
int avoidIntersections( const QList<QgsVectorLayer*>& avoidIntersectionsLayers,
803+
const QHash<QgsVectorLayer*, QSet<QgsFeatureId> >& ignoreFeatures = ( QHash<QgsVectorLayer*, QSet<QgsFeatureId> >() ) );
802804

803805
/** \ingroup core
804806
*/

src/core/geometry/qgsgeometryeditutils.cpp

+20-25
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,9 @@ bool QgsGeometryEditUtils::deletePart( QgsAbstractGeometry* geom, int partNum )
224224
return c->removeGeometry( partNum );
225225
}
226226

227-
QgsAbstractGeometry* QgsGeometryEditUtils::avoidIntersections( const QgsAbstractGeometry& geom, QHash<QgsVectorLayer *, QSet<QgsFeatureId> > ignoreFeatures )
227+
QgsAbstractGeometry* QgsGeometryEditUtils::avoidIntersections( const QgsAbstractGeometry& geom,
228+
const QList<QgsVectorLayer*>& avoidIntersectionsLayers,
229+
QHash<QgsVectorLayer *, QSet<QgsFeatureId> > ignoreFeatures )
228230
{
229231
QScopedPointer<QgsGeometryEngine> geomEngine( QgsGeometry::createGeometryEngine( &geom ) );
230232
if ( geomEngine.isNull() )
@@ -240,39 +242,32 @@ QgsAbstractGeometry* QgsGeometryEditUtils::avoidIntersections( const QgsAbstract
240242
return nullptr;
241243
}
242244

243-
QStringList avoidIntersectionsList = QgsProject::instance()->avoidIntersectionsList();
244-
if ( avoidIntersectionsList.isEmpty() )
245+
if ( avoidIntersectionsLayers.isEmpty() )
245246
return nullptr; //no intersections stored in project does not mean error
246247

247248
QList< QgsAbstractGeometry* > nearGeometries;
248249

249250
//go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each
250-
QgsVectorLayer* currentLayer = nullptr;
251-
QStringList::const_iterator aIt = avoidIntersectionsList.constBegin();
252-
for ( ; aIt != avoidIntersectionsList.constEnd(); ++aIt )
251+
Q_FOREACH ( QgsVectorLayer* currentLayer, avoidIntersectionsLayers )
253252
{
254-
currentLayer = dynamic_cast<QgsVectorLayer*>( QgsProject::instance()->mapLayer( *aIt ) );
255-
if ( currentLayer )
253+
QgsFeatureIds ignoreIds;
254+
QHash<QgsVectorLayer*, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer );
255+
if ( ignoreIt != ignoreFeatures.constEnd() )
256+
ignoreIds = ignoreIt.value();
257+
258+
QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() )
259+
.setFlags( QgsFeatureRequest::ExactIntersect )
260+
.setSubsetOfAttributes( QgsAttributeList() ) );
261+
QgsFeature f;
262+
while ( fi.nextFeature( f ) )
256263
{
257-
QgsFeatureIds ignoreIds;
258-
QHash<QgsVectorLayer*, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer );
259-
if ( ignoreIt != ignoreFeatures.constEnd() )
260-
ignoreIds = ignoreIt.value();
261-
262-
QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() )
263-
.setFlags( QgsFeatureRequest::ExactIntersect )
264-
.setSubsetOfAttributes( QgsAttributeList() ) );
265-
QgsFeature f;
266-
while ( fi.nextFeature( f ) )
267-
{
268-
if ( ignoreIds.contains( f.id() ) )
269-
continue;
264+
if ( ignoreIds.contains( f.id() ) )
265+
continue;
270266

271-
if ( !f.hasGeometry() )
272-
continue;
267+
if ( !f.hasGeometry() )
268+
continue;
273269

274-
nearGeometries << f.geometry().geometry()->clone();
275-
}
270+
nearGeometries << f.geometry().geometry()->clone();
276271
}
277272
}
278273

src/core/geometry/qgsgeometryeditutils.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,12 @@ class QgsGeometryEditUtils
5959

6060
/** Alters a geometry so that it avoids intersections with features from all open vector layers.
6161
* @param geom geometry to alter
62+
* @param avoidIntersectionsLayers list of layers to check for intersections
6263
* @param ignoreFeatures map of layer to feature id of features to ignore
6364
*/
64-
static QgsAbstractGeometry* avoidIntersections( const QgsAbstractGeometry& geom, QHash<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures = ( QHash<QgsVectorLayer*, QSet<QgsFeatureId> >() ) );
65+
static QgsAbstractGeometry* avoidIntersections( const QgsAbstractGeometry& geom,
66+
const QList<QgsVectorLayer*>& avoidIntersectionsLayers,
67+
QHash<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures = ( QHash<QgsVectorLayer*, QSet<QgsFeatureId> >() ) );
6568
};
6669

6770
#endif // QGSGEOMETRYEDITUTILS_H

src/core/qgsproject.cpp

+15-5
Original file line numberDiff line numberDiff line change
@@ -1023,15 +1023,25 @@ void QgsProject::setCustomVariables( const QVariantMap& variables )
10231023
emit customVariablesChanged();
10241024
}
10251025

1026-
QStringList QgsProject::avoidIntersectionsList() const
1026+
QList<QgsVectorLayer*> QgsProject::avoidIntersectionsLayers() const
10271027
{
1028-
return readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), QStringList() );
1028+
QList<QgsVectorLayer*> layers;
1029+
QStringList layerIds = readListEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), QStringList() );
1030+
Q_FOREACH ( const QString& layerId, layerIds )
1031+
{
1032+
if ( QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( mapLayer( layerId ) ) )
1033+
layers << vlayer;
1034+
}
1035+
return layers;
10291036
}
10301037

1031-
void QgsProject::setAvoidIntersectionsList( const QStringList& avoidIntersectionsList )
1038+
void QgsProject::setAvoidIntersectionsLayers( const QList<QgsVectorLayer*>& layers )
10321039
{
1033-
writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), avoidIntersectionsList );
1034-
emit avoidIntersectionsListChanged();
1040+
QStringList list;
1041+
Q_FOREACH ( QgsVectorLayer* layer, layers )
1042+
list << layer->id();
1043+
writeEntry( QStringLiteral( "Digitizing" ), QStringLiteral( "/AvoidIntersectionsList" ), list );
1044+
emit avoidIntersectionsLayersChanged();
10351045
}
10361046

10371047
QgsExpressionContext QgsProject::createExpressionContext() const

src/core/qgsproject.h

+5-5
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
7878
Q_PROPERTY( QgsCoordinateReferenceSystem crs READ crs WRITE setCrs )
7979
Q_PROPERTY( QgsMapThemeCollection* mapThemeCollection READ mapThemeCollection NOTIFY mapThemeCollectionChanged )
8080
Q_PROPERTY( QgsSnappingConfig snappingConfig READ snappingConfig WRITE setSnappingConfig NOTIFY snappingConfigChanged )
81-
Q_PROPERTY( QStringList avoidIntersectionsList READ avoidIntersectionsList WRITE setAvoidIntersectionsList NOTIFY avoidIntersectionsListChanged )
81+
Q_PROPERTY( QList<QgsVectorLayer*> avoidIntersectionsLayers READ avoidIntersectionsLayers WRITE setAvoidIntersectionsLayers NOTIFY avoidIntersectionsLayersChanged )
8282

8383
public:
8484
//! Returns the QgsProject singleton instance
@@ -465,14 +465,14 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
465465
*
466466
* @note Added in QGIS 3.0
467467
*/
468-
QStringList avoidIntersectionsList() const;
468+
QList<QgsVectorLayer*> avoidIntersectionsLayers() const;
469469

470470
/**
471471
* A list of layers with which intersections should be avoided.
472472
*
473473
* @note Added in QGIS 3.0
474474
*/
475-
void setAvoidIntersectionsList( const QStringList& avoidIntersectionsList );
475+
void setAvoidIntersectionsLayers( const QList<QgsVectorLayer*>& layers );
476476

477477
/**
478478
* A map of custom project variables.
@@ -760,11 +760,11 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera
760760
void topologicalEditingChanged();
761761

762762
/**
763-
* Emitted whenever avoidIntersectionsList has changed.
763+
* Emitted whenever avoidIntersectionsLayers has changed.
764764
*
765765
* @note Added in QGIS 3.0
766766
*/
767-
void avoidIntersectionsListChanged();
767+
void avoidIntersectionsLayersChanged();
768768

769769
/**
770770
* Emitted when the map theme collection changes.

0 commit comments

Comments
 (0)