Gerbview: NC drill file reader: add support for routing mode, used by latest Kicad version.
From master branch commit 4136aca221
This commit is contained in:
parent
3f32f0be9e
commit
76adf7dbe8
|
@ -29,6 +29,8 @@
|
||||||
enum drill_M_code_t {
|
enum drill_M_code_t {
|
||||||
DRILL_M_UNKNOWN,
|
DRILL_M_UNKNOWN,
|
||||||
DRILL_M_END,
|
DRILL_M_END,
|
||||||
|
DRILL_M_TOOL_DOWN, // tool down (starting a routed hole)
|
||||||
|
DRILL_M_TOOL_UP, // tool up (ending a routed hole)
|
||||||
DRILL_M_ENDREWIND,
|
DRILL_M_ENDREWIND,
|
||||||
DRILL_M_MESSAGE,
|
DRILL_M_MESSAGE,
|
||||||
DRILL_M_LONGMESSAGE,
|
DRILL_M_LONGMESSAGE,
|
||||||
|
@ -52,12 +54,13 @@ enum drill_M_code_t {
|
||||||
DRILL_AUTOMATIC_TOOL_CHANGE,
|
DRILL_AUTOMATIC_TOOL_CHANGE,
|
||||||
DRILL_FMT,
|
DRILL_FMT,
|
||||||
DRILL_SKIP,
|
DRILL_SKIP,
|
||||||
DRILL_TOOL_INFORMATION
|
DRILL_TOOL_INFORMATION,
|
||||||
|
DRILL_M_END_LIST // not used: sentinel
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum drill_G_code_t {
|
enum drill_G_code_t {
|
||||||
DRILL_G_UNKNOWN,
|
DRILL_G_UNKNOWN = DRILL_M_END_LIST+1, // Use next available value
|
||||||
DRILL_G_ABSOLUTE,
|
DRILL_G_ABSOLUTE,
|
||||||
DRILL_G_INCREMENTAL,
|
DRILL_G_INCREMENTAL,
|
||||||
DRILL_G_ZEROSET,
|
DRILL_G_ZEROSET,
|
||||||
|
@ -78,6 +81,47 @@ struct EXCELLON_CMD
|
||||||
int m_asParams; // 0 = no param, -1 = skip params, 1 = read params
|
int m_asParams; // 0 = no param, -1 = skip params, 1 = read params
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper struct to store Excellon points in routing mode
|
||||||
|
#define ROUTE_CCW 1
|
||||||
|
#define ROUTE_CW -1
|
||||||
|
|
||||||
|
struct EXCELLON_ROUTE_COORD
|
||||||
|
{
|
||||||
|
int m_x; // X coordinate
|
||||||
|
int m_y; // y coordinate
|
||||||
|
int m_cx; // center X coordinate in circular routing mode
|
||||||
|
// (when the IJ commad is used)
|
||||||
|
int m_cy; // center y coordinate in circular routing mode
|
||||||
|
// (when the IJ commad is used)
|
||||||
|
int m_radius; // radius in circular routing mode (when the A## command is used)
|
||||||
|
int m_rmode; // routing mode: 0 = circular, ROUTE_CCW (1) = ccw, ROUTE_CW (-1) = cw
|
||||||
|
int m_arc_type_info; // arc using radius or center coordinates
|
||||||
|
|
||||||
|
EXCELLON_ROUTE_COORD():
|
||||||
|
m_x( 0 ), m_y( 0 ), m_cx( 0 ), m_cy( 0 ), m_radius( 0 ),
|
||||||
|
m_rmode( 0 ), m_arc_type_info( 0 )
|
||||||
|
{}
|
||||||
|
|
||||||
|
EXCELLON_ROUTE_COORD( const wxPoint& aPos ):
|
||||||
|
m_x( aPos.x ), m_y( aPos.y ),
|
||||||
|
m_cx( 0 ), m_cy( 0 ), m_radius( 0 ), m_rmode( 0 ),
|
||||||
|
m_arc_type_info( ARC_INFO_TYPE_NONE )
|
||||||
|
{}
|
||||||
|
|
||||||
|
EXCELLON_ROUTE_COORD( const wxPoint& aPos, const wxPoint& aCenter, int aMode ):
|
||||||
|
m_x( aPos.x ), m_y( aPos.y ),
|
||||||
|
m_cx( aCenter.x ), m_cy( aCenter.y ), m_radius( 0 ), m_rmode( aMode ),
|
||||||
|
m_arc_type_info( ARC_INFO_TYPE_CENTER )
|
||||||
|
{}
|
||||||
|
|
||||||
|
EXCELLON_ROUTE_COORD( const wxPoint& aPos, int aRadius, int aMode ):
|
||||||
|
m_x( aPos.x ), m_y( aPos.y ),
|
||||||
|
m_cx( 0 ), m_cy( 0 ), m_radius( aRadius ), m_rmode( aMode ),
|
||||||
|
m_arc_type_info( ARC_INFO_TYPE_RADIUS )
|
||||||
|
{}
|
||||||
|
|
||||||
|
wxPoint GetPos() { return wxPoint( m_x, m_y ); }
|
||||||
|
};
|
||||||
|
|
||||||
/* EXCELLON_IMAGE handle a drill image
|
/* EXCELLON_IMAGE handle a drill image
|
||||||
* It is derived from GERBER_FILE_IMAGE because there is a lot of likeness
|
* It is derived from GERBER_FILE_IMAGE because there is a lot of likeness
|
||||||
|
@ -96,12 +140,16 @@ private:
|
||||||
|
|
||||||
excellon_state m_State; // state of excellon file analysis
|
excellon_state m_State; // state of excellon file analysis
|
||||||
bool m_SlotOn; // true during an oblong drill definition
|
bool m_SlotOn; // true during an oblong drill definition
|
||||||
|
// by G85 (canned slot) command
|
||||||
|
bool m_RouteModeOn; // true during a route mode (for instance a oval hole) or a cutout
|
||||||
|
std::vector<EXCELLON_ROUTE_COORD> m_RoutePositions; // The list of points in a route mode
|
||||||
|
|
||||||
public: EXCELLON_IMAGE( int layer ) :
|
public: EXCELLON_IMAGE( int layer ) :
|
||||||
GERBER_FILE_IMAGE( layer )
|
GERBER_FILE_IMAGE( layer )
|
||||||
{
|
{
|
||||||
m_State = READ_HEADER_STATE;
|
m_State = READ_HEADER_STATE;
|
||||||
m_SlotOn = false;
|
m_SlotOn = false;
|
||||||
|
m_RouteModeOn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,7 +172,7 @@ public: EXCELLON_IMAGE( int layer ) :
|
||||||
bool LoadFile( const wxString& aFullFileName );
|
bool LoadFile( const wxString& aFullFileName );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Execute_HEADER_Command( char*& text );
|
bool Execute_HEADER_And_M_Command( char*& text );
|
||||||
bool Select_Tool( char*& text );
|
bool Select_Tool( char*& text );
|
||||||
bool Execute_EXCELLON_G_Command( char*& text );
|
bool Execute_EXCELLON_G_Command( char*& text );
|
||||||
bool Execute_Drill_Command( char*& text );
|
bool Execute_Drill_Command( char*& text );
|
||||||
|
@ -233,10 +281,10 @@ private:
|
||||||
* B# Retract Rate
|
* B# Retract Rate
|
||||||
* C# Tool Diameter
|
* C# Tool Diameter
|
||||||
* F# Table Feed Rate;Z Axis Infeed Rate
|
* F# Table Feed Rate;Z Axis Infeed Rate
|
||||||
* G00X#Y# Route Mode
|
* G00X#Y# Route Mode; XY is the starting point
|
||||||
* G01 Linear (Straight Line) Mode
|
* G01X#Y# Linear (Straight Line) Route Mode YX is the ending point
|
||||||
* G02 Circular CW Mode
|
* G02X#Y#... Circular CW Mode. Radius value (A#) or Center position (I#J#) follows
|
||||||
* G03 Circular CCW Mode
|
* G03X#Y#... Circular CCW Mode. Radius value (A#) or Center position (I#J#) follows
|
||||||
* G04 X# Variable Dwell
|
* G04 X# Variable Dwell
|
||||||
* G05 Drill Mode
|
* G05 Drill Mode
|
||||||
* G07 Override current tool feed or speed
|
* G07 Override current tool feed or speed
|
||||||
|
|
|
@ -87,23 +87,103 @@ static const int fmtMantissaInch = 4;
|
||||||
static const int fmtIntegerMM = 3;
|
static const int fmtIntegerMM = 3;
|
||||||
static const int fmtIntegerInch = 2;
|
static const int fmtIntegerInch = 2;
|
||||||
|
|
||||||
|
// A helper function to calculate the arc center of an arc
|
||||||
|
// known by 2 end points, the radius, and the angle direction (CW or CCW)
|
||||||
|
// Arc angles are <= 180 degrees in circular interpol.
|
||||||
|
static wxPoint computeCenter(wxPoint aStart, wxPoint aEnd, int& aRadius, bool aRotCCW )
|
||||||
|
{
|
||||||
|
wxPoint center;
|
||||||
|
VECTOR2D end;
|
||||||
|
end.x = double(aEnd.x - aStart.x);
|
||||||
|
end.y = double(aEnd.y - aStart.y);
|
||||||
|
|
||||||
|
// Be sure aRadius/2 > dist between aStart and aEnd
|
||||||
|
double min_radius = end.EuclideanNorm() * 2;
|
||||||
|
|
||||||
|
if( min_radius <= aRadius )
|
||||||
|
{
|
||||||
|
// Adjust the radius and the arc center for a 180 deg arc between end points
|
||||||
|
aRadius = KiROUND( min_radius );
|
||||||
|
center.x = ( aStart.x + aEnd.x + 1 ) / 2;
|
||||||
|
center.y = ( aStart.y + aEnd.y + 1 ) / 2;
|
||||||
|
return center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* to compute the centers position easily:
|
||||||
|
* rotate the segment (0,0 to end.x,end.y) to make it horizontal (end.y = 0).
|
||||||
|
* the X center position is end.x/2
|
||||||
|
* the Y center positions are on the vertical line starting at end.x/2, 0
|
||||||
|
* and solve aRadius^2 = X^2 + Y^2 (2 values)
|
||||||
|
*/
|
||||||
|
double seg_angle = end.Angle(); //in radian
|
||||||
|
VECTOR2D h_segm = end.Rotate( - seg_angle );
|
||||||
|
double cX = h_segm.x/2;
|
||||||
|
double cY1 = sqrt( (double)aRadius*aRadius - cX*cX );
|
||||||
|
double cY2 = -cY1;
|
||||||
|
VECTOR2D center1( cX, cY1 );
|
||||||
|
center1 = center1.Rotate( seg_angle );
|
||||||
|
double arc_angle1 = (end - center1).Angle() - (VECTOR2D(0.0,0.0) - center1).Angle();
|
||||||
|
VECTOR2D center2( cX, cY2 );
|
||||||
|
center2 = center2.Rotate( seg_angle );
|
||||||
|
double arc_angle2 = (end - center2).Angle() - (VECTOR2D(0.0,0.0) - center2).Angle();
|
||||||
|
|
||||||
|
if( !aRotCCW )
|
||||||
|
{
|
||||||
|
if( arc_angle1 < 0.0 )
|
||||||
|
arc_angle1 += 2*M_PI;
|
||||||
|
|
||||||
|
if( arc_angle2 < 0.0 )
|
||||||
|
arc_angle2 += 2*M_PI;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( arc_angle1 > 0.0 )
|
||||||
|
arc_angle1 -= 2*M_PI;
|
||||||
|
|
||||||
|
if( arc_angle2 > 0.0 )
|
||||||
|
arc_angle2 -= 2*M_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Arc angle must be <= 180.0 degrees.
|
||||||
|
// So choose the center that create a arc angle <= 180.0
|
||||||
|
if( std::abs( arc_angle1 ) <= M_PI )
|
||||||
|
{
|
||||||
|
center.x = KiROUND( center1.x );
|
||||||
|
center.y = KiROUND( center1.y );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
center.x = KiROUND( center2.x );
|
||||||
|
center.y = KiROUND( center2.y );
|
||||||
|
}
|
||||||
|
|
||||||
|
return center+aStart;
|
||||||
|
}
|
||||||
|
|
||||||
extern int ReadInt( char*& text, bool aSkipSeparator = true );
|
extern int ReadInt( char*& text, bool aSkipSeparator = true );
|
||||||
extern double ReadDouble( char*& text, bool aSkipSeparator = true );
|
extern double ReadDouble( char*& text, bool aSkipSeparator = true );
|
||||||
|
|
||||||
// See ds274d.cpp:
|
// See rs274d.cpp:
|
||||||
extern void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
extern void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||||
APERTURE_T aAperture,
|
APERTURE_T aAperture,
|
||||||
int Dcode_index,
|
int Dcode_index,
|
||||||
const wxPoint& aPos,
|
const wxPoint& aPos,
|
||||||
wxSize aSize,
|
wxSize aSize,
|
||||||
bool aLayerNegative );
|
bool aLayerNegative );
|
||||||
void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
|
||||||
|
extern void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||||
int Dcode_index,
|
int Dcode_index,
|
||||||
const wxPoint& aStart,
|
const wxPoint& aStart,
|
||||||
const wxPoint& aEnd,
|
const wxPoint& aEnd,
|
||||||
wxSize aPenSize,
|
wxSize aPenSize,
|
||||||
bool aLayerNegative );
|
bool aLayerNegative );
|
||||||
|
|
||||||
|
extern void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index,
|
||||||
|
const wxPoint& aStart, const wxPoint& aEnd,
|
||||||
|
const wxPoint& aRelCenter, wxSize aPenSize,
|
||||||
|
bool aClockwise, bool aMultiquadrant,
|
||||||
|
bool aLayerNegative );
|
||||||
|
|
||||||
// Gerber X2 files have a file attribute which specify the type of image
|
// Gerber X2 files have a file attribute which specify the type of image
|
||||||
// (copper, solder paste ... and sides tpo, bottom or inner copper layers)
|
// (copper, solder paste ... and sides tpo, bottom or inner copper layers)
|
||||||
// Excellon drill files do not have attributes, so, just to identify the image
|
// Excellon drill files do not have attributes, so, just to identify the image
|
||||||
|
@ -114,6 +194,9 @@ static EXCELLON_CMD excellonHeaderCmdList[] =
|
||||||
{
|
{
|
||||||
{ "M0", DRILL_M_END, -1 }, // End of Program - No Rewind
|
{ "M0", DRILL_M_END, -1 }, // End of Program - No Rewind
|
||||||
{ "M00", DRILL_M_END, -1 }, // End of Program - No Rewind
|
{ "M00", DRILL_M_END, -1 }, // End of Program - No Rewind
|
||||||
|
{ "M15", DRILL_M_TOOL_DOWN, 0 }, // tool down (starting a routed hole)
|
||||||
|
{ "M16", DRILL_M_TOOL_UP, 0 }, // tool up (ending a routed hole)
|
||||||
|
{ "M17", DRILL_M_TOOL_UP, 0 }, // tool up similar to M16 for a viewer
|
||||||
{ "M30", DRILL_M_ENDREWIND, -1 }, // End of Program Rewind
|
{ "M30", DRILL_M_ENDREWIND, -1 }, // End of Program Rewind
|
||||||
{ "M47", DRILL_M_MESSAGE, -1 }, // Operator Message
|
{ "M47", DRILL_M_MESSAGE, -1 }, // Operator Message
|
||||||
{ "M45", DRILL_M_LONGMESSAGE, -1 }, // Long Operator message (use more than one line)
|
{ "M45", DRILL_M_LONGMESSAGE, -1 }, // Long Operator message (use more than one line)
|
||||||
|
@ -149,10 +232,10 @@ static EXCELLON_CMD excellon_G_CmdList[] =
|
||||||
{ "G90", DRILL_G_ZEROSET, 0 }, // Absolute Mode
|
{ "G90", DRILL_G_ZEROSET, 0 }, // Absolute Mode
|
||||||
{ "G00", DRILL_G_ROUT, 1 }, // Route Mode
|
{ "G00", DRILL_G_ROUT, 1 }, // Route Mode
|
||||||
{ "G05", DRILL_G_DRILL, 0 }, // Drill Mode
|
{ "G05", DRILL_G_DRILL, 0 }, // Drill Mode
|
||||||
{ "G85", DRILL_G_SLOT, 0 }, // Drill Mode slot (oval holes)
|
{ "G85", DRILL_G_SLOT, 0 }, // Canned Mode slot (oval holes)
|
||||||
{ "G01", DRILL_G_LINEARMOVE, 0 }, // Linear (Straight Line) Mode
|
{ "G01", DRILL_G_LINEARMOVE, 1 }, // Linear (Straight Line) routing Mode
|
||||||
{ "G02", DRILL_G_CWMOVE, 0 }, // Circular CW Mode
|
{ "G02", DRILL_G_CWMOVE, 1 }, // Circular CW Mode
|
||||||
{ "G03", DRILL_G_CCWMOVE, 0 }, // Circular CCW Mode
|
{ "G03", DRILL_G_CCWMOVE, 1 }, // Circular CCW Mode
|
||||||
{ "G93", DRILL_G_ZERO_SET, 1 }, // Zero Set (XnnYmm and coordintes origin)
|
{ "G93", DRILL_G_ZERO_SET, 1 }, // Zero Set (XnnYmm and coordintes origin)
|
||||||
{ "", DRILL_G_UNKNOWN, 0 }, // last item in list
|
{ "", DRILL_G_UNKNOWN, 0 }, // last item in list
|
||||||
};
|
};
|
||||||
|
@ -264,14 +347,14 @@ bool EXCELLON_IMAGE::LoadFile( const wxString & aFullFileName )
|
||||||
|
|
||||||
if( m_State == EXCELLON_IMAGE::READ_HEADER_STATE )
|
if( m_State == EXCELLON_IMAGE::READ_HEADER_STATE )
|
||||||
{
|
{
|
||||||
Execute_HEADER_Command( text );
|
Execute_HEADER_And_M_Command( text );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch( *text )
|
switch( *text )
|
||||||
{
|
{
|
||||||
case 'M':
|
case 'M':
|
||||||
Execute_HEADER_Command( text );
|
Execute_HEADER_And_M_Command( text );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'G': /* Line type Gxx : command */
|
case 'G': /* Line type Gxx : command */
|
||||||
|
@ -324,7 +407,7 @@ bool EXCELLON_IMAGE::LoadFile( const wxString & aFullFileName )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EXCELLON_IMAGE::Execute_HEADER_Command( char*& text )
|
bool EXCELLON_IMAGE::Execute_HEADER_And_M_Command( char*& text )
|
||||||
{
|
{
|
||||||
EXCELLON_CMD* cmd = NULL;
|
EXCELLON_CMD* cmd = NULL;
|
||||||
wxString msg;
|
wxString msg;
|
||||||
|
@ -465,6 +548,55 @@ bool EXCELLON_IMAGE::Execute_HEADER_Command( char*& text )
|
||||||
case DRILL_TOOL_INFORMATION:
|
case DRILL_TOOL_INFORMATION:
|
||||||
readToolInformation( text );
|
readToolInformation( text );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DRILL_M_TOOL_DOWN: // tool down (starting a routed hole or polyline)
|
||||||
|
// Only the last position is usefull:
|
||||||
|
if( m_RoutePositions.size() > 1 )
|
||||||
|
m_RoutePositions.erase( m_RoutePositions.begin(), m_RoutePositions.begin() + m_RoutePositions.size() - 1 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DRILL_M_TOOL_UP: // tool up (ending a routed polyline)
|
||||||
|
{
|
||||||
|
D_CODE* tool = GetDCODE( m_Current_Tool );
|
||||||
|
|
||||||
|
for( size_t ii = 1; ii < m_RoutePositions.size(); ii++ )
|
||||||
|
{
|
||||||
|
GERBER_DRAW_ITEM* gbritem = new GERBER_DRAW_ITEM( this );
|
||||||
|
|
||||||
|
if( m_RoutePositions[ii].m_rmode == 0 ) // linear routing
|
||||||
|
{
|
||||||
|
fillLineGBRITEM( gbritem, tool->m_Num_Dcode,
|
||||||
|
m_RoutePositions[ii-1].GetPos(), m_RoutePositions[ii].GetPos(),
|
||||||
|
tool->m_Size, false );
|
||||||
|
}
|
||||||
|
else // circular (cw or ccw) routing
|
||||||
|
{
|
||||||
|
bool rot_ccw = m_RoutePositions[ii].m_rmode == ROUTE_CW;
|
||||||
|
int radius = m_RoutePositions[ii].m_radius; // Can be adjusted by computeCenter.
|
||||||
|
wxPoint center;
|
||||||
|
|
||||||
|
if( m_RoutePositions[ii].m_arc_type_info == ARC_INFO_TYPE_CENTER )
|
||||||
|
center = wxPoint( m_RoutePositions[ii].m_cx, m_RoutePositions[ii].m_cy );
|
||||||
|
else
|
||||||
|
center = computeCenter( m_RoutePositions[ii-1].GetPos(),
|
||||||
|
m_RoutePositions[ii].GetPos(), radius, rot_ccw );
|
||||||
|
|
||||||
|
fillArcGBRITEM( gbritem, tool->m_Num_Dcode,
|
||||||
|
m_RoutePositions[ii-1].GetPos(), m_RoutePositions[ii].GetPos(),
|
||||||
|
center - m_RoutePositions[ii-1].GetPos(),
|
||||||
|
tool->m_Size, not rot_ccw , true,
|
||||||
|
false );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Drawings.Append( gbritem );
|
||||||
|
|
||||||
|
StepAndRepeatItem( *gbritem );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_RoutePositions.clear();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
while( *text )
|
while( *text )
|
||||||
|
@ -537,11 +669,12 @@ bool EXCELLON_IMAGE::Execute_Drill_Command( char*& text )
|
||||||
switch( *text )
|
switch( *text )
|
||||||
{
|
{
|
||||||
case 'X':
|
case 'X':
|
||||||
ReadXYCoord( text, true );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'Y':
|
case 'Y':
|
||||||
ReadXYCoord( text, true );
|
ReadXYCoord( text, true );
|
||||||
|
|
||||||
|
if( *text == 'I' || *text == 'J' )
|
||||||
|
ReadIJCoord( text );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'G': // G85 is found here for oval holes
|
case 'G': // G85 is found here for oval holes
|
||||||
|
@ -550,8 +683,31 @@ bool EXCELLON_IMAGE::Execute_Drill_Command( char*& text )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0: // E.O.L: execute command
|
case 0: // E.O.L: execute command
|
||||||
tool = GetDCODE( m_Current_Tool );
|
if( m_RouteModeOn )
|
||||||
|
{
|
||||||
|
// We are in routing mode, and this is an intermediate point.
|
||||||
|
// So just store it
|
||||||
|
int rmode = 0; // linear routing.
|
||||||
|
|
||||||
|
if( m_Iterpolation == GERB_INTERPOL_ARC_NEG )
|
||||||
|
rmode = ROUTE_CW;
|
||||||
|
else if( m_Iterpolation == GERB_INTERPOL_ARC_POS )
|
||||||
|
rmode = ROUTE_CCW;
|
||||||
|
|
||||||
|
if( m_LastArcDataType == ARC_INFO_TYPE_CENTER )
|
||||||
|
{
|
||||||
|
EXCELLON_ROUTE_COORD point( m_CurrentPos, m_IJPos, rmode );
|
||||||
|
m_RoutePositions.push_back( point );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EXCELLON_ROUTE_COORD point( m_CurrentPos, m_ArcRadius, rmode );
|
||||||
|
m_RoutePositions.push_back( point );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tool = GetDCODE( m_Current_Tool );
|
||||||
if( !tool )
|
if( !tool )
|
||||||
{
|
{
|
||||||
wxString msg;
|
wxString msg;
|
||||||
|
@ -666,12 +822,19 @@ bool EXCELLON_IMAGE::Execute_EXCELLON_G_Command( char*& text )
|
||||||
|
|
||||||
case DRILL_G_ROUT:
|
case DRILL_G_ROUT:
|
||||||
m_SlotOn = false;
|
m_SlotOn = false;
|
||||||
m_PolygonFillMode = true;
|
m_RouteModeOn = true;
|
||||||
|
m_RoutePositions.clear();
|
||||||
|
m_LastArcDataType = ARC_INFO_TYPE_NONE;
|
||||||
|
ReadXYCoord( text, true );
|
||||||
|
// This is the first point (starting point) of routing
|
||||||
|
m_RoutePositions.push_back( EXCELLON_ROUTE_COORD( m_CurrentPos ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRILL_G_DRILL:
|
case DRILL_G_DRILL:
|
||||||
m_SlotOn = false;
|
m_SlotOn = false;
|
||||||
m_PolygonFillMode = false;
|
m_RouteModeOn = false;
|
||||||
|
m_RoutePositions.clear();
|
||||||
|
m_LastArcDataType = ARC_INFO_TYPE_NONE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRILL_G_SLOT:
|
case DRILL_G_SLOT:
|
||||||
|
@ -679,15 +842,36 @@ bool EXCELLON_IMAGE::Execute_EXCELLON_G_Command( char*& text )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRILL_G_LINEARMOVE:
|
case DRILL_G_LINEARMOVE:
|
||||||
|
m_LastArcDataType = ARC_INFO_TYPE_NONE;
|
||||||
m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
|
m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
|
||||||
|
ReadXYCoord( text, true );
|
||||||
|
m_RoutePositions.push_back( EXCELLON_ROUTE_COORD( m_CurrentPos ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRILL_G_CWMOVE:
|
case DRILL_G_CWMOVE:
|
||||||
m_Iterpolation = GERB_INTERPOL_ARC_NEG;
|
m_Iterpolation = GERB_INTERPOL_ARC_NEG;
|
||||||
|
ReadXYCoord( text, true );
|
||||||
|
|
||||||
|
if( *text == 'I' || *text == 'J' )
|
||||||
|
ReadIJCoord( text );
|
||||||
|
|
||||||
|
if( m_LastArcDataType == ARC_INFO_TYPE_CENTER )
|
||||||
|
m_RoutePositions.push_back( EXCELLON_ROUTE_COORD( m_CurrentPos, m_IJPos, ROUTE_CW ) );
|
||||||
|
else
|
||||||
|
m_RoutePositions.push_back( EXCELLON_ROUTE_COORD( m_CurrentPos, m_ArcRadius, ROUTE_CW ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRILL_G_CCWMOVE:
|
case DRILL_G_CCWMOVE:
|
||||||
m_Iterpolation = GERB_INTERPOL_ARC_POS;
|
m_Iterpolation = GERB_INTERPOL_ARC_POS;
|
||||||
|
ReadXYCoord( text, true );
|
||||||
|
|
||||||
|
if( *text == 'I' || *text == 'J' )
|
||||||
|
ReadIJCoord( text );
|
||||||
|
|
||||||
|
if( m_LastArcDataType == ARC_INFO_TYPE_CENTER )
|
||||||
|
m_RoutePositions.push_back( EXCELLON_ROUTE_COORD( m_CurrentPos, m_IJPos, ROUTE_CCW ) );
|
||||||
|
else
|
||||||
|
m_RoutePositions.push_back( EXCELLON_ROUTE_COORD( m_CurrentPos, m_ArcRadius, ROUTE_CCW ) );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRILL_G_ABSOLUTE:
|
case DRILL_G_ABSOLUTE:
|
||||||
|
@ -700,15 +884,12 @@ bool EXCELLON_IMAGE::Execute_EXCELLON_G_Command( char*& text )
|
||||||
|
|
||||||
case DRILL_G_UNKNOWN:
|
case DRILL_G_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
{
|
AddMessageToList( wxString::Format( _( "Unknown Excellon G Code: <%s>" ), FROM_UTF8(gcmd) ) );
|
||||||
wxString msg;
|
|
||||||
msg.Printf( _( "Unknown Excellon G Code: <%s>" ), GetChars(FROM_UTF8(gcmd)) );
|
|
||||||
AddMessageToList( msg );
|
|
||||||
while( *text )
|
while( *text )
|
||||||
text++;
|
text++;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -219,6 +219,10 @@ void GERBER_FILE_IMAGE::ResetDefaultValues()
|
||||||
m_PreviousPos.x = m_PreviousPos.y = 0; // last specified coord
|
m_PreviousPos.x = m_PreviousPos.y = 0; // last specified coord
|
||||||
m_IJPos.x = m_IJPos.y = 0; // current centre coord for
|
m_IJPos.x = m_IJPos.y = 0; // current centre coord for
|
||||||
// plot arcs & circles
|
// plot arcs & circles
|
||||||
|
m_ArcRadius = 0; // radius of arcs in circular interpol (given by A## command).
|
||||||
|
// in command like X##Y##A##
|
||||||
|
m_LastArcDataType = ARC_INFO_TYPE_NONE; // Extra coordinate info type for arcs
|
||||||
|
// (radius or IJ center coord)
|
||||||
m_LineNum = 0; // line number in file being read
|
m_LineNum = 0; // line number in file being read
|
||||||
m_Current_File = NULL; // Gerber file to read
|
m_Current_File = NULL; // Gerber file to read
|
||||||
m_PolygonFillMode = false;
|
m_PolygonFillMode = false;
|
||||||
|
|
|
@ -65,6 +65,15 @@ class GERBER_FILE_IMAGE;
|
||||||
class X2_ATTRIBUTE;
|
class X2_ATTRIBUTE;
|
||||||
class X2_ATTRIBUTE_FILEFUNCTION;
|
class X2_ATTRIBUTE_FILEFUNCTION;
|
||||||
|
|
||||||
|
// For arcs, coordinates need 3 info: start point, end point and center or radius
|
||||||
|
// In Excellon files it can be a A## value (radius) or I#J# center coordinates (like in gerber)
|
||||||
|
// We need to know the last read type when reading a list of routing coordinates
|
||||||
|
enum LAST_EXTRA_ARC_DATA_TYPE
|
||||||
|
{
|
||||||
|
ARC_INFO_TYPE_NONE,
|
||||||
|
ARC_INFO_TYPE_CENTER, // last info is a IJ command: arc center is given
|
||||||
|
ARC_INFO_TYPE_RADIUS, // last info is a A command: arc radius is given
|
||||||
|
};
|
||||||
|
|
||||||
class GERBER_LAYER
|
class GERBER_LAYER
|
||||||
{
|
{
|
||||||
|
@ -145,7 +154,8 @@ 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 )
|
||||||
|
int m_ArcRadius; // A value ( = radius in circular routing in Excellon files )
|
||||||
|
LAST_EXTRA_ARC_DATA_TYPE m_LastArcDataType; // Identifier for arc data type (IJ (center) or A## (radius))
|
||||||
FILE* m_Current_File; // Current file to read
|
FILE* m_Current_File; // Current file to read
|
||||||
|
|
||||||
int m_Selected_Tool; // For hightlight: current selected Dcode
|
int m_Selected_Tool; // For hightlight: current selected Dcode
|
||||||
|
|
|
@ -89,7 +89,7 @@ wxPoint GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode )
|
||||||
text = line;
|
text = line;
|
||||||
while( *Text )
|
while( *Text )
|
||||||
{
|
{
|
||||||
if( (*Text == 'X') || (*Text == 'Y') )
|
if( (*Text == 'X') || (*Text == 'Y') || (*Text == 'A') )
|
||||||
{
|
{
|
||||||
type_coord = *Text;
|
type_coord = *Text;
|
||||||
Text++;
|
Text++;
|
||||||
|
@ -111,7 +111,7 @@ wxPoint GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode )
|
||||||
|
|
||||||
if( is_float )
|
if( is_float )
|
||||||
{
|
{
|
||||||
// When X or Y values are float numbers, they are given in mm or inches
|
// When X or Y (or A) values are float numbers, they are given in mm or inches
|
||||||
if( m_GerbMetric ) // units are mm
|
if( m_GerbMetric ) // units are mm
|
||||||
current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
|
current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
|
||||||
else // units are inches
|
else // units are inches
|
||||||
|
@ -160,6 +160,11 @@ wxPoint GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode )
|
||||||
pos.x = current_coord;
|
pos.x = current_coord;
|
||||||
else if( type_coord == 'Y' )
|
else if( type_coord == 'Y' )
|
||||||
pos.y = current_coord;
|
pos.y = current_coord;
|
||||||
|
else if( type_coord == 'A' )
|
||||||
|
{
|
||||||
|
m_ArcRadius = current_coord;
|
||||||
|
m_LastArcDataType = ARC_INFO_TYPE_RADIUS;
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -263,6 +268,8 @@ wxPoint GERBER_FILE_IMAGE::ReadIJCoord( char*& Text )
|
||||||
}
|
}
|
||||||
|
|
||||||
m_IJPos = pos;
|
m_IJPos = pos;
|
||||||
|
m_LastArcDataType = ARC_INFO_TYPE_CENTER;
|
||||||
|
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,7 +208,7 @@ void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||||
* false when arc is inside one quadrant
|
* false when arc is inside one quadrant
|
||||||
* @param aLayerNegative = true if the current layer is negative
|
* @param aLayerNegative = true if the current layer is negative
|
||||||
*/
|
*/
|
||||||
static void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index,
|
void fillArcGBRITEM( GERBER_DRAW_ITEM* aGbrItem, int Dcode_index,
|
||||||
const wxPoint& aStart, const wxPoint& aEnd,
|
const wxPoint& aStart, const wxPoint& aEnd,
|
||||||
const wxPoint& aRelCenter, wxSize aPenSize,
|
const wxPoint& aRelCenter, wxSize aPenSize,
|
||||||
bool aClockwise, bool aMultiquadrant,
|
bool aClockwise, bool aMultiquadrant,
|
||||||
|
|
|
@ -250,11 +250,10 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int aCommand, char* aBuff,
|
||||||
|
|
||||||
// conv_scale = scaling factor from inch to Internal Unit
|
// conv_scale = scaling factor from inch to Internal Unit
|
||||||
double conv_scale = IU_PER_MILS * 1000;
|
double conv_scale = IU_PER_MILS * 1000;
|
||||||
|
|
||||||
if( m_GerbMetric )
|
if( m_GerbMetric )
|
||||||
conv_scale /= 25.4;
|
conv_scale /= 25.4;
|
||||||
|
|
||||||
// DBG( printf( "%22s: Command <%c%c>\n", __func__, (command >> 8) & 0xFF, command & 0xFF ); )
|
|
||||||
|
|
||||||
switch( aCommand )
|
switch( aCommand )
|
||||||
{
|
{
|
||||||
case FORMAT_STATEMENT:
|
case FORMAT_STATEMENT:
|
||||||
|
@ -670,8 +669,7 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int aCommand, char* aBuff,
|
||||||
m_ImageNegative = true;
|
m_ImageNegative = true;
|
||||||
else
|
else
|
||||||
m_ImageNegative = false;
|
m_ImageNegative = false;
|
||||||
DBG( printf( "%22s: IMAGE_POLARITY m_ImageNegative=%s\n", __func__,
|
|
||||||
m_ImageNegative ? "true" : "false" ); )
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LOAD_POLARITY:
|
case LOAD_POLARITY:
|
||||||
|
|
Loading…
Reference in New Issue