53 #include <QMouseEvent>
63 , mLastMapUnitsPerPixel( -1.0 )
64 , mCoordinatePrecision( 6 )
96 return identify( x, y, mode, QList<QgsMapLayer *>(), layerType );
106 return identify( geometry, mode, QList<QgsMapLayer *>(), layerType );
111 QList<IdentifyResult> results;
113 mLastGeometry = geometry;
128 int x = canvasPt.x(), y = canvasPt.y();
130 QPoint globalPos =
mCanvas->mapToGlobal( QPoint( x + 5, y + 5 ) );
133 else if ( mode ==
ActiveLayer && layerList.isEmpty() )
139 emit
identifyMessage( tr(
"No active layer. To identify features, you must choose an active layer." ) );
143 QApplication::setOverrideCursor( Qt::WaitCursor );
145 identifyLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel, layerType );
149 QApplication::setOverrideCursor( Qt::WaitCursor );
152 if ( layerList.isEmpty() )
155 layerCount = layerList.count();
158 for (
int i = 0; i < layerCount; i++ )
162 if ( layerList.isEmpty() )
165 layer = layerList.value( i );
173 if (
identifyLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel, layerType ) )
184 QApplication::restoreOverrideCursor();
191 mOverrideCanvasSearchRadius = searchRadiusMapUnits;
196 mOverrideCanvasSearchRadius = -1;
218 return identifyRasterLayer( results, qobject_cast<QgsRasterLayer *>( layer ), geometry, viewExtent, mapUnitsPerPixel );
226 return identifyMeshLayer( results, qobject_cast<QgsMeshLayer *>( layer ), geometry );
230 return identifyVectorTileLayer( results, qobject_cast<QgsVectorTileLayer *>( layer ), geometry );
255 double searchRadius = mOverrideCanvasSearchRadius < 0 ?
searchRadiusMU(
mCanvas ) : mOverrideCanvasSearchRadius;
258 QList<QgsMeshDatasetIndex> datasetIndexList;
265 if ( activeScalarGroup >= 0 )
267 if ( activeVectorGroup >= 0 && activeVectorGroup != activeScalarGroup )
271 for (
int groupIndex : allGroup )
273 if ( groupIndex != activeScalarGroup && groupIndex != activeVectorGroup )
279 if ( activeScalarGroup >= 0 )
281 if ( activeVectorGroup >= 0 && activeVectorGroup != activeScalarGroup )
288 if ( !index.isValid() )
292 QMap< QString, QString > derivedAttributes;
294 QMap<QString, QString> attribute;
298 const double scalar = scalarValue.
scalar();
299 attribute.insert( tr(
"Scalar Value" ), std::isnan( scalar ) ? tr(
"no data" ) : QString::number( scalar ) );
305 const double vectorX = vectorValue.
x();
306 const double vectorY = vectorValue.
y();
307 if ( std::isnan( vectorX ) || std::isnan( vectorY ) )
308 attribute.insert( tr(
"Vector Value" ), tr(
"no data" ) );
311 attribute.insert( tr(
"Vector Magnitude" ), QString::number( vectorValue.
scalar() ) );
312 derivedAttributes.insert( tr(
"Vector x-component" ), QString::number( vectorY ) );
313 derivedAttributes.insert( tr(
"Vector y-component" ), QString::number( vectorX ) );
320 derivedAttributes.insert( tr(
"Time Step" ), layer->
formatTime( meta.
time() ) );
321 derivedAttributes.insert( tr(
"Source" ), groupMeta.
uri() );
323 QString resultName = groupMeta.
name();
324 if ( isTemporal && ( index.group() == activeScalarGroup || index.group() == activeVectorGroup ) )
325 resultName.append( tr(
" (active)" ) );
327 const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
332 results->append( result );
335 QMap<QString, QString> derivedGeometry;
340 derivedGeometry.insert( tr(
"Snapped Vertex Position X" ), QString::number( vertexPoint.
x() ) );
341 derivedGeometry.insert( tr(
"Snapped Vertex Position Y" ), QString::number( vertexPoint.
y() ) );
347 derivedGeometry.insert( tr(
"Face Centroid X" ), QString::number( faceCentroid.
x() ) );
348 derivedGeometry.insert( tr(
"Face Centroid Y" ), QString::number( faceCentroid.
y() ) );
354 derivedGeometry.insert( tr(
"Point on Edge X" ), QString::number( pointOnEdge.
x() ) );
355 derivedGeometry.insert( tr(
"Point on Edge Y" ), QString::number( pointOnEdge.
y() ) );
358 const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
363 results->append( result );
368 bool QgsMapToolIdentify::identifyVectorTileLayer( QList<QgsMapToolIdentify::IdentifyResult> *results,
QgsVectorTileLayer *layer,
const QgsGeometry &geometry )
381 QMap< QString, QString > commonDerivedAttributes;
384 bool isPointOrRectangle;
389 isPointOrRectangle =
true;
390 point = selectionGeom.
asPoint();
400 int featureCount = 0;
403 std::unique_ptr<QgsGeometryEngine> selectionGeomPrepared;
413 double sr = mOverrideCanvasSearchRadius < 0 ?
searchRadiusMU(
mCanvas ) : mOverrideCanvasSearchRadius;
420 if ( !isPointOrRectangle )
435 for (
int row = tileRange.
startRow(); row <= tileRange.
endRow(); ++row )
440 QByteArray data = layer->
getRawTile( tileID );
441 if ( data.isEmpty() )
445 if ( !decoder.
decode( tileID, data ) )
448 QMap<QString, QgsFields> perLayerFields;
449 const QStringList layerNames = decoder.
layers();
450 for (
const QString &layerName : layerNames )
452 QSet<QString> fieldNames = qgis::listToSet( decoder.
layerFieldNames( layerName ) );
457 const QStringList featuresLayerNames = features.keys();
458 for (
const QString &layerName : featuresLayerNames )
460 const QgsFields fFields = perLayerFields[layerName];
461 const QVector<QgsFeature> &layerFeatures = features[layerName];
464 if ( f.geometry().intersects( r ) && ( !selectionGeomPrepared || selectionGeomPrepared->intersects( f.geometry().constGet() ) ) )
466 QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
467 derivedAttributes.insert( tr(
"Feature ID" ),
FID_TO_STRING( f.id() ) );
469 results->
append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), layerName, fFields, f, derivedAttributes ) );
483 QgsDebugMsg( QStringLiteral(
"Caught CRS exception %1" ).arg( cse.
what() ) );
486 return featureCount > 0;
491 QMap< QString, QString > derivedAttributes;
492 derivedAttributes.insert( tr(
"(clicked coordinate X)" ), formatXCoordinate( point ) );
493 derivedAttributes.insert( tr(
"(clicked coordinate Y)" ), formatYCoordinate( point ) );
495 derivedAttributes.insert( tr(
"(clicked coordinate Z)" ), QString::number( point.
z(),
'f' ) );
496 return derivedAttributes;
506 QgsDebugMsg( QStringLiteral(
"Out of scale limits" ) );
510 QApplication::setOverrideCursor( Qt::WaitCursor );
512 QMap< QString, QString > commonDerivedAttributes;
515 bool isPointOrRectangle;
520 isPointOrRectangle =
true;
521 point = selectionGeom.
asPoint();
531 int featureCount = 0;
534 std::unique_ptr<QgsGeometryEngine> selectionGeomPrepared;
544 double sr = mOverrideCanvasSearchRadius < 0 ?
searchRadiusMU(
mCanvas ) : mOverrideCanvasSearchRadius;
551 if ( !isPointOrRectangle )
566 if ( !selectionGeomPrepared || selectionGeomPrepared->intersects( f.
geometry().
constGet() ) )
574 QgsDebugMsg( QStringLiteral(
"Caught CRS exception %1" ).arg( cse.
what() ) );
581 std::unique_ptr< QgsFeatureRenderer > renderer( layer->
renderer() ? layer->
renderer()->
clone() :
nullptr );
585 renderer->startRender( context, layer->
fields() );
589 for (
const QgsFeature &feature : qgis::as_const( featureList ) )
591 QMap< QString, QString > derivedAttributes = commonDerivedAttributes;
594 context.expressionContext().setFeature( feature );
596 if ( filter && !renderer->willRenderFeature( feature, context ) )
602 derivedAttributes.unite( featureDerivedAttributes( feature, layer,
toLayerCoordinates( layer, point ) ) );
604 derivedAttributes.insert( tr(
"Feature ID" ), fid < 0 ? tr(
"new feature" ) :
FID_TO_STRING( fid ) );
606 results->append( IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), feature, derivedAttributes ) );
611 renderer->stopRender( context );
614 QgsDebugMsgLevel(
"Feature count on identify: " + QString::number( featureCount ), 2 );
616 QApplication::restoreOverrideCursor();
617 return featureCount > 0;
629 QString str = QLocale().toString( vId.
vertex + 1 );
630 derivedAttributes.insert( tr(
"Closest vertex number" ), str );
635 derivedAttributes.insert( tr(
"Closest vertex X" ), formatXCoordinate( closestPointMapCoords ) );
636 derivedAttributes.insert( tr(
"Closest vertex Y" ), formatYCoordinate( closestPointMapCoords ) );
638 if ( closestPoint.
is3D() )
640 str = QLocale().
toString( closestPoint.
z(),
'g', 10 );
641 derivedAttributes.insert( tr(
"Closest vertex Z" ), str );
645 str = QLocale().toString( closestPoint.
m(),
'g', 10 );
646 derivedAttributes.insert( tr(
"Closest vertex M" ), str );
651 double radius, centerX, centerY;
657 geometry.
vertexAt( vIdAfter ), radius, centerX, centerY );
658 derivedAttributes.insert( QStringLiteral(
"Closest vertex radius" ), QLocale().toString( radius ) );
662 void QgsMapToolIdentify::closestPointAttributes(
const QgsAbstractGeometry &geometry,
const QgsPointXY &layerPoint, QMap<QString, QString> &derivedAttributes )
666 derivedAttributes.insert( tr(
"Closest X" ), formatXCoordinate( closestPoint ) );
667 derivedAttributes.insert( tr(
"Closest Y" ), formatYCoordinate( closestPoint ) );
669 if ( closestPoint.
is3D() )
671 const QString str = QLocale().toString( closestPoint.
z(),
'g', 10 );
672 derivedAttributes.insert( tr(
"Interpolated Z" ), str );
676 const QString str = QLocale().toString( closestPoint.
m(),
'g', 10 );
677 derivedAttributes.insert( tr(
"Interpolated M" ), str );
681 QString QgsMapToolIdentify::formatCoordinate(
const QgsPointXY &canvasPoint )
const
684 mCoordinatePrecision );
687 QString QgsMapToolIdentify::formatXCoordinate(
const QgsPointXY &canvasPoint )
const
689 QString coordinate = formatCoordinate( canvasPoint );
690 return coordinate.split(
',' ).at( 0 );
693 QString QgsMapToolIdentify::formatYCoordinate(
const QgsPointXY &canvasPoint )
const
695 QString coordinate = formatCoordinate( canvasPoint );
696 return coordinate.split(
',' ).at( 1 );
703 QMap< QString, QString > derivedAttributes;
729 derivedAttributes.insert( tr(
"Parts" ), str );
730 str = QLocale().toString( vId.
part + 1 );
731 derivedAttributes.insert( tr(
"Part number" ), str );
735 ? displayDistanceUnits() : layer->
crs().mapUnits();
737 ? displayAreaUnits() :
QgsUnitTypes::distanceToAreaUnit( layer->
crs().mapUnits() );
746 str = formatDistance( dist );
747 derivedAttributes.insert( tr(
"Length (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
752 derivedAttributes.insert( tr(
"Length (Cartesian)" ), str );
754 derivedAttributes.insert( tr(
"Length (Cartesian — 2D)" ), str );
757 str = formatDistance( qgsgeometry_cast< const QgsLineString * >( feature.
geometry().
constGet() )->length3D()
759 derivedAttributes.insert( tr(
"Length (Cartesian — 3D)" ), str );
766 derivedAttributes.insert( tr(
"Vertices" ), str );
768 closestVertexAttributes( *geom, vId, layer, derivedAttributes );
769 closestPointAttributes( *geom, layerPoint, derivedAttributes );
771 if (
const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geom ) )
775 str = formatXCoordinate( pnt );
776 derivedAttributes.insert( tr(
"firstX",
"attributes get sorted; translation for lastX should be lexically larger than this one" ), str );
777 str = formatYCoordinate( pnt );
778 derivedAttributes.insert( tr(
"firstY" ), str );
780 str = formatXCoordinate( pnt );
781 derivedAttributes.insert( tr(
"lastX",
"attributes get sorted; translation for firstX should be lexically smaller than this one" ), str );
782 str = formatYCoordinate( pnt );
783 derivedAttributes.insert( tr(
"lastY" ), str );
794 str = formatArea( area );
795 derivedAttributes.insert( tr(
"Area (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
799 derivedAttributes.insert( tr(
"Area (Cartesian)" ), str );
805 str = formatDistance( perimeter );
806 derivedAttributes.insert( tr(
"Perimeter (Ellipsoidal — %1)" ).arg( ellipsoid ), str );
810 derivedAttributes.insert( tr(
"Perimeter (Cartesian)" ), str );
813 derivedAttributes.insert( tr(
"Vertices" ), str );
816 closestVertexAttributes( *feature.
geometry().
constGet(), vId, layer, derivedAttributes );
817 closestPointAttributes( *feature.
geometry().
constGet(), layerPoint, derivedAttributes );
825 QString str = formatXCoordinate( pnt );
826 derivedAttributes.insert( tr(
"X" ), str );
827 str = formatYCoordinate( pnt );
828 derivedAttributes.insert( tr(
"Y" ), str );
833 derivedAttributes.insert( tr(
"Z" ), str );
838 derivedAttributes.insert( tr(
"M" ), str );
848 closestVertexAttributes( *geom, vId, layer, derivedAttributes );
853 return derivedAttributes;
884 QgsDebugMsg( QStringLiteral(
"coordinate not reprojectable: %1" ).arg( cse.
what() ) );
887 QgsDebugMsg( QStringLiteral(
"point = %1 %2" ).arg( point.
x() ).arg( point.
y() ) );
892 QMap< QString, QString > attributes, derivedAttributes;
917 r.
setXMinimum( pointInCanvasCrs.
x() - mapUnitsPerPixel / 2. );
918 r.
setXMaximum( pointInCanvasCrs.
x() + mapUnitsPerPixel / 2. );
919 r.
setYMinimum( pointInCanvasCrs.
y() - mapUnitsPerPixel / 2. );
920 r.
setYMaximum( pointInCanvasCrs.
y() + mapUnitsPerPixel / 2. );
924 identifyResult = dprovider->
identify( point, format, r, 1, 1 );
940 int width =
static_cast< int >( std::round( viewExtent.
width() / mapUnitsPerPixel ) );
941 int height =
static_cast< int >( std::round( viewExtent.
height() / mapUnitsPerPixel ) );
943 QgsDebugMsg( QStringLiteral(
"viewExtent.width = %1 viewExtent.height = %2" ).arg( viewExtent.
width() ).arg( viewExtent.
height() ) );
944 QgsDebugMsg( QStringLiteral(
"width = %1 height = %2" ).arg( width ).arg( height ) );
945 QgsDebugMsg( QStringLiteral(
"xRes = %1 yRes = %2 mapUnitsPerPixel = %3" ).arg( viewExtent.
width() / width ).arg( viewExtent.
height() / height ).arg( mapUnitsPerPixel ) );
947 identifyResult = dprovider->
identify( point, format, viewExtent, width, height );
952 if ( identifyResult.
isValid() )
954 QMap<int, QVariant> values = identifyResult.
results();
958 for (
auto it = values.constBegin(); it != values.constEnd(); ++it )
961 if ( it.value().isNull() )
963 valueString = tr(
"no data" );
967 QVariant value( it.value() );
971 if (
static_cast<QMetaType::Type
>( value.type() ) == QMetaType::Float )
982 QString label = layer->
name();
983 results->append(
IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
987 for (
auto it = values.constBegin(); it != values.constEnd(); ++it )
989 QVariant value = it.value();
990 if ( value.type() == QVariant::Bool && !value.toBool() )
996 if ( value.type() == QVariant::String )
1000 QString label = layer->
subLayers().value( it.key() );
1002 attributes.insert( tr(
"Error" ), value.toString() );
1004 results->append(
IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
1014 for (
const QgsFeature &feature : storeFeatures )
1020 QString sublayer = featureStore.params().value( QStringLiteral(
"sublayer" ) ).toString();
1021 QString featureType = featureStore.params().value( QStringLiteral(
"featureType" ) ).toString();
1023 featureType.remove( QStringLiteral(
"_feature" ) );
1025 if ( sublayer.compare( layer->
name(), Qt::CaseInsensitive ) != 0 )
1029 if ( featureType.compare( sublayer, Qt::CaseInsensitive ) != 0 || labels.isEmpty() )
1031 labels << featureType;
1034 QMap< QString, QString > derAttributes = derivedAttributes;
1035 derAttributes.unite( featureDerivedAttributes( feature, layer,
toLayerCoordinates( layer, point ) ) );
1037 IdentifyResult identifyResult( qobject_cast<QgsMapLayer *>( layer ), labels.join( QLatin1String(
" / " ) ), featureStore.fields(), feature, derAttributes );
1039 identifyResult.
mParams.insert( QStringLiteral(
"getFeatureInfoUrl" ), featureStore.params().value( QStringLiteral(
"getFeatureInfoUrl" ) ) );
1040 results->append( identifyResult );
1047 QgsDebugMsg( QStringLiteral(
"%1 HTML or text values" ).arg( values.size() ) );
1048 for (
auto it = values.constBegin(); it != values.constEnd(); ++it )
1050 QString value = it.value().toString();
1052 attributes.insert( QString(), value );
1054 QString label = layer->
subLayers().value( it.key() );
1055 results->append(
IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
1063 attributes.insert( tr(
"Error" ), value );
1064 QString label = tr(
"Identify error" );
1065 results->append(
IdentifyResult( qobject_cast<QgsMapLayer *>( layer ), label, attributes, derivedAttributes ) );
1081 QString QgsMapToolIdentify::formatDistance(
double distance )
const
1083 return formatDistance( distance, displayDistanceUnits() );
1086 QString QgsMapToolIdentify::formatArea(
double area )
const
1088 return formatArea( area, displayAreaUnits() );
1094 bool baseUnit = settings.
value( QStringLiteral(
"qgis/measure/keepbaseunit" ),
true ).toBool();
1102 bool baseUnit = settings.
value( QStringLiteral(
"qgis/measure/keepbaseunit" ),
true ).toBool();
1109 QList<IdentifyResult> results;
1110 if (
identifyRasterLayer( &results, layer, mLastGeometry, mLastExtent, mLastMapUnitsPerPixel ) )