QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgstriangularmesh.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgstriangularmesh.cpp
3  ---------------------
4  begin : April 2018
5  copyright : (C) 2018 by Peter Petrik
6  email : zilolv 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 <memory>
19 #include <QList>
20 #include "qgspolygon.h"
21 #include "qgslinestring.h"
22 #include "qgstriangularmesh.h"
23 #include "qgsrendercontext.h"
24 #include "qgscoordinatetransform.h"
25 #include "qgsgeometry.h"
26 #include "qgsrectangle.h"
27 #include "qgslogger.h"
28 #include "qgsmeshspatialindex.h"
29 #include "qgsmeshlayerutils.h"
30 #include "meshOptimizer/meshoptimizer.h"
31 
32 static void ENP_centroid_step( const QPolygonF &pX, double &cx, double &cy, double &signedArea, int i, int i1 )
33 {
34  double x0 = 0.0; // Current vertex X
35  double y0 = 0.0; // Current vertex Y
36  double x1 = 0.0; // Next vertex X
37  double y1 = 0.0; // Next vertex Y
38  double a = 0.0; // Partial signed area
39 
40  x0 = pX[i].x();
41  y0 = pX[i].y();
42  x1 = pX[i1].x();
43  y1 = pX[i1].y();
44  a = x0 * y1 - x1 * y0;
45  signedArea += a;
46  cx += ( x0 + x1 ) * a;
47  cy += ( y0 + y1 ) * a;
48 }
49 
50 static void ENP_centroid( const QPolygonF &pX, double &cx, double &cy )
51 {
52  // http://stackoverflow.com/questions/2792443/finding-the-centroid-of-a-polygon/2792459#2792459
53  cx = 0;
54  cy = 0;
55 
56  if ( pX.isEmpty() )
57  return;
58 
59  double signedArea = 0.0;
60 
61  const QPointF &pt0 = pX.first();
62  QPolygonF localPolygon( pX.count() );
63  for ( int i = 0; i < pX.count(); ++i )
64  localPolygon[i] = pX.at( i ) - pt0;
65 
66  // For all vertices except last
67  int i = 0;
68  for ( ; i < localPolygon.size() - 1; ++i )
69  {
70  ENP_centroid_step( localPolygon, cx, cy, signedArea, i, i + 1 );
71  }
72  // Do last vertex separately to avoid performing an expensive
73  // modulus operation in each iteration.
74  ENP_centroid_step( localPolygon, cx, cy, signedArea, i, 0 );
75 
76  signedArea *= 0.5;
77  cx /= ( 6.0 * signedArea );
78  cy /= ( 6.0 * signedArea );
79 
80  cx = cx + pt0.x();
81  cy = cy + pt0.y();
82 }
83 
84 static void triangulateFaces( const QgsMeshFace &face,
85  int nativeIndex,
86  QVector<QgsMeshFace> &destinationFaces,
87  QVector<int> &triangularToNative,
88  const QgsMesh &verticesMeshSource )
89 {
90  int vertexCount = face.size();
91  if ( vertexCount < 3 )
92  return;
93 
94  while ( vertexCount > 3 )
95  {
96  // clip one ear from last 2 and first vertex
97  const QgsMeshFace ear = { face[vertexCount - 2], face[vertexCount - 1], face[0] };
98  if ( !( std::isnan( verticesMeshSource.vertex( ear[0] ).x() ) ||
99  std::isnan( verticesMeshSource.vertex( ear[1] ).x() ) ||
100  std::isnan( verticesMeshSource.vertex( ear[2] ).x() ) ) )
101  {
102  destinationFaces.push_back( ear );
103  triangularToNative.push_back( nativeIndex );
104  }
105  --vertexCount;
106  }
107 
108  const QgsMeshFace triangle = { face[1], face[2], face[0] };
109  if ( !( std::isnan( verticesMeshSource.vertex( triangle[0] ).x() ) ||
110  std::isnan( verticesMeshSource.vertex( triangle[1] ).x() ) ||
111  std::isnan( verticesMeshSource.vertex( triangle[2] ).x() ) ) )
112  {
113  destinationFaces.push_back( triangle );
114  triangularToNative.push_back( nativeIndex );
115  }
116 }
117 
118 void QgsTriangularMesh::triangulate( const QgsMeshFace &face, int nativeIndex )
119 {
120  triangulateFaces( face, nativeIndex, mTriangularMesh.faces, mTrianglesToNativeFaces, mTriangularMesh );
121 }
122 
123 QgsMeshVertex QgsTriangularMesh::transformVertex( const QgsMeshVertex &vertex, Qgis::TransformDirection direction ) const
124 {
125  QgsMeshVertex transformedVertex = vertex;
126 
127  if ( mCoordinateTransform.isValid() )
128  {
129  try
130  {
131  transformedVertex.transform( mCoordinateTransform, direction );
132  }
133  catch ( QgsCsException &cse )
134  {
135  Q_UNUSED( cse )
136  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
137  transformedVertex = QgsMeshVertex();
138  }
139  }
140 
141  return transformedVertex;
142 }
143 
144 QgsMeshVertex QgsTriangularMesh::calculateCentroid( const QgsMeshFace &nativeFace )
145 {
146  return QgsMeshUtils::centroid( nativeFace, mTriangularMesh.vertices );
147 }
148 
150 {
151  return mAverageTriangleSize;
152 }
153 
156 
157 bool QgsTriangularMesh::update( QgsMesh *nativeMesh, const QgsCoordinateTransform &transform )
158 {
159  Q_ASSERT( nativeMesh );
160 
161  bool needUpdateVerticesCoordinates = mTriangularMesh.vertices.size() != nativeMesh->vertices.size() ||
162  ( ( mCoordinateTransform.isValid() || transform.isValid() ) &&
163  ( mCoordinateTransform.sourceCrs() != transform.sourceCrs() ||
164  mCoordinateTransform.destinationCrs() != transform.destinationCrs() ||
165  mCoordinateTransform.isValid() != transform.isValid() ) ) ;
166 
167  bool needUpdateFrame = mTriangularMesh.vertices.size() != nativeMesh->vertices.size() ||
168  mNativeMeshFaceCentroids.size() != nativeMesh->faces.size() ||
169  mTriangularMesh.faces.size() < nativeMesh->faces.size() ||
170  mTriangularMesh.edges.size() != nativeMesh->edges.size();
171 
172 
173  // FIND OUT IF UPDATE IS NEEDED
174  if ( ! needUpdateVerticesCoordinates && !needUpdateFrame )
175  return false;
176 
177  // CLEAN-UP
178  mTriangularMesh.vertices.clear();
179  if ( needUpdateFrame )
180  {
181  mTriangularMesh.faces.clear();
182  mTriangularMesh.edges.clear();
183  mEdgesToNativeEdges.clear();
184  mTrianglesToNativeFaces.clear();
185  }
186 
187  // TRANSFORM VERTICES
188  mCoordinateTransform = transform;
189  mTriangularMesh.vertices.resize( nativeMesh->vertices.size() );
190  mExtent.setMinimal();
191  for ( int i = 0; i < nativeMesh->vertices.size(); ++i )
192  {
193  mTriangularMesh.vertices[i] = nativeToTriangularCoordinates( nativeMesh->vertices.at( i ) );
194  mExtent.include( mTriangularMesh.vertices.at( i ) );
195  }
196 
197  if ( needUpdateFrame )
198  {
199  // CREATE TRIANGULAR MESH
200  for ( int i = 0; i < nativeMesh->faces.size(); ++i )
201  {
202  const QgsMeshFace &face = nativeMesh->faces.at( i ) ;
203  triangulate( face, i );
204  }
205  }
206 
207  // CALCULATE CENTROIDS
208  mNativeMeshFaceCentroids.resize( nativeMesh->faces.size() );
209  for ( int i = 0; i < nativeMesh->faces.size(); ++i )
210  {
211  const QgsMeshFace &face = nativeMesh->faces.at( i ) ;
212  mNativeMeshFaceCentroids[i] = calculateCentroid( face );
213  }
214 
215  // CALCULATE SPATIAL INDEX
216  mSpatialFaceIndex = QgsMeshSpatialIndex( mTriangularMesh, nullptr, QgsMesh::ElementType::Face );
217 
218  if ( needUpdateFrame )
219  {
220  // SET ALL TRIANGLE CCW AND COMPUTE AVERAGE SIZE
221  finalizeTriangles();
222  }
223 
224  // CREATE EDGES
225  // remove all edges with invalid vertices
226  if ( needUpdateFrame )
227  {
228  const QVector<QgsMeshEdge> edges = nativeMesh->edges;
229  for ( int nativeIndex = 0; nativeIndex < edges.size(); ++nativeIndex )
230  {
231  const QgsMeshEdge &edge = edges.at( nativeIndex );
232  if ( !( std::isnan( mTriangularMesh.vertex( edge.first ).x() ) ||
233  std::isnan( mTriangularMesh.vertex( edge.second ).x() ) ) )
234  {
235  mTriangularMesh.edges.push_back( edge );
236  mEdgesToNativeEdges.push_back( nativeIndex );
237  }
238  }
239  }
240 
241  // CALCULATE CENTROIDS
242  mNativeMeshEdgeCentroids.resize( nativeMesh->edgeCount() );
243  for ( int i = 0; i < nativeMesh->edgeCount(); ++i )
244  {
245  const QgsMeshEdge &edge = nativeMesh->edges.at( i ) ;
246  const QgsPoint &a = mTriangularMesh.vertices[edge.first];
247  const QgsPoint &b = mTriangularMesh.vertices[edge.second];
248  mNativeMeshEdgeCentroids[i] = QgsMeshVertex( ( a.x() + b.x() ) / 2.0, ( a.y() + b.y() ) / 2.0, ( a.z() + b.z() ) / 2.0 );
249  }
250 
251  // CALCULATE SPATIAL INDEX
252  mSpatialEdgeIndex = QgsMeshSpatialIndex( mTriangularMesh, nullptr, QgsMesh::ElementType::Edge );
253 
254  return true;
255 }
256 
257 void QgsTriangularMesh::finalizeTriangles()
258 {
259  mAverageTriangleSize = 0;
260  for ( int i = 0; i < mTriangularMesh.faceCount(); ++i )
261  {
262  QgsMeshFace &face = mTriangularMesh.faces[i];
263 
264  const QgsMeshVertex &v0 = mTriangularMesh.vertex( face[0] );
265  const QgsMeshVertex &v1 = mTriangularMesh.vertex( face[1] );
266  const QgsMeshVertex &v2 = mTriangularMesh.vertex( face[2] );
267 
268  QgsRectangle bbox = QgsMeshLayerUtils::triangleBoundingBox( v0, v1, v2 );
269 
270  mAverageTriangleSize += std::fmax( bbox.width(), bbox.height() );
271 
272  QgsMeshUtils::setCounterClockwise( face, v0, v1, v2 );
273  }
274  mAverageTriangleSize /= mTriangularMesh.faceCount();
275 }
276 
278 {
279  return transformVertex( vertex, Qgis::TransformDirection::Forward );
280 }
281 
283 {
284  return transformVertex( vertex, Qgis::TransformDirection::Reverse );
285 }
286 
288 {
290  if ( !mCoordinateTransform.isShortCircuited() )
291  {
292  try
293  {
294  QgsCoordinateTransform extentTransform = mCoordinateTransform;
295  extentTransform.setBallparkTransformsAreAppropriate( true );
296  nativeExtent = extentTransform.transformBoundingBox( extent(), Qgis::TransformDirection::Reverse );
297  }
298  catch ( QgsCsException &cse )
299  {
300  Q_UNUSED( cse )
301  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
302  }
303  }
304  else
305  nativeExtent = extent();
306 
307  return nativeExtent;
308 }
309 
311 {
312  if ( !mIsExtentValid )
313  {
314  mExtent.setMinimal();
315  for ( int i = 0; i < mTriangularMesh.vertices.size(); ++i )
316  if ( !mTriangularMesh.vertices.at( i ).isEmpty() )
317  mExtent.include( mTriangularMesh.vertices.at( i ) );
318 
319  mIsExtentValid = true;
320  }
321  return mExtent;
322 }
323 
325 {
326  return mLod;
327 }
328 
330 {
331  switch ( type )
332  {
333  case QgsMesh::ElementType::Vertex:
334  return mTriangularMesh.vertexCount() != 0;
335  case QgsMesh::ElementType::Edge:
336  return mTriangularMesh.edgeCount() != 0;
337  case QgsMesh::ElementType::Face:
338  return mTriangularMesh.faceCount() != 0;
339  }
340 
341  return false;
342 }
343 
344 void QgsTriangularMesh::addVertex( const QgsMeshVertex &vertex )
345 {
346  QgsMeshVertex vertexInTriangularCoordinates = nativeToTriangularCoordinates( vertex );
347  mTriangularMesh.vertices.append( vertexInTriangularCoordinates );
348  if ( !vertexInTriangularCoordinates.isEmpty() )
349  mExtent.include( vertexInTriangularCoordinates );
350 }
351 
352 const QVector<QgsMeshVertex> &QgsTriangularMesh::vertices() const
353 {
354  return mTriangularMesh.vertices;
355 }
356 
357 const QVector<QgsMeshFace> &QgsTriangularMesh::triangles() const
358 {
359  return mTriangularMesh.faces;
360 }
361 
362 const QVector<QgsMeshEdge> &QgsTriangularMesh::edges() const
363 {
364  return mTriangularMesh.edges;
365 }
366 
367 const QVector<QgsMeshVertex> &QgsTriangularMesh::centroids() const
368 {
369  return faceCentroids();
370 }
371 
372 const QVector<QgsMeshVertex> &QgsTriangularMesh::faceCentroids() const
373 {
374  return mNativeMeshFaceCentroids;
375 }
376 
377 const QVector<QgsMeshVertex> &QgsTriangularMesh::edgeCentroids() const
378 {
379  return mNativeMeshEdgeCentroids;
380 }
381 
382 const QVector<int> &QgsTriangularMesh::trianglesToNativeFaces() const
383 {
384  return mTrianglesToNativeFaces;
385 }
386 
387 const QVector<int> &QgsTriangularMesh::edgesToNativeEdges() const
388 {
389  return mEdgesToNativeEdges;
390 }
391 
393 {
394  QgsPointXY mapPoint;
395  if ( mCoordinateTransform.isValid() )
396  {
397  try
398  {
399  mapPoint = mCoordinateTransform.transform( point );
400  }
401  catch ( QgsCsException &cse )
402  {
403  Q_UNUSED( cse )
404  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
405  mapPoint = point;
406  }
407  }
408  else
409  mapPoint = point;
410 
411  return point;
412 }
413 
415 {
416  const QList<int> faceIndexes = mSpatialFaceIndex.intersects( QgsRectangle( point, point ) );
417  for ( const int faceIndex : faceIndexes )
418  {
419  const QgsMeshFace &face = mTriangularMesh.faces.at( faceIndex );
420  const QgsGeometry geom = QgsMeshUtils::toGeometry( face, mTriangularMesh.vertices );
421  if ( geom.contains( &point ) )
422  return faceIndex;
423  }
424  return -1;
425 }
426 
428 {
429  int triangleIndex = faceIndexForPoint_v2( point );
430  if ( triangleIndex == -1 )
431  return -1;
432 
433  if ( triangleIndex < mTrianglesToNativeFaces.count() )
434  return mTrianglesToNativeFaces.at( triangleIndex );
435 
436  return -1;
437 }
438 
440 {
441  QSet<int> concernedFaceIndex = QgsMeshUtils::nativeFacesFromTriangles(
442  faceIndexesForRectangle( rectangle ),
444  return concernedFaceIndex.values();
445 }
446 
448 {
449  const QList<int> faceIndexes = mSpatialFaceIndex.intersects( QgsRectangle( point, point ) );
450 
451  for ( const int faceIndex : faceIndexes )
452  {
453  const QgsMeshFace &face = mTriangularMesh.faces.at( faceIndex );
454  if ( QgsMeshUtils::isInTriangleFace( point, face, mTriangularMesh.vertices ) )
455  return faceIndex;
456  }
457  return -1;
458 }
459 
460 QList<int> QgsTriangularMesh::faceIndexesForRectangle( const QgsRectangle &rectangle ) const
461 {
462  return mSpatialFaceIndex.intersects( rectangle );
463 }
464 
465 QList<int> QgsTriangularMesh::edgeIndexesForRectangle( const QgsRectangle &rectangle ) const
466 {
467  return mSpatialEdgeIndex.intersects( rectangle );
468 }
469 
470 QVector<QVector3D> QgsTriangularMesh::vertexNormals( float vertScale ) const
471 {
472  QVector<QVector3D> normales( vertices().count(), QVector3D( 0, 0, 0 ) );
473 
474  for ( const auto &face : triangles() )
475  {
476  if ( face.isEmpty() )
477  continue;
478 
479  for ( int i = 0; i < 3; i++ )
480  {
481  int index1( face.at( i ) );
482  int index2( face.at( ( i + 1 ) % 3 ) );
483  int index3( face.at( ( i + 2 ) % 3 ) );
484 
485  const QgsMeshVertex &vert( vertices().at( index1 ) );
486  const QgsMeshVertex &otherVert1( vertices().at( index2 ) );
487  const QgsMeshVertex &otherVert2( vertices().at( index3 ) );
488 
489  QVector3D v1( float( otherVert1.x() - vert.x() ), float( otherVert1.y() - vert.y() ), vertScale * float( otherVert1.z() - vert.z() ) );
490  QVector3D v2( float( otherVert2.x() - vert.x() ), float( otherVert2.y() - vert.y() ), vertScale * float( otherVert2.z() - vert.z() ) );
491 
492  normales[index1] += QVector3D::crossProduct( v1, v2 );
493  }
494  }
495  return normales;
496 }
497 
498 QVector<QgsTriangularMesh *> QgsTriangularMesh::simplifyMesh( double reductionFactor, int minimumTrianglesCount ) const
499 {
500  QVector<QgsTriangularMesh *> simplifiedMeshes;
501 
502  if ( mTriangularMesh.edgeCount() != 0 )
503  return simplifiedMeshes;
504 
505  if ( !( reductionFactor > 1 ) )
506  return simplifiedMeshes;
507 
508  size_t verticesCount = size_t( mTriangularMesh.vertices.count() );
509 
510  unsigned int baseIndexCount = mTriangularMesh.faceCount() * 3;
511 
512  QVector<unsigned int> indexes( mTriangularMesh.faces.count() * 3 );
513  for ( int i = 0; i < mTriangularMesh.faceCount(); ++i )
514  {
515  const QgsMeshFace &f = mTriangularMesh.face( i );
516  for ( int j = 0; j < 3; ++j )
517  indexes[i * 3 + j] = f.at( j );
518  }
519 
520  QVector<float> vertices( mTriangularMesh.vertices.count() * 3 );
521  for ( int i = 0; i < mTriangularMesh.vertices.count(); ++i )
522  {
523  const QgsMeshVertex &v = mTriangularMesh.vertex( i );
524  vertices[i * 3] = v.x() ;
525  vertices[i * 3 + 1] = v.y() ;
526  vertices[i * 3 + 2] = v.z() ;
527  }
528 
529  int path = 0;
530  while ( true )
531  {
532  QgsTriangularMesh *simplifiedMesh = new QgsTriangularMesh( *this );
533  size_t maxNumberOfIndexes = baseIndexCount / pow( reductionFactor, path + 1 );
534 
535  if ( indexes.size() <= int( maxNumberOfIndexes ) )
536  {
537  delete simplifiedMesh;
538  break;
539  }
540 
541  QVector<unsigned int> returnIndexes( indexes.size() );
542  //returned size could be different than goal size but not than the input indexes count
543  size_t size = meshopt_simplifySloppy(
544  returnIndexes.data(),
545  indexes.data(),
546  indexes.size(),
547  vertices.data(),
548  verticesCount,
549  sizeof( float ) * 3,
550  maxNumberOfIndexes );
551 
552 
553  returnIndexes.resize( size );
554 
555  if ( size == 0 || int( size ) >= indexes.size() )
556  {
557  QgsDebugMsg( QStringLiteral( "Mesh simplification failed after %1 path" ).arg( path + 1 ) );
558  delete simplifiedMesh;
559  break;
560  }
561 
562  QgsMesh newMesh;
563  newMesh.vertices = mTriangularMesh.vertices;
564 
565  newMesh.faces.resize( returnIndexes.size() / 3 );
566  for ( int i = 0; i < newMesh.faces.size(); ++i )
567  {
568  QgsMeshFace f( 3 );
569  for ( size_t j = 0; j < 3 ; ++j )
570  f[j] = returnIndexes.at( i * 3 + j ) ;
571  newMesh.faces[i ] = f;
572  }
573 
574  simplifiedMesh->mTriangularMesh = newMesh;
575  simplifiedMesh->mSpatialFaceIndex = QgsMeshSpatialIndex( simplifiedMesh->mTriangularMesh );
576  simplifiedMesh->finalizeTriangles();
577  simplifiedMeshes.push_back( simplifiedMesh );
578 
579  QgsDebugMsgLevel( QStringLiteral( "Simplified mesh created with %1 triangles" ).arg( newMesh.faceCount() ), 2 );
580 
581  simplifiedMesh->mTrianglesToNativeFaces = QVector<int>( simplifiedMesh->triangles().count(), 0 );
582  for ( int i = 0; i < simplifiedMesh->mTrianglesToNativeFaces.count(); ++i )
583  {
584  QgsMeshFace triangle = simplifiedMesh->triangles().at( i );
585  double x = 0;
586  double y = 0;
587  for ( size_t j = 0; j < 3 ; ++j )
588  {
589  x += mTriangularMesh.vertex( triangle[j] ).x();
590  y += mTriangularMesh.vertex( triangle[j] ).y();
591  }
592  x /= 3;
593  y /= 3;
594  QgsPoint centroid( x, y );
595  int indexInBaseMesh = faceIndexForPoint_v2( centroid );
596 
597  if ( indexInBaseMesh == -1 )
598  {
599  // sometime the centroid of simplified mesh could be outside the base mesh,
600  // so try with vertices of the simplified triangle
601  int j = 0;
602  while ( indexInBaseMesh == -1 && j < 3 )
603  indexInBaseMesh = faceIndexForPoint_v2( mTriangularMesh.vertex( triangle[j++] ) );
604  }
605 
606  if ( indexInBaseMesh > -1 && indexInBaseMesh < mTrianglesToNativeFaces.count() )
607  simplifiedMesh->mTrianglesToNativeFaces[i] = mTrianglesToNativeFaces[indexInBaseMesh];
608  }
609 
610  simplifiedMesh->mLod = path + 1;
611  simplifiedMesh->mBaseTriangularMesh = this;
612 
613  if ( simplifiedMesh->triangles().count() < minimumTrianglesCount )
614  break;
615 
616  indexes = returnIndexes;
617  ++path;
618  }
619 
620  return simplifiedMeshes;
621 }
622 
623 std::unique_ptr< QgsPolygon > QgsMeshUtils::toPolygon( const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices )
624 {
625  QVector<QgsPoint> ring;
626  for ( int j = 0; j < face.size(); ++j )
627  {
628  int vertexId = face[j];
629  Q_ASSERT( vertexId < vertices.size() );
630  const QgsPoint &vertex = vertices[vertexId];
631  ring.append( vertex );
632  }
633  std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
634  polygon->setExteriorRing( new QgsLineString( ring ) );
635  return polygon;
636 }
637 
638 QgsGeometry QgsMeshUtils::toGeometry( const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices )
639 {
640  return QgsGeometry( QgsMeshUtils::toPolygon( face, vertices ) );
641 }
642 
643 static QSet<int> _nativeElementsFromElements( const QList<int> &indexes, const QVector<int> &elementToNativeElements )
644 {
645  QSet<int> nativeElements;
646  for ( const int index : indexes )
647  {
648  if ( index < elementToNativeElements.count() )
649  {
650  const int nativeIndex = elementToNativeElements[index];
651  nativeElements.insert( nativeIndex );
652  }
653  }
654  return nativeElements;
655 }
656 
657 QSet<int> QgsMeshUtils::nativeFacesFromTriangles( const QList<int> &triangleIndexes, const QVector<int> &trianglesToNativeFaces )
658 {
659  return _nativeElementsFromElements( triangleIndexes, trianglesToNativeFaces );
660 }
661 
662 QSet<int> QgsMeshUtils::nativeEdgesFromEdges( const QList<int> &edgesIndexes, const QVector<int> &edgesToNativeEdges )
663 {
664  return _nativeElementsFromElements( edgesIndexes, edgesToNativeEdges );
665 }
666 
667 
668 static double _isLeft2D( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p )
669 {
670  return ( p2.x() - p1.x() ) * ( p.y() - p1.y() ) - ( p.x() - p1.x() ) * ( p2.y() - p1.y() );
671 }
672 
673 static bool _isInTriangle2D( const QgsPoint &p, const QVector<QgsMeshVertex> &triangle )
674 {
675  return ( ( _isLeft2D( triangle[2], triangle[0], p ) * _isLeft2D( triangle[2], triangle[0], triangle[1] ) >= 0 )
676  && ( _isLeft2D( triangle[0], triangle[1], p ) * _isLeft2D( triangle[0], triangle[1], triangle[2] ) >= 0 )
677  && ( _isLeft2D( triangle[2], triangle[1], p ) * _isLeft2D( triangle[2], triangle[1], triangle[0] ) >= 0 ) );
678 }
679 
680 bool QgsMeshUtils::isInTriangleFace( const QgsPointXY point, const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices )
681 {
682  if ( face.count() != 3 )
683  return false;
684 
685  QVector<QgsMeshVertex> triangle( 3 );
686  for ( int i = 0; i < 3; ++i )
687  {
688  if ( face[i] > vertices.count() )
689  return false;
690  triangle[i] = vertices[face[i]];
691  }
692 
693  const QgsPoint p( point.x(), point.y() );
694 
695  return _isInTriangle2D( p, triangle );
696 }
697 
698 QSet<int> QgsMeshUtils::nativeVerticesFromTriangles( const QList<int> &triangleIndexes, const QVector<QgsMeshFace> &triangles )
699 {
700  QSet<int> uniqueVertices;
701  for ( int triangleIndex : triangleIndexes )
702  {
703  const QgsMeshFace triangle = triangles[triangleIndex];
704  for ( int i : triangle )
705  {
706  uniqueVertices.insert( i );
707  }
708  }
709  return uniqueVertices;
710 }
711 
712 QSet<int> QgsMeshUtils::nativeVerticesFromEdges( const QList<int> &edgesIndexes, const QVector<QgsMeshEdge> &edges )
713 {
714  QSet<int> uniqueVertices;
715  for ( int edgeIndex : edgesIndexes )
716  {
717  const QgsMeshEdge edge = edges[edgeIndex];
718  uniqueVertices.insert( edge.first );
719  uniqueVertices.insert( edge.second );
720  }
721  return uniqueVertices;
722 }
723 
725 {
726  //if necessary defined removes triangles index
727  if ( changes.mRemovedTriangleIndexes.isEmpty() && !changes.mNativeFaceIndexesToRemove.isEmpty() )
728  {
729  for ( int nf = 0; nf < changes.mNativeFaceIndexesToRemove.count(); ++nf )
730  {
731  int nativeIndex = changes.mNativeFaceIndexesToRemove.at( nf );
732  const QgsMeshFace &nativeFace = changes.mNativeFacesToRemove.at( nf );
733  Q_ASSERT( !nativeFace.isEmpty() );
734 
735  QgsRectangle nativeFaceExtent( mTriangularMesh.vertex( nativeFace.at( 0 ) ), mTriangularMesh.vertex( nativeFace.at( 0 ) ) );
736  for ( int i = 1; i < nativeFace.count(); ++i )
737  {
738  const QgsMeshVertex &triangularVertex = mTriangularMesh.vertex( nativeFace.at( i ) );
739  nativeFaceExtent.include( triangularVertex );
740  }
741 
742  QList<int> concernedTriangle = faceIndexesForRectangle( nativeFaceExtent );
743  //Remove only those corresponding to the native face
744  for ( int i = 0; i < concernedTriangle.count(); ++i )
745  {
746  int triangleIndex = concernedTriangle.at( i );
747  if ( mTrianglesToNativeFaces.at( triangleIndex ) == nativeIndex )
748  changes.mRemovedTriangleIndexes.append( triangleIndex );
749  }
750  }
751  }
752 
753  if ( changes.mOldZValue.isEmpty() && !changes.mNewZValue.isEmpty() )
754  {
755  changes.mOldZValue.reserve( changes.mNewZValue.count() );
756  for ( int i = 0; i < changes.mNewZValue.count(); ++i )
757  changes.mOldZValue.append( mTriangularMesh.vertices.at( changes.mChangedVerticesCoordinates.at( i ) ).z() );
758  }
759 
760  if ( changes.mTriangleIndexesGeometryChanged.isEmpty() && !changes.mNativeFaceIndexesGeometryChanged.isEmpty() )
761  {
762  for ( int i = 0; i < changes.mNativeFaceIndexesGeometryChanged.count(); ++i )
763  {
764  const QgsMeshFace &nativeFace = changes.mNativeFacesGeometryChanged.at( i );
765  if ( nativeFace.count() < 2 )
766  continue;
767  QgsRectangle bbox( mTriangularMesh.vertices.at( nativeFace.at( 0 ) ), mTriangularMesh.vertices.at( nativeFace.at( 1 ) ) );
768 
769  for ( int i = 2; i < nativeFace.count(); ++i )
770  bbox.include( mTriangularMesh.vertices.at( nativeFace.at( i ) ) );
771 
772  QList<int> triangleIndexes = faceIndexesForRectangle( bbox );
773  int pos = 0;
774  while ( pos < triangleIndexes.count() )
775  {
776  if ( trianglesToNativeFaces().at( triangleIndexes.at( pos ) ) !=
777  changes.mNativeFaceIndexesGeometryChanged.at( i ) )
778  triangleIndexes.removeAt( pos );
779  else
780  ++pos;
781  }
782  changes.mTriangleIndexesGeometryChanged.append( triangleIndexes );
783  }
784  }
785 
786  // add vertices
787  for ( const QgsMeshVertex &vertex : std::as_const( changes.mAddedVertices ) )
788  addVertex( vertex );
789 
790  // add faces
791  if ( !changes.mNativeFacesToAdd.isEmpty() )
792  {
793  changes.mTrianglesAddedStartIndex = mTriangularMesh.faceCount();
794  int firstNewNativeFacesIndex = mNativeMeshFaceCentroids.count();
795  for ( int i = 0; i < changes.mNativeFacesToAdd.count(); ++i )
796  {
797  const QgsMeshFace &nativeFace = changes.mNativeFacesToAdd.at( i );
798  triangulate( nativeFace, firstNewNativeFacesIndex + i );
799  mNativeMeshFaceCentroids.append( calculateCentroid( nativeFace ) );
800  }
801 
802  for ( int i = changes.mTrianglesAddedStartIndex; i < mTriangularMesh.faceCount(); ++i )
803  mSpatialFaceIndex.addFace( i, mTriangularMesh );
804  }
805 
806  // remove faces
807  for ( int i = 0; i < changes.mRemovedTriangleIndexes.count(); ++i )
808  {
809  int triangleIndex = changes.mRemovedTriangleIndexes.at( i );
810  mTrianglesToNativeFaces[triangleIndex] = -1;
811  mSpatialFaceIndex.removeFace( triangleIndex, mTriangularMesh );
812  mTriangularMesh.faces[triangleIndex] = QgsMeshFace();
813  }
814 
815  for ( int i = 0; i < changes.mNativeFaceIndexesToRemove.count(); ++i )
816  mNativeMeshFaceCentroids[changes.mNativeFaceIndexesToRemove.at( i )] = QgsMeshVertex();
817 
818  // remove vertices
819  for ( int i = 0; i < changes.mVerticesIndexesToRemove.count(); ++i )
820  mTriangularMesh.vertices[changes.mVerticesIndexesToRemove.at( i )] = QgsMeshVertex();
821 
822  if ( !changes.mVerticesIndexesToRemove.isEmpty() )
823  mIsExtentValid = false;
824 
825  // change Z value
826  for ( int i = 0; i < changes.mNewZValue.count(); ++i )
827  {
828  int vertexIndex = changes.mChangedVerticesCoordinates.at( i );
829  mTriangularMesh.vertices[vertexIndex].setZ( changes.mNewZValue.at( i ) );
830  }
831 
832  //remove outdated spatial index
833  for ( const int triangleIndex : std::as_const( changes.mTriangleIndexesGeometryChanged ) )
834  mSpatialFaceIndex.removeFace( triangleIndex, mTriangularMesh );
835 
836  // change (X,Y) of vertices
837  for ( int i = 0; i < changes.mNewXYValue.count(); ++i )
838  {
839  const QgsPointXY &nativeCoordinates = changes.mNewXYValue.at( i );
840  const QgsMeshVertex nativeVertex( nativeCoordinates.x(),
841  nativeCoordinates.y(),
842  mTriangularMesh.vertices.at( changes.mChangedVerticesCoordinates.at( i ) ).z() );
843 
844  mTriangularMesh.vertices[changes.mChangedVerticesCoordinates.at( i )] = nativeToTriangularCoordinates( nativeVertex );
845  }
846 
847  //restore spatial undex
848  for ( const int triangleIndex : std::as_const( changes.mTriangleIndexesGeometryChanged ) )
849  mSpatialFaceIndex.addFace( triangleIndex, mTriangularMesh );
850 
851  //update native faces
852  for ( int i = 0; i < changes.mNativeFaceIndexesGeometryChanged.count(); ++i )
853  mNativeMeshFaceCentroids[changes.mNativeFaceIndexesGeometryChanged.at( i )] = calculateCentroid( changes.mNativeFacesGeometryChanged.at( i ) );
854 }
855 
857 {
858  //reverse added faces and added vertices
859  if ( !changes.mNativeFacesToAdd.isEmpty() )
860  {
861  for ( int i = changes.mTrianglesAddedStartIndex; i < mTriangularMesh.faceCount(); ++i )
862  mSpatialFaceIndex.removeFace( i, mTriangularMesh );
863 
864  int initialNativeFacesCount = mNativeMeshFaceCentroids.count() - changes.mNativeFacesToAdd.count();
865 
866  mTriangularMesh.faces.resize( changes.mTrianglesAddedStartIndex );
867  mTrianglesToNativeFaces.resize( changes.mTrianglesAddedStartIndex );
868  mNativeMeshFaceCentroids.resize( initialNativeFacesCount );
869  }
870 
871  int initialVerticesCount = mTriangularMesh.vertices.count() - changes.mAddedVertices.count();
872  mTriangularMesh.vertices.resize( initialVerticesCount );
873 
874  if ( !changes.mAddedVertices.isEmpty() )
875  mIsExtentValid = false;
876 
877  // for each vertex to remove we need to update the vertices with the native vertex
878  for ( const int i : std::as_const( changes.mVerticesIndexesToRemove ) )
879  mTriangularMesh.vertices[i] = nativeToTriangularCoordinates( nativeMesh.vertex( i ) );
880 
881  if ( !changes.mVerticesIndexesToRemove.isEmpty() )
882  mIsExtentValid = false;
883 
884  // reverse removed faces
885  QVector<QgsMeshFace> restoredTriangles;
886  QVector<int> restoredTriangularToNative;
887  for ( int i = 0; i < changes.mNativeFacesToRemove.count(); ++i )
888  {
889  const QgsMeshFace &nativeFace = changes.mNativeFacesToRemove.at( i );
890  triangulateFaces( nativeFace,
891  changes.mNativeFaceIndexesToRemove.at( i ),
892  restoredTriangles,
893  restoredTriangularToNative,
894  mTriangularMesh );
895  mNativeMeshFaceCentroids[changes.mNativeFaceIndexesToRemove.at( i )] = calculateCentroid( nativeFace );
896  }
897  for ( int i = 0; i < changes.mRemovedTriangleIndexes.count(); ++i )
898  {
899  int triangleIndex = changes.mRemovedTriangleIndexes.at( i );
900  mTriangularMesh.faces[triangleIndex] = restoredTriangles.at( i );
901  mSpatialFaceIndex.addFace( triangleIndex, mTriangularMesh );
902  mTrianglesToNativeFaces[triangleIndex] = restoredTriangularToNative.at( i );
903  }
904 
905  // reverse Z value
906  for ( int i = 0; i < changes.mOldZValue.count(); ++i )
907  {
908  int vertexIndex = changes.mChangedVerticesCoordinates.at( i );
909  mTriangularMesh.vertices[vertexIndex].setZ( changes.mOldZValue.at( i ) );
910  }
911 
912  //remove outdated spatial index
913  for ( const int triangleIndex : std::as_const( changes.mTriangleIndexesGeometryChanged ) )
914  mSpatialFaceIndex.removeFace( triangleIndex, mTriangularMesh );
915 
916  // reverse (X,Y) of vertices
917  for ( int i = 0; i < changes.mOldXYValue.count(); ++i )
918  {
919  const QgsPointXY &nativeCoordinates = changes.mOldXYValue.at( i );
920  const QgsMeshVertex nativeVertex( nativeCoordinates.x(),
921  nativeCoordinates.y(),
922  mTriangularMesh.vertices.at( changes.mChangedVerticesCoordinates.at( i ) ).z() );
923 
924  mTriangularMesh.vertices[changes.mChangedVerticesCoordinates.at( i )] = nativeToTriangularCoordinates( nativeVertex );
925  }
926 
927  //restore spatial undex
928  for ( const int triangleIndex : std::as_const( changes.mTriangleIndexesGeometryChanged ) )
929  mSpatialFaceIndex.addFace( triangleIndex, mTriangularMesh );
930 
931  //update native faces
932  for ( int i = 0; i < changes.mNativeFaceIndexesGeometryChanged.count(); ++i )
933  mNativeMeshFaceCentroids[changes.mNativeFaceIndexesGeometryChanged.at( i )] = calculateCentroid( changes.mNativeFacesGeometryChanged.at( i ) );
934 }
935 
937  const QgsMesh &nativeMesh )
938 {
939  mAddedVertices = topologicalChanges.addedVertices();
940  mVerticesIndexesToRemove = topologicalChanges.verticesToRemoveIndexes();
941  mNativeFacesToAdd = topologicalChanges.addedFaces();
942  mNativeFacesToRemove = topologicalChanges.removedFaces();
943  mNativeFaceIndexesToRemove = topologicalChanges.removedFaceIndexes();
944  mChangedVerticesCoordinates = topologicalChanges.changedCoordinatesVerticesIndexes();
945  mNewZValue = topologicalChanges.newVerticesZValues();
946  mNewXYValue = topologicalChanges.newVerticesXYValues();
947  mOldXYValue = topologicalChanges.oldVerticesXYValues();
948 
949  mNativeFaceIndexesGeometryChanged = topologicalChanges.nativeFacesIndexesGeometryChanged();
950  mNativeFacesGeometryChanged.resize( mNativeFaceIndexesGeometryChanged.count() );
951  for ( int i = 0; i < mNativeFaceIndexesGeometryChanged.count(); ++i )
952  mNativeFacesGeometryChanged[i] = nativeMesh.face( mNativeFaceIndexesGeometryChanged.at( i ) );
953 }
954 
955 QgsMeshVertex QgsMeshUtils::centroid( const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices )
956 {
957  QVector<QPointF> points( face.size() );
958  for ( int j = 0; j < face.size(); ++j )
959  {
960  int index = face.at( j );
961  const QgsMeshVertex &vertex = vertices.at( index ); // we need vertices in map coordinate
962  points[j] = vertex.toQPointF();
963  }
964  QPolygonF poly( points );
965  double cx, cy;
966  ENP_centroid( poly, cx, cy );
967  return QgsMeshVertex( cx, cy );
968 }
969 
971 {
972  //To have consistent clock wise orientation of triangles which is necessary for 3D rendering
973  //Check the clock wise, and if it is not counter clock wise, swap indexes to make the oientation counter clock wise
974  double ux = v1.x() - v0.x();
975  double uy = v1.y() - v0.y();
976  double vx = v2.x() - v0.x();
977  double vy = v2.y() - v0.y();
978 
979  double crossProduct = ux * vy - uy * vx;
980  if ( crossProduct < 0 ) //CW -->change the orientation
981  {
982  std::swap( triangle[1], triangle[2] );
983  }
984 }
qgsmeshlayerutils.h
qgspolygon.h
QgsTopologicalMesh::Changes::changedCoordinatesVerticesIndexes
QList< int > changedCoordinatesVerticesIndexes() const
Returns the indexes of vertices that have changed coordinates.
Definition: qgstopologicalmesh.cpp:1019
QgsTopologicalMesh::Changes::addedVertices
QVector< QgsMeshVertex > addedVertices() const
Returns the added vertices with this changes.
Definition: qgstopologicalmesh.cpp:1014
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
QgsTriangularMesh::nativeFaceIndexForPoint
int nativeFaceIndexForPoint(const QgsPointXY &point) const
Finds index of native face at given point It uses spatial indexing.
Definition: qgstriangularmesh.cpp:427
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsRectangle::include
void include(const QgsPointXY &p)
Updates the rectangle to include the specified point.
Definition: qgsrectangle.h:307
QgsTriangularMesh::vertices
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
Definition: qgstriangularmesh.cpp:352
qgslinestring.h
qgsrectangle.h
QgsTopologicalMesh::Changes
Class that contains topological differences between two states of a topological mesh,...
Definition: qgstopologicalmesh.h:96
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsTopologicalMesh::Changes::nativeFacesIndexesGeometryChanged
QList< int > nativeFacesIndexesGeometryChanged() const
Returns a list of the native face indexes that have a geometry changed.
Definition: qgstopologicalmesh.cpp:1039
QgsMeshUtils::nativeVerticesFromEdges
CORE_EXPORT QSet< int > nativeVerticesFromEdges(const QList< int > &edgesIndexes, const QVector< QgsMeshEdge > &edges)
Returns unique native faces indexes from list of vertices of triangles.
Definition: qgstriangularmesh.cpp:712
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
qgsmeshspatialindex.h
QgsTriangularMesh::faceIndexForPoint
int faceIndexForPoint(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing.
Definition: qgstriangularmesh.cpp:414
QgsMeshVertex
QgsPoint QgsMeshVertex
xyz coords of vertex
Definition: qgsmeshdataprovider.h:36
QgsMeshUtils::centroid
CORE_EXPORT QgsMeshVertex centroid(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns the centroid of the face.
Definition: qgstriangularmesh.cpp:955
QgsTriangularMesh::faceCentroids
const QVector< QgsMeshVertex > & faceCentroids() const
Returns centroids of the native faces in map CRS.
Definition: qgstriangularmesh.cpp:372
QgsTriangularMesh::averageTriangleSize
double averageTriangleSize() const
Returns the average size of triangles in map unit.
Definition: qgstriangularmesh.cpp:149
QgsMeshUtils::nativeVerticesFromTriangles
CORE_EXPORT QSet< int > nativeVerticesFromTriangles(const QList< int > &triangleIndexes, const QVector< QgsMeshFace > &triangles)
Returns unique native vertex indexes from list of vertices of triangles.
Definition: qgstriangularmesh.cpp:698
QgsTopologicalMesh::Changes::oldVerticesXYValues
QList< QgsPointXY > oldVerticesXYValues() const
Returns the old (X,Y) values of vertices that have changed their coordinates.
Definition: qgstopologicalmesh.cpp:1034
QgsTriangularMesh::applyChanges
void applyChanges(const Changes &changes)
Applies the changes on the triangular mesh (see Changes)
Definition: qgstriangularmesh.cpp:724
QgsCoordinateTransform::transformBoundingBox
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:560
QgsTriangularMesh::extent
QgsRectangle extent() const
Returns the extent of the triangular mesh in map coordinates.
Definition: qgstriangularmesh.cpp:310
QgsPoint::z
double z
Definition: qgspoint.h:71
QgsRectangle::setMinimal
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
Definition: qgsrectangle.h:172
QgsTriangularMesh::update
bool update(QgsMesh *nativeMesh, const QgsCoordinateTransform &transform=QgsCoordinateTransform())
Constructs triangular mesh from layer's native mesh and transform to destination CRS.
Definition: qgstriangularmesh.cpp:157
QgsTriangularMesh::triangles
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
Definition: qgstriangularmesh.cpp:357
QgsMesh
Mesh - vertices, edges and faces.
Definition: qgsmeshdataprovider.h:58
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsMeshUtils::setCounterClockwise
void setCounterClockwise(QgsMeshFace &triangle, const QgsMeshVertex &v0, const QgsMeshVertex &v1, const QgsMeshVertex &v2)
Checks if the triangle is counter clockwise, if not sets it counter clockwise.
Definition: qgstriangularmesh.cpp:970
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsMesh::edges
QVector< QgsMeshEdge > edges
Definition: qgsmeshdataprovider.h:113
QgsCoordinateTransform::isValid
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Definition: qgscoordinatetransform.cpp:900
QgsTriangularMesh::edgeIndexesForRectangle
QList< int > edgeIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of edges intersecting given bounding box It uses spatial indexing.
Definition: qgstriangularmesh.cpp:465
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsMeshUtils::isInTriangleFace
bool isInTriangleFace(const QgsPointXY point, const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Tests if point p is on the face defined with vertices.
Definition: qgstriangularmesh.cpp:680
QgsTriangularMesh::edgeCentroids
const QVector< QgsMeshVertex > & edgeCentroids() const
Returns centroids of the native edges in map CRS.
Definition: qgstriangularmesh.cpp:377
QgsTriangularMesh::levelOfDetail
int levelOfDetail() const
Returns the corresponding index of level of detail on which this mesh is associated.
Definition: qgstriangularmesh.cpp:324
QgsMeshUtils::nativeEdgesFromEdges
CORE_EXPORT QSet< int > nativeEdgesFromEdges(const QList< int > &edgesIndexes, const QVector< int > &edgesToNativeEdges)
Returns unique native faces indexes from list of triangle indexes.
Definition: qgstriangularmesh.cpp:662
QgsCoordinateTransform::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
Definition: qgscoordinatetransform.cpp:267
QgsMeshUtils::nativeFacesFromTriangles
CORE_EXPORT QSet< int > nativeFacesFromTriangles(const QList< int > &triangleIndexes, const QVector< int > &trianglesToNativeFaces)
Returns unique native faces indexes from list of triangle indexes.
Definition: qgstriangularmesh.cpp:657
qgstriangularmesh.h
QgsPoint::y
double y
Definition: qgspoint.h:70
QgsCoordinateTransform::sourceCrs
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source coordinate reference system, which the transform will transform coordinates from.
Definition: qgscoordinatetransform.cpp:262
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsTriangularMesh::nativeExtent
QgsRectangle nativeExtent()
Returns the extent of the mesh in the native mesh coordinates system, returns empty extent if the tra...
Definition: qgstriangularmesh.cpp:287
QgsMesh::faceCount
int faceCount() const
Returns number of faces.
Definition: qgsmeshdataprovider.cpp:205
QgsCoordinateTransform::isShortCircuited
bool isShortCircuited() const
Returns true if the transform short circuits because the source and destination are equivalent.
Definition: qgscoordinatetransform.cpp:905
QgsMesh::vertexCount
int vertexCount() const
Returns number of vertices.
Definition: qgsmeshdataprovider.cpp:200
QgsMesh::ElementType
ElementType
Defines type of mesh elements.
Definition: qgsmeshdataprovider.h:65
QgsCoordinateTransform::setBallparkTransformsAreAppropriate
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
Definition: qgscoordinatetransform.cpp:939
QgsMesh::faces
QVector< QgsMeshFace > faces
Definition: qgsmeshdataprovider.h:114
QgsPoint::transform
void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) override SIP_THROW(QgsCsException)
Transforms the geometry using a coordinate transform.
Definition: qgspoint.cpp:382
QgsPoint::toQPointF
QPointF toQPointF() const SIP_HOLDGIL
Returns the point as a QPointF.
Definition: qgspoint.h:348
QgsTriangularMesh::nativeFaceIndexForRectangle
QList< int > nativeFaceIndexForRectangle(const QgsRectangle &rectangle) const
Finds indexes of native faces which bounding boxes intersect given bounding box It uses spatial index...
Definition: qgstriangularmesh.cpp:439
QgsMesh::edgeCount
int edgeCount() const
Returns number of edge.
Definition: qgsmeshdataprovider.cpp:210
QgsMeshUtils::toPolygon
CORE_EXPORT std::unique_ptr< QgsPolygon > toPolygon(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns face as polygon geometry, caller is responsible for delete.
Definition: qgstriangularmesh.cpp:623
QgsTriangularMesh::contains
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains mesh elements of given type.
Definition: qgstriangularmesh.cpp:329
QgsTriangularMesh::edges
const QVector< QgsMeshEdge > & edges() const
Returns edges.
Definition: qgstriangularmesh.cpp:362
QgsException::what
QString what() const
Definition: qgsexception.h:48
qgsrendercontext.h
QgsMeshSpatialIndex::intersects
QList< int > intersects(const QgsRectangle &rectangle) const
Returns a list of face ids with a bounding box which intersects the specified rectangle.
Definition: qgsmeshspatialindex.cpp:370
QgsTriangularMesh::~QgsTriangularMesh
~QgsTriangularMesh()
Dtor.
QgsMesh::face
QgsMeshFace face(int index) const
Returns a face at the index.
Definition: qgsmeshdataprovider.cpp:145
qgscoordinatetransform.h
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
QgsTriangularMesh::simplifyMesh
QVector< QgsTriangularMesh * > simplifyMesh(double reductionFactor, int minimumTrianglesCount=10) const
Returns simplified meshes.
Definition: qgstriangularmesh.cpp:498
QgsMeshFace
QVector< int > QgsMeshFace
List of vertex indexes.
Definition: qgsmeshdataprovider.h:42
QgsTopologicalMesh::Changes::removedFaceIndexes
QList< int > removedFaceIndexes() const
Returns the indexes of the faces that are removed with this changes.
Definition: qgstopologicalmesh.cpp:1009
QgsTriangularMesh::Changes::Changes
Changes()=default
Default constructor, no changes.
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsMeshSpatialIndex
A spatial index for QgsMeshFace or QgsMeshEdge objects.
Definition: qgsmeshspatialindex.h:49
QgsTriangularMesh::faceIndexesForRectangle
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
Definition: qgstriangularmesh.cpp:460
qgsgeometry.h
QgsMeshEdge
QPair< int, int > QgsMeshEdge
Edge is a straight line seqment between 2 points.
Definition: qgsmeshdataprovider.h:49
QgsMeshSpatialIndex::removeFace
void removeFace(int faceIndex, const QgsMesh &mesh)
Removes a face with faceIndex from the mesh in the spatial index.
Definition: qgsmeshspatialindex.cpp:434
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsTriangularMesh::trianglesToNativeFaces
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
Definition: qgstriangularmesh.cpp:382
QgsPointXY::x
double x
Definition: qgspointxy.h:62
QgsTriangularMesh::QgsTriangularMesh
QgsTriangularMesh()
Ctor.
QgsMesh::vertices
QVector< QgsMeshVertex > vertices
Definition: qgsmeshdataprovider.h:112
QgsTopologicalMesh::Changes::verticesToRemoveIndexes
QList< int > verticesToRemoveIndexes() const
Returns the indexes of vertices to remove.
Definition: qgstopologicalmesh.cpp:1066
QgsTriangularMesh::triangularToNativeCoordinates
QgsMeshVertex triangularToNativeCoordinates(const QgsMeshVertex &vertex) const
Transforms the vertex from triangular mesh coordinates system to native coordinates system.
Definition: qgstriangularmesh.cpp:282
QgsTriangularMesh::vertexNormals
QVector< QVector3D > vertexNormals(float vertScale) const
Calculates and returns normale vector on each vertex that is part of any face.
Definition: qgstriangularmesh.cpp:470
QgsTriangularMesh::Changes
The Changes class is used to make changes of the triangular and to keep traces of this changes If a C...
Definition: qgstriangularmesh.h:251
QgsPoint::isEmpty
bool isEmpty() const override SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgspoint.cpp:767
QgsTriangularMesh::transformFromLayerToTrianglesCoordinates
QgsPointXY transformFromLayerToTrianglesCoordinates(const QgsPointXY &point) const
Transforms a point from layer coordinates system to triangular Mesh coordinates system.
Definition: qgstriangularmesh.cpp:392
QgsTriangularMesh
Triangular/Derived Mesh is mesh with vertices in map coordinates.
Definition: qgstriangularmesh.h:51
QgsGeometry::contains
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
Definition: qgsgeometry.cpp:1303
Qgis::TransformDirection
TransformDirection
Indicates the direction (forward or inverse) of a transform.
Definition: qgis.h:1235
QgsMeshUtils::toGeometry
CORE_EXPORT QgsGeometry toGeometry(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns face as polygon geometry.
Definition: qgstriangularmesh.cpp:638
qgslogger.h
QgsTriangularMesh::edgesToNativeEdges
const QVector< int > & edgesToNativeEdges() const
Returns mapping between edges and original edges.
Definition: qgstriangularmesh.cpp:387
QgsCoordinateTransform::transform
QgsPointXY transform(const QgsPointXY &point, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:272
QgsTriangularMesh::centroids
const Q_DECL_DEPRECATED QVector< QgsMeshVertex > & centroids() const
Returns centroids of the native faces in map CRS.
Definition: qgstriangularmesh.cpp:367
QgsTopologicalMesh::Changes::addedFaces
QVector< QgsMeshFace > addedFaces() const
Returns the face that are added with this changes.
Definition: qgstopologicalmesh.cpp:999
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsMesh::vertex
QgsMeshVertex vertex(int index) const
Returns a vertex at the index.
Definition: qgsmeshdataprovider.cpp:138
QgsTriangularMesh::reverseChanges
void reverseChanges(const Changes &changes, const QgsMesh &nativeMesh)
Reverses the changes on the triangular mesh (see Changes)
Definition: qgstriangularmesh.cpp:856
QgsMeshSpatialIndex::addFace
void addFace(int faceIndex, const QgsMesh &mesh)
Adds a face with faceIndex from the mesh in the spatial index.
Definition: qgsmeshspatialindex.cpp:402
QgsTopologicalMesh::Changes::removedFaces
QVector< QgsMeshFace > removedFaces() const
Returns the faces that are removed with this changes.
Definition: qgstopologicalmesh.cpp:1004
QgsPoint::x
double x
Definition: qgspoint.h:69
QgsTriangularMesh::nativeToTriangularCoordinates
QgsMeshVertex nativeToTriangularCoordinates(const QgsMeshVertex &vertex) const
Transforms the vertex from native coordinates system to triangular mesh coordinates system.
Definition: qgstriangularmesh.cpp:277
QgsTopologicalMesh::Changes::newVerticesZValues
QList< double > newVerticesZValues() const
Returns the new Z values of vertices that have changed their coordinates.
Definition: qgstopologicalmesh.cpp:1024
QgsTopologicalMesh::Changes::newVerticesXYValues
QList< QgsPointXY > newVerticesXYValues() const
Returns the new (X,Y) values of vertices that have changed their coordinates.
Definition: qgstopologicalmesh.cpp:1029