Skip to content

Commit

Permalink
Fix crash in tessellation (polygon 3D symbol) for touching rings
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Oct 1, 2017
1 parent 8dc70b4 commit 0951ff7
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
37 changes: 37 additions & 0 deletions src/3d/qgstessellator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "qgstessellator.h"

#include "qgscurve.h"
#include "qgsgeometry.h"
#include "qgspoint.h"
#include "qgspolygon.h"

Expand Down Expand Up @@ -111,6 +112,42 @@ static void _makeWalls( const QgsCurve &ring, bool ccw, float extrusionHeight, Q

void QgsTessellator::addPolygon( const QgsPolygonV2 &polygon, float extrusionHeight )
{
// At this point we assume that input polygons are valid according to the OGC definition.
// This means e.g. no duplicate points, polygons are simple (no butterfly shaped polygon with self-intersection),
// internal rings are inside exterior rings, rings do not cross each other, no dangles.

// There is however an issue with polygons where rings touch:
// +---+
// | |
// | +-+-+
// | | | |
// | +-+ |
// | |
// +-----+
// This is a valid polygon with one exterior and one interior ring that touch at one point,
// but poly2tri library does not allow interior rings touch each other or exterior ring.
// TODO: Handle the situation better - rather than just detecting the problem, try to fix
// it by converting touching rings into one ring.

if ( polygon.numInteriorRings() > 0 )
{
QList<QgsGeometry> geomRings;
geomRings << QgsGeometry( polygon.exteriorRing()->clone() );
for ( int i = 0; i < polygon.numInteriorRings(); ++i )
geomRings << QgsGeometry( polygon.interiorRing( i )->clone() );

for ( int i = 0; i < geomRings.count(); ++i )
for ( int j = i + 1; j < geomRings.count(); ++j )
{
if ( geomRings[i].intersects( geomRings[j] ) )
{
// skip the polygon - it would cause a crash inside poly2tri library
qDebug() << "polygon rings intersect each other - skipping";
return;
}
}
}

const QgsCurve *exterior = polygon.exteriorRing();

QList< std::vector<p2t::Point *> > polylinesToDelete;
Expand Down
4 changes: 4 additions & 0 deletions src/3d/terrain/qgsflatterraingenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ Qt3DCore::QEntity *FlatTerrainChunkLoader::createEntity( Qt3DCore::QEntity *pare
// ---------------


QgsFlatTerrainGenerator::QgsFlatTerrainGenerator()
{
}

QgsChunkLoader *QgsFlatTerrainGenerator::createChunkLoader( QgsChunkNode *node ) const
{
return new FlatTerrainChunkLoader( mTerrain, node );
Expand Down
3 changes: 2 additions & 1 deletion src/3d/terrain/qgsflatterraingenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
class _3D_EXPORT QgsFlatTerrainGenerator : public QgsTerrainGenerator
{
public:
QgsFlatTerrainGenerator() = default;
//! Creates flat terrain generator object
QgsFlatTerrainGenerator();

virtual QgsChunkLoader *createChunkLoader( QgsChunkNode *node ) const override SIP_FACTORY;

Expand Down

0 comments on commit 0951ff7

Please sign in to comment.