QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 
33 int QgsMeshLayerUtils::datasetValuesCount( const QgsMesh *mesh, QgsMeshDatasetGroupMetadata::DataType dataType )
34 {
35  if ( !mesh )
36  return 0;
37 
38  switch ( dataType )
39  {
40  case QgsMeshDatasetGroupMetadata::DataType::DataOnEdges:
41  return mesh->edgeCount();
42  case QgsMeshDatasetGroupMetadata::DataType::DataOnFaces:
43  return mesh->faceCount();
44  case QgsMeshDatasetGroupMetadata::DataType::DataOnVertices:
45  return mesh->vertexCount();
46  case QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes:
47  return mesh->faceCount(); // because they are averaged to faces
48  }
49  return 0;
50 }
51 
52 QgsMeshDatasetGroupMetadata::DataType QgsMeshLayerUtils::datasetValuesType( const QgsMeshDatasetGroupMetadata::DataType &type )
53 {
54  // data on volumes are averaged to 2D data on faces
55  if ( type == QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes )
56  return QgsMeshDatasetGroupMetadata::DataType::DataOnFaces;
57 
58  return type;
59 }
60 
61 QgsMeshDataBlock QgsMeshLayerUtils::datasetValues(
62  const QgsMeshLayer *meshLayer,
63  QgsMeshDatasetIndex index,
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() );
79  if ( meta.dataType() != QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes )
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 
100 QVector<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 );
154  QgsMeshDatasetValue value;
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 
186 QVector<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 
200 QgsRectangle QgsMeshLayerUtils::boundingBoxToScreenRectangle(
201  const QgsMapToPixel &mtp,
202  const QgsRectangle &bbox
203 )
204 {
205  const QgsPointXY topLeft = mtp.transform( bbox.xMinimum(), bbox.yMaximum() );
206  const QgsPointXY topRight = mtp.transform( bbox.xMaximum(), bbox.yMaximum() );
207  const QgsPointXY bottomLeft = mtp.transform( bbox.xMinimum(), bbox.yMinimum() );
208  const QgsPointXY bottomRight = mtp.transform( bbox.xMaximum(), bbox.yMinimum() );
209 
210  const double xMin = std::min( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
211  const double xMax = std::max( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
212  const double yMin = std::min( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
213  const double yMax = std::max( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
214 
215  const QgsRectangle ret( xMin, yMin, xMax, yMax );
216  return ret;
217 }
218 
219 void QgsMeshLayerUtils::boundingBoxToScreenRectangle(
220  const QgsMapToPixel &mtp,
221  const QSize &outputSize,
222  const QgsRectangle &bbox,
223  int &leftLim,
224  int &rightLim,
225  int &bottomLim,
226  int &topLim )
227 {
228  const QgsRectangle screenBBox = boundingBoxToScreenRectangle( mtp, bbox );
229 
230  bottomLim = std::max( int( screenBBox.yMinimum() ), 0 );
231  topLim = std::min( int( screenBBox.yMaximum() ), outputSize.height() - 1 );
232  leftLim = std::max( int( screenBBox.xMinimum() ), 0 );
233  rightLim = std::min( int( screenBBox.xMaximum() ), outputSize.width() - 1 );
234 }
235 
236 static void lamTol( double &lam )
237 {
238  const static double eps = 1e-6;
239  if ( ( lam < 0.0 ) && ( lam > -eps ) )
240  {
241  lam = 0.0;
242  }
243 }
244 
245 static bool E3T_physicalToBarycentric( const QgsPointXY &pA, const QgsPointXY &pB, const QgsPointXY &pC, const QgsPointXY &pP,
246  double &lam1, double &lam2, double &lam3 )
247 {
248  // Compute vectors
249  const double xa = pA.x();
250  const double ya = pA.y();
251  const double v0x = pC.x() - xa ;
252  const double v0y = pC.y() - ya ;
253  const double v1x = pB.x() - xa ;
254  const double v1y = pB.y() - ya ;
255  const double v2x = pP.x() - xa ;
256  const double v2y = pP.y() - ya ;
257 
258  // Compute dot products
259  const double dot00 = v0x * v0x + v0y * v0y;
260  const double dot01 = v0x * v1x + v0y * v1y;
261  const double dot02 = v0x * v2x + v0y * v2y;
262  const double dot11 = v1x * v1x + v1y * v1y;
263  const double dot12 = v1x * v2x + v1y * v2y;
264 
265  // Compute barycentric coordinates
266  double invDenom = dot00 * dot11 - dot01 * dot01;
267  if ( invDenom == 0 )
268  return false;
269  invDenom = 1.0 / invDenom;
270  lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
271  lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
272  lam3 = 1.0 - lam1 - lam2;
273 
274  // Apply some tolerance to lam so we can detect correctly border points
275  lamTol( lam1 );
276  lamTol( lam2 );
277  lamTol( lam3 );
278 
279  // Return if POI is outside triangle
280  if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
281  {
282  return false;
283  }
284 
285  return true;
286 }
287 
288 double QgsMeshLayerUtils::interpolateFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
289  double val1, double val2, double val3, const QgsPointXY &pt )
290 {
291  double lam1, lam2, lam3;
292  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
293  return std::numeric_limits<double>::quiet_NaN();
294 
295  return lam1 * val3 + lam2 * val2 + lam3 * val1;
296 }
297 
298 double QgsMeshLayerUtils::interpolateZForPoint( const QgsTriangularMesh &mesh, double x, double y )
299 {
300  const QgsPointXY point( x, y );
301  const int faceIndex = mesh.faceIndexForPoint_v2( point );
302  if ( faceIndex < 0 || faceIndex >= mesh.triangles().count() )
303  return std::numeric_limits<float>::quiet_NaN();
304 
305  const QgsMeshFace &face = mesh.triangles().at( faceIndex );
306 
307  const QgsPoint p1 = mesh.vertices().at( face.at( 0 ) );
308  const QgsPoint p2 = mesh.vertices().at( face.at( 1 ) );
309  const QgsPoint p3 = mesh.vertices().at( face.at( 2 ) );
310 
311  return QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, p1.z(), p2.z(), p3.z(), point );
312 }
313 
314 double QgsMeshLayerUtils::interpolateFromVerticesData( double fraction, double val1, double val2 )
315 {
316  if ( std::isnan( val1 ) || std::isnan( val2 ) || ( fraction < 0 ) || ( fraction > 1 ) )
317  {
318  return std::numeric_limits<double>::quiet_NaN();
319  }
320  return val1 + ( val2 - val1 ) * fraction;
321 }
322 
323 QgsMeshDatasetValue QgsMeshLayerUtils::interpolateFromVerticesData( double fraction, const QgsMeshDatasetValue &val1, const QgsMeshDatasetValue &val2 )
324 {
325  return QgsMeshDatasetValue( interpolateFromVerticesData( fraction, val1.x(), val2.x() ),
326  interpolateFromVerticesData( fraction, val1.y(), val2.y() ) );
327 }
328 
329 
330 QgsVector QgsMeshLayerUtils::interpolateVectorFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3, QgsVector vect1, QgsVector vect2, QgsVector vect3, const QgsPointXY &pt )
331 {
332  double lam1, lam2, lam3;
333  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
334  return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
335 
336  return vect3 * lam1 + vect2 * lam2 + vect1 * lam3;
337 }
338 
339 double QgsMeshLayerUtils::interpolateFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
340  double val, const QgsPointXY &pt )
341 {
342  double lam1, lam2, lam3;
343  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
344  return std::numeric_limits<double>::quiet_NaN();
345 
346  return val;
347 }
348 
349 QgsVector QgsMeshLayerUtils::interpolateVectorFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
350  QgsVector vect, const QgsPointXY &pt )
351 {
352  double lam1, lam2, lam3;
353  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
354  return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
355 
356  return vect;
357 }
358 
359 
360 QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
361  QVector<double> valuesOnFaces,
362  const QgsMesh *nativeMesh,
363  const QgsTriangularMesh *triangularMesh,
364  QgsMeshDataBlock *active,
366 {
367  assert( nativeMesh );
368  Q_UNUSED( method );
369  Q_UNUSED( triangularMesh );
370 
371  // assuming that native vertex count = triangular vertex count
372  assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
373 
374  return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
375 }
376 
377 QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces,
378  const QgsMesh &nativeMesh,
379  QgsMeshDataBlock *active,
381 {
382 
383  QgsMeshDataBlock activeFace;
384  if ( active )
385  activeFace = *active;
386  else
387  {
388  activeFace = QgsMeshDataBlock( QgsMeshDataBlock::ActiveFlagInteger, nativeMesh.faceCount() );
389  activeFace.setValid( true );
390  }
391 
392  return interpolateFromFacesData( valuesOnFaces, nativeMesh, activeFace, method );
393 
394 }
395 
396 QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces, const QgsMesh &nativeMesh, const QgsMeshDataBlock &active, QgsMeshRendererScalarSettings::DataResamplingMethod method )
397 {
398  const int vertexCount = nativeMesh.vertexCount();
399  Q_UNUSED( method );
401 
402  QVector<double> res( vertexCount, 0.0 );
403  // for face datasets do simple average of the valid values of all faces that contains this vertex
404  QVector<int> count( vertexCount, 0 );
405 
406  for ( int i = 0; i < nativeMesh.faceCount(); ++i )
407  {
408  if ( active.active( i ) )
409  {
410  const double val = valuesOnFaces[ i ];
411  if ( !std::isnan( val ) )
412  {
413  // assign for all vertices
414  const QgsMeshFace &face = nativeMesh.faces.at( i );
415  for ( int j = 0; j < face.size(); ++j )
416  {
417  const int vertexIndex = face[j];
418  res[vertexIndex] += val;
419  count[vertexIndex] += 1;
420  }
421  }
422  }
423  }
424 
425  for ( int i = 0; i < vertexCount; ++i )
426  {
427  if ( count.at( i ) > 0 )
428  {
429  res[i] = res[i] / double( count.at( i ) );
430  }
431  else
432  {
433  res[i] = std::numeric_limits<double>::quiet_NaN();
434  }
435  }
436 
437  return res;
438 }
439 
440 QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
441  const QVector<double> valuesOnVertices,
442  const QgsMesh *nativeMesh,
443  const QgsTriangularMesh *triangularMesh,
444  const QgsMeshDataBlock *active,
446 {
447  assert( nativeMesh );
448  Q_UNUSED( method );
450 
451  // assuming that native vertex count = triangular vertex count
452  Q_UNUSED( triangularMesh );
453  assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
454 
455  QVector<double> ret( nativeMesh->faceCount(), std::numeric_limits<double>::quiet_NaN() );
456 
457  for ( int i = 0; i < nativeMesh->faces.size(); ++i )
458  {
459  const QgsMeshFace face = nativeMesh->face( i );
460  if ( active->active( i ) && face.count() > 2 )
461  {
462  double value = 0;
463  for ( int j = 0; j < face.count(); ++j )
464  {
465  value += valuesOnVertices.at( face.at( j ) );
466  }
467  ret[i] = value / face.count();
468  }
469  }
470 
471  return ret;
472 }
473 
474 QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMeshLayer *meshLayer,
475  const QgsMeshDatasetIndex index,
476  QgsMeshDataBlock *activeFaceFlagValues,
478 {
479  QVector<double> ret;
480 
481  if ( !meshLayer && !index.isValid() )
482  return ret;
483 
484  const QgsTriangularMesh *triangularMesh = meshLayer->triangularMesh();
485  const QgsMesh *nativeMesh = meshLayer->nativeMesh();
486  if ( !triangularMesh || !nativeMesh )
487  return ret;
488 
489  const QgsMeshDatasetGroupMetadata metadata = meshLayer->datasetGroupMetadata( index );
490  const bool scalarDataOnVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
491 
492  // populate scalar values
493  const int datacount = scalarDataOnVertices ? nativeMesh->vertices.count() : nativeMesh->faces.count();
494  const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
495  meshLayer,
496  index,
497  0,
498  datacount );
499 
500  QgsMeshDataBlock activeFace;
501  if ( !activeFaceFlagValues )
502  {
504  activeFace.setValid( true );
505  }
506  else
507  activeFace = *activeFaceFlagValues;
508 
509  return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, activeFace, method );
510 }
511 
512 QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMesh &nativeMesh,
513  const QgsMeshDatasetGroupMetadata &groupMetadata,
514  const QgsMeshDataBlock &datasetValues,
515  const QgsMeshDataBlock &activeFaceFlagValues,
517 {
518  QVector<double> ret;
519  const bool scalarDataOnVertices = groupMetadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
520 
521  if ( datasetValues.isValid() )
522  {
523  ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
524 
525  if ( !scalarDataOnVertices )
526  {
527  //Need to interpolate data on vertices
528  ret = QgsMeshLayerUtils::interpolateFromFacesData(
529  ret,
530  nativeMesh,
531  activeFaceFlagValues,
532  method );
533  }
534  }
535  return ret;
536 }
537 
538 QgsRectangle QgsMeshLayerUtils::triangleBoundingBox( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 )
539 {
540  // p1
541  double xMin = p1.x();
542  double xMax = p1.x();
543  double yMin = p1.y();
544  double yMax = p1.y();
545 
546  //p2
547  xMin = ( ( xMin < p2.x() ) ? xMin : p2.x() );
548  xMax = ( ( xMax > p2.x() ) ? xMax : p2.x() );
549  yMin = ( ( yMin < p2.y() ) ? yMin : p2.y() );
550  yMax = ( ( yMax > p2.y() ) ? yMax : p2.y() );
551 
552  // p3
553  xMin = ( ( xMin < p3.x() ) ? xMin : p3.x() );
554  xMax = ( ( xMax > p3.x() ) ? xMax : p3.x() );
555  yMin = ( ( yMin < p3.y() ) ? yMin : p3.y() );
556  yMax = ( ( yMax > p3.y() ) ? yMax : p3.y() );
557 
558  const QgsRectangle bbox( xMin, yMin, xMax, yMax );
559  return bbox;
560 }
561 
562 QString QgsMeshLayerUtils::formatTime( double hours, const QDateTime &referenceTime, const QgsMeshTimeSettings &settings )
563 {
564  QString ret;
565 
566  if ( referenceTime.isValid() )
567  {
568  const QString format( settings.absoluteTimeFormat() );
569  QDateTime dateTime( referenceTime );
570  const qint64 seconds = static_cast<qint64>( hours * 3600.0 );
571  dateTime = dateTime.addSecs( seconds );
572  ret = dateTime.toString( format );
573  if ( ret.isEmpty() ) // error
574  ret = dateTime.toString();
575  }
576  else
577  {
578  QString format( settings.relativeTimeFormat() );
579  format = format.trimmed();
580  const int totalHours = static_cast<int>( hours );
581 
582  if ( format == QLatin1String( "hh:mm:ss.zzz" ) )
583  {
584  const int ms = static_cast<int>( hours * 3600.0 * 1000 );
585  const int seconds = ms / 1000;
586  const int z = ms % 1000;
587  int m = seconds / 60;
588  const int s = seconds % 60;
589  const int h = m / 60;
590  m = m % 60;
591  ret = QStringLiteral( "%1:%2:%3.%4" ).
592  arg( h, 2, 10, QLatin1Char( '0' ) ).
593  arg( m, 2, 10, QLatin1Char( '0' ) ).
594  arg( s, 2, 10, QLatin1Char( '0' ) ).
595  arg( z, 3, 10, QLatin1Char( '0' ) );
596  }
597  else if ( format == QLatin1String( "hh:mm:ss" ) )
598  {
599  const int seconds = static_cast<int>( hours * 3600.0 );
600  int m = seconds / 60;
601  const int s = seconds % 60;
602  const int h = m / 60;
603  m = m % 60;
604  ret = QStringLiteral( "%1:%2:%3" ).
605  arg( h, 2, 10, QLatin1Char( '0' ) ).
606  arg( m, 2, 10, QLatin1Char( '0' ) ).
607  arg( s, 2, 10, QLatin1Char( '0' ) );
608 
609  }
610  else if ( format == QLatin1String( "d hh:mm:ss" ) )
611  {
612  const int seconds = static_cast<int>( hours * 3600.0 );
613  int m = seconds / 60;
614  const int s = seconds % 60;
615  int h = m / 60;
616  m = m % 60;
617  const int d = totalHours / 24;
618  h = totalHours % 24;
619  ret = QStringLiteral( "%1 d %2:%3:%4" ).
620  arg( d ).
621  arg( h, 2, 10, QLatin1Char( '0' ) ).
622  arg( m, 2, 10, QLatin1Char( '0' ) ).
623  arg( s, 2, 10, QLatin1Char( '0' ) );
624  }
625  else if ( format == QLatin1String( "d hh" ) )
626  {
627  const int d = totalHours / 24;
628  const int h = totalHours % 24;
629  ret = QStringLiteral( "%1 d %2" ).
630  arg( d ).
631  arg( h );
632  }
633  else if ( format == QLatin1String( "d" ) )
634  {
635  const int d = totalHours / 24;
636  ret = QString::number( d );
637  }
638  else if ( format == QLatin1String( "ss" ) )
639  {
640  const int seconds = static_cast<int>( hours * 3600.0 );
641  ret = QString::number( seconds );
642  }
643  else // "hh"
644  {
645  ret = QString::number( hours );
646  }
647  }
648  return ret;
649 }
650 
651 QVector<QVector3D> QgsMeshLayerUtils::calculateNormals( const QgsTriangularMesh &triangularMesh, const QVector<double> &verticalMagnitude, bool isRelative )
652 {
653  QVector<QVector3D> normals( triangularMesh.vertices().count() );
654  for ( const auto &face : triangularMesh.triangles() )
655  {
656  for ( int i = 0; i < 3; i++ )
657  {
658  const int index( face.at( i ) );
659  const int index1( face.at( ( i + 1 ) % 3 ) );
660  const int index2( face.at( ( i + 2 ) % 3 ) );
661 
662  const QgsMeshVertex &vert( triangularMesh.vertices().at( index ) );
663  const QgsMeshVertex &otherVert1( triangularMesh.vertices().at( index1 ) );
664  const QgsMeshVertex &otherVert2( triangularMesh.vertices().at( index2 ) );
665 
666  float adjustRelative = 0;
667  float adjustRelative1 = 0;
668  float adjustRelative2 = 0;
669 
670  if ( isRelative )
671  {
672  adjustRelative = vert.z();
673  adjustRelative1 = otherVert1.z();
674  adjustRelative2 = otherVert2.z();
675  }
676 
677  const QVector3D v1( float( otherVert1.x() - vert.x() ),
678  float( otherVert1.y() - vert.y() ),
679  float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
680  const QVector3D v2( float( otherVert2.x() - vert.x() ),
681  float( otherVert2.y() - vert.y() ),
682  float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
683 
684  normals[index] += QVector3D::crossProduct( v1, v2 );
685  }
686  }
687 
688  return normals;
689 }
690 
qgsmeshlayerutils.h
qgsmesh3daveraging.h
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsMeshDatasetGroupMetadata::DataOnVolumes
@ DataOnVolumes
Data is defined on volumes.
Definition: qgsmeshdataset.h:360
QgsTriangularMesh::vertices
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
Definition: qgstriangularmesh.cpp:352
QgsMeshTimeSettings
Represents a mesh time settings for mesh datasets.
Definition: qgsmeshtimesettings.h:35
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsMesh3dDataBlock::isValid
bool isValid() const
Whether the block is valid.
Definition: qgsmeshdataset.cpp:342
QgsMeshDatasetValue
QgsMeshDatasetValue represents single dataset value.
Definition: qgsmeshdataset.h:79
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
QgsPoint::z
double z
Definition: qgspoint.h:71
QgsTriangularMesh::triangles
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
Definition: qgstriangularmesh.cpp:357
QgsMesh
Mesh - vertices, edges and faces.
Definition: qgsmeshdataprovider.h:58
QgsMeshLayer::triangularMesh
QgsTriangularMesh * triangularMesh(double minimumTriangleSize=0) const
Returns triangular mesh (nullptr before rendering or calling to updateMesh).
Definition: qgsmeshlayer.cpp:285
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsMesh3dDataBlock
QgsMesh3dDataBlock is a block of 3d stacked mesh data related N faces defined on base mesh frame.
Definition: qgsmeshdataset.h:246
QgsMeshDataBlock::type
DataType type() const
Type of data stored in the block.
Definition: qgsmeshdataset.cpp:252
QgsMeshLayer::rendererSettings
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
Definition: qgsmeshlayer.cpp:344
QgsMeshRendererScalarSettings::NeighbourAverage
@ NeighbourAverage
Does a simple average of values defined for all surrounding faces/vertices.
Definition: qgsmeshrenderersettings.h:116
qgstriangularmesh.h
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
qgsmeshtimesettings.h
QgsMeshDatasetGroupMetadata::DataOnFaces
@ DataOnFaces
Data is defined on faces.
Definition: qgsmeshdataset.h:358
QgsMeshDatasetGroupMetadata::DataOnVertices
@ DataOnVertices
Data is defined on vertices.
Definition: qgsmeshdataset.h:359
QgsMesh::faceCount
int faceCount() const
Returns number of faces.
Definition: qgsmeshdataprovider.cpp:205
QgsMeshDatasetIndex::group
int group() const
Returns a group index.
Definition: qgsmeshdataset.cpp:27
QgsMesh::vertexCount
int vertexCount() const
Returns number of vertices.
Definition: qgsmeshdataprovider.cpp:200
QgsMesh::faces
QVector< QgsMeshFace > faces
Definition: qgsmeshdataprovider.h:114
QgsMesh::edgeCount
int edgeCount() const
Returns number of edge.
Definition: qgsmeshdataprovider.cpp:210
QgsMeshLayer::dataset3dValues
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.
Definition: qgsmeshlayer.cpp:429
QgsMeshDatasetIndex
QgsMeshDatasetIndex is index that identifies the dataset group (e.g. wind speed) and a dataset in thi...
Definition: qgsmeshdataset.h:48
QgsMeshLayer
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:98
QgsMeshDataBlock::active
bool active(int index) const
Returns a value for active flag by the index For scalar and vector 2d the behavior is undefined.
Definition: qgsmeshdataset.cpp:283
QgsMeshDatasetIndex::isValid
bool isValid() const
Returns whether index is valid, ie at least groups is set.
Definition: qgsmeshdataset.cpp:37
QgsMeshTimeSettings::relativeTimeFormat
QString relativeTimeFormat() const
Returns format used for relative time.
Definition: qgsmeshtimesettings.cpp:39
QgsMeshDatasetValue::x
double x() const
Returns x value.
Definition: qgsmeshdataset.cpp:94
QgsMeshLayer::datasetCount
int datasetCount(const QgsMeshDatasetIndex &index) const
Returns the dataset count in the dataset groups.
Definition: qgsmeshlayer.cpp:409
QgsMesh::face
QgsMeshFace face(int index) const
Returns a face at the index.
Definition: qgsmeshdataprovider.cpp:145
QgsMeshLayer::nativeMesh
QgsMesh * nativeMesh()
Returns native mesh (nullptr before rendering or calling to updateMesh)
Definition: qgsmeshlayer.cpp:275
QgsMeshRendererScalarSettings::DataResamplingMethod
DataResamplingMethod
Resampling of value from dataset.
Definition: qgsmeshrenderersettings.h:105
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
QgsTriangularMesh::faceIndexForPoint_v2
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.
Definition: qgstriangularmesh.cpp:447
QgsMeshDatasetGroupMetadata::DataOnEdges
@ DataOnEdges
Data is defined on edges.
Definition: qgsmeshdataset.h:361
QgsMeshFace
QVector< int > QgsMeshFace
List of vertex indexes.
Definition: qgsmeshdataprovider.h:42
QgsMeshTimeSettings::absoluteTimeFormat
QString absoluteTimeFormat() const
Returns format used for absolute time.
Definition: qgsmeshtimesettings.cpp:49
QgsMapToPixel::transform
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:90
QgsMesh3dAveragingMethod
Abstract class to interpolate 3d stacked mesh data to 2d data.
Definition: qgsmesh3daveraging.h:39
QgsMeshDataBlock::setValid
void setValid(bool valid)
Sets block validity.
Definition: qgsmeshdataset.cpp:327
qgsmeshlayer.h
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsMeshDatasetGroupMetadata::dataType
DataType dataType() const
Returns whether dataset group data is defined on vertices or faces or volumes.
Definition: qgsmeshdataset.cpp:172
QgsMeshDatasetGroupMetadata
QgsMeshDatasetGroupMetadata is a collection of dataset group metadata such as whether the data is vec...
Definition: qgsmeshdataset.h:351
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
QgsMapToPixel
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:38
QgsMeshDatasetGroupMetadata::DataType
DataType
Location of where data is specified for datasets in the dataset group.
Definition: qgsmeshdataset.h:356
QgsMeshDataBlock::ActiveFlagInteger
@ ActiveFlagInteger
Integer boolean flag whether face is active.
Definition: qgsmeshdataset.h:143
QgsTriangularMesh::trianglesToNativeFaces
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
Definition: qgstriangularmesh.cpp:382
QgsVector
A class to represent a vector. Currently no Z axis / 2.5D support is implemented.
Definition: qgsvector.h:29
QgsPointXY::x
double x
Definition: qgspointxy.h:62
QgsMeshDatasetValue::y
double y() const
Returns y value.
Definition: qgsmeshdataset.cpp:99
QgsMesh::vertices
QVector< QgsMeshVertex > vertices
Definition: qgsmeshdataprovider.h:112
QgsMeshRendererSettings::averagingMethod
QgsMesh3dAveragingMethod * averagingMethod() const
Returns averaging method for conversion of 3d stacked mesh data to 2d data.
Definition: qgsmeshrenderersettings.cpp:394
QgsMeshDataBlock
QgsMeshDataBlock is a block of integers/doubles that can be used to retrieve: active flags (e....
Definition: qgsmeshdataset.h:137
QgsMeshLayer::datasetGroupMetadata
QgsMeshDatasetGroupMetadata datasetGroupMetadata(const QgsMeshDatasetIndex &index) const
Returns the dataset groups metadata.
Definition: qgsmeshlayer.cpp:404
QgsTriangularMesh
Triangular/Derived Mesh is mesh with vertices in map coordinates.
Definition: qgstriangularmesh.h:51
QgsMeshLayer::datasetValues
QgsMeshDataBlock datasetValues(const QgsMeshDatasetIndex &index, int valueIndex, int count) const
Returns N vector/scalar values from the index from the dataset.
Definition: qgsmeshlayer.cpp:424
qgslogger.h
QgsMeshDatasetGroupMetadata::isVector
bool isVector() const
Returns whether dataset group has vector data.
Definition: qgsmeshdataset.cpp:152
QgsMeshDataBlock::value
QgsMeshDatasetValue value(int index) const
Returns a value represented by the index For active flag the behavior is undefined.
Definition: qgsmeshdataset.cpp:267
QgsMeshDatasetValue::scalar
double scalar() const
Returns magnitude of vector for vector data or scalar value for scalar data.
Definition: qgsmeshdataset.cpp:63
QgsMesh3dAveragingMethod::calculate
QgsMeshDataBlock calculate(const QgsMesh3dDataBlock &block3d, QgsFeedback *feedback=nullptr) const
Calculated 2d block values from 3d stacked mesh values.
Definition: qgsmesh3daveraging.cpp:58
QgsMeshLayer::areFacesActive
QgsMeshDataBlock areFacesActive(const QgsMeshDatasetIndex &index, int faceIndex, int count) const
Returns whether the faces are active for particular dataset.
Definition: qgsmeshlayer.cpp:434
qgsmeshdataprovider.h
QgsMeshDataBlock::isValid
bool isValid() const
Whether the block is valid.
Definition: qgsmeshdataset.cpp:262
QgsMeshDataBlock::count
int count() const
Number of items stored in the block.
Definition: qgsmeshdataset.cpp:257