kicad/gerbview/rs274d.cpp

1099 lines
34 KiB
C++
Raw Blame History

/********************************************************/
/**** Routine de lecture et visu d'un fichier GERBER ****/
/********************************************************/
#include "fctsys.h"
#include "common.h"
#include "gerbview.h"
#include "pcbplot.h"
#include "protos.h"
#define IsNumber( x ) ( ( ( (x) >= '0' ) && ( (x) <='9' ) ) \
|| ( (x) == '-' ) || ( (x) == '+' ) || ( (x) == '.' ) )
/* Format Gerber : NOTES :
* Fonctions preparatoires:
* Gn =
* G01 interpolation lineaire ( trace de droites )
* G02,G20,G21 Interpolation circulaire , sens trigo < 0
* G03,G30,G31 Interpolation circulaire , sens trigo > 0
* G04 commentaire
* G06 Interpolation parabolique
* G07 Interpolation cubique
* G10 interpolation lineaire ( echelle 10x )
* G11 interpolation lineaire ( echelle 0.1x )
* G12 interpolation lineaire ( echelle 0.01x )
* G52 plot symbole reference par Dnn code
* G53 plot symbole reference par Dnn ; symbole tourne de -90 degres
* G54 Selection d'outil
* G55 Mode exposition photo
* G56 plot symbole reference par Dnn A code
* G57 affiche le symbole reference sur la console
* G58 plot et affiche le symbole reference sur la console
* G60 interpolation lineaire ( echelle 100x )
* G70 Unites = Inches
* G71 Unites = Millimetres
* G74 supprime interpolation circulaire sur 360 degre, revient a G01
* G75 Active interpolation circulaire sur 360 degre
* G90 Mode Coordonnees absolues
* G91 Mode Coordonnees Relatives
*
* Coordonnees X,Y
* X,Y sont suivies de + ou - et de m+n chiffres (non separes)
* m = partie entiere
* n = partie apres la virgule
* formats classiques : m = 2, n = 3 (format 2.3)
* m = 3, n = 4 (format 3.4)
* ex:
* G__ X00345Y-06123 D__*
*
* Outils et D_CODES
* numero d'outil ( identification des formes )
* 1 a 99 (classique)
* 1 a 999
* D_CODES:
*
* D01 ... D9 = codes d'action:
* D01 = activation de lumiere (baisser de plume) lors du d<>placement
* D02 = extinction de lumiere (lever de plume) lors du d<>placement
* D03 = Flash
* D09 = VAPE Flash
* D51 = precede par G54 -> Select VAPE
*
* D10 ... D255 = Indentification d'outils ( d'ouvertures )
* Ne sont pas tj dans l'ordre ( voir tableau dans PCBPLOT.H)
*/
// Type d'action du phototraceur:
#define GERB_ACTIVE_DRAW 1 // activation de lumiere ( baisser de plume)
#define GERB_STOP_DRAW 2 // extinction de lumiere ( lever de plume)
#define GERB_FLASH 3 // Flash
#define NEGATE( nb ) (nb) = -(nb)
/* Variables locales : */
static wxPoint LastPosition;
/* Local Functions (are lower case since they are private to this source file) */
/**
* Function fillRoundFlashTRACK
* initializes a given TRACK so that it can draw a flash D code which is round.
*
* @param aTrack The TRACK to fill in.
* @param Dcode_index The DCODE value, like D14
* @param aLayer The layer index to set into the TRACK
* @param aPos The center point of the flash
* @param aDiameter The diameter of the round flash
* @param isDark True if flash is positive and should use a drawing
* color other than the background color, else use the background color
* when drawing so that an erasure happens.
*/
static void fillRoundFlashTRACK( TRACK* aTrack, int Dcode_index, int aLayer,
const wxPoint& aPos, int aDiameter, bool isDark )
{
aTrack->SetLayer( aLayer );
aTrack->m_Width = aDiameter;
aTrack->m_Start = aTrack->m_End = aPos;
NEGATE( aTrack->m_Start.y );
NEGATE( aTrack->m_End.y );
aTrack->SetNet( Dcode_index );
aTrack->m_Shape = S_SPOT_CIRCLE;
if( !isDark )
{
aTrack->m_Flags |= DRAW_ERASED;
}
}
/**
* Function fillOvalOrRectFlashTRACK
* initializes a given TRACK so that it can draw an oval or rectangular flash D code.
*
* @param aTrack The TRACK to fill in.
* @param Dcode_index The DCODE value, like D14
* @param aLayer The layer index to set into the TRACK
* @param aPos The center point of the flash
* @param aSize The size of the flash
* @param aShape What type of flash, S_SPOT_OVALE or S_SPOT_RECT
* @param isDark True if flash is positive and should use a drawing
* color other than the background color, else use the background color
* when drawing so that an erasure happens.
*/
static void fillOvalOrRectFlashTRACK( TRACK* aTrack, int Dcode_index, int aLayer,
const wxPoint& aPos, const wxSize& aSize, int aShape, bool isDark )
{
int width = MIN( aSize.x, aSize.y );
int len = MAX( aSize.x, aSize.y ) - width;
aTrack->SetLayer( aLayer );
aTrack->m_Width = width;
aTrack->m_Start = aTrack->m_End = aPos;
NEGATE( aTrack->m_Start.y );
NEGATE( aTrack->m_End.y );
aTrack->SetNet( Dcode_index );
aTrack->m_Shape = aShape;
len >>= 1;
if( aSize.x > aSize.y ) // oval or rectangle is horizontal
{
aTrack->m_Start.x -= len;
aTrack->m_End.x += len;
}
else // oval or rectangle is vertical
{
aTrack->m_Start.y -= len;
aTrack->m_End.y += len;
}
if( !isDark )
{
aTrack->m_Flags |= DRAW_ERASED;
}
}
/**
* Function fillLineTRACK
* initializes a given TRACK so that it can draw a linear D code.
*
* @param aTrack The TRACK to fill in.
* @param Dcode_index The DCODE value, like D14
* @param aLayer The layer index to set into the TRACK
* @param aPos The center point of the flash
* @param aDiameter The diameter of the round flash
* @param isDark True if flash is positive and should use a drawing
* color other than the background color, else use the background color
* when drawing so that an erasure happens.
*/
static void fillLineTRACK( TRACK* aTrack, int Dcode_index, int aLayer,
const wxPoint& aStart, const wxPoint& aEnd, int aWidth, bool isDark )
{
aTrack->SetLayer( aLayer );
aTrack->m_Width = aWidth;
aTrack->m_Start = aStart;
NEGATE( aTrack->m_Start.y );
aTrack->m_End = aEnd;
NEGATE( aTrack->m_End.y );
aTrack->SetNet( Dcode_index );
if( !isDark )
{
aTrack->m_Flags |= DRAW_ERASED;
}
}
#if 0 // @todo get it into the doxygen function comment for fillArcTRACK below
/*****************************************************************/
static void Append_1_SEG_ARC_GERBER( int Dcode_index,
WinEDA_GerberFrame* frame, wxDC* DC,
const wxPoint& startpoint, const wxPoint& endpoint,
const wxPoint& rel_center, int largeur,
bool trigo_sens, bool multiquadrant, bool isDark )
/*****************************************************************/
/*
* Creates an arc:
* if multiquadrant == true : arc can be 0 to 360 degres
* and rel_center is the center coordiante relative to startpoint.
*
* if multiquadrant == false arc can be only 0 to 90 deg,
* and only in the same quadrant :
* absolute angle 0 to 90 (quadrant 1) or
* absolute angle 90 to 180 (quadrant 2) or
* absolute angle 180 to 270 (quadrant 3) or
* absolute angle 270 to 0 (quadrant 4)
* rel_center is the center coordiante relative to startpoint,
* given in ABSOLUE VALUE and the signe of values x et y de rel_center
* must be calculated from the previously given constraint: arc only in the same quadrant
*/
#endif
/**
* Function fillArcTRACK
* initializes a given TRACK so that it can draw an arc G code.
*
* @param aTrack The TRACK to fill in.
* @param Dcode_index The DCODE value, like D14
* @param aLayer The layer index to set into the TRACK
* @param aPos The center point of the flash
* @param aDiameter The diameter of the round flash
* @param isDark True if flash is positive and should use a drawing
* color other than the background color, else use the background color
* when drawing so that an erasure happens.
*/
static void fillArcTRACK( TRACK* aTrack, int Dcode_index, int aLayer,
const wxPoint& aStart, const wxPoint& aEnd,
const wxPoint& rel_center, int aWidth,
bool trigo_sens, bool multiquadrant, bool isDark )
{
wxPoint center, delta;
aTrack->m_Shape = S_ARC;
aTrack->SetLayer( aLayer );
aTrack->m_Width = aWidth;
if( multiquadrant )
{
center.x = aStart.x + rel_center.x;
center.y = aStart.y - rel_center.y;
if( !trigo_sens )
{
aTrack->m_Start = aStart;
aTrack->m_End = aEnd;
}
else
{
aTrack->m_Start = aEnd;
aTrack->m_End = aStart;
}
}
else
{
center = rel_center;
delta.x = aEnd.x - aStart.x;
delta.y = aEnd.y - aStart.y;
// il faut corriger de signe de rel_center.x et rel_center.y
// selon le quadrant ou on se trouve
if( (delta.x >= 0) && (delta.y >= 0) ) // 1er quadrant
{
center.x = -center.x;
}
else if( (delta.x < 0) && (delta.y >= 0) ) // 2eme quadrant
{
center.x = -center.x;
center.y = -center.y;
}
else if( (delta.x < 0) && (delta.y < 0) ) // 3eme quadrant
{
center.y = -center.y;
}
else // 4eme qadrant: les 2 coord sont >= 0!
{
}
center.x += aStart.x;
center.y = aStart.y + center.y;
if( trigo_sens )
{
aTrack->m_Start = aStart;
aTrack->m_End = aEnd;
}
else
{
aTrack->m_Start = aEnd;
aTrack->m_End = aStart;
}
}
aTrack->SetNet( Dcode_index );
aTrack->m_Param = center.x;
aTrack->SetSubNet( center.y );
NEGATE( aTrack->m_Start.y );
NEGATE( aTrack->m_End.y );
aTrack->SetSubNet( -aTrack->GetSubNet() );
if( !isDark )
{
aTrack->m_Flags |= DRAW_ERASED;
}
}
/**************************************************/
/* Routines utilis<69>es en lecture de ficher gerber */
/**************************************************/
/* ces routines lisent la chaine de texte point<6E>e par Text.
* Apres appel, Text pointe le debut de la sequence non lue
*/
/***********************************************/
wxPoint GERBER::ReadXYCoord( char*& Text )
/***********************************************/
/* Retourne la coord courante pointee par Text (XnnnnYmmmm)
*/
{
wxPoint pos = m_CurrentPos;
int type_coord = 0, current_coord, nbchar;
bool is_float = false;
char* text;
char line[256];
if( m_Relative )
pos.x = pos.y = 0;
else
pos = m_CurrentPos;
if( Text == NULL )
return pos;
text = line;
while( *Text )
{
if( (*Text == 'X') || (*Text == 'Y') )
{
type_coord = *Text;
Text++;
text = line;
nbchar = 0;
while( IsNumber( *Text ) )
{
if( *Text == '.' )
is_float = true;
*(text++) = *(Text++);
if( (*Text >= '0') && (*Text <='9') )
nbchar++;
}
*text = 0;
if( is_float )
{
if( m_GerbMetric )
current_coord = (int) round( atof( line ) / 0.00254 );
else
current_coord = (int) round( atof( line ) * PCB_INTERNAL_UNIT );
}
else
{
int fmt_scale = (type_coord == 'X') ? m_FmtScale.x : m_FmtScale.y;
if( m_NoTrailingZeros )
{
int min_digit = (type_coord == 'X') ? m_FmtLen.x : m_FmtLen.y;
while( nbchar < min_digit )
{
*(text++) = '0';
nbchar++;
}
*text = 0;
}
current_coord = atoi( line );
double real_scale = 1.0;
switch( fmt_scale )
{
case 0:
real_scale = 10000.0;
break;
case 1:
real_scale = 1000.0;
break;
case 2:
real_scale = 100.0;
break;
case 3:
real_scale = 10.0;
break;
case 4:
break;
case 5:
real_scale = 0.1;
break;
case 6:
real_scale = 0.01;
break;
case 7:
real_scale = 0.001;
break;
case 8:
real_scale = 0.0001;
break;
case 9:
real_scale = 0.00001;
break;
}
if( m_GerbMetric )
real_scale = real_scale / 25.4;
current_coord = (int) round( current_coord * real_scale );
}
if( type_coord == 'X' )
pos.x = current_coord;
else if( type_coord == 'Y' )
pos.y = current_coord;
continue;
}
else
break;
}
if( m_Relative )
{
pos.x += m_CurrentPos.x;
pos.y += m_CurrentPos.y;
}
m_CurrentPos = pos;
return pos;
}
/************************************************/
wxPoint GERBER::ReadIJCoord( char*& Text )
/************************************************/
/* Retourne la coord type InnJnn courante pointee par Text (InnnnJmmmm)
* Ces coordonn<6E>es sont relatives, donc si une coord est absente, sa valeur
* par defaut est 0
*/
{
wxPoint pos( 0, 0 );
int type_coord = 0, current_coord, nbchar;
bool is_float = false;
char* text;
char line[256];
if( Text == NULL )
return pos;
text = line;
while( *Text )
{
if( (*Text == 'I') || (*Text == 'J') )
{
type_coord = *Text;
Text++;
text = line;
nbchar = 0;
while( IsNumber( *Text ) )
{
if( *Text == '.' )
is_float = true;
*(text++) = *(Text++);
if( (*Text >= '0') && (*Text <='9') )
nbchar++;
}
*text = 0;
if( is_float )
{
if( m_GerbMetric )
current_coord = (int) round( atof( line ) / 0.00254 );
else
current_coord = (int) round( atof( line ) * PCB_INTERNAL_UNIT );
}
else
{
int fmt_scale = (type_coord == 'I') ? m_FmtScale.x : m_FmtScale.y;
if( m_NoTrailingZeros )
{
int min_digit = (type_coord == 'I') ? m_FmtLen.x : m_FmtLen.y;
while( nbchar < min_digit )
{
*(text++) = '0';
nbchar++;
}
*text = 0;
}
current_coord = atoi( line );
double real_scale = 1.0;
switch( fmt_scale )
{
case 0:
real_scale = 10000.0;
break;
case 1:
real_scale = 1000.0;
break;
case 2:
real_scale = 100.0;
break;
case 3:
real_scale = 10.0;
break;
case 4:
break;
case 5:
real_scale = 0.1;
break;
case 6:
real_scale = 0.01;
break;
case 7:
real_scale = 0.001;
break;
case 8:
real_scale = 0.0001;
break;
case 9:
real_scale = 0.00001;
break;
}
if( m_GerbMetric )
real_scale = real_scale / 25.4;
current_coord = (int) round( current_coord * real_scale );
}
if( type_coord == 'I' )
pos.x = current_coord;
else if( type_coord == 'J' )
pos.y = current_coord;
continue;
}
else
break;
}
m_IJPos = pos;
return pos;
}
/*****************************************************/
int GERBER::ReturnGCodeNumber( char*& Text )
/*****************************************************/
/* Lit la sequence Gnn et retourne la valeur nn
*/
{
int ii = 0;
char* text;
char line[1024];
if( Text == NULL )
return 0;
Text++;
text = line;
while( IsNumber( *Text ) )
{
*(text++) = *(Text++);
}
*text = 0;
ii = atoi( line );
return ii;
}
/**************************************************/
int GERBER::ReturnDCodeNumber( char*& Text )
/**************************************************/
/* Lit la sequence Dnn et retourne la valeur nn
*/
{
int ii = 0;
char* text;
char line[1024];
if( Text == NULL )
return 0;
Text++;
text = line;
while( IsNumber( *Text ) )
*(text++) = *(Text++);
*text = 0;
ii = atoi( line );
return ii;
}
/******************************************************************/
bool GERBER::Execute_G_Command( char*& text, int G_commande )
/******************************************************************/
{
switch( G_commande )
{
case GC_PHOTO_MODE: // can starts a D03 flash command: redundant, can be safely ignored
break;
case GC_LINEAR_INTERPOL_1X:
m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
break;
case GC_CIRCLE_NEG_INTERPOL:
m_Iterpolation = GERB_INTERPOL_ARC_NEG;
break;
case GC_CIRCLE_POS_INTERPOL:
m_Iterpolation = GERB_INTERPOL_ARC_POS;
break;
case GC_COMMENT:
text = NULL;
break;
case GC_LINEAR_INTERPOL_10X:
m_Iterpolation = GERB_INTERPOL_LINEAR_10X;
break;
case GC_LINEAR_INTERPOL_0P1X:
m_Iterpolation = GERB_INTERPOL_LINEAR_01X;
break;
case GC_LINEAR_INTERPOL_0P01X:
m_Iterpolation = GERB_INTERPOL_LINEAR_001X;
break;
case GC_SELECT_TOOL:
{
int D_commande = ReturnDCodeNumber( text );
if( D_commande < FIRST_DCODE )
return false;
if( D_commande > (MAX_TOOLS - 1) )
D_commande = MAX_TOOLS - 1;
m_Current_Tool = D_commande;
D_CODE* pt_Dcode = GetDCODE( D_commande, false );
if( pt_Dcode )
pt_Dcode->m_InUse = true;
break;
}
case GC_SPECIFY_INCHES:
m_GerbMetric = false; // false = Inches, true = metric
break;
case GC_SPECIFY_MILLIMETERS:
m_GerbMetric = true; // false = Inches, true = metric
break;
case GC_TURN_OFF_360_INTERPOL:
m_360Arc_enbl = false;
break;
case GC_TURN_ON_360_INTERPOL:
m_360Arc_enbl = true;
break;
case GC_SPECIFY_ABSOLUES_COORD:
m_Relative = false; // false = absolute Coord, RUE = relative Coord
break;
case GC_SPECIFY_RELATIVEES_COORD:
m_Relative = true; // false = absolute Coord, RUE = relative Coord
break;
case GC_TURN_ON_POLY_FILL:
m_PolygonFillMode = true;
break;
case GC_TURN_OFF_POLY_FILL:
m_PolygonFillMode = false;
m_PolygonFillModeState = 0;
break;
case GC_MOVE: // Non existant
default:
{
wxString msg; msg.Printf( wxT( "G%.2d command not handled" ), G_commande );
DisplayError( NULL, msg );
return false;
}
}
return true;
}
/**
* Function scale
* converts a distance given in floating point to our deci-mils
*/
static int scale( double aCoord, bool isMetric )
{
int ret;
if( isMetric )
ret = (int) round( aCoord / 0.00254 );
else
ret = (int) round( aCoord * PCB_INTERNAL_UNIT );
return ret;
}
/**
* Function mapPt
* translates a point from the aperture macro coordinate system to our
* deci-mils coordinate system.
* @return wxPoint - The gerbview coordinate system vector.
*/
static wxPoint mapPt( double x, double y, bool isMetric )
{
wxPoint ret( scale( x, isMetric ),
scale( y, isMetric ) );
return ret;
}
/**
* Function mapExposure
* translates the first parameter from an aperture macro into a current exposure
* setting.
* @param curExposure A dynamic setting which can change throughout the reading of the
* gerber file, and it indicates whether the current tool is lit or not.
* @param isNegative A dynamic setting which can change throughout the reading of
* the gerber file, and it indicates whether the current D codes are to
* be interpreted as erasures or not.
*/
static bool mapExposure( int param1, bool curExposure, bool isNegative )
{
bool exposure;
switch( param1 )
{
case 0:
exposure = false;
break;
default:
case 1:
exposure = true;
break;
case 2:
exposure = !curExposure;
}
return exposure ^ isNegative;
}
/*****************************************************************************/
bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, wxDC* DC,
char*& text, int D_commande )
/*****************************************************************************/
{
wxSize size( 15, 15 );
APERTURE_T aperture = APT_CIRCLE;
TRACK* track;
int activeLayer = frame->GetScreen()->m_Active_Layer;
int dcode = 0;
D_CODE* tool = NULL;
wxString msg;
if( D_commande >= FIRST_DCODE ) // This is a "Set tool" command
{
if( D_commande > (MAX_TOOLS - 1) )
D_commande = MAX_TOOLS - 1;
// remember which tool is selected, nothing is done with it in this call
m_Current_Tool = D_commande;
D_CODE* pt_Dcode = GetDCODE( D_commande, false );
if( pt_Dcode )
pt_Dcode->m_InUse = true;
return true;
}
else // D_commande = 0..9: this is a pen command (usualy D1, D2 or D3)
{
m_Last_Pen_Command = D_commande;
}
if( m_PolygonFillMode ) // Enter a polygon description:
{
switch( D_commande )
{
case 1: // code D01 Draw line, exposure ON
{
m_Exposure = true;
SEGZONE* edge_poly = new SEGZONE( frame->m_Pcb );
frame->m_Pcb->m_Zone.Append( edge_poly );
edge_poly->SetLayer( activeLayer );
edge_poly->m_Width = 1;
edge_poly->m_Start = m_PreviousPos;
NEGATE( edge_poly->m_Start.y );
edge_poly->m_End = m_CurrentPos;
NEGATE( edge_poly->m_End.y );
edge_poly->SetNet( m_PolygonFillModeState );
m_PreviousPos = m_CurrentPos;
m_PolygonFillModeState = 1;
break;
}
case 2: // code D2: exposure OFF (i.e. "move to")
m_Exposure = false;
m_PreviousPos = m_CurrentPos;
m_PolygonFillModeState = 0;
break;
default:
return false;
}
}
else
{
switch( D_commande )
{
case 1: // code D01 Draw line, exposure ON
m_Exposure = true;
tool = GetDCODE( m_Current_Tool, false );
if( tool )
{
size = tool->m_Size;
dcode = tool->m_Num_Dcode;
aperture = tool->m_Shape;
}
switch( m_Iterpolation )
{
case GERB_INTERPOL_LINEAR_1X:
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillLineTRACK( track, dcode, activeLayer,
m_PreviousPos, m_CurrentPos,
size.x, !(m_LayerNegative ^ m_ImageNegative) );
break;
case GERB_INTERPOL_LINEAR_01X:
case GERB_INTERPOL_LINEAR_001X:
case GERB_INTERPOL_LINEAR_10X:
wxBell();
break;
case GERB_INTERPOL_ARC_NEG:
case GERB_INTERPOL_ARC_POS:
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillArcTRACK( track, dcode, activeLayer,
m_PreviousPos, m_CurrentPos, m_IJPos,
size.x, m_Iterpolation==GERB_INTERPOL_ARC_NEG ? false : true,
m_360Arc_enbl, !(m_LayerNegative ^ m_ImageNegative) );
break;
default:
msg.Printf( wxT( "Execute_DCODE_Command: interpol error (type %X)" ),
m_Iterpolation );
DisplayError( frame, msg );
break;
}
m_PreviousPos = m_CurrentPos;
break;
case 2: // code D2: exposure OFF (i.e. "move to")
m_Exposure = false;
m_PreviousPos = m_CurrentPos;
break;
case 3: // code D3: flash aperture
tool = GetDCODE( m_Current_Tool, false );
if( tool )
{
size = tool->m_Size;
dcode = tool->m_Num_Dcode;
aperture = tool->m_Shape;
}
switch( aperture )
{
case APT_LINE: // APT_LINE is not in the spec, don't know why it's here
case APT_CIRCLE:
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillRoundFlashTRACK( track, dcode, activeLayer,
m_CurrentPos,
size.x, !(m_LayerNegative ^ m_ImageNegative) );
break;
case APT_OVAL:
case APT_RECT:
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillOvalOrRectFlashTRACK( track, dcode, activeLayer,
m_CurrentPos, size,
aperture == APT_RECT ? S_SPOT_RECT : S_SPOT_OVALE,
!(m_LayerNegative ^ m_ImageNegative) );
break;
case APT_MACRO:
{
APERTURE_MACRO* macro = tool->GetMacro();
wxASSERT( macro );
// split the macro primitives up into multiple normal TRACK elements
for( AM_PRIMITIVES::iterator p=macro->primitives.begin(); p!=macro->primitives.end(); ++p )
{
bool exposure;
wxPoint curPos = m_CurrentPos;
switch( p->primitive_id )
{
case AMP_CIRCLE:
{
exposure = mapExposure( p->GetExposure(), m_Exposure, m_ImageNegative );
curPos += mapPt( p->params[2].GetValue( tool ), p->params[3].GetValue( tool ), m_GerbMetric );
int diameter = scale( p->params[1].GetValue( tool ), m_GerbMetric );
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillRoundFlashTRACK( track, dcode, activeLayer,
m_CurrentPos,
diameter, exposure );
}
break;
case AMP_LINE2:
case AMP_LINE20:
{
exposure = mapExposure( p->GetExposure(), m_Exposure, m_ImageNegative );
int width = scale( p->params[1].GetValue( tool ), m_GerbMetric );
wxPoint start = mapPt( p->params[2].GetValue( tool ), p->params[3].GetValue( tool ), m_GerbMetric );
wxPoint end = mapPt( p->params[4].GetValue( tool ), p->params[5].GetValue( tool ), m_GerbMetric );
if( start.x == end.x )
{
size.x = width;
size.y = ABS( end.y - start.y ) + 1;
}
else
{
size.x = ABS( end.x - start.x ) + 1;
size.y = width;
}
wxPoint midPoint( (start.x + end.x)/2, (start.y+end.y)/2 );
curPos += midPoint;
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillOvalOrRectFlashTRACK( track, dcode, activeLayer,
curPos, size, S_SPOT_RECT,
exposure );
}
break;
case AMP_LINE_CENTER:
{
exposure = mapExposure( p->GetExposure(), m_Exposure, m_ImageNegative );
wxPoint msize = mapPt( p->params[1].GetValue( tool ), p->params[2].GetValue( tool ), m_GerbMetric );
size.x = msize.x;
size.y = msize.y;
curPos += mapPt( p->params[3].GetValue( tool ), p->params[4].GetValue( tool ), m_GerbMetric );
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillOvalOrRectFlashTRACK( track, dcode, activeLayer,
curPos, size, S_SPOT_RECT,
exposure );
}
break;
case AMP_LINE_LOWER_LEFT:
{
exposure = mapExposure( p->GetExposure(), m_Exposure, m_ImageNegative );
wxPoint msize = mapPt( p->params[1].GetValue( tool ), p->params[2].GetValue( tool ), m_GerbMetric );
size.x = msize.x;
size.y = msize.y;
wxPoint lowerLeft = mapPt( p->params[3].GetValue( tool ), p->params[4].GetValue( tool ), m_GerbMetric );
curPos += lowerLeft;
// need the middle, so adjust from the lower left
curPos.y += size.y/2;
curPos.x += size.x/2;
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillOvalOrRectFlashTRACK( track, dcode, activeLayer,
curPos, size, S_SPOT_RECT,
exposure );
}
break;
case AMP_THERMAL:
{
int outerDiam = scale( p->params[2].GetValue(tool), m_GerbMetric );
int innerDiam = scale( p->params[3].GetValue(tool), m_GerbMetric );
curPos += mapPt( p->params[0].GetValue( tool ), p->params[1].GetValue( tool ), m_GerbMetric );
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillRoundFlashTRACK( track, dcode, activeLayer, curPos,
outerDiam, !(m_LayerNegative ^ m_ImageNegative) );
track = new TRACK( frame->m_Pcb );
frame->m_Pcb->m_Track.Append( track );
fillRoundFlashTRACK( track, dcode, activeLayer, curPos,
innerDiam, (m_LayerNegative ^ m_ImageNegative) );
// @todo: draw the cross hairs, see page 23 of rs274 spec.
// this might be done with two lines, thickness from params[4], and drawing
// darkness "(m_LayerNegative ^ m_ImageNegative)"
}
break;
case AMP_EOF:
case AMP_OUTLINE:
case AMP_POLYGON:
case AMP_MOIRE:
default:
// not yet supported, waiting for you.
break;
}
}
}
break;
default:
break;
}
m_PreviousPos = m_CurrentPos;
break;
default:
return false;
}
}
return true;
}