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 );
 
  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:
 
  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 = qgis::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