30#include <QRegularExpression>
31#include <QRegularExpressionMatch>
91 if ( !averagingMethod )
98 block = averagingMethod->
calculate( block3d );
103QVector<QgsVector> QgsMeshLayerUtils::griddedVectorValues(
const QgsMeshLayer *meshLayer,
110 QVector<QgsVector> vectors;
112 if ( !meshLayer || !index.
isValid() )
118 if ( !triangularMesh || !nativeMesh )
127 const int datacount = vectorDataOnVertices ? nativeMesh->
vertices.count() : nativeMesh->
faces.count();
128 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues( meshLayer, index, 0, datacount );
138 vectors.reserve( size.height()*size.width() );
143 return QVector<QgsVector>();
146 for (
int iy = 0; iy < size.height(); ++iy )
148 const double y = minCorner.
y() + iy * ySpacing;
149 for (
int ix = 0; ix < size.width(); ++ix )
151 const double x = minCorner.
x() + ix * xSpacing;
154 int nativeFaceIndex = -1;
155 if ( faceIndex != -1 )
158 if ( nativeFaceIndex != -1 && isFacesActive.
active( nativeFaceIndex ) )
164 value = vals.
value( nativeFaceIndex );
169 const int v1 = face[0], v2 = face[1], v3 = face[2];
174 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
x(), val2.
x(), val3.
x(), point );
175 const double y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.
y(), val2.
y(), val3.
y(), point );
183 vectors.append(
QgsVector( value.
x(), value.
y() ) );
189QVector<double> QgsMeshLayerUtils::calculateMagnitudes(
const QgsMeshDataBlock &block )
192 const int count = block.
count();
193 QVector<double> ret( count );
195 for (
int i = 0; i < count; ++i )
203QgsRectangle QgsMeshLayerUtils::boundingBoxToScreenRectangle(
206 double devicePixelRatio
214 const double xMin = std::min( {topLeft.
x(), topRight.
x(), bottomLeft.
x(), bottomRight.
x()} );
215 const double xMax = std::max( {topLeft.
x(), topRight.
x(), bottomLeft.
x(), bottomRight.
x()} );
216 const double yMin = std::min( {topLeft.
y(), topRight.
y(), bottomLeft.
y(), bottomRight.
y()} );
217 const double yMax = std::max( {topLeft.
y(), topRight.
y(), bottomLeft.
y(), bottomRight.
y()} );
223void QgsMeshLayerUtils::boundingBoxToScreenRectangle(
225 const QSize &outputSize,
231 double devicePixelRatio )
233 const QgsRectangle screenBBox = boundingBoxToScreenRectangle( mtp, bbox, devicePixelRatio );
235 bottomLim = std::max(
int( screenBBox.
yMinimum() ), 0 );
236 topLim = std::min(
int( screenBBox.
yMaximum() ), outputSize.height() - 1 );
237 leftLim = std::max(
int( screenBBox.
xMinimum() ), 0 );
238 rightLim = std::min(
int( screenBBox.
xMaximum() ), outputSize.width() - 1 );
241static void lamTol(
double &lam )
243 const static double eps = 1e-6;
244 if ( ( lam < 0.0 ) && ( lam > -eps ) )
251 double &lam1,
double &lam2,
double &lam3 )
254 const double xa = pA.
x();
255 const double ya = pA.
y();
256 const double v0x = pC.
x() - xa ;
257 const double v0y = pC.
y() - ya ;
258 const double v1x = pB.
x() - xa ;
259 const double v1y = pB.
y() - ya ;
260 const double v2x = pP.
x() - xa ;
261 const double v2y = pP.
y() - ya ;
264 const double dot00 = v0x * v0x + v0y * v0y;
265 const double dot01 = v0x * v1x + v0y * v1y;
266 const double dot02 = v0x * v2x + v0y * v2y;
267 const double dot11 = v1x * v1x + v1y * v1y;
268 const double dot12 = v1x * v2x + v1y * v2y;
271 double invDenom = dot00 * dot11 - dot01 * dot01;
274 invDenom = 1.0 / invDenom;
275 lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
276 lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
277 lam3 = 1.0 - lam1 - lam2;
285 if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
293bool QgsMeshLayerUtils::calculateBarycentricCoordinates(
295 double &lam1,
double &lam2,
double &lam3 )
297 return E3T_physicalToBarycentric( pA, pB, pC, pP, lam1, lam2, lam3 );
301 double val1,
double val2,
double val3,
const QgsPointXY &pt )
303 double lam1, lam2, lam3;
304 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
305 return std::numeric_limits<double>::quiet_NaN();
307 return lam1 * val3 + lam2 * val2 + lam3 * val1;
310double QgsMeshLayerUtils::interpolateZForPoint(
const QgsTriangularMesh &mesh,
double x,
double y )
314 if ( faceIndex < 0 || faceIndex >= mesh.
triangles().count() )
315 return std::numeric_limits<float>::quiet_NaN();
323 return QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.
z(), p2.
z(), p3.
z(), point );
326double QgsMeshLayerUtils::interpolateFromVerticesData(
double fraction,
double val1,
double val2 )
328 if ( std::isnan( val1 ) || std::isnan( val2 ) || ( fraction < 0 ) || ( fraction > 1 ) )
330 return std::numeric_limits<double>::quiet_NaN();
332 return val1 + ( val2 - val1 ) * fraction;
338 interpolateFromVerticesData( fraction, val1.
y(), val2.
y() ) );
344 double lam1, lam2, lam3;
345 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
346 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
348 return vect3 * lam1 + vect2 * lam2 + vect1 * lam3;
354 double lam1, lam2, lam3;
355 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
356 return std::numeric_limits<double>::quiet_NaN();
364 double lam1, lam2, lam3;
365 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
366 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
372QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
373 QVector<double> valuesOnFaces,
379 assert( nativeMesh );
381 Q_UNUSED( triangularMesh );
386 return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
389QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
const QVector<double> &valuesOnFaces,
397 activeFace = *active;
404 return interpolateFromFacesData( valuesOnFaces, nativeMesh, activeFace, method );
414 QVector<double> res( vertexCount, 0.0 );
416 QVector<int> count( vertexCount, 0 );
418 for (
int i = 0; i < nativeMesh.
faceCount(); ++i )
422 const double val = valuesOnFaces[ i ];
423 if ( !std::isnan( val ) )
427 for (
int j = 0; j < face.size(); ++j )
429 const int vertexIndex = face[j];
430 res[vertexIndex] += val;
431 count[vertexIndex] += 1;
437 for (
int i = 0; i < vertexCount; ++i )
439 if ( count.at( i ) > 0 )
441 res[i] = res[i] / double( count.at( i ) );
445 res[i] = std::numeric_limits<double>::quiet_NaN();
452QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
453 const QVector<double> valuesOnVertices,
459 assert( nativeMesh );
464 Q_UNUSED( triangularMesh );
467 QVector<double> ret( nativeMesh->
faceCount(), std::numeric_limits<double>::quiet_NaN() );
469 for (
int i = 0; i < nativeMesh->
faces.size(); ++i )
472 if ( active->
active( i ) && face.count() > 2 )
475 for (
int j = 0; j < face.count(); ++j )
477 value += valuesOnVertices.at( face.at( j ) );
479 ret[i] = value / face.count();
486QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices(
const QgsMeshLayer *meshLayer,
493 if ( !meshLayer || !index.
isValid() )
498 if ( !triangularMesh || !nativeMesh )
505 const int datacount = scalarDataOnVertices ? nativeMesh->
vertices.count() : nativeMesh->
faces.count();
513 if ( !activeFaceFlagValues )
519 activeFace = *activeFaceFlagValues;
521 return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, activeFace, method );
524QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices(
const QgsMesh &nativeMesh,
535 ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
537 if ( !scalarDataOnVertices )
540 ret = QgsMeshLayerUtils::interpolateFromFacesData(
543 activeFaceFlagValues,
553 double xMin = p1.
x();
554 double xMax = p1.
x();
555 double yMin = p1.
y();
556 double yMax = p1.
y();
559 xMin = ( ( xMin < p2.
x() ) ? xMin : p2.
x() );
560 xMax = ( ( xMax > p2.
x() ) ? xMax : p2.
x() );
561 yMin = ( ( yMin < p2.
y() ) ? yMin : p2.
y() );
562 yMax = ( ( yMax > p2.
y() ) ? yMax : p2.
y() );
565 xMin = ( ( xMin < p3.
x() ) ? xMin : p3.
x() );
566 xMax = ( ( xMax > p3.
x() ) ? xMax : p3.
x() );
567 yMin = ( ( yMin < p3.
y() ) ? yMin : p3.
y() );
568 yMax = ( ( yMax > p3.
y() ) ? yMax : p3.
y() );
574QString QgsMeshLayerUtils::formatTime(
double hours,
const QDateTime &referenceTime,
const QgsMeshTimeSettings &settings )
578 if ( referenceTime.isValid() )
581 QDateTime dateTime( referenceTime );
582 const qint64 seconds =
static_cast<qint64
>( hours * 3600.0 );
583 dateTime = dateTime.addSecs( seconds );
584 ret = dateTime.toString( format );
586 ret = dateTime.toString();
591 format = format.trimmed();
592 const int totalHours =
static_cast<int>( hours );
594 if ( format == QLatin1String(
"hh:mm:ss.zzz" ) )
596 const int ms =
static_cast<int>( hours * 3600.0 * 1000 );
597 const int seconds = ms / 1000;
598 const int z = ms % 1000;
599 int m = seconds / 60;
600 const int s = seconds % 60;
601 const int h = m / 60;
603 ret = QStringLiteral(
"%1:%2:%3.%4" ).
604 arg( h, 2, 10, QLatin1Char(
'0' ) ).
605 arg( m, 2, 10, QLatin1Char(
'0' ) ).
606 arg( s, 2, 10, QLatin1Char(
'0' ) ).
607 arg( z, 3, 10, QLatin1Char(
'0' ) );
609 else if ( format == QLatin1String(
"hh:mm:ss" ) )
611 const int seconds =
static_cast<int>( hours * 3600.0 );
612 int m = seconds / 60;
613 const int s = seconds % 60;
614 const int h = m / 60;
616 ret = QStringLiteral(
"%1:%2:%3" ).
617 arg( h, 2, 10, QLatin1Char(
'0' ) ).
618 arg( m, 2, 10, QLatin1Char(
'0' ) ).
619 arg( s, 2, 10, QLatin1Char(
'0' ) );
622 else if ( format == QLatin1String(
"d hh:mm:ss" ) )
624 const int seconds =
static_cast<int>( hours * 3600.0 );
625 int m = seconds / 60;
626 const int s = seconds % 60;
629 const int d = totalHours / 24;
631 ret = QStringLiteral(
"%1 d %2:%3:%4" ).
633 arg( h, 2, 10, QLatin1Char(
'0' ) ).
634 arg( m, 2, 10, QLatin1Char(
'0' ) ).
635 arg( s, 2, 10, QLatin1Char(
'0' ) );
637 else if ( format == QLatin1String(
"d hh" ) )
639 const int d = totalHours / 24;
640 const int h = totalHours % 24;
641 ret = QStringLiteral(
"%1 d %2" ).
645 else if ( format == QLatin1String(
"d" ) )
647 const int d = totalHours / 24;
648 ret = QString::number( d );
650 else if ( format == QLatin1String(
"ss" ) )
652 const int seconds =
static_cast<int>( hours * 3600.0 );
653 ret = QString::number( seconds );
657 ret = QString::number( hours );
663QVector<QVector3D> QgsMeshLayerUtils::calculateNormals(
const QgsTriangularMesh &triangularMesh,
const QVector<double> &verticalMagnitude,
bool isRelative )
665 QVector<QVector3D> normals( triangularMesh.
vertices().count() );
666 for (
const auto &face : triangularMesh.
triangles() )
668 for (
int i = 0; i < 3; i++ )
670 const int index( face.at( i ) );
671 const int index1( face.at( ( i + 1 ) % 3 ) );
672 const int index2( face.at( ( i + 2 ) % 3 ) );
674 if ( std::isnan( verticalMagnitude[index] ) ||
675 std::isnan( verticalMagnitude[index1] ) ||
676 std::isnan( verticalMagnitude[index2] ) )
683 float adjustRelative = 0;
684 float adjustRelative1 = 0;
685 float adjustRelative2 = 0;
689 adjustRelative = vert.z();
690 adjustRelative1 = otherVert1.z();
691 adjustRelative2 = otherVert2.z();
694 const QVector3D v1(
float( otherVert1.x() - vert.x() ),
695 float( otherVert1.y() - vert.y() ),
696 float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
697 const QVector3D v2(
float( otherVert2.x() - vert.x() ),
698 float( otherVert2.y() - vert.y() ),
699 float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
701 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.