support also mesh elements with >4 vertices

This commit is contained in:
Peter Petrik 2019-01-22 09:22:55 +01:00
parent 928a559aa9
commit af2501e73d
4 changed files with 143 additions and 25 deletions

View File

@ -108,6 +108,26 @@ static void ENP_centroid( const QPolygonF &pX, double &cx, double &cy )
cy /= ( 6.0 * signedArea ); cy /= ( 6.0 * signedArea );
} }
void QgsTriangularMesh::triangulate( const QgsMeshFace &face, int nativeIndex )
{
int vertexCount = face.size();
if ( vertexCount < 3 )
return;
while ( vertexCount > 3 )
{
// clip one ear from last 2 and first vertex
const QgsMeshFace ear = { face[vertexCount - 2], face[vertexCount - 1], face[0] };
mTriangularMesh.faces.push_back( ear );
mTrianglesToNativeFaces.push_back( nativeIndex );
--vertexCount;
}
const QgsMeshFace triangle = { face[1], face[2], face[0] };
mTriangularMesh.faces.push_back( triangle );
mTrianglesToNativeFaces.push_back( nativeIndex );
}
void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context ) void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
{ {
Q_ASSERT( nativeMesh ); Q_ASSERT( nativeMesh );
@ -159,31 +179,7 @@ void QgsTriangularMesh::update( QgsMesh *nativeMesh, QgsRenderContext *context )
for ( int i = 0; i < nativeMesh->faces.size(); ++i ) for ( int i = 0; i < nativeMesh->faces.size(); ++i )
{ {
const QgsMeshFace &face = nativeMesh->faces.at( i ) ; const QgsMeshFace &face = nativeMesh->faces.at( i ) ;
if ( face.size() == 3 ) triangulate( face, i );
{
// triangle
mTriangularMesh.faces.push_back( face );
mTrianglesToNativeFaces.push_back( i );
}
else if ( face.size() == 4 )
{
// quad
QgsMeshFace face1;
face1.push_back( face[0] );
face1.push_back( face[1] );
face1.push_back( face[2] );
mTriangularMesh.faces.push_back( face1 );
mTrianglesToNativeFaces.push_back( i );
QgsMeshFace face2;
face2.push_back( face[0] );
face2.push_back( face[2] );
face2.push_back( face[3] );
mTriangularMesh.faces.push_back( face2 );
mTrianglesToNativeFaces.push_back( i );
}
} }
// CALCULATE CENTROIDS // CALCULATE CENTROIDS

View File

@ -129,6 +129,19 @@ class CORE_EXPORT QgsTriangularMesh
QList<int> faceIndexesForRectangle( const QgsRectangle &rectangle ) const ; QList<int> faceIndexesForRectangle( const QgsRectangle &rectangle ) const ;
private: private:
/**
* Triangulates native face to triangles
*
* Triangulation does not create any new vertices and uses
* "Ear clipping method". Number of vertices in face is usually
* less than 10 and the faces are usually convex and without holes
*
* Skips the input face if it is not possible to triangulate
* with the given algorithm (e.g. only 2 vertices, polygon with holes)
*/
void triangulate( const QgsMeshFace &face, int nativeIndex );
// vertices: map CRS; 0-N ... native vertices, N+1 - len ... extra vertices // vertices: map CRS; 0-N ... native vertices, N+1 - len ... extra vertices
// faces are derived triangles // faces are derived triangles
QgsMesh mTriangularMesh; QgsMesh mTriangularMesh;
@ -139,6 +152,8 @@ class CORE_EXPORT QgsTriangularMesh
QgsSpatialIndex mSpatialIndex; QgsSpatialIndex mSpatialIndex;
QgsCoordinateTransform mCoordinateTransform; //coordinate transform used to convert native mesh vertices to map vertices QgsCoordinateTransform mCoordinateTransform; //coordinate transform used to convert native mesh vertices to map vertices
friend class TestQgsTriangularMesh;
}; };
namespace QgsMeshUtils namespace QgsMeshUtils

View File

@ -200,6 +200,7 @@ SET(TESTS
testqgssymbol.cpp testqgssymbol.cpp
testqgstaskmanager.cpp testqgstaskmanager.cpp
testqgstracer.cpp testqgstracer.cpp
testqgstriangularmesh.cpp
testqgsfontutils.cpp testqgsfontutils.cpp
testqgsvector.cpp testqgsvector.cpp
testqgsvectordataprovider.cpp testqgsvectordataprovider.cpp

View File

@ -0,0 +1,106 @@
/***************************************************************************
testqgstriangularmesh.cpp
-------------------------
begin : January 2019
copyright : (C) 2019 by Peter Petrik
email : zilolv at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgstest.h"
#include <QObject>
#include <QString>
//qgis includes...
#include "qgstriangularmesh.h"
#include "qgsapplication.h"
#include "qgsproject.h"
/**
* \ingroup UnitTests
* This is a unit test for a triangular mesh
*/
class TestQgsTriangularMesh : public QObject
{
Q_OBJECT
public:
TestQgsTriangularMesh() = default;
private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.
void init() {} // will be called before each testfunction is executed.
void cleanup() {} // will be called after every testfunction.
void test_triangulate();
};
void TestQgsTriangularMesh::initTestCase()
{
// init QGIS's paths - true means that all path will be inited from prefix
QgsApplication::init();
QgsApplication::initQgis();
QgsApplication::showSettings();
}
void TestQgsTriangularMesh::cleanupTestCase()
{
QgsApplication::exitQgis();
}
void TestQgsTriangularMesh::test_triangulate()
{
{
QgsTriangularMesh mesh;
QgsMeshFace point = { 1 };
mesh.triangulate( point, 0 );
QCOMPARE( 0, mesh.mTriangularMesh.faces.size() );
}
{
QgsTriangularMesh mesh;
QgsMeshFace line = { 1, 2 };
mesh.triangulate( line, 0 );
QCOMPARE( 0, mesh.mTriangularMesh.faces.size() );
}
{
QgsTriangularMesh mesh;
QgsMeshFace triangle = { 1, 2, 3 };
mesh.triangulate( triangle, 0 );
QCOMPARE( 1, mesh.mTriangularMesh.faces.size() );
QgsMeshFace firstTriangle = {2, 3, 1};
QCOMPARE( firstTriangle, mesh.mTriangularMesh.faces[0] );
}
{
QgsTriangularMesh mesh;
QgsMeshFace quad = { 1, 2, 3, 4 };
mesh.triangulate( quad, 0 );
QCOMPARE( 2, mesh.mTriangularMesh.faces.size() );
QgsMeshFace firstTriangle = {3, 4, 1};
QCOMPARE( firstTriangle, mesh.mTriangularMesh.faces[0] );
QgsMeshFace secondTriangle = {2, 3, 1};
QCOMPARE( secondTriangle, mesh.mTriangularMesh.faces[1] );
}
{
QgsTriangularMesh mesh;
QgsMeshFace poly = { 1, 2, 3, 4, 5, 6, 7 };
mesh.triangulate( poly, 0 );
QCOMPARE( 5, mesh.mTriangularMesh.faces.size() );
}
}
QGSTEST_MAIN( TestQgsTriangularMesh )
#include "testqgstriangularmesh.moc"