QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 "qgscursors.h"
18 #include "qgsdistancearea.h"
19 #include "qgsfeature.h"
20 #include "qgsfeaturestore.h"
21 #include "qgsfield.h"
22 #include "qgsgeometry.h"
23 #include "qgsidentifymenu.h"
24 #include "qgslogger.h"
25 #include "qgsmapcanvas.h"
26 #include "qgsmaptoolidentify.h"
27 #include "qgsmaptopixel.h"
28 #include "qgsmessageviewer.h"
29 #include "qgsmaplayer.h"
30 #include "qgsrasterlayer.h"
33 #include "qgsvectordataprovider.h"
34 #include "qgsvectorlayer.h"
35 #include "qgsproject.h"
36 #include "qgsmaplayerregistry.h"
37 #include "qgsrendererv2.h"
38 #include "qgsgeometryutils.h"
40 #include "qgscurvev2.h"
41 #include "qgscoordinateutils.h"
42 
43 #include <QSettings>
44 #include <QMouseEvent>
45 #include <QCursor>
46 #include <QPixmap>
47 #include <QStatusBar>
48 #include <QVariant>
49 #include <QMenu>
50 
52  : QgsMapTool( canvas )
53  , mIdentifyMenu( new QgsIdentifyMenu( mCanvas ) )
54  , mLastMapUnitsPerPixel( -1.0 )
55  , mCoordinatePrecision( 6 )
56 {
57  // set cursor
58  QPixmap myIdentifyQPixmap = QPixmap(( const char ** ) identify_cursor );
59  mCursor = QCursor( myIdentifyQPixmap, 1, 1 );
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 
83 {
84  return identify( x, y, mode, layerList, AllLayers );
85 }
86 
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, const LayerType& layerType )
93 {
94  QList<IdentifyResult> results;
95 
96  mLastPoint = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y );
97  mLastExtent = mCanvas->extent();
98  mLastMapUnitsPerPixel = mCanvas->mapUnitsPerPixel();
99 
100  mCoordinatePrecision = QgsCoordinateUtils::calculateCoordinatePrecision( mLastMapUnitsPerPixel, mCanvas->mapSettings().destinationCrs() );
101 
102  if ( mode == DefaultQgsSetting )
103  {
104  QSettings settings;
105  mode = static_cast<IdentifyMode>( settings.value( "/Map/identifyMode", 0 ).toInt() );
106  }
107 
108  if ( mode == LayerSelection )
109  {
110  QList<IdentifyResult> results = identify( x, y, TopDownAll, layerList, layerType );
111  QPoint globalPos = mCanvas->mapToGlobal( QPoint( x + 5, y + 5 ) );
112  return mIdentifyMenu->exec( results, globalPos );
113  }
114  else if ( mode == ActiveLayer && layerList.isEmpty() )
115  {
116  QgsMapLayer *layer = mCanvas->currentLayer();
117 
118  if ( !layer )
119  {
120  emit identifyMessage( tr( "No active layer. To identify features, you must choose an active layer." ) );
121  return results;
122  }
123 
124  QApplication::setOverrideCursor( Qt::WaitCursor );
125 
126  identifyLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel, layerType );
127  }
128  else
129  {
130  QApplication::setOverrideCursor( Qt::WaitCursor );
131 
132  QStringList noIdentifyLayerIdList = QgsProject::instance()->readListEntry( "Identify", "/disabledLayers" );
133 
134  int layerCount;
135  if ( layerList.isEmpty() )
136  layerCount = mCanvas->layerCount();
137  else
138  layerCount = layerList.count();
139 
140 
141  for ( int i = 0; i < layerCount; i++ )
142  {
143 
144  QgsMapLayer *layer;
145  if ( layerList.isEmpty() )
146  layer = mCanvas->layer( i );
147  else
148  layer = layerList.value( i );
149 
150  emit identifyProgress( i, mCanvas->layerCount() );
151  emit identifyMessage( tr( "Identifying on %1..." ).arg( layer->name() ) );
152 
153  if ( noIdentifyLayerIdList.contains( layer->id() ) )
154  continue;
155 
156  if ( identifyLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel, layerType ) )
157  {
158  if ( mode == TopDownStopAtFirst )
159  break;
160  }
161  }
162 
164  emit identifyMessage( tr( "Identifying done." ) );
165  }
166 
168 
169  return results;
170 }
171 
173 {
175 }
176 
178 {
180 }
181 
182 bool QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLayer *layer, const QgsPoint& point, const QgsRectangle& viewExtent, double mapUnitsPerPixel, const LayerType& layerType )
183 {
184  if ( layer->type() == QgsMapLayer::RasterLayer && layerType.testFlag( RasterLayer ) )
185  {
186  return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), point, viewExtent, mapUnitsPerPixel );
187  }
188  else if ( layer->type() == QgsMapLayer::VectorLayer && layerType.testFlag( VectorLayer ) )
189  {
190  return identifyVectorLayer( results, qobject_cast<QgsVectorLayer *>( layer ), point );
191  }
192  else
193  {
194  return false;
195  }
196 }
197 
199 {
200  if ( !layer || !layer->hasGeometryType() )
201  return false;
202 
203  if ( !layer->isInScaleRange( mCanvas->mapSettings().scale() ) )
204  {
205  QgsDebugMsg( "Out of scale limits" );
206  return false;
207  }
208 
209  QApplication::setOverrideCursor( Qt::WaitCursor );
210 
211  QMap< QString, QString > commonDerivedAttributes;
212 
213  commonDerivedAttributes.insert( tr( "(clicked coordinate X)" ), formatXCoordinate( point ) );
214  commonDerivedAttributes.insert( tr( "(clicked coordinate Y)" ), formatYCoordinate( point ) );
215 
216  int featureCount = 0;
217 
218  QgsFeatureList featureList;
219 
220  // toLayerCoordinates will throw an exception for an 'invalid' point.
221  // For example, if you project a world map onto a globe using EPSG 2163
222  // and then click somewhere off the globe, an exception will be thrown.
223  try
224  {
225  // create the search rectangle
226  double searchRadius = searchRadiusMU( mCanvas );
227 
228  QgsRectangle r;
229  r.setXMinimum( point.x() - searchRadius );
230  r.setXMaximum( point.x() + searchRadius );
231  r.setYMinimum( point.y() - searchRadius );
232  r.setYMaximum( point.y() + searchRadius );
233 
234  r = toLayerCoordinates( layer, r );
235 
236  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) );
237  QgsFeature f;
238  while ( fit.nextFeature( f ) )
239  featureList << QgsFeature( f );
240  }
241  catch ( QgsCsException & cse )
242  {
243  Q_UNUSED( cse );
244  // catch exception for 'invalid' point and proceed with no features found
245  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
246  }
247 
248  QgsFeatureList::iterator f_it = featureList.begin();
249 
250  bool filter = false;
251 
254  QgsFeatureRendererV2* renderer = layer->rendererV2();
255  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
256  {
257  // setup scale for scale dependent visibility (rule based)
258  renderer->startRender( context, layer->fields() );
259  filter = renderer->capabilities() & QgsFeatureRendererV2::Filter;
260  }
261 
262  for ( ; f_it != featureList.end(); ++f_it )
263  {
264  QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
265 
266  QgsFeatureId fid = f_it->id();
267  context.expressionContext().setFeature( *f_it );
268 
269  if ( filter && !renderer->willRenderFeature( *f_it, context ) )
270  continue;
271 
272  featureCount++;
273 
274  derivedAttributes.unite( featureDerivedAttributes( &( *f_it ), layer, toLayerCoordinates( layer, point ) ) );
275 
276  derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) );
277 
278  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), *f_it, derivedAttributes ) );
279  }
280 
281  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
282  {
283  renderer->stopRender( context );
284  }
285 
286  QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) );
287 
289  return featureCount > 0;
290 }
291 
292 void QgsMapToolIdentify::closestVertexAttributes( const QgsAbstractGeometryV2& geometry, QgsVertexId vId, QgsMapLayer *layer, QMap< QString, QString >& derivedAttributes )
293 {
294  QString str = QLocale::system().toString( vId.vertex + 1 );
295  derivedAttributes.insert( tr( "Closest vertex number" ), str );
296 
297  QgsPointV2 closestPoint = geometry.vertexAt( vId );
298 
299  QgsPoint closestPointMapCoords = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( closestPoint.x(), closestPoint.y() ) );
300  derivedAttributes.insert( "Closest vertex X", formatXCoordinate( closestPointMapCoords ) );
301  derivedAttributes.insert( "Closest vertex Y", formatYCoordinate( closestPointMapCoords ) );
302 
303  if ( closestPoint.is3D() )
304  {
305  str = QLocale::system().toString( closestPoint.z(), 'g', 10 );
306  derivedAttributes.insert( "Closest vertex Z", str );
307  }
308  if ( closestPoint.isMeasure() )
309  {
310  str = QLocale::system().toString( closestPoint.m(), 'g', 10 );
311  derivedAttributes.insert( "Closest vertex M", str );
312  }
313 
314  if ( vId.type == QgsVertexId::CurveVertex )
315  {
316  double radius, centerX, centerY;
317  QgsVertexId vIdBefore = vId;
318  --vIdBefore.vertex;
319  QgsVertexId vIdAfter = vId;
320  ++vIdAfter.vertex;
321  QgsGeometryUtils::circleCenterRadius( geometry.vertexAt( vIdBefore ), geometry.vertexAt( vId ),
322  geometry.vertexAt( vIdAfter ), radius, centerX, centerY );
323  derivedAttributes.insert( "Closest vertex radius", QLocale::system().toString( radius ) );
324  }
325 }
326 
327 QString QgsMapToolIdentify::formatCoordinate( const QgsPoint& canvasPoint ) const
328 {
329  return QgsCoordinateUtils::formatCoordinateForProject( canvasPoint, mCanvas->mapSettings().destinationCrs(),
330  mCoordinatePrecision );
331 }
332 
333 QString QgsMapToolIdentify::formatXCoordinate( const QgsPoint& canvasPoint ) const
334 {
335  QString coordinate = formatCoordinate( canvasPoint );
336  return coordinate.split( ',' ).at( 0 );
337 }
338 
339 QString QgsMapToolIdentify::formatYCoordinate( const QgsPoint& canvasPoint ) const
340 {
341  QString coordinate = formatCoordinate( canvasPoint );
342  return coordinate.split( ',' ).at( 1 );
343 }
344 
345 QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeature *feature, QgsMapLayer *layer, const QgsPoint& layerPoint )
346 {
347  // Calculate derived attributes and insert:
348  // measure distance or area depending on geometry type
349  QMap< QString, QString > derivedAttributes;
350 
351  // init distance/area calculator
352  QString ellipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE );
353  QgsDistanceArea calc;
355  calc.setEllipsoid( ellipsoid );
356  calc.setSourceCrs( layer->crs().srsid() );
357 
359  QGis::GeometryType geometryType = QGis::NoGeometry;
360 
361  QgsVertexId vId;
362  QgsPointV2 closestPoint;
363  if ( feature->constGeometry() )
364  {
365  geometryType = feature->constGeometry()->type();
366  wkbType = feature->constGeometry()->geometry()->wkbType();
367  //find closest vertex to clicked point
368  closestPoint = QgsGeometryUtils::closestVertex( *feature->constGeometry()->geometry(), QgsPointV2( layerPoint.x(), layerPoint.y() ), vId );
369  }
370 
371  if ( QgsWKBTypes::isMultiType( wkbType ) )
372  {
373  QString str = QLocale::system().toString( static_cast<QgsGeometryCollectionV2*>( feature->constGeometry()->geometry() )->numGeometries() );
374  derivedAttributes.insert( tr( "Parts" ), str );
375  str = QLocale::system().toString( vId.part + 1 );
376  derivedAttributes.insert( tr( "Part number" ), str );
377  }
378 
379  if ( geometryType == QGis::Line )
380  {
381  double dist = calc.measureLength( feature->constGeometry() );
382  dist = calc.convertLengthMeasurement( dist, displayDistanceUnits() );
383  QString str = formatDistance( dist );
384  derivedAttributes.insert( tr( "Length" ), str );
385 
386  const QgsCurveV2* curve = dynamic_cast< const QgsCurveV2* >( feature->constGeometry()->geometry() );
387  if ( curve )
388  {
389  str = QLocale::system().toString( curve->nCoordinates() );
390  derivedAttributes.insert( tr( "Vertices" ), str );
391 
392  //add details of closest vertex to identify point
393  closestVertexAttributes( *curve, vId, layer, derivedAttributes );
394 
395  // Add the start and end points in as derived attributes
396  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( curve->startPoint().x(), curve->startPoint().y() ) );
397  str = formatXCoordinate( pnt );
398  derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
399  str = formatYCoordinate( pnt );
400  derivedAttributes.insert( tr( "firstY" ), str );
401  pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( curve->endPoint().x(), curve->endPoint().y() ) );
402  str = formatXCoordinate( pnt );
403  derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
404  str = formatYCoordinate( pnt );
405  derivedAttributes.insert( tr( "lastY" ), str );
406  }
407  }
408  else if ( geometryType == QGis::Polygon )
409  {
410  double area = calc.measureArea( feature->constGeometry() );
411  area = calc.convertAreaMeasurement( area, displayAreaUnits() );
412  QString str = formatArea( area );
413  derivedAttributes.insert( tr( "Area" ), str );
414 
415  double perimeter = calc.measurePerimeter( feature->constGeometry() );
416  perimeter = calc.convertLengthMeasurement( perimeter, displayDistanceUnits() );
417  str = formatDistance( perimeter );
418  derivedAttributes.insert( tr( "Perimeter" ), str );
419 
420  str = QLocale::system().toString( feature->constGeometry()->geometry()->nCoordinates() );
421  derivedAttributes.insert( tr( "Vertices" ), str );
422 
423  //add details of closest vertex to identify point
424  closestVertexAttributes( *feature->constGeometry()->geometry(), vId, layer, derivedAttributes );
425  }
426  else if ( geometryType == QGis::Point &&
428  {
429  // Include the x and y coordinates of the point as a derived attribute
430  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->constGeometry()->asPoint() );
431  QString str = formatXCoordinate( pnt );
432  derivedAttributes.insert( "X", str );
433  str = formatYCoordinate( pnt );
434  derivedAttributes.insert( "Y", str );
435 
436  if ( QgsWKBTypes::hasZ( wkbType ) )
437  {
438  str = QLocale::system().toString( static_cast<QgsPointV2*>( feature->constGeometry()->geometry() )->z(), 'g', 10 );
439  derivedAttributes.insert( "Z", str );
440  }
441  if ( QgsWKBTypes::hasM( wkbType ) )
442  {
443  str = QLocale::system().toString( static_cast<QgsPointV2*>( feature->constGeometry()->geometry() )->m(), 'g', 10 );
444  derivedAttributes.insert( "M", str );
445  }
446  }
447 
448  return derivedAttributes;
449 }
450 
451 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, QgsPoint point, const QgsRectangle& viewExtent, double mapUnitsPerPixel )
452 {
453  QgsDebugMsg( "point = " + point.toString() );
454  if ( !layer )
455  return false;
456 
457  QgsRasterDataProvider *dprovider = layer->dataProvider();
458  if ( !dprovider )
459  return false;
460 
461  int capabilities = dprovider->capabilities();
462  if ( !( capabilities & QgsRasterDataProvider::Identify ) )
463  return false;
464 
465  QgsPoint pointInCanvasCrs = point;
466  try
467  {
468  point = toLayerCoordinates( layer, point );
469  }
470  catch ( QgsCsException &cse )
471  {
472  Q_UNUSED( cse );
473  QgsDebugMsg( QString( "coordinate not reprojectable: %1" ).arg( cse.what() ) );
474  return false;
475  }
476  QgsDebugMsg( QString( "point = %1 %2" ).arg( point.x() ).arg( point.y() ) );
477 
478  if ( !layer->extent().contains( point ) )
479  return false;
480 
481  QMap< QString, QString > attributes, derivedAttributes;
482 
484 
485  // check if the format is really supported otherwise use first supported format
486  if ( !( QgsRasterDataProvider::identifyFormatToCapability( format ) & capabilities ) )
487  {
489  else if ( capabilities & QgsRasterInterface::IdentifyValue ) format = QgsRaster::IdentifyFormatValue;
490  else if ( capabilities & QgsRasterInterface::IdentifyHtml ) format = QgsRaster::IdentifyFormatHtml;
491  else if ( capabilities & QgsRasterInterface::IdentifyText ) format = QgsRaster::IdentifyFormatText;
492  else return false;
493  }
494 
495  QgsRasterIdentifyResult identifyResult;
496  // We can only use current map canvas context (extent, width, height) if layer is not reprojected,
497  if ( mCanvas->hasCrsTransformEnabled() && dprovider->crs() != mCanvas->mapSettings().destinationCrs() )
498  {
499  // To get some reasonable response for point/line WMS vector layers we must
500  // use a context with approximately a resolution in layer CRS units
501  // corresponding to current map canvas resolution (for examplei UMN Mapserver
502  // in msWMSFeatureInfo() -> msQueryByRect() is using requested pixel
503  // + TOLERANCE (layer param) for feature selection)
504  //
505  QgsRectangle r;
506  r.setXMinimum( pointInCanvasCrs.x() - mapUnitsPerPixel / 2. );
507  r.setXMaximum( pointInCanvasCrs.x() + mapUnitsPerPixel / 2. );
508  r.setYMinimum( pointInCanvasCrs.y() - mapUnitsPerPixel / 2. );
509  r.setYMaximum( pointInCanvasCrs.y() + mapUnitsPerPixel / 2. );
510  r = toLayerCoordinates( layer, r ); // will be a bit larger
511  // Mapserver (6.0.3, for example) does not work with 1x1 pixel box
512  // but that is fixed (the rect is enlarged) in the WMS provider
513  identifyResult = dprovider->identify( point, format, r, 1, 1 );
514  }
515  else
516  {
517  // It would be nice to use the same extent and size which was used for drawing,
518  // so that WCS can use cache from last draw, unfortunately QgsRasterLayer::draw()
519  // is doing some tricks with extent and size to allign raster to output which
520  // would be difficult to replicate here.
521  // Note: cutting the extent may result in slightly different x and y resolutions
522  // and thus shifted point calculated back in QGIS WMS (using average resolution)
523  //viewExtent = dprovider->extent().intersect( &viewExtent );
524 
525  // Width and height are calculated from not projected extent and we hope that
526  // are similar to source width and height used to reproject layer for drawing.
527  // TODO: may be very dangerous, because it may result in different resolutions
528  // in source CRS, and WMS server (QGIS server) calcs wrong coor using average resolution.
529  int width = qRound( viewExtent.width() / mapUnitsPerPixel );
530  int height = qRound( viewExtent.height() / mapUnitsPerPixel );
531 
532  QgsDebugMsg( QString( "viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.width() ).arg( viewExtent.height() ) );
533  QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) );
534  QgsDebugMsg( QString( "xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.width() / width ).arg( viewExtent.height() / height ).arg( mapUnitsPerPixel ) );
535 
536  identifyResult = dprovider->identify( point, format, viewExtent, width, height );
537  }
538 
539  derivedAttributes.insert( tr( "(clicked coordinate X)" ), formatXCoordinate( pointInCanvasCrs ) );
540  derivedAttributes.insert( tr( "(clicked coordinate Y)" ), formatYCoordinate( pointInCanvasCrs ) );
541 
542  if ( identifyResult.isValid() )
543  {
544  QMap<int, QVariant> values = identifyResult.results();
545  QgsGeometry geometry;
546  if ( format == QgsRaster::IdentifyFormatValue )
547  {
548  Q_FOREACH ( int bandNo, values.keys() )
549  {
550  QString valueString;
551  if ( values.value( bandNo ).isNull() )
552  {
553  valueString = tr( "no data" );
554  }
555  else
556  {
557  QVariant value( values.value( bandNo ) );
558  // The cast is legit. Quoting QT doc :
559  // "Although this function is declared as returning QVariant::Type,
560  // the return value should be interpreted as QMetaType::Type"
561  if ( static_cast<QMetaType::Type>( value.type() ) == QMetaType::Float )
562  {
563  valueString = QgsRasterBlock::printValue( value.toFloat() );
564  }
565  else
566  {
567  valueString = QgsRasterBlock::printValue( value.toDouble() );
568  }
569  }
570  attributes.insert( dprovider->generateBandName( bandNo ), valueString );
571  }
572  QString label = layer->name();
573  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
574  }
575  else if ( format == QgsRaster::IdentifyFormatFeature )
576  {
577  Q_FOREACH ( int i, values.keys() )
578  {
579  QVariant value = values.value( i );
580  if ( value.type() == QVariant::Bool && !value.toBool() )
581  {
582  // sublayer not visible or not queryable
583  continue;
584  }
585 
586  if ( value.type() == QVariant::String )
587  {
588  // error
589  // TODO: better error reporting
590  QString label = layer->subLayers().value( i );
591  attributes.clear();
592  attributes.insert( tr( "Error" ), value.toString() );
593 
594  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
595  continue;
596  }
597 
598  // list of feature stores for a single sublayer
599  QgsFeatureStoreList featureStoreList = values.value( i ).value<QgsFeatureStoreList>();
600 
601  Q_FOREACH ( QgsFeatureStore featureStore, featureStoreList )
602  {
603  Q_FOREACH ( QgsFeature feature, featureStore.features() )
604  {
605  attributes.clear();
606  // WMS sublayer and feature type, a sublayer may contain multiple feature types.
607  // Sublayer name may be the same as layer name and feature type name
608  // may be the same as sublayer. We try to avoid duplicities in label.
609  QString sublayer = featureStore.params().value( "sublayer" ).toString();
610  QString featureType = featureStore.params().value( "featureType" ).toString();
611  // Strip UMN MapServer '_feature'
612  featureType.remove( "_feature" );
613  QStringList labels;
614  if ( sublayer.compare( layer->name(), Qt::CaseInsensitive ) != 0 )
615  {
616  labels << sublayer;
617  }
618  if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
619  {
620  labels << featureType;
621  }
622 
623  QMap< QString, QString > derAttributes = derivedAttributes;
624  derAttributes.unite( featureDerivedAttributes( &feature, layer ) );
625 
626  IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( " / " ), featureStore.fields(), feature, derAttributes );
627 
628  identifyResult.mParams.insert( "getFeatureInfoUrl", featureStore.params().value( "getFeatureInfoUrl" ) );
629  results->append( identifyResult );
630  }
631  }
632  }
633  }
634  else // text or html
635  {
636  QgsDebugMsg( QString( "%1 HTML or text values" ).arg( values.size() ) );
637  Q_FOREACH ( int bandNo, values.keys() )
638  {
639  QString value = values.value( bandNo ).toString();
640  attributes.clear();
641  attributes.insert( "", value );
642 
643  QString label = layer->subLayers().value( bandNo );
644  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
645  }
646  }
647  }
648  else
649  {
650  attributes.clear();
651  QString value = identifyResult.error().message( QgsErrorMessage::Text );
652  attributes.insert( tr( "Error" ), value );
653  QString label = tr( "Identify error" );
654  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
655  }
656 
657  return true;
658 }
659 
660 void QgsMapToolIdentify::convertMeasurement( QgsDistanceArea &calc, double &measure, QGis::UnitType &u, bool isArea )
661 {
662  // Helper for converting between units
663  // The parameter &u is out only...
664 
665  // Get the canvas units
666  QGis::UnitType myUnits = mCanvas->mapUnits();
667 
669  calc.convertMeasurement( measure, myUnits, displayUnits(), isArea );
670  u = displayUnits();
672 }
673 
674 QGis::UnitType QgsMapToolIdentify::displayUnits()
675 {
676  return mCanvas->mapUnits();
677 }
678 
679 QGis::UnitType QgsMapToolIdentify::displayDistanceUnits() const
680 {
681  return mCanvas->mapUnits();
682 }
683 
684 QgsUnitTypes::AreaUnit QgsMapToolIdentify::displayAreaUnits() const
685 {
687 }
688 
689 QString QgsMapToolIdentify::formatDistance( double distance ) const
690 {
691  QSettings settings;
692  bool baseUnit = settings.value( "/qgis/measure/keepbaseunit", false ).toBool();
693 
694  return QgsDistanceArea::formatDistance( distance, 3, displayDistanceUnits(), baseUnit );
695 }
696 
697 QString QgsMapToolIdentify::formatArea( double area ) const
698 {
699  QSettings settings;
700  bool baseUnit = settings.value( "/qgis/measure/keepbaseunit", false ).toBool();
701 
702  return QgsDistanceArea::formatArea( area, 3, displayAreaUnits(), baseUnit );
703 }
704 
706 {
707  QList<IdentifyResult> results;
708  if ( identifyRasterLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel ) )
709  {
710  emit changedRasterResults( results );
711  }
712 }
713 
Wrapper for iterator of features from vector data provider or vector layer.
Container for features with the same fields and crs.
bool contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
IdentifyFormat
Definition: qgsraster.h:54
A rectangle specified with double values.
Definition: qgsrectangle.h:35
Base class for all map layer types.
Definition: qgsmaplayer.h:49
double convertLengthMeasurement(double length, QGis::UnitType toUnits) const
Takes a length measurement calculated by this QgsDistanceArea object and converts it to a different d...
virtual QStringList subLayers() const override
Returns the sublayers of this layer - Useful for providers that manage their own layers, such as WMS.
QString readEntry(const QString &scope, const QString &key, const QString &def=QString::null, bool *ok=nullptr) const
static QString printValue(double value)
Print double value with all necessary significant digits.
static double searchRadiusMU(const QgsRenderContext &context)
Get search radius in map units for given context.
Definition: qgsmaptool.cpp:219
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
GeometryType
Definition: qgis.h:115
void changedRasterResults(QList< IdentifyResult > &)
virtual void activate() override
called when set as currently active map tool
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:172
QString toString(qlonglong i) const
Use exact geometry intersection (slower) instead of bounding boxes.
void identifyProgress(int, int)
QMap< Key, T > & unite(const QMap< Key, T > &other)
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:714
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
virtual QgsCoordinateReferenceSystem crs()=0
Get the QgsCoordinateReferenceSystem for this layer.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
virtual QString generateBandName(int theBandNumber) const
helper function to create zero padded band names
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
void setSourceCrs(long srsid)
sets source spatial reference system (by QGIS CRS)
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest())
Query the provider for features specified in request.
const T & at(int i) const
const QgsCoordinateReferenceSystem & crs() const
Returns layer&#39;s spatial reference system.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:487
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:515
bool hasCrsTransformEnabled()
A simple helper method to find out if on the fly projections are enabled or not.
bool contains(const QString &str, Qt::CaseSensitivity cs) const
#define FID_TO_STRING(fid)
Definition: qgsfeature.h:89
static void circleCenterRadius(const QgsPointV2 &pt1, const QgsPointV2 &pt2, const QgsPointV2 &pt3, double &radius, double &centerX, double &centerY)
Returns radius and center of the circle through pt1, pt2, pt3.
QPoint mapToGlobal(const QPoint &pos) const
int layerCount() const
return number of layers on the map
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
Abstract base class for all geometries.
virtual void canvasMoveEvent(QgsMapMouseEvent *e) override
Overridden mouse move event.
static Capability identifyFormatToCapability(QgsRaster::IdentifyFormat format)
bool isInScaleRange(double scale) const
Tests whether the layer should be visible at the specified scale.
QgsPoint toMapCoordinates(int x, int y) const
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:76
virtual void canvasReleaseEvent(QgsMapMouseEvent *e) override
Overridden mouse release event.
static QgsPointV2 closestVertex(const QgsAbstractGeometryV2 &geom, const QgsPointV2 &pt, QgsVertexId &id)
Returns the closest vertex to a geometry for a specified point.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
depends on scale if feature will be rendered (rule based )
QString join(const QString &separator) const
bool setEllipsoid(const QString &ellipsoid)
Sets ellipsoid by its acronym.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:187
QString & remove(int position, int n)
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 z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
void identifyMessage(const QString &)
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:667
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
void clear()
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:99
virtual Q_DECL_DEPRECATED bool willRenderFeature(QgsFeature &feat)
Returns whether the renderer will render a feature or not.
QString tr(const char *sourceText, const char *disambiguation, int n)
QgsMapToolIdentify(QgsMapCanvas *canvas)
constructor
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:109
const QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.cpp:76
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
Needs to be called when a new render cycle is started.
QString what() const
Definition: qgsexception.h:36
QLocale system()
QgsFields fields() const
Returns the list of fields of this layer.
T value(int i) const
virtual void stopRender(QgsRenderContext &context)=0
Needs to be called when a render cycle has finished to clean up.
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
Raster identify results container.
QList< Key > keys() const
virtual void activate()
called when set as currently active map tool
Definition: qgsmaptool.cpp:83
QgsMapCanvas * mCanvas
pointer to map canvas
Definition: qgsmaptool.h:213
QgsIdentifyMenu * mIdentifyMenu
QCursor mCursor
cursor used in map tool
Definition: qgsmaptool.h:216
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
void formatChanged(QgsRasterLayer *layer)
QString number(int n, int base)
bool isValid() const
Returns true if valid.
int count(const T &value) const
virtual QgsRasterIdentifyResult identify(const QgsPoint &thePoint, QgsRaster::IdentifyFormat theFormat, const QgsRectangle &theExtent=QgsRectangle(), int theWidth=0, int theHeight=0, int theDpi=96)
Identify raster value(s) found on the point position.
void append(const T &value)
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
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
virtual void deactivate() override
called when map tool is being deactivated
QgsPoint toLayerCoordinates(QgsMapLayer *layer, QPoint point)
transformation from screen coordinates to layer&#39;s coordinates
Definition: qgsmaptool.cpp:54
int toInt(bool *ok) const
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< IdentifyResult > identify(int x, int y, const QList< QgsMapLayer *> &layerList=QList< QgsMapLayer *>(), IdentifyMode mode=DefaultQgsSetting)
Performs the identification.
double scale() const
Return the calculated scale of the map.
QGis::UnitType mapUnits() const
Get the current canvas map units.
bool isMeasure() const
Returns true if the geometry contains m values.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:207
Point geometry type, with support for z-dimension and m-values.
Definition: qgspointv2.h:34
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:177
bool isEmpty() const
QgsRectangle extent() const
Returns the current zoom exent of the map canvas.
bool identifyLayer(QList< IdentifyResult > *results, QgsMapLayer *layer, const QgsPoint &point, const QgsRectangle &viewExtent, double mapUnitsPerPixel, const QgsMapToolIdentify::LayerType &layerType=AllLayers)
Call the right method depending on layer type.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void setOverrideCursor(const QCursor &cursor)
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Key value accessors.
void restoreOverrideCursor()
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
The QgsIdentifyMenu class builds a menu to be used with identify results (.
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:99
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
A class to represent a point.
Definition: qgspoint.h:117
bool identifyRasterLayer(QList< IdentifyResult > *results, QgsRasterLayer *layer, QgsPoint point, const QgsRectangle &viewExtent, double mapUnitsPerPixel)
QString toString() const
String representation of the point (x,y)
Definition: qgspoint.cpp:134
iterator end()
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
QMap< int, QVariant > results() const
Get results.
double measureArea(const QgsGeometry *geometry) const
Measures the area of a geometry.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
QgsExpressionContext & expressionContext()
Gets the expression context.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
Abstract base class for all map tools.
Definition: qgsmaptool.h:50
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:516
General purpose distance and area calculator.
double measurePerimeter(const QgsGeometry *geometry) const
Measures the perimeter of a polygon geometry.
QVariant value(const QString &key, const QVariant &defaultValue) const
virtual QgsPointV2 endPoint() const =0
Returns the end point of the curve.
Contains information about the context of a rendering operation.
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
QgsPoint layerToMapCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from layer&#39;s CRS to output CRS
virtual void canvasPressEvent(QgsMapMouseEvent *e) override
Overridden mouse press event.
QgsError error() const
Get error.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:182
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
void convertMeasurement(double &measure, QGis::UnitType &measureUnits, QGis::UnitType displayUnits, bool isArea) const
Helper for conversion between physical units.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:382
static AreaUnit distanceToAreaUnit(QGis::UnitType distanceUnit)
Converts a distance unit to its corresponding area unit, eg meters to square meters.
QMap< QString, QVariant > params() const
Get map of optional parameters.
static QString formatArea(double area, int decimals, QgsUnitTypes::AreaUnit unit, bool keepBaseUnit=false)
Returns an area formatted as a friendly string.
bool toBool() const
UnitType
Map units that qgis supports.
Definition: qgis.h:159
const QgsMapToPixel * getCoordinateTransform()
Get the current coordinate transform.
virtual QgsPointV2 startPoint() const =0
Returns the starting point of the curve.
qint64 QgsFeatureId
Definition: qgsfeature.h:31
double measureLength(const QgsGeometry *geometry) const
Measures the length of a geometry.
QgsFields & fields()
Get fields list.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
QString name
Read property of QString layerName.
Definition: qgsmaplayer.h:53
iterator insert(const Key &key, const T &value)
QgsRasterDataProvider * dataProvider()
Returns the data provider.
static QString formatDistance(double distance, int decimals, QGis::UnitType unit, bool keepBaseUnit=false)
Returns an distance formatted as a friendly string.
Custom exception class for Coordinate Reference System related exceptions.
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
const char * identify_cursor[]
Definition: qgscursors.cpp:135
virtual int capabilities()
returns bitwise OR-ed capabilities of the renderer
bool nextFeature(QgsFeature &f)
features may be filtered, i.e. some features may not be rendered (categorized, rule based ...
long srsid() const
Returns the SrsId, if available.
Type type() const
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
virtual QgsRectangle extent()
Return the extent of the layer.
Represents a vector layer which manages a vector based data sets.
int compare(const QString &other) const
QString message(QgsErrorMessage::Format theFormat=QgsErrorMessage::Html) const
Full error messages description.
Definition: qgserror.cpp:50
QString toString() const
bool identifyVectorLayer(QList< IdentifyResult > *results, QgsVectorLayer *layer, const QgsPoint &point)
AreaUnit
Units of area.
Definition: qgsunittypes.h:49
iterator begin()
double m() const
Returns the point&#39;s m value.
Definition: qgspointv2.h:86
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
int size() const
QgsFeatureList & features()
Get features list reference.
QgsMapLayer * layer(int index)
return the map layer at position index in the layer stack
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
virtual QgsPointV2 vertexAt(QgsVertexId id) const =0
Returns the point corresponding to a specified vertex id.
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:167
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
void setEllipsoidalMode(bool flag)
Sets whether coordinates must be projected to ellipsoid before measuring.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:212
const T value(const Key &key) const
Base class for raster data providers.