Commit 26736baa authored by dickelbeck's avatar dickelbeck

gerbview cleanup, and working towards aperture macro support

parent eac91489
...@@ -5,6 +5,17 @@ Started 2007-June-11 ...@@ -5,6 +5,17 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with Please add newer entries at the top, list the date and your name with
email address. email address.
2008-Nov-8 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
+gerview
Added support for reading in aperture macros embedded in a RS274X compatible file.
Cannot display them yet.
General cleanup of gerbview. GERBER_Descr replaced with class GERBER.
ReturnToolDescr() replaced with GERBER::GetDCODE().
D_CODEs are created lazily now. pcbnew's gerber plotting needs testing, might
have broke something there, accidentally.
2008-nov-5 UPDATE Andrey Fedorushkov <andrf@mail.ru> 2008-nov-5 UPDATE Andrey Fedorushkov <andrf@mail.ru>
================================================================================ ================================================================================
+all: +all:
......
...@@ -58,58 +58,3 @@ void Affiche_Infos_PCB_Texte( WinEDA_BasePcbFrame* frame, TEXTE_PCB* pt_texte ) ...@@ -58,58 +58,3 @@ void Affiche_Infos_PCB_Texte( WinEDA_BasePcbFrame* frame, TEXTE_PCB* pt_texte )
Affiche_1_Parametre( frame, 70, _( "V Size" ), Line, RED ); Affiche_1_Parametre( frame, 70, _( "V Size" ), Line, RED );
} }
/*********************************************************************/
void Affiche_Infos_Piste( WinEDA_BasePcbFrame* frame, TRACK* pt_piste )
/*********************************************************************/
/* Affiche les caract principales d'un segment de piste en bas d'ecran */
{
int d_index, ii = -1;
D_CODE* pt_D_code;
int layer = ((PCB_SCREEN*)(frame->GetScreen()))->m_Active_Layer;
wxString msg;
frame->MsgPanel->EraseMsgBox();
d_index = pt_piste->GetNet();
pt_D_code = ReturnToolDescr( layer, d_index, &ii );
switch( pt_piste->Type() )
{
case TYPETRACK:
if( pt_piste->m_Shape < S_SPOT_CIRCLE )
msg = wxT( "LINE" );
else
msg = wxT( "FLASH" );
break;
case TYPEZONE:
msg = wxT( "ZONE" ); break;
default:
msg = wxT( "????" ); break;
}
Affiche_1_Parametre( frame, 1, _( "Type" ), msg, DARKCYAN );
msg.Printf( wxT( "%d" ), ii + 1 );
Affiche_1_Parametre( frame, 10, _( "Tool" ), msg, RED );
if( pt_D_code )
{
msg.Printf( wxT( "D%d" ), d_index );
Affiche_1_Parametre( frame, 20, _( "D-code" ), msg, BLUE );
Affiche_1_Parametre( frame, 30, _( "D-type" ),
pt_D_code ? g_GERBER_Tool_Type[pt_D_code->m_Shape] : _( "????" ),
BLUE );
}
msg.Printf( wxT( "%d" ), pt_piste->GetLayer() + 1 );
Affiche_1_Parametre( frame, 40, _( "Layer" ), msg, BROWN );
/* Affiche Epaisseur */
valeur_param( (unsigned) (pt_piste->m_Width), msg );
Affiche_1_Parametre( frame, 50, _( "Width" ), msg, DARKCYAN );
}
This diff is collapsed.
...@@ -58,16 +58,6 @@ enum APERTURE_T ...@@ -58,16 +58,6 @@ enum APERTURE_T
APT_MACRO = 'M' APT_MACRO = 'M'
}; };
/* replaced by APERTURE_T
enum Gerb_StandardShape {
GERB_CIRCLE = 1,
GERB_RECT,
GERB_LINE,
GERB_OVALE,
GERB_SPECIAL_SHAPE
};
*/
// Interpolation type // Interpolation type
enum Gerb_Interpolation { enum Gerb_Interpolation {
...@@ -111,21 +101,49 @@ enum Gerb_Analyse_Cmd { ...@@ -111,21 +101,49 @@ enum Gerb_Analyse_Cmd {
ENTER_RS274X_CMD ENTER_RS274X_CMD
}; };
class D_CODE;
/** /**
* Struct DCODE_PARAM * Class DCODE_PARAM
* holds a parameter for a DCODE or an "aperture macro" as defined within standard RS274X. * holds a parameter for a DCODE or an "aperture macro" as defined within standard RS274X.
* The \a value field can be either a constant or a place holder for a DCODE * The \a value field can be either a constant or a place holder for a DCODE
* parameter. * parameter.
*/ */
struct DCODE_PARAM class DCODE_PARAM
{ {
public:
DCODE_PARAM() : DCODE_PARAM() :
isImmediate(true), index(-1),
value(0.0) value(0.0)
{} {}
bool isImmediate; ///< the \a value field is an actual value, not a parameter place holder. double GetValue( const D_CODE* aDcode );
void SetValue( double aValue )
{
value = aValue;
index = -1;
}
/**
* Function IsImmediate
* tests if this DCODE_PARAM holds an immediate parameter or is a pointer into
* a parameter held by an owning D_CODE.
*/
bool IsImmediate() { return index == -1; }
int GetIndex()
{
return index;
}
void SetIndex( int aIndex )
{
index = aIndex;
}
private:
int index; ///< if -1, then \a value field is an immediate value, else this is an index into a D_CODE parameter.
double value; ///< if immediate then the value, else an integer index into D_CODE.m_am_params. double value; ///< if immediate then the value, else an integer index into D_CODE.m_am_params.
}; };
...@@ -183,7 +201,7 @@ struct APERTURE_MACRO ...@@ -183,7 +201,7 @@ struct APERTURE_MACRO
*/ */
struct APERTURE_MACRO_less_than struct APERTURE_MACRO_less_than
{ {
// a "less than" test on two wxStrings // a "less than" test on two APERTURE_MACROs (.name wxStrings)
bool operator()( const APERTURE_MACRO& am1, const APERTURE_MACRO& am2) const bool operator()( const APERTURE_MACRO& am1, const APERTURE_MACRO& am2) const
{ {
return am1.name.Cmp( am2.name ) < 0; // case specific wxString compare return am1.name.Cmp( am2.name ) < 0; // case specific wxString compare
...@@ -206,6 +224,14 @@ typedef std::pair<APERTURE_MACRO_SET::iterator, bool> APERTURE_MACRO_SET_PAIR; ...@@ -206,6 +224,14 @@ typedef std::pair<APERTURE_MACRO_SET::iterator, bool> APERTURE_MACRO_SET_PAIR;
*/ */
class D_CODE class D_CODE
{ {
APERTURE_MACRO* m_Macro; ///< no ownership, points to GERBER.m_aperture_macros element
/**
* parameters used only when this D_CODE holds a reference to an aperture
* macro, and these parameters would customize the macro.
*/
DCODE_PARAMS m_am_params;
public: public:
wxSize m_Size; /* Dimensions horiz et Vert */ wxSize m_Size; /* Dimensions horiz et Vert */
APERTURE_T m_Shape; /* shape ( Line, rect , circulaire , ovale .. ) */ APERTURE_T m_Shape; /* shape ( Line, rect , circulaire , ovale .. ) */
...@@ -216,27 +242,55 @@ public: ...@@ -216,27 +242,55 @@ public:
bool m_Defined; /* FALSE si non defini */ bool m_Defined; /* FALSE si non defini */
wxString m_SpecialDescr; wxString m_SpecialDescr;
APERTURE_MACRO* m_Macro; ///< no ownership, points to GERBER.m_aperture_macros element
/**
* parameters used only when this D_CODE holds a reference to an aperture
* macro, and these parameters would customize the macro.
*/
DCODE_PARAMS m_am_params;
public: public:
D_CODE( int num_dcode ); D_CODE( int num_dcode );
~D_CODE(); ~D_CODE();
void Clear_D_CODE_Data(); void Clear_D_CODE_Data();
void AppendParam( double aValue )
{
DCODE_PARAM param;
param.SetValue( aValue );
m_am_params.push_back( param );
}
void SetMacro( APERTURE_MACRO* aMacro )
{
m_Macro = aMacro;
}
/**
* Function ShowApertureType
* returns a character string telling what type of aperture type \a aType is.
* @param aType The aperture type to show.
*/
static const wxChar* ShowApertureType( APERTURE_T aType );
}; };
inline double DCODE_PARAM::GetValue( const D_CODE* aDcode )
{
if( IsImmediate() )
return value;
else
{
// get the parameter from aDcode
return 0.0;
}
}
/** /**
* Class GERBER * Class GERBER
* holds the data for one gerber file or layer * holds the data for one gerber file or layer
*/ */
class GERBER class GERBER
{ {
D_CODE* m_Aperture_List[MAX_TOOLS]; ///< Dcode (Aperture) List for this layer
public: public:
wxString m_FileName; // Full File Name for this layer wxString m_FileName; // Full File Name for this layer
wxString m_Name; // Layer name wxString m_Name; // Layer name
...@@ -247,7 +301,7 @@ public: ...@@ -247,7 +301,7 @@ public:
bool m_NoTrailingZeros; // True: zeros a droite supprims bool m_NoTrailingZeros; // True: zeros a droite supprims
bool m_MirorA; // True: miror / axe A (X) bool m_MirorA; // True: miror / axe A (X)
bool m_MirorB; // True: miror / axe B (Y) bool m_MirorB; // True: miror / axe B (Y)
bool m_As_DCode; // TRUE = DCodes in file (FALSE = no DCode-> bool m_Has_DCode; // TRUE = DCodes in file (FALSE = no DCode->
// separate DCode file // separate DCode file
wxPoint m_Offset; // Coord Offset wxPoint m_Offset; // Coord Offset
wxSize m_FmtScale; // Fmt 2.3: m_FmtScale = 3, fmt 3.4: m_FmtScale = 4 wxSize m_FmtScale; // Fmt 2.3: m_FmtScale = 3, fmt 3.4: m_FmtScale = 4
...@@ -262,7 +316,6 @@ public: ...@@ -262,7 +316,6 @@ public:
wxPoint m_CurrentPos; // current specified coord for plot wxPoint m_CurrentPos; // current specified coord for plot
wxPoint m_PreviousPos; // old current specified coord for plot wxPoint m_PreviousPos; // old current specified coord for plot
wxPoint m_IJPos; // IJ coord (for arcs & circles ) wxPoint m_IJPos; // IJ coord (for arcs & circles )
D_CODE* m_Aperture_List[MAX_TOOLS + FIRST_DCODE + 1]; // Dcode (Aperture) List for this layer
FILE* m_Current_File; // Current file to read FILE* m_Current_File; // Current file to read
FILE* m_FilesList[12]; // Files list FILE* m_FilesList[12]; // Files list
...@@ -283,6 +336,11 @@ public: ...@@ -283,6 +336,11 @@ public:
void Clear_GERBER(); void Clear_GERBER();
int ReturnUsedDcodeNumber(); int ReturnUsedDcodeNumber();
void ResetDefaultValues(); void ResetDefaultValues();
/**
* Function InitToolTable
*/
void InitToolTable(); void InitToolTable();
// Routines utilises en lecture de ficher gerber // Routines utilises en lecture de ficher gerber
...@@ -324,6 +382,26 @@ public: ...@@ -324,6 +382,26 @@ public:
* @return bool - true if a macro was read in successfully, else false. * @return bool - true if a macro was read in successfully, else false.
*/ */
bool ReadApertureMacro( char aBuff[GERBER_BUFZ], char*& text, FILE* gerber_file ); bool ReadApertureMacro( char aBuff[GERBER_BUFZ], char*& text, FILE* gerber_file );
/**
* Function GetDCODE
* returns a pointer to the D_CODE within this GERBER for the given
* \a aDCODE.
* @param aDCODE The numeric value of the D_CODE to look up.
* @param createIfNoExist If true, then create the D_CODE if it does not exist.
* @return D_CODE* - the one implied by the given \a aDCODE, or NULL
* if the requested \a aDCODE is out of range.
*/
D_CODE* GetDCODE( int aDCODE, bool createIfNoExist=true );
/**
* Function FindApertureMacro
* looks up a previously read in aperture macro.
* @param aLookup A dummy APERTURE_MACRO with [only] the name field set.
* @return APERTURE_MACRO* - the one with a matching name, or NULL if not found.
*/
APERTURE_MACRO* FindApertureMacro( const APERTURE_MACRO& aLookup );
}; };
...@@ -334,27 +412,6 @@ public: ...@@ -334,27 +412,6 @@ public:
bool GetEndOfBlock( char buff[GERBER_BUFZ], char*& text, FILE* gerber_file ); bool GetEndOfBlock( char buff[GERBER_BUFZ], char*& text, FILE* gerber_file );
/**
* Function ReturnToolDescr
* returns a D_CODE given a global layer index and Dcode value.
* @param aLayer The index into the global array of GERBER called g_GERBER_List[].
* @param aDcode The dcode value to look up.
* @param aIndex If not null, where to put a one basedindex into the GERBER's m_Aperture_List[] array.
* @return D_CODE* - the looked up D_CODE or NULL if none was encountered in the gerber file for given \a aDcode.
*/
D_CODE * ReturnToolDescr( int layer, int Dcode, int * index = NULL );
eda_global const wxChar* g_GERBER_Tool_Type[6]
#ifdef MAIN
= {
wxT( "????" ), wxT( "Round" ), wxT( "Rect" ), wxT( "Line" ), wxT( "Oval" ), wxT( "Macro" )
}
#endif
;
eda_global GERBER* g_GERBER_List[32]; eda_global GERBER* g_GERBER_List[32];
......
...@@ -261,7 +261,7 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC, ...@@ -261,7 +261,7 @@ bool WinEDA_GerberFrame::Read_GERBER_File( wxDC* DC,
/* Init DCodes list and perhaps read a DCODES file, /* Init DCodes list and perhaps read a DCODES file,
* if the gerber file is only a RS274D file (without any aperture information) * if the gerber file is only a RS274D file (without any aperture information)
*/ */
if( !gerber->m_As_DCode ) if( !gerber->m_Has_DCode )
{ {
wxString DCodeFileName; wxString DCodeFileName;
if( D_Code_FullFileName.IsEmpty() ) if( D_Code_FullFileName.IsEmpty() )
......
...@@ -92,7 +92,7 @@ static int ReadInt( char*& text ) ...@@ -92,7 +92,7 @@ static int ReadInt( char*& text )
/** /**
* Function ReadDouble * Function ReadDouble
* reads a double in from a character buffer. If there is a comma after the double, * reads a double from an ASCII character buffer. If there is a comma after the double,
* then skip over that. * then skip over that.
* @param text A reference to a character pointer from which the ASCII double * @param text A reference to a character pointer from which the ASCII double
* is read from and the pointer advanced for each character read. * is read from and the pointer advanced for each character read.
...@@ -171,9 +171,7 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t ...@@ -171,9 +171,7 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t
{ {
int code; int code;
int xy_seq_len, xy_seq_char; int xy_seq_len, xy_seq_char;
char ctmp;
bool ok = TRUE; bool ok = TRUE;
D_CODE* dcode;
char line[GERBER_BUFZ]; char line[GERBER_BUFZ];
wxString msg; wxString msg;
double fcoord; double fcoord;
...@@ -221,8 +219,9 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t ...@@ -221,8 +219,9 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t
case 'X': case 'X':
case 'Y': // Valeurs transmises :2 (really xy_seq_len : FIX ME) digits case 'Y': // Valeurs transmises :2 (really xy_seq_len : FIX ME) digits
{
code = *(text++); code = *(text++);
ctmp = *(text++) - '0'; char ctmp = *(text++) - '0';
if( code == 'X' ) if( code == 'X' )
{ {
m_FmtScale.x = *text - '0'; // = nb chiffres apres la virgule m_FmtScale.x = *text - '0'; // = nb chiffres apres la virgule
...@@ -234,6 +233,7 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t ...@@ -234,6 +233,7 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t
m_FmtLen.y = ctmp + m_FmtScale.y; m_FmtLen.y = ctmp + m_FmtScale.y;
} }
text++; text++;
}
break; break;
case '*': case '*':
...@@ -321,10 +321,6 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t ...@@ -321,10 +321,6 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t
m_LayerNegative = FALSE; m_LayerNegative = FALSE;
break; break;
case AP_MACRO:
ReadApertureMacro( buff, text, m_Current_File );
break;
case INCLUDE_FILE: case INCLUDE_FILE:
if( m_FilesPtr >= 10 ) if( m_FilesPtr >= 10 )
{ {
...@@ -349,29 +345,45 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t ...@@ -349,29 +345,45 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t
m_FilesPtr++; m_FilesPtr++;
break; break;
case AP_MACRO:
ok = ReadApertureMacro( buff, text, m_Current_File );
if( !ok )
break;
break;
case AP_DEFINITION: case AP_DEFINITION:
if( *text != 'D' )
// input example: %ADD30R,0.081800X0.101500*%
// at this point, text points to 2nd 'D'
if( *text++ != 'D' )
{ {
ok = FALSE; ok = FALSE;
break; break;
} }
m_As_DCode = TRUE;
text++; m_Has_DCode = TRUE;
code = ReadInt( text ); code = ReadInt( text );
ctmp = *text;
dcode = ReturnToolDescr( m_Layer, code ); D_CODE* dcode;
dcode = GetDCODE( code );
if( dcode == NULL ) if( dcode == NULL )
break; break;
if( text[1] == ',' ) // Tool usuel (C,R,O,P) // at this point, text points to character after the ADD<num>, i.e. R in example above
// if text[0] is one of the usual apertures: (C,R,O,P), there is a comma after it.
if( text[1] == ',' )
{ {
text += 2; // text pointe size ( 1er modifier) char stdAperture = *text;
text += 2; // skip "C," for example
dcode->m_Size.x = dcode->m_Size.y = dcode->m_Size.x = dcode->m_Size.y =
(int) round( ReadDouble( text ) * conv_scale ); (int) round( ReadDouble( text ) * conv_scale );
switch( ctmp ) switch( stdAperture )
{ {
case 'C': // Circle case 'C': // Circle
dcode->m_Shape = APT_CIRCLE; dcode->m_Shape = APT_CIRCLE;
...@@ -402,7 +414,7 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t ...@@ -402,7 +414,7 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t
case 'O': // oval case 'O': // oval
case 'R': // rect case 'R': // rect
dcode->m_Shape = (ctmp == 'O') ? APT_OVAL : APT_RECT; dcode->m_Shape = (stdAperture == 'O') ? APT_OVAL : APT_RECT;
while( *text == ' ' ) while( *text == ' ' )
text++; text++;
...@@ -444,6 +456,40 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t ...@@ -444,6 +456,40 @@ bool GERBER::ExecuteRS274XCommand( int command, char buff[GERBER_BUFZ], char*& t
break; break;
} }
} }
else // text[0] starts an aperture macro name
{
APERTURE_MACRO am_lookup;
while( *text && *text!='*' && *text!=',' )
am_lookup.name.Append( *text++ );
if( *text && *text==',' )
{
while( *text && *text!='*' )
{
double param = ReadDouble( text );
if( *text == 'X' )
++text;
dcode->AppendParam( param );
}
}
// lookup the aperture macro here.
APERTURE_MACRO* pam = FindApertureMacro( am_lookup );
if( !pam )
{
// @todo not found, don't know how to report an error
D( printf("aperture macro %s not found\n", CONV_TO_UTF8(am_lookup.name) );)
ok = false;
break;
}
D(printf("pam has %d parameters\n", pam->primitives.size() );)
dcode->SetMacro( (APERTURE_MACRO*) pam );
}
break; break;
default: default:
...@@ -531,7 +577,6 @@ bool GERBER::ReadApertureMacro( char buff[GERBER_BUFZ], char*& text, FILE* gerbe ...@@ -531,7 +577,6 @@ bool GERBER::ReadApertureMacro( char buff[GERBER_BUFZ], char*& text, FILE* gerbe
switch( prim.primitive_id ) switch( prim.primitive_id )
{ {
default:
case AMP_CIRCLE: case AMP_CIRCLE:
paramCount = 4; paramCount = 4;
break; break;
...@@ -558,43 +603,48 @@ bool GERBER::ReadApertureMacro( char buff[GERBER_BUFZ], char*& text, FILE* gerbe ...@@ -558,43 +603,48 @@ bool GERBER::ReadApertureMacro( char buff[GERBER_BUFZ], char*& text, FILE* gerbe
case AMP_THERMAL: case AMP_THERMAL:
paramCount = 6; paramCount = 6;
break; break;
default:
// @todo, there needs to be a way of reporting the line number and character offset.
D(printf("Invalid primitive id code %d\n", prim.primitive_id );)
return false;
} }
DCODE_PARAM param;
for( int i=0; i<paramCount && *text && *text!='*'; ++i ) for( int i=0; i<paramCount && *text && *text!='*'; ++i )
{ {
DCODE_PARAM param; // construct it on each loop iteration
if( *text == '$' ) if( *text == '$' )
{ {
++text; ++text;
param.isImmediate = false; param.SetIndex( ReadInt( text ) );
} }
else else
{ param.SetValue( ReadDouble( text ) );
param.isImmediate = true;
}
param.value = ReadDouble( text );
prim.params.push_back( param ); prim.params.push_back( param );
} }
// there are more parameters to read if this is an AMP_OUTLINE
if( prim.primitive_id == AMP_OUTLINE ) if( prim.primitive_id == AMP_OUTLINE )
{ {
paramCount = (int) prim.params[1].value * 2 + 1; // params[1] is a count of polygon points, so it must be given
// in advance, i.e. be immediate.
wxASSERT( prim.params[1].IsImmediate() );
paramCount = (int) prim.params[1].GetValue(0) * 2 + 1;
for( int i=0; i<paramCount && *text && *text!='*'; ++i ) for( int i=0; i<paramCount && *text && *text!='*'; ++i )
{ {
DCODE_PARAM param; // construct it on each loop
if( *text == '$' ) if( *text == '$' )
{ {
++text; ++text;
param.isImmediate = false; param.SetIndex( ReadInt( text ) );
} }
else else
{ param.SetValue( ReadDouble( text ) );
param.isImmediate = true;
}
param.value = ReadDouble( text );
prim.params.push_back( param ); prim.params.push_back( param );
} }
} }
......
...@@ -25,6 +25,10 @@ ...@@ -25,6 +25,10 @@
#define ABS( y ) ( (y) >= 0 ? (y) : ( -(y) ) ) #define ABS( y ) ( (y) >= 0 ? (y) : ( -(y) ) )
#endif #endif
/// # of elements in an arrray
#define DIM(x) (sizeof(x)/sizeof((x)[0]))
#define DEG2RAD( Deg ) ( (Deg) * M_PI / 180.0 ) #define DEG2RAD( Deg ) ( (Deg) * M_PI / 180.0 )
#define RAD2DEG( Rad ) ( (Rad) * 180.0 / M_PI ) #define RAD2DEG( Rad ) ( (Rad) * 180.0 / M_PI )
......
...@@ -67,11 +67,14 @@ Outils et D_CODES ...@@ -67,11 +67,14 @@ Outils et D_CODES
/*************************************/ /*************************************/
/* codes de type de forme d'outils */ /* codes de type de forme d'outils */
/*
#define GERB_CIRCLE 1 #define GERB_CIRCLE 1
#define GERB_RECT 2 #define GERB_RECT 2
#define GERB_LINE 3 #define GERB_LINE 3
#define GERB_OVALE 4 #define GERB_OVALE 4
#define GERB_DONUT 5 #define GERB_DONUT 5
*/
/* liste des D_CODES en fonction de leur numero d'ordre (numero d'outil) /* liste des D_CODES en fonction de leur numero d'ordre (numero d'outil)
(l'ordre 0 n'est pas utilise) ; (l'ordre 0 n'est pas utilise) ;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment