1114 lines
38 KiB
C++
1114 lines
38 KiB
C++
/***************************************/
|
|
/* AUTOROUTAGE PCB : routine de calcul */
|
|
/***************************************/
|
|
|
|
/* fichier SOLVE.Cpp */
|
|
|
|
#include "fctsys.h"
|
|
#include "gr_basic.h"
|
|
#include "common.h"
|
|
#include "class_drawpanel.h"
|
|
#include "confirm.h"
|
|
|
|
#include "pcbnew.h"
|
|
#include "autorout.h"
|
|
#include "zones.h"
|
|
#include "protos.h"
|
|
|
|
#include <fcntl.h>
|
|
#include "cell.h"
|
|
|
|
/* Routines definies ici : */
|
|
static int Autoroute_One_Track( WinEDA_PcbFrame* pcbframe, wxDC* DC, int two_sides, int row_source,
|
|
int col_source,
|
|
int row_target, int col_target, RATSNEST_ITEM* pt_chevelu );
|
|
static int Retrace( WinEDA_PcbFrame* pcbframe, wxDC* DC, int, int, int, int, int, int net_code );
|
|
static void OrCell_Trace( BOARD* pcb, int col, int row, int side, int orient, int current_net_code );
|
|
static void Place_Piste_en_Buffer( WinEDA_PcbFrame* pcbframe, wxDC* DC );
|
|
|
|
/* Variables locales : */
|
|
static int segm_oX, segm_oY;
|
|
static int segm_fX, segm_fY; /* Origine et fin de la piste en cours de trace */
|
|
static RATSNEST_ITEM* pt_cur_ch;
|
|
static int Ncurrent; /* measures of progress */
|
|
|
|
|
|
#define NOSUCCESS 0
|
|
#define STOP_FROM_ESC -1
|
|
#define ERR_MEMORY -2
|
|
#define SUCCESS 1
|
|
#define TRIVIAL_SUCCESS 2
|
|
|
|
/*
|
|
** visit neighboring cells like this (where [9] is on the other side):
|
|
**
|
|
** +---+---+---+
|
|
** | 1 | 2 | 3 |
|
|
** +---+---+---+
|
|
** | 4 |[9]| 5 |
|
|
** +---+---+---+
|
|
** | 6 | 7 | 8 |
|
|
** +---+---+---+
|
|
*/
|
|
|
|
/* for visiting neighbors on the same side: increments/decrements des coord
|
|
* [][0] = row, []{1] = col a ajouter aux coord du point central pour
|
|
* obtenir les coord des 8 points voisins */
|
|
static int delta[8][2] = {
|
|
{ 1, -1 }, /* northwest */
|
|
{ 1, 0 }, /* north */
|
|
{ 1, 1 }, /* northeast */
|
|
{ 0, -1 }, /* west */
|
|
{ 0, 1 }, /* east */
|
|
{ -1, -1 }, /* southwest */
|
|
{ -1, 0 }, /* south */
|
|
{ -1, 1 } /* southeast */
|
|
};
|
|
|
|
static int ndir[8] = { /* for building paths back to source */
|
|
FROM_SOUTHEAST, FROM_SOUTH, FROM_SOUTHWEST,
|
|
FROM_EAST, FROM_WEST,
|
|
FROM_NORTHEAST, FROM_NORTH, FROM_NORTHWEST
|
|
};
|
|
|
|
/* blocking masks for neighboring cells */
|
|
#define BLOCK_NORTHEAST ( DIAG_NEtoSW | BENT_StoNE | BENT_WtoNE \
|
|
| ANGLE_NEtoSE | ANGLE_NWtoNE \
|
|
| SHARP_NtoNE | SHARP_EtoNE | HOLE )
|
|
#define BLOCK_SOUTHEAST ( DIAG_SEtoNW | BENT_NtoSE | BENT_WtoSE \
|
|
| ANGLE_NEtoSE | ANGLE_SEtoSW \
|
|
| SHARP_EtoSE | SHARP_StoSE | HOLE )
|
|
#define BLOCK_SOUTHWEST ( DIAG_NEtoSW | BENT_NtoSW | BENT_EtoSW \
|
|
| ANGLE_SEtoSW | ANGLE_SWtoNW \
|
|
| SHARP_StoSW | SHARP_WtoSW | HOLE )
|
|
#define BLOCK_NORTHWEST ( DIAG_SEtoNW | BENT_EtoNW | BENT_StoNW \
|
|
| ANGLE_SWtoNW | ANGLE_NWtoNE \
|
|
| SHARP_WtoNW | SHARP_NtoNW | HOLE )
|
|
#define BLOCK_NORTH ( LINE_VERTICAL | BENT_NtoSE | BENT_NtoSW \
|
|
| BENT_EtoNW | BENT_WtoNE \
|
|
| BENT_StoNE | BENT_StoNW \
|
|
| CORNER_NORTHEAST | CORNER_NORTHWEST \
|
|
| ANGLE_NEtoSE | ANGLE_SWtoNW | ANGLE_NWtoNE \
|
|
| DIAG_NEtoSW | DIAG_SEtoNW \
|
|
| SHARP_NtoNE | SHARP_NtoNW \
|
|
| SHARP_EtoNE | SHARP_WtoNW | HOLE )
|
|
#define BLOCK_EAST ( LINE_HORIZONTAL | BENT_EtoSW | BENT_EtoNW \
|
|
| BENT_NtoSE | BENT_StoNE \
|
|
| BENT_WtoNE | BENT_WtoSE \
|
|
| CORNER_NORTHEAST | CORNER_SOUTHEAST \
|
|
| ANGLE_NEtoSE | ANGLE_SEtoSW | ANGLE_NWtoNE \
|
|
| DIAG_NEtoSW | DIAG_SEtoNW \
|
|
| SHARP_EtoNE | SHARP_EtoSE \
|
|
| SHARP_NtoNE | SHARP_StoSE | HOLE )
|
|
#define BLOCK_SOUTH ( LINE_VERTICAL | BENT_StoNE | BENT_StoNW \
|
|
| BENT_EtoSW | BENT_WtoSE \
|
|
| BENT_NtoSE | BENT_NtoSW \
|
|
| CORNER_SOUTHEAST | CORNER_SOUTHWEST \
|
|
| ANGLE_NEtoSE | ANGLE_SWtoNW | ANGLE_SEtoSW \
|
|
| DIAG_NEtoSW | DIAG_SEtoNW \
|
|
| SHARP_StoSE | SHARP_StoSW \
|
|
| SHARP_EtoSE | SHARP_WtoSW | HOLE )
|
|
#define BLOCK_WEST ( LINE_HORIZONTAL | BENT_WtoNE | BENT_WtoSE \
|
|
| BENT_NtoSW | BENT_StoNW \
|
|
| BENT_EtoSW | BENT_EtoNW \
|
|
| CORNER_SOUTHWEST | CORNER_NORTHWEST \
|
|
| ANGLE_SWtoNW | ANGLE_SEtoSW | ANGLE_NWtoNE \
|
|
| DIAG_NEtoSW | DIAG_SEtoNW \
|
|
| SHARP_WtoSW | SHARP_WtoNW \
|
|
| SHARP_NtoNW | SHARP_StoSW | HOLE )
|
|
|
|
struct block
|
|
{
|
|
int r1, c1;
|
|
long b1;
|
|
int r2, c2;
|
|
long b2;
|
|
};
|
|
|
|
/* blocking masks for diagonal traces */
|
|
static struct block blocking[8] =
|
|
{ {
|
|
0, -1,
|
|
BLOCK_NORTHEAST,
|
|
1, 0,
|
|
BLOCK_SOUTHWEST
|
|
},
|
|
{
|
|
0, 0, 0,
|
|
0, 0, 0
|
|
},
|
|
{
|
|
1, 0,
|
|
BLOCK_SOUTHEAST,
|
|
0, 1,
|
|
BLOCK_NORTHWEST
|
|
},
|
|
{
|
|
0, 0, 0,
|
|
0, 0, 0
|
|
},
|
|
{
|
|
0, 0, 0,
|
|
0, 0, 0
|
|
},
|
|
{
|
|
0, -1,
|
|
BLOCK_SOUTHEAST,
|
|
-1, 0,
|
|
BLOCK_NORTHWEST
|
|
},
|
|
{
|
|
0, 0, 0,
|
|
0, 0, 0
|
|
},
|
|
{
|
|
-1, 0,
|
|
BLOCK_NORTHEAST,
|
|
0, 1,
|
|
BLOCK_SOUTHWEST
|
|
} };
|
|
|
|
/* mask for hole-related blocking effects */
|
|
static struct
|
|
{
|
|
long trace;
|
|
int present;
|
|
} selfok2[8] = {
|
|
{ HOLE_NORTHWEST, 0 },
|
|
{ HOLE_NORTH, 0 },
|
|
{ HOLE_NORTHEAST, 0 },
|
|
{ HOLE_WEST, 0 },
|
|
{ HOLE_EAST, 0 },
|
|
{ HOLE_SOUTHWEST, 0 },
|
|
{ HOLE_SOUTH, 0 },
|
|
{ HOLE_SOUTHEAST, 0 }
|
|
};
|
|
|
|
static long newmask[8] = { /* patterns to mask out in neighbor cells */
|
|
0, CORNER_NORTHWEST | CORNER_NORTHEAST,
|
|
0,
|
|
CORNER_NORTHWEST | CORNER_SOUTHWEST, CORNER_NORTHEAST | CORNER_SOUTHEAST,
|
|
0, CORNER_SOUTHWEST | CORNER_SOUTHEAST,
|
|
0
|
|
};
|
|
|
|
|
|
/* Macro d'affichage de l'activite du routeur; */
|
|
#define AFFICHE_ACTIVITE_ROUTE \
|
|
msg.Printf( wxT("Activity: Open %d Closed %d Moved %d"), OpenNodes, ClosNodes, MoveNodes); \
|
|
pcbframe->Affiche_Message(msg);
|
|
|
|
/********************************************************/
|
|
int WinEDA_PcbFrame::Solve( wxDC* DC, int two_sides )
|
|
/********************************************************/
|
|
|
|
/* route all traces
|
|
* Return: 1 si OK
|
|
* -1 si Escape (arret en cours de routage) demande
|
|
* -2 si defaut alloc memoire
|
|
*/
|
|
|
|
{
|
|
int current_net_code;
|
|
int row_source, col_source, row_target, col_target;
|
|
int success, nbsucces = 0, nbunsucces = 0;
|
|
NETINFO_ITEM* net;
|
|
bool stop = FALSE;
|
|
wxString msg;
|
|
|
|
DrawPanel->m_AbortRequest = FALSE;
|
|
DrawPanel->m_AbortEnable = TRUE;
|
|
|
|
Ncurrent = 0;
|
|
MsgPanel->EraseMsgBox();
|
|
msg.Printf( wxT( "%d " ), GetBoard()->m_NbNoconnect );
|
|
Affiche_1_Parametre( this, 72, wxT( "NoConn" ), msg, CYAN );
|
|
|
|
|
|
/* go until no more work to do */
|
|
GetWork( &row_source, &col_source, ¤t_net_code,
|
|
&row_target, &col_target, &pt_cur_ch ); // 1er chevelu a router
|
|
|
|
for( ; row_source != ILLEGAL; GetWork( &row_source, &col_source,
|
|
¤t_net_code, &row_target, &col_target,
|
|
&pt_cur_ch ) )
|
|
{
|
|
/* Tst demande d'arret de routage ( key ESCAPE actionnee ) */
|
|
wxYield();
|
|
if( DrawPanel->m_AbortRequest )
|
|
{
|
|
if( IsOK( this, _( "Abort routing?" ) ) )
|
|
{
|
|
success = STOP_FROM_ESC;
|
|
stop = TRUE;
|
|
break;
|
|
}
|
|
else
|
|
DrawPanel->m_AbortRequest = 0;
|
|
}
|
|
|
|
Ncurrent++;
|
|
net = GetBoard()->FindNet( current_net_code );
|
|
if( net )
|
|
{
|
|
msg.Printf( wxT( "[%8.8s]" ), net->GetNetname().GetData() );
|
|
Affiche_1_Parametre( this, 1, wxT( "Net route" ), msg, BROWN );
|
|
msg.Printf( wxT( "%d / %d" ), Ncurrent, Ntotal );
|
|
Affiche_1_Parametre( this, 12, wxT( "Activity" ), msg, BROWN );
|
|
}
|
|
|
|
pt_cur_ch = pt_cur_ch;
|
|
segm_oX = GetBoard()->m_BoundaryBox.m_Pos.x + (g_GridRoutingSize * col_source);
|
|
segm_oY = GetBoard()->m_BoundaryBox.m_Pos.y + (g_GridRoutingSize * row_source);
|
|
segm_fX = GetBoard()->m_BoundaryBox.m_Pos.x + (g_GridRoutingSize * col_target);
|
|
segm_fY = GetBoard()->m_BoundaryBox.m_Pos.y + (g_GridRoutingSize * row_target);
|
|
|
|
/* Affiche Liaison */
|
|
GRLine( &DrawPanel->m_ClipBox, DC, segm_oX, segm_oY, segm_fX, segm_fY, 0, WHITE | GR_XOR );
|
|
pt_cur_ch->m_PadStart->Draw( DrawPanel, DC, GR_OR | GR_SURBRILL );
|
|
pt_cur_ch->m_PadEnd->Draw( DrawPanel, DC, GR_OR | GR_SURBRILL );
|
|
|
|
success = Autoroute_One_Track( this, DC, two_sides, row_source, col_source,
|
|
row_target, col_target, pt_cur_ch );
|
|
|
|
switch( success )
|
|
{
|
|
case NOSUCCESS:
|
|
pt_cur_ch->m_Status |= CH_UNROUTABLE;
|
|
nbunsucces++;
|
|
break;
|
|
|
|
case STOP_FROM_ESC:
|
|
stop = TRUE;
|
|
break;
|
|
|
|
case ERR_MEMORY:
|
|
stop = TRUE;
|
|
break;
|
|
|
|
default:
|
|
nbsucces++;
|
|
break;
|
|
}
|
|
|
|
msg.Printf( wxT( "%d " ), nbsucces );
|
|
Affiche_1_Parametre( this, 22, wxT( "Ok" ), msg, GREEN );
|
|
msg.Printf( wxT( "%d " ), nbunsucces );
|
|
Affiche_1_Parametre( this, 30, wxT( "Fail" ), msg, RED );
|
|
msg.Printf( wxT( "%d " ), GetBoard()->m_NbNoconnect );
|
|
Affiche_1_Parametre( this, 38, wxT( "NoConn" ), msg, CYAN );
|
|
|
|
/* Effacement des affichages de routage sur l'ecran */
|
|
pt_cur_ch->m_PadStart->Draw( DrawPanel, DC, GR_AND );
|
|
pt_cur_ch->m_PadEnd->Draw( DrawPanel, DC, GR_AND );
|
|
|
|
if( stop )
|
|
break;
|
|
}
|
|
|
|
DrawPanel->m_AbortEnable = FALSE;
|
|
|
|
return SUCCESS;
|
|
}
|
|
|
|
|
|
/**********************************************************************************/
|
|
static int Autoroute_One_Track( WinEDA_PcbFrame* pcbframe, wxDC* DC,
|
|
int two_sides, int row_source, int col_source,
|
|
int row_target, int col_target, RATSNEST_ITEM* pt_chevelu )
|
|
/**********************************************************************************/
|
|
|
|
/* Route une piste du BOARD.
|
|
* Parametres:
|
|
* 1 face / 2 faces ( 0 / 1)
|
|
* coord source (row,col)
|
|
* coord destination (row,col)
|
|
* net_code
|
|
* pointeur sur le chevelu de reference
|
|
*
|
|
* Retourne :
|
|
* SUCCESS si route trouvee
|
|
* TRIVIAL_SUCCESS si pads connectes par superposition ( pas de piste a tirer)
|
|
* NOSUCCESS si echec
|
|
* STOP_FROM_ESC si Escape demande
|
|
* ERR_MEMORY defaut alloc RAM
|
|
*/
|
|
{
|
|
int r, c, side, d, apx_dist, nr, nc;
|
|
int result, skip;
|
|
int i;
|
|
long curcell, newcell, buddy, lastopen, lastclos, lastmove;
|
|
int newdist, olddir, _self;
|
|
int current_net_code;
|
|
int marge, via_marge;
|
|
int pad_masque_layer_s; /* Masque des couches appartenant au pad de depart */
|
|
int pad_masque_layer_e; /* Masque des couches appartenant au pad d'arrivee */
|
|
int masque_layer_TOP = g_TabOneLayerMask[Route_Layer_TOP];
|
|
int masque_layer_BOTTOM = g_TabOneLayerMask[Route_Layer_BOTTOM];
|
|
int masque_layers; /* Masque des 2 couches de routage */
|
|
int tab_mask[2]; /* permet le calcul du Masque de la couche en cours
|
|
* de tst (side = TOP ou BOTTOM)*/
|
|
int start_mask_layer = 0;
|
|
wxString msg;
|
|
|
|
wxBusyCursor dummy_cursor; // Set an hourglass cursor while routing a track
|
|
|
|
result = NOSUCCESS;
|
|
|
|
marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentTrackWidth / 2);
|
|
via_marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentViaSize / 2);
|
|
|
|
/* clear direction flags */
|
|
i = Nrows * Ncols * sizeof(char);
|
|
memset( Board.m_DirSide[TOP], FROM_NOWHERE, i );
|
|
memset( Board.m_DirSide[BOTTOM], FROM_NOWHERE, i );
|
|
|
|
lastopen = lastclos = lastmove = 0;
|
|
|
|
/* Init tab_masque[side] pour tests de fin de routage */
|
|
tab_mask[TOP] = masque_layer_TOP;
|
|
tab_mask[BOTTOM] = masque_layer_BOTTOM;
|
|
/* Init masque des couches actives */
|
|
masque_layers = masque_layer_TOP | masque_layer_BOTTOM;
|
|
|
|
pt_cur_ch = pt_chevelu;
|
|
current_net_code = pt_chevelu->GetNet();
|
|
pad_masque_layer_s = pt_cur_ch->m_PadStart->m_Masque_Layer;
|
|
pad_masque_layer_e = pt_cur_ch->m_PadEnd->m_Masque_Layer;
|
|
|
|
/* Test 1 Si routage possible c.a.d si les pads sont accessibles
|
|
* sur les couches de routage */
|
|
|
|
if( (masque_layers & pad_masque_layer_s) == 0 )
|
|
goto end_of_route;
|
|
if( (masque_layers & pad_masque_layer_e) == 0 )
|
|
goto end_of_route;
|
|
|
|
/* Test 2 Si routage possible c.a.d si les pads sont accessibles
|
|
* sur la grille de routage ( 1 point de grille doit etre dans le pad)*/
|
|
{
|
|
int cX = (g_GridRoutingSize * col_source) + pcbframe->GetBoard()->m_BoundaryBox.m_Pos.x;
|
|
int cY = (g_GridRoutingSize * row_source) + pcbframe->GetBoard()->m_BoundaryBox.m_Pos.y;
|
|
int dx = pt_cur_ch->m_PadStart->m_Size.x / 2;
|
|
int dy = pt_cur_ch->m_PadStart->m_Size.y / 2;
|
|
int px = pt_cur_ch->m_PadStart->GetPosition().x;
|
|
int py = pt_cur_ch->m_PadStart->GetPosition().y;
|
|
|
|
if( ( (pt_cur_ch->m_PadStart->m_Orient / 900) & 1 ) != 0 )
|
|
EXCHG( dx, dy );
|
|
if( (abs( cX - px ) > dx ) || (abs( cY - py ) > dy) )
|
|
goto end_of_route;
|
|
|
|
cX = (g_GridRoutingSize * col_target) + pcbframe->GetBoard()->m_BoundaryBox.m_Pos.x;
|
|
cY = (g_GridRoutingSize * row_target) + pcbframe->GetBoard()->m_BoundaryBox.m_Pos.y;
|
|
dx = pt_cur_ch->m_PadEnd->m_Size.x / 2;
|
|
dy = pt_cur_ch->m_PadEnd->m_Size.y / 2;
|
|
px = pt_cur_ch->m_PadEnd->GetPosition().x;
|
|
py = pt_cur_ch->m_PadEnd->GetPosition().y;
|
|
if( ( (pt_cur_ch->m_PadEnd->m_Orient / 900) & 1 ) != 0 )
|
|
EXCHG( dx, dy );
|
|
|
|
if( (abs( cX - px ) > dx ) || (abs( cY - py ) > dy) )
|
|
goto end_of_route;
|
|
}
|
|
|
|
/* Test du cas trivial: connection directe par superposition des pads */
|
|
if( (row_source == row_target) && (col_source == col_target)
|
|
&& ( pad_masque_layer_e & pad_masque_layer_s &
|
|
g_TabAllCopperLayerMask[g_DesignSettings.m_CopperLayerCount - 1]) )
|
|
{
|
|
result = TRIVIAL_SUCCESS;
|
|
goto end_of_route;
|
|
}
|
|
|
|
|
|
/* Placement du bit de suppression d'obstacle relative aux 2 pads a relier */
|
|
pcbframe->Affiche_Message( wxT( "Gen Cells" ) );
|
|
|
|
Place_1_Pad_Board(
|
|
pcbframe->GetBoard(), pt_cur_ch->m_PadStart, CURRENT_PAD, marge, WRITE_OR_CELL );
|
|
Place_1_Pad_Board( pcbframe->GetBoard(), pt_cur_ch->m_PadEnd, CURRENT_PAD, marge, WRITE_OR_CELL );
|
|
|
|
/* Regenere les barrieres restantes (qui peuvent empieter sur le placement
|
|
* des bits precedents) */
|
|
i = pcbframe->GetBoard()->GetPadsCount();
|
|
for( unsigned ii = 0; ii < pcbframe->GetBoard()->GetPadsCount(); ii++ )
|
|
{
|
|
D_PAD * ptr = pcbframe->GetBoard()->m_NetInfo->GetPad(ii);
|
|
if( (pt_cur_ch->m_PadStart != ptr) && (pt_cur_ch->m_PadEnd != ptr) )
|
|
{
|
|
Place_1_Pad_Board( pcbframe->GetBoard(), ptr, ~CURRENT_PAD, marge, WRITE_AND_CELL );
|
|
}
|
|
}
|
|
|
|
InitQueue(); /* initialize the search queue */
|
|
apx_dist = GetApxDist( row_source, col_source, row_target, col_target );
|
|
|
|
/* Init 1ere recherche */
|
|
if( two_sides ) /* orientation preferentielle */
|
|
{
|
|
if( abs( row_target - row_source ) > abs( col_target - col_source ) )
|
|
{
|
|
if( pad_masque_layer_s & masque_layer_TOP )
|
|
{
|
|
start_mask_layer = 2;
|
|
if( SetQueue( row_source, col_source, TOP, 0, apx_dist,
|
|
row_target, col_target ) == 0 )
|
|
{
|
|
return ERR_MEMORY;
|
|
}
|
|
}
|
|
if( pad_masque_layer_s & masque_layer_BOTTOM )
|
|
{
|
|
start_mask_layer |= 1;
|
|
|
|
if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
|
|
row_target, col_target ) == 0 )
|
|
{
|
|
return ERR_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( pad_masque_layer_s & masque_layer_BOTTOM )
|
|
{
|
|
start_mask_layer = 1;
|
|
if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
|
|
row_target, col_target ) == 0 )
|
|
{
|
|
return ERR_MEMORY;
|
|
}
|
|
}
|
|
if( pad_masque_layer_s & masque_layer_TOP )
|
|
{
|
|
start_mask_layer |= 2;
|
|
|
|
if( SetQueue( row_source, col_source, TOP, 0, apx_dist,
|
|
row_target, col_target ) == 0 )
|
|
{
|
|
return ERR_MEMORY;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if( pad_masque_layer_s & masque_layer_BOTTOM )
|
|
{
|
|
start_mask_layer = 1;
|
|
|
|
if( SetQueue( row_source, col_source, BOTTOM, 0, apx_dist,
|
|
row_target, col_target ) == 0 )
|
|
{
|
|
return ERR_MEMORY;
|
|
}
|
|
}
|
|
|
|
/* search until success or we exhaust all possibilities */
|
|
GetQueue( &r, &c, &side, &d, &apx_dist );
|
|
for( ; r != ILLEGAL; GetQueue( &r, &c, &side, &d, &apx_dist ) )
|
|
{
|
|
curcell = GetCell( r, c, side );
|
|
if( curcell & CURRENT_PAD )
|
|
curcell &= ~HOLE;
|
|
if( (r == row_target) && (c == col_target) /* success si layer OK */
|
|
&& ( tab_mask[side] & pad_masque_layer_e) )
|
|
{
|
|
/* Efface Liaison */
|
|
GRSetDrawMode( DC, GR_XOR );
|
|
GRLine( &pcbframe->DrawPanel->m_ClipBox,
|
|
DC,
|
|
segm_oX,
|
|
segm_oY,
|
|
segm_fX,
|
|
segm_fY,
|
|
0,
|
|
WHITE );
|
|
|
|
/* Generation de la trace */
|
|
if( Retrace( pcbframe, DC, row_source, col_source,
|
|
row_target, col_target, side, current_net_code ) )
|
|
{
|
|
result = SUCCESS; /* Success : Route OK */
|
|
}
|
|
break; /* Fin du routage */
|
|
}
|
|
|
|
if( pcbframe->DrawPanel->m_AbortRequest )
|
|
{
|
|
result = STOP_FROM_ESC; break;
|
|
}
|
|
|
|
/* report every COUNT new nodes or so */
|
|
#define COUNT 20000
|
|
if( (OpenNodes-lastopen > COUNT) || (ClosNodes-lastclos > COUNT) || (MoveNodes - lastmove > COUNT))
|
|
{
|
|
lastopen = OpenNodes;
|
|
lastclos = ClosNodes;
|
|
lastmove = MoveNodes;
|
|
AFFICHE_ACTIVITE_ROUTE;
|
|
}
|
|
|
|
_self = 0;
|
|
if( curcell & HOLE )
|
|
{
|
|
_self = 5;
|
|
/* set 'present' bits */
|
|
for( i = 0; i < 8; i++ )
|
|
{
|
|
selfok2[i].present = 0;
|
|
if( (curcell & selfok2[i].trace) )
|
|
selfok2[i].present = 1;
|
|
}
|
|
}
|
|
|
|
for( i = 0; i < 8; i++ ) /* consider neighbors */
|
|
{
|
|
nr = r + delta[i][0]; nc = c + delta[i][1];
|
|
|
|
/* off the edge? */
|
|
if( nr < 0 || nr >= Nrows || nc < 0 || nc >= Ncols )
|
|
continue; /* off the edge */
|
|
|
|
if( _self == 5 && selfok2[i].present )
|
|
continue;
|
|
newcell = GetCell( nr, nc, side );
|
|
if( newcell & CURRENT_PAD )
|
|
newcell &= ~HOLE;
|
|
|
|
/* check for non-target hole */
|
|
if( newcell & HOLE )
|
|
{
|
|
if( nr != row_target || nc != col_target )
|
|
continue;
|
|
}
|
|
/* check for traces */
|
|
else if( newcell & HOLE & ~(newmask[i]) )
|
|
continue;
|
|
|
|
/* check blocking on corner neighbors */
|
|
if( delta[i][0] && delta[i][1] )
|
|
{
|
|
/* check first buddy */
|
|
buddy = GetCell( r + blocking[i].r1, c + blocking[i].c1, side );
|
|
if( buddy & CURRENT_PAD )
|
|
buddy &= ~HOLE;
|
|
if( buddy & HOLE )
|
|
continue;
|
|
|
|
// if (buddy & (blocking[i].b1)) continue;
|
|
/* check second buddy */
|
|
buddy = GetCell( r + blocking[i].r2, c + blocking[i].c2, side );
|
|
if( buddy & CURRENT_PAD )
|
|
buddy &= ~HOLE;
|
|
if( buddy & HOLE )
|
|
continue;
|
|
|
|
// if (buddy & (blocking[i].b2)) continue;
|
|
}
|
|
|
|
olddir = GetDir( r, c, side );
|
|
newdist = d + CalcDist( ndir[i], olddir,
|
|
(olddir == FROM_OTHERSIDE) ? GetDir( r,
|
|
c,
|
|
1 - side ) : 0, side );
|
|
|
|
/* if (a) not visited yet, or (b) we have */
|
|
/* found a better path, add it to queue */
|
|
if( !GetDir( nr, nc, side ) )
|
|
{
|
|
SetDir( nr, nc, side, ndir[i] );
|
|
SetDist( nr, nc, side, newdist );
|
|
if( SetQueue( nr, nc, side, newdist,
|
|
GetApxDist( nr, nc, row_target, col_target ),
|
|
row_target, col_target ) == 0 )
|
|
{
|
|
return ERR_MEMORY;
|
|
}
|
|
}
|
|
else if( newdist < GetDist( nr, nc, side ) )
|
|
{
|
|
SetDir( nr, nc, side, ndir[i] );
|
|
SetDist( nr, nc, side, newdist );
|
|
ReSetQueue( nr, nc, side, newdist,
|
|
GetApxDist( nr, nc, row_target, col_target ),
|
|
row_target, col_target );
|
|
}
|
|
}
|
|
|
|
/** etude de l'autre couche **/
|
|
if( (two_sides) && !g_No_Via_Route )
|
|
{
|
|
olddir = GetDir( r, c, side );
|
|
if( olddir == FROM_OTHERSIDE )
|
|
continue; /* useless move, so don't bother */
|
|
if( curcell ) /* can't drill via if anything here */
|
|
continue;
|
|
/* check for holes or traces on other side */
|
|
if( ( newcell = GetCell( r, c, 1 - side ) ) != 0 )
|
|
continue;
|
|
/* check for nearby holes or traces on both sides */
|
|
for( skip = 0, i = 0; i < 8; i++ )
|
|
{
|
|
nr = r + delta[i][0]; nc = c + delta[i][1];
|
|
|
|
if( nr < 0 || nr >= Nrows || nc < 0 || nc >= Ncols )
|
|
continue; /* off the edge !! */
|
|
|
|
if( GetCell( nr, nc, side ) /* & blocking2[i]*/ )
|
|
{
|
|
skip = 1; /* can't drill via here */
|
|
break;
|
|
}
|
|
|
|
if( GetCell( nr, nc, 1 - side ) /* & blocking2[i]*/ )
|
|
{
|
|
skip = 1; /* can't drill via here */
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( skip ) /* neighboring hole or trace? */
|
|
continue; /* yes, can't drill via here */
|
|
|
|
newdist = d + CalcDist( FROM_OTHERSIDE, olddir, 0, side );
|
|
|
|
/* if (a) not visited yet,
|
|
* or (b) we have found a better path,
|
|
* add it to queue */
|
|
if( !GetDir( r, c, 1 - side ) )
|
|
{
|
|
SetDir( r, c, 1 - side, FROM_OTHERSIDE );
|
|
SetDist( r, c, 1 - side, newdist );
|
|
if( SetQueue( r, c, 1 - side, newdist, apx_dist, row_target,
|
|
col_target ) == 0 )
|
|
{
|
|
return ERR_MEMORY;
|
|
}
|
|
}
|
|
else if( newdist < GetDist( r, c, 1 - side ) )
|
|
{
|
|
SetDir( r, c, 1 - side, FROM_OTHERSIDE );
|
|
SetDist( r, c, 1 - side, newdist );
|
|
ReSetQueue( r, c, 1 - side, newdist, apx_dist, row_target, col_target );
|
|
}
|
|
} /* Fin de l'exploration de l'autre couche */
|
|
}
|
|
|
|
end_of_route:
|
|
Place_1_Pad_Board(
|
|
pcbframe->GetBoard(), pt_cur_ch->m_PadStart, ~CURRENT_PAD, marge, WRITE_AND_CELL );
|
|
Place_1_Pad_Board(
|
|
pcbframe->GetBoard(), pt_cur_ch->m_PadEnd, ~CURRENT_PAD, marge, WRITE_AND_CELL );
|
|
|
|
AFFICHE_ACTIVITE_ROUTE;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
static long bit[8][9] = { /* OT=Otherside */
|
|
/* N, NE, E, SE, S, SW, W, NW, OT */
|
|
/* N */
|
|
{ LINE_VERTICAL, BENT_StoNE, CORNER_SOUTHEAST,
|
|
SHARP_StoSE,
|
|
0,
|
|
SHARP_StoSW, CORNER_SOUTHWEST, BENT_StoNW, (HOLE | HOLE_SOUTH) },
|
|
/* NE */ { BENT_NtoSW, DIAG_NEtoSW, BENT_EtoSW, ANGLE_SEtoSW,
|
|
SHARP_StoSW,
|
|
0, SHARP_WtoSW, ANGLE_SWtoNW, (HOLE | HOLE_SOUTHWEST) },
|
|
/* E */ { CORNER_NORTHWEST, BENT_WtoNE, LINE_HORIZONTAL, BENT_WtoSE,
|
|
CORNER_SOUTHWEST, SHARP_WtoSW, 0, SHARP_WtoNW, (HOLE | HOLE_WEST) },
|
|
/* SE */ { SHARP_NtoNW, ANGLE_NWtoNE, BENT_EtoNW, DIAG_SEtoNW,
|
|
BENT_StoNW,
|
|
ANGLE_SWtoNW, SHARP_WtoNW, 0, (HOLE | HOLE_NORTHWEST) },
|
|
/* S */ { 0, SHARP_NtoNE, CORNER_NORTHEAST, BENT_NtoSE,
|
|
LINE_VERTICAL,
|
|
BENT_NtoSW, CORNER_NORTHWEST, SHARP_NtoNW, (HOLE | HOLE_NORTH) },
|
|
/* SW */ { SHARP_NtoNE, 0, SHARP_EtoNE, ANGLE_NEtoSE,
|
|
BENT_StoNE,
|
|
DIAG_NEtoSW,
|
|
BENT_WtoNE, ANGLE_NWtoNE, (HOLE | HOLE_NORTHEAST) },
|
|
/* W */ { CORNER_NORTHEAST, SHARP_EtoNE, 0, SHARP_EtoSE,
|
|
CORNER_SOUTHEAST,
|
|
BENT_EtoSW, LINE_HORIZONTAL, BENT_EtoNW, (HOLE | HOLE_EAST) },
|
|
/* NW */ { BENT_NtoSE, ANGLE_NEtoSE, SHARP_EtoSE, 0,
|
|
SHARP_StoSE,
|
|
ANGLE_SEtoSW, BENT_WtoSE, DIAG_SEtoNW, (HOLE | HOLE_SOUTHEAST) }
|
|
};
|
|
|
|
|
|
/*******************************************************************/
|
|
static int Retrace( WinEDA_PcbFrame* pcbframe, wxDC* DC,
|
|
int row_source, int col_source,
|
|
int row_target, int col_target, int target_side,
|
|
int current_net_code )
|
|
/*******************************************************************/
|
|
|
|
/* work from target back to source, actually laying the traces
|
|
* Parametres:
|
|
* start on side target_side, aux coordonnees row_target, col_target.
|
|
* arrivee sur side masque_layer_start, coord row_source, col_source
|
|
* La recherche se fait en sens inverse du routage,
|
|
* c.a.d du point d'arrivee (target) vers le point de depart (source)
|
|
* du routeur.
|
|
*
|
|
* target_side = cote (TOP / BOTTOM) de depart
|
|
* mask_layer_source = masque des couches d'arrivee
|
|
*
|
|
* Retourne:
|
|
* 0 si erreur
|
|
* > 0 si Ok
|
|
*/
|
|
|
|
{
|
|
int r0, c0, s0;
|
|
int r1, c1, s1; /* row, col, side d'ou on vient */
|
|
int r2, c2, s2; /* row, col, side ou on va */
|
|
int x, y = -1;
|
|
long b;
|
|
|
|
r1 = row_target;
|
|
c1 = col_target; /* start point is target ( end point is source )*/
|
|
s1 = target_side;
|
|
r0 = c0 = s0 = ILLEGAL;
|
|
|
|
wxASSERT( g_CurrentTrackList.GetCount() == 0 );
|
|
|
|
do {
|
|
/* find where we came from to get here */
|
|
r2 = r1; c2 = c1; s2 = s1;
|
|
x = GetDir( r1, c1, s1 );
|
|
|
|
switch( x )
|
|
{
|
|
case FROM_NORTH:
|
|
r2++; break;
|
|
|
|
case FROM_EAST:
|
|
c2++; break;
|
|
|
|
case FROM_SOUTH:
|
|
r2--; break;
|
|
|
|
case FROM_WEST:
|
|
c2--; break;
|
|
|
|
case FROM_NORTHEAST:
|
|
r2++; c2++; break;
|
|
|
|
case FROM_SOUTHEAST:
|
|
r2--; c2++; break;
|
|
|
|
case FROM_SOUTHWEST:
|
|
r2--; c2--; break;
|
|
|
|
case FROM_NORTHWEST:
|
|
r2++; c2--; break;
|
|
|
|
case FROM_OTHERSIDE:
|
|
s2 = 1 - s2; break;
|
|
|
|
default:
|
|
DisplayError( pcbframe, wxT( "Retrace: internal error: no way back" ) );
|
|
return 0;
|
|
}
|
|
|
|
if( r0 != ILLEGAL )
|
|
y = GetDir( r0, c0, s0 );
|
|
|
|
/* see if target or hole */
|
|
if( ( (r1 == row_target) && (c1 == col_target) )
|
|
|| (s1 != s0) )
|
|
{
|
|
int p_dir;
|
|
|
|
switch( x )
|
|
{
|
|
case FROM_NORTH:
|
|
p_dir = HOLE_NORTH; break;
|
|
|
|
case FROM_EAST:
|
|
p_dir = HOLE_EAST; break;
|
|
|
|
case FROM_SOUTH:
|
|
p_dir = HOLE_SOUTH; break;
|
|
|
|
case FROM_WEST:
|
|
p_dir = HOLE_WEST; break;
|
|
|
|
case FROM_NORTHEAST:
|
|
p_dir = HOLE_NORTHEAST; break;
|
|
|
|
case FROM_SOUTHEAST:
|
|
p_dir = HOLE_SOUTHEAST; break;
|
|
|
|
case FROM_SOUTHWEST:
|
|
p_dir = HOLE_SOUTHWEST; break;
|
|
|
|
case FROM_NORTHWEST:
|
|
p_dir = HOLE_NORTHWEST; break;
|
|
|
|
case FROM_OTHERSIDE:
|
|
default:
|
|
DisplayError( pcbframe, wxT( "Retrace: error 1" ) );
|
|
return 0;
|
|
}
|
|
|
|
OrCell_Trace( pcbframe->GetBoard(), r1, c1, s1, p_dir, current_net_code );
|
|
}
|
|
else
|
|
{
|
|
if( (y == FROM_NORTH || y == FROM_NORTHEAST
|
|
|| y == FROM_EAST || y == FROM_SOUTHEAST
|
|
|| y == FROM_SOUTH || y == FROM_SOUTHWEST
|
|
|| y == FROM_WEST || y == FROM_NORTHWEST)
|
|
&& (x == FROM_NORTH || x == FROM_NORTHEAST
|
|
|| x == FROM_EAST || x == FROM_SOUTHEAST
|
|
|| x == FROM_SOUTH || x == FROM_SOUTHWEST
|
|
|| x == FROM_WEST || x == FROM_NORTHWEST
|
|
|| x == FROM_OTHERSIDE)
|
|
&& ( (b = bit[y - 1][x - 1]) != 0 ) )
|
|
{
|
|
OrCell_Trace( pcbframe->GetBoard(), r1, c1, s1, b, current_net_code );
|
|
if( b & HOLE )
|
|
OrCell_Trace( pcbframe->GetBoard(), r2, c2, s2, HOLE, current_net_code );
|
|
}
|
|
else
|
|
{
|
|
DisplayError( pcbframe, wxT( "Retrace: error 2" ) );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if( (r2 == row_source) && (c2 == col_source) )
|
|
{ /* see if source */
|
|
int p_dir;
|
|
|
|
switch( x )
|
|
{
|
|
case FROM_NORTH:
|
|
p_dir = HOLE_SOUTH; break;
|
|
|
|
case FROM_EAST:
|
|
p_dir = HOLE_WEST; break;
|
|
|
|
case FROM_SOUTH:
|
|
p_dir = HOLE_NORTH; break;
|
|
|
|
case FROM_WEST:
|
|
p_dir = HOLE_EAST; break;
|
|
|
|
case FROM_NORTHEAST:
|
|
p_dir = HOLE_SOUTHWEST; break;
|
|
|
|
case FROM_SOUTHEAST:
|
|
p_dir = HOLE_NORTHWEST; break;
|
|
|
|
case FROM_SOUTHWEST:
|
|
p_dir = HOLE_NORTHEAST; break;
|
|
|
|
case FROM_NORTHWEST:
|
|
p_dir = HOLE_SOUTHEAST; break;
|
|
|
|
case FROM_OTHERSIDE:
|
|
default:
|
|
DisplayError( pcbframe, wxT( "Retrace: error 3" ) );
|
|
return 0;
|
|
}
|
|
|
|
OrCell_Trace( pcbframe->GetBoard(), r2, c2, s2, p_dir, current_net_code );
|
|
}
|
|
/* move to next cell */
|
|
r0 = r1; c0 = c1; s0 = s1;
|
|
r1 = r2; c1 = c2; s1 = s2;
|
|
} while( !( (r2 == row_source) && (c2 == col_source) ) );
|
|
|
|
Place_Piste_en_Buffer( pcbframe, DC );
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
static void OrCell_Trace( BOARD* pcb, int col, int row,
|
|
int side, int orient, int current_net_code )
|
|
/*****************************************************************************/
|
|
/* appelle la routine OrCell et place la piste reelle sur le pcb */
|
|
{
|
|
int dx0, dy0, dx1, dy1;
|
|
TRACK* newTrack;
|
|
|
|
if( orient == HOLE ) // placement of a via
|
|
{
|
|
newTrack = new SEGVIA( pcb );
|
|
|
|
g_CurrentTrackList.PushBack( newTrack );
|
|
|
|
g_CurrentTrackSegment->SetState( SEGM_AR, ON );
|
|
g_CurrentTrackSegment->SetLayer( 0x0F );
|
|
|
|
g_CurrentTrackSegment->m_Start.x =
|
|
g_CurrentTrackSegment->m_End.x = pcb->m_BoundaryBox.m_Pos.x + (g_GridRoutingSize * row);
|
|
|
|
g_CurrentTrackSegment->m_Start.y =
|
|
g_CurrentTrackSegment->m_End.y = pcb->m_BoundaryBox.m_Pos.y + (g_GridRoutingSize * col);
|
|
|
|
g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentViaSize;
|
|
g_CurrentTrackSegment->m_Shape = g_DesignSettings.m_CurrentViaType;
|
|
|
|
g_CurrentTrackSegment->SetNet( current_net_code );
|
|
}
|
|
else // placement of a standard segment
|
|
{
|
|
newTrack = new TRACK( pcb );
|
|
|
|
g_CurrentTrackList.PushBack( newTrack );
|
|
|
|
g_CurrentTrackSegment->SetLayer( Route_Layer_BOTTOM );
|
|
if( side == TOP )
|
|
g_CurrentTrackSegment->SetLayer( Route_Layer_TOP );
|
|
|
|
g_CurrentTrackSegment->SetState( SEGM_AR, ON );
|
|
g_CurrentTrackSegment->m_End.x = pcb->m_BoundaryBox.m_Pos.x + (g_GridRoutingSize * row);
|
|
g_CurrentTrackSegment->m_End.y = pcb->m_BoundaryBox.m_Pos.y + (g_GridRoutingSize * col);
|
|
g_CurrentTrackSegment->SetNet( current_net_code );
|
|
|
|
if( g_CurrentTrackSegment->Back() == NULL ) /* Start Piste */
|
|
{
|
|
g_CurrentTrackSegment->m_Start.x = segm_fX;
|
|
g_CurrentTrackSegment->m_Start.y = segm_fY;
|
|
|
|
/* Replacement sur le centre du pad si hors grille */
|
|
dx1 = g_CurrentTrackSegment->m_End.x - g_CurrentTrackSegment->m_Start.x;
|
|
dy1 = g_CurrentTrackSegment->m_End.y - g_CurrentTrackSegment->m_Start.y;
|
|
|
|
dx0 = pt_cur_ch->m_PadEnd->GetPosition().x - g_CurrentTrackSegment->m_Start.x;
|
|
dy0 = pt_cur_ch->m_PadEnd->GetPosition().y - g_CurrentTrackSegment->m_Start.y;
|
|
|
|
/* si aligne: modif du point origine */
|
|
if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) ) /* Alignes ! */
|
|
{
|
|
g_CurrentTrackSegment->m_Start = pt_cur_ch->m_PadEnd->GetPosition();
|
|
}
|
|
else // Creation of a supplemental segment
|
|
{
|
|
g_CurrentTrackSegment->m_Start = pt_cur_ch->m_PadEnd->GetPosition();
|
|
|
|
newTrack = g_CurrentTrackSegment->Copy();
|
|
newTrack->m_Start = g_CurrentTrackSegment->m_End;
|
|
|
|
g_CurrentTrackList.PushBack( newTrack );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( g_CurrentTrackSegment->Back() )
|
|
{
|
|
g_CurrentTrackSegment->m_Start = g_CurrentTrackSegment->Back()->m_End;
|
|
}
|
|
}
|
|
g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth;
|
|
|
|
if( g_CurrentTrackSegment->m_Start != g_CurrentTrackSegment->m_End )
|
|
{
|
|
/* Reduction des segments alignes a 1 seul */
|
|
TRACK* oldTrack = g_CurrentTrackSegment->Back();
|
|
if( oldTrack && oldTrack->Type() != TYPE_VIA )
|
|
{
|
|
dx1 = g_CurrentTrackSegment->m_End.x - g_CurrentTrackSegment->m_Start.x;
|
|
dy1 = g_CurrentTrackSegment->m_End.y - g_CurrentTrackSegment->m_Start.y;
|
|
|
|
dx0 = oldTrack->m_End.x - oldTrack->m_Start.x;
|
|
dy0 = oldTrack->m_End.y - oldTrack->m_Start.y;
|
|
|
|
if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) ) /* le dernier segment est en ligne*/
|
|
{
|
|
oldTrack->m_End = g_CurrentTrackSegment->m_End;
|
|
|
|
delete g_CurrentTrackList.PopBack();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************/
|
|
static void Place_Piste_en_Buffer( WinEDA_PcbFrame* pcbframe, wxDC* DC )
|
|
/***********************************************************************/
|
|
|
|
/* Insere la nouvelle piste creee dans la liste standard des pistes.
|
|
* Modifie les points de debut et fin de piste pour qu'ils soient relies
|
|
* au centre des pads corresponadants, meme hors grille
|
|
*/
|
|
{
|
|
if( g_FirstTrackSegment == NULL )
|
|
return;
|
|
|
|
int dx0, dy0, dx1, dy1;
|
|
int marge, via_marge;
|
|
WinEDA_DrawPanel* panel = pcbframe->DrawPanel;
|
|
|
|
marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentTrackWidth / 2);
|
|
via_marge = g_DesignSettings.m_TrackClearence + (g_DesignSettings.m_CurrentViaSize / 2);
|
|
|
|
/* tst point d'arrivee : doit etre sur pad start */
|
|
|
|
dx1 = g_CurrentTrackSegment->m_End.x - g_CurrentTrackSegment->m_Start.x;
|
|
dy1 = g_CurrentTrackSegment->m_End.y - g_CurrentTrackSegment->m_Start.y;
|
|
/* Replacement sur le centre du pad si hors grille */
|
|
|
|
dx0 = pt_cur_ch->m_PadStart->GetPosition().x - g_CurrentTrackSegment->m_Start.x;
|
|
dy0 = pt_cur_ch->m_PadStart->GetPosition().y - g_CurrentTrackSegment->m_Start.y;
|
|
|
|
/* si aligne: modif du point origine */
|
|
if( abs( dx0 * dy1 ) == abs( dx1 * dy0 ) ) /* Alignes ! */
|
|
{
|
|
g_CurrentTrackSegment->m_End = pt_cur_ch->m_PadStart->GetPosition();
|
|
}
|
|
else /* Creation d'un segment suppl raccord */
|
|
{
|
|
TRACK* newTrack = g_CurrentTrackSegment->Copy();
|
|
|
|
newTrack->m_End = pt_cur_ch->m_PadStart->GetPosition();
|
|
newTrack->m_Start = g_CurrentTrackSegment->m_End;
|
|
|
|
g_CurrentTrackList.PushBack( newTrack );
|
|
}
|
|
|
|
g_FirstTrackSegment->start = Locate_Pad_Connecte(
|
|
pcbframe->GetBoard(), g_FirstTrackSegment, START );
|
|
if( g_FirstTrackSegment->start )
|
|
g_FirstTrackSegment->SetState( BEGIN_ONPAD, ON );
|
|
|
|
g_CurrentTrackSegment->end = Locate_Pad_Connecte(
|
|
pcbframe->GetBoard(), g_CurrentTrackSegment, END );
|
|
if( g_CurrentTrackSegment->end )
|
|
g_CurrentTrackSegment->SetState( END_ONPAD, ON );
|
|
|
|
/* Out the new track on the matrix board */
|
|
for( TRACK* track = g_FirstTrackSegment; track; track = track->Next() )
|
|
{
|
|
TraceSegmentPcb( pcbframe->GetBoard(), track, HOLE, marge, WRITE_CELL );
|
|
TraceSegmentPcb( pcbframe->GetBoard(), track, VIA_IMPOSSIBLE, via_marge, WRITE_OR_CELL );
|
|
}
|
|
|
|
// Insert new segments in real board
|
|
int netcode = g_FirstTrackSegment->GetNet();
|
|
TRACK* firstTrack = g_FirstTrackSegment;
|
|
int newCount = g_CurrentTrackList.GetCount();
|
|
|
|
// Put entire new current segment list in BOARD
|
|
TRACK* track;
|
|
TRACK* insertBeforeMe = g_CurrentTrackSegment->GetBestInsertPoint( pcbframe->GetBoard() );
|
|
while( ( track = g_CurrentTrackList.PopFront() ) != NULL )
|
|
{
|
|
pcbframe->GetBoard()->m_Track.Insert( track, insertBeforeMe );
|
|
}
|
|
|
|
Trace_Une_Piste( panel, DC, firstTrack, newCount, GR_OR );
|
|
|
|
pcbframe->test_1_net_connexion( DC, netcode );
|
|
|
|
ActiveScreen->SetModify();
|
|
}
|