Skip to content

Commit

Permalink
Merge pull request #51067 from qgis/backport-50109-to-release-3_28
Browse files Browse the repository at this point in the history
[Backport release-3_28] [Fix] Remove unnecessary geometryChanged calls
  • Loading branch information
troopa81 committed Dec 5, 2022
2 parents 69a843f + f75030d commit 6a07f3c
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 17 deletions.
1 change: 1 addition & 0 deletions python/core/auto_generated/geometry/qgsgeometry.sip.in
Expand Up @@ -2343,6 +2343,7 @@ Modifies geometry to avoid intersections with the layers specified in project pr
1 if geometry is not of polygon type,
2 if avoid intersection would change the geometry type,
3 at least one geometry intersected is invalid. The algorithm may not work and return the same geometry as the input. You must fix your intersecting geometries.
4 if the geometry is not intersected by one of the geometries present in the provided layers.

.. versionadded:: 1.5
%End
Expand Down
14 changes: 9 additions & 5 deletions src/app/vertextool/qgsvertextool.cpp
Expand Up @@ -2377,8 +2377,6 @@ void QgsVertexTool::applyEditsToLayers( QgsVertexTool::VertexEdits &edits )
editor->updateEditor( mLockedFeature.get() );
}



for ( it = edits.begin() ; it != edits.end(); ++it )
{
QgsVectorLayer *layer = it.key();
Expand All @@ -2399,7 +2397,6 @@ void QgsVertexTool::applyEditsToLayers( QgsVertexTool::VertexEdits &edits )
break;
}
QgsGeometry featGeom = it2.value();
layer->changeGeometry( it2.key(), featGeom );
if ( avoidIntersectionsLayers.size() > 0 )
{
QHash<QgsVectorLayer *, QSet<QgsFeatureId> > ignoreFeatures;
Expand All @@ -2416,12 +2413,19 @@ void QgsVertexTool::applyEditsToLayers( QgsVertexTool::VertexEdits &edits )
case 3:
emit messageEmitted( tr( "At least one geometry intersected is invalid. These geometries must be manually repaired." ), Qgis::MessageLevel::Warning );
break;

default:
break;
}
// if the geometry has been changed
if ( avoidIntersectionsReturn != 1 && avoidIntersectionsReturn != 4 )
{
layer->changeGeometry( it2.key(), featGeom );
edits[layer][it2.key()] = featGeom;
}

}
layer->changeGeometry( it2.key(), featGeom );
edits[layer][it2.key()] = featGeom;

}
layer->endEditCommand();
layer->triggerRepaint();
Expand Down
5 changes: 5 additions & 0 deletions src/core/geometry/qgsgeometry.cpp
Expand Up @@ -2850,15 +2850,20 @@ int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidInterse
QgsWkbTypes::Type geomTypeBeforeModification = wkbType();

bool haveInvalidGeometry = false;
bool geomModified = false;

std::unique_ptr< QgsAbstractGeometry > diffGeom = QgsGeometryEditUtils::avoidIntersections( *( d->geometry ), avoidIntersectionsLayers, haveInvalidGeometry, ignoreFeatures );
if ( diffGeom )
{
reset( std::move( diffGeom ) );
geomModified = true;
}

if ( geomTypeBeforeModification != wkbType() )
return 2;
if ( haveInvalidGeometry )
return 3;
if ( !geomModified )
return 4;

return 0;
Expand Down
1 change: 1 addition & 0 deletions src/core/geometry/qgsgeometry.h
Expand Up @@ -2406,6 +2406,7 @@ class CORE_EXPORT QgsGeometry
* 1 if geometry is not of polygon type,
* 2 if avoid intersection would change the geometry type,
* 3 at least one geometry intersected is invalid. The algorithm may not work and return the same geometry as the input. You must fix your intersecting geometries.
* 4 if the geometry is not intersected by one of the geometries present in the provided layers.
* \since QGIS 1.5
*/
int avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers,
Expand Down
4 changes: 4 additions & 0 deletions src/core/geometry/qgsgeometryeditutils.cpp
Expand Up @@ -343,6 +343,10 @@ std::unique_ptr<QgsAbstractGeometry> QgsGeometryEditUtils::avoidIntersections( c
}

std::unique_ptr< QgsAbstractGeometry > diffGeom( geomEngine->difference( combinedGeometries.get() ) );
if ( geomEngine->isEqual( diffGeom.get() ) )
{
return nullptr;
}

return diffGeom;
}
1 change: 1 addition & 0 deletions src/core/geometry/qgsgeometryeditutils.h
Expand Up @@ -73,6 +73,7 @@ class QgsGeometryEditUtils
* \param avoidIntersectionsLayers list of layers to check for intersections
* \param haveInvalidGeometry returns true if at least one geometry intersected is invalid. In this case, the algorithm may not work and return the same geometry as the input. You must fix your intersecting geometries.
* \param ignoreFeatures map of layer to feature id of features to ignore
* \return the modified geometry or a null unique_ptr if the \a geom polygon doesn't intersect any geometry in \a avoidIntersectionsLayers
*/
static std::unique_ptr< QgsAbstractGeometry > avoidIntersections( const QgsAbstractGeometry &geom,
const QList<QgsVectorLayer *> &avoidIntersectionsLayers,
Expand Down
73 changes: 61 additions & 12 deletions tests/src/app/testqgsvertextool.cpp
Expand Up @@ -30,6 +30,8 @@
#include "qgssettingsregistrycore.h"
#include "testqgsmaptoolutils.h"

#include <QSignalSpy>

bool operator==( const QgsGeometry &g1, const QgsGeometry &g2 )
{
if ( g1.isNull() && g2.isNull() )
Expand Down Expand Up @@ -1061,13 +1063,19 @@ void TestQgsVertexTool::testAddVertexTopoFirstSegment()

void TestQgsVertexTool::testAvoidIntersections()
{
// check that when adding a vertex to the first segment of a polygon's ring with topo editing
// enabled, the geometry does not get corrupted (#20774)
// There is one feature in the layer
QCOMPARE( mLayerPolygon->featureCount(), ( long )1 );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "Polygon ((4 1, 7 1, 7 4, 4 4, 4 1))" ) ); // avoid rounding errors

QgsProject::instance()->setTopologicalEditing( true );
const Qgis::AvoidIntersectionsMode mode( QgsProject::instance()->avoidIntersectionsMode() );
QgsProject::instance()->setAvoidIntersectionsMode( Qgis::AvoidIntersectionsMode::AvoidIntersectionsCurrentLayer );

QSignalSpy spy( mLayerPolygon, &QgsVectorLayer::geometryChanged );

// Adds another polygon with topo editing
// to check that when adding a vertex to the first segment of a polygon's ring with topo editing
// enabled, the geometry does not get corrupted (#20774)
QgsPolygonXY polygon2;
QgsPolylineXY polygon2exterior;
polygon2exterior << QgsPointXY( 8, 2 ) << QgsPointXY( 9, 2 ) << QgsPointXY( 9, 3 ) << QgsPointXY( 8, 3 ) << QgsPointXY( 8, 2 );
Expand All @@ -1077,40 +1085,77 @@ void TestQgsVertexTool::testAvoidIntersections()

mLayerPolygon->addFeature( polygonF2 );
const QgsFeatureId mFidPolygonF2 = polygonF2.id();

// Starting point
QCOMPARE( mLayerPolygon->featureCount(), ( long )2 );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "Polygon ((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF2 ).geometry(), QgsGeometry::fromWkt( "Polygon ((8 2, 9 2, 9 3, 8 3, 8 2))" ) );

QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );

// Moves one vertex but without intersection
spy.clear();
QCOMPARE( spy.count(), 0 );

mouseClick( 4, 4, Qt::LeftButton );
mouseClick( 5, 5, Qt::LeftButton );

QCOMPARE( spy.count(), 1 ); // 1 for the moved vertex

QCOMPARE( mLayerPolygon->featureCount(), ( long )2 );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "Polygon ((4 1, 7 1, 7 4, 5 5, 4 1))" ) );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF2 ).geometry(), QgsGeometry::fromWkt( "Polygon ((8 2, 9 2, 9 3, 8 3, 8 2))" ) );

mLayerPolygon->undoStack()->undo();
QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );

// Moves one vertex
spy.clear();
QCOMPARE( spy.count(), 0 );

mouseClick( 7, 1, Qt::LeftButton );
mouseClick( 9, 2, Qt::LeftButton );

QCOMPARE( mLayerPolygon->undoStack()->index(), 3 );
QCOMPARE( spy.count(), 2 ); // 1 for the moved vertex and 1 for the updated geometry

QCOMPARE( QgsGeometry::fromWkt( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry().asWkt( 1 ) ), QgsGeometry::fromWkt( "Polygon ((4 4, 7 4, 8 3, 8 2, 9 2, 4 1, 4 4))" ) ); // avoid rounding errors
QCOMPARE( QgsGeometry::fromWkt( mLayerPolygon->getFeature( mFidPolygonF2 ).geometry().asWkt( 1 ) ), QgsGeometry::fromWkt( "Polygon ((8 2, 9 2, 9 3, 8 3, 8 2))" ) );
QCOMPARE( mLayerPolygon->featureCount(), ( long )2 );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "Polygon ((4 4, 7 4, 8 3, 8 2, 9 2, 4 1, 4 4))" ) );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF2 ).geometry(), QgsGeometry::fromWkt( "Polygon ((8 2, 9 2, 9 3, 8 3, 8 2))" ) );

mLayerPolygon->undoStack()->undo();
QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );

QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
// Moves polygons and check that geometry are not avoided
// the new position of the first polygon is the old posiiton of the second polygon
spy.clear();
QCOMPARE( spy.count(), 0 );

// Move polygons and check that geometry are not avoided
// select polygons
// select the 2 polygons
mousePress( 3, 5, Qt::LeftButton );
mouseMove( 9.5, 0.5 );
mouseRelease( 9.5, 0.5, Qt::LeftButton );

QCOMPARE( spy.count(), 0 );

// move polygons
mouseClick( 8, 2, Qt::LeftButton );
mouseClick( 5, 2, Qt::LeftButton );

QCOMPARE( QgsGeometry::fromWkt( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry().asWkt( 1 ) ), QgsGeometry::fromWkt( "Polygon ((1 1, 4 1, 4 4, 1 4, 1 1))" ) );
QCOMPARE( QgsGeometry::fromWkt( mLayerPolygon->getFeature( mFidPolygonF2 ).geometry().asWkt( 1 ) ), QgsGeometry::fromWkt( "Polygon ((5 2, 6 2, 6 3, 5 3, 5 2))" ) );
QCOMPARE( spy.count(), 2 ); // 2 for the moved geometries

QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "Polygon ((1 1, 4 1, 4 4, 1 4, 1 1))" ) );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF2 ).geometry(), QgsGeometry::fromWkt( "Polygon ((5 2, 6 2, 6 3, 5 3, 5 2))" ) );

mLayerPolygon->undoStack()->undo();
mLayerPolygon->undoStack()->undo(); // delete feature

QCOMPARE( mLayerPolygon->featureCount(), ( long )1 );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );

// If topologicalEditing and avoidIntersections are activated we must take care that the topological points are well added.
QCOMPARE( mLayerPolygon->undoStack()->index(), 1 );

// If topologicalEditing and avoidIntersections are activated, we must take care that the topological points are well added.
// Adds 2 new polygons
QgsPolygonXY polygon_topo1;
QgsPolylineXY polygon_topo1exterior;
polygon_topo1exterior << QgsPointXY( 0, 10 ) << QgsPointXY( 0, 20 ) << QgsPointXY( 5, 15 ) << QgsPointXY( 0, 10 );
Expand All @@ -1132,7 +1177,11 @@ void TestQgsVertexTool::testAvoidIntersections()
const QgsFeatureId mFidPolygonF_topo2 = polygonF_topo2.id();

QCOMPARE( mLayerPolygon->featureCount(), ( long )3 );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "Polygon ((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF_topo1 ).geometry(), QgsGeometry::fromWkt( "Polygon ((0 10, 0 20, 5 15, 0 10))" ) );
QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF_topo2 ).geometry(), QgsGeometry::fromWkt( "Polygon ((10 15, 15 10, 15 20, 10 15))" ) );

// Moves one vertex over the other polygon
mouseClick( 5, 15, Qt::LeftButton );
mouseClick( 12.5, 15, Qt::LeftButton );

Expand All @@ -1145,10 +1194,10 @@ void TestQgsVertexTool::testAvoidIntersections()
mLayerPolygon->undoStack()->undo(); // delete feature polygonF_topo1
QCOMPARE( mLayerPolygon->featureCount(), ( long )1 );


QgsProject::instance()->setTopologicalEditing( false );
QgsProject::instance()->setAvoidIntersectionsMode( mode );
}

void TestQgsVertexTool::testActiveLayerPriority()
{
// check that features from current layer get priority when picking points
Expand Down

0 comments on commit 6a07f3c

Please sign in to comment.