1 /***************************************************************************
2      testqgsmaptoolscalefeature.cpp
3      --------------------------------
4     Date                 : December 2020
5     Copyright            : (C) 2020 by roya0045
6     Contact              : ping me on github
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 "qgisapp.h"
19 #include "qgsgeometry.h"
20 #include "qgsmapcanvas.h"
21 #include "qgsmapcanvassnappingutils.h"
22 #include "qgssnappingconfig.h"
23 #include "qgssnappingutils.h"
24 #include "qgsmaptoolscalefeature.h"
25 #include "qgsproject.h"
26 #include "qgssettings.h"
27 #include "qgsvectorlayer.h"
28 #include "qgsmapmouseevent.h"
29 #include "testqgsmaptoolutils.h"
30 
31 
32 /**
33  * \ingroup UnitTests
34  * This is a unit test for the vertex tool
35  */
36 class TestQgsMapToolScaleFeature: public QObject
37 {
38     Q_OBJECT
39   public:
40     TestQgsMapToolScaleFeature();
41 
42   private slots:
43     void initTestCase();// will be called before the first testfunction is executed.
44     void cleanupTestCase();// will be called after the last testfunction was executed.
45 
46     void testScaleFeature();
47     void testScaleFeatureWithAnchor();
48     void testCancelManualAnchor();
49     void testScaleFeatureWithAnchorSetAfterStart();
50     void testScaleSelectedFeatures();
51     void testScaleFeatureManualAnchorSnapping();
52     void testScaleFeatureDifferentCrs();
53 
54   private:
55     QgisApp *mQgisApp = nullptr;
56     QgsMapCanvas *mCanvas = nullptr;
57     QgsMapToolScaleFeature *mScaleTool = nullptr;
58     QgsVectorLayer *mLayerBase = nullptr;
59 };
60 
61 TestQgsMapToolScaleFeature::TestQgsMapToolScaleFeature() = default;
62 
63 
64 //runs before all tests
initTestCase()65 void TestQgsMapToolScaleFeature::initTestCase()
66 {
67   qDebug() << "TestMapToolCapture::initTestCase()";
68   // init QGIS's paths - true means that all path will be inited from prefix
69   QgsApplication::init();
70   QgsApplication::initQgis();
71 
72   // Set up the QSettings environment
73   QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) );
74   QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) );
75   QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) );
76 
77   mQgisApp = new QgisApp();
78 
79   mCanvas = new QgsMapCanvas();
80 
81   mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3946" ) ) );
82 
83   mCanvas->setFrameStyle( QFrame::NoFrame );
84   mCanvas->resize( 512, 512 );
85   mCanvas->setExtent( QgsRectangle( -4, -4, 4, 4 ) );
86   mCanvas->show(); // to make the canvas resize
87   mCanvas->hide();
88 
89   // make testing layers
90   mLayerBase = new QgsVectorLayer( QStringLiteral( "Polygon?crs=EPSG:3946" ), QStringLiteral( "baselayer" ), QStringLiteral( "memory" ) );
91   QVERIFY( mLayerBase->isValid() );
92   QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << mLayerBase );
93 
94   mLayerBase->startEditing();
95   const QString wkt1 = QStringLiteral( "Polygon ((-2 -2, -2 -1, -1 -1, -1 -2, -2 -2))" );
96   QgsFeature f1;
97   f1.setGeometry( QgsGeometry::fromWkt( wkt1 ) );
98   const QString wkt2 = QStringLiteral( "Polygon ((1.1 0.8, 1.1 5, 2.1 5, 2.1 0.8, 1.1 0.8))" );
99   QgsFeature f2;
100   f2.setGeometry( QgsGeometry::fromWkt( wkt2 ) );
101 
102   QgsFeatureList flist;
103   flist << f1 << f2;
104   mLayerBase->dataProvider()->addFeatures( flist );
105   QCOMPARE( mLayerBase->featureCount(), 2L );
106   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt(), wkt1 );
107   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 1 ), wkt2 );
108 
109   QgsSnappingConfig cfg = mCanvas->snappingUtils()->config();
110   cfg.setMode( QgsSnappingConfig::AllLayers );
111   cfg.setTolerance( 1 );
112   cfg.setTypeFlag( static_cast<QgsSnappingConfig::SnappingTypeFlag>( QgsSnappingConfig::VertexFlag | QgsSnappingConfig::SegmentFlag ) );
113   cfg.setEnabled( true );
114   mCanvas->snappingUtils()->setConfig( cfg );
115 
116   mCanvas->setLayers( QList<QgsMapLayer *>() << mLayerBase );
117   mCanvas->setCurrentLayer( mLayerBase );
118   mCanvas->snappingUtils()->locatorForLayer( mLayerBase )->init();
119 
120   // create the tool
121   mScaleTool = new QgsMapToolScaleFeature( mCanvas );
122   mCanvas->setMapTool( mScaleTool );
123 
124   QCOMPARE( mCanvas->mapSettings().outputSize(), QSize( 512, 512 ) );
125   QCOMPARE( mCanvas->mapSettings().visibleExtent(), QgsRectangle( -4, -4, 4, 4 ) );
126 }
127 
128 //runs after all tests
cleanupTestCase()129 void TestQgsMapToolScaleFeature::cleanupTestCase()
130 {
131   delete mScaleTool;
132   delete mCanvas;
133   QgsApplication::exitQgis();
134 }
135 
testScaleFeature()136 void TestQgsMapToolScaleFeature::testScaleFeature()
137 {
138   TestQgsMapToolUtils utils( mScaleTool );
139 
140   //scale up
141   utils.mouseClick( -2, -1, Qt::LeftButton, Qt::KeyboardModifiers(), true );
142   utils.mouseMove( -2.5, -0.5 );
143   utils.mouseClick( -2.5, -0.5, Qt::LeftButton, Qt::KeyboardModifiers(), true );
144 
145   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-2.5 -2.5, -2.5 -0.5, -0.5 -0.5, -0.5 -2.5, -2.5 -2.5))" ) );
146   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0.8, 1.1 5, 2.1 5, 2.1 0.8, 1.1 0.8))" ) );
147 
148   //scale down
149   utils.mouseClick( 1.1, 0.8, Qt::LeftButton, Qt::KeyboardModifiers(), true );
150   utils.mouseMove( 1.35, 1.85 );
151   utils.mouseClick( 1.35, 1.85, Qt::LeftButton, Qt::KeyboardModifiers(), true );
152 
153   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-2.5 -2.5, -2.5 -0.5, -0.5 -0.5, -0.5 -2.5, -2.5 -2.5))" ) );
154   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.35 1.84, 1.35 3.96, 1.85 3.96, 1.85 1.84, 1.35 1.84))" ) );
155 
156   mLayerBase->undoStack()->undo();
157   mLayerBase->undoStack()->undo();
158 }
159 
testScaleFeatureWithAnchor()160 void TestQgsMapToolScaleFeature::testScaleFeatureWithAnchor()
161 {
162   TestQgsMapToolUtils utils( mScaleTool );
163 
164   //set manual anchor point
165   utils.mouseClick( 1, -1, Qt::LeftButton, Qt::ControlModifier, true );
166 
167   // resize
168   utils.mouseClick( -2, -1, Qt::LeftButton, Qt::KeyboardModifiers(), true );
169   utils.mouseMove( -2.5, -0.5 );
170   utils.mouseClick( -2.5, -0.5, Qt::LeftButton, Qt::KeyboardModifiers(), true );
171 
172   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-2.54 -2.18, -2.54 -1, -1.36 -1, -1.36 -2.18, -2.54 -2.18))" ) );
173   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0.8, 1.1 5, 2.1 5, 2.1 0.8, 1.1 0.8))" ) );
174 
175   mLayerBase->undoStack()->undo();
176 }
177 
testCancelManualAnchor()178 void TestQgsMapToolScaleFeature::testCancelManualAnchor()
179 {
180   TestQgsMapToolUtils utils( mScaleTool );
181 
182   //set manual anchor point
183   utils.mouseClick( 1, -1, Qt::LeftButton, Qt::ControlModifier, true );
184 
185   // remove manual anchor point via right click
186   utils.mouseClick( 10, 25, Qt::RightButton, Qt::KeyboardModifiers(), true );
187 
188   // resize
189   utils.mouseClick( -2, -1, Qt::LeftButton, Qt::KeyboardModifiers(), true );
190   utils.mouseMove( -2.5, -0.5 );
191   utils.mouseClick( -2.5, -0.5, Qt::LeftButton, Qt::KeyboardModifiers(), true );
192 
193   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-2.5 -2.5, -2.5 -0.5, -0.5 -0.5, -0.5 -2.5, -2.5 -2.5))" ) );
194   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0.8, 1.1 5, 2.1 5, 2.1 0.8, 1.1 0.8))" ) );
195 
196   mLayerBase->undoStack()->undo();
197 }
198 
testScaleFeatureWithAnchorSetAfterStart()199 void TestQgsMapToolScaleFeature::testScaleFeatureWithAnchorSetAfterStart()
200 {
201   TestQgsMapToolUtils utils( mScaleTool );
202 
203   // resize
204   utils.mouseClick( -2, -1, Qt::LeftButton, Qt::KeyboardModifiers(), true );
205 
206   //set manual anchor point
207   utils.mouseClick( 1, -1, Qt::LeftButton, Qt::ControlModifier, true );
208 
209   utils.mouseMove( -2.5, -0.5 );
210   utils.mouseClick( -2.5, -0.5, Qt::LeftButton, Qt::KeyboardModifiers(), true );
211 
212   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-14 -6, -14 -1, -9 -1, -9 -6, -14 -6))" ) );
213   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0.8, 1.1 5, 2.1 5, 2.1 0.8, 1.1 0.8))" ) );
214 
215   mLayerBase->undoStack()->undo();
216 }
217 
testScaleSelectedFeatures()218 void TestQgsMapToolScaleFeature::testScaleSelectedFeatures()
219 {
220   TestQgsMapToolUtils utils( mScaleTool );
221   mLayerBase->selectAll();
222 
223   // resize
224   utils.mouseClick( -2, -1, Qt::LeftButton, Qt::KeyboardModifiers(), true );
225   utils.mouseMove( -2.5, -0.5 );
226   utils.mouseClick( -2.5, -0.5, Qt::LeftButton, Qt::KeyboardModifiers(), true );
227 
228   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-2.54 -2.18, -2.54 -1, -1.36 -1, -1.36 -2.18, -2.54 -2.18))" ) );
229   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.12 1.12, 1.12 6.07, 2.3 6.07, 2.3 1.12, 1.12 1.12))" ) );
230 
231   mLayerBase->removeSelection();
232   mLayerBase->undoStack()->undo();
233 }
234 
testScaleFeatureManualAnchorSnapping()235 void TestQgsMapToolScaleFeature::testScaleFeatureManualAnchorSnapping()
236 {
237   TestQgsMapToolUtils utils( mScaleTool );
238 
239   QgsSnappingConfig cfg = mCanvas->snappingUtils()->config();
240   const double tolerance = cfg.tolerance();
241   const QgsTolerance::UnitType units = cfg.units();
242   cfg.setTolerance( 0.5 );
243   cfg.setUnits( QgsTolerance::LayerUnits );
244   mCanvas->snappingUtils()->setConfig( cfg );
245 
246   //set manual anchor point, should snap to (-2, -2)
247   utils.mouseClick( -1.9, -1.9, Qt::LeftButton, Qt::ControlModifier, true );
248 
249   // resize, source point should snap to (-1, -1)
250   utils.mouseMove( -0.9, -0.9 );
251   utils.mouseClick( -0.9, -0.9, Qt::LeftButton, Qt::KeyboardModifiers(), true );
252   // target point should snap to (1.1, 0.8)
253   utils.mouseMove( 1.2, 0.9 );
254   utils.mouseClick( 1.2, 0.9, Qt::LeftButton, Qt::KeyboardModifiers(), true );
255 
256   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-2 -2, -2 0.95, 0.95 0.95, 0.95 -2, -2 -2))" ) );
257   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0.8, 1.1 5, 2.1 5, 2.1 0.8, 1.1 0.8))" ) );
258 
259   mLayerBase->undoStack()->undo();
260 
261   // restore tolerance setting
262   cfg.setTolerance( tolerance );
263   cfg.setUnits( units );
264   mCanvas->snappingUtils()->setConfig( cfg );
265 
266   // remove manual anchor point via right click
267   utils.mouseClick( 10, 25, Qt::RightButton, Qt::KeyboardModifiers(), true );
268 }
269 
testScaleFeatureDifferentCrs()270 void TestQgsMapToolScaleFeature::testScaleFeatureDifferentCrs()
271 {
272   mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
273   TestQgsMapToolUtils utils( mScaleTool );
274 
275   //scale up
276   utils.mouseClick( -8.82187821744550682, 2.0909475540607434, Qt::LeftButton, Qt::KeyboardModifiers(), true );
277   utils.mouseMove( -8.82188215592444536, 2.09095048559432861 );
278   utils.mouseClick( -8.82188215592444536, 2.09095048559432861, Qt::LeftButton, Qt::KeyboardModifiers(), true );
279 
280   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-2.5 -2.5, -2.5 -0.5, -0.5 -0.5, -0.5 -2.5, -2.5 -2.5))" ) );
281   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0.8, 1.1 5, 2.1 5, 2.1 0.8, 1.1 0.8))" ) );
282 
283   //scale down
284   utils.mouseClick( -8.82185881943214234, 2.09096315856551129, Qt::LeftButton, Qt::KeyboardModifiers(), true );
285   utils.mouseMove( -8.82185818217576667, 2.09097065484482636 );
286   utils.mouseClick( -8.82185818217576667, 2.09097065484482636, Qt::LeftButton, Qt::KeyboardModifiers(), true );
287 
288   QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-2.5 -2.5, -2.5 -0.5, -0.5 -0.5, -0.5 -2.5, -2.5 -2.5))" ) );
289   QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.35 1.84, 1.35 3.96, 1.85 3.96, 1.85 1.84, 1.35 1.84))" ) );
290 
291   mLayerBase->undoStack()->undo();
292   mLayerBase->undoStack()->undo();
293   mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3946" ) ) );
294 }
295 
296 QGSTEST_MAIN( TestQgsMapToolScaleFeature )
297 #include "testqgsmaptoolscalefeature.moc"
298