kicad/pcbnew/clean.cpp

1010 lines
32 KiB
C++
Raw Normal View History

/**
* @file clean.cpp
* functions to clean tracks: remove null and redundant segments
*/
2007-05-06 16:03:28 +00:00
#include "fctsys.h"
#include "common.h"
#include "class_drawpanel.h"
2007-05-06 16:03:28 +00:00
#include "pcbnew.h"
2009-07-30 11:04:07 +00:00
#include "wxPcbStruct.h"
2007-05-06 16:03:28 +00:00
#include "protos.h"
/* 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 );
2007-08-10 19:14:51 +00:00
static TRACK* AlignSegment( BOARD* Pcb, TRACK* pt_ref, TRACK* pt_segm, int extremite );
static void Clean_Pcb_Items( PCB_EDIT_FRAME* frame, wxDC* DC,
bool aCleanVias, bool aMergeSegments,
bool aDeleteUnconnectedSegm, bool aConnectToPads );
2007-05-06 16:03:28 +00:00
#include "dialog_cleaning_options.h"
#define CONN2PAD_ENBL
#ifdef CONN2PAD_ENBL
static void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame, wxDC* DC );
2007-10-19 23:02:11 +00:00
static void ConnectDanglingEndToVia( BOARD* pcb );
//static void Gen_Raccord_Track( PCB_EDIT_FRAME* frame, wxDC* DC );
#endif
2007-05-06 16:03:28 +00:00
2007-10-19 23:02:11 +00:00
2007-05-06 16:03:28 +00:00
/*****************************************/
void PCB_EDIT_FRAME::Clean_Pcb( wxDC* DC )
2007-05-06 16:03:28 +00:00
/*****************************************/
/* Install the track operation dialog frame
*/
2007-05-06 16:03:28 +00:00
{
DIALOG_CLEANING_OPTIONS::connectToPads = false;
DIALOG_CLEANING_OPTIONS dlg( this );
if( dlg.ShowModal() == wxID_OK )
Clean_Pcb_Items( this, DC, dlg.cleanVias, dlg.mergeSegments,
dlg.deleteUnconnectedSegm, dlg.connectToPads );
2007-08-10 19:14:51 +00:00
DrawPanel->Refresh( true );
}
2007-08-10 19:14:51 +00:00
/* Main cleaning function.
* Delete
* - Redundant points on tracks (merge aligned segments)
* - vias on pad
* - null segments
* - Redundant segments
* Create segments when track ends are incorrecty 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,
bool aCleanVias, bool aMergeSegments,
bool aDeleteUnconnectedSegm, bool aConnectToPads )
{
wxBusyCursor( dummy );
2007-08-10 19:14:51 +00:00
frame->MsgPanel->EraseMsgBox();
frame->GetBoard()->GetNumSegmTrack(); // update the count
2008-03-10 15:00:22 +00:00
2009-08-03 07:55:08 +00:00
// Clear undo and redo lists to avoid inconsistencies between lists
frame->GetScreen()->ClearUndoRedoList();
/* Rebuild the pad infos (pad list and netcodes) to ensure an up to date info */
frame->GetBoard()->m_Status_Pcb = 0;
frame->GetBoard()->m_NetInfo->BuildListOfNets();
2007-08-10 19:14:51 +00:00
if( aCleanVias ) // delete redundant vias
2007-08-10 19:14:51 +00:00
{
frame->SetStatusText( _( "Clean vias" ) );
clean_vias( frame->GetBoard() );
2007-08-10 19:14:51 +00:00
}
#ifdef CONN2PAD_ENBL
2008-03-10 15:00:22 +00:00
/* Create missing segments when a track end covers a pad or a via,
but is not on the pad or the via center */
if( aConnectToPads )
2007-08-10 19:14:51 +00:00
{
frame->SetStatusText( _( "Reconnect pads" ) );
2008-03-10 15:00:22 +00:00
/* Create missing segments when a track end covers a pad, but is not on the pad center */
ConnectDanglingEndToPad( frame, DC );
2007-08-10 19:14:51 +00:00
2007-10-19 23:02:11 +00:00
// creation of points of connections at the intersection of tracks
// Gen_Raccord_Track(frame, DC);
2007-10-15 03:26:38 +00:00
2008-03-10 15:00:22 +00:00
/* Create missing segments when a track end covers a via, but is not on the via center */
ConnectDanglingEndToVia( frame->GetBoard() );
2007-08-10 19:14:51 +00:00
}
2007-05-06 16:03:28 +00:00
#endif
/* Remove null segments and intermediate points on aligned segments */
if( aMergeSegments )
{
frame->SetStatusText( _( "Merge track segments" ) );
clean_segments( frame );
}
2007-05-06 16:03:28 +00:00
/* Delete dangling tracks */
if( aDeleteUnconnectedSegm )
{
frame->SetStatusText( _( "Delete unconnected tracks" ) );
DeleteUnconnectedTracks( frame, DC );
}
frame->SetStatusText( _( "Cleanup finished" ) );
2007-05-06 16:03:28 +00:00
frame->Compile_Ratsnest( DC, true );
2007-05-06 16:03:28 +00:00
frame->OnModify();
2007-05-06 16:03:28 +00:00
}
void clean_vias( BOARD * aPcb )
{
TRACK* track;
TRACK* next_track;
for( track = aPcb->m_Track; track; track = track->Next() )
{
if( track->Shape() != VIA_THROUGH )
continue;
// Search and delete others vias at same location
TRACK* alt_track = track->Next();
for( ; alt_track != NULL; alt_track = next_track )
{
next_track = alt_track->Next();
if( alt_track->m_Shape != VIA_THROUGH )
continue;
if( alt_track->m_Start != track->m_Start )
continue;
/* delete via */
alt_track->UnLink();
delete alt_track;
}
}
/* Delete Via on pads at same location */
for( track = aPcb->m_Track; track != NULL; track = next_track )
{
next_track = track->Next();
if( track->m_Shape != VIA_THROUGH )
continue;
D_PAD* pad = Fast_Locate_Pad_Connecte( aPcb, track->m_Start, ALL_CU_LAYERS );
if( pad && (pad->m_Masque_Layer & EXTERNAL_LAYERS) == EXTERNAL_LAYERS ) // redundant Via
{
/* delete via */
track->UnLink();
delete track;
}
}
}
2007-05-06 16:03:28 +00:00
/*****************************************************************************/
static void DeleteUnconnectedTracks( PCB_EDIT_FRAME* frame, wxDC* DC )
2007-05-06 16:03:28 +00:00
/*****************************************************************************/
2007-08-10 19:14:51 +00:00
2007-05-06 16:03:28 +00:00
/*
* Delete dangling tracks
* Vias:
* If a via is only connected to a dangling track, it also will be removed
2007-08-10 19:14:51 +00:00
*/
2007-05-06 16:03:28 +00:00
{
2007-10-19 19:58:31 +00:00
TRACK* segment;
TRACK* other;
TRACK* startNetcode;
TRACK* next;
ZONE_CONTAINER* zone;
2007-08-10 19:14:51 +00:00
int masklayer, oldnetcode;
int type_end, flag_erase;
if( frame->GetBoard()->m_Track == NULL )
return;
2007-08-10 19:14:51 +00:00
frame->DrawPanel->m_AbortRequest = FALSE;
// correct via m_End defects
for( segment = frame->GetBoard()->m_Track; segment; segment = next )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
next = segment->Next();
2008-03-10 15:00:22 +00:00
if( segment->Type() == TYPE_VIA )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
if( segment->m_Start != segment->m_End )
segment->m_End = segment->m_Start;
2007-08-10 19:14:51 +00:00
continue;
}
}
2007-10-19 19:58:31 +00:00
// removal of unconnected tracks
segment = startNetcode = frame->GetBoard()->m_Track;
oldnetcode = segment->GetNet();
for( int ii = 0; segment ; segment = next, ii++ )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
next = segment->Next();
2008-03-10 15:00:22 +00:00
2007-08-10 19:14:51 +00:00
if( frame->DrawPanel->m_AbortRequest )
break;
2007-10-15 03:26:38 +00:00
if( segment->GetNet() != oldnetcode )
2007-08-10 19:14:51 +00:00
{
2008-03-10 15:00:22 +00:00
startNetcode = segment;
2007-10-19 19:58:31 +00:00
oldnetcode = segment->GetNet();
2007-08-10 19:14:51 +00:00
}
flag_erase = 0; //Not connected indicator
2007-10-19 19:58:31 +00:00
type_end = 0;
/* Is a pad found on a track end ? */
2007-08-10 19:14:51 +00:00
2007-10-15 03:26:38 +00:00
masklayer = segment->ReturnMaskLayer();
2007-08-10 19:14:51 +00:00
2007-10-19 19:58:31 +00:00
D_PAD* pad;
2008-03-10 15:00:22 +00:00
pad = Fast_Locate_Pad_Connecte( frame->GetBoard(), segment->m_Start, masklayer );
2007-10-19 19:58:31 +00:00
if( pad != NULL )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
segment->start = pad;
type_end |= START_ON_PAD;
2007-08-10 19:14:51 +00:00
}
pad = Fast_Locate_Pad_Connecte( frame->GetBoard(), segment->m_End, masklayer );
2007-10-19 19:58:31 +00:00
if( pad != NULL )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
segment->end = pad;
type_end |= END_ON_PAD;
2007-08-10 19:14:51 +00:00
}
2007-10-19 19:58:31 +00:00
// if not connected to a pad, test if segment's START is connected to another track
// For via tests, an enhancement could to test if connected to 2 items on different layers.
// Currently a via must be connected to 2 items, taht can be on the same layer
int top_layer, bottom_layer;
2007-10-19 19:58:31 +00:00
if( (type_end & START_ON_PAD ) == 0 )
2007-08-10 19:14:51 +00:00
{
other = Locate_Piste_Connectee( segment, frame->GetBoard()->m_Track, NULL, START );
if( other == NULL ) // Test a connection to zones
{
if( segment->Type() != TYPE_VIA )
{
zone = frame->GetBoard()->HitTestForAnyFilledArea(segment->m_Start, segment->GetLayer() );
}
else
{
((SEGVIA*)segment)->ReturnLayerPair( &top_layer, &bottom_layer );
zone = frame->GetBoard()->HitTestForAnyFilledArea(segment->m_Start, top_layer, bottom_layer );
}
}
if( (other == NULL) && (zone == NULL) )
2007-08-10 19:14:51 +00:00
flag_erase |= 1;
else // segment, via or zone connected to this end
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
segment->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() == TYPE_VIA )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
// search for another segment following the via
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
segment->SetState( BUSY, ON );
2008-03-10 15:00:22 +00:00
SEGVIA* via = (SEGVIA*) other;
other = Locate_Piste_Connectee( via, frame->GetBoard()->m_Track,
2007-08-10 19:14:51 +00:00
NULL, START );
2007-10-19 19:58:31 +00:00
if( other == NULL )
{
via->ReturnLayerPair( &top_layer, &bottom_layer );
zone = frame->GetBoard()->HitTestForAnyFilledArea(via->m_Start, bottom_layer, top_layer );
}
if( (other == NULL) && (zone == NULL) )
2007-08-10 19:14:51 +00:00
flag_erase |= 2;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
segment->SetState( BUSY, OFF );
2007-08-10 19:14:51 +00:00
}
}
}
2007-10-19 19:58:31 +00:00
// if not connected to a pad, test if segment's END is connected to another track
if( (type_end & END_ON_PAD ) == 0 )
2007-08-10 19:14:51 +00:00
{
other = Locate_Piste_Connectee( segment, frame->GetBoard()->m_Track,
2007-08-10 19:14:51 +00:00
NULL, END );
if( other == NULL ) // Test a connection to zones
{
if( segment->Type() != TYPE_VIA )
zone = frame->GetBoard()->HitTestForAnyFilledArea(segment->m_End, segment->GetLayer() );
else
{
((SEGVIA*)segment)->ReturnLayerPair( &top_layer, &bottom_layer );
zone = frame->GetBoard()->HitTestForAnyFilledArea(segment->m_End,top_layer, bottom_layer );
}
}
if ( (other == NULL) && (zone == NULL) )
2007-08-10 19:14:51 +00:00
flag_erase |= 0x10;
2008-03-10 15:00:22 +00:00
else // segment, via or zone connected to this end
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
segment->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() == TYPE_VIA )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
// search for another segment following the via
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
segment->SetState( BUSY, ON );
2008-03-10 15:00:22 +00:00
SEGVIA* via = (SEGVIA*) other;
other = Locate_Piste_Connectee( via, frame->GetBoard()->m_Track,
2007-08-10 19:14:51 +00:00
NULL, END );
2007-10-19 19:58:31 +00:00
if( other == NULL )
{
via->ReturnLayerPair( &top_layer, &bottom_layer );
zone = frame->GetBoard()->HitTestForAnyFilledArea(via->m_End, bottom_layer, top_layer );
}
if( (other == NULL) && (zone == NULL) )
2007-08-10 19:14:51 +00:00
flag_erase |= 0x20;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
segment->SetState( BUSY, OFF );
2007-08-10 19:14:51 +00:00
}
}
}
if( flag_erase )
{
2007-10-19 19:58:31 +00:00
// update the pointer to start of the contiguous netcode group
if( segment == startNetcode )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
next = segment->Next();
startNetcode = next;
2007-08-10 19:14:51 +00:00
}
else
2007-10-19 19:58:31 +00:00
next = startNetcode;
2007-08-10 19:14:51 +00:00
2007-10-19 19:58:31 +00:00
// remove segment from screen and board
2007-10-15 03:26:38 +00:00
segment->Draw( frame->DrawPanel, DC, GR_XOR );
segment->DeleteStructure();
2008-03-10 15:00:22 +00:00
2007-10-19 19:58:31 +00:00
if( next == NULL )
2007-08-10 19:14:51 +00:00
break;
}
}
2007-05-06 16:03:28 +00:00
}
/************************************************************/
static void clean_segments( PCB_EDIT_FRAME* frame )
2007-05-06 16:03:28 +00:00
/************************************************************/
/* Delete null lenght segments, and intermediate points .. */
2007-05-06 16:03:28 +00:00
{
TRACK* segment, * nextsegment;
2007-10-19 19:58:31 +00:00
TRACK* other;
int ii;
int flag, no_inc;
2007-08-10 19:14:51 +00:00
wxString msg;
frame->DrawPanel->m_AbortRequest = FALSE;
// Delete null segments
for( segment = frame->GetBoard()->m_Track; segment; segment = nextsegment )
2007-08-10 19:14:51 +00:00
{
nextsegment = segment->Next();
2007-10-15 03:26:38 +00:00
if( !segment->IsNull() )
2007-08-10 19:14:51 +00:00
continue;
2009-02-26 00:37:04 +00:00
/* Length segment = 0; delete it */
2007-10-15 03:26:38 +00:00
segment->DeleteStructure();
2007-08-10 19:14:51 +00:00
}
/* Delete redundant segments */
for( segment = frame->GetBoard()->m_Track, ii = 0; segment; segment = segment->Next(), ii++ )
2007-08-10 19:14:51 +00:00
{
for( other = segment->Next(); other; other = nextsegment )
2007-08-10 19:14:51 +00:00
{
nextsegment = other->Next();
2007-08-10 19:14:51 +00:00
int erase = 0;
2007-10-19 19:58:31 +00:00
if( segment->Type() != other->Type() )
2007-08-10 19:14:51 +00:00
continue;
2008-03-10 15:00:22 +00:00
2007-10-19 19:58:31 +00:00
if( segment->GetLayer() != other->GetLayer() )
2007-08-10 19:14:51 +00:00
continue;
2008-03-10 15:00:22 +00:00
2007-10-19 19:58:31 +00:00
if( segment->GetNet() != other->GetNet() )
2007-08-10 19:14:51 +00:00
break;
2007-10-19 19:58:31 +00:00
if( segment->m_Start == other->m_Start )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
if( segment->m_End == other->m_End )
2007-08-10 19:14:51 +00:00
erase = 1;
}
2007-10-19 19:58:31 +00:00
if( segment->m_Start == other->m_End )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
if( segment->m_End == other->m_Start )
2007-08-10 19:14:51 +00:00
erase = 1;
}
/* Delete redundant point */
2007-08-10 19:14:51 +00:00
if( erase )
{
ii--;
2007-10-19 19:58:31 +00:00
other->DeleteStructure();
2007-08-10 19:14:51 +00:00
}
}
}
/* delete intermediate points */
2007-08-10 19:14:51 +00:00
ii = 0;
for( segment = frame->GetBoard()->m_Track; segment; segment = nextsegment )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
TRACK* segStart;
TRACK* segEnd;
2007-10-19 23:02:11 +00:00
TRACK* segDelete;
2007-08-10 19:14:51 +00:00
nextsegment = segment->Next();
if( frame->DrawPanel->m_AbortRequest )
return;
2007-08-10 19:14:51 +00:00
if( segment->Type() != TYPE_TRACK )
2007-08-10 19:14:51 +00:00
continue;
flag = no_inc = 0;
// search for a possible point that connects on the START point of the segment
2007-10-19 23:02:11 +00:00
for( segStart = segment->Next(); ; )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
segStart = Locate_Piste_Connectee( segment, segStart,
2007-08-10 19:14:51 +00:00
NULL, START );
2007-10-19 19:58:31 +00:00
if( segStart )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
// the two segments must have the same width
if( segment->m_Width != segStart->m_Width )
2007-08-10 19:14:51 +00:00
break;
2007-10-19 19:58:31 +00:00
// it cannot be a via
if( segStart->Type() != TYPE_TRACK )
2007-08-10 19:14:51 +00:00
break;
/* We must have only one segment connected */
2007-10-19 19:58:31 +00:00
segStart->SetState( BUSY, ON );
other = Locate_Piste_Connectee( segment, frame->GetBoard()->m_Track,
2007-08-10 19:14:51 +00:00
NULL, START );
2007-10-19 19:58:31 +00:00
segStart->SetState( BUSY, OFF );
2007-08-10 19:14:51 +00:00
2007-10-19 19:58:31 +00:00
if( other == NULL )
flag = 1; /* OK */
2008-03-10 15:00:22 +00:00
2007-08-10 19:14:51 +00:00
break;
}
break;
}
if( flag ) /* We have the starting point of the segment is connecte to an other segment */
2007-08-10 19:14:51 +00:00
{
segDelete = AlignSegment( frame->GetBoard(), segment, segStart, START );
2007-10-19 23:02:11 +00:00
if( segDelete )
2007-08-10 19:14:51 +00:00
{
no_inc = 1;
2007-10-19 23:02:11 +00:00
segDelete->DeleteStructure();
2007-08-10 19:14:51 +00:00
}
}
/* search for a possible point that connects on the END point of the segment: */
2007-10-19 23:02:11 +00:00
for( segEnd = segment->Next(); ; )
2007-08-10 19:14:51 +00:00
{
2007-10-19 23:02:11 +00:00
segEnd = Locate_Piste_Connectee( segment, segEnd, NULL, END );
2007-10-19 19:58:31 +00:00
if( segEnd )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
if( segment->m_Width != segEnd->m_Width )
2007-08-10 19:14:51 +00:00
break;
2008-03-10 15:00:22 +00:00
if( segEnd->Type() != TYPE_TRACK )
2007-08-10 19:14:51 +00:00
break;
/* We must have only one segment connected */
2007-10-19 19:58:31 +00:00
segEnd->SetState( BUSY, ON );
other = Locate_Piste_Connectee( segment, frame->GetBoard()->m_Track,
2007-08-10 19:14:51 +00:00
NULL, END );
2007-10-19 19:58:31 +00:00
segEnd->SetState( BUSY, OFF );
2008-03-10 15:00:22 +00:00
2007-10-19 19:58:31 +00:00
if( other == NULL )
flag |= 2; /* Ok */
2008-03-10 15:00:22 +00:00
2007-08-10 19:14:51 +00:00
break;
}
else
break;
}
if( flag & 2 ) /* We have the ending point of the segment is connecte to an other segment */
2007-08-10 19:14:51 +00:00
{
segDelete = AlignSegment( frame->GetBoard(), segment, segEnd, END );
2007-10-19 23:02:11 +00:00
if( segDelete )
2007-08-10 19:14:51 +00:00
{
2007-10-19 19:58:31 +00:00
no_inc = 1;
2007-10-19 23:02:11 +00:00
segDelete->DeleteStructure();
2007-08-10 19:14:51 +00:00
}
}
if( no_inc ) /* The current segment was modified, retry to merge it */
nextsegment = segment->Next();
2007-08-10 19:14:51 +00:00
}
return;
2007-05-06 16:03:28 +00:00
}
2007-08-10 19:14:51 +00:00
2007-05-06 16:03:28 +00:00
/****************************************************************************/
2007-08-10 19:14:51 +00:00
static TRACK* AlignSegment( BOARD* Pcb, TRACK* pt_ref, TRACK* pt_segm, int extremite )
2007-05-06 16:03:28 +00:00
/****************************************************************************/
/* Function used by clean_segments.
* Test alignement of pt_segm and pt_ref (which must have acommon 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)
2008-03-10 15:00:22 +00:00
* if the common end can be deleted, this function
* change the common point coordinate of the pt_ref segm
* (and therefore connect the 2 other ending points)
* and return pt_segm (which can be deleted).
* else return NULL
2007-08-10 19:14:51 +00:00
*/
2007-05-06 16:03:28 +00:00
{
2007-08-10 19:14:51 +00:00
int flag = 0;
2008-03-10 15:00:22 +00:00
int refdx = pt_ref->m_End.x - pt_ref->m_Start.x;
2007-10-19 19:58:31 +00:00
int refdy = pt_ref->m_End.y - pt_ref->m_Start.y;
2008-03-10 15:00:22 +00:00
int segmdx = pt_segm->m_End.x - pt_segm->m_Start.x;
2007-10-19 19:58:31 +00:00
int segmdy = pt_segm->m_End.y - pt_segm->m_Start.y;
2007-08-10 19:14:51 +00:00
// test for vertical alignment (easy to handle)
2007-08-10 19:14:51 +00:00
if( refdx == 0 )
{
if( segmdx != 0 )
return NULL;
else
flag = 1;
}
2008-03-10 15:00:22 +00:00
// test for horizontal alignment (easy to handle)
2007-08-10 19:14:51 +00:00
if( refdy == 0 )
{
if( segmdy != 0 )
return NULL;
else
flag = 2;
}
/* tst if alignement in other cases
* We must have refdy/refdx == (+/-)segmdy/segmdx, (i.e. same orientation) */
2007-08-10 19:14:51 +00:00
if( flag == 0 )
{
2007-10-19 19:58:31 +00:00
if( (refdy * segmdx != refdx * segmdy)
2007-10-15 03:26:38 +00:00
&& (refdy * segmdx != -refdx * segmdy) )
2007-08-10 19:14:51 +00:00
return NULL;
flag = 4;
}
/* Here we have 2 aligned segments:
2008-03-10 15:00:22 +00:00
We must change the pt_ref common point only if not on a pad
(this function) is called when thre 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
*/
2007-08-10 19:14:51 +00:00
if( extremite == START )
{
/* We do not have a pad */
2007-08-10 19:14:51 +00:00
if( Fast_Locate_Pad_Connecte( Pcb, pt_ref->m_Start,
2007-08-23 04:28:46 +00:00
g_TabOneLayerMask[pt_ref->GetLayer()] ) )
2007-08-10 19:14:51 +00:00
return NULL;
2008-03-10 15:00:22 +00:00
/* change the common point coordinate of pt_segm tu use the other point
of pt_segm (pt_segm will be removed later) */
2007-10-19 19:58:31 +00:00
if( pt_ref->m_Start == pt_segm->m_Start )
2007-08-10 19:14:51 +00:00
{
2008-03-10 15:00:22 +00:00
pt_ref->m_Start = pt_segm->m_End;
2007-08-10 19:14:51 +00:00
return pt_segm;
}
else
2007-08-10 19:14:51 +00:00
{
2008-03-10 15:00:22 +00:00
pt_ref->m_Start = pt_segm->m_Start;
2007-08-10 19:14:51 +00:00
return pt_segm;
}
}
else /* extremite == END */
{
/* We do not have a pad */
2008-03-10 15:00:22 +00:00
if( Fast_Locate_Pad_Connecte( Pcb, pt_ref->m_End,
2007-10-19 19:58:31 +00:00
g_TabOneLayerMask[pt_ref->GetLayer()] ) )
2007-08-10 19:14:51 +00:00
return NULL;
2008-03-10 15:00:22 +00:00
/* change the common point coordinate of pt_segm tu use the other point
of pt_segm (pt_segm will be removed later) */
2007-08-10 19:14:51 +00:00
if( pt_ref->m_End == pt_segm->m_Start )
{
pt_ref->m_End = pt_segm->m_End;
return pt_segm;
}
else
2007-08-10 19:14:51 +00:00
{
pt_ref->m_End = pt_segm->m_Start;
return pt_segm;
}
}
return NULL;
2007-05-06 16:03:28 +00:00
}
/**
* Function RemoveMisConnectedTracks
2008-03-10 15:00:22 +00:00
* finds all track segments which are mis-connected (to more than one net).
* When such a bad segment is found, mark it as needing to be removed.
* and remove all tracks having at least one flagged segment.
* @param aDC = the current device context (can be NULL)
* @return true if any change is made
2007-08-10 19:14:51 +00:00
*/
bool PCB_EDIT_FRAME::RemoveMisConnectedTracks( wxDC* aDC )
2007-05-06 16:03:28 +00:00
{
2007-10-15 03:26:38 +00:00
TRACK* segment;
TRACK* other;
TRACK* next;
2007-08-10 19:14:51 +00:00
int net_code_s, net_code_e;
bool isModified = false;
2007-08-10 19:14:51 +00:00
for( segment = GetBoard()->m_Track; segment; segment = (TRACK*) segment->Next() )
2007-08-10 19:14:51 +00:00
{
2007-10-15 03:26:38 +00:00
segment->SetState( FLAG0, OFF );
2007-08-10 19:14:51 +00:00
2007-10-15 03:26:38 +00:00
// find the netcode for segment using anything connected to the "start" of "segment"
2007-08-10 19:14:51 +00:00
net_code_s = -1;
if( segment->start && segment->start->Type()==TYPE_PAD )
2007-10-15 03:26:38 +00:00
{
// get the netcode of the pad to propagate.
net_code_s = ((D_PAD*)(segment->start))->GetNet();
}
2007-08-10 19:14:51 +00:00
else
{
other = Locate_Piste_Connectee( segment, GetBoard()->m_Track,
2007-08-10 19:14:51 +00:00
NULL, START );
2007-10-15 03:26:38 +00:00
if( other )
net_code_s = other->GetNet();
2007-08-10 19:14:51 +00:00
}
2008-03-10 15:00:22 +00:00
2007-08-10 19:14:51 +00:00
if( net_code_s < 0 )
2007-10-15 03:26:38 +00:00
continue; // the "start" of segment is not connected
2007-08-10 19:14:51 +00:00
2007-10-15 03:26:38 +00:00
// find the netcode for segment using anything connected to the "end" of "segment"
2007-08-10 19:14:51 +00:00
net_code_e = -1;
if( segment->end && segment->end->Type()==TYPE_PAD )
2007-10-15 03:26:38 +00:00
{
net_code_e = ((D_PAD*)(segment->end))->GetNet();
}
2007-08-10 19:14:51 +00:00
else
{
other = Locate_Piste_Connectee( segment, GetBoard()->m_Track,
2007-08-10 19:14:51 +00:00
NULL, END );
2007-10-15 03:26:38 +00:00
if( other )
net_code_e = other->GetNet();
2007-08-10 19:14:51 +00:00
}
if( net_code_e < 0 )
2007-10-15 03:26:38 +00:00
continue; // the "end" of segment is not connected
2007-08-10 19:14:51 +00:00
// Netcodes do not agree, so mark the segment as needed to be removed
2007-08-10 19:14:51 +00:00
if( net_code_s != net_code_e )
{
2007-10-15 03:26:38 +00:00
segment->SetState( FLAG0, ON );
2007-08-10 19:14:51 +00:00
}
}
// Remove flagged segments
for( segment = GetBoard()->m_Track; segment; segment = next )
2007-08-10 19:14:51 +00:00
{
2007-10-15 03:26:38 +00:00
next = (TRACK*) segment->Next();
2008-03-10 15:00:22 +00:00
if( segment->GetState( FLAG0 ) ) // Ssegment is flagged to be removed
2007-08-10 19:14:51 +00:00
{
2007-10-15 03:26:38 +00:00
segment->SetState( FLAG0, OFF );
isModified = true;
GetBoard()->m_Status_Pcb = 0;
Remove_One_Track( aDC, segment );
// the current segment could be deleted, so restart to the beginning
next = GetBoard()->m_Track;
2007-08-10 19:14:51 +00:00
}
}
return isModified;
2007-05-06 16:03:28 +00:00
}
2007-12-22 07:13:27 +00:00
#if 0
2007-05-06 16:03:28 +00:00
/***************************************************************/
static void Gen_Raccord_Track( PCB_EDIT_FRAME* frame, wxDC* DC )
2007-05-06 16:03:28 +00:00
/***************************************************************/
2007-10-15 03:26:38 +00:00
/**
* Function Gen_Raccord_Track
* tests the ends of segments. If and end is on a segment of other track, but not
* on other's end, the other segment is cut into 2, the point of cut being the end of
2008-03-10 15:00:22 +00:00
* segment first being operated on. This is done so that the subsequent tests
2007-10-15 03:26:38 +00:00
* of connection, which do not test segment overlaps, will see this continuity.
*/
2007-05-06 16:03:28 +00:00
{
2007-10-15 03:26:38 +00:00
TRACK* segment;
TRACK* other;
2007-08-10 19:14:51 +00:00
int nn = 0;
int masquelayer;
int ii, percent, oldpercent;
wxString msg;
frame->Affiche_Message( wxT( "Gen Raccords sur Pistes:" ) );
if( frame->GetBoard()->GetNumSegmTrack() == 0 )
2007-08-10 19:14:51 +00:00
return;
frame->DrawPanel->m_AbortRequest = FALSE;
oldpercent = -1; ii = 0;
for( segment = frame->GetBoard()->m_Track; segment; segment = segment->Next() )
2007-08-10 19:14:51 +00:00
{
2007-10-15 03:26:38 +00:00
// display activity
2007-08-10 19:14:51 +00:00
ii++;
percent = (100 * ii) / frame->GetBoard()->m_Track.GetCount();
2007-08-10 19:14:51 +00:00
if( percent != oldpercent )
{
frame->DisplayActivity( percent, wxT( "Tracks: " ) );
oldpercent = percent;
2008-03-10 15:00:22 +00:00
msg.Printf( wxT( "%d" ), frame->GetBoard()->m_Track.GetCount() );
frame->MsgPanel->SetMessage( POS_AFF_MAX, wxT( "Max" ), msg, GREEN );
2008-03-10 15:00:22 +00:00
2007-08-10 19:14:51 +00:00
msg.Printf( wxT( "%d" ), ii );
frame->MsgPanel->SetMessage( POS_AFF_NUMSEGM, wxT( "Segm" ), msg, CYAN );
2007-08-10 19:14:51 +00:00
}
if( frame->DrawPanel->m_AbortRequest )
return;
2007-10-15 03:26:38 +00:00
masquelayer = segment->ReturnMaskLayer();
2007-08-10 19:14:51 +00:00
2007-10-15 03:26:38 +00:00
// look at the "start" of the "segment"
for( other = frame->GetBoard()->m_Track; other; other = other->Next() )
2007-08-10 19:14:51 +00:00
{
2007-10-15 03:26:38 +00:00
TRACK* newTrack;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
other = Locate_Pistes( other, segment->m_Start, masquelayer );
if( other == NULL )
2007-08-10 19:14:51 +00:00
break;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
if( other == segment )
2007-08-10 19:14:51 +00:00
continue;
2008-03-10 15:00:22 +00:00
if( other->Type() == TYPE_VIA )
2007-08-10 19:14:51 +00:00
continue;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
if( segment->m_Start == other->m_Start )
2007-08-10 19:14:51 +00:00
continue;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
if( segment->m_Start == other->m_End )
2007-08-10 19:14:51 +00:00
continue;
2007-10-15 03:26:38 +00:00
// Test if the "end" of this segment is already connected to other
if( segment->m_End == other->m_Start )
2007-08-10 19:14:51 +00:00
continue;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
if( segment->m_End == other->m_End )
2007-08-10 19:14:51 +00:00
continue;
2007-10-15 03:26:38 +00:00
other->Draw( frame->DrawPanel, DC, GR_XOR );
2008-03-10 15:00:22 +00:00
2007-08-10 19:14:51 +00:00
nn++;
msg.Printf( wxT( "%d" ), nn );
frame->MsgPanel->SetMessage( POS_AFF_VAR, wxT( "New <" ), msg, YELLOW );
2007-10-15 03:26:38 +00:00
2008-03-10 15:00:22 +00:00
// create a new segment and insert it next to "other", then shorten other.
2007-10-15 03:26:38 +00:00
newTrack = other->Copy();
frame->GetBoard()->m_Track.Insert( newTrack, other->Next() );
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
other->m_End = segment->m_Start;
newTrack->m_Start = segment->m_Start;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
Trace_Une_Piste( frame->DrawPanel, DC, other, 2, GR_OR );
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
// skip forward one, skipping the newTrack
other = newTrack;
2007-08-10 19:14:51 +00:00
}
2007-10-15 03:26:38 +00:00
// look at the "end" of the "segment"
for( other = frame->GetBoard()->m_Track; other; other = other->Next() )
2007-08-10 19:14:51 +00:00
{
2007-10-15 03:26:38 +00:00
TRACK* newTrack;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
other = Locate_Pistes( other, segment->m_End, masquelayer );
if( other == NULL )
2007-08-10 19:14:51 +00:00
break;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
if( other == segment )
2007-08-10 19:14:51 +00:00
continue;
2008-03-10 15:00:22 +00:00
if( other->Type() == TYPE_VIA )
2007-08-10 19:14:51 +00:00
continue;
2007-10-15 03:26:38 +00:00
if( segment->m_End == other->m_Start )
2007-08-10 19:14:51 +00:00
continue;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
if( segment->m_End == other->m_End )
2007-08-10 19:14:51 +00:00
continue;
2007-10-15 03:26:38 +00:00
if( segment->m_Start == other->m_Start )
2007-08-10 19:14:51 +00:00
continue;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
if( segment->m_Start == other->m_End )
2007-08-10 19:14:51 +00:00
continue;
2007-10-15 03:26:38 +00:00
other->Draw( frame->DrawPanel, DC, GR_XOR );
2007-08-10 19:14:51 +00:00
2008-03-10 15:00:22 +00:00
nn++;
2007-10-15 03:26:38 +00:00
msg.Printf( wxT( "%d" ), nn );
frame->MsgPanel->SetMessage( POS_AFF_VAR, wxT( "New >" ), msg, YELLOW );
2008-03-10 15:00:22 +00:00
// create a new segment and insert it next to "other", then shorten other.
2007-10-15 03:26:38 +00:00
newTrack = other->Copy();
frame->GetBoard()->m_Track.Insert( newTrack, other->Next() );
2007-10-15 03:26:38 +00:00
2008-03-10 15:00:22 +00:00
other->m_End = segment->m_End;
newTrack->m_Start = segment->m_End;
2007-10-15 03:26:38 +00:00
Trace_Une_Piste( frame->DrawPanel, DC, other, 2, GR_OR );
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
// skip forward one, skipping the newTrack
other = newTrack;
2007-08-10 19:14:51 +00:00
}
}
2007-05-06 16:03:28 +00:00
}
2007-12-22 07:13:27 +00:00
#endif
#if defined(CONN2PAD_ENBL)
2007-08-10 19:14:51 +00:00
2007-10-19 23:02:11 +00:00
/**
* Function ConnectDanglingEndToPad
* looks for vias which have no netcode and which are in electrical contact
* with a track to the degree that the track's end point falls on the via.
* Note that this is not a rigorous electrical check, but is better than
* testing for the track endpoint equaling the via center. When such a via
* is found, then add a small track to bridge from the overlapping track to
2008-03-10 15:00:22 +00:00
* the via and change the via's netcode so that subsequent continuity checks
* can be done with the faster equality algorithm.
2007-10-19 23:02:11 +00:00
*/
static void ConnectDanglingEndToVia( BOARD* pcb )
{
for( TRACK* track = pcb->m_Track; track; track = track->Next() )
{
SEGVIA* via;
2008-03-10 15:00:22 +00:00
if( track->Type()!=TYPE_VIA || (via = (SEGVIA*)track)->GetNet()!=0 )
2007-10-19 23:02:11 +00:00
continue;
for( TRACK* other = pcb->m_Track; other; other = other->Next() )
{
if( other == track )
continue;
if( !via->IsOnLayer( other->GetLayer() ) )
continue;
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
// if the other track's m_End does not match the via position, and the track's m_Start is
// within the bounds of the via, and the other track has no start
2007-12-01 03:42:52 +00:00
if( other->m_End!=via->GetPosition() && via->HitTest( other->m_Start ) && !other->start )
2007-10-19 23:02:11 +00:00
{
TRACK* newTrack = other->Copy();
pcb->m_Track.Insert( newTrack, other->Next() );
2008-03-10 15:00:22 +00:00
2007-12-01 03:42:52 +00:00
newTrack->m_End = via->GetPosition();
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
newTrack->start = other;
newTrack->end = via;
other->start = newTrack;
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
via->SetNet( other->GetNet() );
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
if( !via->start )
via->start = other;
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
if( !via->end )
via->end = other;
}
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
// if the other track's m_Start does not match the via position, and the track's m_End is
// within the bounds of the via, and the other track has no end
2008-03-10 15:00:22 +00:00
else if( other->m_Start!=via->GetPosition() && via->HitTest( other->m_End ) && !other->end )
2007-10-19 23:02:11 +00:00
{
TRACK* newTrack = other->Copy();
pcb->m_Track.Insert( newTrack, other->Next() );
2008-03-10 15:00:22 +00:00
2007-12-01 03:42:52 +00:00
newTrack->m_Start = via->GetPosition();
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
newTrack->start = via;
newTrack->end = other;
other->end = newTrack;
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
via->SetNet( other->GetNet() );
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
if( !via->start )
via->start = other;
2008-03-10 15:00:22 +00:00
2007-10-19 23:02:11 +00:00
if( !via->end )
via->end = other;
}
}
}
}
/***************************************************************/
void ConnectDanglingEndToPad( PCB_EDIT_FRAME* frame, wxDC* DC )
/**************************************************************/
2007-08-10 19:14:51 +00:00
2007-10-15 03:26:38 +00:00
/**
* Function ConnectDanglingEndToPad
* possibly adds a segment to the end of any and all tracks if their end is not exactly
2008-03-10 15:00:22 +00:00
* connected into the center of the pad. This allows faster control of
2007-10-15 03:26:38 +00:00
* connections.
2007-08-10 19:14:51 +00:00
*/
2007-05-06 16:03:28 +00:00
{
2007-10-15 03:26:38 +00:00
TRACK* segment;
int nb_new_piste = 0;
2007-08-10 19:14:51 +00:00
wxString msg;
2008-03-10 15:00:22 +00:00
2007-08-10 19:14:51 +00:00
frame->DrawPanel->m_AbortRequest = FALSE;
for( segment = frame->GetBoard()->m_Track; segment; segment = segment->Next() )
2007-08-10 19:14:51 +00:00
{
2007-10-15 03:26:38 +00:00
D_PAD* pad;
2008-03-10 15:00:22 +00:00
if( frame->DrawPanel->m_AbortRequest )
return;
2007-08-10 19:14:51 +00:00
pad = Locate_Pad_Connecte( frame->GetBoard(), segment, START );
2007-10-15 03:26:38 +00:00
if( pad )
2008-03-10 15:00:22 +00:00
{
2007-10-15 03:26:38 +00:00
// test if the track is not precisely starting on the found pad
if( segment->m_Start != pad->m_Pos )
2007-08-10 19:14:51 +00:00
{
if( Locate_Piste_Connectee( segment, frame->GetBoard()->m_Track,
2007-08-10 19:14:51 +00:00
NULL, START ) == NULL )
{
2007-10-15 03:26:38 +00:00
TRACK* newTrack = segment->Copy();
frame->GetBoard()->m_Track.Insert( newTrack, segment->Next() );
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
newTrack->m_End = pad->m_Pos;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
newTrack->start = segment;
newTrack->end = pad;
2008-03-10 15:00:22 +00:00
2007-08-10 19:14:51 +00:00
nb_new_piste++;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
newTrack->Draw( frame->DrawPanel, DC, GR_OR );
2007-08-10 19:14:51 +00:00
}
}
}
pad = Locate_Pad_Connecte( frame->GetBoard(), segment, END );
2007-10-15 03:26:38 +00:00
if( pad )
2008-03-10 15:00:22 +00:00
{
2007-10-15 03:26:38 +00:00
// test if the track is not precisely ending on the found pad
if( segment->m_End != pad->m_Pos )
2007-08-10 19:14:51 +00:00
{
if( Locate_Piste_Connectee( segment, frame->GetBoard()->m_Track,
2007-08-10 19:14:51 +00:00
NULL, END ) == NULL )
{
2007-10-15 03:26:38 +00:00
TRACK* newTrack = segment->Copy();
frame->GetBoard()->m_Track.Insert( newTrack, segment->Next() );
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
newTrack->m_Start = pad->m_Pos;
2008-03-10 15:00:22 +00:00
2007-10-15 03:26:38 +00:00
newTrack->start = pad;
newTrack->end = segment;
2007-08-10 19:14:51 +00:00
nb_new_piste++;
}
}
}
}
2007-05-06 16:03:28 +00:00
}
#endif