From 70c961fe6aebbc96f87e619dee75cb6ebd0fe0c5 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Fri, 7 Apr 2017 08:02:26 +0200 Subject: [PATCH] Pcbnew: fix serious issues (broken files) when saving and loading .kicad_pcb files when zones have holes in outlines. --- pcbnew/class_zone.cpp | 6 +++- pcbnew/class_zone.h | 10 ++++++ pcbnew/kicad_plugin.cpp | 59 +++++++++++++++++++++-------------- pcbnew/pcb_parser.cpp | 5 ++- pcbnew/tools/point_editor.cpp | 1 - 5 files changed, 55 insertions(+), 26 deletions(-) diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 32db26a5e7..2fab500591 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -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; diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 20964c6cbb..8993fd8f59 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -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 ); diff --git a/pcbnew/kicad_plugin.cpp b/pcbnew/kicad_plugin.cpp index 7e57bd5653..3af27675c6 100644 --- a/pcbnew/kicad_plugin.cpp +++ b/pcbnew/kicad_plugin.cpp @@ -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 diff --git a/pcbnew/pcb_parser.cpp b/pcbnew/pcb_parser.cpp index 55765af61e..543ff91567 100644 --- a/pcbnew/pcb_parser.cpp +++ b/pcbnew/pcb_parser.cpp @@ -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; diff --git a/pcbnew/tools/point_editor.cpp b/pcbnew/tools/point_editor.cpp index b6544cce5b..77a6b3983c 100644 --- a/pcbnew/tools/point_editor.cpp +++ b/pcbnew/tools/point_editor.cpp @@ -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;