@@ -1372,6 +1372,26 @@ QList<QgsPointLocator::Match> QgsVertexTool::layerVerticesSnappedToPoint( QgsVec
1372
1372
return myfilter.matches ;
1373
1373
}
1374
1374
1375
+ QList<QgsPointLocator::Match> QgsVertexTool::layerSegmentsSnappedToSegment ( QgsVectorLayer *layer, const QgsPointXY &mapPoint1, const QgsPointXY &mapPoint2 )
1376
+ {
1377
+ QList<QgsPointLocator::Match> finalMatches;
1378
+ // we want segment matches that have exactly the same vertices as the given segment (mapPoint1, mapPoint2)
1379
+ // so rather than doing nearest edge search which could return any segment within a tolerance,
1380
+ // we first find matches for one endpoint and then see if there is a matching other endpoint.
1381
+ const QList<QgsPointLocator::Match> matches1 = layerVerticesSnappedToPoint ( layer, mapPoint1 );
1382
+ for ( const QgsPointLocator::Match &m : matches1 )
1383
+ {
1384
+ QgsGeometry g = cachedGeometry ( layer, m.featureId () );
1385
+ int v0, v1;
1386
+ g.adjacentVertices ( m.vertexIndex (), v0, v1 );
1387
+ if ( v0 != -1 && QgsPointXY ( g.vertexAt ( v0 ) ) == mapPoint2 )
1388
+ finalMatches << QgsPointLocator::Match ( QgsPointLocator::Edge, layer, m.featureId (), 0 , m.point (), v0 );
1389
+ else if ( v1 != -1 && QgsPointXY ( g.vertexAt ( v1 ) ) == mapPoint2 )
1390
+ finalMatches << QgsPointLocator::Match ( QgsPointLocator::Edge, layer, m.featureId (), 0 , m.point (), m.vertexIndex () );
1391
+ }
1392
+ return finalMatches;
1393
+ }
1394
+
1375
1395
void QgsVertexTool::startDraggingAddVertex ( const QgsPointLocator::Match &m )
1376
1396
{
1377
1397
Q_ASSERT ( m.hasEdge () );
@@ -1383,6 +1403,7 @@ void QgsVertexTool::startDraggingAddVertex( const QgsPointLocator::Match &m )
1383
1403
mDraggingVertexType = AddingVertex;
1384
1404
mDraggingExtraVertices .clear ();
1385
1405
mDraggingExtraVerticesOffset .clear ();
1406
+ mDraggingExtraSegments .clear ();
1386
1407
1387
1408
QgsGeometry geom = cachedGeometry ( m.layer (), m.featureId () );
1388
1409
@@ -1398,6 +1419,36 @@ void QgsVertexTool::startDraggingAddVertex( const QgsPointLocator::Match &m )
1398
1419
if ( v1.x () != 0 || v1.y () != 0 )
1399
1420
addDragBand ( map_v1, m.point () );
1400
1421
1422
+ if ( QgsProject::instance ()->topologicalEditing () )
1423
+ {
1424
+ // find other segments coincident with the one user just picked and store them in a list
1425
+ // so we can add a new vertex also in those to keep topology correct
1426
+ const auto layers = canvas ()->layers ();
1427
+ for ( QgsMapLayer *layer : layers )
1428
+ {
1429
+ QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
1430
+ if ( !vlayer || !vlayer->isEditable () )
1431
+ continue ;
1432
+
1433
+ if ( vlayer->geometryType () != QgsWkbTypes::LineGeometry && vlayer->geometryType () != QgsWkbTypes::PolygonGeometry )
1434
+ continue ;
1435
+
1436
+ QgsPointXY pt1, pt2;
1437
+ m.edgePoints ( pt1, pt2 );
1438
+ const auto snappedSegments = layerSegmentsSnappedToSegment ( vlayer, pt1, pt2 );
1439
+ for ( const QgsPointLocator::Match &otherMatch : snappedSegments )
1440
+ {
1441
+ if ( otherMatch.layer () == m.layer () &&
1442
+ otherMatch.featureId () == m.featureId () &&
1443
+ otherMatch.vertexIndex () == m.vertexIndex () )
1444
+ continue ;
1445
+
1446
+ // start dragging of snapped point of current layer
1447
+ mDraggingExtraSegments << Vertex ( otherMatch.layer (), otherMatch.featureId (), otherMatch.vertexIndex () );
1448
+ }
1449
+ }
1450
+ }
1451
+
1401
1452
cadDockWidget ()->setPoints ( QList<QgsPointXY>() << m.point () << m.point () );
1402
1453
}
1403
1454
@@ -1563,6 +1614,13 @@ void QgsVertexTool::moveVertex( const QgsPointXY &mapPoint, const QgsPointLocato
1563
1614
1564
1615
addExtraVerticesToEdits ( edits, mapPoint, dragLayer, layerPoint );
1565
1616
1617
+ if ( addingVertex && !addingAtEndpoint && QgsProject::instance ()->topologicalEditing () )
1618
+ {
1619
+ // topo editing: when adding a vertex to an existing segment, there may be other coincident segments
1620
+ // that also need adding the same vertex
1621
+ addExtraSegmentsToEdits ( edits, mapPoint, dragLayer, layerPoint );
1622
+ }
1623
+
1566
1624
applyEditsToLayers ( edits );
1567
1625
1568
1626
if ( QgsProject::instance ()->topologicalEditing () && mapPointMatch->hasEdge () && mapPointMatch->layer () )
@@ -1625,6 +1683,40 @@ void QgsVertexTool::addExtraVerticesToEdits( QgsVertexTool::VertexEdits &edits,
1625
1683
}
1626
1684
1627
1685
1686
+ void QgsVertexTool::addExtraSegmentsToEdits ( QgsVertexTool::VertexEdits &edits, const QgsPointXY &mapPoint, QgsVectorLayer *dragLayer, const QgsPointXY &layerPoint )
1687
+ {
1688
+ // insert new vertex also to other geometries/layers
1689
+ for ( int i = 0 ; i < mDraggingExtraSegments .count (); ++i )
1690
+ {
1691
+ const Vertex &topo = mDraggingExtraSegments [i];
1692
+
1693
+ QHash<QgsFeatureId, QgsGeometry> &layerEdits = edits[topo.layer ];
1694
+ QgsGeometry topoGeom;
1695
+ if ( layerEdits.contains ( topo.fid ) )
1696
+ topoGeom = QgsGeometry ( edits[topo.layer ][topo.fid ] );
1697
+ else
1698
+ topoGeom = QgsGeometry ( cachedGeometryForVertex ( topo ) );
1699
+
1700
+ QgsPointXY point;
1701
+ if ( dragLayer && topo.layer ->crs () == dragLayer->crs () )
1702
+ point = layerPoint; // this point may come from exact match so it may be more precise
1703
+ else
1704
+ point = toLayerCoordinates ( topo.layer , mapPoint );
1705
+
1706
+ QgsPoint pt ( point );
1707
+ if ( QgsWkbTypes::hasZ ( topo.layer ->wkbType () ) )
1708
+ pt.addZValue ( defaultZValue () );
1709
+
1710
+ if ( !topoGeom.insertVertex ( pt, topo.vertexId + 1 ) )
1711
+ {
1712
+ QgsDebugMsg ( QStringLiteral ( " [topo] segment insert vertex failed!" ) );
1713
+ continue ;
1714
+ }
1715
+ edits[topo.layer ][topo.fid ] = topoGeom;
1716
+ }
1717
+ }
1718
+
1719
+
1628
1720
void QgsVertexTool::applyEditsToLayers ( QgsVertexTool::VertexEdits &edits )
1629
1721
{
1630
1722
QHash<QgsVectorLayer *, QHash<QgsFeatureId, QgsGeometry> >::iterator it = edits.begin ();
0 commit comments