30#include <QRegularExpression>
31#include <QRegularExpressionMatch>
35using namespace Qt::StringLiterals;
90 if ( !averagingMethod )
97 block = averagingMethod->
calculate( block3d );
102QVector<QgsVector> QgsMeshLayerUtils::griddedVectorValues(
const QgsMeshLayer *meshLayer,
const QgsMeshDatasetIndex index,
double xSpacing,
double ySpacing,
const QSize &size,
const QgsPointXY &minCorner )
104 QVector<QgsVector> vectors;
106 if ( !meshLayer || !index.
isValid() )
112 if ( !triangularMesh || !nativeMesh )
121 const int datacount = vectorDataOnVertices ? nativeMesh->
vertices.count() : nativeMesh->
faces.count();
122 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues( meshLayer, index, 0, datacount );
132 vectors.reserve( size.height() * size.width() );
137 return QVector<QgsVector>();
140 for (
int iy = 0; iy < size.height(); ++iy )
142 const double y = minCorner.
y() + iy * ySpacing;
143 for (
int ix = 0; ix < size.width(); ++ix )
145 const double x = minCorner.
x() + ix * xSpacing;
148 int nativeFaceIndex = -1;
149 if ( faceIndex != -1 )
152 if ( nativeFaceIndex != -1 && isFacesActive.
active( nativeFaceIndex ) )
158 value = vals.
value( nativeFaceIndex );
163 const int v1 = face[0], v2 = face[1], v3 = face[2];
168 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
x(), val2.
x(), val3.
x(), point );
169 const double y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
y(), val2.
y(), val3.
y(), point );
177 vectors.append(
QgsVector( value.
x(), value.
y() ) );
183QVector<double> QgsMeshLayerUtils::calculateMagnitudes(
const QgsMeshDataBlock &block )
186 const int count = block.
count();
187 QVector<double> ret( count );
189 for (
int i = 0; i < count; ++i )
204 const double xMin = std::min( { topLeft.
x(), topRight.
x(), bottomLeft.
x(), bottomRight.
x() } );
205 const double xMax = std::max( { topLeft.
x(), topRight.
x(), bottomLeft.
x(), bottomRight.
x() } );
206 const double yMin = std::min( { topLeft.
y(), topRight.
y(), bottomLeft.
y(), bottomRight.
y() } );
207 const double yMax = std::max( { topLeft.
y(), topRight.
y(), bottomLeft.
y(), bottomRight.
y() } );
213void QgsMeshLayerUtils::boundingBoxToScreenRectangle(
214 const QgsMapToPixel &mtp,
const QSize &outputSize,
const QgsRectangle &bbox,
int &leftLim,
int &rightLim,
int &bottomLim,
int &topLim,
double devicePixelRatio
217 const QgsRectangle screenBBox = boundingBoxToScreenRectangle( mtp, bbox, devicePixelRatio );
219 bottomLim = std::max(
int( screenBBox.
yMinimum() ), 0 );
220 topLim = std::min(
int( screenBBox.
yMaximum() ), outputSize.height() - 1 );
221 leftLim = std::max(
int( screenBBox.
xMinimum() ), 0 );
222 rightLim = std::min(
int( screenBBox.
xMaximum() ), outputSize.width() - 1 );
225static void lamTol(
double &lam )
227 const static double eps = 1e-6;
228 if ( ( lam < 0.0 ) && ( lam > -eps ) )
237 const double xa = pA.
x();
238 const double ya = pA.
y();
239 const double v0x = pC.
x() - xa;
240 const double v0y = pC.
y() - ya;
241 const double v1x = pB.
x() - xa;
242 const double v1y = pB.
y() - ya;
243 const double v2x = pP.
x() - xa;
244 const double v2y = pP.
y() - ya;
247 const double dot00 = v0x * v0x + v0y * v0y;
248 const double dot01 = v0x * v1x + v0y * v1y;
249 const double dot02 = v0x * v2x + v0y * v2y;
250 const double dot11 = v1x * v1x + v1y * v1y;
251 const double dot12 = v1x * v2x + v1y * v2y;
254 double invDenom = dot00 * dot11 - dot01 * dot01;
257 invDenom = 1.0 / invDenom;
258 lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
259 lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
260 lam3 = 1.0 - lam1 - lam2;
268 if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
278 return E3T_physicalToBarycentric( pA, pB, pC, pP, lam1, lam2, lam3 );
283 double lam1, lam2, lam3;
284 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
285 return std::numeric_limits<double>::quiet_NaN();
287 return lam1 * val3 + lam2 * val2 + lam3 * val1;
290double QgsMeshLayerUtils::interpolateZForPoint(
const QgsTriangularMesh &mesh,
double x,
double y )
294 if ( faceIndex < 0 || faceIndex >= mesh.
triangles().count() )
295 return std::numeric_limits<float>::quiet_NaN();
303 return QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(), point );
306double QgsMeshLayerUtils::interpolateFromVerticesData(
double fraction,
double val1,
double val2 )
308 if ( std::isnan( val1 ) || std::isnan( val2 ) || ( fraction < 0 ) || ( fraction > 1 ) )
310 return std::numeric_limits<double>::quiet_NaN();
312 return val1 + ( val2 - val1 ) * fraction;
317 return QgsMeshDatasetValue( interpolateFromVerticesData( fraction, val1.
x(), val2.
x() ), interpolateFromVerticesData( fraction, val1.
y(), val2.
y() ) );
323 double lam1, lam2, lam3;
324 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
325 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
327 return vect3 * lam1 + vect2 * lam2 + vect1 * lam3;
332 double lam1, lam2, lam3;
333 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
334 return std::numeric_limits<double>::quiet_NaN();
341 double lam1, lam2, lam3;
342 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
343 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
349QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
353 assert( nativeMesh );
355 Q_UNUSED( triangularMesh );
360 return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
363QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
369 activeFace = *active;
376 return interpolateFromFacesData( valuesOnFaces, nativeMesh, activeFace, method );
379QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
387 QVector<double> res( vertexCount, 0.0 );
389 QVector<int> count( vertexCount, 0 );
391 for (
int i = 0; i < nativeMesh.
faceCount(); ++i )
395 const double val = valuesOnFaces[i];
396 if ( !std::isnan( val ) )
400 for (
int j = 0; j < face.size(); ++j )
402 const int vertexIndex = face[j];
403 res[vertexIndex] += val;
404 count[vertexIndex] += 1;
410 for (
int i = 0; i < vertexCount; ++i )
412 if ( count.at( i ) > 0 )
414 res[i] = res[i] / double( count.at( i ) );
418 res[i] = std::numeric_limits<double>::quiet_NaN();
425QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
429 assert( nativeMesh );
434 Q_UNUSED( triangularMesh );
437 QVector<double> ret( nativeMesh->
faceCount(), std::numeric_limits<double>::quiet_NaN() );
439 for (
int i = 0; i < nativeMesh->
faces.size(); ++i )
442 if ( active->
active( i ) && face.count() > 2 )
445 for (
int j = 0; j < face.count(); ++j )
447 value += valuesOnVertices.at( face.at( j ) );
449 ret[i] = value / face.count();
456QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices(
462 if ( !meshLayer || !index.
isValid() )
467 if ( !triangularMesh || !nativeMesh )
474 const int datacount = scalarDataOnVertices ? nativeMesh->
vertices.count() : nativeMesh->
faces.count();
475 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues( meshLayer, index, 0, datacount );
478 if ( !activeFaceFlagValues )
484 activeFace = *activeFaceFlagValues;
486 return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, activeFace, method );
489QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices(
502 ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
504 if ( !scalarDataOnVertices )
507 ret = QgsMeshLayerUtils::interpolateFromFacesData( ret, nativeMesh, activeFaceFlagValues, method );
516 double xMin = p1.
x();
517 double xMax = p1.
x();
518 double yMin = p1.
y();
519 double yMax = p1.
y();
522 xMin = ( ( xMin < p2.
x() ) ? xMin : p2.
x() );
523 xMax = ( ( xMax > p2.
x() ) ? xMax : p2.
x() );
524 yMin = ( ( yMin < p2.
y() ) ? yMin : p2.
y() );
525 yMax = ( ( yMax > p2.
y() ) ? yMax : p2.
y() );
528 xMin = ( ( xMin < p3.
x() ) ? xMin : p3.
x() );
529 xMax = ( ( xMax > p3.
x() ) ? xMax : p3.
x() );
530 yMin = ( ( yMin < p3.
y() ) ? yMin : p3.
y() );
531 yMax = ( ( yMax > p3.
y() ) ? yMax : p3.
y() );
537QString QgsMeshLayerUtils::formatTime(
double hours,
const QDateTime &referenceTime,
const QgsMeshTimeSettings &settings )
541 if ( referenceTime.isValid() )
544 QDateTime dateTime( referenceTime );
545 const qint64 seconds =
static_cast<qint64
>( hours * 3600.0 );
546 dateTime = dateTime.addSecs( seconds );
547 ret = dateTime.toString( format );
549 ret = dateTime.toString();
554 format = format.trimmed();
555 const int totalHours =
static_cast<int>( hours );
557 if ( format ==
"hh:mm:ss.zzz"_L1 )
559 const int ms =
static_cast<int>( hours * 3600.0 * 1000 );
560 const int seconds = ms / 1000;
561 const int z = ms % 1000;
562 int m = seconds / 60;
563 const int s = seconds % 60;
564 const int h = m / 60;
566 ret = u
"%1:%2:%3.%4"_s.arg( h, 2, 10,
'0'_L1 ).arg( m, 2, 10,
'0'_L1 ).arg( s, 2, 10,
'0'_L1 ).arg( z, 3, 10,
'0'_L1 );
568 else if ( format ==
"hh:mm:ss"_L1 )
570 const int seconds =
static_cast<int>( hours * 3600.0 );
571 int m = seconds / 60;
572 const int s = seconds % 60;
573 const int h = m / 60;
575 ret = u
"%1:%2:%3"_s.arg( h, 2, 10,
'0'_L1 ).arg( m, 2, 10,
'0'_L1 ).arg( s, 2, 10,
'0'_L1 );
577 else if ( format ==
"d hh:mm:ss"_L1 )
579 const int seconds =
static_cast<int>( hours * 3600.0 );
580 int m = seconds / 60;
581 const int s = seconds % 60;
584 const int d = totalHours / 24;
586 ret = u
"%1 d %2:%3:%4"_s.arg( d ).arg( h, 2, 10,
'0'_L1 ).arg( m, 2, 10,
'0'_L1 ).arg( s, 2, 10,
'0'_L1 );
588 else if ( format ==
"d hh"_L1 )
590 const int d = totalHours / 24;
591 const int h = totalHours % 24;
592 ret = u
"%1 d %2"_s.arg( d ).arg( h );
594 else if ( format ==
"d"_L1 )
596 const int d = totalHours / 24;
597 ret = QString::number( d );
599 else if ( format ==
"ss"_L1 )
601 const int seconds =
static_cast<int>( hours * 3600.0 );
602 ret = QString::number( seconds );
606 ret = QString::number( hours );
612QVector<QVector3D> QgsMeshLayerUtils::calculateNormals(
const QgsTriangularMesh &triangularMesh,
const QVector<double> &verticalMagnitude,
bool isRelative )
614 QVector<QVector3D> normals( triangularMesh.
vertices().count() );
615 for (
const auto &face : triangularMesh.
triangles() )
617 for (
int i = 0; i < 3; i++ )
619 const int index( face.at( i ) );
620 const int index1( face.at( ( i + 1 ) % 3 ) );
621 const int index2( face.at( ( i + 2 ) % 3 ) );
623 if ( std::isnan( verticalMagnitude[index] ) || std::isnan( verticalMagnitude[index1] ) || std::isnan( verticalMagnitude[index2] ) )
630 float adjustRelative = 0;
631 float adjustRelative1 = 0;
632 float adjustRelative2 = 0;
636 adjustRelative = vert.z();
637 adjustRelative1 = otherVert1.z();
638 adjustRelative2 = otherVert2.z();
641 const QVector3D v1(
float( otherVert1.x() - vert.x() ),
float( otherVert1.y() - vert.y() ),
float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
642 const QVector3D v2(
float( otherVert2.x() - vert.x() ),
float( otherVert2.y() - vert.y() ),
float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
644 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 for interpolating 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.
A block of 3d stacked mesh data related N faces defined on base mesh frame.
bool isValid() const
Whether the block is valid.
A block of integers/doubles from a mesh dataset.
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.
An 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.
Represents a single mesh 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.
Point geometry type, with support for z-dimension and m-values.
A rectangle specified with double values.
A triangular/derived 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.
Represent a 2-dimensional vector.
#define QgsDebugMsgLevel(str, level)
QVector< int > QgsMeshFace
List of vertex indexes.
QgsPoint QgsMeshVertex
xyz coords of vertex
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.