Skip to content

Commit 0951ff7

Browse files
committedOct 1, 2017
Fix crash in tessellation (polygon 3D symbol) for touching rings
1 parent 8dc70b4 commit 0951ff7

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed
 

‎src/3d/qgstessellator.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "qgstessellator.h"
1717

1818
#include "qgscurve.h"
19+
#include "qgsgeometry.h"
1920
#include "qgspoint.h"
2021
#include "qgspolygon.h"
2122

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

112113
void QgsTessellator::addPolygon( const QgsPolygonV2 &polygon, float extrusionHeight )
113114
{
115+
// At this point we assume that input polygons are valid according to the OGC definition.
116+
// This means e.g. no duplicate points, polygons are simple (no butterfly shaped polygon with self-intersection),
117+
// internal rings are inside exterior rings, rings do not cross each other, no dangles.
118+
119+
// There is however an issue with polygons where rings touch:
120+
// +---+
121+
// | |
122+
// | +-+-+
123+
// | | | |
124+
// | +-+ |
125+
// | |
126+
// +-----+
127+
// This is a valid polygon with one exterior and one interior ring that touch at one point,
128+
// but poly2tri library does not allow interior rings touch each other or exterior ring.
129+
// TODO: Handle the situation better - rather than just detecting the problem, try to fix
130+
// it by converting touching rings into one ring.
131+
132+
if ( polygon.numInteriorRings() > 0 )
133+
{
134+
QList<QgsGeometry> geomRings;
135+
geomRings << QgsGeometry( polygon.exteriorRing()->clone() );
136+
for ( int i = 0; i < polygon.numInteriorRings(); ++i )
137+
geomRings << QgsGeometry( polygon.interiorRing( i )->clone() );
138+
139+
for ( int i = 0; i < geomRings.count(); ++i )
140+
for ( int j = i + 1; j < geomRings.count(); ++j )
141+
{
142+
if ( geomRings[i].intersects( geomRings[j] ) )
143+
{
144+
// skip the polygon - it would cause a crash inside poly2tri library
145+
qDebug() << "polygon rings intersect each other - skipping";
146+
return;
147+
}
148+
}
149+
}
150+
114151
const QgsCurve *exterior = polygon.exteriorRing();
115152

116153
QList< std::vector<p2t::Point *> > polylinesToDelete;

‎src/3d/terrain/qgsflatterraingenerator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ Qt3DCore::QEntity *FlatTerrainChunkLoader::createEntity( Qt3DCore::QEntity *pare
9393
// ---------------
9494

9595

96+
QgsFlatTerrainGenerator::QgsFlatTerrainGenerator()
97+
{
98+
}
99+
96100
QgsChunkLoader *QgsFlatTerrainGenerator::createChunkLoader( QgsChunkNode *node ) const
97101
{
98102
return new FlatTerrainChunkLoader( mTerrain, node );

‎src/3d/terrain/qgsflatterraingenerator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
class _3D_EXPORT QgsFlatTerrainGenerator : public QgsTerrainGenerator
3232
{
3333
public:
34-
QgsFlatTerrainGenerator() = default;
34+
//! Creates flat terrain generator object
35+
QgsFlatTerrainGenerator();
3536

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

0 commit comments

Comments
 (0)