30
30
31
31
#include < QRubberBand>
32
32
33
+ uint qHash ( const Vertex &v )
34
+ {
35
+ return qHash ( v.layer ) ^ qHash ( v.fid ) ^ qHash ( v.vertexId );
36
+ }
33
37
34
38
//
35
39
// geomutils - may get moved elsewhere
@@ -173,12 +177,6 @@ QgsNodeTool2::QgsNodeTool2( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidge
173
177
mEdgeCenterMarker ->setPenWidth ( 3 );
174
178
mEdgeCenterMarker ->setVisible ( false );
175
179
176
- mDragPointMarker = new QgsVertexMarker ( canvas );
177
- mDragPointMarker ->setIconType ( QgsVertexMarker::ICON_X );
178
- mDragPointMarker ->setColor ( Qt::red );
179
- mDragPointMarker ->setPenWidth ( 3 );
180
- mDragPointMarker ->setVisible ( false );
181
-
182
180
mFeatureBand = createRubberBand ( QgsWkbTypes::LineGeometry );
183
181
mFeatureBand ->setVisible ( false );
184
182
@@ -207,7 +205,6 @@ QgsNodeTool2::~QgsNodeTool2()
207
205
{
208
206
delete mSnapMarker ;
209
207
delete mEdgeCenterMarker ;
210
- delete mDragPointMarker ;
211
208
delete mFeatureBand ;
212
209
delete mVertexBand ;
213
210
delete mEdgeBand ;
@@ -221,26 +218,61 @@ void QgsNodeTool2::deactivate()
221
218
QgsMapToolAdvancedDigitizing::deactivate ();
222
219
}
223
220
224
- void QgsNodeTool2::addDragBand ( const QgsPoint &v1, const QgsPoint &v2 )
221
+ void QgsNodeTool2::addDragBand ( const QgsPoint &v1, const QgsPoint &v2, const QgsVector &offset )
225
222
{
226
223
QgsRubberBand *dragBand = createRubberBand ( QgsWkbTypes::LineGeometry, true );
227
224
dragBand->addPoint ( v1 );
228
225
dragBand->addPoint ( v2 );
229
226
mDragBands << dragBand;
227
+ mDragBandsOffset << offset;
228
+ }
229
+
230
+ void QgsNodeTool2::addDragMiddleBand ( const QgsPoint &v1, const QgsPoint &v2, const QgsVector &offset1, const QgsVector &offset2 )
231
+ {
232
+ QgsRubberBand *dragBand = createRubberBand ( QgsWkbTypes::LineGeometry, true );
233
+ dragBand->addPoint ( v1 );
234
+ dragBand->addPoint ( v2 );
235
+ mDragMiddleBands << dragBand;
236
+ mDragMiddleBandsOffset << qMakePair ( offset1, offset2 );
230
237
}
231
238
232
239
void QgsNodeTool2::clearDragBands ()
233
240
{
234
241
qDeleteAll ( mDragBands );
235
242
mDragBands .clear ();
243
+ mDragBandsOffset .clear ();
244
+
245
+ qDeleteAll ( mDragMiddleBands );
246
+ mDragMiddleBands .clear ();
247
+ mDragMiddleBandsOffset .clear ();
236
248
237
- // for the case when standalone point geometry is being dragged
238
- mDragPointMarker ->setVisible ( false );
249
+ qDeleteAll ( mDragPointMarkers );
250
+ mDragPointMarkers .clear ();
251
+ mDragPointMarkersOffset .clear ();
239
252
}
240
253
241
254
void QgsNodeTool2::cadCanvasPressEvent ( QgsMapMouseEvent *e )
242
255
{
243
- setHighlightedNodes ( QList<Vertex>() ); // reset selection
256
+ if ( !mDraggingVertex && !mSelectedNodes .isEmpty () )
257
+ {
258
+ // only remove highlight if not clicked on one of highlighted nodes
259
+ bool clickedOnHighlightedNode = false ;
260
+ QgsPointLocator::Match m = snapToEditableLayer ( e );
261
+ if ( m.hasVertex () )
262
+ {
263
+ Q_FOREACH ( const Vertex &selectedNode, mSelectedNodes )
264
+ {
265
+ if ( selectedNode.layer == m.layer () && selectedNode.fid == m.featureId () && selectedNode.vertexId == m.vertexIndex () )
266
+ {
267
+ clickedOnHighlightedNode = true ;
268
+ break ;
269
+ }
270
+ }
271
+ }
272
+
273
+ if ( !clickedOnHighlightedNode )
274
+ setHighlightedNodes ( QList<Vertex>() ); // reset selection
275
+ }
244
276
245
277
if ( e->button () == Qt::LeftButton )
246
278
{
@@ -396,13 +428,29 @@ void QgsNodeTool2::mouseMoveDraggingVertex( QgsMapMouseEvent *e )
396
428
397
429
mEdgeCenterMarker ->setVisible ( false );
398
430
399
- Q_FOREACH ( QgsRubberBand *band, mDragBands )
400
- band->movePoint ( 1 , e->mapPoint () );
431
+ // rubber bands with one end moving
432
+ for ( int i = 0 ; i < mDragBands .count (); ++i )
433
+ {
434
+ QgsRubberBand *band = mDragBands [i];
435
+ const QgsVector &offset = mDragBandsOffset [i];
436
+ band->movePoint ( 1 , e->mapPoint () + offset );
437
+ }
438
+
439
+ // rubber bands with both ends moving
440
+ for ( int i = 0 ; i < mDragMiddleBands .count (); ++i )
441
+ {
442
+ QgsRubberBand *band = mDragMiddleBands [i];
443
+ const QPair<QgsVector, QgsVector> &offset = mDragMiddleBandsOffset [i];
444
+ band->movePoint ( 0 , e->mapPoint () + offset.first );
445
+ band->movePoint ( 1 , e->mapPoint () + offset.second );
446
+ }
401
447
402
448
// in case of moving of standalone point geometry
403
- if ( mDragPointMarker -> isVisible () )
449
+ for ( int i = 0 ; i < mDragPointMarkers . count (); ++i )
404
450
{
405
- mDragPointMarker ->setCenter ( e->mapPoint () );
451
+ QgsVertexMarker *marker = mDragPointMarkers [i];
452
+ QgsVector offset = mDragPointMarkersOffset [i];
453
+ marker->setCenter ( e->mapPoint () + offset );
406
454
}
407
455
408
456
// make sure the temporary feature rubber band is not visible
@@ -762,68 +810,118 @@ void QgsNodeTool2::startDraggingMoveVertex( const QgsPoint &mapPoint, const QgsP
762
810
// start dragging of snapped point of current layer
763
811
mDraggingVertex .reset ( new Vertex ( m.layer (), m.featureId (), m.vertexIndex () ) );
764
812
mDraggingVertexType = MovingVertex;
765
- mDraggingTopo .clear ();
813
+ mDraggingExtraVertices .clear ();
814
+ mDraggingExtraVerticesOffset .clear ();
766
815
767
- int v0idx, v1idx;
768
- geom.adjacentVertices ( m.vertexIndex (), v0idx, v1idx );
769
- if ( v0idx != -1 )
770
- {
771
- QgsPoint layerPoint0 = geom.vertexAt ( v0idx );
772
- QgsPoint mapPoint0 = toMapCoordinates ( m.layer (), layerPoint0 );
773
- addDragBand ( mapPoint0, m.point () );
774
- }
775
- if ( v1idx != -1 )
776
- {
777
- QgsPoint layerPoint1 = geom.vertexAt ( v1idx );
778
- QgsPoint mapPoint1 = toMapCoordinates ( m.layer (), layerPoint1 );
779
- addDragBand ( mapPoint1, m.point () );
780
- }
816
+ setHighlightedNodesVisible ( false ); // hide any extra highlight of vertices until we are done with moving
817
+
818
+ QgsPoint origDraggingVertexPoint = geom.vertexAt ( mDraggingVertex ->vertexId );
781
819
782
- if ( v0idx == -1 && v1idx == -1 )
820
+ // if there are other highlighted nodes, they should be dragged as well with their offset
821
+ Q_FOREACH ( const Vertex &v, mSelectedNodes )
783
822
{
784
- // this is a standalone point - we need to use a marker for it
785
- // to give some feedback to the user
786
- mDragPointMarker ->setCenter ( mapPoint );
787
- mDragPointMarker ->setVisible ( true );
823
+ if ( v != *mDraggingVertex )
824
+ {
825
+ // TODO: convert offset to destination layer's CRS
826
+ QgsPoint origPointV = cachedGeometryForVertex ( v ).vertexAt ( v.vertexId );
827
+ QgsVector offset ( origPointV.x () - origDraggingVertexPoint.x (), origPointV.y () - origDraggingVertexPoint.y () );
828
+
829
+ mDraggingExtraVertices << v;
830
+ mDraggingExtraVerticesOffset << offset;
831
+ }
788
832
}
789
833
790
834
mOverrideCadPoints .clear ();
791
835
mOverrideCadPoints << m.point () << m.point ();
792
836
793
- if ( !QgsProject::instance ()->topologicalEditing () )
794
- return ; // we are done now
795
-
796
- // support for topo editing - find extra features
797
- Q_FOREACH ( QgsMapLayer *layer, canvas ()->layers () )
837
+ if ( QgsProject::instance ()->topologicalEditing () )
798
838
{
799
- QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
800
- if ( !vlayer || !vlayer->isEditable () )
801
- continue ;
802
-
803
- Q_FOREACH ( const QgsPointLocator::Match &otherMatch, layerVerticesSnappedToPoint ( vlayer, mapPoint ) )
839
+ // support for topo editing - find extra features
840
+ // that have coincident point with the vertex being dragged
841
+ Q_FOREACH ( QgsMapLayer *layer, canvas ()->layers () )
804
842
{
805
- if ( otherMatch == m )
843
+ QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
844
+ if ( !vlayer || !vlayer->isEditable () )
806
845
continue ;
807
846
808
- QgsGeometry otherGeom = cachedGeometry ( otherMatch.layer (), otherMatch.featureId () );
847
+ Q_FOREACH ( const QgsPointLocator::Match &otherMatch, layerVerticesSnappedToPoint ( vlayer, mapPoint ) )
848
+ {
849
+ if ( otherMatch.layer () == m.layer () &&
850
+ otherMatch.featureId () == m.featureId () &&
851
+ otherMatch.vertexIndex () == m.vertexIndex () )
852
+ continue ;
853
+
854
+ // start dragging of snapped point of current layer
855
+ mDraggingExtraVertices << Vertex ( otherMatch.layer (), otherMatch.featureId (), otherMatch.vertexIndex () );
856
+ mDraggingExtraVerticesOffset << QgsVector (); // topo vertices have the same position
857
+ }
858
+ }
859
+ }
860
+
861
+ // now build drag rubber bands for extra vertices
809
862
810
- // start dragging of snapped point of current layer
811
- mDraggingTopo << Vertex ( otherMatch.layer (), otherMatch.featureId (), otherMatch.vertexIndex () );
863
+ QSet<Vertex> movingVertices;
864
+ movingVertices << *mDraggingVertex ;
865
+ Q_FOREACH ( const Vertex &v, mDraggingExtraVertices )
866
+ movingVertices << v;
812
867
813
- otherGeom.adjacentVertices ( otherMatch.vertexIndex (), v0idx, v1idx );
814
- if ( v0idx != -1 )
868
+ QgsPoint dragVertexMapPoint = m.point ();
869
+
870
+ Q_FOREACH ( const Vertex &v, movingVertices )
871
+ {
872
+ int v0idx, v1idx;
873
+ QgsGeometry geom = cachedGeometry ( v.layer , v.fid );
874
+ QgsPoint pt = geom.vertexAt ( v.vertexId );
875
+ geom.adjacentVertices ( v.vertexId , v0idx, v1idx );
876
+ if ( v0idx != -1 )
877
+ {
878
+ Vertex v0 ( v.layer , v.fid , v0idx );
879
+ QgsPoint otherPoint0 = geom.vertexAt ( v0idx );
880
+ QgsPoint otherMapPoint0 = toMapCoordinates ( v.layer , otherPoint0 );
881
+ if ( !movingVertices.contains ( v0 ) )
882
+ {
883
+ // rubber band that is fixed on one side and moving with mouse cursor on the other
884
+ addDragBand ( otherMapPoint0, pt, pt - dragVertexMapPoint );
885
+ }
886
+ else
887
+ {
888
+ // rubber band that has both endpoints moving with mouse cursor
889
+ if ( v0idx > v.vertexId )
890
+ addDragMiddleBand ( otherMapPoint0, pt, otherMapPoint0 - dragVertexMapPoint, pt - dragVertexMapPoint );
891
+ }
892
+ }
893
+ if ( v1idx != -1 )
894
+ {
895
+ Vertex v1 ( v.layer , v.fid , v1idx );
896
+ QgsPoint otherPoint1 = geom.vertexAt ( v1idx );
897
+ QgsPoint otherMapPoint1 = toMapCoordinates ( v.layer , otherPoint1 );
898
+ if ( !movingVertices.contains ( v1 ) )
815
899
{
816
- QgsPoint otherPoint0 = otherGeom.vertexAt ( v0idx );
817
- QgsPoint otherMapPoint0 = toMapCoordinates ( otherMatch.layer (), otherPoint0 );
818
- addDragBand ( otherMapPoint0, otherMatch.point () );
900
+ // rubber band that is fixed on one side and moving with mouse cursor on the other
901
+ addDragBand ( otherMapPoint1, pt, pt - dragVertexMapPoint );
819
902
}
820
- if ( v1idx != - 1 )
903
+ else
821
904
{
822
- QgsPoint otherPoint1 = otherGeom. vertexAt ( v1idx );
823
- QgsPoint otherMapPoint1 = toMapCoordinates ( otherMatch. layer (), otherPoint1 );
824
- addDragBand ( otherMapPoint1, otherMatch. point () );
905
+ // rubber band that has both endpoints moving with mouse cursor
906
+ if ( v1idx > v. vertexId )
907
+ addDragMiddleBand ( otherMapPoint1, pt, otherMapPoint1 - dragVertexMapPoint, pt - dragVertexMapPoint );
825
908
}
826
909
}
910
+
911
+ if ( v0idx == -1 && v1idx == -1 )
912
+ {
913
+ // this is a standalone point - we need to use a marker for it
914
+ // to give some feedback to the user
915
+
916
+ QgsVertexMarker *marker = new QgsVertexMarker ( mCanvas );
917
+ marker->setIconType ( QgsVertexMarker::ICON_X );
918
+ marker->setColor ( Qt::red );
919
+ marker->setPenWidth ( 3 );
920
+ marker->setVisible ( true );
921
+ marker->setCenter ( toMapCoordinates ( v.layer , pt ) );
922
+ mDragPointMarkers << marker;
923
+ mDragPointMarkersOffset << ( pt - dragVertexMapPoint );
924
+ }
827
925
}
828
926
}
829
927
@@ -844,7 +942,8 @@ void QgsNodeTool2::startDraggingAddVertex( const QgsPointLocator::Match &m )
844
942
845
943
mDraggingVertex .reset ( new Vertex ( m.layer (), m.featureId (), m.vertexIndex () + 1 ) );
846
944
mDraggingVertexType = AddingVertex;
847
- mDraggingTopo .clear ();
945
+ mDraggingExtraVertices .clear ();
946
+ mDraggingExtraVerticesOffset .clear ();
848
947
849
948
QgsGeometry geom = cachedGeometry ( m.layer (), m.featureId () );
850
949
@@ -873,7 +972,8 @@ void QgsNodeTool2::startDraggingAddVertexAtEndpoint( const QgsPoint &mapPoint )
873
972
874
973
mDraggingVertex .reset ( new Vertex ( mMouseAtEndpoint ->layer , mMouseAtEndpoint ->fid , mMouseAtEndpoint ->vertexId ) );
875
974
mDraggingVertexType = AddingEndpoint;
876
- mDraggingTopo .clear ();
975
+ mDraggingExtraVertices .clear ();
976
+ mDraggingExtraVerticesOffset .clear ();
877
977
878
978
QgsGeometry geom = cachedGeometry ( mMouseAtEndpoint ->layer , mMouseAtEndpoint ->fid );
879
979
QgsPoint v0 = geom.vertexAt ( mMouseAtEndpoint ->vertexId );
@@ -896,7 +996,8 @@ void QgsNodeTool2::startDraggingEdge( const QgsPointLocator::Match &m, const Qgs
896
996
setMode ( CaptureLine );
897
997
898
998
mDraggingEdge .reset ( new Edge ( m.layer (), m.featureId (), m.vertexIndex (), mapPoint ) );
899
- mDraggingTopo .clear ();
999
+ mDraggingExtraVertices .clear ();
1000
+ mDraggingExtraVerticesOffset .clear ();
900
1001
901
1002
QgsPoint edge_p0, edge_p1;
902
1003
m.edgePoints ( edge_p0, edge_p1 );
@@ -946,6 +1047,8 @@ void QgsNodeTool2::stopDragging()
946
1047
mDraggingVertexType = NotDragging;
947
1048
mDraggingEdge .reset ();
948
1049
clearDragBands ();
1050
+
1051
+ setHighlightedNodesVisible ( true ); // highlight can be shown again
949
1052
}
950
1053
951
1054
QgsPoint QgsNodeTool2::matchToLayerPoint ( const QgsVectorLayer *destLayer, const QgsPoint &mapPoint, const QgsPointLocator::Match *match )
@@ -1048,9 +1151,13 @@ void QgsNodeTool2::moveVertex( const QgsPoint &mapPoint, const QgsPointLocator::
1048
1151
QHash<QgsVectorLayer *, QHash<QgsFeatureId, QgsGeometry> > edits; // dict { layer : { fid : geom } }
1049
1152
edits[dragLayer][dragFid] = geom;
1050
1153
1154
+ Q_ASSERT ( mDraggingExtraVertices .count () == mDraggingExtraVerticesOffset .count () );
1051
1155
// add moved vertices from other layers
1052
- Q_FOREACH ( const Vertex &topo, mDraggingTopo )
1156
+ for ( int i = 0 ; i < mDraggingExtraVertices . count (); ++i )
1053
1157
{
1158
+ const Vertex &topo = mDraggingExtraVertices [i];
1159
+ const QgsVector &offset = mDraggingExtraVerticesOffset [i];
1160
+
1054
1161
QHash<QgsFeatureId, QgsGeometry> &layerEdits = edits[topo.layer ];
1055
1162
QgsGeometry topoGeom;
1056
1163
if ( layerEdits.contains ( topo.fid ) )
@@ -1064,6 +1171,11 @@ void QgsNodeTool2::moveVertex( const QgsPoint &mapPoint, const QgsPointLocator::
1064
1171
else
1065
1172
point = toLayerCoordinates ( topo.layer , mapPoint );
1066
1173
1174
+ if ( offset.x () || offset.y () )
1175
+ {
1176
+ point += offset;
1177
+ }
1178
+
1067
1179
if ( !topoGeom.moveVertex ( point.x (), point.y (), topo.vertexId ) )
1068
1180
{
1069
1181
QgsDebugMsg ( " [topo] move vertex failed!" );
@@ -1089,6 +1201,9 @@ void QgsNodeTool2::moveVertex( const QgsPoint &mapPoint, const QgsPointLocator::
1089
1201
layer->endEditCommand ();
1090
1202
layer->triggerRepaint ();
1091
1203
}
1204
+
1205
+ setHighlightedNodes ( mSelectedNodes ); // update positions of existing highlighted nodes
1206
+ setHighlightedNodesVisible ( true ); // time to show highlighted nodes again
1092
1207
}
1093
1208
1094
1209
void QgsNodeTool2::deleteVertex ()
@@ -1102,7 +1217,7 @@ void QgsNodeTool2::deleteVertex()
1102
1217
{
1103
1218
bool addingVertex = mDraggingVertexType == AddingVertex || mDraggingVertexType == AddingEndpoint;
1104
1219
toDelete << *mDraggingVertex ;
1105
- toDelete += mDraggingTopo ;
1220
+ toDelete += mDraggingExtraVertices ;
1106
1221
stopDragging ();
1107
1222
1108
1223
if ( addingVertex )
@@ -1199,6 +1314,12 @@ void QgsNodeTool2::setHighlightedNodes( const QList<Vertex> &listNodes )
1199
1314
mSelectedNodes = listNodes;
1200
1315
}
1201
1316
1317
+ void QgsNodeTool2::setHighlightedNodesVisible ( bool visible )
1318
+ {
1319
+ Q_FOREACH ( QgsVertexMarker *marker, mSelectedNodesMarkers )
1320
+ marker->setVisible ( visible );
1321
+ }
1322
+
1202
1323
void QgsNodeTool2::highlightAdjacentVertex ( double offset )
1203
1324
{
1204
1325
if ( mSelectedNodes .isEmpty () )
0 commit comments