[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; 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 class QgsMeshDatasetValue
{ {
%Docstring %Docstring
@ -122,6 +144,76 @@ Returns y value
bool operator==( const QgsMeshDatasetValue &other ) const; 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 class QgsMeshDatasetGroupMetadata
@ -157,6 +249,8 @@ Constructs an empty metadata object
QgsMeshDatasetGroupMetadata( const QString &name, QgsMeshDatasetGroupMetadata( const QString &name,
bool isScalar, bool isScalar,
bool isOnVertices, bool isOnVertices,
double minimum,
double maximum,
const QMap<QString, QString> &extraOptions ); const QMap<QString, QString> &extraOptions );
%Docstring %Docstring
Constructs a valid metadata object Constructs a valid metadata object
@ -164,6 +258,8 @@ Constructs a valid metadata object
:param name: name of the dataset group :param name: name of the dataset group
:param isScalar: dataset contains scalar data, specifically the y-value of QgsMeshDatasetValue is NaN :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 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, ... :param extraOptions: dataset's extra options stored by the provider. Usually contains the name, time value, time units, data file vendor, ...
%End %End
@ -190,6 +286,16 @@ Returns whether dataset group has scalar data
DataType dataType() const; DataType dataType() const;
%Docstring %Docstring
Returns whether dataset group data is defined on vertices or faces 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 %End
}; };
@ -218,7 +324,10 @@ Constructs an empty metadata object
%End %End
QgsMeshDatasetMetadata( double time, QgsMeshDatasetMetadata( double time,
bool isValid ); bool isValid,
double minimum,
double maximum
);
%Docstring %Docstring
Constructs a valid metadata object Constructs a valid metadata object
@ -234,6 +343,16 @@ Returns the time value for this dataset
bool isValid() const; bool isValid() const;
%Docstring %Docstring
Returns whether dataset is valid 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 %End
}; };
@ -278,14 +397,11 @@ Returns number of faces in the native mesh
:return: Number of faces in the mesh :return: Number of faces in the mesh
%End %End
virtual QgsMeshVertex vertex( int index ) const = 0; virtual void populateMesh( QgsMesh *mesh ) const = 0;
%Docstring %Docstring
Returns the mesh vertex at index Populates the mesh vertices and faces
%End
virtual QgsMeshFace face( int index ) const = 0; .. versionadded:: 3.6
%Docstring
Returns the mesh face at index
%End %End
}; };
@ -359,8 +475,19 @@ Returns dataset metadata
virtual QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const = 0; virtual QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const = 0;
%Docstring %Docstring
Returns vector/scalar value associated with the index from the dataset 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 See QgsMeshDatasetMetadata.isVector() to check if the returned value is vector or scalar
.. versionadded:: 3.6
%End %End
virtual bool isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const = 0; virtual bool isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const = 0;
@ -373,6 +500,13 @@ set active flag for F2 to false.
V1 ---- V2 ---- V5-----V7 V1 ---- V2 ---- V5-----V7
| F1 | F2 | F3 | | F1 | F2 | F3 |
V3 ---- V4 ---- V6-----V8 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 %End
}; };
@ -398,14 +532,6 @@ Responsible for reading native mesh data
QgsMeshDataProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options ); QgsMeshDataProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options );
%Docstring %Docstring
Ctor Ctor
%End
virtual QgsRectangle extent() const;
%Docstring
Returns the extent of the layer
:return: QgsRectangle containing the extent of the layer
%End %End
signals: signals:

View File

@ -93,8 +93,9 @@ void QgsMeshRendererScalarSettingsWidget::minMaxEdited()
void QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked() void QgsMeshRendererScalarSettingsWidget::recalculateMinMaxButtonClicked()
{ {
double min, max; const QgsMeshDatasetGroupMetadata metadata = mMeshLayer->dataProvider()->datasetGroupMetadata( mActiveDatasetGroup );
QgsMeshLayerUtils::calculateMinMaxForDatasetGroup( min, max, mMeshLayer->dataProvider(), mActiveDatasetGroup ); double min = metadata.minimum();
double max = metadata.maximum();
whileBlocking( mScalarMinLineEdit )->setText( QString::number( min ) ); whileBlocking( mScalarMinLineEdit )->setText( QString::number( min ) );
whileBlocking( mScalarMaxLineEdit )->setText( QString::number( max ) ); whileBlocking( mScalarMaxLineEdit )->setText( QString::number( max ) );
mScalarColorRampShaderWidget->setMinimumMaximumAndClassify( min, 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 ) QgsMeshDatasetValue::QgsMeshDatasetValue( double x, double y )
: mX( x ), mY( y ) : mX( x ), mY( y )
{} {}
@ -144,14 +127,17 @@ bool QgsMeshDatasetValue::operator==( const QgsMeshDatasetValue &other ) const
return equal; return equal;
} }
QgsMeshDatasetGroupMetadata::QgsMeshDatasetGroupMetadata( QgsMeshDatasetGroupMetadata::QgsMeshDatasetGroupMetadata( const QString &name,
const QString &name, bool isScalar,
bool isScalar, bool isOnVertices,
bool isOnVertices, double minimum,
const QMap<QString, QString> &extraOptions ) double maximum,
const QMap<QString, QString> &extraOptions )
: mName( name ) : mName( name )
, mIsScalar( isScalar ) , mIsScalar( isScalar )
, mIsOnVertices( isOnVertices ) , mIsOnVertices( isOnVertices )
, mMinimumValue( minimum )
, mMaximumValue( maximum )
, mExtraOptions( extraOptions ) , mExtraOptions( extraOptions )
{ {
} }
@ -171,8 +157,6 @@ bool QgsMeshDatasetGroupMetadata::isScalar() const
return mIsScalar; return mIsScalar;
} }
QString QgsMeshDatasetGroupMetadata::name() const QString QgsMeshDatasetGroupMetadata::name() const
{ {
return mName; return mName;
@ -183,6 +167,16 @@ QgsMeshDatasetGroupMetadata::DataType QgsMeshDatasetGroupMetadata::dataType() co
return ( mIsOnVertices ) ? DataType::DataOnVertices : DataType::DataOnFaces; return ( mIsOnVertices ) ? DataType::DataOnVertices : DataType::DataOnFaces;
} }
double QgsMeshDatasetGroupMetadata::minimum() const
{
return mMinimumValue;
}
double QgsMeshDatasetGroupMetadata::maximum() const
{
return mMaximumValue;
}
int QgsMeshDatasetSourceInterface::datasetCount( QgsMeshDatasetIndex index ) const int QgsMeshDatasetSourceInterface::datasetCount( QgsMeshDatasetIndex index ) const
{ {
return datasetCount( index.group() ); return datasetCount( index.group() );
@ -194,9 +188,13 @@ QgsMeshDatasetGroupMetadata QgsMeshDatasetSourceInterface::datasetGroupMetadata(
} }
QgsMeshDatasetMetadata::QgsMeshDatasetMetadata( double time, QgsMeshDatasetMetadata::QgsMeshDatasetMetadata( double time,
bool isValid ) bool isValid,
double minimum,
double maximum )
: mTime( time ) : mTime( time )
, mIsValid( isValid ) , mIsValid( isValid )
, mMinimumValue( minimum )
, mMaximumValue( maximum )
{ {
} }
@ -209,3 +207,130 @@ bool QgsMeshDatasetMetadata::isValid() const
{ {
return mIsValid; 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 //! List of vertex indexes
typedef QVector<int> QgsMeshFace; 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 * \ingroup core
* *
@ -117,6 +142,90 @@ class CORE_EXPORT QgsMeshDatasetValue
double mY = std::numeric_limits<double>::quiet_NaN(); 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 * \ingroup core
* *
@ -147,11 +256,15 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata
* \param name name of the dataset group * \param name name of the dataset group
* \param isScalar dataset contains scalar data, specifically the y-value of QgsMeshDatasetValue is NaN * \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 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, ... * \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, QgsMeshDatasetGroupMetadata( const QString &name,
bool isScalar, bool isScalar,
bool isOnVertices, bool isOnVertices,
double minimum,
double maximum,
const QMap<QString, QString> &extraOptions ); const QMap<QString, QString> &extraOptions );
/** /**
@ -179,10 +292,22 @@ class CORE_EXPORT QgsMeshDatasetGroupMetadata
*/ */
DataType dataType() const; 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: private:
QString mName; QString mName;
bool mIsScalar = false; bool mIsScalar = false;
bool mIsOnVertices = false; bool mIsOnVertices = false;
double mMinimumValue = std::numeric_limits<double>::quiet_NaN();
double mMaximumValue = std::numeric_limits<double>::quiet_NaN();
QMap<QString, QString> mExtraOptions; QMap<QString, QString> mExtraOptions;
}; };
@ -209,7 +334,10 @@ class CORE_EXPORT QgsMeshDatasetMetadata
* \param isValid dataset is loadad and valid for fetching the data * \param isValid dataset is loadad and valid for fetching the data
*/ */
QgsMeshDatasetMetadata( double time, QgsMeshDatasetMetadata( double time,
bool isValid ); bool isValid,
double minimum,
double maximum
);
/** /**
* \brief Returns the time value for this dataset * \brief Returns the time value for this dataset
@ -221,9 +349,21 @@ class CORE_EXPORT QgsMeshDatasetMetadata
*/ */
bool isValid() const; 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: private:
double mTime = std::numeric_limits<double>::quiet_NaN(); double mTime = std::numeric_limits<double>::quiet_NaN();
bool mIsValid = false; 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; 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; virtual void populateMesh( QgsMesh *mesh ) const = 0;
/**
* Returns the mesh face at index
*/
virtual QgsMeshFace face( int index ) const = 0;
}; };
/** /**
@ -336,11 +472,22 @@ class CORE_EXPORT QgsMeshDatasetSourceInterface SIP_ABSTRACT
/** /**
* \brief Returns vector/scalar value associated with the index from the dataset * \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; 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 * \brief Returns whether the face is active for particular dataset
* *
@ -352,6 +499,13 @@ class CORE_EXPORT QgsMeshDatasetSourceInterface SIP_ABSTRACT
* V3 ---- V4 ---- V6-----V8 * V3 ---- V4 ---- V6-----V8
*/ */
virtual bool isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const = 0; 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 //! Ctor
QgsMeshDataProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options ); 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: signals:
//! Emitted when some new dataset groups have been added //! Emitted when some new dataset groups have been added
void datasetGroupsAdded( int count ); void datasetGroupsAdded( int count );

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -17,103 +17,22 @@
#include "qgsmeshlayerutils.h" #include "qgsmeshlayerutils.h"
#include "qgsmeshdataprovider.h"
#include <limits> #include <limits>
///@cond PRIVATE ///@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 ) for ( int i = 0; i < count; ++i )
{ {
double dMin, dMax; double mag = block.value( i ).scalar();
calculateMinMaxForDataset( dMin, dMax, provider, QgsMeshDatasetIndex( groupIndex, i ) ); ret[i] = mag;
min = std::min( min, dMin );
max = std::max( max, dMax );
} }
} return ret;
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;
}
}
}
} }
void QgsMeshLayerUtils::boundingBoxToScreenRectangle( const QgsMapToPixel &mtp, void QgsMeshLayerUtils::boundingBoxToScreenRectangle( const QgsMapToPixel &mtp,

View File

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

View File

@ -17,6 +17,9 @@
///@cond PRIVATE ///@cond PRIVATE
#include "qgsmeshmemorydataprovider.h" #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_KEY = QStringLiteral( "mesh_memory" );
static const QString TEXT_PROVIDER_DESCRIPTION = QStringLiteral( "Mesh memory provider" ); static const QString TEXT_PROVIDER_DESCRIPTION = QStringLiteral( "Mesh memory provider" );
@ -299,16 +302,18 @@ int QgsMeshMemoryDataProvider::faceCount() const
return mFaces.size(); return mFaces.size();
} }
QgsMeshVertex QgsMeshMemoryDataProvider::vertex( int index ) const void QgsMeshMemoryDataProvider::populateMesh( QgsMesh *mesh ) const
{ {
Q_ASSERT( vertexCount() > index ); if ( mesh )
return mVertices[index]; {
mesh->faces = mFaces;
mesh->vertices = mVertices;
}
} }
QgsMeshFace QgsMeshMemoryDataProvider::face( int index ) const QgsRectangle QgsMeshMemoryDataProvider::extent() const
{ {
Q_ASSERT( faceCount() > index ); return calculateExtent( );
return mFaces[index];
} }
bool QgsMeshMemoryDataProvider::addDataset( const QString &uri ) bool QgsMeshMemoryDataProvider::addDataset( const QString &uri )
@ -326,6 +331,7 @@ bool QgsMeshMemoryDataProvider::addDataset( const QString &uri )
QStringLiteral( "Mesh Memory Provider" ) ) ); QStringLiteral( "Mesh Memory Provider" ) ) );
} }
calculateMinMaxForDatasetGroup( group );
mDatasetGroups.push_back( group ); mDatasetGroups.push_back( group );
if ( valid ) if ( valid )
@ -364,6 +370,8 @@ QgsMeshDatasetGroupMetadata QgsMeshMemoryDataProvider::datasetGroupMetadata( int
mDatasetGroups[groupIndex].name, mDatasetGroups[groupIndex].name,
mDatasetGroups[groupIndex].isScalar, mDatasetGroups[groupIndex].isScalar,
mDatasetGroups[groupIndex].isOnVertices, mDatasetGroups[groupIndex].isOnVertices,
mDatasetGroups[groupIndex].minimum,
mDatasetGroups[groupIndex].maximum,
mDatasetGroups[groupIndex].metadata mDatasetGroups[groupIndex].metadata
); );
return metadata; return metadata;
@ -383,7 +391,9 @@ QgsMeshDatasetMetadata QgsMeshMemoryDataProvider::datasetMetadata( QgsMeshDatase
const QgsMeshMemoryDatasetGroup &grp = mDatasetGroups.at( index.group() ); const QgsMeshMemoryDatasetGroup &grp = mDatasetGroups.at( index.group() );
QgsMeshDatasetMetadata metadata( QgsMeshDatasetMetadata metadata(
grp.datasets[index.dataset()].time, 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; 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 bool QgsMeshMemoryDataProvider::isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const
{ {
Q_UNUSED( index ); Q_UNUSED( index );
@ -414,5 +444,83 @@ bool QgsMeshMemoryDataProvider::isFaceActive( QgsMeshDatasetIndex index, int fac
return true; 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 ///@endcond

View File

@ -34,6 +34,8 @@ struct QgsMeshMemoryDataset
QVector<QgsMeshDatasetValue> values; QVector<QgsMeshDatasetValue> values;
double time = -1; double time = -1;
bool valid = false; bool valid = false;
double minimum = std::numeric_limits<double>::quiet_NaN();
double maximum = std::numeric_limits<double>::quiet_NaN();
}; };
struct QgsMeshMemoryDatasetGroup struct QgsMeshMemoryDatasetGroup
@ -43,6 +45,8 @@ struct QgsMeshMemoryDatasetGroup
QString name; QString name;
bool isScalar = true; bool isScalar = true;
bool isOnVertices = 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 vertexCount() const override;
int faceCount() const override; int faceCount() const override;
QgsMeshVertex vertex( int index ) const override; void populateMesh( QgsMesh *mesh ) const override;
QgsMeshFace face( int index ) const override; QgsRectangle extent() const override;
/** /**
* Adds dataset to a mesh in-memory data provider from data string * 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; QgsMeshDatasetGroupMetadata datasetGroupMetadata( int groupIndex ) const override;
QgsMeshDatasetMetadata datasetMetadata( QgsMeshDatasetIndex index ) const override; QgsMeshDatasetMetadata datasetMetadata( QgsMeshDatasetIndex index ) const override;
QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) 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; bool isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const override;
QgsMeshDataBlock areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const override;
//! Returns the memory provider key //! Returns the memory provider key
static QString providerKey(); static QString providerKey();
@ -136,7 +141,12 @@ class QgsMeshMemoryDataProvider: public QgsMeshDataProvider
static QString providerDescription(); static QString providerDescription();
//! Provider factory //! Provider factory
static QgsMeshMemoryDataProvider *createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options ); static QgsMeshMemoryDataProvider *createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options );
private: private:
void calculateMinMaxForDatasetGroup( QgsMeshMemoryDatasetGroup &grp ) const;
void calculateMinMaxForDataset( QgsMeshMemoryDataset &dataset ) const;
QgsRectangle calculateExtent( ) const;
bool splitMeshSections( const QString &uri ); bool splitMeshSections( const QString &uri );
bool addMeshVertices( const QString &def ); bool addMeshVertices( const QString &def );
bool addMeshFaces( 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, QgsMeshVectorRenderer::QgsMeshVectorRenderer( const QgsTriangularMesh &m,
const QVector<double> &datasetValuesX, const QgsMeshDataBlock &datasetValues,
const QVector<double> &datasetValuesY,
const QVector<double> &datasetValuesMag, const QVector<double> &datasetValuesMag,
double datasetMagMinimumValue, double datasetMagMinimumValue,
double datasetMagMaximumValue, double datasetMagMaximumValue,
@ -55,8 +54,7 @@ QgsMeshVectorRenderer::QgsMeshVectorRenderer( const QgsTriangularMesh &m,
const QgsMeshRendererVectorSettings &settings, const QgsMeshRendererVectorSettings &settings,
QgsRenderContext &context, QSize size ) QgsRenderContext &context, QSize size )
: mTriangularMesh( m ) : mTriangularMesh( m )
, mDatasetValuesX( datasetValuesX ) , mDatasetValues( datasetValues )
, mDatasetValuesY( datasetValuesY )
, mDatasetValuesMag( datasetValuesMag ) , mDatasetValuesMag( datasetValuesMag )
, mMinMag( datasetMagMinimumValue ) , mMinMag( datasetMagMinimumValue )
, mMaxMag( datasetMagMaximumValue ) , mMaxMag( datasetMagMaximumValue )
@ -70,6 +68,8 @@ QgsMeshVectorRenderer::QgsMeshVectorRenderer( const QgsTriangularMesh &m,
Q_ASSERT( !mDatasetValuesMag.empty() ); Q_ASSERT( !mDatasetValuesMag.empty() );
Q_ASSERT( !std::isnan( mMinMag ) ); Q_ASSERT( !std::isnan( mMinMag ) );
Q_ASSERT( !std::isnan( mMaxMag ) ); 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 // we need to expand out the extent so that it includes
// arrows which start or end up outside of the // arrows which start or end up outside of the
@ -259,8 +259,9 @@ void QgsMeshVectorRenderer::drawVectorDataOnVertices( const QList<int> &triangle
if ( !mBufferedExtent.contains( vertex ) ) if ( !mBufferedExtent.contains( vertex ) )
continue; continue;
double xVal = mDatasetValuesX[i]; const QgsMeshDatasetValue val = mDatasetValues.value( i );
double yVal = mDatasetValuesY[i]; double xVal = val.x();
double yVal = val.y();
if ( nodataValue( xVal, yVal ) ) if ( nodataValue( xVal, yVal ) )
continue; continue;
@ -286,8 +287,9 @@ void QgsMeshVectorRenderer::drawVectorDataOnFaces( const QList<int> &trianglesIn
if ( !mBufferedExtent.contains( center ) ) if ( !mBufferedExtent.contains( center ) )
continue; continue;
double xVal = mDatasetValuesX[i]; const QgsMeshDatasetValue val = mDatasetValues.value( i );
double yVal = mDatasetValuesY[i]; double xVal = val.x();
double yVal = val.y();
if ( nodataValue( xVal, yVal ) ) if ( nodataValue( xVal, yVal ) )
continue; continue;
@ -342,36 +344,40 @@ void QgsMeshVectorRenderer::drawVectorDataOnGrid( const QList<int> &trianglesInE
if ( mDataOnVertices ) if ( mDataOnVertices )
{ {
const auto val1 = mDatasetValues.value( v1 );
const auto val2 = mDatasetValues.value( v2 );
const auto val3 = mDatasetValues.value( v3 );
val.setX( val.setX(
QgsMeshLayerUtils::interpolateFromVerticesData( QgsMeshLayerUtils::interpolateFromVerticesData(
p1, p2, p3, p1, p2, p3,
mDatasetValuesX[v1], val1.x(),
mDatasetValuesX[v2], val2.x(),
mDatasetValuesX[v3], val3.x(),
p ) p )
); );
val.setY( val.setY(
QgsMeshLayerUtils::interpolateFromVerticesData( QgsMeshLayerUtils::interpolateFromVerticesData(
p1, p2, p3, p1, p2, p3,
mDatasetValuesY[v1], val1.y(),
mDatasetValuesY[v2], val2.y(),
mDatasetValuesY[v3], val3.y(),
p ) p )
); );
} }
else else
{ {
const auto val1 = mDatasetValues.value( nativeFaceIndex );
val.setX( val.setX(
QgsMeshLayerUtils::interpolateFromFacesData( QgsMeshLayerUtils::interpolateFromFacesData(
p1, p2, p3, p1, p2, p3,
mDatasetValuesX[nativeFaceIndex], val1.x(),
p p
) )
); );
val.setY( val.setY(
QgsMeshLayerUtils::interpolateFromFacesData( QgsMeshLayerUtils::interpolateFromFacesData(
p1, p2, p3, p1, p2, p3,
mDatasetValuesY[nativeFaceIndex], val1.y(),
p p
) )
); );

View File

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

View File

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

View File

@ -18,6 +18,7 @@
#include <string> #include <string>
#include "qgsmdalprovider.h" #include "qgsmdalprovider.h"
#include "qgstriangularmesh.h"
#ifdef HAVE_GUI #ifdef HAVE_GUI
#include "qgssourceselectprovider.h" #include "qgssourceselectprovider.h"
@ -82,26 +83,91 @@ int QgsMdalProvider::faceCount() const
return 0; return 0;
} }
QgsMeshVertex QgsMdalProvider::vertex( int index ) const void QgsMdalProvider::populateMesh( QgsMesh *mesh ) const
{ {
Q_ASSERT( index < vertexCount() ); if ( mesh )
double x = MDAL_M_vertexXCoordinatesAt( mMeshH, index ); {
double y = MDAL_M_vertexYCoordinatesAt( mMeshH, index ); mesh->faces = faces();
QgsMeshVertex vertex( x, y ); mesh->vertices = vertices();
return vertex; }
} }
QgsMeshFace QgsMdalProvider::face( int index ) const QVector<QgsMeshVertex> QgsMdalProvider::vertices( ) const
{ {
Q_ASSERT( index < faceCount() ); const int bufferSize = std::min( vertexCount(), 1000 );
QgsMeshFace face; QVector<QgsMeshVertex> ret( vertexCount() );
int n_face_vertices = MDAL_M_faceVerticesCountAt( mMeshH, index ); QVector<double> buffer( bufferSize * 3 );
for ( int j = 0; j < n_face_vertices; ++j ) MeshVertexIteratorH it = MDAL_M_vertexIterator( mMeshH );
int vertexIndex = 0;
while ( vertexIndex < vertexCount() )
{ {
int vertex_index = MDAL_M_faceVerticesIndexAt( mMeshH, index, j ); int verticesRead = MDAL_VI_next( it, bufferSize, buffer.data() );
face.push_back( vertex_index ); 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 isScalar = MDAL_G_hasScalarData( group );
bool isOnVertices = MDAL_G_isOnVertices( group ); bool isOnVertices = MDAL_G_isOnVertices( group );
QString name = MDAL_G_name( group ); QString name = MDAL_G_name( group );
double min, max;
MDAL_G_minimumMaximum( group, &min, &max );
QMap<QString, QString> metadata; QMap<QString, QString> metadata;
int n = MDAL_G_metadataCount( group ); int n = MDAL_G_metadataCount( group );
@ -169,6 +237,8 @@ QgsMeshDatasetGroupMetadata QgsMdalProvider::datasetGroupMetadata( int groupInde
name, name,
isScalar, isScalar,
isOnVertices, isOnVertices,
min,
max,
metadata metadata
); );
@ -187,10 +257,14 @@ QgsMeshDatasetMetadata QgsMdalProvider::datasetMetadata( QgsMeshDatasetIndex ind
bool isValid = MDAL_D_isValid( dataset ); bool isValid = MDAL_D_isValid( dataset );
double time = MDAL_D_time( dataset ); double time = MDAL_D_time( dataset );
double min, max;
MDAL_D_minimumMaximum( dataset, &min, &max );
QgsMeshDatasetMetadata meta( QgsMeshDatasetMetadata meta(
time, time,
isValid isValid,
min,
max
); );
return meta; return meta;
@ -198,41 +272,58 @@ QgsMeshDatasetMetadata QgsMdalProvider::datasetMetadata( QgsMeshDatasetIndex ind
} }
QgsMeshDatasetValue QgsMdalProvider::datasetValue( QgsMeshDatasetIndex index, int valueIndex ) const 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() ); DatasetGroupH group = MDAL_M_datasetGroup( mMeshH, index.group() );
if ( !group ) if ( !group )
return QgsMeshDatasetValue(); return QgsMeshDataBlock();
DatasetH dataset = MDAL_G_dataset( group, index.dataset() ); DatasetH dataset = MDAL_G_dataset( group, index.dataset() );
if ( !dataset ) if ( !dataset )
return QgsMeshDatasetValue(); return QgsMeshDataBlock();
QgsMeshDatasetValue val; bool isScalar = MDAL_G_hasScalarData( group );
if ( MDAL_G_hasScalarData( group ) ) QgsMeshDataBlock ret( isScalar ? QgsMeshDataBlock::ScalarDouble : QgsMeshDataBlock::Vector2DDouble, count );
{ int valRead = MDAL_D_data( dataset,
val.setX( MDAL_D_value( dataset, valueIndex ) ); valueIndex,
} count,
else isScalar ? MDAL_DataType::SCALAR_DOUBLE : MDAL_DataType::VECTOR_2D_DOUBLE,
{ ret.buffer() );
val.setX( MDAL_D_valueX( dataset, valueIndex ) ); if ( valRead != count )
val.setY( MDAL_D_valueY( dataset, valueIndex ) ); return QgsMeshDataBlock();
}
return val; return ret;
} }
bool QgsMdalProvider::isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const 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() ); DatasetGroupH group = MDAL_M_datasetGroup( mMeshH, index.group() );
if ( !group ) if ( !group )
return false; return QgsMeshDataBlock();
DatasetH dataset = MDAL_G_dataset( group, index.dataset() ); DatasetH dataset = MDAL_G_dataset( group, index.dataset() );
if ( !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 vertexCount() const override;
int faceCount() const override; int faceCount() const override;
QgsMeshVertex vertex( int index ) const override; void populateMesh( QgsMesh *mesh ) const override;
QgsMeshFace face( int index ) const override;
bool addDataset( const QString &uri ) override; bool addDataset( const QString &uri ) override;
QStringList extraDatasets() const override; QStringList extraDatasets() const override;
@ -65,9 +64,14 @@ class QgsMdalProvider : public QgsMeshDataProvider
QgsMeshDatasetGroupMetadata datasetGroupMetadata( int groupIndex ) const override; QgsMeshDatasetGroupMetadata datasetGroupMetadata( int groupIndex ) const override;
QgsMeshDatasetMetadata datasetMetadata( QgsMeshDatasetIndex index ) const override; QgsMeshDatasetMetadata datasetMetadata( QgsMeshDatasetIndex index ) const override;
QgsMeshDatasetValue datasetValue( QgsMeshDatasetIndex index, int valueIndex ) 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; bool isFaceActive( QgsMeshDatasetIndex index, int faceIndex ) const override;
QgsMeshDataBlock areFacesActive( QgsMeshDatasetIndex index, int faceIndex, int count ) const override;
QgsRectangle extent() const override;
private: private:
QVector<QgsMeshVertex> vertices( ) const;
QVector<QgsMeshFace> faces( ) const;
MeshH mMeshH; MeshH mMeshH;
QStringList mExtraDatasetUris; QStringList mExtraDatasetUris;
QgsCoordinateReferenceSystem mCrs; QgsCoordinateReferenceSystem mCrs;

View File

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