Branch data Line data Source code
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 : :
31 : : ///@cond PRIVATE
32 : :
33 : 0 : int QgsMeshLayerUtils::datasetValuesCount( const QgsMesh *mesh, QgsMeshDatasetGroupMetadata::DataType dataType )
34 : : {
35 : 0 : if ( !mesh )
36 : 0 : return 0;
37 : :
38 : 0 : switch ( dataType )
39 : : {
40 : : case QgsMeshDatasetGroupMetadata::DataType::DataOnEdges:
41 : 0 : return mesh->edgeCount();
42 : : case QgsMeshDatasetGroupMetadata::DataType::DataOnFaces:
43 : 0 : return mesh->faceCount();
44 : : case QgsMeshDatasetGroupMetadata::DataType::DataOnVertices:
45 : 0 : return mesh->vertexCount();
46 : : case QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes:
47 : 0 : return mesh->faceCount(); // because they are averaged to faces
48 : : }
49 : 0 : return 0;
50 : 0 : }
51 : :
52 : 0 : QgsMeshDatasetGroupMetadata::DataType QgsMeshLayerUtils::datasetValuesType( const QgsMeshDatasetGroupMetadata::DataType &type )
53 : : {
54 : : // data on volumes are averaged to 2D data on faces
55 : 0 : if ( type == QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes )
56 : 0 : return QgsMeshDatasetGroupMetadata::DataType::DataOnFaces;
57 : :
58 : 0 : return type;
59 : 0 : }
60 : :
61 : 0 : QgsMeshDataBlock QgsMeshLayerUtils::datasetValues(
62 : : const QgsMeshLayer *meshLayer,
63 : : QgsMeshDatasetIndex index,
64 : : int valueIndex,
65 : : int count )
66 : : {
67 : 0 : QgsMeshDataBlock block;
68 : 0 : if ( !meshLayer )
69 : 0 : return block;
70 : :
71 : :
72 : 0 : if ( !meshLayer->datasetCount( index ) )
73 : 0 : return block;
74 : :
75 : 0 : if ( !index.isValid() )
76 : 0 : return block;
77 : :
78 : 0 : const QgsMeshDatasetGroupMetadata meta = meshLayer->datasetGroupMetadata( index.group() );
79 : 0 : if ( meta.dataType() != QgsMeshDatasetGroupMetadata::DataType::DataOnVolumes )
80 : : {
81 : 0 : block = meshLayer->datasetValues( index, valueIndex, count );
82 : 0 : if ( block.isValid() )
83 : 0 : return block;
84 : 0 : }
85 : : else
86 : : {
87 : 0 : const QgsMesh3dAveragingMethod *averagingMethod = meshLayer->rendererSettings().averagingMethod();
88 : 0 : if ( !averagingMethod )
89 : 0 : return block;
90 : :
91 : 0 : QgsMesh3dDataBlock block3d = meshLayer->dataset3dValues( index, valueIndex, count );
92 : 0 : if ( !block3d.isValid() )
93 : 0 : return block;
94 : :
95 : 0 : block = averagingMethod->calculate( block3d );
96 : 0 : }
97 : 0 : return block;
98 : 0 : }
99 : :
100 : 0 : 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 : 0 : QVector<QgsVector> vectors;
108 : :
109 : 0 : if ( !meshLayer || !index.isValid() )
110 : 0 : return vectors;
111 : :
112 : 0 : const QgsTriangularMesh *triangularMesh = meshLayer->triangularMesh();
113 : 0 : const QgsMesh *nativeMesh = meshLayer->nativeMesh();
114 : :
115 : 0 : if ( !triangularMesh || !nativeMesh )
116 : 0 : return vectors;
117 : :
118 : 0 : QgsMeshDatasetGroupMetadata meta = meshLayer->datasetGroupMetadata( index );
119 : 0 : if ( !meta.isVector() )
120 : 0 : return vectors;
121 : :
122 : : // extract vector dataset
123 : 0 : bool vectorDataOnVertices = meta.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
124 : 0 : int datacount = vectorDataOnVertices ? nativeMesh->vertices.count() : nativeMesh->faces.count();
125 : 0 : const QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues( meshLayer, index, 0, datacount );
126 : :
127 : 0 : const QgsMeshDataBlock isFacesActive = meshLayer->areFacesActive( index, 0, nativeMesh->faceCount() );
128 : 0 : const QgsMeshDatasetGroupMetadata::DataType dataType = meta.dataType();
129 : :
130 : 0 : if ( dataType == QgsMeshDatasetGroupMetadata::DataOnEdges )
131 : 0 : return vectors;
132 : :
133 : : try
134 : : {
135 : 0 : vectors.reserve( size.height()*size.width() );
136 : 0 : }
137 : : catch ( ... )
138 : : {
139 : 0 : QgsDebugMsgLevel( "Unable to store the arrow grid in memory", 1 );
140 : 0 : return QVector<QgsVector>();
141 : 0 : }
142 : :
143 : 0 : for ( int iy = 0; iy < size.height(); ++iy )
144 : : {
145 : 0 : double y = minCorner.y() + iy * ySpacing;
146 : 0 : for ( int ix = 0; ix < size.width(); ++ix )
147 : : {
148 : 0 : double x = minCorner.x() + ix * xSpacing;
149 : 0 : QgsPoint point( x, y );
150 : 0 : int faceIndex = triangularMesh->faceIndexForPoint_v2( point );
151 : 0 : int nativeFaceIndex = -1;
152 : 0 : if ( faceIndex != -1 )
153 : 0 : nativeFaceIndex = triangularMesh->trianglesToNativeFaces().at( faceIndex );
154 : 0 : QgsMeshDatasetValue value;
155 : 0 : if ( nativeFaceIndex != -1 && isFacesActive.active( nativeFaceIndex ) )
156 : : {
157 : 0 : switch ( dataType )
158 : : {
159 : : case QgsMeshDatasetGroupMetadata::DataOnFaces:
160 : : case QgsMeshDatasetGroupMetadata::DataOnVolumes:
161 : 0 : value = vals.value( nativeFaceIndex );
162 : 0 : break;
163 : : case QgsMeshDatasetGroupMetadata::DataOnVertices:
164 : : {
165 : 0 : const QgsMeshFace &face = triangularMesh->triangles()[faceIndex];
166 : 0 : const int v1 = face[0], v2 = face[1], v3 = face[2];
167 : 0 : const QgsPoint p1 = triangularMesh->vertices()[v1], p2 = triangularMesh->vertices()[v2], p3 = triangularMesh->vertices()[v3];
168 : 0 : const QgsMeshDatasetValue val1 = vals.value( v1 );
169 : 0 : const QgsMeshDatasetValue val2 = vals.value( v2 );
170 : 0 : const QgsMeshDatasetValue val3 = vals.value( v3 );
171 : 0 : const double x = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.x(), val2.x(), val3.x(), point );
172 : 0 : const double y = QgsMeshLayerUtils::interpolateFromVerticesData( p1, p2, p3, val1.y(), val2.y(), val3.y(), point );
173 : 0 : value = QgsMeshDatasetValue( x, y );
174 : 0 : }
175 : 0 : break;
176 : : case QgsMeshDatasetGroupMetadata::DataOnEdges:
177 : 0 : break;
178 : : }
179 : 0 : }
180 : 0 : vectors.append( QgsVector( value.x(), value.y() ) );
181 : 0 : }
182 : 0 : }
183 : 0 : return vectors;
184 : 0 : }
185 : :
186 : 0 : QVector<double> QgsMeshLayerUtils::calculateMagnitudes( const QgsMeshDataBlock &block )
187 : : {
188 : : Q_ASSERT( QgsMeshDataBlock::ActiveFlagInteger != block.type() );
189 : 0 : int count = block.count();
190 : 0 : QVector<double> ret( count );
191 : :
192 : 0 : for ( int i = 0; i < count; ++i )
193 : : {
194 : 0 : double mag = block.value( i ).scalar();
195 : 0 : ret[i] = mag;
196 : 0 : }
197 : 0 : return ret;
198 : 0 : }
199 : :
200 : 0 : QgsRectangle QgsMeshLayerUtils::boundingBoxToScreenRectangle(
201 : : const QgsMapToPixel &mtp,
202 : : const QgsRectangle &bbox
203 : : )
204 : : {
205 : 0 : const QgsPointXY topLeft = mtp.transform( bbox.xMinimum(), bbox.yMaximum() );
206 : 0 : const QgsPointXY topRight = mtp.transform( bbox.xMaximum(), bbox.yMaximum() );
207 : 0 : const QgsPointXY bottomLeft = mtp.transform( bbox.xMinimum(), bbox.yMinimum() );
208 : 0 : const QgsPointXY bottomRight = mtp.transform( bbox.xMaximum(), bbox.yMinimum() );
209 : :
210 : 0 : double xMin = std::min( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
211 : 0 : double xMax = std::max( {topLeft.x(), topRight.x(), bottomLeft.x(), bottomRight.x()} );
212 : 0 : double yMin = std::min( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
213 : 0 : double yMax = std::max( {topLeft.y(), topRight.y(), bottomLeft.y(), bottomRight.y()} );
214 : :
215 : 0 : QgsRectangle ret( xMin, yMin, xMax, yMax );
216 : 0 : return ret;
217 : : }
218 : :
219 : 0 : 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 : 0 : const QgsRectangle screenBBox = boundingBoxToScreenRectangle( mtp, bbox );
229 : :
230 : 0 : bottomLim = std::max( int( screenBBox.yMinimum() ), 0 );
231 : 0 : topLim = std::min( int( screenBBox.yMaximum() ), outputSize.height() - 1 );
232 : 0 : leftLim = std::max( int( screenBBox.xMinimum() ), 0 );
233 : 0 : rightLim = std::min( int( screenBBox.xMaximum() ), outputSize.width() - 1 );
234 : 0 : }
235 : :
236 : 0 : static void lamTol( double &lam )
237 : : {
238 : : const static double eps = 1e-6;
239 : 0 : if ( ( lam < 0.0 ) && ( lam > -eps ) )
240 : : {
241 : 0 : lam = 0.0;
242 : 0 : }
243 : 0 : }
244 : :
245 : 0 : 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 : 0 : double xa = pA.x();
250 : 0 : double ya = pA.y();
251 : 0 : double v0x = pC.x() - xa ;
252 : 0 : double v0y = pC.y() - ya ;
253 : 0 : double v1x = pB.x() - xa ;
254 : 0 : double v1y = pB.y() - ya ;
255 : 0 : double v2x = pP.x() - xa ;
256 : 0 : double v2y = pP.y() - ya ;
257 : :
258 : : // Compute dot products
259 : 0 : double dot00 = v0x * v0x + v0y * v0y;
260 : 0 : double dot01 = v0x * v1x + v0y * v1y;
261 : 0 : double dot02 = v0x * v2x + v0y * v2y;
262 : 0 : double dot11 = v1x * v1x + v1y * v1y;
263 : 0 : double dot12 = v1x * v2x + v1y * v2y;
264 : :
265 : : // Compute barycentric coordinates
266 : 0 : double invDenom = dot00 * dot11 - dot01 * dot01;
267 : 0 : if ( invDenom == 0 )
268 : 0 : return false;
269 : 0 : invDenom = 1.0 / invDenom;
270 : 0 : lam1 = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
271 : 0 : lam2 = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
272 : 0 : lam3 = 1.0 - lam1 - lam2;
273 : :
274 : : // Apply some tolerance to lam so we can detect correctly border points
275 : 0 : lamTol( lam1 );
276 : 0 : lamTol( lam2 );
277 : 0 : lamTol( lam3 );
278 : :
279 : : // Return if POI is outside triangle
280 : 0 : if ( ( lam1 < 0 ) || ( lam2 < 0 ) || ( lam3 < 0 ) )
281 : : {
282 : 0 : return false;
283 : : }
284 : :
285 : 0 : return true;
286 : 0 : }
287 : :
288 : 0 : 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 : 0 : if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
293 : 0 : return std::numeric_limits<double>::quiet_NaN();
294 : :
295 : 0 : return lam1 * val3 + lam2 * val2 + lam3 * val1;
296 : 0 : }
297 : :
298 : 0 : double QgsMeshLayerUtils::interpolateFromVerticesData( double fraction, double val1, double val2 )
299 : : {
300 : 0 : if ( std::isnan( val1 ) || std::isnan( val2 ) || ( fraction < 0 ) || ( fraction > 1 ) )
301 : : {
302 : 0 : return std::numeric_limits<double>::quiet_NaN();
303 : : }
304 : 0 : return val1 + ( val2 - val1 ) * fraction;
305 : 0 : }
306 : :
307 : 0 : QgsMeshDatasetValue QgsMeshLayerUtils::interpolateFromVerticesData( double fraction, const QgsMeshDatasetValue &val1, const QgsMeshDatasetValue &val2 )
308 : : {
309 : 0 : return QgsMeshDatasetValue( interpolateFromVerticesData( fraction, val1.x(), val2.x() ),
310 : 0 : interpolateFromVerticesData( fraction, val1.y(), val2.y() ) );
311 : : }
312 : :
313 : :
314 : 0 : 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 : 0 : if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
318 : 0 : return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
319 : :
320 : 0 : return vect3 * lam1 + vect2 * lam2 + vect1 * lam3;
321 : 0 : }
322 : :
323 : 0 : 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 : 0 : if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
328 : 0 : return std::numeric_limits<double>::quiet_NaN();
329 : :
330 : 0 : return val;
331 : 0 : }
332 : :
333 : 0 : 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 : 0 : if ( !E3T_physicalToBarycentric( p1, p2, p3, pt, lam1, lam2, lam3 ) )
338 : 0 : return QgsVector( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
339 : :
340 : 0 : return vect;
341 : 0 : }
342 : :
343 : :
344 : 0 : QVector<double> QgsMeshLayerUtils::interpolateFromFacesData(
345 : : QVector<double> valuesOnFaces,
346 : : const QgsMesh *nativeMesh,
347 : : const QgsTriangularMesh *triangularMesh,
348 : : QgsMeshDataBlock *active,
349 : : QgsMeshRendererScalarSettings::DataResamplingMethod method )
350 : : {
351 : 0 : assert( nativeMesh );
352 : : Q_UNUSED( method );
353 : : Q_UNUSED( triangularMesh );
354 : :
355 : : // assuming that native vertex count = triangular vertex count
356 : 0 : assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
357 : :
358 : 0 : return interpolateFromFacesData( valuesOnFaces, *nativeMesh, active, method );
359 : : }
360 : :
361 : 0 : QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces,
362 : : const QgsMesh &nativeMesh,
363 : : QgsMeshDataBlock *active,
364 : : QgsMeshRendererScalarSettings::DataResamplingMethod method )
365 : : {
366 : 0 : int vertexCount = nativeMesh.vertexCount();
367 : : Q_UNUSED( method );
368 : 0 : assert( method == QgsMeshRendererScalarSettings::NeighbourAverage );
369 : :
370 : 0 : QVector<double> res( vertexCount, 0.0 );
371 : : // for face datasets do simple average of the valid values of all faces that contains this vertex
372 : 0 : QVector<int> count( vertexCount, 0 );
373 : :
374 : 0 : for ( int i = 0; i < nativeMesh.faceCount(); ++i )
375 : : {
376 : 0 : if ( !active || active->active( i ) )
377 : : {
378 : 0 : double val = valuesOnFaces[ i ];
379 : 0 : if ( !std::isnan( val ) )
380 : : {
381 : : // assign for all vertices
382 : 0 : const QgsMeshFace &face = nativeMesh.faces.at( i );
383 : 0 : for ( int j = 0; j < face.size(); ++j )
384 : : {
385 : 0 : int vertexIndex = face[j];
386 : 0 : res[vertexIndex] += val;
387 : 0 : count[vertexIndex] += 1;
388 : 0 : }
389 : 0 : }
390 : 0 : }
391 : 0 : }
392 : :
393 : 0 : for ( int i = 0; i < vertexCount; ++i )
394 : : {
395 : 0 : if ( count.at( i ) > 0 )
396 : : {
397 : 0 : res[i] = res[i] / double( count.at( i ) );
398 : 0 : }
399 : : else
400 : : {
401 : 0 : res[i] = std::numeric_limits<double>::quiet_NaN();
402 : : }
403 : 0 : }
404 : :
405 : 0 : return res;
406 : 0 : }
407 : :
408 : 0 : QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
409 : : const QVector<double> valuesOnVertices,
410 : : const QgsMesh *nativeMesh,
411 : : const QgsTriangularMesh *triangularMesh,
412 : : const QgsMeshDataBlock *active,
413 : : QgsMeshRendererScalarSettings::DataResamplingMethod method )
414 : : {
415 : 0 : assert( nativeMesh );
416 : : Q_UNUSED( method );
417 : 0 : assert( method == QgsMeshRendererScalarSettings::NeighbourAverage );
418 : :
419 : : // assuming that native vertex count = triangular vertex count
420 : : Q_UNUSED( triangularMesh );
421 : 0 : assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
422 : :
423 : 0 : QVector<double> ret( nativeMesh->faceCount(), std::numeric_limits<double>::quiet_NaN() );
424 : :
425 : 0 : for ( int i = 0; i < nativeMesh->faces.size(); ++i )
426 : : {
427 : 0 : const QgsMeshFace face = nativeMesh->face( i );
428 : 0 : if ( active->active( i ) && face.count() > 2 )
429 : : {
430 : 0 : double value = 0;
431 : 0 : for ( int j = 0; j < face.count(); ++j )
432 : : {
433 : 0 : value += valuesOnVertices.at( face.at( j ) );
434 : 0 : }
435 : 0 : ret[i] = value / face.count();
436 : 0 : }
437 : 0 : }
438 : :
439 : 0 : return ret;
440 : 0 : }
441 : :
442 : 0 : QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMeshLayer *meshLayer,
443 : : const QgsMeshDatasetIndex index,
444 : : QgsMeshDataBlock *activeFaceFlagValues,
445 : : const QgsMeshRendererScalarSettings::DataResamplingMethod method )
446 : : {
447 : 0 : QVector<double> ret;
448 : :
449 : 0 : if ( !meshLayer && !index.isValid() )
450 : 0 : return ret;
451 : :
452 : 0 : const QgsTriangularMesh *triangularMesh = meshLayer->triangularMesh();
453 : 0 : const QgsMesh *nativeMesh = meshLayer->nativeMesh();
454 : 0 : if ( !triangularMesh || !nativeMesh )
455 : 0 : return ret;
456 : :
457 : 0 : const QgsMeshDatasetGroupMetadata metadata = meshLayer->datasetGroupMetadata( index );
458 : 0 : bool scalarDataOnVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
459 : :
460 : : // populate scalar values
461 : 0 : int datacount = scalarDataOnVertices ? nativeMesh->vertices.count() : nativeMesh->faces.count();
462 : 0 : QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
463 : 0 : meshLayer,
464 : 0 : index,
465 : : 0,
466 : 0 : datacount );
467 : :
468 : 0 : return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, *activeFaceFlagValues, method );
469 : 0 : }
470 : :
471 : 0 : QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMesh &nativeMesh,
472 : : const QgsMeshDatasetGroupMetadata &groupMetadata,
473 : : const QgsMeshDataBlock &datasetValues,
474 : : QgsMeshDataBlock &activeFaceFlagValues,
475 : : const QgsMeshRendererScalarSettings::DataResamplingMethod method )
476 : : {
477 : 0 : QVector<double> ret;
478 : 0 : bool scalarDataOnVertices = groupMetadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
479 : :
480 : 0 : if ( datasetValues.isValid() )
481 : : {
482 : 0 : ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
483 : :
484 : 0 : if ( !scalarDataOnVertices )
485 : : {
486 : : //Need to interpolate data on vertices
487 : 0 : ret = QgsMeshLayerUtils::interpolateFromFacesData(
488 : : ret,
489 : 0 : nativeMesh,
490 : 0 : &activeFaceFlagValues,
491 : 0 : method );
492 : 0 : }
493 : 0 : }
494 : 0 : return ret;
495 : 0 : }
496 : :
497 : 0 : QgsRectangle QgsMeshLayerUtils::triangleBoundingBox( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 )
498 : : {
499 : : // p1
500 : 0 : double xMin = p1.x();
501 : 0 : double xMax = p1.x();
502 : 0 : double yMin = p1.y();
503 : 0 : double yMax = p1.y();
504 : :
505 : : //p2
506 : 0 : xMin = ( ( xMin < p2.x() ) ? xMin : p2.x() );
507 : 0 : xMax = ( ( xMax > p2.x() ) ? xMax : p2.x() );
508 : 0 : yMin = ( ( yMin < p2.y() ) ? yMin : p2.y() );
509 : 0 : yMax = ( ( yMax > p2.y() ) ? yMax : p2.y() );
510 : :
511 : : // p3
512 : 0 : xMin = ( ( xMin < p3.x() ) ? xMin : p3.x() );
513 : 0 : xMax = ( ( xMax > p3.x() ) ? xMax : p3.x() );
514 : 0 : yMin = ( ( yMin < p3.y() ) ? yMin : p3.y() );
515 : 0 : yMax = ( ( yMax > p3.y() ) ? yMax : p3.y() );
516 : :
517 : 0 : QgsRectangle bbox( xMin, yMin, xMax, yMax );
518 : 0 : return bbox;
519 : : }
520 : :
521 : 0 : QString QgsMeshLayerUtils::formatTime( double hours, const QDateTime &referenceTime, const QgsMeshTimeSettings &settings )
522 : : {
523 : 0 : QString ret;
524 : :
525 : 0 : if ( referenceTime.isValid() )
526 : : {
527 : 0 : QString format( settings.absoluteTimeFormat() );
528 : 0 : QDateTime dateTime( referenceTime );
529 : 0 : qint64 seconds = static_cast<qint64>( hours * 3600.0 );
530 : 0 : dateTime = dateTime.addSecs( seconds );
531 : 0 : ret = dateTime.toString( format );
532 : 0 : if ( ret.isEmpty() ) // error
533 : 0 : ret = dateTime.toString();
534 : 0 : }
535 : : else
536 : : {
537 : 0 : QString format( settings.relativeTimeFormat() );
538 : 0 : format = format.trimmed();
539 : 0 : int totalHours = static_cast<int>( hours );
540 : :
541 : 0 : if ( format == QLatin1String( "hh:mm:ss.zzz" ) )
542 : : {
543 : 0 : int ms = static_cast<int>( hours * 3600.0 * 1000 );
544 : 0 : int seconds = ms / 1000;
545 : 0 : int z = ms % 1000;
546 : 0 : int m = seconds / 60;
547 : 0 : int s = seconds % 60;
548 : 0 : int h = m / 60;
549 : 0 : m = m % 60;
550 : 0 : ret = QStringLiteral( "%1:%2:%3.%4" ).
551 : 0 : arg( h, 2, 10, QLatin1Char( '0' ) ).
552 : 0 : arg( m, 2, 10, QLatin1Char( '0' ) ).
553 : 0 : arg( s, 2, 10, QLatin1Char( '0' ) ).
554 : 0 : arg( z, 3, 10, QLatin1Char( '0' ) );
555 : 0 : }
556 : 0 : else if ( format == QLatin1String( "hh:mm:ss" ) )
557 : : {
558 : 0 : int seconds = static_cast<int>( hours * 3600.0 );
559 : 0 : int m = seconds / 60;
560 : 0 : int s = seconds % 60;
561 : 0 : int h = m / 60;
562 : 0 : m = m % 60;
563 : 0 : ret = QStringLiteral( "%1:%2:%3" ).
564 : 0 : arg( h, 2, 10, QLatin1Char( '0' ) ).
565 : 0 : arg( m, 2, 10, QLatin1Char( '0' ) ).
566 : 0 : arg( s, 2, 10, QLatin1Char( '0' ) );
567 : :
568 : 0 : }
569 : 0 : else if ( format == QLatin1String( "d hh:mm:ss" ) )
570 : : {
571 : 0 : int seconds = static_cast<int>( hours * 3600.0 );
572 : 0 : int m = seconds / 60;
573 : 0 : int s = seconds % 60;
574 : 0 : int h = m / 60;
575 : 0 : m = m % 60;
576 : 0 : int d = totalHours / 24;
577 : 0 : h = totalHours % 24;
578 : 0 : ret = QStringLiteral( "%1 d %2:%3:%4" ).
579 : 0 : arg( d ).
580 : 0 : arg( h, 2, 10, QLatin1Char( '0' ) ).
581 : 0 : arg( m, 2, 10, QLatin1Char( '0' ) ).
582 : 0 : arg( s, 2, 10, QLatin1Char( '0' ) );
583 : 0 : }
584 : 0 : else if ( format == QLatin1String( "d hh" ) )
585 : : {
586 : 0 : int d = totalHours / 24;
587 : 0 : int h = totalHours % 24;
588 : 0 : ret = QStringLiteral( "%1 d %2" ).
589 : 0 : arg( d ).
590 : 0 : arg( h );
591 : 0 : }
592 : 0 : else if ( format == QLatin1String( "d" ) )
593 : : {
594 : 0 : int d = totalHours / 24;
595 : 0 : ret = QString::number( d );
596 : 0 : }
597 : 0 : else if ( format == QLatin1String( "ss" ) )
598 : : {
599 : 0 : int seconds = static_cast<int>( hours * 3600.0 );
600 : 0 : ret = QString::number( seconds );
601 : 0 : }
602 : : else // "hh"
603 : : {
604 : 0 : ret = QString::number( hours );
605 : : }
606 : 0 : }
607 : 0 : return ret;
608 : 0 : }
609 : :
610 : 0 : QVector<QVector3D> QgsMeshLayerUtils::calculateNormals( const QgsTriangularMesh &triangularMesh, const QVector<double> &verticalMagnitude, bool isRelative )
611 : : {
612 : 0 : QVector<QVector3D> normals( triangularMesh.vertices().count() );
613 : 0 : for ( const auto &face : triangularMesh.triangles() )
614 : : {
615 : 0 : for ( int i = 0; i < 3; i++ )
616 : : {
617 : 0 : int index( face.at( i ) );
618 : 0 : int index1( face.at( ( i + 1 ) % 3 ) );
619 : 0 : int index2( face.at( ( i + 2 ) % 3 ) );
620 : :
621 : 0 : const QgsMeshVertex &vert( triangularMesh.vertices().at( index ) );
622 : 0 : const QgsMeshVertex &otherVert1( triangularMesh.vertices().at( index1 ) );
623 : 0 : const QgsMeshVertex &otherVert2( triangularMesh.vertices().at( index2 ) );
624 : :
625 : 0 : float adjustRelative = 0;
626 : 0 : float adjustRelative1 = 0;
627 : 0 : float adjustRelative2 = 0;
628 : :
629 : 0 : if ( isRelative )
630 : : {
631 : 0 : adjustRelative = vert.z();
632 : 0 : adjustRelative1 = otherVert1.z();
633 : 0 : adjustRelative2 = otherVert2.z();
634 : 0 : }
635 : :
636 : 0 : QVector3D v1( float( otherVert1.x() - vert.x() ),
637 : 0 : float( otherVert1.y() - vert.y() ),
638 : 0 : float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
639 : 0 : QVector3D v2( float( otherVert2.x() - vert.x() ),
640 : 0 : float( otherVert2.y() - vert.y() ),
641 : 0 : float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
642 : :
643 : 0 : normals[index] += QVector3D::crossProduct( v1, v2 );
644 : 0 : }
645 : : }
646 : :
647 : 0 : return normals;
648 : 0 : }
649 : :
650 : : ///@endcond
|