Skip to content

Commit

Permalink
[mesh] [feature] add function to identify value on the point
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterPetrik committed Aug 9, 2018
1 parent 51b63e6 commit c79e1d0
Show file tree
Hide file tree
Showing 11 changed files with 174 additions and 18 deletions.
5 changes: 5 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshdataprovider.sip.in
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@ Returns whether dataset group has scalar data
bool isOnVertices() const; bool isOnVertices() const;
%Docstring %Docstring
Returns whether dataset group data is defined on vertices Returns whether dataset group data is defined on vertices
%End

bool isOnFaces() const;
%Docstring
Returns whether dataset group data is defined on faces
%End %End


}; };
Expand Down
24 changes: 24 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshlayer.sip.in
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -189,6 +189,30 @@ If dataset is not vector based, do nothing. Triggers repaint
QgsMeshDatasetIndex activeVectorDataset() const; QgsMeshDatasetIndex activeVectorDataset() const;
%Docstring %Docstring
Returns active vector dataset Returns active vector dataset
%End

QgsMeshDatasetValue datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point ) const;
%Docstring
Interpolates the value on the given point from given dataset.

Returns NaN for NaN values, for values outside range or when
triangular mesh is not yet initialized on given point
%End

signals:

void activeScalarDatasetChanged( QgsMeshDatasetIndex index );
%Docstring
Emitted when active scalar dataset is changed

.. versionadded:: 3.4
%End

void activeVectorDatasetChanged( QgsMeshDatasetIndex index );
%Docstring
Emitted when active vector dataset is changed

.. versionadded:: 3.4
%End %End


private: // Private methods private: // Private methods
Expand Down
5 changes: 5 additions & 0 deletions src/core/mesh/qgsmeshdataprovider.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ bool QgsMeshDatasetGroupMetadata::isOnVertices() const
return mIsOnVertices; return mIsOnVertices;
} }


bool QgsMeshDatasetGroupMetadata::isOnFaces() const
{
return !mIsOnVertices;
}

int QgsMeshDatasetSourceInterface::datasetCount( QgsMeshDatasetIndex index ) const int QgsMeshDatasetSourceInterface::datasetCount( QgsMeshDatasetIndex index ) const
{ {
return datasetCount( index.group() ); return datasetCount( index.group() );
Expand Down
5 changes: 5 additions & 0 deletions src/core/mesh/qgsmeshdataprovider.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata
*/ */
bool isOnVertices() const; bool isOnVertices() const;


/**
* \brief Returns whether dataset group data is defined on faces
*/
bool isOnFaces() const;

private: private:
QString mName; QString mName;
bool mIsScalar = false; bool mIsScalar = false;
Expand Down
42 changes: 42 additions & 0 deletions src/core/mesh/qgsmeshlayer.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
***************************************************************************/ ***************************************************************************/


#include <cstddef> #include <cstddef>
#include <limits>


#include <QUuid> #include <QUuid>


Expand All @@ -27,6 +28,7 @@
#include "qgsproviderregistry.h" #include "qgsproviderregistry.h"
#include "qgsreadwritecontext.h" #include "qgsreadwritecontext.h"
#include "qgstriangularmesh.h" #include "qgstriangularmesh.h"
#include "qgsmeshlayerinterpolator.h"


QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath, QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
const QString &baseName, const QString &baseName,
Expand Down Expand Up @@ -154,6 +156,8 @@ void QgsMeshLayer::setActiveScalarDataset( QgsMeshDatasetIndex index )
mActiveScalarDataset = QgsMeshDatasetIndex(); mActiveScalarDataset = QgsMeshDatasetIndex();


triggerRepaint(); triggerRepaint();

emit activeScalarDatasetChanged( mActiveScalarDataset );
} }


void QgsMeshLayer::setActiveVectorDataset( QgsMeshDatasetIndex index ) void QgsMeshLayer::setActiveVectorDataset( QgsMeshDatasetIndex index )
Expand All @@ -175,6 +179,44 @@ void QgsMeshLayer::setActiveVectorDataset( QgsMeshDatasetIndex index )
} }


triggerRepaint(); triggerRepaint();

emit activeVectorDatasetChanged( mActiveVectorDataset );
}

QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point ) const
{
QgsMeshDatasetValue value;

if ( mTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
{
int face_index = mTriangularMesh->faceIndexForPoint( point ) ;
if ( face_index >= 0 )
{
bool isOnFaces = dataProvider()->datasetGroupMetadata( index ).isOnFaces();
if ( isOnFaces )
{
int native_face_index = mTriangularMesh->trianglesToNativeFaces().at( face_index );
return dataProvider()->datasetValue( index, native_face_index );
}
else
{
const QgsMeshFace &face = mTriangularMesh->triangles()[face_index];
const int v1 = face[0], v2 = face[1], v3 = face[2];
const QgsPoint p1 = mTriangularMesh->vertices()[v1], p2 = mTriangularMesh->vertices()[v2], p3 = mTriangularMesh->vertices()[v3];
const QgsMeshDatasetValue val1 = dataProvider()->datasetValue( index, v1 );
const QgsMeshDatasetValue val2 = dataProvider()->datasetValue( index, v2 );
const QgsMeshDatasetValue val3 = dataProvider()->datasetValue( index, v3 );
const double x = QgsMeshLayerInterpolator::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
double y = std::numeric_limits<double>::quiet_NaN();
bool isVector = dataProvider()->datasetGroupMetadata( index ).isVector();
if ( isVector )
y = QgsMeshLayerInterpolator::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );

return QgsMeshDatasetValue( x, y );
}
}
}
return value;
} }


void QgsMeshLayer::fillNativeMesh() void QgsMeshLayer::fillNativeMesh()
Expand Down
24 changes: 24 additions & 0 deletions src/core/mesh/qgsmeshlayer.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -183,6 +183,30 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
//! Returns active vector dataset //! Returns active vector dataset
QgsMeshDatasetIndex activeVectorDataset() const { return mActiveVectorDataset; } QgsMeshDatasetIndex activeVectorDataset() const { return mActiveVectorDataset; }


/**
* Interpolates the value on the given point from given dataset.
*
* Returns NaN for NaN values, for values outside range or when
* triangular mesh is not yet initialized on given point
*/
QgsMeshDatasetValue datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point ) const;

signals:

/**
* Emitted when active scalar dataset is changed
*
* \since QGIS 3.4
*/
void activeScalarDatasetChanged( QgsMeshDatasetIndex index );

/**
* Emitted when active vector dataset is changed
*
* \since QGIS 3.4
*/
void activeVectorDatasetChanged( QgsMeshDatasetIndex index );

private: // Private methods private: // Private methods


/** /**
Expand Down
5 changes: 2 additions & 3 deletions src/core/mesh/qgsmeshlayerinterpolator.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -88,9 +88,8 @@ static bool E3T_physicalToBarycentric( const QgsPointXY &pA, const QgsPointXY &p
return true; return true;
} }



double QgsMeshLayerInterpolator::interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
double interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3, double val1, double val2, double val3, const QgsPointXY &pt )
double val1, double val2, double val3, const QgsPointXY &pt )
{ {
double lam1, lam2, lam3; double lam1, lam2, lam3;
if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) ) if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
Expand Down
6 changes: 6 additions & 0 deletions src/core/mesh/qgsmeshlayerinterpolator.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ class QgsMeshLayerInterpolator : public QgsRasterInterface
int bandCount() const override; int bandCount() const override;
QgsRasterBlock *block( int, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback = nullptr ) override; QgsRasterBlock *block( int, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback = nullptr ) override;



static double interpolateFromVerticesData( const QgsPointXY &p1,
const QgsPointXY &p2,
const QgsPointXY &p3,
double val1, double val2, double val3, const QgsPointXY &pt );

private: private:
const QgsTriangularMesh &mTriangularMesh; const QgsTriangularMesh &mTriangularMesh;
const QVector<double> &mDatasetValues; const QVector<double> &mDatasetValues;
Expand Down
12 changes: 1 addition & 11 deletions src/core/mesh/qgsmeshlayerrenderer.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -229,17 +229,7 @@ void QgsMeshLayerRenderer::renderMesh( const std::unique_ptr<QgsSymbol> &symbol,
const QgsMeshFace &face = faces[i]; const QgsMeshFace &face = faces[i];
QgsFeature feat; QgsFeature feat;
feat.setFields( fields ); feat.setFields( fields );
QVector<QgsPointXY> ring; QgsGeometry geom = QgsMeshUtils::toGeometry( face, mTriangularMesh.vertices() ); //Triangular mesh vertices contains also native mesh vertices
for ( int j = 0; j < face.size(); ++j )
{
int vertex_id = face[j];
Q_ASSERT( vertex_id < mTriangularMesh.vertices().size() ); //Triangular mesh vertices contains also native mesh vertices
const QgsPoint &vertex = mTriangularMesh.vertices()[vertex_id];
ring.append( vertex );
}
QgsPolygonXY polygon;
polygon.append( ring );
QgsGeometry geom = QgsGeometry::fromPolygonXY( polygon );
feat.setGeometry( geom ); feat.setGeometry( geom );
renderer.renderFeature( feat, mContext ); renderer.renderFeature( feat, mContext );
} }
Expand Down
42 changes: 41 additions & 1 deletion src/core/mesh/qgstriangularmesh.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
* * * *
***************************************************************************/ ***************************************************************************/


#include <QList>
#include "qgsfeature.h"

#include "qgstriangularmesh.h" #include "qgstriangularmesh.h"
#include "qgsrendercontext.h" #include "qgsrendercontext.h"
#include "qgscoordinatetransform.h" #include "qgscoordinatetransform.h"
Expand Down Expand Up @@ -63,12 +66,12 @@ static void ENP_centroid( const QPolygonF &pX, double &cx, double &cy )
cy /= ( 6.0 * signedArea ); cy /= ( 6.0 * signedArea );
} }



void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context ) void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
{ {
Q_ASSERT( nativeMesh ); Q_ASSERT( nativeMesh );
Q_ASSERT( context ); Q_ASSERT( context );


mSpatialIndex = QgsSpatialIndex();
mTriangularMesh.vertices.clear(); mTriangularMesh.vertices.clear();
mTriangularMesh.faces.clear(); mTriangularMesh.faces.clear();
mTrianglesToNativeFaces.clear(); mTrianglesToNativeFaces.clear();
Expand Down Expand Up @@ -143,6 +146,15 @@ void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
ENP_centroid( poly, cx, cy ); ENP_centroid( poly, cx, cy );
mNativeMeshFaceCentroids[i] = QgsMeshVertex( cx, cy ); mNativeMeshFaceCentroids[i] = QgsMeshVertex( cx, cy );
} }

// CALCULATE SPATIAL INDEX
for ( int i = 0; i < mTriangularMesh.faces.size(); ++i )
{
const QgsMeshFace &face = mTriangularMesh.faces.at( i ) ;
QgsGeometry geom = QgsMeshUtils::toGeometry( face, mTriangularMesh.vertices );
bool success = mSpatialIndex.insertFeature( i, geom.boundingBox() );
Q_UNUSED( success );
}
} }


const QVector<QgsMeshVertex> &QgsTriangularMesh::vertices() const const QVector<QgsMeshVertex> &QgsTriangularMesh::vertices() const
Expand All @@ -165,3 +177,31 @@ const QVector<int> &QgsTriangularMesh::trianglesToNativeFaces() const
return mTrianglesToNativeFaces; return mTrianglesToNativeFaces;
} }


int QgsTriangularMesh::faceIndexForPoint( const QgsPointXY &point ) const
{
const QList<QgsFeatureId> face_indexes = mSpatialIndex.intersects( QgsRectangle( point, point ) );
for ( QgsFeatureId fid : face_indexes )
{
int face_index = static_cast<int>( fid );
const QgsMeshFace &face = mTriangularMesh.faces.at( face_index );
const QgsGeometry geom = QgsMeshUtils::toGeometry( face, mTriangularMesh.vertices );
if ( geom.contains( &point ) )
return face_index;
}
return -1;
}

QgsGeometry QgsMeshUtils::toGeometry( const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices )
{
QVector<QgsPointXY> ring;
for ( int j = 0; j < face.size(); ++j )
{
int vertex_id = face[j];
Q_ASSERT( vertex_id < vertices.size() );
const QgsPoint &vertex = vertices[vertex_id];
ring.append( vertex );
}
QgsPolygonXY polygon;
polygon.append( ring );
return QgsGeometry::fromPolygonXY( polygon );
}
22 changes: 19 additions & 3 deletions src/core/mesh/qgstriangularmesh.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@
#define SIP_NO_FILE #define SIP_NO_FILE


#include <QVector> #include <QVector>

#include "qgis_core.h" #include "qgis_core.h"
#include "qgsmeshdataprovider.h" #include "qgsmeshdataprovider.h"
#include "qgsgeometry.h"
#include "qgsspatialindex.h"


class QgsRenderContext; class QgsRenderContext;


Expand All @@ -40,7 +41,9 @@ struct CORE_EXPORT QgsMesh
/** /**
* \ingroup core * \ingroup core
* *
* Triangular/Derived Mesh * Triangular/Derived Mesh is mesh with vertices in map coordinates. It creates
* spatial index for identification of a triangle that contains a particular point
* on the map.
* *
* \note The API is considered EXPERIMENTAL and can be changed without a notice * \note The API is considered EXPERIMENTAL and can be changed without a notice
* *
Expand All @@ -55,7 +58,7 @@ class CORE_EXPORT QgsTriangularMesh
~QgsTriangularMesh() = default; ~QgsTriangularMesh() = default;


/** /**
* Constructs triangular mesh from layer's native mesh and context * Constructs triangular mesh from layer's native mesh and context. Populates spatial index.
* \param nativeMesh QgsMesh to access native vertices and faces * \param nativeMesh QgsMesh to access native vertices and faces
* \param context Rendering context to estimate number of triagles to create for an face * \param context Rendering context to estimate number of triagles to create for an face
*/ */
Expand All @@ -77,6 +80,12 @@ class CORE_EXPORT QgsTriangularMesh
//! Returns mapping between triangles and original faces //! Returns mapping between triangles and original faces
const QVector<int> &trianglesToNativeFaces() const ; const QVector<int> &trianglesToNativeFaces() const ;


/**
* Returns triangle index that contains the given point, -1 if no such triangle exists
* It uses spatial indexing
*/
int faceIndexForPoint( const QgsPointXY &point ) const ;

private: private:
// vertices: map CRS; 0-N ... native vertices, N+1 - len ... extra vertices // vertices: map CRS; 0-N ... native vertices, N+1 - len ... extra vertices
// faces are derived triangles // faces are derived triangles
Expand All @@ -85,7 +94,14 @@ class CORE_EXPORT QgsTriangularMesh


// centroids of the native faces in map CRS // centroids of the native faces in map CRS
QVector<QgsMeshVertex> mNativeMeshFaceCentroids; QVector<QgsMeshVertex> mNativeMeshFaceCentroids;

QgsSpatialIndex mSpatialIndex;
}; };


namespace QgsMeshUtils
{
//! Returns face as polygon geometry
QgsGeometry toGeometry( const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices );
};


#endif // QGSTRIANGULARMESH_H #endif // QGSTRIANGULARMESH_H

0 comments on commit c79e1d0

Please sign in to comment.