Skip to content

Instantly share code, notes, and snippets.

@kaysond
Last active January 7, 2021 10:45
Show Gist options
  • Save kaysond/9d6f1a648098ed2c4d6fc179952db29f to your computer and use it in GitHub Desktop.
Save kaysond/9d6f1a648098ed2c4d6fc179952db29f to your computer and use it in GitHub Desktop.
import-dxf-v2.1.ulp - an updated Eagle ULP for DXF imports that supports multiple output layers
#usage "<b>DXFimport</b> V2.1<p>"
"This ULP can import DXF files that include polylines.<br>"
"Browse to the DXF file, setup your origins, input units, scale factor and linewidth then click convert. "
"The ULP will then show you the script in case you want to change the layer the input will be written to.<br>"
"Tested in version 5, 6, 7, and Autodesk EAGLE.<br><br>"
"Command line syntax:<br> run import-dxf.ulp filename TargetLayer Units [options]<br><br>"
"TargetLayer is number from 1-255 that corresponds to the layer that you want the imported features to be drawn on."
"If TargetLayer is set to '0 MultiLayer', StartLayer is a number from 1-255 that corresponds to the first layer to be drawn on. Each different layer in the DXF will be drawn on subsequent EAGLE layers"
"Units is a number where 0 means imperial units and 1 means metric units."
"[options] contains 5 additional arguments that are optional and not required by default."
"Xorg is the origin X coordinate of the new location you want the drawing to import to."
"Yorg is the origin Y coordinate of the new location you want the drawing to import to."
"lwidth is the width of the lines used to draw the dxf objects."
"scale allows you increase or decrease the dimensions of the dxf by a user defined factor."
"The second to last argument is a three digit number indicating if the Xorg, Yorg, and width should be scaled. The value for each is"
"either zero or 1 where zero means don't scale and 1 means scale."
"The last argument is the StartLayer, which is used only if TargetLayer is 0 (defaults to 200).<br><br>"
"A complete example would be:<br>"
"run import-dxf.ulp C:\\myfile.dxf 20 0 1.2 3.1 0.001 1.5 001<br><br>"
"myfile.dxf is being imported to layer 20 with imperial units, the new origin is at (1.2 3.1) the linewidth is 0.001 inches."
"The dxf file is being scaled by a factor of 1.5 with the Xorg and Yorg not being scaled but the linewidth being scaled by 1.5 also."
"When running the ULP through the command line the previous settings are not loaded."
"<author>Written by Jorge Garcia of Cadsoft Computer, heavily based off of Hank Wallace's DXF2SCR program.</author><br>"
"With special thanks to Robert Starr, Alfred Zaffran, Billy Coleman, Holger Moessinger."
string Version = "2.1";
string Help = "<b>DXFimport "+Version+ "</b>\n <p>This ULP will import a DXF \
file into EAGLE (Board, Schematic, Package or Symbol-Editor). \
Use the browse button to find the DXF file, make sure to set \
the units to whatever units are used by the DXF file. Set the width, Xorg, and \
Yorg in whatever units you selected. Then set an appropriate scale factor and \
click the OK button, the generated script will be shown for editing. Once \
it's adjusted to your liking click Run.</p>\n run import-dxf.ulp filename TargetLayer Units [options]\n \
<p>TargetLayer is number from 1-255 that corresponds to the layer that you want the imported features to be drawn on. \
If TargetLayer is set to '0 MultiLayer', StartLayer is a number from 1-255 that corresponds to the first layer to be drawn on. Each different layer in the DXF will be drawn on subsequent EAGLE layers. \
Units is a number 0 means imperial units and 1 means metric units. \
[options] contains 5 additional arguments that are optional and not required by default. \
Xorg is the X coordinate of the new location you want the drawing to import to. \
Yorg is the Y coordinate of the new location you want the drawing to import to. Linewidth allows you to \
pick the width of the lines used to draw the dxf objects. Scale allows you increase or decrease the dimensions of the dxf by a user defined factor. \
The second to last argument is a three digit number indicating if the Xorg, Yorg, and width should be scaled. The value for each is \
either zero or 1 where zero means don't scale and 1 means scale. \
The last argument is the StartLayer, which is used only if TargetLayer is 0 (defaults to 200).</p>\n \
A complete example would be:\n \
run import-dxf.ulp C:\\myfile.dxf 20 0 1.2 3.1 0.001 1.5 001\n \
myfile.dxf is being imported to layer 20 with imperial units, the new origin is at (1.2 3.1) the linewidth is 0.001 inches. \
The dxf file is being scaled by a factor of 1.5 with the Xorg and Yorg not being scaled but the linewidth being scaled by 1.5 also. \
When running from the command line settings are not stored.";
/* *******************************************************************
REVISION HISTORY
2012-03-03 Initial Release.
2012-06-19 Finally incorporated Holger Moessinger's improvements to
the polygon import, added him to special thanks section.
2012-07-10 Added support for LWPOLYLINE.
2013-02-13 Check maximum coodinate of eagle, Alfred Zaffran. This
feature keeps track of the size of the DXF file, if it's
outside the drawing limits of EAGLE the ULP will recognize
this and suggest a corrective offset which the user can
approve.
2013-06-12 Discovered that some files don't implement the proper
spacing so I modified the ULP to cope with that.
2014-03-12 Implemented the ability to skip the section search state.
Some DXF files don't have an ENTITIES section which the old
ULP expected. This allows the ULP to try going through the
file again without expecting an ENTITIES section. The
downside is that some extraneous stuff may come in on the
import but usually the user will be able to tell and remove
those features. The generated script file has a comment
added to it when EAGLE uses that feature.
2014-03-12 Assimilated Billy Coleman's scaling functionality. Added
him to the thank you list in the description.
2014-03-13 Implemented a flag in the LWPOLYLINE state of dxf() to
make sure the state isn't exited, before processing the
object. Similar improvements where made in the VERTEX
state of DXF.
2015-02-10 make target layer selectable [email protected]
2017-04-06 fixed critical LWPOLYLINE bug JG
2017-06-05 fixed subtle LWPOLYLINE bug where a value of 0 causes
the LWPOLYLINE object to be exited early. JG
2017-08-18 Added command line support. JG
2019-03-07 Added MultiLayer support. Aram Akhavan
********************************************************************* */
/* ***********************************************************************
Below I have retained Mr. Wallace's original "licensing" statement for two
reasons:
1. As a sign of respect for the original author of the code from which this
ULP was developed and without which it would have not been possible to
develop this ULP.
2. This is quite possibly the funniest licensing statement any one will
ever read.
Officially though, I will license this under the MIT open software license
copied below:
Copyright (c) 2012 Newark, Premier Farnell DBA Cadsoft Computer
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to
do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Jorge Garcia
03-Mar-2012
----------------------------------------------------------------------
DXF2SCR.C
Program that crunches a DXF file with circles, arcs and lines into an
Eagle script file, useful for translating board outlines.
Hank Wallace 20-Mar-03
Revision 20-Mar-03
There are two licensing options for this program:
1. If you are a fan of the GNU license, and you think you
understand it, and you think it is reasonable, and you believe
that 'free to download' means 'high quality' or 'low maintenance
cost', and you are a computer geek who cannot get a date who
measures the value of his/her existence by the number of
marginally useful command line options you can stuff into one
program on a lonely Friday night, and you write C source code in
such a manner that there are more #define'd constants and
conditional compilation directives than there are actual C
source statements, and you attempt to make your programs so
'portable' that they runs on no machine whatsoever without
modification, then you have no license to use this software. Get
a life.
2. If you one of the other 6 billion people on planet Earth,
this program source code and executable is free for your use
without restriction, but NO WARRANTY OR SUPPORT IS GIVEN.
This program compiles under Microsoft's command line compiler, version 12.00.
-----------------------------------------------------------------------------
************************************************************************** */
/* ************************************************************************
* GLOBAL VARIABLES
************************************************************************** */
//include "debug.ulp"
string ConfigFileName = filesetext(argv[0], ".cfg");
real XMax; /* Maximum dimensions of DXF file */
real YMax;
real XMin;
real YMin;
real Exmax = REAL_MAX; /* Maximum dimensions EAGLE can draw in um */
real Eymax = REAL_MAX;
real Exmin = -REAL_MAX;
real Eymin = -REAL_MAX;
real S_factor;
real GUI_scale = 1.0; /* Additional scale factor that can be used to resize dxf */
int GUI_in_unit = 0;
int GUI_scaled_Xorg = 0; /* Checkbox variables */
int GUI_scaled_Yorg = 0;
int GUI_scaled_lwidth = 0;
string GUI_script;
string GUI_fileName;
real GUI_Xorg = 0.0;
real GUI_Yorg = 0.0;
real GUI_lwidth = 0.001;
string GUI_layers[];
GUI_layers[0] = "0 MultiLayer";
int GUI_layerselect = 0;
int GUI_layerstart = 200;
string LayerMap[];
int LayerMapLength = 0;
int Lcnt = 1;
int GUI_TargetLayer = 0;
int SavedTargetLayer = 0;
/*
*******************************************************************************
* NON-GUI FUNCTIONS
*******************************************************************************
*/
/*
*******************************************************************************
* strcomp2()
*
* Description: The purpose of this function is to take the input scompare and
* compare it to strings s1 and s2 for an exact match. If there is
* no match to either string it will return -1, if there is a match
* to one of the strings it will return the index of the
* corresponding strstr function that succeeded.
*
* The strstr function checks to see if a substring shows up within
* a given string, if it does it gives the index where the
* substring shows up within the string. This is not enough to
* ensure an exact match. To ensure an exact match we would need
* the length of the strings to be the the same.
*
* Arguments: scompare String to be compared
* s1 First item to match
* s2 Second item to match
*
* Return: -1 If there is no match
* int If there is a match corresponding to index of strstr
* function that succeeded
*
* Caller: dxf
*
*******************************************************************************
*/
int strcomp2(string scompare, string s1, string s2) {
int result = strstr(scompare, s1);
if(result != -1 && strlen(scompare) == strlen(s1)) {
return result;
}
else {
result = strstr(scompare, s2);
if (result != -1 && strlen(scompare) == strlen(s2)) {
return result;
}
else {
return -1;
}
}
}
/*
*******************************************************************************
* mx() and my()
*
* Description: These functions below are used to find the extreme XY points of
* the DXF file we're importing. This info will later be used to
* make sure the file fits inside the drawing area of EAGLE. They
* modify the drawing Max and Min variables in order to find the
* size of the imported drawing
*
* Arguments: real Real x or y value
*
* Return: real The original x or y value that was passed
*
* Caller: dxf
*
*******************************************************************************
*/
real mx(real x) {
if (XMax < x) XMax = x;
if (XMin > x) XMin = x;
return x;
}
real my(real y) {
if (YMax < y) YMax = y;
if (YMin > y) YMin = y;
return y;
}
/*2019-03-07
*******************************************************************************
* searchlayermap()
*
* Description: This function searches the layer map created by createlayermap()
*
* Arguments: layer The layer name to search
*
* Return: -1 If the layer name is not found
* int Index of the layer name if it is found
*
* Caller: dxf
*
*******************************************************************************
*/
int searchlayermap(string layer) {
int idx;
if (LayerMapLength > 0) {
for (idx = 0; idx < LayerMapLength; idx++) {
if (strstr(LayerMap[idx], layer) != -1 && strlen(LayerMap[idx]) == strlen(layer)) {
return idx;
}
}
}
return -1;
}
/*2019-03-07
*******************************************************************************
* createlayermap()
*
* Description: This function takes a DXF file path and processes it to produce
* an array of DXF layer names whose indices correspond to EAGLE layers
* Unfortunately its necessary to load into a global variable since ULP's
* can't pass arrays or return them
*
* Arguments: dxffile Path to the DXF file to be processed
* ent Skips the search for sections and entities,
* useful for files that don't strictly follow
* the DXF format.
*
* Return: string Returns a script command that adds user layers if necessary
*
* Caller: dxf
*
*******************************************************************************
*/
string createlayermap(string dxffile, int ent) {
string s[]; // This string array will store the DXF file
string out; // Out is the script generated by this function
string temp; // Place holder
string stemp[]; // Place holder for string manipulation
string LayerName; // Output layer name
enum { state_SECTION,
state_ENTITIES,
state_SEARCH,
state_LINE,
state_ARC,
state_CIRCLE,
state_POLYLINE,
state_VERTEX,
state_LWPOLYLINE}; // Defines states for the main state machine
int state;
int nlines;
LayerMapLength = 0;
out = "# Creating layer map\n";
if (ent >= 1) { // Allows the section search to be disabled
state = state_SEARCH;
out += "# Skipped Section Search\n";
}
else {
state = state_SECTION;
}
nlines = fileread(s, dxffile);
for (int m = 0; m < nlines;m++) {
switch (state) {
case state_SECTION: // scan for SECTIONS in the DXF file
if (strstr(s[m],"SECTION") != -1) {
if (ent >= 1) {
state = state_SEARCH;
}
else {
state = state_ENTITIES;
}
}
break;
case state_ENTITIES: // scan for ENTITIES in the DXF file
if (strstr(s[m],"ENDSEC") != -1) {
state = state_SECTION;
}
if (strstr(s[m],"ENTITIES") != -1) {
state = state_SEARCH;
}
break;
case state_SEARCH: // scanning for LINE, ARC, CIRCLE, POLYLINE, SPLINE
if (strstr(s[m],"ENDSEC") != -1) {
if (ent >= 1) {
state = state_SEARCH;
}
else {
state = state_SECTION;
}
}
if (strstr(s[m],"LINE") != -1 && strlen(s[m]) == 4) {
state = state_LINE;
}
if (strstr(s[m],"ARC") != -1 && strlen(s[m]) == 3) {
state = state_ARC;
}
if (strstr(s[m],"CIRCLE") != -1 && strlen(s[m]) == 6) {
state = state_CIRCLE;
}
if (strstr(s[m],"POLYLINE") != -1 && strlen(s[m]) == 8) {
state = state_POLYLINE;
}
if (strstr(s[m],"LWPOLYLINE") != -1 && strlen(s[m]) == 10) { // JG Support for LWPOLYLINE added 07/09/2012
state = state_LWPOLYLINE;
}
break;
case state_LINE:
case state_ARC:
case state_CIRCLE:
case state_POLYLINE:
case state_LWPOLYLINE:
if (strcomp2(s[m], " 8", "8") != -1 || (strstr(s[m], " 8") != -1 && strlen(s[m]) == 3)) {
if (searchlayermap(s[m+1]) == -1) {
LayerMap[LayerMapLength++] = s[m+1];
if (GUI_layerstart + LayerMapLength > 99) {
int LayerNum = GUI_layerstart + LayerMapLength - 1;
// Remove spaces from layer name; not sure if necessary
strsplit(stemp, s[m+1], ' ');
LayerName = strjoin(stemp, '_');
sprintf(temp, "#%s\nLAYER %d %ddxf-%s;\n", s[m+1], LayerNum, LayerNum, LayerName);
sprintf(temp, "%sSET FILL_LAYER %d 10;\n", temp, LayerNum);
sprintf(temp, "%sSET COLOR_LAYER %d %d;\n", temp, LayerNum, LayerMapLength);
out += temp;
}
}
state = state_SEARCH;
}
break;
} //case state
} //for lines
return out;
} //createlayermap()
/*
*******************************************************************************
* dxf()
*
* Description: This function takes a DXF file path and processes it to produce
* a script full of commands to draw the contents of the DXF file
* in EAGLE.
*
* Arguments: dxffile Path to the DXF file to be processed
* units Units of the DXF file
* xorigin User defined offset in the X direction
* yorigin User defined offset in the Y direction
* liwidth User defined line width
* ent Skips the search for sections and entities,
* useful for files that don't strictly follow
* the DXF format.
* scale Optional scaling factor to increase or decrease
* the size of the DXF file
*
* Return: string A long string full of EAGLE commands
*
* Caller: checkscript
*
*******************************************************************************
*/
string dxf(string dxffile, int units, real xorigin, real yorigin, real liwidth, int ent, real scale) {
string s[]; // This string array will store the DXF file
string out; // Out is the script generated by this function
string temp; // Place holder
enum { state_SECTION,
state_ENTITIES,
state_SEARCH,
state_LINE,
state_ARC,
state_CIRCLE,
state_POLYLINE,
state_VERTEX,
state_LWPOLYLINE}; // Defines states for the main state machine
enum { order_LAYER,
order_FIRST,
order_SECOND,
order_THIRD,
order_FOURTH,
order_FIFTH}; // Defines states for the secondary state machines
int i; // index variable for xa and ya
int p; // dummy variable for for loop
int m; // dummy variable for main while loop
int nlines; // number of lines in the text file
int state;
int order; // Used for internal state machines
int lines;
int arcs;
int circles;
int polylines;
int linewidth=1;
int LWPOLY_FLAG=1; // See comment in LWPOLYLINE state
int layernum;
real x;
real y;
real x1;
real y1;
real x2;
real y2;
real x3;
real y3;
real r;
real theta1;
real theta3;
real xorg;
real yorg;
real xa[]; // xa and ya arrays hold the possible vertexes of a polyline
real ya[];
real plclosed;
real bulgevalue[]; // plclosed and bulgevalue array helps in dealing with...
// ... closed polylines
if (units == 1) { // Setup unit scale factor
S_factor = 1000; // Convert mm to um
XMax = u2mm(INT_MIN)*S_factor;
YMax = u2mm(INT_MIN)*S_factor;
XMin = u2mm(INT_MAX)*S_factor;
YMin = u2mm(INT_MAX)*S_factor;
}
else {
S_factor = 25400; // Convert in to um
XMax = u2inch(INT_MIN)*S_factor;
YMax = u2inch(INT_MIN)*S_factor;
XMin = u2inch(INT_MAX)*S_factor;
YMin = u2inch(INT_MAX)*S_factor;
}
linewidth = liwidth * S_factor;
xorg = xorigin * S_factor;
yorg = yorigin * S_factor;
S_factor *= scale; // Added scale factor affects everything except xorg, ...
// ... yorg and linewidth those are handled by the GUI
out += "# dxfimport generated script file.\n";
out += "Grid mic 1 off;\n";
out += "Set Wire_Bend 2;\n";
if (GUI_TargetLayer == 0) {
out += createlayermap(dxffile, ent);
}
else {
sprintf(temp, "CHANGE LAYER %d;\n", GUI_TargetLayer); // 2015-02-10
out += temp;
}
out += "Change Font Vector;\n";
if (ent >= 1) { // Allows the section search to be disabled
state = state_SEARCH;
out += "# Skipped Section Search\n";
}
else {
state = state_SECTION;
}
order = order_LAYER;
lines = arcs = circles = polylines = 0;
nlines = fileread(s, dxffile);
for (m = 0;m < nlines;m++) {
switch (state) {
case state_SECTION: // scan for SECTIONS in the DXF file
if (strstr(s[m],"SECTION") != -1) {
if (ent >= 1) {
state = state_SEARCH;
}
else {
state = state_ENTITIES;
}
}
break;
case state_ENTITIES: // scan for ENTITIES in the DXF file
if (strstr(s[m],"ENDSEC") != -1) {
state = state_SECTION;
}
if (strstr(s[m],"ENTITIES") != -1) {
state = state_SEARCH;
}
break;
case state_SEARCH: // scanning for LINE, ARC, CIRCLE, POLYLINE, SPLINE
if (strstr(s[m],"ENDSEC") != -1) {
if (ent >= 1) {
state = state_SEARCH;
}
else {
state = state_SECTION;
}
}
if (strstr(s[m],"LINE") != -1 && strlen(s[m]) == 4) {
state = state_LINE;
lines++;
}
if (strstr(s[m],"ARC") != -1 && strlen(s[m]) == 3) {
state = state_ARC;
arcs++;
}
if (strstr(s[m],"CIRCLE") != -1 && strlen(s[m]) == 6) {
state = state_CIRCLE;
circles++;
}
if (strstr(s[m],"POLYLINE") != -1 && strlen(s[m]) == 8) {
i=0;
state = state_POLYLINE;
polylines++;
}
if (strstr(s[m],"LWPOLYLINE") != -1 && strlen(s[m]) == 10) {
i=0; // JG Support for LWPOLYLINE added 07/09/2012
state = state_LWPOLYLINE;
polylines++;
}
break;
case state_LINE: // absorbing LINE
switch(order) { // LINE 8, 10, 20, 30 (start point), 11, 21, 31 (end point).
case order_LAYER:
if (GUI_TargetLayer == 0) {
if (strcomp2(s[m], " 8", "8") != -1 || (strstr(s[m], " 8") != -1 && strlen(s[m]) == 3)) {
layernum = searchlayermap(s[m+1]);
if (layernum != -1) {
sprintf(temp, "LAYER %d\n", GUI_layerstart + layernum);
out += temp;
}
else {
out += "# Could not determine layer from map\n";
}
order = order_FIRST;
}
break;
}
case order_FIRST:
if (strcomp2(s[m], " 10", "10") != -1) {
x = S_factor*strtod(s[m+1]);
order = order_SECOND;
}
break;
case order_SECOND:
if (strcomp2(s[m], " 20", "20") != -1) {
y = S_factor*strtod(s[m+1]);
order = order_THIRD;
}
break;
case order_THIRD:
if (strcomp2(s[m], " 11", "11") != -1) {
x1 = S_factor*strtod(s[m+1]);
order = order_FOURTH;
}
break;
case order_FOURTH:
if (strcomp2(s[m], " 21", "21") != -1) {
y1 = S_factor*strtod(s[m+1]);
sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
linewidth,
mx(x+xorg),
my(y+yorg),
mx(x1+xorg),
my(y1+yorg)
);
out += temp; // Write to script
state = state_SEARCH;
order = order_LAYER;
}
break;
}
break;
case state_ARC: // absorbing ARC
switch(order) { // ARC 8, 10, 20, 30 (center), 40 (radius), 50 (start angle), 51 (end)
case order_LAYER:
if (GUI_TargetLayer == 0) {
if (strcomp2(s[m], " 8", "8") != -1 || (strstr(s[m], " 8") != -1 && strlen(s[m]) == 3)) {
layernum = searchlayermap(s[m+1]);
if (layernum != -1) {
sprintf(temp, "LAYER %d\n", GUI_layerstart + layernum);
out += temp;
}
else {
out += "# Could not determine layer from map\n";
}
order = order_LAYER;
}
break;
}
case order_FIRST:
if (strcomp2(s[m], " 10", "10") != -1) {
x = S_factor*strtod(s[m+1]);
order = order_SECOND;
}
break;
case order_SECOND:
if (strcomp2(s[m], " 20", "20") != -1) {
y = S_factor*strtod(s[m+1]);
order = order_THIRD;
}
break;
case order_THIRD:
if (strcomp2(s[m], " 40", "40") != -1) {
r = S_factor*strtod(s[m+1]);
order = order_FOURTH;
}
break;
case order_FOURTH:
if (strcomp2(s[m], " 50", "50") != -1) {
theta1 = strtod(s[m+1]);
theta1 *= (PI/180);
order = order_FIFTH;
}
break;
case order_FIFTH:
if (strcomp2(s[m], " 51", "51") != -1) {
theta3 = strtod(s[m+1]);
theta3 *= (PI/180);
x1 = r*cos(theta1)+x; // compute Eagle arc parameters from DXF arc params
y1 = r*sin(theta1)+y;
x2 = x1-2*r*cos(theta1);
y2 = y1-2*r*sin(theta1);
x3 = r*cos(theta3)+x;
y3 = r*sin(theta3)+y;
sprintf(temp, "Arc CCW %d (%0.2f %0.2f) (%0.2f %0.2f) (%0.2f %0.2f);\n",
linewidth,
mx(x1+xorg),
my(y1+yorg),
mx(x2+xorg),
my(y2+yorg),
mx(x3+xorg),
my(y3+yorg)
);
out += temp;
state = state_SEARCH;
order = order_LAYER;
}
break;
}
break;
case state_CIRCLE: // absorbing CIRCLE
switch(order) { // CIRCLE 8, 10, 20, 30 (center), 40 (radius).
case order_LAYER:
if (GUI_TargetLayer == 0) {
if (strcomp2(s[m], " 8", "8") != -1 || (strstr(s[m], " 8") != -1 && strlen(s[m]) == 3)) {
layernum = searchlayermap(s[m+1]);
if (layernum != -1) {
sprintf(temp, "LAYER %d\n", GUI_layerstart + layernum);
out += temp;
}
else {
out += "# Could not determine layer from map\n";
}
order = order_FIRST;
}
break;
}
case order_FIRST:
if (strcomp2(s[m], " 10", "10") != -1) {
x = S_factor*strtod(s[m+1]);
order = order_SECOND;
}
break;
case order_SECOND:
if (strcomp2(s[m], " 20", "20") != -1) {
y = S_factor*strtod(s[m+1]);
order = order_THIRD;
}
break;
case order_THIRD:
if (strcomp2(s[m], " 40", "40") != -1) {
y1 = S_factor*strtod(s[m+1]);
sprintf(temp, "Circle %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
linewidth,
mx(x+xorg),
my(y+yorg),
mx(x+xorg),
my(y+y1+yorg)
);
out += temp;
state = state_SEARCH;
order = order_LAYER;
}
break;
}
break;
case state_POLYLINE: // absorbing POLYLINE
if (GUI_TargetLayer == 0) {
if (strcomp2(s[m], " 8", "8") != -1 || (strstr(s[m], " 8") != -1 && strlen(s[m]) == 3)) {
layernum = searchlayermap(s[m+1]);
if (layernum != -1) {
sprintf(temp, "LAYER %d\n", GUI_layerstart + layernum);
out += temp;
}
else {
out += "# Could not determine layer from map\n";
}
}
}
if (strstr(s[m], "VERTEX") != -1) { // VERTEX
state = state_VERTEX;
}
if (strcomp2(s[m], " 70", "70") != -1) { // EDIT HM 20120425: Determine if Polyline is closed and...
plclosed = strtod(s[m+1]); // ...take care of bulge values for line segments.
}
if (strstr(s[m], "SEQEND") != -1) {
for (p=0; p < i-1;p++) { // n points give n-1 lines that's why there's an i-1 in...
if (bulgevalue[p] != 0) { // ...the conditional
sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n",
linewidth,
mx(xa[p]+xorg),
my(ya[p]+yorg),
(atan(bulgevalue[p])*180/PI*4),
mx(xa[p+1]+xorg),
my(ya[p+1]+yorg)
);
out += temp;
}
else {
sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
linewidth,
mx(xa[p]+xorg),
my(ya[p]+yorg),
mx(xa[p+1]+xorg),
my(ya[p+1]+yorg)
);
out += temp;
}
}
if(plclosed) {
if(bulgevalue[p] != 0) {
sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n",
linewidth,
mx(xa[p]+xorg),
my(ya[p]+yorg),
(atan(bulgevalue[p])*180/PI*4),
mx(xa[0]+xorg),
my(ya[0]+yorg)
);
out += temp;
}
else {
sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
linewidth,
mx(xa[p]+xorg),
my(ya[p]+yorg),
mx(xa[0]+xorg),
my(ya[0]+yorg)
);
out += temp;
}
}
state = state_SEARCH;
}
break;
case state_VERTEX: // absorbing VERTEX
switch(order) {
case order_LAYER: // layer should show up in polyline state
case order_FIRST:
if (strcomp2(s[m], " 10", "10") != -1) { // 10 (x-value) 20 (y-value)
xa[i] = S_factor*strtod(s[m+1]);
order = order_SECOND;
}
break;
case order_SECOND:
if (strcomp2(s[m], " 20", "20") != -1) {
ya[i] = S_factor*strtod(s[m+1]); // This avoids a misalignment of the bulge array should...
bulgevalue[i] = 0; // ...one or more polylines not have bulges
order = order_THIRD;
}
break;
case order_THIRD:
if (strcomp2(s[m], " 42", "42") != -1) {
bulgevalue[i] = strtod(s[m+1]); //* Store bulge value for node
}
if (strcomp2(s[m], " 0", "0") != -1) {
i++;
state = state_POLYLINE; // Look for next vertex in polyline
order = order_LAYER;
}
break;
}
break;
case state_LWPOLYLINE: // absorbing LWPOLYLINE 07/09/2012
if (GUI_TargetLayer == 0) {
if (strcomp2(s[m], " 8", "8") != -1 || (strstr(s[m], " 8") != -1 && strlen(s[m]) == 3)) {
layernum = searchlayermap(s[m+1]);
if (layernum != -1) {
sprintf(temp, "LAYER %d\n", GUI_layerstart + layernum);
out += temp;
}
else {
out += "# Could not determine layer from map\n";
}
}
}
if (strcomp2(s[m], " 70", "70") != -1) { // Checks for closed polylines and imports them.
plclosed = strtod(s[m+1]);
}
if (strcomp2(s[m], " 10", "10") != -1) {
xa[i] = S_factor*strtod(s[m+1]);
m = m+1; //By doing this I'm having the for loop move to the next untouched
//line. This avoids a bug where a value of 0 for any of the
//LWPOLY attributes will cause it to exit prematurely JG 06/05/2017
//the next few states have similar lines. I set the value to the
//line of the currently processed data that way when the for loop
//comes around it will increment to the next line automatically.
}
if (strcomp2(s[m], " 20", "20") != -1) {
LWPOLY_FLAG = 0; // On poorly formated files, this state may run into an
// improperly formatted zero and exit without
// processing any points. This flag guarantees that
// the state will not be exited before points are
// processed. See the if statement below.
ya[i] = S_factor*strtod(s[m+1]);
if (strcomp2(s[m+2], " 42", "42") == -1) { // No bulge value
bulgevalue[i] = 0;
m = m+1; // See comments on line 624
i++; // This avoids a misalignment of the bulge array should
} // one or more polylines not have bulges.
if (strcomp2(s[m+2], " 42", "42") != -1) {
bulgevalue[i] = strtod(s[m+3]); // Store bulge value for node
i++;
m = m+3; // See comments on line 624
}
}
if (strcomp2(s[m], " 0", "0") != -1 & LWPOLY_FLAG == 0) {
for (p=0; p < i-1;p++) { // n points give n-1 lines that's why there's an i-1 in
if (bulgevalue[p] != 0) { // the conditional.
sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n",
linewidth,
mx(xa[p]+xorg),
my(ya[p]+yorg),
(atan(bulgevalue[p])*(180/PI)*4),
mx(xa[p+1]+xorg),
my(ya[p+1]+yorg)
);
out += temp;
}
else {
sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
linewidth,
mx(xa[p]+xorg),
my(ya[p]+yorg),
mx(xa[p+1]+xorg),
my(ya[p+1]+yorg)
);
out += temp;
}
}
if(plclosed) {
if(bulgevalue[p] != 0) {
sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n",
linewidth,
mx(xa[p]+xorg),
my(ya[p]+yorg),
(atan(bulgevalue[p])*180/PI*4),
mx(xa[0]+xorg),
my(ya[0]+yorg)
);
out += temp;
}
else {
sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n",
linewidth,
mx(xa[p]+xorg),
my(ya[p]+yorg),
mx(xa[0]+xorg),
my(ya[0]+yorg)
);
out += temp;
}
}
state = state_SEARCH;
LWPOLY_FLAG = 1;
}
break;
}
}
sprintf(temp, "Window Fit;\n");
out += temp;
sprintf(temp, "# lines=%d, arcs=%d, circles=%d, polylines=%d\n",
lines,
arcs,
circles,
polylines
);
out += temp;
out += "Grid last;";
return out;
}
/*
********************************************************************************
* GUI FUNCTIONS
********************************************************************************
*/
/*
*******************************************************************************
* get_project_path()
*
* Description: Returns project path, if in board or schematic, otherwise
* it will return the library path
*
* Arguments: none
*
* Return: p String containing full path of project
*
* Caller: runscript
*
*******************************************************************************
*/
string get_project_path() {
string s = "", p = "";;
if (library) { library(L) s = L.name;}
if (board) { board(B) s = B.name;}
if (schematic){ schematic(S) s = S.name;}
char c = '/';
int pos = strrchr(s, c);
if (pos >= 0) {
p = strsub(s, 0, pos + 1);
}
return p;
}
/*
*******************************************************************************
* LoadConfigSettings()
*
* Description: Loads the most recent configuration settings.
*
* Arguments: none
*
* Return: none
*
* Caller: Main GUI code
*
*******************************************************************************
*/
void LoadConfigSettings() {
string lines[];
string rf[];
int nrf = fileglob(rf, ConfigFileName);
if (nrf) {
nrf = fileread(lines, rf[0]);
}
if (nrf == 7) {
int i = 0;
GUI_fileName = lines[i++];
GUI_Xorg = strtod(lines[i++]);
GUI_Yorg = strtod(lines[i++]);
GUI_scale = strtod(lines[i++]);
GUI_lwidth = strtod(lines[i++]);
GUI_in_unit = strtol(lines[i++]);
SavedTargetLayer = strtol(lines[i++]);
}
}
/*
*******************************************************************************
* SaveConfigSettings()
*
* Description: Saves the most recent configuration settings.
*
* Arguments: none
*
* Return: none
*
* Caller: runscript
*
*******************************************************************************
*/
void SaveConfigSettings() {
output(ConfigFileName, "wt") {
printf("%s\n", GUI_fileName);
printf("%f\n", GUI_Xorg);
printf("%f\n", GUI_Yorg);
printf("%f\n", GUI_scale);
printf("%f\n", GUI_lwidth);
printf("%d\n", GUI_in_unit);
printf("%d\n", GUI_TargetLayer);
}
}
/*
*******************************************************************************
* runscript()
*
* Description: This function writes the commands to a script file, and then
* exits the ULP. Upon exit the command to run the script is
* issued to EAGLE.
*
* Arguments: scr List of script commands
*
* Return: none
*
* Caller: checkscript
*
*******************************************************************************
*/
void runscript(string scr) {
string filepath = get_project_path() + "dxfimp.scr";
if (argc <= 1) {
SaveConfigSettings(); //When run from command line don't store settings
}
output(filepath,"wt") {
printf(scr);
}
exit("SCRIPT '" + filepath + "'");
}
/*
*******************************************************************************
* checkscript()
*
* Description: This function checks if the DXF file will fit inside EAGLE's
* drawing area and if not return helpful messages. Addtionally it
* will display the generated script to the user for modifications
* before the script is run.
*
* Arguments: none
*
* Return: none
*
* Caller: Main GUI code
*
*******************************************************************************
*/
void checkscript(void) { // This allows the user to inspect the script and make changes
real sc_xo = GUI_Xorg; // These allow the scale factor to be applied independently
real sc_yo = GUI_Yorg;
real sc_lw = GUI_lwidth;
string error;
if (GUI_scaled_Xorg == 1) {
sc_xo *= GUI_scale;
}
if (GUI_scaled_Yorg == 1) {
sc_yo *= GUI_scale;
}
if (GUI_scaled_lwidth ==1) {
sc_lw *= GUI_scale;
}
GUI_script = dxf(GUI_fileName, GUI_in_unit, sc_xo, sc_yo, sc_lw, 0, GUI_scale);
string dummy[]; // Dummy array to check of dxf function returned valid data
if (strsplit(dummy, GUI_script, '\n') == 8) {
GUI_script = dxf(GUI_fileName,
GUI_in_unit,
sc_xo,
sc_yo,
sc_lw,
1,
GUI_scale); // Run again without searching for sections
}
real Xdim = XMax - XMin; // Max dimensions of DXF file,must be defined after dxf runs
real Ydim = YMax - YMin;
real EXdim = Exmax - Exmin; // Max dimensions of EAGLE
real EYdim = Eymax - Eymin;
if ((Xdim > EXdim) || (Ydim > EYdim)) { // Checks if DXF file is larger than EAGLE's drawing area
dlgMessageBox(":DXF file is larger than EAGLE's drawing area please scale the file in your MCAD software and try again");
exit(-1);
}
if ((Xdim < Exmax) && (Ydim < Eymax)) { // Checks if DXF file is small enough to fit in the
// first quadrant (+X +Y)
if ((XMax > Exmax) || (YMax > Eymax) ||
(XMin < Exmin) || (YMin < Eymin)) { // Check if any of the points are outside of EAGLE's drawing area
GUI_Xorg = -1.0*(XMin/S_factor); // Lower left corner of DXF file will now be at 0 0
GUI_Yorg = -1.0*(YMin/S_factor); // Make sure we return the offset in original units
sprintf(error,":DXF file is outside of EAGLE's drawing area would you like to apply an offset in X of %.1f and %.1f in y?",
GUI_Xorg, GUI_Yorg);
if (dlgMessageBox(error, "Set offset", "CANCEL") != 0) exit(-1);
return;
}
}
else { // DXF file is too large to fit in first quadrant
if ((XMax > Exmax) || (YMax > Eymax) ||
(XMin < Exmin) || (YMin < Eymin)) { // Check if any of the points are outside of EAGLE's drawing area
GUI_Xorg = -1.0*(((XMin+XMax)/2)/S_factor); // Center of DXF file will now be at 0 0
GUI_Yorg = -1.0*(((YMin+YMax)/2)/S_factor);
sprintf(error,":DXF file is outside of EAGLE's drawing area would you like to apply an offset in X of %.1f and %.1f in y?",
GUI_Xorg, GUI_Yorg);
if (dlgMessageBox(error, "Set offset", "CANCEL") != 0) exit(-1);
return;
}
}
if (argc > 1) {
runscript(GUI_script); //Just run the import script no further confirmation needed. Helps Automation JG
}
else {
int Result = dlgDialog("Run Script") {
dlgTextEdit(GUI_script);
dlgHBoxLayout {
dlgPushButton("Run") runscript(GUI_script);
dlgPushButton("Cancel") dlgReject();
}
};
}
}
int gettargetlayer(int select) {
return strtol(GUI_layers[select]);
}
/*
********************************************************************************
* MAIN() *
********************************************************************************
*/
if (argc <= 1) { //When running from command line use defaults only
LoadConfigSettings(); // load the last filename and config settings
}
GUI_TargetLayer = 0;
if (board) {
board(B) {
B.layers(L) {
if (L.name) {
sprintf(GUI_layers[Lcnt], "%d %s",L.number, L.name);
if (L.number == SavedTargetLayer) {
GUI_TargetLayer = L.number;
GUI_layerselect = Lcnt;
}
Lcnt++;
}
}
}
}
else if (schematic) {
schematic(SCH) {
SCH.layers(L) {
if (L.name) {
sprintf(GUI_layers[Lcnt], "%d %s",L.number, L.name);
if (L.number == SavedTargetLayer) {
GUI_TargetLayer = L.number;
GUI_layerselect = Lcnt;
}
Lcnt++;
}
}
}
}
else if (package || symbol) {
library(LIB) {
LIB.layers(L) {
if (L.name) {
sprintf(GUI_layers[Lcnt], "%d %s",L.number, L.name);
if (L.number == SavedTargetLayer) {
GUI_TargetLayer = L.number;
GUI_layerselect = Lcnt;
}
Lcnt++;
}
}
}
}
else {
dlgMessageBox("Start this ULP in a Schematic- or Board- or Package- or Symbol- Editor!", "OK");
exit(-1);
}
int main() {
if (argc > 1) {
//Run from the command line
if (argc < 4) {
dlgMessageBox("Not enough arguments. Please enter the filename, target layer, and units", "OK");
}
GUI_fileName = argv[1];
GUI_TargetLayer = strtol(argv[2]);
GUI_in_unit = strtol(argv[3]); // 0 means imperial, 1 means metric
if (argv[4]) {
GUI_Xorg = strtod(argv[4]);
}
if (argv[5]) {
GUI_Yorg = strtod(argv[5]);
}
if (argv[6]) {
GUI_lwidth = strtod(argv[6]);
}
if (argv[7]) {
GUI_scale = strtod(argv[7]);
}
if (argv[8]) {
string setup_value = argv[8];
char param1 = setup_value[0];
char param2 = setup_value[1];
char param3 = setup_value[2];
if (param1 == '1') {
GUI_scaled_Xorg = 1;
}
if (param2 == '1') {
GUI_scaled_Yorg = 1;
}
if (param3 == '1') {
GUI_scaled_lwidth = 1;
}
}
if (argv[9]) {
GUI_layerstart = strtol(argv[9]);
}
checkscript();
}
else {
string stateline = " ";
int Result = dlgDialog("DXFIMPORT - "+Version) {
dlgHBoxLayout {
dlgLabel(Help);
}
dlgHBoxLayout {
dlgLabel("File &name:");
dlgStringEdit(GUI_fileName);
dlgPushButton("Bro&wse") {
GUI_fileName = dlgFileOpen("Select a file", GUI_fileName, "*.dxf");
}
}
dlgHBoxLayout {
dlgLabel("Target layer ");
dlgComboBox(GUI_layers, GUI_layerselect) GUI_TargetLayer = gettargetlayer(GUI_layerselect);
dlgStretch(1);
}
dlgHBoxLayout {
dlgLabel("MultiLayer StartLayer");
dlgSpinBox(GUI_layerstart, 1, 255);
dlgSpacing(200);
dlgStretch(1);
}
dlgHBoxLayout {
dlgGroup("Input Units") {
dlgRadioButton("Imperial(in)", GUI_in_unit); // GUI_in_unit = 0
dlgRadioButton("Metric(mm)", GUI_in_unit); // GUI_in_unit = 1
}
dlgGridLayout {
dlgCell(0, 0) dlgLabel("Xorg");
dlgCell(1, 0) dlgLabel("Yorg");
dlgCell(0, 1) dlgRealEdit(GUI_Xorg);
dlgCell(1, 1) dlgRealEdit(GUI_Yorg);
dlgCell(2, 0) dlgLabel("Width");
dlgCell(2, 1) dlgRealEdit(GUI_lwidth);
dlgCell(3, 0) dlgLabel("Scale");
dlgCell(3, 1) dlgRealEdit(GUI_scale);
dlgCell(0, 2, 3, 2) {
dlgGroup("Scaled") {
dlgCheckBox("Xorg", GUI_scaled_Xorg); // If checked int contains 1, if unchecked 0
dlgCheckBox("Yorg", GUI_scaled_Yorg);
dlgCheckBox("Width", GUI_scaled_lwidth);
}
}
dlgCell(1, 3) dlgPushButton("OK") {
stateline = "converting file... please wait.";
dlgRedisplay();
checkscript();
stateline = " ";
dlgRedisplay();
}
dlgCell(2, 3) dlgPushButton("-Cancel") dlgReject();
}
}
dlgLabel(stateline, 1);
};
return Result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment