/* * This EAGLE User Language Program generates a script file * of a part or a symbol in a library rotated around the origin. * * Version 1.10 by Hansjörg Sämann, October 1998 * * NO WARRANTY WILL BE GIVEN FOR ANYTHING !!! * * Open a package or a symbol in a library and place a text * like "A=30.5" (or "a=-30.5") on any layer in the package * or symbol to specify the rotation angle. The angle may be * negative for clockwise rotation. No spaces are allowed. * Then run the ULP. * The generated script file can be read into the same or * another part or symbol in the same or another library. * Don't forget to remove the angle specification text when * you have finished your work! * * With program parameters, which you will find at the beginning * of the program, you can influence the generated data. * * Only elements of visible layers will be considered. * * Rectangles are converted to polygons with a width = 0 * SMDs are converted to polygons with a width = 0 * with a small SMD inside. * By specifying the program parameters "SMDXSize", "SMDYSize", * "SolderStopFrame" and "SolderCreamFrame" you can influence * the small SMDs and the generated stop and cream masks. * * Text will be rotated as text with 90 degree restriction * or, converted to wires, with the correct angle * By specifying the program parameter "TextAsText" you can * influence this. * * Pins are converted to length point and function none, * theire symbol elements to wires and circles * * For pads only the center point will be moved. * * If the ULP has finished you will get the message "finished". * If the ULP was not succesfull you will get the message * "finished (errorlevel x)". The following values for x are * used by this ULP: * * -1 = ULP wasn't run in a library * -2 = ULP wasn't run in a package or a symbol * -3 = No valid rotation angle is specified * */ /* * program paramters */ enum {No, Yes}; enum {SMDXSize = 5, SMDYSize = 5}; // size of the smd part in a // rotated smd in mil enum {SolderStopFrame = 10, // value of the solder stop frame in mil SolderCreamFrame = 0}; // value of the solder stop frame in mil enum {TextAsText = No}; // determines if rotated text is still text // and only rotated in 90 degree steps (=Yes) // or is converted into wires and rotated // correctly (=No) /* end program paramters */ /* * global constants */ enum {px, py}; enum {ECOk = 0, ECNotALibrary = -1, ECNotAPartOrSymbol = -2, ECNoAngleSpec = -3}; /* * global variables */ int ExitCode; real Angle = 0; string AngleSpecText = "A="; int AngleSpecPnt []; int ActLayer = -1; int ActRatio = -1; int ActSize = -1; int ActSpacing = -1; int ActPour = -1; int ActDrill = -1; int LayerOn []; string PourTexts [] = {"solid", "hatch"}; int GrdUnit; string GrdUnitTexts [] = {"mic", "mm", "mil", "inch"}; string MirrorTexts [] = {"", "M"}; string ShapeTexts [] = {"Square", "Round", "Octagon", "Xlongoct", "YLongoct"}; string PinDirTexts[] = {"NC", "In", "Out", "I/O", "OC", "Pwr", "Pas", "Hiz", "Sup"}; string PinFuncTexts[] = {"None", "Dot", "Clk", "DotClk"}; string PinLengthTexts[] = {"Point", "Short", "Middle", "Long"}; string PinVisiTexts[] = {"Off", "Pad", "Pin", "Both"}; int P0 []; int P1 []; int P2 []; int P3 []; /* * converts the internal used unit (1/10000mm) to * the actual used grid unit */ real Norm(int i) { real a; switch (GrdUnit) { case GRID_UNIT_MIC: a = u2mic(i); break; case GRID_UNIT_MM: a = u2mm(i); break; case GRID_UNIT_MIL: a = u2mil(i); break; case GRID_UNIT_INCH: a = u2inch(i); } return a; } /* * looks for the angle specification and returns * if a valid one was found or not */ int GetAngle(UL_TEXT T) { string s; real a; ++AngleSpecPnt[0]; if (strstr(strupr(T.value), AngleSpecText) == 0) { s = strsub(T.value, 2); if (strlen(s) == 0) return 0; for (int i = 0; s[i]; ++i) { if (!isdigit(s[i])) if ((s[i] != '.')) if ((s[i] != '-')) return 0; } Angle = strtod(s); a = abs(Angle); while ((a - 360) > 0) { a -= 360; } Angle = (Angle > 0) ? a : -a; return 1; } return 0; } /* * checks which layers are visible */ void GetLayersOn(UL_LAYER L) { if (L.visible) LayerOn[L.number] = L.visible; } /* * initiates a layer change if necessary * and returns if a layer is visible or not */ int HndlLayer(int l) { if (LayerOn[l]) { if (l != ActLayer) { ActLayer = l; printf("Layer %d;\n", ActLayer); } return 1; } else return 0; } /* * initiates a ratio change if necessary */ void HndlRatio(int r) { if (r != ActRatio) { ActRatio = r; printf("Change Ratio %d;\n", ActRatio); } } /* * initiates a size change if necessary */ void HndlSize(int s) { if (s != ActSize) { ActSize = s; printf("Change Size %f;\n", Norm(ActSize)); } } /* * initiates a spacing change if necessary */ void HndlSpacing(int s) { if (s != ActSpacing) { ActSpacing = s; printf("Change Spacing %f;\n", Norm(ActSpacing)); } } /* * initiates a pour change if necessary */ void HndlPour(int p) { if (p != ActPour) { ActPour = p; printf("Change pour %s;\n", PourTexts[ActPour]); } } /* * initiates a drill change if necessary */ void HndlDrill(int d) { if (d != ActDrill) { ActDrill = d; printf("Change Drill %f;\n", Norm(ActDrill)); } } /* * determines and returns the rotation of a text */ int GetRotation(real a) { a += Angle; if (Angle >= 0) { if (a < 45) return 0; if (a < 135) return 90; if (a < 225) return 180; if (a < 315) return 270; if (a < 405) return 0; if (a < 495) return 90; if (a < 585) return 180; if (a < 675) return 270; } else { if (a > 315) return 0; if (a > 225) return 270; if (a > 135) return 180; if (a > 45) return 90; if (a > -45) return 0; if (a > -135) return 270; if (a > -225) return 180; if (a > -315) return 90; if (a > -360) return 0; } } /* * calculates a rotated point */ void CalcRotPoint(real x, real y) { int r; real phi; r = round(sqrt(pow(x,2)+pow(y,2))); if (x > 0) phi = atan(y/x); if (x < 0) phi = atan(y/x)+PI; if (x == 0) { if (y > 0) phi = PI/2; if (y < 0) phi = -PI/2; } phi += (Angle*PI/180); P0[px] = round(r*cos(phi)); P0[py] = round(r*sin(phi)); } /* * writes necessary environment information * to the top of the file */ void SCRHeader(UL_LIBRARY L) { printf("Set Wire_Style 2;\n"); GrdUnit = L.grid.unit; printf("Grid %s;\n", GrdUnitTexts[L.grid.unit]); } /* * rotates an arc */ void RotArc(UL_ARC A) { if (HndlLayer(A.layer)) { CalcRotPoint(A.x1,A.y1); P1[px] = P0[px]; P1[py] = P0[py]; CalcRotPoint(A.x2,A.y2); P3[px] = P0[px]; P3[py] = P0[py]; CalcRotPoint(A.xc,A.yc); P2[px] = P1[px] - ((P1[px] - P0[px]) * 2); P2[py] = P1[py] - ((P1[py] - P0[py]) * 2); printf("Arc CCW %f (%f %f) (%f %f) (%f %f);\n", Norm(A.width), Norm(P1[px]), Norm(P1[py]), Norm(P2[px]), Norm(P2[py]), Norm(P3[px]), Norm(P3[py])); } } /* * rotates a circle */ void RotCircle(UL_CIRCLE C) { if (HndlLayer(C.layer)) { CalcRotPoint(C.x,C.y); P1[px] = P0[px]; P1[py] = P0[py]; P2[px] = P0[px] + C.radius; P2[py] = P0[py]; printf("Circle %f (%f %f) (%f %f);\n", Norm(C.width), Norm(P1[px]), Norm(P1[py]), Norm(P2[px]), Norm(P2[py])); } } /* * rotates a wire */ void RotWire(UL_WIRE W) { if (HndlLayer(W.layer)) { CalcRotPoint(W.x1,W.y1); P1[px] = P0[px]; P1[py] = P0[py]; CalcRotPoint(W.x2,W.y2); P2[px] = P0[px]; P2[py] = P0[py]; printf("Wire %f (%f %f) (%f %f);\n", Norm(W.width), Norm(P1[px]), Norm(P1[py]), Norm(P2[px]), Norm(P2[py])); } } /* * rotates a rectangle and converts * it to a polygon */ void RotConvRect(int x1, int y1, int x2, int y2) { CalcRotPoint(x2,y1); P1[px] = P0[px]; P1[py] = P0[py]; CalcRotPoint(x2,y2); P2[px] = P0[px]; P2[py] = P0[py]; CalcRotPoint(x1,y2); P3[px] = P0[px]; P3[py] = P0[py]; CalcRotPoint(x1,y1); HndlSpacing(1); HndlPour(POLYGON_POUR_SOLID); printf("Polygon %f (%f %f) (%f %f)\n", 0.0, Norm(P0[px]), Norm(P0[py]), Norm(P1[px]), Norm(P1[py])); printf(" (%f %f) (%f %f) (%f %f);\n", Norm(P2[px]), Norm(P2[py]), Norm(P3[px]), Norm(P3[py]), Norm(P0[px]), Norm(P0[py])); } /* * rotates a contact (pad or SMD) */ void RotContact(UL_CONTACT C) { int fr, ls, lc; if (C.pad) { if (LayerOn[LAYER_PADS]) { HndlDrill(C.pad.drill); CalcRotPoint(C.pad.x,C.pad.y); P1[px] = P0[px]; P1[py] = P0[py]; printf("Pad '%s' %s %f (%f %f);\n", C.pad.name, ShapeTexts[C.pad.shape], Norm(C.pad.diameter), Norm(P1[px]), Norm(P1[py])); } } if (C.smd) { if (HndlLayer(C.smd.layer)) { CalcRotPoint(C.smd.x,C.smd.y); P1[px] = P0[px]; P1[py] = P0[py]; printf("Smd '%s' %f %f (%f %f);\n", C.smd.name, Norm(SMDXSize * 254), Norm(SMDYSize * 254), Norm(P1[px]), Norm(P1[py])); RotConvRect(C.smd.x - C.smd.dx / 2, C.smd.y - C.smd.dy / 2, C.smd.x + C.smd.dx / 2, C.smd.y + C.smd.dy / 2); if (C.smd.layer == LAYER_TOP) { ls = LAYER_TSTOP; lc = LAYER_TCREAM; } if (C.smd.layer == LAYER_BOTTOM) { ls = LAYER_BSTOP; lc = LAYER_BCREAM; } HndlLayer(ls); fr = SolderStopFrame * 254; RotConvRect(C.smd.x - (C.smd.dx / 2 + fr), C.smd.y - (C.smd.dy / 2 + fr), C.smd.x + (C.smd.dx / 2 + fr), C.smd.y + (C.smd.dy / 2 + fr)); HndlLayer(lc); fr = SolderCreamFrame * 254; RotConvRect(C.smd.x - (C.smd.dx / 2 + fr), C.smd.y - (C.smd.dy / 2 + fr), C.smd.x + (C.smd.dx / 2 + fr), C.smd.y + (C.smd.dy / 2 + fr)); } } } /* * rotates a pin */ void RotPin(UL_PIN P) { if (LayerOn[LAYER_PINS]) { CalcRotPoint(P.x,P.y); P1[px] = P0[px]; P1[py] = P0[py]; printf("Pin '%s' %s %s %s R%d %s %d (%f %f);\n", P.name, PinDirTexts[P.direction], PinFuncTexts[PIN_FUNCTION_FLAG_NONE], PinLengthTexts[PIN_LENGTH_POINT], GetRotation(P.angle), PinVisiTexts[P.visible], P.swaplevel, Norm(P1[px]), Norm(P1[py])); P.circles(C) { RotCircle(C); } P.wires(W) { RotWire(W); } } } /* * rotates a hole */ void RotHole(UL_HOLE H) { if (LayerOn[LAYER_HOLES]) { CalcRotPoint(H.x,H.y); P1[px] = P0[px]; P1[py] = P0[py]; printf("Hole %f (%f %f);\n", Norm(H.drill), Norm(P1[px]), Norm(P1[py])); } } /* * rotates a polygon */ void RotPolygon(UL_POLYGON P) { int i = 0; int j = 0; if (HndlLayer(P.layer)) { HndlSpacing(P.spacing); HndlPour(P.pour); printf("Polygon %f ", Norm(P.width)); P.wires(W) i++; P.wires(W) { CalcRotPoint(W.x1,W.y1); P1[px] = P0[px]; P1[py] = P0[py]; ++j; if (j == 1) printf("(%f %f) ", Norm(P1[px]), Norm(P1[py])); else if (j%2 > 0) printf(" (%f %f) ", Norm(P1[px]), Norm(P1[py])); else printf("(%f %f) \\\n", Norm(P1[px]), Norm(P1[py])); if (--i == 0) { CalcRotPoint(W.x2,W.y2); P1[px] = P0[px]; P1[py] = P0[py]; if (j%2 > 0) printf("(%f %f);\n", Norm(P1[px]), Norm(P1[py])); else printf(" (%f %f);\n", Norm(P1[px]), Norm(P1[py])); } } } } /* * rotates a rectangle */ void RotRectangle(UL_RECTANGLE R) { if (HndlLayer(R.layer)) { RotConvRect(R.x1, R.y1, R.x2, R.y2); } } /* * rotates a text */ void RotText(UL_TEXT T) { if (AngleSpecPnt[0] != ++AngleSpecPnt[1]) { if (HndlLayer(T.layer)) { if (TextAsText) { HndlSize(T.size); HndlRatio(T.ratio); CalcRotPoint(T.x,T.y); P1[px] = P0[px]; P1[py] = P0[py]; printf("Text '%s' %sR%d (%f %f);\n", T.value, MirrorTexts[T.mirror], GetRotation(T.angle), Norm(P1[px]), Norm(P1[py])); } else { T.wires(W) { RotWire(W); } } } } } /* * processes a package */ void DoPackage(UL_PACKAGE P) { P.arcs(A) { RotArc(A); } P.circles(C) { RotCircle(C); } P.contacts(Cn) { RotContact(Cn); } P.holes(H) { RotHole(H); } P.polygons(Ply) { RotPolygon(Ply); } P.rectangles(R) { RotRectangle(R); } P.texts(T) { RotText(T); } P.wires(W) { RotWire(W); } } /* * processes a symbol */ void DoSymbol(UL_SYMBOL S) { S.arcs(A) { RotArc(A); } S.circles(C) { RotCircle(C); } S.rectangles(R) { RotRectangle(R); } S.pins(Pn) { RotPin(Pn); } S.polygons(P) { RotPolygon(P); } S.texts(T) { RotText(T); } S.wires(W) { RotWire(W); } } /* * main program */ ExitCode = ECNotALibrary; if (library) library(L) { L.layers(Ls) GetLayersOn(Ls); ExitCode = ECNotAPartOrSymbol; if (package) package(P) { ExitCode = ECNoAngleSpec; P.texts(T) { if (GetAngle(T)) { ExitCode = ECOk; break; } } if (ExitCode == ECOk) { output(filesetext(P.name, ".SCR")) { SCRHeader(L); DoPackage(P); } } } if (symbol) symbol(S) { ExitCode = ECNoAngleSpec; S.texts(T) { if (GetAngle(T)) { ExitCode = ECOk; break; } } if (ExitCode == ECOk) { output(filesetext(S.name, ".SCR")) { ExitCode = ECOk; SCRHeader(L); DoSymbol(S); } } } } exit(ExitCode);