Skip to content
Permalink
Browse files

fix identify for mesh layers (#9047)

  • Loading branch information
PeterPetrik committed Feb 1, 2019
1 parent 4495699 commit 3103b00f007520f0695f05f8d0c5a40e3d2dcf24
@@ -39,6 +39,7 @@ after selecting a point, performs the identification:
{
VectorLayer,
RasterLayer,
MeshLayer,
AllLayers
};
typedef QFlags<QgsMapToolIdentify::Type> LayerType;
@@ -103,9 +104,9 @@ this has been made private and two publics methods are offered
:param x: x coordinates of mouseEvent
:param y: y coordinates of mouseEvent
:param mode: Identification mode. Can use Qgis default settings or a defined mode.
:param layerType: Only performs identification in a certain type of layers (raster, vector). Default value is AllLayers.
:param layerType: Only performs identification in a certain type of layers (raster, vector, mesh). Default value is AllLayers.

:return: a list of IdentifyResult*
:return: a list of IdentifyResult
%End

QList<QgsMapToolIdentify::IdentifyResult> identify( const QgsGeometry &geometry, IdentifyMode mode, LayerType layerType );
@@ -144,9 +145,9 @@ this has been made private and two publics methods are offered
:param y: y coordinates of mouseEvent
:param mode: Identification mode. Can use Qgis default settings or a defined mode.
:param layerList: Performs the identification within the given list of layers.
:param layerType: Only performs identification in a certain type of layers (raster, vector).
:param layerType: Only performs identification in a certain type of layers (raster, vector, mesh).

:return: a list of IdentifyResult*
:return: a list of IdentifyResult
%End


@@ -158,6 +159,15 @@ Call the right method depending on layer type
bool identifyRasterLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsRasterLayer *layer, QgsPointXY point, const QgsRectangle &viewExtent, double mapUnitsPerPixel );
bool identifyVectorLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsVectorLayer *layer, const QgsPointXY &point );

bool identifyMeshLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsMeshLayer *layer, const QgsPointXY &point );
%Docstring
Identifies data from active scalar and vector dataset from the mesh layer

Works only if layer was already rendered (triangular mesh is created)

.. versionadded:: 3.6
%End

QMap< QString, QString > derivedAttributesForPoint( const QgsPoint &point );
%Docstring
Returns derived attributes map for a clicked point in map coordinates. May be 2D or 3D point.
@@ -33,6 +33,7 @@
#include "qgsmapcanvas.h"
#include "qgsmaplayeractionregistry.h"
#include "qgsmaplayer.h"
#include "qgsmeshlayer.h"
#include "qgsnetworkaccessmanager.h"
#include "qgsproject.h"
#include "qgsrasterdataprovider.h"
@@ -476,6 +477,9 @@ void QgsIdentifyResultsDialog::addFeature( const QgsMapToolIdentify::IdentifyRes
break;

case QgsMapLayer::MeshLayer:
addFeature( qobject_cast<QgsMeshLayer *>( result.mLayer ), result.mLabel, result.mAttributes, result.mDerivedAttributes );
break;

case QgsMapLayer::PluginLayer:
break;
}
@@ -923,6 +927,49 @@ void QgsIdentifyResultsDialog::addFeature( QgsRasterLayer *layer,
}
}

void QgsIdentifyResultsDialog::addFeature( QgsMeshLayer *layer,
const QString &label,
const QMap< QString, QString > &attributes,
const QMap< QString, QString > &derivedAttributes )
{
QTreeWidgetItem *layItem = layerItem( layer );

if ( !layItem )
{
layItem = new QTreeWidgetItem( QStringList() << QString::number( lstResults->topLevelItemCount() ) << layer->name() );
layItem->setData( 0, Qt::UserRole, QVariant::fromValue( qobject_cast<QObject *>( layer ) ) );

lstResults->addTopLevelItem( layItem );
connect( layer, &QObject::destroyed, this, &QgsIdentifyResultsDialog::layerDestroyed );
connect( layer, &QgsMapLayer::crsChanged, this, &QgsIdentifyResultsDialog::layerDestroyed );
}

QgsIdentifyResultsFeatureItem *featItem = new QgsIdentifyResultsFeatureItem( QgsFields(),
QgsFeature(),
layer->crs(),
QStringList() << label << QString() );
layItem->addChild( featItem );

// attributes
for ( QMap<QString, QString>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
{
featItem->addChild( new QTreeWidgetItem( QStringList() << it.key() << it.value() ) );
}

if ( derivedAttributes.size() >= 0 )
{
QgsTreeWidgetItem *derivedItem = new QgsTreeWidgetItem( QStringList() << tr( "(Derived)" ) );
derivedItem->setData( 0, Qt::UserRole, "derived" );
derivedItem->setAlwaysOnTopPriority( 0 );
featItem->addChild( derivedItem );

for ( QMap< QString, QString>::const_iterator it = derivedAttributes.begin(); it != derivedAttributes.end(); ++it )
{
derivedItem->addChild( new QTreeWidgetItem( QStringList() << it.key() << it.value() ) );
}
}
}

void QgsIdentifyResultsDialog::editingToggled()
{
QTreeWidgetItem *layItem = layerItem( sender() );
@@ -1397,6 +1444,14 @@ QgsRasterLayer *QgsIdentifyResultsDialog::rasterLayer( QTreeWidgetItem *item )
return qobject_cast<QgsRasterLayer *>( item->data( 0, Qt::UserRole ).value<QObject *>() );
}

QgsMeshLayer *QgsIdentifyResultsDialog::meshLayer( QTreeWidgetItem *item )
{
item = layerItem( item );
if ( !item )
return nullptr;
return qobject_cast<QgsMeshLayer *>( item->data( 0, Qt::UserRole ).value<QObject *>() );
}

QTreeWidgetItem *QgsIdentifyResultsDialog::retrieveAttributes( QTreeWidgetItem *item, QgsAttributeMap &attributes, int &idx )
{
QTreeWidgetItem *featItem = featureItem( item );
@@ -45,6 +45,7 @@ class QgsVectorLayer;
class QgsRasterLayer;
class QgsHighlight;
class QgsMapCanvas;
class QgsMeshLayer;
class QgsDockWidget;
class QgsMapLayerAction;
class QgsEditorWidgetSetup;
@@ -123,18 +124,21 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti

public:

//! Constructor - takes it own copy of the QgsAttributeAction so
// that it is independent of whoever created it.
/**
* Constructor -
* takes its own copy of the QgsAttributeAction so
* that it is independent of whoever created it.
*/
QgsIdentifyResultsDialog( QgsMapCanvas *canvas, QWidget *parent = nullptr, Qt::WindowFlags f = nullptr );

~QgsIdentifyResultsDialog() override;

//! Add add feature from vector layer
//! Adds feature from vector layer
void addFeature( QgsVectorLayer *layer,
const QgsFeature &f,
const QMap< QString, QString > &derivedAttributes );

//! Add add feature from other layer
//! Adds feature from raster layer
void addFeature( QgsRasterLayer *layer,
const QString &label,
const QMap< QString, QString > &attributes,
@@ -143,7 +147,16 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
const QgsFeature &feature = QgsFeature(),
const QMap<QString, QVariant> &params = ( QMap<QString, QVariant>() ) );

//! Add feature from identify results
/**
* Adds results from mesh layer
* \since QGIS 3.6
*/
void addFeature( QgsMeshLayer *layer,
const QString &label,
const QMap< QString, QString > &attributes,
const QMap< QString, QString > &derivedAttributes );

//! Adds feature from identify results
void addFeature( const QgsMapToolIdentify::IdentifyResult &result );

//! Map tool was deactivated
@@ -261,6 +274,7 @@ class APP_EXPORT QgsIdentifyResultsDialog: public QDialog, private Ui::QgsIdenti
QgsMapLayer *layer( QTreeWidgetItem *item );
QgsVectorLayer *vectorLayer( QTreeWidgetItem *item );
QgsRasterLayer *rasterLayer( QTreeWidgetItem *item );
QgsMeshLayer *meshLayer( QTreeWidgetItem *item );
QTreeWidgetItem *featureItem( QTreeWidgetItem *item );
QTreeWidgetItem *layerItem( QTreeWidgetItem *item );
QTreeWidgetItem *layerItem( QObject *layer );
@@ -27,6 +27,7 @@
#include "qgsmaptoolidentify.h"
#include "qgsmaptopixel.h"
#include "qgsmessageviewer.h"
#include "qgsmeshlayer.h"
#include "qgsmaplayer.h"
#include "qgsrasterdataprovider.h"
#include "qgsrasterlayer.h"
@@ -214,6 +215,10 @@ bool QgsMapToolIdentify::identifyLayer( QList<IdentifyResult> *results, QgsMapLa
{
return identifyVectorLayer( results, qobject_cast<QgsVectorLayer *>( layer ), geometry );
}
else if ( layer->type() == QgsMapLayer::MeshLayer && layerType.testFlag( MeshLayer ) )
{
return identifyMeshLayer( results, qobject_cast<QgsMeshLayer *>( layer ), geometry );
}
else
{
return false;
@@ -225,6 +230,89 @@ bool QgsMapToolIdentify::identifyVectorLayer( QList<QgsMapToolIdentify::Identify
return identifyVectorLayer( results, layer, QgsGeometry::fromPointXY( point ) );
}

bool QgsMapToolIdentify::identifyMeshLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsMeshLayer *layer, const QgsGeometry &geometry )
{
const QgsPointXY point = geometry.asPoint(); // mesh layers currently only support identification by point
return identifyMeshLayer( results, layer, point );
}

bool QgsMapToolIdentify::identifyMeshLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsMeshLayer *layer, const QgsPointXY &point )
{
QgsDebugMsgLevel( "point = " + point.toString(), 4 );
if ( !layer || !layer->dataProvider() )
return false;

const QgsMeshRendererSettings rendererSettings = layer->rendererSettings();
const QgsMeshDatasetIndex scalarDatasetIndex = rendererSettings.activeScalarDataset();
const QgsMeshDatasetIndex vectorDatasetIndex = rendererSettings.activeVectorDataset();
if ( ! scalarDatasetIndex.isValid() && ! vectorDatasetIndex.isValid() )
return false;

QMap< QString, QString > scalarAttributes, vectorAttributes;

QString scalarGroup;
if ( scalarDatasetIndex.isValid() )
{
scalarGroup = layer->dataProvider()->datasetGroupMetadata( scalarDatasetIndex.group() ).name();

const QgsMeshDatasetValue scalarValue = layer->datasetValue( scalarDatasetIndex, point );
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 ) );
}

QString vectorGroup;
if ( vectorDatasetIndex.isValid() )
{
vectorGroup = layer->dataProvider()->datasetGroupMetadata( vectorDatasetIndex.group() ).name();

const QgsMeshDatasetValue vectorValue = layer->datasetValue( vectorDatasetIndex, point );
const double vectorX = vectorValue.x();
const double vectorY = vectorValue.y();

if ( std::isnan( vectorX ) || std::isnan( vectorY ) )
vectorAttributes.insert( tr( "Vector Value" ), tr( "no data" ) );
else
{
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 QMap< QString, QString > derivedAttributes = derivedAttributesForPoint( QgsPoint( point ) );
if ( scalarGroup == vectorGroup )
{
const IdentifyResult result( qobject_cast<QgsMapLayer *>( layer ),
scalarGroup,
vectorAttributes,
derivedAttributes );
results->append( result );
}
else
{
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 );
}
}
return true;
}

QMap<QString, QString> QgsMapToolIdentify::derivedAttributesForPoint( const QgsPoint &point )
{
QMap< QString, QString > derivedAttributes;
@@ -30,6 +30,7 @@ class QgsRasterLayer;
class QgsVectorLayer;
class QgsMapLayer;
class QgsMapCanvas;
class QgsMeshLayer;
class QgsHighlight;
class QgsIdentifyMenu;
class QgsDistanceArea;
@@ -63,7 +64,8 @@ class GUI_EXPORT QgsMapToolIdentify : public QgsMapTool
{
VectorLayer = 1,
RasterLayer = 2,
AllLayers = VectorLayer | RasterLayer
MeshLayer = 4, //!< \since QGIS 3.6
AllLayers = VectorLayer | RasterLayer | MeshLayer
};
Q_DECLARE_FLAGS( LayerType, Type )
Q_FLAG( LayerType )
@@ -114,13 +116,14 @@ class GUI_EXPORT QgsMapToolIdentify : public QgsMapTool

/**
* Performs the identification.
To avoid being forced to specify IdentifyMode with a list of layers
this has been made private and two publics methods are offered
\param x x coordinates of mouseEvent
\param y y coordinates of mouseEvent
\param mode Identification mode. Can use Qgis default settings or a defined mode.
\param layerType Only performs identification in a certain type of layers (raster, vector). Default value is AllLayers.
\returns a list of IdentifyResult*/
* To avoid being forced to specify IdentifyMode with a list of layers
* this has been made private and two publics methods are offered
* \param x x coordinates of mouseEvent
* \param y y coordinates of mouseEvent
* \param mode Identification mode. Can use Qgis default settings or a defined mode.
* \param layerType Only performs identification in a certain type of layers (raster, vector, mesh). Default value is AllLayers.
* \returns a list of IdentifyResult
*/
QList<QgsMapToolIdentify::IdentifyResult> identify( int x, int y, IdentifyMode mode, LayerType layerType = AllLayers );

//! Performs identification based on a geometry (in map coordinates)
@@ -147,14 +150,15 @@ class GUI_EXPORT QgsMapToolIdentify : public QgsMapTool

/**
* Performs the identification.
To avoid being forced to specify IdentifyMode with a list of layers
this has been made private and two publics methods are offered
\param x x coordinates of mouseEvent
\param y y coordinates of mouseEvent
\param mode Identification mode. Can use Qgis default settings or a defined mode.
\param layerList Performs the identification within the given list of layers.
\param layerType Only performs identification in a certain type of layers (raster, vector).
\returns a list of IdentifyResult*/
* To avoid being forced to specify IdentifyMode with a list of layers
* this has been made private and two publics methods are offered
* \param x x coordinates of mouseEvent
* \param y y coordinates of mouseEvent
* \param mode Identification mode. Can use Qgis default settings or a defined mode.
* \param layerList Performs the identification within the given list of layers.
* \param layerType Only performs identification in a certain type of layers (raster, vector, mesh).
* \returns a list of IdentifyResult
*/
QList<QgsMapToolIdentify::IdentifyResult> identify( int x, int y, IdentifyMode mode, const QList<QgsMapLayer *> &layerList, LayerType layerType = AllLayers );

QgsIdentifyMenu *mIdentifyMenu = nullptr;
@@ -165,6 +169,14 @@ class GUI_EXPORT QgsMapToolIdentify : public QgsMapTool
bool identifyRasterLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsRasterLayer *layer, QgsPointXY point, const QgsRectangle &viewExtent, double mapUnitsPerPixel );
bool identifyVectorLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsVectorLayer *layer, const QgsPointXY &point );

/**
* Identifies data from active scalar and vector dataset from the mesh layer
*
* Works only if layer was already rendered (triangular mesh is created)
* \since QGIS 3.6
*/
bool identifyMeshLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsMeshLayer *layer, const QgsPointXY &point );

//! Returns derived attributes map for a clicked point in map coordinates. May be 2D or 3D point.
QMap< QString, QString > derivedAttributesForPoint( const QgsPoint &point );

@@ -194,6 +206,7 @@ class GUI_EXPORT QgsMapToolIdentify : public QgsMapTool
bool identifyLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsMapLayer *layer, const QgsGeometry &geometry, const QgsRectangle &viewExtent, double mapUnitsPerPixel, QgsMapToolIdentify::LayerType layerType = AllLayers );
bool identifyRasterLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsRasterLayer *layer, const QgsGeometry &geometry, const QgsRectangle &viewExtent, double mapUnitsPerPixel );
bool identifyVectorLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsVectorLayer *layer, const QgsGeometry &geometry );
bool identifyMeshLayer( QList<QgsMapToolIdentify::IdentifyResult> *results, QgsMeshLayer *layer, const QgsGeometry &geometry );

/**
* Desired units for distance display.

0 comments on commit 3103b00

Please sign in to comment.
You can’t perform that action at this time.