#usage "FORMICA 4.30 / 4.2 PCB layout and library export
"
"Author: horsky@semi.mff.cuni.cz"
"Version 0.94 (Feb 2004)
"
"See also http://www.formica.cz"
string title = "FORMICA 4.30 / 4.2 PCB layout and library export";
string version = "Version 0.94 (Feb 2004)";
string copyright = "Copyright (c) 2001-2004 Petr Horský";
/* =============================================================================
--- ZMĚNY OPROTI VERZI 0.92: ---------------------------------------------------
1) upraveno pro Eagle 4.11 (arc pouze jako součást wire)
2) ošetřen obdélník rotovaný o obecný úhel
3) do výstupního souboru doplněna sekce Setup (uvádějící mj. soubor verze 4.30)
4) opravena rotace pájecích bodů SMD (ver. 0.94)
5) texty vystupují vždy v čitelné orientaci (ver. 0.94)
6) ošetřeny polygony (ver. 0.94)
--------------------------------------------------------------------------------
--- ZBÝVAJÍCÍ PROBLÉMY ---------------------------------------------------------
1) generování tabulky Dimensions (spíše než mapování na defaultní tabulku)
2) nečíslované piny (vedou také k neúplnému netlistu - nutno užívat Add Tracks)
3) pájecí body otočené o obecný úhel
4) vyplněné obdélníky
============================================================================= */
// ------------------------------------------------- konverze souřadnic a vrstev
int ofsx = 1000, ofsy = 2000;
int fmUnit(int u) {
return max(u2mil(u), 0);
}
int mapx(int u) {
return u2mil(u) + ofsx;
}
int mapy(int u) {
return u2mil(u) + ofsy;
}
int mapt(int u) {
return (u > 1) ? max(u2mil(u / 6), 1) : 0;
}
int fmAngle(real a) {
int i = round(a / 90.0);
return i & 3;
}
int fmLayer(int l) {
switch (l) {
case LAYER_TOP: return 10;
case LAYER_BOTTOM: return 5;
case LAYER_TSTOP: return 11;
case LAYER_BSTOP: return 4;
case LAYER_TGLUE:
case LAYER_TNAMES: return 13;
case LAYER_TVALUES: return 14;
case LAYER_BGLUE:
case LAYER_BNAMES: return 2;
case LAYER_BVALUES: return 1;
case LAYER_TDOCU:
case LAYER_TPLACE: // component contours are in this layer
case LAYER_TTEST:
case LAYER_TFINISH: return 15;
case LAYER_BDOCU:
case LAYER_BPLACE: // component contours are in this layer
case LAYER_BTEST:
case LAYER_BFINISH: return 0;
default: return 0;
}
}
// ------------------------------------------------------------ hlavička souboru
void fmSetup(int x1, int y1, int x2, int y2) {
printf ("Setup (\n"
" (4 30)\n"
" (20 1000 1000 0 0 %d %d %d %d %d %d %d %d %d 25 4 2 4 1 108 0 50)\n"
" ((50 1 1 1 100 1 1 0 1 1)\n"
" (10 30 32 30 10 32 40 0 0 2 20)\n"
" (10 10 15 10 10 15 50 0 0 0 20)\n"
" )\n"
")\n",
x1, y1, x2, y2,
fmLayer(LAYER_BOTTOM), fmLayer(LAYER_TOP),
fmLayer(LAYER_BOTTOM), fmLayer(LAYER_TOP),
fmLayer(LAYER_BOTTOM));
}
// ----------------------------------------------- mapování logických typů prvků
int fmLineWidths[] = {4, 6, 8, 10, 12, 16, 20, 24, 32, 40, 52, 60, 80, 100, 120, 200};
int fmLineType(int w) {
int i, j, d, m = INT_MAX;
for (i=0; i<16; i++) {
d = abs(fmLineWidths[i] - fmUnit(w));
if (d < m) {j = i; m = d;}
}
return j;
}
int fmPadDiams[] = {32, 40, 48, 52, 60, 60, 72, 80, 96, 120, 152, 152, 200}; // type 0..12
int fmPadHoles[] = {16, 24, 28, 36, 36, 40, 44, 52, 60, 72, 88, 128, 128};
int fmRoundPadType(int diam, int hole) {
int i, t, d, m = INT_MAX;
for (i=0; i<13; i++) {
d = 100 * abs(fmPadDiams[i] - fmUnit(diam))
+ abs(fmPadHoles[i] - fmUnit(hole));
if (d < m) {t = i; m = d;}
}
return t;
}
int fmSmdT[] = {14, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 82, 84, 86, 88};
int fmSmdW[] = {40, 40, 40, 64, 64, 72, 72, 80, 80, 88, 88, 96, 96, 120, 60, 88, 36, 64, 36, 64};
int fmSmdH[] = {40, 56, 212, 56, 104, 200, 264, 96, 128, 12, 16, 104, 152, 112, 400, 24, 16, 16, 20, 20};
int fmSmdPadType(int w, int h, real a, int top) {
int i, t, d, m = INT_MAX;
for (i=0; i<20; i++) {
d = abs(fmSmdW[i] - fmUnit(w))
+ abs(fmSmdH[i] - fmUnit(h));
if (d < m) {t = fmSmdT[i]; m = d;}
d = abs(fmSmdW[i] - fmUnit(h))
+ abs(fmSmdH[i] - fmUnit(w));
if (d < m) {t = fmSmdT[i] | 0x80; m = d;}
}
if (fmAngle(a) & 1) t ^= 0x80;
if (top) t--;
return ((t < 0x40) || (t >= 0xC0)) ? t : t ^ 0xC0;
}
int fmHoleT[] = {47, 48, 100, 49, 50, 51};
int fmHoleD[] = {24, 36, 70, 88, 112, 128};
int fmHoleType(int diam) {
int i, t, d, m = INT_MAX;
for (i=0; i<6; i++) {
d = abs(fmHoleD[i] - fmUnit(diam));
if (d < m) {t = fmHoleT[i]; m = d;}
}
return t;
}
// ---------------------------------------------------------------- výstup prvků
void fmLineSeg(UL_WIRE W, string indent) {
printf( "%s(%d %d %d %d %d %d)\n",
indent,
mapx(W.x1), mapy(W.y1),
mapx(W.x2), mapy(W.y2),
fmLineType(W.width), fmLayer(W.layer));
}
void fmRectangle(UL_RECTANGLE R, string indent) { //// neumi jej vyplnit
if (!R.angle)
printf( "%s(%d %d %d %d %d %d)\n"
"%s(%d %d)\n"
"%s(%d %d)\n"
"%s(%d %d)\n",
indent,
mapx(R.x1), mapy(R.y1),
mapx(R.x2), mapy(R.y1),
fmLineType(0), fmLayer(R.layer),
indent,
mapx(R.x2), mapy(R.y2),
indent,
mapx(R.x1), mapy(R.y2),
indent,
mapx(R.x1), mapy(R.y1));
else {
real a = R.angle / 180.0 * PI, sina = sin(a), cosa = cos(a);
int xc = (R.x1 + R.x2) / 2,
yc = (R.y1 + R.y2) / 2,
w = (R.x2 - R.x1) / 2,
h = (R.y2 - R.y1) / 2;
printf( "%s(%d %d %d %d %d %d)\n"
"%s(%d %d)\n"
"%s(%d %d)\n"
"%s(%d %d)\n",
indent,
mapx(xc - w * cosa + h * sina), mapy(yc - w * sina - h * cosa), // -w, -h
mapx(xc + w * cosa + h * sina), mapy(yc + w * sina - h * cosa), // +w, -h
fmLineType(0), fmLayer(R.layer),
indent,
mapx(xc + w * cosa - h * sina), mapy(yc + w * sina + h * cosa), // +w, +h
indent,
mapx(xc - w * cosa - h * sina), mapy(yc - w * sina + h * cosa), // -w, +h
indent,
mapx(xc - w * cosa + h * sina), mapy(yc - w * sina - h * cosa)); // -w, -h
}
} // fmRectangle
void fmArc(UL_ARC A, string indent) {
for (int i=0; i<8; i++)
if ((A.angle1 <= i * 90) && (A.angle2 >= (i+1) * 90))
printf( "%s(%d %d %d %d %d %d)\n",
indent,
i & 3,
mapx(A.xc), mapy(A.yc),
fmUnit(A.radius),
fmLineType(A.width), fmLayer(A.layer));
}
void fmApprox(UL_ARC A, real a1, real a2, string indent) {
int n = max (ceil((a2 - a1) / 15.0), 1);
real a = a1 / 180.0 * PI;
real b = (a2 - a1) / n / 180.0 * PI;
int x1, y1, x2, y2;
for (int i=0; i<=n; i++) {
x2 = A.xc + A.radius * cos (a);
y2 = A.yc + A.radius * sin (a);
if (i > 0)
printf( "%s(%d %d %d %d %d %d)\n",
indent,
mapx(x1), mapy(y1),
mapx(x2), mapy(y2),
fmLineType(A.width), fmLayer(A.layer));
x1 = x2;
y1 = y2;
a += b;
}
}
void fmApproxArc(UL_ARC A, string indent) {
for (int i=0; i<4; i++)
if ((A.angle1 > i * 90) && (A.angle1 < (i+1) * 90))
if (A.angle2 < (i+1) * 90) {
fmApprox(A, A.angle1, A.angle2, indent);
return;
}
else {
fmApprox(A, A.angle1, (i+1) * 90, indent);
break;
}
for (i=0; i<8; i++)
if ((A.angle2 > i * 90) && (A.angle2 < (i+1) * 90)) {
fmApprox(A, max(A.angle1, i * 90), A.angle2, indent);
return;
}
}
void fmWire(UL_WIRE W, string indent) {
if (!W.arc)
fmLineSeg(W, indent);
else
fmApproxArc(W.arc, indent);
}
void fmPolygon(UL_POLYGON P, string indent) {
P.contours(W) fmWire(W, indent);
P.fillings(W) fmWire(W, indent);
}
void fmCircle(UL_CIRCLE C, string indent) {
printf( "%s(0 %d %d %d %d %d)(1)(2)(3)\n",
indent,
mapx(C.x), mapy(C.y),
fmUnit(C.radius),
fmLineType(C.width), fmLayer(C.layer));
}
void fmText(UL_TEXT T, string s, string indent) {
string str = (s == "") ? T.value : s;
real a = T.angle / 180.0 * PI;
int size = mapt(T.size);
int ofsw = (6 * strlen(str) - 2) * size / 2;
int ofsh = 6 * size / 2;
int lw;
T.wires(W) {
lw = fmLineType(W.width);
break;
}
if ((s != "") || (T.value != ">NAME") && (T.value != ">VALUE"))
printf( "%s(\"%s\" %5.0f %5.0f %d %d %d %d)\n",
indent,
str,
mapx(T.x) + ((T.mirror) ? -1 : 1) * (ofsw * cos(a) - ofsh * sin(a)),
mapy(T.y) + (ofsw * sin(a) + ofsh * cos(a)),
size, fmAngle(T.angle) & 1 | 4 * T.mirror,
lw, fmLayer(T.layer));
}
// ------------------------------------------------------------ výstup součástek
void fmDefault(UL_ELEMENT E, string s, string indent) {
printf( "%s(\"%s\" %d %d %d %d %d %d)\n",
indent,
s,
mapx(E.x), mapy(E.y), // toto je origin, ne stred !!!!
fmUnit(0), fmAngle(0),
fmLineType(0),
fmLayer(LAYER_TNAMES));
}
void fmDefault2(UL_PACKAGE P, string s, string indent) {
printf( "%s(\"%s\" %d %d %d %d %d %d)\n",
indent,
s,
mapx((P.area.x1 + P.area.x2) / 2),
mapy((P.area.y1 + P.area.y2) / 2),
fmUnit(0), fmAngle(0),
fmLineType(0),
fmLayer(LAYER_TNAMES));
}
void fmPackage(UL_PACKAGE P) {
printf( " Pins (\n");
int pin = 300; // undefined pin numbers
P.contacts(C) {
int n = strtol(C.name);
string name = "";
if (n == 0) {
n = ++pin;
name = "{" + C.name + "} ";
}
if (C.pad)
printf( " (%d %s%d %d %d)\n",
n, name, mapx(C.x), mapy(C.y),
fmRoundPadType(C.pad.diameter[LAYER_BOTTOM], C.pad.drill));
else if (C.smd)
printf( " (%d %s%d %d %d)\n",
n, name, mapx(C.x), mapy(C.y),
fmSmdPadType(C.smd.dx, C.smd.dy, C.smd.angle, C.smd.layer == LAYER_TOP));
}
printf( " )\n");
string indent = " ";
printf( " Lines (\n");
P.wires(W) fmWire(W, indent);
P.polygons(Q) fmPolygon(Q, indent);
P.rectangles(R) fmRectangle(R, indent);
printf( " )\n");
printf( " Arcs (\n");
P.circles(C) fmCircle(C, indent);
P.wires(W) if (W.arc)
fmArc(W.arc, indent);
printf( " )\n");
printf( " Pads (\n");
P.holes(H)
printf( " (%d %d %d)\n", mapx(H.x), mapy(H.y), fmHoleType(H.drill));
printf( " )\n");
printf( " Text (\n");
P.texts(T) fmText(T, "", indent);
printf( " )\n");
} // fmPackage
void fmComponent(UL_ELEMENT E) {
int noName = 1, noValue = 1;
printf( " (%d 0\n", fmAngle(E.angle) | 4 * E.mirror);
string indent = " ";
E.texts(T)
if (E.name == T.value) {
fmText(T, "", indent);
noName = 0; // component name found
break;
}
if (noName) fmDefault(E, E.name, indent);
E.texts(T)
if (E.value == T.value) {
fmText(T, "", indent);
noValue = 0; // component value found
break;
}
if (noValue) fmDefault(E, E.value, indent);
fmDefault (E, E.package.name, indent);
fmPackage(E.package);
printf( " )\n");
}
void fmNetlist(UL_SIGNAL S) {
printf(" ( {Signal %s}\n", S.name);
S.contactrefs(C) {
if (strtol(C.contact.name))
printf(" \"%s\" %s\n", C.element.name, C.contact.name);
else
printf(" { %s %s (can't convert to pin number) }\n", C.element.name, C.contact.name);
}
printf(" )\n");
}
// --------------------------------------------------------------- hlavní funkce
string dlgTitle = "EAGLE to FORMICA 4.30 conversion - enter target file name:";
if (board) board(B) {
string fileName = filesetext (B.name, ".PCB");
fileName = dlgFileSave(dlgTitle, fileName, "*.PCB");
if (fileName != "")
output(fileName, "wt") {
ofsx += 200 * ceil((400 - mapx(B.area.x1) + 199) / 200);
ofsy += 200 * ceil((400 - mapy(B.area.y1) + 199) / 200);
printf( "{%s}\n"
"{%s}\n\n"
"{Source file = \"%s\"}\n"
"{Source format = \"%s\"}\n\n",
title,
version,
B.name,
EAGLE_SIGNATURE);
fmSetup(mapx(B.area.x1), mapy(B.area.y1), mapx(B.area.x2), mapy(B.area.y2));
printf( "Dimensions (0)\n");
printf( "Layout (\n");
string indent = " ";
printf( " Text (\n");
B.texts(T) fmText(T, "", indent);
printf( " )\n");
printf( " Lines (\n");
B.wires(W) fmWire(W, indent);
B.polygons(P) fmPolygon(P, indent);
B.rectangles(R) fmRectangle(R, indent);
B.signals(S) {
S.wires(W) fmWire(W, indent);
S.polygons(P) fmPolygon(P, indent);
}
printf( " )\n");
printf( " Arcs (\n");
B.circles(C) fmCircle(C, indent);
B.wires(W)
if (W.arc) fmArc(W.arc, indent);
B.signals(S)
S.wires(W)
if (W.arc) fmArc(W.arc, indent);
printf( " )\n");
printf( " Pads (\n");
B.signals(S)
S.vias(V)
printf( " (%d %d %d)\n",
mapx(V.x), mapy(V.y),
fmRoundPadType(V.diameter[LAYER_TOP], V.drill)); //// odlisit ctvercove!!!
B.holes(H)
printf( " (%d %d %d)\n", mapx(H.x), mapy(H.y), fmHoleType(H.drill));
printf( " )\n");
printf( ")\n");
printf( "Components (\n");
B.elements(E) fmComponent(E);
printf( ")\n");
printf( "Netlist (\n");
B.signals(S) fmNetlist(S);
printf( ")\n");
} // output
} // board
else if (library) library(L) {
string fileName = filesetext (L.name, ".PCB");
fileName = dlgFileSave(dlgTitle, fileName, "*.PCB");
if (fileName != "")
output(fileName, "wt") {
printf( "{%s}\n"
"{%s}\n\n"
"{Source file = \"%s\"}\n"
"{%s}\n"
"{Source format = \"%s\"}\n\n",
title,
version,
L.name,
L.headline,
EAGLE_SIGNATURE);
fmSetup(0, 0, 32000, 32000);
printf( "Dimensions (0)\n");
printf( "Components (\n");
int maxx = 400, maxy = 400, newy = 0;
L.packages(P) {
while (1) {
ofsx += 200 * ceil((maxx - mapx(P.area.x1) + 199) / 200);
ofsy += 200 * ceil((maxy - mapy(P.area.y1) + 199) / 200);
if (mapx(P.area.x2) > 32000) {
maxx = 200;
maxy = newy;
}
else break;
}
printf( " (0 0 {%s}\n", P.headline);
int noName = 1, noValue = 1;
P.texts(T)
if (T.value == ">NAME") {
fmText(T, P.name, " ");
noName = 0; // component name found
break;
}
if (noName) fmDefault2(P, P.name, " ");
P.texts(T)
if (T.value == ">VALUE") {
fmText(T, "VALUE", " ");
noValue = 0; // component value found
break;
}
if (noValue)
printf( " (\"\")\n");
printf( " (\"%s\" %d %d %d %d %d %d)\n",
"PACKAGE",
mapx(0), mapy(0), // toto je origin, ne stred !!!!
fmUnit(0), fmAngle(0),
fmLineType(0),
fmLayer(LAYER_TNAMES));
fmPackage(P);
printf( " )\n");
maxx = mapx(P.area.x2) + 100;
newy = max(mapy(P.area.y2) + 100, newy);
}
printf( ")\n");
} // output
} // library
else
dlgMessageBox("To convert schematics, please use the Formica4-S.ulp.");