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 : :
367 : 0 : QgsMeshDataBlock activeFace;
368 : 0 : if ( active )
369 : 0 : activeFace = *active;
370 : : else
371 : : {
372 : 0 : activeFace = QgsMeshDataBlock( QgsMeshDataBlock::ActiveFlagInteger, nativeMesh.faceCount() );
373 : 0 : activeFace.setValid( true );
374 : : }
375 : :
376 : 0 : return interpolateFromFacesData( valuesOnFaces, nativeMesh, activeFace, method );
377 : :
378 : 0 : }
379 : :
380 : 0 : QVector<double> QgsMeshLayerUtils::interpolateFromFacesData( const QVector<double> &valuesOnFaces, const QgsMesh &nativeMesh, const QgsMeshDataBlock &active, QgsMeshRendererScalarSettings::DataResamplingMethod method )
381 : : {
382 : 0 : int vertexCount = nativeMesh.vertexCount();
383 : : Q_UNUSED( method );
384 : 0 : assert( method == QgsMeshRendererScalarSettings::NeighbourAverage );
385 : :
386 : 0 : QVector<double> res( vertexCount, 0.0 );
387 : : // for face datasets do simple average of the valid values of all faces that contains this vertex
388 : 0 : QVector<int> count( vertexCount, 0 );
389 : :
390 : 0 : for ( int i = 0; i < nativeMesh.faceCount(); ++i )
391 : : {
392 : 0 : if ( active.active( i ) )
393 : : {
394 : 0 : double val = valuesOnFaces[ i ];
395 : 0 : if ( !std::isnan( val ) )
396 : : {
397 : : // assign for all vertices
398 : 0 : const QgsMeshFace &face = nativeMesh.faces.at( i );
399 : 0 : for ( int j = 0; j < face.size(); ++j )
400 : : {
401 : 0 : int vertexIndex = face[j];
402 : 0 : res[vertexIndex] += val;
403 : 0 : count[vertexIndex] += 1;
404 : 0 : }
405 : 0 : }
406 : 0 : }
407 : 0 : }
408 : :
409 : 0 : for ( int i = 0; i < vertexCount; ++i )
410 : : {
411 : 0 : if ( count.at( i ) > 0 )
412 : : {
413 : 0 : res[i] = res[i] / double( count.at( i ) );
414 : 0 : }
415 : : else
416 : : {
417 : 0 : res[i] = std::numeric_limits<double>::quiet_NaN();
418 : : }
419 : 0 : }
420 : :
421 : 0 : return res;
422 : 0 : }
423 : :
424 : 0 : QVector<double> QgsMeshLayerUtils::resampleFromVerticesToFaces(
425 : : const QVector<double> valuesOnVertices,
426 : : const QgsMesh *nativeMesh,
427 : : const QgsTriangularMesh *triangularMesh,
428 : : const QgsMeshDataBlock *active,
429 : : QgsMeshRendererScalarSettings::DataResamplingMethod method )
430 : : {
431 : 0 : assert( nativeMesh );
432 : : Q_UNUSED( method );
433 : 0 : assert( method == QgsMeshRendererScalarSettings::NeighbourAverage );
434 : :
435 : : // assuming that native vertex count = triangular vertex count
436 : : Q_UNUSED( triangularMesh );
437 : 0 : assert( nativeMesh->vertices.size() == triangularMesh->vertices().size() );
438 : :
439 : 0 : QVector<double> ret( nativeMesh->faceCount(), std::numeric_limits<double>::quiet_NaN() );
440 : :
441 : 0 : for ( int i = 0; i < nativeMesh->faces.size(); ++i )
442 : : {
443 : 0 : const QgsMeshFace face = nativeMesh->face( i );
444 : 0 : if ( active->active( i ) && face.count() > 2 )
445 : : {
446 : 0 : double value = 0;
447 : 0 : for ( int j = 0; j < face.count(); ++j )
448 : : {
449 : 0 : value += valuesOnVertices.at( face.at( j ) );
450 : 0 : }
451 : 0 : ret[i] = value / face.count();
452 : 0 : }
453 : 0 : }
454 : :
455 : 0 : return ret;
456 : 0 : }
457 : :
458 : 0 : QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMeshLayer *meshLayer,
459 : : const QgsMeshDatasetIndex index,
460 : : QgsMeshDataBlock *activeFaceFlagValues,
461 : : const QgsMeshRendererScalarSettings::DataResamplingMethod method )
462 : : {
463 : 0 : QVector<double> ret;
464 : :
465 : 0 : if ( !meshLayer && !index.isValid() )
466 : 0 : return ret;
467 : :
468 : 0 : const QgsTriangularMesh *triangularMesh = meshLayer->triangularMesh();
469 : 0 : const QgsMesh *nativeMesh = meshLayer->nativeMesh();
470 : 0 : if ( !triangularMesh || !nativeMesh )
471 : 0 : return ret;
472 : :
473 : 0 : const QgsMeshDatasetGroupMetadata metadata = meshLayer->datasetGroupMetadata( index );
474 : 0 : bool scalarDataOnVertices = metadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
475 : :
476 : : // populate scalar values
477 : 0 : int datacount = scalarDataOnVertices ? nativeMesh->vertices.count() : nativeMesh->faces.count();
478 : 0 : QgsMeshDataBlock vals = QgsMeshLayerUtils::datasetValues(
479 : 0 : meshLayer,
480 : 0 : index,
481 : : 0,
482 : 0 : datacount );
483 : :
484 : 0 : QgsMeshDataBlock activeFace;
485 : 0 : if ( !activeFaceFlagValues )
486 : : {
487 : 0 : activeFace = QgsMeshDataBlock( QgsMeshDataBlock::ActiveFlagInteger, 0 );
488 : 0 : activeFace.setValid( true );
489 : 0 : }
490 : : else
491 : 0 : activeFace = *activeFaceFlagValues;
492 : :
493 : 0 : return calculateMagnitudeOnVertices( *nativeMesh, metadata, vals, activeFace, method );
494 : 0 : }
495 : :
496 : 0 : QVector<double> QgsMeshLayerUtils::calculateMagnitudeOnVertices( const QgsMesh &nativeMesh,
497 : : const QgsMeshDatasetGroupMetadata &groupMetadata,
498 : : const QgsMeshDataBlock &datasetValues,
499 : : const QgsMeshDataBlock &activeFaceFlagValues,
500 : : const QgsMeshRendererScalarSettings::DataResamplingMethod method )
501 : : {
502 : 0 : QVector<double> ret;
503 : 0 : bool scalarDataOnVertices = groupMetadata.dataType() == QgsMeshDatasetGroupMetadata::DataOnVertices;
504 : :
505 : 0 : if ( datasetValues.isValid() )
506 : : {
507 : 0 : ret = QgsMeshLayerUtils::calculateMagnitudes( datasetValues );
508 : :
509 : 0 : if ( !scalarDataOnVertices )
510 : : {
511 : : //Need to interpolate data on vertices
512 : 0 : ret = QgsMeshLayerUtils::interpolateFromFacesData(
513 : : ret,
514 : 0 : nativeMesh,
515 : 0 : activeFaceFlagValues,
516 : 0 : method );
517 : 0 : }
518 : 0 : }
519 : 0 : return ret;
520 : 0 : }
521 : :
522 : 0 : QgsRectangle QgsMeshLayerUtils::triangleBoundingBox( const QgsPointXY &p1, const QgsPointXY &p2, const QgsPointXY &p3 )
523 : : {
524 : : // p1
525 : 0 : double xMin = p1.x();
526 : 0 : double xMax = p1.x();
527 : 0 : double yMin = p1.y();
528 : 0 : double yMax = p1.y();
529 : :
530 : : //p2
531 : 0 : xMin = ( ( xMin < p2.x() ) ? xMin : p2.x() );
532 : 0 : xMax = ( ( xMax > p2.x() ) ? xMax : p2.x() );
533 : 0 : yMin = ( ( yMin < p2.y() ) ? yMin : p2.y() );
534 : 0 : yMax = ( ( yMax > p2.y() ) ? yMax : p2.y() );
535 : :
536 : : // p3
537 : 0 : xMin = ( ( xMin < p3.x() ) ? xMin : p3.x() );
538 : 0 : xMax = ( ( xMax > p3.x() ) ? xMax : p3.x() );
539 : 0 : yMin = ( ( yMin < p3.y() ) ? yMin : p3.y() );
540 : 0 : yMax = ( ( yMax > p3.y() ) ? yMax : p3.y() );
541 : :
542 : 0 : QgsRectangle bbox( xMin, yMin, xMax, yMax );
543 : 0 : return bbox;
544 : : }
545 : :
546 : 0 : QString QgsMeshLayerUtils::formatTime( double hours, const QDateTime &referenceTime, const QgsMeshTimeSettings &settings )
547 : : {
548 : 0 : QString ret;
549 : :
550 : 0 : if ( referenceTime.isValid() )
551 : : {
552 : 0 : QString format( settings.absoluteTimeFormat() );
553 : 0 : QDateTime dateTime( referenceTime );
554 : 0 : qint64 seconds = static_cast<qint64>( hours * 3600.0 );
555 : 0 : dateTime = dateTime.addSecs( seconds );
556 : 0 : ret = dateTime.toString( format );
557 : 0 : if ( ret.isEmpty() ) // error
558 : 0 : ret = dateTime.toString();
559 : 0 : }
560 : : else
561 : : {
562 : 0 : QString format( settings.relativeTimeFormat() );
563 : 0 : format = format.trimmed();
564 : 0 : int totalHours = static_cast<int>( hours );
565 : :
566 : 0 : if ( format == QLatin1String( "hh:mm:ss.zzz" ) )
567 : : {
568 : 0 : int ms = static_cast<int>( hours * 3600.0 * 1000 );
569 : 0 : int seconds = ms / 1000;
570 : 0 : int z = ms % 1000;
571 : 0 : int m = seconds / 60;
572 : 0 : int s = seconds % 60;
573 : 0 : int h = m / 60;
574 : 0 : m = m % 60;
575 : 0 : ret = QStringLiteral( "%1:%2:%3.%4" ).
576 : 0 : arg( h, 2, 10, QLatin1Char( '0' ) ).
577 : 0 : arg( m, 2, 10, QLatin1Char( '0' ) ).
578 : 0 : arg( s, 2, 10, QLatin1Char( '0' ) ).
579 : 0 : arg( z, 3, 10, QLatin1Char( '0' ) );
580 : 0 : }
581 : 0 : else if ( format == QLatin1String( "hh:mm:ss" ) )
582 : : {
583 : 0 : int seconds = static_cast<int>( hours * 3600.0 );
584 : 0 : int m = seconds / 60;
585 : 0 : int s = seconds % 60;
586 : 0 : int h = m / 60;
587 : 0 : m = m % 60;
588 : 0 : ret = QStringLiteral( "%1:%2:%3" ).
589 : 0 : arg( h, 2, 10, QLatin1Char( '0' ) ).
590 : 0 : arg( m, 2, 10, QLatin1Char( '0' ) ).
591 : 0 : arg( s, 2, 10, QLatin1Char( '0' ) );
592 : :
593 : 0 : }
594 : 0 : else if ( format == QLatin1String( "d hh:mm:ss" ) )
595 : : {
596 : 0 : int seconds = static_cast<int>( hours * 3600.0 );
597 : 0 : int m = seconds / 60;
598 : 0 : int s = seconds % 60;
599 : 0 : int h = m / 60;
600 : 0 : m = m % 60;
601 : 0 : int d = totalHours / 24;
602 : 0 : h = totalHours % 24;
603 : 0 : ret = QStringLiteral( "%1 d %2:%3:%4" ).
604 : 0 : arg( d ).
605 : 0 : arg( h, 2, 10, QLatin1Char( '0' ) ).
606 : 0 : arg( m, 2, 10, QLatin1Char( '0' ) ).
607 : 0 : arg( s, 2, 10, QLatin1Char( '0' ) );
608 : 0 : }
609 : 0 : else if ( format == QLatin1String( "d hh" ) )
610 : : {
611 : 0 : int d = totalHours / 24;
612 : 0 : int h = totalHours % 24;
613 : 0 : ret = QStringLiteral( "%1 d %2" ).
614 : 0 : arg( d ).
615 : 0 : arg( h );
616 : 0 : }
617 : 0 : else if ( format == QLatin1String( "d" ) )
618 : : {
619 : 0 : int d = totalHours / 24;
620 : 0 : ret = QString::number( d );
621 : 0 : }
622 : 0 : else if ( format == QLatin1String( "ss" ) )
623 : : {
624 : 0 : int seconds = static_cast<int>( hours * 3600.0 );
625 : 0 : ret = QString::number( seconds );
626 : 0 : }
627 : : else // "hh"
628 : : {
629 : 0 : ret = QString::number( hours );
630 : : }
631 : 0 : }
632 : 0 : return ret;
633 : 0 : }
634 : :
635 : 0 : QVector<QVector3D> QgsMeshLayerUtils::calculateNormals( const QgsTriangularMesh &triangularMesh, const QVector<double> &verticalMagnitude, bool isRelative )
636 : : {
637 : 0 : QVector<QVector3D> normals( triangularMesh.vertices().count() );
638 : 0 : for ( const auto &face : triangularMesh.triangles() )
639 : : {
640 : 0 : for ( int i = 0; i < 3; i++ )
641 : : {
642 : 0 : int index( face.at( i ) );
643 : 0 : int index1( face.at( ( i + 1 ) % 3 ) );
644 : 0 : int index2( face.at( ( i + 2 ) % 3 ) );
645 : :
646 : 0 : const QgsMeshVertex &vert( triangularMesh.vertices().at( index ) );
647 : 0 : const QgsMeshVertex &otherVert1( triangularMesh.vertices().at( index1 ) );
648 : 0 : const QgsMeshVertex &otherVert2( triangularMesh.vertices().at( index2 ) );
649 : :
650 : 0 : float adjustRelative = 0;
651 : 0 : float adjustRelative1 = 0;
652 : 0 : float adjustRelative2 = 0;
653 : :
654 : 0 : if ( isRelative )
655 : : {
656 : 0 : adjustRelative = vert.z();
657 : 0 : adjustRelative1 = otherVert1.z();
658 : 0 : adjustRelative2 = otherVert2.z();
659 : 0 : }
660 : :
661 : 0 : QVector3D v1( float( otherVert1.x() - vert.x() ),
662 : 0 : float( otherVert1.y() - vert.y() ),
663 : 0 : float( verticalMagnitude[index1] - verticalMagnitude[index] + adjustRelative1 - adjustRelative ) );
664 : 0 : QVector3D v2( float( otherVert2.x() - vert.x() ),
665 : 0 : float( otherVert2.y() - vert.y() ),
666 : 0 : float( verticalMagnitude[index2] - verticalMagnitude[index] + adjustRelative2 - adjustRelative ) );
667 : :
668 : 0 : normals[index] += QVector3D::crossProduct( v1, v2 );
669 : 0 : }
670 : : }
671 : :
672 : 0 : return normals;
673 : 0 : }
674 : :
675 : : ///@endcond
|