Gerbview: Excellon drill files reader: add a better support of routing mode.
Previously, the M and G00, G01, G02 and G03 commands were read, but nothing was actually done. The current support is a bit rough, but it allows reading some drill files with routing commands.
This commit is contained in:
parent
b70d0f43b6
commit
4136aca221
|
@ -29,6 +29,8 @@
|
|||
enum drill_M_code_t {
|
||||
DRILL_M_UNKNOWN,
|
||||
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_MESSAGE,
|
||||
DRILL_M_LONGMESSAGE,
|
||||
|
@ -52,12 +54,13 @@ enum drill_M_code_t {
|
|||
DRILL_AUTOMATIC_TOOL_CHANGE,
|
||||
DRILL_FMT,
|
||||
DRILL_SKIP,
|
||||
DRILL_TOOL_INFORMATION
|
||||
DRILL_TOOL_INFORMATION,
|
||||
DRILL_M_END_LIST // not used: sentinel
|
||||
};
|
||||
|
||||
|
||||
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_INCREMENTAL,
|
||||
DRILL_G_ZEROSET,
|
||||
|
@ -78,6 +81,47 @@ struct EXCELLON_CMD
|
|||
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
|
||||
* 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
|
||||
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 ) :
|
||||
GERBER_FILE_IMAGE( layer )
|
||||
{
|
||||
m_State = READ_HEADER_STATE;
|
||||
m_SlotOn = false;
|
||||
m_RouteModeOn = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -124,7 +172,7 @@ public: EXCELLON_IMAGE( int layer ) :
|
|||
bool LoadFile( const wxString& aFullFileName );
|
||||
|
||||
private:
|
||||
bool Execute_HEADER_Command( char*& text );
|
||||
bool Execute_HEADER_And_M_Command( char*& text );
|
||||
bool Select_Tool( char*& text );
|
||||
bool Execute_EXCELLON_G_Command( char*& text );
|
||||
bool Execute_Drill_Command( char*& text );
|
||||
|
@ -233,10 +281,10 @@ private:
|
|||
* B# Retract Rate
|
||||
* C# Tool Diameter
|
||||
* F# Table Feed Rate;Z Axis Infeed Rate
|
||||
* G00X#Y# Route Mode
|
||||
* G01 Linear (Straight Line) Mode
|
||||
* G02 Circular CW Mode
|
||||
* G03 Circular CCW Mode
|
||||
* G00X#Y# Route Mode; XY is the starting point
|
||||
* G01X#Y# Linear (Straight Line) Route Mode YX is the ending point
|
||||
* G02X#Y#... Circular CW Mode. Radius value (A#) or Center position (I#J#) follows
|
||||
* G03X#Y#... Circular CCW Mode. Radius value (A#) or Center position (I#J#) follows
|
||||
* G04 X# Variable Dwell
|
||||
* G05 Drill Mode
|
||||
* G07 Override current tool feed or speed
|
||||
|
|
|
@ -87,23 +87,103 @@ static const int fmtMantissaInch = 4;
|
|||
static const int fmtIntegerMM = 3;
|
||||
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 double ReadDouble( char*& text, bool aSkipSeparator = true );
|
||||
|
||||
// See ds274d.cpp:
|
||||
// See rs274d.cpp:
|
||||
extern void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||
APERTURE_T aAperture,
|
||||
int Dcode_index,
|
||||
const wxPoint& aPos,
|
||||
wxSize aSize,
|
||||
bool aLayerNegative );
|
||||
void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||
|
||||
extern void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
||||
int Dcode_index,
|
||||
const wxPoint& aStart,
|
||||
const wxPoint& aEnd,
|
||||
wxSize aPenSize,
|
||||
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
|
||||
// (copper, solder paste ... and sides tpo, bottom or inner copper layers)
|
||||
// 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
|
||||
{ "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
|
||||
{ "M47", DRILL_M_MESSAGE, -1 }, // Operator Message
|
||||
{ "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
|
||||
{ "G00", DRILL_G_ROUT, 1 }, // Route Mode
|
||||
{ "G05", DRILL_G_DRILL, 0 }, // Drill Mode
|
||||
{ "G85", DRILL_G_SLOT, 0 }, // Drill Mode slot (oval holes)
|
||||
{ "G01", DRILL_G_LINEARMOVE, 0 }, // Linear (Straight Line) Mode
|
||||
{ "G02", DRILL_G_CWMOVE, 0 }, // Circular CW Mode
|
||||
{ "G03", DRILL_G_CCWMOVE, 0 }, // Circular CCW Mode
|
||||
{ "G85", DRILL_G_SLOT, 0 }, // Canned Mode slot (oval holes)
|
||||
{ "G01", DRILL_G_LINEARMOVE, 1 }, // Linear (Straight Line) routing Mode
|
||||
{ "G02", DRILL_G_CWMOVE, 1 }, // Circular CW Mode
|
||||
{ "G03", DRILL_G_CCWMOVE, 1 }, // Circular CCW Mode
|
||||
{ "G93", DRILL_G_ZERO_SET, 1 }, // Zero Set (XnnYmm and coordintes origin)
|
||||
{ "", 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 )
|
||||
{
|
||||
Execute_HEADER_Command( text );
|
||||
Execute_HEADER_And_M_Command( text );
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( *text )
|
||||
{
|
||||
case 'M':
|
||||
Execute_HEADER_Command( text );
|
||||
Execute_HEADER_And_M_Command( text );
|
||||
break;
|
||||
|
||||
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;
|
||||
wxString msg;
|
||||
|
@ -465,6 +548,55 @@ bool EXCELLON_IMAGE::Execute_HEADER_Command( char*& text )
|
|||
case DRILL_TOOL_INFORMATION:
|
||||
readToolInformation( text );
|
||||
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 )
|
||||
|
@ -537,11 +669,12 @@ bool EXCELLON_IMAGE::Execute_Drill_Command( char*& text )
|
|||
switch( *text )
|
||||
{
|
||||
case 'X':
|
||||
ReadXYCoord( text, true );
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
ReadXYCoord( text, true );
|
||||
|
||||
if( *text == 'I' || *text == 'J' )
|
||||
ReadIJCoord( text );
|
||||
|
||||
break;
|
||||
|
||||
case 'G': // G85 is found here for oval holes
|
||||
|
@ -550,8 +683,31 @@ bool EXCELLON_IMAGE::Execute_Drill_Command( char*& text )
|
|||
break;
|
||||
|
||||
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 )
|
||||
{
|
||||
wxString msg;
|
||||
|
@ -666,12 +822,19 @@ bool EXCELLON_IMAGE::Execute_EXCELLON_G_Command( char*& text )
|
|||
|
||||
case DRILL_G_ROUT:
|
||||
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;
|
||||
|
||||
case DRILL_G_DRILL:
|
||||
m_SlotOn = false;
|
||||
m_PolygonFillMode = false;
|
||||
m_RouteModeOn = false;
|
||||
m_RoutePositions.clear();
|
||||
m_LastArcDataType = ARC_INFO_TYPE_NONE;
|
||||
break;
|
||||
|
||||
case DRILL_G_SLOT:
|
||||
|
@ -679,15 +842,36 @@ bool EXCELLON_IMAGE::Execute_EXCELLON_G_Command( char*& text )
|
|||
break;
|
||||
|
||||
case DRILL_G_LINEARMOVE:
|
||||
m_LastArcDataType = ARC_INFO_TYPE_NONE;
|
||||
m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
|
||||
ReadXYCoord( text, true );
|
||||
m_RoutePositions.push_back( EXCELLON_ROUTE_COORD( m_CurrentPos ) );
|
||||
break;
|
||||
|
||||
case DRILL_G_CWMOVE:
|
||||
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;
|
||||
|
||||
case DRILL_G_CCWMOVE:
|
||||
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;
|
||||
|
||||
case DRILL_G_ABSOLUTE:
|
||||
|
@ -700,15 +884,12 @@ bool EXCELLON_IMAGE::Execute_EXCELLON_G_Command( char*& text )
|
|||
|
||||
case DRILL_G_UNKNOWN:
|
||||
default:
|
||||
{
|
||||
wxString msg;
|
||||
msg.Printf( _( "Unknown Excellon G Code: <%s>" ), GetChars(FROM_UTF8(gcmd)) );
|
||||
AddMessageToList( msg );
|
||||
AddMessageToList( wxString::Format( _( "Unknown Excellon G Code: <%s>" ), FROM_UTF8(gcmd) ) );
|
||||
while( *text )
|
||||
text++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
|
@ -219,6 +219,10 @@ void GERBER_FILE_IMAGE::ResetDefaultValues()
|
|||
m_PreviousPos.x = m_PreviousPos.y = 0; // last specified coord
|
||||
m_IJPos.x = m_IJPos.y = 0; // current centre coord for
|
||||
// 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_Current_File = NULL; // Gerber file to read
|
||||
m_PolygonFillMode = false;
|
||||
|
|
|
@ -65,6 +65,15 @@ class GERBER_FILE_IMAGE;
|
|||
class X2_ATTRIBUTE;
|
||||
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
|
||||
{
|
||||
|
@ -145,7 +154,8 @@ public:
|
|||
wxPoint m_CurrentPos; // current specified coord for plot
|
||||
wxPoint m_PreviousPos; // old current specified coord for plot
|
||||
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
|
||||
|
||||
int m_Selected_Tool; // For hightlight: current selected Dcode
|
||||
|
|
|
@ -89,7 +89,7 @@ wxPoint GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode )
|
|||
text = line;
|
||||
while( *Text )
|
||||
{
|
||||
if( (*Text == 'X') || (*Text == 'Y') )
|
||||
if( (*Text == 'X') || (*Text == 'Y') || (*Text == 'A') )
|
||||
{
|
||||
type_coord = *Text;
|
||||
Text++;
|
||||
|
@ -111,7 +111,7 @@ wxPoint GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode )
|
|||
|
||||
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
|
||||
current_coord = KiROUND( atof( line ) * IU_PER_MILS / 0.0254 );
|
||||
else // units are inches
|
||||
|
@ -160,6 +160,11 @@ wxPoint GERBER_FILE_IMAGE::ReadXYCoord( char*& Text, bool aExcellonMode )
|
|||
pos.x = current_coord;
|
||||
else if( type_coord == 'Y' )
|
||||
pos.y = current_coord;
|
||||
else if( type_coord == 'A' )
|
||||
{
|
||||
m_ArcRadius = current_coord;
|
||||
m_LastArcDataType = ARC_INFO_TYPE_RADIUS;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
@ -263,6 +268,8 @@ wxPoint GERBER_FILE_IMAGE::ReadIJCoord( char*& Text )
|
|||
}
|
||||
|
||||
m_IJPos = pos;
|
||||
m_LastArcDataType = ARC_INFO_TYPE_CENTER;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
|
|
@ -208,11 +208,11 @@ void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
|
|||
* false when arc is inside one quadrant
|
||||
* @param aLayerNegative = true if the current layer is negative
|
||||
*/
|
||||
static 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 )
|
||||
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 )
|
||||
{
|
||||
wxPoint center, delta;
|
||||
|
||||
|
|
|
@ -250,11 +250,10 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int aCommand, char* aBuff,
|
|||
|
||||
// conv_scale = scaling factor from inch to Internal Unit
|
||||
double conv_scale = IU_PER_MILS * 1000;
|
||||
|
||||
if( m_GerbMetric )
|
||||
conv_scale /= 25.4;
|
||||
|
||||
// DBG( printf( "%22s: Command <%c%c>\n", __func__, (command >> 8) & 0xFF, command & 0xFF ); )
|
||||
|
||||
switch( aCommand )
|
||||
{
|
||||
case FORMAT_STATEMENT:
|
||||
|
@ -670,8 +669,7 @@ bool GERBER_FILE_IMAGE::ExecuteRS274XCommand( int aCommand, char* aBuff,
|
|||
m_ImageNegative = true;
|
||||
else
|
||||
m_ImageNegative = false;
|
||||
DBG( printf( "%22s: IMAGE_POLARITY m_ImageNegative=%s\n", __func__,
|
||||
m_ImageNegative ? "true" : "false" ); )
|
||||
|
||||
break;
|
||||
|
||||
case LOAD_POLARITY:
|
||||
|
|
Loading…
Reference in New Issue