mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE] Rendering of vector data on mesh layers
Rudimentary support of rendering of vector data (e.g. velocity) on mesh map layers. Rendering can be adjusted by QgsMeshRenderer*Settings. Only in Python API, no GUI widgets for styling present.
This commit is contained in:
parent
9296528822
commit
aea3dccea7
@ -36,19 +36,64 @@ support of nodata values
|
||||
public:
|
||||
QgsMeshDatasetValue( double x,
|
||||
double y );
|
||||
%Docstring
|
||||
Ctor
|
||||
%End
|
||||
|
||||
QgsMeshDatasetValue( double scalar );
|
||||
%Docstring
|
||||
Ctor
|
||||
%End
|
||||
|
||||
QgsMeshDatasetValue( );
|
||||
%Docstring
|
||||
Ctor
|
||||
%End
|
||||
|
||||
~QgsMeshDatasetValue();
|
||||
|
||||
void setNodata( bool nodata = true );
|
||||
%Docstring
|
||||
Sets nodata value for this dataset value
|
||||
%End
|
||||
bool isNodata() const;
|
||||
%Docstring
|
||||
Returns whether it is nodata value
|
||||
%End
|
||||
bool isScalar() const;
|
||||
double scalar() const; //length for vectors, value for scalars
|
||||
%Docstring
|
||||
Returns whether it is scalar value
|
||||
%End
|
||||
double scalar() const;
|
||||
%Docstring
|
||||
Returns scalar value. Length for vectors, value for scalars
|
||||
%End
|
||||
|
||||
void set( double scalar );
|
||||
%Docstring
|
||||
Sets scalar value
|
||||
%End
|
||||
|
||||
void setX( double x );
|
||||
%Docstring
|
||||
Sets X value
|
||||
%End
|
||||
|
||||
void setY( double y );
|
||||
%Docstring
|
||||
Sets Y value
|
||||
%End
|
||||
|
||||
double x() const;
|
||||
%Docstring
|
||||
Returns x value
|
||||
%End
|
||||
|
||||
double y() const;
|
||||
%Docstring
|
||||
Returns y value
|
||||
%End
|
||||
|
||||
bool operator==( const QgsMeshDatasetValue &other ) const;
|
||||
|
||||
};
|
||||
@ -78,14 +123,14 @@ read on demand
|
||||
|
||||
virtual int vertexCount() const = 0;
|
||||
%Docstring
|
||||
Return number of vertices in the native mesh
|
||||
Returns number of vertices in the native mesh
|
||||
|
||||
:return: Number of vertices in the mesh
|
||||
%End
|
||||
|
||||
virtual int faceCount() const = 0;
|
||||
%Docstring
|
||||
Return number of faces in the native mesh
|
||||
Returns number of faces in the native mesh
|
||||
|
||||
:return: Number of faces in the mesh
|
||||
%End
|
||||
@ -94,7 +139,7 @@ read on demand
|
||||
%Docstring
|
||||
Factory for mesh vertex with index
|
||||
|
||||
:return: new mesh vertex on index
|
||||
:return: New mesh vertex on index
|
||||
%End
|
||||
|
||||
virtual QgsMeshFace face( int index ) const = 0;
|
||||
@ -133,32 +178,32 @@ read on demand
|
||||
|
||||
virtual int datasetCount() const = 0;
|
||||
%Docstring
|
||||
Return number of datasets loaded
|
||||
Returns number of datasets loaded
|
||||
%End
|
||||
|
||||
virtual bool datasetHasScalarData( int index ) const = 0;
|
||||
%Docstring
|
||||
Whether dataset has scalar data associated
|
||||
Returns whether dataset has scalar data associated
|
||||
%End
|
||||
|
||||
virtual bool datasetIsOnVertices( int index ) const = 0;
|
||||
%Docstring
|
||||
Whether dataset is on vertices
|
||||
Returns whether dataset is on vertices
|
||||
%End
|
||||
|
||||
virtual QgsMeshDatasetMetadata datasetMetadata( int index ) const = 0;
|
||||
%Docstring
|
||||
Return dataset metadata
|
||||
Returns dataset metadata
|
||||
%End
|
||||
|
||||
virtual QgsMeshDatasetValue datasetValue( int datasetIndex, int valueIndex ) const = 0;
|
||||
%Docstring
|
||||
Return value associated with the index from the dataset
|
||||
Returns value associated with the index from the dataset
|
||||
%End
|
||||
|
||||
virtual bool datasetIsValid( int index ) const = 0;
|
||||
%Docstring
|
||||
Return whether dataset is valid
|
||||
Returns whether dataset is valid
|
||||
%End
|
||||
};
|
||||
|
||||
|
@ -52,8 +52,6 @@ E.g. to create mesh with one quad and one triangle
|
||||
);
|
||||
QgsMeshLayer *scratchLayer = new QgsMeshLayer(uri, "My Scratch layer", "memory_mesh");
|
||||
|
||||
Add datasets by adding them through data provider, :py:func:`QgsMeshDatasetSource.addDataset`
|
||||
|
||||
\subsection mdal MDAL data provider (mdal)
|
||||
|
||||
Accesses data using the MDAL drivers (https://github.com/lutraconsulting/MDAL). The url
|
||||
@ -118,32 +116,68 @@ QgsMeshLayer cannot be copied.
|
||||
|
||||
QString providerType() const;
|
||||
%Docstring
|
||||
Return the provider type for this layer
|
||||
Returns the provider type for this layer
|
||||
%End
|
||||
|
||||
|
||||
|
||||
QgsSymbol *nativeMeshSymbol();
|
||||
QgsMeshRendererMeshSettings rendererNativeMeshSettings() const /Factory/;
|
||||
%Docstring
|
||||
Returns a line symbol used for rendering native mesh.
|
||||
Returns rendrer settings
|
||||
%End
|
||||
|
||||
QgsSymbol *triangularMeshSymbol();
|
||||
void setRendererNativeMeshSettings( const QgsMeshRendererMeshSettings &settings );
|
||||
%Docstring
|
||||
Returns a line symbol used for rendering of triangular (derived) mesh.
|
||||
|
||||
.. seealso:: :py:func:`toggleTriangularMeshRendering`
|
||||
Sets new rendering settings, triggers repaint
|
||||
%End
|
||||
|
||||
void toggleTriangularMeshRendering( bool toggle );
|
||||
QgsMeshRendererMeshSettings rendererTriangularMeshSettings() const /Factory/;
|
||||
%Docstring
|
||||
Toggle rendering of triangular (derived) mesh. Off by default
|
||||
Returns rendrer settings
|
||||
%End
|
||||
|
||||
void setRendererTriangularMeshSettings( const QgsMeshRendererMeshSettings &settings );
|
||||
%Docstring
|
||||
Sets new rendering settings, triggers repaint
|
||||
%End
|
||||
|
||||
QgsMeshRendererScalarSettings rendererScalarSettings() const /Factory/;
|
||||
%Docstring
|
||||
Returns rendrer settings
|
||||
%End
|
||||
|
||||
void setRendererScalarSettings( const QgsMeshRendererScalarSettings &settings );
|
||||
%Docstring
|
||||
Sets new rendering settings, triggers repaint
|
||||
%End
|
||||
|
||||
QgsMeshRendererVectorSettings rendererVectorSettings() const /Factory/;
|
||||
%Docstring
|
||||
Returns rendrer settings
|
||||
%End
|
||||
|
||||
void setRendererVectorSettings( const QgsMeshRendererVectorSettings &settings );
|
||||
%Docstring
|
||||
Sets new rendering settings, triggers repaint
|
||||
%End
|
||||
|
||||
void setActiveScalarDataset( int index = -1 );
|
||||
void setActiveVectorDataset( int index = -1 );
|
||||
|
||||
%Docstring
|
||||
Sets active scalar dataset for rendering
|
||||
%End
|
||||
int activeScalarDataset() const;
|
||||
%Docstring
|
||||
Returns active scalar dataset
|
||||
%End
|
||||
|
||||
void setActiveVectorDataset( int index = -1 );
|
||||
%Docstring
|
||||
Sets active vector dataset for rendering. If dataset is not vector based, do nothing
|
||||
%End
|
||||
int activeVectorDataset() const;
|
||||
%Docstring
|
||||
Returns active vector dataset
|
||||
%End
|
||||
|
||||
private: // Private methods
|
||||
QgsMeshLayer( const QgsMeshLayer &rhs );
|
||||
|
282
python/core/auto_generated/mesh/qgsmeshrenderersettings.sip.in
Normal file
282
python/core/auto_generated/mesh/qgsmeshrenderersettings.sip.in
Normal file
@ -0,0 +1,282 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/mesh/qgsmeshrenderersettings.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsMeshRendererMeshSettings
|
||||
{
|
||||
%Docstring
|
||||
|
||||
Represents a mesh renderer settings for mesh object
|
||||
|
||||
.. note::
|
||||
|
||||
The API is considered EXPERIMENTAL and can be changed without a notice
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsmeshrenderersettings.h"
|
||||
%End
|
||||
public:
|
||||
bool isEnabled() const;
|
||||
%Docstring
|
||||
Returns whether mesh structure rendering is enabled
|
||||
%End
|
||||
void setEnabled( bool enabled );
|
||||
%Docstring
|
||||
Sets whether mesh structure rendering is enabled
|
||||
%End
|
||||
|
||||
double lineWidth() const;
|
||||
%Docstring
|
||||
Returns line width used for rendering (in millimeters)
|
||||
%End
|
||||
void setLineWidth( double lineWidth );
|
||||
%Docstring
|
||||
Sets line width used for rendering (in millimeters)
|
||||
%End
|
||||
|
||||
QColor color() const;
|
||||
%Docstring
|
||||
Returns color used for rendering
|
||||
%End
|
||||
void setColor( const QColor &color );
|
||||
%Docstring
|
||||
Sets color used for rendering of the mesh
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
class QgsMeshRendererScalarSettings
|
||||
{
|
||||
%Docstring
|
||||
|
||||
Represents a mesh renderer settings for scalar datasets
|
||||
|
||||
.. note::
|
||||
|
||||
The API is considered EXPERIMENTAL and can be changed without a notice
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsmeshrenderersettings.h"
|
||||
%End
|
||||
public:
|
||||
QColor maxColor() const;
|
||||
%Docstring
|
||||
Returns color representing maximum scalar value in the dataset
|
||||
%End
|
||||
void setMaxColor( const QColor &maxColor );
|
||||
%Docstring
|
||||
Sets color representing maximum scalar value in the dataset
|
||||
%End
|
||||
|
||||
QColor minColor() const;
|
||||
%Docstring
|
||||
Returns color representing minimum scalar value in the dataset
|
||||
%End
|
||||
void setMinColor( const QColor &minColor );
|
||||
%Docstring
|
||||
Sets color representing maximum scalar value in the dataset
|
||||
%End
|
||||
|
||||
double minValue() const;
|
||||
%Docstring
|
||||
Returns min scalar value that represents minColor()
|
||||
|
||||
if set to numerical_limits<double>.quiet_NaN(), value for minColor() is
|
||||
taken from minimum value of active scalar dataset
|
||||
%End
|
||||
|
||||
void setMinValue( double minValue );
|
||||
%Docstring
|
||||
Sets min scalar value that represents minColor()
|
||||
|
||||
.. seealso:: :py:func:`QgsMeshRendererScalarSettings.minValue`
|
||||
%End
|
||||
|
||||
double maxValue() const;
|
||||
%Docstring
|
||||
Returns max scalar value that represents maxColor()
|
||||
|
||||
if set to numerical_limits<double>.quiet_NaN(), value for maxColor() is
|
||||
taken from maximum value of active scalar dataset
|
||||
%End
|
||||
|
||||
void setMaxValue( double maxValue );
|
||||
%Docstring
|
||||
Sets min scalar value that represents minColor()
|
||||
|
||||
.. seealso:: :py:func:`QgsMeshRendererScalarSettings.maxValue`
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
class QgsMeshRendererVectorSettings
|
||||
{
|
||||
%Docstring
|
||||
|
||||
Represents a mesh renderer settings for vector datasets
|
||||
|
||||
.. note::
|
||||
|
||||
The API is considered EXPERIMENTAL and can be changed without a notice
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsmeshrenderersettings.h"
|
||||
%End
|
||||
public:
|
||||
enum VectorRenderingType
|
||||
{
|
||||
|
||||
MinMax,
|
||||
|
||||
Scaled,
|
||||
|
||||
Fixed
|
||||
};
|
||||
|
||||
double lineWidth() const;
|
||||
%Docstring
|
||||
Returns line width of the arrow (in millimeters)
|
||||
%End
|
||||
void setLineWidth( double lineWidth );
|
||||
%Docstring
|
||||
Sets line width of the arrow in pixels (in millimeters)
|
||||
%End
|
||||
|
||||
QColor color() const;
|
||||
%Docstring
|
||||
Returns color used for drawing arrows
|
||||
%End
|
||||
void setColor( const QColor &color );
|
||||
%Docstring
|
||||
Sets color used for drawing arrows
|
||||
%End
|
||||
|
||||
double filterMin() const;
|
||||
%Docstring
|
||||
Returns filter value for vector magnitudes.
|
||||
|
||||
If magnitude of the vector is lower than this value, the vector is not
|
||||
drawn. -1 represents that filtering is not active.
|
||||
%End
|
||||
|
||||
void setFilterMin( double filterMin );
|
||||
%Docstring
|
||||
Sets filter value for vector magnitudes.
|
||||
|
||||
.. seealso:: :py:func:`QgsMeshRendererVectorSettings.vectorFilterMin`
|
||||
%End
|
||||
|
||||
double filterMax() const;
|
||||
%Docstring
|
||||
Returns filter value for vector magnitudes.
|
||||
|
||||
If magnitude of the vector is higher than this value, the vector is not
|
||||
drawn. -1 represents that filtering is not active.
|
||||
%End
|
||||
|
||||
void setFilterMax( double filterMax );
|
||||
%Docstring
|
||||
Sets filter value for vector magnitudes.
|
||||
|
||||
.. seealso:: :py:func:`QgsMeshRendererVectorSettings.vectorFilterMax`
|
||||
%End
|
||||
|
||||
QgsMeshRendererVectorSettings::VectorRenderingType shaftLengthMethod() const;
|
||||
%Docstring
|
||||
Returns method used for drawing arrows
|
||||
%End
|
||||
void setShaftLengthMethod( const QgsMeshRendererVectorSettings::VectorRenderingType &shaftLengthMethod );
|
||||
%Docstring
|
||||
Sets method used for drawing arrows
|
||||
%End
|
||||
|
||||
double minShaftLength() const;
|
||||
%Docstring
|
||||
Returns mininimum shaft length (in millimeters)
|
||||
|
||||
Only for QgsMeshRendererVectorSettings.ArrowType.MinMax
|
||||
%End
|
||||
|
||||
void setMinShaftLength( double minShaftLength );
|
||||
%Docstring
|
||||
Sets mininimum shaft length (in millimeters)
|
||||
|
||||
Only for QgsMeshRendererVectorSettings.ArrowType.MinMax
|
||||
%End
|
||||
|
||||
double maxShaftLength() const;
|
||||
%Docstring
|
||||
Returns maximum shaft length (in millimeters)
|
||||
|
||||
Only for QgsMeshRendererVectorSettings.ArrowType.MinMax
|
||||
%End
|
||||
|
||||
void setMaxShaftLength( double maxShaftLength );
|
||||
%Docstring
|
||||
Sets maximum shaft length (in millimeters)
|
||||
|
||||
Only for QgsMeshRendererVectorSettings.ArrowType.MinMax
|
||||
%End
|
||||
|
||||
double scaleFactor() const;
|
||||
%Docstring
|
||||
Returns scale factor. Only for QgsMeshRendererVectorSettings.ArrowType.Scaled
|
||||
%End
|
||||
void setScaleFactor( double scaleFactor );
|
||||
%Docstring
|
||||
Sets scale factor. Only for QgsMeshRendererVectorSettings.ArrowType.Scaled
|
||||
%End
|
||||
|
||||
double fixedShaftLength() const;
|
||||
%Docstring
|
||||
Returns fixed arrow length (in millimeters). Only for QgsMeshRendererVectorSettings.ArrowType.Fixed
|
||||
%End
|
||||
void setFixedShaftLength( double fixedShaftLength );
|
||||
%Docstring
|
||||
Sets fixed length (in millimeters). Only for QgsMeshRendererVectorSettings.ArrowType.Fixed
|
||||
%End
|
||||
|
||||
double arrowHeadWidthRatio() const;
|
||||
%Docstring
|
||||
Returns ratio of the head width of the arrow (range 0-1)
|
||||
%End
|
||||
void setArrowHeadWidthRatio( double arrowHeadWidthRatio );
|
||||
%Docstring
|
||||
Sets ratio of the head width of the arrow (range 0-1)
|
||||
%End
|
||||
|
||||
double arrowHeadLengthRatio() const;
|
||||
%Docstring
|
||||
Returns ratio of the head length of the arrow (range 0-1)
|
||||
%End
|
||||
void setArrowHeadLengthRatio( double arrowHeadLengthRatio );
|
||||
%Docstring
|
||||
Sets ratio of the head length of the arrow (range 0-1)
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/mesh/qgsmeshrenderersettings.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -1,4 +1,3 @@
|
||||
// Include auto-generated SIP files
|
||||
%Include auto_generated/expression/qgsexpression.sip
|
||||
%Include auto_generated/expression/qgsexpressionnode.sip
|
||||
%Include auto_generated/expression/qgsexpressionnodeimpl.sip
|
||||
@ -381,6 +380,7 @@
|
||||
%Include auto_generated/raster/qgsrasterprojector.sip
|
||||
%Include auto_generated/mesh/qgsmeshdataprovider.sip
|
||||
%Include auto_generated/mesh/qgsmeshlayer.sip
|
||||
%Include auto_generated/mesh/qgsmeshrenderersettings.sip
|
||||
%Include auto_generated/geometry/qgsabstractgeometry.sip
|
||||
%Include auto_generated/geometry/qgsgeometry.sip
|
||||
%Include auto_generated/geometry/qgspoint.sip
|
||||
|
@ -454,6 +454,8 @@ SET(QGIS_CORE_SRCS
|
||||
mesh/qgsmeshmemorydataprovider.cpp
|
||||
mesh/qgstriangularmesh.cpp
|
||||
mesh/qgsmeshlayerinterpolator.cpp
|
||||
mesh/qgsmeshvectorrenderer.cpp
|
||||
mesh/qgsmeshrenderersettings.cpp
|
||||
|
||||
geometry/qgsabstractgeometry.cpp
|
||||
geometry/qgsbox3d.cpp
|
||||
@ -1077,6 +1079,8 @@ SET(QGIS_CORE_HDRS
|
||||
mesh/qgstriangularmesh.h
|
||||
mesh/qgsmeshlayerrenderer.h
|
||||
mesh/qgsmeshlayerinterpolator.h
|
||||
mesh/qgsmeshvectorrenderer.h
|
||||
mesh/qgsmeshrenderersettings.h
|
||||
|
||||
scalebar/qgsdoubleboxscalebarrenderer.h
|
||||
scalebar/qgsnumericscalebarrenderer.h
|
||||
|
@ -52,21 +52,44 @@ class CORE_EXPORT QgsMeshDatasetValue
|
||||
Q_GADGET
|
||||
|
||||
public:
|
||||
//! Ctor
|
||||
QgsMeshDatasetValue( double x,
|
||||
double y );
|
||||
|
||||
//! Ctor
|
||||
QgsMeshDatasetValue( double scalar );
|
||||
|
||||
//! Ctor
|
||||
QgsMeshDatasetValue( ) = default;
|
||||
|
||||
//! Dtor
|
||||
~QgsMeshDatasetValue() = default;
|
||||
|
||||
//! Sets nodata value for this dataset value
|
||||
void setNodata( bool nodata = true );
|
||||
//! Returns whether it is nodata value
|
||||
bool isNodata() const;
|
||||
//! Returns whether it is scalar value
|
||||
bool isScalar() const;
|
||||
double scalar() const; //length for vectors, value for scalars
|
||||
//! Returns scalar value. Length for vectors, value for scalars
|
||||
double scalar() const;
|
||||
|
||||
//! Sets scalar value
|
||||
void set( double scalar );
|
||||
|
||||
//! Sets X value
|
||||
void setX( double x );
|
||||
|
||||
//! Sets Y value
|
||||
void setY( double y ) ;
|
||||
|
||||
//! Returns x value
|
||||
double x() const;
|
||||
|
||||
//! Returns y value
|
||||
double y() const;
|
||||
|
||||
//! Equals
|
||||
bool operator==( const QgsMeshDatasetValue &other ) const;
|
||||
|
||||
private:
|
||||
@ -96,20 +119,20 @@ class CORE_EXPORT QgsMeshSource SIP_ABSTRACT
|
||||
virtual ~QgsMeshSource() = default;
|
||||
|
||||
/**
|
||||
* \brief Return number of vertices in the native mesh
|
||||
* \brief Returns number of vertices in the native mesh
|
||||
* \returns Number of vertices in the mesh
|
||||
*/
|
||||
virtual int vertexCount() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Return number of faces in the native mesh
|
||||
* \brief Returns number of faces in the native mesh
|
||||
* \returns Number of faces in the mesh
|
||||
*/
|
||||
virtual int faceCount() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Factory for mesh vertex with index
|
||||
* \returns new mesh vertex on index
|
||||
* \returns New mesh vertex on index
|
||||
*/
|
||||
virtual QgsMeshVertex vertex( int index ) const = 0;
|
||||
|
||||
@ -143,32 +166,32 @@ class CORE_EXPORT QgsMeshDatasetSource SIP_ABSTRACT
|
||||
virtual bool addDataset( const QString &uri ) = 0;
|
||||
|
||||
/**
|
||||
* \brief Return number of datasets loaded
|
||||
* \brief Returns number of datasets loaded
|
||||
*/
|
||||
virtual int datasetCount() const = 0;
|
||||
|
||||
/**
|
||||
* \brief Whether dataset has scalar data associated
|
||||
* \brief Returns whether dataset has scalar data associated
|
||||
*/
|
||||
virtual bool datasetHasScalarData( int index ) const = 0;
|
||||
|
||||
/**
|
||||
* \brief Whether dataset is on vertices
|
||||
* \brief Returns whether dataset is on vertices
|
||||
*/
|
||||
virtual bool datasetIsOnVertices( int index ) const = 0;
|
||||
|
||||
/**
|
||||
* \brief Return dataset metadata
|
||||
* \brief Returns dataset metadata
|
||||
*/
|
||||
virtual QgsMeshDatasetMetadata datasetMetadata( int index ) const = 0;
|
||||
|
||||
/**
|
||||
* \brief Return value associated with the index from the dataset
|
||||
* \brief Returns value associated with the index from the dataset
|
||||
*/
|
||||
virtual QgsMeshDatasetValue datasetValue( int datasetIndex, int valueIndex ) const = 0;
|
||||
|
||||
/**
|
||||
* \brief Return whether dataset is valid
|
||||
* \brief Returns whether dataset is valid
|
||||
*/
|
||||
virtual bool datasetIsValid( int index ) const = 0;
|
||||
};
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
#include <QUuid>
|
||||
|
||||
#include "qgsfillsymbollayer.h"
|
||||
|
||||
#include "qgslogger.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
@ -37,12 +37,8 @@ QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
|
||||
// load data
|
||||
setDataProvider( providerKey );
|
||||
|
||||
QgsSymbolLayerList l1;
|
||||
l1 << new QgsSimpleFillSymbolLayer( Qt::white, Qt::NoBrush, Qt::black, Qt::SolidLine, 1.0 );
|
||||
mNativeMeshSymbol.reset( new QgsFillSymbol( l1 ) );
|
||||
|
||||
|
||||
toggleTriangularMeshRendering( false );
|
||||
// show at least the mesh by default so we render something
|
||||
mRendererNativeMeshSettings.setEnabled( true );
|
||||
|
||||
} // QgsMeshLayer ctor
|
||||
|
||||
@ -99,34 +95,53 @@ QgsTriangularMesh *QgsMeshLayer::triangularMesh() SIP_SKIP
|
||||
return mTriangularMesh.get();
|
||||
}
|
||||
|
||||
QgsSymbol *QgsMeshLayer::nativeMeshSymbol()
|
||||
|
||||
QgsMeshRendererMeshSettings QgsMeshLayer::rendererNativeMeshSettings() const
|
||||
{
|
||||
return mNativeMeshSymbol.get();
|
||||
return mRendererNativeMeshSettings;
|
||||
}
|
||||
|
||||
QgsSymbol *QgsMeshLayer::triangularMeshSymbol()
|
||||
void QgsMeshLayer::setRendererNativeMeshSettings( const QgsMeshRendererMeshSettings &settings )
|
||||
{
|
||||
return mTriangularMeshSymbol.get();
|
||||
}
|
||||
|
||||
void QgsMeshLayer::toggleTriangularMeshRendering( bool toggle )
|
||||
{
|
||||
if ( toggle && mTriangularMeshSymbol )
|
||||
return;
|
||||
|
||||
if ( toggle )
|
||||
{
|
||||
QgsSymbolLayerList l2;
|
||||
l2 << new QgsSimpleFillSymbolLayer( Qt::white, Qt::NoBrush, Qt::red, Qt::SolidLine, 0.26 );
|
||||
mTriangularMeshSymbol.reset( new QgsFillSymbol( l2 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mTriangularMeshSymbol.reset();
|
||||
}
|
||||
mRendererNativeMeshSettings = settings;
|
||||
triggerRepaint();
|
||||
}
|
||||
|
||||
QgsMeshRendererMeshSettings QgsMeshLayer::rendererTriangularMeshSettings() const
|
||||
{
|
||||
return mRendererTriangularMeshSettings;
|
||||
}
|
||||
|
||||
void QgsMeshLayer::setRendererTriangularMeshSettings( const QgsMeshRendererMeshSettings &settings )
|
||||
{
|
||||
mRendererTriangularMeshSettings = settings;
|
||||
triggerRepaint();
|
||||
}
|
||||
|
||||
QgsMeshRendererScalarSettings QgsMeshLayer::rendererScalarSettings() const
|
||||
{
|
||||
return mRendererScalarSettings;
|
||||
}
|
||||
|
||||
void QgsMeshLayer::setRendererScalarSettings( const QgsMeshRendererScalarSettings &settings )
|
||||
{
|
||||
mRendererScalarSettings = settings;
|
||||
triggerRepaint();
|
||||
}
|
||||
|
||||
|
||||
QgsMeshRendererVectorSettings QgsMeshLayer::rendererVectorSettings() const
|
||||
{
|
||||
return mRendererVectorSettings;
|
||||
}
|
||||
|
||||
void QgsMeshLayer::setRendererVectorSettings( const QgsMeshRendererVectorSettings &settings )
|
||||
{
|
||||
mRendererVectorSettings = settings;
|
||||
triggerRepaint();
|
||||
}
|
||||
|
||||
|
||||
void QgsMeshLayer::setActiveScalarDataset( int index )
|
||||
{
|
||||
if ( index < 0 )
|
||||
@ -136,8 +151,8 @@ void QgsMeshLayer::setActiveScalarDataset( int index )
|
||||
}
|
||||
|
||||
Q_ASSERT( dataProvider()->datasetCount() > index );
|
||||
if ( dataProvider()->datasetHasScalarData( index ) )
|
||||
mActiveScalarDataset = index;
|
||||
// for vector datasets, we render magnitude
|
||||
mActiveScalarDataset = index;
|
||||
}
|
||||
|
||||
void QgsMeshLayer::setActiveVectorDataset( int index )
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
#include "qgsmeshrenderersettings.h"
|
||||
|
||||
class QgsMapLayerRenderer;
|
||||
class QgsSymbol;
|
||||
@ -70,8 +71,6 @@ struct QgsMesh;
|
||||
* QgsMeshLayer *scratchLayer = new QgsMeshLayer(uri, "My Scratch layer", "memory_mesh");
|
||||
* \endcode
|
||||
*
|
||||
* Add datasets by adding them through data provider, \see QgsMeshDatasetSource::addDataset()
|
||||
*
|
||||
* \subsection mdal MDAL data provider (mdal)
|
||||
*
|
||||
* Accesses data using the MDAL drivers (https://github.com/lutraconsulting/MDAL). The url
|
||||
@ -123,32 +122,49 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
|
||||
bool readXml( const QDomNode &layer_node, QgsReadWriteContext &context ) override;
|
||||
bool writeXml( QDomNode &layer_node, QDomDocument &doc, const QgsReadWriteContext &context ) const override;
|
||||
|
||||
//! Return the provider type for this layer
|
||||
//! Returns the provider type for this layer
|
||||
QString providerType() const;
|
||||
|
||||
//! return native mesh (nullprt before rendering)
|
||||
//! Returns native mesh (nullprt before rendering)
|
||||
QgsMesh *nativeMesh() SIP_SKIP;
|
||||
|
||||
//! return triangular mesh (nullprt before rendering)
|
||||
//! Returns triangular mesh (nullprt before rendering)
|
||||
QgsTriangularMesh *triangularMesh() SIP_SKIP;
|
||||
|
||||
//! Returns a line symbol used for rendering native mesh.
|
||||
QgsSymbol *nativeMeshSymbol();
|
||||
//! Returns rendrer settings
|
||||
QgsMeshRendererMeshSettings rendererNativeMeshSettings() const SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Returns a line symbol used for rendering of triangular (derived) mesh.
|
||||
* \see toggleTriangularMeshRendering
|
||||
*/
|
||||
QgsSymbol *triangularMeshSymbol();
|
||||
//! Sets new rendering settings, triggers repaint
|
||||
void setRendererNativeMeshSettings( const QgsMeshRendererMeshSettings &settings );
|
||||
|
||||
//! Toggle rendering of triangular (derived) mesh. Off by default
|
||||
void toggleTriangularMeshRendering( bool toggle );
|
||||
//! Returns rendrer settings
|
||||
QgsMeshRendererMeshSettings rendererTriangularMeshSettings() const SIP_FACTORY;
|
||||
|
||||
//! Sets new rendering settings, triggers repaint
|
||||
void setRendererTriangularMeshSettings( const QgsMeshRendererMeshSettings &settings );
|
||||
|
||||
//! Returns rendrer settings
|
||||
QgsMeshRendererScalarSettings rendererScalarSettings() const SIP_FACTORY;
|
||||
|
||||
//! Sets new rendering settings, triggers repaint
|
||||
void setRendererScalarSettings( const QgsMeshRendererScalarSettings &settings );
|
||||
|
||||
//! Returns rendrer settings
|
||||
QgsMeshRendererVectorSettings rendererVectorSettings() const SIP_FACTORY;
|
||||
|
||||
//! Sets new rendering settings, triggers repaint
|
||||
void setRendererVectorSettings( const QgsMeshRendererVectorSettings &settings );
|
||||
|
||||
//! Sets active scalar dataset for rendering
|
||||
void setActiveScalarDataset( int index = -1 );
|
||||
void setActiveVectorDataset( int index = -1 );
|
||||
|
||||
//! Returns active scalar dataset
|
||||
int activeScalarDataset() const { return mActiveScalarDataset; }
|
||||
|
||||
//! Sets active vector dataset for rendering. If dataset is not vector based, do nothing
|
||||
void setActiveVectorDataset( int index = -1 );
|
||||
//! Returns active vector dataset
|
||||
int activeVectorDataset() const { return mActiveVectorDataset; }
|
||||
|
||||
private: // Private methods
|
||||
|
||||
/**
|
||||
@ -157,7 +173,7 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
|
||||
bool isReadOnly() const override {return true;}
|
||||
|
||||
/**
|
||||
* Bind layer to a specific data provider
|
||||
* Binds layer to a specific data provider
|
||||
* \param provider provider key string, must match a valid QgsMeshDataProvider key. E.g. "mesh_memory", etc.
|
||||
*/
|
||||
bool setDataProvider( QString const &provider );
|
||||
@ -182,16 +198,15 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
|
||||
//! Pointer to derived mesh structure
|
||||
std::unique_ptr<QgsTriangularMesh> mTriangularMesh;
|
||||
|
||||
//! rendering native mesh
|
||||
std::unique_ptr<QgsSymbol> mNativeMeshSymbol;
|
||||
QgsMeshRendererMeshSettings mRendererNativeMeshSettings;
|
||||
QgsMeshRendererMeshSettings mRendererTriangularMeshSettings;
|
||||
QgsMeshRendererScalarSettings mRendererScalarSettings;
|
||||
QgsMeshRendererVectorSettings mRendererVectorSettings;
|
||||
|
||||
//! rendering triangular mesh
|
||||
std::unique_ptr<QgsSymbol> mTriangularMeshSymbol;
|
||||
|
||||
//! TODO
|
||||
//! index of active scalar dataset; -1 if none
|
||||
int mActiveScalarDataset = -1;
|
||||
|
||||
//! TODO
|
||||
//! index of active vector dataset; -1 if none
|
||||
int mActiveVectorDataset = -1;
|
||||
};
|
||||
|
||||
|
@ -21,66 +21,22 @@
|
||||
|
||||
#include "qgsrasterinterface.h"
|
||||
#include <QVector2D>
|
||||
#include "qgsmaptopixel.h"
|
||||
|
||||
// TODO: use QgsMapToPixel
|
||||
class MapToPixel
|
||||
static void bbox2rect(
|
||||
const QgsMapToPixel &mtp,
|
||||
const QSize &outputSize,
|
||||
const QgsRectangle &bbox,
|
||||
int &leftLim, int &rightLim, int &topLim, int &bottomLim )
|
||||
{
|
||||
public:
|
||||
MapToPixel( double llX, double llY, double mupp, int rows )
|
||||
: mLlX( llX ), mLlY( llY ), mMupp( mupp ), mRows( rows ) {}
|
||||
|
||||
MapToPixel( const MapToPixel &obj )
|
||||
: mLlX( obj.mLlX ), mLlY( obj.mLlY ), mMupp( obj.mMupp ), mRows( obj.mRows ) {}
|
||||
|
||||
QPointF realToPixel( double rx, double ry ) const
|
||||
{
|
||||
double px = ( rx - mLlX ) / mMupp;
|
||||
double py = mRows - ( ry - mLlY ) / mMupp;
|
||||
return QPointF( px, py );
|
||||
}
|
||||
|
||||
|
||||
QPointF realToPixel( const QPointF &pt ) const
|
||||
{
|
||||
return realToPixel( pt.x(), pt.y() );
|
||||
}
|
||||
|
||||
QPointF pixelToReal( double px, double py ) const
|
||||
{
|
||||
double rx = mLlX + ( px * mMupp );
|
||||
double ry = mLlY + mMupp * ( mRows - py );
|
||||
return QPointF( rx, ry );
|
||||
}
|
||||
|
||||
QPointF pixelToReal( const QPointF &pt ) const
|
||||
{
|
||||
return pixelToReal( pt.x(), pt.y() );
|
||||
}
|
||||
|
||||
private:
|
||||
double mLlX, mLlY;
|
||||
double mMupp; // map units per pixel
|
||||
double mRows; // (actually integer value)
|
||||
};
|
||||
|
||||
void bbox2rect( const MapToPixel &mtp, const QSize &outputSize, const QgsRectangle &bbox, int &leftLim, int &rightLim, int &topLim, int &bottomLim )
|
||||
{
|
||||
QPoint ll = mtp.realToPixel( bbox.xMinimum(), bbox.yMinimum() ).toPoint();
|
||||
QPoint ur = mtp.realToPixel( bbox.xMaximum(), bbox.yMaximum() ).toPoint();
|
||||
topLim = std::max( ur.y(), 0 );
|
||||
bottomLim = std::min( ll.y(), outputSize.height() - 1 );
|
||||
leftLim = std::max( ll.x(), 0 );
|
||||
rightLim = std::min( ur.x(), outputSize.width() - 1 );
|
||||
QgsPointXY ll = mtp.transform( bbox.xMinimum(), bbox.yMinimum() );
|
||||
QgsPointXY ur = mtp.transform( bbox.xMaximum(), bbox.yMaximum() );
|
||||
topLim = std::max( int( ur.y() ), 0 );
|
||||
bottomLim = std::min( int( ll.y() ), outputSize.height() - 1 );
|
||||
leftLim = std::max( int( ll.x() ), 0 );
|
||||
rightLim = std::min( int( ur.x() ), outputSize.width() - 1 );
|
||||
}
|
||||
|
||||
struct MapView
|
||||
{
|
||||
MapView(): mtp( 0, 0, 0, 0 ) {}
|
||||
MapToPixel mtp;
|
||||
QSize outputSize;
|
||||
};
|
||||
|
||||
|
||||
static void lam_tol( double &lam )
|
||||
{
|
||||
const static double eps = 1e-6;
|
||||
@ -90,7 +46,7 @@ static void lam_tol( double &lam )
|
||||
}
|
||||
}
|
||||
|
||||
bool E3T_physicalToBarycentric( QPointF pA, QPointF pB, QPointF pC, QPointF pP, double &lam1, double &lam2, double &lam3 )
|
||||
static bool E3T_physicalToBarycentric( QPointF pA, QPointF pB, QPointF pC, QPointF pP, double &lam1, double &lam2, double &lam3 )
|
||||
{
|
||||
if ( pA == pB || pA == pC || pB == pC )
|
||||
return false; // this is not a valid triangle!
|
||||
@ -148,24 +104,14 @@ double interpolateFromFacesData( const QPointF &p1, const QPointF &p2, const QPo
|
||||
|
||||
QgsMeshLayerInterpolator::QgsMeshLayerInterpolator( const QgsTriangularMesh &m,
|
||||
const QVector<double> &datasetValues, bool dataIsOnVertices,
|
||||
const QgsRenderContext &context )
|
||||
const QgsRenderContext &context,
|
||||
const QSize &size )
|
||||
: mTriangularMesh( m ),
|
||||
mDatasetValues( datasetValues ),
|
||||
mContext( context ),
|
||||
mDataOnVertices( dataIsOnVertices )
|
||||
mDataOnVertices( dataIsOnVertices ),
|
||||
mOutputSize( size )
|
||||
{
|
||||
// figure out image size
|
||||
QgsRectangle extent = mContext.extent(); // this is extent in layer's coordinate system - but we need it in map coordinate system
|
||||
QgsMapToPixel mapToPixel = mContext.mapToPixel();
|
||||
// TODO: what if OTF reprojection is used - see crayfish layer_renderer.py (_calculate_extent)
|
||||
QgsPointXY topleft = mapToPixel.transform( extent.xMinimum(), extent.yMaximum() );
|
||||
QgsPointXY bottomright = mapToPixel.transform( extent.xMaximum(), extent.yMinimum() );
|
||||
int width = bottomright.x() - topleft.x();
|
||||
int height = bottomright.y() - topleft.y();
|
||||
|
||||
mMapView.reset( new MapView() );
|
||||
mMapView->mtp = MapToPixel( extent.xMinimum(), extent.yMinimum(), mapToPixel.mapUnitsPerPixel(), height );
|
||||
mMapView->outputSize = QSize( width, height );
|
||||
}
|
||||
|
||||
QgsMeshLayerInterpolator::~QgsMeshLayerInterpolator() = default;
|
||||
@ -177,7 +123,7 @@ QgsRasterInterface *QgsMeshLayerInterpolator::clone() const
|
||||
|
||||
Qgis::DataType QgsMeshLayerInterpolator::dataType( int ) const
|
||||
{
|
||||
return Qgis::Float32;
|
||||
return Qgis::Float64;
|
||||
}
|
||||
|
||||
int QgsMeshLayerInterpolator::bandCount() const
|
||||
@ -187,9 +133,9 @@ int QgsMeshLayerInterpolator::bandCount() const
|
||||
|
||||
QgsRasterBlock *QgsMeshLayerInterpolator::block( int, const QgsRectangle &extent, int width, int height, QgsRasterBlockFeedback *feedback )
|
||||
{
|
||||
QgsRasterBlock *b = new QgsRasterBlock( Qgis::Float32, width, height );
|
||||
QgsRasterBlock *b = new QgsRasterBlock( Qgis::Float64, width, height );
|
||||
b->setIsNoData(); // assume initially that all values are unset
|
||||
float *data = reinterpret_cast<float *>( b->bits() );
|
||||
double *data = reinterpret_cast<double *>( b->bits() );
|
||||
|
||||
const QVector<QgsMeshFace> &triangels = mTriangularMesh.triangles();
|
||||
const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
|
||||
@ -217,16 +163,16 @@ QgsRasterBlock *QgsMeshLayerInterpolator::block( int, const QgsRectangle &extent
|
||||
|
||||
// Get the BBox of the element in pixels
|
||||
int topLim, bottomLim, leftLim, rightLim;
|
||||
bbox2rect( mMapView->mtp, mMapView->outputSize, bbox, leftLim, rightLim, topLim, bottomLim );
|
||||
bbox2rect( mContext.mapToPixel(), mOutputSize, bbox, leftLim, rightLim, topLim, bottomLim );
|
||||
|
||||
// interpolate in the bounding box of the face
|
||||
for ( int j = topLim; j <= bottomLim; j++ )
|
||||
{
|
||||
float *line = data + ( j * width );
|
||||
double *line = data + ( j * width );
|
||||
for ( int k = leftLim; k <= rightLim; k++ )
|
||||
{
|
||||
double val;
|
||||
QPointF p = mMapView->mtp.pixelToReal( k, j );
|
||||
QPointF p = mContext.mapToPixel().toMapCoordinates( k, j ).toQPointF();
|
||||
if ( mDataOnVertices )
|
||||
val = interpolateFromVerticesData(
|
||||
QPointF( p1.x(), p1.y() ),
|
||||
|
@ -24,6 +24,7 @@ class QgsSymbol;
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include <memory>
|
||||
#include <QSize>
|
||||
|
||||
#include "qgis.h"
|
||||
|
||||
@ -37,8 +38,6 @@ class QgsSymbol;
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
struct MapView;
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* Interpolate mesh scalar dataset to raster block
|
||||
@ -49,10 +48,12 @@ struct MapView;
|
||||
class QgsMeshLayerInterpolator : public QgsRasterInterface
|
||||
{
|
||||
public:
|
||||
//! Ctor
|
||||
QgsMeshLayerInterpolator( const QgsTriangularMesh &m,
|
||||
const QVector<double> &datasetValues,
|
||||
bool dataIsOnVertices,
|
||||
const QgsRenderContext &context );
|
||||
const QgsRenderContext &context,
|
||||
const QSize &size );
|
||||
~QgsMeshLayerInterpolator() override;
|
||||
|
||||
virtual QgsRasterInterface *clone() const override;
|
||||
@ -64,8 +65,8 @@ class QgsMeshLayerInterpolator : public QgsRasterInterface
|
||||
const QgsTriangularMesh &mTriangularMesh;
|
||||
const QVector<double> &mDatasetValues;
|
||||
const QgsRenderContext &mContext;
|
||||
std::unique_ptr<MapView> mMapView;
|
||||
bool mDataOnVertices;
|
||||
QSize mOutputSize;
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
@ -27,10 +27,19 @@
|
||||
#include "qgssinglebandpseudocolorrenderer.h"
|
||||
#include "qgsrastershader.h"
|
||||
#include "qgsmeshlayerinterpolator.h"
|
||||
#include "qgsmeshvectorrenderer.h"
|
||||
#include "qgsfillsymbollayer.h"
|
||||
|
||||
|
||||
|
||||
QgsMeshLayerRenderer::QgsMeshLayerRenderer( QgsMeshLayer *layer, QgsRenderContext &context )
|
||||
: QgsMapLayerRenderer( layer->id() )
|
||||
, mFeedback( new QgsMeshLayerRendererFeedback )
|
||||
, mContext( context )
|
||||
, mRendererNativeMeshSettings( layer->rendererNativeMeshSettings() )
|
||||
, mRendererTriangularMeshSettings( layer->rendererTriangularMeshSettings() )
|
||||
, mRendererScalarSettings( layer-> rendererScalarSettings() )
|
||||
, mRendererVectorSettings( layer-> rendererVectorSettings() )
|
||||
{
|
||||
// make copies for mesh data
|
||||
Q_ASSERT( layer->nativeMesh() );
|
||||
@ -38,18 +47,45 @@ QgsMeshLayerRenderer::QgsMeshLayerRenderer( QgsMeshLayer *layer, QgsRenderContex
|
||||
mNativeMesh = *( layer->nativeMesh() );
|
||||
mTriangularMesh = *( layer->triangularMesh() );
|
||||
|
||||
// make copies for symbols
|
||||
if ( layer->nativeMeshSymbol() )
|
||||
{
|
||||
mNativeMeshSymbol.reset( layer->nativeMeshSymbol()->clone() );
|
||||
}
|
||||
|
||||
if ( layer->triangularMeshSymbol() )
|
||||
{
|
||||
mTriangularMeshSymbol.reset( layer->triangularMeshSymbol()->clone() );
|
||||
}
|
||||
createMeshSymbol( mNativeMeshSymbol, mRendererNativeMeshSettings );
|
||||
createMeshSymbol( mTriangularMeshSymbol, mRendererTriangularMeshSettings );
|
||||
|
||||
copyScalarDatasetValues( layer );
|
||||
copyVectorDatasetValues( layer );
|
||||
|
||||
calculateOutputSize();
|
||||
}
|
||||
|
||||
QgsFeedback *QgsMeshLayerRenderer::feedback() const
|
||||
{
|
||||
return mFeedback.get();
|
||||
}
|
||||
|
||||
void QgsMeshLayerRenderer::calculateOutputSize()
|
||||
{
|
||||
// figure out image size
|
||||
QgsRectangle extent = mContext.extent(); // this is extent in layer's coordinate system - but we need it in map coordinate system
|
||||
QgsMapToPixel mapToPixel = mContext.mapToPixel();
|
||||
QgsPointXY topleft = mapToPixel.transform( extent.xMinimum(), extent.yMaximum() );
|
||||
QgsPointXY bottomright = mapToPixel.transform( extent.xMaximum(), extent.yMinimum() );
|
||||
int width = int( bottomright.x() - topleft.x() );
|
||||
int height = int( bottomright.y() - topleft.y() );
|
||||
mOutputSize = QSize( width, height );
|
||||
}
|
||||
|
||||
void QgsMeshLayerRenderer::createMeshSymbol( std::unique_ptr<QgsSymbol> &symbol,
|
||||
const QgsMeshRendererMeshSettings &settings )
|
||||
{
|
||||
if ( settings.isEnabled() )
|
||||
{
|
||||
QgsSymbolLayerList l1;
|
||||
l1 << new QgsSimpleFillSymbolLayer( Qt::white,
|
||||
Qt::NoBrush,
|
||||
settings.color(),
|
||||
Qt::SolidLine,
|
||||
settings.lineWidth() );
|
||||
symbol.reset( new QgsFillSymbol( l1 ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -58,39 +94,69 @@ void QgsMeshLayerRenderer::copyScalarDatasetValues( QgsMeshLayer *layer )
|
||||
int datasetIndex = layer->activeScalarDataset();
|
||||
if ( datasetIndex != -1 )
|
||||
{
|
||||
mDataOnVertices = layer->dataProvider()->datasetIsOnVertices( datasetIndex );
|
||||
if ( mDataOnVertices )
|
||||
mScalarDataOnVertices = layer->dataProvider()->datasetIsOnVertices( datasetIndex );
|
||||
int count;
|
||||
if ( mScalarDataOnVertices )
|
||||
count = mNativeMesh.vertices.count();
|
||||
else
|
||||
count = mNativeMesh.faces.count();
|
||||
|
||||
mScalarDatasetValues.resize( count );
|
||||
for ( int i = 0; i < count; ++i )
|
||||
{
|
||||
int count = mNativeMesh.vertices.count();
|
||||
mDatasetValues.resize( count );
|
||||
for ( int i = 0; i < count; ++i )
|
||||
{
|
||||
double v = layer->dataProvider()->datasetValue( datasetIndex, i ).scalar();
|
||||
mDatasetValues[i] = v;
|
||||
}
|
||||
double v = layer->dataProvider()->datasetValue( datasetIndex, i ).scalar();
|
||||
mScalarDatasetValues[i] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMeshLayerRenderer::copyVectorDatasetValues( QgsMeshLayer *layer )
|
||||
{
|
||||
int datasetIndex = layer->activeVectorDataset();
|
||||
if ( datasetIndex != -1 )
|
||||
{
|
||||
bool isScalar = layer->dataProvider()->datasetHasScalarData( datasetIndex );
|
||||
if ( isScalar )
|
||||
{
|
||||
QgsDebugMsg( "Dataset has no vector values" );
|
||||
}
|
||||
else
|
||||
{
|
||||
//on faces
|
||||
int count = mNativeMesh.faces.count();
|
||||
mDatasetValues.resize( count );
|
||||
mVectorDataOnVertices = layer->dataProvider()->datasetIsOnVertices( datasetIndex );
|
||||
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 v = layer->dataProvider()->datasetValue( datasetIndex, i ).scalar();
|
||||
mDatasetValues[i] = v;
|
||||
double x = layer->dataProvider()->datasetValue( datasetIndex, i ).x();
|
||||
mVectorDatasetValuesX[i] = x;
|
||||
|
||||
double y = layer->dataProvider()->datasetValue( datasetIndex, i ).y();
|
||||
mVectorDatasetValuesY[i] = y;
|
||||
|
||||
double mag = layer->dataProvider()->datasetValue( datasetIndex, i ).scalar();
|
||||
mVectorDatasetValuesMag[i] = mag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool QgsMeshLayerRenderer::render()
|
||||
{
|
||||
|
||||
renderScalarDataset();
|
||||
|
||||
renderMesh( mNativeMeshSymbol, mNativeMesh.faces ); // native mesh
|
||||
renderMesh( mTriangularMeshSymbol, mTriangularMesh.triangles() ); // triangular mesh
|
||||
|
||||
renderVectorDataset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -131,37 +197,30 @@ void QgsMeshLayerRenderer::renderMesh( const std::unique_ptr<QgsSymbol> &symbol,
|
||||
|
||||
void QgsMeshLayerRenderer::renderScalarDataset()
|
||||
{
|
||||
if ( mDatasetValues.isEmpty() )
|
||||
if ( mScalarDatasetValues.isEmpty() )
|
||||
return;
|
||||
|
||||
// figure out image size
|
||||
QgsRectangle extent = mContext.extent(); // this is extent in layer's coordinate system - but we need it in map coordinate system
|
||||
QgsMapToPixel mapToPixel = mContext.mapToPixel();
|
||||
// TODO: what if OTF reprojection is used - see crayfish layer_renderer.py (_calculate_extent)
|
||||
QgsPointXY topleft = mapToPixel.transform( extent.xMinimum(), extent.yMaximum() );
|
||||
QgsPointXY bottomright = mapToPixel.transform( extent.xMaximum(), extent.yMinimum() );
|
||||
int width = bottomright.x() - topleft.x();
|
||||
int height = bottomright.y() - topleft.y();
|
||||
// do not render if magnitude is outside of the filtered range (if filtering is enabled)
|
||||
double vMin = mRendererScalarSettings.minValue();
|
||||
if ( std::isnan( vMin ) )
|
||||
vMin = *std::min_element( mScalarDatasetValues.constBegin(), mScalarDatasetValues.constEnd() );
|
||||
|
||||
double vMin = mDatasetValues[0], vMax = mDatasetValues[0];
|
||||
for ( int i = 1; i < mDatasetValues.count(); ++i )
|
||||
{
|
||||
double v = mDatasetValues[i];
|
||||
if ( v < vMin ) vMin = v;
|
||||
if ( v > vMax ) vMax = v;
|
||||
}
|
||||
|
||||
double vMax = mRendererScalarSettings.maxValue();
|
||||
if ( std::isnan( vMax ) )
|
||||
vMax = *std::max_element( mScalarDatasetValues.constBegin(), mScalarDatasetValues.constEnd() );
|
||||
|
||||
QList<QgsColorRampShader::ColorRampItem> lst;
|
||||
lst << QgsColorRampShader::ColorRampItem( vMin, Qt::red, QString::number( vMin ) );
|
||||
lst << QgsColorRampShader::ColorRampItem( vMax, Qt::blue, QString::number( vMax ) );
|
||||
lst << QgsColorRampShader::ColorRampItem( vMin, mRendererScalarSettings.minColor(), QString::number( vMin ) );
|
||||
lst << QgsColorRampShader::ColorRampItem( vMax, mRendererScalarSettings.maxColor(), QString::number( vMax ) );
|
||||
|
||||
QgsColorRampShader *fcn = new QgsColorRampShader( vMin, vMax );
|
||||
fcn->setColorRampItemList( lst );
|
||||
QgsRasterShader *sh = new QgsRasterShader( 0, 1000 );
|
||||
QgsRasterShader *sh = new QgsRasterShader( vMin, vMax );
|
||||
sh->setRasterShaderFunction( fcn ); // takes ownership of fcn
|
||||
QgsMeshLayerInterpolator interpolator( mTriangularMesh, mDatasetValues, mDataOnVertices, mContext );
|
||||
QgsMeshLayerInterpolator interpolator( mTriangularMesh, mScalarDatasetValues, mScalarDataOnVertices, mContext, mOutputSize );
|
||||
QgsSingleBandPseudoColorRenderer r( &interpolator, 0, sh ); // takes ownership of sh
|
||||
QgsRasterBlock *bl = r.block( 0, extent, width, height ); // TODO: feedback
|
||||
QgsRasterBlock *bl = r.block( 0, mContext.extent(), mOutputSize.width(), mOutputSize.height(), mFeedback.get() );
|
||||
Q_ASSERT( bl );
|
||||
|
||||
QImage img = bl->image();
|
||||
@ -169,3 +228,18 @@ void QgsMeshLayerRenderer::renderScalarDataset()
|
||||
mContext.painter()->drawImage( 0, 0, img );
|
||||
delete bl;
|
||||
}
|
||||
|
||||
void QgsMeshLayerRenderer::renderVectorDataset()
|
||||
{
|
||||
if ( mVectorDatasetValuesX.isEmpty() )
|
||||
return;
|
||||
|
||||
if ( mVectorDatasetValuesX.size() != mVectorDatasetValuesY.size() )
|
||||
return;
|
||||
|
||||
QgsMeshVectorRenderer renderer( mTriangularMesh,
|
||||
mVectorDatasetValuesX, mVectorDatasetValuesY, mVectorDatasetValuesMag,
|
||||
mVectorDataOnVertices, mRendererVectorSettings, mContext, mOutputSize );
|
||||
|
||||
renderer.draw();
|
||||
}
|
||||
|
@ -28,8 +28,24 @@ class QgsSymbol;
|
||||
#include "qgis.h"
|
||||
|
||||
#include "qgsmaplayerrenderer.h"
|
||||
#include "qgsrasterinterface.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgstriangularmesh.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgssymbol.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* Feedback for mesh layer rendering - right now derived from raster block feedback so that we
|
||||
* can pass it to block reading in the raster interface.
|
||||
*/
|
||||
class QgsMeshLayerRendererFeedback : public QgsRasterBlockFeedback
|
||||
{
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
@ -43,16 +59,23 @@ class QgsMeshLayerRenderer : public QgsMapLayerRenderer
|
||||
public:
|
||||
//! Ctor
|
||||
QgsMeshLayerRenderer( QgsMeshLayer *layer, QgsRenderContext &context );
|
||||
|
||||
~QgsMeshLayerRenderer() override = default;
|
||||
QgsFeedback *feedback() const override;
|
||||
bool render() override;
|
||||
|
||||
private:
|
||||
void renderMesh( const std::unique_ptr<QgsSymbol> &symbol, const QVector<QgsMeshFace> &faces );
|
||||
void renderScalarDataset();
|
||||
void renderVectorDataset();
|
||||
void copyScalarDatasetValues( QgsMeshLayer *layer );
|
||||
void copyVectorDatasetValues( QgsMeshLayer *layer );
|
||||
void createMeshSymbol( std::unique_ptr<QgsSymbol> &symbol, const QgsMeshRendererMeshSettings &settings );
|
||||
void calculateOutputSize();
|
||||
|
||||
protected:
|
||||
//! feedback class for cancelation
|
||||
std::unique_ptr<QgsMeshLayerRendererFeedback> mFeedback;
|
||||
|
||||
// copy from mesh layer
|
||||
QgsMesh mNativeMesh;
|
||||
|
||||
@ -60,8 +83,14 @@ class QgsMeshLayerRenderer : public QgsMapLayerRenderer
|
||||
QgsTriangularMesh mTriangularMesh;
|
||||
|
||||
// copy of the scalar dataset
|
||||
QVector<double> mDatasetValues;
|
||||
bool mDataOnVertices;
|
||||
QVector<double> mScalarDatasetValues;
|
||||
bool mScalarDataOnVertices;
|
||||
|
||||
// copy of the vector dataset
|
||||
QVector<double> mVectorDatasetValuesX;
|
||||
QVector<double> mVectorDatasetValuesY;
|
||||
QVector<double> mVectorDatasetValuesMag;
|
||||
bool mVectorDataOnVertices;
|
||||
|
||||
// copy from mesh layer
|
||||
std::unique_ptr<QgsSymbol> mNativeMeshSymbol = nullptr;
|
||||
@ -71,6 +100,15 @@ class QgsMeshLayerRenderer : public QgsMapLayerRenderer
|
||||
|
||||
// rendering context
|
||||
QgsRenderContext &mContext;
|
||||
|
||||
// copy of rendering settings
|
||||
QgsMeshRendererMeshSettings mRendererNativeMeshSettings;
|
||||
QgsMeshRendererMeshSettings mRendererTriangularMeshSettings;
|
||||
QgsMeshRendererScalarSettings mRendererScalarSettings;
|
||||
QgsMeshRendererVectorSettings mRendererVectorSettings;
|
||||
|
||||
// output screen size
|
||||
QSize mOutputSize;
|
||||
};
|
||||
|
||||
|
||||
|
@ -87,7 +87,7 @@ class QgsMeshMemoryDataProvider: public QgsMeshDataProvider
|
||||
|
||||
|
||||
/**
|
||||
* Add dataset to a mesh in-memory data provider from data string
|
||||
* Adds dataset to a mesh in-memory data provider from data string
|
||||
*
|
||||
* Data string constains simple definition of datasets
|
||||
* Each entry is separated by "\n" sign and section deliminer "---"
|
||||
|
198
src/core/mesh/qgsmeshrenderersettings.cpp
Normal file
198
src/core/mesh/qgsmeshrenderersettings.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
/***************************************************************************
|
||||
qgsmeshrenderersettings.cpp
|
||||
---------------------------
|
||||
begin : May 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsmeshrenderersettings.h"
|
||||
|
||||
bool QgsMeshRendererMeshSettings::isEnabled() const
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
void QgsMeshRendererMeshSettings::setEnabled( bool on )
|
||||
{
|
||||
mEnabled = on;
|
||||
}
|
||||
|
||||
double QgsMeshRendererMeshSettings::lineWidth() const
|
||||
{
|
||||
return mLineWidth;
|
||||
}
|
||||
|
||||
void QgsMeshRendererMeshSettings::setLineWidth( double lineWidth )
|
||||
{
|
||||
mLineWidth = lineWidth;
|
||||
}
|
||||
|
||||
QColor QgsMeshRendererMeshSettings::color() const
|
||||
{
|
||||
return mColor;
|
||||
}
|
||||
|
||||
void QgsMeshRendererMeshSettings::setColor( const QColor &color )
|
||||
{
|
||||
mColor = color;
|
||||
}
|
||||
|
||||
QColor QgsMeshRendererScalarSettings::maxColor() const
|
||||
{
|
||||
return mMaxColor;
|
||||
}
|
||||
|
||||
void QgsMeshRendererScalarSettings::setMaxColor( const QColor &maxColor )
|
||||
{
|
||||
mMaxColor = maxColor;
|
||||
}
|
||||
|
||||
QColor QgsMeshRendererScalarSettings::minColor() const
|
||||
{
|
||||
return mMinColor;
|
||||
}
|
||||
|
||||
void QgsMeshRendererScalarSettings::setMinColor( const QColor &minColor )
|
||||
{
|
||||
mMinColor = minColor;
|
||||
}
|
||||
|
||||
double QgsMeshRendererScalarSettings::minValue() const
|
||||
{
|
||||
return mMinValue;
|
||||
}
|
||||
|
||||
void QgsMeshRendererScalarSettings::setMinValue( double minValue )
|
||||
{
|
||||
mMinValue = minValue;
|
||||
}
|
||||
|
||||
double QgsMeshRendererScalarSettings::maxValue() const
|
||||
{
|
||||
return mMaxValue;
|
||||
}
|
||||
|
||||
void QgsMeshRendererScalarSettings::setMaxValue( double maxValue )
|
||||
{
|
||||
mMaxValue = maxValue;
|
||||
}
|
||||
|
||||
double QgsMeshRendererVectorSettings::lineWidth() const
|
||||
{
|
||||
return mLineWidth;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setLineWidth( double lineWidth )
|
||||
{
|
||||
mLineWidth = lineWidth;
|
||||
}
|
||||
|
||||
QColor QgsMeshRendererVectorSettings::color() const
|
||||
{
|
||||
return mColor;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setColor( const QColor &vectorColor )
|
||||
{
|
||||
mColor = vectorColor;
|
||||
}
|
||||
|
||||
double QgsMeshRendererVectorSettings::filterMin() const
|
||||
{
|
||||
return mFilterMin;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setFilterMin( double vectorFilterMin )
|
||||
{
|
||||
mFilterMin = vectorFilterMin;
|
||||
}
|
||||
|
||||
double QgsMeshRendererVectorSettings::filterMax() const
|
||||
{
|
||||
return mFilterMax;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setFilterMax( double vectorFilterMax )
|
||||
{
|
||||
mFilterMax = vectorFilterMax;
|
||||
}
|
||||
|
||||
QgsMeshRendererVectorSettings::VectorRenderingType QgsMeshRendererVectorSettings::shaftLengthMethod() const
|
||||
{
|
||||
return mShaftLengthMethod;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setShaftLengthMethod( const QgsMeshRendererVectorSettings::VectorRenderingType &shaftLengthMethod )
|
||||
{
|
||||
mShaftLengthMethod = shaftLengthMethod;
|
||||
}
|
||||
|
||||
double QgsMeshRendererVectorSettings::minShaftLength() const
|
||||
{
|
||||
return mMinShaftLength;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setMinShaftLength( double minShaftLength )
|
||||
{
|
||||
mMinShaftLength = minShaftLength;
|
||||
}
|
||||
|
||||
double QgsMeshRendererVectorSettings::maxShaftLength() const
|
||||
{
|
||||
return mMaxShaftLength;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setMaxShaftLength( double maxShaftLength )
|
||||
{
|
||||
mMaxShaftLength = maxShaftLength;
|
||||
}
|
||||
|
||||
double QgsMeshRendererVectorSettings::scaleFactor() const
|
||||
{
|
||||
return mScaleFactor;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setScaleFactor( double scaleFactor )
|
||||
{
|
||||
mScaleFactor = scaleFactor;
|
||||
}
|
||||
|
||||
double QgsMeshRendererVectorSettings::fixedShaftLength() const
|
||||
{
|
||||
return mFixedShaftLength;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setFixedShaftLength( double fixedShaftLength )
|
||||
{
|
||||
mFixedShaftLength = fixedShaftLength;
|
||||
}
|
||||
|
||||
double QgsMeshRendererVectorSettings::arrowHeadWidthRatio() const
|
||||
{
|
||||
return mArrowHeadWidthRatio;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setArrowHeadWidthRatio( double vectorHeadWidthRatio )
|
||||
{
|
||||
mArrowHeadWidthRatio = vectorHeadWidthRatio;
|
||||
}
|
||||
|
||||
double QgsMeshRendererVectorSettings::arrowHeadLengthRatio() const
|
||||
{
|
||||
return mArrowHeadLengthRatio;
|
||||
}
|
||||
|
||||
void QgsMeshRendererVectorSettings::setArrowHeadLengthRatio( double vectorHeadLengthRatio )
|
||||
{
|
||||
mArrowHeadLengthRatio = vectorHeadLengthRatio;
|
||||
}
|
254
src/core/mesh/qgsmeshrenderersettings.h
Normal file
254
src/core/mesh/qgsmeshrenderersettings.h
Normal file
@ -0,0 +1,254 @@
|
||||
/***************************************************************************
|
||||
qgsmeshrenderersettings.h
|
||||
-------------------------
|
||||
begin : May 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSMESHRENDERERSETTINGS_H
|
||||
#define QGSMESHRENDERERSETTINGS_H
|
||||
|
||||
#include <QColor>
|
||||
#include <limits>
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
*
|
||||
* Represents a mesh renderer settings for mesh object
|
||||
*
|
||||
* \note The API is considered EXPERIMENTAL and can be changed without a notice
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class CORE_EXPORT QgsMeshRendererMeshSettings
|
||||
{
|
||||
public:
|
||||
//! Returns whether mesh structure rendering is enabled
|
||||
bool isEnabled() const;
|
||||
//! Sets whether mesh structure rendering is enabled
|
||||
void setEnabled( bool enabled );
|
||||
|
||||
//! Returns line width used for rendering (in millimeters)
|
||||
double lineWidth() const;
|
||||
//! Sets line width used for rendering (in millimeters)
|
||||
void setLineWidth( double lineWidth );
|
||||
|
||||
//! Returns color used for rendering
|
||||
QColor color() const;
|
||||
//! Sets color used for rendering of the mesh
|
||||
void setColor( const QColor &color );
|
||||
|
||||
private:
|
||||
bool mEnabled = false;
|
||||
double mLineWidth = DEFAULT_LINE_WIDTH;
|
||||
QColor mColor = Qt::black;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
*
|
||||
* Represents a mesh renderer settings for scalar datasets
|
||||
*
|
||||
* \note The API is considered EXPERIMENTAL and can be changed without a notice
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class CORE_EXPORT QgsMeshRendererScalarSettings
|
||||
{
|
||||
public:
|
||||
//! Returns color representing maximum scalar value in the dataset
|
||||
QColor maxColor() const;
|
||||
//! Sets color representing maximum scalar value in the dataset
|
||||
void setMaxColor( const QColor &maxColor );
|
||||
|
||||
//! Returns color representing minimum scalar value in the dataset
|
||||
QColor minColor() const;
|
||||
//! Sets color representing maximum scalar value in the dataset
|
||||
void setMinColor( const QColor &minColor );
|
||||
|
||||
/**
|
||||
* Returns min scalar value that represents minColor()
|
||||
*
|
||||
* if set to numerical_limits<double>::quiet_NaN(), value for minColor() is
|
||||
* taken from minimum value of active scalar dataset
|
||||
*/
|
||||
double minValue() const;
|
||||
|
||||
/**
|
||||
* Sets min scalar value that represents minColor()
|
||||
* \see QgsMeshRendererScalarSettings::minValue()
|
||||
*/
|
||||
void setMinValue( double minValue );
|
||||
|
||||
/**
|
||||
* Returns max scalar value that represents maxColor()
|
||||
*
|
||||
* if set to numerical_limits<double>::quiet_NaN(), value for maxColor() is
|
||||
* taken from maximum value of active scalar dataset
|
||||
*/
|
||||
double maxValue() const;
|
||||
|
||||
/**
|
||||
* Sets min scalar value that represents minColor()
|
||||
* \see QgsMeshRendererScalarSettings::maxValue()
|
||||
*/
|
||||
void setMaxValue( double maxValue );
|
||||
|
||||
private:
|
||||
QColor mMaxColor = QColor::fromRgb( 255, 0, 0 );
|
||||
QColor mMinColor = QColor::fromRgb( 0, 0, 255 );
|
||||
double mMaxValue = std::numeric_limits<double>::quiet_NaN(); //disabled
|
||||
double mMinValue = std::numeric_limits<double>::quiet_NaN(); //disabled
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
*
|
||||
* Represents a mesh renderer settings for vector datasets
|
||||
*
|
||||
* \note The API is considered EXPERIMENTAL and can be changed without a notice
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
class CORE_EXPORT QgsMeshRendererVectorSettings
|
||||
{
|
||||
public:
|
||||
//! Algorithm how to transform vector magnitude to length of arrow on the device in pixels
|
||||
enum VectorRenderingType
|
||||
{
|
||||
|
||||
/**
|
||||
* Scale vector magnitude linearly to fit in range of vectorFilterMin() and vectorFilterMax()
|
||||
*/
|
||||
MinMax = 0,
|
||||
|
||||
/**
|
||||
* Scale vector magnitude by factor scaleFactor()
|
||||
*/
|
||||
Scaled,
|
||||
|
||||
/**
|
||||
* Use fixed length fixedShaftLength() regardless of vector's magnitude
|
||||
*/
|
||||
Fixed
|
||||
};
|
||||
|
||||
//! Returns line width of the arrow (in millimeters)
|
||||
double lineWidth() const;
|
||||
//! Sets line width of the arrow in pixels (in millimeters)
|
||||
void setLineWidth( double lineWidth );
|
||||
|
||||
//! Returns color used for drawing arrows
|
||||
QColor color() const;
|
||||
//! Sets color used for drawing arrows
|
||||
void setColor( const QColor &color );
|
||||
|
||||
/**
|
||||
* Returns filter value for vector magnitudes.
|
||||
*
|
||||
* If magnitude of the vector is lower than this value, the vector is not
|
||||
* drawn. -1 represents that filtering is not active.
|
||||
*/
|
||||
double filterMin() const;
|
||||
|
||||
/**
|
||||
* Sets filter value for vector magnitudes.
|
||||
* \see QgsMeshRendererVectorSettings::vectorFilterMin()
|
||||
*/
|
||||
void setFilterMin( double filterMin );
|
||||
|
||||
/**
|
||||
* Returns filter value for vector magnitudes.
|
||||
*
|
||||
* If magnitude of the vector is higher than this value, the vector is not
|
||||
* drawn. -1 represents that filtering is not active.
|
||||
*/
|
||||
double filterMax() const;
|
||||
|
||||
/**
|
||||
* Sets filter value for vector magnitudes.
|
||||
* \see QgsMeshRendererVectorSettings::vectorFilterMax()
|
||||
*/
|
||||
void setFilterMax( double filterMax );
|
||||
|
||||
//! Returns method used for drawing arrows
|
||||
QgsMeshRendererVectorSettings::VectorRenderingType shaftLengthMethod() const;
|
||||
//! Sets method used for drawing arrows
|
||||
void setShaftLengthMethod( const QgsMeshRendererVectorSettings::VectorRenderingType &shaftLengthMethod );
|
||||
|
||||
/**
|
||||
* Returns mininimum shaft length (in millimeters)
|
||||
*
|
||||
* Only for QgsMeshRendererVectorSettings::ArrowType::MinMax
|
||||
*/
|
||||
double minShaftLength() const;
|
||||
|
||||
/**
|
||||
* Sets mininimum shaft length (in millimeters)
|
||||
*
|
||||
* Only for QgsMeshRendererVectorSettings::ArrowType::MinMax
|
||||
*/
|
||||
void setMinShaftLength( double minShaftLength );
|
||||
|
||||
/**
|
||||
* Returns maximum shaft length (in millimeters)
|
||||
*
|
||||
* Only for QgsMeshRendererVectorSettings::ArrowType::MinMax
|
||||
*/
|
||||
double maxShaftLength() const;
|
||||
|
||||
/**
|
||||
* Sets maximum shaft length (in millimeters)
|
||||
*
|
||||
* Only for QgsMeshRendererVectorSettings::ArrowType::MinMax
|
||||
*/
|
||||
void setMaxShaftLength( double maxShaftLength );
|
||||
|
||||
//! Returns scale factor. Only for QgsMeshRendererVectorSettings::ArrowType::Scaled
|
||||
double scaleFactor() const;
|
||||
//! Sets scale factor. Only for QgsMeshRendererVectorSettings::ArrowType::Scaled
|
||||
void setScaleFactor( double scaleFactor );
|
||||
|
||||
//! Returns fixed arrow length (in millimeters). Only for QgsMeshRendererVectorSettings::ArrowType::Fixed
|
||||
double fixedShaftLength() const;
|
||||
//! Sets fixed length (in millimeters). Only for QgsMeshRendererVectorSettings::ArrowType::Fixed
|
||||
void setFixedShaftLength( double fixedShaftLength );
|
||||
|
||||
//! Returns ratio of the head width of the arrow (range 0-1)
|
||||
double arrowHeadWidthRatio() const;
|
||||
//! Sets ratio of the head width of the arrow (range 0-1)
|
||||
void setArrowHeadWidthRatio( double arrowHeadWidthRatio );
|
||||
|
||||
//! Returns ratio of the head length of the arrow (range 0-1)
|
||||
double arrowHeadLengthRatio() const;
|
||||
//! Sets ratio of the head length of the arrow (range 0-1)
|
||||
void setArrowHeadLengthRatio( double arrowHeadLengthRatio );
|
||||
|
||||
private:
|
||||
double mLineWidth = DEFAULT_LINE_WIDTH; //in milimeters
|
||||
QColor mColor = Qt::black;
|
||||
double mFilterMin = -1; //disabled
|
||||
double mFilterMax = -1; //disabled
|
||||
QgsMeshRendererVectorSettings::VectorRenderingType mShaftLengthMethod = QgsMeshRendererVectorSettings::VectorRenderingType::MinMax;
|
||||
double mMinShaftLength = 0.8; //in milimeters
|
||||
double mMaxShaftLength = 10; //in milimeters
|
||||
double mScaleFactor = 10;
|
||||
double mFixedShaftLength = 20; //in milimeters
|
||||
double mArrowHeadWidthRatio = 0.15;
|
||||
double mArrowHeadLengthRatio = 0.40;
|
||||
};
|
||||
|
||||
#endif //QGSMESHRENDERERSETTINGS_H
|
264
src/core/mesh/qgsmeshvectorrenderer.cpp
Normal file
264
src/core/mesh/qgsmeshvectorrenderer.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
/***************************************************************************
|
||||
qgsmeshvectorrenderer.cpp
|
||||
-------------------------
|
||||
begin : May 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsmeshvectorrenderer.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgscoordinatetransform.h"
|
||||
#include "qgsmaptopixel.h"
|
||||
#include "qgsunittypes.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <algorithm>
|
||||
#include <QPen>
|
||||
#include <QPainter>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
inline double mag( double input )
|
||||
{
|
||||
if ( input < 0.0 )
|
||||
{
|
||||
return -1.0;
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
QgsMeshVectorRenderer::QgsMeshVectorRenderer( const QgsTriangularMesh &m,
|
||||
const QVector<double> &datasetValuesX,
|
||||
const QVector<double> &datasetValuesY,
|
||||
const QVector<double> &datasetValuesMag,
|
||||
bool dataIsOnVertices,
|
||||
const QgsMeshRendererVectorSettings &settings,
|
||||
QgsRenderContext &context, const QSize &size )
|
||||
: mTriangularMesh( m )
|
||||
, mDatasetValuesX( datasetValuesX )
|
||||
, mDatasetValuesY( datasetValuesY )
|
||||
, mDatasetValuesMag( datasetValuesMag )
|
||||
, mContext( context )
|
||||
, mCfg( settings )
|
||||
, mDataOnVertices( dataIsOnVertices )
|
||||
, mOutputSize( size )
|
||||
{
|
||||
mMinX = *std::min_element( datasetValuesX.constBegin(), datasetValuesX.constEnd() );
|
||||
mMaxX = *std::max_element( datasetValuesX.constBegin(), datasetValuesX.constEnd() );
|
||||
mMinY = *std::min_element( datasetValuesY.constBegin(), datasetValuesY.constEnd() );
|
||||
mMaxY = *std::max_element( datasetValuesY.constBegin(), datasetValuesY.constEnd() );
|
||||
mMinMag = *std::min_element( mDatasetValuesMag.constBegin(), mDatasetValuesMag.constEnd() );
|
||||
mMaxMag = *std::max_element( mDatasetValuesMag.constBegin(), mDatasetValuesMag.constEnd() );
|
||||
}
|
||||
|
||||
QgsMeshVectorRenderer::~QgsMeshVectorRenderer() = default;
|
||||
|
||||
void QgsMeshVectorRenderer::draw()
|
||||
{
|
||||
// Set up the render configuration options
|
||||
QPainter *p = mContext.painter();
|
||||
p->setRenderHint( QPainter::Antialiasing );
|
||||
QPen pen = p->pen();
|
||||
pen.setCapStyle( Qt::FlatCap );
|
||||
pen.setJoinStyle( Qt::MiterJoin );
|
||||
|
||||
double penWidth = mContext.convertToPainterUnits( mCfg.lineWidth(),
|
||||
QgsUnitTypes::RenderUnit::RenderMillimeters );
|
||||
pen.setWidthF( penWidth );
|
||||
pen.setColor( mCfg.color() );
|
||||
p->setPen( pen );
|
||||
|
||||
if ( mDataOnVertices )
|
||||
drawVectorDataOnVertices();
|
||||
else
|
||||
drawVectorDataOnFaces();
|
||||
}
|
||||
|
||||
bool QgsMeshVectorRenderer::calcVectorLineEnd(
|
||||
QgsPointXY &lineEnd,
|
||||
double &vectorLength,
|
||||
double &cosAlpha,
|
||||
double &sinAlpha, //out
|
||||
const QgsPointXY &lineStart,
|
||||
double xVal,
|
||||
double yVal,
|
||||
double magnitude //in
|
||||
)
|
||||
{
|
||||
// return true on error
|
||||
|
||||
if ( xVal == 0.0 && yVal == 0.0 )
|
||||
return true;
|
||||
|
||||
// do not render if magnitude is outside of the filtered range (if filtering is enabled)
|
||||
if ( mCfg.filterMin() >= 0 && magnitude < mCfg.filterMin() )
|
||||
return true;
|
||||
if ( mCfg.filterMax() >= 0 && magnitude > mCfg.filterMax() )
|
||||
return true;
|
||||
|
||||
// Determine the angle of the vector, counter-clockwise, from east
|
||||
// (and associated trigs)
|
||||
double vectorAngle = -1.0 * atan( ( -1.0 * yVal ) / xVal );
|
||||
cosAlpha = cos( vectorAngle ) * mag( xVal );
|
||||
sinAlpha = sin( vectorAngle ) * mag( xVal );
|
||||
|
||||
// Now determine the X and Y distances of the end of the line from the start
|
||||
double xDist = 0.0;
|
||||
double yDist = 0.0;
|
||||
switch ( mCfg.shaftLengthMethod() )
|
||||
{
|
||||
case QgsMeshRendererVectorSettings::VectorRenderingType::MinMax:
|
||||
{
|
||||
double minShaftLength = mContext.convertToPainterUnits( mCfg.minShaftLength(),
|
||||
QgsUnitTypes::RenderUnit::RenderMillimeters );
|
||||
double maxShaftLength = mContext.convertToPainterUnits( mCfg.maxShaftLength(),
|
||||
QgsUnitTypes::RenderUnit::RenderMillimeters );
|
||||
double minVal = mMinMag;
|
||||
double maxVal = mMaxMag;
|
||||
double k = ( magnitude - minVal ) / ( maxVal - minVal );
|
||||
double L = minShaftLength + k * ( maxShaftLength - minShaftLength );
|
||||
xDist = cosAlpha * L;
|
||||
yDist = sinAlpha * L;
|
||||
break;
|
||||
}
|
||||
case QgsMeshRendererVectorSettings::VectorRenderingType::Scaled:
|
||||
{
|
||||
double scaleFactor = mCfg.scaleFactor();
|
||||
xDist = scaleFactor * xVal;
|
||||
yDist = scaleFactor * yVal;
|
||||
break;
|
||||
}
|
||||
case QgsMeshRendererVectorSettings::VectorRenderingType::Fixed:
|
||||
{
|
||||
// We must be using a fixed length
|
||||
double fixedShaftLength = mContext.convertToPainterUnits( mCfg.fixedShaftLength(),
|
||||
QgsUnitTypes::RenderUnit::RenderMillimeters );
|
||||
xDist = cosAlpha * fixedShaftLength;
|
||||
yDist = sinAlpha * fixedShaftLength;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Flip the Y axis (pixel vs real-world axis)
|
||||
yDist *= -1.0;
|
||||
|
||||
if ( qAbs( xDist ) < 1 && qAbs( yDist ) < 1 )
|
||||
return true;
|
||||
|
||||
// Determine the line coords
|
||||
lineEnd = QgsPointXY( lineStart.x() + xDist,
|
||||
lineStart.y() + yDist );
|
||||
|
||||
vectorLength = sqrt( xDist * xDist + yDist * yDist );
|
||||
|
||||
// Check to see if any of the coords are outside the QImage area, if so, skip the whole vector
|
||||
if ( lineStart.x() < 0 || lineStart.x() > mOutputSize.width() ||
|
||||
lineStart.y() < 0 || lineStart.y() > mOutputSize.height() ||
|
||||
lineEnd.x() < 0 || lineEnd.x() > mOutputSize.width() ||
|
||||
lineEnd.y() < 0 || lineEnd.y() > mOutputSize.height() )
|
||||
return true;
|
||||
|
||||
return false; //success
|
||||
}
|
||||
|
||||
|
||||
void QgsMeshVectorRenderer::drawVectorDataOnVertices()
|
||||
{
|
||||
const QVector<QgsMeshVertex> &vertices = mTriangularMesh.vertices();
|
||||
|
||||
// currently expecting that triangulation does not add any new extra vertices on the way
|
||||
Q_ASSERT( mDatasetValuesMag.count() == vertices.count() );
|
||||
|
||||
for ( int i = 0; i < vertices.size(); ++i )
|
||||
{
|
||||
const QgsMeshVertex &vertex = vertices.at( i );
|
||||
//if (!nodeInsideView(nodeIndex))
|
||||
// continue;
|
||||
|
||||
double xVal = mDatasetValuesX[i];
|
||||
double yVal = mDatasetValuesY[i];
|
||||
double V = mDatasetValuesMag[i]; // pre-calculated magnitude
|
||||
QgsPointXY lineStart = mContext.mapToPixel().transform( vertex.x(), vertex.y() );
|
||||
|
||||
drawVectorArrow( lineStart, xVal, yVal, V );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMeshVectorRenderer::drawVectorDataOnFaces()
|
||||
{
|
||||
const QVector<QgsMeshVertex> ¢roids = mTriangularMesh.centroids();
|
||||
|
||||
for ( int i = 0; i < centroids.count(); i++ )
|
||||
{
|
||||
//if (elemOutsideView(elemIndex))
|
||||
// continue;
|
||||
|
||||
QgsPointXY center = centroids.at( i );
|
||||
double xVal = mDatasetValuesX[i];
|
||||
double yVal = mDatasetValuesY[i];
|
||||
double V = mDatasetValuesMag[i]; // pre-calculated magnitude
|
||||
QgsPointXY lineStart = mContext.mapToPixel().transform( center.x(), center.y() );
|
||||
|
||||
drawVectorArrow( lineStart, xVal, yVal, V );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QgsMeshVectorRenderer::drawVectorArrow( const QgsPointXY &lineStart, double xVal, double yVal, double magnitude )
|
||||
{
|
||||
QgsPointXY lineEnd;
|
||||
double vectorLength;
|
||||
double cosAlpha, sinAlpha;
|
||||
if ( calcVectorLineEnd( lineEnd, vectorLength, cosAlpha, sinAlpha,
|
||||
lineStart, xVal, yVal, magnitude ) )
|
||||
return;
|
||||
|
||||
// Make a set of vector head coordinates that we will place at the end of each vector,
|
||||
// scale, translate and rotate.
|
||||
QgsPointXY vectorHeadPoints[3];
|
||||
QVector<QPointF> finalVectorHeadPoints( 3 );
|
||||
|
||||
double vectorHeadWidthRatio = mCfg.arrowHeadWidthRatio();
|
||||
double vectorHeadLengthRatio = mCfg.arrowHeadLengthRatio();
|
||||
|
||||
// First head point: top of ->
|
||||
vectorHeadPoints[0].setX( -1.0 * vectorHeadLengthRatio );
|
||||
vectorHeadPoints[0].setY( vectorHeadWidthRatio * 0.5 );
|
||||
|
||||
// Second head point: right of ->
|
||||
vectorHeadPoints[1].setX( 0.0 );
|
||||
vectorHeadPoints[1].setY( 0.0 );
|
||||
|
||||
// Third head point: bottom of ->
|
||||
vectorHeadPoints[2].setX( -1.0 * vectorHeadLengthRatio );
|
||||
vectorHeadPoints[2].setY( -1.0 * vectorHeadWidthRatio * 0.5 );
|
||||
|
||||
// Determine the arrow head coords
|
||||
for ( int j = 0; j < 3; j++ )
|
||||
{
|
||||
finalVectorHeadPoints[j].setX( lineEnd.x()
|
||||
+ ( vectorHeadPoints[j].x() * cosAlpha * vectorLength )
|
||||
- ( vectorHeadPoints[j].y() * sinAlpha * vectorLength )
|
||||
);
|
||||
|
||||
finalVectorHeadPoints[j].setY( lineEnd.y()
|
||||
- ( vectorHeadPoints[j].x() * sinAlpha * vectorLength )
|
||||
- ( vectorHeadPoints[j].y() * cosAlpha * vectorLength )
|
||||
);
|
||||
}
|
||||
|
||||
// Now actually draw the vector
|
||||
mContext.painter()->drawLine( lineStart.toQPointF(), lineEnd.toQPointF() );
|
||||
mContext.painter()->drawPolygon( finalVectorHeadPoints );
|
||||
}
|
103
src/core/mesh/qgsmeshvectorrenderer.h
Normal file
103
src/core/mesh/qgsmeshvectorrenderer.h
Normal file
@ -0,0 +1,103 @@
|
||||
/***************************************************************************
|
||||
qgstriangularmesh.h
|
||||
-------------------
|
||||
begin : April 2018
|
||||
copyright : (C) 2018 by Peter Petrik
|
||||
email : zilolv at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSMESHVECTORRENDERER_H
|
||||
#define QGSMESHVECTORRENDERER_H
|
||||
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include <QVector>
|
||||
#include <QSize>
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgsmeshdataprovider.h"
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgstriangularmesh.h"
|
||||
#include "qgsmeshlayer.h"
|
||||
#include "qgspointxy.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
*
|
||||
* Helper private class for rendering vector datasets (e.g. velocity)
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
* \note not available in Python bindings
|
||||
*/
|
||||
class QgsMeshVectorRenderer
|
||||
{
|
||||
public:
|
||||
//! Ctor
|
||||
QgsMeshVectorRenderer( const QgsTriangularMesh &m,
|
||||
const QVector<double> &datasetValuesX,
|
||||
const QVector<double> &datasetValuesY,
|
||||
const QVector<double> &datasetValuesMag,
|
||||
bool dataIsOnVertices,
|
||||
const QgsMeshRendererVectorSettings &settings,
|
||||
QgsRenderContext &context,
|
||||
const QSize &size );
|
||||
//! Dtor
|
||||
~QgsMeshVectorRenderer();
|
||||
|
||||
/**
|
||||
* Draws vector arrows in the context's painter base on settings
|
||||
*/
|
||||
void draw();
|
||||
|
||||
private:
|
||||
//! Draws for data defined on vertices
|
||||
void drawVectorDataOnVertices();
|
||||
//! Draws for data defined on face centers
|
||||
void drawVectorDataOnFaces();
|
||||
//! Draws arrow from start point and vector data
|
||||
void drawVectorArrow( const QgsPointXY &lineStart, double xVal, double yVal, double magnitude );
|
||||
//! Calculates the end point of the arrow based on start point and vector data
|
||||
bool calcVectorLineEnd( QgsPointXY &lineEnd,
|
||||
double &vectorLength,
|
||||
double &cosAlpha,
|
||||
double &sinAlpha, //out
|
||||
const QgsPointXY &lineStart,
|
||||
double xVal,
|
||||
double yVal,
|
||||
double magnitude //in
|
||||
);
|
||||
|
||||
|
||||
const QgsTriangularMesh &mTriangularMesh;
|
||||
const QVector<double> &mDatasetValuesX;
|
||||
const QVector<double> &mDatasetValuesY;
|
||||
const QVector<double> &mDatasetValuesMag; //magnitudes
|
||||
double mMinX;
|
||||
double mMaxX;
|
||||
double mMinY;
|
||||
double mMaxY;
|
||||
double mMinMag;
|
||||
double mMaxMag;
|
||||
QgsRenderContext &mContext;
|
||||
const QgsMeshRendererVectorSettings &mCfg;
|
||||
bool mDataOnVertices;
|
||||
QSize mOutputSize;
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
||||
|
||||
|
||||
#endif // QGSMESHVECTORRENDERER_H
|
@ -19,6 +19,51 @@
|
||||
#include "qgsrendercontext.h"
|
||||
#include "qgscoordinatetransform.h"
|
||||
|
||||
static void ENP_centroid_step( const QPolygonF &pX, double &cx, double &cy, double &signedArea, int i, int i1 )
|
||||
{
|
||||
double x0 = 0.0; // Current vertex X
|
||||
double y0 = 0.0; // Current vertex Y
|
||||
double x1 = 0.0; // Next vertex X
|
||||
double y1 = 0.0; // Next vertex Y
|
||||
double a = 0.0; // Partial signed area
|
||||
|
||||
x0 = pX[i].x();
|
||||
y0 = pX[i].y();
|
||||
x1 = pX[i1].x();
|
||||
y1 = pX[i1].y();
|
||||
a = x0 * y1 - x1 * y0;
|
||||
signedArea += a;
|
||||
cx += ( x0 + x1 ) * a;
|
||||
cy += ( y0 + y1 ) * a;
|
||||
}
|
||||
|
||||
static void ENP_centroid( const QPolygonF &pX, double &cx, double &cy )
|
||||
{
|
||||
// http://stackoverflow.com/questions/2792443/finding-the-centroid-of-a-polygon/2792459#2792459
|
||||
cx = 0;
|
||||
cy = 0;
|
||||
|
||||
if ( pX.isEmpty() )
|
||||
return;
|
||||
|
||||
double signedArea = 0.0;
|
||||
|
||||
// For all vertices except last
|
||||
int i = 0;
|
||||
for ( ; i < pX.size() - 1; ++i )
|
||||
{
|
||||
ENP_centroid_step( pX, cx, cy, signedArea, i, i + 1 );
|
||||
}
|
||||
// Do last vertex separately to avoid performing an expensive
|
||||
// modulus operation in each iteration.
|
||||
ENP_centroid_step( pX, cx, cy, signedArea, i, 0 );
|
||||
|
||||
signedArea *= 0.5;
|
||||
cx /= ( 6.0 * signedArea );
|
||||
cy /= ( 6.0 * signedArea );
|
||||
}
|
||||
|
||||
|
||||
void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
|
||||
{
|
||||
Q_ASSERT( nativeMesh );
|
||||
@ -27,6 +72,7 @@ void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
|
||||
mTriangularMesh.vertices.clear();
|
||||
mTriangularMesh.faces.clear();
|
||||
mTrianglesToNativeFaces.clear();
|
||||
mNativeMeshFaceCentroids.clear();
|
||||
|
||||
// TRANSFORM VERTICES
|
||||
QgsCoordinateTransform transform = context->coordinateTransform();
|
||||
@ -79,6 +125,23 @@ void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
|
||||
}
|
||||
}
|
||||
|
||||
// CALCULATE CENTROIDS
|
||||
mNativeMeshFaceCentroids.resize( nativeMesh->faces.size() );
|
||||
for ( int i = 0; i < nativeMesh->faces.size(); ++i )
|
||||
{
|
||||
const QgsMeshFace &face = nativeMesh->faces.at( i ) ;
|
||||
QVector<QPointF> points;
|
||||
for ( int j = 0; j < face.size(); ++j )
|
||||
{
|
||||
int index = face.at( j );
|
||||
const QgsMeshVertex &vertex = mTriangularMesh.vertices[index]; // we need projected vertices
|
||||
points.push_back( vertex.toQPointF() );
|
||||
}
|
||||
QPolygonF poly( points );
|
||||
double cx, cy;
|
||||
ENP_centroid( poly, cx, cy );
|
||||
mNativeMeshFaceCentroids[i] = QgsMeshVertex( cx, cy );
|
||||
}
|
||||
}
|
||||
|
||||
const QVector<QgsMeshVertex> &QgsTriangularMesh::vertices() const
|
||||
@ -91,6 +154,11 @@ const QVector<QgsMeshFace> &QgsTriangularMesh::triangles() const
|
||||
return mTriangularMesh.faces;
|
||||
}
|
||||
|
||||
const QVector<QgsMeshVertex> &QgsTriangularMesh::centroids() const
|
||||
{
|
||||
return mNativeMeshFaceCentroids;
|
||||
}
|
||||
|
||||
const QVector<int> &QgsTriangularMesh::trianglesToNativeFaces() const
|
||||
{
|
||||
return mTrianglesToNativeFaces;
|
||||
|
@ -55,22 +55,26 @@ class CORE_EXPORT QgsTriangularMesh
|
||||
~QgsTriangularMesh() = default;
|
||||
|
||||
/**
|
||||
* Construct triangular mesh from layer's native mesh and context
|
||||
* Constructs triangular mesh from layer's native mesh and context
|
||||
* \param nativeMesh QgsMesh to access native vertices and faces
|
||||
* \param context Rendering context to estimate number of triagles to create for an face
|
||||
*/
|
||||
void update( QgsMesh *nativeMesh, QgsRenderContext *context );
|
||||
|
||||
/**
|
||||
* Return vertices in map CRS
|
||||
* Returns vertices in map CRS
|
||||
*
|
||||
* The list of consist of vertices from native mesh (0-N) and
|
||||
* extra vertices needed to create triangles (N+1 - len)
|
||||
*/
|
||||
const QVector<QgsMeshVertex> &vertices() const ;
|
||||
//! Return triangles
|
||||
//! Returns triangles
|
||||
const QVector<QgsMeshFace> &triangles() const ;
|
||||
//! Return mapping between triangles and original faces
|
||||
|
||||
//! Returns centroids of the native faces in map CRS
|
||||
const QVector<QgsMeshVertex> ¢roids() const ;
|
||||
|
||||
//! Returns mapping between triangles and original faces
|
||||
const QVector<int> &trianglesToNativeFaces() const ;
|
||||
|
||||
private:
|
||||
@ -78,6 +82,9 @@ class CORE_EXPORT QgsTriangularMesh
|
||||
// faces are derived triangles
|
||||
QgsMesh mTriangularMesh;
|
||||
QVector<int> mTrianglesToNativeFaces; //len(mTrianglesToNativeFaces) == len(mTriangles). Mapping derived -> native
|
||||
|
||||
// centroids of the native faces in map CRS
|
||||
QVector<QgsMeshVertex> mNativeMeshFaceCentroids;
|
||||
};
|
||||
|
||||
|
||||
|
@ -23,8 +23,8 @@ class QgsMdalLayerItem : public QgsLayerItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
//! Ctor
|
||||
QgsMdalLayerItem( QgsDataItem *parent, const QString &name, const QString &path, const QString &uri );
|
||||
|
||||
QString layerName() const override;
|
||||
};
|
||||
|
||||
|
@ -64,14 +64,22 @@ class TestQgsMeshRenderer : public QObject
|
||||
|
||||
void test_native_mesh_rendering();
|
||||
void test_triangular_mesh_rendering();
|
||||
|
||||
void test_vertex_scalar_dataset_rendering();
|
||||
void test_vertex_vector_dataset_rendering();
|
||||
void test_face_scalar_dataset_rendering();
|
||||
void test_face_vector_dataset_rendering();
|
||||
};
|
||||
|
||||
void TestQgsMeshRenderer::init()
|
||||
{
|
||||
mMemoryLayer->toggleTriangularMeshRendering( false );
|
||||
mMemoryLayer->setActiveScalarDataset();
|
||||
mMemoryLayer->setActiveVectorDataset();
|
||||
|
||||
mMemoryLayer->setRendererNativeMeshSettings( QgsMeshRendererMeshSettings() );
|
||||
mMemoryLayer->setRendererTriangularMeshSettings( QgsMeshRendererMeshSettings() );
|
||||
mMemoryLayer->setRendererScalarSettings( QgsMeshRendererScalarSettings() );
|
||||
mMemoryLayer->setRendererVectorSettings( QgsMeshRendererVectorSettings() );
|
||||
}
|
||||
|
||||
void TestQgsMeshRenderer::initTestCase()
|
||||
@ -128,15 +136,20 @@ bool TestQgsMeshRenderer::imageCheck( const QString &testType )
|
||||
|
||||
void TestQgsMeshRenderer::test_native_mesh_rendering()
|
||||
{
|
||||
mMemoryLayer->toggleTriangularMeshRendering( false );
|
||||
QVERIFY( mMemoryLayer->triangularMeshSymbol() == nullptr );
|
||||
QgsMeshRendererMeshSettings settings = mMemoryLayer->rendererNativeMeshSettings();
|
||||
settings.setEnabled( true );
|
||||
settings.setLineWidth( 1. );
|
||||
mMemoryLayer->setRendererNativeMeshSettings( settings );
|
||||
QVERIFY( imageCheck( "quad_and_triangle_native_mesh" ) );
|
||||
}
|
||||
|
||||
void TestQgsMeshRenderer::test_triangular_mesh_rendering()
|
||||
{
|
||||
mMemoryLayer->toggleTriangularMeshRendering( true );
|
||||
QVERIFY( mMemoryLayer->triangularMeshSymbol() != nullptr );
|
||||
QgsMeshRendererMeshSettings settings = mMemoryLayer->rendererTriangularMeshSettings();
|
||||
settings.setEnabled( true );
|
||||
settings.setColor( Qt::red );
|
||||
settings.setLineWidth( 0.26 );
|
||||
mMemoryLayer->setRendererTriangularMeshSettings( settings );
|
||||
QVERIFY( imageCheck( "quad_and_triangle_triangular_mesh" ) );
|
||||
}
|
||||
|
||||
@ -146,9 +159,39 @@ void TestQgsMeshRenderer::test_vertex_scalar_dataset_rendering()
|
||||
mMemoryLayer->setActiveScalarDataset( ds );
|
||||
QgsMeshDatasetMetadata metadata = mMemoryLayer->dataProvider()->datasetMetadata( ds );
|
||||
QVERIFY( metadata["name"] == "VertexScalarDataset" );
|
||||
QVERIFY( imageCheck( "quad_and_triangle_vertex_scalar_dataset" ) );
|
||||
}
|
||||
|
||||
// TODO!
|
||||
// QVERIFY( imageCheck( "quad_and_triangle_vertex_scalar_dataset" ) );
|
||||
void TestQgsMeshRenderer::test_vertex_vector_dataset_rendering()
|
||||
{
|
||||
int ds = 1;
|
||||
mMemoryLayer->setActiveVectorDataset( ds );
|
||||
QgsMeshDatasetMetadata metadata = mMemoryLayer->dataProvider()->datasetMetadata( ds );
|
||||
QVERIFY( metadata["name"] == "VertexVectorDataset" );
|
||||
|
||||
QgsMeshRendererVectorSettings settings = mMemoryLayer->rendererVectorSettings();
|
||||
settings.setMinShaftLength( 15 );
|
||||
mMemoryLayer->setRendererVectorSettings( settings );
|
||||
|
||||
QVERIFY( imageCheck( "quad_and_triangle_vertex_vector_dataset" ) );
|
||||
}
|
||||
|
||||
void TestQgsMeshRenderer::test_face_scalar_dataset_rendering()
|
||||
{
|
||||
int ds = 2;
|
||||
mMemoryLayer->setActiveScalarDataset( ds );
|
||||
QgsMeshDatasetMetadata metadata = mMemoryLayer->dataProvider()->datasetMetadata( ds );
|
||||
QVERIFY( metadata["name"] == "FaceScalarDataset" );
|
||||
QVERIFY( imageCheck( "quad_and_triangle_face_scalar_dataset" ) );
|
||||
}
|
||||
|
||||
void TestQgsMeshRenderer::test_face_vector_dataset_rendering()
|
||||
{
|
||||
int ds = 3;
|
||||
mMemoryLayer->setActiveVectorDataset( ds );
|
||||
QgsMeshDatasetMetadata metadata = mMemoryLayer->dataProvider()->datasetMetadata( ds );
|
||||
QVERIFY( metadata["name"] == "FaceVectorDataset" );
|
||||
QVERIFY( imageCheck( "quad_and_triangle_face_vector_dataset" ) );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsMeshRenderer )
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
Loading…
x
Reference in New Issue
Block a user