#usage "Generate IDF files from CADSoft Eagle
\n"
"Run ULP on board file to generate IDF board and library files for import to CAD tools.
"
"Version: 0.1 - Development Started - 12-8-13
"
"Version: 0.2 - Bug fix and cleanup - 12-21-13
"
"Version: 0.3 - Added in logic to lookup height if set - 1-29-14
"
"Version: 0.4 - Added validations on height values to ensure only number values are passed - 2-7-14
"
"Version: 0.5 - Baseline commit before code style changes - 3-20-14
"
"Version: 0.6 - Code style Issues addressed - 3-20-14
"
"Version: 0.7 - Updated component outline bounding box logic - 4-13-14
"
"Version: 0.8 - Cleanup of unused functions - 5-3-14
"
"Version: 0.9 - Fixed minor GUI issues related to reset of html table values - 5-6-14
"
"Version: 0.10 - Added logic for varied heights in packages on board - 5-6-14
"
"Version: 0.11 - Fixed bug in logic to handle HEIGHT attributes set with numbertext value.- 5-13-14
"
"Version: 1.0 - Initial production release.- 5-21-14
"
"Version: 1.1 - Change to consider circles on layer 20 regardless of other lines. Improved arc/circle processing logic. - 9-6-14
"
"Version: 2.0 - Updated to integrate with SSI IDF site - 3-25-15
"
"Version: 2.1 - Updates to include banner and links - 3-29-15
"
"Version: 2.2 - Updates to logic to open links in browser - 4-7-15
"
"
"
"Author: marc.battistello@gmail.com"
#require 5.1000
string version = "2.2"; //ulp version
//vars used for the text dialog
string TextMessageDialog; //used to store text shown to user
string HeightHtmlTable = "";
string BoardThickness = "1.6"; //mm
string WireLayer = "20";
//string DummyHistory[];
string LibraryLookup = "RCL:RESISTOR:TRANSISTOR:PINHEAD:RESISTOR-DIL:SMARTPRJ:C5B2,5A:CAP-WI:POLCAP:ELKO:CON-PTR500:SPECIAL:LED:CAPACITOR-WIMA:CON-WAGO-500:CON-HARTING-ML:ST-ML:CON-ML:CON-LSTB:CON-BERG:CON-SUBD:POLCAP";
string Libraries[]; //used to hold Libraries
string PackageOutlines[]; //used to hold outlines of packages
int PackageCounter = 0; //keeps track of how many entries in packages outline array
string NULL_HEIGHT = "0.000000"; //used for null heights
//web request urls
string Host = "http://www.simplifiedsolutionsinc.com";
string Service_port = "8080";
//string service_port = "80";
string Static_port = "80";
string Service_name = "EMN-EMPAdvancedApp/EagleTo3DSSIServlet";
string Login_name = "EMN-EMPAdvancedApp/LinkLoginServlet";
string Static_name = "EagleTo3D/";
string Service_url = Host + ":" + Service_port + "/" + Service_name;
string Login_url = Host + ":" + Service_port + "/" + Login_name;
string Static_url = Host + "/" + Static_name;
int useSecondaryMappings = 1;
int useSuggestionMappings = 1;
//debug flags
int Debug = 1; //general Debug flag
//-----------------------------------------------------------------------------
// subroutines
//-----------------------------------------------------------------------------
string itos(int num) {
string temp;
sprintf(temp, "%d", num);
return temp;
}
string rtos(real num) {
string temp;
sprintf(temp, "%f", num);
return temp;
}
int IsInt(string str) {
//returns 1 if int. 0 if not string
//first check to make sure its not "0" which Is the fail mode for the cast
if (str == "0") {
return 1;
} else if (strtol(str) != 0) {
return 1;
} else {
return 0;
}
} //end IsInt
int IsReal(string str) {
//returns 1 if int. 0 if not string
//first check to make sure its not "0.0" which Is the fail mode for the cast
if (str == "0.0") {
return 1;
} else if (strtod(str) != 0.0) {
return 1;
} else {
return 0;
}
} //end IsInt
int CompareReals(real n1, real n2) {
string n1s;
string n2s;
sprintf(n1s, "%1.2f", n1);
sprintf(n2s, "%1.2f", n2);
if (n1s == n2s) {
return 1;
} else {
return 0;
}
}
string GetBoardThickness() {
//make sure there Is value for board thickness
if (BoardThickness == "") {
BoardThickness = "1.6";
}
//check if first char Is decimal and if it Is then add 0
char dec = '.';
int pos = strchr(BoardThickness, dec);
if (pos == 0) {
BoardThickness = "0" + BoardThickness;
}
//return form value
return BoardThickness;
} //end func
string GetBoardUnits() {
/*
GRID_UNIT_MIC microns
GRID_UNIT_MM millimeter
GRID_UNIT_MIL mil
GRID_UNIT_INCH inch
*/
/* force to mm
string unitsMap[] = { "MIC", "MM", "MIL", "IN" };
board(B) {
return unitsMap[ B.grid.unit ];
}
*/
return "MM";
}
real BackConvertDimensions(real mmDim) {
real boardDim;
int unitsInt;
//get board dimensions
board(B)
{
unitsInt = B.grid.unit;
}
/*
GRID_UNIT_MIC microns
GRID_UNIT_MM millimeter
GRID_UNIT_MIL mil
GRID_UNIT_INCH inch
*/
switch (unitsInt) {
case 0:
//micron
boardDim = mmDim * 1000;
break;
case 1:
//mm
boardDim = mmDim;
break;
case 2:
//mil
boardDim = mmDim * 39.3700787;
break;
case 3:
//inch
boardDim = mmDim * 0.0393701;
break;
} //end switch
//string unitsMap[] = { "MIC", "MM", "MIL", "IN" };
//dlgMessageBox( "MM:" + rtos( mmDim ) + ", " + unitsMap[ unitsInt ] + ": " + rtos( boardDim ) );
return boardDim;
} //end func
real GetDimInBoardUnits(int dim) {
int unitsInt;
real convDim;
/* removed for force to mm
board(B) {
unitsInt = B.grid.unit;
}
switch( unitsInt ){
case 0:
convDim = u2mic( dim );
break;
case 1:
convDim = u2mm( dim );
break;
case 2:
convDim = u2mil( dim );
break;
case 3:
convDim = u2inch( dim );
break;
} //end switch
*/
convDim = u2mm(dim);
return convDim;
} //end func
real GetTolerance() {
int unitsInt;
real Tolerance;
/* removed to force to mm
board(B) {
unitsInt = B.grid.unit;
}
switch( unitsInt ){
case 0:
Tolerance = 100;
break;
case 1:
Tolerance = 0.05;
break;
case 2:
Tolerance = 3.9;
break;
case 3:
Tolerance = 0.004;
break;
} //end switch
*/
Tolerance = 0.05;
return Tolerance;
} //end func
string GetBoardFilename() {
board(BRD)
{
return filename(BRD.name);
} //end board
}
string GetBoardDir() {
board(BRD)
{
return filedir(BRD.name);
} //end board
}
string GetBoardPath() {
return GetBoardDir() + GetBoardFilename();
}
string PadBRs( int count ){
string padding = "";
for( int i; i < count; i++ ){
padding += "
";
}
return padding;
}
int IsWindows() {
//Returns 1, if EAGLE Is running under Windows (0 for Linux/Mac)
if ((strsub(argv[0], 0, 1) == "/") && (strsub(argv[0], 0, 2) != "//"))
return 0;
return 1;
} //end sub
int IsMac(){
if( (strsub( OS_SIGNATURE, 0, 3 ) == "Mac") || (strsub( OS_SIGNATURE, 0, 3 ) == "MAC") )
return 1;
return 0;
}
void LaunchBrowser( string url ){
string launchCmd = "";
if( IsWindows() ){
launchCmd = "explorer \"" + url + "\"";
}
else if( IsMac() ){
launchCmd = "open " + url;
}
else{
//assume all others linux
//if you are on linux then change this line if the buttons dont work
launchCmd = "xdg-open " + url;
}
//run system command
system( launchCmd );
} //end launch browser
string GetFileSeperator() {
if (IsWindows()) {
return "\\";
} else {
return "/";
}
}
// Removes carriage returns from a string and replaces with
string RemoveCarriageReturns(string dirtyString) {
string cleanedString;
for (int i = 0; dirtyString[i]; ++i) {
if (dirtyString[i] == '\n') {
cleanedString += "
";
} else {
cleanedString += dirtyString[i];
} //end if-else
} //end for
return cleanedString;
} //end sub
// Removes spaces in string and replaces with
string RemoveSpaces(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 CleanString(string dirtyString) {
dirtyString = strupr(dirtyString);
string cleanedString;
for (int i = 0; dirtyString[i]; ++i) {
if (dirtyString[i] == '0' || dirtyString[i] == '1'
|| dirtyString[i] == '2' || dirtyString[i] == '3'
|| dirtyString[i] == '4' || dirtyString[i] == '5'
|| dirtyString[i] == '6' || dirtyString[i] == '7'
|| dirtyString[i] == '8' || dirtyString[i] == '9'
|| dirtyString[i] == 'A' || dirtyString[i] == 'B'
|| dirtyString[i] == 'C' || dirtyString[i] == 'D'
|| dirtyString[i] == 'E' || dirtyString[i] == 'F'
|| dirtyString[i] == 'G' || dirtyString[i] == 'H'
|| dirtyString[i] == 'I' || dirtyString[i] == 'J'
|| dirtyString[i] == 'K' || dirtyString[i] == 'L'
|| dirtyString[i] == 'M' || dirtyString[i] == 'N'
|| dirtyString[i] == 'O' || dirtyString[i] == 'P'
|| dirtyString[i] == 'Q' || dirtyString[i] == 'R'
|| dirtyString[i] == 'S' || dirtyString[i] == 'T'
|| dirtyString[i] == 'U' || dirtyString[i] == 'V'
|| dirtyString[i] == 'W' || dirtyString[i] == 'X'
|| dirtyString[i] == 'Y' || dirtyString[i] == 'Z'
|| dirtyString[i] == '_' || dirtyString[i] == '-'
|| dirtyString[i] == ' ') {
cleanedString += dirtyString[i];
} else {
cleanedString += "_";
} //end if-else
} //end for
return cleanedString;
} //end sub
// Removes spaces in string and replaces with
string ReplaceSpaceWithUnderscore(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
// 0-9, letters, dashes, and underscores are always safe.
// Reads in file and converts it to be used in a html form submit
string ParseFileToHtmlForm(string filePath) {
string fileContents;
int in = fileread(fileContents, filePath);
fileContents = RemoveCarriageReturns(fileContents);
fileContents = RemoveSpaces(fileContents);
//dlgMessageBox( "File input value:" + in );
return fileContents;
} //end sub
string ParseStringToHtmlForm(string input) {
return RemoveSpaces(RemoveCarriageReturns(input));
} //end sub
//this function Is used to Get the html to show in the UI.
//it uses a fixed header and footer and the call sets the body.
string GetHtmlText(string body) {
string os;
//build header html
string htmlHeader =
" \
\
| \
\
\
EAGLE IDF Exporter | \
\
\
| \
";
string htmlFooter = ""; //footer will be built later including OS padding
//detect if windows or other
if (IsWindows()) {
os = "Windows";
} else {
os = "Mac/Linux";
}
//build footer and include OS specific padding for formatting.
if (IsWindows()) {
htmlFooter += "
";
} else {
htmlFooter += "";
} //end if-else
//build version string
string versionString = "ULP Version: " + version + ", OS: " + os;
//build footer text
htmlFooter +=
" \
\
| \
\
\
| CADSoft | Help | \
( ULP Version: "
+ version + "\t, OS: " + os
+ " ) | \
\
\
| \
\
";
return htmlHeader + "| " + body + " |
"
+ htmlFooter;
} //end sub
real GetDistBetweenPts(real x1, real y1, real x2, real y2) {
//dist = sqrt( ( x2 - x1 )^2 + ( y2 - y1 )^2 )
return sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2));
} //end sub
void WriteToFile(string filePath, string fileContents) {
output(filePath, "wt")
{
printf(fileContents);
}
} //end sub
string GetElementHeightAttr( UL_ELEMENT E ){
/* checks for attribute named HEIGHT.
* casts height string to real to handle any invalid values. sets to 0 if not value.
* returns height
*/
string height = NULL_HEIGHT;
//check for element height
E.attributes(A)
{
if (strupr(A.name) == "HEIGHT") {
if ( strtod(A.value) <= 0.0) {
height = NULL_HEIGHT;
} else {
height = rtos( strtod( A.value ) );
} //end if-else
} //end if
} //end loop thru attributes
return height;
} //end sub
//-----------------------------------------------------------------------------
// emp subroutines
//-----------------------------------------------------------------------------
string GetDateTime() {
//time for date.time in header
int now = time();
string dateStr;
sprintf(dateStr, "%d/%02d/%02d.%02d:%02d:%02d", t2year(now), t2month(now),
t2day(now), t2hour(now), t2minute(now), t2second(now));
return dateStr;
} //end sub
//looks up package outline and generates text for .electical section entry
string GetComponentOutline(string footprint, string altname, string packageName,
string units, string height) {
//package array = [ { packname1, maxX, maxY, minX, minY },
// { packname2, maxX, maxY, minX, minY }
// ]
//board->Library->Package->Wires
int foundPackage = 0;
//lookup package name in array
string packageNameLookup = lookup(PackageOutlines, packageName, 0);
//check if found in lookup. if not then generate and put in array
if (packageNameLookup == "") {
//if package not in lookup then generate it
//init max/min values
real maxX = 0, maxY = 0, minX = 0, minY = 0;
//loop thru all Libraries to find packagename
board(B)
{
//go into library
B.libraries(LBR)
{
//loop thru packages in library
LBR.packages(P)
{
//if package name matches the one we are looking for then process it
if (P.name == packageName) {
//check min/ax for each of
//circles() UL_CIRCLE - C.x, C.y, C.radius, C.width)
//holes() UL_HOLE
//polygons() UL_POLYGON -> wires()
//rectangles() UL_RECTANGLE - R.x1, R.y1, R.x2, R.y2);
//wires() UL_WIRE
//set found package flag
foundPackage = 1;
//used to capture first loop of data
int loopCounter = 0;
real w2; //holds 1/2 of width
//loop thru wires and Get max/min x/y
//do wires first to take care of loopCounter == 0 case
P.wires(W)
{
//get first data point
if (loopCounter == 0) {
w2 = W.width / 2;
minX = GetDimInBoardUnits(
min(W.x1 - w2, W.x2 - w2));
minY = GetDimInBoardUnits(
min(W.y1 - w2, W.y2 - w2));
maxX = GetDimInBoardUnits(
max(W.x1 + w2, W.x2 + w2));
maxY = GetDimInBoardUnits(
max(W.y1 + w2, W.y2 + w2));
}
if (W.arc) {
w2 = W.width / 2;
if (W.arc.angle2 > 360)
maxX = max(maxX,
GetDimInBoardUnits(
W.arc.xc + W.arc.radius));
else if (((W.arc.angle1 < 90)
&& (W.arc.angle2 > 90))
|| (W.arc.angle2 > 450))
maxY = max(maxY,
GetDimInBoardUnits(
W.arc.yc + W.arc.radius
+ w2));
else if (((W.arc.angle1 < 180)
&& (W.arc.angle2 > 180))
|| (W.arc.angle2 > 540))
minX = min(minX,
GetDimInBoardUnits(
W.arc.xc - W.arc.radius
- w2));
else if (((W.arc.angle1 < 270)
&& (W.arc.angle2 > 270))
|| (W.arc.angle2 > 630))
minY = min(minY,
GetDimInBoardUnits(
W.arc.yc - W.arc.radius
- w2));
}
else {
//handle non arc wires
minX = min(minX, GetDimInBoardUnits(W.x1));
minY = min(minY, GetDimInBoardUnits(W.y1));
maxX = max(maxX, GetDimInBoardUnits(W.x1));
maxY = max(maxY, GetDimInBoardUnits(W.y1));
} //end if-else
loopCounter++;
} //end wires
//UpdateBBoxBox(C.x - C.radius - w2, C.y - C.radius - w2, C.x + C.radius + w2, C.y + C.radius + w2);
// xmin, ymin, xmax, ymax
P.circles(C)
{
w2 = C.width / 2;
minX = min(minX,
GetDimInBoardUnits(C.x - C.radius - w2));
minY = min(minY,
GetDimInBoardUnits(C.y - C.radius - w2));
maxX = max(maxX,
GetDimInBoardUnits(C.x + C.radius + w2));
maxY = max(maxY,
GetDimInBoardUnits(C.y + C.radius + w2));
loopCounter++;
} //end circles
//P.holes(){} - Not required. These are solder masks
P.polygons(POLY)
{
POLY.wires(PW)
{
minX = min(minX, GetDimInBoardUnits(PW.x1));
minY = min(minY, GetDimInBoardUnits(PW.y1));
maxX = max(maxX, GetDimInBoardUnits(PW.x1));
maxY = max(maxY, GetDimInBoardUnits(PW.y1));
loopCounter++;
} //end wires in polygon
} //end polgons
P.rectangles(R)
{
minX = min(minX,
min(GetDimInBoardUnits(R.x1),
GetDimInBoardUnits(R.x2)));
minY = min(minY,
min(GetDimInBoardUnits(R.y1),
GetDimInBoardUnits(R.y2)));
maxX = max(maxX,
max(GetDimInBoardUnits(R.x1),
GetDimInBoardUnits(R.x2)));
maxY = max(maxY,
max(GetDimInBoardUnits(R.y1),
GetDimInBoardUnits(R.y2)));
loopCounter++;
} //end rectangles
//break out of loop since match found
break;
} //end if for package name match
} //end packages loop
} //end Libraries loop
} //end board loop
//make sure found match. if not then put in default values
string temp;
if (foundPackage) {
//load to array
sprintf(temp, "%s\t%f\t%f\t%f\t%f", packageName, maxX, maxY, minX,
minY);
} else {
sprintf(temp, "%s\t%f\t%f\t%f\t%f", packageName, maxX, maxY, minX,
minY);
} //end if-else for found package check
//add data to package outline so it can be reused in future
PackageOutlines[PackageCounter] = temp;
PackageCounter++;
} //end if for lookup check
//generate outline data. first line is footpring, name, and units
string outline = footprint + " " + altname + " " + units;
//set default height based on units
if (units == "MM") {
outline += " " + height + "\n";
//check if height set. if not set to 1.0
/*if (height == "1.0") {
outline += " 1.00\n";
}
else {
outline += " " + height + "\n";
}*/
}
/*else if (units == "THOU") {
//check if
if (height == "0.0") {
outline += " 39.37\n";
}
else {
outline += " " + height + "\n";
}
}
*/
else {
//treat as MM
//check if
if (height == "1.0") {
outline += " 1.00\n";
} else {
outline += " " + height + "\n";
}
} //end if-else
//map in max/min data
string maxX = lookup(PackageOutlines, packageName, 1);
string maxY = lookup(PackageOutlines, packageName, 2);
string minX = lookup(PackageOutlines, packageName, 3);
string minY = lookup(PackageOutlines, packageName, 4);
/*rectangle based on max/min values. start in upper left and move clockwise
0 minX maxY
0 maxX maxY
0 maxX minY
0 minX minY
0 minX maxY
*/
//if max/min are all zeros then put in 1x1 block
if (maxX == "0.000000" && maxY == "0.000000" && minX == "0.000000"
&& minX == "0.000000") {
outline += "0 1.00 -1.00 0.0\n" + "0 -1.00 -1.00 0.0\n"
+ "0 -1.00 1.00 0.0\n" + "0 1.00 1.00 0.0\n"
+ "0 1.00 -1.00 0.0\n";
}
//if they are all the same they also set in 1x1 block so that something is shown
else if (maxX == minX || maxY == minY) {
outline += "0 1.00 -1.00 0.0\n" + "0 -1.00 -1.00 0.0\n"
+ "0 -1.00 1.00 0.0\n" + "0 1.00 1.00 0.0\n"
+ "0 1.00 -1.00 0.0\n";
}
//otherwise actual coords provided. use those in output
else {
outline += "0 " + minX + " " + maxY + " 0.0\n" + "0 " + maxX
+ " " + maxY + " 0.0\n" + "0 " + maxX + " " + minY
+ " 0.0\n" + "0 " + minX + " " + minY + " 0.0\n"
+ "0 " + minX + " " + maxY + " 0.0\n";
} //end if-else
return outline;
} //end sub
string GetEmpHeader() {
/*
.HEADER
LIBRARY_FILE 3.0 "Commend International >generate_3d_data_v10-5_MJB.ulp V0.9<" 2012/03/21.12:23:09 1
.END_HEADER
*/
return ".HEADER\n" + "LIBRARY_FILE 3.0 \"Eagle IDF Exporter " + version
+ "\" " + GetDateTime() + "\n" + ".END_HEADER\n";
} //end sub
string GetEmpElectrical() {
/*
.ELECTRICAL
TSSOP16 NOREFDES MM 4876.80
0 -2.51 -2.28 0
0 2.51 -2.28 0
0 2.51 2.28 0
0 -2.51 2.28 0
0 -2.51 -2.28 0
.END_ELECTRICAL
*/
string electricalSection;
string footprint;
string altname;
string height = NULL_HEIGHT;
string LibraryLookup;
string components[];
string component;
//loop thru elements on board
board(BRD)
{
int i = 0;
BRD.elements(E)
{
height = NULL_HEIGHT;
//check if library in lookup
LibraryLookup = lookup(Libraries, strupr(E.package.library), 0);
//set footprint and altname based on logic
if (LibraryLookup != "") {
footprint = E.package.name;
altname = E.package.name;
//add comment to emn for debuggin
//placementSection += "#Resistor or rcl library found\n";
} else if (E.value != "") {
altname = E.value;
footprint = E.package.name;
//add comment to emn for debuggin
//placementSection += "#E.value present\n";
} else {
//if library Is not in list and the E.value Is blank then concat refid and package name
altname = E.name + "_" + E.package.name;
footprint = E.package.name;
//add comment to emn for debuggin
//placementSection += "#Fallback logic applied. Not res/rcl and E.value not found.\n";
}
altname = CleanString(altname);
footprint = CleanString(footprint);
//check for element height
/*
E.attributes(A)
{
if (strupr(A.name) == "HEIGHT") {
if (strtod(A.value) < 0) {
height = "0.000000";
} else {
height = rtos(strtod(A.value));
} //end if-else
} //end if
} //end loop thru attributes
*/
//check if height set for element. if not set then set to NULL_HEIGHT
height = GetElementHeightAttr( E );
//add component to height lookup table
HeightHtmlTable = HeightHtmlTable + "| " + E.name
+ " | " + altname + " | " + E.package.name
+ " | ";
//if height is not set then set to default
if (height == NULL_HEIGHT) {
height = "1.0"; //set to value of 1.0
HeightHtmlTable = HeightHtmlTable + "" + height + " |
";
} else {
HeightHtmlTable = HeightHtmlTable + "" + height + " | ";
} //if-else for height value
//if height is default value then do not append it to altname. this will prevent the height from poluting the naming convention
//if height is not default then append it to altname so that its unique
if( height == "1.0" ){
//component = lookup(components, footprint + "~" + altname, 0); - Fix for multi comp and heights
component = lookup(components, footprint + "~" + altname, 0);
//if component Is empty then it has not been written out yet.
if (component == "") {
//build section by call to GetComponentOutlineDummy( string footprint, string altname, string units )
electricalSection += ".ELECTRICAL\n" +
GetComponentOutline(footprint, altname, E.package.name, GetBoardUnits(), height) +
".END_ELECTRICAL\n";
//add component to components list.
//components[i] = footprint + "~" + altname; - Fix for multi comp and heights
components[i] = footprint + "~" + altname;
i++;
} //end if
}
else{
component = lookup(components, footprint + "_" + height + "~" + altname + "_" + height, 0);
//if component Is empty then it has not been written out yet.
if (component == "") {
//build section by call to GetComponentOutlineDummy( string footprint, string altname, string units )
electricalSection += ".ELECTRICAL\n" +
GetComponentOutline(footprint + "_" + height, altname + "_" + height, E.package.name, GetBoardUnits(), height) +
".END_ELECTRICAL\n";
//add component to components list.
//components[i] = footprint + "~" + altname; - Fix for multi comp and heights
components[i] = footprint + "_" + height + "~" + altname + "_" + height;
i++;
} //end if
} //end if-else
} //end loop thru elements
} //end loop thru board
return electricalSection;
} //end sub
string GetEmpMechanical() {
return "";
} //end sub
//-----------------------------------------------------------------------------
// emn subroutines
//-----------------------------------------------------------------------------
string GetEmnHeader() {
/*
.HEADER
BOARD_FILE 3.0 "Commend International >generate_3d_data_v10-5_MJB.ulp V0.9<" 2012/03/21.12:23:10 1
"untitled.brd" MM
.END_HEADER
*/
string boardName;
//get board name
board(BRD)
{
boardName = filename(BRD.name);
}
return ".HEADER\n" + "BOARD_FILE 3.0 \"Eagle IDF Exporter Version "
+ version + "\" " + GetDateTime() + "\n" + "\"" + boardName + "\" "
+ GetBoardUnits() + "\n" + ".END_HEADER\n";
} //end sub
string SetUsedFlag(string pt) {
string fields[];
int fieldCount = strsplit(fields, pt, '\t');
return fields[0] + "\t" + fields[1] + "\t" + fields[2] + "\t" + fields[3]
+ "\ty\n";
}
int IsUsedPoint(string pt) {
string fields[];
int fieldCount = strsplit(fields, pt, '\t');
if (fields[4] == "n\n")
return 0;
else
return 1;
}
string IsUsedPointDebug(string pt) {
string fields[];
int fieldCount = strsplit(fields, pt, '\t');
return fields[4];
}
string FlipPoints(string line) {
string fields[];
int fieldCount = strsplit(fields, line, '\t');
return fields[2] + "\t" + fields[3] + "\t" + fields[0] + "\t" + fields[1]
+ "\t" + fields[4];
}
string GetFieldFromPtString(string ptString, int index) {
string fields[];
// "pt 1\ttype\tx1\ty1\tx2\ty2\tsorted_flag"
int fieldCount = strsplit(fields, ptString, '\t');
if (fieldCount >= index) {
return fields[index];
} else {
return "";
} //end if-else
} //end sub
real GetX1FromPtString(string ptString) {
return strtod(GetFieldFromPtString(ptString, 0));
} //end sub
real GetY1FromPtString(string ptString) {
return strtod(GetFieldFromPtString(ptString, 1));
} //end sub
real GetX2FromPtString(string ptString) {
return strtod(GetFieldFromPtString(ptString, 2));
} //end sub
real GetY2FromPtString(string ptString) {
return strtod(GetFieldFromPtString(ptString, 3));
} //end sub
int LayerNumInUse(int layerNum) {
//returns true=1 if layer Is being used. returns 0 if layer Is not used.
int layerUsed = 0;
board(B)
{
B.layers(L)
{
if (L.number == layerNum) {
layerUsed = 1;
} //end if
} //layers loop
} //board loop
return layerUsed;
}
int LayerIsIDFDebug(int layerNum) {
board(B)
{
B.layers(L)
{
if (L.number == layerNum && L.name == "IDFDebug") {
return 1;
} //end if
} //layers loop
} //board loop
return 0;
}
string GetIDFDebugLayerAvailNum() {
//loop thru layers and check for name IDFDebug
int startSearchNumber = 100;
int layerAvail = -1;
for (int i = startSearchNumber; i < 256; ++i) {
//if layer Is not in use then use it. also have to check if layer Is in use but Is already idf debug
if (!LayerNumInUse(i)) {
layerAvail = i;
break;
} else {
//check to make sure layer Is not already idf debug
if (LayerIsIDFDebug(i)) {
layerAvail = i;
break;
} //end if
} //end if-else
} //end for
string temp;
sprintf(temp, "%d", layerAvail);
return temp;
} //end func
string GetIDFDebugLayerNum() {
//loop thru layers and check for name IDFDebug
int IDFDebugLayerNum = -1;
board(B)
{
B.layers(L)
{
if (L.name == "IDFDebug") {
IDFDebugLayerNum = L.number;
} //end if
} //layers loop
} //board loop
string temp;
sprintf(temp, "%d", IDFDebugLayerNum);
return temp;
} //end func
string RemoveIDFDebugLayerCommands() {
//check if present
string debugLayerNum = GetIDFDebugLayerNum();
//if debugLayerNum Is -1 then it doesnt exist so no delete needed.
if (debugLayerNum == "-1") {
return "";
} else {
string commands;
//commands
//show only IDFDebugLayer
commands += "DISPLAY -20 " + debugLayerNum + ";";
//run group all command to select all circles
//commands += "GROUP ALL;";
//delete circles
//DELETE (x y) where x y are points on circle outline
board(B)
{
B.circles(C)
{
if (C.layer == strtol(debugLayerNum)) {
commands += "DELETE ( " + rtos(GetDimInBoardUnits(C.x))
+ " " + rtos(GetDimInBoardUnits(C.y)) + " );";
} //end if
} //end wire loop
B.wires(W)
{
if (W.layer == strtol(debugLayerNum)) {
commands += "DELETE ( " + rtos(GetDimInBoardUnits(W.x1))
+ " " + rtos(GetDimInBoardUnits(W.y1)) + " );";
} //end if
} //end wire loop
} //board loop
//delete layer now
commands += "LAYER ?? -" + debugLayerNum + ";";
return commands;
} //end if/else
} //end fund
int CountWireHoles() {
int holeCount = 0;
board(BRD)
{
/*
BRD.holes(H){
holeCount++;
} //end holes
*/
BRD.circles(C)
{
if (C.layer == strtol(WireLayer)) {
holeCount++;
}
}
} //end board loop
return holeCount;
} //end func
real Tolerance = GetTolerance();
/*
string getComponentOutlinePoints(){
//init vars
int Debug = 1; //used for debugging and generation of log in board outline processing
string logFilePath = filesetext(GetBoardPath(), ".log");
string BoardThickness = GetBoardThickness();
string boardOutlineSection = ".BOARD_OUTLINE UNOWNED\n" + BoardThickness + "\n";
int wireCount = 0;
string outlinePoints[]; //holds points extracted from board
string outlinePointsSorted[]; //holds points after they are sorted
real deg2rad = 0.0174532925; //used to convert degress to radians for arc parsing
real bx1 = 0.0, by1 = 0.0, bx2 = 0.0, by2 = 0.0; //line start and end points
real startX = 0.0, startY = 0.0;
int outlineNum = 0;
//used for drawing arc lines
real incx = 0.0, incy = 0.0; //store incremental x/y values for arc
real currentAngle = 0.0, incrementAngle = 15.0;
string temp; //temp string used with sprintf
int newOutline = 1;
string pad = " ";
real minDist = -1.0; //used to keep track of min distance found
real dist = 0.0; //used to store distance between two points
string fromPoints, toPoints;
string boardOutlineSectionDebug;
int matchFound = 0;
//get list of component names in board
board(B){
//go into library
B.libraries(LBR){
//loop thru packages in library
LBR.packages(P){
dlgMessageBox( P.name );
} //end package loop
} //end library loop
} //end board loop
exit(0);
// Step 1 & 2
//loop thru layer 20 and wires on layer
board(BRD)
{
//loop thru wires
BRD.wires(W)
{
//only pull layer 20 wires
if (W.layer == strtol(WireLayer)) {
//get wire start and end points
//get x/y for start and end.
bx1 = GetDimInBoardUnits(W.x1), by1 = GetDimInBoardUnits(W.y1), bx2 =
GetDimInBoardUnits(W.x2), by2 = GetDimInBoardUnits(W.y2);
//handle arcs and lines differently
if (W.arc) {
//for arc Get data to generate points
real angle1 = W.arc.angle1, angle2 = W.arc.angle2, centerx =
GetDimInBoardUnits(W.arc.xc), centery =
GetDimInBoardUnits(W.arc.yc);
real endx = bx2, endy = by2; //store arc end points to close arc.
//reset current angle value
currentAngle = incrementAngle;
//determine which direction to draw arc by Getting x/y points based on angle1
incx = (cos(deg2rad * (angle1))
* GetDimInBoardUnits(W.arc.radius)) + centerx;
incy = (sin(deg2rad * (angle1))
* GetDimInBoardUnits(W.arc.radius)) + centery;
//check if arc start points match calculated start points using angle1. if they do then its a counter clockwise drawn arc
if (CompareReals(incx, bx1) && CompareReals(incy, by1)) {
///loop thru 5 deg increments
//arc defined counter clockwise so you need to subtract the increment
while ((angle1 + currentAngle) < angle2) {
incx = (cos(deg2rad * (angle1 + currentAngle))
* GetDimInBoardUnits(W.arc.radius))
+ centerx;
incy = (sin(deg2rad * (angle1 + currentAngle))
* GetDimInBoardUnits(W.arc.radius))
+ centery;
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx, incy);
outlinePoints[wireCount] = temp;
currentAngle += incrementAngle;
wireCount++;
//update beginning x/y values
bx1 = incx;
by1 = incy;
} //end while
} else {
///loop thru 5 deg increments
//arc defined counter clockwise so you need to subtract the increment
while ((angle2 - currentAngle) > angle1) {
incx = (cos(deg2rad * (angle2 - currentAngle))
* GetDimInBoardUnits(W.arc.radius))
+ centerx;
incy = (sin(deg2rad * (angle2 - currentAngle))
* GetDimInBoardUnits(W.arc.radius))
+ centery;
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx,
incy);
outlinePoints[wireCount] = temp;
currentAngle += incrementAngle;
wireCount++;
//update beginning x/y values
bx1 = incx;
by1 = incy;
} //end while
} //end if/else for check on direction of arc
//close arc
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, endx, endy);
outlinePoints[wireCount] = temp;
wireCount++;
} else {
//process lines
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, bx2, by2);
outlinePoints[wireCount] = temp;
wireCount++;
} //end if for arc
} //end if check for layer=20
} //end loop thru wires
} //end loop thru board
//if there are wireholes then consider those as part of the outline
if ( CountWireHoles() > 0) {
board(B){
B.circles(C){
if (C.layer == strtol(WireLayer)) {
real angle1 = 0;
real angle2 = 360;
real currentAngle = 0;
real radius = GetDimInBoardUnits(C.radius);
real centerx = GetDimInBoardUnits(C.x);
real centery = GetDimInBoardUnits(C.y);
real bx1 = centerx + radius;
real by1 = centery;
while ((angle1 + currentAngle) <= angle2) {
//handle first point where angle = 0
if( currentAngle == 0 ){
incx = (cos(deg2rad * (angle1 + (incrementAngle/2))) * radius) + centerx;
incy = (sin(deg2rad * (angle1 + (incrementAngle/2))) * radius) + centery;
}
else{
incx = (cos(deg2rad * (angle1 + currentAngle)) * radius) + centerx;
incy = (sin(deg2rad * (angle1 + currentAngle)) * radius) + centery;
} //end if-else for current angle = 0
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx,incy);
outlinePoints[wireCount] = temp;
currentAngle += incrementAngle;
wireCount++;
//update beginning x/y values
bx1 = incx;
by1 = incy;
} //end while
} //end if for layer check
} //end circle loop
} //end board loop
} //wire holes if
return outlinePoints;
} //end func
*/
string GetEmnBoardOutline() {
/*
Board outline logic
--------------------
1. Loop thru wires on layer 20 and parse out points based on type of wire.
Wire can be either arc or line. If it Is an arc then the .arc property Is set to 1.
2. For lines extract the start and end points. For arcs you need to convert them in
to a set of lines that simulates an arc by drawing a line at angle increments.
3. After looping thru the wires on layer 20 verify that wires were actually found.
If none were found then exit the ulp and notify the user no lines were found on layer 20.
4. Once the points are loaded to the array they need to reordered so that they are written in the correct order in the outline. This Is
due to fact that the loop thru .wires provides the wires in the order they were drawn and not necessarily in the correct order.
To accomplish this you need to first fine the start point. I do this by finding the point closest to 0,0.
5. Once the line with a start point closest to 0,0 Is found I then look thru the points to find a match for the end point of the first line.
The lines may not be written in end point to start point so you need to check for closet match on both the start and end.
6. After sorting the lines you can now write out the points to the board_outline section. I check for matches from end to start points.
If a match Isnt found then I assume a new outline Is found and increment the counter. I also need to make sure that when a new outline Is found that the prev
outline Is closed.
*/
//init vars
int Debug = 1; //used for debugging and generation of log in board outline processing
string logFilePath = filesetext(GetBoardPath(), ".log");
string BoardThickness = GetBoardThickness();
string boardOutlineSection = ".BOARD_OUTLINE UNOWNED\n" + BoardThickness + "\n";
int wireCount = 0;
string outlinePoints[]; //holds points extracted from board
string outlinePointsSorted[]; //holds points after they are sorted
real deg2rad = 0.0174532925; //used to convert degress to radians for arc parsing
real bx1 = 0.0, by1 = 0.0, bx2 = 0.0, by2 = 0.0; //line start and end points
real startX = 0.0, startY = 0.0;
int outlineNum = 0;
//used for drawing arc lines
real incx = 0.0, incy = 0.0; //store incremental x/y values for arc
real currentAngle = 0.0, incrementAngle = 15.0;
string temp; //temp string used with sprintf
int newOutline = 1;
string pad = " ";
real minDist = -1.0; //used to keep track of min distance found
real dist = 0.0; //used to store distance between two points
string fromPoints, toPoints;
string boardOutlineSectionDebug;
int matchFound = 0;
/* Step 1 & 2 */
//loop thru layer 20 and wires on layer
board(BRD)
{
//loop thru wires
BRD.wires(W)
{
//only pull layer 20 wires
if (W.layer == strtol(WireLayer)) {
//get wire start and end points
//get x/y for start and end.
bx1 = GetDimInBoardUnits(W.x1), by1 = GetDimInBoardUnits(W.y1), bx2 =
GetDimInBoardUnits(W.x2), by2 = GetDimInBoardUnits(W.y2);
//handle arcs and lines differently
if (W.arc) {
//for arc Get data to generate points
real angle1 = W.arc.angle1, angle2 = W.arc.angle2, centerx =
GetDimInBoardUnits(W.arc.xc), centery =
GetDimInBoardUnits(W.arc.yc);
real endx = bx2, endy = by2; //store arc end points to close arc.
//reset current angle value
currentAngle = incrementAngle;
//determine which direction to draw arc by Getting x/y points based on angle1
incx = (cos(deg2rad * (angle1))
* GetDimInBoardUnits(W.arc.radius)) + centerx;
incy = (sin(deg2rad * (angle1))
* GetDimInBoardUnits(W.arc.radius)) + centery;
//check if arc start points match calculated start points using angle1. if they do then its a counter clockwise drawn arc
if (CompareReals(incx, bx1) && CompareReals(incy, by1)) {
///loop thru 5 deg increments
//arc defined counter clockwise so you need to subtract the increment
while ((angle1 + currentAngle) < angle2) {
incx = (cos(deg2rad * (angle1 + currentAngle))
* GetDimInBoardUnits(W.arc.radius))
+ centerx;
incy = (sin(deg2rad * (angle1 + currentAngle))
* GetDimInBoardUnits(W.arc.radius))
+ centery;
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx, incy);
outlinePoints[wireCount] = temp;
currentAngle += incrementAngle;
wireCount++;
//update beginning x/y values
bx1 = incx;
by1 = incy;
} //end while
} else {
///loop thru 5 deg increments
//arc defined counter clockwise so you need to subtract the increment
while ((angle2 - currentAngle) > angle1) {
incx = (cos(deg2rad * (angle2 - currentAngle))
* GetDimInBoardUnits(W.arc.radius))
+ centerx;
incy = (sin(deg2rad * (angle2 - currentAngle))
* GetDimInBoardUnits(W.arc.radius))
+ centery;
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx,
incy);
outlinePoints[wireCount] = temp;
currentAngle += incrementAngle;
wireCount++;
//update beginning x/y values
bx1 = incx;
by1 = incy;
} //end while
} //end if/else for check on direction of arc
//close arc
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, endx, endy);
outlinePoints[wireCount] = temp;
wireCount++;
} else {
//process lines
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, bx2, by2);
outlinePoints[wireCount] = temp;
wireCount++;
} //end if for arc
} //end if check for layer=20
} //end loop thru wires
} //end loop thru board
//if there are wireholes then consider those as part of the outline
if ( CountWireHoles() > 0) {
board(B){
B.circles(C){
if (C.layer == strtol(WireLayer)) {
real angle1 = 0;
real angle2 = 360;
real currentAngle = 0;
real radius = GetDimInBoardUnits(C.radius);
real centerx = GetDimInBoardUnits(C.x);
real centery = GetDimInBoardUnits(C.y);
real bx1 = centerx + radius;
real by1 = centery;
while ((angle1 + currentAngle) <= angle2) {
//handle first point where angle = 0
if( currentAngle == 0 ){
incx = (cos(deg2rad * (angle1 + (incrementAngle/2))) * radius) + centerx;
incy = (sin(deg2rad * (angle1 + (incrementAngle/2))) * radius) + centery;
}
else{
incx = (cos(deg2rad * (angle1 + currentAngle)) * radius) + centerx;
incy = (sin(deg2rad * (angle1 + currentAngle)) * radius) + centery;
} //end if-else for current angle = 0
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx,incy);
outlinePoints[wireCount] = temp;
currentAngle += incrementAngle;
wireCount++;
//update beginning x/y values
bx1 = incx;
by1 = incy;
} //end while
} //end if for layer check
} //end circle loop
} //end board loop
} //wire holes if
/* Step 3 - Verify wires found */
if (wireCount == 0) {
dlgMessageBox("No wires were found on layer 20.\nUnable to detect board outline. Exiting.");
//add in check if user wants to use a component as the board outline
if ( dlgMessageBox("No outlines were found on layer 20.\n\nWould you like to select a component to use as outline?\n\nIf you select No then the program will exit.", "&Yes", "&No") == 0) {
//call function to get from component and then assign to ouline array
//outlinePoints = getComponentOutlinePoints();
}
else{
exit(0);
}
} //end if for wirecount = 0 check
if (Debug) {
boardOutlineSectionDebug +=
"########### array before sorts ###########\n";
for (int j = 0; j < wireCount; j++) {
sprintf(temp, "%d\t%s", j, outlinePoints[j]);
boardOutlineSectionDebug += temp;
} //end for
} //end if for debug
/*
//calculate Tolerance based on 1/2 of smallest wire length
for( int i = 0; i < wireCount; i++ ){
bx1 = GetX1FromPtString( outlinePoints[ i ] );
by1 = GetY1FromPtString( outlinePoints[ i ] );
bx2 = GetX2FromPtString( outlinePoints[ i ] );
by2 = GetY2FromPtString( outlinePoints[ i ] );
dist = GetDistBetweenPts( bx1, by1, bx2, by2 );
if( minDist == -1.0 ){
minDist = dist;
}
else if( dist < minDist ){
minDist = dist;
}
else{
//do nothing if dist Is not smaller then minDist
}
} //end for loop
Tolerance = minDist / 2;
*/
/* Step 4 & 5 - Verify wires found */
//loop thru points and sort so they are in order
//outer loop thru points
boardOutlineSectionDebug += "Tolerance=" + rtos(Tolerance) + ".\n";
for (int i = 0; i < wireCount; i++) {
//boardOutlineSection += itos( outlineNum ) + pad +
// rtos( GetX1FromPtString( outlinePoints[ i ] ) ) + pad +
// rtos( GetY1FromPtString( outlinePoints[ i ] ) ) + pad + "0\n";
outlinePoints[i] = SetUsedFlag(outlinePoints[i]);
//get line end points
bx2 = GetX2FromPtString(outlinePoints[i]);
by2 = GetY2FromPtString(outlinePoints[i]);
//handle initializations, new outlines, and closed outline checks.
if (i == 0) {
startX = GetX1FromPtString(outlinePoints[i]);
startY = GetY1FromPtString(outlinePoints[i]);
boardOutlineSection += itos(outlineNum) + pad
+ rtos(GetX1FromPtString(outlinePoints[i])) + pad
+ rtos(GetY1FromPtString(outlinePoints[i])) + pad + "0\n";
newOutline = 0;
}
else if (newOutline) {
startX = GetX1FromPtString(outlinePoints[i]);
startY = GetY1FromPtString(outlinePoints[i]);
boardOutlineSection += itos(outlineNum) + pad
+ rtos(GetX1FromPtString(outlinePoints[i])) + pad
+ rtos(GetY1FromPtString(outlinePoints[i])) + pad + "0\n";
newOutline = 0;
}
//check if point closes outline
else if (GetDistBetweenPts(startX, startY,
GetX2FromPtString(outlinePoints[i]),
GetY2FromPtString(outlinePoints[i])) == 0) {
boardOutlineSection += itos(outlineNum) + pad
+ rtos(GetX2FromPtString(outlinePoints[i])) + pad
+ rtos(GetY2FromPtString(outlinePoints[i])) + pad + "0\n";
outlineNum++;
newOutline = 1;
continue;
} //end if
else if (GetDistBetweenPts(startX, startY,
GetX2FromPtString(outlinePoints[i]),
GetY2FromPtString(outlinePoints[i])) <= Tolerance) {
boardOutlineSection += itos(outlineNum) + pad + rtos(startX) + pad
+ rtos(startY) + pad + "0\n";
outlineNum++;
newOutline = 1;
continue;
} //end if
matchFound = 0;
//inner loop thru points to find matching line
for (int j = 0; j < wireCount; j++) {
//boardOutlineSectionDebug += "Checking points for i=" + itos( i ) + " and j=" + itos( j ) + ".\n";
//check if line Is already used. if it Is then skip it
if (!IsUsedPoint(outlinePoints[j])) {
//check for exact match on line start
if (GetDistBetweenPts(bx2, by2,
GetX1FromPtString(outlinePoints[j]),
GetY1FromPtString(outlinePoints[j])) == 0) {
boardOutlineSectionDebug += "*Exact match for i=" + itos(i)
+ " and j=" + itos(j) + ".\n";
boardOutlineSectionDebug += "*i point " + outlinePoints[i];
boardOutlineSection += itos(outlineNum) + pad
+ rtos(GetX1FromPtString(outlinePoints[j])) + pad
+ rtos(GetY1FromPtString(outlinePoints[j])) + pad
+ "0\n";
//flag points as used
outlinePoints[j] = SetUsedFlag(outlinePoints[j]);
//swap matched point with current point
//outlinePoints = swapPoints( outlinePoints, (i+1), j );
toPoints = outlinePoints[j];
fromPoints = outlinePoints[(i + 1)];
//move toIndex to from position
outlinePoints[(i + 1)] = toPoints;
outlinePoints[j] = fromPoints;
matchFound = 1;
break;
}
//check for exact match on line end
else if (GetDistBetweenPts(bx2, by2,
GetX2FromPtString(outlinePoints[j]),
GetY2FromPtString(outlinePoints[j])) == 0) {
boardOutlineSectionDebug += "*Exact match for i=" + itos(i)
+ " and j=" + itos(j) + ".\n";
boardOutlineSectionDebug += "*i point " + outlinePoints[i];
boardOutlineSection += itos(outlineNum) + pad
+ rtos(GetX2FromPtString(outlinePoints[j])) + pad
+ rtos(GetY2FromPtString(outlinePoints[j])) + pad
+ "0\n";
//flag point as used
outlinePoints[j] = SetUsedFlag(outlinePoints[j]);
boardOutlineSectionDebug += "\t*Before flip \t"
+ outlinePoints[j];
//flip point
outlinePoints[j] = FlipPoints(outlinePoints[j]);
boardOutlineSectionDebug += "\t*After flip \t"
+ outlinePoints[j];
//swap matched point with current point
//outlinePoints = swapPoints( outlinePoints, (i+1), j );
toPoints = outlinePoints[j];
fromPoints = outlinePoints[(i + 1)];
//move toIndex to from position
outlinePoints[(i + 1)] = toPoints;
outlinePoints[j] = fromPoints;
matchFound = 1;
break;
}
//check for Tolerance match on line start
else if (GetDistBetweenPts(bx2, by2,
GetX1FromPtString(outlinePoints[j]),
GetY1FromPtString(outlinePoints[j])) <= Tolerance) {
boardOutlineSectionDebug += "*Tolerance match for i="
+ itos(i) + " and j=" + itos(j) + ". Dist="
+ rtos(
GetDistBetweenPts(bx2, by2,
GetX1FromPtString(outlinePoints[j]),
GetY1FromPtString(
outlinePoints[j]))) + "\n";
boardOutlineSectionDebug += "*i point " + outlinePoints[i];
boardOutlineSection += itos(outlineNum) + pad + rtos(bx2)
+ pad + rtos(by2) + pad + "0\n";
boardOutlineSectionDebug += "\t*Before fix for Tolerance \t"
+ outlinePoints[j];
//update matched point start points to prev line end points to fix the gap
sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx2, by2,
GetX2FromPtString(outlinePoints[j]),
GetY2FromPtString(outlinePoints[j]));
outlinePoints[j] = temp;
boardOutlineSectionDebug += "\t*After fix for Tolerance \t"
+ outlinePoints[j];
//flag points as used
outlinePoints[j] = SetUsedFlag(outlinePoints[j]);
//swap matched point with current point
//outlinePoints = swapPoints( outlinePoints, (i+1), j );
toPoints = outlinePoints[j];
fromPoints = outlinePoints[(i + 1)];
//move toIndex to from position
outlinePoints[(i + 1)] = toPoints;
outlinePoints[j] = fromPoints;
matchFound = 1;
break;
}
//check for Tolerance match on line end
else if (GetDistBetweenPts(bx2, by2,
GetX2FromPtString(outlinePoints[j]),
GetY2FromPtString(outlinePoints[j])) <= Tolerance) {
boardOutlineSectionDebug += "*Tolerance match for i="
+ itos(i) + " and j=" + itos(j) + ". Dist="
+ rtos(
GetDistBetweenPts(bx2, by2,
GetX2FromPtString(outlinePoints[j]),
GetY2FromPtString(
outlinePoints[j]))) + "\n";
boardOutlineSectionDebug += "*i point " + outlinePoints[i];
boardOutlineSection += itos(outlineNum) + pad + rtos(bx2)
+ pad + rtos(by2) + pad + "0\n";
boardOutlineSectionDebug += "\t*Before fix for Tolerance \t"
+ outlinePoints[j];
//update matched point start points to prev line end points to fix the gap
sprintf(temp, "%f\t%f\t%f\t%f\tn\n",
GetX1FromPtString(outlinePoints[j]),
GetY1FromPtString(outlinePoints[j]), bx2, by2);
outlinePoints[j] = temp;
boardOutlineSectionDebug += "\t*After fix for Tolerance \t"
+ outlinePoints[j];
//flag points as used
outlinePoints[j] = SetUsedFlag(outlinePoints[j]);
boardOutlineSectionDebug += "\t*Before flip \t"
+ outlinePoints[j];
//flip point
outlinePoints[j] = FlipPoints(outlinePoints[j]);
boardOutlineSectionDebug += "\t*After flip \t"
+ outlinePoints[j];
//swap matched point with current point
//outlinePoints = swapPoints( outlinePoints, (i+1), j );
toPoints = outlinePoints[j];
fromPoints = outlinePoints[(i + 1)];
//move toIndex to from position
outlinePoints[(i + 1)] = toPoints;
outlinePoints[j] = fromPoints;
matchFound = 1;
break;
}
//else line has not matching point.
else {
//boardOutlineSectionDebug += "No match for i=" + itos( i ) + " and j=" + itos( j ) + ".\n";
} //end if-else
} else {
//do nothing for skipped line
//boardOutlineSectionDebug += "Points skipped for i=" + itos( i ) + " and j=" + itos( j ) + ".\n";
} //end if/else
} //end j loop
//check to make sure a matching point was found. if not notify user and mark on board.
if (!matchFound) {
boardOutlineSectionDebug += "No match for i=" + itos(i) + ".\n";
//if no match found then generate circle command and exit.
string circleDefectCommands;
string runCommands;
sprintf(circleDefectCommands, "CIRCLE (%f %f) (%f %f);",
BackConvertDimensions(bx2), BackConvertDimensions(by2),
BackConvertDimensions(bx2 + 2.0),
BackConvertDimensions(by2));
//delete existing Debug layer if it exists
runCommands += RemoveIDFDebugLayerCommands();
//get Debug layer number
string debugLayerNum = GetIDFDebugLayerAvailNum();
//dlgMessageBox( "A fatal defect was found in your board outline in the form\n" +
// "of a gap in the board outline. We cannot repair this defect.\n\n" +
// "Defects will be shown on layer " + debugLayerNum + " with red circles." );
dlgMessageBox(
"An error was found in your board outline that cannot be automatically repaired. Outlines must be enclosed loops.\n"
+ "Defects will be shown on layer " + debugLayerNum
+ " with red circles.");
string wireCommands = "change width 0.01;\nSET Wire_Bend 2;\n";
if (Debug) {
boardOutlineSectionDebug +=
"########### array after sorts ###########\n";
//build wire commands that will draw the outlines that have been matched. the last wire will be drawn but it has no match
for (int j = 0; j < wireCount; j++) {
sprintf(temp, "%d\t%s", j, outlinePoints[j]);
boardOutlineSectionDebug += temp;
if (IsUsedPoint(outlinePoints[j])) {
wireCommands += "WIRE ( "
+ rtos(
BackConvertDimensions(
GetX1FromPtString(
outlinePoints[j])))
+ " "
+ rtos(
BackConvertDimensions(
GetY1FromPtString(
outlinePoints[j])))
+ ") ("
+ rtos(
BackConvertDimensions(
GetX2FromPtString(
outlinePoints[j])))
+ " "
+ rtos(
BackConvertDimensions(
GetY2FromPtString(
outlinePoints[j])))
+ ");";
}
} //end for
} //end if
//circleDefectCommands = "LAYER 100 IDFDebug;SET COLOR_LAYER 100 red;CHANGE WIDTH 0.01;" +
//removed change width comand
runCommands += "LAYER " + debugLayerNum + " IDFDebug;"
+ "SET COLOR_LAYER " + debugLayerNum + " red;"
+ circleDefectCommands + wireCommands + "DISPLAY NONE;"
+ "DISPLAY 20 " + debugLayerNum + ";" + "WINDOW FIT;";
if (Debug) {
WriteToFile(logFilePath,
boardOutlineSectionDebug + "***************\n"
+ runCommands + "***************\n"
+ boardOutlineSection);
}
exit(runCommands);
} //end if for matchfound
} //end i loop
if (Debug) {
boardOutlineSectionDebug +=
"########### array after sorts ###########\n";
for (int j = 0; j < wireCount; j++) {
sprintf(temp, "%d\t%s", j, outlinePoints[j]);
boardOutlineSectionDebug += temp;
} //end for
} //end if
if (Debug) {
WriteToFile(logFilePath,
boardOutlineSectionDebug + "***************\n"
+ boardOutlineSection);
}
boardOutlineSection += ".END_BOARD_OUTLINE\n";
return boardOutlineSection;
} //end GetEmnBoardOutline
string GetEmnDrilledHoles() {
/*
.DRILLED_HOLES
40.0 1773.0 1207.5 PTH S1 PIN ECAD
40.0 1773.0 1384.5 PTH S1 PIN ECAD
40.0 2029.0 1207.5 PTH S1 PIN ECAD
...
.END_DRILLED_HOLES
*/
string drilledHolesSection = ".DRILLED_HOLES\n";
string temp;
int holeCount = 0;
board(BRD)
{
//loop thru holes
BRD.holes(H)
{
sprintf(temp, "%10.4f%10.4f%10.4f NPTH BOARD OTHER UNOWNED\n",
(GetDimInBoardUnits(H.drill)), (GetDimInBoardUnits(H.x)),
(GetDimInBoardUnits(H.y)));
drilledHolesSection += temp;
holeCount++;
} //end holes
//get any holes from packages on elements
BRD.elements(E)
{
E.package.holes(C)
{
sprintf(temp, "%10.4f%10.4f%10.4f NPTH %-4s PIN UNOWNED\n",
(GetDimInBoardUnits(C.drill)),
(GetDimInBoardUnits(C.x)), (GetDimInBoardUnits(C.y)),
E.name);
drilledHolesSection += temp;
holeCount++;
} //end package.holes
E.package.contacts(P)
{
if (P.pad) {
sprintf(temp, "%.2f %.2f %.2f PTH BOARD VIA UNOWNED\n",
GetDimInBoardUnits(P.pad.drill),
GetDimInBoardUnits(P.x), GetDimInBoardUnits(P.y));
drilledHolesSection += temp;
holeCount++;
} //end if
} //end loop thru contacts
} //end elements
//get any holes on vias
BRD.signals(S)
{
S.vias(V)
{
sprintf(temp, "%10.4f%10.4f%10.4f NPTH BOARD OTHER UNOWNED\n",
(GetDimInBoardUnits(V.drill)),
(GetDimInBoardUnits(V.x)), (GetDimInBoardUnits(V.y)));
drilledHolesSection += temp;
holeCount++;
}
}
} //end board loop
//close drilled holes section
drilledHolesSection += ".END_DRILLED_HOLES\n";
//check if drilled holes Is empty and if so clear it
if (holeCount == 0) {
drilledHolesSection = "";
}
return drilledHolesSection;
} //end sub
string GetEmnPlacements() {
/*
.PLACEMENT
0805 RES R4
2300.0 1275.0 0.0 180.0 TOP PLACED
0805 CAP C13
2565.0 1380.0 0.0 0.0 TOP PLACED
>
...
.END_PLACEMENT
*/
string sideMap[] = { "TOP", "BOTTOM" };
string placementSection;
string footprint;
string altname;
string ref_id;
string components[];
string component;
string temp;
string side;
string height;
placementSection = ".PLACEMENT\n";
//loop thru elements on board
board(BRD)
{
int i = 0;
BRD.elements(E)
{
LibraryLookup = lookup(Libraries, strupr(E.package.library), 0);
//logic to setup footprint an altname values
if (LibraryLookup != "") {
//if found in LibraryLookup then assign package name to both footprint and altname
altname = E.package.name;
footprint = E.package.name;
} else if (E.value != "") {
//if e.value Is not empty then put it in the footprint
altname = E.value;
footprint = E.package.name;
} else {
//if library Is not in list and the E.value Is blank then concat refid and package name
altname = E.name + "_" + E.package.name;
footprint = E.package.name;
} //end if-else
footprint = CleanString(footprint);
altname = CleanString(altname);
ref_id = E.name;
ref_id = CleanString(ref_id);
//get side value based on mirror value
side = sideMap[E.mirror];
//check if height set for element. if not set then set to NULL_HEIGHT
height = GetElementHeightAttr( E );
//if height is not set then set to default
if (height == NULL_HEIGHT) {
height = "1.0"; //set to value of 1.0
}
//if default height then dont append to altname. otherwise put unique height on altname
if( height == "1.0" ){
sprintf(temp, "%s %s %s\n%f %f 0 %f %s PLACED\n", footprint,
altname, ref_id, GetDimInBoardUnits(E.x),
GetDimInBoardUnits(E.y), E.angle, side);
//add component to components list
components[i] = footprint + "~" + altname;
}
else{
sprintf(temp, "%s %s %s\n%f %f 0 %f %s PLACED\n", footprint + "_" + height,
altname + "_" + height, ref_id, GetDimInBoardUnits(E.x),
GetDimInBoardUnits(E.y), E.angle, side);
//add component to components list
components[i] = footprint + "_" + height + "~" + altname + "_" + height;
} //end if-else
placementSection += temp;
i++;
} //end loop thru elements
} //end loop thru board
placementSection += ".END_PLACEMENT\n";
return placementSection;
} //end sub
string GenerateEmn() {
//build emn file
string emn = GetEmnHeader() + GetEmnBoardOutline() + GetEmnDrilledHoles()
+ GetEmnPlacements();
return emn;
} //end sub
string GenerateEmp() {
//build emp file
string emp = GetEmpHeader() + GetEmpElectrical() + GetEmpMechanical();
return emp;
} //end sub
//Submits emn and emp data to IDF site. IDF returns full html page.
void SubmitFormData(){
//update user now as the post will take some time to start
TextMessageDialog = GetHtmlText( "
3D build request submitted. Please wait for update...
" );
dlgRedisplay();
if( 0 ){
dlgMessageBox( path_ulp[0] );
}
//get board name
string boardName;
string boardDir;
board( BRD ){
boardName = filename( BRD.name );
boardDir = filedir( BRD.name );
} //end board
//get emn and emp strings
string emnData = GenerateEmn() + "\n";
string empData = GenerateEmp() + "\n";
//convert to html format
emnData = ParseStringToHtmlForm( emnData );
empData = ParseStringToHtmlForm( empData );
//data for url post
string postResponse;
string postData;
int requestSubmitted = 0;
string urlParams;
//strings used to build some html elements
string tempStr;
string thumbnailImg;
string pdf3dLink;
string thumbnailLink;
string purchaseStlLink;
string purchaseDownloadLink;
string complete3DDesignLink;
//response data
string jobId;
string jobStatus;
string percentComplete;
string sessionKey;
string sessionLink;
string downloadPurchaseUrl;
string stlPurchaseUrl;
string complete3DDesignUrl;
int jobCompleted = 0;
//submit post and get response
sprintf( postData,"emn=%s\nemp=%s\nboardname=%s\nversion=%s", emnData, empData, boardName, version );
if( netpost( postResponse, Service_url, postData ) >= 0 ) {
//dlgMessageBox( postResponse );
//get session key response
sessionKey = xmltext( postResponse, "response/session_key" );
//sessionLink = xmltext( postResponse, "response/session_link" );
//sprintf( complete3DDesignLink, "Click here to open your board.", sessionLink );
TextMessageDialog =
GetHtmlText( "
Your board has been uploaded and is ready.
\
Your browser will open in the background.
" );
//update display
dlgRedisplay();
string login = Login_url + "?sid=" + sessionKey;
LaunchBrowser( login );
}
else{
//handle error in netpost
TextMessageDialog = GetHtmlText( "We were unable to complete your request at this time. Please try submit again. \
If error persists contact support. \
Contact Support
\
Error Code:" + neterror() + "
Post Response:" + postResponse );
dlgRedisplay();
} //end if-else for posting
//********** old code below **********/
/*
//loop thru form post
for( int i = 0; i < 50000; i++ ){
//only check every 10th loop
if( i % 10 == 0 ){
//check if request has already been submitted
if( !requestSubmitted ){
//load data to post parameters including secondary flag
sprintf( postData,"emn=%s\nemp=%s\nboardname=%s\nsecondary=y\nversion=%s", emnData, empData, boardName, version );
}
else{
//load data to post parameters
sprintf( postData,"id=%s\nsecondary=y", jobId );
} //end if-else
//post data and get response
if( netpost( postResponse, Service_url, postData ) >= 0 ) {
//after first request set to 1/true
requestSubmitted = 1;
//parse xml response data
jobStatus = xmltext( postResponse, "response/status" );
jobId = xmltext( postResponse, "response/id" );
percentComplete = xmltext( postResponse, "response/percent_complete" );
sessionKey = xmltext( postResponse, "response/session_key" );
//get response and parse. first check status
if( jobStatus == "ERROR" ){
//post error to user
TextMessageDialog = GetHtmlText( "Error in netpost. Please try submit again. If error persists contact support. Contact Support" );
dlgRedisplay();
break;
}
else if( jobStatus == "ACTIVE" || jobStatus == "NOT STARTED" || jobStatus == "not started" ){
//sprintf( tempStr, "%sRequest is active. Percent Complete: %s
", tagImgActive, percentComplete);
sprintf( tempStr, "
Request is active.
Percent Complete: %s%%
", percentComplete );
TextMessageDialog = GetHtmlText( tempStr );
}
else if( jobStatus == "COMPLETE" ){
//set job complete flag
jobCompleted = 1;
//dlgMessageBox( postResponse );
//get link from xml response
//downloadPurchaseUrl = xmltext( postResponse, "response/betaDownloadKey" );
//stlPurchaseUrl = xmltext( postResponse, "response/betaStlKey" );
//complete3DDesignUrl = xmltext( postResponse, "response/betaComplete3DDesignKey" );
complete3DDesignUrl = xmltext( postResponse, "response/complete3DDesignKey" );
//build image link
sprintf( thumbnailImg, "
", sessionKey);
sprintf( thumbnailLink, "Open Larger Thumbnail - Free", sessionKey);
sprintf( pdf3dLink, "Click here", sessionKey);
//links for purchase
//sprintf( purchaseDownloadLink, "Click here", downloadPurchaseUrl );
//sprintf( purchaseStlLink, "Click here", stlPurchaseUrl );
sprintf( complete3DDesignLink, "Click here", complete3DDesignUrl );
TextMessageDialog =
GetHtmlText( "Generating data complete: A session to map your components with our 3D database is ready.
\
The picture shows your board and components that could be mapped automatically. \
\
\
" + thumbnailImg + " Important: Automatic component mapping works only with the original EAGLE Library. Components shown in red can be mapped manually. | \
\
" + complete3DDesignLink + " to complete the component mapping manually \
\
- Use of our IDF-to-3D tool is free
\
- Generate a 3D PDF of your 3D Board Assembly at no cost
\
- Incorporate additional 3D Models to your design by using our IDF-to-3D model library and 3D STEP Model integration tool
\
\
If satisfied with your 3D image:
\
" + pdf3dLink + " to open a 3D PDF (Free)
\
| \
\
" );
//update display
dlgRedisplay();
break;
}
else{
TextMessageDialog = GetHtmlText( "There was an error in your request. Please try submit again. \
If error persists contact support. \
Contact Support
\
Error Code:" + neterror() + " - Unable to parse xml response
\
XML Response:" + postResponse );
dlgRedisplay();
//dlgMessageBox( postResponse );
break;
}
//this is needed to update the text display
dlgRedisplay();
}
else{
//handle error in netpost
TextMessageDialog = GetHtmlText( "We were unable to complete your request at this time. Please try submit again. \
If error persists contact support. \
Contact Support
\
Error Code:" + neterror() + "
Post Response:" + postResponse );
dlgRedisplay();
break;
} //end if-else
}
} //end for
//alert user to job success
if( jobCompleted ){
dlgMessageBox( "Your job is complete" );
}
else{
dlgMessageBox( "Your job ended in error\n Job Status: " + jobStatus );
TextMessageDialog = GetHtmlText( "There was an error in your request. Please try submit again. \
If error persists contact support. \
Contact Support
\
Error Code:" + neterror() + "" );
//force text view to update
dlgRedisplay();
} //end if-else
*/
} //end sub
//main function to generate IDF fils
void GenerateEmnEmpFiles() {
//update user now as the post will take some time to start
TextMessageDialog = GetHtmlText(
"IDF File generation in process.");
HeightHtmlTable = ""; //reset
//refresh display to show message
dlgRedisplay();
//get board name
string boardName;
string boardDir;
board(BRD)
{
boardName = filename(BRD.name);
boardDir = filedir(BRD.name);
} //end board
//get emn and emp strings
string emnData = GenerateEmn();
string empData = GenerateEmp();
//write strings to files
string dirName;
dirName = dlgDirectory("Select a directory to write IDF files to:",
boardDir);
//show path to user
dlgMessageBox(
"Writing IDF Files: " + dirName + GetFileSeperator()
+ filesetext(boardName, ".emn"));
output(dirName + GetFileSeperator() + filesetext(boardName, ".emn"), "wt")
{
printf(emnData);
}
output(dirName + GetFileSeperator() + filesetext(boardName, ".emp"), "wt")
{
printf(empData);
}
//complete height table
HeightHtmlTable =
"The table below shows the components placed in the emn/emp files. \
The height field in the table indicates an extrusion height used in generating the components on the 3D model. \
A default value is set if a value is not set and is indicated in yellow. The values are defined as HEIGHT attribute values and can be updated in the board file. \
Heights are set at the element level and can vary by placement. This may cause unexpected behavior if you only update a single component in the file.
\
| Ref. ID | Alt. Name | Package Name | Height |
"
+ HeightHtmlTable + "
";
//| Ref. ID | Alt. Name | Package Name | Height |
" + HeightHtmlTable + "
";
TextMessageDialog = GetHtmlText(
"IDF Files written successfully to "
+ dirName + "
" + HeightHtmlTable);
} //end sub
void LoadLibraries() {
int libraryCount = 0;
//load library string in to Libraries array
libraryCount = strsplit(Libraries, LibraryLookup, ':');
} //end sub
string GetHomepageBanner(){
string temp;
//get banner along with version and OS data to help with support and detect unsupportedconfigs for future releases
string url = "https://www.simplifiedsolutionsinc.com/EagleTo3D/eagle_to_3d_ssi_banner.php?os=" + OS_SIGNATURE + "&v=" + version;
if( netget( temp, url) >= 0 ){
//pass
return temp;
}
else{
//fail
return "";
} //end if-else
}
string GetHomepageLinks(){
string temp;
string url = "https://www.simplifiedsolutionsinc.com/EagleTo3D/eagle_to_3d_ssi_bullets.php";
if( netget( temp, url) >= 0 ){
//pass
return temp;
}
else{
//fail
return "";
} //end if-else
}
string RunNetworkTests(){
/*
1. Check internet
2. Check SSI site
3. Check SSI site with port
*/
string temp = "";
string internetSite = "http://www.google.com/";
int internetSiteResult = 0;
string internetSiteError = "";
string internetSiteTroubleshootMsg = "";
string ssiSite = "https://www.simplifiedsolutionsinc.com/";
int ssiSiteResult = 0;
string ssiSiteError = "";
string ssiSiteTroubleshootMsg = "";
string ssiWithPortSite = "http://www.simplifiedsolutionsinc.com:8080/";
int ssiWithPortSiteResult = 0;
string ssiWithPortSiteError = "";
string ssiWithPortSiteTroubleshootMsg = "";
if( netget( temp, internetSite ) >= 0 ){
//pass
internetSiteResult = 1;
}
else{
//fail
internetSiteResult = 0;
internetSiteError = neterror();
internetSiteTroubleshootMsg = "We are unable to reach the internet. Please verify your internet connectivity. If you have an internet proxy please configure it under Help->Check for Update->Configure in the Eagle Control Panel window before running the ULP";
} //end if-else
if( netget( temp, ssiSite ) >= 0 ){
//pass
ssiSiteResult = 1;
}
else{
//fail
ssiSiteResult = 0;
ssiSiteError = neterror();
ssiSiteTroubleshootMsg = "We are unable to reach the internet. Please verify your internet connectivity. If you have an internet proxy please configure it under Help->Check for Update->Configure in the Eagle Control Panel window before running the ULP";
} //end if-else
if( netget( temp, ssiWithPortSite ) >= 0 ){
//pass
ssiWithPortSiteResult = 1;
}
else{
//fail
ssiWithPortSiteResult = 0;
ssiWithPortSiteError = neterror();
ssiWithPortSiteTroubleshootMsg = "We are unable to reach the Simplified Solutions site at port 8080. Please verify your internet connectivity. You may need to request your firewall rules be opened for port 8080.";
} //end if-else
//check results of tests
if( internetSiteResult && ssiSiteResult && ssiWithPortSiteResult ){
return "PASS";
}
else{
return internetSiteError + ":" + internetSiteTroubleshootMsg + ";";
}
}
//-----------------------------------------------------------------------------
// main section
//-----------------------------------------------------------------------------
void main() {
//check to make sure board Is loaded
if (!board) {
dlgMessageBox(
usage
+ "
ERROR: No board!\nThis program can only work in the layout editor.
");
exit(-1);
}
//load Libraries array for lookups
LoadLibraries();
//run network test
string networkTestResults = RunNetworkTests();
string networkTestMessage = "";
//dlgMessageBox( strsub( OS_SIGNATURE, 0, 3 ) );
//if network test fails then add in note to homepage
if( networkTestResults == "PASS" ){
networkTestMessage = "";
}
else{
networkTestMessage ="We have detect potential network/web connection issues that may impact the execution of this ULP.
Troubleshooting:" + networkTestResults + "
";
}
//get banner
string homepageBanner = GetHomepageBanner();
//get links
string homepageLinks= GetHomepageLinks();
string startHTML = networkTestMessage + homepageBanner + " \
IDF Options:
\
\
\
\
\
- Click the \"Generate IDF Files\" button to save IDF files to your computer. Import the IDF files into a Mechanical CAD to view components in \"block\" form
\
- Click the \"Build 3D PCB\" button to utilize IDF-to-3D to build a 3D PCB of your active .brd file. The 3D PCB will contain accurate 3D component geometry. STEP files of the 3D PCBs can be downloaded after purchasing a subscription to IDF-to-3D
\
- Click the \"Login to IDF-to-3D\" button to continue working on an existing IDF-to-3D session.
\
<\ol> \
\
" + homepageLinks +
" | \
\
\
| \
";
//set initial text view content
TextMessageDialog = GetHtmlText(startHTML);
//show dialog to user
int mainDlgResult = dlgDialog( "Eagle IDF Exporter" ) {
//main layout
dlgVBoxLayout {
//set width by creating a spacing hbox to drive width
if( IsWindows() ) {
//windows
dlgHBoxLayout dlgSpacing( 800 );//sets width
}
else {
//mac/linux
dlgHBoxLayout dlgSpacing( 825 );//sets width
} //end if-else
//set height and text view
dlgHBoxLayout {
dlgTextView( TextMessageDialog ); //text view. holds html
if( IsWindows() ) {
//windows
dlgVBoxLayout dlgSpacing( 475 );//sets height
}
else {
//mac/linux
dlgVBoxLayout dlgSpacing( 500 );//sets height
} //end if-else
} //end box layout
//add options for IDF export
dlgHBoxLayout {
dlgLabel("Layer for wires (Default=20): ");
dlgStringEdit( WireLayer );
dlgLabel("Board Thickness (MM): ");
dlgStringEdit( BoardThickness );
} //end box layout
//buttons to submit and exit
dlgHBoxLayout {
dlgPushButton( "Generate IDF Files" ) {
//submit data to idf site
GenerateEmnEmpFiles();
} //end button
dlgPushButton( "Build 3D PCB" ) {
//submit data to idf site
SubmitFormData();
} //end button
dlgPushButton( "Login to IDF-to-3D" ) {
LaunchBrowser( Login_url );
} //end button
dlgPushButton( "Exit" ) dlgReject();
} //end box layout
} //end v box layout
}; //end mainDlgResult
} //end main