Gerbview: Added: read Excellon files created by Pcbnew. The full Excellon command set is not supported, but drill files created by Pcbnew are supported.

This commit is contained in:
jean-pierre charras 2011-03-16 21:51:20 +01:00
parent 0d740e45e3
commit ffbce6de84
9 changed files with 1000 additions and 15 deletions

View File

@ -4,6 +4,12 @@ KiCad ChangeLog 2010
Please add newer entries at the top, list the date and your name with
email address.
2011-Mar-16, UPDATE Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
================================================================================
Gerbview:
Added: read Excellon files created by Pcbnew.
The full Excellon command set is not supported, but drill files created by Pcbnew are supported.
2011-Feb-05, UPDATE Jean-Pierre Charras <jean-pierre.charras@gipsa-lab.inpg.fr>
================================================================================
CvPcb:

View File

@ -34,6 +34,7 @@ set(GERBVIEW_SRCS
dummy_functions.cpp
draw_gerber_screen.cpp
events_called_functions.cpp
excellon_read_drill_file.cpp
export_to_pcbnew.cpp
files.cpp
gerbview.cpp

View File

@ -142,7 +142,16 @@ public:
~GERBER_IMAGE();
void Clear_GERBER_IMAGE();
int ReturnUsedDcodeNumber();
void ResetDefaultValues();
virtual void ResetDefaultValues();
/**
* Function GetParent
* @return the GERBVIEW_FRAME parent of this GERBER_IMAGE
*/
GERBVIEW_FRAME* GetParent()
{
return m_Parent;
}
/**
* Function GetLayerParams

288
gerbview/class_excellon.h Normal file
View File

@ -0,0 +1,288 @@
/********************/
/* class_excellon.h */
/********************/
#ifndef CLASS_EXCELLON_H
#define CLASS_EXCELLON_H
enum drill_M_code_t {
DRILL_M_UNKNOWN,
DRILL_M_END,
DRILL_M_ENDREWIND,
DRILL_M_MESSAGE,
DRILL_M_LONGMESSAGE,
DRILL_M_HEADER,
DRILL_M_ENDHEADER,
DRILL_M_BEGINPATTERN,
DRILL_M_ENDPATTERN,
DRILL_M_CANNEDTEXT,
DRILL_M_TIPCHECK,
DRILL_M_METRIC,
DRILL_M_IMPERIAL,
DRILL_METRICHEADER,
DRILL_IMPERIALHEADER,
DRILL_DETECT_BROKEN,
DRILL_INCREMENTALHEADER,
DRILL_REWIND_STOP,
DRILL_TOOL_CHANGE_STOP,
DRILL_AUTOMATIC_SPEED,
DRILL_AXIS_VERSION,
DRILL_RESET_CMD,
DRILL_AUTOMATIC_TOOL_CHANGE,
DRILL_FMT,
DRILL_SKIP,
DRILL_TOOL_INFORMATION
};
enum drill_G_code_t {
DRILL_G_UNKNOWN,
DRILL_G_ABSOLUTE,
DRILL_G_INCREMENTAL,
DRILL_G_ZEROSET,
DRILL_G_ROUT,
DRILL_G_DRILL,
DRILL_G_SLOT,
DRILL_G_ZERO_SET,
DRILL_G_LINEARMOVE,
DRILL_G_CWMOVE,
DRILL_G_CCWMOVE
};
// Helper struct to analyse Excellon commands
struct EXCELLON_CMD
{
string m_Name; // key string
int m_Code; // internal code, used as id in functions
int m_asParams; // 0 = no param, -1 = skip params, 1 = read params
};
/* EXCELLON_IMAGE handle a drill image
* It is derived from GERBER_IMAGE because there is a lot of likeness
* between EXCELLON files and GERBER files
* DCode aperture are also similat to T Codes.
* So we can reuse GERBER_IMAGE to handle EXCELLON_IMAGE with very few new functions
*/
class EXCELLON_IMAGE : public GERBER_IMAGE
{
private:
enum excellon_state {
READ_HEADER_STATE, // When we are in this state, we are reading header
READ_PROGRAM_STATE // When we are in this state, we are reading drill data
};
excellon_state m_State; // state of excellon file analysis
bool m_SlotOn; // true during an oval driil definition
public: EXCELLON_IMAGE( GERBVIEW_FRAME* aParent, int layer ) :
GERBER_IMAGE( aParent, layer )
{
m_State = READ_HEADER_STATE;
m_SlotOn = false;
}
~EXCELLON_IMAGE() {};
virtual void ResetDefaultValues()
{
GERBER_IMAGE::ResetDefaultValues();
SelectUnits( false );
}
bool Read_EXCELLON_File( FILE* aFile, const wxString& aFullFileName );
private:
bool Execute_HEADER_Command( char*& text );
bool Select_Tool( char*& text );
bool Execute_EXCELLON_G_Command( char*& text );
bool Execute_Drill_Command( char*& text );
int ReturnTCodeNumber( char*& Text )
{
return ReturnDCodeNumber( Text );
}
void SelectUnits( bool aMetric );
};
/*
* EXCELLON commands are given here.
* Pcbnew uses only few excellon commands
*/
/*
* see http://www.excellon.com/manuals/program.htm
*/
/* coordintes units:
* Coordinates are measured either in inch or metric (millimeters).
* Inch coordinates are in six digits (00.0000) with increments as small as 0.0001 (1/10,000).
* Metric coordinates can be measured in microns (thousandths of a millimeter)
* in one of the following three ways:
* Five digit 10 micron resolution (000.00)
* Six digit 10 micron resolution (0000.00)
* Six digit micron resolution (000.000)
*
* Leading and trailing zeros:
* Excellon (CNC-7) uses inches in six digits and metric in five or six digits.
* The zeros to the left of the coordinate are called leading zeros (LZ).
* The zeros to right of the coordinate are called trailing zeros (TZ).
* The CNC-7 uses leading zeros unless you specify otherwise through a part program.
* You can do so with the INCH/METRIC command.
* With leading zeros, the leading zeros must always be included.
* Trailing zeros are unneeded and may be left off.
* For trailing zeros, the reverse of the above is true.
*/
/*
* EXCELLON Commands Used in a Header
* The following table provides you with a list of commands which
* are the most used in a part program header.
* COMMAND DESCRIPTION
* AFS Automatic Feeds and Speeds
* ATC Automatic Tool Change
* BLKD Delete all Blocks starting with a slash (/)
* CCW Clockwise or Counter-clockwise Routing
* CP Cutter Compensation
* DETECT Broken Tool Detection
* DN Down Limit Set
* DTMDIST Maximum Rout Distance Before Toolchange
* EXDA Extended Drill Area
* FMAT Format 1 or 2
* FSB Turns the Feed/Speed Buttons off
* HPCK Home Pulse Check
* ICI Incremental Input of Part Program Coordinates
* INCH Measure Everything in Inches
* METRIC Measure Everything in Metric
* M48 Beginning of Part Program Header
* M95 End of Header
* NCSL NC Slope Enable/Disable
* OM48 Override Part Program Header
* OSTOP Optional Stop Switch
* OTCLMP Override Table Clamp
* PCKPARAM Set up pecking tool,depth,infeed and retract parameters
* PF Floating Pressure Foot Switch
* PPR Programmable Plunge Rate Enable
* PVS Pre-vacuum Shut-off Switch
* R,C Reset Clocks
* R,CP Reset Program Clocks
* R,CR Reset Run Clocks
* R,D Reset All Cutter Distances
* R,H Reset All Hit Counters
* R,T Reset Tool Data
* SBK Single Block Mode Switch
* SG Spindle Group Mode
* SIXM Input From External Source
* T Tool Information
* TCST Tool Change Stop
* UP Upper Limit Set
* VER Selection of X and Y Axis Version
* Z Zero Set
* ZA Auxiliary Zero
* ZC Zero Correction
* ZS Zero Preset
* Z+# or Z-# Set Depth Offset
* % Rewind Stop
* #/#/# Link Tool for Automatic Tool Change
* / Clear Tool Linking
*/
/*
* Beyond The Header: The Part Program Body
* COMMAND DESCRIPTION
* A# Arc Radius
* 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
* G04 X# Variable Dwell
* G05 Drill Mode
* G07 Override current tool feed or speed
* G32X#Y#A# Routed Circle Canned Cycle
* CW G33X#Y#A# Routed Circle Canned Cycle
* CCW G34,#(,#) Select Vision Tool
* G35(X#Y#) Single Point Vision Offset (Relative to Work Zero)
* G36(X#Y#) Multipoint Vision Translation (Relative to Work Zero)
* G37 Cancel Vision Translation or Offset (From G35 or G36)
* G38(X#Y#) Vision Corrected Single Hole Drilling (Relative to Work Zero)
* G39(X#Y#) Vision System Autocalibration
* G40 Cutter Compensation Off
* G41 Cutter Compensation Left
* G42 Cutter Compensation Right
* G45(X#Y#) Single Point Vision Offset (Relative to G35 or G36)
* G46(X#Y#) Multipoint Vision Translation (Relative to G35 or G36)
* G47 Cancel Vision Translation or Offset (From G45 or G46)
* G48(X#Y#) Vision Corrected Single Hole Drilling (Relative to G35 or G36)
* G82(G81) Dual In Line Package
* G83 Eight Pin L Pack
* G84 Circle
* G85 Slot
* G87 Routed Step Slot Canned Cycle
* G90 Absolute Mode
* G91 Incremental Input Mode
* G93X#Y# Zero Set
* H# Maximum hit count
* I#J# Arc Center Offset
* M00(X#Y#) End of Program - No Rewind
* M01 End of Pattern
* M02X#Y# Repeat Pattern Offset
* M06(X#Y#) Optional Stop
* M08 End of Step and Repeat
* M09(X#Y#) Stop for Inspection
* M14 Z Axis Route Position With Depth Controlled Contouring
* M15 Z Axis Route Position
* M16 Retract With Clamping
* M17 Retract Without Clamping
* M18 Command tool tip check
* M25 Beginning of Pattern
* M30(X#Y#) End of Program Rewind
* M45,long message\ Long Operator message on multiple\ part program lines
* M47,text Operator Message
* M50,# Vision Step and Repeat Pattern Start
* M51,# Vision Step and Repeat Rewind
* M52(#) Vision Step and Repeat Offset Counter Control
* M02XYM70 Swap Axes
* M60 Reference Scaling enable
* M61 Reference Scaling disable
* M62 Turn on peck drilling
* M63 Turn off peck drilling
* M71 Metric Measuring Mode
* M72 Inch Measuring Mode
* M02XYM80 Mirror Image X Axis
* M02XYM90 Mirror Image Y Axis
* M97,text Canned Text
* M98,text Canned Text
* M99,subprogram User Defined Stored Pattern
* P#X#(Y#) Repeat Stored Pattern
* R#M02X#Y# Repeat Pattern (S&R)
* R#(X#Y#) Repeat Hole
* S# Spindle RPM
* T# Tool Selection; Cutter Index
* Z+# or Z-# Depth Offset
* % Beginning of Pattern (see M25 command)
* / Block Delete
*/
/*
* Example of a Header
* COMMAND PURPOSE
* M48 The beginning of a header
* INCH,LZ Use the inch measuring system with leading zeros
* VER,1 Use Version 1 X and Y axis layout
* FMAT,2 Use Format 2 commands
* 1/2/3 Link tools 1, 2, and 3
* T1C.04F200S65 Set Tool 1 for 0.040" with infeed rate of 200 inch/min Speed of 65,000 RPM
* DETECT,ON Detect broken tools
* M95 End of the header
*/
#endif // CLASS_EXCELLON_H

View File

@ -0,0 +1,595 @@
/********************************/
/* excellon_read_drill_file.cpp */
/********************************/
/*
* Functions to read drill files (EXCELLON format) created by PcbNew
* These files use only a subset of EXCELLON commands.
* Here is a sample, in decimal format:
* (Note: coordinates formats are same as Gerber, and T commands are near Gerber D commands).
* M48
* ;DRILL file {PCBnew (2011-03-14 BZR 2894)-testing} date 15/03/2011 14:23:22
* ;FORMAT={-:-/ absolute / inch / decimal}
* FMAT,2
* INCH,TZ
* T1C0.02
* T2C0.032
* %
* G90
* G05
* M72
* T1
* X1.580Y-1.360
* X1.580Y-4.860
* X8.680Y-1.360
* X8.680Y-4.860
* T2
* X2.930Y-3.560
* X5.280Y-2.535
* X5.405Y-2.610
* X5.620Y-2.900
* T0
* M30
*/
#include "fctsys.h"
#include "common.h"
#include "confirm.h"
#include "gerbview.h"
#include "trigo.h"
#include "macros.h"
#include "class_gerber_draw_item.h"
#include "class_GERBER.h"
#include "class_excellon.h"
#include "kicad_string.h"
#include <math.h>
#include "dialog_load_error.h"
extern int ReadInt( char*& text, bool aSkipSeparator = true );
extern double ReadDouble( char*& text, bool aSkipSeparator = true );
extern void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
APERTURE_T aAperture,
int Dcode_index,
int aLayer,
const wxPoint& aPos,
wxSize aSize,
bool aLayerNegative );
void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
int Dcode_index,
int aLayer,
const wxPoint& aStart,
const wxPoint& aEnd,
wxSize aPenSize,
bool aLayerNegative );
static EXCELLON_CMD excellonHeaderCmdList[] =
{
{ "M0", DRILL_M_END, -1 }, // End of Program - No Rewind
{ "M00", DRILL_M_END, -1 }, // End of Program - No Rewind
{ "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)
{ "M48", DRILL_M_HEADER, 0 }, // beginning of a header
{ "M95", DRILL_M_ENDHEADER, 0 }, // End of the header
{ "METRIC", DRILL_METRICHEADER, 1 },
{ "INCH", DRILL_IMPERIALHEADER, 1 },
{ "M71", DRILL_M_METRIC, 1 },
{ "M72", DRILL_M_IMPERIAL, 1 },
{ "M25", DRILL_M_BEGINPATTERN, 0 }, // Beginning of Pattern
{ "M01", DRILL_M_ENDPATTERN, 0 }, // End of Pattern
{ "M97", DRILL_M_CANNEDTEXT, -1 },
{ "M98", DRILL_M_CANNEDTEXT, -1 },
{ "DETECT", DRILL_DETECT_BROKEN, -1 },
{ "ICI", DRILL_INCREMENTALHEADER, 1 },
{ "FMAT", DRILL_FMT, 1 }, // Use Format command
{ "ATC", DRILL_AUTOMATIC_TOOL_CHANGE, 0 },
{ "TCST", DRILL_TOOL_CHANGE_STOP, 0 }, // Tool Change Stop
{ "AFS", DRILL_AUTOMATIC_SPEED }, // Automatic Feeds and Speeds
{ "VER", DRILL_AXIS_VERSION, 1 }, // Selection of X and Y Axis Version
{ "R", DRILL_RESET_CMD, -1 }, // Reset commands
{ "%", DRILL_REWIND_STOP, -1 }, // Rewind stop. End of the header
{ "/", DRILL_SKIP, -1 }, // Clear Tool Linking. End of the header
// Keep this item after all commands starting by 'T':
{ "T", DRILL_TOOL_INFORMATION, 0 }, // Tool Information
{ "", DRILL_M_UNKNOWN, 0 } // last item in list
};
static EXCELLON_CMD excellon_G_CmdList[] =
{
{ "G90", DRILL_G_ABSOLUTE, 0 }, // Absolute Mode
{ "G91", DRILL_G_INCREMENTAL, 0 }, // Incremental Input Mode
{ "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
{ "G93", DRILL_G_ZERO_SET, 1 }, // Zero Set (XnnYmm and coordintes origin)
{ "", DRILL_G_UNKNOWN, 0 }, // last item in list
};
/*
* Read a EXCELLON file.
* Gerber classes are used because there is likeness between Gerber files
* and Excellon files
* DCode can easily store T code (tool size) as round (or oval) shape
* Drill commands are similar to flashed gerber items
* Routing commands are similar to Gerber polygons
* coordinates have the same format as Gerber.
*/
bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName )
{
wxString msg;
int layer = getActiveLayer(); // current layer used in gerbview
if( g_GERBER_List[layer] == NULL )
{
g_GERBER_List[layer] = new EXCELLON_IMAGE( this, layer );
}
EXCELLON_IMAGE* drill_Layer = (EXCELLON_IMAGE*) g_GERBER_List[layer];
ClearMessageList();
/* Read the gerber file */
FILE * file = wxFopen( aFullFileName, wxT( "rt" ) );
if( file == NULL )
{
msg.Printf( _( "File %s not found" ), GetChars( aFullFileName ) );
DisplayError( this, msg, 10 );
return false;
}
wxString path = wxPathOnly( aFullFileName );
if( path != wxEmptyString )
wxSetWorkingDirectory( path );
bool success = drill_Layer->Read_EXCELLON_File( file, aFullFileName );
// Display errors list
if( m_Messages.size() > 0 )
{
DIALOG_LOAD_ERROR dlg( this );
dlg.ListSet( m_Messages );
dlg.ShowModal();
}
return success;
}
bool EXCELLON_IMAGE::Read_EXCELLON_File( FILE * aFile,
const wxString & aFullFileName )
{
/* Set the gerber scale: */
ResetDefaultValues();
m_FileName = aFullFileName;
m_Current_File = aFile;
SetLocaleTo_C_standard();
// FILE_LINE_READER will close the file.
if( m_Current_File == NULL )
{
wxMessageBox( wxT("NULL!"), m_FileName );
return false;
}
FILE_LINE_READER excellonReader( m_Current_File, m_FileName );
while( true )
{
if( excellonReader.ReadLine() == 0 )
break;
char* line = excellonReader.Line();
char* text = StrPurge( line );
if( *text == ';' ) // comment: skip line
continue;
if( m_State == EXCELLON_IMAGE::READ_HEADER_STATE )
{
Execute_HEADER_Command( text );
}
else
{
switch( *text )
{
case 'M':
Execute_HEADER_Command( text );
break;
case 'G': /* Line type Gxx : command */
Execute_EXCELLON_G_Command( text );
break;
case 'X':
case 'Y': // command like X12550Y19250
Execute_Drill_Command(text);
break;
case 'I':
case 'J': /* Auxiliary Move command */
m_IJPos = ReadIJCoord( text );
if( *text == '*' ) // command like X35142Y15945J504*
{
Execute_Drill_Command( text);
}
break;
case 'T': // Tool command
Select_Tool( text );
break;
case '%':
break;
default:
{
wxString msg;
msg.Printf( wxT( "Unexpected symbol &lt;%c&gt;" ), *text );
if( GetParent() )
GetParent()->ReportMessage( msg );
}
break;
} // End switch
}
}
SetLocaleTo_Default();
return true;
}
bool EXCELLON_IMAGE::Execute_HEADER_Command( char*& text )
{
EXCELLON_CMD* cmd = NULL;
int iprm;
double dprm;
D_CODE* dcode;
wxString msg;
// Search command in list
EXCELLON_CMD* candidate;
for( unsigned ii = 0; ; ii++ )
{
candidate = &excellonHeaderCmdList[ii];
int len = candidate->m_Name.size();
if( len == 0 ) // End of list reached
break;
if( candidate->m_Name.compare( 0, len, text, len ) == 0 ) // found.
{
cmd = candidate;
text += len;
break;
}
}
if( !cmd )
{
msg.Printf( wxT( "Unknown Excellon command &lt;%s&gt;" ), text );
ReportMessage( msg );
while( *text )
text++;
return false;
}
// Execute command
// some do nothing
switch( cmd->m_Code )
{
case DRILL_SKIP:
case DRILL_M_UNKNOWN:
break;
case DRILL_M_END:
break;
case DRILL_M_ENDREWIND:
break;
case DRILL_M_MESSAGE:
break;
case DRILL_M_LONGMESSAGE:
break;
case DRILL_M_HEADER:
m_State = READ_HEADER_STATE;
break;
case DRILL_M_ENDHEADER:
m_State = READ_PROGRAM_STATE;
break;
case DRILL_REWIND_STOP: // TODO: what this command really is ?
m_State = READ_PROGRAM_STATE;
break;
case DRILL_M_METRIC:
SelectUnits( true );
break;
case DRILL_METRICHEADER: // command like METRIC,TZ or METRIC,LZ
SelectUnits( true );
if( *text != ',' )
{
ReportMessage( _( "METRIC command has no parameter" ) );
break;
}
text++; // skip separator
if( *text == 'T' )
m_NoTrailingZeros = false;
else
m_NoTrailingZeros = true;
break;
case DRILL_M_IMPERIAL:
SelectUnits( false );
break;
case DRILL_IMPERIALHEADER: // command like INCH,TZ or INCH,LZ
SelectUnits( false );
if( *text != ',' )
{
ReportMessage( _( "INCH command has no parameter" ) );
break;
}
text++; // skip separator
if( *text == 'T' )
m_NoTrailingZeros = false;
else
m_NoTrailingZeros = true;
break;
case DRILL_M_BEGINPATTERN:
break;
case DRILL_M_ENDPATTERN:
break;
case DRILL_M_CANNEDTEXT:
break;
case DRILL_M_TIPCHECK:
break;
case DRILL_DETECT_BROKEN:
break;
case DRILL_INCREMENTALHEADER:
m_Relative = true;
break;
case DRILL_TOOL_CHANGE_STOP:
break;
case DRILL_AUTOMATIC_SPEED:
break;
case DRILL_AXIS_VERSION:
break;
case DRILL_RESET_CMD:
break;
case DRILL_AUTOMATIC_TOOL_CHANGE:
break;
case DRILL_FMT:
break;
case DRILL_TOOL_INFORMATION:
// Read a tool definition like T1C0.02:
// Read tool number:
iprm = ReadInt( text, false );
// Read tool shape
if( *text != 'C' )
ReportMessage( _( "Tool definition <%c> not supported" ) );
if( *text )
text++;
//read tool diameter:
dprm = ReadDouble( text, false );
m_Has_DCode = true;
// Initialize Dcode to handle this Tool
dcode = GetDCODE( iprm + FIRST_DCODE ); // Remember: dcodes are >= FIRST_DCODE
if( dcode == NULL )
break;
double conv_scale = m_GerbMetric ? PCB_INTERNAL_UNIT / 25.4 : PCB_INTERNAL_UNIT;
dcode->m_Size.x = dcode->m_Size.y = wxRound( dprm * conv_scale );
dcode->m_Shape = APT_CIRCLE;
break;
}
while( *text )
text++;
return true;
}
bool EXCELLON_IMAGE::Execute_Drill_Command( char*& text )
{
D_CODE* tool;
GERBER_DRAW_ITEM * gbritem;
while( true )
{
switch( *text )
{
case 'X':
ReadXYCoord( text );
break;
case 'Y':
ReadXYCoord( text );
break;
case 'G': // G85 is found here for oval holes
m_PreviousPos = m_CurrentPos;
Execute_EXCELLON_G_Command( text );
break;
case 0: // E.O.L: execute command
tool = GetDCODE( m_Current_Tool, false );
if( !tool )
{
wxString msg;
msg.Printf( _( "Tool <%d> not defined" ), m_Current_Tool );
ReportMessage( msg );
return false;
}
gbritem = new GERBER_DRAW_ITEM( GetParent()->GetBoard(), this );
GetParent()->GetBoard()->m_Drawings.Append( gbritem );
if( m_SlotOn ) // Oval hole
{
fillLineGBRITEM( gbritem,
tool->m_Num_Dcode, GetParent()->getActiveLayer(),
m_PreviousPos, m_CurrentPos,
tool->m_Size, false );
}
else
{
fillFlashedGBRITEM( gbritem, tool->m_Shape,
tool->m_Num_Dcode, GetParent()->getActiveLayer(),
m_CurrentPos,
tool->m_Size, false );
}
StepAndRepeatItem( *gbritem );
m_PreviousPos = m_CurrentPos;
return true;
break;
default:
text++;
break;
}
}
return true;
}
bool EXCELLON_IMAGE::Select_Tool( char*& text )
{
int tool_id = ReturnTCodeNumber( text );
if( tool_id >= 0 )
{
tool_id += FIRST_DCODE; // Remember: dcodes are >= FIRST_DCODE
if( tool_id > (TOOLS_MAX_COUNT - 1) )
tool_id = TOOLS_MAX_COUNT - 1;
m_Current_Tool = tool_id;
D_CODE* pt_Dcode = GetDCODE( tool_id , false );
if( pt_Dcode )
pt_Dcode->m_InUse = true;
}
while( *text )
text++;
return tool_id >= 0;
}
bool EXCELLON_IMAGE::Execute_EXCELLON_G_Command( char*& text )
{
EXCELLON_CMD* cmd = NULL;
bool success = false;
int id = DRILL_G_UNKNOWN;
// Search command in list
EXCELLON_CMD* candidate;
char * gcmd = text; // gcmd points the G command, for error messages.
for( unsigned ii = 0; ; ii++ )
{
candidate = &excellon_G_CmdList[ii];
int len = candidate->m_Name.size();
if( len == 0 ) // End of list reached
break;
if( candidate->m_Name.compare( 0, len, text, len ) == 0 ) // found.
{
cmd = candidate;
text += len;
success = true;
id = cmd->m_Code;
break;
}
}
switch( id )
{
case DRILL_G_ZERO_SET:
ReadXYCoord( text );
m_Offset = m_CurrentPos;
break;
case DRILL_G_ROUT:
m_SlotOn = false;
m_PolygonFillMode = true;
break;
case DRILL_G_DRILL:
m_SlotOn = false;
m_PolygonFillMode = false;
break;
case DRILL_G_SLOT:
m_SlotOn = true;
break;
case DRILL_G_LINEARMOVE:
m_Iterpolation = GERB_INTERPOL_LINEAR_1X;
break;
case DRILL_G_CWMOVE:
m_Iterpolation = GERB_INTERPOL_ARC_NEG;
break;
case DRILL_G_CCWMOVE:
m_Iterpolation = GERB_INTERPOL_ARC_POS;
break;
case DRILL_G_ABSOLUTE:
m_Relative = false; // false = absolute coord
break;
case DRILL_G_INCREMENTAL:
m_Relative = true; // true = relative coord
break;
case DRILL_G_UNKNOWN:
default:
{
wxString msg;
msg.Printf( _( "Unknown Excellon G Code: &lt;%s&gt;" ), GetChars(FROM_UTF8(gcmd)) );
ReportMessage( msg );
while( *text )
text++;
return false;
}
}
return success;
}
void EXCELLON_IMAGE::SelectUnits( bool aMetric )
{
/* Inches: Default fmt = 2.4 for X and Y axis: 6 digits with 0.0001 resolution (00.0000)
* metric: Default fmt = 3.2 for X and Y axis: 5 digits, 1 micron resolution (00.000)
*/
if( aMetric )
{
m_GerbMetric = true;
m_FmtScale.x = m_FmtScale.y = 3; // number of digits in mantissa: here 2
m_FmtLen.x = m_FmtLen.y = 5; // number of digits: here 3+2
}
else
{
m_GerbMetric = false;
m_FmtScale.x = m_FmtScale.y = 4; // number of digits in mantissa: here 4
m_FmtLen.x = m_FmtLen.y = 6; // number of digits: here 2+4
}
}

View File

@ -73,7 +73,8 @@ clear an existing layer to load any new layers." ), NB_LAYERS );
break;
case ID_GERBVIEW_LOAD_DRILL_FILE:
DisplayError( this, _( "Not yet available..." ) );
LoadExcellonFiles( wxEmptyString );
DrawPanel->Refresh();
break;
case ID_GERBVIEW_LOAD_DCODE_FILE:
@ -195,6 +196,88 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFullFileName )
return true;
}
bool GERBVIEW_FRAME::LoadExcellonFiles( const wxString& aFullFileName )
{
wxString filetypes;
wxArrayString filenamesList;
wxFileName filename = aFullFileName;
wxString currentPath;
if( !filename.IsOk() )
{
filetypes = _( "Drill files (.drl)" );
filetypes << wxT("|");
filetypes += wxT(";*.drl;*.DRL" );
filetypes << wxT("|");
/* All filetypes */
filetypes += AllFilesWildcard;
/* Use the current working directory if the file name path does not exist. */
if( filename.DirExists() )
currentPath = filename.GetPath();
else
currentPath = wxGetCwd();
wxFileDialog dlg( this,
_( "Open Drill File" ),
currentPath,
filename.GetFullName(),
filetypes,
wxFD_OPEN | wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE | wxFD_CHANGE_DIR );
if( dlg.ShowModal() == wxID_CANCEL )
return false;
dlg.GetPaths( filenamesList );
currentPath = wxGetCwd();
}
else
{
wxFileName filename = aFullFileName;
filenamesList.Add( aFullFileName );
currentPath = filename.GetPath();
}
// Read gerber files: each file is loaded on a new gerbview layer
int layer = getActiveLayer();
for( unsigned ii = 0; ii < filenamesList.GetCount(); ii++ )
{
wxFileName filename = filenamesList[ii];
if( !filename.IsAbsolute() )
filename.SetPath( currentPath );
GetScreen()->SetFileName( filename.GetFullPath() );
setActiveLayer( layer, false );
if( Read_EXCELLON_File( filename.GetFullPath() ) )
{
layer = getNextAvailableLayer( layer );
if( layer == NO_AVAILABLE_LAYERS )
{
wxString msg = wxT( "No more empty layers are available. The remaining gerber " );
msg += wxT( "files will not be loaded." );
wxMessageBox( msg );
break;
}
setActiveLayer( layer, false );
}
}
Zoom_Automatique( false );
g_SaveTime = time( NULL );
// Synchronize layers tools with actual active layer:
setActiveLayer( getActiveLayer() );
syncLayerBox();
return true;
}
/*
* Read a DCode file (not used with RX274X files , just with RS274D old files).

View File

@ -407,6 +407,17 @@ public: GERBVIEW_FRAME( wxWindow* father, const wxString& title,
bool Read_GERBER_File( const wxString& GERBER_FullFileName,
const wxString& D_Code_FullFileName );
/**
* function LoadDrllFiles
* Load a drill (EXCELLON) file or many files.
* @param aFileName - void string or file name with full path to open or empty string to
* open a new file. In this case one one file is loaded
* if void string: user will be prompted for filename(s)
* @return true if file was opened successfully.
*/
bool LoadExcellonFiles( const wxString& aFileName );
bool Read_EXCELLON_File( const wxString& aFullFileName );
void GeneralControl( wxDC* aDC, const wxPoint& aPosition, int aHotKey = 0 );
/**

View File

@ -39,10 +39,9 @@ void GERBVIEW_FRAME::ReCreateMenuBar( void )
filesMenu->Append( ID_GERBVIEW_LOAD_DCODE_FILE, _( "Load DCodes" ),
_( "Load D-Codes File" ), FALSE );
#if 0 // TODO
filesMenu->Append( ID_GERBVIEW_LOAD_DRILL_FILE, _( "Load EXCELLON Drill File" ),
_( "Load excellon drill file" ), FALSE );
#endif
filesMenu->Append( ID_NEW_BOARD, _( "&Clear All" ),
_( "Clear all layers. All data will be deleted" ), FALSE );

View File

@ -85,7 +85,7 @@
* @param aSize The diameter of the round flash
* @param aLayerNegative = true if the current layer is negative
*/
static void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
APERTURE_T aAperture,
int Dcode_index,
int aLayer,
@ -138,7 +138,7 @@ static void fillFlashedGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
* @param aPenSize The size of the flash. Note rectangular shapes are legal.
* @param aLayerNegative = true if the current layer is negative
*/
static void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
void fillLineGBRITEM( GERBER_DRAW_ITEM* aGbrItem,
int Dcode_index,
int aLayer,
const wxPoint& aStart,
@ -725,10 +725,6 @@ bool GERBER_IMAGE::Execute_DCODE_Command( char*& text, int D_commande )
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;
@ -743,9 +739,6 @@ bool GERBER_IMAGE::Execute_DCODE_Command( char*& text, int D_commande )
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, GetLayerParams().m_LayerNegative );