diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 76d790dec5..9d3c7a739d 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -5,6 +5,20 @@ Started 2007-June-11 Please add newer entries at the top, list the date and your name with email address. + +2009-mar-16 UPDATE Jean-Pierre Charras +================================================================================ +++pcbnew: + Fixed: + bug that crashes pcbnew when removing all footprints + (in connection calculations, pointers to pads not reset) + + bug that crashes pcbnew when filling a zone + if a module has a trapezoidal pad + (trapezoidal pads are not yet implemented in zone filling, + they are now calculated as rect shape (todo: a better handling) ) + + 2009-mar-12 UPDATE Jean-Pierre Charras ================================================================================ ++eeschema: @@ -51,7 +65,7 @@ email address. so delete track (or edit track width) deletes the track and some others segments (last created) bug fix 2660689 Unconnected pads in RC4. Also fixed some no deletion of the old track when creating a new track - + 2009-Feb-25 UPDATE Wayne Stambaugh ================================================================================ ++EESchema diff --git a/pcbnew/connect.cpp b/pcbnew/connect.cpp index 1223757fac..de900d962c 100644 --- a/pcbnew/connect.cpp +++ b/pcbnew/connect.cpp @@ -69,14 +69,14 @@ static int Merge_Two_SubNets( TRACK* pt_start_conn, TRACK* pt_end_conn, int old_ { pt_pad = (D_PAD*) (pt_conn->start); if( pt_pad->GetSubNet() == old_val ) - pt_pad->SetSubNet(pt_conn->GetSubNet()); + pt_pad->SetSubNet( pt_conn->GetSubNet() ); } if( pt_conn->end && (pt_conn->end->Type() == TYPE_PAD) ) { pt_pad = (D_PAD*) (pt_conn->end); if( pt_pad->GetSubNet() == old_val ) - pt_pad->SetSubNet(pt_conn->GetSubNet()); + pt_pad->SetSubNet( pt_conn->GetSubNet() ); } if( pt_conn == pt_end_conn ) break; @@ -115,11 +115,11 @@ static void Propagate_SubNet( TRACK* pt_start_conn, TRACK* pt_end_conn ) pt_conn->SetSubNet( 0 ); PtStruct = pt_conn->start; if( PtStruct && (PtStruct->Type() == TYPE_PAD) ) - ( (D_PAD*) PtStruct )->SetSubNet( 0); + ( (D_PAD*) PtStruct )->SetSubNet( 0 ); PtStruct = pt_conn->end; if( PtStruct && (PtStruct->Type() == TYPE_PAD) ) - ( (D_PAD*) PtStruct )->SetSubNet( 0); + ( (D_PAD*) PtStruct )->SetSubNet( 0 ); if( pt_conn == pt_end_conn ) break; @@ -141,17 +141,17 @@ static void Propagate_SubNet( TRACK* pt_start_conn, TRACK* pt_end_conn ) pt_pad = (D_PAD*) PtStruct; if( pt_conn->GetSubNet() ) /* the track segment is already a cluster member */ { - if( pt_pad->GetSubNet() > 0 ) /* The pad is already a cluster member, so we can merge the 2 clusters */ + if( pt_pad->GetSubNet() > 0 ) /* The pad is already a cluster member, so we can merge the 2 clusters */ { Merge_Two_SubNets( pt_start_conn, pt_end_conn, - pt_pad->GetSubNet(), pt_conn->GetSubNet() ); + pt_pad->GetSubNet(), pt_conn->GetSubNet() ); } else /* The pad is not yet attached to a cluster , so we can add this pad to the cluster */ pt_pad->SetSubNet( pt_conn->GetSubNet() ); } else /* the track segment is not attached to a cluster */ { - if( pt_pad->GetSubNet() > 0 ) /* it is connected to a pad in a cluster, merge this track */ + if( pt_pad->GetSubNet() > 0 ) /* it is connected to a pad in a cluster, merge this track */ { pt_conn->SetSubNet( pt_pad->GetSubNet() ); } @@ -174,7 +174,7 @@ static void Propagate_SubNet( TRACK* pt_start_conn, TRACK* pt_end_conn ) if( pt_pad->GetSubNet() > 0 ) { Merge_Two_SubNets( pt_start_conn, pt_end_conn, - pt_pad->GetSubNet(), pt_conn->GetSubNet() ); + pt_pad->GetSubNet(), pt_conn->GetSubNet() ); } else pt_pad->SetSubNet( pt_conn->GetSubNet() ); @@ -207,7 +207,7 @@ static void Propagate_SubNet( TRACK* pt_start_conn, TRACK* pt_end_conn ) if( pt_autre_piste->GetSubNet() ) /* The other track is already a cluster member, so we can merge the 2 clusters */ { Merge_Two_SubNets( pt_start_conn, pt_end_conn, - pt_autre_piste->GetSubNet(), pt_conn->GetSubNet() ); + pt_autre_piste->GetSubNet(), pt_conn->GetSubNet() ); } else /* The other track is not yet attached to a cluster , so we can add this other track to the cluster */ { @@ -239,7 +239,7 @@ static void Propagate_SubNet( TRACK* pt_start_conn, TRACK* pt_end_conn ) if( pt_autre_piste->GetSubNet() ) { Merge_Two_SubNets( pt_start_conn, pt_end_conn, - pt_autre_piste->GetSubNet(), pt_conn->GetSubNet() ); + pt_autre_piste->GetSubNet(), pt_conn->GetSubNet() ); } else pt_autre_piste->SetSubNet( pt_conn->GetSubNet() ); @@ -291,7 +291,7 @@ void WinEDA_BasePcbFrame::test_connexions( wxDC* DC ) for( TRACK* track = m_Pcb->m_Track; track; ) { // this is the current net because pt_start_conn is the first segment of the net - int current_net_code = track->GetNet(); + int current_net_code = track->GetNet(); // this is the last segment of the current net TRACK* pt_end_conn = track->GetEndNetCode( current_net_code ); @@ -317,7 +317,7 @@ void WinEDA_BasePcbFrame::test_1_net_connexion( wxDC* DC, int net_code ) * @param net_code = net code to test */ { - wxString msg; + wxString msg; if( net_code == 0 ) return; @@ -325,11 +325,11 @@ void WinEDA_BasePcbFrame::test_1_net_connexion( wxDC* DC, int net_code ) if( (m_Pcb->m_Status_Pcb & LISTE_CHEVELU_OK) == 0 ) Compile_Ratsnest( DC, TRUE ); - for( unsigned i=0; im_Pads.size(); ++i ) + for( unsigned i = 0; im_Pads.size(); ++i ) { D_PAD* pad = m_Pcb->m_Pads[i]; - int pad_net_code = pad->GetNet(); + int pad_net_code = pad->GetNet(); if( pad_net_code < net_code ) continue; @@ -345,8 +345,8 @@ void WinEDA_BasePcbFrame::test_1_net_connexion( wxDC* DC, int net_code ) /* Search for the first and the last segment relative to the given net code */ if( m_Pcb->m_Track ) { - TRACK* pt_start_conn; - TRACK* pt_end_conn = NULL; + TRACK* pt_start_conn; + TRACK* pt_end_conn = NULL; pt_start_conn = m_Pcb->m_Track.GetFirst()->GetStartNetCode( net_code ); if( pt_start_conn ) @@ -475,7 +475,7 @@ static D_PAD* SuperFast_Locate_Pad_Connecte( BOARD* aPcb, LISTE_PAD* pt_liste, int nb_pad = aPcb->m_Pads.size(); LISTE_PAD* ptr_pad = pt_liste; - LISTE_PAD* lim = pt_liste + nb_pad - 1; + LISTE_PAD* lim = pt_liste + nb_pad - 1; ptr_pad = pt_liste; while( nb_pad ) @@ -539,7 +539,6 @@ static D_PAD* SuperFast_Locate_Pad_Connecte( BOARD* aPcb, LISTE_PAD* pt_liste, } - /** * Function SortPadsByXCoord * is used to Sort a pad list by x coordinate value. @@ -553,7 +552,6 @@ static int SortPadsByXCoord( const void* pt_ref, const void* pt_comp ) } - /*****************************************************************************/ void CreateSortedPadListByXCoord( BOARD* aBoard, std::vector* aVector ) /*****************************************************************************/ @@ -575,17 +573,29 @@ void WinEDA_BasePcbFrame::reattribution_reference_piste( int affiche ) * We search a connection between a track segment and a pad: if found : this segment netcode is set to the pad netcode */ { - TRACK* pt_piste; - TRACK* pt_next; - int a_color; - char new_passe_request = 1, flag; - std::vector sortedPads; - BOARD_ITEM* PtStruct; - int masque_layer; - wxString msg; + TRACK* pt_piste; + TRACK* pt_next; + int a_color; + char new_passe_request = 1, flag; + + std::vector sortedPads; + BOARD_ITEM* PtStruct; + int masque_layer; + wxString msg; + + if( m_Pcb->m_Pads.size() == 0 ) // If no pad, reset pointers and netcode, and do nothing else + { + pt_piste = m_Pcb->m_Track; + for( ; pt_piste != NULL; pt_piste = pt_piste->Next() ) + { + pt_piste->start = NULL; + pt_piste->SetState( BEGIN_ONPAD | END_ONPAD, OFF ); + pt_piste->SetNet( 0 ); + pt_piste->end = NULL; + } - if( m_Pcb->m_Pads.size() == 0 ) return; + } a_color = CYAN; @@ -795,10 +805,10 @@ void WinEDA_BasePcbFrame::reattribution_reference_piste( int affiche ) */ static int Sort_By_NetCode( const void* left, const void* right ) { - TRACK* pt_ref = *(TRACK**) left; + TRACK* pt_ref = *(TRACK**) left; TRACK* pt_compare = *(TRACK**) right; - int ret = pt_ref->GetNet() - pt_compare->GetNet(); + int ret = pt_ref->GetNet() - pt_compare->GetNet(); return ret; } @@ -815,11 +825,11 @@ static void RebuildTrackChain( BOARD* pcb ) if( pcb->m_Track == NULL ) return; - int nbsegm = pcb->m_Track.GetCount(); + int nbsegm = pcb->m_Track.GetCount(); TRACK** array = (TRACK**) MyZMalloc( nbsegm * sizeof(TRACK*) ); - for( int i=0; im_Track.PopFront(); wxASSERT( array[i] ); @@ -831,7 +841,7 @@ static void RebuildTrackChain( BOARD* pcb ) qsort( array, nbsegm, sizeof(TRACK*), Sort_By_NetCode ); // add them back to the list - for( int i=0; im_Track.PushBack( array[i] ); } diff --git a/pcbnew/initpcb.cpp b/pcbnew/initpcb.cpp index cbdcc62a35..db35f9edbc 100644 --- a/pcbnew/initpcb.cpp +++ b/pcbnew/initpcb.cpp @@ -34,11 +34,14 @@ void WinEDA_PcbGlobalDeleteFrame::AcceptPcbDelete( wxCommandEvent& event ) /***********************************************************************/ { int track_mask; - bool redraw = FALSE; + bool redraw = false; + bool gen_rastnest = false; wxClientDC dc( m_Parent->DrawPanel ); m_Parent->DrawPanel->PrepareGraphicContext( &dc ); + m_Parent->SetCurItem( NULL ); + if( m_DelAlls->GetValue() ) { m_Parent->Clear_Pcb( TRUE ); @@ -49,6 +52,7 @@ void WinEDA_PcbGlobalDeleteFrame::AcceptPcbDelete( wxCommandEvent& event ) if( m_DelZones->GetValue() ) { m_Parent->Erase_Zones( TRUE ); + gen_rastnest = true; redraw = TRUE; } @@ -73,12 +77,12 @@ void WinEDA_PcbGlobalDeleteFrame::AcceptPcbDelete( wxCommandEvent& event ) if( m_DelModules->GetValue() ) { m_Parent->Erase_Modules( TRUE ); + gen_rastnest = true; redraw = TRUE; } - + if( m_DelTracks->GetValue() ) { - { track_mask = 0; if( !m_TrackFilterLocked->GetValue() ) track_mask |= SEGM_FIXE; @@ -87,7 +91,7 @@ void WinEDA_PcbGlobalDeleteFrame::AcceptPcbDelete( wxCommandEvent& event ) m_Parent->Erase_Pistes( &dc, track_mask, TRUE ); redraw = TRUE; - } + gen_rastnest = true; } if( m_DelMarkers->GetValue() ) @@ -95,11 +99,14 @@ void WinEDA_PcbGlobalDeleteFrame::AcceptPcbDelete( wxCommandEvent& event ) m_Parent->Erase_Marqueurs(); redraw = TRUE; } + + if ( gen_rastnest ) + m_Parent->Compile_Ratsnest( &dc, true ); + } if( redraw ) { - m_Parent->SetCurItem( NULL ); m_Parent->DrawPanel->Refresh(); } @@ -278,6 +285,7 @@ void WinEDA_PcbFrame::Erase_Modules( bool query ) GetBoard()->m_NbNodes = 0; GetBoard()->m_NbLinks = 0; GetBoard()->m_NbNoconnect = 0; + m_Pcb->m_Pads.clear(); // empty the pad list pointers GetScreen()->SetModify(); } diff --git a/pcbnew/ratsnest.cpp b/pcbnew/ratsnest.cpp index 5faeacb6fc..8b1307d7b8 100644 --- a/pcbnew/ratsnest.cpp +++ b/pcbnew/ratsnest.cpp @@ -122,7 +122,7 @@ void WinEDA_BasePcbFrame::Compile_Ratsnest( wxDC* DC, bool display_status_pcb ) msg.Printf( wxT( " %d" ), m_Pcb->m_Equipots.GetCount() ); Affiche_1_Parametre( this, 8, wxT( "Nets" ), msg, CYAN ); - + reattribution_reference_piste( display_status_pcb ); /* Compute the full ratsnest @@ -446,6 +446,11 @@ void WinEDA_BasePcbFrame::Build_Board_Ratsnest( wxDC* DC ) m_Pcb->m_NbNoconnect = 0; m_Pcb->m_NbLinks = 0; + if( m_Pcb->m_Ratsnest ) + MyFree( m_Pcb->m_Ratsnest ); + m_Pcb->m_Ratsnest = NULL; + + if( m_Pcb->m_Pads.size() == 0 ) return; @@ -464,13 +469,9 @@ void WinEDA_BasePcbFrame::Build_Board_Ratsnest( wxDC* DC ) /* Allocate memory for buffer ratsnest: there are nb_nodes - 1 ratsnest * maximum ( 1 node = 1 active pad ). - * Meory is allocated for nb_nodes ratsnests... (+ a bit more, just in case) + * Memory is allocated for nb_nodes ratsnests... (+ a bit more, just in case) * The real ratsnests count nb_links < nb_nodes */ - if( m_Pcb->m_Ratsnest ) - MyFree( m_Pcb->m_Ratsnest ); - m_Pcb->m_Ratsnest = NULL; - if( m_Pcb->m_NbNodes == 0 ) return; /* pas de connexions utiles */ diff --git a/pcbnew/zones_convert_brd_items_to_polygons.cpp b/pcbnew/zones_convert_brd_items_to_polygons.cpp index 904b35c15d..fe949ae8ad 100644 --- a/pcbnew/zones_convert_brd_items_to_polygons.cpp +++ b/pcbnew/zones_convert_brd_items_to_polygons.cpp @@ -110,6 +110,8 @@ double s_Correction; /* mult coeff used to enlarge rounded and oval pads (an */ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) { + bool have_poly_to_substract = false; + // Set the number of segments in arc approximations if( m_ArcToSegmentsCount == 32 ) s_CircleToSegmentsCount = 32; @@ -149,6 +151,9 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) CopyPolygonsFromBoolengineToFilledPolysList( booleng ); delete booleng; + if ( m_FilledPolysList.size() == 0 ) + return; + /* Second, Add the main (corrected) polygon (i.e. the filled area using only one outline) * in GroupA in Bool_Engine to do a BOOL_A_SUB_B operation * All areas to remove will be put in GroupB in Bool_Engine @@ -178,6 +183,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) * First : Add pads. Note: pads having the same net as zone are left in zone. * Thermal shapes will be created later if necessary */ + have_poly_to_substract = false; for( MODULE* module = aPcb->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->m_Pads; pad != NULL; pad = pad->Next() ) @@ -189,7 +195,10 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) { item_boundingbox = pad->GetBoundingBox(); if( item_boundingbox.Intersects( zone_boundingbox ) ) + { AddPadWithClearancePolygon( booleng, *pad, clearance ); + have_poly_to_substract = true; + } continue; } @@ -197,7 +206,11 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) { item_boundingbox = pad->GetBoundingBox(); if( item_boundingbox.Intersects( zone_boundingbox ) ) + { AddPadWithClearancePolygon( booleng, *pad, clearance ); + have_poly_to_substract = true; + } + } } } @@ -214,8 +227,11 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) continue; item_boundingbox = track->GetBoundingBox(); if( item_boundingbox.Intersects( zone_boundingbox ) ) + { AddTrackWithClearancePolygon( booleng, *track, clearance ); - } + have_poly_to_substract = true; + } + } // Draw graphic items (copper texts) and board edges // zone clearance is used here regardless of the g_DesignSettings.m_TrackClearence value @@ -234,6 +250,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) AddRingPolygon( booleng, ( (DRAWSEGMENT*) item )->m_Start, // Circle centre ( (DRAWSEGMENT*) item )->m_End, 3600, ( (DRAWSEGMENT*) item )->m_Width + (2 * m_ZoneClearance) ); + have_poly_to_substract = true; break; case S_ARC: @@ -241,6 +258,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) ( (DRAWSEGMENT*) item )->m_End, ( (DRAWSEGMENT*) item )->m_Angle, ( (DRAWSEGMENT*) item )->m_Width + (2 * m_ZoneClearance) ); + have_poly_to_substract = true; break; default: @@ -250,6 +268,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) ( (DRAWSEGMENT*) item )->m_End, ( (DRAWSEGMENT*) item )->m_Width + (2 * m_ZoneClearance) ); + have_poly_to_substract = true; break; } @@ -259,6 +278,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) if( ( (TEXTE_PCB*) item )->GetLength() == 0 ) break; AddTextBoxWithClearancePolygon( booleng, (TEXTE_PCB*) item, m_ZoneClearance ); + have_poly_to_substract = true; break; default: @@ -267,23 +287,32 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) } /* calculates copper areas */ - booleng->Do_Operation( BOOL_A_SUB_B ); + if ( have_poly_to_substract ) + { + booleng->Do_Operation( BOOL_A_SUB_B ); -/* put these areas in m_FilledPolysList */ - m_FilledPolysList.clear(); - CopyPolygonsFromBoolengineToFilledPolysList( booleng ); + /* put these areas in m_FilledPolysList */ + m_FilledPolysList.clear(); + CopyPolygonsFromBoolengineToFilledPolysList( booleng ); + } delete booleng; // Remove insulated islands: if( GetNet() > 0 ) Test_For_Copper_Island_And_Remove_Insulated_Islands( aPcb ); + // remove thermal gaps if required: + if( m_PadOption != THERMAL_PAD || aPcb->m_Modules == NULL ) + return; + // Remove thermal symbols + have_poly_to_substract = false; + if( m_PadOption == THERMAL_PAD ) { booleng = new Bool_Engine(); ArmBoolEng( booleng, true ); - bool have_poly_to_substract = false; + have_poly_to_substract = false; for( MODULE* module = aPcb->m_Modules; module; module = module->Next() ) { @@ -320,15 +349,13 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) CopyPolygonsFromBoolengineToFilledPolysList( booleng ); } delete booleng; + + // Remove insulated islands: + if( GetNet() > 0 ) + Test_For_Copper_Island_And_Remove_Insulated_Islands( aPcb ); + } -// Remove insulated islands: - if( GetNet() > 0 ) - Test_For_Copper_Island_And_Remove_Insulated_Islands( aPcb ); - - if( m_PadOption != THERMAL_PAD ) - return; - // Now we remove all unused thermal stubs. //define REMOVE_UNUSED_THERMAL_STUBS // Can be commented to skip unused thermal stubs calculations //#ifdef REMOVE_UNUSED_THERMAL_STUBS @@ -348,6 +375,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) /* * Test and add polygons to remove thermal stubs. */ + have_poly_to_substract = false; for( MODULE* module = aPcb->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->m_Pads; pad != NULL; pad = pad->Next() ) @@ -446,6 +474,7 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) RotatePoint( &cpos, fAngle ); // Rotate according to module orientation cpos += pad->ReturnShapePos(); // Shift origin to position booleng->AddPoint( cpos.x, cpos.y ); + have_poly_to_substract = true; } booleng->EndPolygonAdd(); @@ -456,16 +485,19 @@ void ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList( BOARD* aPcb ) } /* compute copper areas */ - booleng->Do_Operation( BOOL_A_SUB_B ); + if ( have_poly_to_substract ) + { + booleng->Do_Operation( BOOL_A_SUB_B ); + + /* put these areas in m_FilledPolysList */ + m_FilledPolysList.clear(); + CopyPolygonsFromBoolengineToFilledPolysList( booleng ); + // Remove insulated islands, if any: + if( GetNet() > 0 ) + Test_For_Copper_Island_And_Remove_Insulated_Islands( aPcb ); + } -/* put these areas in m_FilledPolysList */ - m_FilledPolysList.clear(); - CopyPolygonsFromBoolengineToFilledPolysList( booleng ); delete booleng; - -// Remove insulated islands, if any: - if( GetNet() > 0 ) - Test_For_Copper_Island_And_Remove_Insulated_Islands( aPcb ); //#endif } @@ -569,7 +601,12 @@ void AddPadWithClearancePolygon( Bool_Engine* aBooleng, break; } - case PAD_RECT: // Easy implementation for rectangular cutouts with rounded corners + case PAD_TRAPEZOID: + default: /* @todo: the others shapes must be calculated: see trapezoidal shape + * but before this is made, the rect shape is used insteed. + * A polygon *must* be created because we have started a polygon in kbool engine + */ + case PAD_RECT: // Easy implementation for rectangular cutouts with rounded corners // Easy implementation for rectangular cutouts with rounded corners angle = aPad.m_Orient; int rounding_radius = (int) ( aClearanceValue * s_Correction ); // Corner rounding radius int angle_pg; // Polygon increment angle