
	/* EDITEUR de PCB: AUTOROUTAGE: routines "graphiques" */
	/******************************************************/

	/* Fichier BOARD.CC */

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

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


/* Routines externes */

/* routines internes */
void TraceLignePcb( int x0, int y0, int x1, int y1, int layer, int color );
void DrawSegmentQcq(int ux0,int uy0,int ux1,int uy1,int lg,int layer,
					int color, int op_logique);
void DrawHVSegment(int ux0,int uy0,int ux1,int uy1,int demi_largeur,int layer,
					int color, int op_logique);

void TraceFilledCercle(BOARD * Pcb, int cx, int cy, int rayon,int masque_layer,
									 int color, int op_logique);
void TraceCercle(int ux0,int uy0,int ux1,int uy1,int lg,int layer,
					int color, int op_logique);

void TraceArc(int ux0,int uy0,int ux1,int uy1,int ArcAngle, int lg,int layer,
					int color, int op_logique);

/* Macro d'appel de mise a jour de cellules */
#define OP_CELL(layer,dy,dx) {if(layer < 0) \
				{ \
				WriteCell(dy,dx,BOTTOM,color); \
				if(Nb_Sides) WriteCell(dy,dx,TOP,color);\
				} \
			else { \
				if(layer == Route_Layer_BOTTOM) WriteCell(dy,dx,BOTTOM,color);\
				if(Nb_Sides) \
					if(layer == Route_Layer_TOP) WriteCell(dy,dx,TOP,color);\
				} }


/******************************************************************************/
void Place_1_Pad_Board(BOARD * Pcb, D_PAD * pt_pad, int color, int marge, int op_logique)
/******************************************************************************/
/* Initialise a la valeur color, les cellules du Board comprises dans la
	surface du pad pointe par pt_pad, avec la marge reservee pour l'isolement
	et la demi largeur de la piste
	Parametres:
		pt_pad : pointeur sur la description du pad
		color : masque a ecrire dans les cellules
		marge : valeur a ajouter au rayon ou demi cote du pad
		op_logique: type d'ecriture dans la cellule ( WRITE, OR )
*/
{
int dx , dy;
wxPoint shape_pos = pt_pad->ReturnShapePos();;

	dx = pt_pad->m_Size.x / 2 ; dx += marge;

	if(pt_pad->m_PadShape == CIRCLE)
		{
		TraceFilledCercle(Pcb, shape_pos.x, shape_pos.y, dx,
							pt_pad->m_Masque_Layer, color, op_logique);
		return;
		}


	dy = pt_pad->m_Size.y / 2; dy += marge;

	if(pt_pad->m_PadShape == TRAPEZE)
		{
		dx += abs(pt_pad->m_DeltaSize.y) / 2;
		dy += abs(pt_pad->m_DeltaSize.x) / 2;
		}

	if( (pt_pad->m_Orient % 900) == 0 )
		{	/* Le pad est un rectangle horizontal ou vertical */

		if ( (pt_pad->m_Orient == 900 ) || (pt_pad->m_Orient == 2700) )
			{	 /* orient tournee de 90 deg */
			EXCHG(dx, dy) ;
			}

		TraceFilledRectangle(Pcb, shape_pos.x - dx, shape_pos.y - dy,
							 shape_pos.x + dx, shape_pos.y + dy,
							 pt_pad->m_Masque_Layer, color, op_logique);
		}

	else
		{
		TraceFilledRectangle(Pcb, shape_pos.x - dx, shape_pos.y - dy,
							 shape_pos.x + dx, shape_pos.y + dy,
							 (int) pt_pad->m_Orient,
							 pt_pad->m_Masque_Layer, color, op_logique);
		}
}


/************************************************************************/
void TraceFilledCercle(BOARD * Pcb, int cx, int cy, int rayon,int masque_layer,
									 int color, int op_logique)
/************************************************************************/
/* Initialise a la valeur color, les cellules du Board comprises dans la
	surface du cercle de centre cx,cy.
	Parametres:
		rayon : valeur a ajouter au rayon ou demi cote du pad
		masque_layer = couches occupees
		color : masque a ecrire dans les cellules
		op_logique: type d'ecriture dans la cellule ( WRITE, OR )
*/
{
int row, col;
int ux0 , uy0 , ux1, uy1;
int row_max, col_max, row_min, col_min;
int trace = 0;
float fdistmin, fdistx, fdisty;
void (*WriteCell)(int,int,int,BoardCell);
int tstwrite = 0;
int distmin;

	/* Determination des couches occupees : */

	/* routage sur 1 seule couche:
		sur bitmap BOTTOM et Route_Layer_B = Route_Layer_A*/

	if(masque_layer & g_TabOneLayerMask[Route_Layer_BOTTOM])
			trace = 1; /* Trace sur BOTTOM */

	if(masque_layer & g_TabOneLayerMask[Route_Layer_TOP] )
		if(Nb_Sides)
			trace |= 2; /* Trace sur TOP */

	if( trace == 0) return;

	switch(op_logique)
	{
		default:
		case WRITE_CELL: WriteCell = SetCell; break;
		case WRITE_OR_CELL: WriteCell = OrCell; break;
		case WRITE_XOR_CELL: WriteCell = XorCell; break;
		case WRITE_AND_CELL: WriteCell = AndCell; break;
		case WRITE_ADD_CELL: WriteCell = AddCell; break;
	}

	cx -= Pcb->m_BoundaryBox.m_Pos.x; cy -= Pcb->m_BoundaryBox.m_Pos.y;

	distmin = rayon ;

	/* Calcul du rectangle d'encadrement du cercle*/
	ux0 = cx - rayon; uy0 = cy - rayon;
	ux1 = cx + rayon; uy1 = cy + rayon;

	/* Calcul des coord limites des cellules appartenant au rectangle */
	row_max = uy1 / g_GridRoutingSize;
	col_max = ux1 / g_GridRoutingSize;
	row_min = uy0 / g_GridRoutingSize;// if (uy0 > row_min*g_GridRoutingSize ) row_min++;
	col_min = ux0 / g_GridRoutingSize;// if (ux0 > col_min*g_GridRoutingSize ) col_min++;

	if( row_min < 0 ) row_min = 0;
	if( row_max >= (Nrows-1)) row_max = Nrows-1;
	if( col_min < 0 ) col_min = 0;
	if( col_max >= (Ncols-1)) col_max = Ncols-1;

	/* On s'assure que l'on place toujours au moins une cellule */
	if( row_min > row_max )	row_max = row_min;
	if( col_min > col_max )	col_max = col_min;

	fdistmin = (float)distmin*distmin;

	for( row = row_min ;row <= row_max ; row++)
	{
		fdisty = (float)(cy - (row * g_GridRoutingSize));
		fdisty *= fdisty;
		for(col = col_min; col <= col_max; col++)
		{
			fdistx = (float)(cx - (col * g_GridRoutingSize) );
			fdistx *= fdistx;

			if( fdistmin <= (fdistx + fdisty) ) continue;

			if(trace & 1) WriteCell(row,col,BOTTOM,color);
			if(trace & 2) WriteCell(row,col,TOP,color);
			tstwrite = 1;
		}
	}

if (tstwrite) return;

	/* Si aucune cellule n'a ete ecrite, on touche les 4 voisins diagonaux
   	   (cas defavorable: pad hors grille, au centre des 4 voisins diagonaux) */

	distmin = g_GridRoutingSize/2 +1;
	fdistmin = ((float)distmin*distmin) * 2; /* = dist centre au point diagonal*/

	for( row = row_min ;row <= row_max ; row++)
	{
		fdisty = (float)(cy - (row * g_GridRoutingSize));
		fdisty *= fdisty;
		for(col = col_min; col <= col_max; col++)
		{
			fdistx = (float)(cx - (col * g_GridRoutingSize) );
			fdistx *= fdistx;

			if( fdistmin <= (fdistx + fdisty) ) continue;

			if(trace & 1) WriteCell(row,col,BOTTOM,color);
			if(trace & 2) WriteCell(row,col,TOP,color);
		}
	}
}



/******************************************************************************/
void TraceSegmentPcb(BOARD * Pcb, TRACK* pt_segm, int color, int marge, int op_logique )
/******************************************************************************/
/* trace un Segment de piste sur le BOARD de routage
*/
{
int demi_pas, demi_largeur;
int ux0 , uy0 , ux1, uy1;
int layer = pt_segm->m_Layer;


	demi_pas = g_GridRoutingSize / 2;
	demi_largeur = (pt_segm->m_Width / 2) + marge;
	/* Calcul du rectangle d'encadrement du segment ( si H,V ou Via) */
	ux0 = pt_segm->m_Start.x - Pcb->m_BoundaryBox.m_Pos.x;
	uy0 = pt_segm->m_Start.y - Pcb->m_BoundaryBox.m_Pos.y;
	ux1 = pt_segm->m_End.x - Pcb->m_BoundaryBox.m_Pos.x;
	uy1 = pt_segm->m_End.y - Pcb->m_BoundaryBox.m_Pos.y;

	if ( color == VIA_IMPOSSIBLE ) layer = -1;

	/* Test si VIA (cercle plein a tracer) */
	if(pt_segm->m_StructType == TYPEVIA )
	{
		TraceFilledCercle(Pcb, pt_segm->m_Start.x, pt_segm->m_Start.y, demi_largeur,
									0x0000FFFF, color, op_logique);
		return;
	}

	/* Le segment est ici un segment de droite ou un cercle ou un arc: */
	if( pt_segm->m_Shape == S_CIRCLE )
	{
		TraceCercle(ux0,uy0,ux1,uy1,demi_largeur,layer,color,op_logique);
		return;
	}

	if( pt_segm->m_Shape == S_ARC )
	{
		TraceArc(ux0,uy0,ux1,uy1,pt_segm->m_Param,demi_largeur,layer,color,op_logique);
		return;
	}

	/* Le segment est ici un segment de droite */
	if( (ux0 != ux1) && (uy0 != uy1) ) // segment incline
	{
		DrawSegmentQcq(ux0,uy0,ux1,uy1,demi_largeur,layer,color,op_logique);
		return;
	}
		
	// Ici le segment est HORIZONTAL ou VERTICAL 
//	DrawHVSegment(ux0,uy0,ux1,uy1,demi_largeur,layer,color,op_logique);              //F4EXB 051018-01
	DrawSegmentQcq(ux0,uy0,ux1,uy1,demi_largeur,layer,color,op_logique);              //F4EXB 051018-01
	return;                                                                        //F4EXB 051018-01

}


/******************************************************************************************/
void TraceLignePcb( int x0, int y0, int x1, int y1, int layer, int color, int op_logique  )
/******************************************************************************************/
/* trace une ligne; si layer = -1 sur toutes les couches
*/
{
int dx, dy , lim;
int cumul, inc, il, delta;
void (*WriteCell)(int,int,int,BoardCell);

	switch(op_logique)
	{
		default:
		case WRITE_CELL: WriteCell = SetCell; break;
		case WRITE_OR_CELL: WriteCell = OrCell; break;
		case WRITE_XOR_CELL: WriteCell = XorCell; break;
		case WRITE_AND_CELL: WriteCell = AndCell; break;
		case WRITE_ADD_CELL: WriteCell = AddCell; break;
	}

	if( x0 == x1 )  // ligne verticale
	{
		if(y1 < y0 ) EXCHG (y0,y1);
		dy = y0 / g_GridRoutingSize; lim = y1 / g_GridRoutingSize ;
		dx = x0 / g_GridRoutingSize;
		/* Clipping aux limites du board */
		if( (dx < 0) || (dx >= Ncols) ) return;
		if( dy < 0 ) dy = 0;
		if( lim >= Nrows ) lim = Nrows-1;
		for( ; dy <= lim ; dy ++ )
		{
			OP_CELL(layer,dy,dx);
		}
		return;
	}

	if( y0 == y1 )  // ligne horizontale
	{
		if(x1 < x0 ) EXCHG (x0,x1);
		dx = x0 / g_GridRoutingSize; lim = x1 / g_GridRoutingSize ;
		dy = y0 / g_GridRoutingSize;
		/* Clipping aux limites du board */
		if( (dy < 0) || (dy >= Nrows) ) return;
		if( dx < 0 ) dx = 0;
		if( lim >= Ncols ) lim = Ncols-1;
		for( ; dx <= lim ; dx ++ )
		{
			OP_CELL(layer,dy,dx);
		}
		return;
	}

	/* Ici l'angle est quelconque: on utilise l'algorithme de LUCAS */
	if ( abs(x1-x0) >= abs(y1-y0) ) /* segment peu incline */
	{
		if(x1 < x0) {EXCHG(x1,x0); EXCHG(y1,y0) ;}

		dx = x0 / g_GridRoutingSize; lim = x1 / g_GridRoutingSize ;
		dy = y0 / g_GridRoutingSize;
		inc = 1; if( y1 < y0) inc = -1;
		il = lim - dx; cumul = il / 2; delta = abs(y1 - y0)/g_GridRoutingSize;
		for( ; dx <= lim ; )
		{
			if( (dx >= 0) && (dy >= 0) &&
				(dx < Ncols) && (dy < Nrows) )
			{
				OP_CELL(layer,dy,dx);
			}
			dx++; cumul += delta ;
			if(cumul > il )
			{
				cumul -= il; dy += inc;
			}
		}
	}
	else
	{
		if(y1 < y0) {EXCHG(x1,x0); EXCHG(y1,y0) ;}

		dy = y0 / g_GridRoutingSize; lim = y1 / g_GridRoutingSize ;
		dx = x0 / g_GridRoutingSize;
		inc = 1; if( x1 < x0) inc = -1;
		il = lim - dy; cumul = il /2; delta = abs(x1 - x0)/g_GridRoutingSize;
		for( ; dy <= lim ; )
		{
			if( (dx >= 0) && (dy >= 0) &&
				(dx < Ncols) && (dy < Nrows) )
			{
				OP_CELL(layer,dy,dx);
			}
			dy++; cumul += delta ;
			if(cumul > il )
			{
				cumul -= il; dx += inc;
			}
		}
	}
}

/*****************************************************************/
void TraceFilledRectangle(BOARD * Pcb,
				int ux0, int uy0, int ux1, int uy1,
				int masque_layer, int color, int op_logique)
/*****************************************************************/
/*  Fonction Surchargee.

	 Met a la valeur color l'ensemble des cellules du board inscrites dans
	le rectangle de coord ux0,uy0 ( angle haut a gauche )
	a ux1,uy1 ( angle bas a droite )
	Le rectangle est horizontal ( ou vertical )
	Coordonnees PCB.
*/
{
int row, col;
int row_min, row_max, col_min, col_max;
int trace = 0;
void (*WriteCell)(int,int,int,BoardCell);

	if(masque_layer & g_TabOneLayerMask[Route_Layer_BOTTOM])
			trace = 1; /* Trace sur BOTTOM */

	if( (masque_layer & g_TabOneLayerMask[Route_Layer_TOP] ) && Nb_Sides)
			trace |= 2; /* Trace sur TOP */

	if(trace == 0) return;

	switch(op_logique)
	{
		default:
		case WRITE_CELL: WriteCell = SetCell; break;
		case WRITE_OR_CELL: WriteCell = OrCell; break;
		case WRITE_XOR_CELL: WriteCell = XorCell; break;
		case WRITE_AND_CELL: WriteCell = AndCell; break;
		case WRITE_ADD_CELL: WriteCell = AddCell; break;
	}

	ux0 -= Pcb->m_BoundaryBox.m_Pos.x; uy0 -= Pcb->m_BoundaryBox.m_Pos.y;
	ux1 -= Pcb->m_BoundaryBox.m_Pos.x; uy1 -= Pcb->m_BoundaryBox.m_Pos.y;

	/* Calcul des coord limites des cellules appartenant au rectangle */
	row_max = uy1 / g_GridRoutingSize;
	col_max = ux1 / g_GridRoutingSize;
	row_min = uy0 / g_GridRoutingSize; if (uy0 > row_min*g_GridRoutingSize ) row_min++;
	col_min = ux0 / g_GridRoutingSize; if (ux0 > col_min*g_GridRoutingSize ) col_min++;

	if( row_min < 0 ) row_min = 0;
	if( row_max >= (Nrows-1)) row_max = Nrows-1;
	if( col_min < 0 ) col_min = 0;
	if( col_max >= (Ncols-1)) col_max = Ncols-1;

	for( row = row_min ;row <= row_max ; row++)
	{
		for(col = col_min;col <= col_max; col++)
		{
			if(trace & 1) WriteCell(row,col,BOTTOM,color);
			if(trace & 2) WriteCell(row,col,TOP,color);
		}
	}
}


/***********************************************************************************/
void TraceFilledRectangle(BOARD * Pcb, int ux0, int uy0, int ux1, int uy1, int angle,
				 int masque_layer, int color, int op_logique)
/***********************************************************************************/

/*  Fonction Surchargee.

	Met a la valeur color l'ensemble des cellules du board inscrites dans
	le rectangle de coord ux0,uy0 ( angle haut a droite )
	a ux1,uy1 ( angle bas a gauche )
	Le rectangle est tourne de la valeur angle (en 0,1 degres)
	Coordonnees PCB.
*/
{
int row, col;
int cx, cy;			/* Centre du rectangle */
int rayon;			/* rayon du cercle exinscrit */
int row_min, row_max, col_min, col_max;
int rotrow, rotcol;
int trace = 0;
void (*WriteCell)(int,int,int,BoardCell);

	if(masque_layer & g_TabOneLayerMask[Route_Layer_BOTTOM])
			trace = 1; /* Trace sur BOTTOM */

	if(masque_layer & g_TabOneLayerMask[Route_Layer_TOP] )
		if(Nb_Sides)
			trace |= 2; /* Trace sur TOP */

	if(trace == 0) return;

	switch(op_logique)
		{
		default:
		case WRITE_CELL: WriteCell = SetCell; break;
		case WRITE_OR_CELL: WriteCell = OrCell; break;
		case WRITE_XOR_CELL: WriteCell = XorCell; break;
		case WRITE_AND_CELL: WriteCell = AndCell; break;
		case WRITE_ADD_CELL: WriteCell = AddCell; break;
		}

	ux0 -= Pcb->m_BoundaryBox.m_Pos.x; uy0 -= Pcb->m_BoundaryBox.m_Pos.y;
	ux1 -= Pcb->m_BoundaryBox.m_Pos.x; uy1 -= Pcb->m_BoundaryBox.m_Pos.y;

	cx = (ux0 + ux1) / 2; cy = (uy0 + uy1) / 2;
	rayon = (int) sqrt( (float)(cx - ux0) * (cx - ux0)
					  + (float)(cy - uy0) * (cy - uy0) );

	/* Calcul des coord limites des cellules appartenant au rectangle */
	row_max = (cy + rayon) / g_GridRoutingSize;
	col_max = (cx + rayon) / g_GridRoutingSize;
	row_min = (cy - rayon) / g_GridRoutingSize; if (uy0 > row_min*g_GridRoutingSize ) row_min++;
	col_min = (cx - rayon) / g_GridRoutingSize; if (ux0 > col_min*g_GridRoutingSize ) col_min++;

	if( row_min < 0 ) row_min = 0;
	if( row_max >= (Nrows-1)) row_max = Nrows-1;
	if( col_min < 0 ) col_min = 0;
	if( col_max >= (Ncols-1)) col_max = Ncols-1;

	for( row = row_min ;row <= row_max ; row++)
		{
		for(col = col_min;col <= col_max; col++)
			{
			rotrow = row * g_GridRoutingSize; rotcol = col * g_GridRoutingSize;
			RotatePoint(&rotcol, &rotrow, cx, cy, - angle);
			if( rotrow <= uy0 ) continue;
			if( rotrow >= uy1 ) continue;
			if( rotcol <= ux0 ) continue;
			if( rotcol >= ux1 ) continue;
			if(trace & 1) WriteCell(row,col,BOTTOM,color);
			if(trace & 2) WriteCell(row,col,TOP,color);
			}
		}
}



/*****************************************************************/
void DrawSegmentQcq(int ux0,int uy0,int ux1,int uy1,int lg,int layer,
					int color, int op_logique)
/*****************************************************************/
/* Remplit toutes les cellules du BOARD contenues dans le segment
	de demi-largeur lg, org ux,y0 fin ux,y1 a la valeur color .
	coord en unites PCB (0.1 mil) relatives a l'origine pt_pcb->m_PcbBox.m_Xmin,Y du board.
*/
{
int row, col;
int inc;
int row_max, col_max, row_min, col_min;
int demi_pas;
void (*WriteCell)(int,int,int,BoardCell);
int angle;
int cx, cy, dx, dy;

	switch(op_logique)
	{
		default:
		case WRITE_CELL: WriteCell = SetCell; break;
		case WRITE_OR_CELL: WriteCell = OrCell; break;
		case WRITE_XOR_CELL: WriteCell = XorCell; break;
		case WRITE_AND_CELL: WriteCell = AndCell; break;
		case WRITE_ADD_CELL: WriteCell = AddCell; break;
	}

	/* on rend la coordonnee ux1 tj > ux0 , pour simplifier les calculs */
	if( ux1 < ux0 ) { EXCHG(ux1,ux0); EXCHG(uy1,uy0);}

	/* calcul de l'increment selon axe Y */
	inc = 1; if(uy1 < uy0) inc = -1;

	/* Calcul de l'encadrement : */
	demi_pas = g_GridRoutingSize/2;

	col_min = (ux0 - lg) / g_GridRoutingSize;
	if (col_min < 0 ) col_min = 0;
	col_max = (ux1 + lg + demi_pas) / g_GridRoutingSize;
	if (col_max > (Ncols-1) ) col_max = Ncols-1;

	if(inc > 0)
	{
		row_min = (uy0 - lg) / g_GridRoutingSize;
		row_max = (uy1 + lg + demi_pas) / g_GridRoutingSize;
	}
	else{
		row_min = (uy1 - lg) / g_GridRoutingSize;
		row_max = (uy0 + lg + demi_pas) / g_GridRoutingSize;
		}

	if (row_min < 0 ) row_min = 0;
	if (row_min > (Nrows-1) ) row_min = Nrows-1;
	if (row_max < 0 ) row_max = 0;
	if (row_max > (Nrows-1) ) row_max = Nrows-1;


	dx = ux1 - ux0; dy = uy1 - uy0;
	if (dx) angle = (int)(atan2(dy,dx) * 1800 / M_PI);
	else { angle = 900; if (dy < 0) angle = -900; }

	RotatePoint(&dx, &dy, angle);	/* dx = longueur, dy = 0 */
	for( col = col_min; col <= col_max ; col++ )
	{
		int cxr;
		cxr = (col * g_GridRoutingSize) - ux0;
		for(row = row_min; row <= row_max ;  row ++ )
		{
			cy = (row * g_GridRoutingSize) - uy0;
			cx = cxr;
			RotatePoint(&cx, &cy, angle);
			if( abs(cy) > lg) continue; /* Le point est trop loin sur l'axe Y */

			/* ici le point a tester est proche du segment: la position
				selon l'axe X doit etre testee */
			if( (cx >= 0) && (cx <= dx) )
			{
				OP_CELL(layer,row,col);
				continue;
			}
			/* examen des extremites qui sont arrondies */
			if( (cx < 0) && (cx >= -lg) )
			{
				if( ((cx * cx) + (cy*cy)) <= (lg*lg) )
				OP_CELL(layer,row,col);
				continue;
			}
			if( (cx > dx) && (cx <= (dx+lg)) )
			{
				if( (((cx-dx) * (cx-dx)) + (cy*cy)) <= (lg*lg) )
				OP_CELL(layer,row,col);
				continue;
			}
		}
	}
}

/********************************************************************/
void DrawHVSegment(int ux0,int uy0,int ux1,int uy1,int demi_largeur,int layer,
					int color, int op_logique)
/********************************************************************/
/* Draw a horizontal or vertical segment.
same as DrawSegmentQcq, but faster
*/
{
int row, col;
int row_max, col_max, row_min, col_min;
void (*WriteCell)(int,int,int,BoardCell);

	switch(op_logique)
	{
		default:
		case WRITE_CELL: WriteCell = SetCell; break;
		case WRITE_OR_CELL: WriteCell = OrCell; break;
		case WRITE_XOR_CELL: WriteCell = XorCell; break;
		case WRITE_AND_CELL: WriteCell = AndCell; break;
		case WRITE_ADD_CELL: WriteCell = AddCell; break;
	}

	// Modif des coord pour que les coord de fin soient > coord de debut 
   	if( uy1 < uy0 ) EXCHG(uy0,uy1) ; // ceci n'est vrai que parce que 
	if( ux1 < ux0 ) EXCHG(ux0,ux1) ; // dx ou dy ou les 2 sonts nuls 

	// Le segment est assimile a un rectangle.
	// TODO: traiter correctement les extremites arrondies
//	if ( ux0 == ux1 )	// Vertical Segment
	{
		ux0 -= demi_largeur; ux1 += demi_largeur;
	}
//	else	// Horizontal segment
	{
		uy0 -= demi_largeur ;uy1 += demi_largeur;
	}

	// Calcul des coord limites des cellules appartenant au rectangle 
	row_max = uy1 / g_GridRoutingSize;
	col_max = ux1 / g_GridRoutingSize;

	row_min = uy0 / g_GridRoutingSize;
	if (uy0 > row_min*g_GridRoutingSize ) row_min++; // Traitement de l'arrondi par defaut

	col_min = ux0 / g_GridRoutingSize;
	if (ux0 > col_min*g_GridRoutingSize ) col_min++;

	if( row_min < 0 ) row_min = 0;
	if( row_max >= (Nrows-1)) row_max = Nrows-1;
	if( col_min < 0 ) col_min = 0;
	if( col_max >= (Ncols-1)) col_max = Ncols-1;

	if( row_min > row_max ) row_max = row_min;
	if( col_min > col_max ) col_max = col_min;

	for( row = row_min ;row <= row_max ; row++)
	{
		for(col = col_min;col <= col_max; col++)
		{
			OP_CELL(layer,row,col);
		}
	}
}

/*****************************************************************/
void TraceCercle(int ux0,int uy0,int ux1,int uy1,int lg,int layer,
					int color, int op_logique)
/*****************************************************************/
/* Remplit toutes les cellules du BOARD contenues dans le cercle
	de demi-largeur lg, centre ux,y0 passant par ux,y1 a la valeur color .
	coord en unites PCB (0.1 mil) relatives a l'origine pt_pcb->m_PcbBox.m_Xmin,Y du board.
*/
{
int rayon, nb_segm;
int x0,y0,  // Point de depart du segment en cours de trace
	x1,y1;  // point d'arrivee
int ii;
int angle;

	rayon = (int)hypot((double)(ux1-ux0),(double)(uy1-uy0) );

	x0 = x1 = rayon; y0 = y1 = 0;
	if( lg < 1 ) lg = 1;
	nb_segm = (2 * rayon) / lg;
	if(nb_segm < 5) nb_segm = 5;
	if(nb_segm > 100) nb_segm = 100;
	for( ii = 1 ; ii < nb_segm ; ii++)
	{
		angle = (3600 * ii) / nb_segm;
		x1 = (int)(rayon * fcosinus[angle]);
		y1 = (int)(rayon * fsinus[angle]);
		DrawSegmentQcq(x0+ux0,y0+uy0, x1+ux0,y1+uy0,lg,layer, color, op_logique);
		x0 = x1; y0 = y1;
	}

	DrawSegmentQcq(x1+ux0,y1+uy0, ux0+rayon, uy0,lg,layer, color, op_logique);
}

/****************************************************************************/
void TraceArc(int ux0,int uy0,int ux1,int uy1, int ArcAngle, int lg,int layer,
					int color, int op_logique)
/****************************************************************************/

/* Remplit toutes les cellules du BOARD contenues dans l'arc de "longueur" angle
	de demi-largeur lg, centre ux,y0 commencant en ux,y1 a la valeur color .
	coord en unites PCB (0.1 mil) relatives a l'origine
	pt_pcb->m_PcbBox.m_Xmin,Y du board.
*/
{
int rayon, nb_segm;
int x0,y0,  // Point de depart du segment en cours de trace
	x1,y1;  // point d'arrivee
int ii;
int angle, StAngle;


	rayon = (int)hypot((double)(ux1-ux0),(double)(uy1-uy0) );

	x0 = ux1 - ux0;
	y0 = uy1 - uy0;
	StAngle = ArcTangente(uy1 - uy0, ux1 - ux0);
	if( lg < 1 ) lg = 1;
	nb_segm = (2 * rayon) / lg;
	nb_segm = (nb_segm * abs(ArcAngle)) / 3600;
	if(nb_segm < 5) nb_segm = 5;
	if(nb_segm > 100) nb_segm = 100;

	for( ii = 1 ; ii <= nb_segm ; ii++)
	{
		angle = (ArcAngle * ii) / nb_segm;
		angle += StAngle;

		while ( angle >= 3600 ) angle -= 3600;
		while ( angle < 0 ) angle += 3600;

		x1 = (int)(rayon * fcosinus[angle]);
		y1 = (int)(rayon * fsinus[angle]);
		DrawSegmentQcq(x0+ux0,y0+uy0, x1+ux0,y1+uy0,lg,layer, color, op_logique);
		x0 = x1; y0 = y1;
	}

//	  DrawSegmentQcq(x1+ux0,y1+uy0, ux0+rayon, uy0,lg,layer, color, op_logique);
}

