/* GEDTRC2 (GED) -- Advanced/Unreleased GED Trace and Routing Functions */ /* GEDTRC2 (GED) -- Erweiterte Leiterbahn- und Routingfunktionen */ /* -- INTENDED FOR KEY-CALL USE -- */ /* // Copyright (c) 1996-2006 Oliver Bartels F+E, Erding // Author: Manfred Baumeister // Changes History: // mb (980911) ADAPTED TO BAE V4.2. // mb (980713) ENHANCEMENT: // Pulldown menu delimiters introduced. // mb (980713) ENHANCEMENT: Dynamic multi-language support. // mb (971211) ADAPTED TO BAE V4.0. // mb (960620) ORIGINAL CODING. // // DESCRIPTION // // The gedtrc2 User Language program provides advanced/unreleased GED // trace and routing utilities such as find antennas (i.e. trace ends // not ending on any padstack), create surrounding rectangle fill areas // for all paths (in order to prepare for copper fill for supporting // so-called 'negative techniques'), convert traces to areas, convert // hatch areas to traces. // // WARNINGS // // findantennas() performs EQUALITY trace end point to padstack coordinates // check. findantennas() does not perform trace/padstack layer match check. // findantennas() does not perform special T-connection recognition. // // trace2area() won't work on traces with arc segments. */ // Includes #include "pop.ulh" // User Language popup utilities // Messages string UPRABORT = M_UPRABORT(); string UPRPEXIT = M_UPRPEXIT(); string REPDONE = M("Es wurden keine Fehler festgestellt.", "Operation completed without errors."); string REPSCANMAC = M("Scannen Macros...","Scanning Macros..."); string REPPROCPATH = M("Bearbeite Leiterbahnen...", "Processing paths..."); string REPFANTHD1 = M("Antennensuche","Antenna Search"); string REPFANTHD2 = M(" Projektdatei .......................: '%s'", " Project File .......................: '%s'"); string REPFANTHD3 = M(" Layout .............................: '%s'", " Layout .............................: '%s'"); string REPFANTHD4 = M(" Bahnenden ohne Pin-/Viaanschluss ...: %d", " Trace Ends not ending on Pin/Via ...: %d"); string REPFANTHD5 = M("Antennen/Bahnendpositionen ohne Pin-/Viaanschluss :", "Antennas/Trace End Positions without Pin/Via Connection :"); string REPFANTPOS = M(" %8.3f %8.3f %s"," %8.3f %8.3f %s"); string REPFANTEND = M(" -- Ende --"," -- End --"); string UPRFCT = M("Leiterbahn-/Routing-Funktion selektieren!", "Select Trace/Routing Function!"); string UPRFCT1 = M("%An&tennensuche","%&Search Antennas"); string UPRFCT2 = M("&Bahn->Flaeche","&Trace->Area"); string UPRFCT3 = M("Bahn&fuellflaechen","Trace &Fill Areas"); string UPRFCT4 = M("&Schraff.fl.->Bahn","&Hatch Area->Trace"); string UPRSELTRC = M("Leiterbahn waehlen!","Select Trace!"); string ERRDELTRC = M("Fehler beim Loeschen der alten Leiterbahn!", "Error deleting old trace!"); string ERRPATH = M("Fehler beim Erzeugen der neuen Leiterbahn!", "Error creating new trace!"); string ERRARCPROC = M("Bogenfoermige Leiterbahnen nicht unterstuetzt!", "Sorry, trace arcs are not yet supported!"); string ERRTRCSEGL = M("Zu kurze Bahnsegmente fuer diese Ausdehnung!", "Trace segments too short for given distance!"); string ERRPOLYFILL = M("Fehler beim Plazieren der Fuellbereiche!", "Error placing fill area!"); string ERRDELHATCH = M("Fehler beim Loeschen der Schraffurflaeche!", "Error deleting hatch area!"); // Trace to area Compiler directives #define ROUNDTRCEND // Round trace ends request flag #undef ROUNDTRCEND // Disable trace ends rounding // Trace antenna globals double xs,ys; // Trace start point coordinates double xe,ye; // Trace end point coordinates int founds; // Padstack on trace start flag int founde; // Padstack on trace end flag string UNIT = bae_getcoorddisp() ? "[\"]" : "[mm]"; // Unit designator double ITOB = baecvtl(1.0); // Int. to BAE disp. scale factor // Trace to area globals double PI = cvtangle(180.0,1,2); // (Constant) PI value struct { // Point descriptor double x; // Point x coordinate double y; // Point y coordinate int typ; // Point type } pointl[]; // Point list int pointn; // Point count int pointfound; // Point found flag // Trace fill globals #define BORDEREXT 10.0 // Trace rect. border ext. factor struct trcrectdes { // Trace rectangle descriptor int lay; // Trace rectangle layer double xmin,ymin; // Trace rect. lower boundaries double xmax,ymax; // Trace rect. upper boundaries double area; // Trace area string netname; // Trace net name } rectl[]; // Trace rectangle list int rectn = 0; // Trace rectangle count int rectsl[]; // Sorted rectangle list struct ptdes { // Point descriptor double x,y; // Point coordinates int typ; // Point type }; // Hatch area to trace conversion globals int pcnt; // Path count // Main program main() { // Abort if invalid plan class if (bae_planddbclass()!=DDBCLLAY && bae_planddbclass()!=DDBCLLPRT) error_class(); // Select trace/routing function type perror(UPRFCT); switch (bae_askmenu(5,UPRFCT1,UPRFCT2,UPRFCT3,UPRFCT4,UPRABORT)) { // Find antennas case 0 : findantennas(); break; // Trace to area conversion case 1 : trace2area(); break; // Trace fill area generation case 2 : tracefill(); break; // Hatch area to trace conversion case 3 : hatch2trace(); break; // Abort on default default : error("\n"); } } //__________________________________________________________________ // Trace antenna functions void findantennas() // Find Antennas (i.e. trace ends not ending on any padstack) { index L_LINE line; // Trace path index index L_POINT point; // Polygon point index double nx,ny; // Plan origin coordinates STRINGS hl; // Popup header/entry list int hn; // Popup header/entry count STRINGS el; // Popup header/entry list int en = 0; // Popup header/entry count // Get plan origin coordinates nx=bae_planwsnx(); ny=bae_planwsny(); // Iterate trace paths forall (line) { // Iterate trace path points forall (point of line) { // Test if start point if (point==0) { // Get start coordinates xs=point.X; ys=point.Y; } else { // Set end coordinates xe=point.X; ye=point.Y; } } // Init found flags founds=founde=0; // Scan macros perror(REPSCANMAC); lay_scanall(0.0,0.0,0.0,1,1, findantennas_macfunc,NULL,NULL,NULL,NULL,NULL,NULL); // Issue message if no padstack at start point if (!founds) { sprintf(el[en],REPFANTPOS, ITOB*(xs-nx),ITOB*(ys-ny),UNIT); en++; } // Issue message if no padstack at end point if (!founde) { sprintf(el[en],REPFANTPOS, ITOB*(xe-nx),ITOB*(ye-ny),UNIT); en++; } } // Issue report header hn=5; hl[1]=""; hl[0]=REPFANTHD1; sprintf(hl[2],REPFANTHD2,bae_planfname()); sprintf(hl[3],REPFANTHD3,bae_planename()); sprintf(hl[4],REPFANTHD4,en); if (en) { hl[5]=""; hl[6]=REPFANTHD5; hn=7; el[en++]=REPFANTEND; } // Show report with popup menu popupmenu(0,"",hl,hn,el,en,UINPOPABORT,0,-1,-1,hn+en+2,100,0,""); } int findantennas_macfunc(index L_MACRO macro,index L_POOL pool, int macinws,string refname,index L_LEVEL level) // Find antennas macro scan function // Returns: // 0 if out of workspace, 1 if inside, 2 if unknown, or (-1) on error // Parameters: // index L_MACRO macro : Macro index // index L_POOL pool : Macro pool index // int macinws : Macro in workspace flag // string refname : Macro reference name // index L_LEVEL level : Level index { double x,y; // Macro coordinates // Abort program on request if (kbhit() && verify(UPRPEXIT,0)) error_abort(); // Test if padstack macro if (macro.CLASS==DDBCLLSTK) { // Get macro coordinates lay_maccoords(x,y,0.0,0,0); // Test on trace start point match if (x==xs && y==ys) founds=1; // Test on trace end point match if (x==xe && y==ye) founde=1; // Done return(0); } // Continue scan return(1); } //__________________________________________________________________ // Trace to area conversion functions void trace2area() // Convert traces to areas { index L_FIGURE fig; // Figure list index index L_CNET net; // Netlist index string netname; // Net name int layer; // Layer number // Abort if invalid plan class if (bae_planddbclass()!=DDBCLLAY && bae_planddbclass()!=DDBCLLAY) { error_class(); } // Loop while pick element found while (perror(UPRSELTRC),ged_pickelem(fig,L_FIGPATH)==0) { // Get path layer layer=fig.LAYER; // Get path net name if (lay_gettreeidx(fig.TREE,net)) { netname=""; } else { netname=net.NAME; } // Clear internal polygon point list bae_clearpoints(); // Clear point found flag pointfound=0; // Scan path data if (lay_scanfelem(fig,0.0,0.0,0.0,1,0, NULL,NULL,trace2area_pathfunc,NULL,NULL,NULL,NULL)) error_scan(); // Check if path points found if (pointfound) { // Store copper layer polygon if (ged_storepoly(layer, netname ? L_POLYCOPACT : L_POLYCOPPASS,netname,0)) { error(ERRTRCSEGL); } // Delete old path if (ged_delelem(fig)) { error(ERRDELTRC); } } } // Screen redraw screenredraw(); // Done perror(REPDONE); } int trace2area_pathfunc(index L_LINE path, int layer,int pathinws,index L_LEVEL level) // Path scan function; generates path boundary polygon // Returns: // zero if done or (-1) on error // Parameters: // index L_LINE path : Path index // int layer : Path layer // int pathinws : Path in workspace flag // index L_LEVEL level : Path level { index L_POINT point; // Polygon point index double x,y; // Point coordinate buffers double ex,ey; // Extra point coordinate buffers double sl1,sl2; // Segment lengths double sx1,sx2; // Segment x-coordinates double sy1,sy2; // Segment y-coordinates double wx,wy; // Bisector vector coords. double wl = 0; // Bisector length double smang; // Smaller segment angle double rang; // Real segment angle double rad; // Real radius int i; // Loop control variable // Reset point count pointn=0; // Scan points forall (point of path) { // Add point to path point list pointl[pointn].x=point.X; pointl[pointn].y=point.Y; if (point.TYP) { error(ERRARCPROC); } // Check double points if (pointn && point.X==pointl[pointn-1].x && point.Y==pointl[pointn-1].y) { continue; } // Check redundant points if (pointn>1) { if (((pointl[pointn-1].x-pointl[pointn-2].x)* (pointl[pointn].y-pointl[pointn-1].y))== ((pointl[pointn-1].y-pointl[pointn-2].y)* (pointl[pointn].x-pointl[pointn-1].x))) { pointl[pointn-1].x=point.X; pointl[pointn-1].y=point.Y; continue; } } // Increment point count pointn++; } // Check if processable path if (pointn<2) { // Don't process return(0); } // Set point found flag pointfound=1; // Get real radius rad=path.WIDTH/2.0; // Store start points ex=pointl[0].x; ey=pointl[0].y; sx1=ex-pointl[1].x; sy1=ey-pointl[1].y; normvect(sx1,sy1,sl1); if (bae_storepoint(ex+rad*sy1,ey-rad*sx1,0)) return(-1); #ifdef ROUNDTRCEND if (bae_storepoint(ex,ey,1)) return(-1); #endif if (bae_storepoint(ex-rad*sy1,ey+rad*sx1,0)) return(-1); // Loop for inner points for (i=1;i<(pointn-1);i++) { // Get point coordinates x=pointl[i].x; y=pointl[i].y; // Get normalized data of first segment vector sx1=pointl[i-1].x-x; sy1=pointl[i-1].y-y; normvect(sx1,sy1,sl1); // Get normalized data of second segment vector sx2=pointl[i+1].x-x; sy2=pointl[i+1].y-y; normvect(sx2,sy2,sl2); // Get normalized bisector vector wx=sx1+sx2; wy=sy1+sy2; normvect(wx,wy,wl); // Get smaller angle between the two segments smang=acos(sx1*sx2+sy1*sy2)/2.0; // Set bisector circle center dist. wl=rad/sin(smang); // Get real angle rang=fmod(atan2(sx2,sy2)-atan2(sx1,sy1)+2.0*PI,2.0*PI); // Store path circle center point if (rang>PI) { if (bae_storepoint(x+wl*wx,y+wl*wy,0)) { return(-1); } } else { if (bae_storepoint(x-wl*wx,y-wl*wy,0)) { return(-1); } } } // Store end points ex=pointl[pointn-1].x; ey=pointl[pointn-1].y; sx1=ex-pointl[pointn-2].x; sy1=ey-pointl[pointn-2].y; normvect(sx1,sy1,sl1); if (bae_storepoint(ex+rad*sy1,ey-rad*sx1,0)) { return(-1); } #ifdef ROUNDTRCEND if (bae_storepoint(ex,ey,1)) { return(-1); } #endif if (bae_storepoint(ex-rad*sy1,ey+rad*sx1,0)) { return(-1); } // Process second path side for (i=pointn-2;i>0;i--) { // Get point coordinates x=pointl[i].x; y=pointl[i].y; // Get normalized data of first segment vector sx1=pointl[i-1].x-x; sy1=pointl[i-1].y-y; normvect(sx1,sy1,sl1); // Get normalized data of second segment vector sx2=pointl[i+1].x-x; sy2=pointl[i+1].y-y; normvect(sx2,sy2,sl2); // Get normalized bisector vector wx=sx1+sx2; wy=sy1+sy2; normvect(wx,wy,wl); // Get smaller angle between the two segments smang=acos(sx1*sx2+sy1*sy2)/2.0; // Set bisector circle center dist. wl=rad/sin(smang); // Get real angle rang=fmod(atan2(sx2,sy2)-atan2(sx1,sy1)+2.0*PI,2.0*PI); // Store path circle center point if (rangxmax) xmax=cpoint.x; else if (cpoint.xymax) ymax=cpoint.y; else if (cpoint.yxmax) xmax=cpoint.x+r; else if ((cpoint.x-r)ymax) ymax=cpoint.y+r; else if ((cpoint.y-r)ridx;i--) { rectsl[i]=rectsl[i-1]; } // Store new rectangle index to sorted index list rectsl[ridx]=rectn; // Store rectangle data rectl[rectn].lay=layer; rectl[rectn].xmin=xmin; rectl[rectn].xmax=xmax; rectl[rectn].ymin=ymin; rectl[rectn].ymax=ymax; rectl[rectn].area=area; if (lay_gettreeidx(path.TREE,cnet)) { rectl[rectn].netname=""; } else { rectl[rectn].netname=cnet.NAME; } // Increment rectangle count rectn++; // Return without errors return(0); } int findinsrect(double area) // Search insertion point in size sorted rectangle list // Returns: // rectangle list insertion point // Parameters ; // double area : Rectangle area { int slb = 0; // Search lower boundary int sub = rectn-1; // Search upper boundary int sidx; // Search index int compres; // Compare result // Loop until search area empty while (slb<=sub) { // Get search index sidx=(slb+sub)>>1; // Compare rectangle areas if (area==rectl[rectsl[sidx]].area) // Rectangle found return(sidx); else compres=area1 && ged_delelem(fig)) { error(ERRDELHATCH); } } // Screen redraw screenredraw(); // Done perror(REPDONE); } int hatch2trace_pathfunc(index L_LINE path, int layer,int pathinws,index L_LEVEL level) // Hatch area to trace conversion path scan function // Returns: // zero if done or (-1) on error // Parameters: // index L_LINE path : Path index // int layer : Path layer // int pathinws : Path in workspace flag // index L_LEVEL level : Path level { index L_POINT point; // Point index // Clear internal point list bae_clearpoints(); // Check if valid path if (path.PN<2) { return(0); } // Iterate path points forall (point of path) { // Store path point if (bae_storepoint(point.X,point.Y,point.TYP)) { return(-1); } } // Store new path if (ged_storepath(layer,path.WIDTH)) { error(ERRPATH); } // Increment path count pcnt++; // Return without errors return(0); } //__________________________________________________________________ // User Language program end