Skip to content

Commit

Permalink
[mesh] fix bug in rendering datasets with inactive faces
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterPetrik authored and wonder-sk committed Aug 20, 2018
1 parent b39ee5a commit 419ec1f
Show file tree
Hide file tree
Showing 15 changed files with 207 additions and 39 deletions.
12 changes: 12 additions & 0 deletions python/core/auto_generated/mesh/qgsmeshdataprovider.sip.in
Expand Up @@ -359,6 +359,18 @@ Returns dataset metadata
Returns vector/scalar value associated with the index from the dataset

See QgsMeshDatasetMetadata.isVector() to check if the returned value is vector or scalar
%End

virtual bool faceIsActive( QgsMeshDatasetIndex index, int faceIndex ) const = 0;
%Docstring
Returns whether the face is active for particular dataset

For example to represent the situation when F1 and F3 are flooded, but F2 is dry,
some solvers store water depth on vertices V1-V8 (all non-zero values) and
set active flag for F2 to false.
V1 ---- V2 ---- V5-----V7
| F1 | F2 | F3 |
V3 ---- V4 ---- V6-----V8
%End
};

Expand Down
12 changes: 12 additions & 0 deletions src/core/mesh/qgsmeshdataprovider.h
Expand Up @@ -337,6 +337,18 @@ class CORE_EXPORT QgsMeshDatasetSourceInterface SIP_ABSTRACT
* See QgsMeshDatasetMetadata::isVector() to check if the returned value is vector or scalar
*/
virtual QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const = 0;

/**
* \brief Returns whether the face is active for particular dataset
*
* For example to represent the situation when F1 and F3 are flooded, but F2 is dry,
* some solvers store water depth on vertices V1-V8 (all non-zero values) and
* set active flag for F2 to false.
* V1 ---- V2 ---- V5-----V7
* | F1 | F2 | F3 |
* V3 ---- V4 ---- V6-----V8
*/
virtual bool faceIsActive( QgsMeshDatasetIndex index, int faceIndex ) const = 0;
};


Expand Down
45 changes: 26 additions & 19 deletions src/core/mesh/qgsmeshlayer.cpp
Expand Up @@ -127,29 +127,36 @@ QgsMeshDatasetValue QgsMeshLayer::datasetValue( const QgsMeshDatasetIndex &index
int faceIndex = mTriangularMesh->faceIndexForPoint( point ) ;
if ( faceIndex >= 0 )
{
if ( dataProvider()->datasetGroupMetadata( index ).dataType() == QgsMeshDatasetGroupMetadata::DataOnFaces )
int nativeFaceIndex = mTriangularMesh->trianglesToNativeFaces().at( faceIndex );
if ( dataProvider()->faceIsActive( index, nativeFaceIndex ) )
{
int nativeFaceIndex = mTriangularMesh->trianglesToNativeFaces().at( faceIndex );
return dataProvider()->datasetValue( index, nativeFaceIndex );
}
else
{
const QgsMeshFace &face = mTriangularMesh->triangles()[faceIndex];
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 );

if ( dataProvider()->datasetGroupMetadata( index ).dataType() == QgsMeshDatasetGroupMetadata::DataOnFaces )
{
int nativeFaceIndex = mTriangularMesh->trianglesToNativeFaces().at( faceIndex );
value = dataProvider()->datasetValue( index, nativeFaceIndex );
}
else
{
const QgsMeshFace &face = mTriangularMesh->triangles()[faceIndex];
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 );

value = QgsMeshDatasetValue( x, y );
}

}
}
}

return value;
}

Expand Down
17 changes: 11 additions & 6 deletions src/core/mesh/qgsmeshlayerinterpolator.cpp
Expand Up @@ -107,14 +107,14 @@ double interpolateFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, con
return val;
}

QgsMeshLayerInterpolator::QgsMeshLayerInterpolator(
const QgsTriangularMesh &m,
const QVector<double> &datasetValues,
bool dataIsOnVertices,
const QgsRenderContext &context,
const QSize &size )
QgsMeshLayerInterpolator::QgsMeshLayerInterpolator( const QgsTriangularMesh &m,
const QVector<double> &datasetValues, const QVector<bool> &activeFaceFlagValues,
bool dataIsOnVertices,
const QgsRenderContext &context,
const QSize &size )
: mTriangularMesh( m ),
mDatasetValues( datasetValues ),
mActiveFaceFlagValues( activeFaceFlagValues ),
mContext( context ),
mDataOnVertices( dataIsOnVertices ),
mOutputSize( size )
Expand Down Expand Up @@ -162,6 +162,11 @@ QgsRasterBlock *QgsMeshLayerInterpolator::block( int, const QgsRectangle &extent
const int v1 = face[0], v2 = face[1], v3 = face[2];
const QgsPoint p1 = vertices[v1], p2 = vertices[v2], p3 = vertices[v3];

const int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces()[i];
const bool isActive = mActiveFaceFlagValues[nativeFaceIndex];
if ( !isActive )
continue;

QgsRectangle bbox;
bbox.combineExtentWith( p1.x(), p1.y() );
bbox.combineExtentWith( p2.x(), p2.y() );
Expand Down
2 changes: 2 additions & 0 deletions src/core/mesh/qgsmeshlayerinterpolator.h
Expand Up @@ -49,6 +49,7 @@ class QgsMeshLayerInterpolator : public QgsRasterInterface
//! Ctor
QgsMeshLayerInterpolator( const QgsTriangularMesh &m,
const QVector<double> &datasetValues,
const QVector<bool> &activeFaceFlagValues,
bool dataIsOnVertices,
const QgsRenderContext &context,
const QSize &size );
Expand Down Expand Up @@ -78,6 +79,7 @@ class QgsMeshLayerInterpolator : public QgsRasterInterface
private:
const QgsTriangularMesh &mTriangularMesh;
const QVector<double> &mDatasetValues;
const QVector<bool> &mActiveFaceFlagValues;
const QgsRenderContext &mContext;
bool mDataOnVertices = true;
QSize mOutputSize;
Expand Down
11 changes: 10 additions & 1 deletion src/core/mesh/qgsmeshlayerrenderer.cpp
Expand Up @@ -110,6 +110,14 @@ void QgsMeshLayerRenderer::copyScalarDatasetValues( QgsMeshLayer *layer )
mScalarDatasetValues[i] = v;
}

// populate face active flag, always defined on faces
mScalarActiveFaceFlagValues.resize( mNativeMesh.faces.count() );
for ( int i = 0; i < mNativeMesh.faces.count(); ++i )
{
bool active = layer->dataProvider()->faceIsActive( datasetIndex, i );
mScalarActiveFaceFlagValues[i] = active;
}

QgsMeshLayerUtils::calculateMinimumMaximum( mScalarDatasetMinimum, mScalarDatasetMaximum, mScalarDatasetValues );
}
}
Expand Down Expand Up @@ -209,7 +217,8 @@ void QgsMeshLayerRenderer::renderScalarDataset()
QgsColorRampShader *fcn = new QgsColorRampShader( scalarSettings.colorRampShader() );
QgsRasterShader *sh = new QgsRasterShader();
sh->setRasterShaderFunction( fcn ); // takes ownership of fcn
QgsMeshLayerInterpolator interpolator( mTriangularMesh, mScalarDatasetValues, mScalarDataOnVertices, mContext, mOutputSize );
QgsMeshLayerInterpolator interpolator( mTriangularMesh, mScalarDatasetValues, mScalarActiveFaceFlagValues,
mScalarDataOnVertices, mContext, mOutputSize );
QgsSingleBandPseudoColorRenderer renderer( &interpolator, 0, sh ); // takes ownership of sh
renderer.setClassificationMin( scalarSettings.classificationMinimum() );
renderer.setClassificationMax( scalarSettings.classificationMaximum() );
Expand Down
3 changes: 2 additions & 1 deletion src/core/mesh/qgsmeshlayerrenderer.h
Expand Up @@ -34,6 +34,7 @@ class QgsSymbol;
#include "qgstriangularmesh.h"
#include "qgsmeshlayer.h"
#include "qgssymbol.h"
#include "qgsmeshdataprovider.h"

///@cond PRIVATE

Expand Down Expand Up @@ -69,7 +70,6 @@ class QgsMeshLayerRenderer : public QgsMapLayerRenderer
void renderVectorDataset();
void copyScalarDatasetValues( QgsMeshLayer *layer );
void copyVectorDatasetValues( QgsMeshLayer *layer );

void createMeshSymbol( std::unique_ptr<QgsSymbol> &symbol, const QgsMeshRendererMeshSettings &settings );
void calculateOutputSize();

Expand All @@ -85,6 +85,7 @@ class QgsMeshLayerRenderer : public QgsMapLayerRenderer

// copy of the scalar dataset
QVector<double> mScalarDatasetValues;
QVector<bool> mScalarActiveFaceFlagValues;
bool mScalarDataOnVertices = true;
double mScalarDatasetMinimum = std::numeric_limits<double>::quiet_NaN();
double mScalarDatasetMaximum = std::numeric_limits<double>::quiet_NaN();
Expand Down
7 changes: 7 additions & 0 deletions src/core/mesh/qgsmeshmemorydataprovider.cpp
Expand Up @@ -407,5 +407,12 @@ QgsMeshDatasetValue QgsMeshMemoryDataProvider::datasetValue( QgsMeshDatasetIndex
}
}

bool QgsMeshMemoryDataProvider::faceIsActive( QgsMeshDatasetIndex index, int faceIndex ) const
{
Q_UNUSED( index );
Q_UNUSED( faceIndex );
return true;
}


///@endcond
1 change: 1 addition & 0 deletions src/core/mesh/qgsmeshmemorydataprovider.h
Expand Up @@ -128,6 +128,7 @@ class QgsMeshMemoryDataProvider: public QgsMeshDataProvider
QgsMeshDatasetGroupMetadata datasetGroupMetadata( int groupIndex ) const override;
QgsMeshDatasetMetadata datasetMetadata( QgsMeshDatasetIndex index ) const override;
QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const override;
bool faceIsActive( QgsMeshDatasetIndex index, int faceIndex ) const override;

//! Returns the memory provider key
static QString providerKey();
Expand Down
13 changes: 13 additions & 0 deletions src/providers/mdal/qgsmdalprovider.cpp
Expand Up @@ -216,6 +216,19 @@ QgsMeshDatasetValue QgsMdalProvider::datasetValue( QgsMeshDatasetIndex index, in
return val;
}

bool QgsMdalProvider::faceIsActive( QgsMeshDatasetIndex index, int faceIndex ) const
{
DatasetGroupH group = MDAL_M_datasetGroup( mMeshH, index.group() );
if ( !group )
return false;

DatasetH dataset = MDAL_G_dataset( group, index.dataset() );
if ( !dataset )
return false;

return MDAL_D_active( dataset, faceIndex );
}

/*----------------------------------------------------------------------------------------------*/

/**
Expand Down
1 change: 1 addition & 0 deletions src/providers/mdal/qgsmdalprovider.h
Expand Up @@ -64,6 +64,7 @@ class QgsMdalProvider : public QgsMeshDataProvider
QgsMeshDatasetGroupMetadata datasetGroupMetadata( int groupIndex ) const override;
QgsMeshDatasetMetadata datasetMetadata( QgsMeshDatasetIndex index ) const override;
QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const override;
bool faceIsActive( QgsMeshDatasetIndex index, int faceIndex ) const override;

private:
MeshH mMeshH;
Expand Down
44 changes: 44 additions & 0 deletions tests/src/core/testqgsmeshlayer.cpp
Expand Up @@ -55,6 +55,7 @@ class TestQgsMeshLayer : public QObject
void test_read_vertex_vector_dataset();
void test_read_face_scalar_dataset();
void test_read_face_vector_dataset();
void test_read_vertex_scalar_dataset_with_inactive_face();
void test_extent();
};

Expand Down Expand Up @@ -178,6 +179,8 @@ void TestQgsMeshLayer::test_read_vertex_scalar_dataset()
QCOMPARE( QgsMeshDatasetValue( 3.0 + i ), dp->datasetValue( ds, 2 ) );
QCOMPARE( QgsMeshDatasetValue( 2.0 + i ), dp->datasetValue( ds, 3 ) );
QCOMPARE( QgsMeshDatasetValue( 1.0 + i ), dp->datasetValue( ds, 4 ) );

QVERIFY( dp->faceIsActive( ds, 0 ) );
}
}
}
Expand Down Expand Up @@ -216,6 +219,8 @@ void TestQgsMeshLayer::test_read_vertex_vector_dataset()
QCOMPARE( QgsMeshDatasetValue( 3 + i, 2 + i ), dp->datasetValue( ds, 2 ) );
QCOMPARE( QgsMeshDatasetValue( 2 + i, 2 + i ), dp->datasetValue( ds, 3 ) );
QCOMPARE( QgsMeshDatasetValue( 1 + i, -2 + i ), dp->datasetValue( ds, 4 ) );

QVERIFY( dp->faceIsActive( ds, 0 ) );
}
}
}
Expand Down Expand Up @@ -251,6 +256,8 @@ void TestQgsMeshLayer::test_read_face_scalar_dataset()
// We have 2 values, since dp->faceCount() = 2
QCOMPARE( QgsMeshDatasetValue( 1 + i ), dp->datasetValue( ds, 0 ) );
QCOMPARE( QgsMeshDatasetValue( 2 + i ), dp->datasetValue( ds, 1 ) );

QVERIFY( dp->faceIsActive( ds, 0 ) );
}
}
}
Expand Down Expand Up @@ -287,10 +294,47 @@ void TestQgsMeshLayer::test_read_face_vector_dataset()
// We have 2 values, since dp->faceCount() = 2
QCOMPARE( QgsMeshDatasetValue( 1 + i, 1 + i ), dp->datasetValue( ds, 0 ) );
QCOMPARE( QgsMeshDatasetValue( 2 + i, 2 + i ), dp->datasetValue( ds, 1 ) );

QVERIFY( dp->faceIsActive( ds, 0 ) );
}
}
}

void TestQgsMeshLayer::test_read_vertex_scalar_dataset_with_inactive_face()
{
QString uri( mDataDir + "/quad_and_triangle.2dm" );
QgsMeshLayer layer( uri, "Triangle and Quad MDAL", "mdal" );
layer.dataProvider()->addDataset( mDataDir + "/quad_and_triangle_vertex_scalar_with_inactive_face.dat" );
QgsMeshDataProvider *dp = layer.dataProvider();
QVERIFY( dp != nullptr );
QVERIFY( dp->isValid() );
QCOMPARE( 1, dp->datasetGroupCount() );

for ( int i = 0; i < 2 ; ++i )
{
QgsMeshDatasetIndex ds( 0, i );

const QgsMeshDatasetGroupMetadata meta = dp->datasetGroupMetadata( ds );
QCOMPARE( meta.name(), QString( "VertexScalarDatasetWithInactiveFace1" ) );
QVERIFY( meta.isScalar() );
QVERIFY( meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices );

const QgsMeshDatasetMetadata dmeta = dp->datasetMetadata( ds );
QVERIFY( qgsDoubleNear( dmeta.time(), i ) );
QVERIFY( dmeta.isValid() );

// We have 5 values, since dp->vertexCount() = 5
QCOMPARE( QgsMeshDatasetValue( 1.0 + i ), dp->datasetValue( ds, 0 ) );
QCOMPARE( QgsMeshDatasetValue( 2.0 + i ), dp->datasetValue( ds, 1 ) );
QCOMPARE( QgsMeshDatasetValue( 3.0 + i ), dp->datasetValue( ds, 2 ) );
QCOMPARE( QgsMeshDatasetValue( 2.0 + i ), dp->datasetValue( ds, 3 ) );
QCOMPARE( QgsMeshDatasetValue( 1.0 + i ), dp->datasetValue( ds, 4 ) );

// We have 2 faces
QVERIFY( !dp->faceIsActive( ds, 0 ) );
QVERIFY( dp->faceIsActive( ds, 1 ) );
}
}

void TestQgsMeshLayer::test_extent()
{
Expand Down

0 comments on commit 419ec1f

Please sign in to comment.