kicad/gerbview/dcode.cpp

536 lines
15 KiB
C++

/***************************/
/**** Read GERBER files ****/
/***************************/
#include "fctsys.h"
#include "common.h"
#include "class_drawpanel.h"
#include "confirm.h"
#include "macros.h"
#include "gerbview.h"
#include "pcbplot.h"
#include "protos.h"
#define DEFAULT_SIZE 100
/* Format Gerber: NOTES:
* Features history:
* Gn =
* G01 linear interpolation (right trace)
* G02, G20, G21 Circular interpolation, meaning trig < 0
* G03, G30, G31 Circular interpolation, meaning trig > 0
* G04 review
* G06 parabolic interpolation
* G07 Cubic Interpolation
* G10 linear interpolation (scale x10)
* G11 linear interpolation (0.1x range)
* G12 linear interpolation (0.01x scale)
* G52 plot symbol reference code by Dnn
* G53 plot symbol reference by Dnn; symbol rotates from -90 degrees
* G54 Selection Tool
* G55 Fashion photo exhibition
* G56 plot symbol reference code for DNN
* G57 displays the symbol link to the console
* G58 plot displays the symbol and link to the console
* G60 linear interpolation (scale x100)
* G70 Units = Inches
* G71 Units = Millimeters
* G74 circular interpolation removes 360 degree, has returned G01
* G75 circular interpolation Active 360 degree
* G90 mode absolute coordinates
* G91 Fashion Related Contacts
*
* Coordinates X, Y
* X and Y are followed by + or - and m + n digits (not separated)
* m = integer part
* n = part after the comma
* conventional formats: m = 2, n = 3 (size 2.3)
* m = 3, n = 4 (size 3.4)
* eg
* G__ X00345Y-06123 * D__
*
* Tools and D_CODES
* tool number (identification of shapes)
* 1 to 99 (Classical)
* 1 to 999
*
* D_CODES:
* D01 ... D9 = action codes:
* D01 = activating light (lower pen) when di ¿½ placement
* D02 = light extinction (lift pen) when di ¿½ placement
* D03 Flash
* D09 = VAPE Flash
* D10 ... = Indentification Tool (Opening)
*/
GERBER::GERBER( int aLayer )
{
m_Layer = aLayer; // Layer Number
m_Selected_Tool = FIRST_DCODE;
ResetDefaultValues();
for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
m_Aperture_List[ii] = 0;
m_Pcb = 0;
}
GERBER::~GERBER()
{
for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
{
delete m_Aperture_List[ii];
// m_Aperture_List[ii] = NULL;
}
delete m_Pcb;
}
D_CODE* GERBER::GetDCODE( int aDCODE, bool create )
{
unsigned ndx = aDCODE - FIRST_DCODE;
if( ndx < (unsigned) DIM( m_Aperture_List ) )
{
// lazily create the D_CODE if it does not exist.
if( create )
{
if( m_Aperture_List[ndx] == NULL )
m_Aperture_List[ndx] = new D_CODE( ndx + FIRST_DCODE );
}
return m_Aperture_List[ndx];
}
return NULL;
}
APERTURE_MACRO* GERBER::FindApertureMacro( const APERTURE_MACRO& aLookup )
{
APERTURE_MACRO_SET::iterator iter = m_aperture_macros.find( aLookup );
if( iter != m_aperture_macros.end() )
{
APERTURE_MACRO* pam = (APERTURE_MACRO*) &(*iter);
return pam;
}
return NULL; // not found
}
void GERBER::ResetDefaultValues()
{
m_FileName.Empty();
m_Name = wxT( "no name" ); // Layer name
m_LayerNegative = FALSE; // TRUE = Negative Layer
m_ImageNegative = FALSE; // TRUE = Negative image
m_GerbMetric = FALSE; // FALSE = Inches, TRUE = metric
m_Relative = FALSE; // FALSE = absolute Coord, RUE =
// relative Coord
m_NoTrailingZeros = FALSE; // True: trailing zeros deleted
m_MirorA = FALSE; // True: miror / axe A (X)
m_MirorB = FALSE; // True: miror / axe B (Y)
m_Has_DCode = FALSE; // TRUE = DCodes in file (FALSE = no
// DCode->
// separate DCode file
m_Offset.x = m_Offset.y = 0; // Coord Offset
m_FmtScale.x = m_FmtScale.y = g_Default_GERBER_Format % 10;
m_FmtLen.x = m_FmtLen.y = m_FmtScale.x + (g_Default_GERBER_Format / 10);
m_LayerScale.x = m_LayerScale.y = 1.0; // scale (X and Y) this
// layer
m_Rotation = 0;
m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Linear, 90 arc, Circ.
m_360Arc_enbl = FALSE; // 360 deg circular
// interpolation disable
m_Current_Tool = 0; // Current Tool (Dcode)
// number selected
m_CommandState = 0; // gives tate of the
// stacking order analysis
m_CurrentPos.x = m_CurrentPos.y = 0; // current specified coord
// for plot
m_PreviousPos.x = m_PreviousPos.y = 0; // old current specified
// coord for plot
m_IJPos.x = m_IJPos.y = 0; // current centre coord for
// plot arcs & circles
m_Current_File = NULL; // File to read
m_FilesPtr = 0;
m_Transform[0][0] = m_Transform[1][1] = 1;
m_Transform[0][1] = m_Transform[1][0] = 0; // Rotation/mirror = Normal
m_PolygonFillMode = FALSE;
m_PolygonFillModeState = 0;
}
int GERBER::ReturnUsedDcodeNumber()
{
int count = 0;
for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
{
if( m_Aperture_List[ii] )
if( m_Aperture_List[ii]->m_InUse || m_Aperture_List[ii]->m_Defined )
++count;
}
return count;
}
void GERBER::InitToolTable()
{
for( int count = 0; count < MAX_TOOLS; count++ )
{
if( m_Aperture_List[count] == NULL )
continue;
m_Aperture_List[count]->m_Num_Dcode = count + FIRST_DCODE;
m_Aperture_List[count]->Clear_D_CODE_Data();
}
}
/***************/
/* Class DCODE */
/***************/
D_CODE::D_CODE( int num_dcode )
{
m_Num_Dcode = num_dcode;
Clear_D_CODE_Data();
}
D_CODE::~D_CODE()
{
}
void D_CODE::Clear_D_CODE_Data()
{
m_Size.x = DEFAULT_SIZE;
m_Size.y = DEFAULT_SIZE;
m_Shape = APT_CIRCLE;
m_Drill.x = m_Drill.y = 0;
m_DrillShape = 0;
m_InUse = FALSE;
m_Defined = FALSE;
m_Macro = 0;
}
const wxChar* D_CODE::ShowApertureType( APERTURE_T aType )
{
const wxChar* ret;
switch( aType )
{
case APT_CIRCLE:
ret = wxT( "Round" ); break;
case APT_LINE:
ret = wxT( "Line" ); break;
case APT_RECT:
ret = wxT( "Rect" ); break;
case APT_OVAL:
ret = wxT( "Oval" ); break;
case APT_POLYGON:
ret = wxT( "Poly" ); break;
case APT_MACRO:
ret = wxT( "Macro" ); break;
default:
ret = wxT( "???" ); break;
}
return ret;
}
int WinEDA_GerberFrame::Read_D_Code_File( const wxString& D_Code_FullFileName )
{
int current_Dcode, ii, dcode_scale;
char* ptcar;
int dimH, dimV, drill, dummy;
float fdimH, fdimV, fdrill;
char c_type_outil[256];
char line[GERBER_BUFZ];
wxString msg;
D_CODE* dcode;
FILE* dest;
int layer = GetScreen()->m_Active_Layer;
int type_outil;
if( g_GERBER_List[layer] == NULL )
{
g_GERBER_List[layer] = new GERBER( layer );
}
GERBER* gerber = g_GERBER_List[layer];
/* Updating gerber scale: */
dcode_scale = 10; /* By uniting dCode = mil, internal unit = 0.1 mil
* -> 1 unite dcode = 10 unit PCB */
current_Dcode = 0;
if( D_Code_FullFileName.IsEmpty() )
return 0;
dest = wxFopen( D_Code_FullFileName, wxT( "rt" ) );
if( dest == 0 )
{
msg = _( "File " ) + D_Code_FullFileName + _( " not found" );
DisplayError( this, msg, 10 );
return -1;
}
gerber->InitToolTable();
while( fgets( line, sizeof(line) - 1, dest ) != NULL )
{
if( *line == ';' )
continue;
if( strlen( line ) < 10 )
continue; /* Skip blank line. */
dcode = NULL;
current_Dcode = 0;
/* Determine of the type of file from D_Code. */
ptcar = line;
ii = 0;
while( *ptcar )
if( *(ptcar++) == ',' )
ii++;
if( ii >= 6 ) /* valeurs en mils */
{
sscanf( line, "%d,%d,%d,%d,%d,%d,%d", &ii,
&dimH, &dimV, &drill,
&dummy, &dummy,
&type_outil );
dimH = (int) ( (dimH * dcode_scale) + 0.5 );
dimV = (int) ( (dimV * dcode_scale) + 0.5 );
drill = (int) ( (drill * dcode_scale) + 0.5 );
if( ii < 1 )
ii = 1;
current_Dcode = ii - 1 + FIRST_DCODE;
}
else /* Values in inches are converted to mils. */
{
fdrill = 0;
current_Dcode = 0;
sscanf( line, "%f,%f,%1s", &fdimV, &fdimH, c_type_outil );
ptcar = line;
while( *ptcar )
{
if( *ptcar == 'D' )
{
sscanf( ptcar + 1, "%d,%f", &current_Dcode, &fdrill );
break;
}
else
ptcar++;
}
dimH = (int) ( (fdimH * dcode_scale * 1000) + 0.5 );
dimV = (int) ( (fdimV * dcode_scale * 1000) + 0.5 );
drill = (int) ( (fdrill * dcode_scale * 1000) + 0.5 );
if( strchr( "CLROP", c_type_outil[0] ) )
type_outil = (APERTURE_T) c_type_outil[0];
else
{
fclose( dest );
return -2;
}
}
/* Update the list of d_codes if consistant. */
if( current_Dcode < FIRST_DCODE )
continue;
if( current_Dcode >= MAX_TOOLS )
continue;
dcode = gerber->GetDCODE( current_Dcode );
dcode->m_Size.x = dimH;
dcode->m_Size.y = dimV;
dcode->m_Shape = (APERTURE_T) type_outil;
dcode->m_Drill.x = dcode->m_Drill.y = drill;
dcode->m_Defined = TRUE;
}
fclose( dest );
return 1;
}
/* Set Size Items (Lines, Flashes) from DCodes List
*/
void WinEDA_GerberFrame::CopyDCodesSizeToItems()
{
static D_CODE dummy( 999 ); //Used if D_CODE not found in list
for( TRACK* track = GetBoard()->m_Track; track; track = track->Next() )
{
GERBER* gerber = g_GERBER_List[track->GetLayer()];
wxASSERT( gerber );
D_CODE* dcode = gerber->GetDCODE( track->GetNet(), false );
wxASSERT( dcode );
if( dcode == NULL )
dcode = &dummy;
dcode->m_InUse = TRUE;
if( // Line Item
(track->m_Shape == S_SEGMENT ) /* rectilinear segment */
|| (track->m_Shape == S_RECT ) /* rect segment form (i.e.
* non-rounded ends) */
|| (track->m_Shape == S_ARC ) /* segment arc (rounded tips) */
|| (track->m_Shape == S_CIRCLE ) /* segment in a circle (ring) */
|| (track->m_Shape == S_ARC_RECT ) /* segment arc (stretches)
* (GERBER)*/
)
{
track->m_Width = dcode->m_Size.x;
}
else // Spots ( Flashed Items )
{
int width, len;
wxSize size = dcode->m_Size;
width = MIN( size.x, size.y );
len = MAX( size.x, size.y ) - width;
track->m_Width = width;
track->m_Start.x = (track->m_Start.x + track->m_End.x) / 2;
track->m_Start.y = (track->m_Start.y + track->m_End.y) / 2;
track->m_End = track->m_Start; // m_Start = m_End = Spot center
switch( dcode->m_Shape )
{
case APT_LINE: // might not appears here, but some broken
// gerber files use it
case APT_CIRCLE: /* spot round (for GERBER) */
track->m_Shape = S_SPOT_CIRCLE;
break;
case APT_OVAL: /* spot oval (for GERBER)*/
track->m_Shape = S_SPOT_OVALE;
break;
default: /* spot rect (for GERBER)*/
track->m_Shape = S_SPOT_RECT;
break;
}
len >>= 1;
if( size.x > size.y )
{
track->m_Start.x -= len;
track->m_End.x += len;
}
else
{
track->m_Start.y -= len;
track->m_End.y += len;
}
}
}
}
void WinEDA_GerberFrame::Liste_D_Codes( wxDC* DC )
{
int ii, jj;
D_CODE* pt_D_code;
wxString Line;
WinEDA_TextFrame* List;
int scale = 10000;
int curr_layer = GetScreen()->m_Active_Layer;
List = new WinEDA_TextFrame( this, _( "List D codes" ) );
for( int layer = 0; layer < 32; layer++ )
{
GERBER* gerber = g_GERBER_List[layer];
if( gerber == NULL )
continue;
if( gerber->ReturnUsedDcodeNumber() == 0 )
continue;
if( layer == curr_layer )
Line.Printf( wxT( "*** Active layer (%2.2d) ***" ), layer + 1 );
else
Line.Printf( wxT( "*** layer %2.2d ***" ), layer + 1 );
List->Append( Line );
for( ii = 0, jj = 1; ii < MAX_TOOLS; ii++ )
{
pt_D_code = gerber->GetDCODE( ii + FIRST_DCODE, false );
if( pt_D_code == NULL )
continue;
if( !pt_D_code->m_InUse && !pt_D_code->m_Defined )
continue;
Line.Printf( wxT(
"tool %2.2d: D%2.2d V %2.4f H %2.4f %s" ),
jj,
pt_D_code->m_Num_Dcode,
(float) pt_D_code->m_Size.y / scale,
(float) pt_D_code->m_Size.x / scale,
D_CODE::ShowApertureType( pt_D_code->m_Shape )
);
if( !pt_D_code->m_Defined )
Line += wxT( " ?" );
if( !pt_D_code->m_InUse )
Line += wxT( " *" );
List->Append( Line );
jj++;
}
}
ii = List->ShowModal();
List->Destroy();
if( ii < 0 )
return;
#if 0
// Highlight segment corresponding to dCode selected.
if( Etat_Surbrillance )
Hight_Light( DrawPanel, DC );
net_code_Surbrillance = (GetScreen()->m_Active_Layer << 16) + ii;
Hight_Light( DrawPanel, DC );
#endif
}