QGIS API Documentation  2.14.0-Essen
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->hasScaleBasedVisibility() &&
204  ( layer->minimumScale() > mCanvas->mapSettings().scale() ||
205  layer->maximumScale() <= mCanvas->mapSettings().scale() ) )
206  {
207  QgsDebugMsg( "Out of scale limits" );
208  return false;
209  }
210 
211  QApplication::setOverrideCursor( Qt::WaitCursor );
212 
213  QMap< QString, QString > commonDerivedAttributes;
214 
215  commonDerivedAttributes.insert( tr( "(clicked coordinate X)" ), formatXCoordinate( point ) );
216  commonDerivedAttributes.insert( tr( "(clicked coordinate Y)" ), formatYCoordinate( point ) );
217 
218  int featureCount = 0;
219 
220  QgsFeatureList featureList;
221 
222  // toLayerCoordinates will throw an exception for an 'invalid' point.
223  // For example, if you project a world map onto a globe using EPSG 2163
224  // and then click somewhere off the globe, an exception will be thrown.
225  try
226  {
227  // create the search rectangle
228  double searchRadius = searchRadiusMU( mCanvas );
229 
230  QgsRectangle r;
231  r.setXMinimum( point.x() - searchRadius );
232  r.setXMaximum( point.x() + searchRadius );
233  r.setYMinimum( point.y() - searchRadius );
234  r.setYMaximum( point.y() + searchRadius );
235 
236  r = toLayerCoordinates( layer, r );
237 
238  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) );
239  QgsFeature f;
240  while ( fit.nextFeature( f ) )
241  featureList << QgsFeature( f );
242  }
243  catch ( QgsCsException & cse )
244  {
245  Q_UNUSED( cse );
246  // catch exception for 'invalid' point and proceed with no features found
247  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
248  }
249 
250  QgsFeatureList::iterator f_it = featureList.begin();
251 
252  bool filter = false;
253 
256  QgsFeatureRendererV2* renderer = layer->rendererV2();
257  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
258  {
259  // setup scale for scale dependent visibility (rule based)
260  renderer->startRender( context, layer->fields() );
261  filter = renderer->capabilities() & QgsFeatureRendererV2::Filter;
262  }
263 
264  for ( ; f_it != featureList.end(); ++f_it )
265  {
266  QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
267 
268  QgsFeatureId fid = f_it->id();
269  context.expressionContext().setFeature( *f_it );
270 
271  if ( filter && !renderer->willRenderFeature( *f_it, context ) )
272  continue;
273 
274  featureCount++;
275 
276  derivedAttributes.unite( featureDerivedAttributes( &( *f_it ), layer, toLayerCoordinates( layer, point ) ) );
277 
278  derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) );
279 
280  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), *f_it, derivedAttributes ) );
281  }
282 
283  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
284  {
285  renderer->stopRender( context );
286  }
287 
288  QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) );
289 
291  return featureCount > 0;
292 }
293 
294 void QgsMapToolIdentify::closestVertexAttributes( const QgsAbstractGeometryV2& geometry, QgsVertexId vId, QgsMapLayer *layer, QMap< QString, QString >& derivedAttributes )
295 {
296  QString str = QLocale::system().toString( vId.vertex + 1 );
297  derivedAttributes.insert( tr( "Closest vertex number" ), str );
298 
299  QgsPointV2 closestPoint = geometry.vertexAt( vId );
300 
301  QgsPoint closestPointMapCoords = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( closestPoint.x(), closestPoint.y() ) );
302  derivedAttributes.insert( "Closest vertex X", formatXCoordinate( closestPointMapCoords ) );
303  derivedAttributes.insert( "Closest vertex Y", formatYCoordinate( closestPointMapCoords ) );
304 
305  if ( closestPoint.is3D() )
306  {
307  str = QLocale::system().toString( closestPoint.z(), 'g', 10 );
308  derivedAttributes.insert( "Closest vertex Z", str );
309  }
310  if ( closestPoint.isMeasure() )
311  {
312  str = QLocale::system().toString( closestPoint.m(), 'g', 10 );
313  derivedAttributes.insert( "Closest vertex M", str );
314  }
315 }
316 
317 QString QgsMapToolIdentify::formatCoordinate( const QgsPoint& canvasPoint ) const
318 {
319  return QgsCoordinateUtils::formatCoordinateForProject( canvasPoint, mCanvas->mapSettings().destinationCrs(),
320  mCoordinatePrecision );
321 }
322 
323 QString QgsMapToolIdentify::formatXCoordinate( const QgsPoint& canvasPoint ) const
324 {
325  QString coordinate = formatCoordinate( canvasPoint );
326  return coordinate.split( ',' ).at( 0 );
327 }
328 
329 QString QgsMapToolIdentify::formatYCoordinate( const QgsPoint& canvasPoint ) const
330 {
331  QString coordinate = formatCoordinate( canvasPoint );
332  return coordinate.split( ',' ).at( 1 );
333 }
334 
335 QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeature *feature, QgsMapLayer *layer, const QgsPoint& layerPoint )
336 {
337  // Calculate derived attributes and insert:
338  // measure distance or area depending on geometry type
339  QMap< QString, QString > derivedAttributes;
340 
341  // init distance/area calculator
342  QString ellipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE );
343  QgsDistanceArea calc;
345  calc.setEllipsoid( ellipsoid );
346  calc.setSourceCrs( layer->crs().srsid() );
347 
349  QGis::GeometryType geometryType = QGis::NoGeometry;
350 
351  QgsVertexId vId;
352  QgsPointV2 closestPoint;
353  if ( feature->constGeometry() )
354  {
355  geometryType = feature->constGeometry()->type();
356  wkbType = feature->constGeometry()->geometry()->wkbType();
357  //find closest vertex to clicked point
358  closestPoint = QgsGeometryUtils::closestVertex( *feature->constGeometry()->geometry(), QgsPointV2( layerPoint.x(), layerPoint.y() ), vId );
359  }
360 
361  if ( QgsWKBTypes::isMultiType( wkbType ) )
362  {
363  QString str = QLocale::system().toString( static_cast<QgsGeometryCollectionV2*>( feature->constGeometry()->geometry() )->numGeometries() );
364  derivedAttributes.insert( tr( "Parts" ), str );
365  str = QLocale::system().toString( vId.part + 1 );
366  derivedAttributes.insert( tr( "Part number" ), str );
367  }
368 
369  if ( geometryType == QGis::Line )
370  {
371  double dist = calc.measureLength( feature->constGeometry() );
372  dist = calc.convertLengthMeasurement( dist, displayDistanceUnits() );
373  QString str = formatDistance( dist );
374  derivedAttributes.insert( tr( "Length" ), str );
375 
376  const QgsCurveV2* curve = dynamic_cast< const QgsCurveV2* >( feature->constGeometry()->geometry() );
377  if ( curve )
378  {
379  str = QLocale::system().toString( curve->nCoordinates() );
380  derivedAttributes.insert( tr( "Vertices" ), str );
381 
382  //add details of closest vertex to identify point
383  closestVertexAttributes( *curve, vId, layer, derivedAttributes );
384 
385  // Add the start and end points in as derived attributes
386  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( curve->startPoint().x(), curve->startPoint().y() ) );
387  str = formatXCoordinate( pnt );
388  derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
389  str = formatYCoordinate( pnt );
390  derivedAttributes.insert( tr( "firstY" ), str );
391  pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( curve->endPoint().x(), curve->endPoint().y() ) );
392  str = formatXCoordinate( pnt );
393  derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
394  str = formatYCoordinate( pnt );
395  derivedAttributes.insert( tr( "lastY" ), str );
396  }
397  }
398  else if ( geometryType == QGis::Polygon )
399  {
400  double area = calc.measureArea( feature->constGeometry() );
401  area = calc.convertAreaMeasurement( area, displayAreaUnits() );
402  QString str = formatArea( area );
403  derivedAttributes.insert( tr( "Area" ), str );
404 
405  double perimeter = calc.measurePerimeter( feature->constGeometry() );
406  perimeter = calc.convertLengthMeasurement( perimeter, displayDistanceUnits() );
407  str = formatDistance( perimeter );
408  derivedAttributes.insert( tr( "Perimeter" ), str );
409 
410  str = QLocale::system().toString( feature->constGeometry()->geometry()->nCoordinates() );
411  derivedAttributes.insert( tr( "Vertices" ), str );
412 
413  //add details of closest vertex to identify point
414  closestVertexAttributes( *feature->constGeometry()->geometry(), vId, layer, derivedAttributes );
415  }
416  else if ( geometryType == QGis::Point &&
418  {
419  // Include the x and y coordinates of the point as a derived attribute
420  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->constGeometry()->asPoint() );
421  QString str = formatXCoordinate( pnt );
422  derivedAttributes.insert( "X", str );
423  str = formatYCoordinate( pnt );
424  derivedAttributes.insert( "Y", str );
425 
426  if ( QgsWKBTypes::hasZ( wkbType ) )
427  {
428  str = QLocale::system().toString( static_cast<QgsPointV2*>( feature->constGeometry()->geometry() )->z(), 'g', 10 );
429  derivedAttributes.insert( "Z", str );
430  }
431  if ( QgsWKBTypes::hasM( wkbType ) )
432  {
433  str = QLocale::system().toString( static_cast<QgsPointV2*>( feature->constGeometry()->geometry() )->m(), 'g', 10 );
434  derivedAttributes.insert( "M", str );
435  }
436  }
437 
438  return derivedAttributes;
439 }
440 
441 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, QgsPoint point, const QgsRectangle& viewExtent, double mapUnitsPerPixel )
442 {
443  QgsDebugMsg( "point = " + point.toString() );
444  if ( !layer )
445  return false;
446 
447  QgsRasterDataProvider *dprovider = layer->dataProvider();
448  if ( !dprovider )
449  return false;
450 
451  int capabilities = dprovider->capabilities();
452  if ( !( capabilities & QgsRasterDataProvider::Identify ) )
453  return false;
454 
455  QgsPoint pointInCanvasCrs = point;
456  try
457  {
458  point = toLayerCoordinates( layer, point );
459  }
460  catch ( QgsCsException &cse )
461  {
462  Q_UNUSED( cse );
463  QgsDebugMsg( QString( "coordinate not reprojectable: %1" ).arg( cse.what() ) );
464  return false;
465  }
466  QgsDebugMsg( QString( "point = %1 %2" ).arg( point.x() ).arg( point.y() ) );
467 
468  if ( !layer->extent().contains( point ) )
469  return false;
470 
471  QMap< QString, QString > attributes, derivedAttributes;
472 
474 
475  // check if the format is really supported otherwise use first supported format
476  if ( !( QgsRasterDataProvider::identifyFormatToCapability( format ) & capabilities ) )
477  {
479  else if ( capabilities & QgsRasterInterface::IdentifyValue ) format = QgsRaster::IdentifyFormatValue;
480  else if ( capabilities & QgsRasterInterface::IdentifyHtml ) format = QgsRaster::IdentifyFormatHtml;
481  else if ( capabilities & QgsRasterInterface::IdentifyText ) format = QgsRaster::IdentifyFormatText;
482  else return false;
483  }
484 
485  QgsRasterIdentifyResult identifyResult;
486  // We can only use current map canvas context (extent, width, height) if layer is not reprojected,
487  if ( mCanvas->hasCrsTransformEnabled() && dprovider->crs() != mCanvas->mapSettings().destinationCrs() )
488  {
489  // To get some reasonable response for point/line WMS vector layers we must
490  // use a context with approximately a resolution in layer CRS units
491  // corresponding to current map canvas resolution (for examplei UMN Mapserver
492  // in msWMSFeatureInfo() -> msQueryByRect() is using requested pixel
493  // + TOLERANCE (layer param) for feature selection)
494  //
495  QgsRectangle r;
496  r.setXMinimum( pointInCanvasCrs.x() - mapUnitsPerPixel / 2. );
497  r.setXMaximum( pointInCanvasCrs.x() + mapUnitsPerPixel / 2. );
498  r.setYMinimum( pointInCanvasCrs.y() - mapUnitsPerPixel / 2. );
499  r.setYMaximum( pointInCanvasCrs.y() + mapUnitsPerPixel / 2. );
500  r = toLayerCoordinates( layer, r ); // will be a bit larger
501  // Mapserver (6.0.3, for example) does not work with 1x1 pixel box
502  // but that is fixed (the rect is enlarged) in the WMS provider
503  identifyResult = dprovider->identify( point, format, r, 1, 1 );
504  }
505  else
506  {
507  // It would be nice to use the same extent and size which was used for drawing,
508  // so that WCS can use cache from last draw, unfortunately QgsRasterLayer::draw()
509  // is doing some tricks with extent and size to allign raster to output which
510  // would be difficult to replicate here.
511  // Note: cutting the extent may result in slightly different x and y resolutions
512  // and thus shifted point calculated back in QGIS WMS (using average resolution)
513  //viewExtent = dprovider->extent().intersect( &viewExtent );
514 
515  // Width and height are calculated from not projected extent and we hope that
516  // are similar to source width and height used to reproject layer for drawing.
517  // TODO: may be very dangerous, because it may result in different resolutions
518  // in source CRS, and WMS server (QGIS server) calcs wrong coor using average resolution.
519  int width = qRound( viewExtent.width() / mapUnitsPerPixel );
520  int height = qRound( viewExtent.height() / mapUnitsPerPixel );
521 
522  QgsDebugMsg( QString( "viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.width() ).arg( viewExtent.height() ) );
523  QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) );
524  QgsDebugMsg( QString( "xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.width() / width ).arg( viewExtent.height() / height ).arg( mapUnitsPerPixel ) );
525 
526  identifyResult = dprovider->identify( point, format, viewExtent, width, height );
527  }
528 
529  derivedAttributes.insert( tr( "(clicked coordinate X)" ), formatXCoordinate( pointInCanvasCrs ) );
530  derivedAttributes.insert( tr( "(clicked coordinate Y)" ), formatYCoordinate( pointInCanvasCrs ) );
531 
532  if ( identifyResult.isValid() )
533  {
534  QMap<int, QVariant> values = identifyResult.results();
535  QgsGeometry geometry;
536  if ( format == QgsRaster::IdentifyFormatValue )
537  {
538  Q_FOREACH ( int bandNo, values.keys() )
539  {
540  QString valueString;
541  if ( values.value( bandNo ).isNull() )
542  {
543  valueString = tr( "no data" );
544  }
545  else
546  {
547  double value = values.value( bandNo ).toDouble();
548  valueString = QgsRasterBlock::printValue( value );
549  }
550  attributes.insert( dprovider->generateBandName( bandNo ), valueString );
551  }
552  QString label = layer->name();
553  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
554  }
555  else if ( format == QgsRaster::IdentifyFormatFeature )
556  {
557  Q_FOREACH ( int i, values.keys() )
558  {
559  QVariant value = values.value( i );
560  if ( value.type() == QVariant::Bool && !value.toBool() )
561  {
562  // sublayer not visible or not queryable
563  continue;
564  }
565 
566  if ( value.type() == QVariant::String )
567  {
568  // error
569  // TODO: better error reporting
570  QString label = layer->subLayers().value( i );
571  attributes.clear();
572  attributes.insert( tr( "Error" ), value.toString() );
573 
574  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
575  continue;
576  }
577 
578  // list of feature stores for a single sublayer
579  QgsFeatureStoreList featureStoreList = values.value( i ).value<QgsFeatureStoreList>();
580 
581  Q_FOREACH ( QgsFeatureStore featureStore, featureStoreList )
582  {
583  Q_FOREACH ( QgsFeature feature, featureStore.features() )
584  {
585  attributes.clear();
586  // WMS sublayer and feature type, a sublayer may contain multiple feature types.
587  // Sublayer name may be the same as layer name and feature type name
588  // may be the same as sublayer. We try to avoid duplicities in label.
589  QString sublayer = featureStore.params().value( "sublayer" ).toString();
590  QString featureType = featureStore.params().value( "featureType" ).toString();
591  // Strip UMN MapServer '_feature'
592  featureType.remove( "_feature" );
593  QStringList labels;
594  if ( sublayer.compare( layer->name(), Qt::CaseInsensitive ) != 0 )
595  {
596  labels << sublayer;
597  }
598  if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
599  {
600  labels << featureType;
601  }
602 
603  QMap< QString, QString > derAttributes = derivedAttributes;
604  derAttributes.unite( featureDerivedAttributes( &feature, layer ) );
605 
606  IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( " / " ), featureStore.fields(), feature, derAttributes );
607 
608  identifyResult.mParams.insert( "getFeatureInfoUrl", featureStore.params().value( "getFeatureInfoUrl" ) );
609  results->append( identifyResult );
610  }
611  }
612  }
613  }
614  else // text or html
615  {
616  QgsDebugMsg( QString( "%1 HTML or text values" ).arg( values.size() ) );
617  Q_FOREACH ( int bandNo, values.keys() )
618  {
619  QString value = values.value( bandNo ).toString();
620  attributes.clear();
621  attributes.insert( "", value );
622 
623  QString label = layer->subLayers().value( bandNo );
624  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
625  }
626  }
627  }
628  else
629  {
630  attributes.clear();
631  QString value = identifyResult.error().message( QgsErrorMessage::Text );
632  attributes.insert( tr( "Error" ), value );
633  QString label = tr( "Identify error" );
634  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
635  }
636 
637  return true;
638 }
639 
640 void QgsMapToolIdentify::convertMeasurement( QgsDistanceArea &calc, double &measure, QGis::UnitType &u, bool isArea )
641 {
642  // Helper for converting between units
643  // The parameter &u is out only...
644 
645  // Get the canvas units
646  QGis::UnitType myUnits = mCanvas->mapUnits();
647 
649  calc.convertMeasurement( measure, myUnits, displayUnits(), isArea );
650  u = displayUnits();
652 }
653 
654 QGis::UnitType QgsMapToolIdentify::displayUnits()
655 {
656  return mCanvas->mapUnits();
657 }
658 
659 QGis::UnitType QgsMapToolIdentify::displayDistanceUnits() const
660 {
661  return mCanvas->mapUnits();
662 }
663 
664 QgsUnitTypes::AreaUnit QgsMapToolIdentify::displayAreaUnits() const
665 {
667 }
668 
669 QString QgsMapToolIdentify::formatDistance( double distance ) const
670 {
671  QSettings settings;
672  bool baseUnit = settings.value( "/qgis/measure/keepbaseunit", false ).toBool();
673 
674  return QgsDistanceArea::textUnit( distance, 3, displayDistanceUnits(), false, baseUnit );
675 }
676 
677 QString QgsMapToolIdentify::formatArea( double area ) const
678 {
679  QSettings settings;
680  bool baseUnit = settings.value( "/qgis/measure/keepbaseunit", false ).toBool();
681 
682  return QgsDistanceArea::formatArea( area, 3, displayAreaUnits(), baseUnit );
683 }
684 
686 {
687  QgsDebugMsg( "Entered" );
688  QList<IdentifyResult> results;
689  if ( identifyRasterLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel ) )
690  {
691  emit changedRasterResults( results );
692  }
693 }
694 
bool isValid() const
Returns true if valid.
Wrapper for iterator of features from vector data provider or vector layer.
Container for features with the same fields and crs.
QgsWKBTypes::Type wkbType() const
Returns the WKB type of the geometry.
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
QgsPoint layerToMapCoordinates(QgsMapLayer *theLayer, QgsPoint point) const
transform point coordinates from layer&#39;s CRS to output CRS
virtual QStringList subLayers() const override
Returns the sublayers of this layer - Useful for providers that manage their own layers, such as WMS.
QgsMapLayer::LayerType type() const
Get the type of the layer.
Definition: qgsmaplayer.cpp:99
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
GeometryType
Definition: qgis.h:111
void convertMeasurement(double &measure, QGis::UnitType &measureUnits, QGis::UnitType displayUnits, bool isArea) const
Helper for conversion between physical units.
double scale() const
Return the calculated scale of the map.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
void changedRasterResults(QList< IdentifyResult > &)
int layerCount() const
return number of layers on the map
QString name() const
Get the display name of the layer.
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.
double x() const
Returns the point&#39;s x-coordinate.
Definition: qgspointv2.h:68
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:703
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.
QgsFields fields() const
Returns the list of fields of this layer.
long srsid() const
Returns the SrsId, if available.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
QgsAbstractGeometryV2 * geometry() const
Returns the underlying geometry store.
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.
bool contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
const T & at(int i) const
float minimumScale() const
Returns the minimum scale denominator at which the layer is visible.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:476
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:407
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
QGis::GeometryType type() const
Returns type of the geometry as a QGis::GeometryType.
QPoint mapToGlobal(const QPoint &pos) const
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)
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
QStringList readListEntry(const QString &scope, const QString &key, const QStringList &def=QStringList(), bool *ok=nullptr) const
Key value accessors.
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.
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)
void identifyMessage(const QString &)
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:656
void clear()
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:105
QMap< int, QVariant > results() const
Get results.
double x() const
Get the x value of the point.
Definition: qgspoint.h:128
int nCoordinates() const
Returns the number of nodes contained in the geometry.
QList< IdentifyResult > identify(int x, int y, const QList< QgsMapLayer * > &layerList=QList< QgsMapLayer * >(), IdentifyMode mode=DefaultQgsSetting)
Performs the identification.
const QString GEO_NONE
Constant that holds the string representation for "No ellips/No CRS".
Definition: qgis.cpp:76
virtual void startRender(QgsRenderContext &context, const QgsFields &fields)=0
Needs to be called when a new render cycle is started.
QLocale system()
T value(int i) const
double y() const
Returns the point&#39;s y-coordinate.
Definition: qgspointv2.h:74
virtual void stopRender(QgsRenderContext &context)=0
Needs to be called when a render cycle has finished to clean up.
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:194
QgsIdentifyMenu * mIdentifyMenu
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual QgsRasterIdentifyResult identify(const QgsPoint &thePoint, QgsRaster::IdentifyFormat theFormat, const QgsRectangle &theExtent=QgsRectangle(), int theWidth=0, int theHeight=0)
Identify raster value(s) found on the point position.
QCursor mCursor
cursor used in map tool
Definition: qgsmaptool.h:197
QgsFeatureRendererV2 * rendererV2()
Return renderer V2.
QString readEntry(const QString &scope, const QString &key, const QString &def=QString::null, bool *ok=nullptr) const
void formatChanged(QgsRasterLayer *layer)
QString number(int n, int base)
int count(const T &value) const
void append(const T &value)
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
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.
bool isMeasure() const
Returns true if the geometry contains m values.
double z() const
Returns the point&#39;s z-coordinate.
Definition: qgspointv2.h:80
static QgsRaster::IdentifyFormat identifyFormatFromName(const QString &formatName)
double convertAreaMeasurement(double area, QgsUnitTypes::AreaUnit toUnits) const
Takes an area measurement calculated by this QgsDistanceArea object and converts it to a different ar...
float maximumScale() const
Returns the maximum scale denominator at which the layer is visible.
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
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
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)
QString toString() const
String representation of the point (x,y)
Definition: qgspoint.cpp:126
void restoreOverrideCursor()
double measurePerimeter(const QgsGeometry *geometry) const
Measures the perimeter of a polygon geometry.
QString id() const
Get this layer&#39;s unique ID, this ID is used to access this layer from map layer registry.
virtual QString generateBandName(int theBandNumber) const
helper function to create zero padded band names
The QgsIdentifyMenu class builds a menu to be used with identify results (.
QGis::UnitType mapUnits() const
Get the current canvas map units.
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:99
QVariant customProperty(const QString &value, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer.
QString message(QgsErrorMessage::Format theFormat=QgsErrorMessage::Html) const
Full error messages description.
Definition: qgserror.cpp:50
A class to represent a point.
Definition: qgspoint.h:65
bool identifyRasterLayer(QList< IdentifyResult > *results, QgsRasterLayer *layer, QgsPoint point, const QgsRectangle &viewExtent, double mapUnitsPerPixel)
iterator end()
double measureArea(const QgsGeometry *geometry) const
Measures the area of a geometry.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsPoint toMapCoordinates(int x, int y) const
static QString textUnit(double value, int decimals, QGis::UnitType u, bool isArea, bool keepBaseUnit=false)
Returns a measurement formatted as a friendly string.
Abstract base class for all map tools.
Definition: qgsmaptool.h:50
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:408
General purpose distance and area calculator.
QString what() const
Definition: qgsexception.h:36
double measureLength(const QgsGeometry *geometry) const
Measures the length of a geometry.
bool hasGeometryType() const
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
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.
virtual void canvasPressEvent(QgsMapMouseEvent *e) override
Overridden mouse press event.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:182
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:381
static AreaUnit distanceToAreaUnit(QGis::UnitType distanceUnit)
Converts a distance unit to its corresponding area unit, eg meters to square meters.
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
static QString formatArea(double area, int decimals, QgsUnitTypes::AreaUnit unit, bool keepBaseUnit=false)
Returns an area formatted as a friendly string.
double m() const
Returns the point&#39;s m value.
Definition: qgspointv2.h:86
bool toBool() const
UnitType
Map units that qgis supports.
Definition: qgis.h:155
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 y() const
Get the y value of the point.
Definition: qgspoint.h:136
const QgsCoordinateReferenceSystem & crs() const
Returns layer&#39;s spatial reference system.
QgsFields & fields()
Get fields list.
static Type flatType(Type type)
Returns the flat type for a WKB type.
Definition: qgswkbtypes.h:366
iterator insert(const Key &key, const T &value)
QgsRasterDataProvider * dataProvider()
Returns the data provider.
QgsRectangle extent() const
Returns the current zoom exent of the map canvas.
Custom exception class for Coordinate Reference System related exceptions.
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)
Type type() const
Abstract base class for curved geometry type.
Definition: qgscurvev2.h:32
double convertLengthMeasurement(double length, QGis::UnitType toUnits) const
Takes a length measurement calculated by this QgsDistanceArea object and converts it to a different d...
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:207
QgsPoint asPoint() const
Return contents of the geometry as a point if wkbType is WKBPoint, otherwise returns [0...
QgsError error() const
Get error.
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 toString() const
bool identifyVectorLayer(QList< IdentifyResult > *results, QgsVectorLayer *layer, const QgsPoint &point)
QMap< QString, QVariant > params() const
Get map of optional parameters.
AreaUnit
Units of area.
Definition: qgsunittypes.h:49
iterator begin()
int size() const
QgsFeatureList & features()
Get features list reference.
QgsMapLayer * layer(int index)
return the map layer at position index in the layer stack
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
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.