1 /***************************************************************************
2 testqgsmaptoolidentifyaction.cpp
3 --------------------------------
4 Date : 2016-02-14
5 Copyright : (C) 2016 by Nyall Dawson
6 Email : nyall dot dawson 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 "qgsapplication.h"
19 #include "qgsvectorlayer.h"
20 #include "qgsrasterlayer.h"
21 #include "qgsfeature.h"
22 #include "qgsgeometry.h"
23 #include "qgsvectordataprovider.h"
24 #include "qgsvectortilelayer.h"
25 #include "qgsproject.h"
26 #include "qgsmapcanvas.h"
27 #include "qgsmeshlayer.h"
28 #include "qgsunittypes.h"
29 #include "qgsmaptoolidentifyaction.h"
30 #include "qgssettings.h"
31 #include "qgsidentifymenu.h"
32 #include "qgisapp.h"
33 #include "qgsaction.h"
34 #include "qgsactionmanager.h"
35 #include "qgsactionmenu.h"
36 #include "qgsidentifyresultsdialog.h"
37 #include "qgsmapmouseevent.h"
38 #include "qgsmaplayertemporalproperties.h"
39 #include "qgsmeshlayertemporalproperties.h"
40
41 #include <QTimer>
42
43 #include "cpl_conv.h"
44
45 class TestQgsMapToolIdentifyAction : public QObject
46 {
47 Q_OBJECT
48 public:
49 TestQgsMapToolIdentifyAction() = default;
50
51 private slots:
52 void initTestCase(); // will be called before the first testfunction is executed.
53 void cleanupTestCase(); // will be called after the last testfunction was executed.
54 void init(); // will be called before each testfunction is executed.
55 void cleanup(); // will be called after every testfunction.
56 void lengthCalculation(); //test calculation of derived length attributes
57 void perimeterCalculation(); //test calculation of derived perimeter attribute
58 void areaCalculation(); //test calculation of derived area attribute
59 void identifyRasterFloat32(); // test pixel identification and decimal precision
60 void identifyRasterFloat64(); // test pixel identification and decimal precision
61 void identifyMesh(); // test identification for mesh layer
62 void identifyVectorTile(); // test identification for vector tile layer
63 void identifyInvalidPolygons(); // test selecting invalid polygons
64 void clickxy(); // test if click_x and click_y variables are propagated
65 void closestPoint();
66
67 private:
68 void doAction();
69
70 QgsMapCanvas *canvas = nullptr;
71 QgsMapToolIdentifyAction *mIdentifyAction = nullptr;
72 QgisApp *mQgisApp = nullptr;
73
74 QString testIdentifyRaster( QgsRasterLayer *layer, double xGeoref, double yGeoref );
75 QList<QgsMapToolIdentify::IdentifyResult> testIdentifyVector( QgsVectorLayer *layer, double xGeoref, double yGeoref );
76 QList<QgsMapToolIdentify::IdentifyResult> testIdentifyMesh( QgsMeshLayer *layer, double xGeoref, double yGeoref );
77 QList<QgsMapToolIdentify::IdentifyResult> testIdentifyVectorTile( QgsVectorTileLayer *layer, double xGeoref, double yGeoref );
78
79 // Release return with delete []
80 unsigned char *
hex2bytes(const char * hex,int * size)81 hex2bytes( const char *hex, int *size )
82 {
83 QByteArray ba = QByteArray::fromHex( hex );
84 unsigned char *out = new unsigned char[ba.size()];
85 memcpy( out, ba.data(), ba.size() );
86 *size = ba.size();
87 return out;
88 }
89
90 // TODO: make this a QgsGeometry member...
geomFromHexWKB(const char * hexwkb)91 QgsGeometry geomFromHexWKB( const char *hexwkb )
92 {
93 int wkbsize;
94 unsigned char *wkb = hex2bytes( hexwkb, &wkbsize );
95 QgsGeometry geom;
96 // NOTE: QgsGeometry takes ownership of wkb
97 geom.fromWkb( wkb, wkbsize );
98 return geom;
99 }
100 };
101
initTestCase()102 void TestQgsMapToolIdentifyAction::initTestCase()
103 {
104 QgsApplication::init();
105 QgsApplication::initQgis();
106 // Set up the QgsSettings environment
107 QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) );
108 QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) );
109 QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) );
110
111 QgsApplication::showSettings();
112
113 // enforce C locale because the tests expect it
114 // (decimal separators / thousand separators)
115 QLocale::setDefault( QLocale::c() );
116
117 mQgisApp = new QgisApp();
118 }
119
cleanupTestCase()120 void TestQgsMapToolIdentifyAction::cleanupTestCase()
121 {
122 QgsApplication::exitQgis();
123 }
124
init()125 void TestQgsMapToolIdentifyAction::init()
126 {
127 canvas = new QgsMapCanvas();
128 }
129
cleanup()130 void TestQgsMapToolIdentifyAction::cleanup()
131 {
132 delete canvas;
133 }
134
doAction()135 void TestQgsMapToolIdentifyAction::doAction()
136 {
137 bool ok = false;
138 int clickxOk = 2484588;
139 int clickyOk = 2425722;
140
141 // test QActionMenu
142 QList<QAction *> actions = mIdentifyAction->identifyMenu()->actions();
143 bool testDone = false;
144
145 for ( int i = 0; i < actions.count(); i++ )
146 {
147 if ( actions[i]->text().compare( "MyAction" ) == 0 )
148 {
149 QgsActionMenu::ActionData data = actions[i]->data().value<QgsActionMenu::ActionData>();
150 QgsAction act = data.actionData.value<QgsAction>();
151
152 int clickx = act.expressionContextScope().variable( "click_x" ).toString().toInt( &ok, 10 );
153 QCOMPARE( clickx, clickxOk );
154
155 int clicky = act.expressionContextScope().variable( "click_y" ).toString().toInt( &ok, 10 );
156 QCOMPARE( clicky, clickyOk );
157
158 testDone = true;
159 }
160 }
161
162 QCOMPARE( testDone, true );
163
164 // test QgsIdentifyResultsDialog expression context scope
165 QgsIdentifyResultsDialog *dlg = mIdentifyAction->resultsDialog();
166 int clickx = dlg->expressionContextScope().variable( "click_x" ).toString().toInt( &ok, 10 );
167 QCOMPARE( clickx, clickxOk );
168
169 int clicky = dlg->expressionContextScope().variable( "click_y" ).toString().toInt( &ok, 10 );
170 QCOMPARE( clicky, clickyOk );
171
172 // close
173 mIdentifyAction->identifyMenu()->close();
174 }
175
clickxy()176 void TestQgsMapToolIdentifyAction::clickxy()
177 {
178 // create temp layer
179 std::unique_ptr< QgsVectorLayer> tempLayer( new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:3111" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
180 QVERIFY( tempLayer->isValid() );
181
182 // add feature
183 QgsFeature f1( tempLayer->dataProvider()->fields(), 1 );
184 QgsPointXY wordPoint( 2484588, 2425722 );
185 QgsGeometry geom = QgsGeometry::fromPointXY( wordPoint ) ;
186 f1.setGeometry( geom );
187 tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
188
189 // prepare canvas
190 QList<QgsMapLayer *> layers;
191 layers.append( tempLayer.get() );
192
193 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3111" ) );
194 canvas->setDestinationCrs( srs );
195 canvas->setLayers( layers );
196 canvas->setCurrentLayer( tempLayer.get() );
197
198 // create/add action
199 QgsAction act( QgsAction::GenericPython, "MyAction", "", true );
200
201 QSet<QString> scopes;
202 scopes << "Feature";
203 act.setActionScopes( scopes );
204 tempLayer->actions()->addAction( act );
205
206 // init map tool identify action
207 mIdentifyAction = new QgsMapToolIdentifyAction( canvas );
208
209 // simulate a click on the canvas
210 QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( 2484588, 2425722 );
211 QPoint point = QPoint( mapPoint.x(), mapPoint.y() );
212 QMouseEvent releases( QEvent::MouseButtonRelease, point,
213 Qt::RightButton, Qt::LeftButton, Qt::NoModifier );
214 QgsMapMouseEvent mapReleases( nullptr, &releases );
215
216 // simulate a click on the corresponding action
217 QTimer::singleShot( 2000, this, &TestQgsMapToolIdentifyAction::doAction );
218 mIdentifyAction->canvasReleaseEvent( &mapReleases );
219 }
220
closestPoint()221 void TestQgsMapToolIdentifyAction::closestPoint()
222 {
223 QgsSettings s;
224 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
225
226 //create a temporary layer
227 std::unique_ptr< QgsVectorLayer> tempLayer( new QgsVectorLayer( QStringLiteral( "LineStringZM?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
228 QVERIFY( tempLayer->isValid() );
229 QgsFeature f1( tempLayer->dataProvider()->fields(), 1 );
230 f1.setAttribute( QStringLiteral( "pk" ), 1 );
231 f1.setAttribute( QStringLiteral( "col1" ), 0.0 );
232 QgsPolylineXY line3111;
233 line3111 << QgsPointXY( 2484588, 2425722 ) << QgsPointXY( 2482767, 2398853 );
234 QgsGeometry line3111G = QgsGeometry::fromWkt( QStringLiteral( "LineStringZM( 2484588 2425722 11 31, 2484588 2398853 15 37)" ) ) ;
235 f1.setGeometry( line3111G );
236 tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
237
238 // set project CRS and ellipsoid
239 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3111" ) );
240 canvas->setDestinationCrs( srs );
241 canvas->setExtent( f1.geometry().boundingBox() );
242 QgsProject::instance()->setCrs( srs );
243 QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
244 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceMeters );
245
246 QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( 2484587, 2399800 );
247
248 std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
249
250 //check that closest point attributes are present
251 QList<QgsMapToolIdentify::IdentifyResult> result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
252 QCOMPARE( result.length(), 1 );
253 QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest X" )], QStringLiteral( "2484588" ) );
254 QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest Y" )], QStringLiteral( "2399800" ) );
255 QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Interpolated M" )].left( 4 ), QStringLiteral( "36.7" ) );
256 QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Interpolated Z" )].left( 4 ), QStringLiteral( "14.8" ) );
257
258 // polygons
259 //create a temporary layer
260 std::unique_ptr< QgsVectorLayer> tempLayer2( new QgsVectorLayer( QStringLiteral( "PolygonZM?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
261 QVERIFY( tempLayer2->isValid() );
262 f1 = QgsFeature( tempLayer2->dataProvider()->fields(), 1 );
263 f1.setAttribute( QStringLiteral( "pk" ), 1 );
264 f1.setAttribute( QStringLiteral( "col1" ), 0.0 );
265
266 f1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "PolygonZM((2484588 2425722 1 11, 2484588 2398853 2 12, 2520109 2397715 3 13, 2520792 2425494 4 14, 2484588 2425722 1 11))" ) ) );
267 QVERIFY( f1.hasGeometry() );
268 tempLayer2->dataProvider()->addFeatures( QgsFeatureList() << f1 );
269
270 mapPoint = canvas->getCoordinateTransform()->transform( 2484589, 2399800 );
271 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer2.get() );
272 QCOMPARE( result.length(), 1 );
273 QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest X" )], QStringLiteral( "2484588" ) );
274 QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Closest Y" )], QStringLiteral( "2399800" ) );
275 QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Interpolated M" )].left( 4 ), QStringLiteral( "11.9" ) );
276 QCOMPARE( result.at( 0 ).mDerivedAttributes[tr( "Interpolated Z" )].left( 4 ), QStringLiteral( "1.96" ) );
277 }
278
lengthCalculation()279 void TestQgsMapToolIdentifyAction::lengthCalculation()
280 {
281 QgsSettings s;
282 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
283
284 //create a temporary layer
285 std::unique_ptr< QgsVectorLayer> tempLayer( new QgsVectorLayer( QStringLiteral( "LineString?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
286 QVERIFY( tempLayer->isValid() );
287 QgsFeature f1( tempLayer->dataProvider()->fields(), 1 );
288 f1.setAttribute( QStringLiteral( "pk" ), 1 );
289 f1.setAttribute( QStringLiteral( "col1" ), 0.0 );
290 QgsPolylineXY line3111;
291 line3111 << QgsPointXY( 2484588, 2425722 ) << QgsPointXY( 2482767, 2398853 );
292 QgsGeometry line3111G = QgsGeometry::fromPolylineXY( line3111 ) ;
293 f1.setGeometry( line3111G );
294 tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
295
296 // set project CRS and ellipsoid
297 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3111" ) );
298 canvas->setDestinationCrs( srs );
299 canvas->setExtent( f1.geometry().boundingBox() );
300 QgsProject::instance()->setCrs( srs );
301 QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
302 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceMeters );
303
304 QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( 2484588, 2425722 );
305
306 std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
307 QList<QgsMapToolIdentify::IdentifyResult> result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
308 QCOMPARE( result.length(), 1 );
309 QString derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Ellipsoidal — WGS84)" )];
310 double length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
311 QGSCOMPARENEAR( length, 26932.2, 0.1 );
312 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian)" )];
313 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
314 QGSCOMPARENEAR( length, 26930.6, 0.1 );
315
316 //check that project units are respected
317 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceFeet );
318 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
319 QCOMPARE( result.length(), 1 );
320 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Ellipsoidal — WGS84)" )];
321 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
322 QGSCOMPARENEAR( length, 88360.1, 0.1 );
323 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian)" )];
324 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
325 QGSCOMPARENEAR( length, 88355.1, 0.1 );
326
327 //test unchecked "keep base units" setting
328 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), false );
329 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
330 QCOMPARE( result.length(), 1 );
331 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Ellipsoidal — WGS84)" )];
332 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
333 QGSCOMPARENEAR( length, 16.735, 0.001 );
334 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian)" )];
335 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
336 QGSCOMPARENEAR( length, 16.734000, 0.001 );
337
338 // no conversion of Cartesian lengths between unit types
339 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
340 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceDegrees );
341 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
342 QCOMPARE( result.length(), 1 );
343 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Ellipsoidal — WGS84)" )];
344 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
345 QGSCOMPARENEAR( length, 0.242000, 0.001 );
346 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian)" )];
347 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
348 QGSCOMPARENEAR( length, 26930.6, 0.1 );
349
350 // LineString with Z
351 tempLayer = qgis::make_unique< QgsVectorLayer>( QStringLiteral( "LineStringZ?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
352 QVERIFY( tempLayer->isValid() );
353 f1.setGeometry( QgsGeometry::fromWkt( QStringLiteral( "LineStringZ(2484588 2425722 10, 2482767 2398853 1000)" ) ) );
354 tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
355 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
356 QCOMPARE( result.length(), 1 );
357 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Ellipsoidal — WGS84)" )];
358 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
359 QGSCOMPARENEAR( length, 0.242000, 0.001 );
360 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian — 2D)" )];
361 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
362 QGSCOMPARENEAR( length, 26930.6, 0.1 );
363 derivedLength = result.at( 0 ).mDerivedAttributes[tr( "Length (Cartesian — 3D)" )];
364 length = derivedLength.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
365 QGSCOMPARENEAR( length, 26948.827000, 0.1 );
366 }
367
perimeterCalculation()368 void TestQgsMapToolIdentifyAction::perimeterCalculation()
369 {
370 QgsSettings s;
371 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
372
373 //create a temporary layer
374 std::unique_ptr< QgsVectorLayer> tempLayer( new QgsVectorLayer( QStringLiteral( "Polygon?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
375 QVERIFY( tempLayer->isValid() );
376 QgsFeature f1( tempLayer->dataProvider()->fields(), 1 );
377 f1.setAttribute( QStringLiteral( "pk" ), 1 );
378 f1.setAttribute( QStringLiteral( "col1" ), 0.0 );
379 QgsPolylineXY polygonRing3111;
380 polygonRing3111 << QgsPointXY( 2484588, 2425722 ) << QgsPointXY( 2482767, 2398853 ) << QgsPointXY( 2520109, 2397715 ) << QgsPointXY( 2520792, 2425494 ) << QgsPointXY( 2484588, 2425722 );
381 QgsPolygonXY polygon3111;
382 polygon3111 << polygonRing3111;
383 QgsGeometry polygon3111G = QgsGeometry::fromPolygonXY( polygon3111 ) ;
384 f1.setGeometry( polygon3111G );
385 tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
386
387 // set project CRS and ellipsoid
388 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3111" ) );
389 canvas->setDestinationCrs( srs );
390 canvas->setExtent( f1.geometry().boundingBox() );
391 QgsProject::instance()->setCrs( srs );
392 QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
393 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceMeters );
394
395 QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( 2484588, 2425722 );
396
397 std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
398 QList<QgsMapToolIdentify::IdentifyResult> result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
399 QCOMPARE( result.length(), 1 );
400 QString derivedPerimeter = result.at( 0 ).mDerivedAttributes[tr( "Perimeter (Ellipsoidal — WGS84)" )];
401 double perimeter = derivedPerimeter.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
402 QCOMPARE( perimeter, 128289.074 );
403 derivedPerimeter = result.at( 0 ).mDerivedAttributes[tr( "Perimeter (Cartesian)" )];
404 perimeter = derivedPerimeter.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
405 QCOMPARE( perimeter, 128282.086 );
406
407 //check that project units are respected
408 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceFeet );
409 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
410 QCOMPARE( result.length(), 1 );
411 derivedPerimeter = result.at( 0 ).mDerivedAttributes[tr( "Perimeter (Ellipsoidal — WGS84)" )];
412 perimeter = derivedPerimeter.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
413 QGSCOMPARENEAR( perimeter, 420896.0, 0.1 );
414 derivedPerimeter = result.at( 0 ).mDerivedAttributes[tr( "Perimeter (Cartesian)" )];
415 perimeter = derivedPerimeter.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
416 QGSCOMPARENEAR( perimeter, 420873.0, 0.1 );
417
418 //test unchecked "keep base units" setting
419 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), false );
420 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
421 QCOMPARE( result.length(), 1 );
422 derivedPerimeter = result.at( 0 ).mDerivedAttributes[tr( "Perimeter (Ellipsoidal — WGS84)" )];
423 perimeter = derivedPerimeter.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
424 QGSCOMPARENEAR( perimeter, 79.715, 0.001 );
425 derivedPerimeter = result.at( 0 ).mDerivedAttributes[tr( "Perimeter (Cartesian)" )];
426 perimeter = derivedPerimeter.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
427 QCOMPARE( perimeter, 79.711 );
428
429 // no conversion of Cartesian lengths between unit types
430 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
431 QgsProject::instance()->setDistanceUnits( QgsUnitTypes::DistanceDegrees );
432 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
433 QCOMPARE( result.length(), 1 );
434 derivedPerimeter = result.at( 0 ).mDerivedAttributes[tr( "Perimeter (Ellipsoidal — WGS84)" )];
435 perimeter = derivedPerimeter.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
436 QGSCOMPARENEAR( perimeter, 1.152000, 0.001 );
437 derivedPerimeter = result.at( 0 ).mDerivedAttributes[tr( "Perimeter (Cartesian)" )];
438 perimeter = derivedPerimeter.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
439 QGSCOMPARENEAR( perimeter, 128282, 0.1 );
440 }
441
areaCalculation()442 void TestQgsMapToolIdentifyAction::areaCalculation()
443 {
444 QgsSettings s;
445 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
446
447 //create a temporary layer
448 std::unique_ptr< QgsVectorLayer> tempLayer( new QgsVectorLayer( QStringLiteral( "Polygon?crs=epsg:3111&field=pk:int&field=col1:double" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
449 QVERIFY( tempLayer->isValid() );
450 QgsFeature f1( tempLayer->dataProvider()->fields(), 1 );
451 f1.setAttribute( QStringLiteral( "pk" ), 1 );
452 f1.setAttribute( QStringLiteral( "col1" ), 0.0 );
453
454 QgsPolylineXY polygonRing3111;
455 polygonRing3111 << QgsPointXY( 2484588, 2425722 ) << QgsPointXY( 2482767, 2398853 ) << QgsPointXY( 2520109, 2397715 ) << QgsPointXY( 2520792, 2425494 ) << QgsPointXY( 2484588, 2425722 );
456 QgsPolygonXY polygon3111;
457 polygon3111 << polygonRing3111;
458 QgsGeometry polygon3111G = QgsGeometry::fromPolygonXY( polygon3111 ) ;
459 f1.setGeometry( polygon3111G );
460 tempLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
461
462 // set project CRS and ellipsoid
463 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3111" ) );
464 canvas->setDestinationCrs( srs );
465 canvas->setExtent( f1.geometry().boundingBox() );
466 QgsProject::instance()->setCrs( srs );
467 QgsProject::instance()->setEllipsoid( QStringLiteral( "WGS84" ) );
468 QgsProject::instance()->setAreaUnits( QgsUnitTypes::AreaSquareMeters );
469
470 QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( 2484588, 2425722 );
471
472 std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
473 QList<QgsMapToolIdentify::IdentifyResult> result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
474 QCOMPARE( result.length(), 1 );
475 QString derivedArea = result.at( 0 ).mDerivedAttributes[tr( "Area (Ellipsoidal — WGS84)" )];
476 double area = derivedArea.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
477 QGSCOMPARENEAR( area, 1005721496.780000, 1.0 );
478 derivedArea = result.at( 0 ).mDerivedAttributes[tr( "Area (Cartesian)" )];
479 area = derivedArea.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
480 QGSCOMPARENEAR( area, 1005640568.0, 1.0 );
481
482 //check that project units are respected
483 QgsProject::instance()->setAreaUnits( QgsUnitTypes::AreaSquareMiles );
484 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
485 QCOMPARE( result.length(), 1 );
486 derivedArea = result.at( 0 ).mDerivedAttributes[tr( "Area (Ellipsoidal — WGS84)" )];
487 area = derivedArea.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
488 QGSCOMPARENEAR( area, 388.311000, 0.001 );
489 derivedArea = result.at( 0 ).mDerivedAttributes[tr( "Area (Cartesian)" )];
490 area = derivedArea.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
491 QGSCOMPARENEAR( area, 388.280000, 0.001 );
492
493 //test unchecked "keep base units" setting
494 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), false );
495 QgsProject::instance()->setAreaUnits( QgsUnitTypes::AreaSquareFeet );
496 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
497 QCOMPARE( result.length(), 1 );
498 derivedArea = result.at( 0 ).mDerivedAttributes[tr( "Area (Ellipsoidal — WGS84)" )];
499 area = derivedArea.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
500 QGSCOMPARENEAR( area, 388.311000, 0.001 );
501 derivedArea = result.at( 0 ).mDerivedAttributes[tr( "Area (Cartesian)" )];
502 area = derivedArea.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
503 QGSCOMPARENEAR( area, 388.280000, 0.001 );
504
505 // no conversion of Cartesian lengths between unit types
506 s.setValue( QStringLiteral( "/qgis/measure/keepbaseunit" ), true );
507 QgsProject::instance()->setAreaUnits( QgsUnitTypes::AreaSquareDegrees );
508 result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << tempLayer.get() );
509 QCOMPARE( result.length(), 1 );
510 derivedArea = result.at( 0 ).mDerivedAttributes[tr( "Area (Ellipsoidal — WGS84)" )];
511 area = derivedArea.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
512 QGSCOMPARENEAR( area, 0.081000, 0.001 );
513 derivedArea = result.at( 0 ).mDerivedAttributes[tr( "Area (Cartesian)" )];
514 area = derivedArea.remove( ',' ).split( ' ' ).at( 0 ).toDouble();
515 QGSCOMPARENEAR( area, 1005640568.6, 1 );
516 }
517
518 // private
testIdentifyRaster(QgsRasterLayer * layer,double xGeoref,double yGeoref)519 QString TestQgsMapToolIdentifyAction::testIdentifyRaster( QgsRasterLayer *layer, double xGeoref, double yGeoref )
520 {
521 std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
522 QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( xGeoref, yGeoref );
523 QList<QgsMapToolIdentify::IdentifyResult> result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << layer );
524 if ( result.length() != 1 )
525 return QString();
526 return result[0].mAttributes[QStringLiteral( "Band 1" )];
527 }
528
529 // private
testIdentifyMesh(QgsMeshLayer * layer,double xGeoref,double yGeoref)530 QList<QgsMapToolIdentify::IdentifyResult> TestQgsMapToolIdentifyAction::testIdentifyMesh( QgsMeshLayer *layer, double xGeoref, double yGeoref )
531 {
532 std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
533 QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( xGeoref, yGeoref );
534 //check that closest point attributes are present
535 QgsIdentifyContext identifyContext;
536 if ( canvas->mapSettings().isTemporal() )
537 identifyContext.setTemporalRange( canvas->temporalRange() );
538 QList<QgsMapToolIdentify::IdentifyResult> result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << layer, QgsMapToolIdentify::DefaultQgsSetting, identifyContext );
539 return result;
540 }
541
542 // private
543 QList<QgsMapToolIdentify::IdentifyResult>
testIdentifyVector(QgsVectorLayer * layer,double xGeoref,double yGeoref)544 TestQgsMapToolIdentifyAction::testIdentifyVector( QgsVectorLayer *layer, double xGeoref, double yGeoref )
545 {
546 std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
547 QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( xGeoref, yGeoref );
548 QgsIdentifyContext identifyContext;
549 if ( canvas->mapSettings().isTemporal() )
550 identifyContext.setTemporalRange( canvas->temporalRange() );
551 QList<QgsMapToolIdentify::IdentifyResult> result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << layer, QgsMapToolIdentify::DefaultQgsSetting, identifyContext );
552 return result;
553 }
554
555 // private
556 QList<QgsMapToolIdentify::IdentifyResult>
testIdentifyVectorTile(QgsVectorTileLayer * layer,double xGeoref,double yGeoref)557 TestQgsMapToolIdentifyAction::testIdentifyVectorTile( QgsVectorTileLayer *layer, double xGeoref, double yGeoref )
558 {
559 std::unique_ptr< QgsMapToolIdentifyAction > action( new QgsMapToolIdentifyAction( canvas ) );
560 QgsPointXY mapPoint = canvas->getCoordinateTransform()->transform( xGeoref, yGeoref );
561 QgsIdentifyContext identifyContext;
562 if ( canvas->mapSettings().isTemporal() )
563 identifyContext.setTemporalRange( canvas->temporalRange() );
564 QList<QgsMapToolIdentify::IdentifyResult> result = action->identify( mapPoint.x(), mapPoint.y(), QList<QgsMapLayer *>() << layer, QgsMapToolIdentify::DefaultQgsSetting, identifyContext );
565 return result;
566 }
567
identifyRasterFloat32()568 void TestQgsMapToolIdentifyAction::identifyRasterFloat32()
569 {
570 //create a temporary layer
571 QString raster = QStringLiteral( TEST_DATA_DIR ) + "/raster/test.asc";
572
573 // By default the QgsRasterLayer forces AAIGRID_DATATYPE=Float64
574 CPLSetConfigOption( "AAIGRID_DATATYPE", "Float32" );
575 std::unique_ptr< QgsRasterLayer> tempLayer( new QgsRasterLayer( raster ) );
576 CPLSetConfigOption( "AAIGRID_DATATYPE", nullptr );
577
578 QVERIFY( tempLayer->isValid() );
579
580 canvas->setExtent( QgsRectangle( 0, 0, 7, 1 ) );
581
582 QCOMPARE( testIdentifyRaster( tempLayer.get(), 0.5, 0.5 ), QString( "-999.9" ) );
583
584 QCOMPARE( testIdentifyRaster( tempLayer.get(), 1.5, 0.5 ), QString( "-999.987" ) );
585
586 // More than 6 significant digits for corresponding value in .asc:
587 // precision loss in Float32
588 QCOMPARE( testIdentifyRaster( tempLayer.get(), 2.5, 0.5 ), QString( "1.234568" ) ); // in .asc file : 1.2345678
589
590 QCOMPARE( testIdentifyRaster( tempLayer.get(), 3.5, 0.5 ), QString( "123456" ) );
591
592 // More than 6 significant digits: no precision loss here for that particular value
593 QCOMPARE( testIdentifyRaster( tempLayer.get(), 4.5, 0.5 ), QString( "1234567" ) );
594
595 // More than 6 significant digits: no precision loss here for that particular value
596 QCOMPARE( testIdentifyRaster( tempLayer.get(), 5.5, 0.5 ), QString( "-999.9876" ) );
597
598 // More than 6 significant digits for corresponding value in .asc:
599 // precision loss in Float32
600 QCOMPARE( testIdentifyRaster( tempLayer.get(), 6.5, 0.5 ), QString( "1.234568" ) ); // in .asc file : 1.2345678901234
601 }
602
identifyRasterFloat64()603 void TestQgsMapToolIdentifyAction::identifyRasterFloat64()
604 {
605 //create a temporary layer
606 QString raster = QStringLiteral( TEST_DATA_DIR ) + "/raster/test.asc";
607 std::unique_ptr< QgsRasterLayer> tempLayer( new QgsRasterLayer( raster ) );
608 QVERIFY( tempLayer->isValid() );
609
610 canvas->setExtent( QgsRectangle( 0, 0, 7, 1 ) );
611
612 QCOMPARE( testIdentifyRaster( tempLayer.get(), 0.5, 0.5 ), QString( "-999.9" ) );
613
614 QCOMPARE( testIdentifyRaster( tempLayer.get(), 1.5, 0.5 ), QString( "-999.987" ) );
615
616 QCOMPARE( testIdentifyRaster( tempLayer.get(), 2.5, 0.5 ), QString( "1.2345678" ) );
617
618 QCOMPARE( testIdentifyRaster( tempLayer.get(), 3.5, 0.5 ), QString( "123456" ) );
619
620 QCOMPARE( testIdentifyRaster( tempLayer.get(), 4.5, 0.5 ), QString( "1234567" ) );
621
622 QCOMPARE( testIdentifyRaster( tempLayer.get(), 5.5, 0.5 ), QString( "-999.9876" ) );
623
624 QCOMPARE( testIdentifyRaster( tempLayer.get(), 6.5, 0.5 ), QString( "1.2345678901234" ) );
625 }
626
identifyMesh()627 void TestQgsMapToolIdentifyAction::identifyMesh()
628 {
629 //create a temporary layer
630 const QString mesh = QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle.2dm";
631 QgsMeshLayer *tempLayer = new QgsMeshLayer( mesh, "testlayer", "mdal" );
632 QVERIFY( tempLayer->isValid() );
633 const QString vectorDs = QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle_vertex_vector.dat";
634 tempLayer->dataProvider()->addDataset( vectorDs );
635 static_cast<QgsMeshLayerTemporalProperties *>(
636 tempLayer->temporalProperties() )->setReferenceTime(
637 QDateTime( QDate( 1950, 01, 01 ), QTime( 0, 0, 0 ), Qt::UTC ), tempLayer->dataProvider()->temporalCapabilities() );
638
639 // we need to setup renderer otherwise triangular mesh
640 // will not be populated and identify will not work
641 QgsMapSettings mapSettings;
642 mapSettings.setExtent( tempLayer->extent() );
643 mapSettings.setDestinationCrs( tempLayer->crs() );
644 mapSettings.setOutputDpi( 96 );
645
646 // here we check that datasets automatically get our default color ramp applied ("Plasma")
647 QgsRenderContext context = QgsRenderContext::fromMapSettings( mapSettings );
648 tempLayer->createMapRenderer( context );
649
650 // only scalar dataset
651 tempLayer->temporalProperties()->setIsActive( false );
652 tempLayer->setStaticScalarDatasetIndex( QgsMeshDatasetIndex( 0, 0 ) );
653 QList<QgsMapToolIdentify::IdentifyResult> results;
654
655 results = testIdentifyMesh( tempLayer, 500, 500 );
656 QCOMPARE( results.size(), 2 );
657 QCOMPARE( results[0].mAttributes[ QStringLiteral( "Scalar Value" )], QStringLiteral( "no data" ) );
658 QCOMPARE( results[0].mDerivedAttributes[QStringLiteral( "Source" )], mesh );
659 QCOMPARE( results[1].mLabel, QStringLiteral( "Geometry" ) );
660 results = testIdentifyMesh( tempLayer, 2400, 2400 );
661 QCOMPARE( results.size(), 2 );
662 QCOMPARE( results[0].mAttributes[ QStringLiteral( "Scalar Value" )], QStringLiteral( "42" ) );
663 QCOMPARE( results[0].mDerivedAttributes[QStringLiteral( "Source" )], mesh );
664 QCOMPARE( results[1].mLabel, QStringLiteral( "Geometry" ) );
665 QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Face Centroid X" )], QStringLiteral( "2333.33" ) );
666 QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Face Centroid Y" )], QStringLiteral( "2333.33" ) );
667 results = testIdentifyMesh( tempLayer, 1999, 2999 );
668 QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Snapped Vertex Position X" )], QStringLiteral( "2000" ) );
669 QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Snapped Vertex Position Y" )], QStringLiteral( "3000" ) );
670
671 canvas->setTemporalRange( QgsDateTimeRange( QDateTime( QDate( 1950, 01, 01 ), QTime( 0, 0, 0 ), Qt::UTC ),
672 QDateTime( QDate( 1950, 01, 01 ), QTime( 1, 0, 0 ), Qt::UTC ) ) );
673
674 tempLayer->temporalProperties()->setIsActive( true );
675 results = testIdentifyMesh( tempLayer, 2400, 2400 );
676 QCOMPARE( results.size(), 3 );
677 QCOMPARE( results[0].mLabel, QStringLiteral( "Bed Elevation (active)" ) );
678 QCOMPARE( results[0].mAttributes[ QStringLiteral( "Scalar Value" )], QStringLiteral( "42" ) );
679 QCOMPARE( results[0].mDerivedAttributes[QStringLiteral( "Source" )], mesh );
680
681 QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Time Step" )], QStringLiteral( "01.01.1950 00:00:00" ) );
682
683 QCOMPARE( results[1].mLabel, QStringLiteral( "VertexVectorDataset" ) );
684 QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Source" )], vectorDs );
685 QCOMPARE( results[1].mAttributes[ QStringLiteral( "Vector Magnitude" )], QStringLiteral( "3" ) );
686 QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
687 QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );
688
689 QCOMPARE( results[2].mLabel, QStringLiteral( "Geometry" ) );
690 QCOMPARE( results[2].mDerivedAttributes[QStringLiteral( "Face Centroid X" )], QStringLiteral( "2333.33" ) );
691 QCOMPARE( results[2].mDerivedAttributes[QStringLiteral( "Face Centroid Y" )], QStringLiteral( "2333.33" ) );
692 results = testIdentifyMesh( tempLayer, 1999, 2999 );
693 QCOMPARE( results[2].mDerivedAttributes[QStringLiteral( "Snapped Vertex Position X" )], QStringLiteral( "2000" ) );
694 QCOMPARE( results[2].mDerivedAttributes[QStringLiteral( "Snapped Vertex Position Y" )], QStringLiteral( "3000" ) );
695
696 tempLayer->temporalProperties()->setIsActive( false );
697
698 // scalar + vector same
699 tempLayer->setStaticScalarDatasetIndex( QgsMeshDatasetIndex( 1, 0 ) );
700 tempLayer->setStaticVectorDatasetIndex( QgsMeshDatasetIndex( 1, 0 ) );
701 results = testIdentifyMesh( tempLayer, 500, 500 );
702 QCOMPARE( results.size(), 2 );
703 QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector Value" )], QStringLiteral( "no data" ) );
704 results = testIdentifyMesh( tempLayer, 2400, 2400 );
705 QCOMPARE( results.size(), 2 );
706 QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector Magnitude" )], QStringLiteral( "3" ) );
707 QCOMPARE( results[0].mDerivedAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
708 QCOMPARE( results[0].mDerivedAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );
709
710 // scalar + vector different
711 tempLayer->setStaticScalarDatasetIndex( QgsMeshDatasetIndex( 0, 0 ) );
712 tempLayer->setStaticVectorDatasetIndex( QgsMeshDatasetIndex( 1, 0 ) );
713 results = testIdentifyMesh( tempLayer, 2400, 2400 );
714 QCOMPARE( results.size(), 3 );
715 QCOMPARE( results[0].mAttributes[ QStringLiteral( "Scalar Value" )], QStringLiteral( "42" ) );
716 QCOMPARE( results[1].mAttributes[ QStringLiteral( "Vector Magnitude" )], QStringLiteral( "3" ) );
717 QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
718 QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );
719
720 // only vector
721 tempLayer->setStaticScalarDatasetIndex( QgsMeshDatasetIndex() );
722 tempLayer->setStaticVectorDatasetIndex( QgsMeshDatasetIndex( 1, 0 ) );
723 results = testIdentifyMesh( tempLayer, 2400, 2400 );
724 QCOMPARE( results.size(), 2 );
725 QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector Magnitude" )], QStringLiteral( "3" ) );
726 QCOMPARE( results[0].mDerivedAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
727 QCOMPARE( results[0].mDerivedAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );
728 }
729
identifyVectorTile()730 void TestQgsMapToolIdentifyAction::identifyVectorTile()
731 {
732 //create a temporary layer
733 QString vtPath = QStringLiteral( TEST_DATA_DIR ) + QStringLiteral( "/vector_tile/{z}-{x}-{y}.pbf" );
734 QgsDataSourceUri dsUri;
735 dsUri.setParam( QStringLiteral( "type" ), QStringLiteral( "xyz" ) );
736 dsUri.setParam( QStringLiteral( "url" ), QUrl::fromLocalFile( vtPath ).toString() );
737 QgsVectorTileLayer *tempLayer = new QgsVectorTileLayer( dsUri.encodedUri(), QStringLiteral( "testlayer" ) );
738 QVERIFY( tempLayer->isValid() );
739
740 QgsCoordinateReferenceSystem srs( QStringLiteral( "EPSG:3857" ) );
741 canvas->setDestinationCrs( srs );
742 canvas->setExtent( tempLayer->extent() );
743 canvas->resize( 512, 512 );
744 canvas->setLayers( QList<QgsMapLayer *>() << tempLayer );
745 canvas->setCurrentLayer( tempLayer );
746
747 QList<QgsMapToolIdentify::IdentifyResult> results;
748 results = testIdentifyVectorTile( tempLayer, 15186127, -2974969 );
749 QCOMPARE( results.size(), 1 );
750 QCOMPARE( results[0].mLayer, tempLayer );
751 QCOMPARE( results[0].mLabel, QStringLiteral( "place" ) );
752 QCOMPARE( results[0].mFeature.geometry().wkbType(), QgsWkbTypes::Point );
753 QCOMPARE( results[0].mFeature.attribute( QStringLiteral( "class" ) ).toString(), QStringLiteral( "country" ) );
754 QCOMPARE( results[0].mFeature.attribute( QStringLiteral( "name" ) ).toString(), QStringLiteral( "Australia" ) );
755
756 delete tempLayer;
757 }
758
identifyInvalidPolygons()759 void TestQgsMapToolIdentifyAction::identifyInvalidPolygons()
760 {
761 //create a temporary layer
762 std::unique_ptr< QgsVectorLayer > memoryLayer( new QgsVectorLayer( QStringLiteral( "Polygon?field=pk:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) ) );
763 QVERIFY( memoryLayer->isValid() );
764 QgsFeature f1( memoryLayer->dataProvider()->fields(), 1 );
765 f1.setAttribute( QStringLiteral( "pk" ), 1 );
766 // This geometry is an invalid polygon (3 distinct vertices).
767 // GEOS reported invalidity: Points of LinearRing do not form a closed linestring
768 f1.setGeometry( geomFromHexWKB(
769 "010300000001000000030000000000000000000000000000000000000000000000000024400000000000000000000000000000244000000000000024400000000000000000"
770 ) );
771 // TODO: check why we need the ->dataProvider() part, since
772 // there's a QgsVectorLayer::addFeatures method too
773 //memoryLayer->addFeatures( QgsFeatureList() << f1 );
774 memoryLayer->dataProvider()->addFeatures( QgsFeatureList() << f1 );
775
776 canvas->setExtent( QgsRectangle( 0, 0, 10, 10 ) );
777 QList<QgsMapToolIdentify::IdentifyResult> identified;
778 identified = testIdentifyVector( memoryLayer.get(), 4, 6 );
779 QCOMPARE( identified.length(), 0 );
780 identified = testIdentifyVector( memoryLayer.get(), 6, 4 );
781 QCOMPARE( identified.length(), 1 );
782 QCOMPARE( identified[0].mFeature.attribute( "pk" ), QVariant( 1 ) );
783
784 }
785
786
787 QGSTEST_MAIN( TestQgsMapToolIdentifyAction )
788 #include "testqgsmaptoolidentifyaction.moc"
789
790
791
792
793