Pcbnew: fix serious issues (broken files) when saving and loading .kicad_pcb files when zones have holes in outlines.

This commit is contained in:
jean-pierre charras 2017-04-07 08:02:26 +02:00
parent ba37d6fca3
commit 70c961fe6a
5 changed files with 55 additions and 26 deletions

View File

@ -819,9 +819,13 @@ void ZONE_CONTAINER::AddPolygon( std::vector< wxPoint >& aPolygon )
outline.SetClosed( true );
// Add the outline as a new polygon in the polygon set
m_Poly->AddOutline( outline );
if( m_Poly->OutlineCount() == 0 )
m_Poly->AddOutline( outline );
else
m_Poly->AddHole( outline );
}
wxString ZONE_CONTAINER::GetSelectMenuText() const
{
wxString text;

View File

@ -620,8 +620,18 @@ public:
unsigned int GetCornerRadius() const { return m_cornerRadius; };
/**
* add a polygon to the zone outline
* if the zone outline is empty, this is the main outline
* else it is a hole inside the main outline
*/
void AddPolygon( std::vector< wxPoint >& aPolygon );
/**
* add a polygon to the zone filled areas list.
* these polygons have no hole, therefore any added polygon is a new
* filled area
*/
void AddFilledPolygon( SHAPE_POLY_SET& aPolygon )
{
m_FilledPolysList.Append( aPolygon );

View File

@ -1610,11 +1610,20 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
if( aZone->GetNumCorners() )
{
m_out->Print( aNestLevel+1, "(polygon\n");
m_out->Print( aNestLevel+2, "(pts\n" );
bool new_polygon = true;
bool is_closed = false;
for( auto iterator = aZone->IterateWithHoles(); iterator; iterator++ )
{
if( new_polygon )
{
newLine = 0;
m_out->Print( aNestLevel+1, "(polygon\n" );
m_out->Print( aNestLevel+2, "(pts\n" );
new_polygon = false;
is_closed = false;
}
if( newLine == 0 )
m_out->Print( aNestLevel+3, "(xy %s %s)",
FMT_IU( iterator->x ).c_str(), FMT_IU( iterator->y ).c_str() );
@ -1634,35 +1643,42 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
if( iterator.IsEndContour() )
{
is_closed = true;
if( newLine != 0 )
m_out->Print( 0, "\n" );
m_out->Print( aNestLevel+2, ")\n" );
if( !iterator.IsLastPolygon() )
{
newLine = 0;
m_out->Print( aNestLevel+1, ")\n" );
m_out->Print( aNestLevel+1, "(polygon\n" );
m_out->Print( aNestLevel+2, "(pts" );
}
m_out->Print( aNestLevel+1, ")\n" );
new_polygon = true;
}
}
m_out->Print( aNestLevel+1, ")\n" );
if( !is_closed ) // Should not happen, but...
m_out->Print( aNestLevel+1, ")\n" );
}
// Save the PolysList
// Save the PolysList (filled areas)
const SHAPE_POLY_SET& fv = aZone->GetFilledPolysList();
newLine = 0;
if( !fv.IsEmpty() )
{
m_out->Print( aNestLevel+1, "(filled_polygon\n" );
m_out->Print( aNestLevel+2, "(pts\n" );
bool new_polygon = true;
bool is_closed = false;
for( auto it = fv.CIterate(); it; ++it )
{
if( new_polygon )
{
newLine = 0;
m_out->Print( aNestLevel+1, "(filled_polygon\n" );
m_out->Print( aNestLevel+2, "(pts\n" );
new_polygon = false;
is_closed = false;
}
if( newLine == 0 )
m_out->Print( aNestLevel+3, "(xy %s %s)",
FMT_IU( it->x ).c_str(), FMT_IU( it->y ).c_str() );
@ -1682,22 +1698,19 @@ void PCB_IO::format( ZONE_CONTAINER* aZone, int aNestLevel ) const
if( it.IsEndContour() )
{
is_closed = true;
if( newLine != 0 )
m_out->Print( 0, "\n" );
m_out->Print( aNestLevel+2, ")\n" );
if( !it.IsLastPolygon() )
{
newLine = 0;
m_out->Print( aNestLevel+1, ")\n" );
m_out->Print( aNestLevel+1, "(filled_polygon\n" );
m_out->Print( aNestLevel+2, "(pts\n" );
}
m_out->Print( aNestLevel+1, ")\n" );
new_polygon = true;
}
}
m_out->Print( aNestLevel+1, ")\n" );
if( !is_closed ) // Should not happen, but...
m_out->Print( aNestLevel+1, ")\n" );
}
// Save the filling segments list

View File

@ -2888,12 +2888,15 @@ ZONE_CONTAINER* PCB_PARSER::parseZONE_CONTAINER() throw( IO_ERROR, PARSE_ERROR )
if( token != T_pts )
Expecting( T_pts );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
corners.push_back( parseXY() );
}
NeedRIGHT();
// Remark: The first polygon is the main outline.
// Others are holes inside the main outline.
zone->AddPolygon( corners );
}
break;

View File

@ -780,7 +780,6 @@ int POINT_EDITOR::addCorner( const TOOL_EVENT& aEvent )
commit.Modify( zone );
// Handle the last segment, so other segments can be easily handled in a loop
unsigned int nearestIdx = 0;
unsigned int nextNearestIdx = 0;
unsigned int nearestDist = INT_MAX;