QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsmaptoolidentify.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaptoolidentify.cpp - map tool for identifying features
3  ---------------------
4  begin : January 2006
5  copyright : (C) 2006 by Martin Dobias
6  email : wonder.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 "qgsapplication.h"
17 #include "qgsdistancearea.h"
18 #include "qgsfeature.h"
19 #include "qgsfeatureiterator.h"
20 #include "qgsfeaturestore.h"
21 #include "qgsfields.h"
22 #include "qgsgeometry.h"
23 #include "qgsgeometryengine.h"
24 #include "qgsidentifymenu.h"
25 #include "qgslogger.h"
26 #include "qgsmapcanvas.h"
27 #include "qgsmaptoolidentify.h"
28 #include "qgsmaptopixel.h"
29 #include "qgsmessageviewer.h"
30 #include "qgsmaplayer.h"
31 #include "qgsrasterdataprovider.h"
32 #include "qgsrasterlayer.h"
35 #include "qgsvectordataprovider.h"
36 #include "qgsvectorlayer.h"
37 #include "qgsproject.h"
38 #include "qgsrenderer.h"
39 #include "qgsgeometryutils.h"
40 #include "qgsgeometrycollection.h"
41 #include "qgscurve.h"
42 #include "qgscoordinateutils.h"
43 #include "qgsexception.h"
44 #include "qgssettings.h"
45 
46 #include <QMouseEvent>
47 #include <QCursor>
48 #include <QPixmap>
49 #include <QStatusBar>
50 #include <QVariant>
51 #include <QMenu>
52 
54  : QgsMapTool( canvas )
55  , mIdentifyMenu( new QgsIdentifyMenu( mCanvas ) )
56  , mLastMapUnitsPerPixel( -1.0 )
57  , mCoordinatePrecision( 6 )
58 {
59  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::Identify ) );
60 }
61 
63 {
64  delete mIdentifyMenu;
65 }
66 
68 {
69  Q_UNUSED( e );
70 }
71 
73 {
74  Q_UNUSED( e );
75 }
76 
78 {
79  Q_UNUSED( e );
80 }
81 
82 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, const QList<QgsMapLayer *> &layerList, IdentifyMode mode )
83 {
84  return identify( x, y, mode, layerList, AllLayers );
85 }
86 
87 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, IdentifyMode mode, LayerType layerType )
88 {
89  return identify( x, y, mode, QList<QgsMapLayer *>(), layerType );
90 }
91 
92 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, IdentifyMode mode, const QList<QgsMapLayer *> &layerList, LayerType layerType )
93 {
94  return identify( QgsGeometry::fromPointXY( toMapCoordinates( QPoint( x, y ) ) ), mode, layerList, layerType );
95 }
96 
97 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( const QgsGeometry &geometry, IdentifyMode mode, LayerType layerType )
98 {
99  return identify( geometry, mode, QList<QgsMapLayer *>(), layerType );
100 }
101 
102 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( const QgsGeometry &geometry, IdentifyMode mode, const QList<QgsMapLayer *> &layerList, LayerType layerType )
103 {
104  QList<IdentifyResult> results;
105 
106  mLastGeometry = geometry;
107  mLastExtent = mCanvas->extent();
108  mLastMapUnitsPerPixel = mCanvas->mapUnitsPerPixel();
109 
110  mCoordinatePrecision = QgsCoordinateUtils::calculateCoordinatePrecision( mLastMapUnitsPerPixel, mCanvas->mapSettings().destinationCrs() );
111 
112  if ( mode == DefaultQgsSetting )
113  {
114  QgsSettings settings;
115  mode = settings.enumValue( QStringLiteral( "Map/identifyMode" ), ActiveLayer );
116  }
117 
118  if ( mode == LayerSelection )
119  {
120  QPoint canvasPt = toCanvasCoordinates( geometry.asPoint() );
121  int x = canvasPt.x(), y = canvasPt.y();
122  QList<IdentifyResult> results = identify( x, y, TopDownAll, layerList, layerType );
123  QPoint globalPos = mCanvas->mapToGlobal( QPoint( x + 5, y + 5 ) );
124  return mIdentifyMenu->exec( results, globalPos );
125  }
126  else if ( mode == ActiveLayer && layerList.isEmpty() )
127  {
128  QgsMapLayer *layer = mCanvas->currentLayer();
129 
130  if ( !layer )
131  {
132  emit identifyMessage( tr( "No active layer. To identify features, you must choose an active layer." ) );
133  return results;
134  }
135 
136  QApplication::setOverrideCursor( Qt::WaitCursor );
137 
138  identifyLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel, layerType );
139  }
140  else
141  {
142  QApplication::setOverrideCursor( Qt::WaitCursor );
143 
144  QStringList noIdentifyLayerIdList = QgsProject::instance()->readListEntry( QStringLiteral( "Identify" ), QStringLiteral( "/disabledLayers" ) );
145 
146  int layerCount;
147  if ( layerList.isEmpty() )
148  layerCount = mCanvas->layerCount();
149  else
150  layerCount = layerList.count();
151 
152 
153  for ( int i = 0; i < layerCount; i++ )
154  {
155 
156  QgsMapLayer *layer = nullptr;
157  if ( layerList.isEmpty() )
158  layer = mCanvas->layer( i );
159  else
160  layer = layerList.value( i );
161 
162  emit identifyProgress( i, mCanvas->layerCount() );
163  emit identifyMessage( tr( "Identifying on %1…" ).arg( layer->name() ) );
164 
165  if ( noIdentifyLayerIdList.contains( layer->id() ) )
166  continue;
167 
168  if ( identifyLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel, layerType ) )
169  {
170  if ( mode == TopDownStopAtFirst )
171  break;
172  }
173  }
174 
176  emit identifyMessage( tr( "Identifying done." ) );
177  }
178 
179  QApplication::restoreOverrideCursor();
180 
181  return results;
182 }
183 
185 {
187 }
188 
190 {
192 }
193 
194 bool QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLayer *layer, const QgsPointXY &point, const QgsRectangle &viewExtent, double mapUnitsPerPixel, QgsMapToolIdentify::LayerType layerType )
195 {
196  return identifyLayer( results, layer, QgsGeometry::fromPointXY( point ), viewExtent, mapUnitsPerPixel, layerType );
197 }
198 
199 bool QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLayer *layer, const QgsGeometry &geometry, const QgsRectangle &viewExtent, double mapUnitsPerPixel, QgsMapToolIdentify::LayerType layerType )
200 {
201  if ( layer->type() == QgsMapLayer::RasterLayer && layerType.testFlag( RasterLayer ) )
202  {
203  return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), geometry, viewExtent, mapUnitsPerPixel );
204  }
205  else if ( layer->type() == QgsMapLayer::VectorLayer && layerType.testFlag( VectorLayer ) )
206  {
207  return identifyVectorLayer( results, qobject_cast<QgsVectorLayer *>( layer ), geometry );
208  }
209  else
210  {
211  return false;
212  }
213 }
214 
215 bool QgsMapToolIdentify::identifyVectorLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsVectorLayer *layer, const QgsPointXY &point )
216 {
217  return identifyVectorLayer( results, layer, QgsGeometry::fromPointXY( point ) );
218 }
219 
220 bool QgsMapToolIdentify::identifyVectorLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsVectorLayer *layer, const QgsGeometry &geometry )
221 {
222  if ( !layer || !layer->isSpatial() )
223  return false;
224 
225  if ( !layer->isInScaleRange( mCanvas->mapSettings().scale() ) )
226  {
227  QgsDebugMsg( "Out of scale limits" );
228  return false;
229  }
230 
231  QApplication::setOverrideCursor( Qt::WaitCursor );
232 
233  QMap< QString, QString > commonDerivedAttributes;
234 
235  QgsGeometry selectionGeom = geometry;
236  bool isPointOrRectangle;
237  QgsPointXY point;
238  bool isSingleClick = selectionGeom.type() == QgsWkbTypes::PointGeometry;
239  if ( isSingleClick )
240  {
241  isPointOrRectangle = true;
242  point = selectionGeom.asPoint();
243 
244  commonDerivedAttributes.insert( tr( "(clicked coordinate X)" ), formatXCoordinate( point ) );
245  commonDerivedAttributes.insert( tr( "(clicked coordinate Y)" ), formatYCoordinate( point ) );
246  }
247  else
248  {
249  // we have a polygon - maybe it is a rectangle - in such case we can avoid costly insterestion tests later
250  isPointOrRectangle = QgsGeometry::fromRect( selectionGeom.boundingBox() ).isGeosEqual( selectionGeom );
251  }
252 
253  int featureCount = 0;
254 
255  QgsFeatureList featureList;
256  std::unique_ptr<QgsGeometryEngine> selectionGeomPrepared;
257 
258  // toLayerCoordinates will throw an exception for an 'invalid' point.
259  // For example, if you project a world map onto a globe using EPSG 2163
260  // and then click somewhere off the globe, an exception will be thrown.
261  try
262  {
263  QgsRectangle r;
264  if ( isSingleClick )
265  {
266  double sr = searchRadiusMU( mCanvas );
267  r = toLayerCoordinates( layer, QgsRectangle( point.x() - sr, point.y() - sr, point.x() + sr, point.y() + sr ) );
268  }
269  else
270  {
271  r = toLayerCoordinates( layer, selectionGeom.boundingBox() );
272 
273  if ( !isPointOrRectangle )
274  {
276  if ( ct.isValid() )
277  selectionGeom.transform( ct );
278 
279  // use prepared geometry for faster intersection test
280  selectionGeomPrepared.reset( QgsGeometry::createGeometryEngine( selectionGeom.constGet() ) );
281  }
282  }
283 
284  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) );
285  QgsFeature f;
286  while ( fit.nextFeature( f ) )
287  {
288  if ( !selectionGeomPrepared || selectionGeomPrepared->intersects( f.geometry().constGet() ) )
289  featureList << QgsFeature( f );
290  }
291  }
292  catch ( QgsCsException &cse )
293  {
294  Q_UNUSED( cse );
295  // catch exception for 'invalid' point and proceed with no features found
296  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
297  }
298 
299  bool filter = false;
300 
303  std::unique_ptr< QgsFeatureRenderer > renderer( layer->renderer() ? layer->renderer()->clone() : nullptr );
304  if ( renderer )
305  {
306  // setup scale for scale dependent visibility (rule based)
307  renderer->startRender( context, layer->fields() );
308  filter = renderer->capabilities() & QgsFeatureRenderer::Filter;
309  }
310 
311  for ( const QgsFeature &feature : qgis::as_const( featureList ) )
312  {
313  QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
314 
315  QgsFeatureId fid = feature.id();
316  context.expressionContext().setFeature( feature );
317 
318  if ( filter && !renderer->willRenderFeature( feature, context ) )
319  continue;
320 
321  featureCount++;
322 
323  if ( isSingleClick )
324  derivedAttributes.unite( featureDerivedAttributes( feature, layer, toLayerCoordinates( layer, point ) ) );
325 
326  derivedAttributes.insert( tr( "Feature ID" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) );
327 
328  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), feature, derivedAttributes ) );
329  }
330 
331  if ( renderer )
332  {
333  renderer->stopRender( context );
334  }
335 
336  QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) );
337 
338  QApplication::restoreOverrideCursor();
339  return featureCount > 0;
340 }
341 
342 void QgsMapToolIdentify::closestVertexAttributes( const QgsAbstractGeometry &geometry, QgsVertexId vId, QgsMapLayer *layer, QMap< QString, QString > &derivedAttributes )
343 {
344  QString str = QLocale().toString( vId.vertex + 1 );
345  derivedAttributes.insert( tr( "Closest vertex number" ), str );
346 
347  QgsPoint closestPoint = geometry.vertexAt( vId );
348 
349  QgsPointXY closestPointMapCoords = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPointXY( closestPoint.x(), closestPoint.y() ) );
350  derivedAttributes.insert( QStringLiteral( "Closest vertex X" ), formatXCoordinate( closestPointMapCoords ) );
351  derivedAttributes.insert( QStringLiteral( "Closest vertex Y" ), formatYCoordinate( closestPointMapCoords ) );
352 
353  if ( closestPoint.is3D() )
354  {
355  str = QLocale().toString( closestPoint.z(), 'g', 10 );
356  derivedAttributes.insert( QStringLiteral( "Closest vertex Z" ), str );
357  }
358  if ( closestPoint.isMeasure() )
359  {
360  str = QLocale().toString( closestPoint.m(), 'g', 10 );
361  derivedAttributes.insert( QStringLiteral( "Closest vertex M" ), str );
362  }
363 
364  if ( vId.type == QgsVertexId::CurveVertex )
365  {
366  double radius, centerX, centerY;
367  QgsVertexId vIdBefore = vId;
368  --vIdBefore.vertex;
369  QgsVertexId vIdAfter = vId;
370  ++vIdAfter.vertex;
371  QgsGeometryUtils::circleCenterRadius( geometry.vertexAt( vIdBefore ), geometry.vertexAt( vId ),
372  geometry.vertexAt( vIdAfter ), radius, centerX, centerY );
373  derivedAttributes.insert( QStringLiteral( "Closest vertex radius" ), QLocale().toString( radius ) );
374  }
375 }
376 
377 QString QgsMapToolIdentify::formatCoordinate( const QgsPointXY &canvasPoint ) const
378 {
379  return QgsCoordinateUtils::formatCoordinateForProject( QgsProject::instance(), canvasPoint, mCanvas->mapSettings().destinationCrs(),
380  mCoordinatePrecision );
381 }
382 
383 QString QgsMapToolIdentify::formatXCoordinate( const QgsPointXY &canvasPoint ) const
384 {
385  QString coordinate = formatCoordinate( canvasPoint );
386  return coordinate.split( ',' ).at( 0 );
387 }
388 
389 QString QgsMapToolIdentify::formatYCoordinate( const QgsPointXY &canvasPoint ) const
390 {
391  QString coordinate = formatCoordinate( canvasPoint );
392  return coordinate.split( ',' ).at( 1 );
393 }
394 
395 QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( const QgsFeature &feature, QgsMapLayer *layer, const QgsPointXY &layerPoint )
396 {
397  // Calculate derived attributes and insert:
398  // measure distance or area depending on geometry type
399  QMap< QString, QString > derivedAttributes;
400 
401  // init distance/area calculator
402  QString ellipsoid = QgsProject::instance()->ellipsoid();
403  QgsDistanceArea calc;
404  calc.setEllipsoid( ellipsoid );
405  calc.setSourceCrs( layer->crs(), QgsProject::instance()->transformContext() );
406 
409 
410  QgsVertexId vId;
411  QgsPoint closestPoint;
412  if ( feature.hasGeometry() )
413  {
414  geometryType = feature.geometry().type();
415  wkbType = feature.geometry().wkbType();
416  //find closest vertex to clicked point
417  closestPoint = QgsGeometryUtils::closestVertex( *feature.geometry().constGet(), QgsPoint( layerPoint.x(), layerPoint.y() ), vId );
418  }
419 
420  if ( QgsWkbTypes::isMultiType( wkbType ) )
421  {
422  QString str = QLocale().toString( static_cast<const QgsGeometryCollection *>( feature.geometry().constGet() )->numGeometries() );
423  derivedAttributes.insert( tr( "Parts" ), str );
424  str = QLocale().toString( vId.part + 1 );
425  derivedAttributes.insert( tr( "Part number" ), str );
426  }
427 
428  QgsUnitTypes::DistanceUnit cartesianDistanceUnits = QgsUnitTypes::unitType( layer->crs().mapUnits() ) == QgsUnitTypes::unitType( displayDistanceUnits() )
429  ? displayDistanceUnits() : layer->crs().mapUnits();
430  QgsUnitTypes::AreaUnit cartesianAreaUnits = QgsUnitTypes::unitType( QgsUnitTypes::distanceToAreaUnit( layer->crs().mapUnits() ) ) == QgsUnitTypes::unitType( displayAreaUnits() )
431  ? displayAreaUnits() : QgsUnitTypes::distanceToAreaUnit( layer->crs().mapUnits() );
432 
433  if ( geometryType == QgsWkbTypes::LineGeometry )
434  {
435  double dist = calc.measureLength( feature.geometry() );
436  dist = calc.convertLengthMeasurement( dist, displayDistanceUnits() );
437  QString str;
438  if ( ellipsoid != GEO_NONE )
439  {
440  str = formatDistance( dist );
441  derivedAttributes.insert( tr( "Length (Ellipsoidal, %1)" ).arg( ellipsoid ), str );
442  }
443  str = formatDistance( feature.geometry().constGet()->length()
444  * QgsUnitTypes::fromUnitToUnitFactor( layer->crs().mapUnits(), cartesianDistanceUnits ), cartesianDistanceUnits );
445  derivedAttributes.insert( tr( "Length (Cartesian)" ), str );
446 
447  const QgsAbstractGeometry *geom = feature.geometry().constGet();
448  if ( geom )
449  {
450  str = QLocale().toString( geom->nCoordinates() );
451  derivedAttributes.insert( tr( "Vertices" ), str );
452  //add details of closest vertex to identify point
453  closestVertexAttributes( *geom, vId, layer, derivedAttributes );
454 
455  if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom ) )
456  {
457  // Add the start and end points in as derived attributes
458  QgsPointXY pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPointXY( curve->startPoint().x(), curve->startPoint().y() ) );
459  str = formatXCoordinate( pnt );
460  derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
461  str = formatYCoordinate( pnt );
462  derivedAttributes.insert( tr( "firstY" ), str );
463  pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPointXY( curve->endPoint().x(), curve->endPoint().y() ) );
464  str = formatXCoordinate( pnt );
465  derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
466  str = formatYCoordinate( pnt );
467  derivedAttributes.insert( tr( "lastY" ), str );
468  }
469  }
470  }
471  else if ( geometryType == QgsWkbTypes::PolygonGeometry )
472  {
473  double area = calc.measureArea( feature.geometry() );
474  area = calc.convertAreaMeasurement( area, displayAreaUnits() );
475  QString str;
476  if ( ellipsoid != GEO_NONE )
477  {
478  str = formatArea( area );
479  derivedAttributes.insert( tr( "Area (Ellipsoidal, %1)" ).arg( ellipsoid ), str );
480  }
481  str = formatArea( feature.geometry().area()
482  * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::distanceToAreaUnit( layer->crs().mapUnits() ), cartesianAreaUnits ), cartesianAreaUnits );
483  derivedAttributes.insert( tr( "Area (Cartesian)" ), str );
484 
485  if ( ellipsoid != GEO_NONE )
486  {
487  double perimeter = calc.measurePerimeter( feature.geometry() );
488  perimeter = calc.convertLengthMeasurement( perimeter, displayDistanceUnits() );
489  str = formatDistance( perimeter );
490  derivedAttributes.insert( tr( "Perimeter (Ellipsoidal, %1)" ).arg( ellipsoid ), str );
491  }
492  str = formatDistance( feature.geometry().constGet()->perimeter()
493  * QgsUnitTypes::fromUnitToUnitFactor( layer->crs().mapUnits(), cartesianDistanceUnits ), cartesianDistanceUnits );
494  derivedAttributes.insert( tr( "Perimeter (Cartesian)" ), str );
495 
496  str = QLocale().toString( feature.geometry().constGet()->nCoordinates() );
497  derivedAttributes.insert( tr( "Vertices" ), str );
498 
499  //add details of closest vertex to identify point
500  closestVertexAttributes( *feature.geometry().constGet(), vId, layer, derivedAttributes );
501  }
502  else if ( geometryType == QgsWkbTypes::PointGeometry )
503  {
504  if ( QgsWkbTypes::flatType( wkbType ) == QgsWkbTypes::Point )
505  {
506  // Include the x and y coordinates of the point as a derived attribute
507  QgsPointXY pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature.geometry().asPoint() );
508  QString str = formatXCoordinate( pnt );
509  derivedAttributes.insert( QStringLiteral( "X" ), str );
510  str = formatYCoordinate( pnt );
511  derivedAttributes.insert( QStringLiteral( "Y" ), str );
512 
513  if ( QgsWkbTypes::hasZ( wkbType ) )
514  {
515  str = QLocale().toString( static_cast<const QgsPoint *>( feature.geometry().constGet() )->z(), 'g', 10 );
516  derivedAttributes.insert( QStringLiteral( "Z" ), str );
517  }
518  if ( QgsWkbTypes::hasM( wkbType ) )
519  {
520  str = QLocale().toString( static_cast<const QgsPoint *>( feature.geometry().constGet() )->m(), 'g', 10 );
521  derivedAttributes.insert( QStringLiteral( "M" ), str );
522  }
523  }
524  else
525  {
526  //multipart
527 
528  //add details of closest vertex to identify point
529  const QgsAbstractGeometry *geom = feature.geometry().constGet();
530  {
531  closestVertexAttributes( *geom, vId, layer, derivedAttributes );
532  }
533  }
534  }
535 
536  return derivedAttributes;
537 }
538 
539 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, const QgsGeometry &geometry, const QgsRectangle &viewExtent, double mapUnitsPerPixel )
540 {
541  QgsPointXY point = geometry.asPoint(); // raster layers currently only support identification by point
542  return identifyRasterLayer( results, layer, point, viewExtent, mapUnitsPerPixel );
543 }
544 
545 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, QgsPointXY point, const QgsRectangle &viewExtent, double mapUnitsPerPixel )
546 {
547  QgsDebugMsg( "point = " + point.toString() );
548  if ( !layer )
549  return false;
550 
551  QgsRasterDataProvider *dprovider = layer->dataProvider();
552  if ( !dprovider )
553  return false;
554 
555  int capabilities = dprovider->capabilities();
556  if ( !( capabilities & QgsRasterDataProvider::Identify ) )
557  return false;
558 
559  QgsPointXY pointInCanvasCrs = point;
560  try
561  {
562  point = toLayerCoordinates( layer, point );
563  }
564  catch ( QgsCsException &cse )
565  {
566  Q_UNUSED( cse );
567  QgsDebugMsg( QStringLiteral( "coordinate not reprojectable: %1" ).arg( cse.what() ) );
568  return false;
569  }
570  QgsDebugMsg( QStringLiteral( "point = %1 %2" ).arg( point.x() ).arg( point.y() ) );
571 
572  if ( !layer->extent().contains( point ) )
573  return false;
574 
575  QMap< QString, QString > attributes, derivedAttributes;
576 
577  QgsRaster::IdentifyFormat format = QgsRasterDataProvider::identifyFormatFromName( layer->customProperty( QStringLiteral( "identify/format" ) ).toString() );
578 
579  // check if the format is really supported otherwise use first supported format
580  if ( !( QgsRasterDataProvider::identifyFormatToCapability( format ) & capabilities ) )
581  {
583  else if ( capabilities & QgsRasterInterface::IdentifyValue ) format = QgsRaster::IdentifyFormatValue;
584  else if ( capabilities & QgsRasterInterface::IdentifyHtml ) format = QgsRaster::IdentifyFormatHtml;
585  else if ( capabilities & QgsRasterInterface::IdentifyText ) format = QgsRaster::IdentifyFormatText;
586  else return false;
587  }
588 
589  QgsRasterIdentifyResult identifyResult;
590  // We can only use current map canvas context (extent, width, height) if layer is not reprojected,
591  if ( dprovider->crs() != mCanvas->mapSettings().destinationCrs() )
592  {
593  // To get some reasonable response for point/line WMS vector layers we must
594  // use a context with approximately a resolution in layer CRS units
595  // corresponding to current map canvas resolution (for examplei UMN Mapserver
596  // in msWMSFeatureInfo() -> msQueryByRect() is using requested pixel
597  // + TOLERANCE (layer param) for feature selection)
598  //
599  QgsRectangle r;
600  r.setXMinimum( pointInCanvasCrs.x() - mapUnitsPerPixel / 2. );
601  r.setXMaximum( pointInCanvasCrs.x() + mapUnitsPerPixel / 2. );
602  r.setYMinimum( pointInCanvasCrs.y() - mapUnitsPerPixel / 2. );
603  r.setYMaximum( pointInCanvasCrs.y() + mapUnitsPerPixel / 2. );
604  r = toLayerCoordinates( layer, r ); // will be a bit larger
605  // Mapserver (6.0.3, for example) does not work with 1x1 pixel box
606  // but that is fixed (the rect is enlarged) in the WMS provider
607  identifyResult = dprovider->identify( point, format, r, 1, 1 );
608  }
609  else
610  {
611  // It would be nice to use the same extent and size which was used for drawing,
612  // so that WCS can use cache from last draw, unfortunately QgsRasterLayer::draw()
613  // is doing some tricks with extent and size to align raster to output which
614  // would be difficult to replicate here.
615  // Note: cutting the extent may result in slightly different x and y resolutions
616  // and thus shifted point calculated back in QGIS WMS (using average resolution)
617  //viewExtent = dprovider->extent().intersect( &viewExtent );
618 
619  // Width and height are calculated from not projected extent and we hope that
620  // are similar to source width and height used to reproject layer for drawing.
621  // TODO: may be very dangerous, because it may result in different resolutions
622  // in source CRS, and WMS server (QGIS server) calcs wrong coor using average resolution.
623  int width = std::round( viewExtent.width() / mapUnitsPerPixel );
624  int height = std::round( viewExtent.height() / mapUnitsPerPixel );
625 
626  QgsDebugMsg( QStringLiteral( "viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.width() ).arg( viewExtent.height() ) );
627  QgsDebugMsg( QStringLiteral( "width = %1 height = %2" ).arg( width ).arg( height ) );
628  QgsDebugMsg( QStringLiteral( "xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.width() / width ).arg( viewExtent.height() / height ).arg( mapUnitsPerPixel ) );
629 
630  identifyResult = dprovider->identify( point, format, viewExtent, width, height );
631  }
632 
633  derivedAttributes.insert( tr( "(clicked coordinate X)" ), formatXCoordinate( pointInCanvasCrs ) );
634  derivedAttributes.insert( tr( "(clicked coordinate Y)" ), formatYCoordinate( pointInCanvasCrs ) );
635 
636  if ( identifyResult.isValid() )
637  {
638  QMap<int, QVariant> values = identifyResult.results();
639  QgsGeometry geometry;
640  if ( format == QgsRaster::IdentifyFormatValue )
641  {
642  for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
643  {
644  QString valueString;
645  if ( it.value().isNull() )
646  {
647  valueString = tr( "no data" );
648  }
649  else
650  {
651  QVariant value( it.value() );
652  // The cast is legit. Quoting QT doc :
653  // "Although this function is declared as returning QVariant::Type,
654  // the return value should be interpreted as QMetaType::Type"
655  if ( static_cast<QMetaType::Type>( value.type() ) == QMetaType::Float )
656  {
657  valueString = QgsRasterBlock::printValue( value.toFloat() );
658  }
659  else
660  {
661  valueString = QgsRasterBlock::printValue( value.toDouble() );
662  }
663  }
664  attributes.insert( dprovider->generateBandName( it.key() ), valueString );
665  }
666  QString label = layer->name();
667  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
668  }
669  else if ( format == QgsRaster::IdentifyFormatFeature )
670  {
671  for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
672  {
673  QVariant value = it.value();
674  if ( value.type() == QVariant::Bool && !value.toBool() )
675  {
676  // sublayer not visible or not queryable
677  continue;
678  }
679 
680  if ( value.type() == QVariant::String )
681  {
682  // error
683  // TODO: better error reporting
684  QString label = layer->subLayers().value( it.key() );
685  attributes.clear();
686  attributes.insert( tr( "Error" ), value.toString() );
687 
688  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
689  continue;
690  }
691 
692  // list of feature stores for a single sublayer
693  const QgsFeatureStoreList featureStoreList = it.value().value<QgsFeatureStoreList>();
694 
695  for ( const QgsFeatureStore &featureStore : featureStoreList )
696  {
697  const QgsFeatureList storeFeatures = featureStore.features();
698  for ( QgsFeature feature : storeFeatures )
699  {
700  attributes.clear();
701  // WMS sublayer and feature type, a sublayer may contain multiple feature types.
702  // Sublayer name may be the same as layer name and feature type name
703  // may be the same as sublayer. We try to avoid duplicities in label.
704  QString sublayer = featureStore.params().value( QStringLiteral( "sublayer" ) ).toString();
705  QString featureType = featureStore.params().value( QStringLiteral( "featureType" ) ).toString();
706  // Strip UMN MapServer '_feature'
707  featureType.remove( QStringLiteral( "_feature" ) );
708  QStringList labels;
709  if ( sublayer.compare( layer->name(), Qt::CaseInsensitive ) != 0 )
710  {
711  labels << sublayer;
712  }
713  if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
714  {
715  labels << featureType;
716  }
717 
718  QMap< QString, QString > derAttributes = derivedAttributes;
719  derAttributes.unite( featureDerivedAttributes( feature, layer ) );
720 
721  IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( QStringLiteral( " / " ) ), featureStore.fields(), feature, derAttributes );
722 
723  identifyResult.mParams.insert( QStringLiteral( "getFeatureInfoUrl" ), featureStore.params().value( QStringLiteral( "getFeatureInfoUrl" ) ) );
724  results->append( identifyResult );
725  }
726  }
727  }
728  }
729  else // text or html
730  {
731  QgsDebugMsg( QStringLiteral( "%1 HTML or text values" ).arg( values.size() ) );
732  for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
733  {
734  QString value = it.value().toString();
735  attributes.clear();
736  attributes.insert( QLatin1String( "" ), value );
737 
738  QString label = layer->subLayers().value( it.key() );
739  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
740  }
741  }
742  }
743  else
744  {
745  attributes.clear();
746  QString value = identifyResult.error().message( QgsErrorMessage::Text );
747  attributes.insert( tr( "Error" ), value );
748  QString label = tr( "Identify error" );
749  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
750  }
751 
752  return true;
753 }
754 
755 QgsUnitTypes::DistanceUnit QgsMapToolIdentify::displayDistanceUnits() const
756 {
757  return mCanvas->mapUnits();
758 }
759 
760 QgsUnitTypes::AreaUnit QgsMapToolIdentify::displayAreaUnits() const
761 {
763 }
764 
765 QString QgsMapToolIdentify::formatDistance( double distance ) const
766 {
767  return formatDistance( distance, displayDistanceUnits() );
768 }
769 
770 QString QgsMapToolIdentify::formatArea( double area ) const
771 {
772  return formatArea( area, displayAreaUnits() );
773 }
774 
775 QString QgsMapToolIdentify::formatDistance( double distance, QgsUnitTypes::DistanceUnit unit ) const
776 {
777  QgsSettings settings;
778  bool baseUnit = settings.value( QStringLiteral( "qgis/measure/keepbaseunit" ), true ).toBool();
779 
780  return QgsDistanceArea::formatDistance( distance, 3, unit, baseUnit );
781 }
782 
783 QString QgsMapToolIdentify::formatArea( double area, QgsUnitTypes::AreaUnit unit ) const
784 {
785  QgsSettings settings;
786  bool baseUnit = settings.value( QStringLiteral( "qgis/measure/keepbaseunit" ), true ).toBool();
787 
788  return QgsDistanceArea::formatArea( area, 3, unit, baseUnit );
789 }
790 
792 {
793  QList<IdentifyResult> results;
794  if ( identifyRasterLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel ) )
795  {
796  emit changedRasterResults( results );
797  }
798 }
799 
bool isMeasure() const
Returns true if the geometry contains m values.
Wrapper for iterator of features from vector data provider or vector layer.
A container for features with the same fields and crs.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:335
IdentifyFormat
Definition: qgsraster.h:57
A rectangle specified with double values.
Definition: qgsrectangle.h:40
Base class for all map layer types.
Definition: qgsmaplayer.h:61
double y
Definition: qgspoint.h:42
void changedRasterResults(QList< QgsMapToolIdentify::IdentifyResult > &)
QStringList subLayers() const override
Returns the sublayers of this layer.
static QString printValue(double value)
Print double value with all necessary significant digits.
static double searchRadiusMU(const QgsRenderContext &context)
Gets search radius in map units for given context.
Definition: qgsmaptool.cpp:206
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
OperationResult transform(const QgsCoordinateTransform &ct, QgsCoordinateTransform::TransformDirection direction=QgsCoordinateTransform::ForwardTransform, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
void activate() override
called when set as currently active map tool
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:134
Use exact geometry intersection (slower) instead of bounding boxes.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:557
void identifyProgress(int, int)
bool identifyLayer(QList< QgsMapToolIdentify::IdentifyResult > *results, QgsMapLayer *layer, const QgsPointXY &point, const QgsRectangle &viewExtent, double mapUnitsPerPixel, QgsMapToolIdentify::LayerType layerType=AllLayers)
Call the right method depending on layer type.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
Features may be filtered, i.e. some features may not be rendered (categorized, rule based ...
Definition: qgsrenderer.h:244
QList< QgsFeatureStore > QgsFeatureStoreList
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:549
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
#define FID_TO_STRING(fid)
Definition: qgsfeature.h:52
int layerCount() const
Returns number of layers on the map.
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
void canvasMoveEvent(QgsMapMouseEvent *e) override
Mouse move event for overriding. Default implementation does nothing.
static Capability identifyFormatToCapability(QgsRaster::IdentifyFormat format)
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:104
void canvasReleaseEvent(QgsMapMouseEvent *e) override
Mouse release event for overriding. Default implementation does nothing.
QgsPointXY toMapCoordinates(QPoint point)
transformation from screen coordinates to map coordinates
Definition: qgsmaptool.cpp:40
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Definition: qgspointxy.cpp:40
double convertLengthMeasurement(double length, QgsUnitTypes::DistanceUnit toUnits) const
Takes a length measurement calculated by this QgsDistanceArea object and converts it to a different d...
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
bool identifyRasterLayer(QList< QgsMapToolIdentify::IdentifyResult > *results, QgsRasterLayer *layer, QgsPointXY point, const QgsRectangle &viewExtent, double mapUnitsPerPixel)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
double convertAreaMeasurement(double area, QgsUnitTypes::AreaUnit toUnits) const
Takes an area measurement calculated by this QgsDistanceArea object and converts it to a different ar...
QString ellipsoid
Definition: qgsproject.h:92
void identifyMessage(const QString &)
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:190
QgsMapLayer::LayerType type() const
Returns the type of the layer.
QgsMapToolIdentify(QgsMapCanvas *canvas)
constructor
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:768
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
QgsCoordinateTransformContext transformContext() const
Returns a copy of the project&#39;s coordinate transform context, which stores various information regard...
Definition: qgsproject.cpp:543
const QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.cpp:71
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
virtual QgsRectangle extent() const
Returns the extent of the layer.
QString what() const
Definition: qgsexception.h:48
Raster identify results container.
virtual void activate()
called when set as currently active map tool
Definition: qgsmaptool.cpp:81
QgsMapCanvas * mCanvas
pointer to map canvas
Definition: qgsmaptool.h:236
QgsIdentifyMenu * mIdentifyMenu
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
QgsRasterDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
virtual double length() const
Returns the length of the geometry.
void formatChanged(QgsRasterLayer *layer)
bool isValid() const
Returns true if valid.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:67
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
QList< QgsMapToolIdentify::IdentifyResult > exec(const QList< QgsMapToolIdentify::IdentifyResult > &idResults, QPoint pos)
exec
void deactivate() override
called when map tool is being deactivated
QgsFields fields() const override
Returns the list of fields of this layer.
Utility class for identifying a unique vertex within a geometry.
static QgsRaster::IdentifyFormat identifyFormatFromName(const QString &formatName)
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
QList< QgsMapToolIdentify::IdentifyResult > identify(int x, int y, const QList< QgsMapLayer *> &layerList=QList< QgsMapLayer *>(), IdentifyMode mode=DefaultQgsSetting)
Performs the identification.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
double scale() const
Returns the calculated map scale.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:201
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:139
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
bool isSpatial() const override
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Key value accessors.
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
QgsFeatureRenderer * renderer()
Returns renderer.
The QgsIdentifyMenu class builds a menu to be used with identify results (.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:97
double measureLength(const QgsGeometry &geometry) const
Measures the length of a geometry.
Abstract base class for all geometries.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
bool identifyVectorLayer(QList< QgsMapToolIdentify::IdentifyResult > *results, QgsVectorLayer *layer, const QgsPointXY &point)
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:37
QgsWkbTypes::GeometryType type() const
Returns type of the geometry as a QgsWkbTypes::GeometryType.
double measurePerimeter(const QgsGeometry &geometry) const
Measures the perimeter of a polygon geometry.
double x
Definition: qgspointxy.h:47
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request.
QMap< int, QVariant > results() const
Returns the identify results.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
QgsExpressionContext & expressionContext()
Gets the expression context.
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:43
static Q_INVOKABLE DistanceUnitType unitType(QgsUnitTypes::DistanceUnit unit)
Returns the type for a distance unit.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:137
Abstract base class for all map tools.
Definition: qgsmaptool.h:63
A general purpose distance and area calculator, capable of performing ellipsoid based calculations...
QgsUnitTypes::DistanceUnit mapUnits() const
Convenience function for returning the current canvas map units.
Contains information about the context of a rendering operation.
QgsPointXY toLayerCoordinates(const QgsMapLayer *layer, QPoint point)
transformation from screen coordinates to layer&#39;s coordinates
Definition: qgsmaptool.cpp:52
QString message(QgsErrorMessage::Format format=QgsErrorMessage::Html) const
Full error messages description.
Definition: qgserror.cpp:49
QgsPointXY asPoint() const
Returns contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
void canvasPressEvent(QgsMapMouseEvent *e) override
Mouse press event for overriding. Default implementation does nothing.
QgsError error() const
Returns the last error.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:144
QgsPointXY layerToMapCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from layer&#39;s CRS to output CRS
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:391
virtual double perimeter() const
Returns the perimeter of the geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
virtual QgsRasterIdentifyResult identify(const QgsPointXY &point, QgsRaster::IdentifyFormat format, const QgsRectangle &boundingBox=QgsRectangle(), int width=0, int height=0, int dpi=96)
Identify raster value(s) found on the point position.
static void circleCenterRadius(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double &centerX, double &centerY)
Returns radius and center of the circle through pt1, pt2, pt3.
static QString formatArea(double area, int decimals, QgsUnitTypes::AreaUnit unit, bool keepBaseUnit=false)
Returns an area formatted as a friendly string.
Class for doing transforms between two map coordinate systems.
T enumValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on an enum.
Definition: qgssettings.h:235
qint64 QgsFeatureId
Definition: qgsfeature.h:37
double z
Definition: qgspoint.h:43
virtual void setCursor(const QCursor &cursor)
Sets a user defined cursor.
Definition: qgsmaptool.cpp:142
QString name
Definition: qgsmaplayer.h:65
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:818
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
double area() const
Returns the area of the geometry using GEOS.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
bool nextFeature(QgsFeature &f)
virtual QString generateBandName(int bandNumber) const
helper function to create zero padded band names
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
Represents a vector layer which manages a vector based data sets.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:427
static Q_INVOKABLE QgsUnitTypes::AreaUnit distanceToAreaUnit(QgsUnitTypes::DistanceUnit distanceUnit)
Converts a distance unit to its corresponding area unit, e.g., meters to square meters.
QPoint toCanvasCoordinates(const QgsPointXY &point)
transformation from map coordinates to screen coordinates
Definition: qgsmaptool.cpp:73
AreaUnit
Units of area.
Definition: qgsunittypes.h:69
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
QgsMapLayer * layer(int index)
Returns the map layer at position index in the layer stack.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
double measureArea(const QgsGeometry &geometry) const
Measures the area of a geometry.
static QgsGeometry fromPointXY(const QgsPointXY &point)
Creates a new geometry from a QgsPointXY object.
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:129
double m
Definition: qgspoint.h:44
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:208
Base class for raster data providers.
static QString formatDistance(double distance, int decimals, QgsUnitTypes::DistanceUnit unit, bool keepBaseUnit=false)
Returns an distance formatted as a friendly string.
double x
Definition: qgspoint.h:41