polygon: Fix missing steiner removal and fracture

When removing steiner points, there is the possibility that the test
point is also removed.  In this case, it is no longer a member of the
linked list and will break the output.

The test for re-fracturing a broken polygon can also result in multiple
polygons, rather than only 0 or 1.  Skipping the extra polygons will
result in a limited tesselation.

Fixes: lp:1812393
* https://bugs.launchpad.net/kicad/+bug/1812393
This commit is contained in:
Seth Hillbrand 2019-01-18 07:13:50 -08:00
parent e2afe5e1a3
commit 4a68ae4bae
2 changed files with 18 additions and 17 deletions

View File

@ -1871,27 +1871,23 @@ void SHAPE_POLY_SET::CacheTriangulation()
m_triangulatedPolys.clear();
m_triangulationValid = true;
for( int i = 0; i < tmpSet.OutlineCount(); i++ )
while( tmpSet.OutlineCount() > 0 )
{
m_triangulatedPolys.push_back( std::make_unique<TRIANGULATED_POLYGON>() );
PolygonTriangulation tess( *m_triangulatedPolys.back() );
// If the tesselation fails, we re-fracture the polygon, which will
// first simplify the system before fracturing and removing the holes
if( !tess.TesselatePolygon( tmpSet.Polygon( i ).front() ) )
// This may result in multiple, disjoint polygons.
if( !tess.TesselatePolygon( tmpSet.Polygon( 0 ).front() ) )
{
tmpSet.Fracture( PM_FAST );
// After fracturing, we may have zero or one polygon
// Check for zero polygons before tesselating and break regardless
if( !tmpSet.OutlineCount() || !tess.TesselatePolygon( tmpSet.Polygon( i ).front() ) )
{
m_triangulatedPolys.pop_back();
m_triangulationValid = false;
}
break;
m_triangulationValid = false;
continue;
}
tmpSet.DeletePolygon( 0 );
m_triangulationValid = true;
}
if( m_triangulationValid )

View File

@ -263,9 +263,9 @@ private:
* as the NULL triangles are inserted as Steiner points to improve the
* triangulation regularity of polygons
*/
bool removeNullTriangles( Vertex* aStart )
Vertex* removeNullTriangles( Vertex* aStart )
{
bool retval = false;
Vertex* retval = nullptr;
Vertex* p = aStart->next;
while( p != aStart )
@ -274,7 +274,7 @@ private:
{
p = p->prev;
p->next->remove();
retval = true;
retval = aStart;
if( p == p->next )
break;
@ -286,8 +286,8 @@ private:
// here we do the final check for this as a Steiner point
if( area( aStart->prev, aStart, aStart->next ) == 0.0 )
{
retval = p->next;
p->remove();
retval = true;
}
return retval;
@ -433,8 +433,13 @@ private:
if( aPoint == stop )
{
// First, try to remove the remaining steiner points
if( removeNullTriangles( aPoint ) )
// If aPoint is a steiner, we need to re-assign both the start and stop points
if( auto newPoint = removeNullTriangles( aPoint ) )
{
aPoint = newPoint;
stop = newPoint;
continue;
}
// If we don't have any NULL triangles left, cut the polygon in two and try again
splitPolygon( aPoint );