/****************************************/ /**** 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(); 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) (10 * spot_mini * 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; } SetLocaleTo_C_standard( ); 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( !g_Exclude_Edges_Pcb ) layer_mask |= EDGE_LAYER; switch( Layer ) { case FIRST_COPPER_LAYER: 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 LAST_COPPER_LAYER: 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 ); SetLocaleTo_Default( ); } /***********************************************************************/ 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 93 and 94.) // 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->Type() ) { 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 TYPEMARKER: 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->Type() ) { 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 + 2 * garde; size.y = PtPad->m_Size.y + 2 * garde; /* Don't draw a null size item : */ if( size.x <= 0 || size.y <= 0 ) continue; nb_items++; switch( PtPad->m_PadShape ) { case PAD_CIRCLE: Plot_1_CIRCLE_pad_GERBER( pos, size.x ); break; case PAD_OVAL: // Check whether the pad really has a circular shape instead if( size.x == size.y ) Plot_1_CIRCLE_pad_GERBER( pos, size.x ); else trace_1_pastille_OVALE_GERBER( pos, size, PtPad->m_Orient ); break; case PAD_TRAPEZOID: { wxSize delta = PtPad->m_DeltaSize; trace_1_pad_TRAPEZE_GERBER( pos, size, delta, PtPad->m_Orient, FILLED ); } break; case PAD_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->Type() != 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 + 2 * garde; /* Don't draw a null size item : */ if( size.x <= 0 ) continue; 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->Type() == 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 PAD_OVAL 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 ); if( orient < 2700 ) orient += 900; else orient -= 2700; } /* 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 circular 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 ); // Pass through case 0: case 1800: 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() /***********************************/ /* 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: // PAD_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: // PAD_OVAL 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; }