52 #include <QMouseEvent>
62 , mLastMapUnitsPerPixel( -1.0 )
63 , mCoordinatePrecision( 6 )
95 return identify( x, y, mode, QList<QgsMapLayer *>(), layerType );
105 return identify( geometry, mode, QList<QgsMapLayer *>(), layerType );
110 QList<IdentifyResult> results;
112 mLastGeometry = geometry;
127 int x = canvasPt.x(), y = canvasPt.y();
129 QPoint globalPos =
mCanvas->mapToGlobal( QPoint( x + 5, y + 5 ) );
132 else if ( mode ==
ActiveLayer && layerList.isEmpty() )
138 emit
identifyMessage( tr(
"No active layer. To identify features, you must choose an active layer." ) );
142 QApplication::setOverrideCursor( Qt::WaitCursor );
144 identifyLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel, layerType );
148 QApplication::setOverrideCursor( Qt::WaitCursor );
151 if ( layerList.isEmpty() )
154 layerCount = layerList.count();
157 for (
int i = 0; i < layerCount; i++ )
161 if ( layerList.isEmpty() )
164 layer = layerList.value( i );
172 if (
identifyLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel, layerType ) )
183 QApplication::restoreOverrideCursor();
190 mOverrideCanvasSearchRadius = searchRadiusMapUnits;
195 mOverrideCanvasSearchRadius = -1;
217 return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), geometry, viewExtent, mapUnitsPerPixel );
225 return identifyMeshLayer( results, qobject_cast<QgsMeshLayer *>( layer ), geometry );
229 return identifyVectorTileLayer( results, qobject_cast<QgsVectorTileLayer *>( layer ), geometry );
257 if ( ! scalarDatasetIndex.
isValid() && ! vectorDatasetIndex.
isValid() )
260 QMap< QString, QString > scalarAttributes, vectorAttributes, raw3dAttributes;
262 double searchRadius = mOverrideCanvasSearchRadius < 0 ?
searchRadiusMU(
mCanvas ) : mOverrideCanvasSearchRadius;
265 if ( scalarDatasetIndex.
isValid() )
270 const double scalar = scalarValue.
scalar();
271 if ( std::isnan( scalar ) )
272 scalarAttributes.insert( tr(
"Scalar Value" ), tr(
"no data" ) );
274 scalarAttributes.insert( tr(
"Scalar Value" ), QString::number( scalar ) );
278 if ( vectorDatasetIndex.
isValid() )
283 const double vectorX = vectorValue.
x();
284 const double vectorY = vectorValue.
y();
286 if ( std::isnan( vectorX ) || std::isnan( vectorY ) )
287 vectorAttributes.insert( tr(
"Vector Value" ), tr(
"no data" ) );
290 vectorAttributes.insert( tr(
"Vector Magnitude" ), QString::number( vectorValue.
scalar() ) );
291 vectorAttributes.insert( tr(
"Vector x-component" ), QString::number( vectorY ) );
292 vectorAttributes.insert( tr(
"Vector y-component" ), QString::number( vectorX ) );
297 if ( scalarGroup == vectorGroup )
299 const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
303 results->append( result );
307 if ( !scalarGroup.isEmpty() )
309 const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
313 results->append( result );
315 if ( !vectorGroup.isEmpty() )
317 const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
321 results->append( result );
327 bool QgsMapToolIdentify::identifyVectorTileLayer( QList<QgsMapToolIdentify::IdentifyResult> *results,
QgsVectorTileLayer *layer,
const QgsGeometry &geometry )
340 QMap< QString, QString > commonDerivedAttributes;
343 bool isPointOrRectangle;
348 isPointOrRectangle =
true;
349 point = selectionGeom.
asPoint();
359 int featureCount = 0;
362 std::unique_ptr<QgsGeometryEngine> selectionGeomPrepared;
372 double sr = mOverrideCanvasSearchRadius < 0 ?
searchRadiusMU(
mCanvas ) : mOverrideCanvasSearchRadius;
379 if ( !isPointOrRectangle )
394 for (
int row = tileRange.
startRow(); row <= tileRange.
endRow(); ++row )
399 QByteArray data = layer->
getRawTile( tileID );
400 if ( data.isEmpty() )
404 if ( !decoder.
decode( tileID, data ) )
407 QMap<QString, QgsFields> perLayerFields;
408 const QStringList layerNames = decoder.
layers();
409 for (
const QString &layerName : layerNames )
411 QSet<QString> fieldNames = qgis::listToSet( decoder.
layerFieldNames( layerName ) );
416 const QStringList featuresLayerNames = features.keys();
417 for (
const QString &layerName : featuresLayerNames )
419 const QgsFields fFields = perLayerFields[layerName];
420 const QVector<QgsFeature> &layerFeatures = features[layerName];
423 if ( f.geometry().intersects( r ) && ( !selectionGeomPrepared || selectionGeomPrepared->intersects( f.geometry().constGet() ) ) )
425 QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
426 derivedAttributes.insert( tr(
"Feature ID" ),
FID_TO_STRING( f.id() ) );
428 results->
append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), layerName, fFields, f, derivedAttributes ) );
442 QgsDebugMsg( QStringLiteral(
"Caught CRS exception %1" ).arg( cse.
what() ) );
445 return featureCount > 0;
450 QMap< QString, QString > derivedAttributes;
451 derivedAttributes.insert( tr(
"(clicked coordinate X)" ), formatXCoordinate( point ) );
452 derivedAttributes.insert( tr(
"(clicked coordinate Y)" ), formatYCoordinate( point ) );
454 derivedAttributes.insert( tr(
"(clicked coordinate Z)" ), QString::number( point.
z(),
'f' ) );
455 return derivedAttributes;
465 QgsDebugMsg( QStringLiteral(
"Out of scale limits" ) );
469 QApplication::setOverrideCursor( Qt::WaitCursor );
471 QMap< QString, QString > commonDerivedAttributes;
474 bool isPointOrRectangle;
479 isPointOrRectangle =
true;
480 point = selectionGeom.
asPoint();
490 int featureCount = 0;
493 std::unique_ptr<QgsGeometryEngine> selectionGeomPrepared;
503 double sr = mOverrideCanvasSearchRadius < 0 ?
searchRadiusMU(
mCanvas ) : mOverrideCanvasSearchRadius;
510 if ( !isPointOrRectangle )
525 if ( !selectionGeomPrepared || selectionGeomPrepared->intersects( f.
geometry().
constGet() ) )
533 QgsDebugMsg( QStringLiteral(
"Caught CRS exception %1" ).arg( cse.
what() ) );
540 std::unique_ptr< QgsFeatureRenderer > renderer( layer->
renderer() ? layer->
renderer()->
clone() :
nullptr );
544 renderer->startRender( context, layer->
fields() );
548 for (
const QgsFeature &feature : qgis::as_const( featureList ) )
550 QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
553 context.expressionContext().setFeature( feature );
555 if ( filter && !renderer->willRenderFeature( feature, context ) )
561 derivedAttributes.unite( featureDerivedAttributes( feature, layer,
toLayerCoordinates( layer, point ) ) );
563 derivedAttributes.insert( tr(
"Feature ID" ), fid < 0 ? tr(
"new feature" ) :
FID_TO_STRING( fid ) );
565 results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), feature, derivedAttributes ) );
570 renderer->stopRender( context );
573 QgsDebugMsgLevel(
"Feature count on identify: " + QString::number( featureCount ), 2 );
575 QApplication::restoreOverrideCursor();
576 return featureCount > 0;
588 QString str = QLocale().toString( vId.
vertex + 1 );
589 derivedAttributes.insert( tr(
"Closest vertex number" ), str );
594 derivedAttributes.insert( tr(
"Closest vertex X" ), formatXCoordinate( closestPointMapCoords ) );
595 derivedAttributes.insert( tr(
"Closest vertex Y" ), formatYCoordinate( closestPointMapCoords ) );
597 if ( closestPoint.
is3D() )
599 str = QLocale().
toString( closestPoint.
z(),
'g', 10 );
600 derivedAttributes.insert( tr(
"Closest vertex Z" ), str );
604 str = QLocale().toString( closestPoint.
m(),
'g', 10 );
605 derivedAttributes.insert( tr(
"Closest vertex M" ), str );
610 double radius, centerX, centerY;
616 geometry.
vertexAt( vIdAfter ), radius, centerX, centerY );
617 derivedAttributes.insert( QStringLiteral(
"Closest vertex radius" ), QLocale().toString( radius ) );
621 void QgsMapToolIdentify::closestPointAttributes(
const QgsAbstractGeometry &geometry,
const QgsPointXY &layerPoint, QMap<QString, QString> &derivedAttributes )
625 derivedAttributes.insert( tr(
"Closest X" ), formatXCoordinate( closestPoint ) );
626 derivedAttributes.insert( tr(
"Closest Y" ), formatYCoordinate( closestPoint ) );
628 if ( closestPoint.
is3D() )
630 const QString str = QLocale().toString( closestPoint.
z(),
'g', 10 );
631 derivedAttributes.insert( tr(
"Interpolated Z" ), str );
635 const QString str = QLocale().toString( closestPoint.
m(),
'g', 10 );
636 derivedAttributes.insert( tr(
"Interpolated M" ), str );
640 QString QgsMapToolIdentify::formatCoordinate(
const QgsPointXY &canvasPoint )
const
643 mCoordinatePrecision );
646 QString QgsMapToolIdentify::formatXCoordinate(
const QgsPointXY &canvasPoint )
const
648 QString coordinate = formatCoordinate( canvasPoint );
649 return coordinate.split(
',' ).at( 0 );
652 QString QgsMapToolIdentify::formatYCoordinate(
const QgsPointXY &canvasPoint )
const
654 QString coordinate = formatCoordinate( canvasPoint );
655 return coordinate.split(
',' ).at( 1 );
662 QMap< QString, QString > derivedAttributes;
688 derivedAttributes.insert( tr(
"Parts" ), str );
689 str = QLocale().toString( vId.
part + 1 );
690 derivedAttributes.insert( tr(
"Part number" ), str );
694 ? displayDistanceUnits() : layer->
crs().mapUnits();
696 ? displayAreaUnits() :
QgsUnitTypes::distanceToAreaUnit( layer->
crs().mapUnits() );
705 str = formatDistance( dist );
706 derivedAttributes.insert( tr(
"Length (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
711 derivedAttributes.insert( tr(
"Length (Cartesian)" ), str );
713 derivedAttributes.insert( tr(
"Length (Cartesian — 2D)" ), str );
716 str = formatDistance( qgsgeometry_cast< const QgsLineString * >( feature.
geometry().
constGet() )->length3D()
718 derivedAttributes.insert( tr(
"Length (Cartesian — 3D)" ), str );
725 derivedAttributes.insert( tr(
"Vertices" ), str );
727 closestVertexAttributes( *geom, vId, layer, derivedAttributes );
728 closestPointAttributes( *geom, layerPoint, derivedAttributes );
730 if (
const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom ) )
734 str = formatXCoordinate( pnt );
735 derivedAttributes.insert( tr(
"firstX",
"attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
736 str = formatYCoordinate( pnt );
737 derivedAttributes.insert( tr(
"firstY" ), str );
739 str = formatXCoordinate( pnt );
740 derivedAttributes.insert( tr(
"lastX",
"attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
741 str = formatYCoordinate( pnt );
742 derivedAttributes.insert( tr(
"lastY" ), str );
753 str = formatArea( area );
754 derivedAttributes.insert( tr(
"Area (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
758 derivedAttributes.insert( tr(
"Area (Cartesian)" ), str );
764 str = formatDistance( perimeter );
765 derivedAttributes.insert( tr(
"Perimeter (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
769 derivedAttributes.insert( tr(
"Perimeter (Cartesian)" ), str );
772 derivedAttributes.insert( tr(
"Vertices" ), str );
775 closestVertexAttributes( *feature.
geometry().
constGet(), vId, layer, derivedAttributes );
776 closestPointAttributes( *feature.
geometry().
constGet(), layerPoint, derivedAttributes );
784 QString str = formatXCoordinate( pnt );
785 derivedAttributes.insert( tr(
"X" ), str );
786 str = formatYCoordinate( pnt );
787 derivedAttributes.insert( tr(
"Y" ), str );
792 derivedAttributes.insert( tr(
"Z" ), str );
797 derivedAttributes.insert( tr(
"M" ), str );
807 closestVertexAttributes( *geom, vId, layer, derivedAttributes );
812 return derivedAttributes;
843 QgsDebugMsg( QStringLiteral(
"coordinate not reprojectable: %1" ).arg( cse.
what() ) );
846 QgsDebugMsg( QStringLiteral(
"point = %1 %2" ).arg( point.
x() ).arg( point.
y() ) );
851 QMap< QString, QString > attributes, derivedAttributes;
876 r.
setXMinimum( pointInCanvasCrs.
x() - mapUnitsPerPixel / 2. );
877 r.
setXMaximum( pointInCanvasCrs.
x() + mapUnitsPerPixel / 2. );
878 r.
setYMinimum( pointInCanvasCrs.
y() - mapUnitsPerPixel / 2. );
879 r.
setYMaximum( pointInCanvasCrs.
y() + mapUnitsPerPixel / 2. );
883 identifyResult = dprovider->
identify( point, format, r, 1, 1 );
899 int width =
static_cast< int >( std::round( viewExtent.
width() / mapUnitsPerPixel ) );
900 int height =
static_cast< int >( std::round( viewExtent.
height() / mapUnitsPerPixel ) );
902 QgsDebugMsg( QStringLiteral(
"viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.
width() ).arg( viewExtent.
height() ) );
903 QgsDebugMsg( QStringLiteral(
"width = %1 height = %2" ).arg( width ).arg( height ) );
904 QgsDebugMsg( QStringLiteral(
"xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.
width() / width ).arg( viewExtent.
height() / height ).arg( mapUnitsPerPixel ) );
906 identifyResult = dprovider->
identify( point, format, viewExtent, width, height );
911 if ( identifyResult.
isValid() )
913 QMap<int, QVariant> values = identifyResult.
results();
917 for (
auto it = values.constBegin(); it != values.constEnd(); ++it )
920 if ( it.value().isNull() )
922 valueString = tr(
"no data" );
926 QVariant value( it.value() );
930 if (
static_cast<QMetaType::Type
>( value.type() ) == QMetaType::Float )
941 QString label = layer->
name();
942 results->append(
IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
946 for (
auto it = values.constBegin(); it != values.constEnd(); ++it )
948 QVariant value = it.value();
949 if ( value.type() == QVariant::Bool && !value.toBool() )
955 if ( value.type() == QVariant::String )
959 QString label = layer->
subLayers().value( it.key() );
961 attributes.insert( tr(
"Error" ), value.toString() );
963 results->append(
IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
973 for (
const QgsFeature &feature : storeFeatures )
979 QString sublayer = featureStore.params().value( QStringLiteral(
"sublayer" ) ).toString();
980 QString featureType = featureStore.params().value( QStringLiteral(
"featureType" ) ).toString();
982 featureType.remove( QStringLiteral(
"_feature" ) );
984 if ( sublayer.compare( layer->
name(), Qt::CaseInsensitive ) != 0 )
988 if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
990 labels << featureType;
993 QMap< QString, QString > derAttributes = derivedAttributes;
994 derAttributes.unite( featureDerivedAttributes( feature, layer,
toLayerCoordinates( layer, point ) ) );
996 IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( QStringLiteral(
" / " ) ), featureStore.fields(), feature, derAttributes );
998 identifyResult.
mParams.insert( QStringLiteral(
"getFeatureInfoUrl" ), featureStore.params().value( QStringLiteral(
"getFeatureInfoUrl" ) ) );
999 results->append( identifyResult );
1006 QgsDebugMsg( QStringLiteral(
"%1 HTML or text values" ).arg( values.size() ) );
1007 for (
auto it = values.constBegin(); it != values.constEnd(); ++it )
1009 QString value = it.value().toString();
1011 attributes.insert( QString(), value );
1013 QString label = layer->
subLayers().value( it.key() );
1014 results->append(
IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
1022 attributes.insert( tr(
"Error" ), value );
1023 QString label = tr(
"Identify error" );
1024 results->append(
IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
1040 QString QgsMapToolIdentify::formatDistance(
double distance )
const
1042 return formatDistance( distance, displayDistanceUnits() );
1045 QString QgsMapToolIdentify::formatArea(
double area )
const
1047 return formatArea( area, displayAreaUnits() );
1053 bool baseUnit = settings.
value( QStringLiteral(
"qgis/measure/keepbaseunit" ),
true ).toBool();
1061 bool baseUnit = settings.
value( QStringLiteral(
"qgis/measure/keepbaseunit" ),
true ).toBool();
1068 QList<IdentifyResult> results;
1069 if (
identifyRasterLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel ) )