1023 lines
31 KiB
C++
1023 lines
31 KiB
C++
/********************/
|
|
/**** rs274d.cpp ****/
|
|
/********************/
|
|
|
|
#include "fctsys.h"
|
|
|
|
//#include "polygons_defs.h"
|
|
#include "common.h"
|
|
|
|
//#include "confirm.h"
|
|
//#include "macros.h"
|
|
#include "gerbview.h"
|
|
#include "trigo.h"
|
|
#include "macros.h"
|
|
#include "class_gerber_draw_item.h"
|
|
#include "class_GERBER.h"
|
|
|
|
#include <math.h>
|
|
|
|
#define IsNumber( x ) ( ( ( (x) >= '0' ) && ( (x) <='9' ) ) \
|
|
|| ( (x) == '-' ) || ( (x) == '+' ) || ( (x) == '.' ) )
|
|
|
|
/* Gerber: NOTES about some important commands found in RS274D and RS274X (G codes):
|
|
* Gn =
|
|
* G01 linear interpolation (right trace)
|
|
* G02, G20, G21 Circular interpolation, meaning trig <0 (clockwise)
|
|
* G03, G30, G31 Circular interpolation, meaning trigo> 0 (counterclockwise)
|
|
* G04 = comment
|
|
* G06 parabolic interpolation
|
|
* G07 Cubic Interpolation
|
|
* G10 linear interpolation (scale x10)
|
|
* G11 linear interpolation (0.1x range)
|
|
* G12 linear interpolation (0.01x scale)
|
|
* G36 Start polygon mode
|
|
* G37 Stop polygon mode (and close it)
|
|
* G54 Selection Tool
|
|
* G60 linear interpolation (scale x100)
|
|
* G70 Select Units = Inches
|
|
* G71 Select Units = Millimeters
|
|
* G74 disable 360 degrees circular interpolation (return to 90 deg mode)
|
|
* and perhaps circular interpolation (return to linear interpolation )
|
|
* see rs274xrevd_e.pdf pages 47 and 48
|
|
* Unfortunately page 47 said G74 disable G02 or G03
|
|
* and page 48 said G01 must be used to disable G02 or G03.
|
|
* Currently Gerbview disable G02 or G03 after a G74 command (tests using 2 gerber files).
|
|
* G75 enable 360 degrees circular interpolation
|
|
* G90 mode absolute coordinates
|
|
*
|
|
* X, Y
|
|
* X and Y are followed by + or - and m + n digits (not separated)
|
|
* m = integer part
|
|
* n = part after the comma
|
|
* Classic formats: m = 2, n = 3 (size 2.3)
|
|
* m = 3, n = 4 (size 3.4)
|
|
* eg
|
|
* GxxX00345Y-06123*
|
|
*
|
|
* Tools and D_CODES
|
|
* Tool number (identification of shapes)
|
|
* 10 to 999
|
|
* D_CODES:
|
|
* D01 ... D9 = command codes:
|
|
* D01 = activating light (pen down) when placement
|
|
* D02 = light extinction (pen up) when placement
|
|
* D03 = Flash
|
|
* D09 = VAPE Flash (I never see this command in gerber file)
|
|
* D51 = G54 preceded by -> Select VAPE
|
|
*
|
|
* D10 ... D999 = Identification Tool: tool selection
|
|
*/
|
|
|
|
// Photoplot actions:
|
|
#define GERB_ACTIVE_DRAW 1 // Activate light (lower pen)
|
|
#define GERB_STOP_DRAW 2 // Extinguish light (lift pen)
|
|
#define GERB_FLASH 3 // Flash
|
|
|
|
static wxPoint LastPosition;
|
|
|
|
|
|
/* Local Functions (are lower case since they are private to this source file)
|
|
**/
|
|
|
|
|
|
/**
|
|
* Function fillFlashedGBRITEM
|
|
* initializes a given GBRITEM so that it can draw a circle which is filled and
|
|
* has no pen border.
|
|
*
|
|
* @param aGbrItem The GBRITEM to fill in.
|
|
* @param aAperture the associated type of aperture
|
|
* @param Dcode_index The DCODE value, like D14
|
|
* @param aLayer The layer index to set into the GBRITEM
|
|
* @param aPos The center point of the flash
|
|
* @param aSize The diameter of the round flash
|
|
* @param aLayerNegative = true if the current layer is negative
|
|
* @param aImageNegative = true if the current image is negative
|
|
*/
|
|
static void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
|
APERTURE_T aAperture,
|
|
int Dcode_index,
|
|
int aLayer,
|
|
const wxPoint& aPos,
|
|
wxSize aSize,
|
|
bool aLayerNegative,
|
|
bool aImageNegative )
|
|
{
|
|
aGbrItem->SetLayer( aLayer );
|
|
aGbrItem->m_Size = aSize;
|
|
aGbrItem->m_Start = aPos;
|
|
aGbrItem->m_End = aGbrItem->m_Start;
|
|
aGbrItem->m_DCode = Dcode_index;
|
|
aGbrItem->m_LayerNegative = aLayerNegative;
|
|
aGbrItem->m_ImageNegative = aImageNegative;
|
|
aGbrItem->m_Flashed = true;
|
|
switch( aAperture )
|
|
{
|
|
case APT_POLYGON: // flashed regular polygon
|
|
aGbrItem->m_Shape = GBR_SPOT_POLY;
|
|
break;
|
|
|
|
case APT_LINE: // Should not be used.
|
|
case APT_CIRCLE:
|
|
aGbrItem->m_Shape = GBR_SPOT_CIRCLE;
|
|
aGbrItem->m_Size.y = aGbrItem->m_Size.x;
|
|
break;
|
|
|
|
case APT_OVAL:
|
|
aGbrItem->m_Shape = GBR_SPOT_OVAL;
|
|
break;
|
|
|
|
case APT_RECT:
|
|
aGbrItem->m_Shape = GBR_SPOT_RECT;
|
|
break;
|
|
|
|
case APT_MACRO:
|
|
aGbrItem->m_Shape = GBR_SPOT_MACRO;
|
|
break;
|
|
}
|
|
|
|
bool isDark = !(aGbrItem->m_LayerNegative ^ aGbrItem->m_ImageNegative);
|
|
|
|
/* isDark is 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.
|
|
*/
|
|
if( !isDark )
|
|
{
|
|
aGbrItem->m_Flags |= DRAW_ERASED;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Function fillLineGBRITEM
|
|
* initializes a given GBRITEM so that it can draw a linear D code.
|
|
*
|
|
* @param aGbrItem The GERBER_DRAW_ITEM to fill in.
|
|
* @param Dcode_index The DCODE value, like D14
|
|
* @param aLayer The layer index to set into the GBRITEM
|
|
* @param aPos The center point of the flash
|
|
* @param aDiameter The diameter of the round flash
|
|
* @param aLayerNegative = true if the current layer is negative
|
|
* @param aImageNegative = true if the current image is negative
|
|
*/
|
|
static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
|
int Dcode_index,
|
|
int aLayer,
|
|
const wxPoint& aStart,
|
|
const wxPoint& aEnd,
|
|
int aWidth,
|
|
bool aLayerNegative,
|
|
bool aImageNegative )
|
|
{
|
|
aGbrItem->SetLayer( aLayer );
|
|
aGbrItem->m_Flashed = false;
|
|
|
|
aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth;
|
|
|
|
aGbrItem->m_Start = aStart;
|
|
aGbrItem->m_End = aEnd;
|
|
|
|
aGbrItem->m_DCode = Dcode_index;
|
|
aGbrItem->m_LayerNegative = aLayerNegative;
|
|
aGbrItem->m_ImageNegative = aImageNegative;
|
|
|
|
bool isDark = !(aGbrItem->m_LayerNegative ^ aGbrItem->m_ImageNegative);
|
|
|
|
/* isDark is 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.
|
|
*/
|
|
if( !isDark )
|
|
{
|
|
aGbrItem->m_Flags |= DRAW_ERASED;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Function fillArcGBRITEM
|
|
* initializes a given GBRITEM so that it can draw an arc G code.
|
|
* <p>
|
|
* if multiquadrant == true : arc can be 0 to 360 degrees
|
|
* and \a rel_center is the center coordinate relative to start point.
|
|
* <p>
|
|
* if multiquadrant == false arc can be only 0 to 90 deg,
|
|
* and only in the same quadrant :
|
|
* <ul>
|
|
* <li> absolute angle 0 to 90 (quadrant 1) or
|
|
* <li> absolute angle 90 to 180 (quadrant 2) or
|
|
* <li> absolute angle 180 to 270 (quadrant 3) or
|
|
* <li> absolute angle 270 to 0 (quadrant 4)
|
|
* </ul><p>
|
|
* @param GERBER_DRAW_ITEM is the GBRITEM to fill in.
|
|
* @param Dcode_index is the DCODE value, like D14
|
|
* @param aLayer is the layer index to set into the GBRITEM
|
|
* @param aStart is the starting point
|
|
* @param aEnd is the ending point
|
|
* @param rel_center is the center coordinate relative to start point,
|
|
* given in ABSOLUTE VALUE and the sign of values x et y de rel_center
|
|
* must be calculated from the previously given constraint: arc only in the
|
|
* same quadrant.
|
|
* @param aDiameter The diameter of the round flash
|
|
* @param aWidth is the pen width.
|
|
* @param aLayerNegative = true if the current layer is negative
|
|
* @param aImageNegative = true if the current image is negative
|
|
*/
|
|
static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index, int aLayer,
|
|
const wxPoint& aStart, const wxPoint& aEnd,
|
|
const wxPoint& aRelCenter, int aWidth,
|
|
bool aClockwise, bool aMultiquadrant,
|
|
bool aLayerNegative,
|
|
bool aImageNegative )
|
|
{
|
|
wxPoint center, delta;
|
|
|
|
aGbrItem->m_Shape = GBR_ARC;
|
|
aGbrItem->SetLayer( aLayer );
|
|
aGbrItem->m_Size.x = aGbrItem->m_Size.y = aWidth;
|
|
aGbrItem->m_Flashed = false;
|
|
|
|
|
|
if( aMultiquadrant )
|
|
center = aStart + aRelCenter;
|
|
else
|
|
{
|
|
// in single quadrant mode the relative coordinate aRelCenter is always >= 0
|
|
// So we must recalculate the actual sign of aRelCenter.x and aRelCenter.y
|
|
center = aRelCenter;
|
|
|
|
// calculate arc end coordinate relative to the staring point,
|
|
// because center is relative to the center point
|
|
delta = aEnd - aStart;
|
|
|
|
// now calculate the relative to aStart center position, for a draw function
|
|
// that use trigonometric arc angle (or counter-clockwise)
|
|
/* Quadrants:
|
|
* Y
|
|
* 2 | 1
|
|
* -------X
|
|
* 3 | 4
|
|
* C = actual relative arc center, S = arc start (axis origin) E = relative arc end
|
|
*/
|
|
if( (delta.x >= 0) && (delta.y >= 0) )
|
|
{
|
|
/* Quadrant 1 (trigo or cclockwise):
|
|
* C | E
|
|
* ---S---
|
|
* 3 | 4
|
|
*/
|
|
NEGATE( center.x);
|
|
}
|
|
else if( (delta.x >= 0) && (delta.y < 0) )
|
|
{
|
|
/* Quadrant 4 (trigo or cclockwise):
|
|
* 2 | C
|
|
* ---S---
|
|
* 3 | E
|
|
*/
|
|
// Nothing to do
|
|
}
|
|
else if( (delta.x < 0) && (delta.y >= 0) )
|
|
{
|
|
/* Quadrant 2 (trigo or cclockwise):
|
|
* E | 1
|
|
* ---S---
|
|
* C | 4
|
|
*/
|
|
NEGATE( center.x);
|
|
NEGATE( center.y);
|
|
}
|
|
else
|
|
{
|
|
/* Quadrant 3 (trigo or cclockwise):
|
|
* 2 | 1
|
|
* ---S---
|
|
* E | C
|
|
*/
|
|
NEGATE( center.y);
|
|
}
|
|
|
|
// Due to your draw arc function, we need this:
|
|
if( !aClockwise )
|
|
center = - center;
|
|
|
|
// Calculate actual arc center coordinate:
|
|
center += aStart;
|
|
}
|
|
|
|
if( aClockwise )
|
|
{
|
|
aGbrItem->m_Start = aStart;
|
|
aGbrItem->m_End = aEnd;
|
|
}
|
|
else
|
|
{
|
|
aGbrItem->m_Start = aEnd;
|
|
aGbrItem->m_End = aStart;
|
|
}
|
|
|
|
aGbrItem->m_ArcCentre = center;
|
|
|
|
aGbrItem->m_DCode = Dcode_index;
|
|
aGbrItem->m_LayerNegative = aLayerNegative;
|
|
aGbrItem->m_ImageNegative = aImageNegative;
|
|
|
|
bool isDark = !(aGbrItem->m_LayerNegative ^ aGbrItem->m_ImageNegative);
|
|
|
|
/* isDark is 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.
|
|
*/
|
|
if( !isDark )
|
|
{
|
|
aGbrItem->m_Flags |= DRAW_ERASED;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Function fillArcPOLY
|
|
* creates an arc G code when found in poly outlines.
|
|
* <p>
|
|
* if multiquadrant == true : arc can be 0 to 360 degrees
|
|
* and \a rel_center is the center coordinate relative to start point.
|
|
* <p>
|
|
* if multiquadrant == false arc can be only 0 to 90 deg,
|
|
* and only in the same quadrant :
|
|
* <ul>
|
|
* <li> absolute angle 0 to 90 (quadrant 1) or
|
|
* <li> absolute angle 90 to 180 (quadrant 2) or
|
|
* <li> absolute angle 180 to 270 (quadrant 3) or
|
|
* <li> absolute angle 270 to 0 (quadrant 4)
|
|
* </ul><p>
|
|
* @param aPcb is the board.
|
|
* @param aLayer is the layer index to set into the GBRITEM
|
|
* @param aStart is the starting point
|
|
* @param aEnd is the ending point
|
|
* @param rel_center is the center coordinate relative to start point,
|
|
* given in ABSOLUTE VALUE and the sign of values x et y de rel_center
|
|
* must be calculated from the previously given constraint: arc only in the
|
|
* same quadrant.
|
|
* @param aDiameter The diameter of the round flash
|
|
* @param aWidth is the pen width.
|
|
* @param aLayerNegative = true if the current layer is negative
|
|
* @param aImageNegative = true if the current image is negative
|
|
*/
|
|
static void fillArcPOLY( BOARD* aPcb, GERBER_DRAW_ITEM* aGbrItem,
|
|
const wxPoint& aStart, const wxPoint& aEnd,
|
|
const wxPoint& rel_center,
|
|
bool clockwise, bool multiquadrant,
|
|
bool aLayerNegative,
|
|
bool aImageNegative )
|
|
{
|
|
/* in order to calculate arc parameters, we use fillArcGBRITEM
|
|
* so we muse create a dummy track and use its geometric parameters
|
|
*/
|
|
static GERBER_DRAW_ITEM dummyGbrItem( NULL, NULL );
|
|
|
|
aGbrItem->m_LayerNegative = aLayerNegative;
|
|
aGbrItem->m_ImageNegative = aImageNegative;
|
|
|
|
bool isDark = !(aGbrItem->m_LayerNegative ^ aGbrItem->m_ImageNegative);
|
|
|
|
/* isDark is 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.
|
|
*/
|
|
if( !isDark )
|
|
{
|
|
aGbrItem->m_Flags |= DRAW_ERASED;
|
|
}
|
|
|
|
fillArcGBRITEM( &dummyGbrItem, 0, 0,
|
|
aStart, aEnd, rel_center, 0,
|
|
clockwise, multiquadrant, aLayerNegative, aImageNegative );
|
|
|
|
wxPoint center;
|
|
center = dummyGbrItem.m_ArcCentre;
|
|
|
|
// Calculate coordinates relative to arc center;
|
|
wxPoint start = dummyGbrItem.m_Start - center;
|
|
wxPoint end = dummyGbrItem.m_End - center;
|
|
|
|
/* Calculate angle arc
|
|
* angles are in 0.1 deg
|
|
* angle is trigonometrical (counter-clockwise),
|
|
* and axis is the X,Y gerber coordinates
|
|
*/
|
|
int start_angle = wxRound(atan2( (double) start.y, (double) start.x ) * 1800 / M_PI);
|
|
int end_angle = wxRound(atan2( (double) end.y, (double) end.x ) * 1800 / M_PI);
|
|
|
|
// dummyTrack has right geometric parameters, but
|
|
// fillArcGBRITEM calculates arc parameters for a draw function that expects
|
|
// start_angle < end_angle. So ensure this is the case here:
|
|
// Due to the fact atan2 returns angles between -180 to + 180 degrees,
|
|
// this is not always the case ( a modulo 360.0 degrees can be lost )
|
|
if( start_angle > end_angle )
|
|
end_angle += 3600;
|
|
|
|
int arc_angle = start_angle - end_angle;
|
|
// Approximate arc by 36 segments per 360 degree
|
|
const int increment_angle = 3600 / 36;
|
|
int count = ABS( arc_angle / increment_angle );
|
|
|
|
// calculate polygon corners
|
|
// when arc is counter-clockwise, dummyGbrItem arc goes from end to start
|
|
// and we must always create a polygon from start to end.
|
|
wxPoint start_arc = start;
|
|
for( int ii = 0; ii <= count; ii++ )
|
|
{
|
|
int rot;
|
|
wxPoint end_arc = start;
|
|
if( clockwise )
|
|
rot = ii * increment_angle; // rot is in 0.1 deg
|
|
else
|
|
rot = (count - ii) * increment_angle; // rot is in 0.1 deg
|
|
|
|
if( ii < count )
|
|
RotatePoint( &end_arc, -rot );
|
|
else // last point
|
|
end_arc = clockwise ? end : start;
|
|
|
|
aGbrItem->m_PolyCorners.push_back( end_arc + center );
|
|
|
|
start_arc = end_arc;
|
|
}
|
|
}
|
|
|
|
|
|
/* These routines read the text string point from Text.
|
|
* After use, advanced Text the beginning of the sequence unread
|
|
*/
|
|
wxPoint GERBER::ReadXYCoord( char*& Text )
|
|
{
|
|
wxPoint pos;
|
|
int type_coord = 0, current_coord, nbdigits;
|
|
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;
|
|
nbdigits = 0;
|
|
while( IsNumber( *Text ) )
|
|
{
|
|
if( *Text == '.' )
|
|
is_float = true;
|
|
|
|
// count digits only (sign and decimal point are not counted)
|
|
if( (*Text >= '0') && (*Text <='9') )
|
|
nbdigits++;
|
|
*(text++) = *(Text++);
|
|
}
|
|
|
|
*text = 0;
|
|
if( is_float )
|
|
{
|
|
if( m_GerbMetric )
|
|
current_coord = wxRound( atof( line ) / 0.00254 );
|
|
else
|
|
current_coord = wxRound( 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( nbdigits < min_digit )
|
|
{
|
|
*(text++) = '0';
|
|
nbdigits++;
|
|
}
|
|
|
|
*text = 0;
|
|
}
|
|
current_coord = atoi( line );
|
|
double real_scale = 1.0;
|
|
double scale_list[10] =
|
|
{
|
|
10000.0, 1000.0, 100.0, 10.0,
|
|
1,
|
|
0.1, 0.01, 0.001, 0.0001,0.00001
|
|
};
|
|
real_scale = scale_list[fmt_scale];
|
|
|
|
if( m_GerbMetric )
|
|
real_scale = real_scale / 25.4;
|
|
|
|
current_coord = wxRound( 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;
|
|
}
|
|
|
|
|
|
/* Returns the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
|
|
* These coordinates are relative, so if coordinate is absent, it's value
|
|
* defaults to 0
|
|
*/
|
|
wxPoint GERBER::ReadIJCoord( char*& Text )
|
|
{
|
|
wxPoint pos( 0, 0 );
|
|
|
|
int type_coord = 0, current_coord, nbdigits;
|
|
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;
|
|
nbdigits = 0;
|
|
while( IsNumber( *Text ) )
|
|
{
|
|
if( *Text == '.' )
|
|
is_float = true;
|
|
|
|
// count digits only (sign and decimal point are not counted)
|
|
if( (*Text >= '0') && (*Text <='9') )
|
|
nbdigits++;
|
|
*(text++) = *(Text++);
|
|
}
|
|
|
|
*text = 0;
|
|
if( is_float )
|
|
{
|
|
if( m_GerbMetric )
|
|
current_coord = wxRound( atof( line ) / 0.00254 );
|
|
else
|
|
current_coord = wxRound( 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( nbdigits < min_digit )
|
|
{
|
|
*(text++) = '0';
|
|
nbdigits++;
|
|
}
|
|
|
|
*text = 0;
|
|
}
|
|
current_coord = atoi( line );
|
|
double real_scale = 1.0;
|
|
if( fmt_scale < 0 || fmt_scale > 9 )
|
|
fmt_scale = 4; // select scale 1.0
|
|
|
|
double scale_list[10] =
|
|
{
|
|
10000.0, 1000.0, 100.0, 10.0,
|
|
1,
|
|
0.1, 0.01, 0.001, 0.0001,0.00001
|
|
};
|
|
real_scale = scale_list[fmt_scale];
|
|
|
|
if( m_GerbMetric )
|
|
real_scale = real_scale / 25.4;
|
|
current_coord = wxRound( 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;
|
|
}
|
|
|
|
|
|
/* Read the Gnn sequence and returns the value nn.
|
|
*/
|
|
int GERBER::ReturnGCodeNumber( char*& Text )
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
/* Get the sequence Dnn and returns the value nn
|
|
*/
|
|
int GERBER::ReturnDCodeNumber( char*& Text )
|
|
{
|
|
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 )
|
|
{
|
|
// D( printf( "%22s: G_CODE<%d>\n", __func__, 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 > (TOOLS_MAX_COUNT - 1) )
|
|
D_commande = TOOLS_MAX_COUNT - 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: // disable Multi cadran arc and Arc interpol
|
|
m_360Arc_enbl = false;
|
|
m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // not sure it should be done
|
|
break;
|
|
|
|
case GC_TURN_ON_360_INTERPOL:
|
|
m_360Arc_enbl = true;
|
|
break;
|
|
|
|
case GC_SPECIFY_ABSOLUES_COORD:
|
|
m_Relative = false; // false = absolute Coord, true = relative
|
|
// Coord
|
|
break;
|
|
|
|
case GC_SPECIFY_RELATIVEES_COORD:
|
|
m_Relative = true; // false = absolute Coord, true = 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 existent
|
|
default:
|
|
{
|
|
wxString msg;
|
|
msg.Printf( wxT( "G%0.2d command not handled" ), G_commande );
|
|
ReportMessage( msg );
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* Function scale
|
|
* converts a distance given in floating point to our deci-mils
|
|
*/
|
|
int scale( double aCoord, bool isMetric )
|
|
{
|
|
int ret;
|
|
|
|
if( isMetric )
|
|
ret = wxRound( aCoord / 0.00254 );
|
|
else
|
|
ret = wxRound( 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.
|
|
*/
|
|
wxPoint mapPt( double x, double y, bool isMetric )
|
|
{
|
|
wxPoint ret( scale( x, isMetric ), scale( y, isMetric ) );
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
bool GERBER::Execute_DCODE_Command( WinEDA_GerberFrame* frame, char*& text, int D_commande )
|
|
{
|
|
wxSize size( 15, 15 );
|
|
|
|
APERTURE_T aperture = APT_CIRCLE;
|
|
GERBER_DRAW_ITEM* gbritem;
|
|
BOARD* pcb = frame->GetBoard();
|
|
|
|
int activeLayer = frame->GetScreen()->m_Active_Layer;
|
|
|
|
int dcode = 0;
|
|
D_CODE* tool = NULL;
|
|
wxString msg;
|
|
|
|
// D( printf( "%22s: D_CODE<%d>\n", __func__, D_commande ); )
|
|
|
|
if( D_commande >= FIRST_DCODE ) // This is a "Set tool" command
|
|
{
|
|
if( D_commande > (TOOLS_MAX_COUNT - 1) )
|
|
D_commande = TOOLS_MAX_COUNT - 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 (usually 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
|
|
if( !m_Exposure )
|
|
{
|
|
m_Exposure = true;
|
|
gbritem = new GERBER_DRAW_ITEM( pcb, this );
|
|
pcb->m_Drawings.Append( gbritem );
|
|
gbritem->m_Shape = GBR_POLYGON;
|
|
gbritem->SetLayer( activeLayer );
|
|
gbritem->m_Flashed = false;
|
|
}
|
|
|
|
switch( m_Iterpolation )
|
|
{
|
|
case GERB_INTERPOL_ARC_NEG:
|
|
case GERB_INTERPOL_ARC_POS:
|
|
gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );
|
|
|
|
// D( printf( "Add arc poly %d,%d to %d,%d fill %d interpol %d 360_enb %d\n",
|
|
// m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x,
|
|
// m_CurrentPos.y, m_PolygonFillModeState,
|
|
// m_Iterpolation, m_360Arc_enbl ); )
|
|
fillArcPOLY( pcb, gbritem, m_PreviousPos,
|
|
m_CurrentPos, m_IJPos,
|
|
( m_Iterpolation == GERB_INTERPOL_ARC_NEG ) ? false : true,
|
|
m_360Arc_enbl, m_LayerNegative, m_ImageNegative );
|
|
break;
|
|
|
|
default:
|
|
gbritem = (GERBER_DRAW_ITEM*)( pcb->m_Drawings.GetLast() );
|
|
|
|
// D( printf( "Add poly edge %d,%d to %d,%d fill %d\n",
|
|
// m_PreviousPos.x, m_PreviousPos.y,
|
|
// m_CurrentPos.x, m_CurrentPos.y, m_Iterpolation ); )
|
|
|
|
gbritem->m_Start = m_PreviousPos; // m_Start is used as temporary storage
|
|
if( gbritem->m_PolyCorners.size() == 0 )
|
|
gbritem->m_PolyCorners.push_back( gbritem->m_Start );
|
|
|
|
gbritem->m_End = m_CurrentPos; // m_End is used as temporary storage
|
|
gbritem->m_PolyCorners.push_back( gbritem->m_End );
|
|
|
|
// Set the erasure flag of gbritem if a negative polygon.
|
|
if( !m_PolygonFillModeState )
|
|
{
|
|
if( m_LayerNegative ^ m_ImageNegative )
|
|
gbritem->m_Flags |= DRAW_ERASED;
|
|
}
|
|
break;
|
|
}
|
|
|
|
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:
|
|
gbritem = new GERBER_DRAW_ITEM( pcb, this );
|
|
pcb->m_Drawings.Append( gbritem );
|
|
|
|
// D( printf( "Add line %d,%d to %d,%d\n",
|
|
// m_PreviousPos.x, m_PreviousPos.y,
|
|
// m_CurrentPos.x, m_CurrentPos.y ); )
|
|
fillLineGBRITEM( gbritem, 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:
|
|
gbritem = new GERBER_DRAW_ITEM( pcb, this );
|
|
pcb->m_Drawings.Append( gbritem );
|
|
|
|
// D( printf( "Add arc %d,%d to %d,%d center %d, %d interpol %d 360_enb %d\n",
|
|
// m_PreviousPos.x, m_PreviousPos.y, m_CurrentPos.x,
|
|
// m_CurrentPos.y, m_IJPos.x,
|
|
// m_IJPos.y, m_Iterpolation, m_360Arc_enbl ); )
|
|
fillArcGBRITEM( gbritem, 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( "RS274D: DCODE Command: interpol error (type %X)" ),
|
|
m_Iterpolation );
|
|
ReportMessage( msg );
|
|
break;
|
|
}
|
|
|
|
m_PreviousPos = m_CurrentPos;
|
|
break;
|
|
|
|
case 2: // code D2: exposure OFF (i.e. "move to")
|
|
m_Exposure = false;
|
|
|
|
// D( printf( "Move to %d,%d to %d,%d\n",
|
|
// m_PreviousPos.x, m_PreviousPos.y,
|
|
// m_CurrentPos.x, m_CurrentPos.y ); )
|
|
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;
|
|
}
|
|
|
|
gbritem = new GERBER_DRAW_ITEM( pcb, this );
|
|
pcb->m_Drawings.Append( gbritem );
|
|
|
|
// D( printf( "Add flashed dcode %d layer %d at %d %d\n", dcode, activeLayer,
|
|
// m_CurrentPos.x, m_CurrentPos.y ); )
|
|
fillFlashedGBRITEM( gbritem, aperture,
|
|
dcode, activeLayer, m_CurrentPos,
|
|
size, m_LayerNegative, m_ImageNegative );
|
|
m_PreviousPos = m_CurrentPos;
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|