Skip to content

Commit c79e1d0

Browse files
committedAug 9, 2018
[mesh] [feature] add function to identify value on the point
1 parent 51b63e6 commit c79e1d0

11 files changed

+174
-18
lines changed
 

‎python/core/auto_generated/mesh/qgsmeshdataprovider.sip.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ Returns whether dataset group has scalar data
181181
bool isOnVertices() const;
182182
%Docstring
183183
Returns whether dataset group data is defined on vertices
184+
%End
185+
186+
bool isOnFaces() const;
187+
%Docstring
188+
Returns whether dataset group data is defined on faces
184189
%End
185190

186191
};

‎python/core/auto_generated/mesh/qgsmeshlayer.sip.in

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,30 @@ If dataset is not vector based, do nothing. Triggers repaint
189189
QgsMeshDatasetIndex activeVectorDataset() const;
190190
%Docstring
191191
Returns active vector dataset
192+
%End
193+
194+
QgsMeshDatasetValue datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point ) const;
195+
%Docstring
196+
Interpolates the value on the given point from given dataset.
197+
198+
Returns NaN for NaN values, for values outside range or when
199+
triangular mesh is not yet initialized on given point
200+
%End
201+
202+
signals:
203+
204+
void activeScalarDatasetChanged( QgsMeshDatasetIndex index );
205+
%Docstring
206+
Emitted when active scalar dataset is changed
207+
208+
.. versionadded:: 3.4
209+
%End
210+
211+
void activeVectorDatasetChanged( QgsMeshDatasetIndex index );
212+
%Docstring
213+
Emitted when active vector dataset is changed
214+
215+
.. versionadded:: 3.4
192216
%End
193217

194218
private: // Private methods

‎src/core/mesh/qgsmeshdataprovider.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ bool QgsMeshDatasetGroupMetadata::isOnVertices() const
172172
return mIsOnVertices;
173173
}
174174

175+
bool QgsMeshDatasetGroupMetadata::isOnFaces() const
176+
{
177+
return !mIsOnVertices;
178+
}
179+
175180
int QgsMeshDatasetSourceInterface::datasetCount( QgsMeshDatasetIndex index ) const
176181
{
177182
return datasetCount( index.group() );

‎src/core/mesh/qgsmeshdataprovider.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata
168168
*/
169169
bool isOnVertices() const;
170170

171+
/**
172+
* \brief Returns whether dataset group data is defined on faces
173+
*/
174+
bool isOnFaces() const;
175+
171176
private:
172177
QString mName;
173178
bool mIsScalar = false;

‎src/core/mesh/qgsmeshlayer.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
***************************************************************************/
1717

1818
#include <cstddef>
19+
#include <limits>
1920

2021
#include <QUuid>
2122

@@ -27,6 +28,7 @@
2728
#include "qgsproviderregistry.h"
2829
#include "qgsreadwritecontext.h"
2930
#include "qgstriangularmesh.h"
31+
#include "qgsmeshlayerinterpolator.h"
3032

3133
QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
3234
const QString &baseName,
@@ -154,6 +156,8 @@ void QgsMeshLayer::setActiveScalarDataset( QgsMeshDatasetIndex index )
154156
mActiveScalarDataset = QgsMeshDatasetIndex();
155157

156158
triggerRepaint();
159+
160+
emit activeScalarDatasetChanged( mActiveScalarDataset );
157161
}
158162

159163
void QgsMeshLayer::setActiveVectorDataset( QgsMeshDatasetIndex index )
@@ -175,6 +179,44 @@ void QgsMeshLayer::setActiveVectorDataset( QgsMeshDatasetIndex index )
175179
}
176180

177181
triggerRepaint();
182+
183+
emit activeVectorDatasetChanged( mActiveVectorDataset );
184+
}
185+
186+
QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point ) const
187+
{
188+
QgsMeshDatasetValue value;
189+
190+
if ( mTriangularMesh && dataProvider() && dataProvider()->isValid() && index.isValid() )
191+
{
192+
int face_index = mTriangularMesh->faceIndexForPoint( point ) ;
193+
if ( face_index >= 0 )
194+
{
195+
bool isOnFaces = dataProvider()->datasetGroupMetadata( index ).isOnFaces();
196+
if ( isOnFaces )
197+
{
198+
int native_face_index = mTriangularMesh->trianglesToNativeFaces().at( face_index );
199+
return dataProvider()->datasetValue( index, native_face_index );
200+
}
201+
else
202+
{
203+
const QgsMeshFace &face = mTriangularMesh->triangles()[face_index];
204+
const int v1 = face[0], v2 = face[1], v3 = face[2];
205+
const QgsPoint p1 = mTriangularMesh->vertices()[v1], p2 = mTriangularMesh->vertices()[v2], p3 = mTriangularMesh->vertices()[v3];
206+
const QgsMeshDatasetValue val1 = dataProvider()->datasetValue( index, v1 );
207+
const QgsMeshDatasetValue val2 = dataProvider()->datasetValue( index, v2 );
208+
const QgsMeshDatasetValue val3 = dataProvider()->datasetValue( index, v3 );
209+
const double x = QgsMeshLayerInterpolator::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
210+
double y = std::numeric_limits<double>::quiet_NaN();
211+
bool isVector = dataProvider()->datasetGroupMetadata( index ).isVector();
212+
if ( isVector )
213+
y = QgsMeshLayerInterpolator::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
214+
215+
return QgsMeshDatasetValue( x, y );
216+
}
217+
}
218+
}
219+
return value;
178220
}
179221

180222
void QgsMeshLayer::fillNativeMesh()

‎src/core/mesh/qgsmeshlayer.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,30 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
183183
//! Returns active vector dataset
184184
QgsMeshDatasetIndex activeVectorDataset() const { return mActiveVectorDataset; }
185185

186+
/**
187+
* Interpolates the value on the given point from given dataset.
188+
*
189+
* Returns NaN for NaN values, for values outside range or when
190+
* triangular mesh is not yet initialized on given point
191+
*/
192+
QgsMeshDatasetValue datasetValue( const QgsMeshDatasetIndex &index, const QgsPointXY &point ) const;
193+
194+
signals:
195+
196+
/**
197+
* Emitted when active scalar dataset is changed
198+
*
199+
* \since QGIS 3.4
200+
*/
201+
void activeScalarDatasetChanged( QgsMeshDatasetIndex index );
202+
203+
/**
204+
* Emitted when active vector dataset is changed
205+
*
206+
* \since QGIS 3.4
207+
*/
208+
void activeVectorDatasetChanged( QgsMeshDatasetIndex index );
209+
186210
private: // Private methods
187211

188212
/**

‎src/core/mesh/qgsmeshlayerinterpolator.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,8 @@ static bool E3T_physicalToBarycentric( const QgsPointXY &pA, const QgsPointXY &p
8888
return true;
8989
}
9090

91-
92-
double interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
93-
double val1, double val2, double val3, const QgsPointXY &pt )
91+
double QgsMeshLayerInterpolator::interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
92+
double val1, double val2, double val3, const QgsPointXY &pt )
9493
{
9594
double lam1, lam2, lam3;
9695
if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )

‎src/core/mesh/qgsmeshlayerinterpolator.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ class QgsMeshLayerInterpolator : public QgsRasterInterface
5959
int bandCount() const override;
6060
QgsRasterBlock *block( int, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback = nullptr ) override;
6161

62+
63+
static double interpolateFromVerticesData( const QgsPointXY &p1,
64+
const QgsPointXY &p2,
65+
const QgsPointXY &p3,
66+
double val1, double val2, double val3, const QgsPointXY &pt );
67+
6268
private:
6369
const QgsTriangularMesh &mTriangularMesh;
6470
const QVector<double> &mDatasetValues;

‎src/core/mesh/qgsmeshlayerrenderer.cpp

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,7 @@ void QgsMeshLayerRenderer::renderMesh( const std::unique_ptr<QgsSymbol> &symbol,
229229
const QgsMeshFace &face = faces[i];
230230
QgsFeature feat;
231231
feat.setFields( fields );
232-
QVector<QgsPointXY> ring;
233-
for ( int j = 0; j < face.size(); ++j )
234-
{
235-
int vertex_id = face[j];
236-
Q_ASSERT( vertex_id < mTriangularMesh.vertices().size() ); //Triangular mesh vertices contains also native mesh vertices
237-
const QgsPoint &vertex = mTriangularMesh.vertices()[vertex_id];
238-
ring.append( vertex );
239-
}
240-
QgsPolygonXY polygon;
241-
polygon.append( ring );
242-
QgsGeometry geom = QgsGeometry::fromPolygonXY( polygon );
232+
QgsGeometry geom = QgsMeshUtils::toGeometry( face, mTriangularMesh.vertices() ); //Triangular mesh vertices contains also native mesh vertices
243233
feat.setGeometry( geom );
244234
renderer.renderFeature( feat, mContext );
245235
}

‎src/core/mesh/qgstriangularmesh.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
* *
1616
***************************************************************************/
1717

18+
#include <QList>
19+
#include "qgsfeature.h"
20+
1821
#include "qgstriangularmesh.h"
1922
#include "qgsrendercontext.h"
2023
#include "qgscoordinatetransform.h"
@@ -63,12 +66,12 @@ static void ENP_centroid( const QPolygonF &pX, double &cx, double &cy )
6366
cy /= ( 6.0 * signedArea );
6467
}
6568

66-
6769
void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
6870
{
6971
Q_ASSERT( nativeMesh );
7072
Q_ASSERT( context );
7173

74+
mSpatialIndex = QgsSpatialIndex();
7275
mTriangularMesh.vertices.clear();
7376
mTriangularMesh.faces.clear();
7477
mTrianglesToNativeFaces.clear();
@@ -143,6 +146,15 @@ void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
143146
ENP_centroid( poly, cx, cy );
144147
mNativeMeshFaceCentroids[i] = QgsMeshVertex( cx, cy );
145148
}
149+
150+
// CALCULATE SPATIAL INDEX
151+
for ( int i = 0; i < mTriangularMesh.faces.size(); ++i )
152+
{
153+
const QgsMeshFace &face = mTriangularMesh.faces.at( i ) ;
154+
QgsGeometry geom = QgsMeshUtils::toGeometry( face, mTriangularMesh.vertices );
155+
bool success = mSpatialIndex.insertFeature( i, geom.boundingBox() );
156+
Q_UNUSED( success );
157+
}
146158
}
147159

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

180+
int QgsTriangularMesh::faceIndexForPoint( const QgsPointXY &point ) const
181+
{
182+
const QList<QgsFeatureId> face_indexes = mSpatialIndex.intersects( QgsRectangle( point, point ) );
183+
for ( QgsFeatureId fid : face_indexes )
184+
{
185+
int face_index = static_cast<int>( fid );
186+
const QgsMeshFace &face = mTriangularMesh.faces.at( face_index );
187+
const QgsGeometry geom = QgsMeshUtils::toGeometry( face, mTriangularMesh.vertices );
188+
if ( geom.contains( &point ) )
189+
return face_index;
190+
}
191+
return -1;
192+
}
193+
194+
QgsGeometry QgsMeshUtils::toGeometry( const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices )
195+
{
196+
QVector<QgsPointXY> ring;
197+
for ( int j = 0; j < face.size(); ++j )
198+
{
199+
int vertex_id = face[j];
200+
Q_ASSERT( vertex_id < vertices.size() );
201+
const QgsPoint &vertex = vertices[vertex_id];
202+
ring.append( vertex );
203+
}
204+
QgsPolygonXY polygon;
205+
polygon.append( ring );
206+
return QgsGeometry::fromPolygonXY( polygon );
207+
}

‎src/core/mesh/qgstriangularmesh.h

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@
2222
#define SIP_NO_FILE
2323

2424
#include <QVector>
25-
2625
#include "qgis_core.h"
2726
#include "qgsmeshdataprovider.h"
27+
#include "qgsgeometry.h"
28+
#include "qgsspatialindex.h"
2829

2930
class QgsRenderContext;
3031

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

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

83+
/**
84+
* Returns triangle index that contains the given point, -1 if no such triangle exists
85+
* It uses spatial indexing
86+
*/
87+
int faceIndexForPoint( const QgsPointXY &point ) const ;
88+
8089
private:
8190
// vertices: map CRS; 0-N ... native vertices, N+1 - len ... extra vertices
8291
// faces are derived triangles
@@ -85,7 +94,14 @@ class CORE_EXPORT QgsTriangularMesh
8594

8695
// centroids of the native faces in map CRS
8796
QVector<QgsMeshVertex> mNativeMeshFaceCentroids;
97+
98+
QgsSpatialIndex mSpatialIndex;
8899
};
89100

101+
namespace QgsMeshUtils
102+
{
103+
//! Returns face as polygon geometry
104+
QgsGeometry toGeometry( const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices );
105+
};
90106

91107
#endif // QGSTRIANGULARMESH_H

0 commit comments

Comments
 (0)
Please sign in to comment.