Pcbnew: fix a possible crash after a board cleanup

This commit is contained in:
jean-pierre charras 2011-11-15 20:21:16 +01:00
parent 4b9b2f4e66
commit 38553be4de
2 changed files with 83 additions and 77 deletions

View File

@ -6,23 +6,24 @@
#include "fctsys.h"
#include "class_drawpanel.h"
#include "gr_basic.h"
//#include "gr_basic.h"
#include "pcbcommon.h"
#include "wxPcbStruct.h"
#include "pcbnew.h"
#include "protos.h"
//#include "protos.h"
#include "class_board.h"
#include "class_track.h"
typedef long long int64;
/* local functions : */
static void clean_segments( PCB_EDIT_FRAME* frame );
static void clean_vias( BOARD* aPcb );
static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* frame, wxDC* DC );
static TRACK* AlignSegment( BOARD* Pcb, TRACK* pt_ref, TRACK* pt_segm, int extremite );
static void Clean_Pcb_Items( PCB_EDIT_FRAME* frame, wxDC* DC,
static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* frame );
static TRACK* MergeColinearSegmentIfPossible( BOARD* aPcb, TRACK* aTrackRef, TRACK* aCandidate, int aEndType );
static void CleanupTracks( PCB_EDIT_FRAME* frame,
bool aCleanVias, bool aMergeSegments,
bool aDeleteUnconnectedSegm, bool aConnectToPads );
@ -31,7 +32,7 @@ static void Clean_Pcb_Items( PCB_EDIT_FRAME* frame, wxDC* DC,
#define CONN2PAD_ENBL
#ifdef CONN2PAD_ENBL
static void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame, wxDC* DC );
static void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame );
static void ConnectDanglingEndToVia( BOARD* pcb );
#endif
@ -44,7 +45,7 @@ void PCB_EDIT_FRAME::Clean_Pcb( wxDC* DC )
DIALOG_CLEANING_OPTIONS dlg( this );
if( dlg.ShowModal() == wxID_OK )
Clean_Pcb_Items( this, DC, dlg.cleanVias, dlg.mergeSegments,
CleanupTracks( this, dlg.cleanVias, dlg.mergeSegments,
dlg.deleteUnconnectedSegm, dlg.connectToPads );
DrawPanel->Refresh( true );
@ -60,7 +61,7 @@ void PCB_EDIT_FRAME::Clean_Pcb( wxDC* DC )
* Create segments when track ends are incorrectly connected:
* i.e. when a track end covers a pad or a via but is not exactly on the pad or the via center
*/
void Clean_Pcb_Items( PCB_EDIT_FRAME* frame, wxDC* DC,
void CleanupTracks( PCB_EDIT_FRAME* frame,
bool aCleanVias, bool aMergeSegments,
bool aDeleteUnconnectedSegm, bool aConnectToPads )
{
@ -71,6 +72,7 @@ void Clean_Pcb_Items( PCB_EDIT_FRAME* frame, wxDC* DC,
// Clear undo and redo lists to avoid inconsistencies between lists
frame->GetScreen()->ClearUndoRedoList();
frame->SetCurItem( NULL );
/* Rebuild the pad infos (pad list and netcodes) to ensure an up to date info */
frame->GetBoard()->m_Status_Pcb = 0;
@ -90,7 +92,7 @@ void Clean_Pcb_Items( PCB_EDIT_FRAME* frame, wxDC* DC,
frame->SetStatusText( _( "Reconnect pads" ) );
/* Create missing segments when a track end covers a pad, but is not on the pad center */
ConnectDanglingEndToPad( frame, DC );
ConnectDanglingEndToPad( frame );
/* Create missing segments when a track end covers a via, but is not on the via center */
ConnectDanglingEndToVia( frame->GetBoard() );
@ -108,12 +110,12 @@ void Clean_Pcb_Items( PCB_EDIT_FRAME* frame, wxDC* DC,
if( aDeleteUnconnectedSegm )
{
frame->SetStatusText( _( "Delete unconnected tracks" ) );
DeleteUnconnectedTracks( frame, DC );
DeleteUnconnectedTracks( frame );
}
frame->SetStatusText( _( "Cleanup finished" ) );
frame->Compile_Ratsnest( DC, true );
frame->Compile_Ratsnest( NULL, true );
frame->OnModify();
}
@ -173,7 +175,7 @@ void clean_vias( BOARD * aPcb )
* Vias:
* If a via is only connected to a dangling track, it also will be removed
*/
static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* frame, wxDC* DC )
static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* frame )
{
TRACK* segment;
TRACK* other;
@ -372,8 +374,7 @@ static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* frame, wxDC* DC )
next = startNetcode;
}
// remove segment from screen and board
segment->Draw( frame->DrawPanel, DC, GR_XOR );
// remove segment from board
segment->DeleteStructure();
if( next == NULL )
@ -493,7 +494,7 @@ static void clean_segments( PCB_EDIT_FRAME* frame )
if( flag ) // We have the starting point of the segment is connected to an other segment
{
segDelete = AlignSegment( frame->GetBoard(), segment, segStart, START );
segDelete = MergeColinearSegmentIfPossible( frame->GetBoard(), segment, segStart, START );
if( segDelete )
{
@ -533,7 +534,7 @@ static void clean_segments( PCB_EDIT_FRAME* frame )
if( flag & 2 ) // We have the ending point of the segment is connected to an other segment
{
segDelete = AlignSegment( frame->GetBoard(), segment, segEnd, END );
segDelete = MergeColinearSegmentIfPossible( frame->GetBoard(), segment, segEnd, END );
if( segDelete )
{
@ -551,25 +552,42 @@ static void clean_segments( PCB_EDIT_FRAME* frame )
/* Function used by clean_segments.
* Test alignment of pt_segm and pt_ref (which must have a common end).
* Test alignment of aTrackRef and aCandidate (which must have a common end).
* and see if the common point is not on a pad (i.e. if this common point can be removed).
* the ending point of pt_ref is the start point (extremite == START)
* or the end point (extremite == FIN)
* if the common end can be deleted, this function
* change the common point coordinate of the pt_ref segm
* the ending point of pt_ref is the start point (aEndType == START)
* or the end point (aEndType != START)
* if the common point can be deleted, this function
* change the common point coordinate of the aTrackRef segm
* (and therefore connect the 2 other ending points)
* and return pt_segm (which can be deleted).
* and return aCandidate (which can be deleted).
* else return NULL
*/
static TRACK* AlignSegment( BOARD* Pcb, TRACK* pt_ref, TRACK* pt_segm, int extremite )
TRACK* MergeColinearSegmentIfPossible( BOARD* aPcb,
TRACK* aTrackRef, TRACK* aCandidate,
int aEndType )
{
int flag = 0;
if( aTrackRef->m_Width != aCandidate->m_Width )
return NULL;
int refdx = pt_ref->m_End.x - pt_ref->m_Start.x;
int refdy = pt_ref->m_End.y - pt_ref->m_Start.y;
bool is_colinear = false;
int segmdx = pt_segm->m_End.x - pt_segm->m_Start.x;
int segmdy = pt_segm->m_End.y - pt_segm->m_Start.y;
// Trivial case: superimposed tracks ( tracks, not vias ):
if( aTrackRef->Type() == PCB_TRACE_T && aCandidate->Type() == PCB_TRACE_T )
{
if( aTrackRef->m_Start == aCandidate->m_Start )
if( aTrackRef->m_End == aCandidate->m_End )
return aCandidate;
if( aTrackRef->m_Start == aCandidate->m_End )
if( aTrackRef->m_End == aCandidate->m_Start )
return aCandidate;
}
int refdx = aTrackRef->m_End.x - aTrackRef->m_Start.x;
int refdy = aTrackRef->m_End.y - aTrackRef->m_Start.y;
int segmdx = aCandidate->m_End.x - aCandidate->m_Start.x;
int segmdy = aCandidate->m_End.y - aCandidate->m_Start.y;
// test for vertical alignment (easy to handle)
if( refdx == 0 )
@ -577,7 +595,7 @@ static TRACK* AlignSegment( BOARD* Pcb, TRACK* pt_ref, TRACK* pt_segm, int extre
if( segmdx != 0 )
return NULL;
else
flag = 1;
is_colinear = true;
}
// test for horizontal alignment (easy to handle)
@ -586,18 +604,18 @@ static TRACK* AlignSegment( BOARD* Pcb, TRACK* pt_ref, TRACK* pt_segm, int extre
if( segmdy != 0 )
return NULL;
else
flag = 2;
is_colinear = true;
}
/* test if alignment in other cases
* We must have refdy/refdx == (+/-)segmdy/segmdx, (i.e. same orientation) */
if( flag == 0 )
if( is_colinear == false )
{
if( (refdy * segmdx != refdx * segmdy)
&& (refdy * segmdx != -refdx * segmdy) )
if( ( (int64)refdy * segmdx != (int64)refdx * segmdy )
&& ( (int64)refdy * segmdx != -(int64)refdx * segmdy ) )
return NULL;
flag = 4;
is_colinear = true;
}
/* Here we have 2 aligned segments:
@ -605,42 +623,42 @@ static TRACK* AlignSegment( BOARD* Pcb, TRACK* pt_ref, TRACK* pt_segm, int extre
* (this function) is called when there is only 2 connected segments,
*and if this point is not on a pad, it can be removed and the 2 segments will be merged
*/
if( extremite == START )
if( aEndType == START )
{
/* We do not have a pad */
if( Pcb->GetPadFast( pt_ref->m_Start, g_TabOneLayerMask[pt_ref->GetLayer()] ) )
// We must not have a pad, which is a always terminal point for a track
if( aPcb->GetPadFast( aTrackRef->m_Start, g_TabOneLayerMask[aTrackRef->GetLayer()] ) )
return NULL;
/* change the common point coordinate of pt_segm to use the other point
* of pt_segm (pt_segm will be removed later) */
if( pt_ref->m_Start == pt_segm->m_Start )
if( aTrackRef->m_Start == aCandidate->m_Start )
{
pt_ref->m_Start = pt_segm->m_End;
return pt_segm;
aTrackRef->m_Start = aCandidate->m_End;
return aCandidate;
}
else
{
pt_ref->m_Start = pt_segm->m_Start;
return pt_segm;
aTrackRef->m_Start = aCandidate->m_Start;
return aCandidate;
}
}
else /* extremite == END */
else // aEndType == END
{
/* We do not have a pad */
if( Pcb->GetPadFast( pt_ref->m_End, g_TabOneLayerMask[pt_ref->GetLayer()] ) )
// We must not have a pad, which is a always terminal point for a track
if( aPcb->GetPadFast( aTrackRef->m_End, g_TabOneLayerMask[aTrackRef->GetLayer()] ) )
return NULL;
/* change the common point coordinate of pt_segm to use the other point
* of pt_segm (pt_segm will be removed later) */
if( pt_ref->m_End == pt_segm->m_Start )
if( aTrackRef->m_End == aCandidate->m_Start )
{
pt_ref->m_End = pt_segm->m_End;
return pt_segm;
aTrackRef->m_End = aCandidate->m_End;
return aCandidate;
}
else
{
pt_ref->m_End = pt_segm->m_Start;
return pt_segm;
aTrackRef->m_End = aCandidate->m_Start;
return aCandidate;
}
}
@ -812,7 +830,7 @@ static void ConnectDanglingEndToVia( BOARD* pcb )
* connected into the center of the pad. This allows faster control of
* connections.
*/
void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame, wxDC* DC )
void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame )
{
TRACK* segment;
int nb_new_trace = 0;
@ -831,7 +849,7 @@ void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame, wxDC* DC )
if( pad )
{
// test if the track is not precisely starting on the found pad
// test if the track start point is not exactly starting on the pad
if( segment->m_Start != pad->m_Pos )
{
if( segment->GetTrace( frame->GetBoard()->m_Track, NULL, START ) == NULL )
@ -845,8 +863,6 @@ void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame, wxDC* DC )
newTrack->end = pad;
nb_new_trace++;
newTrack->Draw( frame->DrawPanel, DC, GR_OR );
}
}
}
@ -855,7 +871,7 @@ void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame, wxDC* DC )
if( pad )
{
// test if the track is not precisely ending on the found pad
// test if the track end point is not exactly on the pad
if( segment->m_End != pad->m_Pos )
{
if( segment->GetTrace( frame->GetBoard()->m_Track, NULL, END ) == NULL )

View File

@ -627,35 +627,25 @@ void PCB_BASE_FRAME::RecalculateAllTracksNetcode()
// Build the net info list
GetBoard()->m_NetInfo->BuildListOfNets();
if( m_Pcb->GetPadsCount() == 0 ) // If no pad, reset pointers and netcode, and do nothing else
{
curr_track = m_Pcb->m_Track;
for( ; curr_track != NULL; curr_track = curr_track->Next() )
{
curr_track->start = NULL;
curr_track->SetState( BEGIN_ONPAD | END_ONPAD, OFF );
curr_track->SetNet( 0 );
curr_track->end = NULL;
}
return;
}
// Prepare connections calculations between tracks and pads */
m_Pcb->GetSortedPadListByXthenYCoord( sortedPads );
// Reset variables and flags used in computation
curr_track = m_Pcb->m_Track;
for( ; curr_track != NULL; curr_track = curr_track->Next() )
{
curr_track->m_TracksConnected.clear();
curr_track->start = NULL;
curr_track->end = NULL;
curr_track->SetState( BUSY | IN_EDIT | BEGIN_ONPAD | END_ONPAD, OFF );
curr_track->SetZoneSubNet( 0 );
curr_track->SetNet( 0 ); // net code = 0 means not connected
}
// If no pad, reset pointers and netcode, and do nothing else
if( m_Pcb->GetPadsCount() == 0 )
return;
// Prepare connections calculations between tracks and pads */
m_Pcb->GetSortedPadListByXthenYCoord( sortedPads );
/* First pass: search connection between a track segment and a pad.
* if found, set the track net code to the pad netcode
*/