1331 lines
45 KiB
C++
1331 lines
45 KiB
C++
/************************************/
|
|
/**** editeur de PCB ****/
|
|
/* traitement du Chevelu (Rastnest) */
|
|
/************************************/
|
|
|
|
/* Fichier RATSNEST.CPP */
|
|
|
|
#include "fctsys.h"
|
|
#include "gr_basic.h"
|
|
|
|
#include "common.h"
|
|
#include "pcbnew.h"
|
|
#include "autorout.h"
|
|
|
|
#include "protos.h"
|
|
|
|
/* variables locales */
|
|
CHEVELU* g_pt_chevelu;
|
|
CHEVELU* local_liste_chevelu; // adresse de base du buffer des chevelus locaux
|
|
int nb_local_chevelu; // nbr de links du module en deplacement
|
|
int nb_pads_ref; // nbr de nodes du module en deplacement
|
|
int nb_pads_externes; // nbr de pads connectes au module en deplacement
|
|
bool DisplayRastnestInProgress; // autorise affichage chevelu en cours de calcul
|
|
// de celui-ci
|
|
|
|
|
|
/******************************************************************************/
|
|
void WinEDA_BasePcbFrame::Compile_Ratsnest( wxDC* DC, bool display_status_pcb )
|
|
/******************************************************************************/
|
|
|
|
/*
|
|
* Génère le chevelu complet de la carte.
|
|
* Doit etre appelé APRES le calcul de connectivité
|
|
* Doit etre appelé apres changement de structure de la carte (modif
|
|
* de pads, de nets, de modules).
|
|
*
|
|
* Si display_status_pcb : affichage des résultats en bas d'ecran
|
|
*/
|
|
{
|
|
wxString msg;
|
|
|
|
DisplayRastnestInProgress = TRUE;
|
|
|
|
/* construction de la liste des coordonnées des pastilles */
|
|
m_Pcb->m_Status_Pcb = 0; /* réinit total du calcul */
|
|
build_liste_pads();
|
|
MsgPanel->EraseMsgBox(); /* effacement du bas d'ecran */
|
|
msg.Printf( wxT( " %d" ), m_Pcb->m_NbPads );
|
|
Affiche_1_Parametre( this, 1, wxT( "pads" ), msg, RED );
|
|
|
|
msg.Printf( wxT( " %d" ), m_Pcb->m_NbNets );
|
|
Affiche_1_Parametre( this, 8, wxT( "Nets" ), msg, CYAN );
|
|
|
|
reattribution_reference_piste( display_status_pcb );
|
|
Build_Board_Ratsnest( DC ); /* calcul du chevelu general */
|
|
test_connexions( DC ); /* determine les blocks de pads connectés par
|
|
* les pistes existantes */
|
|
|
|
Tst_Ratsnest( DC, 0 ); /* calcul du chevelu actif */
|
|
|
|
// Reaffichage des chevelus actifs
|
|
if( g_Show_Ratsnest )
|
|
DrawGeneralRatsnest( DC, 0 );
|
|
|
|
if( display_status_pcb )
|
|
m_Pcb->Display_Infos( this );
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
static int tri_par_net( LISTE_PAD* pt_ref, LISTE_PAD* pt_compare )
|
|
/****************************************************************/
|
|
/* routine utilisee par la foncion QSORT */
|
|
{
|
|
return (*pt_ref)->m_NetCode - (*pt_compare)->m_NetCode;
|
|
}
|
|
|
|
|
|
/********************************************************/
|
|
static int sort_by_length( CHEVELU* ref, CHEVELU* compare )
|
|
/********************************************************/
|
|
/* routine de tri par longueur des chevelus utilisee par la foncion QSORT */
|
|
{
|
|
return ref->dist - compare->dist;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
static int gen_rats_block_to_block( WinEDA_DrawPanel* DrawPanel, wxDC* DC,
|
|
LISTE_PAD* pt_liste_pad, LISTE_PAD* pt_limite, int* nblinks )
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* Routine utilisee par Build_Board_Ratsnest()
|
|
* Routine generant le chevelu entre 2 blocks ( supposes du meme net )
|
|
* la recherche est faite entre les pads du block 1 et les autres blocks
|
|
* le block n ( n > 1 ) est alors connecte au block 1 par leur 2 pads
|
|
* les plus proches.
|
|
* Entree :
|
|
* pt_chain_pad = adresse de debut de recherche
|
|
* pt_limite = adresse de fin de recherche (borne non comprise)
|
|
* Sortie:
|
|
* liste des chevelus ( structures)
|
|
* mise a jour de g_pt_chevelu a la 1ere case libre
|
|
* Retourne:
|
|
* nombre de blocks non connectes entre eux
|
|
*/
|
|
{
|
|
int dist_min, current_dist;
|
|
int current_num_block = 1;
|
|
LISTE_PAD* pt_liste_pad_tmp,
|
|
* pt_liste_pad_aux,
|
|
* pt_liste_pad_block1 = NULL,
|
|
* pt_start_liste;
|
|
|
|
pt_liste_pad_tmp = NULL; dist_min = 0x7FFFFFFF;
|
|
pt_start_liste = pt_liste_pad;
|
|
|
|
if( DC )
|
|
GRSetDrawMode( DC, GR_XOR );
|
|
|
|
/* Recherche du pad le plus proche du block 1 */
|
|
for( ; pt_liste_pad < pt_limite; pt_liste_pad++ )
|
|
{
|
|
D_PAD* ref_pad = *pt_liste_pad;
|
|
if( ref_pad->m_logical_connexion != 1 )
|
|
continue;
|
|
|
|
for( pt_liste_pad_aux = pt_start_liste; ; pt_liste_pad_aux++ )
|
|
{
|
|
D_PAD* curr_pad = *pt_liste_pad_aux;
|
|
if( pt_liste_pad_aux >= pt_limite )
|
|
break;
|
|
if( curr_pad->m_logical_connexion == 1 )
|
|
continue;
|
|
|
|
/* Comparaison des distances des pastilles (calcul simplifie) */
|
|
current_dist =
|
|
abs( curr_pad->m_Pos.x - ref_pad->m_Pos.x )
|
|
+ abs( curr_pad->m_Pos.y - ref_pad->m_Pos.y );
|
|
|
|
if( dist_min > current_dist )
|
|
{
|
|
current_num_block = curr_pad->m_logical_connexion;
|
|
dist_min = current_dist;
|
|
pt_liste_pad_tmp = pt_liste_pad_aux;
|
|
pt_liste_pad_block1 = pt_liste_pad;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( current_num_block > 1 ) /* le block n a ete connecte au bloc 1 */
|
|
{
|
|
/* le block n est fondu avec le bloc 1 : */
|
|
for( pt_liste_pad = pt_start_liste; pt_liste_pad < pt_limite; pt_liste_pad++ )
|
|
{
|
|
if( (*pt_liste_pad)->m_logical_connexion == current_num_block )
|
|
(*pt_liste_pad)->m_logical_connexion = 1;
|
|
}
|
|
|
|
pt_liste_pad = pt_liste_pad_block1;
|
|
|
|
(*nblinks)++;
|
|
g_pt_chevelu->m_NetCode = (*pt_liste_pad)->m_NetCode;
|
|
g_pt_chevelu->status = CH_ACTIF | CH_VISIBLE;
|
|
g_pt_chevelu->dist = dist_min;
|
|
g_pt_chevelu->pad_start = *pt_liste_pad;
|
|
g_pt_chevelu->pad_end = *pt_liste_pad_tmp;
|
|
|
|
if( DisplayRastnestInProgress && DC )
|
|
GRLine( &DrawPanel->m_ClipBox, DC, g_pt_chevelu->pad_start->m_Pos.x,
|
|
g_pt_chevelu->pad_start->m_Pos.y,
|
|
g_pt_chevelu->pad_end->m_Pos.x,
|
|
g_pt_chevelu->pad_end->m_Pos.y,
|
|
0, g_DesignSettings.m_RatsnestColor );
|
|
|
|
g_pt_chevelu++;
|
|
}
|
|
return current_num_block;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
static int gen_rats_pad_to_pad( WinEDA_DrawPanel* DrawPanel, wxDC* DC,
|
|
LISTE_PAD* pt_liste_pad,
|
|
LISTE_PAD* pt_limite, int current_num_block, int* nblinks )
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* Routine utilisee par Build_Board_Ratsnest()
|
|
* Routine generant le chevelu entre 2 pads ( supposes du meme net )
|
|
* la routine connecte 1 pad non deja connecte a un autre et crée donc un certqins nombre
|
|
* de blocks de pads liées par un chevelu
|
|
* Ces blocks sont donc constitués de 2 pads.
|
|
*
|
|
* Entree :
|
|
* pt_chain_pad = adresse de debut de recherche
|
|
* pt_limite = adresse de fin de recherche (borne non comprise)
|
|
* current_num_block = numero du dernier block de pads (constitué par les connexions
|
|
* de pistes existantes
|
|
*
|
|
* Sortie:
|
|
* liste des chevelus ( structures)
|
|
* mise a jour de g_pt_chevelu a la 1ere case libre
|
|
*
|
|
* Retourne:
|
|
* nombre de blocks crees (paquets de pads)
|
|
*/
|
|
{
|
|
int dist_min, current_dist;
|
|
LISTE_PAD* pt_liste_pad_tmp;
|
|
LISTE_PAD* pt_liste_pad_aux;
|
|
LISTE_PAD* pt_start_liste;
|
|
D_PAD* ref_pad, * pad;
|
|
|
|
pt_start_liste = pt_liste_pad;
|
|
|
|
if( DC )
|
|
GRSetDrawMode( DC, GR_XOR );
|
|
|
|
for( ; pt_liste_pad < pt_limite; pt_liste_pad++ )
|
|
{
|
|
ref_pad = *pt_liste_pad;
|
|
if( ref_pad->m_logical_connexion )
|
|
continue; // Pad deja connecte
|
|
|
|
pt_liste_pad_tmp = NULL; dist_min = 0x7FFFFFFF;
|
|
|
|
for( pt_liste_pad_aux = pt_start_liste; ; pt_liste_pad_aux++ )
|
|
{
|
|
if( pt_liste_pad_aux >= pt_limite )
|
|
break;
|
|
if( pt_liste_pad_aux == pt_liste_pad )
|
|
continue;
|
|
|
|
pad = *pt_liste_pad_aux;
|
|
/* Comparaison des distances des pastilles (calcul simplifie) */
|
|
current_dist =
|
|
abs( pad->m_Pos.x - ref_pad->m_Pos.x )
|
|
+ abs( pad->m_Pos.y - ref_pad->m_Pos.y );
|
|
|
|
if( dist_min > current_dist )
|
|
{
|
|
dist_min = current_dist;
|
|
pt_liste_pad_tmp = pt_liste_pad_aux;
|
|
}
|
|
}
|
|
|
|
if( pt_liste_pad_tmp != NULL )
|
|
{
|
|
pad = *pt_liste_pad_tmp;
|
|
|
|
/* Mise a jour du numero de block ( ou de sous graphe ) */
|
|
/* si aucun des 2 pads n'est deja connecte : creation d'un nouveau block */
|
|
if( (pad->m_logical_connexion == 0) && (ref_pad->m_logical_connexion == 0) )
|
|
{
|
|
current_num_block++;
|
|
pad->m_logical_connexion = current_num_block;
|
|
ref_pad->m_logical_connexion = current_num_block;
|
|
}
|
|
/* si 1 des 2 pads est deja connecte : mise a jour pour l'autre */
|
|
else
|
|
{
|
|
ref_pad->m_logical_connexion = pad->m_logical_connexion;
|
|
}
|
|
(*nblinks)++;
|
|
g_pt_chevelu->m_NetCode = ref_pad->m_NetCode;
|
|
g_pt_chevelu->status = CH_ACTIF | CH_VISIBLE;
|
|
g_pt_chevelu->dist = dist_min;
|
|
g_pt_chevelu->pad_start = ref_pad;
|
|
g_pt_chevelu->pad_end = pad;
|
|
|
|
if( DisplayRastnestInProgress )
|
|
{
|
|
GRLine( &DrawPanel->m_ClipBox, DC, g_pt_chevelu->pad_start->m_Pos.x,
|
|
g_pt_chevelu->pad_start->m_Pos.y,
|
|
g_pt_chevelu->pad_end->m_Pos.x,
|
|
g_pt_chevelu->pad_end->m_Pos.y,
|
|
0, g_DesignSettings.m_RatsnestColor );
|
|
}
|
|
g_pt_chevelu++;
|
|
}
|
|
}
|
|
|
|
return current_num_block;
|
|
}
|
|
|
|
|
|
/***********************************************************/
|
|
void WinEDA_BasePcbFrame::Build_Board_Ratsnest( wxDC* DC )
|
|
/***********************************************************/
|
|
|
|
/* Routine de calcul du chevelu complet du circuit (algorithme de LEE )
|
|
* les connexions physiques (pistes) ne sont pas ici prises en compte
|
|
* Il s'agit donc du chevelu de base qui ne depend que de la disposition des pads.
|
|
*
|
|
* - etablit la liste complete des pads si nécessaire
|
|
* les pads utiles (cad appartenant a un net ) sont appeles
|
|
* nodes (noeuds)
|
|
* et la trie par blocs de pads homogenes ( i.e. appartenant au meme net )
|
|
*
|
|
* - puis calcule le ratsnest selon l'algorithme de LEE, consistant a
|
|
* a - etablir le ratsnest entre 1 pad non "connecte" et son plus proche
|
|
* voisin. Ceci cree des "blocks" ou sous graphes non connectes entre
|
|
* eux
|
|
* b - "connecter" (par un chevelu) entre eux ces blocks en prenant le 1er block et
|
|
* en le connectant a son plus proche voisin par les 2 pads les plus
|
|
* proches (Iteration jusqu'a ce qu'il n'y ait plus qu'un seul block).
|
|
*
|
|
* les chevelus calculés montrent les connexions "logiques"
|
|
*
|
|
* Entree = adr du buffer de classement (usuellement buf_work)
|
|
* met a jour :
|
|
* nb_nodes = nombre de pads connectes a un net ( pads "utiles")
|
|
* nb_links = nombre min de liens :
|
|
* il y a n-1 liens par equipotentielle comportant n pads.
|
|
*
|
|
*/
|
|
{
|
|
LISTE_PAD* pt_liste_pad, * pt_start_liste, * pt_end_liste, * pt_liste_pad_limite;
|
|
D_PAD* pad;
|
|
int ii, num_block, nbpads;
|
|
CHEVELU* pt_deb_liste_ch;
|
|
int current_net_code, noconn;
|
|
EQUIPOT* equipot;
|
|
|
|
m_Pcb->m_NbNoconnect = 0;
|
|
m_Pcb->m_NbLinks = 0;
|
|
|
|
if( m_Pcb->m_NbPads == 0 )
|
|
return;
|
|
|
|
/* Etablissement de la liste des pads et leur net_codes si necessaire */
|
|
if( (m_Pcb->m_Status_Pcb & NET_CODES_OK) == 0 )
|
|
recalcule_pad_net_code();
|
|
|
|
pt_liste_pad = m_Pcb->m_Pads;
|
|
for( ii = m_Pcb->m_NbPads; ii > 0; pt_liste_pad++, ii-- )
|
|
{
|
|
pad = *pt_liste_pad;
|
|
pad->m_logical_connexion = 0;
|
|
}
|
|
|
|
/* classement des pointeurs sur pads par nets */
|
|
qsort( m_Pcb->m_Pads, m_Pcb->m_NbPads, sizeof(LISTE_PAD),
|
|
( int( * ) ( const void*, const void* ) )tri_par_net );
|
|
|
|
/* Allocation memoire du buffer des chevelus: il y a nb_nodes - 1 chevelu
|
|
* au maximum ( 1 node = 1 pad connecte ).
|
|
* on alloue donc un buffer pour nb_nodes chevelus... (+ une petite marge)
|
|
* le nombre reel de chevelus est nb_links
|
|
*/
|
|
if( m_Pcb->m_Ratsnest )
|
|
MyFree( m_Pcb->m_Ratsnest );
|
|
m_Pcb->m_Ratsnest = NULL;
|
|
|
|
if( m_Pcb->m_NbNodes == 0 )
|
|
return; /* pas de connexions utiles */
|
|
|
|
m_Pcb->m_Ratsnest = (CHEVELU*) MyZMalloc( (m_Pcb->m_NbNodes + 10 ) * sizeof(CHEVELU) );
|
|
if( m_Pcb->m_Ratsnest == NULL )
|
|
return;
|
|
|
|
|
|
/* calcul du chevelu */
|
|
DisplayRastnestInProgress = TRUE;
|
|
g_pt_chevelu = m_Pcb->m_Ratsnest;
|
|
pt_liste_pad = pt_start_liste = m_Pcb->m_Pads;
|
|
pt_liste_pad_limite = pt_start_liste + m_Pcb->m_NbPads;
|
|
current_net_code = 1; // 1er net_code a analyser (net_code = 0 -> no connect)
|
|
equipot = m_Pcb->m_Equipots;
|
|
noconn = 0;
|
|
|
|
for( ; pt_liste_pad < pt_liste_pad_limite; )
|
|
{
|
|
pt_deb_liste_ch = g_pt_chevelu;
|
|
pad = *pt_liste_pad;
|
|
/* saut des pads non connectes */
|
|
if( pad->m_NetCode == 0 )
|
|
{
|
|
pt_liste_pad++; pt_start_liste = pt_liste_pad;
|
|
continue;
|
|
}
|
|
/* Recherche de la fin de la liste des pads du net courant */
|
|
num_block = pad->m_logical_connexion;
|
|
nbpads = 0;
|
|
for( pt_end_liste = pt_liste_pad + 1; ; pt_end_liste++ )
|
|
{
|
|
if( pt_end_liste >= pt_liste_pad_limite )
|
|
break;
|
|
pad = *pt_end_liste;
|
|
if( pad->m_NetCode != current_net_code )
|
|
break;
|
|
nbpads++;
|
|
if( num_block < pad->m_logical_connexion )
|
|
num_block = pad->m_logical_connexion;
|
|
}
|
|
|
|
m_Pcb->m_NbLinks += nbpads;
|
|
|
|
/* fin de liste trouvee: calcul du chevelu du net "net_code" */
|
|
equipot = m_Pcb->FindNet( current_net_code );
|
|
if( equipot == NULL )
|
|
DisplayError( this, wxT( "Gen ratsnest err: NULL equipot" ) );
|
|
else
|
|
{
|
|
equipot->m_NbNodes = nbpads;
|
|
equipot->m_NbLink = nbpads + 1;
|
|
equipot->m_PadzoneStart = pt_start_liste;
|
|
equipot->m_PadzoneEnd = pt_end_liste;
|
|
equipot->m_RatsnestStart = g_pt_chevelu;
|
|
}
|
|
|
|
/* a - connexion des pads entre eux */
|
|
ii = gen_rats_pad_to_pad( DrawPanel, DC, pt_start_liste,
|
|
pt_end_liste, num_block, &noconn );
|
|
|
|
/* b - connexion des blocks formes precedemment (Iteration) */
|
|
while( ii > 1 )
|
|
{
|
|
ii = gen_rats_block_to_block( DrawPanel, DC, pt_liste_pad,
|
|
pt_end_liste, &noconn );
|
|
}
|
|
|
|
if( equipot )
|
|
{
|
|
equipot->m_RatsnestEnd = g_pt_chevelu;
|
|
/* classement des chevelus par longueur croissante */
|
|
qsort( equipot->m_RatsnestStart,
|
|
equipot->m_RatsnestEnd - equipot->m_RatsnestStart,
|
|
sizeof(CHEVELU),
|
|
( int( * ) ( const void*, const void* ) )sort_by_length );
|
|
}
|
|
pt_liste_pad = pt_start_liste = pt_end_liste;
|
|
pt_deb_liste_ch = g_pt_chevelu;
|
|
if( pt_start_liste < pt_liste_pad_limite )
|
|
current_net_code = (*pt_start_liste)->m_NetCode;
|
|
}
|
|
|
|
m_Pcb->m_NbNoconnect = noconn;
|
|
m_Pcb->m_Status_Pcb |= LISTE_CHEVELU_OK;
|
|
adr_lowmem = buf_work;
|
|
|
|
// Effacement du chevelu calcule
|
|
CHEVELU* Chevelu = (CHEVELU*) m_Pcb->m_Ratsnest;
|
|
GRSetDrawMode( DC, GR_XOR );
|
|
for( ii = m_Pcb->GetNumRatsnests(); ii > 0; ii--, Chevelu++ )
|
|
{
|
|
if( !g_Show_Ratsnest )
|
|
Chevelu->status &= ~CH_VISIBLE;
|
|
if( DC )
|
|
GRLine( &DrawPanel->m_ClipBox, DC,
|
|
Chevelu->pad_start->m_Pos.x, Chevelu->pad_start->m_Pos.y,
|
|
Chevelu->pad_end->m_Pos.x, Chevelu->pad_end->m_Pos.y,
|
|
0, g_DesignSettings.m_RatsnestColor );
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************/
|
|
void WinEDA_BasePcbFrame::ReCompile_Ratsnest_After_Changes( wxDC* DC )
|
|
/**********************************************************************/
|
|
|
|
/* recompile rastnest afet am module move, delete, ..
|
|
*/
|
|
{
|
|
if( g_Show_Ratsnest && DC )
|
|
Compile_Ratsnest( DC, TRUE );
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
void WinEDA_BasePcbFrame::DrawGeneralRatsnest( wxDC* DC, int net_code )
|
|
/*********************************************************************/
|
|
|
|
/*
|
|
* Affiche le chevelu general du circuit
|
|
* Affiche les chevelus dont le bit CH_VISIBLE du status du chevelu est a 1
|
|
* Si net_code > 0, affichage des seuls chevelus de net_code correspondant
|
|
*/
|
|
{
|
|
int ii;
|
|
CHEVELU* Chevelu;
|
|
|
|
if( (m_Pcb->m_Status_Pcb & LISTE_CHEVELU_OK) == 0 )
|
|
return;
|
|
if( (m_Pcb->m_Status_Pcb & DO_NOT_SHOW_GENERAL_RASTNEST) )
|
|
return;
|
|
if( DC == NULL )
|
|
return;
|
|
|
|
Chevelu = m_Pcb->m_Ratsnest;
|
|
if( Chevelu == NULL )
|
|
return;
|
|
|
|
GRSetDrawMode( DC, GR_XOR );
|
|
for( ii = m_Pcb->GetNumRatsnests(); ii > 0; Chevelu++, ii-- )
|
|
{
|
|
if( ( Chevelu->status & (CH_VISIBLE | CH_ACTIF) ) != (CH_VISIBLE | CH_ACTIF) )
|
|
continue;
|
|
if( (net_code <= 0) || (net_code == Chevelu->m_NetCode) )
|
|
{
|
|
GRLine( &DrawPanel->m_ClipBox, DC,
|
|
Chevelu->pad_start->m_Pos.x, Chevelu->pad_start->m_Pos.y,
|
|
Chevelu->pad_end->m_Pos.x, Chevelu->pad_end->m_Pos.y,
|
|
0, g_DesignSettings.m_RatsnestColor );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
static int tst_rats_block_to_block( WinEDA_DrawPanel* DrawPanel, wxDC* DC,
|
|
LISTE_PAD* pt_liste_pad_start, LISTE_PAD* pt_liste_pad_end,
|
|
CHEVELU* start_rat_list, CHEVELU* end_rat_list )
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* Routine utilisee par Tst_Ratsnest()
|
|
* Routine tres proche de gen_rats_block_to_block(..)
|
|
* Routine testant le chevelu entre 2 blocks ( supposes du meme net )
|
|
* la recherche est faite entre les pads du block 1 et les autres blocks
|
|
* le block n ( n > 1 ) est alors connecte au block 1 par le chevelu le plus court
|
|
* A la différence de gen_rats_block_to_block(..),
|
|
* l'analyse n'est pas faite pads a pads mais a travers la liste générale des chevelus.
|
|
* La routine active alors le chevelu le plus court reliant le block 1 au block n
|
|
* (etablissement d'une connexion "logique")
|
|
*
|
|
* Entree :
|
|
* pt_chain_pad = adresse de debut de zone pad utile
|
|
* pt_limite = adresse de fin de zone (borne non comprise)
|
|
* Sortie:
|
|
* Membre .state du chevelu sélectionné
|
|
* Retourne:
|
|
* nombre de blocks non connectes entre eux
|
|
*/
|
|
{
|
|
int current_num_block, min_block;
|
|
LISTE_PAD* pt_liste_pad;
|
|
CHEVELU* chevelu, * min_chevelu;
|
|
|
|
/* Recherche du chevelu le plus court d'un block a un autre block */
|
|
min_chevelu = NULL;
|
|
for( chevelu = start_rat_list; chevelu < end_rat_list; chevelu++ )
|
|
{
|
|
if( chevelu->pad_start->m_logical_connexion == chevelu->pad_end->m_logical_connexion )
|
|
continue;
|
|
if( min_chevelu == NULL )
|
|
min_chevelu = chevelu;
|
|
else if( min_chevelu->dist > chevelu->dist )
|
|
min_chevelu = chevelu;
|
|
}
|
|
|
|
if( min_chevelu == NULL )
|
|
return 1;
|
|
|
|
min_chevelu->status |= CH_ACTIF;
|
|
current_num_block = min_chevelu->pad_start->m_logical_connexion;
|
|
min_block = min_chevelu->pad_end->m_logical_connexion;
|
|
if( min_block > current_num_block )
|
|
EXCHG( min_block, current_num_block );
|
|
|
|
/* les 2 blocks vont etre fondus */
|
|
for( pt_liste_pad = pt_liste_pad_start; pt_liste_pad < pt_liste_pad_end; pt_liste_pad++ )
|
|
{
|
|
if( (*pt_liste_pad)->m_logical_connexion == current_num_block )
|
|
{
|
|
(*pt_liste_pad)->m_logical_connexion = min_block;
|
|
}
|
|
}
|
|
|
|
return current_num_block;
|
|
}
|
|
|
|
|
|
/*********************************************************************/
|
|
static int tst_rats_pad_to_pad( WinEDA_DrawPanel* DrawPanel, wxDC* DC,
|
|
int current_num_block,
|
|
CHEVELU* start_rat_list, CHEVELU* end_rat_list )
|
|
/**********************************************************************/
|
|
|
|
/*
|
|
* Routine utilisee par Tst_Ratsnest_general()
|
|
* Routine Activant le chevelu entre 2 pads ( supposes du meme net )
|
|
* la routine connecte 1 pad non deja connecte a un autre et active donc
|
|
* un certain nombre de blocks de pads liées par un chevelu
|
|
* Ces blocks sont donc constitués de 2 pads.
|
|
*
|
|
* Entree :
|
|
* pt_chain_pad = adresse de debut de zone pad
|
|
* pt_limite = adresse de fin de recherche (borne non comprise)
|
|
* current_num_block = numero du dernier block de pads (constitué par les connexions
|
|
* de pistes existantes
|
|
*
|
|
* Sortie:
|
|
* liste des chevelus ( structures)
|
|
* mise a jour du membre .state du chevelu activé
|
|
*
|
|
* Retourne:
|
|
* nombre de blocks crees (paquets de pads)
|
|
*/
|
|
{
|
|
D_PAD* pad_start, * pad_end;
|
|
CHEVELU* chevelu;
|
|
|
|
for( chevelu = start_rat_list; chevelu < end_rat_list; chevelu++ )
|
|
{
|
|
pad_start = chevelu->pad_start; pad_end = chevelu->pad_end;
|
|
/* Mise a jour du numero de block ( ou de sous graphe ) */
|
|
|
|
/* si aucun des 2 pads n'est deja connecte : creation d'un nouveau block */
|
|
if( (pad_start->m_logical_connexion == 0) && (pad_end->m_logical_connexion == 0) )
|
|
{
|
|
current_num_block++;
|
|
pad_start->m_logical_connexion = current_num_block;
|
|
pad_end->m_logical_connexion = current_num_block;
|
|
chevelu->status |= CH_ACTIF;
|
|
}
|
|
/* si 1 des 2 pads est deja connecte : mise a jour pour l'autre */
|
|
else if( pad_start->m_logical_connexion == 0 )
|
|
{
|
|
pad_start->m_logical_connexion = pad_end->m_logical_connexion;
|
|
chevelu->status |= CH_ACTIF;
|
|
}
|
|
else if( pad_end->m_logical_connexion == 0 )
|
|
{
|
|
pad_end->m_logical_connexion = pad_start->m_logical_connexion;
|
|
chevelu->status |= CH_ACTIF;
|
|
}
|
|
}
|
|
|
|
return current_num_block;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
void WinEDA_BasePcbFrame::Tst_Ratsnest( wxDC* DC, int ref_netcode )
|
|
/*******************************************************************/
|
|
|
|
/* calcul du chevelu actif
|
|
* Le chevelu général doit etre calculé
|
|
* Determite les chevelus ACTIFS dans la liste générale des chevelus
|
|
*/
|
|
{
|
|
LISTE_PAD* pt_liste_pad;
|
|
CHEVELU* chevelu;
|
|
D_PAD* pad;
|
|
int ii, num_block;
|
|
int net_code;
|
|
EQUIPOT* equipot;
|
|
|
|
if( m_Pcb->m_NbPads == 0 )
|
|
return;
|
|
|
|
for( net_code = 1; ; net_code++ )
|
|
{
|
|
equipot = m_Pcb->FindNet( net_code );
|
|
if( equipot == NULL )
|
|
break;
|
|
if( ref_netcode && (net_code != ref_netcode) )
|
|
continue;
|
|
|
|
num_block = 0;
|
|
pt_liste_pad = equipot->m_PadzoneStart;
|
|
for( ; pt_liste_pad < equipot->m_PadzoneEnd; pt_liste_pad++ )
|
|
{
|
|
pad = *pt_liste_pad;
|
|
pad->m_logical_connexion = pad->m_physical_connexion;
|
|
num_block = MAX( num_block, pad->m_logical_connexion );
|
|
}
|
|
|
|
for( chevelu = equipot->m_RatsnestStart; chevelu < equipot->m_RatsnestEnd; chevelu++ )
|
|
{
|
|
chevelu->status &= ~CH_ACTIF;
|
|
}
|
|
|
|
/* a - tst connexion des pads entre eux */
|
|
ii = tst_rats_pad_to_pad( DrawPanel, DC, num_block,
|
|
equipot->m_RatsnestStart, equipot->m_RatsnestEnd );
|
|
|
|
/* b - connexion des blocks formes precedemment (Iteration) */
|
|
while( ii > 1 )
|
|
{
|
|
ii = tst_rats_block_to_block( DrawPanel, DC,
|
|
equipot->m_PadzoneStart, equipot->m_PadzoneEnd,
|
|
equipot->m_RatsnestStart, equipot->m_RatsnestEnd );
|
|
}
|
|
}
|
|
|
|
m_Pcb->m_NbNoconnect = 0;
|
|
CHEVELU* Chevelu = m_Pcb->m_Ratsnest;
|
|
for( ii = m_Pcb->GetNumRatsnests(); ii > 0; ii--, Chevelu++ )
|
|
{
|
|
if( Chevelu->status & CH_ACTIF )
|
|
m_Pcb->m_NbNoconnect++;
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************/
|
|
int WinEDA_BasePcbFrame::Test_1_Net_Ratsnest( wxDC* DC, int ref_netcode )
|
|
/**************************************************************************/
|
|
/* Calcule le chevelu du net net_code */
|
|
{
|
|
DisplayRastnestInProgress = FALSE;
|
|
DrawGeneralRatsnest( DC, ref_netcode );
|
|
Tst_Ratsnest( DC, ref_netcode );
|
|
DrawGeneralRatsnest( DC, ref_netcode );
|
|
|
|
return m_Pcb->GetNumRatsnests();
|
|
}
|
|
|
|
|
|
/*****************************************************/
|
|
void WinEDA_BasePcbFrame::recalcule_pad_net_code()
|
|
/*****************************************************/
|
|
|
|
/*
|
|
* Calcule et met a jour les net_codes des PADS et des equipotentielles
|
|
* met a jour le buffer des equipotentielles
|
|
* A utiliser apres edition de nets sur un pad ou lecture d'une netliste
|
|
* positionne a 1 le bit NET_CODE_OK du status_pcb;
|
|
*/
|
|
{
|
|
LISTE_PAD* pad_ref, * pad_courant;
|
|
int ii, jj;
|
|
EQUIPOT* pt_equipot;
|
|
EDA_BaseStruct* PtStruct;
|
|
EQUIPOT** BufPtEquipot;
|
|
|
|
/* construction de la liste des adr des PADS */
|
|
build_liste_pads();
|
|
|
|
/* calcul des net_codes des pads */
|
|
ii = m_Pcb->m_NbPads;
|
|
m_Pcb->m_NbNodes = 0;
|
|
m_Pcb->m_NbNets = 0;
|
|
|
|
pad_courant = m_Pcb->m_Pads;
|
|
for( ; ii > 0; pad_courant++, ii-- )
|
|
{
|
|
if( (*pad_courant)->m_Netname.IsEmpty() ) // pad non connecte
|
|
{
|
|
(*pad_courant)->m_NetCode = 0; continue;
|
|
}
|
|
m_Pcb->m_NbNodes++;
|
|
/* si le netname a deja ete rencontre: mise a jour , sinon nouveau net_code */
|
|
pad_ref = m_Pcb->m_Pads;
|
|
while( pad_ref < pad_courant )
|
|
{
|
|
if( (*pad_ref)->m_Netname == (*pad_courant)->m_Netname )
|
|
break; // sont du meme met
|
|
pad_ref++;
|
|
}
|
|
|
|
/* si pad_ref = pad_courant: nouveau net sinon, deja net deja traite */
|
|
if( pad_ref == pad_courant )
|
|
{
|
|
m_Pcb->m_NbNets++; (*pad_courant)->m_NetCode = m_Pcb->m_NbNets;
|
|
}
|
|
else
|
|
(*pad_courant)->m_NetCode = (*pad_ref)->m_NetCode;
|
|
}
|
|
|
|
/* Construction ou correction de la liste des equipotentielles,
|
|
* et construction d'un tableau d'adressage des equipots*/
|
|
|
|
BufPtEquipot = (EQUIPOT**) MyMalloc( sizeof(EQUIPOT *) * (m_Pcb->m_NbNets + 1) );
|
|
pt_equipot = m_Pcb->m_Equipots;
|
|
PtStruct = (EDA_BaseStruct*) m_Pcb;
|
|
for( ii = 0; ii <= m_Pcb->m_NbNets; ii++ )
|
|
{
|
|
if( pt_equipot == NULL ) /* Creation d'une nouvelle equipot */
|
|
{
|
|
pt_equipot = new EQUIPOT( m_Pcb );
|
|
|
|
if( ii == 0 )
|
|
{
|
|
m_Pcb->m_Equipots = pt_equipot;
|
|
pt_equipot->Pback = m_Pcb;
|
|
}
|
|
else
|
|
{
|
|
PtStruct->Pnext = pt_equipot;
|
|
pt_equipot->Pback = PtStruct;
|
|
}
|
|
pt_equipot->Pnext = NULL;
|
|
}
|
|
|
|
pt_equipot->m_NetCode = ii; // Mise a jour du numero d'equipot
|
|
pt_equipot->m_NbNodes = 0;
|
|
pt_equipot->m_Netname.Empty();
|
|
|
|
BufPtEquipot[ii] = pt_equipot;
|
|
PtStruct = (EDA_BaseStruct*) pt_equipot;
|
|
pt_equipot = (EQUIPOT*) pt_equipot->Pnext;
|
|
}
|
|
|
|
/* Effacement des equipots inutiles */
|
|
|
|
while( pt_equipot )
|
|
{
|
|
PtStruct = pt_equipot->Pnext;
|
|
DeleteStructure( pt_equipot );
|
|
pt_equipot = (EQUIPOT*) PtStruct;
|
|
}
|
|
|
|
pad_courant = m_Pcb->m_Pads;
|
|
pt_equipot = m_Pcb->m_Equipots;
|
|
|
|
/* Placement des noms de net en structure EQUIPOT */
|
|
for( ii = m_Pcb->m_NbPads; ii > 0; pad_courant++, ii-- )
|
|
{
|
|
jj = (*pad_courant)->m_NetCode;
|
|
pt_equipot = BufPtEquipot[jj];
|
|
pt_equipot->m_NbNodes++;
|
|
if( pt_equipot->m_Netname.IsEmpty() )
|
|
{
|
|
pt_equipot->m_Netname = (*pad_courant)->m_Netname;
|
|
}
|
|
}
|
|
|
|
MyFree( BufPtEquipot );
|
|
m_Pcb->m_Status_Pcb |= NET_CODES_OK;
|
|
}
|
|
|
|
|
|
/***********************************************/
|
|
void WinEDA_BasePcbFrame::build_liste_pads()
|
|
/***********************************************/
|
|
|
|
/*
|
|
* construction de la liste ( sous forme d'une liste de stucture )
|
|
* des caract utiles des pads du PCB pour autoroutage,DRC .. )
|
|
* parametres:
|
|
* adresse du buffer de classement = buf_work
|
|
* retourne:
|
|
* 1ere adresse disponible si OK
|
|
* NULL si trop de pastilles
|
|
*
|
|
*
|
|
* Parametres de routage calcules et mis a jour
|
|
* - parametre net_code:
|
|
* numero de code interne de chaque net du PCB.
|
|
* permet d'accelerer les calculs de chevelu et de connexions
|
|
* - parametre .link est mis a jour
|
|
* pour chaque pastille, il indique le nombre d'autres pastilles du meme net
|
|
* appartenant au meme module.
|
|
*
|
|
* Variables globales mise a jour:
|
|
* pointeur base_adr_liste_pad (adr de classement de la liste des pads)
|
|
* nb_pads = nombre total de pastilles du PCB
|
|
* nb_nets = nombre de nets differents
|
|
* status_pcb |= LISTE_PAD_OK (flag permettant d'eviter la reexecution inutile
|
|
* de cette routine)
|
|
*/
|
|
{
|
|
LISTE_PAD* pt_liste_pad;
|
|
MODULE* Module;
|
|
D_PAD* PtPad;
|
|
|
|
if( m_Pcb->m_Status_Pcb & LISTE_PAD_OK )
|
|
return;
|
|
|
|
/* construction de la liste des pointeurs sur les structures D_PAD */
|
|
if( m_Pcb->m_Pads )
|
|
MyFree( m_Pcb->m_Pads );
|
|
m_Pcb->m_Pads = NULL;
|
|
|
|
/* Calcul du nombre de pads */
|
|
Module = m_Pcb->m_Modules; m_Pcb->m_NbPads = 0;
|
|
for( ; Module != NULL; Module = (MODULE*) Module->Pnext )
|
|
{
|
|
PtPad = (D_PAD*) Module->m_Pads;
|
|
for( ; PtPad != NULL; PtPad = (D_PAD*) PtPad->Pnext )
|
|
m_Pcb->m_NbPads++;
|
|
}
|
|
|
|
if( m_Pcb->m_NbPads == 0 )
|
|
return;
|
|
|
|
/* Allocation memoire du buffer */
|
|
pt_liste_pad = m_Pcb->m_Pads
|
|
= (D_PAD**) MyZMalloc( (m_Pcb->m_NbPads + 1) * sizeof(D_PAD *) );
|
|
m_Pcb->m_NbNodes = 0;
|
|
|
|
/* Initialisation du buffer et des variables de travail */
|
|
Module = m_Pcb->m_Modules;
|
|
for( ; Module != NULL; Module = (MODULE*) Module->Pnext )
|
|
{
|
|
PtPad = (D_PAD*) Module->m_Pads;
|
|
for( ; PtPad != NULL; PtPad = (D_PAD*) PtPad->Pnext )
|
|
{
|
|
*pt_liste_pad = PtPad;
|
|
PtPad->m_logical_connexion = 0;
|
|
PtPad->m_Parent = Module;
|
|
if( PtPad->m_NetCode )
|
|
m_Pcb->m_NbNodes++;
|
|
pt_liste_pad++;
|
|
}
|
|
}
|
|
|
|
*pt_liste_pad = NULL; // fin de liste
|
|
|
|
adr_lowmem = buf_work;
|
|
if( m_Pcb->m_Ratsnest )
|
|
MyFree( m_Pcb->m_Ratsnest );
|
|
m_Pcb->m_Ratsnest = NULL;
|
|
m_Pcb->m_Status_Pcb = LISTE_PAD_OK;
|
|
}
|
|
|
|
|
|
/*****************************************************************************/
|
|
char* WinEDA_BasePcbFrame::build_ratsnest_module( wxDC* DC, MODULE* Module )
|
|
/*****************************************************************************/
|
|
|
|
/*
|
|
* construction de la liste en mode de calcul rapide pour affichage
|
|
* en temps reel lors des deplacements du chevelu d'un module.
|
|
*
|
|
* parametres d'appel:
|
|
* Module = pointeur sur module dont le ratsnest est a calculer
|
|
*
|
|
* retourne: adresse memoire disponible
|
|
* Le chevelu calcule comporte 2 parties
|
|
* - un chevelu interne relatif aux pads du module appartenant a un
|
|
* meme net. Il est calcule 1 seule fois
|
|
* - le chevelu externe reliant un pad interne a un pad externe au module
|
|
* Ce chevelu est recalcule a chaque deplacement
|
|
*/
|
|
{
|
|
LISTE_PAD* pt_liste_pad,
|
|
* pt_liste_ref,
|
|
* pt_liste_generale;
|
|
D_PAD* pad_ref,
|
|
* pad_externe;
|
|
LISTE_PAD* pt_liste_pad_limite,
|
|
* pt_start_liste,
|
|
* pt_end_liste;
|
|
int ii, jj;
|
|
CHEVELU* local_chevelu;
|
|
static CHEVELU* pt_fin_int_chevelu; // pointeur sur la fin de la liste
|
|
// des chevelus internes au module
|
|
static int nb_int_chevelu; // nombre e chevelus internes
|
|
int current_net_code;
|
|
int increment, distance; // variables de calcul de ratsnest
|
|
int pad_pos_X, pad_pos_Y; // position reelle des pads du module en mouvement
|
|
|
|
|
|
if( (m_Pcb->m_Status_Pcb & LISTE_PAD_OK) == 0 )
|
|
build_liste_pads();
|
|
|
|
/* construction de la liste des pads du module si necessaire */
|
|
if( (m_Pcb->m_Status_Pcb & CHEVELU_LOCAL_OK) != 0 )
|
|
goto calcul_chevelu_ext;
|
|
|
|
/* calcul du chevelu "interne", c.a.d. liant les seuls pads du module */
|
|
pt_liste_pad = (LISTE_PAD*) adr_lowmem; nb_pads_ref = 0;
|
|
pad_ref = Module->m_Pads;
|
|
for( ; pad_ref != NULL; pad_ref = (D_PAD*) pad_ref->Pnext )
|
|
{
|
|
if( pad_ref->m_NetCode == 0 )
|
|
continue;
|
|
*pt_liste_pad = pad_ref;
|
|
pad_ref->m_logical_connexion = 0;
|
|
pad_ref->m_physical_connexion = 0;
|
|
pt_liste_pad++; nb_pads_ref++;
|
|
}
|
|
|
|
if( nb_pads_ref == 0 )
|
|
return (char*) pt_liste_pad; /* pas de connexions! */
|
|
|
|
qsort( adr_lowmem, nb_pads_ref, sizeof(D_PAD *),
|
|
( int( * ) ( const void*, const void* ) )tri_par_net );
|
|
|
|
/* construction de la liste des pads connectes aux pads de ce module */
|
|
DisplayRastnestInProgress = FALSE;
|
|
pt_liste_ref = (LISTE_PAD*) adr_lowmem;
|
|
nb_pads_externes = 0; current_net_code = 0;
|
|
for( ii = 0; ii < nb_pads_ref; ii++ )
|
|
{
|
|
pad_ref = pt_liste_ref[ii];
|
|
if( pad_ref->m_NetCode == current_net_code )
|
|
continue;
|
|
current_net_code = pad_ref->m_NetCode;
|
|
|
|
pt_liste_generale = m_Pcb->m_Pads;
|
|
for( jj = m_Pcb->m_NbPads; jj > 0; jj-- )
|
|
{
|
|
pad_externe = *pt_liste_generale; pt_liste_generale++;
|
|
if( pad_externe->m_NetCode != current_net_code )
|
|
continue;
|
|
if( pad_externe->m_Parent == Module )
|
|
continue;
|
|
pad_externe->m_logical_connexion = 0;
|
|
pad_externe->m_physical_connexion = 0;
|
|
*pt_liste_pad = pad_externe; pt_liste_pad++;
|
|
nb_pads_externes++;
|
|
}
|
|
}
|
|
|
|
/* tri par net_codes croissants de la liste des pads externes */
|
|
qsort( pt_liste_ref + nb_pads_ref, nb_pads_externes, sizeof(D_PAD *),
|
|
( int( * ) ( const void*, const void* ) )tri_par_net );
|
|
|
|
/* calcul du chevelu interne au module:
|
|
* Ce calcul est identique au calcul du chevelu general, mais il est
|
|
* restreint aux seuls pads du module courant */
|
|
local_liste_chevelu = (CHEVELU*) (pt_liste_pad); // buffer chevelu a la suite de la liste des pads
|
|
nb_local_chevelu = 0;
|
|
pt_liste_ref = (LISTE_PAD*) adr_lowmem;
|
|
|
|
g_pt_chevelu = local_liste_chevelu;
|
|
pt_liste_pad = pt_start_liste = (LISTE_PAD*) adr_lowmem;
|
|
pt_liste_pad_limite = pt_liste_pad + nb_pads_ref;
|
|
current_net_code = (*pt_liste_pad)->m_NetCode;
|
|
|
|
for( ; pt_liste_pad < pt_liste_pad_limite; )
|
|
{
|
|
/* Recherche de la fin de la liste des pads du net courant */
|
|
|
|
for( pt_end_liste = pt_liste_pad + 1; ; pt_end_liste++ )
|
|
{
|
|
if( pt_end_liste >= pt_liste_pad_limite )
|
|
break;
|
|
if( (*pt_end_liste)->m_NetCode != current_net_code )
|
|
break;
|
|
}
|
|
|
|
/* fin de liste trouvee : */
|
|
/* a - connexion des pads entre eux */
|
|
ii = gen_rats_pad_to_pad( DrawPanel, DC, pt_start_liste, pt_end_liste,
|
|
0, &nb_local_chevelu );
|
|
|
|
/* b - connexion des blocks formes precedemment (Iteration) */
|
|
while( ii > 1 )
|
|
{
|
|
ii = gen_rats_block_to_block( DrawPanel, DC, pt_liste_pad,
|
|
pt_end_liste, &nb_local_chevelu );
|
|
}
|
|
|
|
pt_liste_pad = pt_start_liste = pt_end_liste;
|
|
if( pt_start_liste < pt_liste_pad_limite )
|
|
current_net_code = (*pt_start_liste)->m_NetCode;
|
|
}
|
|
|
|
pt_fin_int_chevelu = local_chevelu = g_pt_chevelu;
|
|
nb_int_chevelu = nb_local_chevelu;
|
|
|
|
/* Mise a 1 du flag LOCAL */
|
|
g_pt_chevelu = local_liste_chevelu;
|
|
while( g_pt_chevelu < pt_fin_int_chevelu )
|
|
{
|
|
g_pt_chevelu->status = LOCAL_CHEVELU; g_pt_chevelu++;
|
|
}
|
|
|
|
m_Pcb->m_Status_Pcb |= CHEVELU_LOCAL_OK;
|
|
|
|
/////////////////////////////////////////
|
|
// calcul du chevelu externe au module //
|
|
/////////////////////////////////////////
|
|
calcul_chevelu_ext:
|
|
|
|
/* Cette partie est executee a chaque deplacement du module: on calcule
|
|
* pour chaque pad du module courant la + courte distance a un pad externe.
|
|
* Pour chaque groupe de pad du module courant appartenant a un meme net,
|
|
* on ne garde qu'un seul chevelu: le plus court.
|
|
*/
|
|
local_chevelu = pt_fin_int_chevelu;
|
|
nb_local_chevelu = nb_int_chevelu;
|
|
pt_liste_ref = (LISTE_PAD*) adr_lowmem;
|
|
pad_ref = *pt_liste_ref;
|
|
current_net_code = pad_ref->m_NetCode;
|
|
local_chevelu->dist = 0x7FFFFFFF;
|
|
local_chevelu->status = 0;
|
|
increment = 0;
|
|
for( ii = 0; ii < nb_pads_ref; ii++ )
|
|
{
|
|
pad_ref = *(pt_liste_ref + ii);
|
|
if( pad_ref->m_NetCode != current_net_code )
|
|
{ /* un nouveau chevelu est cree (si necessaire) pour
|
|
* chaque nouveau net */
|
|
if( increment )
|
|
{
|
|
nb_local_chevelu++; local_chevelu++;
|
|
}
|
|
increment = 0;
|
|
current_net_code = pad_ref->m_NetCode;
|
|
local_chevelu->dist = 0x7FFFFFFF;
|
|
}
|
|
|
|
pad_pos_X = pad_ref->m_Pos.x - g_Offset_Module.x;
|
|
pad_pos_Y = pad_ref->m_Pos.y - g_Offset_Module.y;
|
|
pt_liste_generale = pt_liste_ref + nb_pads_ref;
|
|
|
|
for( jj = nb_pads_externes; jj > 0; jj-- )
|
|
{
|
|
pad_externe = *pt_liste_generale; pt_liste_generale++;
|
|
/* les netcodes doivent etre identiques */
|
|
if( pad_externe->m_NetCode < pad_ref->m_NetCode )
|
|
continue;
|
|
if( pad_externe->m_NetCode > pad_ref->m_NetCode )
|
|
break;
|
|
distance = abs( pad_externe->m_Pos.x - pad_pos_X ) +
|
|
abs( pad_externe->m_Pos.y - pad_pos_Y );
|
|
if( distance < local_chevelu->dist )
|
|
{
|
|
local_chevelu->pad_start = pad_ref;
|
|
local_chevelu->pad_end = pad_externe;
|
|
local_chevelu->m_NetCode = pad_ref->m_NetCode;
|
|
local_chevelu->dist = distance;
|
|
local_chevelu->status = 0;
|
|
increment = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( increment ) // fin de balayage : le ratsnest courant doit etre memorise
|
|
{
|
|
nb_local_chevelu++; local_chevelu++;
|
|
}
|
|
|
|
/* Retourne l'adr de la zone disponible */
|
|
adr_max = MAX( adr_max, (char*) (local_chevelu + 1) );
|
|
|
|
return (char*) (local_chevelu + 1); /* la struct pointee par
|
|
* local_chevelu est utilisee
|
|
* pour des calculs temporaires */
|
|
}
|
|
|
|
|
|
/***********************************************************/
|
|
void WinEDA_BasePcbFrame::trace_ratsnest_module( wxDC* DC )
|
|
/**********************************************************/
|
|
|
|
/*
|
|
* affiche le chevelu d'un module calcule en mode rapide.
|
|
* retourne: rien
|
|
*/
|
|
{
|
|
CHEVELU* local_chevelu;
|
|
int ii;
|
|
|
|
if( (m_Pcb->m_Status_Pcb & CHEVELU_LOCAL_OK) == 0 )
|
|
return;
|
|
|
|
local_chevelu = local_liste_chevelu;
|
|
ii = nb_local_chevelu;
|
|
|
|
GRSetDrawMode( DC, GR_XOR );
|
|
|
|
while( ii-- > 0 )
|
|
{
|
|
if( local_chevelu->status & LOCAL_CHEVELU )
|
|
{
|
|
GRLine( &DrawPanel->m_ClipBox, DC,
|
|
local_chevelu->pad_start->m_Pos.x - g_Offset_Module.x,
|
|
local_chevelu->pad_start->m_Pos.y - g_Offset_Module.y,
|
|
local_chevelu->pad_end->m_Pos.x - g_Offset_Module.x,
|
|
local_chevelu->pad_end->m_Pos.y - g_Offset_Module.y,
|
|
0, YELLOW );
|
|
}
|
|
else
|
|
{
|
|
GRLine( &DrawPanel->m_ClipBox, DC,
|
|
local_chevelu->pad_start->m_Pos.x - g_Offset_Module.x,
|
|
local_chevelu->pad_start->m_Pos.y - g_Offset_Module.y,
|
|
local_chevelu->pad_end->m_Pos.x,
|
|
local_chevelu->pad_end->m_Pos.y,
|
|
0, g_DesignSettings.m_RatsnestColor );
|
|
}
|
|
local_chevelu++;
|
|
}
|
|
}
|
|
|
|
|
|
/*********************************************************************************************/
|
|
/* int * WinEDA_BasePcbFrame::build_ratsnest_pad(D_PAD * pad_ref, const wxPoint & refpos) */
|
|
/*********************************************************************************************/
|
|
|
|
/*
|
|
* construction de la liste en mode de calcul rapide pour affichage
|
|
* en temps reel du chevelu d'un pad lors des tracés d'une piste démarrant
|
|
* sur ce pad.
|
|
*
|
|
* parametres d'appel:
|
|
* pad_ref ( si null : mise a 0 du nombre de chevelus )
|
|
* ox, oy = coord de l'extremite de la piste en trace
|
|
* init (flag)
|
|
* = 0 : mise a jour des chevelu
|
|
* <> 0: creation de la liste
|
|
* retourne: adresse memoire disponible
|
|
*/
|
|
|
|
/* routine locale de tri par longueur de links utilisee par la fonction QSORT */
|
|
static int sort_by_localnetlength( int* ref, int* compare )
|
|
{
|
|
int* org = (int*) adr_lowmem;
|
|
int ox = *org++;
|
|
int oy = *org++;
|
|
int lengthref, lengthcmp;
|
|
|
|
lengthref = abs( *ref - ox );
|
|
ref++;
|
|
lengthref += abs( *ref - oy ); // = longueur entre point origine et pad ref
|
|
lengthcmp = abs( *compare - ox );
|
|
compare++;
|
|
lengthcmp += abs( *compare - oy ); // = longueur entre point origine et pad comparé
|
|
|
|
return lengthref - lengthcmp;
|
|
}
|
|
|
|
|
|
/****************************************************************************************/
|
|
int* WinEDA_BasePcbFrame::build_ratsnest_pad( EDA_BaseStruct* ref,
|
|
const wxPoint& refpos, bool init )
|
|
/****************************************************************************************/
|
|
{
|
|
int ii;
|
|
int* pt_coord, * base_data;
|
|
int current_net_code = 0, conn_number = 0;
|
|
LISTE_PAD* padlist;
|
|
D_PAD* pad_ref = NULL;
|
|
|
|
if( ( (m_Pcb->m_Status_Pcb & LISTE_CHEVELU_OK) == 0 )
|
|
|| ( (m_Pcb->m_Status_Pcb & LISTE_PAD_OK) == 0 ) )
|
|
{
|
|
nb_local_chevelu = 0;
|
|
return NULL;
|
|
}
|
|
|
|
|
|
base_data = pt_coord = (int*) adr_lowmem;
|
|
local_liste_chevelu = (CHEVELU*) pt_coord;
|
|
if( init )
|
|
{
|
|
nb_local_chevelu = 0;
|
|
if( ref == NULL )
|
|
return NULL;
|
|
|
|
switch( ref->Type() )
|
|
{
|
|
case TYPEPAD:
|
|
pad_ref = (D_PAD*) ref;
|
|
current_net_code = pad_ref->m_NetCode;
|
|
conn_number = pad_ref->m_physical_connexion;
|
|
break;
|
|
|
|
case TYPETRACK:
|
|
case TYPEVIA:
|
|
{
|
|
TRACK* track_ref = (TRACK*) ref;
|
|
current_net_code = track_ref->m_NetCode;
|
|
conn_number = track_ref->m_Sous_Netcode;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
;
|
|
}
|
|
|
|
if( current_net_code <= 0 )
|
|
return NULL;
|
|
|
|
*pt_coord = refpos.x; pt_coord++;
|
|
*pt_coord = refpos.y; pt_coord++;
|
|
|
|
if( m_Pcb->m_Ratsnest == NULL )
|
|
return NULL;
|
|
|
|
padlist = m_Pcb->m_Pads;
|
|
for( ii = 0; ii < m_Pcb->m_NbPads; padlist++, ii++ )
|
|
{
|
|
D_PAD* pad = *padlist;
|
|
if( pad->m_NetCode != current_net_code )
|
|
continue;
|
|
if( pad == pad_ref )
|
|
continue;
|
|
if( !pad->m_physical_connexion || (pad->m_physical_connexion != conn_number) )
|
|
{
|
|
*pt_coord = pad->m_Pos.x; pt_coord++;
|
|
*pt_coord = pad->m_Pos.y; pt_coord++;
|
|
nb_local_chevelu++;
|
|
}
|
|
}
|
|
} /* Fin Init */
|
|
else if( nb_local_chevelu )
|
|
{
|
|
*pt_coord = refpos.x; *(pt_coord + 1) = refpos.y;
|
|
}
|
|
|
|
qsort( base_data + 2, nb_local_chevelu, 2 * sizeof(int),
|
|
( int( * ) ( const void*, const void* ) )sort_by_localnetlength );
|
|
return pt_coord;
|
|
}
|
|
|
|
|
|
/*******************************************************/
|
|
void WinEDA_BasePcbFrame::trace_ratsnest_pad( wxDC* DC )
|
|
/*******************************************************/
|
|
|
|
/*
|
|
* affiche le "chevelu" d'un pad lors des trace de segments de piste
|
|
*/
|
|
{
|
|
int* pt_coord;
|
|
int ii;
|
|
int refX, refY;
|
|
|
|
if( (m_Pcb->m_Status_Pcb & LISTE_CHEVELU_OK) == 0 )
|
|
return;
|
|
if( nb_local_chevelu == 0 )
|
|
return;
|
|
if( local_liste_chevelu == NULL )
|
|
return;
|
|
|
|
pt_coord = (int*) local_liste_chevelu;
|
|
refX = *pt_coord; pt_coord++;
|
|
refY = *pt_coord; pt_coord++;
|
|
|
|
GRSetDrawMode( DC, GR_XOR );
|
|
for( ii = 0; ii < nb_local_chevelu; ii++ )
|
|
{
|
|
if( ii >= g_MaxLinksShowed )
|
|
break;
|
|
GRLine( &DrawPanel->m_ClipBox, DC, refX, refY, *pt_coord, *(pt_coord + 1),
|
|
0, YELLOW );
|
|
pt_coord += 2;
|
|
}
|
|
}
|