/************************************/ /**** 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; pt_equipot ->DeleteStructure(); 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; } }