Files
SyncHome/trunk/ulp/mirror-board-remirror-element-swap-layer.ulp

432 lines
17 KiB
Plaintext
Raw Permalink Normal View History

2023-03-09 10:24:21 +00:00
#usage "de:<b>Spiegelt das gesamte Board, spiegelt dann die Bauteile an ihrem Origin zurück und zeichnet die Leiterbahnen "
"(Top/Bottom) gespiegelt ohne die Layer zu tauschen.</b><br>"
"Um zum Beispiel aus dem Layout für einem linken Scheinwerfer das Layout für einen rechten Scheinwerfer zu erzeugen.<p>"
"Bei symmetrischen zweipoligen Bauteilen in senkrechter Ausrichtung reicht es die Bauteile einfach zurück zu spiegeln, "
"symmetrische zweipolige Bauteile in waagerechter Ausrichtung müssen zusätzlich um 180<38> gedreht werden "
"um die Position der PADs mit den Leiterbahnen wieder in Einklang zu bringen.<p>"
"Achtung: Asymmetrische und mehrreihige Bauteile wie SOT23 SO14 ... können nicht ohne weiteres gespiegelt und "
"die Anbindung der Leiterbahnen an den PADs behalten werden. "
"Hier muß der Layouter die gerouteten Wire (Leiterbahnen) teilweise aufripen und neu verlegen.<br>"
"Um die Anschlüsse zu überprüfen wird der DRC gestartet und die die Fehlerliste angezeigt. Jeder Overlap bedeutet "
"eine falsch angeschlossene Leiterbahn die entsprechend behandelt werden muß.<br>"
"Je nach Symmetrie des Bauteiles muß entweder das Bauteil verschoben/gedreht und/oder die Wire neu verlegt werden "
"(RIPUP und ROUTE).<p>"
"Interessant ist schon die Definition beim Anlegen in der Bibliothek, so wie beim platzieren der Bauteile "
"im Board ob man den entsprechenden Platz für die gespiegelte Version freihalten kann. "
"Das erspart einiges an Nacharbeit.<br>"
"Unter Umständen mach es Sinn das Bauteil symmetrisch in Bezug auf die PADs und asymmetrisch zu den Packagekonturen "
"anzulegen, damit dann der Origin zwischen den Pads liegt und man das Bauteil nur noch drehen mus.<p>"
"Die Meldung <b>! Alle Signale umwandeln?</b> muß mit <b>Ja</b> beanbtwortet werden, damit die Leiterbahnen aufgeript "
"werden können."
"<p>"
"<author>Author: alf@cadsoft.de</author>"
,
"en: <b>Mirrors the whole board, flips the components back to their original positions and draws the "
"mirrored traces in top and bottom without changing the original layer.<p>"
"For example, for creating the layout for a headlamp on the left out of the layout of a headlamp on the right side. "
"In case you are using symmetrical two-pole components in a vertical orientation it suffices to mirror the components, "
"if they are in a horizontal orientation you additionally have to rotate them by 180 degrees in order to conciliate "
"the position of the pads and the traces.<br>"
"Note: Asymmetric and multi-row components like SOT23, SO14.... can't be mirrored without mixing up the connections "
"between pads and traces. In this case you have to ripup the traces and layout them correctly afterwards.<br>"
"For checking the connections, run the DRC and look into the errors list. Each overlap error shows a mis-connected "
"trace you have to take care on.<br>"
"Depending on the symmetry of the component you have to move/rotate it and/or re-route the traces (RIPUP and ROUTE).<p>"
"Think of this already when creating the library element and placing the component in the layout, and try to "
"reserve some space for the mirrored component. This can save a lot of effort.<br>"
"I can be senseful to create the component symmetric in terms of the pads and asymmetric in terms of the package "
"contours so that the origin is located between the pads and you finally only have to rotate the component.<p>"
"The message Ripup all signals? has to be answered with Yes in order to ripup all signals."
"<p>"
"<author>Author: alf@cadsoft.de</author>"
#require 5.1100
// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
string Version = "1.0.0"; // 2011-05-25
int test = 0;
string Sname = "";
string CheckPos = "";
int CntCheckPos = 0;
int CntSymPos = 0;
int CntSymPos180 = 0;
string cmd, s;
int lVisible[];
int useLayer[];
int lcolor[];
int lfill[];
string lNames[] = { " " };
string lockName[];
int cntlock = 0;
int maxX = INT_MIN;
int minX = INT_MAX;
int maxY = INT_MIN;
int minY = INT_MAX;
int bminx, bmaxx, bminy, bmaxy;
string vShape[];
vShape[VIA_SHAPE_SQUARE] = "square";
vShape[VIA_SHAPE_ROUND] = "round";
vShape[VIA_SHAPE_OCTAGON] = "octagon";
vShape[VIA_SHAPE_ANNULUS] = "annulus";
vShape[VIA_SHAPE_THERMAL] = "thermal";
/**** functions ****/
void checkmaxmin(int x1, int x2, int y1, int y2) {
if (x1 > maxX) maxX = x1;
if (x2 > maxX) maxX = x2;
if (y1 > maxY) maxY = y1;
if (y2 > maxY) maxY = y2;
if (x1 < minX) minX = x1;
if (x2 < minX) minX = x2;
if (y1 < minY) minY = y1;
if (y2 < minY) minY = y2;
return;
}
void checkarc( int x1, int x2, int y1, int y2, int xc, int yc, real angle1, real angle2, real radius) {
checkmaxmin( x1, x2, y1, y2 );
if ( angle2 > angle1 + 270.0) {
if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, yc - radius );
else if( angle1 < 180 ) checkmaxmin( xc - radius, xc + radius, y1 , yc - radius );
else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, yc + radius );
else if( angle1 < 360 ) checkmaxmin( xc + radius, xc - radius, y1 , yc + radius );
}
else if( angle2 > angle1 + 180.0) {
if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, y2 );
else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, yc - radius, y2 );
else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, y2 );
else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, yc + radius, y2 );
}
else if( angle2 > angle1 + 90.0 ) {
if ( angle1 < 90 ) checkmaxmin( x1 , x2 , yc + radius, y2 );
else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, y1 , y2 );
else if( angle1 < 270 ) checkmaxmin( x1 , x2 , yc - radius, y2 );
else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, y1 , y2 );
}
return;
}
void lock_elements(void) {
for (int lc = 0; lc < cntlock; lc++) {
cmd += "LOCK " + lockName[lc] + ";\n";
}
return;
}
void setcolor(void) {
string s;
sprintf(s, "SET COLOR_LAYER 1 %d;\n", lcolor[16]); // shwap layer color and fill
cmd += s;
sprintf(s, "SET FILL_LAYER 1 %d;\n", lfill[16]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 16 %d;\n", lcolor[1]);
cmd += s;
sprintf(s, "SET FILL_LAYER 16 %d;\n", lfill[1]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 21 %d;\n", lcolor[22]);
cmd += s;
sprintf(s, "SET FILL_LAYER 21 %d;\n", lfill[22]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 22 %d;\n", lcolor[21]);
cmd += s;
sprintf(s, "SET FILL_LAYER 22 %d;\n", lfill[21]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 23 %d;\n", lcolor[24]);
cmd += s;
sprintf(s, "SET FILL_LAYER 23 %d;\n", lfill[24]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 24 %d;\n", lcolor[23]);
cmd += s;
sprintf(s, "SET FILL_LAYER 24 %d;\n", lfill[23]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 25 %d;\n", lcolor[26]);
cmd += s;
sprintf(s, "SET FILL_LAYER 25 %d;\n", lfill[26]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 26 %d;\n", lcolor[25]);
cmd += s;
sprintf(s, "SET FILL_LAYER 26 %d;\n", lfill[25]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 27 %d;\n", lcolor[28]);
cmd += s;
sprintf(s, "SET FILL_LAYER 27 %d;\n", lfill[28]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 28 %d;\n", lcolor[27]);
cmd += s;
sprintf(s, "SET FILL_LAYER 28 %d;\n", lfill[27]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 29 %d;\n", lcolor[30]);
cmd += s;
sprintf(s, "SET FILL_LAYER 29 %d;\n", lfill[30]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 30 %d;\n", lcolor[29]);
cmd += s;
sprintf(s, "SET FILL_LAYER 30 %d;\n", lfill[29]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 31 %d;\n", lcolor[32]);
cmd += s;
sprintf(s, "SET FILL_LAYER 31 %d;\n", lfill[32]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 32 %d;\n", lcolor[31]);
cmd += s;
sprintf(s, "SET FILL_LAYER 32 %d;\n", lfill[31]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 51 %d;\n", lcolor[52]);
cmd += s;
sprintf(s, "SET FILL_LAYER 51 %d;\n", lfill[52]);
cmd += s;
sprintf(s, "SET COLOR_LAYER 52 %d;\n", lcolor[51]);
cmd += s;
sprintf(s, "SET FILL_LAYER 52 %d;\n", lfill[51]);
cmd += s;
return;
}
int checkVia(UL_VIA V) {
if (V.start != 1 || V.end != 16) return 1;
return 0;
}
// main
if (board) {
board(B) {
if (argc < 2) {
int verror = 0;
B.signals(S) S.vias(V) verror += checkVia(V);
if (verror) {
dlgMessageBox("!Do not use this ULP if used blind or micro via(s)!", "OK");
exit(-1);
}
bminx = B.area.x1;
bmaxx = B.area.x2;
bminy = B.area.y1;
bmaxy = B.area.y2;
B.layers(L) {
lNames[L.number] = L.name;
lVisible[L.number] = L.visible;
useLayer[L.number] = L.used;
lcolor[L.number] = L.color;
lfill[L.number] = L.fill;
}
B.wires(W) {
if (W.layer == 20) {
if (W.arc) {
checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius);
}
else {
checkmaxmin( W.x1, W.x2, W.y1, W.y2 );
}
}
}
B.circles(C) {
if (C.layer == 20) {
checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius );
}
}
B.elements(E) {
E.package.wires(W) {
if (W.layer == 20) {
// *** Dimension in Packages ***
if (W.arc) {
checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius);
}
else {
checkmaxmin( W.x1, W.x2, W.y1, W.y2 );
}
}
}
E.package.circles(C) {
if (C.layer == 20) {
checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius );
}
}
}
real mirrorline = (u2mm(maxX) + u2mm(minX)) / 2;
sprintf(s, "DISPLAY ALL;\n");
cmd += s;
sprintf(s, "GROUP ALL;\n");
cmd += s;
cmd += "LOCK (>S 0 0);\n"; // unlock all
sprintf(s, "GRID MM FINEST;\nMIRROR (>%.4fmm %.4fmm);\nGRID LAST;\n", mirrorline, u2mm(minY) );
cmd += s;
cmd += "SET CONFIRM YES;\n"; // die folgende Abfrage mit Ja beantworten.
cmd += "RIPUP;\n"; // alles aufripen bevor die Wire neu gezeichnet werden.
cmd += "SET CONFIRM OFF;\n";
B.elements(E) {
//checkMirrorRotate(E);
int ccnt = 0;
int east = 0, south = 0, west = 0, north = 0, un_defined = 0; // Ost- Süd- West- Nord-Ausrichtung der Pads
E.package.contacts(C) {
ccnt++;
if (C.x == E.x && C.y < E.y) south++; // ist im Westen
else if (C.x == E.x && C.y > E.y) north++; // ist im Osten
else if (C.y == E.y && C.x < E.x) west++; // ist im Süden
else if (C.y == E.y && C.x > E.x) east++; // ist im Norden
else un_defined++; // undefiniert
}
if (un_defined) {
// nur spiegeln, der Anwender muß sich das ansehen
sprintf(s, "MIRROR %s; # un_defined \n", E.name);
cmd += s;
CntCheckPos++;
}
else if (east || west) {
// spiegen und 180<38> drehen X-Achse
sprintf(s, "MIrror %s; # east || west\nROTATE R180 %s; # east || west\n", E.name, E.name);
cmd += s;
sprintf(s, "%s\n", E.name);
CheckPos += s;
CntSymPos180++;
}
else if (north || south) {
// nur spiegeln Y-Achse
sprintf(s, "MIRROR %s; # north || south \n", E.name);
cmd += s;
CntSymPos ++;
}
else {
if (ccnt) {
sprintf(s, "MIRROR %s; # any \n", E.name);
cmd += s;
CntCheckPos++;
}
// ccnt = 0 - Packages ohne Pads nicht zurückspiegeln, kann Dimesion-Package oder sonstiges sein.
}
}
B.signals(S) {
S.wires(W) {
if (W.layer != 19) {
if (W.layer == 1) cmd += "CHANGE LAYER 1;\n";
else if (W.layer == 16) cmd += "CHANGE LAYER 16;\n";
else {
if (dlgMessageBox("!Es werden nur Layer 1 und 16 unterstützt.", "OK", "CANCEL") != 0) exit(-99);
}
sprintf(s, "WIRE '%s' %.4fmm (%.4fmm %.4fmm ) %+.3f (%.4fmm %.4fmm );\n",
S.name, u2mm(W.width),
u2mm(W.x1) * -1.0 + mirrorline*2, u2mm(W.y1),
W.curve,
u2mm(W.x2) * -1.0 + mirrorline*2 , u2mm(W.y2)
);
cmd += s;
}
}
S.vias(V) {
string vFlag = "";
if (V.flags) vFlag = "STOP";
sprintf(s, "CHANGE DRILL %.4fmm;\n", u2mm(V.drill));
sprintf(s, "VIA '%s' %.4fmm %s %d-%d %s (%.4fmm %.4fmm);\n",
S.name,
u2mm(V.diameter[16]),
vShape[V.shape[16]],
V.start, V.end,
vFlag,
u2mm(V.x) * -1.0 + mirrorline*2, u2mm(V.y)
);
cmd += s;
}
S.polygons(P) { // swap polygon to origin layer
P.wires(W) {
sprintf(s, "CHANGE LAYER %d (%.4fmm %.4fmm);\n", W.layer, u2mm(W.x1) * -1.0 + mirrorline*2, u2mm(W.y1));
cmd += s;
break;
}
}
}
cmd += ";\n";
B.elements(E) if (E.locked) cmd += "LOCK " + E.name + ";\n"; // 2009-12-01
cmd += "DISPLAY NONE ";
for(int l = 1; l < 256; l++) {
if (lNames[l]) { // Layer defined
if (lVisible[l]) {
if (l == 1 || l == 16 || l == 21 || l == 22 || l == 23 || l == 24 || l == 25 || l == 26 || l == 27 || l == 28 || l == 29 || l == 30 || l == 31 || l == 32 || l == 51 || l == 52 ) {
if (l == 1) sprintf(s, " %d", 16); // 2009-12-01 shwap visible layers
else if (l == 16) sprintf(s, " %d", 1);
else if (l == 21) sprintf(s, " %d", 22);
else if (l == 22) sprintf(s, " %d", 21);
else if (l == 23) sprintf(s, " %d", 24);
else if (l == 24) sprintf(s, " %d", 23);
else if (l == 25) sprintf(s, " %d", 26);
else if (l == 26) sprintf(s, " %d", 25);
else if (l == 27) sprintf(s, " %d", 28);
else if (l == 28) sprintf(s, " %d", 27);
else if (l == 29) sprintf(s, " %d", 30);
else if (l == 30) sprintf(s, " %d", 29);
else if (l == 31) sprintf(s, " %d", 32);
else if (l == 32) sprintf(s, " %d", 31);
else if (l == 51) sprintf(s, " %d", 52);
else if (l == 52) sprintf(s, " %d", 51);
}
else sprintf(s, " %d", l);
cmd += s;
}
}
}
cmd += ";\n";
}
Sname = filesetext(B.name, "~mirror~script~.scr");
string saveas = dlgFileSave("Save as", B.name, "*.brd");
if (saveas) {
sprintf(s, "WRITE '@%s';\n", saveas); // 2011-05-25 save as
cmd += s;
}
else {
cmd += "RUN ulpmessage 'Do not forgot to save the board by a new name.<p>Vergessen Sie nicht die Datei unter einem anderen Namen zu speichern.';\n";
}
cmd += "DRC ; \n ERRORS ";
output(Sname, "wtD") printf("%s", cmd);
}
}
if (CheckPos) {
sprintf(s, "%d Elements mirrord / Bauteile bespiegelt.\n%d Elements mirrord an 180 degree rotated / Bauteile gespiegelt und 180<38> gedreht.\n\n%d Elements to check, see list / Bauteile zum überpüfen nach Liste.\n",
CntSymPos, CntSymPos180, CntCheckPos
);
dlgDialog("Check routig of elements") {
dlgHBoxLayout dlgSpacing(800);
dlgLabel(usage);
dlgSpacing(12);
dlgLabel(s);
dlgHBoxLayout {
dlgVBoxLayout dlgSpacing(300);
dlgTextView(CheckPos);
}
dlgHBoxLayout {
dlgStretch(1);
dlgPushButton("+OK") dlgAccept();
dlgPushButton("-CANCEL") { dlgReject(); exit(-1); }
dlgStretch(1);
}
};
}
if (test) {
dlgDialog("Test") {
dlgTextEdit(cmd);
dlgHBoxLayout {
dlgPushButton("ok") dlgAccept();
dlgPushButton("esc") { dlgReject(); exit(-2); }
}
};
}
exit("SCRIPT '" + Sname + "'");