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 : }
|