QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 "qgscoordinateformatter.h"
18 #include "qgsdistancearea.h"
19 #include "qgsfeature.h"
20 #include "qgsfeatureiterator.h"
21 #include "qgsfeaturestore.h"
22 #include "qgsfields.h"
23 #include "qgsgeometry.h"
24 #include "qgsgeometryengine.h"
25 #include "qgsidentifymenu.h"
26 #include "qgslogger.h"
27 #include "qgsmapcanvas.h"
28 #include "qgsmaptoolidentify.h"
29 #include "qgsmaptopixel.h"
30 #include "qgsmessageviewer.h"
31 #include "qgsmeshlayer.h"
33 #include "qgsmaplayer.h"
34 #include "qgsrasterdataprovider.h"
35 #include "qgsrasterlayer.h"
38 #include "qgsvectordataprovider.h"
39 #include "qgsvectorlayer.h"
41 #include "qgsvectortilelayer.h"
43 #include "qgsvectortileutils.h"
44 #include "qgsproject.h"
45 #include "qgsrenderer.h"
46 #include "qgstiles.h"
47 #include "qgsgeometryutils.h"
48 #include "qgsgeometrycollection.h"
49 #include "qgscurve.h"
50 #include "qgscoordinateutils.h"
51 #include "qgsexception.h"
52 #include "qgssettings.h"
54 #include "qgspointcloudlayer.h"
55 #include "qgspointcloudrenderer.h"
58 #include "qgssymbol.h"
59 #include "qgsmultilinestring.h"
60 
61 #include <QMouseEvent>
62 #include <QCursor>
63 #include <QPixmap>
64 #include <QStatusBar>
65 #include <QVariant>
66 
68  : QgsMapTool( canvas )
69  , mIdentifyMenu( new QgsIdentifyMenu( mCanvas ) )
70  , mLastMapUnitsPerPixel( -1.0 )
71  , mCoordinatePrecision( 6 )
72 {
73  setCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::Identify ) );
74 }
75 
77 {
78  delete mIdentifyMenu;
79 }
80 
82 {
83  Q_UNUSED( e )
84 }
85 
87 {
88  Q_UNUSED( e )
89 }
90 
92 {
93  Q_UNUSED( e )
94 }
95 
96 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, const QList<QgsMapLayer *> &layerList, IdentifyMode mode, const QgsIdentifyContext &identifyContext )
97 {
98  return identify( x, y, mode, layerList, AllLayers, identifyContext );
99 }
100 
101 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, IdentifyMode mode, LayerType layerType, const QgsIdentifyContext &identifyContext )
102 {
103  return identify( x, y, mode, QList<QgsMapLayer *>(), layerType, identifyContext );
104 }
105 
106 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, IdentifyMode mode, const QList<QgsMapLayer *> &layerList, LayerType layerType, const QgsIdentifyContext &identifyContext )
107 {
108  return identify( QgsGeometry::fromPointXY( toMapCoordinates( QPoint( x, y ) ) ), mode, layerList, layerType, identifyContext );
109 }
110 
111 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( const QgsGeometry &geometry, IdentifyMode mode, LayerType layerType, const QgsIdentifyContext &identifyContext )
112 {
113  return identify( geometry, mode, QList<QgsMapLayer *>(), layerType, identifyContext );
114 }
115 
116 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( const QgsGeometry &geometry, IdentifyMode mode, const QList<QgsMapLayer *> &layerList, LayerType layerType, const QgsIdentifyContext &identifyContext )
117 {
118  QList<IdentifyResult> results;
119 
120  mLastGeometry = geometry;
121  mLastExtent = mCanvas->extent();
122  mLastMapUnitsPerPixel = mCanvas->mapUnitsPerPixel();
123 
124  mCoordinatePrecision = QgsCoordinateUtils::calculateCoordinatePrecision( mLastMapUnitsPerPixel, mCanvas->mapSettings().destinationCrs() );
125 
126  if ( mode == DefaultQgsSetting )
127  {
128  QgsSettings settings;
129  mode = settings.enumValue( QStringLiteral( "Map/identifyMode" ), ActiveLayer );
130  }
131 
132  if ( mode == LayerSelection )
133  {
134  QPoint canvasPt = toCanvasCoordinates( geometry.asPoint() );
135  int x = canvasPt.x(), y = canvasPt.y();
136  QList<IdentifyResult> results = identify( x, y, TopDownAll, layerList, layerType, identifyContext );
137  QPoint globalPos = mCanvas->mapToGlobal( QPoint( x + 5, y + 5 ) );
138  return mIdentifyMenu->exec( results, globalPos );
139  }
140  else if ( mode == ActiveLayer && layerList.isEmpty() )
141  {
143 
144  if ( !layer )
145  {
146  emit identifyMessage( tr( "No active layer. To identify features, you must choose an active layer." ) );
147  return results;
148  }
149  if ( !layer->flags().testFlag( QgsMapLayer::Identifiable ) )
150  return results;
151 
152  QApplication::setOverrideCursor( Qt::WaitCursor );
153 
154  identifyLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel, layerType, identifyContext );
155  }
156  else
157  {
158  QApplication::setOverrideCursor( Qt::WaitCursor );
159 
160  QList< QgsMapLayer * > targetLayers;
161  if ( layerList.isEmpty() )
162  targetLayers = mCanvas->layers( true );
163  else
164  targetLayers = layerList;
165 
166  const int layerCount = targetLayers.size();
167  for ( int i = 0; i < layerCount; i++ )
168  {
169  QgsMapLayer *layer = targetLayers.value( i );
170 
171  emit identifyProgress( i, layerCount );
172  emit identifyMessage( tr( "Identifying on %1…" ).arg( layer->name() ) );
173 
174  if ( !layer->flags().testFlag( QgsMapLayer::Identifiable ) )
175  continue;
176 
177  if ( identifyLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel, layerType, identifyContext ) )
178  {
179  if ( mode == TopDownStopAtFirst )
180  break;
181  }
182  }
183 
184  emit identifyProgress( layerCount, layerCount );
185  emit identifyMessage( tr( "Identifying done." ) );
186  }
187 
188  QApplication::restoreOverrideCursor();
189 
190  return results;
191 }
192 
193 void QgsMapToolIdentify::setCanvasPropertiesOverrides( double searchRadiusMapUnits )
194 {
195  mOverrideCanvasSearchRadius = searchRadiusMapUnits;
196 }
197 
199 {
200  mOverrideCanvasSearchRadius = -1;
201 }
202 
204 {
206 }
207 
209 {
211 }
212 
213 bool QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLayer *layer, const QgsPointXY &point, const QgsRectangle &viewExtent, double mapUnitsPerPixel, QgsMapToolIdentify::LayerType layerType, const QgsIdentifyContext &identifyContext )
214 {
215  return identifyLayer( results, layer, QgsGeometry::fromPointXY( point ), viewExtent, mapUnitsPerPixel, layerType, identifyContext );
216 }
217 
218 bool QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLayer *layer, const QgsGeometry &geometry, const QgsRectangle &viewExtent, double mapUnitsPerPixel, QgsMapToolIdentify::LayerType layerType, const QgsIdentifyContext &identifyContext )
219 {
220  if ( layer->type() == QgsMapLayerType::RasterLayer && layerType.testFlag( RasterLayer ) )
221  {
222  return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), geometry, viewExtent, mapUnitsPerPixel, identifyContext );
223  }
224  else if ( layer->type() == QgsMapLayerType::VectorLayer && layerType.testFlag( VectorLayer ) )
225  {
226  return identifyVectorLayer( results, qobject_cast<QgsVectorLayer *>( layer ), geometry, identifyContext );
227  }
228  else if ( layer->type() == QgsMapLayerType::MeshLayer && layerType.testFlag( MeshLayer ) )
229  {
230  return identifyMeshLayer( results, qobject_cast<QgsMeshLayer *>( layer ), geometry, identifyContext );
231  }
232  else if ( layer->type() == QgsMapLayerType::VectorTileLayer && layerType.testFlag( VectorTileLayer ) )
233  {
234  return identifyVectorTileLayer( results, qobject_cast<QgsVectorTileLayer *>( layer ), geometry, identifyContext );
235  }
236  else if ( layer->type() == QgsMapLayerType::PointCloudLayer && layerType.testFlag( PointCloudLayer ) )
237  {
238  return identifyPointCloudLayer( results, qobject_cast<QgsPointCloudLayer *>( layer ), geometry, identifyContext );
239  }
240  else
241  {
242  return false;
243  }
244 }
245 
246 bool QgsMapToolIdentify::identifyVectorLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsVectorLayer *layer, const QgsPointXY &point, const QgsIdentifyContext &identifyContext )
247 {
248  return identifyVectorLayer( results, layer, QgsGeometry::fromPointXY( point ), identifyContext );
249 }
250 
251 bool QgsMapToolIdentify::identifyMeshLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsMeshLayer *layer, const QgsGeometry &geometry, const QgsIdentifyContext &identifyContext )
252 {
253  const QgsPointXY point = geometry.asPoint(); // mesh layers currently only support identification by point
254  return identifyMeshLayer( results, layer, point, identifyContext );
255 }
256 
257 bool QgsMapToolIdentify::identifyMeshLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsMeshLayer *layer, const QgsPointXY &point, const QgsIdentifyContext &identifyContext )
258 {
259  QgsDebugMsgLevel( "point = " + point.toString(), 4 );
260  if ( !layer )
261  return false;
262 
263  double searchRadius = mOverrideCanvasSearchRadius < 0 ? searchRadiusMU( mCanvas ) : mOverrideCanvasSearchRadius;
264  bool isTemporal = identifyContext.isTemporal() && layer->temporalProperties()->isActive();
265 
266  QList<QgsMeshDatasetIndex> datasetIndexList;
267  int activeScalarGroup = layer->rendererSettings().activeScalarDatasetGroup();
268  int activeVectorGroup = layer->rendererSettings().activeVectorDatasetGroup();
269 
270  const QList<int> allGroup = layer->enabledDatasetGroupsIndexes();
271  if ( isTemporal ) //non active dataset group value are only accesible if temporal is active
272  {
273  const QgsDateTimeRange &time = identifyContext.temporalRange();
274  if ( activeScalarGroup >= 0 )
275  datasetIndexList.append( layer->activeScalarDatasetAtTime( time ) );
276  if ( activeVectorGroup >= 0 && activeVectorGroup != activeScalarGroup )
277  datasetIndexList.append( layer->activeVectorDatasetAtTime( time ) );
278 
279  for ( int groupIndex : allGroup )
280  {
281  if ( groupIndex != activeScalarGroup && groupIndex != activeVectorGroup )
282  datasetIndexList.append( layer->datasetIndexAtTime( time, groupIndex ) );
283  }
284  }
285  else
286  {
287  // only active dataset group
288  if ( activeScalarGroup >= 0 )
289  datasetIndexList.append( layer->staticScalarDatasetIndex() );
290  if ( activeVectorGroup >= 0 && activeVectorGroup != activeScalarGroup )
291  datasetIndexList.append( layer->staticVectorDatasetIndex() );
292 
293  // ...and static dataset group
294  for ( int groupIndex : allGroup )
295  {
296  if ( groupIndex != activeScalarGroup && groupIndex != activeVectorGroup )
297  {
298  if ( !layer->datasetGroupMetadata( groupIndex ).isTemporal() )
299  datasetIndexList.append( groupIndex );
300  }
301  }
302  }
303 
304  //create results
305  for ( const QgsMeshDatasetIndex &index : datasetIndexList )
306  {
307  if ( !index.isValid() )
308  continue;
309 
310  const QgsMeshDatasetGroupMetadata &groupMeta = layer->datasetGroupMetadata( index );
311  QMap< QString, QString > derivedAttributes;
312 
313  QMap<QString, QString> attribute;
314  if ( groupMeta.isScalar() )
315  {
316  const QgsMeshDatasetValue scalarValue = layer->datasetValue( index, point, searchRadius );
317  const double scalar = scalarValue.scalar();
318  attribute.insert( tr( "Scalar Value" ), std::isnan( scalar ) ? tr( "no data" ) : QLocale().toString( scalar ) );
319  }
320 
321  if ( groupMeta.isVector() )
322  {
323  const QgsMeshDatasetValue vectorValue = layer->datasetValue( index, point, searchRadius );
324  const double vectorX = vectorValue.x();
325  const double vectorY = vectorValue.y();
326  if ( std::isnan( vectorX ) || std::isnan( vectorY ) )
327  attribute.insert( tr( "Vector Value" ), tr( "no data" ) );
328  else
329  {
330  attribute.insert( tr( "Vector Magnitude" ), QLocale().toString( vectorValue.scalar() ) );
331  derivedAttributes.insert( tr( "Vector x-component" ), QLocale().toString( vectorY ) );
332  derivedAttributes.insert( tr( "Vector y-component" ), QLocale().toString( vectorX ) );
333  }
334  }
335 
336  const QgsMeshDatasetMetadata &meta = layer->datasetMetadata( index );
337 
338  if ( groupMeta.isTemporal() )
339  derivedAttributes.insert( tr( "Time Step" ), layer->formatTime( meta.time() ) );
340  derivedAttributes.insert( tr( "Source" ), groupMeta.uri() );
341 
342  QString resultName = groupMeta.name();
343  if ( isTemporal && ( index.group() == activeScalarGroup || index.group() == activeVectorGroup ) )
344  resultName.append( tr( " (active)" ) );
345 
346  const IdentifyResult result( layer,
347  resultName,
348  attribute,
349  derivedAttributes );
350 
351  results->append( result );
352  }
353 
354  QMap<QString, QString> derivedGeometry;
355 
356  QgsPointXY vertexPoint = layer->snapOnElement( QgsMesh::Vertex, point, searchRadius );
357  if ( !vertexPoint.isEmpty() )
358  {
359  derivedGeometry.insert( tr( "Snapped Vertex Position X" ), QLocale().toString( vertexPoint.x() ) );
360  derivedGeometry.insert( tr( "Snapped Vertex Position Y" ), QLocale().toString( vertexPoint.y() ) );
361  }
362 
363  QgsPointXY faceCentroid = layer->snapOnElement( QgsMesh::Face, point, searchRadius );
364  if ( !faceCentroid.isEmpty() )
365  {
366  derivedGeometry.insert( tr( "Face Centroid X" ), QLocale().toString( faceCentroid.x() ) );
367  derivedGeometry.insert( tr( "Face Centroid Y" ), QLocale().toString( faceCentroid.y() ) );
368  }
369 
370  QgsPointXY pointOnEdge = layer->snapOnElement( QgsMesh::Edge, point, searchRadius );
371  if ( !pointOnEdge.isEmpty() )
372  {
373  derivedGeometry.insert( tr( "Point on Edge X" ), QLocale().toString( pointOnEdge.x() ) );
374  derivedGeometry.insert( tr( "Point on Edge Y" ), QLocale().toString( pointOnEdge.y() ) );
375  }
376 
377  const IdentifyResult result( layer,
378  tr( "Geometry" ),
380  derivedGeometry );
381 
382  results->append( result );
383 
384  return true;
385 }
386 
387 bool QgsMapToolIdentify::identifyVectorTileLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsVectorTileLayer *layer, const QgsGeometry &geometry, const QgsIdentifyContext &identifyContext )
388 {
389  Q_UNUSED( identifyContext )
390  if ( !layer || !layer->isSpatial() )
391  return false;
392 
393  if ( !layer->isInScaleRange( mCanvas->mapSettings().scale() ) )
394  {
395  QgsDebugMsgLevel( QStringLiteral( "Out of scale limits" ), 2 );
396  return false;
397  }
398 
399  QgsTemporaryCursorOverride waitCursor( Qt::WaitCursor );
400 
401  QMap< QString, QString > commonDerivedAttributes;
402 
403  QgsGeometry selectionGeom = geometry;
404  bool isPointOrRectangle;
405  QgsPointXY point;
406  bool isSingleClick = selectionGeom.type() == QgsWkbTypes::PointGeometry;
407  if ( isSingleClick )
408  {
409  isPointOrRectangle = true;
410  point = selectionGeom.asPoint();
411 
412  commonDerivedAttributes = derivedAttributesForPoint( QgsPoint( point ) );
413  }
414  else
415  {
416  // we have a polygon - maybe it is a rectangle - in such case we can avoid costly insterestion tests later
417  isPointOrRectangle = QgsGeometry::fromRect( selectionGeom.boundingBox() ).isGeosEqual( selectionGeom );
418  }
419 
420  int featureCount = 0;
421 
422  std::unique_ptr<QgsGeometryEngine> selectionGeomPrepared;
423 
424  // toLayerCoordinates will throw an exception for an 'invalid' point.
425  // For example, if you project a world map onto a globe using EPSG 2163
426  // and then click somewhere off the globe, an exception will be thrown.
427  try
428  {
429  QgsRectangle r;
430  if ( isSingleClick )
431  {
432  double sr = mOverrideCanvasSearchRadius < 0 ? searchRadiusMU( mCanvas ) : mOverrideCanvasSearchRadius;
433  r = toLayerCoordinates( layer, QgsRectangle( point.x() - sr, point.y() - sr, point.x() + sr, point.y() + sr ) );
434  }
435  else
436  {
437  r = toLayerCoordinates( layer, selectionGeom.boundingBox() );
438 
439  if ( !isPointOrRectangle )
440  {
442  if ( ct.isValid() )
443  selectionGeom.transform( ct );
444 
445  // use prepared geometry for faster intersection test
446  selectionGeomPrepared.reset( QgsGeometry::createGeometryEngine( selectionGeom.constGet() ) );
447  }
448  }
449 
450  const int tileZoom = layer->tileMatrixSet().scaleToZoomLevel( mCanvas->scale() );
451  const QgsTileMatrix tileMatrix = layer->tileMatrixSet().tileMatrix( tileZoom );
452  const QgsTileRange tileRange = tileMatrix.tileRangeFromExtent( r );
453 
454  for ( int row = tileRange.startRow(); row <= tileRange.endRow(); ++row )
455  {
456  for ( int col = tileRange.startColumn(); col <= tileRange.endColumn(); ++col )
457  {
458  QgsTileXYZ tileID( col, row, tileZoom );
459  QByteArray data = layer->getRawTile( tileID );
460  if ( data.isEmpty() )
461  continue; // failed to get data
462 
463  QgsVectorTileMVTDecoder decoder( layer->tileMatrixSet() );
464  if ( !decoder.decode( tileID, data ) )
465  continue; // failed to decode
466 
467  QMap<QString, QgsFields> perLayerFields;
468  const QStringList layerNames = decoder.layers();
469  for ( const QString &layerName : layerNames )
470  {
471  QSet<QString> fieldNames = qgis::listToSet( decoder.layerFieldNames( layerName ) );
472  perLayerFields[layerName] = QgsVectorTileUtils::makeQgisFields( fieldNames );
473  }
474 
475  const QgsVectorTileFeatures features = decoder.layerFeatures( perLayerFields, QgsCoordinateTransform() );
476  const QStringList featuresLayerNames = features.keys();
477  for ( const QString &layerName : featuresLayerNames )
478  {
479  const QgsFields fFields = perLayerFields[layerName];
480  const QVector<QgsFeature> &layerFeatures = features[layerName];
481  for ( const QgsFeature &f : layerFeatures )
482  {
483  if ( f.geometry().intersects( r ) && ( !selectionGeomPrepared || selectionGeomPrepared->intersects( f.geometry().constGet() ) ) )
484  {
485  QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
486  derivedAttributes.insert( tr( "Feature ID" ), FID_TO_STRING( f.id() ) );
487 
488  results->append( IdentifyResult( layer, layerName, fFields, f, derivedAttributes ) );
489 
490  featureCount++;
491  }
492  }
493  }
494  }
495  }
496 
497  }
498  catch ( QgsCsException &cse )
499  {
500  Q_UNUSED( cse )
501  // catch exception for 'invalid' point and proceed with no features found
502  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
503  }
504 
505  return featureCount > 0;
506 }
507 
508 bool QgsMapToolIdentify::identifyPointCloudLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsPointCloudLayer *layer, const QgsGeometry &geometry, const QgsIdentifyContext &identifyContext )
509 {
510  Q_UNUSED( identifyContext )
511  QgsPointCloudRenderer *renderer = layer->renderer();
512 
515 
516  const double searchRadiusMapUnits = mOverrideCanvasSearchRadius < 0 ? searchRadiusMU( mCanvas ) : mOverrideCanvasSearchRadius;
517 
518  const QVector<QVariantMap> points = renderer->identify( layer, context, geometry, searchRadiusMapUnits );
519 
521 
522  return true;
523 }
524 
525 QMap<QString, QString> QgsMapToolIdentify::derivedAttributesForPoint( const QgsPoint &point )
526 {
527  QMap< QString, QString > derivedAttributes;
528  derivedAttributes.insert( tr( "(clicked coordinate X)" ), formatXCoordinate( point ) );
529  derivedAttributes.insert( tr( "(clicked coordinate Y)" ), formatYCoordinate( point ) );
530  if ( point.is3D() )
531  derivedAttributes.insert( tr( "(clicked coordinate Z)" ), QLocale().toString( point.z(), 'f' ) );
532  return derivedAttributes;
533 }
534 
535 bool QgsMapToolIdentify::identifyVectorLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsVectorLayer *layer, const QgsGeometry &geometry, const QgsIdentifyContext &identifyContext )
536 {
537  if ( !layer || !layer->isSpatial() || !layer->dataProvider() )
538  return false;
539 
540  if ( !layer->isInScaleRange( mCanvas->mapSettings().scale() ) )
541  {
542  QgsDebugMsg( QStringLiteral( "Out of scale limits" ) );
543  return false;
544  }
545 
546  QString temporalFilter;
547  if ( identifyContext.isTemporal() )
548  {
549  if ( !layer->temporalProperties()->isVisibleInTemporalRange( identifyContext.temporalRange() ) )
550  return false;
551 
552  QgsVectorLayerTemporalContext temporalContext;
553  temporalContext.setLayer( layer );
554  temporalFilter = qobject_cast< const QgsVectorLayerTemporalProperties * >( layer->temporalProperties() )->createFilterString( temporalContext, identifyContext.temporalRange() );
555  }
556 
557  const bool fetchFeatureSymbols = layer->dataProvider()->capabilities() & QgsVectorDataProvider::FeatureSymbology;
558 
559  QApplication::setOverrideCursor( Qt::WaitCursor );
560 
561  QMap< QString, QString > commonDerivedAttributes;
562 
563  QgsGeometry selectionGeom = geometry;
564  bool isPointOrRectangle;
565  QgsPointXY point;
566  bool isSingleClick = selectionGeom.type() == QgsWkbTypes::PointGeometry;
567  if ( isSingleClick )
568  {
569  isPointOrRectangle = true;
570  point = selectionGeom.asPoint();
571 
572  commonDerivedAttributes = derivedAttributesForPoint( QgsPoint( point ) );
573  }
574  else
575  {
576  // we have a polygon - maybe it is a rectangle - in such case we can avoid costly insterestion tests later
577  isPointOrRectangle = QgsGeometry::fromRect( selectionGeom.boundingBox() ).isGeosEqual( selectionGeom );
578  }
579 
580  int featureCount = 0;
581 
582  QgsFeatureList featureList;
583  std::unique_ptr<QgsGeometryEngine> selectionGeomPrepared;
584 
585  // toLayerCoordinates will throw an exception for an 'invalid' point.
586  // For example, if you project a world map onto a globe using EPSG 2163
587  // and then click somewhere off the globe, an exception will be thrown.
588  try
589  {
590  QgsRectangle r;
591  if ( isSingleClick )
592  {
593  double sr = mOverrideCanvasSearchRadius < 0 ? searchRadiusMU( mCanvas ) : mOverrideCanvasSearchRadius;
594  r = toLayerCoordinates( layer, QgsRectangle( point.x() - sr, point.y() - sr, point.x() + sr, point.y() + sr ) );
595  }
596  else
597  {
598  r = toLayerCoordinates( layer, selectionGeom.boundingBox() );
599 
600  if ( !isPointOrRectangle )
601  {
603  if ( ct.isValid() )
604  selectionGeom.transform( ct );
605 
606  // use prepared geometry for faster intersection test
607  selectionGeomPrepared.reset( QgsGeometry::createGeometryEngine( selectionGeom.constGet() ) );
608  }
609  }
610 
611  QgsFeatureRequest featureRequest;
612  featureRequest.setFilterRect( r );
613  featureRequest.setFlags( QgsFeatureRequest::ExactIntersect | ( fetchFeatureSymbols ? QgsFeatureRequest::EmbeddedSymbols : QgsFeatureRequest::Flags() ) );
614  if ( !temporalFilter.isEmpty() )
615  featureRequest.setFilterExpression( temporalFilter );
616 
617  QgsFeatureIterator fit = layer->getFeatures( featureRequest );
618  QgsFeature f;
619  while ( fit.nextFeature( f ) )
620  {
621  if ( !selectionGeomPrepared || selectionGeomPrepared->intersects( f.geometry().constGet() ) )
622  featureList << QgsFeature( f );
623  }
624  }
625  catch ( QgsCsException &cse )
626  {
627  Q_UNUSED( cse )
628  // catch exception for 'invalid' point and proceed with no features found
629  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
630  }
631 
632  bool filter = false;
633 
637  std::unique_ptr< QgsFeatureRenderer > renderer( layer->renderer() ? layer->renderer()->clone() : nullptr );
638  if ( renderer )
639  {
640  // setup scale for scale dependent visibility (rule based)
641  renderer->startRender( context, layer->fields() );
642  filter = renderer->capabilities() & QgsFeatureRenderer::Filter;
643  }
644 
645  for ( const QgsFeature &feature : std::as_const( featureList ) )
646  {
647  QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
648 
649  QgsFeatureId fid = feature.id();
650  context.expressionContext().setFeature( feature );
651 
652  if ( filter && !renderer->willRenderFeature( feature, context ) )
653  continue;
654 
655  featureCount++;
656 
657  // When not single click identify, pass an empty point so some derived attributes may still be computed
658  if ( !isSingleClick )
659  point = QgsPointXY();
660  derivedAttributes.unite( featureDerivedAttributes( feature, layer, toLayerCoordinates( layer, point ) ) );
661 
662  derivedAttributes.insert( tr( "Feature ID" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) );
663 
664  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), feature, derivedAttributes ) );
665  }
666 
667  if ( renderer )
668  {
669  renderer->stopRender( context );
670  }
671 
672  QgsDebugMsgLevel( "Feature count on identify: " + QString::number( featureCount ), 2 );
673 
674  QApplication::restoreOverrideCursor();
675  return featureCount > 0;
676 }
677 
678 void QgsMapToolIdentify::closestVertexAttributes( const QgsAbstractGeometry &geometry, QgsVertexId vId, QgsMapLayer *layer, QMap< QString, QString > &derivedAttributes )
679 {
680  if ( ! vId.isValid( ) )
681  {
682  // We should not get here ...
683  QgsDebugMsg( "Invalid vertex id!" );
684  return;
685  }
686 
687  QString str = QLocale().toString( vId.vertex + 1 );
688  derivedAttributes.insert( tr( "Closest vertex number" ), str );
689 
690  QgsPoint closestPoint = geometry.vertexAt( vId );
691 
692  QgsPointXY closestPointMapCoords = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPointXY( closestPoint.x(), closestPoint.y() ) );
693  derivedAttributes.insert( tr( "Closest vertex X" ), formatXCoordinate( closestPointMapCoords ) );
694  derivedAttributes.insert( tr( "Closest vertex Y" ), formatYCoordinate( closestPointMapCoords ) );
695 
696  if ( closestPoint.is3D() )
697  {
698  str = QLocale().toString( closestPoint.z(), 'g', 10 );
699  derivedAttributes.insert( tr( "Closest vertex Z" ), str );
700  }
701  if ( closestPoint.isMeasure() )
702  {
703  str = QLocale().toString( closestPoint.m(), 'g', 10 );
704  derivedAttributes.insert( tr( "Closest vertex M" ), str );
705  }
706 
707  if ( vId.type == Qgis::VertexType::Curve )
708  {
709  double radius, centerX, centerY;
710  QgsVertexId vIdBefore = vId;
711  --vIdBefore.vertex;
712  QgsVertexId vIdAfter = vId;
713  ++vIdAfter.vertex;
714  QgsGeometryUtils::circleCenterRadius( geometry.vertexAt( vIdBefore ), geometry.vertexAt( vId ),
715  geometry.vertexAt( vIdAfter ), radius, centerX, centerY );
716  derivedAttributes.insert( QStringLiteral( "Closest vertex radius" ), QLocale().toString( radius ) );
717  }
718 }
719 
720 void QgsMapToolIdentify::closestPointAttributes( const QgsAbstractGeometry &geometry, const QgsPointXY &layerPoint, QMap<QString, QString> &derivedAttributes )
721 {
722  QgsPoint closestPoint = QgsGeometryUtils::closestPoint( geometry, QgsPoint( layerPoint ) );
723 
724  derivedAttributes.insert( tr( "Closest X" ), formatXCoordinate( closestPoint ) );
725  derivedAttributes.insert( tr( "Closest Y" ), formatYCoordinate( closestPoint ) );
726 
727  if ( closestPoint.is3D() )
728  {
729  const QString str = QLocale().toString( closestPoint.z(), 'g', 10 );
730  derivedAttributes.insert( tr( "Interpolated Z" ), str );
731  }
732  if ( closestPoint.isMeasure() )
733  {
734  const QString str = QLocale().toString( closestPoint.m(), 'g', 10 );
735  derivedAttributes.insert( tr( "Interpolated M" ), str );
736  }
737 }
738 
739 QString QgsMapToolIdentify::formatCoordinate( const QgsPointXY &canvasPoint ) const
740 {
741  return QgsCoordinateUtils::formatCoordinateForProject( QgsProject::instance(), canvasPoint, mCanvas->mapSettings().destinationCrs(),
742  mCoordinatePrecision );
743 }
744 
745 QString QgsMapToolIdentify::formatXCoordinate( const QgsPointXY &canvasPoint ) const
746 {
747  QString coordinate = formatCoordinate( canvasPoint );
748  return coordinate.split( QgsCoordinateFormatter::separator() ).at( 0 );
749 }
750 
751 QString QgsMapToolIdentify::formatYCoordinate( const QgsPointXY &canvasPoint ) const
752 {
753  QString coordinate = formatCoordinate( canvasPoint );
754  return coordinate.split( QgsCoordinateFormatter::separator() ).at( 1 );
755 }
756 
757 QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( const QgsFeature &feature, QgsMapLayer *layer, const QgsPointXY &layerPoint )
758 {
759  // Calculate derived attributes and insert:
760  // measure distance or area depending on geometry type
761  QMap< QString, QString > derivedAttributes;
762 
763  // init distance/area calculator
764  QString ellipsoid = QgsProject::instance()->ellipsoid();
765  QgsDistanceArea calc;
766  calc.setEllipsoid( ellipsoid );
768 
771 
772  QgsVertexId vId;
773  QgsPoint closestPoint;
774  if ( feature.hasGeometry() )
775  {
776  geometryType = feature.geometry().type();
777  wkbType = feature.geometry().wkbType();
778  if ( !layerPoint.isEmpty() )
779  {
780  //find closest vertex to clicked point
781  closestPoint = QgsGeometryUtils::closestVertex( *feature.geometry().constGet(), QgsPoint( layerPoint ), vId );
782  }
783  }
784 
785 
786 
787  if ( QgsWkbTypes::isMultiType( wkbType ) )
788  {
789  QString str = QLocale().toString( static_cast<const QgsGeometryCollection *>( feature.geometry().constGet() )->numGeometries() );
790  derivedAttributes.insert( tr( "Parts" ), str );
791  if ( !layerPoint.isEmpty() )
792  {
793  str = QLocale().toString( vId.part + 1 );
794  derivedAttributes.insert( tr( "Part number" ), str );
795  }
796  }
797 
798  QgsUnitTypes::DistanceUnit cartesianDistanceUnits = QgsUnitTypes::unitType( layer->crs().mapUnits() ) == QgsUnitTypes::unitType( displayDistanceUnits() )
799  ? displayDistanceUnits() : layer->crs().mapUnits();
801  ? displayAreaUnits() : QgsUnitTypes::distanceToAreaUnit( layer->crs().mapUnits() );
802 
803  if ( geometryType == QgsWkbTypes::LineGeometry )
804  {
805  const QgsAbstractGeometry *geom = feature.geometry().constGet();
806 
807  double dist = calc.measureLength( feature.geometry() );
808  dist = calc.convertLengthMeasurement( dist, displayDistanceUnits() );
809  QString str;
810  if ( ellipsoid != geoNone() )
811  {
812  str = formatDistance( dist );
813  derivedAttributes.insert( tr( "Length (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
814  }
815 
816  str = formatDistance( geom->length()
817  * QgsUnitTypes::fromUnitToUnitFactor( layer->crs().mapUnits(), cartesianDistanceUnits ), cartesianDistanceUnits );
818  if ( QgsWkbTypes::hasZ( geom->wkbType() )
820  {
821  // 3d linestring (or multiline)
822  derivedAttributes.insert( tr( "Length (Cartesian — 2D)" ), str );
823 
824  double totalLength3d = std::accumulate( geom->const_parts_begin(), geom->const_parts_end(), 0.0, []( double total, const QgsAbstractGeometry * part )
825  {
826  return total + qgsgeometry_cast< const QgsLineString * >( part )->length3D();
827  } );
828 
829  str = formatDistance( totalLength3d, cartesianDistanceUnits );
830  derivedAttributes.insert( tr( "Length (Cartesian — 3D)" ), str );
831  }
832  else
833  {
834  derivedAttributes.insert( tr( "Length (Cartesian)" ), str );
835  }
836 
837  str = QLocale().toString( geom->nCoordinates() );
838  derivedAttributes.insert( tr( "Vertices" ), str );
839  if ( !layerPoint.isEmpty() )
840  {
841  //add details of closest vertex to identify point
842  closestVertexAttributes( *geom, vId, layer, derivedAttributes );
843  closestPointAttributes( *geom, layerPoint, derivedAttributes );
844  }
845 
846  if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom ) )
847  {
848  // Add the start and end points in as derived attributes
849  QgsPointXY pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPointXY( curve->startPoint().x(), curve->startPoint().y() ) );
850  str = formatXCoordinate( pnt );
851  derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
852  str = formatYCoordinate( pnt );
853  derivedAttributes.insert( tr( "firstY" ), str );
854  pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPointXY( curve->endPoint().x(), curve->endPoint().y() ) );
855  str = formatXCoordinate( pnt );
856  derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
857  str = formatYCoordinate( pnt );
858  derivedAttributes.insert( tr( "lastY" ), str );
859  }
860  }
861  else if ( geometryType == QgsWkbTypes::PolygonGeometry )
862  {
863  double area = calc.measureArea( feature.geometry() );
864  area = calc.convertAreaMeasurement( area, displayAreaUnits() );
865  QString str;
866  if ( ellipsoid != geoNone() )
867  {
868  str = formatArea( area );
869  derivedAttributes.insert( tr( "Area (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
870  }
871  str = formatArea( feature.geometry().area()
872  * QgsUnitTypes::fromUnitToUnitFactor( QgsUnitTypes::distanceToAreaUnit( layer->crs().mapUnits() ), cartesianAreaUnits ), cartesianAreaUnits );
873  derivedAttributes.insert( tr( "Area (Cartesian)" ), str );
874 
875  if ( ellipsoid != geoNone() )
876  {
877  double perimeter = calc.measurePerimeter( feature.geometry() );
878  perimeter = calc.convertLengthMeasurement( perimeter, displayDistanceUnits() );
879  str = formatDistance( perimeter );
880  derivedAttributes.insert( tr( "Perimeter (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
881  }
882  str = formatDistance( feature.geometry().constGet()->perimeter()
883  * QgsUnitTypes::fromUnitToUnitFactor( layer->crs().mapUnits(), cartesianDistanceUnits ), cartesianDistanceUnits );
884  derivedAttributes.insert( tr( "Perimeter (Cartesian)" ), str );
885 
886  str = QLocale().toString( feature.geometry().constGet()->nCoordinates() );
887  derivedAttributes.insert( tr( "Vertices" ), str );
888 
889  if ( !layerPoint.isEmpty() )
890  {
891  //add details of closest vertex to identify point
892  closestVertexAttributes( *feature.geometry().constGet(), vId, layer, derivedAttributes );
893  closestPointAttributes( *feature.geometry().constGet(), layerPoint, derivedAttributes );
894  }
895  }
896  else if ( geometryType == QgsWkbTypes::PointGeometry )
897  {
898  if ( QgsWkbTypes::flatType( wkbType ) == QgsWkbTypes::Point )
899  {
900  // Include the x and y coordinates of the point as a derived attribute
902  QString str = formatXCoordinate( pnt );
903  derivedAttributes.insert( tr( "X" ), str );
904  str = formatYCoordinate( pnt );
905  derivedAttributes.insert( tr( "Y" ), str );
906 
907  if ( QgsWkbTypes::hasZ( wkbType ) )
908  {
909  str = QLocale().toString( static_cast<const QgsPoint *>( feature.geometry().constGet() )->z(), 'g', 10 );
910  derivedAttributes.insert( tr( "Z" ), str );
911  }
912  if ( QgsWkbTypes::hasM( wkbType ) )
913  {
914  str = QLocale().toString( static_cast<const QgsPoint *>( feature.geometry().constGet() )->m(), 'g', 10 );
915  derivedAttributes.insert( tr( "M" ), str );
916  }
917  }
918  else
919  {
920  //multipart
921 
922  if ( !layerPoint.isEmpty() )
923  {
924  //add details of closest vertex to identify point
925  const QgsAbstractGeometry *geom = feature.geometry().constGet();
926  closestVertexAttributes( *geom, vId, layer, derivedAttributes );
927  }
928  }
929  }
930 
931  if ( feature.embeddedSymbol() )
932  {
933  derivedAttributes.insert( tr( "Embedded Symbol" ), tr( "%1 (%2)" ).arg( QgsSymbol::symbolTypeToString( feature.embeddedSymbol()->type() ), feature.embeddedSymbol()->color().name() ) );
934  }
935 
936  return derivedAttributes;
937 }
938 
939 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, const QgsGeometry &geometry, const QgsRectangle &viewExtent, double mapUnitsPerPixel, const QgsIdentifyContext &identifyContext )
940 {
941  QgsPointXY point = geometry.asPoint(); // raster layers currently only support identification by point
942  return identifyRasterLayer( results, layer, point, viewExtent, mapUnitsPerPixel, identifyContext );
943 }
944 
945 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, QgsPointXY point, const QgsRectangle &viewExtent, double mapUnitsPerPixel, const QgsIdentifyContext &identifyContext )
946 {
947  QgsDebugMsg( "point = " + point.toString() );
948  if ( !layer )
949  return false;
950 
951  std::unique_ptr< QgsRasterDataProvider > dprovider( layer->dataProvider()->clone() );
952  if ( !dprovider )
953  return false;
954 
955  int capabilities = dprovider->capabilities();
956  if ( !( capabilities & QgsRasterDataProvider::Identify ) )
957  return false;
958 
959  if ( identifyContext.isTemporal() )
960  {
961  if ( !layer->temporalProperties()->isVisibleInTemporalRange( identifyContext.temporalRange() ) )
962  return false;
963 
964  dprovider->temporalCapabilities()->setRequestedTemporalRange( identifyContext.temporalRange() );
965  }
966 
967  QgsPointXY pointInCanvasCrs = point;
968  try
969  {
970  point = toLayerCoordinates( layer, point );
971  }
972  catch ( QgsCsException &cse )
973  {
974  Q_UNUSED( cse )
975  QgsDebugMsg( QStringLiteral( "coordinate not reprojectable: %1" ).arg( cse.what() ) );
976  return false;
977  }
978  QgsDebugMsg( QStringLiteral( "point = %1 %2" ).arg( point.x() ).arg( point.y() ) );
979 
980  if ( !layer->extent().contains( point ) )
981  return false;
982 
983  QMap< QString, QString > attributes, derivedAttributes;
984 
985  QgsRaster::IdentifyFormat format = QgsRasterDataProvider::identifyFormatFromName( layer->customProperty( QStringLiteral( "identify/format" ) ).toString() );
986 
987  // check if the format is really supported otherwise use first supported format
988  if ( !( QgsRasterDataProvider::identifyFormatToCapability( format ) & capabilities ) )
989  {
991  else if ( capabilities & QgsRasterInterface::IdentifyValue ) format = QgsRaster::IdentifyFormatValue;
992  else if ( capabilities & QgsRasterInterface::IdentifyHtml ) format = QgsRaster::IdentifyFormatHtml;
993  else if ( capabilities & QgsRasterInterface::IdentifyText ) format = QgsRaster::IdentifyFormatText;
994  else return false;
995  }
996 
997  QgsRasterIdentifyResult identifyResult;
998  // We can only use current map canvas context (extent, width, height) if layer is not reprojected,
999  if ( dprovider->crs() != mCanvas->mapSettings().destinationCrs() )
1000  {
1001  // To get some reasonable response for point/line WMS vector layers we must
1002  // use a context with approximately a resolution in layer CRS units
1003  // corresponding to current map canvas resolution (for examplei UMN Mapserver
1004  // in msWMSFeatureInfo() -> msQueryByRect() is using requested pixel
1005  // + TOLERANCE (layer param) for feature selection)
1006  //
1007  QgsRectangle r;
1008  r.setXMinimum( pointInCanvasCrs.x() - mapUnitsPerPixel / 2. );
1009  r.setXMaximum( pointInCanvasCrs.x() + mapUnitsPerPixel / 2. );
1010  r.setYMinimum( pointInCanvasCrs.y() - mapUnitsPerPixel / 2. );
1011  r.setYMaximum( pointInCanvasCrs.y() + mapUnitsPerPixel / 2. );
1012  r = toLayerCoordinates( layer, r ); // will be a bit larger
1013  // Mapserver (6.0.3, for example) does not work with 1x1 pixel box
1014  // but that is fixed (the rect is enlarged) in the WMS provider
1015  identifyResult = dprovider->identify( point, format, r, 1, 1 );
1016  }
1017  else
1018  {
1019  // It would be nice to use the same extent and size which was used for drawing,
1020  // so that WCS can use cache from last draw, unfortunately QgsRasterLayer::draw()
1021  // is doing some tricks with extent and size to align raster to output which
1022  // would be difficult to replicate here.
1023  // Note: cutting the extent may result in slightly different x and y resolutions
1024  // and thus shifted point calculated back in QGIS WMS (using average resolution)
1025  //viewExtent = dprovider->extent().intersect( &viewExtent );
1026 
1027  // Width and height are calculated from not projected extent and we hope that
1028  // are similar to source width and height used to reproject layer for drawing.
1029  // TODO: may be very dangerous, because it may result in different resolutions
1030  // in source CRS, and WMS server (QGIS server) calcs wrong coor using average resolution.
1031  int width = static_cast< int >( std::round( viewExtent.width() / mapUnitsPerPixel ) );
1032  int height = static_cast< int >( std::round( viewExtent.height() / mapUnitsPerPixel ) );
1033 
1034  QgsDebugMsg( QStringLiteral( "viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.width() ).arg( viewExtent.height() ) );
1035  QgsDebugMsg( QStringLiteral( "width = %1 height = %2" ).arg( width ).arg( height ) );
1036  QgsDebugMsg( QStringLiteral( "xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.width() / width ).arg( viewExtent.height() / height ).arg( mapUnitsPerPixel ) );
1037 
1038  identifyResult = dprovider->identify( point, format, viewExtent, width, height );
1039  }
1040 
1041  derivedAttributes.unite( derivedAttributesForPoint( QgsPoint( pointInCanvasCrs ) ) );
1042 
1043  if ( identifyResult.isValid() )
1044  {
1045  QMap<int, QVariant> values = identifyResult.results();
1046  QgsGeometry geometry;
1047  if ( format == QgsRaster::IdentifyFormatValue )
1048  {
1049  for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
1050  {
1051  QString valueString;
1052  if ( it.value().isNull() )
1053  {
1054  valueString = tr( "no data" );
1055  }
1056  else
1057  {
1058  QVariant value( it.value() );
1059  // The cast is legit. Quoting QT doc :
1060  // "Although this function is declared as returning QVariant::Type,
1061  // the return value should be interpreted as QMetaType::Type"
1062  if ( static_cast<QMetaType::Type>( value.type() ) == QMetaType::Float )
1063  {
1064  valueString = QgsRasterBlock::printValue( value.toFloat() );
1065  }
1066  else
1067  {
1068  valueString = QgsRasterBlock::printValue( value.toDouble() );
1069  }
1070  }
1071  attributes.insert( dprovider->generateBandName( it.key() ), valueString );
1072  }
1073  QString label = layer->name();
1074  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
1075  }
1076  else if ( format == QgsRaster::IdentifyFormatFeature )
1077  {
1078  for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
1079  {
1080  QVariant value = it.value();
1081  if ( value.type() == QVariant::Bool && !value.toBool() )
1082  {
1083  // sublayer not visible or not queryable
1084  continue;
1085  }
1086 
1087  if ( value.type() == QVariant::String )
1088  {
1089  // error
1090  // TODO: better error reporting
1091  QString label = layer->subLayers().value( it.key() );
1092  attributes.clear();
1093  attributes.insert( tr( "Error" ), value.toString() );
1094 
1095  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
1096  continue;
1097  }
1098 
1099  // list of feature stores for a single sublayer
1100  const QgsFeatureStoreList featureStoreList = value.value<QgsFeatureStoreList>();
1101 
1102  for ( const QgsFeatureStore &featureStore : featureStoreList )
1103  {
1104  const QgsFeatureList storeFeatures = featureStore.features();
1105  for ( const QgsFeature &feature : storeFeatures )
1106  {
1107  attributes.clear();
1108  // WMS sublayer and feature type, a sublayer may contain multiple feature types.
1109  // Sublayer name may be the same as layer name and feature type name
1110  // may be the same as sublayer. We try to avoid duplicities in label.
1111  QString sublayer = featureStore.params().value( QStringLiteral( "sublayer" ) ).toString();
1112  QString featureType = featureStore.params().value( QStringLiteral( "featureType" ) ).toString();
1113  // Strip UMN MapServer '_feature'
1114  featureType.remove( QStringLiteral( "_feature" ) );
1115  QStringList labels;
1116  if ( sublayer.compare( layer->name(), Qt::CaseInsensitive ) != 0 )
1117  {
1118  labels << sublayer;
1119  }
1120  if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
1121  {
1122  labels << featureType;
1123  }
1124 
1125  QMap< QString, QString > derAttributes = derivedAttributes;
1126  derAttributes.unite( featureDerivedAttributes( feature, layer, toLayerCoordinates( layer, point ) ) );
1127 
1128  IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( QLatin1String( " / " ) ), featureStore.fields(), feature, derAttributes );
1129 
1130  identifyResult.mParams.insert( QStringLiteral( "getFeatureInfoUrl" ), featureStore.params().value( QStringLiteral( "getFeatureInfoUrl" ) ) );
1131  results->append( identifyResult );
1132  }
1133  }
1134  }
1135  }
1136  else // text or html
1137  {
1138  QgsDebugMsg( QStringLiteral( "%1 HTML or text values" ).arg( values.size() ) );
1139  for ( auto it = values.constBegin(); it != values.constEnd(); ++it )
1140  {
1141  QString value = it.value().toString();
1142  attributes.clear();
1143  attributes.insert( QString(), value );
1144 
1145  QString label = layer->subLayers().value( it.key() );
1146  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
1147  }
1148  }
1149  }
1150  else
1151  {
1152  attributes.clear();
1153  QString value = identifyResult.error().message( QgsErrorMessage::Text );
1154  attributes.insert( tr( "Error" ), value );
1155  QString label = tr( "Identify error" );
1156  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
1157  }
1158 
1159  return true;
1160 }
1161 
1162 QgsUnitTypes::DistanceUnit QgsMapToolIdentify::displayDistanceUnits() const
1163 {
1164  return mCanvas->mapUnits();
1165 }
1166 
1167 QgsUnitTypes::AreaUnit QgsMapToolIdentify::displayAreaUnits() const
1168 {
1170 }
1171 
1172 QString QgsMapToolIdentify::formatDistance( double distance ) const
1173 {
1174  return formatDistance( distance, displayDistanceUnits() );
1175 }
1176 
1177 QString QgsMapToolIdentify::formatArea( double area ) const
1178 {
1179  return formatArea( area, displayAreaUnits() );
1180 }
1181 
1182 QString QgsMapToolIdentify::formatDistance( double distance, QgsUnitTypes::DistanceUnit unit ) const
1183 {
1184  QgsSettings settings;
1185  bool baseUnit = settings.value( QStringLiteral( "qgis/measure/keepbaseunit" ), true ).toBool();
1186 
1187  return QgsDistanceArea::formatDistance( distance, mCoordinatePrecision, unit, baseUnit );
1188 }
1189 
1190 QString QgsMapToolIdentify::formatArea( double area, QgsUnitTypes::AreaUnit unit ) const
1191 {
1192  QgsSettings settings;
1193  bool baseUnit = settings.value( QStringLiteral( "qgis/measure/keepbaseunit" ), true ).toBool();
1194 
1195  return QgsDistanceArea::formatArea( area, mCoordinatePrecision, unit, baseUnit );
1196 }
1197 
1199 {
1200  QList<IdentifyResult> results;
1201  if ( identifyRasterLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel ) )
1202  {
1203  emit changedRasterResults( results );
1204  }
1205 }
1206 
1207 void QgsMapToolIdentify::fromPointCloudIdentificationToIdentifyResults( QgsPointCloudLayer *layer, const QVector<QVariantMap> &identified, QList<QgsMapToolIdentify::IdentifyResult> &results )
1208 {
1209  int id = 1;
1210  const QgsPointCloudLayerElevationProperties *elevationProps = qobject_cast< const QgsPointCloudLayerElevationProperties *>( layer->elevationProperties() );
1211  for ( const QVariantMap &pt : identified )
1212  {
1213  QMap<QString, QString> ptStr;
1214  QString classification;
1215  for ( auto attrIt = pt.constBegin(); attrIt != pt.constEnd(); ++attrIt )
1216  {
1217  if ( attrIt.key().compare( QLatin1String( "Z" ), Qt::CaseInsensitive ) == 0
1218  && ( !qgsDoubleNear( elevationProps->zScale(), 1 ) || !qgsDoubleNear( elevationProps->zOffset(), 0 ) ) )
1219  {
1220  // Apply elevation properties
1221  ptStr[ tr( "Z (original)" ) ] = attrIt.value().toString();
1222  ptStr[ tr( "Z (adjusted)" ) ] = QString::number( attrIt.value().toDouble() * elevationProps->zScale() + elevationProps->zOffset() );
1223  }
1224  else if ( attrIt.key().compare( QLatin1String( "Classification" ), Qt::CaseInsensitive ) == 0 )
1225  {
1226  classification = QgsPointCloudDataProvider::translatedLasClassificationCodes().value( attrIt.value().toInt() );
1227  ptStr[ attrIt.key() ] = QStringLiteral( "%1 (%2)" ).arg( attrIt.value().toString(), classification );
1228  }
1229  else
1230  {
1231  ptStr[attrIt.key()] = attrIt.value().toString();
1232  }
1233  }
1234  QgsMapToolIdentify::IdentifyResult res( layer, classification.isEmpty() ? QString::number( id ) : QStringLiteral( "%1 (%2)" ).arg( id ).arg( classification ), ptStr, QMap<QString, QString>() );
1235  results.append( res );
1236  ++id;
1237  }
1238 }
Abstract base class for all geometries.
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual double perimeter() const
Returns the planar, 2-dimensional perimeter of the geometry.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
virtual QgsPoint vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
virtual double length() const
Returns the planar, 2-dimensional length of the geometry.
const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary const part after the last part of the geometry.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
const_part_iterator const_parts_begin() const
Returns STL-style iterator pointing to the const first part of the geometry.
bool isMeasure() const SIP_HOLDGIL
Returns true if the geometry contains m values.
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
static QChar separator()
Returns the character used as X/Y separator, this is a , on locales that do not use ,...
Q_GADGET QgsUnitTypes::DistanceUnit mapUnits
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
Abstract base class for curved geometry type.
Definition: qgscurve.h:36
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
static QString formatDistance(double distance, int decimals, QgsUnitTypes::DistanceUnit unit, bool keepBaseUnit=false)
Returns an distance formatted as a friendly string.
double measureArea(const QgsGeometry &geometry) const
Measures the area of a geometry.
double measurePerimeter(const QgsGeometry &geometry) const
Measures the perimeter of a polygon geometry.
double measureLength(const QgsGeometry &geometry) const
Measures the length of a geometry.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
static QString formatArea(double area, int decimals, QgsUnitTypes::AreaUnit unit, bool keepBaseUnit=false)
Returns an area formatted as a friendly string.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
double convertAreaMeasurement(double area, QgsUnitTypes::AreaUnit toUnits) const
Takes an area measurement calculated by this QgsDistanceArea object and converts it to a different ar...
double convertLengthMeasurement(double length, QgsUnitTypes::DistanceUnit toUnits) const
Takes a length measurement calculated by this QgsDistanceArea object and converts it to a different d...
QString message(QgsErrorMessage::Format format=QgsErrorMessage::Html) const
Full error messages description.
Definition: qgserror.cpp:49
QString what() const
Definition: qgsexception.h:48
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
@ Filter
Features may be filtered, i.e. some features may not be rendered (categorized, rule based ....
Definition: qgsrenderer.h:265
This class wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
@ EmbeddedSymbols
Retrieve any embedded feature symbology (since QGIS 3.20)
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
A container for features with the same fields and crs.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
const QgsSymbol * embeddedSymbol() const
Returns the feature's embedded symbology, or nullptr if the feature has no embedded symbol.
Definition: qgsfeature.cpp:306
QgsGeometry geometry
Definition: qgsfeature.h:67
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:223
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
Geometry collection.
int numGeometries() const SIP_HOLDGIL
Returns the number of geometries within the collection.
static QgsPoint closestPoint(const QgsAbstractGeometry &geometry, const QgsPoint &point)
Returns the nearest point on a segment of a geometry for the specified point.
static void circleCenterRadius(const QgsPoint &pt1, const QgsPoint &pt2, const QgsPoint &pt3, double &radius, double &centerX, double &centerY) SIP_HOLDGIL
Returns radius and center of the circle through pt1, pt2, pt3.
static QgsPoint closestVertex(const QgsAbstractGeometry &geom, const QgsPoint &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
static QgsGeometry fromPointXY(const QgsPointXY &point) SIP_HOLDGIL
Creates a new geometry from a QgsPointXY object.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:128
double area() const
Returns the planar, 2-dimensional area of the geometry.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry)
Creates and returns a new geometry engine representing the specified geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
bool isGeosEqual(const QgsGeometry &) const
Compares the geometry with another geometry using GEOS.
Identify contexts are used to encapsulate the settings to be used to perform an identify action.
bool isTemporal() const
Returns true if the temporal range setting is enabled.
const QgsDateTimeRange & temporalRange() const
Returns the datetime range to be used with the identify action.
The QgsIdentifyMenu class builds a menu to be used with identify results (.
QList< QgsMapToolIdentify::IdentifyResult > exec(const QList< QgsMapToolIdentify::IdentifyResult > &idResults, QPoint pos)
exec
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
QgsUnitTypes::DistanceUnit mapUnits() const
Convenience function for returning the current canvas map units.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
QList< QgsMapLayer * > layers(bool expandGroupLayers=false) const
Returns the list of layers shown within the map canvas.
double scale() const
Returns the last reported scale of the canvas.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
virtual bool isVisibleInTemporalRange(const QgsDateTimeRange &range) const
Returns true if the layer should be visible and rendered for the specified time range.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
virtual bool isSpatial() const
Returns true if the layer is considered a spatial layer, ie it has some form of geometry associated w...
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
virtual QgsRectangle extent() const
Returns the extent of the layer.
Q_INVOKABLE QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QgsMapLayerType type
Definition: qgsmaplayer.h:80
QgsMapLayer::LayerFlags flags() const
Returns the flags for this layer.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
virtual QgsMapLayer * clone() const =0
Returns a new instance equivalent to this one except for the id which is still unique.
virtual QStringList subLayers() const
Returns the sublayers of this layer.
@ Identifiable
If the layer is identifiable using the identify map tool and as a WMS layer.
Definition: qgsmaplayer.h:145
virtual QgsMapLayerElevationProperties * elevationProperties()
Returns the layer's elevation properties.
Definition: qgsmaplayer.h:1496
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
virtual QgsMapLayerTemporalProperties * temporalProperties()
Returns the layer's temporal properties.
Definition: qgsmaplayer.h:1489
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsPointXY layerToMapCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from layer's CRS to output CRS
double scale() const
Returns the calculated map scale.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
QgsCoordinateTransformContext transformContext() const
Returns the coordinate transform context, which stores various information regarding which datum tran...
QMap< QString, QString > derivedAttributesForPoint(const QgsPoint &point)
Returns derived attributes map for a clicked point in map coordinates. May be 2D or 3D point.
bool identifyLayer(QList< QgsMapToolIdentify::IdentifyResult > *results, QgsMapLayer *layer, const QgsPointXY &point, const QgsRectangle &viewExtent, double mapUnitsPerPixel, QgsMapToolIdentify::LayerType layerType=AllLayers, const QgsIdentifyContext &identifyContext=QgsIdentifyContext())
Call the right method depending on layer type.
static void fromPointCloudIdentificationToIdentifyResults(QgsPointCloudLayer *layer, const QVector< QVariantMap > &identified, QList< QgsMapToolIdentify::IdentifyResult > &results)
Converts point cloud identification results from variant maps to QgsMapToolIdentify::IdentifyResult a...
void changedRasterResults(QList< QgsMapToolIdentify::IdentifyResult > &)
void identifyProgress(int, int)
void deactivate() override
called when map tool is being deactivated
void identifyMessage(const QString &)
void activate() override
called when set as currently active map tool
QList< QgsMapToolIdentify::IdentifyResult > identify(int x, int y, const QList< QgsMapLayer * > &layerList=QList< QgsMapLayer * >(), IdentifyMode mode=DefaultQgsSetting, const QgsIdentifyContext &identifyContext=QgsIdentifyContext())
Performs the identification.
void formatChanged(QgsRasterLayer *layer)
void canvasReleaseEvent(QgsMapMouseEvent *e) override
Mouse release event for overriding. Default implementation does nothing.
void setCanvasPropertiesOverrides(double searchRadiusMapUnits)
Overrides some map canvas properties inside the map tool for the upcoming identify requests.
QgsMapToolIdentify(QgsMapCanvas *canvas)
constructor
void canvasMoveEvent(QgsMapMouseEvent *e) override
Mouse move event for overriding. Default implementation does nothing.
bool identifyRasterLayer(QList< QgsMapToolIdentify::IdentifyResult > *results, QgsRasterLayer *layer, QgsPointXY point, const QgsRectangle &viewExtent, double mapUnitsPerPixel, const QgsIdentifyContext &identifyContext=QgsIdentifyContext())
Performs the identification against a given raster layer.
bool identifyMeshLayer(QList< QgsMapToolIdentify::IdentifyResult > *results, QgsMeshLayer *layer, const QgsPointXY &point, const QgsIdentifyContext &identifyContext=QgsIdentifyContext())
Identifies data from active scalar and vector dataset from the mesh layer.
QgsIdentifyMenu * mIdentifyMenu
void canvasPressEvent(QgsMapMouseEvent *e) override
Mouse press event for overriding. Default implementation does nothing.
bool identifyVectorLayer(QList< QgsMapToolIdentify::IdentifyResult > *results, QgsVectorLayer *layer, const QgsPointXY &point, const QgsIdentifyContext &identifyContext=QgsIdentifyContext())
Performs the identification against a given vector layer.
void restoreCanvasPropertiesOverrides()
Clears canvas properties overrides previously set with setCanvasPropertiesOverrides()
Abstract base class for all map tools.
Definition: qgsmaptool.h:71
QgsPoint toLayerCoordinates(const QgsMapLayer *layer, const QgsPoint &point)
Transforms a point from map coordinates to layer coordinates.
Definition: qgsmaptool.cpp:62
QgsMapCanvas * mCanvas
The pointer to the map canvas.
Definition: qgsmaptool.h:336
QgsMapLayer * layer(const QString &id)
Returns the map layer with the matching ID, or nullptr if no layers could be found.
Definition: qgsmaptool.cpp:84
QgsPointXY toMapCoordinates(QPoint point)
Transforms a point from screen coordinates to map coordinates.
Definition: qgsmaptool.cpp:41
virtual void setCursor(const QCursor &cursor)
Sets a user defined cursor.
Definition: qgsmaptool.cpp:160
static double searchRadiusMU(const QgsRenderContext &context)
Gets search radius in map units for given context.
Definition: qgsmaptool.cpp:232
QPoint toCanvasCoordinates(const QgsPointXY &point) const
Transforms a point from map coordinates to screen coordinates.
Definition: qgsmaptool.cpp:77
virtual void activate()
called when set as currently active map tool
Definition: qgsmaptool.cpp:94
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:110
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
bool isTemporal() const
Returns whether the dataset group is temporal (contains time-related dataset)
bool isVector() const
Returns whether dataset group has vector data.
QString name() const
Returns name of the dataset group.
bool isScalar() const
Returns whether dataset group has scalar data.
QString uri() const
Returns the uri of the source.
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
QgsMeshDatasetMetadata is a collection of mesh dataset metadata such as whether the data is valid or ...
double time() const
Returns the time value for this dataset.
QgsMeshDatasetValue represents single dataset value.
double y() const
Returns y value.
double scalar() const
Returns magnitude of vector for vector data or scalar value for scalar data.
double x() const
Returns x value.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:97
static QMap< int, QString > translatedLasClassificationCodes()
Returns the map of LAS classification code to translated string value, corresponding to the ASPRS Sta...
Point cloud layer specific subclass of QgsMapLayerElevationProperties.
double zOffset() const
Returns the z offset, which is a fixed offset amount which should be added to z values from the layer...
double zScale() const
Returns the z scale, which is a scaling factor which should be applied to z values from the layer.
Represents a map layer supporting display of point clouds.
Abstract base class for 2d point cloud renderers.
QVector< QVariantMap > identify(QgsPointCloudLayer *layer, const QgsRenderContext &context, const QgsGeometry &geometry, double toleranceForPointIdentification=0)
Returns the list of visible points of the point cloud layer layer and an extent defined by a geometry...
virtual void startRender(QgsPointCloudRenderContext &context)
Must be called when a new render cycle is started.
virtual void stopRender(QgsPointCloudRenderContext &context)
Must be called when a render cycle has finished, to allow the renderer to clean up.
A class to represent a 2D point.
Definition: qgspointxy.h:59
bool isEmpty() const SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgspointxy.h:249
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
Definition: qgspointxy.cpp:51
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:49
Q_GADGET double x
Definition: qgspoint.h:52
double z
Definition: qgspoint.h:54
double m
Definition: qgspoint.h:55
double y
Definition: qgspoint.h:53
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:470
QString ellipsoid
Definition: qgsproject.h:108
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:107
static QString printValue(double value)
Print double value with all necessary significant digits.
static QgsRaster::IdentifyFormat identifyFormatFromName(const QString &formatName)
static Capability identifyFormatToCapability(QgsRaster::IdentifyFormat format)
Raster identify results container.
QgsError error() const
Returns the last error.
bool isValid() const
Returns true if valid.
QMap< int, QVariant > results() const
Returns the identify results.
@ IdentifyValue
Numerical values.
@ Identify
At least one identify format supported.
@ IdentifyFeature
WMS GML -> feature.
Represents a raster layer.
IdentifyFormat
Definition: qgsraster.h:58
@ IdentifyFormatFeature
Definition: qgsraster.h:63
@ IdentifyFormatValue
Definition: qgsraster.h:60
@ IdentifyFormatText
Definition: qgsraster.h:61
@ IdentifyFormatHtml
Definition: qgsraster.h:62
A rectangle specified with double values.
Definition: qgsrectangle.h:42
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
Definition: qgsrectangle.h:161
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
Definition: qgsrectangle.h:156
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
Definition: qgsrectangle.h:151
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
Definition: qgsrectangle.h:166
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:363
Contains information about the context of a rendering operation.
void setCoordinateTransform(const QgsCoordinateTransform &t)
Sets the current coordinate transform for the context.
QgsExpressionContext & expressionContext()
Gets the expression context.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
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:253
static QString symbolTypeToString(Qgis::SymbolType type)
Returns a translated string version of the specified symbol type.
Definition: qgssymbol.cpp:230
QColor color() const
Returns the symbol's color.
Definition: qgssymbol.cpp:551
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:97
bool isActive() const
Returns true if the temporal property is active.
Temporarily sets a cursor override for the QApplication for the lifetime of the object.
Definition: qgsguiutils.h:221
Defines a matrix of tiles for a single zoom level: it is defined by its size (width *.
Definition: qgstiles.h:108
QgsTileRange tileRangeFromExtent(const QgsRectangle &mExtent) const
Returns tile range that fully covers the given extent.
Definition: qgstiles.cpp:97
Range of tiles in a tile matrix to be rendered.
Definition: qgstiles.h:71
int endColumn() const
Returns index of the last column in the range.
Definition: qgstiles.h:83
int endRow() const
Returns index of the last row in the range.
Definition: qgstiles.h:87
int startRow() const
Returns index of the first row in the range.
Definition: qgstiles.h:85
int startColumn() const
Returns index of the first column in the range.
Definition: qgstiles.h:81
Stores coordinates of a tile in a tile matrix set.
Definition: qgstiles.h:38
Helper functions for various unit types.
Definition: qgsunittypes.h:39
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:68
static Q_INVOKABLE QgsUnitTypes::AreaUnit distanceToAreaUnit(QgsUnitTypes::DistanceUnit distanceUnit)
Converts a distance unit to its corresponding area unit, e.g., meters to square meters.
static Q_INVOKABLE double fromUnitToUnitFactor(QgsUnitTypes::DistanceUnit fromUnit, QgsUnitTypes::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE QgsUnitTypes::DistanceUnitType unitType(QgsUnitTypes::DistanceUnit unit)
Returns the type for a distance unit.
AreaUnit
Units of area.
Definition: qgsunittypes.h:94
@ FeatureSymbology
Provider is able retrieve embedded symbology associated with individual features. Since QGIS 3....
Encapsulates the context in which a QgsVectorLayer's temporal capabilities will be applied.
void setLayer(QgsVectorLayer *layer)
Sets the associated layer.
Represents a vector layer which manages a vector based data sets.
Implements a map layer that is dedicated to rendering of vector tiles.
This class is responsible for decoding raw tile data written with Mapbox Vector Tiles encoding.
static QgsFields makeQgisFields(const QSet< QString > &flds)
Returns QgsFields instance based on the set of field names.
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:862
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:141
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1130
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:70
static Type singleType(Type type) SIP_HOLDGIL
Returns the single type for a WKB type.
Definition: qgswkbtypes.h:157
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:732
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1080
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
#define str(x)
Definition: qgis.cpp:37
CONSTLATIN1STRING geoNone()
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.h:1983
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:1578
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:882
#define FID_TO_STRING(fid)
Definition: qgsfeatureid.h:33
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
QVector< QgsFeatureStore > QgsFeatureStoreList
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QMap< QString, QVector< QgsFeature > > QgsVectorTileFeatures
Features of a vector tile, grouped by sub-layer names (key of the map)
const QgsCoordinateReferenceSystem & crs
QMap< QString, QVariant > mParams
Utility class for identifying a unique vertex within a geometry.
Definition: qgsvertexid.h:31
int vertex
Vertex number.
Definition: qgsvertexid.h:95
int part
Part number.
Definition: qgsvertexid.h:89
Qgis::VertexType type
Vertex type.
Definition: qgsvertexid.h:98
bool isValid() const SIP_HOLDGIL
Returns true if the vertex id is valid.
Definition: qgsvertexid.h:46