Fix segfault when removing the last corner of a cutout

Fixes: lp:1736147
* https://bugs.launchpad.net/kicad/+bug/1736147
This commit is contained in:
Maciej Suminski 2017-12-06 15:51:47 +01:00
parent 1e88695001
commit f44d4d01ea
1 changed files with 64 additions and 21 deletions

View File

@ -784,19 +784,46 @@ bool POINT_EDITOR::addCornerCondition( const SELECTION& aSelection )
}
// Finds a corresponding vertex in a polygon set
static std::pair<bool, SHAPE_POLY_SET::VERTEX_INDEX>
findVertex( SHAPE_POLY_SET& aPolySet, const EDIT_POINT& aPoint )
{
for( auto it = aPolySet.IterateWithHoles(); it; ++it )
{
auto vertexIdx = it.GetIndex();
if( aPolySet.Vertex( vertexIdx ) == aPoint.GetPosition() )
return std::make_pair( true, vertexIdx );
}
return std::make_pair( false, SHAPE_POLY_SET::VERTEX_INDEX() );
}
bool POINT_EDITOR::removeCornerCondition( const SELECTION& )
{
if( !m_editPoints )
if( !m_editPoints || !m_editedPoint )
return false;
EDA_ITEM* item = m_editPoints->GetParent();
if( item->Type() != PCB_ZONE_AREA_T )
if( !item || item->Type() != PCB_ZONE_AREA_T )
return false;
ZONE_CONTAINER* zone = static_cast<ZONE_CONTAINER*>( item );
auto& polyset = *zone->Outline();
auto vertex = findVertex( polyset, *m_editedPoint );
if( zone->GetNumCorners() <= 3 )
if( !vertex.first )
return false;
const auto& vertexIdx = vertex.second;
// Check if there are enough vertices so one can be removed without
// degenerating the polygon.
// The first condition allows to remove all corners from holes (when there
// are only 2 vertices left, a hole is removed).
if( vertexIdx.m_contour == 0 && polyset.Polygon( vertexIdx.m_polygon )[vertexIdx.m_contour].PointCount() <= 3 )
return false;
// Remove corner does not work with lines
@ -931,44 +958,60 @@ int POINT_EDITOR::removeCorner( const TOOL_EVENT& aEvent )
if( !item )
return 0;
SHAPE_POLY_SET *outline = nullptr;
SHAPE_POLY_SET* polygon = nullptr;
if( item->Type() == PCB_ZONE_AREA_T)
{
auto zone = static_cast<ZONE_CONTAINER*>( item );
outline = zone->Outline();
polygon = zone->Outline();
}
else if ( item->Type() == PCB_LINE_T )
else if( item->Type() == PCB_LINE_T )
{
auto ds = static_cast<DRAWSEGMENT*>( item );
if( ds->GetShape() == S_POLYGON )
{
outline = &ds->GetPolyShape();
}
polygon = &ds->GetPolyShape();
}
if( !outline )
if( !polygon )
return 0;
PCB_BASE_FRAME* frame = getEditFrame<PCB_BASE_FRAME>();
BOARD_COMMIT commit( frame );
auto vertex = findVertex( *polygon, *m_editedPoint );
commit.Modify( item );
for( int i = 0; i < outline->TotalVertices(); ++i )
if( vertex.first )
{
if( outline->Vertex( i ) == m_editedPoint->GetPosition() )
const auto& vertexIdx = vertex.second;
auto& outline = polygon->Polygon( vertexIdx.m_polygon )[vertexIdx.m_contour];
if( outline.PointCount() > 3 )
{
outline->RemoveVertex( i );
setEditedPoint( NULL );
commit.Push( _( "Remove a zone/polygon corner" ) );
break;
// the usual case: remove just the corner when there are >3 vertices
commit.Modify( item );
polygon->RemoveVertex( vertexIdx );
}
else
{
// either remove a hole or the polygon when there are <= 3 corners
if( vertexIdx.m_contour > 0 )
{
// remove hole
commit.Modify( item );
polygon->RemoveContour( vertexIdx.m_contour );
}
else
{
m_toolMgr->RunAction( PCB_ACTIONS::selectionClear, true );
commit.Remove( item );
}
}
setEditedPoint( nullptr );
commit.Push( _( "Remove a zone/polygon corner" ) );
updatePoints();
}
updatePoints();
return 0;
}