Skip to content
Permalink
Browse files

[mesh] fix bug in rendering datasets with inactive faces

  • Loading branch information
PeterPetrik authored and wonder-sk committed Aug 17, 2018
1 parent b39ee5a commit 419ec1f736f0a96d30a54f4861b634e6e00bcc05
@@ -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
};

@@ -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;
};


@@ -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;
}

@@ -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 )
@@ -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() );
@@ -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 );
@@ -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;
@@ -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 );
}
}
@@ -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() );
@@ -34,6 +34,7 @@ class QgsSymbol;
#include "qgstriangularmesh.h"
#include "qgsmeshlayer.h"
#include "qgssymbol.h"
#include "qgsmeshdataprovider.h"

///@cond PRIVATE

@@ -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();

@@ -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();
@@ -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
@@ -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();
@@ -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 );
}

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

/**
@@ -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;
@@ -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();
};

@@ -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 ) );
}
}
}
@@ -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 ) );
}
}
}
@@ -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 ) );
}
}
}
@@ -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()
{

0 comments on commit 419ec1f

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