QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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  // For all vertices except last
62  int i = 0;
63  for ( ; i < pX.size() - 1; ++i )
64  {
65  ENP_centroid_step( pX, cx, cy, signedArea, i, i + 1 );
66  }
67  // Do last vertex separately to avoid performing an expensive
68  // modulus operation in each iteration.
69  ENP_centroid_step( pX, cx, cy, signedArea, i, 0 );
70 
71  signedArea *= 0.5;
72  cx /= ( 6.0 * signedArea );
73  cy /= ( 6.0 * signedArea );
74 }
75 
76 void QgsTriangularMesh::triangulate( const QgsMeshFace &face, int nativeIndex )
77 {
78  int vertexCount = face.size();
79  if ( vertexCount < 3 )
80  return;
81 
82  while ( vertexCount > 3 )
83  {
84  // clip one ear from last 2 and first vertex
85  const QgsMeshFace ear = { face[vertexCount - 2], face[vertexCount - 1], face[0] };
86  if ( !( std::isnan( mTriangularMesh.vertex( ear[0] ).x() ) ||
87  std::isnan( mTriangularMesh.vertex( ear[1] ).x() ) ||
88  std::isnan( mTriangularMesh.vertex( ear[2] ).x() ) ) )
89  {
90  mTriangularMesh.faces.push_back( ear );
91  mTrianglesToNativeFaces.push_back( nativeIndex );
92  }
93  --vertexCount;
94  }
95 
96  const QgsMeshFace triangle = { face[1], face[2], face[0] };
97  if ( !( std::isnan( mTriangularMesh.vertex( triangle[0] ).x() ) ||
98  std::isnan( mTriangularMesh.vertex( triangle[1] ).x() ) ||
99  std::isnan( mTriangularMesh.vertex( triangle[2] ).x() ) ) )
100  {
101  mTriangularMesh.faces.push_back( triangle );
102  mTrianglesToNativeFaces.push_back( nativeIndex );
103  }
104 }
105 
107 {
108  return mAverageTriangleSize;
109 }
110 
113 
114 bool QgsTriangularMesh::update( QgsMesh *nativeMesh, const QgsCoordinateTransform &transform )
115 {
116  Q_ASSERT( nativeMesh );
117 
118  // FIND OUT IF UPDATE IS NEEDED
119  if ( mTriangularMesh.vertices.size() >= nativeMesh->vertices.size() &&
120  mTriangularMesh.faces.size() >= nativeMesh->faces.size() &&
121  mTriangularMesh.edges.size() == nativeMesh->edges.size() &&
122  ( ( !mCoordinateTransform.isValid() && !transform.isValid() ) ||
123  ( mCoordinateTransform.sourceCrs() == transform.sourceCrs() &&
124  mCoordinateTransform.destinationCrs() == transform.destinationCrs() &&
125  mCoordinateTransform.isValid() == transform.isValid() ) ) )
126  return false;
127 
128  // CLEAN-UP
129  mTriangularMesh.vertices.clear();
130  mTriangularMesh.faces.clear();
131  mTriangularMesh.edges.clear();
132  mTrianglesToNativeFaces.clear();
133  mEdgesToNativeEdges.clear();
134  mNativeMeshFaceCentroids.clear();
135  mNativeMeshEdgeCentroids.clear();
136 
137  // TRANSFORM VERTICES
138  mCoordinateTransform = transform;
139  mTriangularMesh.vertices.resize( nativeMesh->vertices.size() );
140  mExtent.setMinimal();
141  for ( int i = 0; i < nativeMesh->vertices.size(); ++i )
142  {
143  const QgsMeshVertex &vertex = nativeMesh->vertices.at( i );
144  if ( mCoordinateTransform.isValid() )
145  {
146  try
147  {
148  QgsPointXY mapPoint = mCoordinateTransform.transform( QgsPointXY( vertex.x(), vertex.y() ) );
149  QgsMeshVertex mapVertex( mapPoint );
150  mapVertex.addZValue( vertex.z() );
151  mapVertex.setM( vertex.m() );
152  mTriangularMesh.vertices[i] = mapVertex;
153  mExtent.include( mapPoint );
154  }
155  catch ( QgsCsException &cse )
156  {
157  Q_UNUSED( cse )
158  QgsDebugMsg( QStringLiteral( "Caught CRS exception %1" ).arg( cse.what() ) );
159  mTriangularMesh.vertices[i] = QgsMeshVertex();
160  }
161  }
162  else
163  {
164  mTriangularMesh.vertices[i] = vertex;
165  mExtent.include( vertex );
166  }
167  }
168 
169  // CREATE TRIANGULAR MESH
170  for ( int i = 0; i < nativeMesh->faces.size(); ++i )
171  {
172  const QgsMeshFace &face = nativeMesh->faces.at( i ) ;
173  triangulate( face, i );
174  }
175 
176  // CALCULATE CENTROIDS
177  mNativeMeshFaceCentroids.resize( nativeMesh->faces.size() );
178  for ( int i = 0; i < nativeMesh->faces.size(); ++i )
179  {
180  const QgsMeshFace &face = nativeMesh->faces.at( i ) ;
181  QVector<QPointF> points;
182  points.reserve( face.size() );
183  for ( int j = 0; j < face.size(); ++j )
184  {
185  int index = face.at( j );
186  const QgsMeshVertex &vertex = mTriangularMesh.vertices[index]; // we need projected vertices
187  points.push_back( vertex.toQPointF() );
188  }
189  QPolygonF poly( points );
190  double cx, cy;
191  ENP_centroid( poly, cx, cy );
192  mNativeMeshFaceCentroids[i] = QgsMeshVertex( cx, cy );
193  }
194 
195  // CALCULATE SPATIAL INDEX
196  mSpatialFaceIndex = QgsMeshSpatialIndex( mTriangularMesh, nullptr, QgsMesh::ElementType::Face );
197 
198  // SET ALL TRIANGLE CCW AND COMPUTE AVERAGE SIZE
199  finalizeTriangles();
200 
201  // CREATE EDGES
202  // remove all edges with invalid vertices
203  const QVector<QgsMeshEdge> edges = nativeMesh->edges;
204  for ( int nativeIndex = 0; nativeIndex < edges.size(); ++nativeIndex )
205  {
206  const QgsMeshEdge &edge = edges.at( nativeIndex );
207  if ( !( std::isnan( mTriangularMesh.vertex( edge.first ).x() ) ||
208  std::isnan( mTriangularMesh.vertex( edge.second ).x() ) ) )
209  {
210  mTriangularMesh.edges.push_back( edge );
211  mEdgesToNativeEdges.push_back( nativeIndex );
212  }
213  }
214 
215  // CALCULATE CENTROIDS
216  mNativeMeshEdgeCentroids.resize( nativeMesh->edgeCount() );
217  for ( int i = 0; i < nativeMesh->edgeCount(); ++i )
218  {
219  const QgsMeshEdge &edge = nativeMesh->edges.at( i ) ;
220  const QgsPoint &a = mTriangularMesh.vertices[edge.first];
221  const QgsPoint &b = mTriangularMesh.vertices[edge.second];
222  mNativeMeshEdgeCentroids[i] = QgsMeshVertex( ( a.x() + b.x() ) / 2.0, ( a.y() + b.y() ) / 2.0, ( a.z() + b.z() ) / 2.0 );
223  }
224 
225  // CALCULATE SPATIAL INDEX
226  mSpatialEdgeIndex = QgsMeshSpatialIndex( mTriangularMesh, nullptr, QgsMesh::ElementType::Edge );
227 
228  return true;
229 }
230 
231 void QgsTriangularMesh::finalizeTriangles()
232 {
233  mAverageTriangleSize = 0;
234  for ( int i = 0; i < mTriangularMesh.faceCount(); ++i )
235  {
236  QgsMeshFace &face = mTriangularMesh.faces[i];
237 
238  const QgsMeshVertex &v0 = mTriangularMesh.vertex( face[0] );
239  const QgsMeshVertex &v1 = mTriangularMesh.vertex( face[1] );
240  const QgsMeshVertex &v2 = mTriangularMesh.vertex( face[2] );
241 
242  QgsRectangle bbox = QgsMeshLayerUtils::triangleBoundingBox( v0, v1, v2 );
243 
244  mAverageTriangleSize += std::fmax( bbox.width(), bbox.height() );
245 
246  //To have consistent clock wise orientation of triangles which is necessary for 3D rendering
247  //Check the clock wise, and if it is not counter clock wise, swap indexes to make the oientation counter clock wise
248  double ux = v1.x() - v0.x();
249  double uy = v1.y() - v0.y();
250  double vx = v2.x() - v0.x();
251  double vy = v2.y() - v0.y();
252 
253  double crossProduct = ux * vy - uy * vx;
254  if ( crossProduct < 0 ) //CW -->change the orientation
255  {
256  std::swap( face[1], face[2] );
257  }
258  }
259  mAverageTriangleSize /= mTriangularMesh.faceCount();
260 }
261 
263 {
264  return mExtent;
265 }
266 
268 {
269  return mLod;
270 }
271 
273 {
274  switch ( type )
275  {
276  case QgsMesh::ElementType::Vertex:
277  return mTriangularMesh.vertexCount() != 0;
278  case QgsMesh::ElementType::Edge:
279  return mTriangularMesh.edgeCount() != 0;
281  return mTriangularMesh.faceCount() != 0;
282  }
283 
284  return false;
285 }
286 
287 const QVector<QgsMeshVertex> &QgsTriangularMesh::vertices() const
288 {
289  return mTriangularMesh.vertices;
290 }
291 
292 const QVector<QgsMeshFace> &QgsTriangularMesh::triangles() const
293 {
294  return mTriangularMesh.faces;
295 }
296 
297 const QVector<QgsMeshEdge> &QgsTriangularMesh::edges() const
298 {
299  return mTriangularMesh.edges;
300 }
301 
302 const QVector<QgsMeshVertex> &QgsTriangularMesh::centroids() const
303 {
304  return faceCentroids();
305 }
306 
307 const QVector<QgsMeshVertex> &QgsTriangularMesh::faceCentroids() const
308 {
309  return mNativeMeshFaceCentroids;
310 }
311 
312 const QVector<QgsMeshVertex> &QgsTriangularMesh::edgeCentroids() const
313 {
314  return mNativeMeshEdgeCentroids;
315 }
316 
317 const QVector<int> &QgsTriangularMesh::trianglesToNativeFaces() const
318 {
319  return mTrianglesToNativeFaces;
320 }
321 
322 const QVector<int> &QgsTriangularMesh::edgesToNativeEdges() const
323 {
324  return mEdgesToNativeEdges;
325 }
326 
328 {
329  const QList<int> faceIndexes = mSpatialFaceIndex.intersects( QgsRectangle( point, point ) );
330  for ( const int faceIndex : faceIndexes )
331  {
332  const QgsMeshFace &face = mTriangularMesh.faces.at( faceIndex );
333  const QgsGeometry geom = QgsMeshUtils::toGeometry( face, mTriangularMesh.vertices );
334  if ( geom.contains( &point ) )
335  return faceIndex;
336  }
337  return -1;
338 }
339 
341 {
342  const QList<int> faceIndexes = mSpatialFaceIndex.intersects( QgsRectangle( point, point ) );
343 
344  for ( const int faceIndex : faceIndexes )
345  {
346  const QgsMeshFace &face = mTriangularMesh.faces.at( faceIndex );
347  if ( QgsMeshUtils::isInTriangleFace( point, face, mTriangularMesh.vertices ) )
348  return faceIndex;
349  }
350  return -1;
351 }
352 
353 QList<int> QgsTriangularMesh::faceIndexesForRectangle( const QgsRectangle &rectangle ) const
354 {
355  return mSpatialFaceIndex.intersects( rectangle );
356 }
357 
358 QList<int> QgsTriangularMesh::edgeIndexesForRectangle( const QgsRectangle &rectangle ) const
359 {
360  return mSpatialEdgeIndex.intersects( rectangle );
361 }
362 
363 QVector<QVector3D> QgsTriangularMesh::vertexNormals( float vertScale ) const
364 {
365  QVector<QVector3D> normales( vertices().count(), QVector3D( 0, 0, 0 ) );
366 
367  for ( const auto &face : triangles() )
368  {
369  for ( int i = 0; i < 3; i++ )
370  {
371  int index1( face.at( i ) );
372  int index2( face.at( ( i + 1 ) % 3 ) );
373  int index3( face.at( ( i + 2 ) % 3 ) );
374 
375  const QgsMeshVertex &vert( vertices().at( index1 ) );
376  const QgsMeshVertex &otherVert1( vertices().at( index2 ) );
377  const QgsMeshVertex &otherVert2( vertices().at( index3 ) );
378 
379  QVector3D v1( float( otherVert1.x() - vert.x() ), float( otherVert1.y() - vert.y() ), vertScale * float( otherVert1.z() - vert.z() ) );
380  QVector3D v2( float( otherVert2.x() - vert.x() ), float( otherVert2.y() - vert.y() ), vertScale * float( otherVert2.z() - vert.z() ) );
381 
382  normales[index1] += QVector3D::crossProduct( v1, v2 );
383  }
384  }
385  return normales;
386 }
387 
388 QVector<QgsTriangularMesh *> QgsTriangularMesh::simplifyMesh( double reductionFactor, int minimumTrianglesCount ) const
389 {
390  QVector<QgsTriangularMesh *> simplifiedMeshes;
391 
392  if ( mTriangularMesh.edgeCount() != 0 )
393  return simplifiedMeshes;
394 
395  if ( !( reductionFactor > 1 ) )
396  return simplifiedMeshes;
397 
398  size_t verticesCount = size_t( mTriangularMesh.vertices.count() );
399 
400  unsigned int baseIndexCount = mTriangularMesh.faceCount() * 3;
401 
402  QVector<unsigned int> indexes( mTriangularMesh.faces.count() * 3 );
403  for ( int i = 0; i < mTriangularMesh.faceCount(); ++i )
404  {
405  const QgsMeshFace &f = mTriangularMesh.face( i );
406  for ( int j = 0; j < 3; ++j )
407  indexes[i * 3 + j] = f.at( j );
408  }
409 
410  QVector<float> vertices( mTriangularMesh.vertices.count() * 3 );
411  for ( int i = 0; i < mTriangularMesh.vertices.count(); ++i )
412  {
413  const QgsMeshVertex &v = mTriangularMesh.vertex( i );
414  vertices[i * 3] = v.x() ;
415  vertices[i * 3 + 1] = v.y() ;
416  vertices[i * 3 + 2] = v.z() ;
417  }
418 
419  int path = 0;
420  while ( true )
421  {
422  QgsTriangularMesh *simplifiedMesh = new QgsTriangularMesh( *this );
423  size_t maxNumberOfIndexes = baseIndexCount / pow( reductionFactor, path + 1 );
424 
425  if ( indexes.size() <= int( maxNumberOfIndexes ) )
426  break;
427 
428  QVector<unsigned int> returnIndexes( indexes.size() );
429  //returned size could be different than goal size but not than the input indexes count
430  size_t size = meshopt_simplifySloppy(
431  returnIndexes.data(),
432  indexes.data(),
433  indexes.size(),
434  vertices.data(),
435  verticesCount,
436  sizeof( float ) * 3,
437  maxNumberOfIndexes );
438 
439 
440  returnIndexes.resize( size );
441 
442  if ( size == 0 || int( size ) >= indexes.size() )
443  {
444  QgsDebugMsg( QStringLiteral( "Mesh simplification failed after %1 path" ).arg( path + 1 ) );
445  break;
446  }
447 
448  QgsMesh newMesh;
449  newMesh.vertices = mTriangularMesh.vertices;
450 
451  newMesh.faces.resize( returnIndexes.size() / 3 );
452  for ( int i = 0; i < newMesh.faces.size(); ++i )
453  {
454  QgsMeshFace f( 3 );
455  for ( size_t j = 0; j < 3 ; ++j )
456  f[j] = returnIndexes.at( i * 3 + j ) ;
457  newMesh.faces[i ] = f;
458  }
459 
460  simplifiedMesh->mTriangularMesh = newMesh;
461  simplifiedMesh->mSpatialFaceIndex = QgsMeshSpatialIndex( simplifiedMesh->mTriangularMesh );
462  simplifiedMesh->finalizeTriangles();
463  simplifiedMeshes.push_back( simplifiedMesh );
464 
465  QgsDebugMsg( QStringLiteral( "Simplified mesh created with %1 triangles" ).arg( newMesh.faceCount() ) );
466 
467  simplifiedMesh->mTrianglesToNativeFaces = QVector<int>( simplifiedMesh->triangles().count(), 0 );
468  for ( int i = 0; i < simplifiedMesh->mTrianglesToNativeFaces.count(); ++i )
469  {
470  QgsMeshFace triangle = simplifiedMesh->triangles().at( i );
471  double x = 0;
472  double y = 0;
473  for ( size_t j = 0; j < 3 ; ++j )
474  {
475  x += mTriangularMesh.vertex( triangle[j] ).x();
476  y += mTriangularMesh.vertex( triangle[j] ).y();
477  }
478  x /= 3;
479  y /= 3;
480  QgsPoint centroid( x, y );
481  int indexInBaseMesh = faceIndexForPoint_v2( centroid );
482 
483  if ( indexInBaseMesh == -1 )
484  {
485  // sometime the centroid of simplified mesh could be outside the base mesh,
486  // so try with vertices of the simplified triangle
487  int j = 0;
488  while ( indexInBaseMesh == -1 && j < 3 )
489  indexInBaseMesh = faceIndexForPoint_v2( mTriangularMesh.vertex( triangle[j++] ) );
490  }
491 
492  if ( indexInBaseMesh > -1 && indexInBaseMesh < mTrianglesToNativeFaces.count() )
493  simplifiedMesh->mTrianglesToNativeFaces[i] = mTrianglesToNativeFaces[indexInBaseMesh];
494  }
495 
496  simplifiedMesh->mLod = path + 1;
497  simplifiedMesh->mBaseTriangularMesh = this;
498 
499  if ( simplifiedMesh->triangles().count() < minimumTrianglesCount )
500  break;
501 
502  indexes = returnIndexes;
503  ++path;
504  }
505 
506  return simplifiedMeshes;
507 }
508 
509 std::unique_ptr< QgsPolygon > QgsMeshUtils::toPolygon( const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices )
510 {
511  QVector<QgsPoint> ring;
512  for ( int j = 0; j < face.size(); ++j )
513  {
514  int vertexId = face[j];
515  Q_ASSERT( vertexId < vertices.size() );
516  const QgsPoint &vertex = vertices[vertexId];
517  ring.append( vertex );
518  }
519  std::unique_ptr< QgsPolygon > polygon = qgis::make_unique< QgsPolygon >();
520  polygon->setExteriorRing( new QgsLineString( ring ) );
521  return polygon;
522 }
523 
524 QgsGeometry QgsMeshUtils::toGeometry( const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices )
525 {
526  return QgsGeometry( QgsMeshUtils::toPolygon( face, vertices ) );
527 }
528 
529 static QSet<int> _nativeElementsFromElements( const QList<int> &indexes, const QVector<int> &elementToNativeElements )
530 {
531  QSet<int> nativeElements;
532  for ( const int index : indexes )
533  {
534  const int nativeIndex = elementToNativeElements[index];
535  nativeElements.insert( nativeIndex );
536  }
537  return nativeElements;
538 }
539 
540 QSet<int> QgsMeshUtils::nativeFacesFromTriangles( const QList<int> &triangleIndexes, const QVector<int> &trianglesToNativeFaces )
541 {
542  return _nativeElementsFromElements( triangleIndexes, trianglesToNativeFaces );
543 }
544 
545 QSet<int> QgsMeshUtils::nativeEdgesFromEdges( const QList<int> &edgesIndexes, const QVector<int> &edgesToNativeEdges )
546 {
547  return _nativeElementsFromElements( edgesIndexes, edgesToNativeEdges );
548 }
549 
550 
551 static double _isLeft2D( const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &p )
552 {
553  return ( p2.x() - p1.x() ) * ( p.y() - p1.y() ) - ( p.x() - p1.x() ) * ( p2.y() - p1.y() );
554 }
555 
556 static bool _isInTriangle2D( const QgsPoint &p, const QVector<QgsMeshVertex> &triangle )
557 {
558  return ( ( _isLeft2D( triangle[2], triangle[0], p ) * _isLeft2D( triangle[2], triangle[0], triangle[1] ) >= 0 )
559  && ( _isLeft2D( triangle[0], triangle[1], p ) * _isLeft2D( triangle[0], triangle[1], triangle[2] ) >= 0 )
560  && ( _isLeft2D( triangle[2], triangle[1], p ) * _isLeft2D( triangle[2], triangle[1], triangle[0] ) >= 0 ) );
561 }
562 
563 bool QgsMeshUtils::isInTriangleFace( const QgsPointXY point, const QgsMeshFace &face, const QVector<QgsMeshVertex> &vertices )
564 {
565  if ( face.count() != 3 )
566  return false;
567 
568  QVector<QgsMeshVertex> triangle( 3 );
569  for ( int i = 0; i < 3; ++i )
570  {
571  if ( face[i] > vertices.count() )
572  return false;
573  triangle[i] = vertices[face[i]];
574  }
575 
576  const QgsPoint p( point.x(), point.y() );
577 
578  return _isInTriangle2D( p, triangle );
579 }
580 
581 QSet<int> QgsMeshUtils::nativeVerticesFromTriangles( const QList<int> &triangleIndexes, const QVector<QgsMeshFace> &triangles )
582 {
583  QSet<int> uniqueVertices;
584  for ( int triangleIndex : triangleIndexes )
585  {
586  const QgsMeshFace triangle = triangles[triangleIndex];
587  for ( int i : triangle )
588  {
589  uniqueVertices.insert( i );
590  }
591  }
592  return uniqueVertices;
593 }
594 
595 QSet<int> QgsMeshUtils::nativeVerticesFromEdges( const QList<int> &edgesIndexes, const QVector<QgsMeshEdge> &edges )
596 {
597  QSet<int> uniqueVertices;
598  for ( int edgeIndex : edgesIndexes )
599  {
600  const QgsMeshEdge edge = edges[edgeIndex];
601  uniqueVertices.insert( edge.first );
602  uniqueVertices.insert( edge.second );
603  }
604  return uniqueVertices;
605 }
qgsmeshlayerutils.h
qgspolygon.h
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
QgsPointXY::y
double y
Definition: qgspointxy.h:48
QgsRectangle::include
void include(const QgsPointXY &p)
Updates the rectangle to include the specified point.
Definition: qgsrectangle.h:286
Face
struct Face_t Face
QgsTriangularMesh::vertices
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
Definition: qgstriangularmesh.cpp:287
qgslinestring.h
qgsrectangle.h
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:38
QgsPoint::setM
void setM(double m) SIP_HOLDGIL
Sets the point's m-value.
Definition: qgspoint.h:308
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:595
qgsmeshspatialindex.h
QgsTriangularMesh::faceIndexForPoint
int faceIndexForPoint(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing.
Definition: qgstriangularmesh.cpp:327
QgsMeshVertex
QgsPoint QgsMeshVertex
xyz coords of vertex
Definition: qgsmeshdataprovider.h:35
QgsPoint::addZValue
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
Definition: qgspoint.cpp:541
QgsTriangularMesh::faceCentroids
const QVector< QgsMeshVertex > & faceCentroids() const
Returns centroids of the native faces in map CRS.
Definition: qgstriangularmesh.cpp:307
QgsPointXY::x
Q_GADGET double x
Definition: qgspointxy.h:47
QgsTriangularMesh::averageTriangleSize
double averageTriangleSize() const
Returns the average size of triangles in map unit.
Definition: qgstriangularmesh.cpp:106
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:581
QgsTriangularMesh::extent
QgsRectangle extent() const
Returns the extent of the triangular mesh in map coordinates.
Definition: qgstriangularmesh.cpp:262
QgsPoint::z
double z
Definition: qgspoint.h:43
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:151
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:114
QgsTriangularMesh::triangles
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
Definition: qgstriangularmesh.cpp:292
QgsMesh
Mesh - vertices, edges and faces.
Definition: qgsmeshdataprovider.h:58
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
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:112
QgsCoordinateTransform::transform
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const SIP_THROW(QgsCsException)
Transform the point from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:239
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:892
QgsTriangularMesh::edgeIndexesForRectangle
QList< int > edgeIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of edges intersecting given bounding box It uses spatial indexing.
Definition: qgstriangularmesh.cpp:358
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:42
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:563
QgsTriangularMesh::edgeCentroids
const QVector< QgsMeshVertex > & edgeCentroids() const
Returns centroids of the native edges in map CRS.
Definition: qgstriangularmesh.cpp:312
QgsTriangularMesh::levelOfDetail
int levelOfDetail() const
Returns the corresponding index of level of detail on which this mesh is associated.
Definition: qgstriangularmesh.cpp:267
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:545
QgsCoordinateTransform::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
Definition: qgscoordinatetransform.cpp:234
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:540
qgstriangularmesh.h
QgsPoint::y
double y
Definition: qgspoint.h:42
QgsCoordinateTransform::sourceCrs
QgsCoordinateReferenceSystem sourceCrs() const
Returns the source coordinate reference system, which the transform will transform coordinates from.
Definition: qgscoordinatetransform.cpp:229
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
QgsMesh::faceCount
int faceCount() const
Returns number of faces.
Definition: qgsmeshdataprovider.cpp:174
QgsMesh::vertexCount
int vertexCount() const
Returns number of vertices.
Definition: qgsmeshdataprovider.cpp:169
QgsMesh::ElementType
ElementType
Defines type of mesh elements.
Definition: qgsmeshdataprovider.h:65
QgsMesh::faces
QVector< QgsMeshFace > faces
Definition: qgsmeshdataprovider.h:113
QgsPoint::toQPointF
QPointF toQPointF() const SIP_HOLDGIL
Returns the point as a QPointF.
Definition: qgspoint.h:320
QgsMesh::edgeCount
int edgeCount() const
Returns number of edge.
Definition: qgsmeshdataprovider.cpp:179
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:509
QgsTriangularMesh::contains
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains at mesh elements of given type.
Definition: qgstriangularmesh.cpp:272
QgsTriangularMesh::edges
const QVector< QgsMeshEdge > & edges() const
Returns edges.
Definition: qgstriangularmesh.cpp:297
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:353
QgsTriangularMesh::~QgsTriangularMesh
~QgsTriangularMesh()
Dtor.
QgsMesh::face
QgsMeshFace face(int index) const
Returns a face at the index.
Definition: qgsmeshdataprovider.cpp:114
QgsPoint::x
Q_GADGET double x
Definition: qgspoint.h:41
QgsPoint::m
double m
Definition: qgspoint.h:44
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:340
QgsTriangularMesh::simplifyMesh
QVector< QgsTriangularMesh * > simplifyMesh(double reductionFactor, int minimumTrianglesCount=10) const
Returns simplified meshes.
Definition: qgstriangularmesh.cpp:388
QgsMeshFace
QVector< int > QgsMeshFace
List of vertex indexes.
Definition: qgsmeshdataprovider.h:41
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:44
QgsMeshSpatialIndex
A spatial index for QgsMeshFace or QgsMeshEdge objects.
Definition: qgsmeshspatialindex.h:50
QgsTriangularMesh::faceIndexesForRectangle
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
Definition: qgstriangularmesh.cpp:353
qgsgeometry.h
QgsMeshEdge
QPair< int, int > QgsMeshEdge
Edge is a straight line seqment between 2 points.
Definition: qgsmeshdataprovider.h:48
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:202
QgsTriangularMesh::trianglesToNativeFaces
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
Definition: qgstriangularmesh.cpp:317
QgsTriangularMesh::QgsTriangularMesh
QgsTriangularMesh()
Ctor.
QgsMesh::vertices
QVector< QgsMeshVertex > vertices
Definition: qgsmeshdataprovider.h:111
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:363
QgsTriangularMesh
Triangular/Derived Mesh is mesh with vertices in map coordinates.
Definition: qgstriangularmesh.h:50
QgsGeometry::contains
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
Definition: qgsgeometry.cpp:1184
QgsMeshUtils::toGeometry
CORE_EXPORT QgsGeometry toGeometry(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns face as polygon geometry.
Definition: qgstriangularmesh.cpp:524
qgslogger.h
QgsTriangularMesh::edgesToNativeEdges
const QVector< int > & edgesToNativeEdges() const
Returns mapping between edges and original edges.
Definition: qgstriangularmesh.cpp:322
QgsTriangularMesh::centroids
Q_DECL_DEPRECATED const QVector< QgsMeshVertex > & centroids() const
Returns centroids of the native faces in map CRS.
Definition: qgstriangularmesh.cpp:302
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:53
QgsMesh::vertex
QgsMeshVertex vertex(int index) const
Returns a vertex at the index.
Definition: qgsmeshdataprovider.cpp:107