Skip to content
Permalink
Browse files
[tessallator] Remove self-intersecting skip, crash fixed in upstream …
…library

(fixes #46021)
  • Loading branch information
nirvn authored and github-actions committed Nov 16, 2021
1 parent e3b5c63 commit 183a15eef0b83c58d6c58d24942c5ebd0bf757ba
Showing with 0 additions and 65 deletions.
  1. +0 −65 src/core/qgstessellator.cpp
@@ -431,64 +431,6 @@ static QgsPolygon *_transform_polygon_to_new_base( const QgsPolygon &polygon, co
return p;
}

static bool _check_intersecting_rings( const QgsPolygon &polygon )
{
std::vector< std::unique_ptr< QgsGeometryEngine > > ringEngines;
ringEngines.reserve( 1 + polygon.numInteriorRings() );
ringEngines.emplace_back( QgsGeometry::createGeometryEngine( polygon.exteriorRing() ) );
for ( int i = 0; i < polygon.numInteriorRings(); ++i )
ringEngines.emplace_back( QgsGeometry::createGeometryEngine( polygon.interiorRing( i ) ) );

// we need to make sure that the polygon has no rings with self-intersection: that may
// crash the tessellator. The original geometry maybe have been valid and the self-intersection
// was introduced when transforming to a new base (in a rare case when all points are not in the same plane)

for ( const std::unique_ptr< QgsGeometryEngine > &ring : ringEngines )
{
if ( !ring->isSimple() )
return false;
}

// 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 ( ringEngines.size() > 1 )
{
for ( size_t i = 0; i < ringEngines.size(); ++i )
{
std::unique_ptr< QgsGeometryEngine > &first = ringEngines.at( i );
if ( polygon.numInteriorRings() > 1 )
first->prepareGeometry();

// TODO this is inefficient - QgsGeometryEngine::intersects only works with QgsAbstractGeometry
// objects and accordingly we have to use those, instead of the previously build geos
// representations available in ringEngines
// This needs addressing by extending the QgsGeometryEngine relation tests to allow testing against
// another QgsGeometryEngine object.
for ( int interiorRing = static_cast< int >( i ); interiorRing < polygon.numInteriorRings(); ++interiorRing )
{
if ( first->intersects( polygon.interiorRing( interiorRing ) ) )
return false;
}
}
}
return true;
}


double _minimum_distance_between_coordinates( const QgsPolygon &polygon )
{
@@ -687,13 +629,6 @@ void QgsTessellator::addPolygon( const QgsPolygon &polygon, float extrusionHeigh
}
}

if ( !_check_intersecting_rings( *polygonNew ) )
{
// skip the polygon - it would cause a crash inside poly2tri library
QgsMessageLog::logMessage( QObject::tr( "polygon rings self-intersect or intersect each other - skipping" ), QObject::tr( "3D" ) );
return;
}

QList< std::vector<p2t::Point *> > polylinesToDelete;
QHash<p2t::Point *, float> z;

0 comments on commit 183a15e

Please sign in to comment.