		/*******************************/
		/* Edition des pistes			*/
		/* Routines de trace de pistes */
		/*******************************/

#include "fctsys.h"
#include "gr_basic.h"

#include "common.h"
#include "pcbnew.h"
#include "autorout.h"

#include "protos.h"


/* Routines Locales */
static void Exit_Editrack(WinEDA_DrawFrame * frame, wxDC *DC);
void ShowNewTrackWhenMovingCursor(WinEDA_DrawPanel * panel,
				wxDC * DC, bool erase);
static int Met_Coude_a_45(WinEDA_BasePcbFrame * frame, wxDC * DC,
						TRACK * ptfinsegment);
static void ComputeBreakPoint( TRACK * track, int n );
static TRACK * DeleteNullTrackSegments(BOARD * pcb, TRACK * track, int * segmcount);
static void EnsureEndTrackOnPad(D_PAD * Pad);

/* variables locales */
static int OldNetCodeSurbrillance;
static int OldEtatSurbrillance;


/************************************************************/
static void Exit_Editrack(WinEDA_DrawFrame * _frame, wxDC *DC)
/************************************************************/
/* routine d'annulation de la Commande Begin_Route si une piste est en cours
	de tracage, ou de sortie de l'application EDITRACK.
 */
{
WinEDA_PcbFrame * frame = (WinEDA_PcbFrame *) _frame;
TRACK * track = (TRACK * ) frame->GetScreen()->m_CurrentItem;

	if( track != NULL )
	{
		/* Erase the current drawing */
		ShowNewTrackWhenMovingCursor(frame->DrawPanel, DC, FALSE);
		if(g_HightLigt_Status) ( (WinEDA_PcbFrame *)frame)->Hight_Light(DC);
		g_HightLigth_NetCode = OldNetCodeSurbrillance;
		if(OldEtatSurbrillance) ( (WinEDA_PcbFrame *)frame)->Hight_Light(DC);

		frame->MsgPanel->EraseMsgBox();
		TRACK * previoustrack;
		// Delete current (new) track
		for(  ;track != NULL; track = previoustrack)
		{
			previoustrack = (TRACK*) track->Pback;
			delete track;
		}
	}
	frame->GetScreen()->ManageCurseur = NULL;
	frame->GetScreen()->ForceCloseManageCurseur = NULL;
	frame->GetScreen()->m_CurrentItem = NULL;
}


/*************************************************************/
TRACK * WinEDA_PcbFrame::Begin_Route(TRACK * track, wxDC * DC)
/*************************************************************/
/*
Routine d'initialisation d'un trace de piste et/ou de mise en place d'un
nouveau point piste

	Si pas de piste en cours de trace:
		- Recherche de netname de la nouvelle piste ( pad de depart out netname
		 de la piste si depart sur une ancienne piste
		- Met en surbrillance tout le net
		- Initilise les divers pointeurs de trace
	Si piste en cours:
		- controle DRC
		- si DRC OK : addition d'un nouveau point piste
*/
{
D_PAD * pt_pad = NULL;
TRACK * adr_buf = NULL, * Track;
int masquelayer = g_TabOneLayerMask[GetScreen()->m_Active_Layer];
EDA_BaseStruct * LockPoint;
wxPoint pos = GetScreen()->m_Curseur;

	GetScreen()->ManageCurseur = ShowNewTrackWhenMovingCursor;
	GetScreen()->ForceCloseManageCurseur = Exit_Editrack;

	if(track == NULL )	/* debut reel du trace */
	{
		/* effacement surbrillance ancienne */
		OldNetCodeSurbrillance = g_HightLigth_NetCode;
		OldEtatSurbrillance = g_HightLigt_Status;

		if(g_HightLigt_Status) Hight_Light(DC);

		g_FirstTrackSegment = g_CurrentTrackSegment = new TRACK(m_Pcb);
		g_CurrentTrackSegment->m_Flags = IS_NEW;
		g_TrackSegmentCount = 1;
		g_HightLigth_NetCode = 0;

		/* Localisation de la pastille de reference de la piste: */
		LockPoint = LocateLockPoint(m_Pcb, pos, masquelayer);

		if( LockPoint )
		{
			if( LockPoint->m_StructType == TYPEPAD )
			{
				pt_pad = (D_PAD *) LockPoint;
				/* le debut de la piste est remis sur le centre du pad */
				pos = pt_pad->m_Pos;
				g_HightLigth_NetCode = pt_pad->m_NetCode;
			}

			else /* le point d'accrochage est un segment */
			{
				adr_buf = (TRACK *) LockPoint;
				g_HightLigth_NetCode = adr_buf->m_NetCode;
				CreateLockPoint( &pos.x, &pos.y, adr_buf, NULL);
			}
		}

		build_ratsnest_pad(LockPoint, wxPoint(0,0), TRUE);
		Hight_Light(DC);

		g_CurrentTrackSegment->m_Flags = IS_NEW;
		g_CurrentTrackSegment->m_Layer = GetScreen()->m_Active_Layer;
		g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth ;
		g_CurrentTrackSegment->m_Start = pos;
		g_CurrentTrackSegment->m_End = g_CurrentTrackSegment->m_Start;
		g_CurrentTrackSegment->m_NetCode = g_HightLigth_NetCode ;
		if(pt_pad)
		{
			g_CurrentTrackSegment->start = pt_pad ;
			g_CurrentTrackSegment->SetState(BEGIN_ONPAD,ON);
		}
		else g_CurrentTrackSegment->start = adr_buf ;

		if ( g_TwoSegmentTrackBuild )
		{	// Create 2 segments
			g_CurrentTrackSegment = new TRACK(*g_CurrentTrackSegment);
			g_TrackSegmentCount++;
			g_CurrentTrackSegment->Pback = g_FirstTrackSegment;
			g_FirstTrackSegment->Pnext = g_CurrentTrackSegment;
			g_CurrentTrackSegment->start = g_FirstTrackSegment;
			g_FirstTrackSegment->end = g_CurrentTrackSegment;
			g_FirstTrackSegment->SetState(BEGIN_ONPAD|END_ONPAD,OFF);
		}
		Affiche_Infos_Piste(this, g_CurrentTrackSegment) ;
		GetScreen()->m_CurrentItem = g_CurrentTrackSegment;
		GetScreen()->ManageCurseur(DrawPanel, DC, FALSE);
		if( Drc_On && (Drc(this, DC,g_CurrentTrackSegment,m_Pcb->m_Track,1 ) == BAD_DRC) )
		{
			return g_CurrentTrackSegment;
		}

	}

	else	/* Track in progress : segment coordinates are updated by ShowNewTrackWhenMovingCursor*/
	{
		/* Tst for a D.R.C. error: */
		if ( Drc_On )
		{
			if ( Drc(this, DC,g_CurrentTrackSegment,m_Pcb->m_Track,1 ) == BAD_DRC)
				return NULL;
			if ( g_TwoSegmentTrackBuild &&	// We must handle 2 segments
				 g_CurrentTrackSegment->Back() )
			{
				if( Drc(this, DC,g_CurrentTrackSegment->Back(),m_Pcb->m_Track,1 ) == BAD_DRC )
						return NULL;
			}
		}

		/* Current track is Ok: current segment is kept, and a new one is created
		unless the current segment is null, or 2 last are null if a 2 segments track build
		*/
		bool CanCreateNewSegment = TRUE;
		if( ! g_TwoSegmentTrackBuild && g_CurrentTrackSegment->IsNull() )
			CanCreateNewSegment = FALSE;
		if( g_TwoSegmentTrackBuild && g_CurrentTrackSegment->IsNull() &&
			g_CurrentTrackSegment->Back() && g_CurrentTrackSegment->Back()->IsNull() )
				CanCreateNewSegment = FALSE;
		if ( CanCreateNewSegment )
		{
			/* Erase old track on screen */
			ShowNewTrackWhenMovingCursor(DrawPanel, DC, FALSE);

			if( g_Raccord_45_Auto )
			{
				if( Met_Coude_a_45(this, DC, g_CurrentTrackSegment) != 0 )
					g_TrackSegmentCount++;
			}
			Track = g_CurrentTrackSegment->Copy();
			Track->Insert(m_Pcb, g_CurrentTrackSegment);

			Track->SetState(BEGIN_ONPAD|END_ONPAD,OFF);
			g_CurrentTrackSegment->end = Locate_Pad_Connecte(m_Pcb, g_CurrentTrackSegment, END);
			if( g_CurrentTrackSegment->end )
			{
				g_CurrentTrackSegment->SetState(END_ONPAD,ON);
				Track->SetState(BEGIN_ONPAD,ON);
			}
			Track->start = g_CurrentTrackSegment->end;

			g_CurrentTrackSegment = Track;
			g_CurrentTrackSegment->m_Flags = IS_NEW;
			g_TrackSegmentCount++ ;
			g_CurrentTrackSegment->m_Start = g_CurrentTrackSegment->m_End;
			g_CurrentTrackSegment->m_Layer = GetScreen()->m_Active_Layer;
			g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth ;
			/* Show the new position */
			ShowNewTrackWhenMovingCursor(DrawPanel, DC, FALSE);
		}
		Affiche_Infos_Piste(this, g_CurrentTrackSegment) ;
	}

	GetScreen()->m_CurrentItem = g_CurrentTrackSegment;
	return g_CurrentTrackSegment;
}


/**************************************************************************/
int Met_Coude_a_45(WinEDA_BasePcbFrame * frame, wxDC * DC, TRACK * pt_segm)
/***************************************************************************/
/* rectifie un virage a 90 et le modifie par 2 coudes a 45
	n'opere que sur des segments horizontaux ou verticaux.

	entree : pointeur sur le segment qui vient d'etre trace
			On suppose que le segment precedent est celui qui a ete
			precedement trace
	retourne:
		1 si ok
		0 si impossible
*/
{
TRACK * Previous;
TRACK *NewTrack;
int pas_45;
int dx0, dy0, dx1, dy1 ;

	if(g_TrackSegmentCount < 2 ) return(0) ;	/* il faut au moins 2 segments */

	Previous = (TRACK*)pt_segm->Pback;	  // pointe le segment precedent

	// Test s'il y a 2 segments consecutifs a raccorder
	if( (pt_segm->m_StructType != TYPETRACK ) ||
		(Previous->m_StructType != TYPETRACK) )
		{
		return(0) ;
		}

	pas_45 = frame->GetScreen()->GetGrid().x / 2 ;
	if( pas_45 < pt_segm->m_Width )
		pas_45 = frame->GetScreen()->GetGrid().x;
	while(pas_45 < pt_segm->m_Width) pas_45 *= 2;

	// OK : tst si les segments sont a 90 degre et vertic ou horiz
	dx0 = Previous->m_End.x - Previous->m_Start.x;
	dy0 = Previous->m_End.y - Previous->m_Start.y;
	dx1 = pt_segm->m_End.x - pt_segm->m_Start.x;
	dy1 = pt_segm->m_End.y - pt_segm->m_Start.y;
	// les segments doivent etre de longueur suffisante:
	if(max(abs(dx0),abs(dy0)) < (pas_45*2) ) return(0);
	if(max(abs(dx1),abs(dy1)) < (pas_45*2) ) return(0);

	/* creation du nouveau segment, raccordant des 2 segm: */
	NewTrack = pt_segm->Copy();

	NewTrack->m_Start.x = Previous->m_End.x;
	NewTrack->m_Start.y = Previous->m_End.y;
	NewTrack->m_End.x = pt_segm->m_Start.x;
	NewTrack->m_End.y = pt_segm->m_Start.y;

	if( dx0 == 0 )	// Segment precedent Vertical
		{
		if(dy1 != 0 )	// les 2 segments ne sont pas a 90 ;
			{
			delete NewTrack;
			return(0);
			}

		/* Calcul des coordonnees du point de raccord :
		le nouveau segment raccorde le 1er segment Vertical
		au 2eme segment Horizontal */

		if(dy0 > 0 ) NewTrack->m_Start.y -= pas_45 ;
		else		 NewTrack->m_Start.y += pas_45 ;

		if(dx1 > 0 ) NewTrack->m_End.x += pas_45 ;
		else		 NewTrack->m_End.x -= pas_45 ;

		if ( Drc_On && (Drc(frame, DC, pt_segm, frame->m_Pcb->m_Track, 1) == BAD_DRC) )
			{
			delete NewTrack;
			return(0) ;
			}

		Previous->m_End = NewTrack->m_Start;
		pt_segm->m_Start = NewTrack->m_End;
		NewTrack->Insert(frame->m_Pcb, Previous);
		return(1) ;
		}

	if (dy0 == 0 )		// Segment precedent Horizontal : dy0 = 0
		{
		if (dx1 != 0 )	// les 2 segments ne sont pas a 90 ;
			{
			delete NewTrack;
			return(0);
			}

		// Segments a 90
		/* Modif des coordonnees du point de raccord :
			un nouveau segment a ete cree, raccordant le 1er segment Horizontal
		au 2eme segment Vertical */

		if(dx0 > 0 ) NewTrack->m_Start.x -= pas_45 ;
		else		 NewTrack->m_Start.x += pas_45 ;

		if(dy1 > 0 ) NewTrack->m_End.y += pas_45 ;
		else		 NewTrack->m_End.y -= pas_45 ;

		if ( Drc_On && (Drc(frame, DC, NewTrack, frame->m_Pcb->m_Track, 1) == BAD_DRC) )
			{
			delete NewTrack;
			return(0);
			}

		Previous->m_End = NewTrack->m_Start;
		pt_segm->m_Start = NewTrack->m_End;
		NewTrack->Insert(frame->m_Pcb, Previous);
		return(1) ;
		}

	return(0);
}


/**************************************************************/
void WinEDA_PcbFrame::End_Route(TRACK * track, wxDC * DC)
/*************************************************************/
/*
	Routine de fin de trace d'une piste (succession de segments)
*/
{
TRACK * pt_track;
int masquelayer = g_TabOneLayerMask[GetScreen()->m_Active_Layer];
wxPoint pos;
EDA_BaseStruct * LockPoint;
TRACK * adr_buf;

	if( track == NULL ) return;

	if ( Drc_On && ( Drc(this, DC,g_CurrentTrackSegment,m_Pcb->m_Track,1 ) == BAD_DRC) )
		return ;

	/* Sauvegarde des coord du point terminal de la piste */
	pos = g_CurrentTrackSegment->m_End;

	if ( Begin_Route(track, DC) == NULL ) return;

	ShowNewTrackWhenMovingCursor(DrawPanel, DC, TRUE);  /* mise a jour trace reel */
	ShowNewTrackWhenMovingCursor(DrawPanel, DC, FALSE);  /* efface trace piste*/
	trace_ratsnest_pad(DC);		  /* efface trace chevelu*/


	// cleanup
	if (g_CurrentTrackSegment->Pnext != NULL){
		delete g_CurrentTrackSegment->Pnext;
		g_CurrentTrackSegment->Pnext = NULL;
	}


	/* La piste est ici non chainee a la liste des segments de piste.
		Il faut la replacer dans la zone de net,
		le plus pres possible du segment d'attache ( ou de fin ), car
		ceci contribue a la reduction du temps de calcul */

	/* Accrochage de la fin de la piste */
	LockPoint = LocateLockPoint(m_Pcb, pos, masquelayer);

	if ( LockPoint ) /* La fin de la piste est sur un PAD */
	{
		if( LockPoint->m_StructType ==  TYPEPAD )
		{
			EnsureEndTrackOnPad( (D_PAD *) LockPoint);
		}

		else	/* la fin de la piste est sur une autre piste: il faudra
				peut-etre creer un point d'ancrage */
		{
			adr_buf = (TRACK *) LockPoint;
			g_HightLigth_NetCode = adr_buf->m_NetCode;
			/* creation eventuelle d'un point d'accrochage */
			LockPoint = CreateLockPoint(&g_CurrentTrackSegment->m_End.x, &g_CurrentTrackSegment->m_End.y,
								adr_buf, g_CurrentTrackSegment);
		}
	}


	// Delete Null segments:
	g_FirstTrackSegment = DeleteNullTrackSegments(m_Pcb, g_FirstTrackSegment, & g_TrackSegmentCount);
	/* Test if no segment left. Can happend on a double click on the start point */
	if ( g_FirstTrackSegment != NULL )
	{

		/* Put new track in buffer: search the best insertion poinr */
		pt_track = g_FirstTrackSegment->GetBestInsertPoint(m_Pcb);
	
		/* Uut track in linked list */
		g_FirstTrackSegment->Insert(m_Pcb, pt_track);
	
		trace_ratsnest_pad(DC);
		Trace_Une_Piste(DrawPanel, DC, g_FirstTrackSegment, g_TrackSegmentCount,GR_OR) ;
	
		// Reset flags:
		TRACK * ptr = g_FirstTrackSegment; int ii;
		for ( ii = 0; (ptr != NULL) && (ii < g_TrackSegmentCount) ; ii++ )
		{
			ptr->m_Flags = 0; ptr = ptr->Next();
		}
	
		/* Delete the old track, if exists */
		if(g_AutoDeleteOldTrack)
		{
			EraseOldTrack(this, m_Pcb, DC, g_FirstTrackSegment, g_TrackSegmentCount);
		}
	
		/* compute the new rastnest : */
		test_1_net_connexion(DC, g_FirstTrackSegment->m_NetCode );
	
		GetScreen()->SetModify();
		Affiche_Infos_Status_Pcb(this);
	}
	/* Finish the work, clear used variables */
	g_FirstTrackSegment = NULL;

	if(g_HightLigt_Status) Hight_Light(DC);

	g_HightLigth_NetCode = OldNetCodeSurbrillance;
	if(OldEtatSurbrillance) Hight_Light(DC);

	GetScreen()->ManageCurseur = NULL;
	GetScreen()->ForceCloseManageCurseur = NULL;
	GetScreen()->m_CurrentItem = NULL;
}


/****************************************************************************/
void ShowNewTrackWhenMovingCursor(WinEDA_DrawPanel * panel,wxDC * DC, bool erase)
/****************************************************************************/
/* redessin du contour de la piste  lors des deplacements de la souris
	Cette routine est utilisee comme .ManageCurseur()
	si ShowIsolDuringCreateTrack_Item.State == RUN la marge d'isolation
	est aussi affichee
*/
{
int IsolTmp, Track_fill_copy;
PCB_SCREEN * screen = (PCB_SCREEN *) panel->GetScreen();

	Track_fill_copy = DisplayOpt.DisplayPcbTrackFill;
	DisplayOpt.DisplayPcbTrackFill = SKETCH;
	IsolTmp = DisplayOpt.DisplayTrackIsol;

	if ( g_ShowIsolDuringCreateTrack)
		DisplayOpt.DisplayTrackIsol = TRUE;

	/* efface ancienne position si elle a ete deja dessinee */
	if( erase )
		{
		Trace_Une_Piste(panel, DC, g_FirstTrackSegment,g_TrackSegmentCount,GR_XOR) ;
		((WinEDA_BasePcbFrame*)(panel->m_Parent))->trace_ratsnest_pad( DC);
		}

	/* dessin de la nouvelle piste : mise a jour du point d'arrivee */
	g_CurrentTrackSegment->m_Layer = screen->m_Active_Layer;
	g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth;

	if (Track_45_Only)
	{
		if ( g_TwoSegmentTrackBuild )
 			ComputeBreakPoint(g_CurrentTrackSegment, g_TrackSegmentCount);
		else
		{
		/* Calcul de l'extremite de la piste pour orientations permises:
										horiz,vertical ou 45 degre */
		Calcule_Coord_Extremite_45(g_CurrentTrackSegment->m_Start.x,g_CurrentTrackSegment->m_Start.y,
						&g_CurrentTrackSegment->m_End.x, &g_CurrentTrackSegment->m_End.y);

		}
	}

	else	/* ici l'angle d'inclinaison est quelconque */
	{
		g_CurrentTrackSegment->m_End = screen->m_Curseur;
	}

	Trace_Une_Piste(panel, DC, g_FirstTrackSegment,g_TrackSegmentCount,GR_XOR) ;

	DisplayOpt.DisplayTrackIsol = IsolTmp;
	DisplayOpt.DisplayPcbTrackFill = Track_fill_copy ;

	((WinEDA_BasePcbFrame*)(panel->m_Parent))->
		build_ratsnest_pad(NULL, g_CurrentTrackSegment->m_End, FALSE);

	((WinEDA_BasePcbFrame*)(panel->m_Parent))->trace_ratsnest_pad(DC);
}


/*****************************************************************/
void Calcule_Coord_Extremite_45(int ox, int oy, int* fx, int* fy )
/*****************************************************************/
/* determine les parametres .fx et .fy du segment pointe par pt_segm
	pour avoir un segment oriente a 0, 90 ou 45 degres, selon position
	du oint d'origine et de la souris
*/
{
int deltax, deltay, angle;

	deltax = ActiveScreen->m_Curseur.x - ox ;
	deltay = ActiveScreen->m_Curseur.y - oy ;
	/* calcul de l'angle preferentiel : 0, 45 , 90 degre */
	deltax = abs(deltax) ; deltay = abs(deltay) ; angle = 45 ;
	if( deltax >= deltay )
		{
		if ( deltax == 0 ) angle = 0 ;
		else if( ((deltay << 6 )/ deltax ) < 26 ) angle = 0 ;
		}
	else
		{
		angle = 45 ;
		if (deltay == 0 ) angle = 90 ;
		else if( ((deltax << 6 )/ deltay ) < 26 ) angle = 90 ;
		}

	switch ( angle )
		{
		case 0 :
			*fx = ActiveScreen->m_Curseur.x;
			*fy = oy ;
			break ;

		case 45 :
			deltax = min(deltax,deltay) ; deltay = deltax ;
			/* recalcul des signes de deltax et deltay */
			if( (ActiveScreen->m_Curseur.x - ox) < 0 ) deltax = -deltax;
			if( (ActiveScreen->m_Curseur.y - oy) < 0 ) deltay = -deltay;
			*fx = ox + deltax ;
			*fy = oy + deltay ;
			break ;

		case 90 :
			*fx = ox ;
			*fy = ActiveScreen->m_Curseur.y;
			break ;
		}
}


/********************************************************/
void ComputeBreakPoint( TRACK * track, int SegmentCount )
/********************************************************/
/**
 * Compute new track angle based on previous track.
 */
{
	int iDx = 0;
	int iDy = 0;
	int iAngle = 0;

	if ( SegmentCount <= 0 ) return;
	if ( track == NULL ) return;

	TRACK * NewTrack = track;
	track = (TRACK*)track->Pback;
	SegmentCount--;
	if ( track )
	{
		iDx = ActiveScreen->m_Curseur.x - track->m_Start.x;
		iDy = ActiveScreen->m_Curseur.y - track->m_Start.y;

		iDx = abs(iDx);
		iDy = abs(iDy);
	}

	TRACK * LastTrack = track ? (TRACK*)track->Pback : NULL;
	if ( LastTrack ) {
		if ( (LastTrack->m_End.x == LastTrack->m_Start.x) ||
			(LastTrack->m_End.y == LastTrack->m_Start.y)    ){
			iAngle = 45;
		}
	}

	if (iAngle == 0){
		if (iDx >= iDy) iAngle = 0;
		else iAngle = 90;

	}

	if ( track == NULL ) iAngle = -1;
	switch ( iAngle )
	{
		case -1:
			break;

		case 0 :
			if ( (ActiveScreen->m_Curseur.x - track->m_Start.x) < 0 )
				track->m_End.x = ActiveScreen->m_Curseur.x + iDy;
			else
				track->m_End.x = ActiveScreen->m_Curseur.x - iDy;
			track->m_End.y = track->m_Start.y;
			break ;

		case 45 :
			iDx = min(iDx,iDy);
			iDy = iDx ;
			/* recalcul des signes de deltax et deltay */
			if( (ActiveScreen->m_Curseur.x - track->m_Start.x) < 0 )
				iDx = -iDx;
			if( (ActiveScreen->m_Curseur.y - track->m_Start.y) < 0 )
				iDy = -iDy;
			track->m_End.x = track->m_Start.x + iDx;
			track->m_End.y = track->m_Start.y + iDy;
			break ;

		case 90 :
			if ( (ActiveScreen->m_Curseur.y - track->m_Start.y) < 0 )
				track->m_End.y = ActiveScreen->m_Curseur.y + iDx;
			else
				track->m_End.y = ActiveScreen->m_Curseur.y - iDx;
			track->m_End.x = track->m_Start.x;
			break ;
	}

	if ( track )
	{
		if ( track->IsNull() ) track->m_End = ActiveScreen->m_Curseur;
		NewTrack->m_Start = track->m_End;
	}
	NewTrack->m_End = ActiveScreen->m_Curseur;
}


/****************************************************************************/
TRACK * DeleteNullTrackSegments(BOARD * pcb, TRACK * track, int * segmcount)
/****************************************************************************/
/* Delete track segments which have len = 0; after creating a new track
	return a pointer on the first segment (start of track list)
*/
{
TRACK * firsttrack = track;
TRACK * oldtrack;
int nn = 0;
EDA_BaseStruct * LockPoint;

	LockPoint = track->start;
	while ( track != NULL )
	{
		oldtrack = track;
		track = track->Next();
		if ( ! oldtrack->IsNull() )
		{
			nn++;
			continue;
		}
		// NULL segment, delete it
		if ( firsttrack == oldtrack ) firsttrack = track;
		oldtrack->UnLink();
		delete oldtrack;
	}

	if ( segmcount ) *segmcount = nn;
	
	if ( nn == 0 ) return NULL;	// all the new track segments have been deleted


	// we must set the pointers on connected items and the connection status
	oldtrack = track = firsttrack;
	firsttrack->start = NULL;
	while ( track != NULL )
	{
		oldtrack = track;
		track = track->Next();
		oldtrack->end = track;
		if ( track ) track->start = oldtrack;
		oldtrack->SetStatus(0);
	}

	firsttrack->start = LockPoint;
	if ( LockPoint && (LockPoint->m_StructType == TYPEPAD ) )
		firsttrack->SetState(BEGIN_ONPAD,ON);

	track = firsttrack;
	while ( track != NULL )
	{
		TRACK * next_track = track->Next();
		LockPoint = Locate_Pad_Connecte(pcb, track, END);
		if ( LockPoint )
		{
			track->end = LockPoint;
			track->SetState(END_ONPAD,ON);
			if ( next_track )
			{
				next_track->start = LockPoint;
				next_track->SetState(BEGIN_ONPAD,ON);
			}
		}
		track = next_track;
	}

	return firsttrack;
}

/************************************/
void EnsureEndTrackOnPad(D_PAD * Pad)
/************************************/
/* Ensure the end point of g_CurrentTrackSegment is on the pas "Pad"
	if no, create a new track segment if necessary
	and move current (or new) end segment on pad
*/
{
	if( g_CurrentTrackSegment->m_End == Pad->m_Pos ) // Ok !
	{
		g_CurrentTrackSegment->end = Pad;
		g_CurrentTrackSegment->SetState(END_ONPAD, ON);
		return;
	}
		
	TRACK * lasttrack = g_CurrentTrackSegment;
	if ( ! g_CurrentTrackSegment->IsNull() )
	{ /* Must create a new segment, from track end to pad center */
		g_CurrentTrackSegment = new TRACK(*lasttrack);
		g_TrackSegmentCount++;
		lasttrack->Pnext = g_CurrentTrackSegment;
		g_CurrentTrackSegment->Pback = lasttrack;
		lasttrack->end = g_CurrentTrackSegment;
	}
	g_CurrentTrackSegment->m_End = Pad->m_Pos;
	g_CurrentTrackSegment->SetState(END_ONPAD, OFF);

	g_CurrentTrackSegment->end = Pad;
	g_CurrentTrackSegment->SetState(END_ONPAD, ON);
}
