/* * This EAGLE User Language Program converts a board * or a schematic into a DXF file. The drawing appears in * black and white. * * DXF syntax generated according to the specifications given in * the book * * "Der DXF-Standard" * Author: Dietmar Rudolph * Publisher: Dr. L. Rossipaul Verlagsgesellschaft m.b.H., Muenchen, 1993 * ISBN 3-87686-246-9 * */ // // The following switches allow us to customize the generated DXF file: // enum { NO, YES }; int UseWireWidths = YES; // YES will generate wires, arcs and circles // as polygons showing their real widths. // This, however, can cause the DXF file to // become very large! // Set this to NO if you do not need the real // widths. int FillAreas = YES; // YES will fill wires, arcs etc. You must also // set UseWireWidths to YES for this to work // // Some tools we need later: // real DxfAngle(real a) { return a >= 360 ? a - 360 : a; // 0 <= DXF-Angle < 360 } int tx2 = 0, ty2 = 0; void GetTextPoint(UL_TEXT T) { int w, ex, ey; ex = tx2 = T.x; ey = ty2 = T.y; T.wires(W) { tx2 = (W.x1 > ex) ? max(W.x1, max(W.x2, tx2)) : min(W.x1, min(W.x2, tx2)); ty2 = (W.y1 > ey) ? max(W.y1, max(W.y2, ty2)) : min(W.y1, min(W.y2, ty2)); w = W.width; } w /= 2; tx2 += (tx2 > ex) ? w : -w; ty2 += (ty2 > ey) ? w : -w; } int LayerActive[] = {1}; // // Level 0: DXF code generating functions: // void DxfString(int code, string value) { printf("%3d\n%s\n", code, value); } void DxfInt(int code, int value) { printf("%3d\n%d\n", code, value); } void DxfReal(int code, real value) { printf("%3d\n%1.3f\n", code, value); } // // Level 1: DXF group functions: // void DxfCoordinate(int n, real x, real y) { DxfReal(10 + n, x); DxfReal(20 + n, y); DxfReal(30 + n, 0.0); } void DxfSection(string name) { DxfString(0, "SECTION"); DxfString(2, name); } void DxfEndSection(void) { DxfString(0, "ENDSEC"); } void DxfTable(string name, int number) { DxfString(0, "TABLE"); DxfString(2, name); DxfInt(70, number); } void DxfEndTable(void) { DxfString(0, "ENDTAB"); } void DxfBlock(string name) { DxfString(0, "BLOCK"); DxfInt(8, 0); DxfString(2, name); DxfInt(70, 64); DxfCoordinate(0, 0.0, 0.0); DxfString(3, name); } void DxfEndBlock(void) { DxfString(0, "ENDBLK"); DxfInt(8, 0); } void DxfVariable(string name) { DxfString(9, "$" + name); } void DxfTrailer(void) { DxfString(0, "EOF"); } void DxfPolyline(int layer, real width) { DxfString(0, "POLYLINE"); DxfInt(8, layer); DxfInt(66, 1); DxfCoordinate(0, 0.0, 0.0); DxfReal(40, width); DxfReal(41, width); DxfInt(70, width ? 0 : 1); } void DxfVertex(int layer, real x, real y) { DxfString(0, "VERTEX"); DxfInt(8, layer); DxfCoordinate(0, x, y); } void DxfVertexRound(int layer, real x, real y, real r) { DxfString(0, "VERTEX"); DxfInt(8, layer); DxfCoordinate(0, x, y); DxfReal(42, r); } void DxfSeqEnd(void) { DxfString(0, "SEQEND"); DxfInt(8, 0); } void DxfInsert(int layer, string name, real x, real y, real dx, real dy) { if (LayerActive[layer]) { DxfString(0, "INSERT"); DxfInt(8, layer); DxfString(2, name); DxfCoordinate(0, x, y); DxfReal(41, dx); DxfReal(42, dy); DxfReal(43, 1.0); } } void DxfPoint(int layer, real x, real y) { if (LayerActive[layer]) { DxfString(0, "POINT"); DxfInt(8, layer); DxfCoordinate(0, x, y); } } void DxfLine(int layer, real x1, real y1, real x2, real y2) { if (LayerActive[layer]) { DxfString(0, "LINE"); DxfInt(8, layer); DxfCoordinate(0, x1, y1); DxfCoordinate(1, x2, y2); } } void DxfCircle(int layer, real x, real y, real r) { if (LayerActive[layer]) { DxfString(0, "CIRCLE"); DxfInt(8, layer); DxfCoordinate(0, x, y); DxfReal(40, r); } } void DxfArc(int layer, real x, real y, real r, real a1, real a2) { if (LayerActive[layer]) { DxfString(0, "ARC"); DxfInt(8, layer); DxfCoordinate(0, x, y); DxfReal(40, r); DxfReal(50, a1); DxfReal(51, a2); } } void DxfSolid(int layer, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4) { if (LayerActive[layer]) { DxfString(0, "SOLID"); DxfInt(8, layer); DxfCoordinate(0, x1, y1); DxfCoordinate(1, x2, y2); DxfCoordinate(2, x3, y3); DxfCoordinate(3, x4, y4); } } void DxfText(int layer, real x, real y, real size, string value, real angle, int mirror) { if (LayerActive[layer]) { DxfString(0, "TEXT"); DxfInt(8, layer); DxfCoordinate(0, x, y); DxfReal(40, size); DxfString(1, value); if (angle) DxfReal(50, angle); if (mirror) DxfInt(71, 2); } } void DxfLayer(int number, int color) { int Color[] = { 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/, 7/*Black*/}; DxfString(0, "LAYER"); DxfInt(2, number); DxfInt(70, 64); DxfInt(62, Color[color]); DxfString(6, "CONTINUOUS"); } void DxfLineTypes(void) { DxfString(0, "LTYPE"); DxfString(2, "CONTINUOUS"); DxfInt(70, 64); DxfString(3, "Solid line"); DxfInt(72, 65); DxfInt(73, 0); DxfInt(40, 0); } void DxfVersion(void) { DxfVariable("ACADVER"); DxfString(1, "AC1009"); DxfVariable("FILLMODE"); DxfInt(70, FillAreas ? 1 : 0); } // // Level 1: Block definitions for EAGLE primitives: // void DxfOctagonBlock(string name, int layer, real w, real x1, real y1, real x2, real y2) { DxfBlock(name); DxfPolyline(layer, w); DxfVertex(layer, -x1, -y1); DxfVertex(layer, -x1, y1); DxfVertex(layer, -x2, y2); DxfVertex(layer, x2, y2); DxfVertex(layer, x1, y1); DxfVertex(layer, x1, -y1); DxfVertex(layer, x2, -y2); DxfVertex(layer, -x2, -y2); if (FillAreas) { DxfVertex(layer, -x1, -y1); DxfVertex(layer, -x1, y1); } DxfSeqEnd(); DxfEndBlock(); } void DxfBoardBlocks(void) { real f = 1.0 / ((sqrt(2) + 1) * 2); real x = 0.5; real y = f; real w = FillAreas ? 0.5 : 0; real d = FillAreas ? 0.5 : 1; real x1 = x - w / 4; real y1 = (y - w / 4 / sqrt(2)) * 0.5; real x2 = x - (x - (y - w / 4 / sqrt(2))) * 0.5; real y2 = x * 0.5 - w / 4; string pv[] = { "P", "V" }; int l[] = {LAYER_PADS, LAYER_VIAS}; DxfOctagonBlock("XLONGOCT", LAYER_PADS, w / 2, x1, y1, x2, y2); DxfOctagonBlock("YLONGOCT", LAYER_PADS, w / 2, y2, x2, y1, x1); for (int i = 0; i < 2; ++i) { DxfOctagonBlock("OCTAGON" + pv[i], l[i], w, x * d, y * d, y * d, x * d); DxfBlock("SQUARE" + pv[i]); DxfSolid(l[i], -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5); DxfEndBlock(); DxfBlock("ROUND" + pv[i]); if (FillAreas) { DxfPolyline(l[i], 0.5); DxfVertexRound(l[i], 0, -0.25, 1); DxfVertexRound(l[i], 0, 0.25, 1); DxfVertex(l[i], 0, -0.25); DxfSeqEnd(); } else DxfCircle(l[i], 0, 0, 0.5); DxfEndBlock(); } } // // Level 2: Low level EAGLE to DXF conversion functions: // void Layer(UL_LAYER L) { if (L.visible) DxfLayer(L.number, L.color); LayerActive[L.number] = L.visible; } void Area(UL_AREA A) { DxfVariable("EXTMIN"); DxfCoordinate(0, u2mm(A.x1), u2mm(A.y1)); DxfVariable("EXTMAX"); DxfCoordinate(0, u2mm(A.x2), u2mm(A.y2)); } void Wire(UL_WIRE W) { if (LayerActive[W.layer]) { if (UseWireWidths && W.width > 0) { real dx = u2mm(W.x2 - W.x1); real dy = u2mm(W.y2 - W.y1); real l = sqrt(dx * dx + dy * dy); if (l > 0) { if (FillAreas) l *= 2; real w2 = u2mm(W.width / 2); real dxl = dx / l; real dyl = dy / l; real x1 = u2mm(W.x1) + dyl * w2; real y1 = u2mm(W.y1) - dxl * w2; real x2 = u2mm(W.x2) + dyl * w2; real y2 = u2mm(W.y2) - dxl * w2; real x3 = u2mm(W.x2) - dyl * w2; real y3 = u2mm(W.y2) + dxl * w2; real x4 = u2mm(W.x1) - dyl * w2; real y4 = u2mm(W.y1) + dxl * w2; if (FillAreas) { DxfPolyline(W.layer, u2mm(W.width)); DxfVertex(W.layer, u2mm(W.x1), u2mm(W.y1)); DxfVertex(W.layer, u2mm(W.x2), u2mm(W.y2)); DxfSeqEnd(); DxfPolyline(W.layer, u2mm(W.width) / 2); DxfVertexRound(W.layer, x2, y2, 1); DxfVertex(W.layer, x3, y3); DxfSeqEnd(); DxfPolyline(W.layer, u2mm(W.width) / 2); DxfVertexRound(W.layer, x4, y4, 1); DxfVertex(W.layer, x1, y1); DxfSeqEnd(); } else { DxfPolyline(W.layer, 0); DxfVertex(W.layer, x1, y1); DxfVertexRound(W.layer, x2, y2, 1); DxfVertex(W.layer, x3, y3); DxfVertexRound(W.layer, x4, y4, 1); DxfSeqEnd(); } } } else DxfLine(W.layer, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2)); } } void Circle(UL_CIRCLE C) { if (LayerActive[C.layer]) { if (UseWireWidths) { if (C.width > 0) { if (FillAreas) { DxfPolyline(C.layer, u2mm(C.width)); DxfVertexRound(C.layer, u2mm(C.x), u2mm(C.y - C.radius), 1); DxfVertexRound(C.layer, u2mm(C.x), u2mm(C.y + C.radius), 1); DxfVertex(C.layer, u2mm(C.x), u2mm(C.y - C.radius)); DxfSeqEnd(); } else { DxfCircle(C.layer, u2mm(C.x), u2mm(C.y), u2mm(C.radius - C.width / 2)); DxfCircle(C.layer, u2mm(C.x), u2mm(C.y), u2mm(C.radius + C.width / 2)); } } else if (FillAreas) { DxfPolyline(C.layer, u2mm(C.radius)); DxfVertexRound(C.layer, u2mm(C.x), u2mm(C.y - C.radius / 2), 1); DxfVertexRound(C.layer, u2mm(C.x), u2mm(C.y + C.radius / 2), 1); DxfVertex(C.layer, u2mm(C.x), u2mm(C.y - C.radius / 2)); DxfSeqEnd(); } return; } DxfCircle(C.layer, u2mm(C.x), u2mm(C.y), u2mm(C.radius)); } } void Arc(UL_ARC A) { if (LayerActive[A.layer]) { if (UseWireWidths && A.width > 0) { real a1 = A.angle1 / 180 * PI; real a2 = A.angle2 / 180 * PI; real ra = tan((A.angle2 - A.angle1) / 180 * PI / 4); if (FillAreas) { DxfPolyline(A.layer, u2mm(A.width)); DxfVertexRound(A.layer, u2mm(A.x1), u2mm(A.y1), ra); DxfVertex(A.layer, u2mm(A.x2), u2mm(A.y2)); DxfSeqEnd(); } else { real w2 = u2mm(A.width / 2); real x1 = u2mm(A.x1) - w2 * cos(a1); real y1 = u2mm(A.y1) - w2 * sin(a1); real x2 = u2mm(A.x1) + w2 * cos(a1); real y2 = u2mm(A.y1) + w2 * sin(a1); real x3 = u2mm(A.x2) + w2 * cos(a2); real y3 = u2mm(A.y2) + w2 * sin(a2); real x4 = u2mm(A.x2) - w2 * cos(a2); real y4 = u2mm(A.y2) - w2 * sin(a2); DxfPolyline(A.layer, 0); DxfVertex(A.layer, x1, y1); DxfVertexRound(A.layer, x2, y2, ra); DxfVertex(A.layer, x3, y3); DxfVertexRound(A.layer, x4, y4, -ra); DxfSeqEnd(); } } else DxfArc(A.layer, u2mm(A.xc), u2mm(A.yc), u2mm(A.radius), DxfAngle(A.angle1), DxfAngle(A.angle2)); } } void Rectangle(UL_RECTANGLE R) { DxfSolid(R.layer, u2mm(R.x1), u2mm(R.y1), u2mm(R.x2), u2mm(R.y1), u2mm(R.x1), u2mm(R.y2), u2mm(R.x2), u2mm(R.y2)); } void Hole(UL_HOLE H) { DxfCircle(LAYER_DIMENSION, u2mm(H.x), u2mm(H.y), u2mm(H.drill / 2)); } void Via(UL_VIA V) { string Shape[] = { "SQUAREV", "ROUNDV", "OCTAGONV" }; DxfInsert(LAYER_VIAS, Shape[V.shape], u2mm(V.x), u2mm(V.y), u2mm(V.diameter), u2mm(V.diameter)); DxfCircle(LAYER_DRILLS, u2mm(V.x), u2mm(V.y), u2mm(V.drill / 2)); } void Pad(UL_PAD P) { string Shape[] = { "SQUAREP", "ROUNDP", "OCTAGONP", "XLONGOCT", "YLONGOCT" }; DxfInsert(LAYER_PADS, Shape[P.shape], u2mm(P.x), u2mm(P.y), u2mm(P.diameter), u2mm(P.diameter)); DxfCircle(LAYER_DRILLS, u2mm(P.x), u2mm(P.y), u2mm(P.drill / 2)); } void Smd(UL_SMD S) { DxfSolid(S.layer, u2mm(S.x - S.dx / 2), u2mm(S.y - S.dy / 2), u2mm(S.x + S.dx / 2), u2mm(S.y - S.dy / 2), u2mm(S.x - S.dx / 2), u2mm(S.y + S.dy / 2), u2mm(S.x + S.dx / 2), u2mm(S.y + S.dy / 2)); } void Junction(UL_JUNCTION J) { DxfCircle(LAYER_NETS, u2mm(J.x), u2mm(J.y), u2mm(J.diameter / 2)); } void Polygon(UL_POLYGON P) { P.wires(W) Wire(W); } void Text(UL_TEXT T) { // Although DXF offers several parameters to fine tune a text, most // DXF aware programs do not process these parameters correctly. // Therefore we make a very basic approach here. int x = T.x; int y = T.y; int angle = T.angle; // makes it int for easier processing! if (T.mirror) { switch (angle) { case 0: case 90: if (!board) { GetTextPoint(T); x = tx2; } break; case 180: case 270: GetTextPoint(T); if (board) x = tx2; y = ty2; break; } } else { switch (angle) { case 180: case 270: GetTextPoint(T); x = tx2; y = ty2; break; } } if (sheet || !T.mirror) angle = (angle == 90 || angle == 270) ? 90 : 0; else if (T.mirror) angle = (angle == 90 || angle == 270) ? 270 : 0; DxfText(T.layer, u2mm(x), u2mm(y), u2mm(T.size), T.value, angle, board ? T.mirror : 0); } // // Level 3: High level EAGLE decomposing functions: // void Package(UL_PACKAGE P) { P.polygons(P) Polygon(P); P.wires(W) Wire(W); P.texts(T) Text(T); P.arcs(A) Arc(A); P.circles(C) Circle(C); P.rectangles(R) Rectangle(R); P.holes(H) Hole(H); P.contacts(C) { if (C.pad) Pad(C.pad); else Smd(C.smd); } } void Element(UL_ELEMENT E) { int layer; switch (E.mirror) { case 0: layer = LAYER_TORIGINS; break; // not mirrored case 1: layer = LAYER_BORIGINS; break; // mirrored } DxfPoint(layer, u2mm(E.x), u2mm(E.y)); Package(E.package); E.texts(T) Text(T); } void Signal(UL_SIGNAL S) { S.polygons(P) Polygon(P); S.wires(W) Wire(W); S.vias(V) Via(V); } void Board(UL_BOARD B) { B.polygons(P) Polygon(P); B.wires(W) Wire(W); B.texts(T) Text(T); B.arcs(A) Arc(A); B.circles(C) Circle(C); B.rectangles(R) Rectangle(R); B.holes(H) Hole(H); B.elements(E) Element(E); B.signals(S) Signal(S); } void Pin(UL_PIN P) { P.wires(W) Wire(W); P.circles(C) Circle(C); P.texts(T) Text(T); } void Symbol(UL_SYMBOL S) { S.polygons(P) Polygon(P); S.wires(W) Wire(W); S.texts(T) Text(T); S.pins(P) Pin(P); S.arcs(A) Arc(A); S.circles(C) Circle(C); S.rectangles(R) Rectangle(R); } void Instance(UL_INSTANCE I) { Symbol(I.gate.symbol); I.texts(T) Text(T); } void Part(UL_PART P) { P.instances(I) Instance(I); } void Segment(UL_SEGMENT S) { S.wires(W) Wire(W); S.junctions(J) Junction(J); S.texts(T) Text(T); } void Bus(UL_BUS B) { B.segments(S) Segment(S); } void Net(UL_NET N) { N.segments(S) Segment(S); } void Sheet(UL_SHEET S) { S.polygons(P) Polygon(P); S.wires(W) Wire(W); S.texts(T) Text(T); S.arcs(A) Arc(A); S.circles(C) Circle(C); S.rectangles(R) Rectangle(R); S.parts(P) Part(P); S.busses(B) Bus(B); S.nets(N) Net(N); } // // Main program: // string OutputFileName = ""; if (board) board(B) OutputFileName = B.name; else if (schematic) schematic(SCH) OutputFileName = SCH.name; if (OutputFileName) { output(filesetext(OutputFileName, ".dxf")) { DxfSection("HEADER"); DxfVersion(); if (board) board(B) Area(B.area); else sheet(S) Area(S.area); DxfEndSection(); DxfSection("TABLES"); DxfTable("LTYPE", 1); DxfLineTypes(); DxfEndTable(); DxfTable("LAYER", 255); if (board) board(B) B.layers(L) Layer(L); else schematic(SCH) SCH.layers(L) Layer(L); DxfEndTable(); DxfEndSection(); if (board) { DxfSection("BLOCKS"); DxfBoardBlocks(); DxfEndSection(); } DxfSection("ENTITIES"); if (board) board(B) Board(B); else sheet(S) Sheet(S); DxfEndSection(); DxfTrailer(); } }