\n"
"Run ULP on board file to import Gerber data.
"
"Version: 0.1 - Development Started
"
"Version: 0.2 - Add functionality, improved performance. - 9-20-15
"
"Version: 0.3 - Performance, functionality for layer selection. - 9-27-15
"
"Version: 0.4 - Performance improvement. Changed to += - 10-5-15
"
"Version: 0.5 - Add param handling to macros. Load .scr file when generated. Updates to extension to layer mappings - 10-26-15
"
"Version: 0.6 - Updates to polygon aperture wire draw - 10-28-15
"
"Version: 0.7 - Updates to improve usability - 11-2-15
"
"Version: 0.8 - Additional tweaks - 11-4-15
"
"Version: 0.9 - Handle apertures like D0XX and convert to DXX. - 11-13-15
"
"Version: 0.10 - Added help dialog - 11-16-15
"
"
"
""
"UI Element | Description. |
"
" | Select button used to pick the Gerber file to import. Once a file is selected it will be automatically loaded. |
"
" | Import button used to import the Gerber into EAGLE. Once clicked the data points will be used to generate the EAGLE wire commands to represent the board in EAGLE. |
"
" | Load process indicator is used to show the progress on loading the Gerber file. Gerber files can often be very large and there is a lot of text processing going on. This indicatory shows you the current status. |
"
" | File Attributes shows the units, format specification, and parsed format specification values the ULP is using. |
"
" | Import Layer is the EAGLE layer the Gerber commands will be loaded to. The ULP looks at the Gerber file extension and tries to make common extensions to the proper EAGLE layer. You can override the value selected by updating this value. |
"
" | The lower portion of the File Attributes includes additional settings that can be used to import and debug the ULP."
"- Write to SCR: This option writes the EAGLE commands to a file that can be saved or loaded separately. For very large Gerber files its recommended you write the wire commands to a SCR file for better performance.
"
"- Debug Mode: This option writes a debug mode that can be used by support to troubleshoot import issues. Normally this option is disabled as it will impact the performance of the ULP when enabled.
"
"- Thin Wire Mode: This mode uses 0.0 width wires for aperture draws. This mode is recommended to be enabled for most Gerber files.
"
"- Run Ulp Again: This will cause the ULP to run automatically after importing a file. This option is useful for loading multiple Gerber files into a single EAGLE board file.
"
" |
"
" | Aperture Definitions and Macros are parsed from the Gerber file and displayed in these tables. Reviewing these can be helpful if your Apertures are not being shown as expected. |
"
" | Processing Messages displays warnings of data in the Gerber which could not be properly rendered in EAGLE. The Gerber specification is designed to be used by light plotters to draw the board surface. Some elements of the Gerber file cannot be replicated in EAGLE and when the ULP encounters these situations it logs a message here so you are aware of any deviations from the Gerber file. |
"
"
";
//global UI parametes
string LogView = ""; //holds logging messages from gerber load
string Progress = "Select file to Import"; //shows load and import progress bars
string Layers[]; //holds list of layers in board
string LayerMap[]; //file name to layers mapping
int DoImport = false; //used to run import but not actually trigger import
int WriteCommandsToFile = false;
int WriteCommandThreshold = 1000000; //if gerber file has more than this many lines it will force to file
string CommandString = "";
int EAGLELayerSelection = -1; //used to set selected layer to import to based on gerber file extension
int FileLoaded = false;
int UseThinMode = true;
int RunUlpAgain = true;
enum{ INCH, MM }
string UnitsString[] = { "Inch", "MM" };
int Units;
//string UnitsString = "";
string CoordFormat;
enum{ multi, single }
int QuadMode = multi;
string QuadModeString[] = { "Multi", "Single" };
//op codes
int OpCodeCounter = 0;
string OpCodes[];
real CurrentX = 0.0;
real CurrentY = 0.0;
real CurrentI = 0.0;
real CurrentJ = 0.0;
//format spec
int XIntegerSize = 0;
int XDecimalSize = 0;
int YIntegerSize = 0;
int YDecimalSize = 0;
enum{ zeroOmmLeading, zeroOmmTrailing }
enum{ absNotation, incNotation }
int ZeroOmmission = zeroOmmLeading;
int ValueNotation = absNotation;
string ZeroOmmissionString[] = { "Zero Leading", "Zero Trailing" };
string ValueNotationString[] = { "Absolute", "Incremental" };
//aperture definitions and macros
string ApertureDefs[];
string ApertureMacros[];
int ApDefCounter = 0;
int ApMacCounter = 0;
//init aperture arrays with headers
ApertureDefs[ ApDefCounter ] = "id\tdefinition";
ApDefCounter++;
ApertureMacros[ ApMacCounter ] = "id\tmacro";
ApMacCounter++;
string CurrentAperture = "";
//comments
string Comments[];
int CommentCounter = 0;
//attributes
string Attributes[];
int AttributeCounter = 0;
//processing exceptions
string ParseExceptions[]; //Line\tException messsage
int ParseExcepCounter = 0;
ParseExceptions[ ParseExcepCounter ] = "Id\tException Message";
ParseExcepCounter++;
int HasFillCommand = false;
int SignalCount = 0;
//******************* general utils *******************//
string itos(int num) {
string temp;
sprintf(temp, "%d", num);
return temp;
}
string rtos(real num) {
string temp;
sprintf(temp, "%f", num);
return temp;
}
string GetStartDir(){
string dir = cfgget("ulp.gerberimport.startdir", UlpPath);
return dir;
}
void SaveStartDir( string fileName ){
cfgset("ulp.gerberimport.startdir", filedir( fileName ) );
}
//******************* gerber utils *******************//
void AddLogMessage( string msg ){
if( DebugMode ){
LogView += msg + "\n";
}
}
void WriteLog(){
if( DebugMode ){
output( UlpPath + "log.txt", "wt") {
printf( LogView );
}
}
}
void ResetLogMessage(){
LogView = "";
}
void ResetExceptions(){
for( int i = 0; i < ParseExcepCounter; i++ ){
ParseExceptions[ i ] = "";
}
ParseExcepCounter = 0;
ParseExceptions[ ParseExcepCounter ] = "Id\tException Message";
ParseExcepCounter++;
} //end func
void ResetApertures(){
//reset defs
for( int i = 0; i < ApDefCounter; i++ ){
ApertureDefs[ i ] = "";
}
ApDefCounter = 0;
ApertureDefs[ ApDefCounter ] = "id\tdefinition";
ApDefCounter++;
//reset macs
for( i = 0; i < ApMacCounter; i++ ){
ApertureMacros[ i ] = "";
}
ApMacCounter = 0;
ApertureMacros[ ApMacCounter ] = "id\tmacro";
ApMacCounter++;
} //end func
void ResetOpCodes(){
for( int i = 0; i < OpCodeCounter; i++ ){
OpCodes[ i ] = "";
}
OpCodeCounter = 0;
} //end func
void AddException( string msg ){
ParseExceptions[ ParseExcepCounter ] = itos( ParseExcepCounter ) + "\t" + msg;
ParseExcepCounter++;
} //end func
string GetExceptionMsgs(){
string msg;
for( int i = 0; i < ParseExcepCounter; i++ ){
msg = msg + ParseExceptions[ i ] + "\n";
}
return msg;
}
string GetProgressBar( int numLines, int currentLine, string msg ){
if( currentLine == 0 ){
currentLine = 1;
}
int percent = (currentLine * 100) / numLines;
int scalePer = percent / 5; //25 -> 5, 50 -> 10, 75 -> 15, etc
string scaleStr = "";
for( int i = 0; i < 20; i++ ){
if( i < scalePer ){
scaleStr = scaleStr + "*";
}
else{
scaleStr = scaleStr + " ";
} //end if-else
} //end for
return itos( percent ) + "% [" + scaleStr + "] " + msg;
}
string RemoveNegatives(string dirtyString) {
string cleanedString;
for (int i = 0; dirtyString[i]; ++i) {
if (dirtyString[i] == '-') {
cleanedString += "";
}
else {
cleanedString += dirtyString[i];
} //end if-else
} //end for
return cleanedString;
} //end sub
string ReplaceString( string dirtyString, string stringToReplace, string newString ){
int index = strstr( dirtyString, stringToReplace );
int replaceLen = strlen( stringToReplace );
if( index >= 0 ){
string front = strsub( dirtyString, 0, index );
string back = strsub( dirtyString, index+replaceLen, strlen( dirtyString ) - index - replaceLen );
//dlgMessageBox( dirtyString + ":" + front + back );
return front + newString + back;
}
else{
return dirtyString;
} //end if-else
} //end func
string RemoveG54( string dirtyString ){
int index = strstr( dirtyString, "G54" );
if( index >= 0 ){
string front = strsub( dirtyString, 0, index );
string back = strsub( dirtyString, index+3, strlen( dirtyString ) - index - 3 );
dlgMessageBox( dirtyString + ":" + front + back );
return front + back;
}
else{
return dirtyString;
} //end if-else
} //end sub
int MapFileNameToLayer( string fileName ){
/*
*.cmp Top, Via, Pad……………Component side
*.ly2 Route2, Via, Pad……….Inner signal layer
*.ly3 Route3, Via, Pad……….Inner signal layer
*.sol Bot, Via, Pad……………Solder side
*.plc tPl, Dim, tName,…….….Silkscreen component side
*.pls bPl, Dim, bName,………Silkscreen solder side
*.stc tStop ………………….…Solder stop mask component side
*.sts bStop …………………...Solder stop mask solder side
*.drd Drills, Holes…………….Drill data for NC drill
.cmp cmp is component side copper (TOP)
.sec .Sol (Solder Side)
.smc .Stc (Solder Stop Mask, Top Side)
.sms .Sts (Solder Stop Mask, Bottom Side)
.ssc .plc (Component Side Silk Data)
.sss .pls (Solder Side Silk Data)
.drl .Drl (Excellon Tool List)
.drd Drd. (Excellon NC Drill file)
.dri Dri. (Drill Station Info File)
.gpi gpi is gerber plot information
.brd brd is eagle board fiel, cad tool (eagle native file format)
*/
string layerName = "Top";
int layerIndex = -1;
int foundMatch = true;
//convert file name to all lower case
fileName = strlwr( fileName );
if( strxstr( fileName, "\.cmp" ) >= 0 ){
layerName = "Top";
}
else if( strxstr( fileName, "\.ly2" ) >= 0 ){
layerName = "Layer2";
}
else if( strxstr( fileName, "\.ly3" ) >= 0 ){
layerName = "Layer3";
}
else if( strxstr( fileName, "\.l15" ) >= 0 ){
layerName = "Pads";
}
else if( strxstr( fileName, "\.crc" ) >= 0 ){
layerName = "tCream";
}
else if( strxstr( fileName, "\.crs" ) >= 0 ){
layerName = "bCream";
}
else if( strxstr( fileName, "\.mil" ) >= 0 ){
layerName = "Milling";
}
else if( strxstr( fileName, "\.dim" ) >= 0 ){
layerName = "Dimension";
}
else if( strxstr( fileName, "\.fic" ) >= 0 ){
layerName = "tFinish";
}
else if( strxstr( fileName, "\.fis" ) >= 0 ){
layerName = "bFinish";
}
else if( strxstr( fileName, "\.glc" ) >= 0 ){
layerName = "tGlue";
}
else if( strxstr( fileName, "\.gls" ) >= 0 ){
layerName = "bGlue";
}
else if( strxstr( fileName, "\.sol" ) >= 0 || strxstr( fileName, "\.sec" ) >= 0 ){
layerName = "Bottom";
}
else if( strxstr( fileName, "\.plc" ) >= 0 || strxstr( fileName, "\.ssc" ) >= 0 ){
layerName = "tPlace";
}
else if( strxstr( fileName, "\.pls" ) >= 0 || strxstr( fileName, "\.sss" ) >= 0 ){
layerName = "bPlace";
}
else if( strxstr( fileName, "\.stc" ) >= 0 || strxstr( fileName, "\.smc" ) >= 0 ){
layerName = "tStop";
}
else if( strxstr( fileName, "\.sts" ) >= 0 || strxstr( fileName, "\.sms" ) >= 0 ){
layerName = "bStop";
}
else if( strxstr( fileName, "\.drd" ) >= 0 ){
layerName = "Drills";
}
else if( strxstr( fileName, "\.hol" ) >= 0 ){
layerName = "Holes";
}
else{
foundMatch = false;
}
//find match in layer list
int layerCount = 0;
board(B){
B.layers(L){
if( L.name == layerName ){
layerIndex = layerCount;
}
layerCount++;
} //layers loop
} //board loop
if( foundMatch ){
dlgMessageBox( "Recommended layer '" + layerName + "' has been selected based on file extension. Change the Layer dropdown if you want to import to another layer." );
}
else{
dlgMessageBox( "No match found for file extension of Gerber file. Layer defaulted to Top. Change the Layer dropdown if you want to import to another layer." );
} //end if-else
return layerIndex;
} //end func
//******************* gerber functions *******************//
void WriteCommands( string command ){
//command path
string file = UlpPath + "commands_" + itos( EAGLELayerSelection ) + ".scr";
//check if in simluate mode
if( DoImport ){
//check if commands have been written yet. if not then force creation of new file
if( CommandString == "" && WriteCommandsToFile ){
output( file, "wt") {
//dlgMessageBox( "Writing command file to " + file );
} //end output
} //end if
if( WriteCommandsToFile ){
//open file and write command
output( file, "at") {
printf( command );
} //end output
//init command string so that the init file is not run each time
if( CommandString == "" ){
CommandString = "TOFILE";
} //end if
}
else{
//append to string
CommandString += command;
} //end if-else
}
else{
//if false then do nothing
} //end if-else
} //end func
//******************* aperture def wire width functions *******************//
string CircleApertureWireWidth( string aperture ){
//%ADD10C,.025*% - Circle, 0.025 diameter
// 0123456
int firstCommaInd = strstr( aperture, "," );
int xFound = strstr( aperture, "X" );
string changeWidth = "";
//check if circle aperture has x which means its complex
if( xFound >= 0 ){
//%ADD23C,.100X.050X.050*% - (c) 0.10 dia circle with 0.05 square hole on d23.
//C,.100X.050X.050*%
//012345678901234567
AddException( "Complex circle aperture found. Using diameter for width." );
//trim off complex part
aperture = strsub( aperture, 0, xFound );
}
changeWidth = strsub( aperture, (firstCommaInd+1), strlen( aperture ) - firstCommaInd );
changeWidth = "CHANGE WIDTH " + changeWidth + ";\n";
return changeWidth;
}
string RectApertureWireWidth( string aperture ){
//%ADD10R,.050x.050x.027*% - Rectangle, 0.05x0.05 sides with 0.027 round hole
int firstCommaInd = strstr( aperture, "," );
int xFound = strstr( aperture, "X" );
string changeWidth = "";
//check if circle aperture has x which means its complex
if( xFound >= 0 ){
//%ADD10R,.050x.050x.027*%
//R,.050x.050x.027*%
//012345678901234567
AddException( "Complex rectangle aperture found. Setting wire width to width of rectangle." );
//trim off complex part
aperture = strsub( aperture, 0, xFound );
}
changeWidth = strsub( aperture, (firstCommaInd+1), strlen( aperture ) - firstCommaInd );
changeWidth = "CHANGE WIDTH " + changeWidth + ";\n";
return changeWidth;
}
string OBroundApertureWireWidth( string aperture ){
//%ADD10O,.030x.040x.015*% - obround with 0.03x0.04 with 0.015 dia hole
int firstCommaInd = strstr( aperture, "," );
int xFound = strstr( aperture, "X" );
string changeWidth = "";
//check if circle aperture has x which means its complex
if( xFound >= 0 ){
//%ADD10R,.050x.050x.027*%
//R,.050x.050x.027*%
//012345678901234567
AddException( "Complex obround aperture found. Unable to render. Setting to circle." );
//trim off complex part
aperture = strsub( aperture, 0, xFound );
}
changeWidth = strsub( aperture, (firstCommaInd+1), strlen( aperture ) - firstCommaInd );
changeWidth = "CHANGE WIDTH " + changeWidth + ";\n";
return changeWidth;
}
string PolygonApertureWireWidth( string aperture ){
//%ADD10P,.016X6*% - 6 vertex polygon with 0.016 outer dia
int firstCommaInd = strstr( aperture, "," );
int xFound = strstr( aperture, "X" );
string changeWidth = "";
//check if circle aperture has x which means its complex
if( xFound >= 0 ){
//%ADD10R,.050x.050x.027*%
//R,.050x.050x.027*%
//012345678901234567
AddException( "Complex polygon aperture found. Unable to render for D01/02 operations. Setting aperture to circle." );
//trim off complex part
aperture = strsub( aperture, 0, xFound );
}
changeWidth = strsub( aperture, (firstCommaInd+1), strlen( aperture ) - firstCommaInd );
changeWidth = "CHANGE WIDTH " + changeWidth + ";\n";
return changeWidth;
}
string GetWireWidth( string aperture ){
//get aperture def from lookup
string definition = lookup( ApertureDefs, aperture, "definition" );
//TODO - If AD points to AM then you need to do lookup on ApertureMacros to get diameter?
if( definition == "" ){
AddException( "Unknown aperture '" + aperture + "' provided. Unable to map. No wire width set." );
return "";
}
/*
%ADD10C,.025*% - Circle, 0.025 diameter
%ADD10R,.050x.050x.027*% - Rectangle, 0.05x0.05 sides with 0.027 round hole
%ADD10O,.030x.040x.015*% - obround with 0.03x0.04 with 0.015 dia hole
%ADD10P,.016X6*% - 6 vertex polygon with 0.016 outer dia
%ADD15CIRC*5 - refers back to AM CIRC
0123456789
*/
//get type of def
string defType = strsub( definition, 0, 1 );
string defType2 = strsub( definition, 1, 1 );
int firstCommaInd = strstr( definition, "," );
//circle vars
string changeWire;
if( defType == "C" && defType2 == "," ){
changeWire = CircleApertureWireWidth( definition );
}
else if( defType == "R" && defType2 == "," ){
changeWire = RectApertureWireWidth( definition );
}
else if( defType == "O" && defType2 == "," ){
changeWire = OBroundApertureWireWidth( definition );
}
else if( defType == "P" && defType2 == "," ){
changeWire = PolygonApertureWireWidth( definition );
}
else{
//dlgMessageBox( defType );
changeWire = CircleApertureWireWidth( definition );
AddException( "Unknown aperture definition '" + definition + "' found while trying to determine wire width. Drawing as circle for non Flash operations.");
}
return changeWire;
}
//******************* aperture macro functions *******************//
string CircleMacroWires( string macro, real x, real y ){
//%AMCIRCLE*1,1,1.5,0,0*%
///passed in macro=1,1,1.5,0,0
// type = 1
// exposure = 1
// diameter = 1.5
// x = 0
// y = 0
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
string exposure, diaStr, xStr, yStr;
real dia, xPos, yPos;
if( numFields < 5 ){
AddException( "Error parsing circle aperture macro. Less than 4 fields found. Aperture not drawn." );
}
else{
exposure = fields[ 1 ];
diaStr = fields[ 2 ];
xStr = fields[ 3 ];
yStr = fields[ 4 ];
dia = strtod( diaStr );
xPos = strtod( xStr );
yPos = strtod( yStr );
wire = "CIRCLE ( " + rtos( x + xPos ) + " " + rtos( y + yPos ) + " ) ( " + rtos( x + xPos + dia/2 ) + " " + rtos( y + yPos ) + " );\n";
}
return wire;
}
string VectorLineMacroWires( string macro, real x, real y ){
// type
// exposure
// width
// xstart
// ystart
// xend
// yend
// rotation around orgin - not center?
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
string exposure, lineWidthStr, xStartStr, yStartStr, xEndStr, yEndStr, rotStr;
real xStart, yStart, xEnd, yEnd, rotation;
if( numFields < 8 ){
AddException( "Error parsing circle aperture macro. Less than 4 fields found. Aperture not drawn." );
}
else{
exposure = fields[ 1 ];
lineWidthStr = fields[ 2 ];
xStartStr = fields[ 3 ];
yStartStr = fields[ 4 ];
xEndStr = fields[ 5 ];
yEndStr = fields[ 6 ];
rotStr = fields[ 7 ];
xStart = strtod( xStartStr );
yStart = strtod( yStartStr );
xEnd = strtod( xEndStr );
yEnd = strtod( yEndStr );
rotation = strtod( rotStr );
//set wire width
wire = wire + "CHANGE WIDTH " + lineWidthStr + ";\n";
//calc x/y values based on rotation
real rotRadians = rotation / 360 * 2 * PI;
real length = sqrt( pow( xEnd - xStart, 2 ) + pow( yEnd - yStart, 2 ) );
xEnd = cos( rotRadians ) + length + xEnd;
yEnd = sin( rotRadians ) + length + yEnd;
//final wires
wire = wire + "WIRE ( " + rtos( xStart + x ) + " " + rtos( yStart + y ) + " ) ( " + rtos( xEnd + x ) + " " + rtos( yEnd + y ) + ");\n";
} //end if-else
return wire;
}
string CenterLineMacroWires( string macro, real x, real y ){
// type
// exposure
// width
// height
// x center
// y center
// rotation
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
string exposure, lineWidthStr, widthStr, heightStr, xCenterStr, yCenterStr, rotStr;
real width, height, xCenter, yCenter, rotation;
if( numFields < 7 ){
AddException( "Error parsing center line aperture macro. Less than 7 fields found. Aperture not drawn." );
}
else{
exposure = fields[ 1 ];
widthStr = fields[ 2 ];
heightStr = fields[ 3 ];
xCenterStr = fields[ 4 ];
yCenterStr = fields[ 5 ];
rotStr = fields[ 6 ];
width = strtod( widthStr );
height = strtod( heightStr );
xCenter = strtod( xCenterStr );
yCenter = strtod( yCenterStr );
rotation = strtod( rotStr );
//set wire width
wire = wire + "CHANGE WIDTH " + heightStr + ";\n"; //consider height as wire width
//calc start end points to start
real xStart, yStart, xEnd, yEnd;
xStart = xCenter - width/2;
yStart = yCenter;
xEnd = xCenter + width/2;
yEnd = yCenter;
//calc x/y values based on rotation
real rotRadians = rotation / 360 * 2 * PI;
real length = sqrt( pow( xEnd - xStart, 2 ) + pow( yEnd - yStart, 2 ) );
xEnd = cos( rotRadians ) + length;
yEnd = sin( rotRadians ) + length;
//final wires
wire = wire + "WIRE ( " + rtos( xStart + x ) + " " + rtos( yStart + y ) + " ) ( " + rtos( xEnd + x ) + " " + rtos( yEnd + y ) + ");\n";
} //end if-else
return wire;
}
string LowerLeftLineMacroWires( string macro, real x, real y ){
// type
// exposure
// width
// height
// x lower left
// y lower left
// rotation
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
string exposure, lineWidthStr, widthStr, heightStr, xLowerLeftStr, yLowerLeftStr, rotStr;
real width, height, xLowerLeft, yLowerLeft, rotation;
if( numFields < 7 ){
AddException( "Error parsing lower left line aperture macro. Less than 7 fields found. Aperture not drawn." );
}
else{
exposure = fields[ 1 ];
widthStr = fields[ 2 ];
heightStr = fields[ 3 ];
xLowerLeftStr = fields[ 4 ];
yLowerLeftStr = fields[ 5 ];
rotStr = fields[ 6 ];
width = strtod( widthStr );
height = strtod( heightStr );
xLowerLeft = strtod( xLowerLeftStr );
yLowerLeft = strtod( yLowerLeftStr );
rotation = strtod( rotStr );
//set wire width
wire = wire + "CHANGE WIDTH " + heightStr + ";\n"; //consider height as wire width
//calc start end points to start
real xStart, yStart, xEnd, yEnd;
xStart = xLowerLeft;
yStart = yLowerLeft + height/2;
xEnd = xLowerLeft + width;
yEnd = yLowerLeft + height/2;
//calc x/y values based on rotation
real rotRadians = rotation / 360 * 2 * PI;
real length = sqrt( pow( xEnd - xStart, 2 ) + pow( yEnd - yStart, 2 ) );
xEnd = cos( rotRadians ) + length;
yEnd = sin( rotRadians ) + length;
//final wires
wire = wire + "WIRE ( " + rtos( xStart + x ) + " " + rtos( yStart + y ) + " ) ( " + rtos( xEnd + x ) + " " + rtos( yEnd + y ) + ");\n";
} //end if-else
return wire;
}
string OutlineMacroWires( string macro, real x, real y ){
// type - 0
// exposure - 1
// num points - 2
// xn, yn points 3, 4, ....
// rotation - last
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
//determine number of points
int numPoints = strtod( fields[ 2 ] );
//check to makes sure you got all points
if( numFields != ( 4 + ( 2 * numPoints ) + 2 ) ){ //4 points for type, exposure, num points, rotation + ( 2 * num points ) + 2 for start points again
AddException( "Error parsing outine aperture macro. Incorrect number of fields provided. Aperture not drawn." );
}
else{
//TODO: what should wire width be set to?
wire = wire + "WIRE ";
for( int i = 0; i < numPoints; i++ ){
wire = wire + "( " + fields[ i + 3 ] + " " + fields[ i + 4 ] + " ) ";
} //end for
wire = wire + ";\n";
} //end if-else
return wire;
}
string PolygonMacroWires( string macro, real x, real y ){
// type - 0
// exposure - 1
// num verts - 2
// x center - 3
// y center - 4
// dia - 5
// rot - 6
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
string numVertStr, xCenterStr, yCenterStr, diaStr, rotStr;
real numVert, xCenter, yCenter, dia, rot;
int wireCount = 0;
//check to makes sure you got all points
if( numFields < 7 ){
AddException( "Error parsing polygon aperture macro. Incorrect number of fields provided. " + itos( numFields) + " found, expecting 7. Aperture not drawn." );
}
else{
numVert = strtod( fields[ 2 ] );
real degRot = strtod(fields[ 6 ]);
//build wires for polygon
real angleBetweenPoints = ( 2 * PI ) / numVert;
real xPt, yPt, prevX, prevY, startX, startY;
xCenter = strtod( fields[ 3 ] );
yCenter = strtod( fields[ 4 ] );
dia = strtod( fields[ 5 ] );
int inc = 10;
real diaIncrement = dia/inc;
//loop thru diameter increments
for( int k = 0; k < inc; k++ ){
//loop thru vertices in polygon
for( int i = 0; i <= numVert; i++ ){
xPt = cos( i * angleBetweenPoints + ( degRot / 360 * 2*PI ) ) * (dia-k*diaIncrement)/2;
yPt = sin( i * angleBetweenPoints + ( degRot / 360 * 2*PI ) ) * (dia-k*diaIncrement)/2;
//set line width - first line set 0.0, other lines set to width of increment
if( k == 0 ){
//wire += "SET WIDTH 0.0;\n ";
}
else if( k >= 1 ){
wire += "SET WIDTH " + rtos( diaIncrement/2 ) + ";\n ";
//generate wire commands. for first point save start values
if( i == 0 ){
//first point.
startX = xPt + x + xCenter;
startY = yPt + y + yCenter;
}
else if( i == numVert ){
//for final line connect back to start
wire += "WIRE 'S$" + itos( SignalCount ) + "' ( " + rtos( prevX ) + " " + rtos( prevY ) + " ) ( " + rtos( startX ) + " " + rtos( startY ) + ");\n";
SignalCount++;
}
else{
//draw outlines
wire += "WIRE 'S$" + itos( SignalCount ) + "' ( " + rtos( prevX ) + " " + rtos( prevY ) + " ) ( " + rtos( xPt + x + xCenter ) + " " + rtos( yPt + y + yCenter ) + ");\n";
SignalCount++;
} //end if-else on i
} // end if-else on k
prevX = xPt + x + xCenter;
prevY = yPt + y + yCenter;
} //end for i
} //end for k
} //end if-else
return wire;
}
string PolygonMacroWires_polygon( string macro, real x, real y ){
// type - 0
// exposure - 1
// num verts - 2
// x center - 3
// y center - 4
// dia - 5
// rot - 6
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
string numVertStr, xCenterStr, yCenterStr, diaStr, rotStr;
real numVert, xCenter, yCenter, dia, rot;
//check to makes sure you got all points
if( numFields < 7 ){
AddException( "Error parsing polygon aperture macro. Incorrect number of fields provided. " + itos( numFields) + " found, expecting 7. Aperture not drawn." );
}
else{
numVert = strtod( fields[ 2 ] );
real degRot = strtod(fields[ 6 ]);
//build wires for polygon
real angleBetweenPoints = ( 2 * PI ) / numVert;
real xPt, yPt, prevX, prevY;
xCenter = strtod( fields[ 3 ] );
yCenter = strtod( fields[ 4 ] );
dia = strtod( fields[ 5 ] );
real diaIncrement = dia/10;
wire += "SET WIDTH 0.0;\n ";
for( int k = 0; k < 10; k++ ){
wire += "POLYGON ";
//build points for polygone
for( int i = 0; i <= numVert; i++ ){
xPt = cos( i * angleBetweenPoints + ( degRot / 360 * 2*PI ) ) * (dia-k*diaIncrement)/2;
yPt = sin( i * angleBetweenPoints + ( degRot / 360 * 2*PI ) ) * (dia-k*diaIncrement)/2;
wire += " ( " + rtos( xPt + x + xCenter ) + " " + rtos( yPt + y + yCenter ) + " )";
} //end for
wire += ";\n";
} //end k
} //end if-else
return wire;
}
string PolygonMacroWires_polygon_outline( string macro, real x, real y ){
// type - 0
// exposure - 1
// num verts - 2
// x center - 3
// y center - 4
// dia - 5
// rot - 6
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
string numVertStr, xCenterStr, yCenterStr, diaStr, rotStr;
real numVert, xCenter, yCenter, dia, rot;
//check to makes sure you got all points
if( numFields < 7 ){
AddException( "Error parsing polygon aperture macro. Incorrect number of fields provided. " + itos( numFields) + " found, expecting 7. Aperture not drawn." );
}
else{
numVert = strtod( fields[ 2 ] );
real degRot = strtod(fields[ 6 ]);
//build wires for polygon
real angleBetweenPoints = ( 2 * PI ) / numVert;
real xPt, yPt, prevX, prevY;
xCenter = strtod( fields[ 3 ] );
yCenter = strtod( fields[ 4 ] );
dia = strtod( fields[ 5 ] );
//wire += "SET POLYGON_RATSNEST ON;\n";
wire += "POLYGON ";
for( int i = 0; i <= numVert; i++ ){
xPt = cos( i * angleBetweenPoints + ( degRot / 360 * 2*PI ) ) * dia/2;
yPt = sin( i * angleBetweenPoints + ( degRot / 360 * 2*PI ) ) * dia/2;
wire += " ( " + rtos( xPt + x + xCenter ) + " " + rtos( yPt + y + yCenter ) + " )";
} //end for
wire += ";\n";
} //end if-else
return wire;
}
string MoireMacroWires( string macro, real x, real y ){
// type - 0
// x center - 1
// y center - 2
// outer dia - 3
// ring thickness - 4
// ring gap - 5
// max num rings - 6
// cross hair thickness - 7
// cross hair length - 8
// angle - 9
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
int numRings;
real xCenter, yCenter, dia, ringThickness, ringGap, crossHairThickness, crossHairLength, angle;
if( numFields < 10 ){
AddException( "Error parsing moire aperture macro. Incorrect number of fields provided. Aperture not drawn." );
}
else{
//get values
xCenter = strtod( fields[ 1 ] );
yCenter = strtod( fields[ 2 ] );
dia = strtod( fields[ 3 ] ); //used for circles
ringThickness = strtod( fields[ 4 ] );
ringGap = strtod( fields[ 5 ] );
numRings = strtol( fields[ 6 ] );
crossHairThickness = strtod( fields[ 7 ] );
crossHairLength = strtod( fields[ 8 ] );
angle = strtod( fields[ 9 ] );
angle = angle / 360 * 2 * PI; //convert to radians
//draw cirlces
wire = wire + "SET WIDTH " + rtos( ringThickness ) + ";\n";
for( int i = 0; i < numRings; i++ ){
wire = wire + "CIRCLE ( " + rtos( x + xCenter ) + " " + rtos( y + yCenter ) + " ) ( " + rtos( x + xCenter + dia/2 ) + " " + rtos( y + yCenter ) + " );\n";
dia = dia - ( i * ( 2 * ( ringThickness + ringGap ) ) );
} //end for
//draw cross hairs
wire = wire + "SET WIDTH " + rtos( crossHairThickness ) + ";\n";
real xIncrement, yIncrement;
xIncrement = cos( angle ) * crossHairLength/2;
yIncrement = sin( angle ) * crossHairLength/2;
//hor cross
wire = wire + "WIRE ( " + rtos( -1.0 * xIncrement + x ) + " " + rtos( yIncrement - y ) + " ) ( " + rtos( xIncrement + x ) + " " + rtos( yIncrement + y ) + " );\n";
//vert cross
wire = wire + "WIRE ( " + rtos( yIncrement + x ) + " " + rtos( -1.0 * xIncrement + y ) + " ) ( " + rtos( x - yIncrement ) + " " + rtos( xIncrement + y ) + " );\n";
} //end if/else
return wire;
}
string ThermalMacroWires( string macro, real x, real y ){
// type = 0
// x center = 1
// y center = 2
// outer dia = 3
// inner dia = 4
// gap thickness = 5
// angle = 6
string wire;
string fields[];
int numFields = strsplit( fields, macro, ',' );
real xCenter, yCenter, outerDia, innerDia;
if( numFields < 7 ){
AddException( "Error parsing thermal aperture macro. Incorrect number of fields provided. Aperture not drawn." );
}
else{
AddException( "Thermal aperture macro found. Gaps not draw for thermal." );
xCenter = strtod( fields[ 1 ] );
yCenter = strtod( fields[ 2 ] );
outerDia = strtod( fields[ 3 ] );
innerDia = strtod( fields[ 4 ] );
wire = wire + "SET WIDTH " + rtos( outerDia/2 - innerDia/2 ) + ";\n";
wire = wire + "CIRCLE ( " + rtos( x + xCenter ) + " " + rtos( y + yCenter )+ " ) ( " + rtos( x + xCenter + outerDia/2 ) + " " +rtos( y + yCenter ) + " );\n";
} //end if-else
return wire;
}
string GetApertureMacroWires( string aperture, real x, real y, string apertureDef ){
//http://www.artwork.com/gerber/274x/rs274x.htm
//%AMOC8*5,1,8,0,0,1.08239X$1,22.5*
//get aperture macro from lookup
string macro = lookup( ApertureMacros, aperture, "macro" );
//make sure a value was found.
if( macro == "" ){
AddException( "Problem getting macro definition for aperture id '" + aperture + "'." );
return "";
}
//handle complex macros
string macros[];
int numMacros = strsplit( macros, macro, '*' );
string allMacroWires, macroWires;
//loop thru macro fields
for( int i = 0; i < numMacros; i++ ){
macro = macros[ i ];
//check if macro includes $ which means it has parameters that need to be handled
if( strstr( macro, "$" ) >= 0 ){
//AddException( "Macro includes complex parameters that cannot be rendered. Skipping macro '" + macro + "'." );
//dlgMessageBox( "Found Param:" + macro + ", " + apertureDef );
//parse out values from definition. ex OC8,0.1900 --> OC8 & 0.1900.
string params[];
int numParams = strsplit( params, apertureDef, ',' );
//split macro and find $$ places. ex 5,1,8,0,0,1.08239X$1,22.5* --> split and then find ones with $ in them
string macroFields[];
int numMacroFields = strsplit( macroFields, macro, ',' );
int paramCounter = 1; //start at 1 since the first value of param is the macro def
real param; //actual real value of param
//loop thru fields and check if params and then do replace
for( int k = 0; k < numMacroFields; k++ ){
if( strstr( macroFields[k], "$" ) >= 0 ){
//local fields for spliting of macro individual fields
string fs[];
int numF = 0;
//found param. get value from definition
param = strtod( params[ paramCounter ] );
//split by X values. assume first value is the multiplier and second is the parama we parsed from def
numF = strsplit( fs, macroFields[k], 'X' );
macroFields[k] = rtos( strtod( fs[0] ) * param );
paramCounter++;
}
} //end for k
//merge macrofields back to string for usage below
macro = strjoin( macroFields, ',' );
//dlgMessageBox( macro );
} //end if
//get type of macro
//int firstAsteriskInd = strstr( macro, "*" );
int firstCommaInd = strstr( macro, "," );
string macType = strsub( macro, 0, firstCommaInd );
macroWires = "";
if( macType == "0" ){
//comment. do nothing
}
else if( macType == "1" ){
//circle
macroWires = CircleMacroWires( macro, x, y );
}
else if( macType == "2" || macType == "20" ){
//vector line
macroWires = VectorLineMacroWires( macro, x, y );
}
else if( macType == "21" ){
//center line
macroWires = CenterLineMacroWires( macro, x, y );
}
else if( macType == "22" ){
//lower left line
macroWires = LowerLeftLineMacroWires( macro, x, y );
}
else if( macType == "4" ){
//outline
macroWires = OutlineMacroWires( macro, x, y );
}
else if( macType == "5" ){
//polygon
macroWires = PolygonMacroWires( macro, x, y );
}
else if( macType == "6" ){
//moire
macroWires = MoireMacroWires( macro, x, y );
}
else if( macType == "7" ){
//thermal
macroWires = ThermalMacroWires( macro, x, y );
}
else{
//unknown - too complex
AddException( "Unknown aperture macro '" + macro + "' for aperture id '" + aperture + "'. Macro type='" + macType + "'" );
} //end if-else for macType
//add
allMacroWires = allMacroWires + macroWires;
} //end for loop
//dlgMessageBox( macro + ":" + macroWires );
return macroWires;
}
//******************* aperture def wires functions *******************//
string CircleApertureWires( string definition, real x, real y ){
//C,