30#include <QRegularExpression>
31#include <QRegularExpressionMatch>
35using namespace Qt::StringLiterals;
94 if ( !averagingMethod )
101 block = averagingMethod->
calculate( block3d );
106QVector<QgsVector> QgsMeshLayerUtils::griddedVectorValues(
const QgsMeshLayer *meshLayer,
113 QVector<QgsVector> vectors;
115 if ( !meshLayer || !index.
isValid() )
121 if ( !triangularMesh || !nativeMesh )
130 const int datacount = vectorDataOnVertices ? nativeMesh->
vertices.count() : nativeMesh->
faces.count();
131 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues( meshLayer, index, 0, datacount );
141 vectors.reserve( size.height()*size.width() );
146 return QVector<QgsVector>();
149 for (
int iy = 0; iy < size.height(); ++iy )
151 const double y = minCorner.
y() + iy * ySpacing;
152 for (
int ix = 0; ix < size.width(); ++ix )
154 const double x = minCorner.
x() + ix * xSpacing;
157 int nativeFaceIndex = -1;
158 if ( faceIndex != -1 )
161 if ( nativeFaceIndex != -1 && isFacesActive.
active( nativeFaceIndex ) )
167 value = vals.
value( nativeFaceIndex );
172 const int v1 = face[0], v2 = face[1], v3 = face[2];
177 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
x(), val2.
x(), val3.
x(), point );
178 const double y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
y(), val2.
y(), val3.
y(), point );
186 vectors.append(
QgsVector( value.
x(), value.
y() ) );
192QVector<double> QgsMeshLayerUtils::calculateMagnitudes(
const QgsMeshDataBlock &block )
195 const int count = block.
count();
196 QVector<double> ret( count );
198 for (
int i = 0; i < count; ++i )
206QgsRectangle QgsMeshLayerUtils::boundingBoxToScreenRectangle(
209 double devicePixelRatio
217 const double xMin = std::min( {topLeft.
x(), topRight.
x(), bottomLeft.
x(), bottomRight.
x()} );
218 const double xMax = std::max( {topLeft.
x(), topRight.
x(), bottomLeft.
x(), bottomRight.
x()} );
219 const double yMin = std::min( {topLeft.
y(), topRight.
y(), bottomLeft.
y(), bottomRight.
y()} );
220 const double yMax = std::max( {topLeft.
y(), topRight.
y(), bottomLeft.
y(), bottomRight.
y()} );
226void QgsMeshLayerUtils::boundingBoxToScreenRectangle(
228 const QSize &outputSize,
234 double devicePixelRatio )
236 const QgsRectangle screenBBox = boundingBoxToScreenRectangle( mtp, bbox, devicePixelRatio );
238 bottomLim = std::max(
int( screenBBox.
yMinimum() ), 0 );
239 topLim = std::min(
int( screenBBox.
yMaximum() ), outputSize.height() - 1 );
240 leftLim = std::max(
int( screenBBox.
xMinimum() ), 0 );
241 rightLim = std::min(
int( screenBBox.
xMaximum() ), outputSize.width() - 1 );
244static void lamTol(
double &lam )
246 const static double eps = 1e-6;
247 if ( ( lam < 0.0 ) && ( lam > -eps ) )
254 double &lam1,
double &lam2,
double &lam3 )
257 const double xa = pA.
x();
258 const double ya = pA.
y();
259 const double v0x = pC.
x() - xa ;
260 const double v0y = pC.
y() - ya ;
261 const double v1x = pB.
x() - xa ;
262 const double v1y = pB.
y() - ya ;
263 const double v2x = pP.
x() - xa ;
264 const double v2y = pP.
y() - ya ;
267 const double dot00 = v0x * v0x + v0y * v0y;
268 const double dot01 = v0x * v1x + v0y * v1y;
269 const double dot02 = v0x * v2x + v0y * v2y;
270 const double dot11 = v1x * v1x + v1y * v1y;
271 const double dot12 = v1x * v2x + v1y * v2y;
274 double invDenom = dot00 * dot11 - dot01 * dot01;
277 invDenom = 1.0 / invDenom;
278 lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
279 lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
280 lam3 = 1.0 - lam1 - lam2;
288 if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
296bool QgsMeshLayerUtils::calculateBarycentricCoordinates(
298 double &lam1,
double &lam2,
double &lam3 )
300 return E3T_physicalToBarycentric( pA, pB, pC, pP, lam1, lam2, lam3 );
304 double val1,
double val2,
double val3,
const QgsPointXY &pt )
306 double lam1, lam2, lam3;
307 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
308 return std::numeric_limits<double>::quiet_NaN();
310 return lam1 * val3 + lam2 * val2 + lam3 * val1;
313double QgsMeshLayerUtils::interpolateZForPoint(
const QgsTriangularMesh &mesh,
double x,
double y )
317 if ( faceIndex < 0 || faceIndex >= mesh.
triangles().count() )
318 return std::numeric_limits<float>::quiet_NaN();
326 return QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(), point );
329double QgsMeshLayerUtils::interpolateFromVerticesData(
double fraction,
double val1,
double val2 )
331 if ( std::isnan( val1 ) || std::isnan( val2 ) || ( fraction < 0 ) || ( fraction > 1 ) )
333 return std::numeric_limits<double>::quiet_NaN();
335 return val1 + ( val2 - val1 ) * fraction;
341 interpolateFromVerticesData( fraction, val1.
y(), val2.
y() ) );
347 double lam1, lam2, lam3;
348 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
349 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
351 return vect3 * lam1 + vect2 * lam2 + vect1 * lam3;
357 double lam1, lam2, lam3;
358 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
359 return std::numeric_limits<double>::quiet_NaN();
367 double lam1, lam2, lam3;
368 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
369 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
375QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
376 QVector<double> valuesOnFaces,
382 assert( nativeMesh );
384 Q_UNUSED( triangularMesh );
389 return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
392QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
const QVector<double> &valuesOnFaces,
400 activeFace = *active;
407 return interpolateFromFacesData( valuesOnFaces, nativeMesh, activeFace, method );
417 QVector<double> res( vertexCount, 0.0 );
419 QVector<int> count( vertexCount, 0 );
421 for (
int i = 0; i < nativeMesh.
faceCount(); ++i )
425 const double val = valuesOnFaces[ i ];
426 if ( !std::isnan( val ) )
430 for (
int j = 0; j < face.size(); ++j )
432 const int vertexIndex = face[j];
433 res[vertexIndex] += val;
434 count[vertexIndex] += 1;
440 for (
int i = 0; i < vertexCount; ++i )
442 if ( count.at( i ) > 0 )
444 res[i] = res[i] / double( count.at( i ) );
448 res[i] = std::numeric_limits<double>::quiet_NaN();
455QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
456 const QVector<double> valuesOnVertices,
462 assert( nativeMesh );
467 Q_UNUSED( triangularMesh );
470 QVector<double> ret( nativeMesh->
faceCount(), std::numeric_limits<double>::quiet_NaN() );
472 for (
int i = 0; i < nativeMesh->
faces.size(); ++i )
475 if ( active->
active( i ) && face.count() > 2 )
478 for (
int j = 0; j < face.count(); ++j )
480 value += valuesOnVertices.at( face.at( j ) );
482 ret[i] = value / face.count();
489QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices(
const QgsMeshLayer *meshLayer,
496 if ( !meshLayer || !index.
isValid() )
501 if ( !triangularMesh || !nativeMesh )
508 const int datacount = scalarDataOnVertices ? nativeMesh->
vertices.count() : nativeMesh->
faces.count();
516 if ( !activeFaceFlagValues )
522 activeFace = *activeFaceFlagValues;
524 return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, activeFace, method );
527QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices(
const QgsMesh &nativeMesh,
538 ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
540 if ( !scalarDataOnVertices )
543 ret = QgsMeshLayerUtils::interpolateFromFacesData(
546 activeFaceFlagValues,
556 double xMin = p1.
x();
557 double xMax = p1.
x();
558 double yMin = p1.
y();
559 double yMax = p1.
y();
562 xMin = ( ( xMin < p2.
x() ) ? xMin : p2.
x() );
563 xMax = ( ( xMax > p2.
x() ) ? xMax : p2.
x() );
564 yMin = ( ( yMin < p2.
y() ) ? yMin : p2.
y() );
565 yMax = ( ( yMax > p2.
y() ) ? yMax : p2.
y() );
568 xMin = ( ( xMin < p3.
x() ) ? xMin : p3.
x() );
569 xMax = ( ( xMax > p3.
x() ) ? xMax : p3.
x() );
570 yMin = ( ( yMin < p3.
y() ) ? yMin : p3.
y() );
571 yMax = ( ( yMax > p3.
y() ) ? yMax : p3.
y() );
577QString QgsMeshLayerUtils::formatTime(
double hours,
const QDateTime &referenceTime,
const QgsMeshTimeSettings &settings )
581 if ( referenceTime.isValid() )
584 QDateTime dateTime( referenceTime );
585 const qint64 seconds =
static_cast<qint64
>( hours * 3600.0 );
586 dateTime = dateTime.addSecs( seconds );
587 ret = dateTime.toString( format );
589 ret = dateTime.toString();
594 format = format.trimmed();
595 const int totalHours =
static_cast<int>( hours );
597 if ( format ==
"hh:mm:ss.zzz"_L1 )
599 const int ms =
static_cast<int>( hours * 3600.0 * 1000 );
600 const int seconds = ms / 1000;
601 const int z = ms % 1000;
602 int m = seconds / 60;
603 const int s = seconds % 60;
604 const int h = m / 60;
606 ret = u
"%1:%2:%3.%4"_s.
607 arg( h, 2, 10,
'0'_L1 ).
608 arg( m, 2, 10,
'0'_L1 ).
609 arg( s, 2, 10,
'0'_L1 ).
610 arg( z, 3, 10,
'0'_L1 );
612 else if ( format ==
"hh:mm:ss"_L1 )
614 const int seconds =
static_cast<int>( hours * 3600.0 );
615 int m = seconds / 60;
616 const int s = seconds % 60;
617 const int h = m / 60;
620 arg( h, 2, 10,
'0'_L1 ).
621 arg( m, 2, 10,
'0'_L1 ).
622 arg( s, 2, 10,
'0'_L1 );
625 else if ( format ==
"d hh:mm:ss"_L1 )
627 const int seconds =
static_cast<int>( hours * 3600.0 );
628 int m = seconds / 60;
629 const int s = seconds % 60;
632 const int d = totalHours / 24;
634 ret = u
"%1 d %2:%3:%4"_s.
636 arg( h, 2, 10,
'0'_L1 ).
637 arg( m, 2, 10,
'0'_L1 ).
638 arg( s, 2, 10,
'0'_L1 );
640 else if ( format ==
"d hh"_L1 )
642 const int d = totalHours / 24;
643 const int h = totalHours % 24;
648 else if ( format ==
"d"_L1 )
650 const int d = totalHours / 24;
651 ret = QString::number( d );
653 else if ( format ==
"ss"_L1 )
655 const int seconds =
static_cast<int>( hours * 3600.0 );
656 ret = QString::number( seconds );
660 ret = QString::number( hours );
666QVector<QVector3D> QgsMeshLayerUtils::calculateNormals(
const QgsTriangularMesh &triangularMesh,
const QVector<double> &verticalMagnitude,
bool isRelative )
668 QVector<QVector3D> normals( triangularMesh.
vertices().count() );
669 for (
const auto &face : triangularMesh.
triangles() )
671 for (
int i = 0; i < 3; i++ )
673 const int index( face.at( i ) );
674 const int index1( face.at( ( i + 1 ) % 3 ) );
675 const int index2( face.at( ( i + 2 ) % 3 ) );
677 if ( std::isnan( verticalMagnitude[index] ) ||
678 std::isnan( verticalMagnitude[index1] ) ||
679 std::isnan( verticalMagnitude[index2] ) )
686 float adjustRelative = 0;
687 float adjustRelative1 = 0;
688 float adjustRelative2 = 0;
692 adjustRelative = vert.z();
693 adjustRelative1 = otherVert1.z();
694 adjustRelative2 = otherVert2.z();
697 const QVector3D v1(
float( otherVert1.x() - vert.x() ),
698 float( otherVert1.y() - vert.y() ),
699 float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
700 const QVector3D v2(
float( otherVert2.x() - vert.x() ),
701 float( otherVert2.y() - vert.y() ),
702 float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
704 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.