30 #include "meshOptimizer/meshoptimizer.h"
32 static void ENP_centroid_step(
const QPolygonF &pX,
double &cx,
double &cy,
double &signedArea,
int i,
int i1 )
44 a = x0 * y1 - x1 * y0;
46 cx += ( x0 + x1 ) * a;
47 cy += ( y0 + y1 ) * a;
50 static void ENP_centroid(
const QPolygonF &pX,
double &cx,
double &cy )
59 double signedArea = 0.0;
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;
68 for ( ; i < localPolygon.size() - 1; ++i )
70 ENP_centroid_step( localPolygon, cx, cy, signedArea, i, i + 1 );
74 ENP_centroid_step( localPolygon, cx, cy, signedArea, i, 0 );
77 cx /= ( 6.0 * signedArea );
78 cy /= ( 6.0 * signedArea );
84 void QgsTriangularMesh::triangulate(
const QgsMeshFace &face,
int nativeIndex )
86 int vertexCount = face.size();
87 if ( vertexCount < 3 )
90 while ( vertexCount > 3 )
93 const QgsMeshFace ear = { face[vertexCount - 2], face[vertexCount - 1], face[0] };
94 if ( !( std::isnan( mTriangularMesh.
vertex( ear[0] ).
x() ) ||
95 std::isnan( mTriangularMesh.
vertex( ear[1] ).
x() ) ||
96 std::isnan( mTriangularMesh.
vertex( ear[2] ).
x() ) ) )
98 mTriangularMesh.
faces.push_back( ear );
99 mTrianglesToNativeFaces.push_back( nativeIndex );
104 const QgsMeshFace triangle = { face[1], face[2], face[0] };
105 if ( !( std::isnan( mTriangularMesh.
vertex( triangle[0] ).
x() ) ||
106 std::isnan( mTriangularMesh.
vertex( triangle[1] ).
x() ) ||
107 std::isnan( mTriangularMesh.
vertex( triangle[2] ).
x() ) ) )
109 mTriangularMesh.
faces.push_back( triangle );
110 mTrianglesToNativeFaces.push_back( nativeIndex );
116 return mAverageTriangleSize;
124 Q_ASSERT( nativeMesh );
128 mTriangularMesh.
faces.size() >= nativeMesh->
faces.size() &&
129 mTriangularMesh.
edges.size() == nativeMesh->
edges.size() &&
138 mTriangularMesh.
faces.clear();
139 mTriangularMesh.
edges.clear();
140 mTrianglesToNativeFaces.clear();
141 mEdgesToNativeEdges.clear();
142 mNativeMeshFaceCentroids.clear();
143 mNativeMeshEdgeCentroids.clear();
146 mCoordinateTransform = transform;
149 for (
int i = 0; i < nativeMesh->
vertices.size(); ++i )
152 if ( mCoordinateTransform.
isValid() )
159 mapVertex.
setM( vertex.
m() );
160 mTriangularMesh.
vertices[i] = mapVertex;
166 QgsDebugMsg( QStringLiteral(
"Caught CRS exception %1" ).arg( cse.
what() ) );
172 mTriangularMesh.
vertices[i] = vertex;
178 for (
int i = 0; i < nativeMesh->
faces.size(); ++i )
181 triangulate( face, i );
185 mNativeMeshFaceCentroids.resize( nativeMesh->
faces.size() );
186 for (
int i = 0; i < nativeMesh->
faces.size(); ++i )
189 QVector<QPointF> points;
190 points.reserve( face.size() );
191 for (
int j = 0; j < face.size(); ++j )
193 int index = face.at( j );
197 QPolygonF poly( points );
199 ENP_centroid( poly, cx, cy );
204 mSpatialFaceIndex =
QgsMeshSpatialIndex( mTriangularMesh,
nullptr, QgsMesh::ElementType::Face );
211 const QVector<QgsMeshEdge>
edges = nativeMesh->
edges;
212 for (
int nativeIndex = 0; nativeIndex <
edges.size(); ++nativeIndex )
215 if ( !( std::isnan( mTriangularMesh.
vertex( edge.first ).
x() ) ||
216 std::isnan( mTriangularMesh.
vertex( edge.second ).
x() ) ) )
218 mTriangularMesh.
edges.push_back( edge );
219 mEdgesToNativeEdges.push_back( nativeIndex );
224 mNativeMeshEdgeCentroids.resize( nativeMesh->
edgeCount() );
225 for (
int i = 0; i < nativeMesh->
edgeCount(); ++i )
230 mNativeMeshEdgeCentroids[i] =
QgsMeshVertex( ( a.
x() + b.
x() ) / 2.0, ( a.
y() + b.
y() ) / 2.0, ( a.
z() + b.
z() ) / 2.0 );
234 mSpatialEdgeIndex =
QgsMeshSpatialIndex( mTriangularMesh,
nullptr, QgsMesh::ElementType::Edge );
239 void QgsTriangularMesh::finalizeTriangles()
241 mAverageTriangleSize = 0;
242 for (
int i = 0; i < mTriangularMesh.
faceCount(); ++i )
250 QgsRectangle bbox = QgsMeshLayerUtils::triangleBoundingBox( v0, v1, v2 );
252 mAverageTriangleSize += std::fmax( bbox.
width(), bbox.
height() );
256 double ux = v1.
x() - v0.
x();
257 double uy = v1.
y() - v0.
y();
258 double vx = v2.
x() - v0.
x();
259 double vy = v2.
y() - v0.
y();
261 double crossProduct = ux * vy - uy * vx;
262 if ( crossProduct < 0 )
264 std::swap( face[1], face[2] );
267 mAverageTriangleSize /= mTriangularMesh.
faceCount();
284 case QgsMesh::ElementType::Vertex:
286 case QgsMesh::ElementType::Edge:
288 case QgsMesh::ElementType::Face:
302 return mTriangularMesh.
faces;
307 return mTriangularMesh.
edges;
317 return mNativeMeshFaceCentroids;
322 return mNativeMeshEdgeCentroids;
327 return mTrianglesToNativeFaces;
332 return mEdgesToNativeEdges;
338 for (
const int faceIndex : faceIndexes )
352 for (
const int faceIndex : faceIndexes )
363 return mSpatialFaceIndex.
intersects( rectangle );
368 return mSpatialEdgeIndex.
intersects( rectangle );
373 QVector<QVector3D> normales(
vertices().count(), QVector3D( 0, 0, 0 ) );
377 for (
int i = 0; i < 3; i++ )
379 int index1( face.at( i ) );
380 int index2( face.at( ( i + 1 ) % 3 ) );
381 int index3( face.at( ( i + 2 ) % 3 ) );
387 QVector3D v1(
float( otherVert1.
x() - vert.
x() ),
float( otherVert1.
y() - vert.
y() ), vertScale *
float( otherVert1.
z() - vert.
z() ) );
388 QVector3D v2(
float( otherVert2.
x() - vert.
x() ),
float( otherVert2.
y() - vert.
y() ), vertScale *
float( otherVert2.
z() - vert.
z() ) );
390 normales[index1] += QVector3D::crossProduct( v1, v2 );
398 QVector<QgsTriangularMesh *> simplifiedMeshes;
401 return simplifiedMeshes;
403 if ( !( reductionFactor > 1 ) )
404 return simplifiedMeshes;
406 size_t verticesCount = size_t( mTriangularMesh.
vertices.count() );
408 unsigned int baseIndexCount = mTriangularMesh.
faceCount() * 3;
410 QVector<unsigned int> indexes( mTriangularMesh.
faces.count() * 3 );
411 for (
int i = 0; i < mTriangularMesh.
faceCount(); ++i )
414 for (
int j = 0; j < 3; ++j )
415 indexes[i * 3 + j] = f.at( j );
419 for (
int i = 0; i < mTriangularMesh.
vertices.count(); ++i )
431 size_t maxNumberOfIndexes = baseIndexCount / pow( reductionFactor, path + 1 );
433 if ( indexes.size() <=
int( maxNumberOfIndexes ) )
436 QVector<unsigned int> returnIndexes( indexes.size() );
438 size_t size = meshopt_simplifySloppy(
439 returnIndexes.data(),
445 maxNumberOfIndexes );
448 returnIndexes.resize( size );
450 if ( size == 0 ||
int( size ) >= indexes.size() )
452 QgsDebugMsg( QStringLiteral(
"Mesh simplification failed after %1 path" ).arg( path + 1 ) );
459 newMesh.
faces.resize( returnIndexes.size() / 3 );
460 for (
int i = 0; i < newMesh.
faces.size(); ++i )
463 for (
size_t j = 0; j < 3 ; ++j )
464 f[j] = returnIndexes.at( i * 3 + j ) ;
465 newMesh.
faces[i ] = f;
468 simplifiedMesh->mTriangularMesh = newMesh;
469 simplifiedMesh->mSpatialFaceIndex =
QgsMeshSpatialIndex( simplifiedMesh->mTriangularMesh );
470 simplifiedMesh->finalizeTriangles();
471 simplifiedMeshes.push_back( simplifiedMesh );
473 QgsDebugMsg( QStringLiteral(
"Simplified mesh created with %1 triangles" ).arg( newMesh.
faceCount() ) );
475 simplifiedMesh->mTrianglesToNativeFaces = QVector<int>( simplifiedMesh->
triangles().count(), 0 );
476 for (
int i = 0; i < simplifiedMesh->mTrianglesToNativeFaces.count(); ++i )
481 for (
size_t j = 0; j < 3 ; ++j )
483 x += mTriangularMesh.
vertex( triangle[j] ).
x();
484 y += mTriangularMesh.
vertex( triangle[j] ).
y();
491 if ( indexInBaseMesh == -1 )
496 while ( indexInBaseMesh == -1 && j < 3 )
500 if ( indexInBaseMesh > -1 && indexInBaseMesh < mTrianglesToNativeFaces.count() )
501 simplifiedMesh->mTrianglesToNativeFaces[i] = mTrianglesToNativeFaces[indexInBaseMesh];
504 simplifiedMesh->mLod = path + 1;
505 simplifiedMesh->mBaseTriangularMesh =
this;
507 if ( simplifiedMesh->
triangles().count() < minimumTrianglesCount )
510 indexes = returnIndexes;
514 return simplifiedMeshes;
519 QVector<QgsPoint> ring;
520 for (
int j = 0; j < face.size(); ++j )
522 int vertexId = face[j];
523 Q_ASSERT( vertexId < vertices.size() );
524 const QgsPoint &vertex = vertices[vertexId];
525 ring.append( vertex );
527 std::unique_ptr< QgsPolygon > polygon = std::make_unique< QgsPolygon >();
537 static QSet<int> _nativeElementsFromElements(
const QList<int> &indexes,
const QVector<int> &elementToNativeElements )
539 QSet<int> nativeElements;
540 for (
const int index : indexes )
542 const int nativeIndex = elementToNativeElements[index];
543 nativeElements.insert( nativeIndex );
545 return nativeElements;
550 return _nativeElementsFromElements( triangleIndexes, trianglesToNativeFaces );
555 return _nativeElementsFromElements( edgesIndexes, edgesToNativeEdges );
561 return ( p2.
x() - p1.
x() ) * ( p.
y() - p1.
y() ) - ( p.
x() - p1.
x() ) * ( p2.
y() - p1.
y() );
564 static bool _isInTriangle2D(
const QgsPoint &p,
const QVector<QgsMeshVertex> &triangle )
566 return ( ( _isLeft2D( triangle[2], triangle[0], p ) * _isLeft2D( triangle[2], triangle[0], triangle[1] ) >= 0 )
567 && ( _isLeft2D( triangle[0], triangle[1], p ) * _isLeft2D( triangle[0], triangle[1], triangle[2] ) >= 0 )
568 && ( _isLeft2D( triangle[2], triangle[1], p ) * _isLeft2D( triangle[2], triangle[1], triangle[0] ) >= 0 ) );
573 if ( face.count() != 3 )
576 QVector<QgsMeshVertex> triangle( 3 );
577 for (
int i = 0; i < 3; ++i )
579 if ( face[i] > vertices.count() )
581 triangle[i] = vertices[face[i]];
586 return _isInTriangle2D( p, triangle );
591 QSet<int> uniqueVertices;
592 for (
int triangleIndex : triangleIndexes )
594 const QgsMeshFace triangle = triangles[triangleIndex];
595 for (
int i : triangle )
597 uniqueVertices.insert( i );
600 return uniqueVertices;
605 QSet<int> uniqueVertices;
606 for (
int edgeIndex : edgesIndexes )
609 uniqueVertices.insert( edge.first );
610 uniqueVertices.insert( edge.second );
612 return uniqueVertices;
Custom exception class for Coordinate Reference System related exceptions.
A geometry is the spatial representation of a feature.
bool contains(const QgsPointXY *p) const
Returns true if the geometry contains the point p.
Line string geometry type, with support for z-dimension and m-values.
A spatial index for QgsMeshFace or QgsMeshEdge objects.
QList< int > intersects(const QgsRectangle &rectangle) const
Returns a list of face ids with a bounding box which intersects the specified rectangle.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
QPointF toQPointF() const SIP_HOLDGIL
Returns the point as a QPointF.
bool addZValue(double zValue=0) override
Adds a z-dimension to the geometry, initialized to a preset value.
void setM(double m) SIP_HOLDGIL
Sets the point's m-value.
A rectangle specified with double values.
void include(const QgsPointXY &p)
Updates the rectangle to include the specified point.
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
void setMinimal() SIP_HOLDGIL
Set a rectangle so that min corner is at max and max corner is at min.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Triangular/Derived Mesh is mesh with vertices in map coordinates.
bool update(QgsMesh *nativeMesh, const QgsCoordinateTransform &transform=QgsCoordinateTransform())
Constructs triangular mesh from layer's native mesh and transform to destination CRS.
const QVector< QgsMeshVertex > & edgeCentroids() const
Returns centroids of the native edges in map CRS.
const QVector< QgsMeshFace > & triangles() const
Returns triangles.
QVector< QgsTriangularMesh * > simplifyMesh(double reductionFactor, int minimumTrianglesCount=10) const
Returns simplified meshes.
int levelOfDetail() const
Returns the corresponding index of level of detail on which this mesh is associated.
QgsRectangle extent() const
Returns the extent of the triangular mesh in map coordinates.
int faceIndexForPoint(const QgsPointXY &point) const
Finds index of triangle at given point It uses spatial indexing.
double averageTriangleSize() const
Returns the average size of triangles in map unit.
QList< int > edgeIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of edges intersecting given bounding box It uses spatial indexing.
Q_DECL_DEPRECATED const QVector< QgsMeshVertex > & centroids() const
Returns centroids of the native faces in map CRS.
const QVector< QgsMeshVertex > & vertices() const
Returns vertices in map coordinate system.
const QVector< QgsMeshEdge > & edges() const
Returns edges.
bool contains(const QgsMesh::ElementType &type) const
Returns whether the mesh contains at mesh elements of given type.
QVector< QVector3D > vertexNormals(float vertScale) const
Calculates and returns normale vector on each vertex that is part of any face.
~QgsTriangularMesh()
Dtor.
const QVector< QgsMeshVertex > & faceCentroids() const
Returns centroids of the native faces in map CRS.
const QVector< int > & trianglesToNativeFaces() const
Returns mapping between triangles and original faces.
const QVector< int > & edgesToNativeEdges() const
Returns mapping between edges and original edges.
QList< int > faceIndexesForRectangle(const QgsRectangle &rectangle) const
Finds indexes of triangles intersecting given bounding box It uses spatial indexing.
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.
bool isInTriangleFace(const QgsPointXY point, const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Tests if point p is on the face defined with vertices.
CORE_EXPORT QSet< int > nativeEdgesFromEdges(const QList< int > &edgesIndexes, const QVector< int > &edgesToNativeEdges)
Returns unique native faces indexes from list of triangle indexes.
CORE_EXPORT std::unique_ptr< QgsPolygon > toPolygon(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns face as polygon geometry, caller is responsible for delete.
CORE_EXPORT QgsGeometry toGeometry(const QgsMeshFace &face, const QVector< QgsMeshVertex > &vertices)
Returns face as polygon geometry.
CORE_EXPORT QSet< int > nativeVerticesFromEdges(const QList< int > &edgesIndexes, const QVector< QgsMeshEdge > &edges)
Returns unique native faces indexes from list of vertices of triangles.
CORE_EXPORT QSet< int > nativeVerticesFromTriangles(const QList< int > &triangleIndexes, const QVector< QgsMeshFace > &triangles)
Returns unique native vertex indexes from list of vertices of triangles.
CORE_EXPORT QSet< int > nativeFacesFromTriangles(const QList< int > &triangleIndexes, const QVector< int > &trianglesToNativeFaces)
Returns unique native faces indexes from list of triangle indexes.
QVector< int > QgsMeshFace
List of vertex indexes.
QPair< int, int > QgsMeshEdge
Edge is a straight line seqment between 2 points.
QgsPoint QgsMeshVertex
xyz coords of vertex
Mesh - vertices, edges and faces.
int vertexCount() const
Returns number of vertices.
QVector< QgsMeshVertex > vertices
QgsMeshFace face(int index) const
Returns a face at the index.
QVector< QgsMeshFace > faces
int faceCount() const
Returns number of faces.
ElementType
Defines type of mesh elements.
QgsMeshVertex vertex(int index) const
Returns a vertex at the index.
int edgeCount() const
Returns number of edge.
QVector< QgsMeshEdge > edges