LCOV - code coverage report
Current view: top level - core/mesh - qgstriangularmesh.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 367 0.0 %
Date: 2021-03-26 12:19:53 Functions: 0 0 -
Branches: 0 0 -

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

Generated by: LCOV version 1.14