QGIS API Documentation  2.13.0-Master
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 
42 #include <QSettings>
43 #include <QMouseEvent>
44 #include <QCursor>
45 #include <QPixmap>
46 #include <QStatusBar>
47 #include <QVariant>
48 #include <QMenu>
49 
51  : QgsMapTool( canvas )
52  , mIdentifyMenu( new QgsIdentifyMenu( mCanvas ) )
53  , mLastMapUnitsPerPixel( -1.0 )
54 {
55  // set cursor
56  QPixmap myIdentifyQPixmap = QPixmap(( const char ** ) identify_cursor );
57  mCursor = QCursor( myIdentifyQPixmap, 1, 1 );
58 }
59 
61 {
62  delete mIdentifyMenu;
63 }
64 
66 {
67  Q_UNUSED( e );
68 }
69 
71 {
72  Q_UNUSED( e );
73 }
74 
76 {
77  Q_UNUSED( e );
78 }
79 
81 {
82  return identify( x, y, mode, layerList, AllLayers );
83 }
84 
86 {
87  return identify( x, y, mode, QList<QgsMapLayer*>(), layerType );
88 }
89 
90 QList<QgsMapToolIdentify::IdentifyResult> QgsMapToolIdentify::identify( int x, int y, IdentifyMode mode, const QList<QgsMapLayer*>& layerList, const LayerType& layerType )
91 {
92  QList<IdentifyResult> results;
93 
94  mLastPoint = mCanvas->getCoordinateTransform()->toMapCoordinates( x, y );
95  mLastExtent = mCanvas->extent();
96  mLastMapUnitsPerPixel = mCanvas->mapUnitsPerPixel();
97 
98  if ( mode == DefaultQgsSetting )
99  {
100  QSettings settings;
101  mode = static_cast<IdentifyMode>( settings.value( "/Map/identifyMode", 0 ).toInt() );
102  }
103 
104  if ( mode == LayerSelection )
105  {
106  QList<IdentifyResult> results = identify( x, y, TopDownAll, layerList, layerType );
107  QPoint globalPos = mCanvas->mapToGlobal( QPoint( x + 5, y + 5 ) );
108  return mIdentifyMenu->exec( results, globalPos );
109  }
110  else if ( mode == ActiveLayer && layerList.isEmpty() )
111  {
112  QgsMapLayer *layer = mCanvas->currentLayer();
113 
114  if ( !layer )
115  {
116  emit identifyMessage( tr( "No active layer. To identify features, you must choose an active layer." ) );
117  return results;
118  }
119 
120  QApplication::setOverrideCursor( Qt::WaitCursor );
121 
122  identifyLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel, layerType );
123  }
124  else
125  {
126  QApplication::setOverrideCursor( Qt::WaitCursor );
127 
128  QStringList noIdentifyLayerIdList = QgsProject::instance()->readListEntry( "Identify", "/disabledLayers" );
129 
130  int layerCount;
131  if ( layerList.isEmpty() )
132  layerCount = mCanvas->layerCount();
133  else
134  layerCount = layerList.count();
135 
136 
137  for ( int i = 0; i < layerCount; i++ )
138  {
139 
140  QgsMapLayer *layer;
141  if ( layerList.isEmpty() )
142  layer = mCanvas->layer( i );
143  else
144  layer = layerList.value( i );
145 
146  emit identifyProgress( i, mCanvas->layerCount() );
147  emit identifyMessage( tr( "Identifying on %1..." ).arg( layer->name() ) );
148 
149  if ( noIdentifyLayerIdList.contains( layer->id() ) )
150  continue;
151 
152  if ( identifyLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel, layerType ) )
153  {
154  if ( mode == TopDownStopAtFirst )
155  break;
156  }
157  }
158 
160  emit identifyMessage( tr( "Identifying done." ) );
161  }
162 
164 
165  return results;
166 }
167 
169 {
171 }
172 
174 {
176 }
177 
178 bool QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLayer *layer, const QgsPoint& point, const QgsRectangle& viewExtent, double mapUnitsPerPixel, const LayerType& layerType )
179 {
180  if ( layer->type() == QgsMapLayer::RasterLayer && layerType.testFlag( RasterLayer ) )
181  {
182  return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), point, viewExtent, mapUnitsPerPixel );
183  }
184  else if ( layer->type() == QgsMapLayer::VectorLayer && layerType.testFlag( VectorLayer ) )
185  {
186  return identifyVectorLayer( results, qobject_cast<QgsVectorLayer *>( layer ), point );
187  }
188  else
189  {
190  return false;
191  }
192 }
193 
195 {
196  if ( !layer || !layer->hasGeometryType() )
197  return false;
198 
199  if ( layer->hasScaleBasedVisibility() &&
200  ( layer->minimumScale() > mCanvas->mapSettings().scale() ||
201  layer->maximumScale() <= mCanvas->mapSettings().scale() ) )
202  {
203  QgsDebugMsg( "Out of scale limits" );
204  return false;
205  }
206 
207  QApplication::setOverrideCursor( Qt::WaitCursor );
208 
209  QMap< QString, QString > commonDerivedAttributes;
210 
211  commonDerivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() );
212 
213  int featureCount = 0;
214 
215  QgsFeatureList featureList;
216 
217  // toLayerCoordinates will throw an exception for an 'invalid' point.
218  // For example, if you project a world map onto a globe using EPSG 2163
219  // and then click somewhere off the globe, an exception will be thrown.
220  try
221  {
222  // create the search rectangle
223  double searchRadius = searchRadiusMU( mCanvas );
224 
225  QgsRectangle r;
226  r.setXMinimum( point.x() - searchRadius );
227  r.setXMaximum( point.x() + searchRadius );
228  r.setYMinimum( point.y() - searchRadius );
229  r.setYMaximum( point.y() + searchRadius );
230 
231  r = toLayerCoordinates( layer, r );
232 
233  QgsFeatureIterator fit = layer->getFeatures( QgsFeatureRequest().setFilterRect( r ).setFlags( QgsFeatureRequest::ExactIntersect ) );
234  QgsFeature f;
235  while ( fit.nextFeature( f ) )
236  featureList << QgsFeature( f );
237  }
238  catch ( QgsCsException & cse )
239  {
240  Q_UNUSED( cse );
241  // catch exception for 'invalid' point and proceed with no features found
242  QgsDebugMsg( QString( "Caught CRS exception %1" ).arg( cse.what() ) );
243  }
244 
245  QgsFeatureList::iterator f_it = featureList.begin();
246 
247  bool filter = false;
248 
251  QgsFeatureRendererV2* renderer = layer->rendererV2();
252  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
253  {
254  // setup scale for scale dependent visibility (rule based)
255  renderer->startRender( context, layer->fields() );
256  filter = renderer->capabilities() & QgsFeatureRendererV2::Filter;
257  }
258 
259  for ( ; f_it != featureList.end(); ++f_it )
260  {
261  QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
262 
263  QgsFeatureId fid = f_it->id();
264  context.expressionContext().setFeature( *f_it );
265 
266  if ( filter && !renderer->willRenderFeature( *f_it, context ) )
267  continue;
268 
269  featureCount++;
270 
271  derivedAttributes.unite( featureDerivedAttributes( &( *f_it ), layer, toLayerCoordinates( layer, point ) ) );
272 
273  derivedAttributes.insert( tr( "feature id" ), fid < 0 ? tr( "new feature" ) : FID_TO_STRING( fid ) );
274 
275  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), *f_it, derivedAttributes ) );
276  }
277 
278  if ( renderer && renderer->capabilities() & QgsFeatureRendererV2::ScaleDependent )
279  {
280  renderer->stopRender( context );
281  }
282 
283  QgsDebugMsg( "Feature count on identify: " + QString::number( featureCount ) );
284 
286  return featureCount > 0;
287 }
288 
289 void QgsMapToolIdentify::closestVertexAttributes( const QgsAbstractGeometryV2& geometry, QgsVertexId vId, QgsMapLayer *layer, QMap< QString, QString >& derivedAttributes )
290 {
291  QString str = QLocale::system().toString( vId.vertex + 1 );
292  derivedAttributes.insert( tr( "Closest vertex number" ), str );
293 
294  QgsPointV2 closestPoint = geometry.vertexAt( vId );
295 
296  QgsPoint closestPointMapCoords = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( closestPoint.x(), closestPoint.y() ) );
297  str = QLocale::system().toString( closestPointMapCoords.x(), 'g', 10 );
298  derivedAttributes.insert( "Closest vertex X", str );
299  str = QLocale::system().toString( closestPointMapCoords.y(), 'g', 10 );
300  derivedAttributes.insert( "Closest vertex Y", str );
301 
302  if ( closestPoint.is3D() )
303  {
304  str = QLocale::system().toString( closestPoint.z(), 'g', 10 );
305  derivedAttributes.insert( "Closest vertex Z", str );
306  }
307  if ( closestPoint.isMeasure() )
308  {
309  str = QLocale::system().toString( closestPoint.m(), 'g', 10 );
310  derivedAttributes.insert( "Closest vertex M", str );
311  }
312 }
313 
314 QMap< QString, QString > QgsMapToolIdentify::featureDerivedAttributes( QgsFeature *feature, QgsMapLayer *layer, const QgsPoint& layerPoint )
315 {
316  // Calculate derived attributes and insert:
317  // measure distance or area depending on geometry type
318  QMap< QString, QString > derivedAttributes;
319 
320  // init distance/area calculator
321  QString ellipsoid = QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE );
322  QgsDistanceArea calc;
324  calc.setEllipsoid( ellipsoid );
325  calc.setSourceCrs( layer->crs().srsid() );
326 
328  QGis::GeometryType geometryType = QGis::NoGeometry;
329 
330  QgsVertexId vId;
331  QgsPointV2 closestPoint;
332  if ( feature->constGeometry() )
333  {
334  geometryType = feature->constGeometry()->type();
335  wkbType = feature->constGeometry()->geometry()->wkbType();
336  //find closest vertex to clicked point
337  closestPoint = QgsGeometryUtils::closestVertex( *feature->constGeometry()->geometry(), QgsPointV2( layerPoint.x(), layerPoint.y() ), vId );
338  }
339 
340  if ( QgsWKBTypes::isMultiType( wkbType ) )
341  {
342  QString str = QLocale::system().toString( static_cast<QgsGeometryCollectionV2*>( feature->constGeometry()->geometry() )->numGeometries() );
343  derivedAttributes.insert( tr( "Parts" ), str );
344  str = QLocale::system().toString( vId.part + 1 );
345  derivedAttributes.insert( tr( "Part number" ), str );
346  }
347 
348  if ( geometryType == QGis::Line )
349  {
350  double dist = calc.measureLength( feature->constGeometry() );
351  QGis::UnitType myDisplayUnits;
352  convertMeasurement( calc, dist, myDisplayUnits, false );
353  QString str = calc.textUnit( dist, 3, myDisplayUnits, false ); // dist and myDisplayUnits are out params
354  derivedAttributes.insert( tr( "Length" ), str );
355 
356  const QgsCurveV2* curve = dynamic_cast< const QgsCurveV2* >( feature->constGeometry()->geometry() );
357  if ( curve )
358  {
359  str = QLocale::system().toString( curve->nCoordinates() );
360  derivedAttributes.insert( tr( "Vertices" ), str );
361 
362  //add details of closest vertex to identify point
363  closestVertexAttributes( *curve, vId, layer, derivedAttributes );
364 
365  // Add the start and end points in as derived attributes
366  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( curve->startPoint().x(), curve->startPoint().y() ) );
367  str = QLocale::system().toString( pnt.x(), 'g', 10 );
368  derivedAttributes.insert( tr( "firstX", "attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
369  str = QLocale::system().toString( pnt.y(), 'g', 10 );
370  derivedAttributes.insert( tr( "firstY" ), str );
371  pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, QgsPoint( curve->endPoint().x(), curve->endPoint().y() ) );
372  str = QLocale::system().toString( pnt.x(), 'g', 10 );
373  derivedAttributes.insert( tr( "lastX", "attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
374  str = QLocale::system().toString( pnt.y(), 'g', 10 );
375  derivedAttributes.insert( tr( "lastY" ), str );
376  }
377  }
378  else if ( geometryType == QGis::Polygon )
379  {
380  double area = calc.measureArea( feature->constGeometry() );
381  double perimeter = calc.measurePerimeter( feature->constGeometry() );
382  QGis::UnitType myDisplayUnits;
383  convertMeasurement( calc, area, myDisplayUnits, true ); // area and myDisplayUnits are out params
384  QString str = calc.textUnit( area, 3, myDisplayUnits, true );
385  derivedAttributes.insert( tr( "Area" ), str );
386  convertMeasurement( calc, perimeter, myDisplayUnits, false ); // perimeter and myDisplayUnits are out params
387  str = calc.textUnit( perimeter, 3, myDisplayUnits, false );
388  derivedAttributes.insert( tr( "Perimeter" ), str );
389 
390  str = QLocale::system().toString( feature->constGeometry()->geometry()->nCoordinates() );
391  derivedAttributes.insert( tr( "Vertices" ), str );
392 
393  //add details of closest vertex to identify point
394  closestVertexAttributes( *feature->constGeometry()->geometry(), vId, layer, derivedAttributes );
395  }
396  else if ( geometryType == QGis::Point &&
398  {
399  // Include the x and y coordinates of the point as a derived attribute
400  QgsPoint pnt = mCanvas->mapSettings().layerToMapCoordinates( layer, feature->constGeometry()->asPoint() );
401  QString str = QLocale::system().toString( pnt.x(), 'g', 10 );
402  derivedAttributes.insert( "X", str );
403  str = QLocale::system().toString( pnt.y(), 'g', 10 );
404  derivedAttributes.insert( "Y", str );
405 
406  if ( QgsWKBTypes::hasZ( wkbType ) )
407  {
408  str = QLocale::system().toString( static_cast<QgsPointV2*>( feature->constGeometry()->geometry() )->z(), 'g', 10 );
409  derivedAttributes.insert( "Z", str );
410  }
411  if ( QgsWKBTypes::hasM( wkbType ) )
412  {
413  str = QLocale::system().toString( static_cast<QgsPointV2*>( feature->constGeometry()->geometry() )->m(), 'g', 10 );
414  derivedAttributes.insert( "M", str );
415  }
416  }
417 
418  return derivedAttributes;
419 }
420 
421 bool QgsMapToolIdentify::identifyRasterLayer( QList<IdentifyResult> *results, QgsRasterLayer *layer, QgsPoint point, const QgsRectangle& viewExtent, double mapUnitsPerPixel )
422 {
423  QgsDebugMsg( "point = " + point.toString() );
424  if ( !layer )
425  return false;
426 
427  QgsRasterDataProvider *dprovider = layer->dataProvider();
428  if ( !dprovider )
429  return false;
430 
431  int capabilities = dprovider->capabilities();
432  if ( !( capabilities & QgsRasterDataProvider::Identify ) )
433  return false;
434 
435  QgsPoint pointInCanvasCrs = point;
436  try
437  {
438  point = toLayerCoordinates( layer, point );
439  }
440  catch ( QgsCsException &cse )
441  {
442  Q_UNUSED( cse );
443  QgsDebugMsg( QString( "coordinate not reprojectable: %1" ).arg( cse.what() ) );
444  return false;
445  }
446  QgsDebugMsg( QString( "point = %1 %2" ).arg( point.x() ).arg( point.y() ) );
447 
448  if ( !layer->extent().contains( point ) )
449  return false;
450 
451  QMap< QString, QString > attributes, derivedAttributes;
452 
454 
455  // check if the format is really supported otherwise use first supported format
456  if ( !( QgsRasterDataProvider::identifyFormatToCapability( format ) & capabilities ) )
457  {
459  else if ( capabilities & QgsRasterInterface::IdentifyValue ) format = QgsRaster::IdentifyFormatValue;
460  else if ( capabilities & QgsRasterInterface::IdentifyHtml ) format = QgsRaster::IdentifyFormatHtml;
461  else if ( capabilities & QgsRasterInterface::IdentifyText ) format = QgsRaster::IdentifyFormatText;
462  else return false;
463  }
464 
465  QgsRasterIdentifyResult identifyResult;
466  // We can only use current map canvas context (extent, width, height) if layer is not reprojected,
467  if ( mCanvas->hasCrsTransformEnabled() && dprovider->crs() != mCanvas->mapSettings().destinationCrs() )
468  {
469  // To get some reasonable response for point/line WMS vector layers we must
470  // use a context with approximately a resolution in layer CRS units
471  // corresponding to current map canvas resolution (for examplei UMN Mapserver
472  // in msWMSFeatureInfo() -> msQueryByRect() is using requested pixel
473  // + TOLERANCE (layer param) for feature selection)
474  //
475  QgsRectangle r;
476  r.setXMinimum( pointInCanvasCrs.x() - mapUnitsPerPixel / 2. );
477  r.setXMaximum( pointInCanvasCrs.x() + mapUnitsPerPixel / 2. );
478  r.setYMinimum( pointInCanvasCrs.y() - mapUnitsPerPixel / 2. );
479  r.setYMaximum( pointInCanvasCrs.y() + mapUnitsPerPixel / 2. );
480  r = toLayerCoordinates( layer, r ); // will be a bit larger
481  // Mapserver (6.0.3, for example) does not work with 1x1 pixel box
482  // but that is fixed (the rect is enlarged) in the WMS provider
483  identifyResult = dprovider->identify( point, format, r, 1, 1 );
484  }
485  else
486  {
487  // It would be nice to use the same extent and size which was used for drawing,
488  // so that WCS can use cache from last draw, unfortunately QgsRasterLayer::draw()
489  // is doing some tricks with extent and size to allign raster to output which
490  // would be difficult to replicate here.
491  // Note: cutting the extent may result in slightly different x and y resolutions
492  // and thus shifted point calculated back in QGIS WMS (using average resolution)
493  //viewExtent = dprovider->extent().intersect( &viewExtent );
494 
495  // Width and height are calculated from not projected extent and we hope that
496  // are similar to source width and height used to reproject layer for drawing.
497  // TODO: may be very dangerous, because it may result in different resolutions
498  // in source CRS, and WMS server (QGIS server) calcs wrong coor using average resolution.
499  int width = qRound( viewExtent.width() / mapUnitsPerPixel );
500  int height = qRound( viewExtent.height() / mapUnitsPerPixel );
501 
502  QgsDebugMsg( QString( "viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.width() ).arg( viewExtent.height() ) );
503  QgsDebugMsg( QString( "width = %1 height = %2" ).arg( width ).arg( height ) );
504  QgsDebugMsg( QString( "xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.width() / width ).arg( viewExtent.height() / height ).arg( mapUnitsPerPixel ) );
505 
506  identifyResult = dprovider->identify( point, format, viewExtent, width, height );
507  }
508 
509  derivedAttributes.insert( tr( "(clicked coordinate)" ), point.toString() );
510 
511  if ( identifyResult.isValid() )
512  {
513  QMap<int, QVariant> values = identifyResult.results();
514  QgsGeometry geometry;
515  if ( format == QgsRaster::IdentifyFormatValue )
516  {
517  Q_FOREACH ( int bandNo, values.keys() )
518  {
519  QString valueString;
520  if ( values.value( bandNo ).isNull() )
521  {
522  valueString = tr( "no data" );
523  }
524  else
525  {
526  double value = values.value( bandNo ).toDouble();
527  valueString = QgsRasterBlock::printValue( value );
528  }
529  attributes.insert( dprovider->generateBandName( bandNo ), valueString );
530  }
531  QString label = layer->name();
532  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
533  }
534  else if ( format == QgsRaster::IdentifyFormatFeature )
535  {
536  Q_FOREACH ( int i, values.keys() )
537  {
538  QVariant value = values.value( i );
539  if ( value.type() == QVariant::Bool && !value.toBool() )
540  {
541  // sublayer not visible or not queryable
542  continue;
543  }
544 
545  if ( value.type() == QVariant::String )
546  {
547  // error
548  // TODO: better error reporting
549  QString label = layer->subLayers().value( i );
550  attributes.clear();
551  attributes.insert( tr( "Error" ), value.toString() );
552 
553  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
554  continue;
555  }
556 
557  // list of feature stores for a single sublayer
558  QgsFeatureStoreList featureStoreList = values.value( i ).value<QgsFeatureStoreList>();
559 
560  Q_FOREACH ( QgsFeatureStore featureStore, featureStoreList )
561  {
562  Q_FOREACH ( QgsFeature feature, featureStore.features() )
563  {
564  attributes.clear();
565  // WMS sublayer and feature type, a sublayer may contain multiple feature types.
566  // Sublayer name may be the same as layer name and feature type name
567  // may be the same as sublayer. We try to avoid duplicities in label.
568  QString sublayer = featureStore.params().value( "sublayer" ).toString();
569  QString featureType = featureStore.params().value( "featureType" ).toString();
570  // Strip UMN MapServer '_feature'
571  featureType.remove( "_feature" );
572  QStringList labels;
573  if ( sublayer.compare( layer->name(), Qt::CaseInsensitive ) != 0 )
574  {
575  labels << sublayer;
576  }
577  if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
578  {
579  labels << featureType;
580  }
581 
582  QMap< QString, QString > derAttributes = derivedAttributes;
583  derAttributes.unite( featureDerivedAttributes( &feature, layer ) );
584 
585  IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( " / " ), featureStore.fields(), feature, derAttributes );
586 
587  identifyResult.mParams.insert( "getFeatureInfoUrl", featureStore.params().value( "getFeatureInfoUrl" ) );
588  results->append( identifyResult );
589  }
590  }
591  }
592  }
593  else // text or html
594  {
595  QgsDebugMsg( QString( "%1 HTML or text values" ).arg( values.size() ) );
596  Q_FOREACH ( int bandNo, values.keys() )
597  {
598  QString value = values.value( bandNo ).toString();
599  attributes.clear();
600  attributes.insert( "", value );
601 
602  QString label = layer->subLayers().value( bandNo );
603  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
604  }
605  }
606  }
607  else
608  {
609  attributes.clear();
610  QString value = identifyResult.error().message( QgsErrorMessage::Text );
611  attributes.insert( tr( "Error" ), value );
612  QString label = tr( "Identify error" );
613  results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
614  }
615 
616  return true;
617 }
618 
619 void QgsMapToolIdentify::convertMeasurement( QgsDistanceArea &calc, double &measure, QGis::UnitType &u, bool isArea )
620 {
621  // Helper for converting between meters and feet
622  // The parameter &u is out only...
623 
624  // Get the canvas units
625  QGis::UnitType myUnits = mCanvas->mapUnits();
626 
627  calc.convertMeasurement( measure, myUnits, displayUnits(), isArea );
628  u = displayUnits();
629 }
630 
631 QGis::UnitType QgsMapToolIdentify::displayUnits()
632 {
633  return mCanvas->mapUnits();
634 }
635 
637 {
638  QgsDebugMsg( "Entered" );
639  QList<IdentifyResult> results;
640  if ( identifyRasterLayer( &results, layer, mLastPoint, mLastExtent, mLastMapUnitsPerPixel ) )
641  {
642  emit changedRasterResults( results );
643  }
644 }
645 
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:171
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.
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
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
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:193
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:196
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)
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:176
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)
Abstract base class for all map tools.
Definition: qgsmaptool.h:50
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:181
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:379
const QgsGeometry * constGeometry() const
Gets a const pointer to the geometry object associated with this feature.
Definition: qgsfeature.cpp:82
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 width() const
Width of the rectangle.
Definition: qgsrectangle.h:206
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.
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:166
void setEllipsoidalMode(bool flag)
Sets whether coordinates must be projected to ellipsoid before measuring.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:211
const T value(const Key &key) const
Base class for raster data providers.