21#include <QRegularExpression>
22#include <QRegularExpressionMatch>
90 if ( !averagingMethod )
97 block = averagingMethod->
calculate( block3d );
102QVector<QgsVector> QgsMeshLayerUtils::griddedVectorValues(
const QgsMeshLayer *meshLayer,
109 QVector<QgsVector> vectors;
111 if ( !meshLayer || !index.
isValid() )
117 if ( !triangularMesh || !nativeMesh )
126 const int datacount = vectorDataOnVertices ? nativeMesh->
vertices.count() : nativeMesh->
faces.count();
127 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues( meshLayer, index, 0, datacount );
137 vectors.reserve( size.height()*size.width() );
142 return QVector<QgsVector>();
145 for (
int iy = 0; iy < size.height(); ++iy )
147 const double y = minCorner.
y() + iy * ySpacing;
148 for (
int ix = 0; ix < size.width(); ++ix )
150 const double x = minCorner.
x() + ix * xSpacing;
153 int nativeFaceIndex = -1;
154 if ( faceIndex != -1 )
157 if ( nativeFaceIndex != -1 && isFacesActive.
active( nativeFaceIndex ) )
163 value = vals.
value( nativeFaceIndex );
168 const int v1 = face[0], v2 = face[1], v3 = face[2];
173 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
x(), val2.
x(), val3.
x(), point );
174 const double y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
y(), val2.
y(), val3.
y(), point );
182 vectors.append(
QgsVector( value.
x(), value.
y() ) );
188QVector<double> QgsMeshLayerUtils::calculateMagnitudes(
const QgsMeshDataBlock &block )
191 const int count = block.
count();
192 QVector<double> ret( count );
194 for (
int i = 0; i < count; ++i )
202QgsRectangle QgsMeshLayerUtils::boundingBoxToScreenRectangle(
205 double devicePixelRatio
213 const double xMin = std::min( {topLeft.
x(), topRight.
x(), bottomLeft.
x(), bottomRight.
x()} );
214 const double xMax = std::max( {topLeft.
x(), topRight.
x(), bottomLeft.
x(), bottomRight.
x()} );
215 const double yMin = std::min( {topLeft.
y(), topRight.
y(), bottomLeft.
y(), bottomRight.
y()} );
216 const double yMax = std::max( {topLeft.
y(), topRight.
y(), bottomLeft.
y(), bottomRight.
y()} );
222void QgsMeshLayerUtils::boundingBoxToScreenRectangle(
224 const QSize &outputSize,
230 double devicePixelRatio )
232 const QgsRectangle screenBBox = boundingBoxToScreenRectangle( mtp, bbox, devicePixelRatio );
234 bottomLim = std::max(
int( screenBBox.
yMinimum() ), 0 );
235 topLim = std::min(
int( screenBBox.
yMaximum() ), outputSize.height() - 1 );
236 leftLim = std::max(
int( screenBBox.
xMinimum() ), 0 );
237 rightLim = std::min(
int( screenBBox.
xMaximum() ), outputSize.width() - 1 );
240static void lamTol(
double &lam )
242 const static double eps = 1e-6;
243 if ( ( lam < 0.0 ) && ( lam > -eps ) )
250 double &lam1,
double &lam2,
double &lam3 )
253 const double xa = pA.
x();
254 const double ya = pA.
y();
255 const double v0x = pC.
x() - xa ;
256 const double v0y = pC.
y() - ya ;
257 const double v1x = pB.
x() - xa ;
258 const double v1y = pB.
y() - ya ;
259 const double v2x = pP.
x() - xa ;
260 const double v2y = pP.
y() - ya ;
263 const double dot00 = v0x * v0x + v0y * v0y;
264 const double dot01 = v0x * v1x + v0y * v1y;
265 const double dot02 = v0x * v2x + v0y * v2y;
266 const double dot11 = v1x * v1x + v1y * v1y;
267 const double dot12 = v1x * v2x + v1y * v2y;
270 double invDenom = dot00 * dot11 - dot01 * dot01;
273 invDenom = 1.0 / invDenom;
274 lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
275 lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
276 lam3 = 1.0 - lam1 - lam2;
284 if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
292bool QgsMeshLayerUtils::calculateBarycentricCoordinates(
294 double &lam1,
double &lam2,
double &lam3 )
296 return E3T_physicalToBarycentric( pA, pB, pC, pP, lam1, lam2, lam3 );
300 double val1,
double val2,
double val3,
const QgsPointXY &pt )
302 double lam1, lam2, lam3;
303 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
304 return std::numeric_limits<double>::quiet_NaN();
306 return lam1 * val3 + lam2 * val2 + lam3 * val1;
309double QgsMeshLayerUtils::interpolateZForPoint(
const QgsTriangularMesh &mesh,
double x,
double y )
313 if ( faceIndex < 0 || faceIndex >= mesh.
triangles().count() )
314 return std::numeric_limits<float>::quiet_NaN();
322 return QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(), point );
325double QgsMeshLayerUtils::interpolateFromVerticesData(
double fraction,
double val1,
double val2 )
327 if ( std::isnan( val1 ) || std::isnan( val2 ) || ( fraction < 0 ) || ( fraction > 1 ) )
329 return std::numeric_limits<double>::quiet_NaN();
331 return val1 + ( val2 - val1 ) * fraction;
337 interpolateFromVerticesData( fraction, val1.
y(), val2.
y() ) );
343 double lam1, lam2, lam3;
344 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
345 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
347 return vect3 * lam1 + vect2 * lam2 + vect1 * lam3;
353 double lam1, lam2, lam3;
354 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
355 return std::numeric_limits<double>::quiet_NaN();
363 double lam1, lam2, lam3;
364 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
365 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
371QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
372 QVector<double> valuesOnFaces,
378 assert( nativeMesh );
380 Q_UNUSED( triangularMesh );
385 return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
388QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
const QVector<double> &valuesOnFaces,
396 activeFace = *active;
403 return interpolateFromFacesData( valuesOnFaces, nativeMesh, activeFace, method );
413 QVector<double> res( vertexCount, 0.0 );
415 QVector<int> count( vertexCount, 0 );
417 for (
int i = 0; i < nativeMesh.
faceCount(); ++i )
421 const double val = valuesOnFaces[ i ];
422 if ( !std::isnan( val ) )
426 for (
int j = 0; j < face.size(); ++j )
428 const int vertexIndex = face[j];
429 res[vertexIndex] += val;
430 count[vertexIndex] += 1;
436 for (
int i = 0; i < vertexCount; ++i )
438 if ( count.at( i ) > 0 )
440 res[i] = res[i] / double( count.at( i ) );
444 res[i] = std::numeric_limits<double>::quiet_NaN();
451QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
452 const QVector<double> valuesOnVertices,
458 assert( nativeMesh );
463 Q_UNUSED( triangularMesh );
466 QVector<double> ret( nativeMesh->
faceCount(), std::numeric_limits<double>::quiet_NaN() );
468 for (
int i = 0; i < nativeMesh->
faces.size(); ++i )
471 if ( active->
active( i ) && face.count() > 2 )
474 for (
int j = 0; j < face.count(); ++j )
476 value += valuesOnVertices.at( face.at( j ) );
478 ret[i] = value / face.count();
485QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices(
const QgsMeshLayer *meshLayer,
492 if ( !meshLayer && !index.
isValid() )
497 if ( !triangularMesh || !nativeMesh )
504 const int datacount = scalarDataOnVertices ? nativeMesh->
vertices.count() : nativeMesh->
faces.count();
512 if ( !activeFaceFlagValues )
518 activeFace = *activeFaceFlagValues;
520 return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, activeFace, method );
523QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices(
const QgsMesh &nativeMesh,
534 ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
536 if ( !scalarDataOnVertices )
539 ret = QgsMeshLayerUtils::interpolateFromFacesData(
542 activeFaceFlagValues,
552 double xMin = p1.
x();
553 double xMax = p1.
x();
554 double yMin = p1.
y();
555 double yMax = p1.
y();
558 xMin = ( ( xMin < p2.
x() ) ? xMin : p2.x() );
559 xMax = ( ( xMax > p2.
x() ) ? xMax : p2.x() );
560 yMin = ( ( yMin < p2.
y() ) ? yMin : p2.y() );
561 yMax = ( ( yMax > p2.
y() ) ? yMax : p2.y() );
564 xMin = ( ( xMin < p3.
x() ) ? xMin : p3.x() );
565 xMax = ( ( xMax > p3.
x() ) ? xMax : p3.x() );
566 yMin = ( ( yMin < p3.
y() ) ? yMin : p3.y() );
567 yMax = ( ( yMax > p3.
y() ) ? yMax : p3.y() );
573QString QgsMeshLayerUtils::formatTime(
double hours,
const QDateTime &referenceTime,
const QgsMeshTimeSettings &settings )
577 if ( referenceTime.isValid() )
580 QDateTime dateTime( referenceTime );
581 const qint64 seconds =
static_cast<qint64
>( hours * 3600.0 );
582 dateTime = dateTime.addSecs( seconds );
583 ret = dateTime.toString( format );
585 ret = dateTime.toString();
590 format = format.trimmed();
591 const int totalHours =
static_cast<int>( hours );
593 if ( format == QLatin1String(
"hh:mm:ss.zzz" ) )
595 const int ms =
static_cast<int>( hours * 3600.0 * 1000 );
596 const int seconds = ms / 1000;
597 const int z = ms % 1000;
598 int m = seconds / 60;
599 const int s = seconds % 60;
600 const int h = m / 60;
602 ret = QStringLiteral(
"%1:%2:%3.%4" ).
603 arg( h, 2, 10, QLatin1Char(
'0' ) ).
604 arg( m, 2, 10, QLatin1Char(
'0' ) ).
605 arg( s, 2, 10, QLatin1Char(
'0' ) ).
606 arg( z, 3, 10, QLatin1Char(
'0' ) );
608 else if ( format == QLatin1String(
"hh:mm:ss" ) )
610 const int seconds =
static_cast<int>( hours * 3600.0 );
611 int m = seconds / 60;
612 const int s = seconds % 60;
613 const int h = m / 60;
615 ret = QStringLiteral(
"%1:%2:%3" ).
616 arg( h, 2, 10, QLatin1Char(
'0' ) ).
617 arg( m, 2, 10, QLatin1Char(
'0' ) ).
618 arg( s, 2, 10, QLatin1Char(
'0' ) );
621 else if ( format == QLatin1String(
"d hh:mm:ss" ) )
623 const int seconds =
static_cast<int>( hours * 3600.0 );
624 int m = seconds / 60;
625 const int s = seconds % 60;
628 const int d = totalHours / 24;
630 ret = QStringLiteral(
"%1 d %2:%3:%4" ).
632 arg( h, 2, 10, QLatin1Char(
'0' ) ).
633 arg( m, 2, 10, QLatin1Char(
'0' ) ).
634 arg( s, 2, 10, QLatin1Char(
'0' ) );
636 else if ( format == QLatin1String(
"d hh" ) )
638 const int d = totalHours / 24;
639 const int h = totalHours % 24;
640 ret = QStringLiteral(
"%1 d %2" ).
644 else if ( format == QLatin1String(
"d" ) )
646 const int d = totalHours / 24;
647 ret = QString::number( d );
649 else if ( format == QLatin1String(
"ss" ) )
651 const int seconds =
static_cast<int>( hours * 3600.0 );
652 ret = QString::number( seconds );
656 ret = QString::number( hours );
662QVector<QVector3D> QgsMeshLayerUtils::calculateNormals(
const QgsTriangularMesh &triangularMesh,
const QVector<double> &verticalMagnitude,
bool isRelative )
664 QVector<QVector3D> normals( triangularMesh.
vertices().count() );
665 for (
const auto &face : triangularMesh.triangles() )
667 for (
int i = 0; i < 3; i++ )
669 const int index( face.at( i ) );
670 const int index1( face.at( ( i + 1 ) % 3 ) );
671 const int index2( face.at( ( i + 2 ) % 3 ) );
673 if ( std::isnan( verticalMagnitude[index] ) ||
674 std::isnan( verticalMagnitude[index1] ) ||
675 std::isnan( verticalMagnitude[index2] ) )
682 float adjustRelative = 0;
683 float adjustRelative1 = 0;
684 float adjustRelative2 = 0;
688 adjustRelative = vert.z();
689 adjustRelative1 = otherVert1.z();
690 adjustRelative2 = otherVert2.z();
693 const QVector3D v1(
float( otherVert1.x() - vert.x() ),
694 float( otherVert1.y() - vert.y() ),
695 float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
696 const QVector3D v2(
float( otherVert2.x() - vert.x() ),
697 float( otherVert2.y() - vert.y() ),
698 float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
700 normals[index] += QVector3D::crossProduct( v1, v2 );
Perform transforms between map coordinates and device coordinates.
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Abstract class to interpolate 3d stacked mesh data to 2d data.
QgsMeshDataBlock calculate(const QgsMesh3DDataBlock &block3d, QgsFeedback *feedback=nullptr) const
Calculated 2d block values from 3d stacked mesh values.
QgsMesh3DDataBlock is a block of 3d stacked mesh data related N faces defined on base mesh frame.
bool isValid() const
Whether the block is valid.
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e....
QgsMeshDatasetValue value(int index) const
Returns a value represented by the index For active flag the behavior is undefined.
bool isValid() const
Whether the block is valid.
DataType type() const
Type of data stored in the block.
@ ActiveFlagInteger
Integer boolean flag whether face is active.
bool active(int index) const
Returns a value for active flag by the index For scalar and vector 2d the behavior is undefined.
int count() const
Number of items stored in the block.
void setValid(bool valid)
Sets block validity.
QgsMeshDatasetIndex is index that identifies the dataset group (e.g.
bool isValid() const
Returns whether index is valid, ie at least groups is set.
int group() const
Returns a group index.
QgsMeshDatasetValue represents single dataset value.
double y() const
Returns y value.
double scalar() const
Returns magnitude of vector for vector data or scalar value for scalar data.
double x() const
Returns x value.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
int datasetCount(const QgsMeshDatasetIndex &index) const
Returns the dataset count in the dataset groups.
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh)
QgsMeshDataBlock datasetValues(const QgsMeshDatasetIndex &index, int valueIndex, int count) const
Returns N vector/scalar values from the index from the dataset.
QgsMeshDataBlock areFacesActive(const QgsMeshDatasetIndex &index, int faceIndex, int count) const
Returns whether the faces are active for particular dataset.
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
QgsMesh3DDataBlock dataset3dValues(const QgsMeshDatasetIndex &index, int faceIndex, int count) const
Returns N vector/scalar values from the face index from the dataset for 3d stacked meshes.
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
DataResamplingMethod
Resampling of value from dataset.
@ NeighbourAverage
Does a simple average of values defined for all surrounding faces/vertices.
QgsMesh3DAveragingMethod * averagingMethod() const
Returns averaging method for conversion of 3d stacked mesh data to 2d data.
Represents a mesh time settings for mesh datasets.
QString relativeTimeFormat() const
Returns format used for relative time.
QString absoluteTimeFormat() const
Returns format used for absolute time.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
A rectangle specified with double values.
Triangular/Derived Mesh is mesh with vertices in map coordinates.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
int faceIndexForPoint_v2(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing and don't use geos to be faster.
A class to represent a vector.
#define QgsDebugMsgLevel(str, level)
QVector< int > QgsMeshFace
List of vertex indexes.
Mesh - vertices, edges and faces.
int vertexCount() const
Returns number of vertices.
QVector< QgsMeshVertex > vertices
QgsMeshFace face(int index) const
Returns a face at the index.
QVector< QgsMeshFace > faces
int faceCount() const
Returns number of faces.
int edgeCount() const
Returns number of edge.