Skip to content

Commit

Permalink
Multi identify for mesh layer (#37916)
Browse files Browse the repository at this point in the history
[FEATURE] map tool identify for mesh layer with displaying the dataset value corresponding of the current time of the temporal controller for all dataset groups
  • Loading branch information
vcloarec committed Jul 23, 2020
1 parent 4988694 commit 282d5f9
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 65 deletions.
2 changes: 2 additions & 0 deletions src/app/qgsidentifyresultsdialog.cpp
Expand Up @@ -1087,7 +1087,9 @@ void QgsIdentifyResultsDialog::addFeature( QgsMeshLayer *layer,
QgsFeature(),
layer->crs(),
QStringList() << label << QString() );

layItem->addChild( featItem );
featItem->setExpanded( true );

// attributes
for ( QMap<QString, QString>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
Expand Down
147 changes: 94 additions & 53 deletions src/gui/qgsmaptoolidentify.cpp
Expand Up @@ -28,6 +28,7 @@
#include "qgsmaptopixel.h"
#include "qgsmessageviewer.h"
#include "qgsmeshlayer.h"
#include "qgsmeshlayertemporalproperties.h"
#include "qgsmaplayer.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasterlayer.h"
Expand Down Expand Up @@ -251,76 +252,116 @@ bool QgsMapToolIdentify::identifyMeshLayer( QList<QgsMapToolIdentify::IdentifyRe
if ( !layer )
return false;

const QgsMeshRendererSettings rendererSettings = layer->rendererSettings();
const QgsMeshDatasetIndex scalarDatasetIndex = layer->activeScalarDatasetAtTime( mCanvas->temporalRange() );
const QgsMeshDatasetIndex vectorDatasetIndex = layer->activeVectorDatasetAtTime( mCanvas->temporalRange() );
if ( ! scalarDatasetIndex.isValid() && ! vectorDatasetIndex.isValid() )
return false;

QMap< QString, QString > scalarAttributes, vectorAttributes, raw3dAttributes;

double searchRadius = mOverrideCanvasSearchRadius < 0 ? searchRadiusMU( mCanvas ) : mOverrideCanvasSearchRadius;
bool isTemporal = mCanvas->mapSettings().isTemporal() && layer->temporalProperties()->isActive();

QString scalarGroup;
if ( scalarDatasetIndex.isValid() )
{
scalarGroup = layer->datasetGroupMetadata( scalarDatasetIndex.group() ).name();
QList<QgsMeshDatasetIndex> datasetIndexList;
int activeScalarGroup = layer->rendererSettings().activeScalarDatasetGroup();
int activeVectorGroup = layer->rendererSettings().activeVectorDatasetGroup();

const QgsMeshDatasetValue scalarValue = layer->datasetValue( scalarDatasetIndex, point, searchRadius );
const double scalar = scalarValue.scalar();
if ( std::isnan( scalar ) )
scalarAttributes.insert( tr( "Scalar Value" ), tr( "no data" ) );
else
scalarAttributes.insert( tr( "Scalar Value" ), QString::number( scalar ) );
if ( isTemporal ) //non active dataset group value are only accesible if temporal is active
{
const QgsDateTimeRange &time = mCanvas->mapSettings().temporalRange();
if ( activeScalarGroup >= 0 )
datasetIndexList.append( layer->activeScalarDatasetAtTime( time ) );
if ( activeVectorGroup >= 0 && activeVectorGroup != activeScalarGroup )
datasetIndexList.append( layer->activeVectorDatasetAtTime( time ) );

const QList<int> allGroup = layer->datasetGroupsIndexes();
for ( int groupIndex : allGroup )
{
if ( groupIndex != activeScalarGroup && groupIndex != activeVectorGroup )
datasetIndexList.append( layer->datasetIndexAtTime( time, groupIndex ) );
}
}
else
{
if ( activeScalarGroup >= 0 )
datasetIndexList.append( layer->staticScalarDatasetIndex() );
if ( activeVectorGroup >= 0 && activeVectorGroup != activeScalarGroup )
datasetIndexList.append( layer->staticVectorDatasetIndex() );
}

QString vectorGroup;
if ( vectorDatasetIndex.isValid() )
//create results
for ( const QgsMeshDatasetIndex &index : datasetIndexList )
{
vectorGroup = layer->datasetGroupMetadata( vectorDatasetIndex.group() ).name();
if ( !index.isValid() )
continue;

const QgsMeshDatasetValue vectorValue = layer->datasetValue( vectorDatasetIndex, point, searchRadius );
const double vectorX = vectorValue.x();
const double vectorY = vectorValue.y();
const QgsMeshDatasetGroupMetadata &groupMeta = layer->datasetGroupMetadata( index );
QMap< QString, QString > derivedAttributes;

if ( std::isnan( vectorX ) || std::isnan( vectorY ) )
vectorAttributes.insert( tr( "Vector Value" ), tr( "no data" ) );
else
QMap<QString, QString> attribute;
if ( groupMeta.isScalar() )
{
vectorAttributes.insert( tr( "Vector Magnitude" ), QString::number( vectorValue.scalar() ) );
vectorAttributes.insert( tr( "Vector x-component" ), QString::number( vectorY ) );
vectorAttributes.insert( tr( "Vector y-component" ), QString::number( vectorX ) );
const QgsMeshDatasetValue scalarValue = layer->datasetValue( index, point, searchRadius );
const double scalar = scalarValue.scalar();
attribute.insert( tr( "Scalar Value" ), std::isnan( scalar ) ? tr( "no data" ) : QString::number( scalar ) );
}
}

const QMap< QString, QString > derivedAttributes = derivedAttributesForPoint( QgsPoint( point ) );
if ( scalarGroup == vectorGroup )
{
if ( groupMeta.isVector() )
{
const QgsMeshDatasetValue vectorValue = layer->datasetValue( index, point, searchRadius );
const double vectorX = vectorValue.x();
const double vectorY = vectorValue.y();
if ( std::isnan( vectorX ) || std::isnan( vectorY ) )
attribute.insert( tr( "Vector Value" ), tr( "no data" ) );
else
{
attribute.insert( tr( "Vector Magnitude" ), QString::number( vectorValue.scalar() ) );
derivedAttributes.insert( tr( "Vector x-component" ), QString::number( vectorY ) );
derivedAttributes.insert( tr( "Vector y-component" ), QString::number( vectorX ) );
}
}

const QgsMeshDatasetMetadata &meta = layer->datasetMetadata( index );

if ( groupMeta.isTemporal() )
derivedAttributes.insert( tr( "Time Step" ), layer->formatTime( meta.time() ) );
derivedAttributes.insert( tr( "Source" ), groupMeta.uri() );

QString resultName = groupMeta.name();
if ( isTemporal && ( index.group() == activeScalarGroup || index.group() == activeVectorGroup ) )
resultName.append( tr( " (active)" ) );

const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
scalarGroup,
vectorAttributes,
resultName,
attribute,
derivedAttributes );

results->append( result );
}
else

QMap<QString, QString> derivedGeometry;

QgsPointXY vertexPoint = layer->snapOnElement( QgsMesh::Vertex, point, searchRadius );
if ( !vertexPoint.isEmpty() )
{
if ( !scalarGroup.isEmpty() )
{
const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
scalarGroup,
scalarAttributes,
derivedAttributes );
results->append( result );
}
if ( !vectorGroup.isEmpty() )
{
const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
vectorGroup,
vectorAttributes,
derivedAttributes );
results->append( result );
}
derivedGeometry.insert( tr( "Snapped Vertex Position X" ), QString::number( vertexPoint.x() ) );
derivedGeometry.insert( tr( "Snapped Vertex Position Y" ), QString::number( vertexPoint.y() ) );
}

QgsPointXY faceCentroid = layer->snapOnElement( QgsMesh::Face, point, searchRadius );
if ( !faceCentroid.isEmpty() )
{
derivedGeometry.insert( tr( "Face Centroid X" ), QString::number( faceCentroid.x() ) );
derivedGeometry.insert( tr( "Face Centroid Y" ), QString::number( faceCentroid.y() ) );
}

QgsPointXY pointOnEdge = layer->snapOnElement( QgsMesh::Edge, point, searchRadius );
if ( !pointOnEdge.isEmpty() )
{
derivedGeometry.insert( tr( "Point on Edge X" ), QString::number( pointOnEdge.x() ) );
derivedGeometry.insert( tr( "Point on Edge Y" ), QString::number( pointOnEdge.y() ) );
}

const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
tr( "Geometry" ),
derivedAttributesForPoint( QgsPoint( point ) ),
derivedGeometry );

results->append( result );

return true;
}

Expand Down
64 changes: 52 additions & 12 deletions tests/src/app/testqgsmaptoolidentifyaction.cpp
Expand Up @@ -36,6 +36,7 @@
#include "qgsidentifyresultsdialog.h"
#include "qgsmapmouseevent.h"
#include "qgsmaplayertemporalproperties.h"
#include "qgsmeshlayertemporalproperties.h"

#include <QTimer>

Expand Down Expand Up @@ -621,6 +622,9 @@ void TestQgsMapToolIdentifyAction::identifyMesh()
QVERIFY( tempLayer->isValid() );
const QString vectorDs = QStringLiteral( TEST_DATA_DIR ) + "/mesh/quad_and_triangle_vertex_vector.dat";
tempLayer->dataProvider()->addDataset( vectorDs );
static_cast<QgsMeshLayerTemporalProperties *>(
tempLayer->temporalProperties() )->setReferenceTime(
QDateTime( QDate( 1950, 01, 01 ), QTime( 0, 0, 0, Qt::UTC ), Qt::UTC ), tempLayer->dataProvider()->temporalCapabilities() );

// we need to setup renderer otherwise triangular mesh
// will not be populated and identify will not work
Expand All @@ -639,42 +643,78 @@ void TestQgsMapToolIdentifyAction::identifyMesh()
QList<QgsMapToolIdentify::IdentifyResult> results;

results = testIdentifyMesh( tempLayer, 500, 500 );
QCOMPARE( results.size(), 1 );
QCOMPARE( results.size(), 2 );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Scalar Value" )], QStringLiteral( "no data" ) );
QCOMPARE( results[0].mDerivedAttributes[QStringLiteral( "Source" )], mesh );
QCOMPARE( results[1].mLabel, QStringLiteral( "Geometry" ) );
results = testIdentifyMesh( tempLayer, 2400, 2400 );
QCOMPARE( results.size(), 1 );
QCOMPARE( results.size(), 2 );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Scalar Value" )], QStringLiteral( "42" ) );
QCOMPARE( results[0].mDerivedAttributes[QStringLiteral( "Source" )], mesh );
QCOMPARE( results[1].mLabel, QStringLiteral( "Geometry" ) );
QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Face Centroid X" )], QStringLiteral( "2333.33" ) );
QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Face Centroid Y" )], QStringLiteral( "2333.33" ) );
results = testIdentifyMesh( tempLayer, 1999, 2999 );
QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Snapped Vertex Position X" )], QStringLiteral( "2000" ) );
QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Snapped Vertex Position Y" )], QStringLiteral( "3000" ) );

canvas->setTemporalRange( QgsDateTimeRange( QDateTime( QDate( 1950, 01, 01 ), QTime( 0, 0, 0, Qt::UTC ), Qt::UTC ),
QDateTime( QDate( 1950, 01, 01 ), QTime( 1, 0, 0, Qt::UTC ), Qt::UTC ) ) );

tempLayer->temporalProperties()->setIsActive( true );
results = testIdentifyMesh( tempLayer, 2400, 2400 );
QCOMPARE( results.size(), 3 );
QCOMPARE( results[0].mLabel, QStringLiteral( "Bed Elevation (active)" ) );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Scalar Value" )], QStringLiteral( "42" ) );
QCOMPARE( results[0].mDerivedAttributes[QStringLiteral( "Source" )], mesh );

QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Time Step" )], QStringLiteral( "01.01.1950 00:00:00" ) );

QCOMPARE( results[1].mLabel, QStringLiteral( "VertexVectorDataset" ) );
QCOMPARE( results[1].mDerivedAttributes[QStringLiteral( "Source" )], vectorDs );
QCOMPARE( results[1].mAttributes[ QStringLiteral( "Vector Magnitude" )], QStringLiteral( "3" ) );
QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );

QCOMPARE( results[2].mLabel, QStringLiteral( "Geometry" ) );
QCOMPARE( results[2].mDerivedAttributes[QStringLiteral( "Face Centroid X" )], QStringLiteral( "2333.33" ) );
QCOMPARE( results[2].mDerivedAttributes[QStringLiteral( "Face Centroid Y" )], QStringLiteral( "2333.33" ) );
results = testIdentifyMesh( tempLayer, 1999, 2999 );
QCOMPARE( results[2].mDerivedAttributes[QStringLiteral( "Snapped Vertex Position X" )], QStringLiteral( "2000" ) );
QCOMPARE( results[2].mDerivedAttributes[QStringLiteral( "Snapped Vertex Position Y" )], QStringLiteral( "3000" ) );

tempLayer->temporalProperties()->setIsActive( false );

// scalar + vector same
tempLayer->setStaticScalarDatasetIndex( QgsMeshDatasetIndex( 1, 0 ) );
tempLayer->setStaticVectorDatasetIndex( QgsMeshDatasetIndex( 1, 0 ) );
results = testIdentifyMesh( tempLayer, 500, 500 );
QCOMPARE( results.size(), 1 );
QCOMPARE( results.size(), 2 );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector Value" )], QStringLiteral( "no data" ) );
results = testIdentifyMesh( tempLayer, 2400, 2400 );
QCOMPARE( results.size(), 1 );
QCOMPARE( results.size(), 2 );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector Magnitude" )], QStringLiteral( "3" ) );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );
QCOMPARE( results[0].mDerivedAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
QCOMPARE( results[0].mDerivedAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );

// scalar + vector different
tempLayer->setStaticScalarDatasetIndex( QgsMeshDatasetIndex( 0, 0 ) );
tempLayer->setStaticVectorDatasetIndex( QgsMeshDatasetIndex( 1, 0 ) );
results = testIdentifyMesh( tempLayer, 2400, 2400 );
QCOMPARE( results.size(), 2 );
QCOMPARE( results.size(), 3 );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Scalar Value" )], QStringLiteral( "42" ) );
QCOMPARE( results[1].mAttributes[ QStringLiteral( "Vector Magnitude" )], QStringLiteral( "3" ) );
QCOMPARE( results[1].mAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
QCOMPARE( results[1].mAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );
QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
QCOMPARE( results[1].mDerivedAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );

// only vector
tempLayer->setStaticScalarDatasetIndex( QgsMeshDatasetIndex() );
tempLayer->setStaticVectorDatasetIndex( QgsMeshDatasetIndex( 1, 0 ) );
results = testIdentifyMesh( tempLayer, 2400, 2400 );
QCOMPARE( results.size(), 1 );
QCOMPARE( results.size(), 2 );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector Magnitude" )], QStringLiteral( "3" ) );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
QCOMPARE( results[0].mAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );
QCOMPARE( results[0].mDerivedAttributes[ QStringLiteral( "Vector x-component" )], QStringLiteral( "1.8" ) );
QCOMPARE( results[0].mDerivedAttributes[ QStringLiteral( "Vector y-component" )], QStringLiteral( "2.4" ) );
}

void TestQgsMapToolIdentifyAction::identifyVectorTile()
Expand Down

0 comments on commit 282d5f9

Please sign in to comment.