QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  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  QgsMeshDatasetGroupMetadata meta = meshLayer->datasetGroupMetadata( index );
119  if ( !meta.isVector() )
120  return vectors;
121 
122  // extract vector dataset
123  bool vectorDataOnVertices = meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
124  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  double y = minCorner.y() + iy * ySpacing;
146  for ( int ix = 0; ix < size.width(); ++ix )
147  {
148  double x = minCorner.x() + ix * xSpacing;
149  QgsPoint point( x, y );
150  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  int count = block.count();
190  QVector<double> ret( count );
191 
192  for ( int i = 0; i < count; ++i )
193  {
194  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  double xMin = std::min( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
211  double xMax = std::max( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
212  double yMin = std::min( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
213  double yMax = std::max( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
214 
215  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  double xa = pA.x();
250  double ya = pA.y();
251  double v0x = pC.x() - xa ;
252  double v0y = pC.y() - ya ;
253  double v1x = pB.x() - xa ;
254  double v1y = pB.y() - ya ;
255  double v2x = pP.x() - xa ;
256  double v2y = pP.y() - ya ;
257 
258  // Compute dot products
259  double dot00 = v0x * v0x + v0y * v0y;
260  double dot01 = v0x * v1x + v0y * v1y;
261  double dot02 = v0x * v2x + v0y * v2y;
262  double dot11 = v1x * v1x + v1y * v1y;
263  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::interpolateFromVerticesData( double fraction, double val1, double val2 )
299 {
300  if ( std::isnan( val1 ) || std::isnan( val2 ) || ( fraction < 0 ) || ( fraction > 1 ) )
301  {
302  return std::numeric_limits<double>::quiet_NaN();
303  }
304  return val1 + ( val2 - val1 ) * fraction;
305 }
306 
307 QgsMeshDatasetValue QgsMeshLayerUtils::interpolateFromVerticesData( double fraction, const QgsMeshDatasetValue &val1, const QgsMeshDatasetValue &val2 )
308 {
309  return QgsMeshDatasetValue( interpolateFromVerticesData( fraction, val1.x(), val2.x() ),
310  interpolateFromVerticesData( fraction, val1.y(), val2.y() ) );
311 }
312 
313 
314 QgsVector QgsMeshLayerUtils::interpolateVectorFromVerticesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3, QgsVector vect1, QgsVector vect2, QgsVector vect3, const QgsPointXY &pt )
315 {
316  double lam1, lam2, lam3;
317  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
318  return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
319 
320  return vect3 * lam1 + vect2 * lam2 + vect1 * lam3;
321 }
322 
323 double QgsMeshLayerUtils::interpolateFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
324  double val, const QgsPointXY &pt )
325 {
326  double lam1, lam2, lam3;
327  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
328  return std::numeric_limits<double>::quiet_NaN();
329 
330  return val;
331 }
332 
333 QgsVector QgsMeshLayerUtils::interpolateVectorFromFacesData( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3,
334  QgsVector vect, const QgsPointXY &pt )
335 {
336  double lam1, lam2, lam3;
337  if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
338  return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
339 
340  return vect;
341 }
342 
343 
344 QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
345  QVector<double> valuesOnFaces,
346  const QgsMesh *nativeMesh,
347  const QgsTriangularMesh *triangularMesh,
348  QgsMeshDataBlock *active,
350 {
351  assert( nativeMesh );
352  Q_UNUSED( method );
353 
354 
355  // assuming that native vertex count = triangular vertex count
356  assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
357 
358  return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
359 }
360 
361 QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces,
362  const QgsMesh &nativeMesh,
363  QgsMeshDataBlock *active,
365 {
366  int vertexCount = nativeMesh.vertexCount();
368 
369  QVector<double> res( vertexCount, 0.0 );
370  // for face datasets do simple average of the valid values of all faces that contains this vertex
371  QVector<int> count( vertexCount, 0 );
372 
373  for ( int i = 0; i < nativeMesh.faceCount(); ++i )
374  {
375  if ( !active || active->active( i ) )
376  {
377  double val = valuesOnFaces[ i ];
378  if ( !std::isnan( val ) )
379  {
380  // assign for all vertices
381  const QgsMeshFace &face = nativeMesh.faces.at( i );
382  for ( int j = 0; j < face.size(); ++j )
383  {
384  int vertexIndex = face[j];
385  res[vertexIndex] += val;
386  count[vertexIndex] += 1;
387  }
388  }
389  }
390  }
391 
392  for ( int i = 0; i < vertexCount; ++i )
393  {
394  if ( count.at( i ) > 0 )
395  {
396  res[i] = res[i] / double( count.at( i ) );
397  }
398  else
399  {
400  res[i] = std::numeric_limits<double>::quiet_NaN();
401  }
402  }
403 
404  return res;
405 }
406 
407 QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
408  const QVector<double> valuesOnVertices,
409  const QgsMesh *nativeMesh,
410  const QgsTriangularMesh *triangularMesh,
411  const QgsMeshDataBlock *active,
413 {
414  assert( nativeMesh );
415  Q_UNUSED( method );
417 
418  // assuming that native vertex count = triangular vertex count
419  Q_UNUSED( triangularMesh );
420  assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
421 
422  QVector<double> ret( nativeMesh->faceCount(), std::numeric_limits<double>::quiet_NaN() );
423 
424  for ( int i = 0; i < nativeMesh->faces.size(); ++i )
425  {
426  const QgsMeshFace face = nativeMesh->face( i );
427  if ( active->active( i ) && face.count() > 2 )
428  {
429  double value = 0;
430  for ( int j = 0; j < face.count(); ++j )
431  {
432  value += valuesOnVertices.at( face.at( j ) );
433  }
434  ret[i] = value / face.count();
435  }
436  }
437 
438  return ret;
439 }
440 
441 QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMeshLayer *meshLayer,
442  const QgsMeshDatasetIndex index,
443  QgsMeshDataBlock *activeFaceFlagValues,
445 {
446  QVector<double> ret;
447 
448  if ( !meshLayer && !index.isValid() )
449  return ret;
450 
451  const QgsTriangularMesh *triangularMesh = meshLayer->triangularMesh();
452  const QgsMesh *nativeMesh = meshLayer->nativeMesh();
453  if ( !triangularMesh || !nativeMesh )
454  return ret;
455 
456  const QgsMeshDatasetGroupMetadata metadata = meshLayer->datasetGroupMetadata( index );
457  bool scalarDataOnVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
458 
459  // populate scalar values
460  int datacount = scalarDataOnVertices ? nativeMesh->vertices.count() : nativeMesh->faces.count();
461  QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
462  meshLayer,
463  index,
464  0,
465  datacount );
466 
467  return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, *activeFaceFlagValues, method );
468 }
469 
470 QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMesh &nativeMesh,
471  const QgsMeshDatasetGroupMetadata &groupMetadata,
472  const QgsMeshDataBlock &datasetValues,
473  QgsMeshDataBlock &activeFaceFlagValues,
475 {
476  QVector<double> ret;
477  bool scalarDataOnVertices = groupMetadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
478 
479  if ( datasetValues.isValid() )
480  {
481  ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
482 
483  if ( !scalarDataOnVertices )
484  {
485  //Need to interpolate data on vertices
486  ret = QgsMeshLayerUtils::interpolateFromFacesData(
487  ret,
488  nativeMesh,
489  &activeFaceFlagValues,
490  method );
491  }
492  }
493  return ret;
494 }
495 
496 QgsRectangle QgsMeshLayerUtils::triangleBoundingBox( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 )
497 {
498  // p1
499  double xMin = p1.x();
500  double xMax = p1.x();
501  double yMin = p1.y();
502  double yMax = p1.y();
503 
504  //p2
505  xMin = ( ( xMin < p2.x() ) ? xMin : p2.x() );
506  xMax = ( ( xMax > p2.x() ) ? xMax : p2.x() );
507  yMin = ( ( yMin < p2.y() ) ? yMin : p2.y() );
508  yMax = ( ( yMax > p2.y() ) ? yMax : p2.y() );
509 
510  // p3
511  xMin = ( ( xMin < p3.x() ) ? xMin : p3.x() );
512  xMax = ( ( xMax > p3.x() ) ? xMax : p3.x() );
513  yMin = ( ( yMin < p3.y() ) ? yMin : p3.y() );
514  yMax = ( ( yMax > p3.y() ) ? yMax : p3.y() );
515 
516  QgsRectangle bbox( xMin, yMin, xMax, yMax );
517  return bbox;
518 }
519 
520 QString QgsMeshLayerUtils::formatTime( double hours, const QDateTime &referenceTime, const QgsMeshTimeSettings &settings )
521 {
522  QString ret;
523 
524  if ( referenceTime.isValid() )
525  {
526  QString format( settings.absoluteTimeFormat() );
527  QDateTime dateTime( referenceTime );
528  qint64 seconds = static_cast<qint64>( hours * 3600.0 );
529  dateTime = dateTime.addSecs( seconds );
530  ret = dateTime.toString( format );
531  if ( ret.isEmpty() ) // error
532  ret = dateTime.toString();
533  }
534  else
535  {
536  QString format( settings.relativeTimeFormat() );
537  format = format.trimmed();
538  int totalHours = static_cast<int>( hours );
539 
540  if ( format == QLatin1String( "hh:mm:ss.zzz" ) )
541  {
542  int ms = static_cast<int>( hours * 3600.0 * 1000 );
543  int seconds = ms / 1000;
544  int z = ms % 1000;
545  int m = seconds / 60;
546  int s = seconds % 60;
547  int h = m / 60;
548  m = m % 60;
549  ret = QStringLiteral( "%1:%2:%3.%4" ).
550  arg( h, 2, 10, QLatin1Char( '0' ) ).
551  arg( m, 2, 10, QLatin1Char( '0' ) ).
552  arg( s, 2, 10, QLatin1Char( '0' ) ).
553  arg( z, 3, 10, QLatin1Char( '0' ) );
554  }
555  else if ( format == QLatin1String( "hh:mm:ss" ) )
556  {
557  int seconds = static_cast<int>( hours * 3600.0 );
558  int m = seconds / 60;
559  int s = seconds % 60;
560  int h = m / 60;
561  m = m % 60;
562  ret = QStringLiteral( "%1:%2:%3" ).
563  arg( h, 2, 10, QLatin1Char( '0' ) ).
564  arg( m, 2, 10, QLatin1Char( '0' ) ).
565  arg( s, 2, 10, QLatin1Char( '0' ) );
566 
567  }
568  else if ( format == QLatin1String( "d hh:mm:ss" ) )
569  {
570  int seconds = static_cast<int>( hours * 3600.0 );
571  int m = seconds / 60;
572  int s = seconds % 60;
573  int h = m / 60;
574  m = m % 60;
575  int d = totalHours / 24;
576  h = totalHours % 24;
577  ret = QStringLiteral( "%1 d %2:%3:%4" ).
578  arg( d ).
579  arg( h, 2, 10, QLatin1Char( '0' ) ).
580  arg( m, 2, 10, QLatin1Char( '0' ) ).
581  arg( s, 2, 10, QLatin1Char( '0' ) );
582  }
583  else if ( format == QLatin1String( "d hh" ) )
584  {
585  int d = totalHours / 24;
586  int h = totalHours % 24;
587  ret = QStringLiteral( "%1 d %2" ).
588  arg( d ).
589  arg( h );
590  }
591  else if ( format == QLatin1String( "d" ) )
592  {
593  int d = totalHours / 24;
594  ret = QString::number( d );
595  }
596  else if ( format == QLatin1String( "ss" ) )
597  {
598  int seconds = static_cast<int>( hours * 3600.0 );
599  ret = QString::number( seconds );
600  }
601  else // "hh"
602  {
603  ret = QString::number( hours );
604  }
605  }
606  return ret;
607 }
608 
609 QVector<QVector3D> QgsMeshLayerUtils::calculateNormals( const QgsTriangularMesh &triangularMesh, const QVector<double> &verticalMagnitude, bool isRelative )
610 {
611  QVector<QVector3D> normals( triangularMesh.vertices().count() );
612  for ( const auto &face : triangularMesh.triangles() )
613  {
614  for ( int i = 0; i < 3; i++ )
615  {
616  int index( face.at( i ) );
617  int index1( face.at( ( i + 1 ) % 3 ) );
618  int index2( face.at( ( i + 2 ) % 3 ) );
619 
620  const QgsMeshVertex &vert( triangularMesh.vertices().at( index ) );
621  const QgsMeshVertex &otherVert1( triangularMesh.vertices().at( index1 ) );
622  const QgsMeshVertex &otherVert2( triangularMesh.vertices().at( index2 ) );
623 
624  float adjustRelative = 0;
625  float adjustRelative1 = 0;
626  float adjustRelative2 = 0;
627 
628  if ( isRelative )
629  {
630  adjustRelative = vert.z();
631  adjustRelative1 = otherVert1.z();
632  adjustRelative2 = otherVert2.z();
633  }
634 
635  QVector3D v1( float( otherVert1.x() - vert.x() ),
636  float( otherVert1.y() - vert.y() ),
637  float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
638  QVector3D v2( float( otherVert2.x() - vert.x() ),
639  float( otherVert2.y() - vert.y() ),
640  float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
641 
642  normals[index] += QVector3D::crossProduct( v1, v2 );
643  }
644  }
645 
646  return normals;
647 }
648 
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
QgsPointXY transform(const QgsPointXY &p) const
Transform the point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:82
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.
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.
Definition: qgsmeshlayer.h:95
int datasetCount(const QgsMeshDatasetIndex &index) const
Returns the dataset count in the dataset groups.
QgsMeshRendererSettings rendererSettings() const
Returns renderer settings.
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.
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).
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:44
double y
Definition: qgspointxy.h:48
Q_GADGET double x
Definition: qgspointxy.h:47
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
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.