kicad/pcbnew/track.cpp

432 lines
13 KiB
C++

/*********************************************/
/* Edition des pistes: Routines d'effacement */
/* Effacement de segment, piste, net et zone */
/*********************************************/
#include "fctsys.h"
#include "common.h"
#include "pcbnew.h"
#include "protos.h"
class TSTSEGM /* memorisation des segments marques */
{
public:
TSTSEGM* Pnext, * Pback;
TRACK* RefTrack;
public:
TSTSEGM( TRACK * Father ) {
Pback = Pnext = NULL;
RefTrack = Father;
}
};
/* Routines externes : */
void Montre_Position_New_Piste( int flag );/* defini dans editrack.cc */
/* Routines Locales */
static void Marque_Chaine_segments( BOARD* Pcb, wxPoint ref_pos, int masklayer );
/* Variables locales */
TSTSEGM* ListSegm = NULL;
/****************************************************************************/
TRACK* Marque_Une_Piste( WinEDA_BasePcbFrame* frame, wxDC* DC,
TRACK* pt_segm, int* nb_segm, int flagcolor )
/****************************************************************************/
/* Routine de Marquage de 1 piste, a partir du segment pointe par pt_segm.
* le segment pointe est marque puis les segments connectes
* jusqu'a un pad ou un point de jonction de plus de 2 segments
* le marquage est la mise a 1 du bit BUSY
* Les segments sont ensuite reclasses pour etre contigus en liste chainee
* Retourne:
* adresse du 1er segment de la chaine creee
* nombre de segments
*/
{
int NbSegmBusy, masque_layer;
TRACK* Track, * FirstTrack, * NextTrack;
TSTSEGM* Segm, * NextSegm;
*nb_segm = 0;
if( pt_segm == NULL )
return NULL;
/* Marquage du segment pointe */
if( flagcolor )
pt_segm->Draw( frame->DrawPanel, DC, flagcolor );
pt_segm->SetState( BUSY, ON );
masque_layer = pt_segm->ReturnMaskLayer();
ListSegm = new TSTSEGM( pt_segm );
/* Traitement du segment pointe : si c'est un segment, le cas est simple.
* Si c'est une via, on doit examiner le nombre de segments connectes.
* Si <=2, on doit detecter une piste, si > 2 seule la via est marquee
*/
if( pt_segm->Type() == TYPEVIA )
{
TRACK* Segm1, * Segm2 = NULL, * Segm3 = NULL;
Segm1 = Fast_Locate_Piste( frame->m_Pcb->m_Track, NULL,
pt_segm->m_Start, masque_layer );
if( Segm1 )
{
Segm2 = Fast_Locate_Piste( (TRACK*) Segm1->Pnext, NULL,
pt_segm->m_Start, masque_layer );
}
if( Segm2 )
{
Segm3 = Fast_Locate_Piste( (TRACK*) Segm2->Pnext, NULL,
pt_segm->m_Start, masque_layer );
}
if( Segm3 )
{
*nb_segm = 1; return pt_segm;
}
if( Segm1 )
{
masque_layer = Segm1->ReturnMaskLayer();
Marque_Chaine_segments( frame->m_Pcb, pt_segm->m_Start, masque_layer );
}
if( Segm2 )
{
masque_layer = Segm2->ReturnMaskLayer();
Marque_Chaine_segments( frame->m_Pcb, pt_segm->m_Start, masque_layer );
}
}
else /* Marquage de la chaine connectee aux extremites du segment */
{
Marque_Chaine_segments( frame->m_Pcb, pt_segm->m_Start, masque_layer );
Marque_Chaine_segments( frame->m_Pcb, pt_segm->m_End, masque_layer );
}
/* marquage des vias (vias non connectees ou inutiles */
for( Segm = ListSegm; Segm != NULL; Segm = Segm->Pnext )
{
int layer;
if( Segm->RefTrack->Type() != TYPEVIA )
continue;
if( Segm->RefTrack == pt_segm )
continue;
Segm->RefTrack->SetState( BUSY, ON );
masque_layer = Segm->RefTrack->ReturnMaskLayer();
Track = Fast_Locate_Piste( frame->m_Pcb->m_Track, NULL,
Segm->RefTrack->m_Start,
masque_layer );
if( Track == NULL )
continue;
/* Test des connexions: si via utile: suppression marquage */
layer = Track->GetLayer();
while( ( Track = Fast_Locate_Piste( (TRACK*) Track->Pnext, NULL,
Segm->RefTrack->m_Start,
masque_layer ) ) != NULL )
{
if( layer != Track->GetLayer() )
{
Segm->RefTrack->SetState( BUSY, OFF );
break;
}
}
}
/* liberation memoire */
for( Segm = ListSegm; Segm != NULL; Segm = NextSegm )
{
NextSegm = Segm->Pnext;
delete Segm;
}
ListSegm = NULL;
/* Reclassement des segments marques en une chaine */
FirstTrack = frame->m_Pcb->m_Track; NbSegmBusy = 0;
for( ; FirstTrack != NULL; FirstTrack = (TRACK*) FirstTrack->Pnext )
{
/* recherche du debut de la liste des segments marques a BUSY */
if( FirstTrack->GetState( BUSY ) )
{
NbSegmBusy = 1;
break;
}
}
/* Reclassement de la chaine debutant a FirstTrack et finissant
* au dernier segment marque. FirstTrack n'est pas modifie */
Track = (TRACK*) FirstTrack->Pnext;
for( ; Track != NULL; Track = NextTrack )
{
NextTrack = (TRACK*) Track->Pnext;
if( Track->GetState( BUSY ) )
{
NbSegmBusy++;
Track->UnLink();
Track->Insert( frame->m_Pcb, FirstTrack );
}
}
*nb_segm = NbSegmBusy;
if( flagcolor )
Trace_Une_Piste( frame->DrawPanel, DC, FirstTrack, NbSegmBusy, flagcolor );
return FirstTrack;
}
/********************************************************************************/
static void Marque_Chaine_segments( BOARD* Pcb, wxPoint ref_pos, int masque_layer )
/********************************************************************************/
/*
* routine utilisee par Supprime_1_Piste()
* Positionne le bit BUSY dans la chaine de segments commencant
* au point ox, oy sur la couche layer
*
* Les vias sont mises en liste des segments traites mais ne sont pas
* marquees.
*/
{
TRACK* pt_segm, // Pointe le segment courant analyse
* pt_via, // pointe la via reperee, eventuellement a detruire
* MarqSegm; // pointe le segment a detruire (= NULL ou pt_segm
int NbSegm;
TSTSEGM* Segm;
if( Pcb->m_Track == NULL )
return;
/* Marquage de la chaine */
for( ; ; )
{
if( Fast_Locate_Pad_Connecte( Pcb, ref_pos, masque_layer ) != NULL )
return;
/* Localisation d'une via (car elle connecte plusieurs segments) */
pt_via = Fast_Locate_Via( Pcb->m_Track, NULL, ref_pos, masque_layer );
if( pt_via )
{
if( pt_via->GetState( EDIT ) )
return;
masque_layer = pt_via->ReturnMaskLayer();
Segm = new TSTSEGM( pt_via );
Segm->Pnext = ListSegm;
ListSegm->Pback = Segm;
ListSegm = Segm;
}
/* Recherche des segments connectes au point ref_pos
* si 1 segment: peut etre marque
* si > 1 segment:
* le segment ne peut etre marque
*/
pt_segm = Pcb->m_Track; MarqSegm = NULL;
NbSegm = 0;
while( ( pt_segm = Fast_Locate_Piste( pt_segm, NULL,
ref_pos, masque_layer ) ) != NULL )
{
if( pt_segm->GetState( EDIT ) ) /* Fin de piste */
return;
if( pt_segm->GetState( BUSY ) )
{
pt_segm = (TRACK*) pt_segm->Pnext;
continue;
}
if( pt_segm == pt_via ) /* deja traite */
{
pt_segm = (TRACK*) pt_segm->Pnext;
continue;
}
NbSegm++;
if( NbSegm == 1 ) /* 1ere detection de segment de piste */
{
MarqSegm = pt_segm;
pt_segm = (TRACK*) pt_segm->Pnext;
}
else /* 2eme detection de segment -> fin de piste */
{
return;
}
}
if( MarqSegm )
{
/* preparation de la nouvelle recherche */
masque_layer = MarqSegm->ReturnMaskLayer();
if( ref_pos == MarqSegm->m_Start )
{
ref_pos = MarqSegm->m_End;
}
else
{
ref_pos = MarqSegm->m_Start;
}
pt_segm = Pcb->m_Track; /* reinit recherche des segments */
/* Marquage et mise en liste du segment */
Segm = new TSTSEGM( MarqSegm );
Segm->Pnext = ListSegm;
ListSegm->Pback = Segm;
ListSegm = Segm;
MarqSegm->SetState( BUSY, ON );
}
else
return;
}
}
/********************************************************/
int ReturnEndsTrack( TRACK* RefTrack, int NbSegm,
TRACK** StartTrack, TRACK** EndTrack )
/**********************************************************/
/* Calcule les coordonnes des extremites d'une piste
* retourne 1 si OK, 0 si piste bouclee
* Retourne dans *StartTrack en *EndTrack les segments de debut et fin
* Les coord StartTrack->m_Start.x, m_Start.y contiennent le debut de la piste
* Les coord EndTrack->m_End.x, m_End.y contiennent le debut de la piste
* Les segments sont supposes chaines de facon consecutive
*/
{
TRACK* Track, * via, * segm, * TrackListEnd;
int NbEnds, masque_layer, ii, ok = 0;
if( NbSegm <= 1 )
{
*StartTrack = *EndTrack = RefTrack;
return 1; /* cas trivial */
}
/* calcul de la limite d'analyse */
*StartTrack = *EndTrack = NULL;
TrackListEnd = Track = RefTrack; ii = 0;
for( ; (Track != NULL) && (ii < NbSegm); ii++, Track = (TRACK*) Track->Pnext )
{
TrackListEnd = Track;
Track->m_Param = 0;
}
/* Calcul des extremites */
NbEnds = 0; Track = RefTrack; ii = 0;
for( ; (Track != NULL) && (ii < NbSegm); ii++, Track = (TRACK*) Track->Pnext )
{
if( Track->Type() == TYPEVIA )
continue;
masque_layer = Track->ReturnMaskLayer();
via = Fast_Locate_Via( RefTrack, TrackListEnd,
Track->m_Start, masque_layer );
if( via )
{
masque_layer |= via->ReturnMaskLayer();
via->SetState( BUSY, ON );
}
Track->SetState( BUSY, ON );
segm = Fast_Locate_Piste( RefTrack, TrackListEnd,
Track->m_Start, masque_layer );
Track->SetState( BUSY, OFF );
if( via )
via->SetState( BUSY, OFF );
if( segm == NULL )
{
switch( NbEnds )
{
case 0:
*StartTrack = Track; NbEnds++;
break;
case 1:
int BeginPad, EndPad;
*EndTrack = Track;
/* permutation de ox,oy avec fx,fy */
BeginPad = Track->GetState( BEGIN_ONPAD );
EndPad = Track->GetState( END_ONPAD );
Track->SetState( BEGIN_ONPAD | END_ONPAD, OFF );
if( BeginPad )
Track->SetState( END_ONPAD, ON );
if( EndPad )
Track->SetState( BEGIN_ONPAD, ON );
EXCHG( Track->m_Start, Track->m_End );
EXCHG( Track->start, Track->end );
ok = 1; return ok;
}
}
masque_layer = Track->ReturnMaskLayer();
via = Fast_Locate_Via( RefTrack, TrackListEnd,
Track->m_End, masque_layer );
if( via )
{
masque_layer |= via->ReturnMaskLayer();
via->SetState( BUSY, ON );
}
Track->SetState( BUSY, ON );
segm = Fast_Locate_Piste( RefTrack, TrackListEnd,
Track->m_End, masque_layer );
Track->SetState( BUSY, OFF );
if( via )
via->SetState( BUSY, OFF );
if( segm == NULL )
{
switch( NbEnds )
{
case 0:
int BeginPad, EndPad;
*StartTrack = Track; NbEnds++;
/* permutation de ox,oy avec fx,fy */
BeginPad = Track->GetState( BEGIN_ONPAD );
EndPad = Track->GetState( END_ONPAD );
Track->SetState( BEGIN_ONPAD | END_ONPAD, OFF );
if( BeginPad )
Track->SetState( END_ONPAD, ON );
if( EndPad )
Track->SetState( BEGIN_ONPAD, ON );
EXCHG( Track->m_Start, Track->m_End );
EXCHG( Track->start, Track->end );
break;
case 1:
*EndTrack = Track;
ok = 1; return ok;
}
}
}
return ok;
}
/***************************************************************************/
void ListSetState( EDA_BaseStruct* Start, int NbItem, int State, int onoff )
/***************************************************************************/
/* Met a jour le membre .state d'une chaine de structures
*/
{
if( Start == NULL )
return;
for( ; (Start != NULL) && (NbItem > 0); NbItem--, Start = Start->Pnext )
{
Start->SetState( State, onoff );
}
}