bool TRACKS_CLEANER::merge_collinear_of_track( TRACK *aSegment )
{
    bool merged_this = false;

    // *WHY* doesn't C++ have prec and succ (or ++ --) like PASCAL?
    for( ENDPOINT_T endpoint = ENDPOINT_START; endpoint <= ENDPOINT_END;
            endpoint = ENDPOINT_T( endpoint + 1 ) )
    {
        // search for a possible segment connected to the current endpoint of the current one
        TRACK *other = aSegment->Next();
        if( other )
        {
            other = aSegment->GetTrack( other, NULL, endpoint, true, false );

            if( other )
            {
                // the two segments must have the same width and the other
                // cannot be a via
                if( (aSegment->GetWidth() == other->GetWidth()) &&
                        (other->Type() == PCB_TRACE_T) )
                {
                    // There can be only one segment connected
                    other->SetState( BUSY, true );
                    TRACK *yet_another = aSegment->GetTrack( m_Brd->m_Track, NULL,
                            endpoint, true, false );
                    other->SetState( BUSY, false );

                    if( !yet_another )
                    {
                        // Try to merge them
                        TRACK *segDelete = mergeCollinearSegmentIfPossible( aSegment,
                                other, endpoint );

                        // Merge succesful, the other one has to go away
                        if( segDelete )
                        {
                            m_Brd->GetRatsnest()->Remove( segDelete );
                            segDelete->ViewRelease();
                            segDelete->DeleteStructure();
                            merged_this = true;
                        }
                    }
                }
            }
        }
    }

    return merged_this;
}
/** Abort function for drag or move track
 */
static void Abort_MoveTrack( EDA_DRAW_PANEL* aPanel, wxDC* aDC )
{
    PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) aPanel->GetParent();
    BOARD * pcb = frame->GetBoard();

    pcb->HighLightOFF();
    pcb->PopHighLight();

    frame->SetCurItem( NULL );
    aPanel->SetMouseCapture( NULL, NULL );

    // Undo move and redraw trace segments.
    for( unsigned jj=0 ; jj < g_DragSegmentList.size(); jj++ )
    {
        TRACK* track = g_DragSegmentList[jj].m_Track;
        g_DragSegmentList[jj].RestoreInitialValues();
        track->SetState( IN_EDIT, false );
        track->ClearFlags();
    }

    // Clear the undo picker list:
    s_ItemsListPicker.ClearListAndDeleteItems();
    EraseDragList();
    aPanel->Refresh();
}
/* Cancel move pad command.
 */
static void Abort_Move_Pad( EDA_DRAW_PANEL* Panel, wxDC* DC )
{
    D_PAD* pad = s_CurrentSelectedPad;

    Panel->SetMouseCapture( NULL, NULL );

    if( pad == NULL )
        return;

    pad->Draw( Panel, DC, GR_XOR );
    pad->ClearFlags();
    pad->SetPosition( Pad_OldPos );
    pad->Draw( Panel, DC, GR_XOR );

    // Pad move in progress: restore origin of dragged tracks, if any.
    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        TRACK* Track = g_DragSegmentList[ii].m_Track;
        Track->Draw( Panel, DC, GR_XOR );
        Track->SetState( IN_EDIT, OFF );
        g_DragSegmentList[ii].RestoreInitialValues();
        Track->Draw( Panel, DC, GR_OR );
    }

    EraseDragList();
    s_CurrentSelectedPad = NULL;
}
Beispiel #4
0
void TRACKS_CLEANER::buildTrackConnectionInfo()
{
    BuildTracksCandidatesList( m_Brd->m_Track, NULL);

    // clear flags and variables used in cleanup
    for( TRACK * track = m_Brd->m_Track; track; track = track->Next() )
    {
        track->start = NULL;
        track->end = NULL;
        track->m_PadsConnected.clear();
        track->SetState( START_ON_PAD|END_ON_PAD|BUSY, false );
    }

    // Build connections info tracks to pads
    SearchTracksConnectedToPads();
    for( TRACK * track = m_Brd->m_Track; track; track = track->Next() )
    {
        // Mark track if connected to pads
        for( unsigned jj = 0; jj < track->m_PadsConnected.size(); jj++ )
        {
            D_PAD * pad = track->m_PadsConnected[jj];

            if( pad->HitTest( track->GetStart() ) )
            {
                track->start = pad;
                track->SetState( START_ON_PAD, true );
            }

            if( pad->HitTest( track->GetEnd() ) )
            {
                track->end = pad;
                track->SetState( END_ON_PAD, true );
            }
        }
    }
}
void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC*  DC )
{
    TRACK* TrackToStartPoint = NULL;
    TRACK* TrackToEndPoint   = NULL;
    bool   error = false;

    if( !track )
        return;

    // TODO: Use clenup functions to merge collinear segments if track
    // is connected to a collinear segment.

    s_StartSegmentPresent = s_EndSegmentPresent = true;

    if( ( track->start == NULL ) || ( track->start->Type() == PCB_TRACE_T ) )
        TrackToStartPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false );

    //  Test if more than one segment is connected to this point
    if( TrackToStartPoint )
    {
        TrackToStartPoint->SetState( BUSY, true );

        if( ( TrackToStartPoint->Type() == PCB_VIA_T )
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false ) )
            error = true;

        TrackToStartPoint->SetState( BUSY, false );
    }

    if( ( track->end == NULL ) || ( track->end->Type() == PCB_TRACE_T ) )
        TrackToEndPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false );

    //  Test if more than one segment is connected to this point
    if( TrackToEndPoint )
    {
        TrackToEndPoint->SetState( BUSY, true );

        if( (TrackToEndPoint->Type() == PCB_VIA_T)
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false ) )
            error = true;

        TrackToEndPoint->SetState( BUSY, false );
    }

    if( error )
    {
        DisplayError( this,
                      _( "Unable to drag this segment: too many segments connected" ) );
        return;
    }

    if( !TrackToStartPoint || ( TrackToStartPoint->Type() != PCB_TRACE_T ) )
        s_StartSegmentPresent = false;

    if( !TrackToEndPoint || ( TrackToEndPoint->Type() != PCB_TRACE_T ) )
        s_EndSegmentPresent = false;

    // Change high light net: the new one will be highlighted
    GetBoard()->PushHighLight();

    if( GetBoard()->IsHighLightNetON() )
        HighLight( DC );

    EraseDragList();

    track->SetFlags( IS_DRAGGED );

    if( TrackToStartPoint )
    {
        STATUS_FLAGS flag = STARTPOINT;

        if( track->GetStart() != TrackToStartPoint->GetStart() )
            flag = ENDPOINT;

        AddSegmentToDragList( flag, TrackToStartPoint );
        track->SetFlags( STARTPOINT );
    }

    if( TrackToEndPoint )
    {
        STATUS_FLAGS flag = STARTPOINT;

        if( track->GetEnd() != TrackToEndPoint->GetStart() )
            flag = ENDPOINT;

        AddSegmentToDragList( flag, TrackToEndPoint );
        track->SetFlags( ENDPOINT );
    }

    AddSegmentToDragList( track->GetFlags(), track );

    UndrawAndMarkSegmentsToDrag( m_canvas, DC );


    PosInit   = GetCrossHairPosition();
    s_LastPos = GetCrossHairPosition();
    m_canvas->SetMouseCapture( Show_Drag_Track_Segment_With_Cte_Slope, Abort_MoveTrack );

    GetBoard()->SetHighLightNet( track->GetNetCode() );
    GetBoard()->HighLightON();
    GetBoard()->DrawHighLight( m_canvas, DC, GetBoard()->GetHighLightNetCode() );

    // Prepare the Undo command
    ITEM_PICKER picker( NULL, UR_CHANGED );

    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        TRACK* draggedtrack = g_DragSegmentList[ii].m_Track;
        picker.SetItem( draggedtrack);
        picker.SetLink ( draggedtrack->Clone() );
        s_ItemsListPicker.PushItem( picker );
        draggedtrack = (TRACK*) picker.GetLink();
        draggedtrack->SetStatus( 0 );
        draggedtrack->ClearFlags();
    }

    if( !InitialiseDragParameters() )
    {
        DisplayError( this, _( "Unable to drag this segment: two collinear segments" ) );
        m_canvas->SetMouseCaptureCallback( NULL );
        Abort_MoveTrack( m_canvas, DC );
        return;
    }
}
Beispiel #6
0
bool PCB_EDIT_FRAME::RemoveMisConnectedTracks()
{
     /* finds all track segments which are mis-connected (to more than one net).
     * When such a bad segment is found, it is flagged to be removed.
     * All tracks having at least one flagged segment are removed.
     */
    TRACK*          segment;
    TRACK*          other;
    TRACK*          next;
    int             net_code_s, net_code_e;
    bool            isModified = false;

    for( segment = GetBoard()->m_Track;  segment;  segment = (TRACK*) segment->Next() )
    {
        segment->SetState( FLAG0, false );

        // find the netcode for segment using anything connected to the "start" of "segment"
        net_code_s = -1;

        if( segment->start && segment->start->Type()==PCB_PAD_T )
        {
            // get the netcode of the pad to propagate.
            net_code_s = ((D_PAD*)(segment->start))->GetNetCode();
        }
        else
        {
            other = segment->GetTrace( GetBoard()->m_Track, NULL, FLG_START );

            if( other )
                net_code_s = other->GetNetCode();
        }

        if( net_code_s < 0 )
            continue;           // the "start" of segment is not connected

        // find the netcode for segment using anything connected to the "end" of "segment"
        net_code_e = -1;

        if( segment->end && segment->end->Type()==PCB_PAD_T )
        {
            net_code_e = ((D_PAD*)(segment->end))->GetNetCode();
        }
        else
        {
            other = segment->GetTrace( GetBoard()->m_Track, NULL, FLG_END );

            if( other )
                net_code_e = other->GetNetCode();
        }

        if( net_code_e < 0 )
            continue;           // the "end" of segment is not connected

        // Netcodes do not agree, so mark the segment as "to be removed"
        if( net_code_s != net_code_e )
        {
            segment->SetState( FLAG0, true );
        }
    }

    // Remove tracks having a flagged segment
    for( segment = GetBoard()->m_Track; segment; segment = next )
    {
        next = (TRACK*) segment->Next();

        if( segment->GetState( FLAG0 ) )    // Segment is flagged to be removed
        {
            segment->SetState( FLAG0, false );
            isModified = true;
            GetBoard()->m_Status_Pcb = 0;
            Remove_One_Track( NULL, segment );

            // the current segment is deleted,
            // we do not know the next "not yet tested" segment,
            // so restart to the beginning
            next = GetBoard()->m_Track;
        }
    }

    return isModified;
}
Beispiel #7
0
// Delete null length segments, and intermediate points ..
bool TRACKS_CLEANER::clean_segments()
{
    bool modified = false;
    TRACK*          segment, * nextsegment;
    TRACK*          other;
    int             flag, no_inc;


    // Delete null segments
    for( segment = m_Brd->m_Track; segment; segment = nextsegment )
    {
        nextsegment = segment->Next();

        if( segment->IsNull() )     // Length segment = 0; delete it
            segment->DeleteStructure();
    }

    // Delete redundant segments, i.e. segments having the same end points
    // and layers
    for( segment  = m_Brd->m_Track; segment; segment = segment->Next() )
    {
        for( other = segment->Next(); other; other = nextsegment )
        {
            nextsegment = other->Next();
            bool erase = false;

            if( segment->Type() != other->Type() )
                continue;

            if( segment->GetLayer() != other->GetLayer() )
                continue;

            if( segment->GetNetCode() != other->GetNetCode() )
                break;

            if( ( segment->GetStart() == other->GetStart() ) &&
                ( segment->GetEnd() == other->GetEnd() ) )
                erase = true;

            if( ( segment->GetStart() == other->GetEnd() ) &&
                ( segment->GetEnd() == other->GetStart() ) )
                erase = true;

            // Delete redundant point
            if( erase )
            {
                other->DeleteStructure();
                modified = true;
            }
        }
    }

    // merge collinear segments:
    for( segment = m_Brd->m_Track; segment; segment = nextsegment )
    {
        TRACK*  segStart;
        TRACK*  segEnd;
        TRACK*  segDelete;

        nextsegment = segment->Next();

        if( segment->Type() != PCB_TRACE_T )
            continue;

        flag = no_inc = 0;

        // search for a possible point connected to the START point of the current segment
        for( segStart = segment->Next(); ; )
        {
            segStart = segment->GetTrace( segStart, NULL, FLG_START );

            if( segStart )
            {
                // the two segments must have the same width
                if( segment->GetWidth() != segStart->GetWidth() )
                    break;

                // it cannot be a via
                if( segStart->Type() != PCB_TRACE_T )
                    break;

                // We must have only one segment connected
                segStart->SetState( BUSY, true );
                other = segment->GetTrace( m_Brd->m_Track, NULL, FLG_START );
                segStart->SetState( BUSY, false );

                if( other == NULL )
                    flag = 1;           // OK

                break;
            }
            break;
        }

        if( flag )   // We have the starting point of the segment is connected to an other segment
        {
            segDelete = mergeCollinearSegmentIfPossible( segment, segStart, FLG_START );

            if( segDelete )
            {
                no_inc = 1;
                segDelete->DeleteStructure();
                modified = true;
            }
        }

        // search for a possible point connected to the END point of the current segment:
        for( segEnd = segment->Next(); ; )
        {
            segEnd = segment->GetTrace( segEnd, NULL, FLG_END );

            if( segEnd )
            {
                if( segment->GetWidth() != segEnd->GetWidth() )
                    break;

                if( segEnd->Type() != PCB_TRACE_T )
                    break;

                // We must have only one segment connected
                segEnd->SetState( BUSY, true );
                other = segment->GetTrace( m_Brd->m_Track, NULL, FLG_END );
                segEnd->SetState( BUSY, false );

                if( other == NULL )
                    flag |= 2;          // Ok

                break;
            }
            else
            {
                break;
            }
        }

        if( flag & 2 )  // We have the ending point of the segment is connected to an other segment
        {
            segDelete = mergeCollinearSegmentIfPossible( segment, segEnd, FLG_END );

            if( segDelete )
            {
                no_inc = 1;
                segDelete->DeleteStructure();
                modified = true;
            }
        }

        if( no_inc ) // The current segment was modified, retry to merge it
            nextsegment = segment->Next();
    }

    return modified;
}
Beispiel #8
0
/*
 *  Delete dangling tracks
 *  Vias:
 *  If a via is only connected to a dangling track, it also will be removed
 */
bool TRACKS_CLEANER::deleteUnconnectedTracks()
{
    if( m_Brd->m_Track == NULL )
        return false;

    bool modified = false;
    bool item_erased = true;
    while( item_erased )    // Iterate when at least one track is deleted
    {
        item_erased = false;
        TRACK* next_track;
        for( TRACK * track = m_Brd->m_Track; track ; track = next_track )
        {
            next_track = track->Next();

            int flag_erase = 0; //Not connected indicator
            int type_end = 0;

            if( track->GetState( START_ON_PAD ) )
                type_end |= START_ON_PAD;

            if( track->GetState( END_ON_PAD ) )
                type_end |= END_ON_PAD;

            // if the track start point is not connected to a pad,
            // test if this track start point is connected to another track
            // For via test, an enhancement could be to test if connected
            // to 2 items on different layers.
            // Currently a via must be connected to 2 items, that can be on the same layer
            LAYER_NUM top_layer, bottom_layer;
            ZONE_CONTAINER* zone;

            if( (type_end & START_ON_PAD ) == 0 )
            {
                TRACK* other = track->GetTrace( m_Brd->m_Track, NULL, FLG_START );

                if( other == NULL )     // Test a connection to zones
                {
                    if( track->Type() != PCB_VIA_T )
                    {
                        zone = m_Brd->HitTestForAnyFilledArea( track->GetStart(),
                                                               track->GetLayer(),
                                                               track->GetLayer(),
                                                               track->GetNetCode() );
                    }
                    else
                    {
                        ((SEGVIA*)track)->LayerPair( &top_layer, &bottom_layer );
                        zone = m_Brd->HitTestForAnyFilledArea( track->GetStart(),
                                                               top_layer, bottom_layer,
                                                               track->GetNetCode() );
                    }
                }

                if( (other == NULL) && (zone == NULL) )
                {
                    flag_erase |= 1;
                }
                else    // segment, via or zone connected to this end
                {
                    track->start = other;
                    // If a via is connected to this end,
                    // test if this via has a second item connected.
                    // If no, remove it with the current segment

                    if( other && other->Type() == PCB_VIA_T )
                    {
                        // search for another segment following the via
                        track->SetState( BUSY, true );

                        SEGVIA* via = (SEGVIA*) other;
                        other = via->GetTrace( m_Brd->m_Track, NULL, FLG_START );

                        if( other == NULL )
                        {
                            via->LayerPair( &top_layer, &bottom_layer );
                            zone = m_Brd->HitTestForAnyFilledArea( via->GetStart(),
                                                                   bottom_layer,
                                                                   top_layer,
                                                                   via->GetNetCode() );
                        }

                        if( (other == NULL) && (zone == NULL) )
                            flag_erase |= 2;

                        track->SetState( BUSY, false );
                    }
                }
            }

            // if track end point is not connected to a pad,
            // test if this track end point is connected to an other track
            if( (type_end & END_ON_PAD ) == 0 )
            {
                TRACK* other = track->GetTrace( m_Brd->m_Track, NULL, FLG_END );

                if( other == NULL )     // Test a connection to zones
                {
                    if( track->Type() != PCB_VIA_T )
                    {
                        zone = m_Brd->HitTestForAnyFilledArea( track->GetEnd(),
                                                               track->GetLayer(),
                                                               track->GetLayer(),
                                                               track->GetNetCode() );
                    }
                    else
                    {
                        ((SEGVIA*)track)->LayerPair( &top_layer, &bottom_layer );
                        zone = m_Brd->HitTestForAnyFilledArea( track->GetEnd(),
                                                               top_layer, bottom_layer,
                                                               track->GetNetCode() );
                    }
                }

                if ( (other == NULL) && (zone == NULL) )
                {
                    flag_erase |= 0x10;
                }
                else     // segment, via or zone connected to this end
                {
                    track->end = other;

                    // If a via is connected to this end, test if this via has a second item connected
                    // if no, remove it with the current segment

                    if( other && other->Type() == PCB_VIA_T )
                    {
                        // search for another segment following the via

                        track->SetState( BUSY, true );

                        SEGVIA* via = (SEGVIA*) other;
                        other = via->GetTrace( m_Brd->m_Track, NULL, FLG_END );

                        if( other == NULL )
                        {
                            via->LayerPair( &top_layer, &bottom_layer );
                            zone = m_Brd->HitTestForAnyFilledArea( via->GetEnd(),
                                                                   bottom_layer, top_layer,
                                                                   via->GetNetCode() );
                        }

                        if( (other == NULL) && (zone == NULL) )
                            flag_erase |= 0x20;

                        track->SetState( BUSY, false );
                    }
                }
            }

            if( flag_erase )
            {
                // remove segment from board
                track->DeleteStructure();
                // iterate, because a track connected to the deleted track
                // is now perhaps now not connected and should be deleted
                item_erased = true;
                modified = true;
            }
        }
    }

    return modified;
}
/* search connections between tracks and pads and propagate pad net codes to the track
 * segments.
 * Pads netcodes are assumed to be up to date.
 */
void PCB_BASE_FRAME::RecalculateAllTracksNetcode()
{
    // Build the net info list
    GetBoard()->BuildListOfNets();

    // Reset variables and flags used in computation
    for( TRACK* t = m_Pcb->m_Track;  t;  t = t->Next() )
    {
        t->m_TracksConnected.clear();
        t->m_PadsConnected.clear();
        t->start = NULL;
        t->end = NULL;
        t->SetState( BUSY | IN_EDIT | BEGIN_ONPAD | END_ONPAD, false );
        t->SetZoneSubNet( 0 );
        t->SetNetCode( NETINFO_LIST::UNCONNECTED );
    }

    // If no pad, reset pointers and netcode, and do nothing else
    if( m_Pcb->GetPadCount() == 0 )
        return;

    CONNECTIONS connections( m_Pcb );
    connections.BuildPadsList();
    connections.BuildTracksCandidatesList(m_Pcb->m_Track);

    // First pass: build connections between track segments and pads.
    connections.SearchTracksConnectedToPads();

    // For tracks connected to at least one pad,
    // set the track net code to the pad netcode
    for( TRACK* t = m_Pcb->m_Track;  t;  t = t->Next() )
    {
        if( t->m_PadsConnected.size() )
            t->SetNetCode( t->m_PadsConnected[0]->GetNetCode() );
    }

    // Pass 2: build connections between track ends
    for( TRACK* t = m_Pcb->m_Track;  t;  t = t->Next() )
    {
        connections.SearchConnectedTracks( t );
        connections.GetConnectedTracks( t );
    }

    // Propagate net codes from a segment to other connected segments
    bool new_pass_request = true;   // set to true if a track has its netcode changed from 0
                                    // to a known netcode to re-evaluate netcodes
                                    // of connected items
    while( new_pass_request )
    {
        new_pass_request = false;

        for( TRACK* t = m_Pcb->m_Track;  t;  t = t->Next() )
        {
            int netcode = t->GetNetCode();

            if( netcode == 0 )
            {
                // try to find a connected item having a netcode
                for( unsigned kk = 0; kk < t->m_TracksConnected.size(); kk++ )
                {
                    int altnetcode = t->m_TracksConnected[kk]->GetNetCode();
                    if( altnetcode )
                    {
                        new_pass_request = true;
                        netcode = altnetcode;
                        t->SetNetCode(netcode);
                        break;
                    }
                }
            }

            if( netcode )    // this track has a netcode
            {
                // propagate this netcode to connected tracks having no netcode
                for( unsigned kk = 0; kk < t->m_TracksConnected.size(); kk++ )
                {
                    int altnetcode = t->m_TracksConnected[kk]->GetNetCode();
                    if( altnetcode == 0 )
                    {
                        t->m_TracksConnected[kk]->SetNetCode(netcode);
                        new_pass_request = true;
                    }
                }
            }
        }
    }

    // Sort the track list by net codes:
    RebuildTrackChain( m_Pcb );
}
// Routine to place a moved pad.
void PCB_BASE_FRAME::PlacePad( D_PAD* aPad, wxDC* DC )
{
    int     dX, dY;
    TRACK*  Track;

    if( aPad == NULL )
        return;

    MODULE* module = aPad->GetParent();

    ITEM_PICKER       picker( NULL, UR_CHANGED );
    PICKED_ITEMS_LIST pickList;

    // Save dragged track segments in undo list
    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        Track = g_DragSegmentList[ii].m_Track;

        // Set the old state
        if( g_DragSegmentList[ii].m_Pad_Start )
            Track->SetStart( Pad_OldPos );

        if( g_DragSegmentList[ii].m_Pad_End )
            Track->SetEnd( Pad_OldPos );

        picker.SetItem( Track );
        pickList.PushItem( picker );
    }

    // Save old module and old items values
    wxPoint pad_curr_position = aPad->GetPosition();

    aPad->SetPosition( Pad_OldPos );

    if( g_DragSegmentList.size() == 0 )
        SaveCopyInUndoList( module, UR_CHANGED );
    else
    {
        picker.SetItem( module );
        pickList.PushItem( picker );
        SaveCopyInUndoList( pickList, UR_CHANGED );
    }

    aPad->SetPosition( pad_curr_position );
    aPad->Draw( m_canvas, DC, GR_XOR );

    // Redraw dragged track segments
    for( unsigned ii = 0; ii < g_DragSegmentList.size(); ii++ )
    {
        Track = g_DragSegmentList[ii].m_Track;

        // Set the new state
        if( g_DragSegmentList[ii].m_Pad_Start )
            Track->SetStart( aPad->GetPosition() );

        if( g_DragSegmentList[ii].m_Pad_End )
            Track->SetEnd( aPad->GetPosition() );

        Track->SetState( IN_EDIT, OFF );

        if( DC )
            Track->Draw( m_canvas, DC, GR_OR );
    }

    // Compute local coordinates (i.e refer to module position and for module orient = 0)
    dX = aPad->GetPosition().x - Pad_OldPos.x;
    dY = aPad->GetPosition().y - Pad_OldPos.y;

    RotatePoint( &dX, &dY, -module->GetOrientation() );

    aPad->SetX0( dX + aPad->GetPos0().x );
    aPad->SetY0( dY + aPad->GetPos0().y );

    aPad->ClearFlags();

    if( DC )
        aPad->Draw( m_canvas, DC, GR_OR );

    module->CalculateBoundingBox();
    module->SetLastEditTime();

    EraseDragList();

    OnModify();
    m_canvas->SetMouseCapture( NULL, NULL );
    m_Pcb->m_Status_Pcb &= ~( LISTE_RATSNEST_ITEM_OK | CONNEXION_OK );
}
static void Exit_MoveTrack(WinEDA_DrawFrame * frame, wxDC *DC)
/***************************************************************/
/* routine d'annulation de la commande drag, copy ou move track  si une piste est en cours
	de tracage, ou de sortie de l'application EDITRACK.
	Appel par la touche ESC
 */
{
TRACK * NextS;
int ii;


	/* Effacement du trace en cours */
	wxPoint oldpos = frame->GetScreen()->m_Curseur;
	frame->GetScreen()->m_Curseur = PosInit;
	frame->GetScreen()->ManageCurseur(frame->DrawPanel, DC, TRUE);
	frame->GetScreen()->m_Curseur = oldpos;
	g_HightLigt_Status = FALSE;
	( (WinEDA_PcbFrame *)frame)->DrawHightLight( DC, g_HightLigth_NetCode) ;

	if( NewTrack )
	{
		if (NewTrack->m_Flags & IS_NEW )
		{
			for( ii = 0; ii < NbPtNewTrack; ii++, NewTrack = NextS)
			{
				if(NewTrack == NULL) break;
				NextS = (TRACK*) NewTrack->Pnext;
				delete NewTrack;
			}
		}
		else	/* Move : remise en ancienne position */
		{
			TRACK * Track = NewTrack;
			int dx = LastPos.x - PosInit.x;
			int dy = LastPos.y - PosInit.y;
			for( ii = 0; ii < NbPtNewTrack; ii++, Track = (TRACK*) Track->Pnext)
			{
				if( Track == NULL ) break;
				Track->m_Start.x -= dx;
				Track->m_Start.y -= dy;
				Track->m_End.x -= dx;
				Track->m_End.y -= dy;
				Track->m_Flags = 0;

			}
			Trace_Une_Piste(frame->DrawPanel, DC, NewTrack,NbPtNewTrack,GR_OR);
		}

		NewTrack = NULL;
	}

	frame->GetScreen()->ManageCurseur = NULL;
	frame->GetScreen()->ForceCloseManageCurseur = NULL;
	frame->GetScreen()->m_CurrentItem = NULL;
	frame->EraseMsgBox();

	/* Annulation deplacement et Redessin des segments dragges */
	DRAG_SEGM * pt_drag = g_DragSegmentList;
	for( ; pt_drag != NULL; pt_drag = pt_drag->Pnext)
	{
		TRACK * Track = pt_drag->m_Segm;
		pt_drag->SetInitialValues();
		Track->SetState(EDIT,OFF);
		Track->m_Flags = 0;
		Track->Draw(frame->DrawPanel, DC, GR_OR);
	}

	g_HightLigth_NetCode = Old_HightLigth_NetCode;
	g_HightLigt_Status = Old_HightLigt_Status;
	if(g_HightLigt_Status)
		( (WinEDA_PcbFrame *)frame)->DrawHightLight( DC, g_HightLigth_NetCode) ;

	EraseDragListe();
}