1 /***************************************************************************
2 testqgsvertextool.cpp
3 ----------------------
4 Date : 2017-03-01
5 Copyright : (C) 2017 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgstest.h"
17
18 #include "qgsadvanceddigitizingdockwidget.h"
19 #include "qgsgeometry.h"
20 #include "qgsgeos.h"
21 #include "qgsmapcanvas.h"
22 #include "qgsmapcanvassnappingutils.h"
23 #include "qgsproject.h"
24 #include "qgsvectorlayer.h"
25 #include "qgsmapmouseevent.h"
26 #include "vertextool/qgsvertextool.h"
27 #include "qgslinestring.h"
28 #include "qgscircularstring.h"
29 #include "qgssnappingconfig.h"
30 #include "qgssettingsregistrycore.h"
31 #include "testqgsmaptoolutils.h"
32
operator ==(const QgsGeometry & g1,const QgsGeometry & g2)33 bool operator==( const QgsGeometry &g1, const QgsGeometry &g2 )
34 {
35 if ( g1.isNull() && g2.isNull() )
36 return true;
37 else
38 return g1.isGeosEqual( g2 );
39 }
40
41 namespace QTest
42 {
43 // pretty printing of geometries in comparison tests
toString(const QgsGeometry & geom)44 template<> char *toString( const QgsGeometry &geom )
45 {
46 QByteArray ba = geom.asWkt().toLatin1();
47 return qstrdup( ba.data() );
48 }
49 }
50
51 /**
52 * \ingroup UnitTests
53 * This is a unit test for the vertex tool
54 */
55 class TestQgsVertexTool : public QObject
56 {
57 Q_OBJECT
58 public:
59 TestQgsVertexTool();
60
61 private slots:
62 void initTestCase();// will be called before the first testfunction is executed.
63 void cleanupTestCase();// will be called after the last testfunction was executed.
64
65 void testSelectVerticesByPolygon();
66 void testTopologicalEditingMoveVertexZ();
67 void testTopologicalEditingMoveVertexOnSegmentZ();
68 void testTopologicalEditingMoveVertexOnIntersectionZ();
69 void testMoveVertex();
70 void testMoveEdge();
71 void testAddVertex();
72 void testAddVertexAtEndpoint();
73 void testAddVertexDoubleClick();
74 void testAddVertexDoubleClickWithShift();
75 void testAvoidIntersections();
76 void testDeleteVertex();
77 void testConvertVertex();
78 void testMoveMultipleVertices();
79 void testMoveMultipleVertices2();
80 void testMoveVertexTopo();
81 void testDeleteVertexTopo();
82 void testAddVertexTopo();
83 void testMoveEdgeTopo();
84 void testAddVertexTopoFirstSegment();
85 void testActiveLayerPriority();
86 void testSelectedFeaturesPriority();
87 void testVertexToolCompoundCurve();
88
89
90 private:
mapToScreen(double mapX,double mapY)91 QPoint mapToScreen( double mapX, double mapY )
92 {
93 const QgsPointXY pt = mCanvas->mapSettings().mapToPixel().transform( mapX, mapY );
94 return QPoint( std::round( pt.x() ), std::round( pt.y() ) );
95 }
96
mouseMove(double mapX,double mapY)97 void mouseMove( double mapX, double mapY )
98 {
99 QgsMapMouseEvent e( mCanvas, QEvent::MouseMove, mapToScreen( mapX, mapY ) );
100 mVertexTool->cadCanvasMoveEvent( &e );
101 }
102
mousePress(double mapX,double mapY,Qt::MouseButton button,Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers (),bool snap=false)103 void mousePress( double mapX, double mapY, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(), bool snap = false )
104 {
105 QgsMapMouseEvent e1( mCanvas, QEvent::MouseButtonPress, mapToScreen( mapX, mapY ), button, button, stateKey );
106 if ( snap )
107 e1.snapPoint();
108 mVertexTool->cadCanvasPressEvent( &e1 );
109 }
110
mouseRelease(double mapX,double mapY,Qt::MouseButton button,Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers (),bool snap=false)111 void mouseRelease( double mapX, double mapY, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(), bool snap = false )
112 {
113 QgsMapMouseEvent e2( mCanvas, QEvent::MouseButtonRelease, mapToScreen( mapX, mapY ), button, Qt::MouseButton(), stateKey );
114 if ( snap )
115 e2.snapPoint();
116 mVertexTool->cadCanvasReleaseEvent( &e2 );
117 }
118
mouseClick(double mapX,double mapY,Qt::MouseButton button,Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers (),bool snap=false)119 void mouseClick( double mapX, double mapY, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(), bool snap = false )
120 {
121 mousePress( mapX, mapY, button, stateKey, snap );
122 mouseRelease( mapX, mapY, button, stateKey, snap );
123 }
124
mouseDoubleClick(double mapX,double mapY,Qt::MouseButton button,Qt::KeyboardModifiers stateKey=Qt::KeyboardModifiers (),bool snap=false)125 void mouseDoubleClick( double mapX, double mapY, Qt::MouseButton button, Qt::KeyboardModifiers stateKey = Qt::KeyboardModifiers(), bool snap = false )
126 {
127 // this is how Qt passes the events: 1. mouse press, 2. mouse release, 3. mouse double-click, 4. mouse release
128
129 mouseClick( mapX, mapY, button, stateKey, snap );
130
131 QgsMapMouseEvent e( mCanvas, QEvent::MouseButtonDblClick, mapToScreen( mapX, mapY ), button, button, stateKey );
132 if ( snap )
133 e.snapPoint();
134 mVertexTool->canvasDoubleClickEvent( &e );
135
136 mouseRelease( mapX, mapY, button, stateKey );
137 }
138
keyClick(int key)139 void keyClick( int key )
140 {
141 QKeyEvent e1( QEvent::KeyPress, key, Qt::KeyboardModifiers() );
142 mVertexTool->keyPressEvent( &e1 );
143
144 QKeyEvent e2( QEvent::KeyRelease, key, Qt::KeyboardModifiers() );
145 mVertexTool->keyReleaseEvent( &e2 );
146 }
147
148 private:
149 QgsMapCanvas *mCanvas = nullptr;
150 QgisApp *mQgisApp = nullptr;
151 QgsAdvancedDigitizingDockWidget *mAdvancedDigitizingDockWidget = nullptr;
152 QgsVertexTool *mVertexTool = nullptr;
153 QgsVectorLayer *mLayerLine = nullptr;
154 QgsVectorLayer *mLayerMultiLine = nullptr;
155 QgsVectorLayer *mLayerPolygon = nullptr;
156 QgsVectorLayer *mLayerMultiPolygon = nullptr;
157 QgsVectorLayer *mLayerPoint = nullptr;
158 QgsVectorLayer *mLayerLineZ = nullptr;
159 QgsVectorLayer *mLayerCompoundCurve = nullptr;
160 QgsVectorLayer *mLayerLineReprojected = nullptr;
161 QgsFeatureId mFidLineZF1 = 0;
162 QgsFeatureId mFidLineZF2 = 0;
163 QgsFeatureId mFidLineZF3 = 0;
164 QgsFeatureId mFidLineF1 = 0;
165 QgsFeatureId mFidMultiLineF1 = 0;
166 QgsFeatureId mFidLineF13857 = 0;
167 QgsFeatureId mFidPolygonF1 = 0;
168 QgsFeatureId mFidMultiPolygonF1 = 0;
169 QgsFeatureId mFidPointF1 = 0;
170 QgsFeatureId mFidCompoundCurveF1 = 0;
171 QgsFeatureId mFidCompoundCurveF2 = 0;
172 };
173
174 TestQgsVertexTool::TestQgsVertexTool() = default;
175
176
177 //runs before all tests
initTestCase()178 void TestQgsVertexTool::initTestCase()
179 {
180 qDebug() << "TestQgisAppClipboard::initTestCase()";
181 // init QGIS's paths - true means that all path will be inited from prefix
182 QgsApplication::init();
183 QgsApplication::initQgis();
184 mQgisApp = new QgisApp();
185
186 // Set up the QSettings environment
187 QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) );
188 QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) );
189 QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) );
190
191 mCanvas = new QgsMapCanvas();
192
193 mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:27700" ) ) );
194
195 mAdvancedDigitizingDockWidget = new QgsAdvancedDigitizingDockWidget( mCanvas );
196
197 // make testing layers
198 mLayerLine = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:27700" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) );
199 QVERIFY( mLayerLine->isValid() );
200 mLayerMultiLine = new QgsVectorLayer( QStringLiteral( "MultiLineString?crs=EPSG:27700" ), QStringLiteral( "layer multiline" ), QStringLiteral( "memory" ) );
201 QVERIFY( mLayerMultiLine->isValid() );
202 mLayerLineReprojected = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:3857" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) );
203 QVERIFY( mLayerLineReprojected->isValid() );
204 mLayerPolygon = new QgsVectorLayer( QStringLiteral( "Polygon?crs=EPSG:27700" ), QStringLiteral( "layer polygon" ), QStringLiteral( "memory" ) );
205 QVERIFY( mLayerPolygon->isValid() );
206 mLayerMultiPolygon = new QgsVectorLayer( QStringLiteral( "MultiPolygon?crs=EPSG:27700" ), QStringLiteral( "layer multipolygon" ), QStringLiteral( "memory" ) );
207 QVERIFY( mLayerMultiPolygon->isValid() );
208 mLayerPoint = new QgsVectorLayer( QStringLiteral( "Point?crs=EPSG:27700" ), QStringLiteral( "layer point" ), QStringLiteral( "memory" ) );
209 QVERIFY( mLayerPoint->isValid() );
210 mLayerLineZ = new QgsVectorLayer( QStringLiteral( "LineStringZ?crs=EPSG:27700" ), QStringLiteral( "layer line" ), QStringLiteral( "memory" ) );
211 QVERIFY( mLayerLineZ->isValid() );
212 mLayerCompoundCurve = new QgsVectorLayer( QStringLiteral( "CompoundCurve?crs=27700" ), QStringLiteral( "layer compound curve" ), QStringLiteral( "memory" ) );
213 QVERIFY( mLayerCompoundCurve->isValid() );
214 QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << mLayerLine << mLayerMultiLine << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerLineZ << mLayerCompoundCurve );
215
216 QgsFeature lineF1;
217 lineF1.setGeometry( QgsGeometry::fromWkt( "LineString (2 1, 1 1, 1 3)" ) );
218
219 QgsFeature multiLineF1;
220 multiLineF1.setGeometry( QgsGeometry::fromWkt( "MultiLineString ((3 1, 3 2),(3 3, 3 4))" ) );
221
222 const QgsCoordinateTransform ct( mLayerLine->crs(), mLayerLineReprojected->crs(), QgsCoordinateTransformContext() );
223 QgsGeometry line3857 = lineF1.geometry();
224 line3857.transform( ct );
225 QgsFeature lineF13857;
226 lineF13857.setGeometry( line3857 );
227
228 QgsFeature polygonF1;
229 polygonF1.setGeometry( QgsGeometry::fromWkt( "Polygon ((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
230
231 QgsFeature multiPolygonF1;
232 multiPolygonF1.setGeometry( QgsGeometry::fromWkt( "MultiPolygon (((1 5, 2 5, 2 6.5, 2 8, 1 8, 1 6.5, 1 5),(1.25 5.5, 1.25 6, 1.75 6, 1.75 5.5, 1.25 5.5),(1.25 7, 1.75 7, 1.75 7.5, 1.25 7.5, 1.25 7)),((3 5, 3 6.5, 3 8, 4 8, 4 6.5, 4 5, 3 5),(3.25 5.5, 3.75 5.5, 3.75 6, 3.25 6, 3.25 5.5),(3.25 7, 3.75 7, 3.75 7.5, 3.25 7.5, 3.25 7)))" ) );
233
234 QgsFeature pointF1;
235 pointF1.setGeometry( QgsGeometry::fromWkt( "Point (2 3)" ) );
236
237 QgsFeature linez1, linez2, linez3;
238 linez1.setGeometry( QgsGeometry::fromWkt( "LineStringZ (5 5 1, 6 6 1, 7 5 1)" ) );
239 linez2.setGeometry( QgsGeometry::fromWkt( "LineStringZ (5 7 5, 7 7 10)" ) );
240 linez3.setGeometry( QgsGeometry::fromWkt( "LineStringZ (5 5.5 5, 7 5.5 10)" ) );
241
242 QgsFeature curveF1;
243 curveF1.setGeometry( QgsGeometry::fromWkt( "CompoundCurve (CircularString (14 14, 10 10, 17 10))" ) );
244 QgsFeature curveF2;
245 curveF2.setGeometry( QgsGeometry::fromWkt( "CompoundCurve ((16 11, 17 11, 17 13))" ) );
246
247 mLayerLine->startEditing();
248 mLayerLine->addFeature( lineF1 );
249 mFidLineF1 = lineF1.id();
250 QCOMPARE( mLayerLine->featureCount(), ( long )1 );
251
252 mLayerMultiLine->startEditing();
253 mLayerMultiLine->addFeature( multiLineF1 );
254 mFidMultiLineF1 = multiLineF1.id();
255 QCOMPARE( mLayerMultiLine->featureCount(), ( long )1 );
256
257 mLayerLineReprojected->startEditing();
258 mLayerLineReprojected->addFeature( lineF13857 );
259 mFidLineF13857 = lineF13857.id();
260 QCOMPARE( mLayerLineReprojected->featureCount(), ( long )1 );
261
262 mLayerPolygon->startEditing();
263 mLayerPolygon->addFeature( polygonF1 );
264 mFidPolygonF1 = polygonF1.id();
265 QCOMPARE( mLayerPolygon->featureCount(), ( long )1 );
266
267 mLayerMultiPolygon->startEditing();
268 mLayerMultiPolygon->addFeature( multiPolygonF1 );
269 mFidMultiPolygonF1 = multiPolygonF1.id();
270 QCOMPARE( mLayerMultiPolygon->featureCount(), ( long )1 );
271
272 mLayerPoint->startEditing();
273 mLayerPoint->addFeature( pointF1 );
274 mFidPointF1 = pointF1.id();
275 QCOMPARE( mLayerPoint->featureCount(), ( long )1 );
276
277 mLayerLineZ->startEditing();
278 mLayerLineZ->addFeature( linez1 );
279 mLayerLineZ->addFeature( linez2 );
280 mLayerLineZ->addFeature( linez3 );
281 mFidLineZF1 = linez1.id();
282 mFidLineZF2 = linez2.id();
283 mFidLineZF3 = linez3.id();
284 QCOMPARE( mLayerLineZ->featureCount(), ( long ) 3 );
285
286 mLayerCompoundCurve->startEditing();
287 mLayerCompoundCurve->addFeature( curveF1 );
288 mLayerCompoundCurve->addFeature( curveF2 );
289 mFidCompoundCurveF1 = curveF1.id();
290 mFidCompoundCurveF2 = curveF2.id();
291 QCOMPARE( mLayerCompoundCurve->featureCount(), ( long ) 2 );
292
293 // just one added feature in each undo stack
294 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
295 QCOMPARE( mLayerMultiLine->undoStack()->index(), 1 );
296 QCOMPARE( mLayerPolygon->undoStack()->index(), 1 );
297 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 1 );
298 QCOMPARE( mLayerPoint->undoStack()->index(), 1 );
299 // except for layerLineZ
300 QCOMPARE( mLayerLineZ->undoStack()->index(), 3 );
301 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 2 );
302
303 mCanvas->setFrameStyle( QFrame::NoFrame );
304 mCanvas->resize( 512, 512 );
305 mCanvas->setExtent( QgsRectangle( 0, 0, 8, 8 ) );
306 mCanvas->show(); // to make the canvas resize
307 mCanvas->hide();
308 QCOMPARE( mCanvas->mapSettings().outputSize(), QSize( 512, 512 ) );
309 QCOMPARE( mCanvas->mapSettings().visibleExtent(), QgsRectangle( 0, 0, 8, 8 ) );
310
311 mCanvas->setLayers( QList<QgsMapLayer *>() << mLayerLine << mLayerMultiLine << mLayerLineReprojected << mLayerPolygon << mLayerMultiPolygon << mLayerPoint << mLayerLineZ << mLayerCompoundCurve );
312
313 QgsMapCanvasSnappingUtils *snappingUtils = new QgsMapCanvasSnappingUtils( mCanvas, this );
314 mCanvas->setSnappingUtils( snappingUtils );
315
316 snappingUtils->locatorForLayer( mLayerLine )->init();
317 snappingUtils->locatorForLayer( mLayerMultiLine )->init();
318 snappingUtils->locatorForLayer( mLayerLineReprojected )->init();
319 snappingUtils->locatorForLayer( mLayerPolygon )->init();
320 snappingUtils->locatorForLayer( mLayerMultiPolygon )->init();
321 snappingUtils->locatorForLayer( mLayerPoint )->init();
322 snappingUtils->locatorForLayer( mLayerLineZ )->init();
323 snappingUtils->locatorForLayer( mLayerCompoundCurve )->init();
324
325 // create vertex tool
326 mVertexTool = new QgsVertexTool( mCanvas, mAdvancedDigitizingDockWidget );
327
328 mCanvas->setMapTool( mVertexTool );
329 }
330
331 //runs after all tests
cleanupTestCase()332 void TestQgsVertexTool::cleanupTestCase()
333 {
334 delete mVertexTool;
335 delete mAdvancedDigitizingDockWidget;
336 delete mCanvas;
337 QgsApplication::exitQgis();
338 }
339
testTopologicalEditingMoveVertexZ()340 void TestQgsVertexTool::testTopologicalEditingMoveVertexZ()
341 {
342 const bool topologicalEditing = QgsProject::instance()->topologicalEditing();
343 QgsProject::instance()->setTopologicalEditing( true );
344 QgsSnappingConfig cfg = mCanvas->snappingUtils()->config();
345 cfg.setMode( QgsSnappingConfig::AllLayers );
346 cfg.setTolerance( 10 );
347 cfg.setTypeFlag( static_cast<QgsSnappingConfig::SnappingTypeFlag>( QgsSnappingConfig::VertexFlag | QgsSnappingConfig::SegmentFlag ) );
348 cfg.setEnabled( true );
349 mCanvas->snappingUtils()->setConfig( cfg );
350
351 mouseClick( 6, 6, Qt::LeftButton, Qt::KeyboardModifiers(), true );
352 mouseClick( 5, 7, Qt::LeftButton, Qt::KeyboardModifiers(), true );
353
354 QCOMPARE( mLayerLineZ->getFeature( mFidLineZF1 ).geometry().asWkt(), QString( "LineStringZ (5 5 1, 5 7 5, 7 5 1)" ) );
355 QCOMPARE( mLayerLineZ->getFeature( mFidLineZF2 ).geometry().asWkt(), QString( "LineStringZ (5 7 5, 7 7 10)" ) );
356
357 QgsProject::instance()->setTopologicalEditing( topologicalEditing );
358 mLayerLineZ->undoStack()->undo();
359 cfg.setEnabled( false );
360 mCanvas->snappingUtils()->setConfig( cfg );
361 }
362
testTopologicalEditingMoveVertexOnSegmentZ()363 void TestQgsVertexTool::testTopologicalEditingMoveVertexOnSegmentZ()
364 {
365 QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 333 );
366
367 const bool topologicalEditing = QgsProject::instance()->topologicalEditing();
368 QgsProject::instance()->setTopologicalEditing( true );
369 QgsSnappingConfig cfg = mCanvas->snappingUtils()->config();
370 cfg.setMode( QgsSnappingConfig::AllLayers );
371 cfg.setTolerance( 10 );
372 cfg.setTypeFlag( static_cast<QgsSnappingConfig::SnappingTypeFlag>( QgsSnappingConfig::VertexFlag | QgsSnappingConfig::SegmentFlag ) );
373 cfg.setEnabled( true );
374 mCanvas->snappingUtils()->setConfig( cfg );
375
376 mouseClick( 6, 6, Qt::LeftButton, Qt::KeyboardModifiers(), true );
377 mouseClick( 6, 7, Qt::LeftButton, Qt::KeyboardModifiers(), true );
378
379 QCOMPARE( mLayerLineZ->getFeature( mFidLineZF1 ).geometry().asWkt(), QString( "LineStringZ (5 5 1, 6 7 7.5, 7 5 1)" ) );
380 QCOMPARE( mLayerLineZ->getFeature( mFidLineZF2 ).geometry().asWkt(), QString( "LineStringZ (5 7 5, 6 7 7.5, 7 7 10)" ) );
381
382 QgsProject::instance()->setTopologicalEditing( topologicalEditing );
383 // Two undo steps, one for the vertex move, one for the topological point
384 mLayerLineZ->undoStack()->undo();
385 mLayerLineZ->undoStack()->undo();
386 cfg.setEnabled( false );
387 mCanvas->snappingUtils()->setConfig( cfg );
388 }
389
testTopologicalEditingMoveVertexOnIntersectionZ()390 void TestQgsVertexTool::testTopologicalEditingMoveVertexOnIntersectionZ()
391 {
392 QgsSettingsRegistryCore::settingsDigitizingDefaultZValue.setValue( 333 );
393
394 const bool topologicalEditing = QgsProject::instance()->topologicalEditing();
395 QgsProject::instance()->setTopologicalEditing( true );
396 QgsSnappingConfig cfg = mCanvas->snappingUtils()->config();
397 cfg.setMode( QgsSnappingConfig::AllLayers );
398 cfg.setTolerance( 10 );
399 cfg.setTypeFlag( static_cast<QgsSnappingConfig::SnappingTypeFlag>( QgsSnappingConfig::VertexFlag | QgsSnappingConfig::SegmentFlag ) );
400 cfg.setIntersectionSnapping( true );
401 cfg.setEnabled( true );
402 mCanvas->snappingUtils()->setConfig( cfg );
403
404 mouseClick( 5, 5.5, Qt::LeftButton, Qt::KeyboardModifiers(), true );
405 mouseClick( 5.5, 5.5, Qt::LeftButton, Qt::KeyboardModifiers(), true );
406
407 // The undo stack gets two entries, one for the vertex move and one for the topological point
408 QCOMPARE( mLayerLineZ->undoStack()->index(), 5 );
409 QCOMPARE( mLayerLineZ->getFeature( mFidLineZF1 ).geometry().asWkt(), QString( "LineStringZ (5 5 1, 5.5 5.5 333, 6 6 1, 7 5 1)" ) );
410 QCOMPARE( mLayerLineZ->getFeature( mFidLineZF3 ).geometry().asWkt(), QString( "LineStringZ (5.5 5.5 5, 7 5.5 10)" ) );
411
412 QgsProject::instance()->setTopologicalEditing( topologicalEditing );
413 // Two undo steps, one for the vertex move, one for the topological point
414 mLayerLineZ->undoStack()->undo();
415 mLayerLineZ->undoStack()->undo();
416 cfg.setEnabled( false );
417 mCanvas->snappingUtils()->setConfig( cfg );
418 }
419
testMoveVertex()420 void TestQgsVertexTool::testMoveVertex()
421 {
422 QCOMPARE( mCanvas->mapSettings().outputSize(), QSize( 512, 512 ) );
423 QCOMPARE( mCanvas->mapSettings().visibleExtent(), QgsRectangle( 0, 0, 8, 8 ) );
424
425 // move vertex of linestring
426
427 mouseClick( 2, 1, Qt::LeftButton );
428 mouseClick( 2, 2, Qt::LeftButton );
429
430 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
431 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 2, 1 1, 1 3)" ) );
432
433 mLayerLine->undoStack()->undo();
434 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
435
436 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
437
438 mouseClick( 1, 1, Qt::LeftButton );
439 mouseClick( 0.5, 0.5, Qt::LeftButton );
440
441 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
442 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 0.5 0.5, 1 3)" ) );
443
444 mLayerLine->undoStack()->undo();
445
446 // move point
447
448 mouseClick( 2, 3, Qt::LeftButton );
449 mouseClick( 1, 4, Qt::LeftButton );
450
451 QCOMPARE( mLayerPoint->undoStack()->index(), 2 );
452 QCOMPARE( mLayerPoint->getFeature( mFidPointF1 ).geometry(), QgsGeometry::fromWkt( "POINT(1 4)" ) );
453
454 mLayerPoint->undoStack()->undo();
455
456 QCOMPARE( mLayerPoint->getFeature( mFidPointF1 ).geometry(), QgsGeometry::fromWkt( "POINT(2 3)" ) );
457
458 // move vertex of polygon
459
460 mouseClick( 4, 1, Qt::LeftButton );
461 mouseClick( 5, 2, Qt::LeftButton );
462
463 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
464 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((5 2, 7 1, 7 4, 4 4, 5 2))" ) );
465
466 mLayerPolygon->undoStack()->undo();
467
468 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
469
470 mouseClick( 4, 4, Qt::LeftButton );
471 mouseClick( 5, 5, Qt::LeftButton );
472
473 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
474 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 5 5, 4 1))" ) );
475
476 mLayerPolygon->undoStack()->undo();
477
478 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
479
480 // cancel moving of a linestring with right mouse button
481 mouseClick( 2, 1, Qt::LeftButton );
482 mouseClick( 2, 2, Qt::RightButton );
483
484 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
485 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
486
487 // clicks somewhere away from features - should do nothing
488 mouseClick( 2, 2, Qt::LeftButton );
489 mouseClick( 2, 4, Qt::LeftButton );
490
491 // no other unexpected changes happened
492 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
493 QCOMPARE( mLayerPolygon->undoStack()->index(), 1 );
494 QCOMPARE( mLayerPoint->undoStack()->index(), 1 );
495 }
496
testMoveEdge()497 void TestQgsVertexTool::testMoveEdge()
498 {
499 // move edge of linestring
500
501 mouseClick( 1.2, 1, Qt::LeftButton );
502 mouseClick( 1.2, 2, Qt::LeftButton );
503
504 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
505 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 2, 1 2, 1 3)" ) );
506
507 mLayerLine->undoStack()->undo();
508 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
509
510 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
511
512 // move edge of polygon
513
514 mouseClick( 5, 1, Qt::LeftButton );
515 mouseClick( 6, 1, Qt::LeftButton );
516
517 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
518 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((5 1, 8 1, 7 4, 4 4, 5 1))" ) );
519
520 mLayerPolygon->undoStack()->undo();
521
522 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
523
524 // no other unexpected changes happened
525 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
526 QCOMPARE( mLayerPolygon->undoStack()->index(), 1 );
527 QCOMPARE( mLayerPoint->undoStack()->index(), 1 );
528 }
529
testAddVertex()530 void TestQgsVertexTool::testAddVertex()
531 {
532 // add vertex in linestring
533
534 mouseClick( 1.5, 1, Qt::LeftButton );
535 mouseClick( 1.5, 2, Qt::LeftButton );
536
537 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
538 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1.5 2, 1 1, 1 3)" ) );
539
540 mLayerLine->undoStack()->undo();
541 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
542
543 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
544
545 // add vertex in polygon
546
547 mouseClick( 4, 2.5, Qt::LeftButton );
548 mouseClick( 3, 2.5, Qt::LeftButton );
549
550 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
551 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 3 2.5, 4 1))" ) );
552
553 mLayerPolygon->undoStack()->undo();
554
555 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
556
557 // no other unexpected changes happened
558 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
559 QCOMPARE( mLayerPolygon->undoStack()->index(), 1 );
560 QCOMPARE( mLayerPoint->undoStack()->index(), 1 );
561 }
562
testAddVertexAtEndpoint()563 void TestQgsVertexTool::testAddVertexAtEndpoint()
564 {
565 // offset of the endpoint marker - currently set as 15px away from the last vertex in direction of the line
566 const double offsetInMapUnits = 15 * mCanvas->mapSettings().mapUnitsPerPixel();
567
568 // add vertex at the end
569 // for polyline
570 mouseMove( 1, 3 ); // first we need to move to the vertex
571 mouseClick( 1, 3 + offsetInMapUnits, Qt::LeftButton );
572 mouseClick( 2, 3, Qt::LeftButton );
573 mouseClick( 2, 3, Qt::RightButton ); // we need a right click to stop adding new nodes
574
575 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
576 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3, 2 3)" ) );
577
578 mLayerLine->undoStack()->undo();
579 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
580
581 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
582
583 // add vertex at the start
584
585 mouseMove( 2, 1 ); // first we need to move to the vertex
586 mouseClick( 2 + offsetInMapUnits, 1, Qt::LeftButton );
587 mouseClick( 2, 2, Qt::LeftButton );
588 mouseClick( 2, 2, Qt::RightButton ); // we need a right click to stop adding new nodes
589
590 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
591 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 2, 2 1, 1 1, 1 3)" ) );
592
593 mLayerLine->undoStack()->undo();
594 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
595
596 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
597
598 // add three vertices at once
599
600 mouseMove( 2, 1 ); // first we need to move to the vertex
601 mouseClick( 2 + offsetInMapUnits, 1, Qt::LeftButton );
602 mouseClick( 2, 2, Qt::LeftButton );
603 mouseClick( 2, 3, Qt::LeftButton );
604 mouseClick( 2, 4, Qt::LeftButton );
605 mouseClick( 2, 2, Qt::RightButton ); // we need a right click to stop adding new nodes
606
607 QCOMPARE( mLayerLine->undoStack()->index(), 4 );
608 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 4, 2 3, 2 2, 2 1, 1 1, 1 3)" ) );
609
610 mLayerLine->undoStack()->undo();
611 mLayerLine->undoStack()->undo();
612 mLayerLine->undoStack()->undo();
613 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
614
615 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
616
617 }
618
testAddVertexDoubleClick()619 void TestQgsVertexTool::testAddVertexDoubleClick()
620 {
621 // add vertex in linestring with double-click and then place the point to the new location
622
623 mouseDoubleClick( 1, 1.5, Qt::LeftButton );
624 mouseClick( 2, 2, Qt::LeftButton );
625
626 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
627 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 2 2, 1 3)" ) );
628
629 mLayerLine->undoStack()->undo();
630 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
631
632 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
633
634 // add vertex in polygon
635 mouseDoubleClick( 4, 2, Qt::LeftButton );
636 mouseClick( 3, 2.5, Qt::LeftButton );
637
638 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
639 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 3 2.5, 4 1))" ) );
640
641 mLayerPolygon->undoStack()->undo();
642
643 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
644
645 // no other unexpected changes happened
646 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
647 QCOMPARE( mLayerPolygon->undoStack()->index(), 1 );
648 QCOMPARE( mLayerPoint->undoStack()->index(), 1 );
649
650 }
651
testAddVertexDoubleClickWithShift()652 void TestQgsVertexTool::testAddVertexDoubleClickWithShift()
653 {
654 // add vertex in linestring with shift + double-click to immediately place the new vertex
655
656 mouseDoubleClick( 1, 1.5, Qt::LeftButton, Qt::ShiftModifier );
657
658 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
659 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 1.5, 1 3)" ) );
660
661 mLayerLine->undoStack()->undo();
662 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
663
664 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
665
666 // add vertex in polygon
667 mouseDoubleClick( 4, 2, Qt::LeftButton, Qt::ShiftModifier );
668
669 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
670 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 2, 4 1))" ) );
671
672 mLayerPolygon->undoStack()->undo();
673
674 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
675
676 // no other unexpected changes happened
677 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
678 QCOMPARE( mLayerPolygon->undoStack()->index(), 1 );
679 QCOMPARE( mLayerPoint->undoStack()->index(), 1 );
680
681 }
682
testDeleteVertex()683 void TestQgsVertexTool::testDeleteVertex()
684 {
685 // delete vertex in linestring
686
687 mouseClick( 1, 1, Qt::LeftButton );
688 keyClick( Qt::Key_Delete );
689
690 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
691 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 3)" ) );
692
693 mLayerLine->undoStack()->undo();
694 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
695
696 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
697
698 // delete vertex in polygon
699
700 mouseClick( 7, 4, Qt::LeftButton );
701 keyClick( Qt::Key_Delete );
702
703 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
704 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 4 4, 4 1))" ) );
705
706 mLayerPolygon->undoStack()->undo();
707
708 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
709
710 // delete vertex in point - deleting its geometry
711
712 mouseClick( 2, 3, Qt::LeftButton );
713 keyClick( Qt::Key_Delete );
714
715 QCOMPARE( mLayerPoint->undoStack()->index(), 2 );
716 QCOMPARE( mLayerPoint->getFeature( mFidPointF1 ).geometry(), QgsGeometry() );
717
718 mLayerPoint->undoStack()->undo();
719
720 QCOMPARE( mLayerPoint->getFeature( mFidPointF1 ).geometry(), QgsGeometry::fromWkt( "POINT(2 3)" ) );
721
722 // delete a vertex by dragging a selection rect
723
724 mousePress( 0.5, 2.5, Qt::LeftButton );
725 mouseMove( 1.5, 3.5 );
726 mouseRelease( 1.5, 3.5, Qt::LeftButton );
727 keyClick( Qt::Key_Delete );
728
729 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
730 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1)" ) );
731
732 mLayerLine->undoStack()->undo();
733 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
734
735 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
736
737 // delete multiline part by dragging
738
739 mousePress( 2.5, 0.5, Qt::LeftButton );
740 mouseMove( 3.5, 2.5 );
741 mouseRelease( 3.5, 2.5, Qt::LeftButton );
742 keyClick( Qt::Key_Delete );
743
744 QCOMPARE( mLayerMultiLine->undoStack()->index(), 2 );
745 QCOMPARE( mLayerMultiLine->getFeature( mFidMultiLineF1 ).geometry(), QgsGeometry::fromWkt( "MultiLineString ((3 3, 3 4))" ) );
746
747 mLayerMultiLine->undoStack()->undo();
748 QCOMPARE( mLayerMultiLine->undoStack()->index(), 1 );
749
750 // delete multiline part by dragging and leaving only one vertex to the part
751
752 mousePress( 2.5, 0.5, Qt::LeftButton );
753 mouseMove( 3.5, 1.5 );
754 mouseRelease( 3.5, 1.5, Qt::LeftButton );
755 keyClick( Qt::Key_Delete );
756
757 QCOMPARE( mLayerMultiLine->undoStack()->index(), 2 );
758 QCOMPARE( mLayerMultiLine->getFeature( mFidMultiLineF1 ).geometry(), QgsGeometry::fromWkt( "MultiLineString ((3 3, 3 4))" ) );
759
760 mLayerMultiLine->undoStack()->undo();
761 QCOMPARE( mLayerMultiLine->undoStack()->index(), 1 );
762
763 // delete inner ring by dragging
764
765 mousePress( 1.1, 5.1, Qt::LeftButton );
766 mouseMove( 1.8, 6.2 );
767 mouseRelease( 1.8, 6.2, Qt::LeftButton );
768 keyClick( Qt::Key_Delete );
769
770 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 2 );
771 QCOMPARE( mLayerMultiPolygon->getFeature( mFidMultiPolygonF1 ).geometry(), QgsGeometry::fromWkt( "MultiPolygon (((1 5, 2 5, 2 6.5, 2 8, 1 8, 1 6.5, 1 5),(1.25 7, 1.75 7, 1.75 7.5, 1.25 7.5, 1.25 7)),((3 5, 3 6.5, 3 8, 4 8, 4 6.5, 4 5, 3 5),(3.25 5.5, 3.75 5.5, 3.75 6, 3.25 6, 3.25 5.5),(3.25 7, 3.75 7, 3.75 7.5, 3.25 7.5, 3.25 7)))" ) );
772
773 mLayerMultiPolygon->undoStack()->undo();
774 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 1 );
775
776 // delete inner ring by dragging and leaving less than 4 vertices to the ring
777
778 mousePress( 1.1, 5.1, Qt::LeftButton );
779 mouseMove( 1.8, 5.7 );
780 mouseRelease( 1.8, 5.7, Qt::LeftButton );
781 keyClick( Qt::Key_Delete );
782
783 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 2 );
784 QCOMPARE( mLayerMultiPolygon->getFeature( mFidMultiPolygonF1 ).geometry(), QgsGeometry::fromWkt( "MultiPolygon (((1 5, 2 5, 2 6.5, 2 8, 1 8, 1 6.5, 1 5),(1.25 7, 1.75 7, 1.75 7.5, 1.25 7.5, 1.25 7)),((3 5, 3 6.5, 3 8, 4 8, 4 6.5, 4 5, 3 5),(3.25 5.5, 3.75 5.5, 3.75 6, 3.25 6, 3.25 5.5),(3.25 7, 3.75 7, 3.75 7.5, 3.25 7.5, 3.25 7)))" ) );
785
786 mLayerMultiPolygon->undoStack()->undo();
787 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 1 );
788
789 // delete part and rings by dragging
790
791 mousePress( 0.5, 4.5, Qt::LeftButton );
792 mouseMove( 2.5, 8.5 );
793 mouseRelease( 2.5, 8.5, Qt::LeftButton );
794 keyClick( Qt::Key_Delete );
795
796 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 2 );
797 QCOMPARE( mLayerMultiPolygon->getFeature( mFidMultiPolygonF1 ).geometry(), QgsGeometry::fromWkt( "MultiPolygon (((3 5, 3 6.5, 3 8, 4 8, 4 6.5, 4 5, 3 5),(3.25 5.5, 3.75 5.5, 3.75 6, 3.25 6, 3.25 5.5),(3.25 7, 3.75 7, 3.75 7.5, 3.25 7.5, 3.25 7)))" ) );
798
799 mLayerMultiPolygon->undoStack()->undo();
800 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 1 );
801
802 // combined delete rings from different parts by dragging
803
804 mousePress( 0.5, 4.5, Qt::LeftButton );
805 mouseMove( 4.5, 6.2 );
806 mouseRelease( 4.5, 6.2, Qt::LeftButton );
807 keyClick( Qt::Key_Delete );
808
809 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 2 );
810 QCOMPARE( mLayerMultiPolygon->getFeature( mFidMultiPolygonF1 ).geometry(), QgsGeometry::fromWkt( "MultiPolygon (((1 6.5, 2 6.5, 2 8, 1 8, 1 6.5),(1.25 7, 1.75 7, 1.75 7.5, 1.25 7.5, 1.25 7)),((4 6.5, 3 6.5, 3 8, 4 8, 4 6.5),(3.25 7, 3.75 7, 3.75 7.5, 3.25 7.5, 3.25 7)))" ) );
811
812 mLayerMultiPolygon->undoStack()->undo();
813 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 1 );
814
815 // no other unexpected changes happened
816 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
817 QCOMPARE( mLayerPolygon->undoStack()->index(), 1 );
818 QCOMPARE( mLayerPoint->undoStack()->index(), 1 );
819 }
820
821
testConvertVertex()822 void TestQgsVertexTool::testConvertVertex()
823 {
824 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 2 );
825
826 // convert vertex in compoundCurve while moving vertex
827 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF1 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ( CircularString (14 14, 10 10, 17 10))" ) );
828 mouseClick( 10, 10, Qt::LeftButton );
829 keyClick( Qt::Key_O );
830 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 3 );
831 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF1 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ((14 14, 10 10, 17 10))" ) );
832 mLayerCompoundCurve->undoStack()->undo();
833 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 2 );
834 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF1 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ( CircularString (14 14, 10 10, 17 10))" ) );
835
836 // convert vertex in compoundCurve by selection
837 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF1 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ( CircularString (14 14, 10 10, 17 10))" ) );
838 mousePress( 9.5, 9.5, Qt::LeftButton );
839 mouseMove( 10.5, 10.5 );
840 mouseRelease( 10.5, 10.5, Qt::LeftButton );
841 keyClick( Qt::Key_O );
842 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 3 );
843 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF1 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ((14 14, 10 10, 17 10))" ) );
844 mLayerCompoundCurve->undoStack()->undo();
845 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 2 );
846 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF1 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ( CircularString (14 14, 10 10, 17 10))" ) );
847 }
848
testMoveMultipleVertices()849 void TestQgsVertexTool::testMoveMultipleVertices()
850 {
851 // select two vertices
852 mousePress( 0.5, 0.5, Qt::LeftButton );
853 mouseMove( 1.5, 3.5 );
854 mouseRelease( 1.5, 3.5, Qt::LeftButton );
855
856 // move them by -1,-1
857 mouseClick( 1, 1, Qt::LeftButton );
858 mouseClick( 0, 0, Qt::LeftButton );
859
860 // extra click away from everything to clear the selection
861 mouseClick( 8, 8, Qt::LeftButton );
862
863 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
864 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 0 0, 0 2)" ) );
865
866 mLayerLine->undoStack()->undo();
867 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
868
869 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
870
871 QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-841256 6405990, -841259 6405988)" ) );
872 mLayerLineReprojected->undoStack()->undo();
873 QCOMPARE( mLayerLineReprojected->getFeature( mFidLineF13857 ).geometry().asWkt( 0 ), QStringLiteral( "LineString (-841256 6405990, -841258 6405990)" ) );
874 }
875
testMoveMultipleVertices2()876 void TestQgsVertexTool::testMoveMultipleVertices2()
877 {
878 // this time select two vertices with shift
879 mouseClick( 1, 1, Qt::LeftButton, Qt::ShiftModifier );
880 mouseClick( 2, 1, Qt::LeftButton, Qt::ShiftModifier );
881
882 // move them by +1, +1
883 mouseClick( 1, 1, Qt::LeftButton );
884 mouseClick( 2, 2, Qt::LeftButton );
885
886 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
887 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(3 2, 2 2, 1 3)" ) );
888
889 mLayerLine->undoStack()->undo();
890 QCOMPARE( mLayerLine->undoStack()->index(), 1 );
891
892 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
893 }
894
testMoveVertexTopo()895 void TestQgsVertexTool::testMoveVertexTopo()
896 {
897 // test moving of vertices of two features at once
898
899 QgsProject::instance()->setTopologicalEditing( true );
900
901 // connect linestring with polygon at point (2, 1)
902 mouseClick( 4, 1, Qt::LeftButton );
903 mouseClick( 2, 1, Qt::LeftButton );
904
905 // move shared vertex of linestring and polygon
906 mouseClick( 2, 1, Qt::LeftButton );
907 mouseClick( 3, 3, Qt::LeftButton );
908
909 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(3 3, 1 1, 1 3)" ) );
910 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((3 3, 7 1, 7 4, 4 4, 3 3))" ) );
911
912 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
913 QCOMPARE( mLayerPolygon->undoStack()->index(), 3 ); // one more move of vertex from earlier
914 mLayerLine->undoStack()->undo();
915 mLayerPolygon->undoStack()->undo();
916 mLayerPolygon->undoStack()->undo();
917
918 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
919 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
920
921 QgsProject::instance()->setTopologicalEditing( false );
922 }
923
testDeleteVertexTopo()924 void TestQgsVertexTool::testDeleteVertexTopo()
925 {
926 // test deletion of vertices with topological editing enabled
927
928 QgsProject::instance()->setTopologicalEditing( true );
929
930 // connect linestring with polygon at point (2, 1)
931 mouseClick( 4, 1, Qt::LeftButton );
932 mouseClick( 2, 1, Qt::LeftButton );
933
934 // move shared vertex of linestring and polygon
935 mouseClick( 2, 1, Qt::LeftButton );
936 keyClick( Qt::Key_Delete );
937
938 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(1 1, 1 3)" ) );
939 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((7 1, 7 4, 4 4, 7 1))" ) );
940
941 QCOMPARE( mLayerLine->undoStack()->index(), 2 );
942 QCOMPARE( mLayerPolygon->undoStack()->index(), 3 ); // one more move of vertex from earlier
943 mLayerLine->undoStack()->undo();
944 mLayerPolygon->undoStack()->undo();
945 mLayerPolygon->undoStack()->undo();
946
947 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
948 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
949
950 QgsProject::instance()->setTopologicalEditing( false );
951 }
952
testAddVertexTopo()953 void TestQgsVertexTool::testAddVertexTopo()
954 {
955 // test addition of a vertex on a segment shared with another geometry
956
957 // add a temporary polygon
958 QgsFeature fTmp;
959 fTmp.setGeometry( QgsGeometry::fromWkt( "POLYGON((4 4, 7 4, 7 6, 4 6, 4 4))" ) );
960 const bool resAdd = mLayerPolygon->addFeature( fTmp );
961 QVERIFY( resAdd );
962 const QgsFeatureId fTmpId = fTmp.id();
963
964 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
965
966 QgsProject::instance()->setTopologicalEditing( true );
967
968 mouseClick( 5.5, 4, Qt::LeftButton );
969 mouseClick( 5, 5, Qt::LeftButton );
970
971 QCOMPARE( mLayerPolygon->undoStack()->index(), 3 );
972
973 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 5 5, 4 4, 4 1))" ) );
974 QCOMPARE( mLayerPolygon->getFeature( fTmpId ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 4, 5 5, 7 4, 7 6, 4 6, 4 4))" ) );
975
976 mLayerPolygon->undoStack()->undo();
977 mLayerPolygon->undoStack()->undo();
978
979 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
980
981 QgsProject::instance()->setTopologicalEditing( false );
982 }
983
testMoveEdgeTopo()984 void TestQgsVertexTool::testMoveEdgeTopo()
985 {
986 // test move of an edge shared with another feature
987
988 // add a temporary polygon
989 QgsFeature fTmp;
990 fTmp.setGeometry( QgsGeometry::fromWkt( "POLYGON((4 4, 7 4, 7 6, 4 6, 4 4))" ) );
991 const bool resAdd = mLayerPolygon->addFeature( fTmp );
992 QVERIFY( resAdd );
993 const QgsFeatureId fTmpId = fTmp.id();
994
995 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
996
997 QgsProject::instance()->setTopologicalEditing( true );
998
999 // move shared segment
1000 mouseClick( 6, 4, Qt::LeftButton );
1001 mouseClick( 6, 5, Qt::LeftButton );
1002
1003 QCOMPARE( mLayerPolygon->undoStack()->index(), 3 );
1004
1005 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 5, 4 5, 4 1))" ) );
1006 QCOMPARE( mLayerPolygon->getFeature( fTmpId ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 5, 7 5, 7 6, 4 6, 4 5))" ) );
1007
1008 mLayerPolygon->undoStack()->undo();
1009
1010 // another test to move a shared segment - but this time we just pick two individual points of a feature
1011 // and do vertex move
1012
1013 QgsProject::instance()->setTopologicalEditing( false );
1014
1015 // this time select two vertices with shift
1016 mouseClick( 4, 4, Qt::LeftButton, Qt::ShiftModifier );
1017 mouseClick( 7, 4, Qt::LeftButton, Qt::ShiftModifier );
1018
1019 QgsProject::instance()->setTopologicalEditing( true );
1020
1021 // now move the shared segment
1022 mouseClick( 4, 4, Qt::LeftButton );
1023 mouseClick( 4, 3, Qt::LeftButton );
1024
1025 QCOMPARE( mLayerPolygon->undoStack()->index(), 3 );
1026
1027 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 3, 4 3, 4 1))" ) );
1028 QCOMPARE( mLayerPolygon->getFeature( fTmpId ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 3, 7 3, 7 6, 4 6, 4 3))" ) );
1029
1030 mLayerPolygon->undoStack()->undo();
1031
1032 //
1033
1034 mLayerPolygon->undoStack()->undo();
1035
1036 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
1037
1038 QgsProject::instance()->setTopologicalEditing( false );
1039 }
1040
testAddVertexTopoFirstSegment()1041 void TestQgsVertexTool::testAddVertexTopoFirstSegment()
1042 {
1043 // check that when adding a vertex to the first segment of a polygon's ring with topo editing
1044 // enabled, the geometry does not get corrupted (#20774)
1045
1046 QgsProject::instance()->setTopologicalEditing( true );
1047
1048 mouseClick( 5.5, 1, Qt::LeftButton );
1049 mouseClick( 5, 2, Qt::LeftButton );
1050
1051 QCOMPARE( mLayerPolygon->undoStack()->index(), 2 );
1052
1053 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 5 2, 7 1, 7 4, 4 4, 4 1))" ) );
1054
1055 mLayerPolygon->undoStack()->undo();
1056
1057 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
1058
1059 QgsProject::instance()->setTopologicalEditing( false );
1060 }
1061
testAvoidIntersections()1062 void TestQgsVertexTool::testAvoidIntersections()
1063 {
1064 // check that when adding a vertex to the first segment of a polygon's ring with topo editing
1065 // enabled, the geometry does not get corrupted (#20774)
1066
1067 QgsProject::instance()->setTopologicalEditing( true );
1068 const QgsProject::AvoidIntersectionsMode mode( QgsProject::instance()->avoidIntersectionsMode() );
1069 QgsProject::instance()->setAvoidIntersectionsMode( QgsProject::AvoidIntersectionsMode::AvoidIntersectionsCurrentLayer );
1070
1071 QgsPolygonXY polygon2;
1072 QgsPolylineXY polygon2exterior;
1073 polygon2exterior << QgsPointXY( 8, 2 ) << QgsPointXY( 9, 2 ) << QgsPointXY( 9, 3 ) << QgsPointXY( 8, 3 ) << QgsPointXY( 8, 2 );
1074 polygon2 << polygon2exterior;
1075 QgsFeature polygonF2;
1076 polygonF2.setGeometry( QgsGeometry::fromPolygonXY( polygon2 ) );
1077
1078 mLayerPolygon->addFeature( polygonF2 );
1079 const QgsFeatureId mFidPolygonF2 = polygonF2.id();
1080 QCOMPARE( mLayerPolygon->featureCount(), ( long )2 );
1081
1082 mouseClick( 7, 1, Qt::LeftButton );
1083 mouseClick( 9, 2, Qt::LeftButton );
1084
1085 QCOMPARE( mLayerPolygon->undoStack()->index(), 3 );
1086
1087 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
1088 QCOMPARE( QgsGeometry::fromWkt( mLayerPolygon->getFeature( mFidPolygonF2 ).geometry().asWkt( 1 ) ), QgsGeometry::fromWkt( "Polygon ((8 2, 9 2, 9 3, 8 3, 8 2))" ) );
1089
1090 mLayerPolygon->undoStack()->undo();
1091
1092 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
1093
1094 // Move polygons and check that geometry are not avoided
1095 // select polygons
1096 mousePress( 3, 5, Qt::LeftButton );
1097 mouseMove( 9.5, 0.5 );
1098 mouseRelease( 9.5, 0.5, Qt::LeftButton );
1099
1100 // move polygons
1101 mouseClick( 8, 2, Qt::LeftButton );
1102 mouseClick( 5, 2, Qt::LeftButton );
1103
1104 QCOMPARE( QgsGeometry::fromWkt( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry().asWkt( 1 ) ), QgsGeometry::fromWkt( "Polygon ((1 1, 4 1, 4 4, 1 4, 1 1))" ) );
1105 QCOMPARE( QgsGeometry::fromWkt( mLayerPolygon->getFeature( mFidPolygonF2 ).geometry().asWkt( 1 ) ), QgsGeometry::fromWkt( "Polygon ((5 2, 6 2, 6 3, 5 3, 5 2))" ) );
1106
1107 mLayerPolygon->undoStack()->undo();
1108 mLayerPolygon->undoStack()->undo(); // delete feature
1109
1110 QCOMPARE( mLayerPolygon->featureCount(), ( long )1 );
1111 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((4 1, 7 1, 7 4, 4 4, 4 1))" ) );
1112
1113 // If topologicalEditing and avoidIntersections are activated we must take care that the topological points are well added.
1114 QgsPolygonXY polygon_topo1;
1115 QgsPolylineXY polygon_topo1exterior;
1116 polygon_topo1exterior << QgsPointXY( 0, 10 ) << QgsPointXY( 0, 20 ) << QgsPointXY( 5, 15 ) << QgsPointXY( 0, 10 );
1117 polygon_topo1 << polygon_topo1exterior;
1118 QgsFeature polygonF_topo1;
1119 polygonF_topo1.setGeometry( QgsGeometry::fromPolygonXY( polygon_topo1 ) );
1120
1121 mLayerPolygon->addFeature( polygonF_topo1 );
1122 const QgsFeatureId mFidPolygonF_topo1 = polygonF_topo1.id();
1123
1124 QgsPolygonXY polygon_topo2;
1125 QgsPolylineXY polygon_topo2exterior;
1126 polygon_topo2exterior << QgsPointXY( 10, 15 ) << QgsPointXY( 15, 10 ) << QgsPointXY( 15, 20 ) << QgsPointXY( 10, 15 );
1127 polygon_topo2 << polygon_topo2exterior;
1128 QgsFeature polygonF_topo2;
1129 polygonF_topo2.setGeometry( QgsGeometry::fromPolygonXY( polygon_topo2 ) );
1130
1131 mLayerPolygon->addFeature( polygonF_topo2 );
1132 const QgsFeatureId mFidPolygonF_topo2 = polygonF_topo2.id();
1133
1134 QCOMPARE( mLayerPolygon->featureCount(), ( long )3 );
1135
1136 mouseClick( 5, 15, Qt::LeftButton );
1137 mouseClick( 12.5, 15, Qt::LeftButton );
1138
1139 if ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR < 9 )
1140 {
1141 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF_topo1 ).geometry().asWkt( 1 ), "Polygon ((0 10, 0 20, 10.7 15.7, 10 15, 10.7 14.3, 0 10))" );
1142 }
1143 else
1144 {
1145 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF_topo1 ).geometry().asWkt( 1 ), "Polygon ((0 20, 10.7 15.7, 10 15, 10.7 14.3, 0 10, 0 20))" );
1146 }
1147 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF_topo2 ).geometry().asWkt( 1 ), "Polygon ((10 15, 10.7 14.3, 15 10, 15 20, 10.7 15.7, 10 15))" );
1148
1149 mLayerPolygon->undoStack()->undo(); // undo topological points
1150 mLayerPolygon->undoStack()->undo(); // undo move
1151 mLayerPolygon->undoStack()->undo(); // delete feature polygonF_topo2
1152 mLayerPolygon->undoStack()->undo(); // delete feature polygonF_topo1
1153 QCOMPARE( mLayerPolygon->featureCount(), ( long )1 );
1154
1155
1156 QgsProject::instance()->setTopologicalEditing( false );
1157 QgsProject::instance()->setAvoidIntersectionsMode( mode );
1158 }
testActiveLayerPriority()1159 void TestQgsVertexTool::testActiveLayerPriority()
1160 {
1161 // check that features from current layer get priority when picking points
1162
1163 // create a temporary line layer that has a common vertex with existing line layer at (1, 1)
1164 QgsVectorLayer *layerLine2 = new QgsVectorLayer( QStringLiteral( "LineString?crs=EPSG:27700" ), QStringLiteral( "layer line 2" ), QStringLiteral( "memory" ) );
1165 QVERIFY( layerLine2->isValid() );
1166 QgsPolylineXY line1;
1167 line1 << QgsPointXY( 0, 1 ) << QgsPointXY( 1, 1 ) << QgsPointXY( 1, 0 );
1168 QgsFeature lineF1;
1169 lineF1.setGeometry( QgsGeometry::fromPolylineXY( line1 ) );
1170 layerLine2->startEditing();
1171 layerLine2->addFeature( lineF1 );
1172 const QgsFeatureId fidLineF1 = lineF1.id();
1173 QCOMPARE( layerLine2->featureCount(), ( long )1 );
1174 QgsProject::instance()->addMapLayer( layerLine2 );
1175 mCanvas->setLayers( QList<QgsMapLayer *>() << mLayerLine << mLayerPolygon << mLayerPoint << mLayerCompoundCurve << layerLine2 );
1176
1177 // make one layer active and check its vertex is used
1178
1179 mCanvas->snappingUtils()->locatorForLayer( layerLine2 )->init();
1180
1181 mCanvas->setCurrentLayer( mLayerLine );
1182
1183 mouseClick( 1, 1, Qt::LeftButton );
1184 mouseClick( 0, 0, Qt::LeftButton );
1185
1186 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 0 0, 1 3)" ) );
1187 QCOMPARE( layerLine2->getFeature( fidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(0 1, 1 1, 1 0)" ) );
1188 mLayerLine->undoStack()->undo();
1189
1190 // make the other layer active and check its vertex is used
1191
1192 mCanvas->setCurrentLayer( layerLine2 );
1193
1194 mouseClick( 1, 1, Qt::LeftButton );
1195 mouseClick( 0, 0, Qt::LeftButton );
1196
1197 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
1198 QCOMPARE( layerLine2->getFeature( fidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(0 1, 0 0, 1 0)" ) );
1199 layerLine2->undoStack()->undo();
1200
1201 mCanvas->setCurrentLayer( nullptr );
1202
1203 // get rid of the temporary layer
1204 mCanvas->setLayers( QList<QgsMapLayer *>() << mLayerLine << mLayerPolygon << mLayerPoint << mLayerCompoundCurve );
1205 QgsProject::instance()->removeMapLayer( layerLine2 );
1206 }
1207
testSelectedFeaturesPriority()1208 void TestQgsVertexTool::testSelectedFeaturesPriority()
1209 {
1210 // preparation: make the polygon feature touch line feature
1211 mouseClick( 4, 1, Qt::LeftButton );
1212 mouseClick( 2, 1, Qt::LeftButton );
1213
1214 //
1215 // test that clicking a location with selected and non-selected feature will always pick the selected feature
1216 //
1217
1218 mLayerLine->selectByIds( QgsFeatureIds() << mFidLineF1 );
1219 mLayerPolygon->selectByIds( QgsFeatureIds() );
1220
1221 mouseClick( 2, 1, Qt::LeftButton );
1222 mouseClick( 3, 1, Qt::LeftButton );
1223
1224 // check that move of (2,1) to (3,1) affects only line layer
1225 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(3 1, 1 1, 1 3)" ) );
1226 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((2 1, 7 1, 7 4, 4 4, 2 1))" ) );
1227 mLayerLine->undoStack()->undo();
1228
1229 mLayerLine->selectByIds( QgsFeatureIds() );
1230 mLayerPolygon->selectByIds( QgsFeatureIds() << mFidPolygonF1 );
1231
1232 mouseClick( 2, 1, Qt::LeftButton );
1233 mouseClick( 3, 1, Qt::LeftButton );
1234
1235 // check that move of (2,1) to (3,1) affects only polygon layer
1236 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
1237 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((3 1, 7 1, 7 4, 4 4, 3 1))" ) );
1238 mLayerPolygon->undoStack()->undo();
1239
1240 //
1241 // test that dragging rectangle to pick vertices in location with selected and non-selected feature
1242 // will always pick vertices only from the selected feature
1243 //
1244
1245 mLayerLine->selectByIds( QgsFeatureIds() );
1246 mLayerPolygon->selectByIds( QgsFeatureIds() );
1247
1248 mousePress( 1.5, 0.5, Qt::LeftButton );
1249 mouseMove( 2.5, 1.5 );
1250 mouseRelease( 2.5, 1.5, Qt::LeftButton );
1251 keyClick( Qt::Key_Delete );
1252
1253 // check we have deleted vertex at (2,1) from both line and polygon features
1254 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(1 1, 1 3)" ) );
1255 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((7 1, 7 4, 4 4, 7 1))" ) );
1256 mLayerLine->undoStack()->undo();
1257 mLayerPolygon->undoStack()->undo();
1258
1259 mLayerLine->selectByIds( QgsFeatureIds() << mFidLineF1 );
1260 mLayerPolygon->selectByIds( QgsFeatureIds() );
1261
1262 mousePress( 1.5, 0.5, Qt::LeftButton );
1263 mouseMove( 2.5, 1.5 );
1264 mouseRelease( 2.5, 1.5, Qt::LeftButton );
1265 keyClick( Qt::Key_Delete );
1266
1267 // check we have deleted vertex at (2,1) just from line feature
1268 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(1 1, 1 3)" ) );
1269 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((2 1, 7 1, 7 4, 4 4, 2 1))" ) );
1270 mLayerLine->undoStack()->undo();
1271
1272 mLayerLine->selectByIds( QgsFeatureIds() );
1273 mLayerPolygon->selectByIds( QgsFeatureIds() << mFidPolygonF1 );
1274
1275 mousePress( 1.5, 0.5, Qt::LeftButton );
1276 mouseMove( 2.5, 1.5 );
1277 mouseRelease( 2.5, 1.5, Qt::LeftButton );
1278 keyClick( Qt::Key_Delete );
1279
1280 // check we have deleted vertex at (2,1) just from polygon feature
1281 QCOMPARE( mLayerLine->getFeature( mFidLineF1 ).geometry(), QgsGeometry::fromWkt( "LINESTRING(2 1, 1 1, 1 3)" ) );
1282 QCOMPARE( mLayerPolygon->getFeature( mFidPolygonF1 ).geometry(), QgsGeometry::fromWkt( "POLYGON((7 1, 7 4, 4 4, 7 1))" ) );
1283 mLayerPolygon->undoStack()->undo();
1284
1285 mLayerPolygon->undoStack()->undo(); // undo the initial change
1286 }
1287
testVertexToolCompoundCurve()1288 void TestQgsVertexTool::testVertexToolCompoundCurve()
1289 {
1290 // move vertex on CompoundCurve layer
1291 // for curve
1292 mouseClick( 10, 10, Qt::LeftButton );
1293 mouseClick( 18, 17, Qt::LeftButton );
1294
1295 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 3 );
1296 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF1 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ( CircularString (14 14, 18 17, 17 10))" ) );
1297
1298 mLayerCompoundCurve->undoStack()->undo();
1299
1300 // for polyline
1301 mouseClick( 16, 11, Qt::LeftButton );
1302 mouseClick( 18, 13, Qt::LeftButton );
1303
1304 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 3 );
1305 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF2 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ((18 13, 17 11, 17 13))" ) );
1306
1307 mLayerCompoundCurve->undoStack()->undo();
1308
1309 // add vertex in compoundcurve
1310
1311 mouseDoubleClick( 11, 13, Qt::LeftButton );
1312 mouseClick( 18, 17, Qt::LeftButton );
1313
1314 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 3 );
1315 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF1 ).geometry(),
1316 QgsGeometry::fromWkt( "CompoundCurve ( CircularString (14 14, 18 17, 13.75126265847083928 13.78427124746189492, 10 10, 17 10))" ) );
1317
1318 mLayerCompoundCurve->undoStack()->undo();
1319
1320 // offset of the endpoint marker - currently set as 15px away from the last vertex in direction of the line
1321 const double offsetInMapUnits = 15 * mCanvas->mapSettings().mapUnitsPerPixel();
1322
1323 // for polyline
1324 mouseMove( 17, 13 );
1325 mouseClick( 17, 13 + offsetInMapUnits, Qt::LeftButton );
1326 mouseClick( 0, 0, Qt::LeftButton );
1327 mouseClick( 0, 0, Qt::RightButton );
1328
1329 // verifying that it's possible to add a extra vertex to a LineString in a CompoundCurveLayer
1330 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 3 );
1331 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF2 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ((16 11, 17 11, 17 13, 0 0))" ) );
1332
1333 mLayerCompoundCurve->undoStack()->undo();
1334
1335 // // for compoundcurve
1336 mouseMove( 17, 10 );
1337 mouseClick( 17 + offsetInMapUnits, 10, Qt::LeftButton );
1338 mouseClick( 7, 2, Qt::LeftButton );
1339 mouseClick( 7, 1, Qt::RightButton );
1340
1341 // verifying that it's not possible to add a extra vertex to a CircularString
1342 QCOMPARE( mLayerCompoundCurve->undoStack()->index(), 2 );
1343 QCOMPARE( mLayerCompoundCurve->getFeature( mFidCompoundCurveF1 ).geometry(), QgsGeometry::fromWkt( "CompoundCurve ( CircularString (14 14, 10 10, 17 10))" ) );
1344 }
1345
testSelectVerticesByPolygon()1346 void TestQgsVertexTool::testSelectVerticesByPolygon()
1347 {
1348 // Test selecting vertices by polygon
1349 mouseClick( 1.2, 7.7, Qt::LeftButton, Qt::AltModifier );
1350 mouseClick( 1.2, 6.5, Qt::LeftButton );
1351 mouseClick( 1.5, 6.5, Qt::LeftButton );
1352 mouseClick( 1.5, 5.2, Qt::LeftButton );
1353 mouseClick( 1.9, 5.2, Qt::LeftButton );
1354 mouseClick( 1.9, 6.5, Qt::LeftButton );
1355 mouseClick( 1.9, 6.5, Qt::RightButton );
1356
1357 mouseMove( 1.25, 7 );
1358 mouseClick( 1.25, 7, Qt::LeftButton );
1359 mouseMove( 1.25, 7.25 );
1360 mouseClick( 1.25, 7.25, Qt::LeftButton );
1361
1362 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 2 );
1363 QCOMPARE( mLayerMultiPolygon->getFeature( mFidMultiPolygonF1 ).geometry(), QgsGeometry::fromWkt( "MultiPolygon (((1 5, 2 5, 2 6.5, 2 8, 1 8, 1 6.5, 1 5),(1.25 5.5, 1.25 6, 1.75 6.25, 1.75 5.75, 1.25 5.5),(1.25 7.25, 1.75 7, 1.75 7.5, 1.25 7.75, 1.25 7.25)),((3 5, 3 6.5, 3 8, 4 8, 4 6.5, 4 5, 3 5),(3.25 5.5, 3.75 5.5, 3.75 6, 3.25 6, 3.25 5.5),(3.25 7, 3.75 7, 3.75 7.5, 3.25 7.5, 3.25 7)))" ) );
1364
1365 // Undo and reset vertex selection
1366 mLayerMultiPolygon->undoStack()->undo();
1367 mouseClick( 0.5, 7, Qt::RightButton );
1368 QCOMPARE( mLayerMultiPolygon->undoStack()->index(), 1 );
1369 QCOMPARE( mLayerMultiPolygon->getFeature( mFidMultiPolygonF1 ).geometry(), QgsGeometry::fromWkt( "MultiPolygon (((1 5, 2 5, 2 6.5, 2 8, 1 8, 1 6.5, 1 5),(1.25 5.5, 1.25 6, 1.75 6, 1.75 5.5, 1.25 5.5),(1.25 7, 1.75 7, 1.75 7.5, 1.25 7.5, 1.25 7)),((3 5, 3 6.5, 3 8, 4 8, 4 6.5, 4 5, 3 5),(3.25 5.5, 3.75 5.5, 3.75 6, 3.25 6, 3.25 5.5),(3.25 7, 3.75 7, 3.75 7.5, 3.25 7.5, 3.25 7)))" ) );
1370 }
1371
1372
1373 QGSTEST_MAIN( TestQgsVertexTool )
1374 #include "testqgsvertextool.moc"
1375