[mesh] use MDAL 0.1.0 API in QGIS. Allows lazy loading of formats and effective transfer of data

introduce MeshDataBlock

use mesh block in rendering

calculate magnitude

use new mesh API

fix bug for memory layer

fix SIP, sip is unable to work with qvector<qgsmeshvertex>

fix tests

implement new MDAL min/max api

improve mesh documentation

fix travis build
This commit is contained in:
Peter Petrik 2018-11-23 15:20:52 +01:00
parent d43f6376eb
commit 28071728f1
19 changed files with 833 additions and 312 deletions

View File

@ -53,6 +53,28 @@ typedef QgsPoint QgsMeshVertex;
typedef QVector<int> QgsMeshFace;
struct QgsMesh
{
int vertexCount() const;
%Docstring
Returns number of vertices
%End
int faceCount() const;
%Docstring
Returns number of faces
%End
QgsMeshVertex vertex( int index ) const;
%Docstring
Returns a vertex at the index
%End
QgsMeshFace face( int index ) const;
%Docstring
Returns a face at the index
%End
};
class QgsMeshDatasetValue
{
%Docstring
@ -122,6 +144,76 @@ Returns y value
bool operator==( const QgsMeshDatasetValue &other ) const;
};
class QgsMeshDataBlock
{
%Docstring
QgsMeshDataBlock is a block that can be used to retrieve a block of
active flag (e.g. face's active integer flag)
scalars (e.g. scalar dataset double values)
vectors (e.g. vector dataset doubles x,y values)
data are implicitly shared, so the class can be quickly copied
std.numeric_limits<double>.quiet_NaN() represents NODATA value
Data can be accessed all at once with buffer() (faster) or
value by value (slower) with active() or value()
.. versionadded:: 3.6
%End
%TypeHeaderCode
#include "qgsmeshdataprovider.h"
%End
public:
enum DataType
{
ActiveFlagInteger,
ScalarDouble,
Vector2DDouble,
};
QgsMeshDataBlock();
%Docstring
Constructs an invalid block
%End
QgsMeshDataBlock( DataType type, int count );
%Docstring
Constructs a new block
%End
DataType type() const;
%Docstring
Type of data stored in the block
%End
int count() const;
%Docstring
Number of items stored in the block
%End
bool isValid() const;
%Docstring
Whether the block is valid
%End
QgsMeshDatasetValue value( int index ) const;
%Docstring
Returns a value represented by the index
For active flag the behavior is undefined
%End
bool active( int index ) const;
%Docstring
Returns a value for active flag by the index
For scalar and vector 2d the behavior is undefined
%End
};
class QgsMeshDatasetGroupMetadata
@ -157,6 +249,8 @@ Constructs an empty metadata object
QgsMeshDatasetGroupMetadata( const QString &name,
bool isScalar,
bool isOnVertices,
double minimum,
double maximum,
const QMap<QString, QString> &extraOptions );
%Docstring
Constructs a valid metadata object
@ -164,6 +258,8 @@ Constructs a valid metadata object
:param name: name of the dataset group
:param isScalar: dataset contains scalar data, specifically the y-value of QgsMeshDatasetValue is NaN
:param isOnVertices: dataset values are defined on mesh's vertices. If false, values are defined on faces.
:param minimum: minimum value (magnitude for vectors) present among all group's dataset values
:param maximum: maximum value (magnitude for vectors) present among all group's dataset values
:param extraOptions: dataset's extra options stored by the provider. Usually contains the name, time value, time units, data file vendor, ...
%End
@ -190,6 +286,16 @@ Returns whether dataset group has scalar data
DataType dataType() const;
%Docstring
Returns whether dataset group data is defined on vertices or faces
%End
double minimum() const;
%Docstring
Returns minimum scalar value/vector magnitude present for whole dataset group
%End
double maximum() const;
%Docstring
Returns maximum scalar value/vector magnitude present for whole dataset group
%End
};
@ -218,7 +324,10 @@ Constructs an empty metadata object
%End
QgsMeshDatasetMetadata( double time,
bool isValid );
bool isValid,
double minimum,
double maximum
);
%Docstring
Constructs a valid metadata object
@ -234,6 +343,16 @@ Returns the time value for this dataset
bool isValid() const;
%Docstring
Returns whether dataset is valid
%End
double minimum() const;
%Docstring
Returns minimum scalar value/vector magnitude present for the dataset
%End
double maximum() const;
%Docstring
Returns maximum scalar value/vector magnitude present for the dataset
%End
};
@ -278,14 +397,11 @@ Returns number of faces in the native mesh
:return: Number of faces in the mesh
%End
virtual QgsMeshVertex vertex( int index ) const = 0;
virtual void populateMesh( QgsMesh *mesh ) const = 0;
%Docstring
Returns the mesh vertex at index
%End
Populates the mesh vertices and faces
virtual QgsMeshFace face( int index ) const = 0;
%Docstring
Returns the mesh face at index
.. versionadded:: 3.6
%End
};
@ -359,8 +475,19 @@ Returns dataset metadata
virtual QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const = 0;
%Docstring
Returns vector/scalar value associated with the index from the dataset
To read multiple continuous values, use :py:func:`QgsMeshDatasetSourceInterface.datasetValues()`
See QgsMeshDatasetMetadata.isVector() or :py:func:`QgsMeshDataBlock.type()`
to check if the returned value is vector or scalar
%End
virtual QgsMeshDataBlock datasetValues( QgsMeshDatasetIndex index, int valueIndex, int count ) const = 0;
%Docstring
Returns N vector/scalar values from the index from the dataset
See QgsMeshDatasetMetadata.isVector() to check if the returned value is vector or scalar
.. versionadded:: 3.6
%End
virtual bool isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const = 0;
@ -373,6 +500,13 @@ set active flag for F2 to false.
V1 ---- V2 ---- V5-----V7
| F1 | F2 | F3 |
V3 ---- V4 ---- V6-----V8
%End
virtual QgsMeshDataBlock areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const = 0;
%Docstring
Returns whether the faces are active for particular dataset
.. versionadded:: 3.6
%End
};
@ -398,14 +532,6 @@ Responsible for reading native mesh data
QgsMeshDataProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options );
%Docstring
Ctor
%End
virtual QgsRectangle extent() const;
%Docstring
Returns the extent of the layer
:return: QgsRectangle containing the extent of the layer
%End
signals:

View File

@ -93,8 +93,9 @@ void QgsMeshRendererScalarSettingsWidget::minMaxEdited()
void QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked()
{
double min, max;
QgsMeshLayerUtils::calculateMinMaxForDatasetGroup( min, max, mMeshLayer->dataProvider(), mActiveDatasetGroup );
const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->dataProvider()->datasetGroupMetadata( mActiveDatasetGroup );
double min = metadata.minimum();
double max = metadata.maximum();
whileBlocking( mScalarMinLineEdit )->setText( QString::number( min ) );
whileBlocking( mScalarMaxLineEdit )->setText( QString::number( max ) );
mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, max );

View File

@ -58,23 +58,6 @@ QgsMeshDataProvider::QgsMeshDataProvider( const QString &uri, const QgsDataProvi
{
}
QgsRectangle QgsMeshDataProvider::extent() const
{
QgsRectangle rec;
rec.setMinimal();
for ( int i = 0; i < vertexCount(); ++i )
{
QgsMeshVertex v = vertex( i );
rec.setXMinimum( std::min( rec.xMinimum(), v.x() ) );
rec.setYMinimum( std::min( rec.yMinimum(), v.y() ) );
rec.setXMaximum( std::max( rec.xMaximum(), v.x() ) );
rec.setYMaximum( std::max( rec.yMaximum(), v.y() ) );
}
return rec;
}
QgsMeshDatasetValue::QgsMeshDatasetValue( double x, double y )
: mX( x ), mY( y )
{}
@ -144,14 +127,17 @@ bool QgsMeshDatasetValue::operator==( const QgsMeshDatasetValue &other ) const
return equal;
}
QgsMeshDatasetGroupMetadata::QgsMeshDatasetGroupMetadata(
const QString &name,
bool isScalar,
bool isOnVertices,
const QMap<QString, QString> &extraOptions )
QgsMeshDatasetGroupMetadata::QgsMeshDatasetGroupMetadata( const QString &name,
bool isScalar,
bool isOnVertices,
double minimum,
double maximum,
const QMap<QString, QString> &extraOptions )
: mName( name )
, mIsScalar( isScalar )
, mIsScalar( isScalar )
, mIsOnVertices( isOnVertices )
, mMinimumValue( minimum )
, mMaximumValue( maximum )
, mExtraOptions( extraOptions )
{
}
@ -171,8 +157,6 @@ bool QgsMeshDatasetGroupMetadata::isScalar() const
return mIsScalar;
}
QString QgsMeshDatasetGroupMetadata::name() const
{
return mName;
@ -183,6 +167,16 @@ QgsMeshDatasetGroupMetadata::DataType QgsMeshDatasetGroupMetadata::dataType() co
return ( mIsOnVertices ) ? DataType::DataOnVertices : DataType::DataOnFaces;
}
double QgsMeshDatasetGroupMetadata::minimum() const
{
return mMinimumValue;
}
double QgsMeshDatasetGroupMetadata::maximum() const
{
return mMaximumValue;
}
int QgsMeshDatasetSourceInterface::datasetCount( QgsMeshDatasetIndex index ) const
{
return datasetCount( index.group() );
@ -194,9 +188,13 @@ QgsMeshDatasetGroupMetadata QgsMeshDatasetSourceInterface::datasetGroupMetadata(
}
QgsMeshDatasetMetadata::QgsMeshDatasetMetadata( double time,
bool isValid )
bool isValid,
double minimum,
double maximum )
: mTime( time )
, mIsValid( isValid )
, mMinimumValue( minimum )
, mMaximumValue( maximum )
{
}
@ -209,3 +207,130 @@ bool QgsMeshDatasetMetadata::isValid() const
{
return mIsValid;
}
double QgsMeshDatasetMetadata::minimum() const
{
return mMinimumValue;
}
double QgsMeshDatasetMetadata::maximum() const
{
return mMaximumValue;
}
QgsMeshDataBlock::QgsMeshDataBlock()
: mType( ActiveFlagInteger )
{
}
QgsMeshDataBlock::QgsMeshDataBlock( QgsMeshDataBlock::DataType type, int count )
: mType( type )
{
switch ( type )
{
case ActiveFlagInteger:
mIntegerBuffer.resize( count );
break;
case ScalarDouble:
mDoubleBuffer.resize( count );
break;
case Vector2DDouble:
mDoubleBuffer.resize( 2 * count );
break;
}
}
QgsMeshDataBlock::DataType QgsMeshDataBlock::type() const
{
return mType;
}
int QgsMeshDataBlock::count() const
{
switch ( mType )
{
case ActiveFlagInteger:
return mIntegerBuffer.size();
case ScalarDouble:
return mDoubleBuffer.size();
case Vector2DDouble:
return static_cast<int>( mDoubleBuffer.size() / 2.0 );
}
}
bool QgsMeshDataBlock::isValid() const
{
return count() > 0;
}
QgsMeshDatasetValue QgsMeshDataBlock::value( int index ) const
{
switch ( mType )
{
case ActiveFlagInteger:
return QgsMeshDatasetValue();
case ScalarDouble:
return QgsMeshDatasetValue( mDoubleBuffer[index] );
case Vector2DDouble:
return QgsMeshDatasetValue(
mDoubleBuffer[2 * index],
mDoubleBuffer[2 * index + 1]
);
}
}
bool QgsMeshDataBlock::active( int index ) const
{
if ( ActiveFlagInteger == mType )
return bool( mIntegerBuffer[index] );
else
return false;
}
void *QgsMeshDataBlock::buffer()
{
if ( ActiveFlagInteger == mType )
{
return mIntegerBuffer.data();
}
else
{
return mDoubleBuffer.data();
}
}
const void *QgsMeshDataBlock::constBuffer() const
{
if ( ActiveFlagInteger == mType )
{
return mIntegerBuffer.constData();
}
else
{
return mDoubleBuffer.constData();
}
}
QgsMeshVertex QgsMesh::vertex( int index ) const
{
if ( index < vertices.size() && index >= 0 )
return vertices[index];
return QgsMeshVertex();
}
QgsMeshFace QgsMesh::face( int index ) const
{
if ( index < faces.size() && index >= 0 )
return faces[index];
return QgsMeshFace();
}
int QgsMesh::vertexCount() const
{
return vertices.size();
}
int QgsMesh::faceCount() const
{
return faces.size();
}

View File

@ -65,6 +65,31 @@ typedef QgsPoint QgsMeshVertex;
//! List of vertex indexes
typedef QVector<int> QgsMeshFace;
/**
* \ingroup core
*
* Mesh - vertices and faces
*
* \since QGIS 3.6
*/
struct CORE_EXPORT QgsMesh
{
//! Returns number of vertices
int vertexCount() const;
//! Returns number of faces
int faceCount() const;
//! Returns a vertex at the index
QgsMeshVertex vertex( int index ) const;
//! Returns a face at the index
QgsMeshFace face( int index ) const;
//! vertices
QVector<QgsMeshVertex> vertices SIP_SKIP;
//! faces
QVector<QgsMeshFace> faces SIP_SKIP;
};
/**
* \ingroup core
*
@ -117,6 +142,90 @@ class CORE_EXPORT QgsMeshDatasetValue
double mY = std::numeric_limits<double>::quiet_NaN();
};
/**
* \ingroup core
*
* QgsMeshDataBlock is a block that can be used to retrieve a block of
* active flag (e.g. face's active integer flag)
* scalars (e.g. scalar dataset double values)
* vectors (e.g. vector dataset doubles x,y values)
*
* data are implicitly shared, so the class can be quickly copied
* std::numeric_limits<double>::quiet_NaN() represents NODATA value
*
* Data can be accessed all at once with buffer() (faster) or
* value by value (slower) with active() or value()
*
* \since QGIS 3.6
*/
class CORE_EXPORT QgsMeshDataBlock
{
public:
//! Type of data stored in the block
enum DataType
{
ActiveFlagInteger, //!< Integer boolean flag whether face is active
ScalarDouble, //!< Scalar double values
Vector2DDouble, //!< Vector double pairs (x1, y1, x2, y2, ... )
};
//! Constructs an invalid block
QgsMeshDataBlock();
//! Constructs a new block
QgsMeshDataBlock( DataType type, int count );
//! Type of data stored in the block
DataType type() const;
//! Number of items stored in the block
int count() const;
//! Whether the block is valid
bool isValid() const;
/**
* Returns a value represented by the index
* For active flag the behavior is undefined
*/
QgsMeshDatasetValue value( int index ) const;
/**
* Returns a value for active flag by the index
* For scalar and vector 2d the behavior is undefined
*/
bool active( int index ) const;
/**
* Returns internal buffer to the array
*
* The buffer is already allocated with size:
* count() * sizeof(int) for ActiveFlagInteger
* count() * sizeof(double) for ScalarDouble
* count() * 2 * sizeof(double) for Vector2DDouble
*
* Primary usage of the function is to write/populate
* data to the block by data provider.
*/
void *buffer() SIP_SKIP;
/**
* Returns internal buffer to the array for fast
* values reading
*
* The buffer is allocated with size:
* count() * sizeof(int) for ActiveFlagInteger
* count() * sizeof(double) for ScalarDouble
* count() * 2 * sizeof(double) for Vector2DDouble
*/
const void *constBuffer() const SIP_SKIP;
private:
QVector<double> mDoubleBuffer;
QVector<int> mIntegerBuffer;
DataType mType;
};
/**
* \ingroup core
*
@ -147,11 +256,15 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata
* \param name name of the dataset group
* \param isScalar dataset contains scalar data, specifically the y-value of QgsMeshDatasetValue is NaN
* \param isOnVertices dataset values are defined on mesh's vertices. If false, values are defined on faces.
* \param minimum minimum value (magnitude for vectors) present among all group's dataset values
* \param maximum maximum value (magnitude for vectors) present among all group's dataset values
* \param extraOptions dataset's extra options stored by the provider. Usually contains the name, time value, time units, data file vendor, ...
*/
QgsMeshDatasetGroupMetadata( const QString &name,
bool isScalar,
bool isOnVertices,
double minimum,
double maximum,
const QMap<QString, QString> &extraOptions );
/**
@ -179,10 +292,22 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata
*/
DataType dataType() const;
/**
* \brief Returns minimum scalar value/vector magnitude present for whole dataset group
*/
double minimum() const;
/**
* \brief Returns maximum scalar value/vector magnitude present for whole dataset group
*/
double maximum() const;
private:
QString mName;
bool mIsScalar = false;
bool mIsOnVertices = false;
double mMinimumValue = std::numeric_limits<double>::quiet_NaN();
double mMaximumValue = std::numeric_limits<double>::quiet_NaN();
QMap<QString, QString> mExtraOptions;
};
@ -209,7 +334,10 @@ class CORE_EXPORT QgsMeshDatasetMetadata
* \param isValid dataset is loadad and valid for fetching the data
*/
QgsMeshDatasetMetadata( double time,
bool isValid );
bool isValid,
double minimum,
double maximum
);
/**
* \brief Returns the time value for this dataset
@ -221,9 +349,21 @@ class CORE_EXPORT QgsMeshDatasetMetadata
*/
bool isValid() const;
/**
* \brief Returns minimum scalar value/vector magnitude present for the dataset
*/
double minimum() const;
/**
* \brief Returns maximum scalar value/vector magnitude present for the dataset
*/
double maximum() const;
private:
double mTime = std::numeric_limits<double>::quiet_NaN();
bool mIsValid = false;
double mMinimumValue = std::numeric_limits<double>::quiet_NaN();
double mMaximumValue = std::numeric_limits<double>::quiet_NaN();
};
/**
@ -261,14 +401,10 @@ class CORE_EXPORT QgsMeshDataSourceInterface SIP_ABSTRACT
virtual int faceCount() const = 0;
/**
* Returns the mesh vertex at index
* Populates the mesh vertices and faces
* \since QGIS 3.6
*/
virtual QgsMeshVertex vertex( int index ) const = 0;
/**
* Returns the mesh face at index
*/
virtual QgsMeshFace face( int index ) const = 0;
virtual void populateMesh( QgsMesh *mesh ) const = 0;
};
/**
@ -336,11 +472,22 @@ class CORE_EXPORT QgsMeshDatasetSourceInterface SIP_ABSTRACT
/**
* \brief Returns vector/scalar value associated with the index from the dataset
* To read multiple continuous values, use QgsMeshDatasetSourceInterface::datasetValues()
*
* See QgsMeshDatasetMetadata::isVector() to check if the returned value is vector or scalar
* See QgsMeshDatasetMetadata::isVector() or QgsMeshDataBlock::type()
* to check if the returned value is vector or scalar
*/
virtual QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const = 0;
/**
* \brief Returns N vector/scalar values from the index from the dataset
*
* See QgsMeshDatasetMetadata::isVector() to check if the returned value is vector or scalar
*
* \since QGIS 3.6
*/
virtual QgsMeshDataBlock datasetValues( QgsMeshDatasetIndex index, int valueIndex, int count ) const = 0;
/**
* \brief Returns whether the face is active for particular dataset
*
@ -352,6 +499,13 @@ class CORE_EXPORT QgsMeshDatasetSourceInterface SIP_ABSTRACT
* V3 ---- V4 ---- V6-----V8
*/
virtual bool isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const = 0;
/**
* \brief Returns whether the faces are active for particular dataset
*
* \since QGIS 3.6
*/
virtual QgsMeshDataBlock areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const = 0;
};
@ -373,12 +527,6 @@ class CORE_EXPORT QgsMeshDataProvider: public QgsDataProvider, public QgsMeshDat
//! Ctor
QgsMeshDataProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options );
/**
* Returns the extent of the layer
* \returns QgsRectangle containing the extent of the layer
*/
QgsRectangle extent() const override;
signals:
//! Emitted when some new dataset groups have been added
void datasetGroupsAdded( int count );

View File

@ -177,17 +177,7 @@ void QgsMeshLayer::fillNativeMesh()
if ( !( dataProvider() && dataProvider()->isValid() ) )
return;
mNativeMesh->vertices.resize( dataProvider()->vertexCount() );
for ( int i = 0; i < dataProvider()->vertexCount(); ++i )
{
mNativeMesh->vertices[i] = dataProvider()->vertex( i );
}
mNativeMesh->faces.resize( dataProvider()->faceCount() );
for ( int i = 0; i < dataProvider()->faceCount(); ++i )
{
mNativeMesh->faces[i] = dataProvider()->face( i );
}
dataProvider()->populateMesh( mNativeMesh.get() );
}
void QgsMeshLayer::onDatasetGroupsAdded( int count )
@ -224,8 +214,9 @@ static QgsColorRamp *_createDefaultColorRamp()
void QgsMeshLayer::assignDefaultStyleToDatasetGroup( int groupIndex )
{
double groupMin, groupMax;
QgsMeshLayerUtils::calculateMinMaxForDatasetGroup( groupMin, groupMax, mDataProvider, groupIndex );
const QgsMeshDatasetGroupMetadata metadata = mDataProvider->datasetGroupMetadata( groupIndex );
double groupMin = metadata.minimum();
double groupMax = metadata.maximum();
QgsColorRampShader fcn( groupMin, groupMax, _createDefaultColorRamp() );
fcn.classifyColorRamp( 5, -1, QgsRectangle(), nullptr );

View File

@ -29,7 +29,7 @@
#include "qgsmeshlayerutils.h"
QgsMeshLayerInterpolator::QgsMeshLayerInterpolator( const QgsTriangularMesh &m,
const QVector<double> &datasetValues, const QVector<bool> &activeFaceFlagValues,
const QVector<double> &datasetValues, const QgsMeshDataBlock &activeFaceFlagValues,
bool dataIsOnVertices,
const QgsRenderContext &context,
const QSize &size )
@ -87,7 +87,7 @@ QgsRasterBlock *QgsMeshLayerInterpolator::block( int, const QgsRectangle &extent
const QgsPoint p1 = vertices[v1], p2 = vertices[v2], p3 = vertices[v3];
const int nativeFaceIndex = mTriangularMesh.trianglesToNativeFaces()[i];
const bool isActive = mActiveFaceFlagValues[nativeFaceIndex];
const bool isActive = mActiveFaceFlagValues.active( nativeFaceIndex );
if ( !isActive )
continue;

View File

@ -49,7 +49,7 @@ class QgsMeshLayerInterpolator : public QgsRasterInterface
//! Ctor
QgsMeshLayerInterpolator( const QgsTriangularMesh &m,
const QVector<double> &datasetValues,
const QVector<bool> &activeFaceFlagValues,
const QgsMeshDataBlock &activeFaceFlagValues,
bool dataIsOnVertices,
const QgsRenderContext &context,
const QSize &size );
@ -63,7 +63,7 @@ class QgsMeshLayerInterpolator : public QgsRasterInterface
private:
const QgsTriangularMesh &mTriangularMesh;
const QVector<double> &mDatasetValues;
const QVector<bool> &mActiveFaceFlagValues;
const QgsMeshDataBlock &mActiveFaceFlagValues;
const QgsRenderContext &mContext;
bool mDataOnVertices = true;
QSize mOutputSize;

View File

@ -97,28 +97,25 @@ void QgsMeshLayerRenderer::copyScalarDatasetValues( QgsMeshLayer *layer )
{
const QgsMeshDatasetGroupMetadata metadata = layer->dataProvider()->datasetGroupMetadata( datasetIndex );
mScalarDataOnVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
int count;
if ( mScalarDataOnVertices )
count = mNativeMesh.vertices.count();
else
count = mNativeMesh.faces.count();
mScalarDatasetValues.resize( count );
for ( int i = 0; i < count; ++i )
{
double v = layer->dataProvider()->datasetValue( datasetIndex, i ).scalar();
mScalarDatasetValues[i] = v;
}
// populate scalar values
QgsMeshDataBlock vals = layer->dataProvider()->datasetValues(
datasetIndex,
0,
mScalarDataOnVertices ? mNativeMesh.vertices.count() : mNativeMesh.faces.count() );
// vals could be scalar or vectors, for contour rendering we want always magnitude
mScalarDatasetValues = QgsMeshLayerUtils::calculateMagnitudes( vals );
// 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()->isFaceActive( datasetIndex, i );
mScalarActiveFaceFlagValues[i] = active;
}
mScalarActiveFaceFlagValues = layer->dataProvider()->areFacesActive(
datasetIndex,
0,
mNativeMesh.faces.count() );
QgsMeshLayerUtils::calculateMinimumMaximum( mScalarDatasetMinimum, mScalarDatasetMaximum, mScalarDatasetValues );
const QgsMeshDatasetMetadata datasetMetadata = layer->dataProvider()->datasetMetadata( datasetIndex );
mScalarDatasetMinimum = datasetMetadata.minimum();
mScalarDatasetMaximum = datasetMetadata.maximum();
}
// update cache
@ -141,11 +138,12 @@ void QgsMeshLayerRenderer::copyVectorDatasetValues( QgsMeshLayer *layer )
if ( ( cache->mDatasetGroupsCount == datasetGroupCount ) &&
( cache->mActiveVectorDatasetIndex == datasetIndex ) )
{
mVectorDatasetValuesX = cache->mVectorDatasetValuesX;
mVectorDatasetValuesY = cache->mVectorDatasetValuesY;
mVectorDatasetValues = cache->mVectorDatasetValues;
mVectorDatasetValuesMag = cache->mVectorDatasetValuesMag;
mVectorDatasetMagMinimum = cache->mVectorDatasetMagMinimum;
mVectorDatasetMagMaximum = cache->mVectorDatasetMagMaximum;
mVectorDatasetGroupMagMinimum = cache->mVectorDatasetMagMinimum;
mVectorDatasetGroupMagMaximum = cache->mVectorDatasetMagMaximum;
mVectorDataOnVertices = cache->mVectorDataOnVertices;
return;
}
@ -164,39 +162,38 @@ void QgsMeshLayerRenderer::copyVectorDatasetValues( QgsMeshLayer *layer )
else
{
mVectorDataOnVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
mVectorDatasetGroupMagMinimum = metadata.minimum();
mVectorDatasetGroupMagMaximum = metadata.maximum();
int count;
if ( mVectorDataOnVertices )
count = mNativeMesh.vertices.count();
else
count = mNativeMesh.faces.count();
mVectorDatasetValuesX.resize( count );
mVectorDatasetValuesY.resize( count );
mVectorDatasetValuesMag.resize( count );
for ( int i = 0; i < count; ++i )
{
double x = layer->dataProvider()->datasetValue( datasetIndex, i ).x();
mVectorDatasetValuesX[i] = x;
double y = layer->dataProvider()->datasetValue( datasetIndex, i ).y();
mVectorDatasetValuesY[i] = y;
mVectorDatasetValues = layer->dataProvider()->datasetValues(
datasetIndex,
0,
count );
double mag = layer->dataProvider()->datasetValue( datasetIndex, i ).scalar();
mVectorDatasetValuesMag[i] = mag;
}
mVectorDatasetValuesMag = QgsMeshLayerUtils::calculateMagnitudes( mVectorDatasetValues );
const QgsMeshDatasetMetadata datasetMetadata = layer->dataProvider()->datasetMetadata( datasetIndex );
mVectorDatasetMagMinimum = datasetMetadata.minimum();
mVectorDatasetMagMaximum = datasetMetadata.maximum();
}
QgsMeshLayerUtils::calculateMinimumMaximum( mVectorDatasetMagMinimum, mVectorDatasetMagMaximum, mVectorDatasetValuesMag );
}
// update cache
cache->mDatasetGroupsCount = datasetGroupCount;
cache->mActiveVectorDatasetIndex = datasetIndex;
cache->mVectorDatasetValuesX = mVectorDatasetValuesX;
cache->mVectorDatasetValuesY = mVectorDatasetValuesY;
cache->mVectorDatasetValues = mVectorDatasetValues;
cache->mVectorDatasetValuesMag = mVectorDatasetValuesMag;
cache->mVectorDatasetMagMinimum = mVectorDatasetMagMinimum;
cache->mVectorDatasetMagMaximum = mVectorDatasetMagMaximum;
cache->mVectorDatasetGroupMagMinimum = mVectorDatasetMagMinimum;
cache->mVectorDatasetGroupMagMaximum = mVectorDatasetMagMaximum;
cache->mVectorDataOnVertices = mVectorDataOnVertices;
}
@ -304,8 +301,12 @@ void QgsMeshLayerRenderer::renderScalarDataset()
QgsColorRampShader *fcn = new QgsColorRampShader( scalarSettings.colorRampShader() );
QgsRasterShader *sh = new QgsRasterShader();
sh->setRasterShaderFunction( fcn ); // takes ownership of fcn
QgsMeshLayerInterpolator interpolator( mTriangularMesh, mScalarDatasetValues, mScalarActiveFaceFlagValues,
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() );
@ -323,19 +324,21 @@ void QgsMeshLayerRenderer::renderVectorDataset()
if ( !index.isValid() )
return;
if ( mVectorDatasetValuesX.isEmpty() )
return;
if ( !mVectorDatasetValues.isValid() )
return; // no data at all
if ( std::isnan( mVectorDatasetMagMinimum ) || std::isnan( mVectorDatasetMagMaximum ) )
return; // only NODATA values
if ( mVectorDatasetValuesX.size() != mVectorDatasetValuesY.size() )
return;
QgsMeshVectorRenderer renderer( mTriangularMesh,
mVectorDatasetValuesX, mVectorDatasetValuesY, mVectorDatasetValuesMag,
mVectorDatasetMagMinimum, mVectorDatasetMagMaximum,
mVectorDataOnVertices, mRendererSettings.vectorSettings( index.group() ), mContext, mOutputSize );
mVectorDatasetValues,
mVectorDatasetValuesMag,
mVectorDatasetMagMinimum,
mVectorDatasetMagMaximum,
mVectorDataOnVertices,
mRendererSettings.vectorSettings( index.group() ),
mContext,
mOutputSize );
renderer.draw();
}

View File

@ -56,18 +56,19 @@ struct CORE_NO_EXPORT QgsMeshLayerRendererCache
// scalar dataset
QgsMeshDatasetIndex mActiveScalarDatasetIndex;
QVector<double> mScalarDatasetValues;
QVector<bool> mScalarActiveFaceFlagValues;
QgsMeshDataBlock mScalarActiveFaceFlagValues;
bool mScalarDataOnVertices = true;
double mScalarDatasetMinimum = std::numeric_limits<double>::quiet_NaN();
double mScalarDatasetMaximum = std::numeric_limits<double>::quiet_NaN();
// vector dataset
QgsMeshDatasetIndex mActiveVectorDatasetIndex;
QVector<double> mVectorDatasetValuesX;
QVector<double> mVectorDatasetValuesY;
QgsMeshDataBlock mVectorDatasetValues;
QVector<double> mVectorDatasetValuesMag;
double mVectorDatasetMagMinimum = std::numeric_limits<double>::quiet_NaN();
double mVectorDatasetMagMaximum = std::numeric_limits<double>::quiet_NaN();
double mVectorDatasetGroupMagMinimum = std::numeric_limits<double>::quiet_NaN();
double mVectorDatasetGroupMagMaximum = std::numeric_limits<double>::quiet_NaN();
bool mVectorDataOnVertices = true;
};
@ -110,17 +111,18 @@ class QgsMeshLayerRenderer : public QgsMapLayerRenderer
// copy of the scalar dataset
QVector<double> mScalarDatasetValues;
QVector<bool> mScalarActiveFaceFlagValues;
QgsMeshDataBlock mScalarActiveFaceFlagValues;
bool mScalarDataOnVertices = true;
double mScalarDatasetMinimum = std::numeric_limits<double>::quiet_NaN();
double mScalarDatasetMaximum = std::numeric_limits<double>::quiet_NaN();
// copy of the vector dataset
QVector<double> mVectorDatasetValuesX;
QVector<double> mVectorDatasetValuesY;
QgsMeshDataBlock mVectorDatasetValues;
QVector<double> mVectorDatasetValuesMag;
double mVectorDatasetMagMinimum = std::numeric_limits<double>::quiet_NaN();
double mVectorDatasetMagMaximum = std::numeric_limits<double>::quiet_NaN();
double mVectorDatasetGroupMagMinimum = std::numeric_limits<double>::quiet_NaN();
double mVectorDatasetGroupMagMaximum = std::numeric_limits<double>::quiet_NaN();
bool mVectorDataOnVertices = true;
// rendering context

View File

@ -17,103 +17,22 @@
#include "qgsmeshlayerutils.h"
#include "qgsmeshdataprovider.h"
#include <limits>
///@cond PRIVATE
void QgsMeshLayerUtils::calculateMinimumMaximum( double &min, double &max, const QVector<double> &arr )
QVector<double> QgsMeshLayerUtils::calculateMagnitudes( const QgsMeshDataBlock &block )
{
bool found = false;
Q_ASSERT( QgsMeshDataBlock::ActiveFlagInteger != block.type() );
int count = block.count();
QVector<double> ret( count );
min = std::numeric_limits<double>::max();
max = std::numeric_limits<double>::min();
for ( const double val : arr )
{
if ( !std::isnan( val ) )
{
found = true;
if ( val < min )
min = val;
if ( val > max )
max = val;
}
}
if ( !found )
{
min = std::numeric_limits<double>::quiet_NaN();
max = std::numeric_limits<double>::quiet_NaN();
}
}
void QgsMeshLayerUtils::calculateMinMaxForDatasetGroup( double &min, double &max, QgsMeshDataProvider *provider, int groupIndex )
{
if ( groupIndex < 0 || !provider || groupIndex >= provider->datasetGroupCount() )
{
min = std::numeric_limits<double>::quiet_NaN();
max = std::numeric_limits<double>::quiet_NaN();
return;
}
min = std::numeric_limits<double>::max();
max = std::numeric_limits<double>::min();
int count = provider->datasetCount( groupIndex );
for ( int i = 0; i < count; ++i )
{
double dMin, dMax;
calculateMinMaxForDataset( dMin, dMax, provider, QgsMeshDatasetIndex( groupIndex, i ) );
min = std::min( min, dMin );
max = std::max( max, dMax );
double mag = block.value( i ).scalar();
ret[i] = mag;
}
}
void QgsMeshLayerUtils::calculateMinMaxForDataset( double &min, double &max, QgsMeshDataProvider *provider, QgsMeshDatasetIndex index )
{
if ( !index.isValid() || !provider )
{
min = std::numeric_limits<double>::quiet_NaN();
max = std::numeric_limits<double>::quiet_NaN();
return;
}
const QgsMeshDatasetGroupMetadata metadata = provider->datasetGroupMetadata( index );
bool onVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
int count;
if ( onVertices )
count = provider->vertexCount();
else
count = provider->faceCount();
bool firstIteration = true;
for ( int i = 0; i < count; ++i )
{
double v = provider->datasetValue( index, i ).scalar();
if ( std::isnan( v ) )
continue;
if ( firstIteration )
{
firstIteration = false;
min = v;
max = v;
}
else
{
if ( v < min )
{
min = v;
}
if ( v > max )
{
max = v;
}
}
}
return ret;
}
void QgsMeshLayerUtils::boundingBoxToScreenRectangle( const QgsMapToPixel &mtp,

View File

@ -23,9 +23,7 @@
#include "qgis_core.h"
#include "qgsrectangle.h"
#include "qgsmaptopixel.h"
class QgsMeshDataProvider;
class QgsMeshDatasetIndex;
#include "qgsmeshdataprovider.h"
#include <QVector>
#include <QSize>
@ -44,22 +42,11 @@ class CORE_EXPORT QgsMeshLayerUtils
public:
/**
* Calculates min/max values from the given vector of values.
* Ignores any NaN values in the input. Returns NaN for min/max on error.
* Calculates magnitude values from the given QgsMeshDataBlock.
*
* \since QGIS 3.6
*/
static void calculateMinimumMaximum( double &min, double &max, const QVector<double> &arr );
/**
* Calculates min/max values for the whole dataset group (considering all datasets within it).
* Ignores any NaN values in the input. Returns NaN for min/max on error.
*/
static void calculateMinMaxForDatasetGroup( double &min, double &max, QgsMeshDataProvider *provider, int groupIndex );
/**
* Calculates min/max values for one dataset.
* Ignores any NaN values in the input. Returns NaN for min/max on error.
*/
static void calculateMinMaxForDataset( double &min, double &max, QgsMeshDataProvider *provider, QgsMeshDatasetIndex index );
static QVector<double> calculateMagnitudes( const QgsMeshDataBlock &block );
/**
* Transformes the bounding box to rectangle in screen coordinates (in pixels)

View File

@ -17,6 +17,9 @@
///@cond PRIVATE
#include "qgsmeshmemorydataprovider.h"
#include "qgsmeshlayerutils.h"
#include "qgstriangularmesh.h"
#include <cstring>
static const QString TEXT_PROVIDER_KEY = QStringLiteral( "mesh_memory" );
static const QString TEXT_PROVIDER_DESCRIPTION = QStringLiteral( "Mesh memory provider" );
@ -299,16 +302,18 @@ int QgsMeshMemoryDataProvider::faceCount() const
return mFaces.size();
}
QgsMeshVertex QgsMeshMemoryDataProvider::vertex( int index ) const
void QgsMeshMemoryDataProvider::populateMesh( QgsMesh *mesh ) const
{
Q_ASSERT( vertexCount() > index );
return mVertices[index];
if ( mesh )
{
mesh->faces = mFaces;
mesh->vertices = mVertices;
}
}
QgsMeshFace QgsMeshMemoryDataProvider::face( int index ) const
QgsRectangle QgsMeshMemoryDataProvider::extent() const
{
Q_ASSERT( faceCount() > index );
return mFaces[index];
return calculateExtent( );
}
bool QgsMeshMemoryDataProvider::addDataset( const QString &uri )
@ -326,6 +331,7 @@ bool QgsMeshMemoryDataProvider::addDataset( const QString &uri )
QStringLiteral( "Mesh Memory Provider" ) ) );
}
calculateMinMaxForDatasetGroup( group );
mDatasetGroups.push_back( group );
if ( valid )
@ -364,6 +370,8 @@ QgsMeshDatasetGroupMetadata QgsMeshMemoryDataProvider::datasetGroupMetadata( int
mDatasetGroups[groupIndex].name,
mDatasetGroups[groupIndex].isScalar,
mDatasetGroups[groupIndex].isOnVertices,
mDatasetGroups[groupIndex].minimum,
mDatasetGroups[groupIndex].maximum,
mDatasetGroups[groupIndex].metadata
);
return metadata;
@ -383,7 +391,9 @@ QgsMeshDatasetMetadata QgsMeshMemoryDataProvider::datasetMetadata( QgsMeshDatase
const QgsMeshMemoryDatasetGroup &grp = mDatasetGroups.at( index.group() );
QgsMeshDatasetMetadata metadata(
grp.datasets[index.dataset()].time,
grp.datasets[index.dataset()].valid
grp.datasets[index.dataset()].valid,
grp.datasets[index.dataset()].minimum,
grp.datasets[index.dataset()].maximum
);
return metadata;
}
@ -407,6 +417,26 @@ QgsMeshDatasetValue QgsMeshMemoryDataProvider::datasetValue( QgsMeshDatasetIndex
}
}
QgsMeshDataBlock QgsMeshMemoryDataProvider::datasetValues( QgsMeshDatasetIndex index, int valueIndex, int count ) const
{
bool isScalar = mDatasetGroups[index.group()].isScalar;
QgsMeshDataBlock ret( isScalar ? QgsMeshDataBlock::ScalarDouble : QgsMeshDataBlock::Vector2DDouble, count );
double *buf = static_cast<double *>( ret.buffer() );
for ( int i = 0; i < count; ++i )
{
QgsMeshDatasetValue val = datasetValue( index, valueIndex + i );
if ( isScalar )
buf[i] = val.x();
else
{
buf[2 * i] = val.x();
buf[2 * i + 1] = val.y();
}
}
return ret;
}
bool QgsMeshMemoryDataProvider::isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const
{
Q_UNUSED( index );
@ -414,5 +444,83 @@ bool QgsMeshMemoryDataProvider::isFaceActive( QgsMeshDatasetIndex index, int fac
return true;
}
QgsMeshDataBlock QgsMeshMemoryDataProvider::areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const
{
Q_UNUSED( index );
Q_UNUSED( faceIndex );
QgsMeshDataBlock ret( QgsMeshDataBlock::ActiveFlagInteger, count );
memset( ret.buffer(), 1, static_cast<size_t>( count ) * sizeof( int ) );
return ret;
}
void QgsMeshMemoryDataProvider::calculateMinMaxForDatasetGroup( QgsMeshMemoryDatasetGroup &grp ) const
{
double min = std::numeric_limits<double>::max();
double max = std::numeric_limits<double>::min();
int count = grp.datasets.size();
for ( int i = 0; i < count; ++i )
{
calculateMinMaxForDataset( grp.datasets[i] );
min = std::min( min, grp.datasets[i].minimum );
max = std::max( max, grp.datasets[i].maximum );
}
grp.minimum = min;
grp.maximum = max;
}
void QgsMeshMemoryDataProvider::calculateMinMaxForDataset( QgsMeshMemoryDataset &dataset ) const
{
double min = std::numeric_limits<double>::max();
double max = std::numeric_limits<double>::min();
if ( !dataset.valid )
{
return;
}
bool firstIteration = true;
for ( int i = 0; i < dataset.values.size(); ++i )
{
double v = dataset.values[i].scalar();
if ( std::isnan( v ) )
continue;
if ( firstIteration )
{
firstIteration = false;
min = v;
max = v;
}
else
{
if ( v < min )
{
min = v;
}
if ( v > max )
{
max = v;
}
}
}
dataset.minimum = min;
dataset.maximum = max;
}
QgsRectangle QgsMeshMemoryDataProvider::calculateExtent() const
{
QgsRectangle rec;
rec.setMinimal();
for ( const QgsMeshVertex &v : mVertices )
{
rec.setXMinimum( std::min( rec.xMinimum(), v.x() ) );
rec.setYMinimum( std::min( rec.yMinimum(), v.y() ) );
rec.setXMaximum( std::max( rec.xMaximum(), v.x() ) );
rec.setYMaximum( std::max( rec.yMaximum(), v.y() ) );
}
return rec;
}
///@endcond

View File

@ -34,6 +34,8 @@ struct QgsMeshMemoryDataset
QVector<QgsMeshDatasetValue> values;
double time = -1;
bool valid = false;
double minimum = std::numeric_limits<double>::quiet_NaN();
double maximum = std::numeric_limits<double>::quiet_NaN();
};
struct QgsMeshMemoryDatasetGroup
@ -43,6 +45,8 @@ struct QgsMeshMemoryDatasetGroup
QString name;
bool isScalar = true;
bool isOnVertices = true;
double minimum = std::numeric_limits<double>::quiet_NaN();
double maximum = std::numeric_limits<double>::quiet_NaN();
};
/**
@ -87,9 +91,8 @@ class QgsMeshMemoryDataProvider: public QgsMeshDataProvider
int vertexCount() const override;
int faceCount() const override;
QgsMeshVertex vertex( int index ) const override;
QgsMeshFace face( int index ) const override;
void populateMesh( QgsMesh *mesh ) const override;
QgsRectangle extent() const override;
/**
* Adds dataset to a mesh in-memory data provider from data string
@ -128,7 +131,9 @@ class QgsMeshMemoryDataProvider: public QgsMeshDataProvider
QgsMeshDatasetGroupMetadata datasetGroupMetadata( int groupIndex ) const override;
QgsMeshDatasetMetadata datasetMetadata( QgsMeshDatasetIndex index ) const override;
QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const override;
QgsMeshDataBlock datasetValues( QgsMeshDatasetIndex index, int valueIndex, int count ) const override;
bool isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const override;
QgsMeshDataBlock areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const override;
//! Returns the memory provider key
static QString providerKey();
@ -136,7 +141,12 @@ class QgsMeshMemoryDataProvider: public QgsMeshDataProvider
static QString providerDescription();
//! Provider factory
static QgsMeshMemoryDataProvider *createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options );
private:
void calculateMinMaxForDatasetGroup( QgsMeshMemoryDatasetGroup &grp ) const;
void calculateMinMaxForDataset( QgsMeshMemoryDataset &dataset ) const;
QgsRectangle calculateExtent( ) const;
bool splitMeshSections( const QString &uri );
bool addMeshVertices( const QString &def );
bool addMeshFaces( const QString &def );

View File

@ -46,8 +46,7 @@ inline bool nodataValue( double x, double y )
}
QgsMeshVectorRenderer::QgsMeshVectorRenderer( const QgsTriangularMesh &m,
const QVector<double> &datasetValuesX,
const QVector<double> &datasetValuesY,
const QgsMeshDataBlock &datasetValues,
const QVector<double> &datasetValuesMag,
double datasetMagMinimumValue,
double datasetMagMaximumValue,
@ -55,8 +54,7 @@ QgsMeshVectorRenderer::QgsMeshVectorRenderer( const QgsTriangularMesh &m,
const QgsMeshRendererVectorSettings &settings,
QgsRenderContext &context, QSize size )
: mTriangularMesh( m )
, mDatasetValuesX( datasetValuesX )
, mDatasetValuesY( datasetValuesY )
, mDatasetValues( datasetValues )
, mDatasetValuesMag( datasetValuesMag )
, mMinMag( datasetMagMinimumValue )
, mMaxMag( datasetMagMaximumValue )
@ -70,6 +68,8 @@ QgsMeshVectorRenderer::QgsMeshVectorRenderer( const QgsTriangularMesh &m,
Q_ASSERT( !mDatasetValuesMag.empty() );
Q_ASSERT( !std::isnan( mMinMag ) );
Q_ASSERT( !std::isnan( mMaxMag ) );
Q_ASSERT( mDatasetValues.isValid() );
Q_ASSERT( QgsMeshDataBlock::Vector2DDouble == mDatasetValues.type() );
// we need to expand out the extent so that it includes
// arrows which start or end up outside of the
@ -259,8 +259,9 @@ void QgsMeshVectorRenderer::drawVectorDataOnVertices( const QList<int> &triangle
if ( !mBufferedExtent.contains( vertex ) )
continue;
double xVal = mDatasetValuesX[i];
double yVal = mDatasetValuesY[i];
const QgsMeshDatasetValue val = mDatasetValues.value( i );
double xVal = val.x();
double yVal = val.y();
if ( nodataValue( xVal, yVal ) )
continue;
@ -286,8 +287,9 @@ void QgsMeshVectorRenderer::drawVectorDataOnFaces( const QList<int> &trianglesIn
if ( !mBufferedExtent.contains( center ) )
continue;
double xVal = mDatasetValuesX[i];
double yVal = mDatasetValuesY[i];
const QgsMeshDatasetValue val = mDatasetValues.value( i );
double xVal = val.x();
double yVal = val.y();
if ( nodataValue( xVal, yVal ) )
continue;
@ -342,36 +344,40 @@ void QgsMeshVectorRenderer::drawVectorDataOnGrid( const QList<int> &trianglesInE
if ( mDataOnVertices )
{
const auto val1 = mDatasetValues.value( v1 );
const auto val2 = mDatasetValues.value( v2 );
const auto val3 = mDatasetValues.value( v3 );
val.setX(
QgsMeshLayerUtils::interpolateFromVerticesData(
p1, p2, p3,
mDatasetValuesX[v1],
mDatasetValuesX[v2],
mDatasetValuesX[v3],
val1.x(),
val2.x(),
val3.x(),
p )
);
val.setY(
QgsMeshLayerUtils::interpolateFromVerticesData(
p1, p2, p3,
mDatasetValuesY[v1],
mDatasetValuesY[v2],
mDatasetValuesY[v3],
val1.y(),
val2.y(),
val3.y(),
p )
);
}
else
{
const auto val1 = mDatasetValues.value( nativeFaceIndex );
val.setX(
QgsMeshLayerUtils::interpolateFromFacesData(
p1, p2, p3,
mDatasetValuesX[nativeFaceIndex],
val1.x(),
p
)
);
val.setY(
QgsMeshLayerUtils::interpolateFromFacesData(
p1, p2, p3,
mDatasetValuesY[nativeFaceIndex],
val1.y(),
p
)
);

View File

@ -46,8 +46,7 @@ class QgsMeshVectorRenderer
public:
//! Ctor
QgsMeshVectorRenderer( const QgsTriangularMesh &m,
const QVector<double> &datasetValuesX,
const QVector<double> &datasetValuesY,
const QgsMeshDataBlock &datasetValues,
const QVector<double> &datasetValuesMag,
double datasetMagMaximumValue,
double datasetMagMinimumValue,
@ -92,8 +91,7 @@ class QgsMeshVectorRenderer
double calcExtentBufferSize() const;
const QgsTriangularMesh &mTriangularMesh;
const QVector<double> &mDatasetValuesX;
const QVector<double> &mDatasetValuesY;
const QgsMeshDataBlock &mDatasetValues;
const QVector<double> &mDatasetValuesMag; //magnitudes
double mMinMag = 0.0;
double mMaxMag = 0.0;

View File

@ -33,15 +33,6 @@ class QgsRenderContext;
class QgsCoordinateTransform;
class QgsRectangle;
//! Mesh - vertices and faces
struct CORE_EXPORT QgsMesh
{
//! vertices
QVector<QgsMeshVertex> vertices;
//! faces
QVector<QgsMeshFace> faces;
};
///@cond PRIVATE
/**

View File

@ -18,6 +18,7 @@
#include <string>
#include "qgsmdalprovider.h"
#include "qgstriangularmesh.h"
#ifdef HAVE_GUI
#include "qgssourceselectprovider.h"
@ -82,26 +83,91 @@ int QgsMdalProvider::faceCount() const
return 0;
}
QgsMeshVertex QgsMdalProvider::vertex( int index ) const
void QgsMdalProvider::populateMesh( QgsMesh *mesh ) const
{
Q_ASSERT( index < vertexCount() );
double x = MDAL_M_vertexXCoordinatesAt( mMeshH, index );
double y = MDAL_M_vertexYCoordinatesAt( mMeshH, index );
QgsMeshVertex vertex( x, y );
return vertex;
if ( mesh )
{
mesh->faces = faces();
mesh->vertices = vertices();
}
}
QgsMeshFace QgsMdalProvider::face( int index ) const
QVector<QgsMeshVertex> QgsMdalProvider::vertices( ) const
{
Q_ASSERT( index < faceCount() );
QgsMeshFace face;
int n_face_vertices = MDAL_M_faceVerticesCountAt( mMeshH, index );
for ( int j = 0; j < n_face_vertices; ++j )
const int bufferSize = std::min( vertexCount(), 1000 );
QVector<QgsMeshVertex> ret( vertexCount() );
QVector<double> buffer( bufferSize * 3 );
MeshVertexIteratorH it = MDAL_M_vertexIterator( mMeshH );
int vertexIndex = 0;
while ( vertexIndex < vertexCount() )
{
int vertex_index = MDAL_M_faceVerticesIndexAt( mMeshH, index, j );
face.push_back( vertex_index );
int verticesRead = MDAL_VI_next( it, bufferSize, buffer.data() );
if ( verticesRead == 0 )
break;
for ( int i = 0; i < verticesRead; i++ )
{
QgsMeshVertex vertex(
buffer[3 * i],
buffer[3 * i + 1],
buffer[3 * i + 2]
);
ret[vertexIndex + i] = vertex;
}
vertexIndex += verticesRead;
}
return face;
MDAL_VI_close( it );
return ret;
}
QVector<QgsMeshFace> QgsMdalProvider::faces( ) const
{
const int faceOffsetsBufferLen = std::min( faceCount(), 1000 );
const int vertexIndicesBufferLen = faceOffsetsBufferLen * 4; // most usually we have quads
int facesCount = faceCount();
QVector<QgsMeshFace> ret( facesCount );
QVector<int> faceOffsetsBuffer( faceOffsetsBufferLen );
QVector<int> vertexIndicesBuffer( vertexIndicesBufferLen );
MeshFaceIteratorH it = MDAL_M_faceIterator( mMeshH );
int faceIndex = 0;
while ( faceIndex < facesCount )
{
int facesRead = MDAL_FI_next( it,
faceOffsetsBufferLen,
faceOffsetsBuffer.data(),
vertexIndicesBufferLen,
vertexIndicesBuffer.data() );
if ( facesRead == 0 )
break;
for ( int i = 0; i < facesRead; i++ )
{
QgsMeshFace face;
int startIndex = 0;
if ( i > 0 )
startIndex = faceOffsetsBuffer[ i - 1 ];
int endIndex = faceOffsetsBuffer[ i ];
for ( int j = startIndex; j < endIndex; ++j )
{
int vertexIndex = vertexIndicesBuffer[j];
face.push_back( vertexIndex );
}
ret[faceIndex + i] = face;
}
faceIndex += facesRead;
}
MDAL_FI_close( it );
return ret;
}
QgsRectangle QgsMdalProvider::extent() const
{
double xMin, yMin, xMax, yMax;
MDAL_M_extent( mMeshH, &xMin, &xMax, &yMin, &yMax );
QgsRectangle ret( xMin, yMin, xMax, yMax );
return ret;
}
/*----------------------------------------------------------------------------------------------*/
@ -155,6 +221,8 @@ QgsMeshDatasetGroupMetadata QgsMdalProvider::datasetGroupMetadata( int groupInde
bool isScalar = MDAL_G_hasScalarData( group );
bool isOnVertices = MDAL_G_isOnVertices( group );
QString name = MDAL_G_name( group );
double min, max;
MDAL_G_minimumMaximum( group, &min, &max );
QMap<QString, QString> metadata;
int n = MDAL_G_metadataCount( group );
@ -169,6 +237,8 @@ QgsMeshDatasetGroupMetadata QgsMdalProvider::datasetGroupMetadata( int groupInde
name,
isScalar,
isOnVertices,
min,
max,
metadata
);
@ -187,10 +257,14 @@ QgsMeshDatasetMetadata QgsMdalProvider::datasetMetadata( QgsMeshDatasetIndex ind
bool isValid = MDAL_D_isValid( dataset );
double time = MDAL_D_time( dataset );
double min, max;
MDAL_D_minimumMaximum( dataset, &min, &max );
QgsMeshDatasetMetadata meta(
time,
isValid
isValid,
min,
max
);
return meta;
@ -198,41 +272,58 @@ QgsMeshDatasetMetadata QgsMdalProvider::datasetMetadata( QgsMeshDatasetIndex ind
}
QgsMeshDatasetValue QgsMdalProvider::datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const
{
QgsMeshDataBlock vals = datasetValues( index, valueIndex, 1 );
return vals.value( 0 );
}
QgsMeshDataBlock QgsMdalProvider::datasetValues( QgsMeshDatasetIndex index, int valueIndex, int count ) const
{
DatasetGroupH group = MDAL_M_datasetGroup( mMeshH, index.group() );
if ( !group )
return QgsMeshDatasetValue();
return QgsMeshDataBlock();
DatasetH dataset = MDAL_G_dataset( group, index.dataset() );
if ( !dataset )
return QgsMeshDatasetValue();
return QgsMeshDataBlock();
QgsMeshDatasetValue val;
bool isScalar = MDAL_G_hasScalarData( group );
if ( MDAL_G_hasScalarData( group ) )
{
val.setX( MDAL_D_value( dataset, valueIndex ) );
}
else
{
val.setX( MDAL_D_valueX( dataset, valueIndex ) );
val.setY( MDAL_D_valueY( dataset, valueIndex ) );
}
QgsMeshDataBlock ret( isScalar ? QgsMeshDataBlock::ScalarDouble : QgsMeshDataBlock::Vector2DDouble, count );
int valRead = MDAL_D_data( dataset,
valueIndex,
count,
isScalar ? MDAL_DataType::SCALAR_DOUBLE : MDAL_DataType::VECTOR_2D_DOUBLE,
ret.buffer() );
if ( valRead != count )
return QgsMeshDataBlock();
return val;
return ret;
}
bool QgsMdalProvider::isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const
{
QgsMeshDataBlock vals = areFacesActive( index, faceIndex, 1 );
return vals.active( 0 );
}
QgsMeshDataBlock QgsMdalProvider::areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const
{
DatasetGroupH group = MDAL_M_datasetGroup( mMeshH, index.group() );
if ( !group )
return false;
return QgsMeshDataBlock();
DatasetH dataset = MDAL_G_dataset( group, index.dataset() );
if ( !dataset )
return false;
return QgsMeshDataBlock();
return MDAL_D_active( dataset, faceIndex );
QgsMeshDataBlock ret( QgsMeshDataBlock::ActiveFlagInteger, count );
int valRead = MDAL_D_data( dataset, faceIndex, count, MDAL_DataType::ACTIVE_INTEGER, ret.buffer() );
if ( valRead != count )
return ret;
return ret;
}
/*----------------------------------------------------------------------------------------------*/

View File

@ -53,8 +53,7 @@ class QgsMdalProvider : public QgsMeshDataProvider
int vertexCount() const override;
int faceCount() const override;
QgsMeshVertex vertex( int index ) const override;
QgsMeshFace face( int index ) const override;
void populateMesh( QgsMesh *mesh ) const override;
bool addDataset( const QString &uri ) override;
QStringList extraDatasets() const override;
@ -65,9 +64,14 @@ class QgsMdalProvider : public QgsMeshDataProvider
QgsMeshDatasetGroupMetadata datasetGroupMetadata( int groupIndex ) const override;
QgsMeshDatasetMetadata datasetMetadata( QgsMeshDatasetIndex index ) const override;
QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const override;
QgsMeshDataBlock datasetValues( QgsMeshDatasetIndex index, int valueIndex, int count ) const override;
bool isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const override;
QgsMeshDataBlock areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const override;
QgsRectangle extent() const override;
private:
QVector<QgsMeshVertex> vertices( ) const;
QVector<QgsMeshFace> faces( ) const;
MeshH mMeshH;
QStringList mExtraDatasetUris;
QgsCoordinateReferenceSystem mCrs;

View File

@ -25,6 +25,7 @@
#include "qgsapplication.h"
#include "qgsproviderregistry.h"
#include "qgsproject.h"
#include "qgstriangularmesh.h"
/**
* \ingroup UnitTests
@ -126,21 +127,31 @@ void TestQgsMeshLayer::test_read_mesh()
QVERIFY( dp != nullptr );
QVERIFY( dp->isValid() );
QgsMesh mesh;
dp->populateMesh( &mesh );
QCOMPARE( 5, dp->vertexCount() );
QCOMPARE( QgsMeshVertex( 1000.0, 2000.0 ), dp->vertex( 0 ) );
QCOMPARE( QgsMeshVertex( 2000.0, 2000.0 ), dp->vertex( 1 ) );
QCOMPARE( QgsMeshVertex( 3000.0, 2000.0 ), dp->vertex( 2 ) );
QCOMPARE( QgsMeshVertex( 2000.0, 3000.0 ), dp->vertex( 3 ) );
QCOMPARE( QgsMeshVertex( 1000.0, 3000.0 ), dp->vertex( 4 ) );
const QVector<QgsMeshVertex> vertices = mesh.vertices;
QCOMPARE( 1000.0, vertices.at( 0 ).x() );
QCOMPARE( 2000.0, vertices.at( 1 ).x() );
QCOMPARE( 3000.0, vertices.at( 2 ).x() );
QCOMPARE( 2000.0, vertices.at( 3 ).x() );
QCOMPARE( 1000.0, vertices.at( 4 ).x() );
QCOMPARE( 2000.0, vertices.at( 0 ).y() );
QCOMPARE( 2000.0, vertices.at( 1 ).y() );
QCOMPARE( 2000.0, vertices.at( 2 ).y() );
QCOMPARE( 3000.0, vertices.at( 3 ).y() );
QCOMPARE( 3000.0, vertices.at( 4 ).y() );
QCOMPARE( 2, dp->faceCount() );
const QVector<QgsMeshFace> faces = mesh.faces;
QgsMeshFace f1;
f1 << 0 << 1 << 3 << 4;
QCOMPARE( f1, dp->face( 0 ) );
QCOMPARE( f1, faces.at( 0 ) );
QgsMeshFace f2;
f2 << 1 << 2 << 3;
QCOMPARE( f2, dp->face( 1 ) );
QCOMPARE( f2, faces.at( 1 ) );
}
}