#usage "en: Calculate the wire length from pad to pad" "

" "Example:
" "RUN lpp Elementname Padname Elementname Padname [Elementname Padname Elementname Padname ...]
" "RUN lpp /G

" "You always have to specify a pair of Elementname + Padname.
" "The ULP now calculates the length of the wire connection between the given pads. " "So it is possible to measure the lenght of the trace between two contacts. " "Other PADs/SMDs which are on the way are not taken into consideration.
" "Option:/G
" "The ULP can be used with option /G, in case you defined a group in the layout before. " "For each signal of the group the ULP searches for a starting point and the PAD/SMD next to it. " "
" "Micro, blind and buried vias are supported." "

" "Limitations:
" "There shouldn't be several signal branches and vias at the same location, " "otherwise it may happen that the wrong branch will be calculated!

" "Length information of traces that have such a branching point with vias as well as " "non-continuous traces will be especially marked.

" "For displaying possible additional information double-click one of the list entries " "and choose (one of) the available parameter(s) in the menu. " "
" "WIREs of an arbitrary PAD/SMD shape within a package will be ignored and might prompt a " "message that tells you that the pad is not routed! " "

" "

" "Autor: info@az-cad.de" , "de: Berechnet die Länge von Leiterbahnen zwischen zwei PADs." "

" "Beispiel:
" "RUN lpp Elementname Padname Elementname Padname [Elementname Padname Elementname Padname ...]
" "RUN lpp /G

" "Es muss immer ein Paar von Elementname + Padname angegeben werden.
" "Es wird nur die Länge der Leitung zwischen den beiden angegebenen Pads berechnet. " "Somit ist es möglich eine beliebige Strecke zwischen zwei Kontaktpunkten zu messen. " "Dazwischen liegende PADs/SMDs werden nicht beachtet.
" "Option:/G
" "Man kann vorher auch eine GROUP definieren und dann mit der Option /G starten.
" "Dabei wird von jedem Signal in der Gruppe eine Anfangskoordinate benutzt und bis zum nächsten PAD/SMD gesucht." "
" "Micro-, Blind- und Buried-VIAs werden unterstützt." "

" "Einschränkungen:
" "Es dürfen keine Mehrfachabzweigungen und VIAs an derselben Koordinate vorkommen, " "da sonst die falsche Abzweigung benutzt werden kann!

" "Längenangaben, bei denen innerhalb der Strecke Mehrfachabzweigung und zugleich VIAs vorkommen sowie " "nicht durchgängig geroutete Leitungen, werden enstprechend markiert.

" "Um mögliche weitere Details anzeigen zu lassen, doppelklicken Sie auf eine Zeile der Liste " "und wählen Sie im sich öffnenden Menü die entsprechenden (Einzel-) Parameter." "
" "Die WIREs eines erweiterten PAD/SMD innerhalb eines Package werden nicht berücksichtigt und führen " "u.U. zu der Meldung, dass das Pad nicht geroutet ist!" "

" "

" "Autor: info@az-cad.de" string Version = "1.0.6"; // 2013-01-03 info@az-cad.de // 2013-01-11 // 2013-01-13 Option /G // 2013-03-02 Pad am Wire-Ende suchen berichtigt // Signal darf auch aus nur einem Wire-Segement bestehen bei Option /G // 2013-04-16 usage und diverse Meldungen in Englisch #require 6.0400; string Option = ""; enum { null, TypeW, TypeS, TypeP, TypeV }; string Typ[] = { "null", "Wire", "Smd ", "Pad ", "Via " }; int wx1[]; // X coordinate int wy1[]; // Y coordinate int wx2[]; // X coordinate int wy2[]; // Y coordinate int wl[]; // Layer int ws[]; // Start Layer for Via & Pad, Smd and Wire int we[]; // End Layer for Via & Pad, Smd and Wire == Start Layer int wt[]; // Type real wlen[]; // Länge des Wire in mm real LengthPadPad; real LengthDif[]; string wirelen[]; // Liste der berechneten Längen der Wiresegemente von Pad zu Pad int wused[]; // Zähler ob benutzt und zugleich die gefundene Reihenfolge // ein minus Wert signalisiert eine Via string wpart[]; string wpad[]; int Ucnt = 1; int Ncoord = 0; // Anzahl der Koordinaten (WIRE/VIA/SMD/PAD) int K2 = 0; // Index auf die aktuell bearbeitete Wire-Koordiante x1y1 x2y2 int NumSEcoord = 0; // Anzahl aller Start / End-Koordinaten int ErrorCoord = 0; // Zeiger auf die Koordinate, an der es klemmt. string ElementName1; string PadName1; string ElementName2; string padname2; string StartElement; // für die Option /G 2013-02-25 string StartPad; string EndElement; string EndPad; string FoundElement; string FoundPad; int StartPadX, StartPadY, EndPadX, EndPadY; int vs[]; // Layerstacktiefe Anfang | VIAs nie als Start benutzen, sondern die Startbedingung int ve[]; // Layerstacktiefe Ende | der Wire prüfen, ob er duch die Via angebunden ist. int LayerStart1, LayerStart2, LayerEnd1, LayerEnd2; int LastX, LastY, LastK2, LastI; // da es mehr als eine End-Koordinate geben kann, // muß immer die vorhergehende Koordinate überprüft werden. string Header = "diff. mm\t\diff. %\tMM\tSignal\tPart\tPad\tCoord\tPart\tPad\tCoord\tComment"; int Start1X, Start1Y, End2X, End2Y; int StartI, EndI, Start2I, End2I; // zum debuggen string WireCoordText; // ### ---------------- functions ------------------- ### void checkshow(string line) { string s[]; int cnt = strsplit(s, line, '\t'); string list[]; string viewheadline; if (language() == "de") { sprintf(list[0], "mm diff\t%s\tHighlighted das Signal", s[0]); sprintf(list[1], "%c diff\t%s\tHighlighted das Signal", '%', s[1]); sprintf(list[2], "Länge\t%s\tZoomt die Pad-Koordinaten und highlighted das Signal", s[2]); sprintf(list[3], "Signal\t%s\tHighlighted das Signal mit einer Box inkl. Strahl von links oben", s[3]); sprintf(list[4], "Element 1\t%s\tHighlighted das Element mit einer Box inkl. Strahl von links oben", s[4]); sprintf(list[5], "Pad 1\t%s\tZoomt den Pad in die Mitte und highlighted das Element", s[5]); sprintf(list[6], "Start-Koordinate\t%s\tZoomt die Koordinate in die Mitte und highlighted das Signal", s[6]); sprintf(list[7], "Element 2\t%s\tHighlighted das Element mit einer Box inkl. Strahl von links oben", s[7]); sprintf(list[8], "Pad 2\t%s\tZoomt den Pad in die Mitte und highlighted das Element", s[8]); sprintf(list[9], "End-Koordinate\t%s\tZoomt die Koordinate in die Mitte und highlighted das Signal", s[9]); viewheadline = "Zeige\tDetail\tBereich"; } else { sprintf(list[0], "mm diff\t%s\thighlight the signal", s[0]); sprintf(list[1], "%c diff\t%s\thighlight the signal", '%', s[1]); sprintf(list[2], "Length\t%s\tzoom in at pad coordinates and highlight the signal", s[2]); sprintf(list[3], "Signal\t%s\thighlight the signal and draw box incl. pointer from upper left corner", s[3]); sprintf(list[4], "Element 1\t%s\thighlight the element and draw a box incl. a pointer from upper left corner", s[4]); sprintf(list[5], "Pad 1\t%s\tzoom and center pad and highlight element", s[5]); sprintf(list[6], "Start coordinate\t%s\tzoom in and center at this coordinate and highlight the signal", s[6]); sprintf(list[7], "Element 2\t%s\thighlight the element and draw a box with a pointer from upper left corner", s[7]); sprintf(list[8], "Pad 2\t%s\tzoom in and center pad and higlight the element", s[8]); sprintf(list[9], "End coordinate\t%s\tzoom in and center at the coordinate and highlight the signal", s[9]); viewheadline = "Show\tDetail\tArea"; } int sel; int srt; dlgDialog("List Detail") { dlgHBoxLayout { dlgVBoxLayout dlgSpacing(220); dlgListView(viewheadline, list, sel, srt) { switch(sel) { case 0 : exit("SHOW "+s[3]); case 1 : exit("SHOW "+s[3]); case 2 : exit("WIN "+s[6]+" "+s[9]+";SHOW @ "+s[3]); case 3 : exit("SHOW @ "+s[sel]); case 4 : exit("SHOW @ "+s[sel]); case 5 : exit("WIN "+s[6]+";"+"SHOW "+s[4]); case 6 : exit("WIN "+s[sel]+";"+"SHOW "+s[sel]); case 7 : exit("SHOW @ "+s[sel]); case 8 : exit("WIN "+s[9]+";"+"SHOW "+s[7]); case 9 : exit("WIN "+s[sel]+";"+"SHOW "+s[sel]); default : ; } } } dlgPushButton("+OK") dlgAccept(); }; } // *** different length to shortesd signals in percent *** string percent( real length, real length100) { string s; if (length100) sprintf(s, "%.3f", (length - length100) / (length100 / 100)); else s = "--"; return s; } // save data void save(string fname, string option) { output(filesetext(fname, option+".lpp"), "wtD") { int n; printf("#%s : Option:%s\n%s\n", filename(argv[0]), option, Header); do { printf("%s\n", wirelen[n]); } while (wirelen[n++]); } exit(0); } real ArcLength(real ang1, real ang2, real radius) { return radius * 2 * PI / 360 * (ang2 - ang1); } real WireLength(real x1, real x2, real y1, real y2) { return sqrt((pow(x2 - x1, 2) + pow(y2 - y1, 2)) ); } real addlength(UL_WIRE W) { if (W.curve) { return ArcLength(W.arc.angle1, W.arc.angle2, u2mm(W.arc.radius)); } else { return WireLength(u2mm(W.x2), u2mm(W.x1), u2mm(W.y2), u2mm(W.y1)); } } // collect coordinate void add(int x1, int y1, int x2, int y2, int lay, int l_start, int l_end, int type, real wirelength) { if (lay == 19) return; // keine Luftlinien benutzen 2013-02-27 wx1[Ncoord] = x1; wy1[Ncoord] = y1; wx2[Ncoord] = x2; wy2[Ncoord] = y2; wl[Ncoord] = lay; ws[Ncoord] = l_start; we[Ncoord] = l_end; wt[Ncoord] = type; wlen[Ncoord] = wirelength; wused[Ncoord] = 0; // preset Ncoord++; return; } // get and check signalname on pads string get_check_signal(string elementname1, string PadName1, string elementname2, string padname2, int cnt) { string found1 = "", found2 = ""; board(B) { B.elements(E) { if (E.name == elementname1) { E.package.contacts(C) { if (C.name == PadName1) { found1 = C.signal; StartPadX = C.x; StartPadY = C.y; if (C.smd) { LayerStart1 = C.smd.layer; LayerStart2 = C.smd.layer; } else if (C.pad) { LayerStart1 = 1; LayerStart2 = 16; } break; } } break; } } B.elements(E) { if (E.name == elementname2) { E.package.contacts(C) { if (C.name == padname2) { found2 = C.signal; EndPadX = C.x; EndPadY = C.y; if (C.smd) { LayerEnd1 = C.smd.layer; LayerEnd2 = C.smd.layer; } else if (C.pad) { LayerEnd1 = 1; LayerEnd2 = 16; } } } break; } } } if (!found1 || !found2 || found1 != found2) { string err; if (!found1) { sprintf(err, "!Pad %s of element %s not found!", PadName1, ElementName1); } if (!found2) { sprintf(err, "!Pad %s of element %s not found!", padname2, ElementName2); } if (found1 != found2) { string fe1 = found1, fe2 = found2; if (!fe1) fe1 = "~no signal~"; if (!fe2) fe2 = "~no signal~"; sprintf(err, "!Different Signal #%d %s [%s %s] : %s [%s %s]", cnt, fe1, ElementName1, PadName1, fe2, ElementName2, padname2); } dlgMessageBox(err + "\nQuit with SHOW command!", "OK"); exit("SHOW "+found1+" "+found2); } return found1; } // suche die weiterführende Koordinate auf dem selben Layer, // wenn es nicht mehr weiter geht, suche nach einer Via, // und dann wieder weiter. int getnextcoord(int i, int k) { int x, y, l; l = wl[i]; // der Layer des Wire if (k == 2) { // wenn 2 suche nach Koordinate 1 x = wx1[i]; y = wy1[i]; } else { // wenn 1 suche nach Koordinate 2 x = wx2[i]; y = wy2[i]; } for (int n=0; n= LayerEnd2) { if (x == EndPadX && y == EndPadY) { K2 = 0; return n; // Ende durch Via erreicht } } if (via >= 0) { // ist eine Via an diesem "Ende", dann suche in einem anderen Layer weiter. for (int n = 0; n = LayerEnd2) { // passt der Layer if (K2 == 1) { // K2 == 1 if (EndPadX == wx2[i] && EndPadY == wy2[i]) { // suche nach der anderen Seite wie k return i; } } else { // dann K2 == 2 if (EndPadX == wx1[i] && EndPadY == wy1[i]) { // suche nach der anderen Seite von k return i; } } }// Ende von if gleich mal prüfen ob das Ende schon erreicht ist /* durchsuche die Liste auf die nachfolgende Koordinate */ /****** VIAs sind in der Suche eingeschlossen, werden also übersprungen. ******/ i = getnextcoord(i, K2); // K2 ist Global! Eine Funktion kann nur einen Return-Wert zurückgeben. /****** VIAs sind in der Suche eingeschlossen, werden also übersprungen. ******/ if (i < 0) return i; /*** hier ist es zu Ende, wenn keine weiterführende Koordinate gefunden wurde ***/ if (K2 == 1) { // K2 == 1 if (EndPadX == wx2[i] && EndPadY == wy2[i]) { // suche nach der anderen Seite wie k LengthPadPad += wlen[i]; // 2013-03-02 return i; } } else { // dann K2 == 2 if (EndPadX == wx1[i] && EndPadY == wy1[i]) { // suche nach der anderen Seite von k LengthPadPad += wlen[i]; // 2013-03-02 return i; } } cntdebug++; } while(i >= 0); /********** suche durch die Liste bis zum End-Pad **********/ // index zum zuletzt gefundenen Wire der auf den PAD/SMD zeigt return i; // - negative Zahl heisst das Ende nicht gefunden! } // überprüfe ob der Wire über eine Via an den SMD (Pad) angebuden ist. int viaandindung(int l, int cntv) { int fehler = 0; string v; for (int cnt = 0; cnt < cntv; cnt++) { if (l >= vs[cnt] && l <= ve[cnt]) return 1; // evtl. noch die Stacktiefe auf die Länge addieren? sprintf(v, "WIRE layer %d : VIA Layer %d-%d", l, vs[cnt], ve[cnt]); } dlgMessageBox(v); return 0; } /*** Hauptschleife der Option [Elementname Pad Elementname Padname] ***/ // ermittle Start-Koordinaten in den Wire-Koordinaten für dieses Signal real checkcoordpadpad(string sigName) { // 2013-01-09 info@az-cad.de NumSEcoord = 0; int cntstart = 0; int cntend = 0; int indexstart[]; int wk[]; int x; int cnti = 0; int cntv = 0; for (x = 0; x < Ncoord; x++) { // Suche zuerst eventuelle Start-VIAs if (StartPadX == wx1[x] && StartPadY == wy1[x] && (wt[x] == TypeV)) { // Via hat 1. Koordinate gleich wie 2. Koordinate vs[cntv] = ws[x]; ve[cntv] = we[x]; cntv++; } } for (x = 0; x < Ncoord; x++) { // Eine VIA nie als Startbedingung benutzen, sondern gleich die entsprechenden Wire suchen, // die an der Via angebunden sind. if (StartPadX == wx1[x] && StartPadY == wy1[x] && wt[x] == TypeW) { // Die erste Seite des Wire if (LayerStart1 == ws[x] || viaandindung(ws[x], cntv)) { indexstart[cntstart] = x; wk[cntstart] = 1; // die Startseite LayerStart1 = ws[x]; LayerStart2 = we[x]; cntstart++; NumSEcoord++; } } if (StartPadX == wx2[x] && StartPadY == wy2[x] && wt[x] == TypeW) { // die zweite Seite des Wire if (LayerStart1 == ws[x] || viaandindung(ws[x], cntv)) { indexstart[cntstart] = x; wk[cntstart] = 2; // die Startseite LayerStart1 = ws[x]; LayerStart2 = we[x]; cntstart++; NumSEcoord++; } } // prüfe auch ob die Enden geroutet sind if (EndPadX == wx1[x] && EndPadY == wy1[x] && (wt[x] == TypeW || wt[x] == TypeV)) { cntend++; } if (EndPadX == wx2[x] && EndPadY == wy2[x] && (wt[x] == TypeW || wt[x] == TypeV)) { cntend++; } } string errorinfo = ""; if (!cntstart) { if (language() == "de") sprintf(errorinfo, "%s PAD %s nicht geroutet!", ElementName1, PadName1); else sprintf(errorinfo, "%s PAD %s not routed!", ElementName1, PadName1); dlgMessageBox(errorinfo); sprintf(errorinfo, "WIN (%.fmm %.fmm);SHOW (%.fmm %.fmm)", u2mm(StartPadX), u2mm(StartPadY), u2mm(StartPadX), u2mm(StartPadY)); exit(errorinfo); } if (!cntend) { if (language() == "de") sprintf(errorinfo, "%s PAD %s nicht geroutet!", ElementName2, padname2); sprintf(errorinfo, "%s PAD %s not routed!", ElementName2, padname2); dlgMessageBox(errorinfo); sprintf(errorinfo, "WIN (%.fmm %.fmm);SHOW (%.fmm %.fmm)", u2mm(EndPadX), u2mm(EndPadY), u2mm(EndPadX), u2mm(EndPadY)); exit(errorinfo); } int foundend = -1; int n = 0; if (Ncoord > 1) { if (NumSEcoord) { foundend = -1; // ### loop ### for (int s = 0; s < cntstart; s++) { // durchsuche alle Start-Koordinaten LengthPadPad = 0; // die Stelle in der Funktion Pad-Pad zum reseten der Gesamtlänge foundend = getendpadpad(indexstart[s], wk[s], sigName); // suche das Ende (PAD/SMD) if (foundend >= 0) return LengthPadPad; } } } return LengthPadPad *= -1.0; // * -1.0; // erzeuge im Fehlerfall ein negatives Vorzeichen //return LengthPadPad; } // ****************************************************** // suche die weiterführende Koordinate auf dem selben Layer, // wenn es nicht mehr weiter geht, suche nach einer Via, // und dann wieder weiter. int getnextcoordpad(int i, int k) { int x, y, l; l = wl[i]; // der Layer des Wire if (k == 2) { // wenn 2 suche nach Koordinate 1 x = wx1[i]; y = wy1[i]; } else { // wenn 1 suche nach Koordinate 2 x = wx2[i]; y = wy2[i]; } int e; for (e = Ncoord-1; e; e--) { // suche vom Ende der Liste her, die Pad/Smd stehen am Schluß if (wt[e] == TypeP || wt[e] == TypeS) { // in Type PAD und SMD suchen if (ws[e] >= ws[i] && we[e] <= we[i]) { // Trifft der Layer des Wire auf den PAD if (x == wx1[e] && y == wy1[e]) { wused[e] = Ucnt++; // zum debuggen LastI = e; return e; } } } } // in Type WIRE suchen und mit gleichen Layer for (int n=0; n= 0) { // ist eine Via an diesem "Ende", dann suche in einem anderen Layer weiter. // gleich mal prüfen ob die Via einen Pad/Smd erreicht? for (e = Ncoord-1; e; e--) { // suche vom Ende der Liste her, die Pad/Smd stehen am Schluß if (wt[e] == TypeP || wt[e] == TypeS) { // in Type PAD und SMD suchen if (x == wx1[e] && y == wy1[e]) { if (ws[e] >= ws[n] && we[e] <= we[n]) { // Trifft der Layer des Via auf den PAD wused[e] = Ucnt++; // zum debuggen LastI = e; return e; } } } } for (int n = 0; n = ws[i] && we[e] <= we[i]) { // Trifft der Layer des Wire auf den Layer des PAD if (x == wx1[e] && y == wy1[e]) { wused[e] = Ucnt++; // zum debuggen LastI = e; return e; } } } } // nichts gefunden? Dann suche nach Via für einen Layer wechsel int via = -1; int n; for (n = 0; n= ws[i] && we[n] <= we[i]) { // Trifft der Layer des Wire auf den Layer des PAD if (x == wx1[n] && y == wy1[n]) { via = n; wused[n] = Ucnt*-1; // zum debuggen break; } } } } if (via >= 0) { // ist eine Via an diesem "Ende", dann suche in einem anderen Layer weiter. // gleich mal prüfen ob die Via einen Pad/Smd erreicht? for (e = Ncoord-1; e; e--) { // suche vom Ende der Liste her, die Pad/Smd stehen am Schluß if (wt[e] == TypeP || wt[e] == TypeS) { // in Type PAD und SMD suchen if (x == wx1[e] && y == wy1[e]) { if (ws[e] >= ws[n] && we[e] <= we[n]) { // Trifft der Layer des Via auf den PAD wused[e] = Ucnt++; // zum debuggen LastI = e; return e; } } } } } // for (e = Ncoord-1; e; e--) { // suche vom Ende des Array, die Pad/Smd stehen am Schluß if (x == wx1[e] && y == wy1[e] && (wt[e] == TypeP || wt[e] == TypeS)) { // ist der Type ein SMD oder PAD if (ws[e] <= ws[i] && we[e] >= we[i]) { // Trifft der Layer des Wire auf den PAD LastX = x; LastY = y; LastI = e; return e; // 2013-01-15 } } } i = getnextcoordpad(i, K2); // K2 ist Global! Weil eine Funktion nur einen Return-Wert zurückgeben kann. cnt++; } while(i >= 0); LastI = i; return i; // 2013-01-15 Ende nicht gefunden } // Option Gruppe markiert. Suche nach dem ersten Pad/Smd in der Kette real searchgrouppad(int n, int k, string signame) { LengthPadPad = 0.0; // die Einzig wahre Stelle zum reseten der Gesamtlänge des Signal in der Group-Option int foundend = -1; foundend = getendgrouppad(n, k, signame); // die Startseite k wird übergeben if (foundend >= 0) { FoundElement = wpart[foundend]; FoundPad = wpad[foundend]; return LengthPadPad; } return LengthPadPad * -1.0; // erzeuge im Fehlerfall ein negatives Vorzeichen } // Option Gruppe markiert. Messe die Wire des markierten Signal real measuringgroup(UL_WIRE W, UL_SIGNAL S, int wx, int wy) { // samme alle koordinaten und suche nach wx1 wy1 Ncoord = 0; S.wires(W) { // zuerst alle Wire sammeln. add(W.x1, W.y1, W.x2, W.y2, W.layer, W.layer, W.layer, TypeW, addlength(W)); } S.vias(V) { // dann die Vias sammeln add(V.x, V.y, V.x, V.y, 18, V.start, V.end, TypeV, 0); // hier evtl. die Bohrtiefe aus den DRC-Daten berechnen 2013-01-02 } S.contactrefs(C) { if (C.contact) { // jetzt noch die CONTACTs sammeln wpart[Ncoord] = C.element.name; wpad[Ncoord] = C.contact.name; if (C.contact.smd) { add(C.contact.x, C.contact.y, C.contact.x, C.contact.y, C.contact.smd.layer, C.contact.smd.layer, C.contact.smd.layer, TypeS, 0); } else { add(C.contact.pad.x, C.contact.pad.y, C.contact.pad.x, C.contact.pad.y, 17, 1, 16, TypeP, 0); } } else { if (language() == "de") dlgMessageBox("Signal '"+ S.name + "' ohne Contactrefs gefunden!\nPrüfen Sie die Konsistenz und evtl. korrupte Signale!", "OK"); else dlgMessageBox("Found signal '"+ S.name + "' without contactrefs!\nCheck consistency and corrupted signals!", "OK"); exit(-1); } } // Das Problem beim Selektieren ist, man kann mit Group keinen Wire in der Mitte selektieren, // sondern nur an den Enden. real len = 0.0; int cntw = 0; int n; /** Reset all global strings **/ StartPad = ""; FoundPad = ""; StartElement = ""; FoundElement = ""; EndPad = ""; FoundPad = ""; EndElement = ""; FoundElement = ""; string h; for (n = 0; n < Ncoord; n++) { if (wx == wx1[n] && wy == wy1[n] && TypeW == wt[n]) { len += searchgrouppad(n, 1, S.name); StartPad = FoundPad; StartElement = FoundElement; Start1X = LastX; Start1Y = LastY; len += searchgrouppad(n, 2, S.name) - wlen[n]; // suche auch nach der anderen Seite EndPad = FoundPad; EndElement = FoundElement; End2X = LastX; End2Y = LastY; cntw++; n = Ncoord; // 2013-02-27 den Wire nur einmal benutzen } else { if (wx == wx2[n] && wy == wy2[n] && TypeW == wt[n]) { len += searchgrouppad(n, 2, S.name); StartPad = FoundPad; StartElement = FoundElement; Start1X = LastX; Start1Y = LastY; len += searchgrouppad(n, 1, S.name) - wlen[n]; // suche auch nach der anderen Seite EndPad = FoundPad; EndElement = FoundElement; End2X = LastX; End2Y = LastY; cntw++; n = Ncoord; // 2013-02-27 den Wire nur einmal benutzen } } } if (cntw > 2) { string h; if (language() == "de") sprintf(h, "!Signal %s\nStartkoordinate enthält Abzweigung!", S.name); else sprintf(h, "!Signal %s\nBranching on starting coordinate!", S.name); if (dlgMessageBox(h, "OK", "ESC") != 0) { string s; sprintf(s, "WIN (%.6fmm %.6fmm);", u2mm(wx), u2mm(wy) ); exit(s); } } return len; } // Option Gruppe markiert, suche nach Wire im Signal die in der Gruppe enthalten sind. int usegroup(void) { int l = 0; board(B) { B.signals(S) { if (ingroup(S)) { // Signal ist in der Group int nx = 0; S.wires(W) { if (ingroup(W)) { real len = measuringgroup(W, S, W.x1, W.y1); // sammel alle koordinaten und suche nach wx1 wy1 LengthDif[l] = len; if (StartElement == EndElement && StartPad == EndPad) { sprintf(wirelen[l], "%s\t%s\t?%s\t?%s\t(%.9fmm %.9fmm)\t?%s\t?%s\t(%.9fmm %.9fmm)", "*start==end*", S.name, StartElement, StartPad, u2mm(Start1X), u2mm(Start1Y), EndElement, EndPad, u2mm(End2X), u2mm(End2Y) ); } else if ((!StartElement && !StartPad) && EndElement && EndPad) { sprintf(wirelen[l], "%s\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)", "*not routed*", S.name, "???", "???", u2mm(Start1X), u2mm(Start1Y), EndElement, EndPad, u2mm(End2X), u2mm(End2Y) ); } else if (StartElement && StartPad && (!EndElement && !EndPad)) { sprintf(wirelen[l], "%s\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)", "*not routed*", S.name, StartElement, StartPad, u2mm(Start1X), u2mm(Start1Y), "???", "???", u2mm(End2X), u2mm(End2Y) ); } else { if (len < 0.0) { LengthDif[l] = 0.0; // 2013-02-27 sprintf(wirelen[l], "*%s\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)", "not found", S.name, StartElement, StartPad, u2mm(Start1X), u2mm(Start1Y), EndElement, EndPad, u2mm(End2X), u2mm(End2Y) ); } else { sprintf(wirelen[l], "%.9f\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)", len, S.name, StartElement, StartPad, u2mm(Start1X), u2mm(Start1Y), EndElement, EndPad, u2mm(End2X), u2mm(End2Y) ); } } l++; break; // W-Schleife abbrechen, nur einen Wire (Koordinate) aus der Gruppe benutzen } } } } if (!l) { if (language() == "de") dlgMessageBox("!Keine Gruppe definiert. ", "OK"); else dlgMessageBox("!No group defined. ", "OK"); exit(-4); } } return l; } // ### main ### if (board) { board(B) { int l = 0; if (argc == 2 && argv[1] == "/G") { // benutze Option Group Option = "~group"; l = usegroup(); } // Ende von benutze definierte Group else { // benutze Option [Element Pad Element Pad] Option = "~pad-pad"; int cnt = argc-1; if (argc > 1) { string h; if (cnt < 4) { if (language() == "de") sprintf(h, "!Zu wenig Parameter: %d", cnt); else sprintf(h, "!Insufficient number of parameters: %d", cnt); dlgMessageBox(h, "OK"); exit(-3); } else { if (cnt & 3 != 2) { if (language() == "de") sprintf(h, "!Ungenügende Anzahl von Parametern: %d", cnt); else sprintf(h, "!Insufficient number of parameters: %d", cnt); dlgMessageBox(h, "OK"); exit(-2); } } } else { dlgDialog("HELP: Lenght PAD PAD") { dlgLabel(usage); dlgHBoxLayout { dlgStretch(1); dlgPushButton("+OK") dlgAccept(); dlgStretch(1); } }; exit(0); } l = 0; string sig; for (int n = 1; n <= cnt; n+=4) { ElementName1 = strupr(argv[n]); PadName1 = strupr(argv[n+1]); ElementName2 = strupr(argv[n+2]); padname2 = strupr(argv[n+3]); sig = get_check_signal(ElementName1, PadName1, ElementName2, padname2, n); string h; sprintf(h, "%s %s (%.9f_%.9f) %s %s (%.9f_%.9f)\n", ElementName1, PadName1, u2mm(StartPadX), u2mm(StartPadY), ElementName2, padname2, u2mm(EndPadX), u2mm(EndPadY) ); WireCoordText += h; B.signals(S) { status(" check "+sig); if (S.name == sig) { // Der Signalname der Pads ist gefunden. Ncoord = 0; S.wires(W) { // zuerst alle Wire sammeln. 2013-01-09 add(W.x1, W.y1, W.x2, W.y2, W.layer, W.layer, W.layer, TypeW, addlength(W)); } S.vias(V) { // dann die Vias sammeln add(V.x, V.y, V.x, V.y, 18, V.start, V.end, TypeV, 0); // hier evtl. die Bohrtiefe aus den DRC-Daten berechnen 2013-01-02 } S.contactrefs(C) { if (C.contact) { // jetzt noch den CONTACT ermitteln, das sind die letzen beiden. 2013-01-09 if (C.contact.smd) { add(C.contact.x, C.contact.y, C.contact.x, C.contact.y, C.contact.smd.layer, C.contact.smd.layer, C.contact.smd.layer, TypeS, 0); } else { add(C.contact.pad.x, C.contact.pad.y, C.contact.pad.x, C.contact.pad.y, 17, 1, 16, TypeP, 0); } } } real len = checkcoordpadpad(S.name); // Suche die Endkoordinaten und ermittle die Länge LengthDif[l] = len; if (len < 0.0) { sprintf(wirelen[l++], "%s\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)", "*not routet*", // markiere nicht geroutete Verbindung S.name, ElementName1, PadName1, u2mm(StartPadX), u2mm(StartPadY), ElementName2, padname2, u2mm(wx2[ErrorCoord]), u2mm(wy2[ErrorCoord]) ); } else { sprintf(wirelen[l++], "%.9f\t%s\t%s\t%s\t(%.9fmm %.9fmm)\t%s\t%s\t(%.9fmm %.9fmm)", len, S.name, ElementName1, PadName1, u2mm(StartPadX), u2mm(StartPadY), ElementName2, padname2, u2mm(EndPadX), u2mm(EndPadY) ); } } } } } // Ende von benutzen Element Pad Element Pad int index[]; sort(l, index, LengthDif); real null_length = LengthDif[index[0]]; string h; for (int i = 0; i < l; ++i) { sprintf(h, "%.6f\t%s\t", LengthDif[index[i]] - null_length, percent(LengthDif[index[i]], null_length) ); wirelen[index[i]] = h + wirelen[index[i]]; } int sel = -1; int srt = 0 ; dlgDialog("Lenght PAD PAD" + Option) { dlgLabel("Option:" + Option); dlgHBoxLayout { dlgVBoxLayout dlgSpacing(200); dlgListView(Header, wirelen, sel, srt) dlgAccept(); } if (language() == "de") dlgLabel("Um Details eines Eintrag anzuzeigen, selektieren (doppelklicken) Sie eine Zeile."); else dlgLabel("To show details of a list entry, select (double click) a line."); dlgHBoxLayout { dlgPushButton("+OK") dlgAccept(); dlgPushButton("&Save") { dlgAccept(); save(B.name, Option); } dlgStretch(1); dlgLabel(Version); } }; if (sel >= 0) checkshow(wirelen[sel]); exit(0); } } else { if (language() == "de") dlgMessageBox("Starten Sie das ULP in einem Board", "OK"); else dlgMessageBox("Start this ULP in a Board", "OK"); }