		/****************************************/
		/**** Routine de trace GERBER RS274X ****/
		/****************************************/

#include "fctsys.h"

#include "common.h"
#include "plot_common.h"
#include "pcbnew.h"
#include "pcbplot.h"
#include "trigo.h"
#include "plotgerb.h"

#include "protos.h"


/* Variables locales : */
static int s_Last_D_code ;
static float Gerb_scale_plot;		/*Coeff de conversion d'unites des traces */
static int scale_spot_mini;			/* Ouverture mini (pour remplissages) */
static D_CODE * s_DCodeList;			/* Pointeur sur la zone de stockage des D_CODES */
wxString GerberFullFileName;
static double scale_x , scale_y ; /* echelles de convertion en X et Y (compte tenu
									des unites relatives du PCB et des traceurs*/
static bool ShowDcodeError = TRUE;

/* Routines Locales */

static void Init_Trace_GERBER(WinEDA_BasePcbFrame * frame, FILE * gerbfile);
static void Init_ApertureList(void);
static void Fin_Trace_GERBER(WinEDA_BasePcbFrame * frame, FILE * gerbfile);
static void Plot_1_CIRCLE_pad_GERBER(wxPoint pos,int diametre) ;
static void trace_1_pastille_OVALE_GERBER(wxPoint pos, wxSize size,int orient);
static void PlotRectangularPad_GERBER(wxPoint pos, wxSize size, int orient);

static D_CODE * get_D_code(int dx,int dy, int type, int drill ) ;
static void trace_1_pad_TRAPEZE_GERBER(wxPoint pos, wxSize size,wxSize delta,
							int orient,int modetrace);


/********************************************************************************/
void WinEDA_BasePcbFrame::Genere_GERBER(const wxString & FullFileName, int Layer,
		bool PlotOriginIsAuxAxis)
/********************************************************************************/
/* Genere les divers fichiers de trace:
	Pour chaque couche  1 fichier xxxc.PHO au format RS274X
*/
{
int tracevia = 1;

	EraseMsgBox();
	GerberFullFileName = FullFileName;

	g_PlotOrient = 0;
	if (Plot_Set_MIROIR) g_PlotOrient |= PLOT_MIROIR;

	/* Calcul des echelles de conversion */
	Gerb_scale_plot = 1.0;  /* pour unites gerber en 0,1 Mils, format 3.4 */
	scale_spot_mini = (int)(spot_mini * 10 * Gerb_scale_plot);
	scale_x = Scale_X * Gerb_scale_plot;
	scale_y = Scale_Y * Gerb_scale_plot;
	g_PlotOffset.x = 0;
	g_PlotOffset.y = 0;
	if ( PlotOriginIsAuxAxis )
	{
		g_PlotOffset = m_Auxiliary_Axis_Position;
	}
	
	dest = wxFopen(FullFileName, wxT("wt"));
	if (dest == NULL)
	{
		wxString msg = _("unable to create file ") + FullFileName;
		DisplayError(this, msg); return ;
	}

	setlocale(LC_NUMERIC, "C");

	InitPlotParametresGERBER(g_PlotOffset, scale_x, scale_y);

	/*	Clear the memory used for handle the D_CODE (aperture) list	 */
	Init_ApertureList();
	
	Affiche_1_Parametre(this, 0, _("File"),FullFileName,CYAN) ;

	Init_Trace_GERBER(this, dest) ;

	nb_plot_erreur = 0 ;

	int layer_mask = g_TabOneLayerMask[Layer];
	// Specify that the contents of the "Edges Pcb" layer are also to be
	// plotted, unless the option of excluding that layer has been selected.
	if( ! Exclude_Edges_Pcb )
		layer_mask |= EDGE_LAYER;

	switch(Layer)
		{
		case CUIVRE_N :
		case LAYER_N_2 :
		case LAYER_N_3 :
		case LAYER_N_4 :
		case LAYER_N_5 :
		case LAYER_N_6 :
		case LAYER_N_7 :
		case LAYER_N_8 :
		case LAYER_N_9 :
		case LAYER_N_10 :
		case LAYER_N_11:
		case LAYER_N_12:
		case LAYER_N_13 :
		case LAYER_N_14 :
		case LAYER_N_15 :
		case CMP_N  :
			Plot_Layer_GERBER(dest, layer_mask, 0, 1);
			break;

		case SOLDERMASK_N_CU :
		case SOLDERMASK_N_CMP :  /* Trace du vernis epargne */
			if ( g_DrawViaOnMaskLayer ) tracevia = 1;
			else tracevia = 0;
			Plot_Layer_GERBER(dest, layer_mask, g_DesignSettings.m_MaskMargin, tracevia);
			break;

		case SOLDERPASTE_N_CU :
		case SOLDERPASTE_N_CMP :  /* Trace du masque de pate de soudure */
			Plot_Layer_GERBER(dest, layer_mask, 0, 0);
			break;

		default:
			Plot_Serigraphie(PLOT_FORMAT_GERBER, dest, layer_mask);
			break;
		}

	Fin_Trace_GERBER(this, dest) ;
	setlocale(LC_NUMERIC, "");
}


/***********************************************************************/
void WinEDA_BasePcbFrame::Plot_Layer_GERBER(FILE * File,int masque_layer,
						int garde, int tracevia)
/***********************************************************************/
/* Trace en format GERBER. d'une couche cuivre ou masque
*/
{
wxPoint pos;
wxSize size;
MODULE * Module;
D_PAD * PtPad;
TRACK * track ;
EDA_BaseStruct * PtStruct;
wxString msg;

//	(Following command has been superceded by new command on lines 92 and 93.)
//	masque_layer |= EDGE_LAYER;	/* Les elements de la couche EDGE sont tj traces */

	/* trace des elements type Drawings Pcb : */
	PtStruct = m_Pcb->m_Drawings;
	for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
		{
		switch( PtStruct->m_StructType )
			{
			case TYPEDRAWSEGMENT:
				PlotDrawSegment( (DRAWSEGMENT*) PtStruct, PLOT_FORMAT_GERBER,
												masque_layer );
				break;

			case TYPETEXTE:
				PlotTextePcb( (TEXTE_PCB*) PtStruct, PLOT_FORMAT_GERBER,
												masque_layer );
				break;

			case TYPECOTATION:
				PlotCotation( (COTATION*) PtStruct, PLOT_FORMAT_GERBER,
												masque_layer );
				break;

			case TYPEMIRE:
				PlotMirePcb( (MIREPCB*) PtStruct, PLOT_FORMAT_GERBER,
												masque_layer );
				break;

			case TYPEMARQUEUR:
				break;

			default:
				DisplayError(this, wxT("Type Draw non gere"));
				break;
			}
		}

	/* Trace des Elements des modules autres que pads */
	nb_items = 0 ;
	Affiche_1_Parametre(this, 38, wxT("DrawMod"), wxEmptyString,GREEN) ;
	Module = m_Pcb->m_Modules;
	for( ; Module != NULL ;Module = (MODULE *)Module->Pnext )
		{
		 PtStruct = Module->m_Drawings;
		 for( ; PtStruct != NULL; PtStruct = PtStruct->Pnext )
			 {
			switch( PtStruct->m_StructType )
				 {
				 case TYPEEDGEMODULE:
					if( masque_layer & g_TabOneLayerMask[((EDGE_MODULE*)PtStruct)->GetLayer()] )
						Plot_1_EdgeModule(PLOT_FORMAT_GERBER, (EDGE_MODULE*) PtStruct);
					break;

				default: break;
				}
			}
		}

	/* Trace des Elements des modules : Pastilles */
	nb_items = 0 ;
	Affiche_1_Parametre(this, 48, wxT("Pads"),wxEmptyString,GREEN) ;
	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 )
		{
			wxPoint shape_pos;
			if( (PtPad->m_Masque_Layer & masque_layer) == 0)
							continue ;
			shape_pos = PtPad->ReturnShapePos();
			pos = shape_pos;

			size.x = PtPad->m_Size.x + (garde * 2) ;
			size.y = PtPad->m_Size.y + (garde * 2) ;
			
			/* Don't draw a null size item : */
			if ( (size.x == 0) || (size.y == 0) ) continue;

			nb_items++ ;

			switch (PtPad->m_PadShape)
			{
				case CIRCLE :
					Plot_1_CIRCLE_pad_GERBER(pos,size.x) ;
					break ;

				case OVALE :
					{
					trace_1_pastille_OVALE_GERBER(pos, size,PtPad->m_Orient);
					break ;
					}

				case TRAPEZE :
					{
					wxSize delta = PtPad->m_DeltaSize;
					trace_1_pad_TRAPEZE_GERBER(pos,size,
								delta, PtPad->m_Orient, FILLED) ;
					break ;
					}

				case RECT:
				default:
					PlotRectangularPad_GERBER(pos,size, PtPad->m_Orient) ;
					break ;
			}
			msg.Printf( wxT("%d"),nb_items) ;
			Affiche_1_Parametre(this, 48,wxEmptyString, msg,GREEN) ;
		}
	}
	/* trace des VIAS : */
	if(tracevia)
	{
		nb_items = 0 ;
		Affiche_1_Parametre(this, 56, wxT("Vias"), wxEmptyString,RED) ;
		for( track = m_Pcb->m_Track; track != NULL; track = (TRACK*) track->Pnext)
		{
			if( track->m_StructType != TYPEVIA ) continue;
			SEGVIA * Via = (SEGVIA *) track;
			/* vias not plotted if not on selected layer, but if layer
			== SOLDERMASK_LAYER_CU or SOLDERMASK_LAYER_CMP, vias are drawn ,
			if they are on a external copper layer
			*/
			int via_mask_layer = Via->ReturnMaskLayer();
			if ( (via_mask_layer & CUIVRE_LAYER ) ) via_mask_layer |= SOLDERMASK_LAYER_CU;
			if ( (via_mask_layer & CMP_LAYER ) ) via_mask_layer |= SOLDERMASK_LAYER_CMP;
			if( (via_mask_layer & masque_layer) == 0 ) continue;

			pos = Via->m_Start;
			size.x = size.y = Via->m_Width  + (garde * 2);
			Plot_1_CIRCLE_pad_GERBER(pos,size.x) ;
			nb_items++ ; msg.Printf( wxT("%d"),nb_items) ;
			Affiche_1_Parametre(this, 56,wxEmptyString, msg,RED) ;
		}
	}
	/* trace des pistes : */
	nb_items = 0 ;
	Affiche_1_Parametre(this, 64, wxT("Tracks"),wxEmptyString,YELLOW) ;

	for( track = m_Pcb->m_Track; track != NULL; track = (TRACK*) track->Pnext)
	{
		wxPoint end;

		if ( track->m_StructType == TYPEVIA ) continue ;
		if( (g_TabOneLayerMask[track->GetLayer()] & masque_layer) == 0 ) continue;

		size.x = size.y = track->m_Width;
		pos = track->m_Start; end = track->m_End;

		PlotGERBERLine(pos,end, size.x) ;

		nb_items++ ; msg.Printf( wxT("%d"),nb_items) ;
		Affiche_1_Parametre(this, 64, wxEmptyString, msg,YELLOW) ;
	}

	/* trace des zones: */
	nb_items = 0 ;
	if ( m_Pcb->m_Zone ) Affiche_1_Parametre(this, 72, wxT("Zones  "),wxEmptyString,YELLOW) ;

	for( track = m_Pcb->m_Zone; track != NULL; track = (TRACK*) track->Pnext)
	{
		wxPoint end;

		if( (g_TabOneLayerMask[track->GetLayer()] & masque_layer) == 0 ) continue;

		size.x = size.y = track->m_Width;
		pos = track->m_Start; end = track->m_End;

		PlotGERBERLine(pos,end, size.x) ;

		nb_items++ ; msg.Printf( wxT("%d"),nb_items) ;
		Affiche_1_Parametre(this, 72, wxEmptyString,msg,YELLOW) ;
	}
}


/**********************************************************************/
void trace_1_pastille_OVALE_GERBER(wxPoint pos, wxSize size, int orient)
/**********************************************************************/
/* Trace 1 pastille OVALE en position pos_X,Y:
		dimensions dx,dy,
		orientation orient
	Pour une orientation verticale ou horizontale, la forme est flashee
	Pour une orientation quelconque la forme est tracee comme un segment
*/
{
D_CODE * dcode_ptr;
int x0, y0, x1, y1, delta;

	if( (orient == 900) || (orient == 2700)) /* orient tournee de 90 deg */
	{
		EXCHG(size.x,size.y);
	}

	/* Trace de la forme flashee */
	if( (orient == 0) || (orient == 900) ||
		(orient == 1800) || (orient == 2700) )
	{
		UserToDeviceCoordinate(pos) ;
		UserToDeviceSize(size);

		dcode_ptr = get_D_code(size.x,size.y,GERB_OVALE,0) ;
		if (dcode_ptr->m_NumDcode != s_Last_D_code )
		{
			sprintf(cbuf,"G54D%d*\n",dcode_ptr->m_NumDcode) ;
			fputs(cbuf,dest) ;
			s_Last_D_code = dcode_ptr->m_NumDcode;
		}
		sprintf(cbuf,"X%5.5dY%5.5dD03*\n", pos.x, pos.y);
		fputs(cbuf,dest) ;
	}

	else	/* Forme tracee comme un segment */
	{
		if(size.x > size.y )
		{
			EXCHG(size.x,size.y); orient += 900;
		}
		/* la pastille est ramenee a une pastille ovale avec dy > dx */
		delta = size.y - size.x;
		x0 = 0; y0 = -delta / 2;
		x1 = 0; y1 = delta / 2;
		RotatePoint(&x0,&y0, orient);
		RotatePoint(&x1,&y1, orient);
		PlotGERBERLine( wxPoint(pos.x + x0, pos.y + y0),
						wxPoint(pos.x + x1, pos.y + y1), size.x);
	}
}


/******************************************************************/
void Plot_1_CIRCLE_pad_GERBER(wxPoint pos,int diametre)
/******************************************************************/
/* Plot a circulat pad or via at the user position pos
*/
{
D_CODE * dcode_ptr;
wxSize size(diametre, diametre);

	UserToDeviceCoordinate(pos);
	UserToDeviceSize(size);

	dcode_ptr = get_D_code(size.x,size.x,GERB_CIRCLE,0) ;
	if (dcode_ptr->m_NumDcode != s_Last_D_code )
	{
		sprintf(cbuf,"G54D%d*\n", dcode_ptr->m_NumDcode) ;
		fputs(cbuf,dest) ;
		s_Last_D_code = dcode_ptr->m_NumDcode;
	}

	sprintf(cbuf,"X%5.5dY%5.5dD03*\n", pos.x, pos.y);
	fputs(cbuf,dest) ;
}

/**************************************************************************/
void PlotRectangularPad_GERBER(wxPoint pos, wxSize size, int orient)
/**************************************************************************/
/*
 Trace 1 pad rectangulaire d'orientation quelconque
	donne par son centre, ses dimensions, et son orientation
	Pour une orientation verticale ou horizontale, la forme est flashee
	Pour une orientation quelconque la forme est tracee par 4 segments
	de largeur 1/2 largeur pad
*/
{
D_CODE * dcode_ptr;

	/* Trace de la forme flashee */
	switch (orient)
	{
		case 900 :
		case 2700 :  /* la rotation de 90 ou 270 degres revient a permutter des dimensions */
				 EXCHG(size.x,size.y);
		case 1800 :
		case 0 :
			UserToDeviceCoordinate(pos) ;
			UserToDeviceSize(size);

			dcode_ptr = get_D_code(size.x,size.y,GERB_RECT,0) ;
			if (dcode_ptr->m_NumDcode != s_Last_D_code )
			{
				sprintf(cbuf,"G54D%d*\n", dcode_ptr->m_NumDcode) ;
				fputs(cbuf,dest) ;
				s_Last_D_code = dcode_ptr->m_NumDcode;
			}
			sprintf(cbuf,"X%5.5dY%5.5dD03*\n", pos.x, pos.y);
			fputs(cbuf,dest) ;
			break;

		default:	  /* Forme tracee par remplissage */
				trace_1_pad_TRAPEZE_GERBER(pos, size, wxSize(0, 0), orient,FILLED);
			break;
	}
}


/*****************************************************************/
void trace_1_contour_GERBER(wxPoint pos, wxSize size, wxSize delta,
										int penwidth, int orient)
/*****************************************************************/
/*
 Trace 1 contour rectangulaire ou trapezoidal d'orientation quelconque
	donne par son centre,
	ses dimensions ,
	ses variations ,
	l'epaisseur du trait,
	et son orientation orient
*/
{
int ii;
wxPoint coord[4];

	size.x /= 2;  size.y /= 2 ;
	delta.x /= 2; delta.y /= 2 ; /* demi dim  dx et dy */

	coord[0].x = pos.x - size.x - delta.y;
	coord[0].y = pos.y + size.y + delta.x;

	coord[1].x = pos.x - size.x + delta.y;
	coord[1].y = pos.y - size.y - delta.x;

	coord[2].x = pos.x + size.x - delta.y;
	coord[2].y = pos.y - size.y + delta.x;

	coord[3].x = pos.x + size.x + delta.y;
	coord[3].y = pos.y + size.y - delta.x;

	for (ii = 0; ii < 4; ii++)
		{
		RotatePoint(&coord[ii].x, &coord[ii].y, pos.x, pos.y, orient);
		}


	PlotGERBERLine( coord[0], coord[1], penwidth);
	PlotGERBERLine( coord[1], coord[2], penwidth);
	PlotGERBERLine( coord[2], coord[3], penwidth);
	PlotGERBERLine( coord[3], coord[0], penwidth);
}


/*******************************************************************/
void trace_1_pad_TRAPEZE_GERBER(wxPoint pos, wxSize size,wxSize delta,
							int orient,int modetrace)
/*******************************************************************/

/*
 Trace 1 pad trapezoidal donne par :
	son centre pos.x,pos.y
	ses dimensions size.x et size.y
	les variations delta.x et delta.y ( 1 des deux au moins doit etre nulle)
	son orientation orient en 0.1 degres
	le mode de trace (FILLED, SKETCH, FILAIRE)

 Le trace n'est fait que pour un trapeze, c.a.d que delta.x ou delta.y
	= 0.

	les notation des sommets sont ( vis a vis de la table tracante )

"       0 ------------- 3   "
"        .             .    "
"         .     O     .     "
"          .         .      "
"           1 ---- 2        "


	exemple de Disposition pour delta.y > 0, delta.x = 0
"           1 ---- 2        "
"          .         .      "
"         .     O     .     "
"        .             .    "
"       0 ------------- 3   "


	exemple de Disposition pour delta.y = 0, delta.x > 0
"       0                  "
"       . .                "
"       .     .            "
"       .           3      "
"       .           .      "
"       .     O     .      "
"       .           .      "
"       .           2      "
"       .     .            "
"       . .                "
"       1                  "
*/
{
int ii , jj;
int dx,dy;
wxPoint polygone[4];	/* coord sommets */
int coord[8];
int ddx, ddy ;

	/* calcul des dimensions optimales du spot choisi = 1/4 plus petite dim */
	dx = size.x - abs(delta.y);
	dy = size.y - abs(delta.x);

	dx = size.x / 2;  dy = size.y / 2 ;
	ddx = delta.x / 2; ddy = delta.y / 2 ;

	polygone[0].x = - dx - ddy; polygone[0].y = + dy + ddx;
	polygone[1].x = - dx + ddy; polygone[1].y = - dy - ddx;
	polygone[2].x = + dx - ddy; polygone[2].y = - dy + ddx;
	polygone[3].x = + dx + ddy; polygone[3].y = + dy - ddx;

	/* Dessin du polygone et Remplissage eventuel de l'interieur */

	for (ii = 0, jj = 0; ii < 4; ii++)
	{
		RotatePoint(&polygone[ii].x, &polygone[ii].y, orient);
		coord[jj] = polygone[ii].x += pos.x;
		jj++;
		coord[jj] = polygone[ii].y += pos.y;
		jj++;
	}

	if(modetrace != FILLED )
	{
		PlotGERBERLine( polygone[0], polygone[1], scale_spot_mini);
		PlotGERBERLine( polygone[1], polygone[2], scale_spot_mini);
		PlotGERBERLine( polygone[2], polygone[3], scale_spot_mini);
		PlotGERBERLine( polygone[3], polygone[0], scale_spot_mini);
	}
	
	else
		PlotPolygon_GERBER(4, coord, TRUE);
}


/**********************************************************/
void PlotGERBERLine(wxPoint start, wxPoint end, int large)
/**********************************************************/
/* Trace 1 segment de piste :
*/
{
D_CODE * dcode_ptr;

	UserToDeviceCoordinate(start);
	UserToDeviceCoordinate(end);

	dcode_ptr = get_D_code(large,large,GERB_LINE,0) ;
	if (dcode_ptr->m_NumDcode != s_Last_D_code )
	{
		sprintf(cbuf,"G54D%d*\n", dcode_ptr->m_NumDcode) ;
		fputs(cbuf,dest) ;
		s_Last_D_code = dcode_ptr->m_NumDcode;
	}
	sprintf(cbuf,"X%5.5dY%5.5dD02*\n",start.x,start.y) ; fputs(cbuf,dest) ;
	sprintf(cbuf,"X%5.5dY%5.5dD01*\n",end.x,end.y) ; fputs(cbuf,dest) ;
}

/********************************************************************/
void PlotCircle_GERBER( wxPoint centre, int rayon, int epaisseur)
/********************************************************************/
/* routine de trace de 1 cercle de centre centre par approximation de segments
*/
{
int ii ;
int ox, oy, fx, fy;
int delta;  /* increment (en 0.1 degres) angulaire pour trace de cercles */

	delta = 120;	/* un cercle sera trace en 3600/delta segments */
	/* Correction pour petits cercles par rapport a l'epaisseur du trait */
	if( rayon < (epaisseur * 10) ) delta = 225; /* 16 segm pour 360 deg */
	if( rayon < (epaisseur * 5) ) delta = 300;  /* 12 segm pour 360 deg */
	if( rayon < (epaisseur * 2) ) delta = 600;  /* 6 segm pour 360 deg */

	ox = centre.x + rayon; oy = centre.y;
	for (ii = delta ; ii < 3600 ; ii += delta )
		{
		fx = centre.x + (int)(rayon * fcosinus[ii]);
		fy = centre.y + (int)(rayon * fsinus[ii]);
		PlotGERBERLine(wxPoint(ox,oy), wxPoint(fx,fy), epaisseur) ;
		ox = fx; oy = fy;
		}

	fx = centre.x + rayon; fy = centre.y;
	PlotGERBERLine(wxPoint(ox,oy), wxPoint(fx,fy), epaisseur) ;
}


/***************************************************************/
void PlotPolygon_GERBER(int nb_segm, int * coord, bool fill)
/***************************************************************/
{
int ii;
wxPoint pos;

	fputs("G36*\n", dest);
	pos.x = *coord; coord++;
	pos.y = *coord; coord++;
	UserToDeviceCoordinate(pos);
	fprintf(dest, "X%5.5dY%5.5dD02*\n", pos.x, pos.y );
	for ( ii = 1; ii < nb_segm; ii++ )
	{
		pos.x = *coord; coord++;
		pos.y = *coord; coord++;
		UserToDeviceCoordinate(pos);
		fprintf(dest, "X%5.5dY%5.5dD01*\n", pos.x, pos.y );
	}

	fputs("G37*\n", dest);
}


/*******************************************************/
D_CODE * get_D_code(int dx,int dy, int type, int drill )
/*******************************************************/
/*
 Fonction Recherchant et Creant eventuellement la description
	du D_CODE du type et dimensions demandees
*/
{
D_CODE * ptr_tool, * last_dcode_ptr;
int num_new_D_code = FIRST_DCODE_VALUE;


	ptr_tool = last_dcode_ptr = s_DCodeList;

	while(ptr_tool && ptr_tool->m_Type >= 0 )
	{
		if( ( ptr_tool->m_Size.x == dx ) &&
			( ptr_tool->m_Size.y == dy ) &&
			( ptr_tool->m_Type == type ) )
					return(ptr_tool);	/* D_code deja existant */
			last_dcode_ptr = ptr_tool;
			ptr_tool = ptr_tool->m_Pnext ;
			num_new_D_code++ ;
	}

	/* At this point, the requested D_CODE does not exist: It will be created */
	if ( ptr_tool == NULL )	/* We must create a new data */
	{
		ptr_tool = new D_CODE();
		ptr_tool->m_NumDcode = num_new_D_code;
		if ( last_dcode_ptr )
		{
			ptr_tool->m_Pback = last_dcode_ptr;
			last_dcode_ptr->m_Pnext = ptr_tool;
		}
		else s_DCodeList = ptr_tool;
	}
	ptr_tool->m_Size.x = dx ;
	ptr_tool->m_Size.y = dy ;
	ptr_tool->m_Type = type ;
	return(ptr_tool);
}


/******************************************************************/
void Init_Trace_GERBER(WinEDA_BasePcbFrame * frame, FILE * gerbfile)
/******************************************************************/
{
char Line[1024];

	s_Last_D_code = 0 ;

	DateAndTime(Line);
	wxString Title = g_Main_Title + wxT(" ") + GetBuildVersion();
	fprintf(gerbfile,"G04 (Genere par %s) le %s*\n",CONV_TO_UTF8(Title), Line);

	// Specify linear interpol (G01), unit = INCH (G70), abs format (G90):
	fputs("G01*\nG70*\nG90*\n", gerbfile);
	fputs("%MOIN*%\n", gerbfile);		// set unites = INCHES

	/* Set gerber format to 3.4 */
	strcpy(Line,"G04 Gerber Fmt 3.4, Leading zero omitted, Abs format*\n%FSLAX34Y34*%\n") ;

	fputs(Line,gerbfile);

	fputs("G04 APERTURE LIST*\n", gerbfile);
}


/***********************************/
static void Init_ApertureList(void)
/***********************************/
/* Init the memory to handle the aperture list:
	the member .m_Type is used by get_D_code() to handle the end of list:
	.m_Type < 0 is the first free aperture descr */
{
D_CODE * ptr_tool;

	ptr_tool = s_DCodeList;
	while ( ptr_tool )
	{
		s_DCodeList->m_Type = -1;
		ptr_tool = ptr_tool->m_Pnext ;
	}
	ShowDcodeError = TRUE;
}

/*****************************************************************/
void Fin_Trace_GERBER(WinEDA_BasePcbFrame * frame, FILE * gerbfile)
/*****************************************************************/
{
char line[1024];
wxString TmpFileName, msg;
FILE * outfile;

	fputs("M02*\n",gerbfile);
	fclose(gerbfile);

	// Reouverture gerbfile pour ajout des Apertures
	gerbfile = wxFopen(GerberFullFileName, wxT("rt") );
	if (gerbfile == NULL)
	{
		msg.Printf( _("unable to reopen file <%s>"),GerberFullFileName.GetData() ) ;
		DisplayError(frame, msg); return ;
	}


	// Ouverture tmpfile
	TmpFileName = GerberFullFileName + wxT(".$$$");
	outfile = wxFopen(TmpFileName, wxT("wt") );
	if ( outfile == NULL )
	{
		fclose(gerbfile);
		DisplayError(frame, wxT("Fin_Trace_GERBER(): Can't Open tmp file"));
		return;
	}

	// Placement des Apertures en RS274X
	rewind(gerbfile);
	while ( fgets(line, 1024, gerbfile) )
	{
		fputs(line, outfile);
		if ( strcmp(strtok(line, "\n\r"),"G04 APERTURE LIST*") == 0 )
		{
			frame->Gen_D_CODE_File(outfile);
			fputs("G04 APERTURE END LIST*\n", outfile);
		}
	}

	fclose(outfile);
	fclose(gerbfile);
	wxRemoveFile(GerberFullFileName);
	wxRenameFile(TmpFileName, GerberFullFileName);

}


/******************************************************/
int WinEDA_BasePcbFrame::Gen_D_CODE_File(FILE * penfile)
/******************************************************/
/* Genere la liste courante des D_CODES
	Retourne le nombre de D_Codes utilises
	Genere une sequence RS274X
 */
{
D_CODE * ptr_tool;
int nb_dcodes = 0 ;

	/* Init : */
	ptr_tool = s_DCodeList;

	while(ptr_tool && (ptr_tool->m_Type >= 0 ) )
	{
		float fscale = 0.0001;	// For 3.4 format
		char * text;
		sprintf(cbuf,"%%ADD%d", ptr_tool->m_NumDcode);
		text = cbuf + strlen(cbuf);
		switch ( ptr_tool->m_Type )
		{
			case 1:	// Circle (flash )
				sprintf(text,"C,%f*%%\n", ptr_tool->m_Size.x * fscale);
				break;

			case 2:	// RECT
				sprintf(text,"R,%fX%f*%%\n", ptr_tool->m_Size.x * fscale,
								ptr_tool->m_Size.y * fscale);
				break;

			case 3:	// Circle ( lines )
				sprintf(text,"C,%f*%%\n", ptr_tool->m_Size.x * fscale);
				break;

			case 4:	// OVALE
				sprintf(text,"O,%fX%f*%%\n", ptr_tool->m_Size.x * fscale,
								ptr_tool->m_Size.y * fscale);
				break;

			default:
				DisplayError(this, wxT("Gen_D_CODE_File(): Dcode Type err") );
				break;
		}
		// compensation localisation printf (float x.y généré x,y)
		to_point ( text + 2 );

		fputs(cbuf,penfile) ;
		ptr_tool = ptr_tool->m_Pnext; nb_dcodes++ ;
	}

	return(nb_dcodes);
}


