From 6a63d4fbff0dddffbe31c6d036b266224b05020c Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Mon, 19 Jun 2017 13:29:57 +0200 Subject: [PATCH] pcbnew crash while opening old .brd file Fixes: lp:1698697 https://bugs.launchpad.net/kicad/+bug/1698697 The incorrect method ZONE_CONTAINER::AppendCorner() is also fixed: It was expecting the corner must be added to the main outline, but this is a false expectation: it can be added to a hole inside the zone outline. --- pcbnew/class_board.cpp | 17 +++++++++------ pcbnew/class_board.h | 12 ++++++++--- pcbnew/class_zone.cpp | 18 ++++++++++++++++ pcbnew/class_zone.h | 14 +++++------- pcbnew/eagle_plugin.cpp | 11 +++++----- pcbnew/legacy_plugin.cpp | 24 +++++++++++++++------ pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp | 3 +-- pcbnew/zones_by_polygon.cpp | 5 +++-- 8 files changed, 69 insertions(+), 35 deletions(-) diff --git a/pcbnew/class_board.cpp b/pcbnew/class_board.cpp index 29f6c33140..09a4642d46 100644 --- a/pcbnew/class_board.cpp +++ b/pcbnew/class_board.cpp @@ -2348,21 +2348,24 @@ void BOARD::RemoveArea( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_to } -ZONE_CONTAINER* BOARD::InsertArea( int netcode, int iarea, PCB_LAYER_ID layer, int x, int y, int hatch ) +ZONE_CONTAINER* BOARD::InsertArea( int aNetcode, int aAreaIdx, PCB_LAYER_ID aLayer, + int aCornerX, int aCornerY, int aHatch ) { ZONE_CONTAINER* new_area = new ZONE_CONTAINER( this ); - new_area->SetNetCode( netcode ); - new_area->SetLayer( layer ); + new_area->SetNetCode( aNetcode ); + new_area->SetLayer( aLayer ); new_area->SetTimeStamp( GetNewTimeStamp() ); - if( iarea < (int) ( m_ZoneDescriptorList.size() - 1 ) ) - m_ZoneDescriptorList.insert( m_ZoneDescriptorList.begin() + iarea + 1, new_area ); + if( aAreaIdx < (int) ( m_ZoneDescriptorList.size() - 1 ) ) + m_ZoneDescriptorList.insert( m_ZoneDescriptorList.begin() + aAreaIdx + 1, new_area ); else m_ZoneDescriptorList.push_back( new_area ); - new_area->SetHatchStyle( (ZONE_CONTAINER::HATCH_STYLE) hatch ); - new_area->AppendCorner( wxPoint( x, y ) ); + new_area->SetHatchStyle( (ZONE_CONTAINER::HATCH_STYLE) aHatch ); + + // Add the first corner to the new zone + new_area->AppendCorner( wxPoint( aCornerX, aCornerY ), -1 ); return new_area; } diff --git a/pcbnew/class_board.h b/pcbnew/class_board.h index a03a4e633f..0b061c89d8 100644 --- a/pcbnew/class_board.h +++ b/pcbnew/class_board.h @@ -1070,11 +1070,17 @@ public: PCB_LAYER_ID aLayer, wxPoint aStartPointPosition, int aHatch ); /** - * Function InsertArea - * add empty copper area to net, inserting after m_ZoneDescriptorList[iarea] + * Add a copper area to net, inserting after m_ZoneDescriptorList[aAreaIdx] + * @param aNetcode is the netcode of the new copper zone + * @param aAreaIdx is the netcode of the new copper zone + * @param aLayer is the copper layer id of the new copper zone + * @param aCornerX,aCornerY is the coordinate of the first corner + * (a zone cannot have a empty outline) + * @param aHatch is the hatch option * @return pointer to the new area */ - ZONE_CONTAINER* InsertArea( int netcode, int iarea, PCB_LAYER_ID layer, int x, int y, int hatch ); + ZONE_CONTAINER* InsertArea( int aNetcode, int aAreaIdx, PCB_LAYER_ID aLayer, + int aCornerX, int aCornerY, int aHatch ); /** * Function NormalizeAreaPolygon diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp index 0c4f4e3366..babed06f0a 100644 --- a/pcbnew/class_zone.cpp +++ b/pcbnew/class_zone.cpp @@ -843,6 +843,24 @@ void ZONE_CONTAINER::AddPolygon( std::vector< wxPoint >& aPolygon ) } +bool ZONE_CONTAINER::AppendCorner( wxPoint aPosition, int aHoleIdx, bool aAllowDuplication ) +{ + // Ensure the main outline exists: + if( m_Poly->OutlineCount() == 0 ) + m_Poly->NewOutline(); + + // If aHoleIdx >= 0, the corner musty be added to the hole, index aHoleIdx. + // (remember: the index of the first hole is 0) + // Return error if if does dot exist. + if( aHoleIdx >= m_Poly->HoleCount( 0 ) ) + return false; + + m_Poly->Append( aPosition.x, aPosition.y, -1, aHoleIdx, aAllowDuplication ); + + return true; +} + + wxString ZONE_CONTAINER::GetSelectMenuText() const { wxString text; diff --git a/pcbnew/class_zone.h b/pcbnew/class_zone.h index 82ab6e9762..f43da75000 100644 --- a/pcbnew/class_zone.h +++ b/pcbnew/class_zone.h @@ -537,18 +537,14 @@ public: } /** - * Function AppendCorner - * @param position is the position of the new corner. + * Add a new corner to the zone outline (to the main outline or a hole) + * @param aPosition is the position of the new corner. + * @param aHoleIdx is the index of the hole (-1 for the main outline, >= 0 for hole). * @param aAllowDuplication is a flag to indicate whether it is allowed to add this corner * even if it is duplicated. + * @return true if the corner was added, false if error (aHoleIdx > hole count -1) */ - void AppendCorner( wxPoint position, bool aAllowDuplication = false ) - { - if( m_Poly->OutlineCount() == 0 ) - m_Poly->NewOutline(); - - m_Poly->Append( position.x, position.y, -1, -1, aAllowDuplication ); - } + bool AppendCorner( wxPoint aPosition, int aHoleIdx, bool aAllowDuplication = false ); HATCH_STYLE GetHatchStyle() const { diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 92c66ae57c..5d3dfeb515 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -621,10 +621,11 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics ) ZONE_CONTAINER::HATCH_STYLE outline_hatch = ZONE_CONTAINER::DIAGONAL_EDGE; - zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ) ); - zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ) ); - zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ) ); - zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ) ); + const int outlineIdx = -1; // this is the id of the copper zone main outline + zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y1 ) ), outlineIdx ); + zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y1 ) ), outlineIdx ); + zone->AppendCorner( wxPoint( kicad_x( r.x2 ), kicad_y( r.y2 ) ), outlineIdx ); + zone->AppendCorner( wxPoint( kicad_x( r.x1 ), kicad_y( r.y2 ) ), outlineIdx ); // this is not my fault: zone->SetHatch( outline_hatch, Mils2iu( zone->GetDefaultHatchPitchMils() ), true ); @@ -1812,7 +1813,7 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals ) EVERTEX v( vertex ); // Append the corner - zone->AppendCorner( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ) ); + zone->AppendCorner( wxPoint( kicad_x( v.x ), kicad_y( v.y ) ), -1 ); vertex = vertex->GetNext(); } diff --git a/pcbnew/legacy_plugin.cpp b/pcbnew/legacy_plugin.cpp index 1c1db62641..73f9b26f41 100644 --- a/pcbnew/legacy_plugin.cpp +++ b/pcbnew/legacy_plugin.cpp @@ -2475,7 +2475,8 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() unique_ptr zc( new ZONE_CONTAINER( m_board ) ); ZONE_CONTAINER::HATCH_STYLE outline_hatch = ZONE_CONTAINER::NO_HATCH; - bool sawCorner = false; + bool endContour = false; + int holeIndex = -1; // -1 is the main outline; holeIndex >= 0 = hole index char buf[1024]; char* line; char* saveptr; @@ -2484,18 +2485,27 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() { const char* data; - if( TESTLINE( "ZCorner" ) ) // new corner found + if( TESTLINE( "ZCorner" ) ) // new corner of the zone outlines found { // e.g. "ZCorner 25650 49500 0" BIU x = biuParse( line + SZ( "ZCorner" ), &data ); BIU y = biuParse( data, &data ); - if( !sawCorner ) + if( endContour ) + { + // the previous corner was the last corner of a contour. + // so this corner is the first of a new hole + endContour = false; zc->NewHole(); - else - zc->AppendCorner( wxPoint( x, y ) ); + holeIndex++; + } - sawCorner = true; + zc->AppendCorner( wxPoint( x, y ), holeIndex ); + + // Is this corner the end of current contour? + // the next corner (if any) will be stored in a new contour (a hole) + // intParse( data )returns 0 = usual corner, 1 = last corner of the current contour: + endContour = intParse( data ); } else if( TESTLINE( "ZInfo" ) ) // general info found @@ -2655,7 +2665,7 @@ void LEGACY_PLUGIN::loadZONE_CONTAINER() else if( TESTLINE( "$POLYSCORNERS" ) ) { - // Read the PolysList (polygons used for fill areas in the zone) + // Read the PolysList (polygons that are the solid areas in the filled zone) SHAPE_POLY_SET polysList; bool makeNewOutline = true; diff --git a/pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp b/pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp index 7a09351ceb..a644edd9c9 100644 --- a/pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp +++ b/pcbnew/pcad2kicadpcb_plugin/pcb_polygon.cpp @@ -182,7 +182,7 @@ void PCB_POLYGON::AddToBoard() for( i = 0; i < (int) m_outline.GetCount(); i++ ) { zone->AppendCorner( wxPoint( KiROUND( m_outline[i]->x ), - KiROUND( m_outline[i]->y ) ) ); + KiROUND( m_outline[i]->y ) ), -1 ); } zone->SetZoneClearance( m_width ); @@ -206,7 +206,6 @@ void PCB_POLYGON::AddToBoard() } //if( m_filled ) - // cvpcb is not linked // zone->BuildFilledPolysListData( m_board ); } } diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index 25d1ce1306..e22a793b8c 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -669,8 +669,9 @@ int PCB_EDIT_FRAME::Begin_Zone( wxDC* DC ) zone->SetLayer( zoneInfo.m_CurrentZone_Layer ); // A duplicated corner is needed; null segments are removed when the zone is finished. - zone->AppendCorner( GetCrossHairPosition() ); - zone->AppendCorner( GetCrossHairPosition(), true ); + zone->AppendCorner( GetCrossHairPosition(), -1 ); + // Add the duplicate corner: + zone->AppendCorner( GetCrossHairPosition(), -1, true ); if( g_Drc_On && (m_drc->Drc( zone, 0 ) == BAD_DRC) && zone->IsOnCopperLayer() ) {