mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[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:
parent
d43f6376eb
commit
28071728f1
@ -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:
|
||||
|
@ -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 );
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 );
|
||||
|
@ -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
|
||||
)
|
||||
);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------------------------*/
|
||||
|
@ -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;
|
||||
|
@ -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 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user