Commit 38553be4 authored by jean-pierre charras's avatar jean-pierre charras
Browse files

Pcbnew: fix a possible crash after a board cleanup

parent 4b9b2f4e
Loading
Loading
Loading
Loading
+73 −57
Original line number Diff line number Diff line
@@ -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;

    bool is_colinear = false;

    int refdx = pt_ref->m_End.x - pt_ref->m_Start.x;
    int refdy = pt_ref->m_End.y - pt_ref->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;

    int segmdx = pt_segm->m_End.x - pt_segm->m_Start.x;
    int segmdy = pt_segm->m_End.y - pt_segm->m_Start.y;
        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 )
+10 −20
Original line number Diff line number Diff line
@@ -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
    {
    // 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->SetState( BEGIN_ONPAD | END_ONPAD, OFF );
            curr_track->SetNet( 0 );
        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 );

    // 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->SetState( BUSY | IN_EDIT | BEGIN_ONPAD | END_ONPAD, OFF );
        curr_track->SetZoneSubNet( 0 );
        curr_track->SetNet( 0 );  // net code = 0 means not connected
    }

    /* First pass: search connection between a track segment and a pad.
     * if found, set the track net code to the pad netcode
     */