QGIS API Documentation 3.34.0-Prizren (ffbdd678812)
Loading...
Searching...
No Matches
qgsmeshlayerutils.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmeshlayerutils.cpp
3 --------------------------
4 begin : August 2018
5 copyright : (C) 2018 by Martin Dobias
6 email : wonder dot sk at gmail dot com
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18#include <limits>
19#include <QTime>
20#include <QDateTime>
21
22#include "qgsmeshlayerutils.h"
23#include "qgsmeshtimesettings.h"
24#include "qgstriangularmesh.h"
25#include "qgslogger.h"
26#include "qgsmeshdataprovider.h"
27#include "qgsmesh3daveraging.h"
28#include "qgsmeshlayer.h"
29
30
32
33int QgsMeshLayerUtils::datasetValuesCount( const QgsMesh *mesh, QgsMeshDatasetGroupMetadata::DataType dataType )
34{
35 if ( !mesh )
36 return 0;
37
38 switch ( dataType )
39 {
41 return mesh->edgeCount();
43 return mesh->faceCount();
45 return mesh->vertexCount();
47 return mesh->faceCount(); // because they are averaged to faces
48 }
49 return 0;
50}
51
52QgsMeshDatasetGroupMetadata::DataType QgsMeshLayerUtils::datasetValuesType( const QgsMeshDatasetGroupMetadata::DataType &type )
53{
54 // data on volumes are averaged to 2D data on faces
57
58 return type;
59}
60
61QgsMeshDataBlock QgsMeshLayerUtils::datasetValues(
62 const QgsMeshLayer *meshLayer,
64 int valueIndex,
65 int count )
66{
67 QgsMeshDataBlock block;
68 if ( !meshLayer )
69 return block;
70
71
72 if ( !meshLayer->datasetCount( index ) )
73 return block;
74
75 if ( !index.isValid() )
76 return block;
77
78 const QgsMeshDatasetGroupMetadata meta = meshLayer->datasetGroupMetadata( index.group() );
80 {
81 block = meshLayer->datasetValues( index, valueIndex, count );
82 if ( block.isValid() )
83 return block;
84 }
85 else
86 {
87 const QgsMesh3DAveragingMethod *averagingMethod = meshLayer->rendererSettings().averagingMethod();
88 if ( !averagingMethod )
89 return block;
90
91 const QgsMesh3DDataBlock block3d = meshLayer->dataset3dValues( index, valueIndex, count );
92 if ( !block3d.isValid() )
93 return block;
94
95 block = averagingMethod->calculate( block3d );
96 }
97 return block;
98}
99
100QVector<QgsVector> QgsMeshLayerUtils::griddedVectorValues( const QgsMeshLayer *meshLayer,
101 const QgsMeshDatasetIndex index,
102 double xSpacing,
103 double ySpacing,
104 const QSize &size,
105 const QgsPointXY &minCorner )
106{
107 QVector<QgsVector> vectors;
108
109 if ( !meshLayer || !index.isValid() )
110 return vectors;
111
112 const QgsTriangularMesh *triangularMesh = meshLayer->triangularMesh();
113 const QgsMesh *nativeMesh = meshLayer->nativeMesh();
114
115 if ( !triangularMesh || !nativeMesh )
116 return vectors;
117
118 const QgsMeshDatasetGroupMetadata meta = meshLayer->datasetGroupMetadata( index );
119 if ( !meta.isVector() )
120 return vectors;
121
122 // extract vector dataset
123 const bool vectorDataOnVertices = meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
124 const int datacount = vectorDataOnVertices ? nativeMesh->vertices.count() : nativeMesh->faces.count();
125 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues( meshLayer, index, 0, datacount );
126
127 const QgsMeshDataBlock isFacesActive = meshLayer->areFacesActive( index, 0, nativeMesh->faceCount() );
128 const QgsMeshDatasetGroupMetadata::DataType dataType = meta.dataType();
129
131 return vectors;
132
133 try
134 {
135 vectors.reserve( size.height()*size.width() );
136 }
137 catch ( ... )
138 {
139 QgsDebugMsgLevel( "Unable to store the arrow grid in memory", 1 );
140 return QVector<QgsVector>();
141 }
142
143 for ( int iy = 0; iy < size.height(); ++iy )
144 {
145 const double y = minCorner.y() + iy * ySpacing;
146 for ( int ix = 0; ix < size.width(); ++ix )
147 {
148 const double x = minCorner.x() + ix * xSpacing;
149 const QgsPoint point( x, y );
150 const int faceIndex = triangularMesh->faceIndexForPoint_v2( point );
151 int nativeFaceIndex = -1;
152 if ( faceIndex != -1 )
153 nativeFaceIndex = triangularMesh->trianglesToNativeFaces().at( faceIndex );
155 if ( nativeFaceIndex != -1 && isFacesActive.active( nativeFaceIndex ) )
156 {
157 switch ( dataType )
158 {
161 value = vals.value( nativeFaceIndex );
162 break;
164 {
165 const QgsMeshFace &face = triangularMesh->triangles()[faceIndex];
166 const int v1 = face[0], v2 = face[1], v3 = face[2];
167 const QgsPoint p1 = triangularMesh->vertices()[v1], p2 = triangularMesh->vertices()[v2], p3 = triangularMesh->vertices()[v3];
168 const QgsMeshDatasetValue val1 = vals.value( v1 );
169 const QgsMeshDatasetValue val2 = vals.value( v2 );
170 const QgsMeshDatasetValue val3 = vals.value( v3 );
171 const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
172 const double y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
173 value = QgsMeshDatasetValue( x, y );
174 }
175 break;
177 break;
178 }
179 }
180 vectors.append( QgsVector( value.x(), value.y() ) );
181 }
182 }
183 return vectors;
184}
185
186QVector<double> QgsMeshLayerUtils::calculateMagnitudes( const QgsMeshDataBlock &block )
187{
188 Q_ASSERT( QgsMeshDataBlock::ActiveFlagInteger != block.type() );
189 const int count = block.count();
190 QVector<double> ret( count );
191
192 for ( int i = 0; i < count; ++i )
193 {
194 const double mag = block.value( i ).scalar();
195 ret[i] = mag;
196 }
197 return ret;
198}
199
200QgsRectangle QgsMeshLayerUtils::boundingBoxToScreenRectangle(
201 const QgsMapToPixel &mtp,
202 const QgsRectangle &bbox,
203 double devicePixelRatio
204)
205{
206 const QgsPointXY topLeft = mtp.transform( bbox.xMinimum(), bbox.yMaximum() ) * devicePixelRatio;
207 const QgsPointXY topRight = mtp.transform( bbox.xMaximum(), bbox.yMaximum() ) * devicePixelRatio;
208 const QgsPointXY bottomLeft = mtp.transform( bbox.xMinimum(), bbox.yMinimum() ) * devicePixelRatio;
209 const QgsPointXY bottomRight = mtp.transform( bbox.xMaximum(), bbox.yMinimum() ) * devicePixelRatio;
210
211 const double xMin = std::min( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
212 const double xMax = std::max( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
213 const double yMin = std::min( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
214 const double yMax = std::max( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
215
216 const QgsRectangle ret( xMin, yMin, xMax, yMax );
217 return ret;
218}
219
220void QgsMeshLayerUtils::boundingBoxToScreenRectangle(
221 const QgsMapToPixel &mtp,
222 const QSize &outputSize,
223 const QgsRectangle &bbox,
224 int &leftLim,
225 int &rightLim,
226 int &bottomLim,
227 int &topLim,
228 double devicePixelRatio )
229{
230 const QgsRectangle screenBBox = boundingBoxToScreenRectangle( mtp, bbox, devicePixelRatio );
231
232 bottomLim = std::max( int( screenBBox.yMinimum() ), 0 );
233 topLim = std::min( int( screenBBox.yMaximum() ), outputSize.height() - 1 );
234 leftLim = std::max( int( screenBBox.xMinimum() ), 0 );
235 rightLim = std::min( int( screenBBox.xMaximum() ), outputSize.width() - 1 );
236}
237
238static void lamTol( double &lam )
239{
240 const static double eps = 1e-6;
241 if ( ( lam < 0.0 ) && ( lam > -eps ) )
242 {
243 lam = 0.0;
244 }
245}
246
247static bool E3T_physicalToBarycentric( const QgsPointXY &pA, const QgsPointXY &pB, const QgsPointXY &pC, const QgsPointXY &pP,
248 double &lam1, double &lam2, double &lam3 )
249{
250 // Compute vectors
251 const double xa = pA.x();
252 const double ya = pA.y();
253 const double v0x = pC.x() - xa ;
254 const double v0y = pC.y() - ya ;
255 const double v1x = pB.x() - xa ;
256 const double v1y = pB.y() - ya ;
257 const double v2x = pP.x() - xa ;
258 const double v2y = pP.y() - ya ;
259
260 // Compute dot products
261 const double dot00 = v0x * v0x + v0y * v0y;
262 const double dot01 = v0x * v1x + v0y * v1y;
263 const double dot02 = v0x * v2x + v0y * v2y;
264 const double dot11 = v1x * v1x + v1y * v1y;
265 const double dot12 = v1x * v2x + v1y * v2y;
266
267 // Compute barycentric coordinates
268 double invDenom = dot00 * dot11 - dot01 * dot01;
269 if ( invDenom == 0 )
270 return false;
271 invDenom = 1.0 / invDenom;
272 lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
273 lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
274 lam3 = 1.0 - lam1 - lam2;
275
276 // Apply some tolerance to lam so we can detect correctly border points
277 lamTol( lam1 );
278 lamTol( lam2 );
279 lamTol( lam3 );
280
281 // Return if POI is outside triangle
282 if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
283 {
284 return false;
285 }
286
287 return true;
288}
289
290double QgsMeshLayerUtils::interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
291 double val1, double val2, double val3, const QgsPointXY &pt )
292{
293 double lam1, lam2, lam3;
294 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
295 return std::numeric_limits<double>::quiet_NaN();
296
297 return lam1 * val3 + lam2 * val2 + lam3 * val1;
298}
299
300double QgsMeshLayerUtils::interpolateZForPoint( const QgsTriangularMesh &mesh, double x, double y )
301{
302 const QgsPointXY point( x, y );
303 const int faceIndex = mesh.faceIndexForPoint_v2( point );
304 if ( faceIndex < 0 || faceIndex >= mesh.triangles().count() )
305 return std::numeric_limits<float>::quiet_NaN();
306
307 const QgsMeshFace &face = mesh.triangles().at( faceIndex );
308
309 const QgsPoint p1 = mesh.vertices().at( face.at( 0 ) );
310 const QgsPoint p2 = mesh.vertices().at( face.at( 1 ) );
311 const QgsPoint p3 = mesh.vertices().at( face.at( 2 ) );
312
313 return QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.z(), p2.z(), p3.z(), point );
314}
315
316double QgsMeshLayerUtils::interpolateFromVerticesData( double fraction, double val1, double val2 )
317{
318 if ( std::isnan( val1 ) || std::isnan( val2 ) || ( fraction < 0 ) || ( fraction > 1 ) )
319 {
320 return std::numeric_limits<double>::quiet_NaN();
321 }
322 return val1 + ( val2 - val1 ) * fraction;
323}
324
325QgsMeshDatasetValue QgsMeshLayerUtils::interpolateFromVerticesData( double fraction, const QgsMeshDatasetValue &val1, const QgsMeshDatasetValue &val2 )
326{
327 return QgsMeshDatasetValue( interpolateFromVerticesData( fraction, val1.x(), val2.x() ),
328 interpolateFromVerticesData( fraction, val1.y(), val2.y() ) );
329}
330
331
332QgsVector QgsMeshLayerUtils::interpolateVectorFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3, QgsVector vect1, QgsVector vect2, QgsVector vect3, const QgsPointXY &pt )
333{
334 double lam1, lam2, lam3;
335 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
336 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
337
338 return vect3 * lam1 + vect2 * lam2 + vect1 * lam3;
339}
340
341double QgsMeshLayerUtils::interpolateFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
342 double val, const QgsPointXY &pt )
343{
344 double lam1, lam2, lam3;
345 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
346 return std::numeric_limits<double>::quiet_NaN();
347
348 return val;
349}
350
351QgsVector QgsMeshLayerUtils::interpolateVectorFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
352 QgsVector vect, const QgsPointXY &pt )
353{
354 double lam1, lam2, lam3;
355 if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
356 return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
357
358 return vect;
359}
360
361
362QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
363 QVector<double> valuesOnFaces,
364 const QgsMesh *nativeMesh,
365 const QgsTriangularMesh *triangularMesh,
366 QgsMeshDataBlock *active,
368{
369 assert( nativeMesh );
370 Q_UNUSED( method );
371 Q_UNUSED( triangularMesh );
372
373 // assuming that native vertex count = triangular vertex count
374 assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
375
376 return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
377}
378
379QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces,
380 const QgsMesh &nativeMesh,
381 QgsMeshDataBlock *active,
383{
384
385 QgsMeshDataBlock activeFace;
386 if ( active )
387 activeFace = *active;
388 else
389 {
391 activeFace.setValid( true );
392 }
393
394 return interpolateFromFacesData( valuesOnFaces, nativeMesh, activeFace, method );
395
396}
397
398QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces, const QgsMesh &nativeMesh, const QgsMeshDataBlock &active, QgsMeshRendererScalarSettings::DataResamplingMethod method )
399{
400 const int vertexCount = nativeMesh.vertexCount();
401 Q_UNUSED( method );
403
404 QVector<double> res( vertexCount, 0.0 );
405 // for face datasets do simple average of the valid values of all faces that contains this vertex
406 QVector<int> count( vertexCount, 0 );
407
408 for ( int i = 0; i < nativeMesh.faceCount(); ++i )
409 {
410 if ( active.active( i ) )
411 {
412 const double val = valuesOnFaces[ i ];
413 if ( !std::isnan( val ) )
414 {
415 // assign for all vertices
416 const QgsMeshFace &face = nativeMesh.faces.at( i );
417 for ( int j = 0; j < face.size(); ++j )
418 {
419 const int vertexIndex = face[j];
420 res[vertexIndex] += val;
421 count[vertexIndex] += 1;
422 }
423 }
424 }
425 }
426
427 for ( int i = 0; i < vertexCount; ++i )
428 {
429 if ( count.at( i ) > 0 )
430 {
431 res[i] = res[i] / double( count.at( i ) );
432 }
433 else
434 {
435 res[i] = std::numeric_limits<double>::quiet_NaN();
436 }
437 }
438
439 return res;
440}
441
442QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
443 const QVector<double> valuesOnVertices,
444 const QgsMesh *nativeMesh,
445 const QgsTriangularMesh *triangularMesh,
446 const QgsMeshDataBlock *active,
448{
449 assert( nativeMesh );
450 Q_UNUSED( method );
452
453 // assuming that native vertex count = triangular vertex count
454 Q_UNUSED( triangularMesh );
455 assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
456
457 QVector<double> ret( nativeMesh->faceCount(), std::numeric_limits<double>::quiet_NaN() );
458
459 for ( int i = 0; i < nativeMesh->faces.size(); ++i )
460 {
461 const QgsMeshFace face = nativeMesh->face( i );
462 if ( active->active( i ) && face.count() > 2 )
463 {
464 double value = 0;
465 for ( int j = 0; j < face.count(); ++j )
466 {
467 value += valuesOnVertices.at( face.at( j ) );
468 }
469 ret[i] = value / face.count();
470 }
471 }
472
473 return ret;
474}
475
476QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMeshLayer *meshLayer,
477 const QgsMeshDatasetIndex index,
478 QgsMeshDataBlock *activeFaceFlagValues,
480{
481 QVector<double> ret;
482
483 if ( !meshLayer && !index.isValid() )
484 return ret;
485
486 const QgsTriangularMesh *triangularMesh = meshLayer->triangularMesh();
487 const QgsMesh *nativeMesh = meshLayer->nativeMesh();
488 if ( !triangularMesh || !nativeMesh )
489 return ret;
490
491 const QgsMeshDatasetGroupMetadata metadata = meshLayer->datasetGroupMetadata( index );
492 const bool scalarDataOnVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
493
494 // populate scalar values
495 const int datacount = scalarDataOnVertices ? nativeMesh->vertices.count() : nativeMesh->faces.count();
496 const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
497 meshLayer,
498 index,
499 0,
500 datacount );
501
502 QgsMeshDataBlock activeFace;
503 if ( !activeFaceFlagValues )
504 {
506 activeFace.setValid( true );
507 }
508 else
509 activeFace = *activeFaceFlagValues;
510
511 return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, activeFace, method );
512}
513
514QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMesh &nativeMesh,
515 const QgsMeshDatasetGroupMetadata &groupMetadata,
516 const QgsMeshDataBlock &datasetValues,
517 const QgsMeshDataBlock &activeFaceFlagValues,
519{
520 QVector<double> ret;
521 const bool scalarDataOnVertices = groupMetadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
522
523 if ( datasetValues.isValid() )
524 {
525 ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
526
527 if ( !scalarDataOnVertices )
528 {
529 //Need to interpolate data on vertices
530 ret = QgsMeshLayerUtils::interpolateFromFacesData(
531 ret,
532 nativeMesh,
533 activeFaceFlagValues,
534 method );
535 }
536 }
537 return ret;
538}
539
540QgsRectangle QgsMeshLayerUtils::triangleBoundingBox( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 )
541{
542 // p1
543 double xMin = p1.x();
544 double xMax = p1.x();
545 double yMin = p1.y();
546 double yMax = p1.y();
547
548 //p2
549 xMin = ( ( xMin < p2.x() ) ? xMin : p2.x() );
550 xMax = ( ( xMax > p2.x() ) ? xMax : p2.x() );
551 yMin = ( ( yMin < p2.y() ) ? yMin : p2.y() );
552 yMax = ( ( yMax > p2.y() ) ? yMax : p2.y() );
553
554 // p3
555 xMin = ( ( xMin < p3.x() ) ? xMin : p3.x() );
556 xMax = ( ( xMax > p3.x() ) ? xMax : p3.x() );
557 yMin = ( ( yMin < p3.y() ) ? yMin : p3.y() );
558 yMax = ( ( yMax > p3.y() ) ? yMax : p3.y() );
559
560 const QgsRectangle bbox( xMin, yMin, xMax, yMax );
561 return bbox;
562}
563
564QString QgsMeshLayerUtils::formatTime( double hours, const QDateTime &referenceTime, const QgsMeshTimeSettings &settings )
565{
566 QString ret;
567
568 if ( referenceTime.isValid() )
569 {
570 const QString format( settings.absoluteTimeFormat() );
571 QDateTime dateTime( referenceTime );
572 const qint64 seconds = static_cast<qint64>( hours * 3600.0 );
573 dateTime = dateTime.addSecs( seconds );
574 ret = dateTime.toString( format );
575 if ( ret.isEmpty() ) // error
576 ret = dateTime.toString();
577 }
578 else
579 {
580 QString format( settings.relativeTimeFormat() );
581 format = format.trimmed();
582 const int totalHours = static_cast<int>( hours );
583
584 if ( format == QLatin1String( "hh:mm:ss.zzz" ) )
585 {
586 const int ms = static_cast<int>( hours * 3600.0 * 1000 );
587 const int seconds = ms / 1000;
588 const int z = ms % 1000;
589 int m = seconds / 60;
590 const int s = seconds % 60;
591 const int h = m / 60;
592 m = m % 60;
593 ret = QStringLiteral( "%1:%2:%3.%4" ).
594 arg( h, 2, 10, QLatin1Char( '0' ) ).
595 arg( m, 2, 10, QLatin1Char( '0' ) ).
596 arg( s, 2, 10, QLatin1Char( '0' ) ).
597 arg( z, 3, 10, QLatin1Char( '0' ) );
598 }
599 else if ( format == QLatin1String( "hh:mm:ss" ) )
600 {
601 const int seconds = static_cast<int>( hours * 3600.0 );
602 int m = seconds / 60;
603 const int s = seconds % 60;
604 const int h = m / 60;
605 m = m % 60;
606 ret = QStringLiteral( "%1:%2:%3" ).
607 arg( h, 2, 10, QLatin1Char( '0' ) ).
608 arg( m, 2, 10, QLatin1Char( '0' ) ).
609 arg( s, 2, 10, QLatin1Char( '0' ) );
610
611 }
612 else if ( format == QLatin1String( "d hh:mm:ss" ) )
613 {
614 const int seconds = static_cast<int>( hours * 3600.0 );
615 int m = seconds / 60;
616 const int s = seconds % 60;
617 int h = m / 60;
618 m = m % 60;
619 const int d = totalHours / 24;
620 h = totalHours % 24;
621 ret = QStringLiteral( "%1 d %2:%3:%4" ).
622 arg( d ).
623 arg( h, 2, 10, QLatin1Char( '0' ) ).
624 arg( m, 2, 10, QLatin1Char( '0' ) ).
625 arg( s, 2, 10, QLatin1Char( '0' ) );
626 }
627 else if ( format == QLatin1String( "d hh" ) )
628 {
629 const int d = totalHours / 24;
630 const int h = totalHours % 24;
631 ret = QStringLiteral( "%1 d %2" ).
632 arg( d ).
633 arg( h );
634 }
635 else if ( format == QLatin1String( "d" ) )
636 {
637 const int d = totalHours / 24;
638 ret = QString::number( d );
639 }
640 else if ( format == QLatin1String( "ss" ) )
641 {
642 const int seconds = static_cast<int>( hours * 3600.0 );
643 ret = QString::number( seconds );
644 }
645 else // "hh"
646 {
647 ret = QString::number( hours );
648 }
649 }
650 return ret;
651}
652
653QVector<QVector3D> QgsMeshLayerUtils::calculateNormals( const QgsTriangularMesh &triangularMesh, const QVector<double> &verticalMagnitude, bool isRelative )
654{
655 QVector<QVector3D> normals( triangularMesh.vertices().count() );
656 for ( const auto &face : triangularMesh.triangles() )
657 {
658 for ( int i = 0; i < 3; i++ )
659 {
660 const int index( face.at( i ) );
661 const int index1( face.at( ( i + 1 ) % 3 ) );
662 const int index2( face.at( ( i + 2 ) % 3 ) );
663
664 if ( std::isnan( verticalMagnitude[index] ) ||
665 std::isnan( verticalMagnitude[index1] ) ||
666 std::isnan( verticalMagnitude[index2] ) )
667 continue;
668
669 const QgsMeshVertex &vert( triangularMesh.vertices().at( index ) );
670 const QgsMeshVertex &otherVert1( triangularMesh.vertices().at( index1 ) );
671 const QgsMeshVertex &otherVert2( triangularMesh.vertices().at( index2 ) );
672
673 float adjustRelative = 0;
674 float adjustRelative1 = 0;
675 float adjustRelative2 = 0;
676
677 if ( isRelative )
678 {
679 adjustRelative = vert.z();
680 adjustRelative1 = otherVert1.z();
681 adjustRelative2 = otherVert2.z();
682 }
683
684 const QVector3D v1( float( otherVert1.x() - vert.x() ),
685 float( otherVert1.y() - vert.y() ),
686 float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
687 const QVector3D v2( float( otherVert2.x() - vert.x() ),
688 float( otherVert2.y() - vert.y() ),
689 float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
690
691 normals[index] += QVector3D::crossProduct( v1, v2 );
692 }
693 }
694
695 return normals;
696}
697
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.
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
bool isVector() const
Returns whether dataset group has vector data.
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
DataType
Location of where data is specified for datasets in the dataset group.
@ DataOnEdges
Data is defined on edges.
@ DataOnFaces
Data is defined on faces.
@ DataOnVertices
Data is defined on vertices.
@ DataOnVolumes
Data is defined on volumes.
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.
Definition qgspointxy.h:59
double y
Definition qgspointxy.h:63
double x
Definition qgspointxy.h:62
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
double z
Definition qgspoint.h:54
A rectangle specified with double values.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
double xMaximum() const
Returns the x maximum value (right side of rectangle).
double yMaximum() const
Returns the y maximum value (top side of rectangle).
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.
Definition qgsvector.h:30
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
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.