/* GEDTRACE (GED) -- GED Trace and Routing Functions */ /* GEDTRACE (GED) -- GED-Leiterbahn- und Routingfunktionen */ /* -- INTENDED FOR KEY-CALL USE -- */ /* // Copyright (c) 1993-2012 Oliver Bartels F+E, Muenchen // Author: Manfred Baumeister // Changes History: // rl (120427) RELEASED FOR BAE V7.8. // rl (110406) ENHANCEMENT: // Added all and inner layer support to trace copy function. // rl (101019) RELEASED FOR BAE V7.6. // rl (091027) RELEASED FOR BAE V7.4. // rl (091006) ENHANCEMENT: // Added differential pair report. // rl (090507) ENHANCEMENT: // Added trace length/width and via count violations to report. // rl (081014) RELEASED FOR BAE V7.2. // rl (080327) ENHANCEMENT: // Added trace layer pair creation function. // rl (080130) ENHANCEMENT: // Added end gap length correction to pair length adjust. // Added optional end length offset to pair length adjust. // Fixed disfunctional start length offset of pair length adjust. // rl (071203) ENHANCEMENT: // Added unroute coordinate list with zoom to option. // rl (071029) RELEASED FOR BAE V7.0. // rl (071015) ENHANCEMENT: // Added trace route and group trace length measurement functions. // Added optional sort by name to tracelist functions. // rl (070509) ENHANCEMENT: // Added trace beautify function. // rl (070208) ENHANCEMENT: // Added trace length serpentine function. // rl (060829) RELEASED FOR BAE V6.8. // rl (060616) ENHANCEMENT: // Introduced via trace center split on via pick. // rl (060612) ENHANCEMENT: // Allowed trace split for gridless trace segments. // rl (051114) ENHANCEMENT: // Added routing grid query function. // rl (050906) RELEASED FOR BAE V6.6. // rl (050602) ENHANCEMENT: // Added antenna search function. // rl (050502) ENHANCEMENT: // Added short circuit trace deletion function. // rl (040831) RELEASED FOR BAE V6.4. // rl (040318) ENHANCEMENT: // Added trace width display to overall length report. // rl (040205) ENHANCEMENT: // Improved approximation for strip line impedance. // rl (030926) ENHANCEMENT: // Introduced trace pattern continue function. // rl (030905) RELEASED FOR BAE V6.2. // rl (030905) ENHANCEMENT: // Introduced HighEnd trace impedance functions. // rl (021214) RELEASED FOR BAE V6.0. // rl (020618) RELEASED FOR BAE V5.4. // rl (010626) RELEASED FOR BAE V5.0. // rl (010529) CHANGE: // Remove redundant countstacks function. // rl (010518) ENHANCEMENT: // Introduced new trace filled with DRC edit function. // rl (010516) ENHANCEMENT: // Added new function to set via check grid range. // Added abort option to tracelist function. // rl (010511) BUGFIX: // Fixed problem with repetitive single trace selections of // same net. // rl (010320) ENHANCEMENT: // Added optional parameter settings from bae.ini file. // rl (001208) ENHANCEMENT: // Added trace fix state restore for trace manipulation functions. // rl (001107) ENHANCEMENT. // Introduced equidistant parallel trace creation function. // rl (000726) RELEASED FOR BAE V4.6. // rl (000726) ENHANCEMENT. // Introduced new trace filled with distance edit function. // rl (000525) ENHANCEMENT. // Introduced trace split function. // rl (000307) ENHANCEMENT. // Introduced trace length adjust function. // rl (991208) ENHANCEMENT. // Fixed single trace length output bug. // rl (990813) RELEASED FOR BAE V4.4. // rl (990331) ENHANCEMENT: // Added overall trace list report with highlight function. // rl (980929) RELEASED FOR BAE V4.2. // mb (980712) ENHANCEMENT: // Pulldown menu delimiters introduced. // mb (980712) ENHANCEMENT: // Dynamic multi-language support introduced. // rl (980514) IMPROVEMENT: // Added arc radius display to trace length report. // rl (971210) RELEASED FOR BAE V4.0. // mb (960919) RELEASED FOR BAE V3.4. // mb (951030) CHANGE: // Changed "Teardrops erzeugen"/"Create Teardrops" menu // item text to "Teardrop-Utilities"/"Teardrop Utilities". // mb (951013) CHANGE: // Changed menu items for TRACERND call. // mb (95) RELEASED FOR BAE V3.2. // mb (941221) IMPROVEMENT: // Trace end cut only optionally with trcparal(). // mb (941221) ENHANCEMENT: // Via functions provided with UL program call to GEDVIA. // mb (941121) ORIGINAL CODING: // Retrieved from TRCUTIL. // mb (941121) ENHANCEMENT: // Integrated POWLAYER, TRCPARAL, TRACECUT // mb (94) RELEASED FOR BAE V3.0. // mb (94) ENHANCEMENT: // Introduced unroutes report function. // mb (93) RELEASED FOR BAE V2.6. // mb (93) ORIGINAL CODING. // // DESCRIPTION // // The gedtrace User Language program activates a menu with // a series of advanced trace, via and netlist functions such // as automatic rounding of trace corners, trace end cutting, // parallel trace generation on alternate layers, trace to // split power plane conversion, teardrop generation, trace // width change, net data query, net highlight with optional // zoom, netlist output, trace length query, power layer // re-definition, trace and/or unroutes report, pin/via statistics // display, via placement, via movement, via type change, etc. // // WARNINGS // // Function trcparal() will cut end segments at a given distance // from trace end points or will drop them if shorter than that // distance. trcparal() WON'T WORK PROPERLY ON TRACES WITH ARC ENDS! // // Function tracecut() will unfix all changed traces. Only the leftmost // (bottom) drill is processed, if there is more than one drill at a // path end. tracecut() WON'T WORK PROPERLY ON TRACES WITH ARC ENDS! */ // Includes #include "pop.ulh" // User Language popup utilities #include "popdraw.ulh" // User Language popup draw. util. #include "lay.ulh" // User Language layout utilities #include "sql.ulh" // User Language SQL utilities // Disable undo state request #pragma ULCALLERNOUNDO // INI file parameter name definitions #define PAR_TRCPARCUT "TRCPARCUT_GED" // Parallel trace end cut length [m] #define PAR_TRCBSLEN "TRCBSLEN_GED" // Trace beautify scan length #define PAR_TRCBSCORN "TRCBSCORN_GED" // Trace beautify corner mode #define PAR_TRCBSCRNL "TRCBSCRNL_GED" // Trace beautify corner length #define PAR_TRCBFSTYP "TRCBFSTYP_GED" // Trace beautify forb. area sub types #define PAR_TRCBSTSET "TRCBSTSET_GED" // Trace beautify trace set #define PAR_TRCSERPLEN "TRCSERPLEN_GED"// Trace serpentine jog length #define PAR_TRCSERPCRN "TRCSERPCRN_GED"// Trace serpentine corner width #define PAR_TRCSERPMAX "TRCSERPMAX_GED"// Trace serpentine max. elevation #define PAR_TRCSERPMIN "TRCSERPMIN_GED"// Trace serpentine min. elevation #define PAR_TRCSERPMOD "TRCSERPMOD_GED"// Trace serpentine corner mode #define PAR_TRCSERPSID "TRCSERPSID_GED"// Trace serpentine side mode #define PAR_TRCSERPLPT "TRCSERPLPT_GED"// Trace serpentine length prio. mode #define PAR_TRCSERPNET "TRCSERPNET_GED"// Trace serpentine net mode #define PAR_TRCWAVELEN "TRCWAVELEN_GED"// Trace pair wave length #define PAR_TRCWAVETYP "TRCDISPTYP_GED"// Trace pair wave display type #define PAR_TRCWAVERAMP "TRCDISPRAMP_GED"// Trace pair ramp factor #define PAR_TRCWAVEF3 "TRCDISPF3_GED" // Trace pair wave 3rd freq. factor #define PAR_TRCWAVEF5 "TRCDISPF5_GED" // Trace pair wave 5th freq. factor #define PAR_TRCDISPLAY "TRCDISPLAY_GED"// Trace pair wave display layer #define PAR_TRCPAIRTOL "TRCPAIRTOL_GED"// Trace pair distance tolerance #define PAR_EPSR "LAYEPSR_LAY" // Default epsilon r #define PAR_LAYT "LAYTHICK_LAY" // Default layer thickness #define PAR_LAYI "LAYISO_LAY" // Default layer isolation #define PAR_LAYF "LAYFILL_LAY" // Default layer fill flag #define PAR_TRCLBOXLD "TRCLBOXLD_GED" // Trace length report box layer display #define PAR_TRCLBOXW "TRCLBOXW_GED" // Trace length report box width // Messages string UPRABORT = M_UPRABORT(); string UPRPEXIT = M_UPRPEXIT(); string UPRFEXIT = M_UPRFEXIT(); string REPDONE = M("Es wurden keine Fehler festgestellt.", "Operation completed without errors."); string REPTRCCONV = M("%d Bahn(en) konvertiert.", "%d trace(s) converted."); string REPGRAFDEL = M("%d Grafikelemente entfernt.", "%d graphic elements deleted."); string REPSCANTRC = M("Scannen Leiterbahnen...", "Scanning traces..."); string REPSCNDRL = M("Scannen Bohrungen...","Scanning drills..."); string REPSCANLEV = M("Scannen Levels ...","Scanning Levels..."); string REPNOANT = M("Keine Antennen gefunden.","No antenna found."); string REPANTCNT = M("%d Antenne(n) gefunden (siehe Highlight).", "%d antenna(s) found (see highlight)."); string REPGRIDMATCH = M("Zur Leiterbahn passende Routingraster:", "Routing Grids matching trace:"); string REPGRID20 = M("1/20\" Standardraster","1/20\" Standard Grid"); string REPGRID40 = M("1/40\" Standardraster, 1/20\" Halbraster", "1/40\" Standard Grid, 1/20\" Half Grid"); string REPGRID50 = M("1/50\" Standardraster","1/50\" Standard Grid"); string REPGRID60 = M("1/60\" Standardraster","1/60\" Standard Grid"); string REPGRID80 = M("1/80\" Standardraster, 1/40\" Halbraster", "1/80\" Standard Grid, 1/40\" Half Grid"); string REPGRID100 = M("1/100\" Standardraster, 1/50\" Halbraster", "1/100\" Standard Grid, 1/50\" Half Grid"); string REPGRID120 = M("1/60\" Halbraster","1/60\" Half Grid"); string REPGRID160 = M("1/80\" Halbraster","1/80\" Half Grid"); string REPGRID200 = M("1/100\" Halbraster","1/100\" Half grid"); string REPTRCLONG = M("Bahnlaenge %s%s bereits laenger als Vorgabe %s%s!", "Picked length %s%s already greater than target length %s%s!"); string REPNETLONG = M("Netzlaenge %s%s bereits laenger als Vorgabe %s%s!", "Picked length %s%s already greater than target length %s%s!"); string REPTRCNLONG = M("Vorgabe %s%s kann mit diesen Parametern nicht erreicht werden (max. %s%s)!", "Target length %s%s cannot be reached with given parameter set (max. %s%s)!"); string REPTRCMINMAX = M("Maxmimalausschlag muss groesser als Minimalausschlag sein!", "Max. elevation must be greater than min. elevation!"); string REPTRCDIFF = M("Enddifferenz %s%s kann nicht ausgeglichen werden (Bahnsegmente zu kurz)!", "Remaining difference %s%s cannot be compensated (segments too short)!"); string REPCHKPATH = M("Pruefen Bahnenden (%d/%d).", "Checking Trace Ends (%d/%d)."); string REPTRCLEN = M("Netz %s : %d Bahn(en), %d Via(s), %s%s", "Net %s : %d Trace(s), %d Via(s), %s%s"); string REPGTRCLEN = M("Gruppe : %d Bahn(en), %d Via(s), %s%s", "Group : %d Trace(s), %d Via(s), %s%s"); string REPTRCRLEN = M("Einzelbahnzug Netz %s : %d Bahn(en), %d Via(s), %s%s", "Single Trace Route Net %s : %d Trace(s), %d Via(s), %s%s"); string REPSTRCLEN = M("Einzelbahn Netz %s, %s%s", "Single Trace Net %s, %s%s"); string REPSPTRCLEN = M("Einzelbahn %s%s","Single Trace %s%s"); string REPPTRCRLEN = M("Einzelbahnzug %d Bahn(en), %d Via(s), %s%s", "Single Trace Route %d Trace(s), %d Via(s), %s%s"); string REPATRCLEN = M(", Radius [%s%s,%s%s]", ", Radius [%s%s,%s%s]"); string REPLTRCLEN1 = M("%-*s : %s%s, %d Bahn(en), %d Via(s)", "%-*s : %s%s, %d Trace(s), %d Via(s)"); string REPLTRCLEN2 = M(",min. %s%s, max. %s%s",",min. %s%s, max. %s%s"); string REPTRCLREP = M("Bahnlaengen Report...","Trace Length Report..."); string REPTRCLHD1A = M("Datei '%s'","File '%s'"); string REPTRCLHD1B = M("Layout '%s'","Layout '%s'"); string REPTRCLHD2 = M("Bahnlaengen Report:","Trace Length Report:"); string REPTRCLHD2V = M("Bahnlaengen Report sichtbare Netze:", "Trace Length Report Visible Nets:"); string REPUNRREP = M("Unroutes Report...","Unroutes Report..."); string REPUNRHD1 = M("Layout '%s' / '%s'","Layout '%s' / '%s'"); string REPUNRHD2 = M("Unroutes Report:","Unroutes Report:"); string REPUNRCNT = M(" Unroutes Gesamtanzahl ..............: %7d", " Unroutes Total Count ...............: %7d"); string REPUNRALL = M(" Unroutes Gesamtlaenge Luftlinien ...: %7.*f [%s]", " Unroutes Total Length Airlines .....: %7.*f [%s]"); string REPUNRHV = M(" Unroutes Gesamtlaenge H+V Summe ....: %7.*f [%s]", " Unroutes Total Length H+V Sum ......: %7.*f [%s]"); string REPUNRH = M(" Unroutes Gesamtlaenge Horizontal ...: %7.*f [%s]", " Unroutes Total Length Horizontal ...: %7.*f [%s]"); string REPUNRV = M(" Unroutes Gesamtlaenge Vertikal .....: %7.*f [%s]", " Unroutes Total Length Vertical .....: %7.*f [%s]"); string REPUNRLIST = M("Unroutesliste :","Unroute List :"); string REPUNRDISP = M("Unroute %d ('%s'), + naechster, - vorheriger. Liste mit ", "Unroute %d, + next, - previous. for list."); string REPMIMP = M("Mikrostrip Leiterbahnimpedanz %s Ohm.", "Micro Strip Trace Impedance %s Ohm."); string REPSIMP = M("Streifenleitung Leiterbahnimpedanz %s Ohm.", "Strip Line Trace Impedance %s Ohm."); string REPNEWMIMP = M("Mikrostrip neue Leiterbahnimpedanz %s Ohm (%s %s).", "Micro Strip Trace Impedance %s Ohm (%s %s)."); string REPNEWSIMP = M("Streifenleitung neue Leiterbahnimpedanz %s Ohm (%s %s).", "Strip Line Trace Impedance %s Ohm (%s %s)."); string REPIMPSET = M("%s (Vorgabe %s Ohm).", "%s (Requested %s Ohm)."); string REPSETLIST = M("Auswahl Versorgungslagendefinitionen :", "Power Layer Setup Name Selection :"); string REPLOADSET = M("Versorgungslagendefinitionen durch '%s' aus '%s' ersetzt.", "Replaced Power Layer Setup by '%s' from '%s'?"); string REPSTORESET = M("Versorgungslagendefinitionen nach '%s' in '%s' geschrieben und zurueckgesetzt.", "Stored Power Layer Setup '%s' to '%s', removed from current layout."); string REPDELSET = M("Versorgungslagendefinitionen '%s' aus '%s' geloescht.", "Deleted Power Layer Setup '%s' from '%s'?"); string REPSETCOMM = M("Nur als Gruppe laden, da sonst Netzinfoverlust bei Flaechen!", "Load as group only, as else area net info will be lost!"); string REPTRCPROC = M("%d/%d Bahnen bearbeitet...", "Processing Traces (%d/%d)..."); string REPTRCPROCDONE = M("%d Bahnen geaendert.","%d traces changed."); string REPPAIRHD2 = M("Differential Pair Report:", "Differential Pair Report:"); string REPPAIRNETS = M("Netzpaar %s/%s %.1f%% parallel", "Net Pair %s/%s %.1f%% parallel"); string REPPAIRNET = M(" Netz %s : %d Via(s), %s%s parallel %s%s", " Net %s : %d Via(s), %s%s parallel %s%s"); string UPRFCT = M("Leiterbahn-/Routing-Funktion selektieren!", "Select Trace/Routing Function!"); string UPRFCT1 = M("Bahn&laengen","Trace Len>h"); string UPRFCT2 = M("Bahnen &Report","Trace Rep&ort"); string UPRFCT3 = M("Unr&outes Report","&Unroutes Report"); string UPRFCT4 = M("%Se&gmente schieben","%Trace &Segment Push"); string UPRFCT5 = M("Bahne&cken aendern","T&race Corner Cut"); string UPRFCT6 = M("Bahn&enden kuerzen","Trace &End Cut"); string UPRFCT7 = M("Bahnen &auftrennen","Trace S&plit"); string UPRFCT8 = M("%&Parallel-Bahnen","%Paralle&l Traces"); string UPRFCT9 = M("Ba&hnen nach Flaechen","Tra&ce to Area"); string UPRFCT10 = M("%Segment&breite","%Segment &Width"); string UPRFCT11 = M("%&Teardrop-Utilities","%&Teardrop Utilities"); string UPRFCT12 = M("&Via-Funktionen","&Via Functions"); string UPRFCT13 = M("%Ver&sorgungslagen","%Power L&ayers"); string UPRFCT14 = M("%E&ditierdarstellung","%Edit &Display"); string UPRFCT15 = M("V&ia Checkbereich","%V&ia Check Range"); string UPRFCT16 = M("%I&mpedanz","%I&mpedance"); string UPRFCT17 = M("%&Kurzschlussbahnen loeschen", "%Delete S&hort Circuit Traces"); string UPRFCT18 = M("A&ntennensuche","A&ntenna Check"); string UPRFCT19 = M("%Rastera&bfrage","%Grid &Query"); string UPRFCT20 = M("%Bahnbegradig&ung","%Trace Beauti&fy"); string UPRTFCT = M("Bahn-Funktion selektieren!", "Select Trace Function!"); string UPRTFCT1 = M("&Laengenabfrage","Length &Query"); string UPRTFCT2 = M("Antennenlaengen &setzen","&Set Antenna Length"); string UPRTFCT3 = M("Auf Laenge &maeandern","Serpentine &Trim Length"); string UPRTFCT4 = M("&Paar Laengenausgleich","&Pair Trim Length"); string UPRTFCT5 = M("P&hasenanzeige Paar","&Display Pair Phases"); string UPRTFCT6 = M("Paarp&ruefreport","Pair &Check Report"); string UPRLFCT = M("Report-Funktion selektieren!", "Select Report Function!"); string UPRLFCT1 = M("&Einzelbahnen","&Query Single Trace"); string UPRLFCT2 = M("Einzel&netze","Query &Net"); string UPRLFCT3 = M("Ein&zelbahnzuege","Query Trace &Routes"); string UPRLFCT4 = M("&Gruppenbahnen","Query &Group Traces"); string UPRLFCT5 = M("%&Alle Netze nach Namen","%&All Nets by Name"); string UPRLFCT6 = M("Alle Netze nach &Laenge","All Nets by &Length"); string UPRLFCT7 = M("&Sichtbare Netze nach Namen", "&Visible Nets by Name"); string UPRLFCT8 = M("S&ichtbare Netze nach Laenge", "V&isible Nets by Length"); string UPRUNRLIST = M("Unroutes Liste","List Unroutes"); string UPRPFCT = M("Parallel-Modus selektieren!", "Select Parallel Mode!"); string UPRPFCT1 = M("Ae&quidistant","&Equidistant"); string UPRPFCT2 = M("&Andere Lage","&Other Layer"); string UPRPFCT3 = M("&Muster fortsetzen","&Continue Pattern"); string UPRPFCT4 = M("Breit zu &Differential Pair", "Wide to &Differential Pair"); string UPRPFCT5 = M("&Lagenpaar","&Layer Pair"); string UPRTRCSID = M("Leiterbahnseite waehlen!", "Select Trace Side!"); string UPRTRCSID1 = M("&Linke Seite","&Left Side"); string UPRTRCSID2 = M("&Rechte Seite","&Right Side"); string UPREFCT = M("Darstellungsmodus fuer Editierbahnen selektieren!", "Select Display Mode for Trace Edit!"); string UPREFCT1 = M("&Strichanzeige","&Line Display"); string UPREFCT2 = M("&Fuellanzeige","&Filled Display"); string UPREFCT3 = M("&Randanzeige","&Outline Display"); string UPREFCT4 = M("Fuellen && &Distanz","Fill && &Distance"); string UPREFCT5 = M("Fuellen && DR&C","Fill && DR&C"); string UPREFCT6 = M("&Ausweich-DRC","DRC &Snap"); string UPRVFCT = M("Viacheck Rasterdistanz selektieren!", "Select Via Check Grid Distance!"); string UPRVFCT1 = M("&Kein Viacheck","&No Via Check"); string UPRVFCT2 = M("&1","&1"); string UPRVFCT3 = M("&2","&2"); string UPRVFCT4 = M("&3","&3"); string UPRVFCT5 = M("&4","&4"); string UPRVFCT6 = M("&5","&5"); string UPRIFCT = M("Impedanz-Funktion selektieren!", "Select Trace Function!"); string UPRIFCT1 = M("&Impedanzabfrage","Impedance &Query"); string UPRIFCT2 = M("Impedanz &setzen","&Set Impedance"); string UPRMIMP = M("Gewuenschte Impedanz Mikrostrip [Ohm] ? ", "Requested Impedance Micro Strip [Ohm] ? "); string UPRSIMP = M("Gewuenschte Impedanz Streifenleitung [Ohm] ? ", "Requested Impedance Strip Line [Ohm] ? "); string UPRNET = M("Netzname ? ","Net Name ? "); string UPRSELTRC = M("Leiterbahn waehlen!","Select Trace!"); string UPRSELPTRC = M("Leiterbahn an Startsegment waehlen!", "Select Trace at Start Segment!"); string UPRSELPTRC1 = M("Erste Leiterbahn des Musters waehlen!", "Select First Pattern Trace!"); string UPRSELPTRC2 = M("Zweite Leiterbahn des Musters waehlen!", "Select Second Pattern Trace!"); string UPRSELDTRC1 = M("Erste Leiterbahn des Paares an Startsegment waehlen!", "Select First Trace of Pair at Start Segment!"); string UPRSELDTRC2 = M("Zweite Leiterbahn des Paares an Startsegment waehlen!", "Select Second Trace of Pair at Start Segment!"); string UPRENDCUT = M("Bahnenden kuerzen ? ","Cut Trace Ends ? "); string UPRLAYER1 = M("Erste Lage selektieren!", "Select First Layer!"); string UPRLAYER2 = M("Zweite Lage selektieren!", "Select Second Layer!"); string UPRSEGMWM = M("Segmentbreite [mm] ? ", "Segment Width [mm] ? "); string UPRSEGMWI = M("Segmentbreite [Inch] ? ", "Segment Width [Inch] ? "); string UPRTRCPAR = M("Parallelbahnen Aequidistant", "Parallel Traces Equidistant!"); string UPRPARTD = M("Parallelabstand : ","Parallel Spacing : "); string UPRPARTDM = M("Parallelabstand [mm] ? ", "Parallel Spacing [mm] ? "); string UPRPARTDI = M("Parallelabstand [Inch] ? ", "Parallel Spacing [Inch] ? "); string UPRTRCCNTD = M("Anzahl Parallelbahnen :", "Number of parallel traces :"); string UPRNRNDCORNER = M("Ecken beibehalten","Keep corners"); string UPRRNDCORNER = M("Ecken abrunden","Round corners"); string UPRTRCCNT = M("Anzahl Parallelbahnen ? ", "Number of parallel traces ? "); string UPRPTRCCNT = M("Anzahl neue Bahnen ? ", "Number of new traces ? "); string UPRSELSEG = M("Segment(e) waehlen!","Select Segment(s)!"); string UPRTRCLM = M("Neue Leiterbahnlaenge [mm] ? ", "New Trace Length [mm] ? "); string UPRTRCLI = M("Neue Leiterbahnlaenge [Inch] ? ", "New Trace Length [Inch] ? "); string UPRTRCLPARAM = M("Bahnlaengenanpassung","Trace Length Adjustment"); string UPRSERP45 = M("45-Grad-Schraegen","45 Degree Corners"); string UPRSERPRND = M("Kreisboegen ","Arcs"); string UPRTRCL = M("Neue Leiterbahnlaenge :","New Trace Length :"); string UPRTRCSSTEP = M("Schrittlaenge (l) :","Step Length (l) :"); string UPRTRCSCORN = M("Max. Abschraegung (r) :","Max. Chamfer (r) :"); string UPRTRCSMAX = M("Maximalausschlag (a):","Max. Elevation (a):"); string UPRTRCSMIN = M("Minimalausschlag (a):","Min. Elevation (a):"); string UPRTRCSLEFT = M("links","left"); string UPRTRCSRIGHT = M("rechts","right"); string UPRTRCSALT = M("alternierend","alternating"); string UPRDTRCNET1 = M("Bahnzug","Trace Route"); string UPRDTRCNET2 = M("Netz","Net"); string UPRDTRCPHASE = M("Anzeige Phasenlage Differential Pair", "Differential Pair Phase Integrity Display"); string UPRTRCLSOFF = M("Startoffset Bahn 1 ? ", "1st Trace Start Offset ? "); string UPRDTRCLSOFF = M("Startoffset Bahn 1 :", "1st Trace Start Offset :"); string UPRDTRCLEOFF = M("Endoffset Bahn 1 :", "1st Trace End Offset :"); string UPRDTRCPRIO = M("Prioritaet :","Priority :"); string UPRDTRCPRIO1 = M("Phase","Phase"); string UPRDTRCPRIO2 = M("Gleiche Gesamtlaenge","Same Total Length"); string UPRTRCWLEN = M("Wellenlaenge ? ","Wave Length ? "); string UPRDTRCWLEN = M("Wellenlaenge :","Wave Length :"); string UPRDGLAYER = M("Anzeigelage :","Display Layer :"); string UPRSELGLAYER = M("Anzeigelage selektieren!","Select Display Layer!"); string UPRDTRCTYP = M("Signaltyp :","Signal Type :"); string UPRDTRCTYPS = M("Sinus","Sine"); string UPRDTRCTYPT = M("Trapez","Trapezoid"); string UPRDTRCRAMP = M("Rampenanteil [%] :","Ramp Factor [%] :"); string UPRDTRCF3 = M("Anteil 3-fache Frequenz [%] :","3*Frequency Factor [%] :"); string UPRDTRCF5 = M("Anteil 5-fache Frequenz [%] :","5*Frequency Factor [%] :"); string UPRGRAFDEL = M("Alte Grafik loeschen","Delete old graphic"); string UPRPRADM = M("Polygonabstand [mm] ? ", "Polygon Distance [mm] ? "); string UPRPRADI = M("Polygonabstand [Inch] ? ", "Polygon Distance [Inch] ? "); string UPRSELDSTLAY = M("Ziellage waehlen!","Select Destination Layer!"); string UPRPTYP = M("Polygon-Typ selektieren!", "Select Polygon Type!"); string UPRPROCMODE = M("Bearbeitungsmodus waehlen!", "Select Process Mode!"); string UPRELEM1 = M("&Einzeln umwandeln","Convert &Single Elements"); string UPRELEM2 = M("Ein&zeln kopieren","Copy S&ingle Elements"); string UPRELEM3 = M("%Gruppe &umwandeln","%Convert &Group Elements"); string UPRELEM4 = M("Gruppe &kopieren","Copy G&roup Elements"); string UPRPLFCT = M("Versorgungslagen-Funktion selektieren!", "Select Power Layer Utility Function!"); string UPRPLFCT1 = M("Versorgungslagen &neu setzen","&Redefine Power Layers"); string UPRPLFCT2 = M("Versorgungslagen &loeschen","&Clear Power Layers"); string UPRPLFCT3 = M("%Versorgungsdefinitionen l&aden","%&Load Power Layer Setup"); string UPRPLFCT4 = M("Versorgungsdefinitionen &speichern","&Store Power Layer Setup"); string UPRPLFCT5 = M("Versorgungsdefinitionen l&oeschen","&Delete Power Layer Setup"); string UPRDUNITMM = M("&mm","&mm"); string UPRDUNITMIL = M("mi&l","mi&l"); string UPRDUMP = M("&Dump","&Dump"); string UPREDIT = M("Edit","Edit"); string UPRCLRHL = M("&Highlights ruecksetzen","&Reset Highlights"); string UPRLAYDISP = M("Bahnlagen einblenden","Path Layer Fade In"); string UPRAUTOFOCUS = M("Autofokus","Autofocus"); string UPRUPDATE = M("&Update","&Update"); string UPRDUMPFILE = M("!Report-Dump Ausgabedatei Name ? ", "!Report Dump Output File Name ? "); string UPRSETNAME = M("Name Versorgungsdefinition ? ","Setup Name ? "); string UPRSETFILE = M("Versorgungsdefinition Dateiname ? ", "Power Layer Setup File Name ? "); string UPRDBLSETUP = M("Eintrag/Layout '%s' in '%s' ueberschreiben?", "Overwrite Entry/Layout '%s' in '%s'?"); string UPRSETDCONF = M("Versorgungslagendefinition '%s' aus '%s' loeschen?", "Delete Power Layer Setup Entry '%s' in '%s'?"); string UPRDIALBTRC = M("Einstellungen Bahnbegradigung", "Trace Beautify Settings:"); string UPRTRCSET = M("Leiterbahnmenge :","Trace Set :"); string UPRTRCSING = M("&Einzelbahnen","&Single Traces"); string UPRTRCGRP = M("&Gruppenbahnen","&Group Traces"); string UPRTRCALL = M("&Alle Bahnen","&All Traces"); string UPRDSCANLEN = M("Scanbereich :","Scan Range :"); string UPRROUTFA = M("Routersperrflaechen beruecksichtigen", "Avoid Autorouter Keepouts"); string UPRFILLFA = M("Fuellsperrflaechen beruecksichtigen", "Avoid Copper Fill Keepouts"); string UPREDGEGRID = M("Bahnabschraegung :","Trace Chamfer :"); string UPREGRID01 = M("%1/&10 Zoll","%1/&10 Inch"); string UPREGRID02 = M("1/&20 Zoll","1/&20 Inch"); string UPREGRID03 = M("1/&40 Zoll","1/&40 Inch"); string UPREGRID04 = M("1/&60 Zoll","1/&60 Inch"); string UPREGRID05 = M("1/&80 Zoll","1/&80 Inch"); string UPREGRID06 = M("1/100 Zoll","1/100 Inch"); string UPREGRID07 = M("1/120 Zoll","1/120 Inch"); string UPREGRID08 = M("1/160 Zoll","1/160 Inch"); string UPREGRID09 = M("1/200 Zoll","1/200 Inch"); string UPREGRID10 = M("1/240 Zoll","1/240 Inch"); string UPREGRID11 = M("1/480 Zoll","1/480 Inch"); string UPREMGRID01 = M("%0.05 mm","%0.05 mm"); string UPREMGRID02 = M("0.1 mm","0.1 mm"); string UPREMGRID03 = M("0.125 mm","0.125 mm"); string UPREMGRID04 = M("0.25 mm","0.25 mm"); string UPREMGRID05 = M("0.5 mm","0.5 mm"); string UPREMGRID06 = M("0.625 mm","0.625 mm"); string UPREMGRID07 = M("1.0 mm","1.0 mm"); string UPREMGRID08 = M("1.25 mm","1.25 mm"); string UPREMGRID09 = M("2.0 mm","2.0 mm"); string UPREMGRID10 = M("2.5 mm","2.5 mm"); string UPREMGRID11 = M("10.0 mm","10.0 mm"); string UPRIGRID00 = M("0.25 * Eingaberaster","0.25 * Input Grid"); string UPRIGRID01 = M("0.5 * Eingaberaster","0.5 * Input Grid"); string UPRIGRID02 = M("Eingaberaster","Input Grid"); string UPRIGRID03 = M("2.0 * Eingaberaster","2.0 * Input Grid"); string UPRNGRID = M("&Kein Grid","&No Grid"); string UPRUGRID = M("Anderes &Grid","Select &Grid"); string REPGRIDTRC = M("Kein Standardroutingraster. Evtentuell %smm.", "No standard routing grid. Guessing %smm."); string ERRPATH = M("Fehler beim Erzeugen der neuen Leiterbahn!", "Error creating new trace!"); string ERRPLCVIA = M("Fehler beim Platzieren von Via '%s'!", "Error placing via '%s'!"); string ERRDELTRC = M("Fehler beim Loeschen der alten Leiterbahn!", "Error deleting old trace!"); string ERRPOLY = M("Zu kurze Bahnsegmente fuer diese Ausdehnung oder Bahnschleife!", "Trace segments too short for given distance or trace loop!"); string ERRARC = M("Bogenfoermige Leiterbahnen nicht unterstuetzt!", "Trace arcs not supported!"); string ERRGRIDETRC = M("Leiterbahn enthaelt zu wenig verwertbare Eckpunkte!", "Trace contains not enough usable edges!"); string ERRGRIDNTRC = M("Kein passendes Standardroutingraster gefunden!", "No matching standard routing grid found!"); string ERRARCTRC = M("Leiterbahn mit Kreisbogen wurde nicht vom Autorouter erzeugt!", "Trace contains arc - not created by Autorouter!"); string ERRNOGRP = M("Gruppe enthaelt kein Leiterbahn-Element!", "Group contains no trace element!"); string ERRINVSLAY = M("Ungueltige Signallagennummer %d in der Lagenzuordung!", "Invalid layer number %d in layer assignment!"); string ERRDBLSLAY = M("Signallage %d ist verschiedenen Lagen zugeordnet (%d/%d)!", "Signal layer %d is assigned to multiple layers (%d/%d)!"); string ERRNOLAYASS = M("Keine Paarlagenzuordung gefunden!", "No pair layer assignment found!"); string ERRNOSLAYASS = M("Keine Lagenzuordung fuer Signallage %d gefunden!", "No layer assignment for signal layer %d found!"); string ERRNORPSTK = M("Kein Ersetzungspadstack fuer Padstack '%s' definiert!", "Padstack '%s' has no replacement padstack assignment!"); string ERRNORPGRID = M("Kein Basisgrid definiert!", "No base grid assignment!"); string ERRDUPVIA = M("Ungueltige Doppelviaplatzierung!", "Invalid double via placement!"); string ERRNOGNDLAY = M("Keine Masselagen definiert!", "No ground layers defined!"); string ERRNOTGNDLAY = M("Keine Masselage gegen '%s' gefunden!", "No ground layer around '%s' found!"); string ERRNOLAYSTK = M("Lage '%s' nicht im Lagenaufbau definiert!", "Layer '%s' undefined in layer stackup!"); string ERRTRCGND = M("Leiterbahn auf Masselage '%s' nicht unterstuetzt!", "Trace on ground layer '%s' not supported!"); string ERRTRCCHG = M("Fehler bei der Leiterbahnbreitenaenderung!", "Error changing trace width!"); string ERRTRCPLAY = M("Selektierte Leiterbahnen sind auf unterschiedliche Lagen!", "Selected traces are on different layers!"); string ERRTRCPSIZ = M("Selektierte Leiterbahnen haben unterschiedliche Breiten!", "Selected traces have different width!"); string ERRTRCPCNT = M("Leiterbahnen haben unterschiedliche Anzahl Eckpunkte!", "Selected traces have different corner count!"); string ERRTRCPTYP = M("Leiterbahnen haben unterschiedliche Eckpunkttypen!", "Selected traces have different corner types!"); string ERRTRCNPAIR = M("Selektierte Leiterbahnen bilden kein Paar!", "Selected traces don't match as pair!"); string ERRTRCGLUED = M("Bahn ist verankert!","Trace is glued!"); string ERROWNLOVWR = M("Eintrag '%s' wuerde aktuelles Layout ueberschreiben!", "Entry '%s' would overwrite current layout!"); string ERRVIACNT = M("%-*s : Ueberschreitung max. Viaanzahl (%d>%d)!", "%-*s : Max. via count violation (%d>%d)!"); string ERRTRCLEN = M("%-*s : Ueberschreitung max. Bahnlaenge (%s%s>%s%s)!", "%-*s : Max. trace length violation (%s%s>%s%s)!"); string ERRTRCWIDTH = M("%-*s : Unterschreitung min. Bahnbreite (%s%s<%s%s)!", "%-*s : Min. trace width violation (%s%s<%s%s)!"); string ERRNOPAIR = M("Keine mit $pairid verknuepften Netze gefunden!", "No $pairid grouped nets found!"); string ERRPORPHANT = M("Netz '%s': Kein zu $pairid '%s' passendes Gegennetz gefunden!", "Net '%s': No net corresponding to $pairid '%s' found!"); string ERRPMULTI = M("$pairid '%s' mehr als zwei Netzen zugewiesen:", "$pairid '%s' assigned to more than two nets:"); string ERRPNET = M(" '%s'"," '%s'"); string ERRPLINPATH = M("Netz '%s': Kein linearer Pfad von %s%s,%s%s nach %s%s,%s%s gefunden!", "Net '%s': No linear path from %s%s,%s%s to %s%s,%s%s found!"); string ERRPAIRDIST = M("Netzpaar %s/%s: Paarabstand unbekannt ($pairdist)!", "Net Pair %s/%s: Pair distance unknowen ($pairdist)!"); string ERRPAIRDDIST = M("Netzpaar %s/%s: Unterschiedliche Paarabstaende $pairdist %s%s<>%s%s!", "Net Pair %s/%s: Different pair distances $pairdist %s%s<>%s%s!"); string ERRDBLREPDB = M("Bahnlaengenreport ist bereits aktiv!", "Trace Length Report already active!"); string ERRNOWIN = M("Nur in Windowsumgebungen verfuegbar!", "Windows Environment needed!"); string ERRDBINIT = M("SQL/DB-Datei '%s' kann nicht initialisiert werden!", "Error initialyzing SQL/DB file '%s'!"); string ERRNOPICK = M_ERRNOPICK(); string ERRINPVAL = M_ERRINPVAL(); // Format definitions #define FMTUNRITEM "%s (%.1fmm, %.1fmm) (%.1fmm, %.1fmm)" // Global User Language program variables #define UL_TRACEREP "tracerep" // ULP: Trace Report #define UL_TRCPUSH "trcpush" // ULP: Push Trace Segments #define UL_TRACERND "tracernd" // ULP: Trace Corner Round #define UL_TEARDROP "teardrop" // ULP: Create Teardrops #define UL_GEDVIA "gedvia" // ULP: Via Utility Functions // Globals #define COLFIN 2 // Fade in color value #define GRID25 0x01 // Edge grid quarter of input grid #define GRID50 0x02 // Edge grid half of input grid #define GRID100 0x03 // Edge grid equal input grid #define GRID200 0x04 // Edge grid doubled input grid #define MAXOPTLOOP 5 // Max. optimization loop count double TRCLBOXW = bae_inidblval(PAR_TRCLBOXW,80.0) /* Trace length report box width */; double TRCPARENDDIST = bae_inidblval(PAR_TRCPARCUT,0.002) /* Path end segment offset 2mm */; double TRCBSCANLEN = bae_inidblval(PAR_TRCBSLEN,0.100) /* Trace beautify scan length */; int TRCBSCORN = bae_iniintval(PAR_TRCBSCORN,GRID100) /* Trace beautify corner len. mode */; double TRCBSCORNLEN = bae_inidblval(PAR_TRCBSCRNL,0.0003) /* Trace beautify corner length */; int TRCBSTSET = bae_iniintval(PAR_TRCBSTSET,0) /* Trace beautify trace set mode */; int TRCBFSTYP = bae_iniintval(PAR_TRCBFSTYP,1) /* Trace beautify forb. poly types */; double TRCSERPLEN = bae_inidblval(PAR_TRCSERPLEN,0.0006) /* Trace serpentine jog length */; double TRCSERPCRN = bae_inidblval(PAR_TRCSERPCRN,0.0002) /* Trace serpentine corner width */; double TRCSERPMAX = bae_inidblval(PAR_TRCSERPMAX,0.0004) /* Trace serpentine max. elevation */; double TRCSERPMIN = bae_inidblval(PAR_TRCSERPMIN,0.0002) /* Trace serpentine min. elevation */; int TRCSERPMOD = bae_iniintval(PAR_TRCSERPMOD,0) /* Trace serpentine corner mode */; int TRCSERPLPT = bae_iniintval(PAR_TRCSERPLPT,1) /* Trace serpentine length priority */; int TRCSERPSID = bae_iniintval(PAR_TRCSERPSID,2) /* Trace serpentine side mode */; double TRCSERPNET = bae_iniintval(PAR_TRCSERPNET,0.0) /* Trace serpentine net mode */; int TRCDISPLAY = bae_iniintval(PAR_TRCDISPLAY,0x400) /* Diff. pair wave display layer */; double TRCWAVELEN = bae_inidblval(PAR_TRCWAVELEN,0.018) /* Diff. pair wave length */; int TRCWAVETYP = bae_iniintval(PAR_TRCWAVETYP,0) /* Diff. pair wave display type */; double TRCWAVERAMP = bae_inidblval(PAR_TRCWAVERAMP,10.0) /* Diff. pair wave ramp percentage */; double TRCWAVEF3 = bae_inidblval(PAR_TRCWAVEF3,0.0) /* Diff. pair wave 3rd freq. perc. */; double TRCWAVEF5 = bae_inidblval(PAR_TRCWAVEF5,0.0) /* Diff. pair wave 5th freq. perc. */; double TRCPAIRTOL = bae_inidblval(PAR_TRCPAIRTOL,10.0)/100.0 /* Trace pair distance tolerance */; double trcserpgain /* Serp. corner length gain factor */; double DEF_EPSR = bae_inidblval(PAR_EPSR,4.5); // Default epsilon r double DEF_LAYT = bae_inidblval(PAR_LAYT,0.000070); // Default layer thickness double DEF_LAYI = bae_inidblval(PAR_LAYI,0.0003); // Default layer isolation int DEF_LAYF = bae_iniintval(PAR_LAYF,0); // Default layer fill flag struct laysdes { // Layer stackup descriptor int layer /* Layer code */; double epsr /* Epsilon r */; double cu /* Copper thickness */; double iso /* Isolation */; int fill /* Layer fill flag */; } laysl[]; int layscnt /* Layer stackup count */; int laysidx1, laysidx2 /* Layer stackup indices */; #define GV_POWTRCRAD "pow_trcrad" // Power layer trace radius variable #define GV_TRCSEGWIDTH "trcseg_width" // Trace segment width variable #define GV_TRCANTLEN "trcant_length" // Trace antenna length variable #define GV_TRCPARSPC "trcpar_spc" // Parallel trace spacing variable #define GV_TRCPARCNT "trcpar_cnt" // Parallel trace count variable #define GV_TRCPATCNT "trcpat_cnt" // Pattern trace count variable #define GV_TRCRNDCRN "trc_rndcrn" // Trace corner mode variable #define GV_TRCSERPTLEN "trcserp_tlen" // Trace serpentine total length #define GV_TRCSERPLEN "trcserp_len" // Trace serpentine jog length #define GV_TRCSERPCRN "trcserp_crn" // Trace serpentine corner width #define GV_TRCSERPMAX "trcserp_max" // Trace serpentine max. elevation #define GV_TRCSERPMIN "trcserp_min" // Trace serpentine min. elevation #define GV_TRCSERPMOD "trcserp_mod" // Trace serpentine corner mode #define GV_TRCSERPLPT "trcserp_lpt" // Trace serpentine length priority #define GV_TRCSERPSID "trcserp_sid" // Trace serpentine side mode #define GV_TRCSERPNET "trcserp_net" // Trace serpentine net mode #define GV_TRCSLENOFF "trcpair_soff" // Trace pair start length offset #define GV_TRCELENOFF "trcpair_eoff" // Trace pair end length offset #define GV_TRCWAVELEN "trcpair_wlen" // Trace pair wave length #define GV_TRCWAVETYP "trcpair_typ" // Trace pair wave display type #define GV_TRCWAVERAMP "trcpair_ramp" // Trace pair ramp factor #define GV_TRCWAVEF3 "trcpair_f3" // Trace pair wave 3rd freq. factor #define GV_TRCWAVEF5 "trcpair_f5" // Trace pair wave 5th freq. factor #define GV_TRCDISPLAY "trcpair_lay" // Trace pair display layer #define SMALLVAL 0.000000001 // Small compare value #define SMALLCVAL 0.0000001 // Small coordinate compare value #define PICLABHEIGHT 4.0 // Label button height #define PICLABWIDTH 32.0 // Label button width #define TRCDISPGNAME "trcwave" // Trace pair wave display group name #define TRCPAIRGNAME "trcpairgap" // Trace pair gap group name #define UNITMM "mm" // mm units designator #define UNITIN "Inch" // Inch units designator string UNITDES = bae_getcoorddisp() ? UNITIN : UNITMM /* Length unit designator */; #define SMALLANG 0.00001 // Small angle compare value #define ODDANG 0.001 // Odd angle compare value double PI = cvtangle(180.0,1,2) /* (Constant) PI value */; int curcnt /* Current unroutes counter */; double curalen /* Current unroutes length */; double curhlen /* Current unroutes h length */; double curvlen /* Current unroutes v length */; struct unritem { // Unroute item descriptor double x1, y1 /* Unroute 1st coordinate */; double x2, y2 /* Unroute 2nd coordinate */; int netnum /* Unroute net number */; string netname /* Unroute net name */; } unrl[] /* Unroute list */; int unrn = 0 /* Unroute count */; double zoomlx,zoomly /* Zoom lower boundaries */; double zoomux,zoomuy /* Zoom upper boundaries */; int curnetnum /* Current net tree number */; string curnetname /* Current net name */; double px,py /* Pick coordinates */; int segidx /* Pick segment index */; double pickmin /* Pick min. match value */; struct segpairdes { // Segment pair data descriptor double ls, le /* Segment parallel lambda range */; int elidx /* Segment pair element index */; int sidx /* Segment pair segment index */; }; struct offdes { // Segment offset list descriptor double off /* Segment offset */; double step /* Segment side step */; int side /* Segment side */; int scrn /* Segment start corner flag */; int ecrn /* Segment end corner flag */; }; struct pointdes { // Point segment descriptor double x /* Point x coordinate */; double y /* Point y coordinate */; struct offdes ol[] /* Point segment offset list */; int on /* Point segment offset count */; struct segpairdes spl[] /* Point segment pair list */; int spn /* Point segment pair count */; int typ /* Point type */; } pointl[] /* Point list */; int pointn /* Point count */; double tracerad = 0.0 /* Trace boundary distance */; int pointfound /* Point found flag */; int pcnt /* Path point count */; struct pelemdes { // Path element descriptor index L_FIGURE fig /* Path figure list element */; index L_LEVEL plev /* Path level element */; struct pointdes pl[] /* Path point list */; int pn /* Path point count */; int offflag /* Path segment offset(s) flag */; int side /* Path side flag */; int vmidx /* Path via macro index */; double wx, wy /* Path via angle point */; double xs, ys /* Path start point */; double xe, ye /* Path end point */; } pel[] /* Current path element list */; int pen /* Current path element count */; struct pelemdes p1el[] /* 1st path element list */; int p1en /* 1st path element count */; struct pelemdes p2el[] /* 2nd path element list */; int p2en /* 2nd path element count */; struct vmacdes { // Via macro data descriptor index L_MACRO mac /* Via macro index */; string stk1 /* Via 1st replacement padstack */; string stk2 /* Via 2nd replacement padstack */; } vmacl[] /* Via macro data list */; int vmacn = 0 /* Via macro data count */; struct drilldes { // Drill descriptor double x,y /* Drill coordinates */; double rad /* Drill radius */; } drilll[] /* Drill list */; int drilln = 0 /* Drill elements count */; double drlmaxrad /* Maximum drill radius */; int play /* Path layer */; double pwidth /* Path width */; double prad /* Path radius */; index L_LEVEL plevel /* Path level */; index L_CPART cpart /* Connection part index */; int partside = lay_plantoplay() /* Part side layer */; int ilaylb /* Inner layer lower boundary */; int ilayub /* Inner layer upper boundary */; int snfound /* Path start neighbour found flag */; int enfound /* Path end neighbour found flag */; int fll[] /* Figure list levels */; int fln = 0 /* Figure list level count */; double pxs, pys /* Path start coordinates */; double pxe, pye /* Path start coordinates */; int viapowcon /* Via power connection flag */; int curidx /* Current power layer index */; string setl[] /* Batch name list */; int setn /* Batch count */; struct nettrcdat { // Net trace data index L_CNET net /* Net index */; double minrad /* Min. arc radius */; double maxrad /* Max. arc radius */; double minwidth /* Min. width */; double maxwidth /* Max. width */; double trclen /* Trace length */; double maxtrclen /* Max. allowed trace length */; double mintrcwidth /* Min. requestred trace width */; int maxviacnt /* Max. allowed via count */; int trccnt /* Trace count */; int viacnt /* Via count */; int disabled /* Net disabled flag */; } netndatl[] /* Net number indexed data list */; struct ptdes { // Point coordinate descriptor double x /* Point x coordinate */; double y /* Point y coordinate */; int typ /* Point type */; }; struct netptrc { // Net pair trace data struct ptdes pl[] /* Path point list */; int pn /* Path point count */; int ps /* Path point scan start index */; double width /* Path width */; int layer /* Path layer */; double xs, ys /* Path start point */; double xe, ye /* Path end point */; }; struct netpairdat { // Net pair data index L_CNET net /* Net index */; struct netptrc trcl[] /* Net trace list */; int trcn /* Net trace count */; double parlen /* Net parallel trace length */; double trclen /* Net total trace length */; int viacnt /* Net via count */; string pairid /* Net pair ID */; double pairdist /* Net pair distance */; int pairidx /* Net pair index */; } netpdatl[] /* Net number indexed data list */; int netidatl[] /* Net sort index list */; int netidatn /* Net count */; struct ptdes e1l[] /* 1st error point list */; int e1n /* 1st error point count */; double e1width /* 1st error trace width */; struct ptdes e2l[] /* 2nd error point list */; int e2n /* 2nd error point count */; double e2width /* 2nd error trace width */; double e2xs,e2ys /* 2nd error trace start point */; double trcminrad /* Trace min. arc radius */; double trcmaxrad /* Trace max. arc radius */; double trcminwidth /* Trace min. width */; double trcmaxwidth /* Trace max. width */; double trcslen /* Trace scan length */; int curlayer /* Current layer */; int trcscnt /* Trace scan count */; int viascnt /* Via scan count */; int ddbclass = bae_planddbclass() /* Layout plan DDB class */; double wsnx = bae_planwsnx() /* Workspace x origin */; double wsny = bae_planwsny() /* Workspace y origin */; // SQL command definitions #define P_SELECT "select idx,netname from powlaydef where name=%s;" #define P_CREATE1 "create table powlaydef (idx integer,name string," #define P_CREATE2 "netname string);" #define P_CREATE P_CREATE1+P_CREATE2 #define P_HELP "help powlaydef;" #define P_INSERT "insert into powlaydef values(%d,%s,%s);" #define P_DELETE "delete from powlaydef where name=%s;" #define PN_SELECT "select name from powlaydef where idx=0;" string sqlcommand /* SQL command string */; // Parameter definitions #define GV_NETCOUNT "tr_netcnt" // Trace report net count #define GV_NETNAME "tr_netname%d" // Trace report net name #define GV_LASTNET "tr_lastnet" // Trace report last net name #define GV_SORTMIDX "tr_sortmidx" // Trace report sort mode index #define GV_LAYDISP "tr_laydisp" // Trace report layer display index #define GV_REPLIDX "tr_replidx" // Trace report list index #define GV_FOCUSFIELD "tr_focusidx" // Autofocus flag field index // Main program void main() { string h_dis = (bae_swconfig(0)==BAE_HighEnd) ? "" : "," /* HighEnd functions disable */; // Abort if invalid plan class if (varget(VAR_PDBOXIDX,0) && ddbclass!=DDBCLLAY && ddbclass!=DDBCLLPRT) error_class(); // Check if call inside function check_fctactive(); // Select trace/routing function type bae_defmenusel(-1); bae_promptdialog(UPRFCT); switch (bae_askmenu(21,UPRFCT1,UPRFCT2,UPRFCT3,UPRFCT4,UPRFCT5, UPRFCT6,UPRFCT7,UPRFCT8,UPRFCT9,UPRFCT10,UPRFCT11,UPRFCT12,UPRFCT13, UPRFCT14,UPRFCT15,h_dis+UPRFCT16,UPRFCT17,UPRFCT18,UPRFCT19,UPRFCT20, UPRABORT)) { // Trace length case 0 : // Select trace function bae_defmenusel(-1); bae_promptdialog(UPRTFCT); switch (bae_askmenu(7,UPRTFCT1,UPRTFCT2,UPRTFCT3,UPRTFCT4, UPRTFCT5,(ddbclass==DDBCLLAY ? "" : ",")+UPRTFCT6,UPRABORT)) { case 0 : // Select report function type bae_promptdialog(UPRLFCT); switch (bae_askmenu(9,UPRLFCT1,UPRLFCT2,UPRLFCT3, UPRLFCT4,UPRLFCT5,UPRLFCT6,UPRLFCT7,UPRLFCT8, UPRABORT)) { // Single trace case 0 : tracelen(0); break; // Single net case 1 : tracelen(1); break; // Single trace route case 2 : tracelen(2); break; // Group traces case 3 : tracelen(3); break; // All nets by name case 4 : tracelist(0,0); break; // All nets by length case 5 : tracelist(0,1); break; // Visible nets by name case 6 : tracelist(1,0); break; // Visible nets by length case 7 : tracelist(1,1); break; // Abort on default default : error_abort(); } break; case 1 : traceadjust(); break; case 2 : traceserpentine(); break; case 3 : pairadjust(); break; case 4 : pairdisp(); break; case 5 : paircheck(); break; // Abort on default default : error_abort(); } break; // Trace report case 1 : // Run the trace report program runulprogexit(UL_TRACEREP); // Unroutes report case 2 : unroutesrep(); break; // Trace segments push case 3 : // Run the trace push program runulprogexit(UL_TRCPUSH); // Trace corner round case 4 : // Run the trace corner round program runulprogexit(UL_TRACERND); // Trace end cut case 5 : tracecut(); break; // Trace split case 6 : tracesplit(); break; // Parallel traces case 7 : trcparal(); break; // Copy traces to power layer case 8 : trcpowlay(); break; // Segment width case 9 : segwidth(); break; // Create teardrops case 10 : // Run the create teardrops program runulprogexit(UL_TEARDROP); // Via functions case 11 : // Run the via utility functions program runulprogexit(UL_GEDVIA); // Power layer management case 12 : powlayer(); break; // Trace edit display mode case 13 : traceeditmode(); break; // Via check grid range case 14 : viachkrange(); break; // Trace impedance functions case 15 : if (h_dis=="") { // Query layer stackup getlaystackup(1); // Ask user for impedance function bae_defmenusel(-1); bae_promptdialog(UPRIFCT); switch (bae_askmenu(3,UPRIFCT1,UPRIFCT2,UPRABORT)) { // Query impedance case 0 : trcimpedance(0); break; // Set impedance case 1 : trcimpedance(1); break; default : error_abort(); } break; } // Delete short circuit traces case 16 : delshort(); break; // Antenna check case 17 : antenna(); break; // Grid query case 18 : gridquery(); break; // Trace beautify case 19 : tracebeautify(); break; // Abort on default default : } } /*________________________________________________________________*/ // Trace length routines void tracelen(int netmode) /* // Trace length query // Parameter : // int netmode : Net query mode */ { index L_FIGURE fig /* Figure list index */; index L_FIGURE lfig /* Last figure list index */; index L_CNET cnet /* Connection net index */; double trclen /* Trace length */; int firstflag = 1 /* First pick flag */; int trccnt = 0 /* Trace count */; int viacnt = 0 /* Via count */; int treenum = (-1) /* Trace tree number */; int newtreenum /* Trace tree number */; string msgbuf /* Message buffer string */; double minrad,maxrad /* Radius min./max. values */; // Abort if invalid plan class if (netmode==1 && ddbclass!=DDBCLLAY) error_class(); if (netmode==0) bae_callmenu(MNU_GEDGRPRESE); if (netmode && bae_swconfig(0)==BAE_HighEnd) // Query layer stackup getlaystackup(0); // Loop while trace picked bae_promptdialog(UPRSELTRC); while (netmode==3 || (netmode!=2 && ged_pickelem(fig,L_FIGPATH)==0) || (netmode==2 && pickgrppath()==0)) { if (netmode==0) { if (firstflag) firstflag=0; else if (lfig!=fig) ged_elemgrpchg(lfig,0); ged_elemgrpchg(fig,1); lfig=fig; } // Check if part loaded if (ddbclass==DDBCLLPRT) { // Get path length bae_prtdialog(REPSCANTRC); trclen= netmode ? treepathlen(netmode, fig.TREE,trccnt,viacnt,minrad,maxrad,0.0,0.0) : pathlen(fig.LINE,minrad,maxrad) ; // Build the trace length message if (minrad==0.0) { switch (netmode) { case 2 : sprintf(msgbuf,REPPTRCRLEN, trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 3 : sprintf(msgbuf,REPGTRCLEN, trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 0 : default : sprintf(msgbuf,REPSPTRCLEN, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM); } } else { switch (netmode) { case 2 : sprintf(msgbuf,REPPTRCRLEN+REPATRCLEN, trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(minrad),4), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(maxrad),4), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 3 : sprintf(msgbuf,REPGTRCLEN+REPATRCLEN, trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(minrad),4), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(maxrad),4), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 0 : default : sprintf(msgbuf,REPSPTRCLEN+REPATRCLEN, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(minrad),4), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(maxrad),4), bae_getcoorddisp() ? UNITIN : UNITMM); } } } else { // Layout currently loaded switch (netmode) { // Single tree pick case 1 : newtreenum=fig.TREE; // No update if same than previous tree sel. if (newtreenum>=0 && newtreenum==treenum) { // Display the trace length message bae_prtdialog(msgbuf); continue; } // De-highlight previously selected tree if (treenum>=0) ged_highlnet(treenum,0); // Get the new tree number and highl. the tree if (newtreenum>=0) ged_highlnet(newtreenum,1); break; // Traces route case 2 : // Group traces case 3 : newtreenum=(-1); forall (fig where fig.GROUP) { newtreenum=fig.TREE; break; } break; // Single path pick case 0 : default : newtreenum=fig.TREE; } treenum=newtreenum; // Get path length bae_prtdialog(REPSCANTRC); trclen= netmode ? treepathlen( netmode,treenum,trccnt,viacnt,minrad,maxrad,0.0,0.0) : pathlen(fig.LINE,minrad,maxrad) ; // Build the trace length message if (minrad==0.0) { switch (netmode) { case 1 : sprintf(msgbuf,REPTRCLEN, lay_gettreeidx(treenum,cnet) ? itoa(treenum) : cnet.NAME, trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 2 : sprintf(msgbuf,REPTRCRLEN, lay_gettreeidx(treenum,cnet) ? itoa(treenum) : cnet.NAME, trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 3 : sprintf(msgbuf,REPGTRCLEN,trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 0 : default : sprintf(msgbuf,REPSTRCLEN, lay_gettreeidx(treenum,cnet) ? itoa(treenum) : cnet.NAME, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM); } } else { switch (netmode) { case 1 : sprintf(msgbuf,REPTRCLEN+REPATRCLEN, lay_gettreeidx(treenum,cnet) ? itoa(treenum) : cnet.NAME, trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(minrad),4), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(maxrad),4), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 2 : sprintf(msgbuf,REPTRCRLEN+REPATRCLEN, lay_gettreeidx(treenum,cnet) ? itoa(treenum) : cnet.NAME, trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(minrad),4), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(maxrad),4), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 3 : sprintf(msgbuf,REPGTRCLEN+REPATRCLEN, trccnt,viacnt, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(minrad),4), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(maxrad),4), bae_getcoorddisp() ? UNITIN : UNITMM); break; case 0 : default : sprintf(msgbuf,REPSTRCLEN+REPATRCLEN, lay_gettreeidx(treenum,cnet) ? itoa(treenum) : cnet.NAME, bae_numstring(baecvtl(trclen),3), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(minrad),4), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(maxrad),4), bae_getcoorddisp() ? UNITIN : UNITMM); } } } // Display the trace length message bae_prtdialog(msgbuf); if (netmode==3) return; } // De-highlight previously selected tree if (netmode==1 && treenum>=0) { ged_highlnet(treenum,0); } else if (netmode==2) { bae_callmenu(MNU_GEDGRPRESE); bae_prtdialog(""); } else if (netmode==0 && !firstflag) { ged_elemgrpchg(lfig,0); } } void tracelist(int netmode,int lensort) /* // Produce an overall trace length report // Parameter : // int netmode : Net query mode // int lensort : Length sort mode */ { index L_FIGURE fig /* Figure list index */; index L_CNET net /* Net index */; index L_CPIN pin /* Connection pin index */; index L_ATTRIBUTE attr /* Attribute index */; string netname = "" /* Net name string */; string lastnet = "" /* Last net name string */; string msgbuf /* Message buffer string */; string units /* Unit string */; int maxnamelen = 0 /* Max. net name length */; int netnum /* Net number */; double maxtrclen /* Max. allowed trace length */; double mintrcwidth /* Min. requested trace width */; int maxviacnt /* Max. allowed via count */; double cx /* Dialog box current x coordinate */; double cy = DIAL_TOPMARG /* Dialog box current y coordinate */; double dialwidth /* Dialog box width */; double dialheight /* Dialog box height */; double baseheight /* Dialog box base height */; int autofocus = 1 /* Autofocus flag */; int boxidx /* Dialog box index */; int actcode /* Action code */; int reason /* Callback reason */; int intval /* Dialog box item integer value */; string name /* Dialog box item name */; string varname /* Variable name */; int lbidx /* Report list field index */; int smidx /* Sort mode item field index */; int ldidx /* Layer display item field index */; int focidx /* Autofocus field index */; int lbsel /* List field selection index */; int laydisp = bae_iniintval(PAR_TRCLBOXLD,0) /* Layer display flag */; string fn /* Output file name */; int fh /* Output file name handle */; int i /* Loop control variable */; // Check if action call if (varget(VAR_PDBOXIDX,boxidx)==0 && varget(VAR_PDBOXACT,actcode)==0 && varget(VAR_PDBOXREAS,reason)==0 && varget(VAR_PDBOXIVAL,intval)==0 && varget(VAR_PDBOXNAME,name)==0) { // Remove callback parameters vardelete(VAR_PDBOXIDX); vardelete(VAR_PDBOXACT); vardelete(VAR_PDBOXREAS); vardelete(VAR_PDBOXIVAL); vardelete(VAR_PDBOXNAME); varget(GV_NETCOUNT,netidatn); varget(GV_SORTMIDX,smidx); varget(GV_LAYDISP,ldidx); varget(GV_REPLIDX,lbidx); varget(GV_FOCUSFIELD,focidx); if (varget(GV_LASTNET,lastnet)) lastnet=""; bae_dialsetcurrent(boxidx); bae_dialgetdata(smidx,lensort,0.0,""); bae_dialgetdata(ldidx,laydisp,0.0,""); bae_dialgetdata(focidx,autofocus,0.0,""); bae_dialsetcurrent(0); netmode= lensort>=2 ? 1 : 0 ; lensort&=0x01; // Get the selected net name if (actcode==7) { netname=lastnet; } else if (intval>=0 && intval3)) { if (lastnet!="" && lay_findcontree(lastnet,net)==0) // Dehighlight last net ged_highlnet(net.NUMBER,0); exit(0); } } if (varget(GV_NETCOUNT,netidatn)==0) error(ERRDBLREPDB); // Abort if invalid plan class if (ddbclass!=DDBCLLAY) error_class(); // Check if dialog box support if (bae_dialclr()) error(ERRNOWIN); // Print report in progress message bae_msgprogressrep(REPTRCLREP,PB_TYPPROC|PB_ABORT,0,40); // Init. the net data list netidatn=0; forall (net) { netnum=net.NUMBER; // Test on program abort request checkabort(); // Check if invisible net skip if (netmode && !net.VIS) { netndatl[netnum].disabled=1; continue; } netidatl[netidatn]=netnum; netidatn++; // Update max. name length if (strlen(net.NAME)>maxnamelen) maxnamelen=strlen(net.NAME); maxtrclen=mintrcwidth=(-1.0); maxviacnt=(-1); forall (attr of net) switch (attr.NAME) { case "$maxviacnt" : if (attr.VALUE!="") maxviacnt=atoi(attr.VALUE); break; case "$maxnetlen" : if (attr.VALUE!="") maxtrclen=atof_len(attr.VALUE); break; } forall (pin of net) if (pin.RWIDTH!=0.0 && (mintrcwidth<0.0 || pin.RWIDTH=0 && netndatl[netnum].viacnt>netndatl[netnum].maxviacnt) { sprintf(msgbuf,ERRVIACNT,maxnamelen,netname, netndatl[netnum].viacnt,netndatl[netnum].maxviacnt); // Store list entry bae_dialaddcontrol(PA_LBE,0,0,i,0.0,0.0,0.0,"",0, 0.0,0.0,0.0,msgbuf); } // Check trace length if (netndatl[netnum].maxtrclen>=0.0 && netndatl[netnum].trclen>netndatl[netnum].maxtrclen) { sprintf(msgbuf,ERRTRCLEN,maxnamelen,netname, bae_numstring(baecvtl(netndatl[netnum].trclen),3), units,bae_numstring( baecvtl(netndatl[netnum].maxtrclen),3),units); // Store list entry bae_dialaddcontrol(PA_LBE,0,0,i,0.0,0.0,0.0,"",0, 0.0,0.0,0.0,msgbuf); } // Check trace width if (netndatl[netnum].trccnt>0 && netndatl[netnum].mintrcwidth>0.0 && netndatl[netnum].minwidth=0 && !netndatl[viatree].disabled) netndatl[viatree].viacnt++; // Stop scan return(0); // Pad case DDBCLLPAD : // Stop scan return(0); } // Continue scan return(1); } static int ntlpathfunc( index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Net trace length scan path function // Return value : // zero if done or (-1) on error // Parameters : // index L_LINE path : Path index // int layer : Path transformed layer code // int pathinws : Path in workspace flag // index L_LEVEL level : Path level */ { double pminrad /* Path min. arc radius */; double pmaxrad /* Path max. arc radius */; int trctree /* Trace tree number */; // Get the trace tree number from level if ((trctree=lay_getlevtreenum(level))<0 || netndatl[trctree].disabled) // Level tree not of interest return(0); // Update the trace length netndatl[trctree].trclen+=pathlen(path,pminrad,pmaxrad); // Update path width extrema if (netndatl[trctree].trccnt==0) { netndatl[trctree].minwidth=netndatl[trctree].maxwidth= path.WIDTH; } else { if (netndatl[trctree].minwidth>path.WIDTH) netndatl[trctree].minwidth=path.WIDTH; if (netndatl[trctree].maxwidthnetndatl[trctree].maxrad) netndatl[trctree].maxrad=pmaxrad; // Increment the trace count netndatl[trctree].trccnt++; // Return without errors return(0); } static int ntlsmacfunc(index L_MACRO macro,index L_POOL pool, int macinws,string refname,index L_LEVEL level) /* // Net tree length stackup scan macro scan function // Return value : // (-1) on scan error, 0 on scan stop, 1 on scan continue // Parameters : // index L_MACRO macro : Macro index // index L_POOL pool : Macro pool element // int macinws : Macro in workspace flag // string refname : Macro reference name // index L_LEVEL level : Macro level */ { double a /* Via macro rotation angle */; int m /* Via macro mirror flag */; int l /* Via macro layer number */; int viatree /* Via tree number */; int i /* Loop control variable */; // Check class switch (macro.CLASS) { // Part case DDBCLLPRT : break; // Padstack case DDBCLLSTK : // Check if pin if (refname!="") break; // Test on program abort request checkabort(); // Get the via tree number from level if ((viatree=lay_getlevtreenum(level))<0) // Invalid level tree viatree=(-1); if (viatree>=0 && !netndatl[viatree].disabled) { // Get via macro coordinates lay_maccoords(px,py,a,m,l); laysidx1=layscnt; laysidx2=(-1); curnetnum=viatree; if (lay_scanall(0.0,0.0,0.0,0,1, NULL,NULL,tlspathfunc,NULL,NULL,NULL,NULL)) error_scan(); if (laysidx1!=layscnt && laysidx2!=(-1) && laysidx1!=laysidx2) { netndatl[viatree].trclen+=laysl[laysidx1].iso; for (i=laysidx1+1;iidx2 // Parameters : // int idx1 : First compare index // int idx2 : Second compare index */ { // Check if same length if (netndatl[idx1].trclen==netndatl[idx2].trclen) return(strcmp(netndatl[idx1].net.NAME,netndatl[idx2].net.NAME)); // Return compare result return(netndatl[idx1].trclen>netndatl[idx2].trclen ? (-1) : 1); } void traceadjust() /* // Trace antenna length adjust */ { index L_FIGURE fig /* Figure list index */; index L_FIGURE nfig /* New figure list index */; index L_LINE line /* Path index */; index L_POINT p /* Point index */; double trclen /* Trace length */; double newtrclen /* New trace length */; double sx, sy /* Segment vector */; double slen /* Segment length */; int fidx, lidx /* First and last point index */; STRINGS rl /* Rule list */; int cflag = 0 /* Change flag */; int i /* Loop control variable */; // Get new length if (varget(GV_TRCANTLEN,newtrclen)) newtrclen=0.0; if (askdist(newtrclen,lay_defusrunit()?UPRTRCLI:UPRTRCLM,0) || newtrclen==0.0) // Invalid input value error(ERRINPVAL); // Preserve length data for next call varset(GV_TRCANTLEN,newtrclen); // Loop while trace picked bae_prtdialog(UPRSELTRC); while (ged_pickelem(fig,L_FIGPATH)==0) { if (fig.FIXED&2) error(ERRTRCGLUED); // Get the current mouse position bae_wsmouse(px,py,0); // Get the trace length trclen=pathlen(fig.LINE,0.0,0.0) ; // Loop for all path points line=fig.LINE; pointn=0; forall (p of line) { // Store current coordinates pointl[pointn].x=p.X; pointl[pointn].y=p.Y; pointl[pointn].typ=p.TYP; pointl[pointn].on=0; pointl[pointn].spn=0; pointn++; } // Set the path point index range fidx=0; lidx=pointn-1; // Check which path end to adjust if ((fabs(pointl[fidx].x-px)+fabs(pointl[fidx].y-py))< (fabs(pointl[lidx].x-px)+fabs(pointl[lidx].y-py))) { // Scan the path segments from path start for (;fidx0.0 && (trclen-slen)fidx;lidx--) { // Check if straight segment if (pointl[lidx].typ!=0 || pointl[lidx-1].typ!=0) error(ERRARC); // Get the segment start vector and length sx=pointl[lidx].x-pointl[lidx-1].x; sy=pointl[lidx].y-pointl[lidx-1].y; slen=sqrt(sx*sx+sy*sy); // Check if adjust with this segment possible if (slen>0.0 && (trclen-slen)=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); // Delete old path if (ged_delelem(fig)) error(ERRDELTRC); // Redraw the screen bae_callmenu(MNU_BAEREDISPL); } } void traceserpentine() /* // Trace serpentine length adjust */ { index L_FIGURE fig /* Figure list index */; index L_LINE path /* Trace index */; string msgbuf /* Message buffer string */; double trcwidth /* Trace width */; int lay /* Trace layer */; double x,y /* Current coordinates */; int t /* Current point type */; double lx,ly /* Last coordinates */; int lt /* Last point type */; double newlen /* New length */; double sx,sy /* Segment normalized vector */; double seglen /* Segment length */; double curlen /* Current length */; double serprng /* Serpentine elevation range */; double serpoff /* Serpentine creation offset */; double serpend /* Serpentine scan end offset */; double serpmin /* Serpentine current min. elevation */; double serpgain /* Serpentine length gain */; double serprad /* Serpentine used radius/length */; int serpdone /* Serpentine done flag */; double maxgain /* Serpentine gain at max. elevation */; double distgap /* Distance gap */; double labwidth /* Picture label width */; double labheight /* Picture label height */; double pcol = 18.0 /* Parameter column */; double cy /* Dialog box current y coordinate */; int res /* Dialog box result */; int varidx /* INI variable index */; int repflag /* Dialog box repeat flag */; int nlenidx /* New length parameter index */; int nmidx /* Net mode param. index */; int slenidx /* Serpentine length parameter index */; int scrnidx /* Serpentine corner parameter index */; int smaxidx /* Serpentine max. el. param. index */; int sminidx /* Serpentine min. el. param. index */; int smodidx /* Serpentine corn.mode param. index */; int ssididx /* Serpentine side mode param. index */; int cunits /* Coordinate display units */; int cnt = 0 /* Element count */; int lastcorr /* Last segment shifted */; double lastshift /* Last segment shift radius */; double off /* Segment scan offset */; double stepval /* Search step value */; double l /* Current length step value */; int firststep /* First search step flag */; int side /* Current serpentine side */; int stoggle /* Side toggle */; int scrn /* Serpentine start corner flag */; int ecrn /* Serpentine end corner flag */; int pidx /* Path element index */; int offn /* Segment offset count */; int lp /* Last point index */; int scnt /* Segment step count */; int lstep /* Last step index */; double lrad /* Last used radius */; double cang /* Current segment direction angle */; double lang /* Last segment direction angle */; double dang /* Direction difference angle */; double dist /* Trace to trace distance */; int cflag = 0 /* Change flag */; int i /* Loop control variable */; // Get default parameters if (varget(GV_TRCSERPTLEN,newlen)) newlen=0.0; if (varget(GV_TRCSERPLEN,curlen)==0) TRCSERPLEN=curlen; if (varget(GV_TRCSERPNET,i)==0) TRCSERPNET=i; if (varget(GV_TRCSERPCRN,curlen)==0) TRCSERPCRN=curlen; if (varget(GV_TRCSERPMAX,curlen)==0) TRCSERPMAX=curlen; if (varget(GV_TRCSERPMIN,curlen)==0) TRCSERPMIN=curlen; if (varget(GV_TRCSERPMOD,i)==0) TRCSERPMOD=i; if (varget(GV_TRCSERPSID,i)==0) TRCSERPSID=i; lay_getplanchkparam(dist,0.0,0.0,0,"",-1,0); // Check for dialog support if (bae_dialclr()==0) { // Init. the y coordinate cy=DIAL_TOPMARG; // Set the default picture button bitmap size labwidth=PICLABWIDTH; labheight=PICLABHEIGHT; // Create the picture button bitmap if (bmp_setsize( -1.0,4.0,14.0,-3.5,labwidth,labheight,0.0,0.0) || bae_dialbmpalloc(labwidth,labheight,2,0,0)!=2) error_abort(); // Draw the first picture label bitmap bae_popsetarea(2); // Display edged trace graphic btp_drawwideline(2,DM_REPLACE,1,0.5,0.0,1.5,0.0,0.2); btp_drawwideline(2,DM_REPLACE,1,1.5,0.0,2.5,1.0,0.2); btp_drawwideline(2,DM_REPLACE,1,2.5,1.0,2.5,2.0,0.2); btp_drawwideline(2,DM_REPLACE,1,2.5,2.0,3.5,3.0,0.2); btp_drawwideline(2,DM_REPLACE,1,3.5,3.0,5.5,3.0,0.2); btp_drawwideline(2,DM_REPLACE,1,5.5,3.0,6.5,2.0,0.2); btp_drawwideline(2,DM_REPLACE,1,6.5,2.0,6.5,-2.0,0.2); btp_drawwideline(2,DM_REPLACE,1,6.5,-2.0,7.5,-3.0,0.2); btp_drawwideline(2,DM_REPLACE,1,7.5,-3.0,9.5,-3.0,0.2); btp_drawwideline(2,DM_REPLACE,1,9.5,-3.0,10.5,-2.0,0.2); btp_drawwideline(2,DM_REPLACE,1,10.5,-2.0,10.5,-1.0,0.2); btp_drawwideline(2,DM_REPLACE,1,10.5,-1.0,11.5,0.0,0.2); btp_drawwideline(2,DM_REPLACE,1,11.5,0.0,13.5,0.0,0.2); // Display legend drawlegend(); bae_popsetarea(0); // Store the bitmap label bae_dialadvcontrol(PA_BMLAB,0,0,2,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol,cy,labwidth,labheight,""); // Create the picture button bitmap labwidth=PICLABWIDTH; labheight=PICLABHEIGHT; // Create the picture button bitmap if (bmp_setsize( -1.0,4.0,14.0,-3.5,labwidth,labheight,0.0,0.0) || bae_dialbmpalloc(labwidth,labheight,3,0,0)!=3) error_abort(); // Draw the second picture label bitmap bae_popsetarea(3); // Display round trace graphic btp_drawwideline(2,DM_REPLACE,1,0.5,0.0,1.5,0.0,0.2); btp_drawwidearc(2,DM_REPLACE,1,1.5,0.0,1.5,1.0,2.5,1.0,1,0.2); btp_drawwideline(2,DM_REPLACE,1,2.5,1.0,2.5,2.0,0.2); btp_drawwidearc(2,DM_REPLACE,1,2.5,2.0,3.5,2.0,3.5,3.0,2,0.2); btp_drawwideline(2,DM_REPLACE,1,3.5,3.0,5.5,3.0,0.2); btp_drawwidearc(2,DM_REPLACE,1,5.5,3.0,5.5,2.0,6.5,2.0,2,0.2); btp_drawwideline(2,DM_REPLACE,1,6.5,2.0,6.5,-2.0,0.2); btp_drawwidearc(2,DM_REPLACE,1, 6.5,-2.0,7.5,-2.0,7.5,-3.0,1,0.2); btp_drawwideline(2,DM_REPLACE,1,7.5,-3.0,9.5,-3.0,0.2); btp_drawwidearc(2,DM_REPLACE,1, 9.5,-3.0,9.5,-2.0,10.5,-2.0,1,0.2); btp_drawwideline(2,DM_REPLACE,1,10.5,-2.0,10.5,-1.0,0.2); btp_drawwidearc(2,DM_REPLACE,1, 10.5,-1.0,11.5,-1.0,11.5,0.0,2,0.2); btp_drawwideline(2,DM_REPLACE,1,11.5,0.0,13.5,0.0,0.2); // Display legend drawlegend(); bae_popsetarea(0); // Store the bitmap label bae_dialadvcontrol(PA_BMLAB,0,0,3,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol,cy+4.0,labwidth,labheight,""); // Store corner mode controls smodidx=bae_dialaddcontrol(PA_RBF,0,0,TRCSERPMOD,0.0,0.0, 0.0,"",0,DIAL_LEFTMARG,cy+1.5,0.0,UPRSERP45); cy+=PICLABHEIGHT; // Store side mode controls bae_dialaddcontrol(PA_RBN,1,0,0,0.0,0.0,0.0, "",0,DIAL_LEFTMARG,cy+1.5,0.0,UPRSERPRND); cy+=PICLABHEIGHT; ssididx=bae_dialaddcontrol(PA_RBF,0,0,TRCSERPSID,0.0,0.0, 0.0,"",0,DIAL_LEFTMARG+pcol,cy,0.0,UPRTRCSLEFT); bae_dialaddcontrol(PA_RBN,1,0,0,0.0,0.0,0.0, "",0,DIAL_LEFTMARG+pcol+10.0,cy,0.0,UPRTRCSRIGHT); bae_dialaddcontrol(PA_RBN,2,0,0,0.0,0.0,0.0, "",0,DIAL_LEFTMARG+pcol+20.0,cy,0.0,UPRTRCSALT); cy+=DIAL_CTRVSTEP; // Store serpentine length controls dial_label(0.0,cy,UPRTRCL); nlenidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,newlen,"",0,DIAL_LEFTMARG+pcol,cy,9.0,""); // Store net mode controls nmidx=bae_dialaddcontrol(PA_RBF,0,0,TRCSERPNET,0.0,0.0,0.0, "",0,DIAL_LEFTMARG+pcol+10.0,cy,0.0,UPRDTRCNET1); bae_dialaddcontrol(PA_RBN,1,0,0,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol+20.0,cy,0.0,UPRDTRCNET2); cy+=DIAL_CTRVSTEP; dial_label(0.0,cy,UPRTRCSSTEP); slenidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,TRCSERPLEN,"",0,DIAL_LEFTMARG+pcol,cy,9.0,""); cy+=DIAL_CTRVSTEP; // Store corner mode controls dial_label(0.0,cy,UPRTRCSCORN); scrnidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,TRCSERPCRN,"",0,DIAL_LEFTMARG+pcol,cy,9.0,""); cy+=DIAL_CTRVSTEP; dial_label(0.0,cy,UPRTRCSMAX); smaxidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,TRCSERPMAX,"",0,DIAL_LEFTMARG+pcol,cy,9.0,""); cy+=DIAL_CTRVSTEP; dial_label(0.0,cy,UPRTRCSMIN); sminidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,TRCSERPMIN,"",0,DIAL_LEFTMARG+pcol,cy,9.0,""); cy+=DIAL_CTRVSTEP; // Store the OK and abort button with seperator dial_hsep(cy); dial_okabortini(cy,pcol+labwidth+1.0+DIAL_RIGHTSMARG,3); // Store coordinate unit controls cunits= bae_getcoorddisp() ? 2 : 0; bae_dialaddcontrol(PA_RBF,0,1,cunits,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol,cy-DIAL_BUTVSTEP-DIAL_SEPVSTEP,0.0, UPRDUNITMM); bae_dialaddcontrol(PA_RBN,2,2,0,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol+6.0,cy-DIAL_BUTVSTEP-DIAL_SEPVSTEP,0.0, UPRDUNITMIL); // Perform the dialog input loop repflag=1; do { // Call the dialog function bae_setintpar(16,3088); switch (res=bae_dialaskparams(UPRTRCLPARAM,cunits, DIAL_LEFTMARG+pcol+labwidth+1.0+DIAL_RIGHTSMARG,cy)) { // Done case 0 : case 3 : bae_dialgetdata(nlenidx,0,newlen,""); bae_dialgetdata(slenidx,0,TRCSERPLEN,""); bae_dialgetdata(scrnidx,0,TRCSERPCRN,""); bae_dialgetdata(smaxidx,0,TRCSERPMAX,""); bae_dialgetdata(sminidx,0,TRCSERPMIN,""); bae_dialgetdata(smodidx,TRCSERPMOD,0.0,""); bae_dialgetdata(ssididx,TRCSERPSID,0.0,""); bae_dialgetdata(nmidx,TRCSERPNET,0.0,""); if (TRCSERPMAX=0) { curlen=treepathlen(1,pel[pidx].fig.TREE,0,0,0.0,0.0,0.0,0.0); } else { curlen=0.0; for (pidx=0;pidx0 && pidx<(pen-1) && pel[pidx-1].fig.TYP==L_FIGPATH && pel[pidx+1].fig.TYP==L_FIGPATH) { laysidx1=layscnt; laysidx2=(-1); lay=trclayer(pel[pidx-1].fig.LAYER); for (i=0;ilaysidx2) laysidx2=i; break; } lay=trclayer(pel[pidx+1].fig.LAYER); for (i=0;ilaysidx2) laysidx2=i; break; } if (laysidx1!=layscnt && laysidx2!=(-1) && laysidx1!=laysidx2) { curlen+=laysl[laysidx1].iso; for (i=laysidx1+1;i=newlen) { sprintf(msgbuf,TRCSERPNET ? REPNETLONG : REPTRCLONG, bae_numstring(baecvtl(curlen),3), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(newlen),3), bae_getcoorddisp() ? UNITIN : UNITMM); bae_msgbox(1,msgbuf,""); continue; } distgap=newlen-curlen; // Get the length correction parameters serpmin=TRCSERPMIN; serpdone=0; lastcorr=0; for (pidx=0;pidxmaxgain) { serppoly(0,side,lx,ly,sx,sy, off,TRCSERPLEN,serpmin, TRCSERPCRN,TRCSERPMOD,scrn, distgap>2.0*maxgain ? 0 : 1, serpgain,serprad); if (serpgain>distgap || ged_drcpath( lay,trcwidth,plevel,1)!=0) // End corner ecrn=1; else // Side change at end ecrn=0; } else { // Create serpentine end corner ecrn=1; } } // Check if minimum step possible serppoly(0,side,lx,ly,sx,sy,off, TRCSERPLEN,serpmin,TRCSERPCRN, TRCSERPMOD,scrn,ecrn,serpgain,serprad); if (serpgain>distgap || ged_drcpath(lay,trcwidth,plevel,1)!=0) // Side step not possible continue; // Check if last corner correction if (TRCSERPSID==2 && scrn && lstep==(scnt-1)) { off+=2.0*lrad; // Check if minimum step possible serppoly(0,side,lx,ly,sx,sy,off, TRCSERPLEN,serpmin,TRCSERPCRN, TRCSERPMOD,scrn,ecrn,serpgain,serprad); if (serpgain>distgap || ged_drcpath(lay,trcwidth,plevel,1)!=0) // Side step not possible continue; lastcorr=1; lastshift=lrad; } // Scan side step range stepval=serprng; l=0.0; firststep=1; while (stepval>=SMALLCVAL) { serppoly(0,side,lx,ly,sx,sy,off, TRCSERPLEN,l+stepval+serpmin, TRCSERPCRN,TRCSERPMOD, scrn,ecrn,serpgain,serprad); if (serpgain<=distgap && ged_drcpath( lay,trcwidth,plevel,1)==0) { l+=stepval; if (firststep) break; } /* Continue range scan */ stepval*=0.5; firststep=0; } // Calculate the side step length serppoly(0,side,lx,ly,sx,sy,off, TRCSERPLEN,l+serpmin,TRCSERPCRN,TRCSERPMOD, scrn,ecrn,serpgain,serprad); if (lastcorr) { // Check if minimum step possible lrad=serprad; serppoly(0,side,lx,ly,sx,sy, off-lastshift+lrad, TRCSERPLEN,l+serpmin,TRCSERPCRN, TRCSERPMOD,scrn,ecrn,serpgain,serprad); if (ged_drcpath( lay,trcwidth,plevel,1)==0) { off-=lastshift-lrad; lastcorr=0; } else { // Recalculate side step length serppoly(0,side,lx,ly,sx,sy,off, TRCSERPLEN,l+serpmin, TRCSERPCRN,TRCSERPMOD, scrn,ecrn,serpgain,serprad); } } // Store the side step pel[pidx].pl[lp].ol[offn].side=side; pel[pidx].pl[lp].ol[offn].off=off; pel[pidx].pl[lp].ol[offn].step=l+serpmin; pel[pidx].pl[lp].ol[offn].scrn=scrn; pel[pidx].pl[lp].ol[offn].ecrn=ecrn; offn++; lstep=scnt; lrad=serprad; // Adjust length gap distgap-=serpgain; // Check if last correction if (distgap<4.0*SMALLCVAL) { serpdone=1; break; } } pel[pidx].pl[lp].on=offn; if (offn) pel[pidx].offflag=1; } // Check if serpentine done if (serpdone) break; } if (!serpdone) { sprintf(msgbuf,REPTRCNLONG,bae_numstring(baecvtl(newlen),3), bae_getcoorddisp() ? UNITIN : UNITMM, bae_numstring(baecvtl(newlen-distgap),3), bae_getcoorddisp() ? UNITIN : UNITMM); bae_msgbox(1,msgbuf,""); continue; } // Save current state for undo if (cflag==0) { bae_callmenu(MNU_BAESAVESTATE); cflag=1; } // Create the adjusted path createadjpath(); cnt++; } // No pick if (cnt) bae_prtdialog(ERRNOPICK); else perror(ERRNOPICK); } void drawlegend() /* // Draw serpentine data legend */ { // Display legend bae_clearpoints(); btp_storepoint(0.3,0.0,0); btp_storepoint(0.7,0.0,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); bae_clearpoints(); btp_storepoint(0.3,3.0,0); btp_storepoint(0.7,3.0,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); bae_clearpoints(); btp_storepoint(0.5,0.0,0); btp_storepoint(0.5,3.0,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); btp_drawtext(-0.2,2.0,15,0,"a"); bae_clearpoints(); btp_storepoint(2.3,3.0,0); btp_storepoint(3.5,3.0,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); bae_clearpoints(); btp_storepoint(2.3,2.0,0); btp_storepoint(2.7,2.0,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); bae_clearpoints(); btp_storepoint(2.5,2.0,0); btp_storepoint(2.5,3.2,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); bae_clearpoints(); btp_storepoint(3.5,2.8,0); btp_storepoint(3.5,3.2,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); btp_drawtext(2.7,4.1,15,0,"r"); btp_drawtext(1.8,3.0,15,0,"r"); bae_clearpoints(); btp_storepoint(2.5,0.2,0); btp_storepoint(2.5,-0.2,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); bae_clearpoints(); btp_storepoint(6.5,0.2,0); btp_storepoint(6.5,-0.2,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); bae_clearpoints(); btp_storepoint(2.5,-0.0,0); btp_storepoint(6.5,-0.0,0); bae_popdrawpoly(15,DM_REPLACE,PPFM_LINE); btp_drawtext(4.2,0.0,15,0,"l"); } void createadjpath() /* // Create the length adjusted path, dismiss old path elements */ { index L_FIGURE fig /* Figure list index */; index L_FIGURE nfig /* New figure list index */; STRINGS rl /* Rule list */; double x,y /* Current coordinates */; int t /* Current point type */; double lx,ly /* Last coordinates */; double sx,sy /* Segment normalized vector */; double serpgain /* Serpentine length gain */; double serprad /* Serpentine used radius/length */; int pidx /* Path element index */; int offn /* Segment offset count */; int lp /* Last point index */; int i, j /* Loop control variables */; for (pidx=0;pidx=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); // Delete old path if (ged_delelem(fig)) error(ERRDELTRC); // Redisplay new path if (lay_lastfigelem(nfig)==0) ged_drawelem(nfig,DM_SET); } } void pairadjust() /* // Length adjust pair with phase correction */ { string msgbuf /* Message buffer string */; index L_FIGURE fig /* Figure list index */; index L_LEVEL plev1 /* 1st path level */; index L_LEVEL plev2 /* 2nd path level */; struct pointdes p1l[] /* 1st trace point list */; int p1n /* 1st trace point count */; struct pointdes p2l[] /* 2nd trace point list */; int p2n /* 2nd trace point count */; double trcwidth1 /* 1st trace width */; int lay1 /* 1st trace layer */; double trcwidth2 /* 1st trace width */; int lay2 /* 1st trace layer */; double dist /* Pair distance */; double curlen1, curlen2 /* Current pair lengthes */; double x1s,y1s /* 1st segment start coordinates */; double x1e,y1e /* 1st segment end coordinates */; double x2s,y2s /* 2nd segment start coordinates */; double x2e,y2e /* 2nd segment end coordinates */; double l1s /* 1st parallel sub segment data */; double l2s /* 2nd parallel sub segment data */; int lp1, lp2 /* Segment last point indeces */; int sp1n, sp2n /* Segment pair indeces */; double sx,sy /* Segment normalized vector */; double seglen /* Segment length */; double serprng /* Serpentine elevation range */; double serpoff /* Serpentine creation offset */; double serpend /* Serpentine scan end offset */; double serpmin /* Serpentine current min. elevation */; double serpgain /* Serpentine length gain */; double serprad /* Serpentine used radius/length */; int stoggle /* Side toggle */; double maxgain /* Serpentine gain at max. elevation */; double distgap /* Distance gap */; double off /* Segment scan offset */; int curoff /* Current offset index */; int offn /* Segment offset count */; int oldoffn /* Old segment offset count */; double stepval /* Search step value */; double l /* Current length step value */; int firststep /* First search step flag */; int scanabort /* Scan abort flag */; int scanendflag /* Scan from end of segment flag */; int endscanstat = 0 /* End scan status */; double slenoff /* Start length offset */; double elenoff /* End length offset */; double labwidth /* Picture label width */; double labheight /* Picture label height */; double pcol = 18.0 /* Parameter column */; double cy /* Dialog box current y coordinate */; int repflag /* Dialog box repeat flag */; int res /* Dialog box result */; int varidx /* INI variable index */; int soffidx /* Start offset parameter index */; int eoffidx /* End offset parameter index */; int slenidx /* Serpentine length parameter index */; int scrnidx /* Serpentine corner parameter index */; int smaxidx /* Serpentine max. el. param. index */; int sminidx /* Serpentine min. el. param. index */; int smodidx /* Serpentine corn.mode param. index */; int ptidx /* Length priority param. index */; int cunits /* Coordinate display units */; int p1idx /* 1st path element index */; int p2idx /* 2nd path element index */; int s1idx /* 1st path segment index */; int s2idx /* 2nd path segment index */; int np2idx /* Next path element index */; int ns2idx /* Next path segment index */; int sp1idx /* 1st segment parallel scan index */; int sp2idx /* 2nd segment parallel scan index */; int eidx /* Loop end index */; int side1 /* First path side */; int side2 /* Second path side */; int i /* Loop control variable */; if (varget(GV_TRCSERPCRN,cy)==0) TRCSERPCRN=cy; if (varget(GV_TRCSERPMAX,cy)==0) TRCSERPMAX=cy; if (varget(GV_TRCSERPMIN,cy)==0) TRCSERPMIN=cy; if (varget(GV_TRCSERPLEN,cy)==0) TRCSERPLEN=cy; if (varget(GV_TRCSLENOFF,slenoff)) slenoff=0.0; if (varget(GV_TRCELENOFF,elenoff)) elenoff=0.0; if (varget(GV_TRCSERPMOD,i)==0) TRCSERPMOD=i; if (varget(GV_TRCSERPLPT,i)==0) TRCSERPLPT=i; // Check for dialog support if (bae_dialclr()==0) { // Init. the y coordinate cy=DIAL_TOPMARG; // Set the default picture button bitmap size labwidth=PICLABWIDTH; labheight=PICLABHEIGHT; // Create the picture button bitmap if (bmp_setsize( -1.0,4.5,10.0,-1.0,labwidth,labheight,0.0,0.0) || bae_dialbmpalloc(labwidth,labheight,2,0,0)!=2) error_abort(); // Draw the first picture label bitmap bae_popsetarea(2); // Display edged trace graphic btp_drawwideline(2,DM_REPLACE,1,0.5,0.0,1.5,0.0,0.2); btp_drawwideline(2,DM_REPLACE,1,1.5,0.0,2.5,1.0,0.2); btp_drawwideline(2,DM_REPLACE,1,2.5,1.0,2.5,2.0,0.2); btp_drawwideline(2,DM_REPLACE,1,2.5,2.0,3.5,3.0,0.2); btp_drawwideline(2,DM_REPLACE,1,3.5,3.0,5.5,3.0,0.2); btp_drawwideline(2,DM_REPLACE,1,5.5,3.0,6.5,2.0,0.2); btp_drawwideline(2,DM_REPLACE,1,6.5,2.0,6.5,1.0,0.2); btp_drawwideline(2,DM_REPLACE,1,6.5,1.0,7.5,0.0,0.2); btp_drawwideline(2,DM_REPLACE,1,7.5,0.0,9.5,0.0,0.2); // Display legend drawlegend(); bae_popsetarea(0); // Store the bitmap label bae_dialadvcontrol(PA_BMLAB,0,0,2,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol,cy,labwidth,labheight,""); // Create the picture button bitmap labwidth=PICLABWIDTH; labheight=PICLABHEIGHT; // Create the picture button bitmap if (bmp_setsize( -1.0,4.5,10.0,-1.0,labwidth,labheight,0.0,0.0) || bae_dialbmpalloc(labwidth,labheight,3,0,0)!=3) error_abort(); // Draw the second picture label bitmap bae_popsetarea(3); // Display round trace graphic btp_drawwideline(2,DM_REPLACE,1,0.5,0.0,1.5,0.0,0.2); btp_drawwidearc(2,DM_REPLACE,1,1.5,0.0,1.5,1.0,2.5,1.0,1,0.2); btp_drawwideline(2,DM_REPLACE,1,2.5,1.0,2.5,2.0,0.2); btp_drawwidearc(2,DM_REPLACE,1,2.5,2.0,3.5,2.0,3.5,3.0,2,0.2); btp_drawwideline(2,DM_REPLACE,1,3.5,3.0,5.5,3.0,0.2); btp_drawwidearc(2,DM_REPLACE,1,5.5,3.0,5.5,2.0,6.5,2.0,2,0.2); btp_drawwideline(2,DM_REPLACE,1,6.5,2.0,6.5,1.0,0.2); btp_drawwidearc(2,DM_REPLACE,1,6.5,1.0,7.5,1.0,7.5,0.0,1,0.2); btp_drawwideline(2,DM_REPLACE,1,7.5,0.0,9.5,0.0,0.2); // Display legend drawlegend(); bae_popsetarea(0); // Store the bitmap label bae_dialadvcontrol(PA_BMLAB,0,0,3,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol,cy+4.0,labwidth,labheight,""); // Store corner mode controls smodidx=bae_dialaddcontrol(PA_RBF,0,0,TRCSERPMOD,0.0,0.0, 0.0,"",0,DIAL_LEFTMARG,cy+1.5,0.0,UPRSERP45); cy+=PICLABHEIGHT; bae_dialaddcontrol(PA_RBN,1,0,0,0.0,0.0,0.0, "",0,DIAL_LEFTMARG,cy+1.5,0.0,UPRSERPRND); cy+=PICLABHEIGHT; // Store serpentine length controls dial_label(0.0,cy,UPRDTRCLSOFF); soffidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,slenoff,"",0,DIAL_LEFTMARG+pcol,cy,10.0,""); cy+=DIAL_CTRVSTEP; dial_label(0.0,cy,UPRDTRCLEOFF); eoffidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,elenoff,"",0,DIAL_LEFTMARG+pcol,cy,10.0,""); cy+=DIAL_CTRVSTEP; dial_label(0.0,cy,UPRTRCSSTEP); slenidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,TRCSERPLEN,"",0,DIAL_LEFTMARG+pcol,cy,10.0,""); cy+=DIAL_CTRVSTEP; // Store corner mode controls dial_label(0.0,cy,UPRTRCSCORN); scrnidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,TRCSERPCRN,"",0,DIAL_LEFTMARG+pcol,cy,10.0,""); cy+=DIAL_CTRVSTEP; dial_label(0.0,cy,UPRTRCSMAX); smaxidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,TRCSERPMAX,"",0,DIAL_LEFTMARG+pcol,cy,10.0,""); cy+=DIAL_CTRVSTEP; dial_label(0.0,cy,UPRTRCSMIN); sminidx=bae_dialaddcontrol(PA_DBL|PA_DIST,0,5,0, 0.0,0.0,TRCSERPMIN,"",0,DIAL_LEFTMARG+pcol,cy,10.0,""); cy+=DIAL_CTRVSTEP; // Store length priority controls dial_label(0.0,cy,UPRDTRCPRIO); ptidx=bae_dialaddcontrol(PA_RBF,0,0,TRCSERPLPT,0.0,0.0,0.0, "",0,DIAL_LEFTMARG+pcol,cy,0.0,UPRDTRCPRIO1); bae_dialaddcontrol(PA_RBN,1,0,0,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol+6.0,cy,0.0,UPRDTRCPRIO2); cy+=DIAL_CTRVSTEP; // Store the OK and abort button with seperator dial_hsep(cy); dial_okabortini(cy,pcol+labwidth+1.0+DIAL_RIGHTSMARG,3); // Store coordinate unit controls cunits= bae_getcoorddisp() ? 2 : 0; bae_dialaddcontrol(PA_RBF,0,1,cunits,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol,cy-DIAL_BUTVSTEP-DIAL_SEPVSTEP,0.0, UPRDUNITMM); bae_dialaddcontrol(PA_RBN,2,2,0,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol+6.0,cy-DIAL_BUTVSTEP-DIAL_SEPVSTEP,0.0, UPRDUNITMIL); // Perform the dialog input loop repflag=1; do { // Call the dialog function bae_setintpar(16,3088); switch (res=bae_dialaskparams(UPRTRCLPARAM,cunits, DIAL_LEFTMARG+pcol+labwidth+1.0+DIAL_RIGHTSMARG,cy)) { // Done case 0 : case 3 : bae_dialgetdata(soffidx,0,slenoff,""); bae_dialgetdata(eoffidx,0,elenoff,""); bae_dialgetdata(slenidx,0,TRCSERPLEN,""); bae_dialgetdata(scrnidx,0,TRCSERPCRN,""); bae_dialgetdata(smaxidx,0,TRCSERPMAX,""); bae_dialgetdata(sminidx,0,TRCSERPMIN,""); bae_dialgetdata(smodidx,TRCSERPMOD,0.0,""); bae_dialgetdata(ptidx,TRCSERPLPT,0.0,""); if (TRCSERPMAXSMALLCVAL) { // Get the segment vector sx=x1e-x1s; sy=y1e-y1s; // Normalize segment vector normvect(sx,sy,seglen); // Check if long enough for correction segment if (seglen<2.0*TRCSERPLEN) // Leave segment unchanged continue; serpend=seglen-serpoff-TRCSERPLEN; offn=p1el[p1idx].pl[lp1].on; stoggle=0; for (off=serpoff;off<=serpend;off+=TRCSERPLEN) { stoggle=1-stoggle; if (stoggle==0) continue; // Check if last adjustment step if (distgapdistgap || ged_drcpath(lay1,trcwidth1,plev1,1)!=0) // Side step not possible continue; // Scan side step range stepval=serprng; l=0.0; firststep=1; while (stepval>=SMALLCVAL) { serppoly(0,side1,x1s,y1s,sx,sy,off, TRCSERPLEN,l+stepval+serpmin, TRCSERPCRN,TRCSERPMOD, 1,1,serpgain,serprad); if (serpgain<=distgap && ged_drcpath( lay1,trcwidth1,plev1,1)==0) { l+=stepval; if (firststep) break; } /* Continue range scan */ stepval*=0.5; firststep=0; } // Calculate the side step length serppoly(0,side1,x1s,y1s,sx,sy,off, TRCSERPLEN,l+serpmin,TRCSERPCRN,TRCSERPMOD, 1,1,serpgain,serprad); // Store the side step p1el[p1idx].pl[lp1].ol[offn].side=side1; p1el[p1idx].pl[lp1].ol[offn].off=off; p1el[p1idx].pl[lp1].ol[offn].step=l+serpmin; p1el[p1idx].pl[lp1].ol[offn].scrn=1; p1el[p1idx].pl[lp1].ol[offn].ecrn=1; offn++; // Adjust length gap distgap-=serpgain; curlen1+=serpgain; // Check if last correction if (distgap<4.0*SMALLCVAL) break; } p1el[p1idx].pl[lp1].on=offn; if (offn) p1el[p1idx].offflag=1; } // Check if 2nd path start adjustment else if (distgap<(-SMALLCVAL)) { distgap=-distgap; // Get the segment vector sx=x2e-x2s; sy=y2e-y2s; // Normalize segment vector normvect(sx,sy,seglen); // Check if long enough for correction segment if (seglen<2.0*TRCSERPLEN) // Leave segment unchanged continue; serpend=seglen-serpoff-TRCSERPLEN; offn=p2el[p2idx].pl[lp2].on; stoggle=0; for (off=serpoff;off<=serpend;off+=TRCSERPLEN) { stoggle=1-stoggle; if (stoggle==0) continue; // Check if last adjustment step if (distgapdistgap || ged_drcpath(lay2,trcwidth2,plev2,1)!=0) // Side step not possible continue; // Scan side step range stepval=serprng; l=0.0; firststep=1; while (stepval>=SMALLCVAL) { serppoly(0,side2,x2s,y2s,sx,sy,off, TRCSERPLEN,l+stepval+serpmin, TRCSERPCRN,TRCSERPMOD, 1,1,serpgain,serprad); if (serpgain<=distgap && ged_drcpath( lay2,trcwidth2,plev2,1)==0) { l+=stepval; if (firststep) break; } /* Continue range scan */ stepval*=0.5; firststep=0; } // Calculate the side step length serppoly(0,side2,x2s,y2s,sx,sy,off, TRCSERPLEN,l+serpmin,TRCSERPCRN,TRCSERPMOD, 1,1,serpgain,serprad); // Store the side step p2el[p2idx].pl[lp2].ol[offn].side=side2; p2el[p2idx].pl[lp2].ol[offn].off=off; p2el[p2idx].pl[lp2].ol[offn].step=l+serpmin; p2el[p2idx].pl[lp2].ol[offn].scrn=1; p2el[p2idx].pl[lp2].ol[offn].ecrn=1; offn++; // Adjust length gap distgap-=serpgain; curlen2+=serpgain; // Check if last correction if (distgap<4.0*SMALLCVAL) break; } p2el[p2idx].pl[lp2].on=offn; if (offn) p2el[p2idx].offflag=1; } } curlen1+=dist(x1s,y1s,x1e,y1e); } } // Scan second path length up to end while (p2idx4.0*SMALLCVAL) { pel=p1el; pen=p1en; endscanstat=1; } // Check if 2nd path start adjustment else if (distgap<(-4.0*SMALLCVAL)) { pel=p2el; pen=p2en; distgap=fabs(distgap); endscanstat=2; } if (endscanstat!=0) // Scan the path in reverse order for (p1idx=pen-1;p1idx>=0 && !scanabort;p1idx--) { fig=pel[p1idx].fig; // Skip vias if (fig.TYP==L_FIGUREF) continue; // Get path point list p1n=pel[p1idx].pn; p1l=pel[p1idx].pl; side1=pel[p1idx].side; trcwidth1=fig.SIZE; lay1=fig.LAYER; plev1=pel[p1idx].plev; // Scan path segments for (s1idx=p1n-1;s1idx>0 && !scanabort;s1idx--) { lp1=s1idx-1; // Check if arc if (p1l[lp1].typ || p1l[s1idx].typ) continue; // Get segment data x1s=p1l[lp1].x; y1s=p1l[lp1].y; x1e=p1l[s1idx].x; y1e=p1l[s1idx].y; // Get the segment vector sx=x1e-x1s; sy=y1e-y1s; // Normalize segment vector normvect(sx,sy,seglen); // Check if long enough for correction segment if (seglen<2.0*TRCSERPLEN) // Leave segment unchanged continue; // Get the length correction parameters serpmin=TRCSERPMIN; serprng=TRCSERPMAX-TRCSERPMIN; offn=pel[p1idx].pl[lp1].on; stoggle=0; if (offn==0 && scanendflag==0) { serpend=seglen-serpoff-TRCSERPLEN; } else { serpend=offn==0 ? serpoff : pel[p1idx].pl[lp1].ol[offn-1].off+ 2.0*TRCSERPLEN; scanendflag=1; } oldoffn=offn; for (off=scanendflag==0 ? serpoff : (seglen-serpoff-TRCSERPLEN); ((scanendflag==0 && off<=serpend) || (scanendflag==1 && off>=serpend)) && !scanabort; off+=(scanendflag==0 ? TRCSERPLEN : -TRCSERPLEN)) { stoggle=1-stoggle; if (stoggle==0) continue; // Check if last adjustment step if (distgapdistgap || ged_drcpath(lay1,trcwidth1,plev1,1)!=0) // Side step not possible continue; // Scan side step range stepval=serprng; l=0.0; firststep=1; while (stepval>=SMALLCVAL) { serppoly(0,side1,x1s,y1s,sx,sy,off, TRCSERPLEN,l+stepval+serpmin, TRCSERPCRN,TRCSERPMOD, 1,1,serpgain,serprad); if (serpgain<=distgap && ged_drcpath( lay1,trcwidth1,plev1,1)==0) { l+=stepval; if (firststep) break; } /* Continue range scan */ stepval*=0.5; firststep=0; } // Calculate the side step length serppoly(0,side1,x1s,y1s,sx,sy,off, TRCSERPLEN,l+serpmin,TRCSERPCRN,TRCSERPMOD, 1,1,serpgain,serprad); if (scanendflag) { for (curoff=offn;curoff>oldoffn;curoff--) pel[p1idx].pl[lp1].ol[curoff]= pel[p1idx].pl[lp1].ol[curoff-1]; } else { curoff=offn; } // Store the side step pel[p1idx].pl[lp1].ol[curoff].side=side1; pel[p1idx].pl[lp1].ol[curoff].off=off; pel[p1idx].pl[lp1].ol[curoff].step=l+serpmin; pel[p1idx].pl[lp1].ol[curoff].scrn=1; pel[p1idx].pl[lp1].ol[curoff].ecrn=1; offn++; // Adjust length gap distgap-=serpgain; // Check if last correction if (distgap<4.0*SMALLCVAL) { scanabort=1; break; } } pel[p1idx].pl[lp1].on=offn; if (offn) pel[p1idx].offflag=1; if (TRCSERPLPT==0 && scanendflag) scanabort=1; } } // Store end corrected point lists switch (endscanstat) { case 1 : p1el=pel; p1en=pen; break; case 2 : p2el=pel; p2en=pen; break; default : ; } // Save current state for undo bae_callmenu(MNU_BAESAVESTATE); // Create the adjusted pathes pel=p1el; pen=p1en; createadjpath(); pel=p2el; pen=p2en; createadjpath(); if (fabs(distgap)>4.0*SMALLCVAL) { sprintf(msgbuf,REPTRCDIFF, bae_numstring(baecvtl(fabs(distgap)),3), bae_getcoorddisp() ? UNITIN : UNITMM); bae_msgbox(1,msgbuf,""); } } void pairdisp() /* // Display differential pair phase */ { index L_FIGURE fig /* Figure list index */; index L_FIGURE dfig /* Delete figure list element */; index L_FIGURE nfig /* New figure list index */; string msg /* Grid message */; string name /* Documentary layer name */; struct pointdes pl[] /* Trace point list */; int pn /* Trace point count */; int lp /* Segment last point index */; int pidx /* Path element index */; double lenoff /* Length offset */; int repflag /* Dialog box repeat flag */; int res /* Dialog box selection result */; int varidx /* INI variable index */; int cunits /* Coordinate display units */; double pcol = 21.0 /* Parameter column */; double cy /* Dialog box current y coordinate */; int loidx = (-1) /* Length off. dialog box item idx. */; int wlidx = (-1) /* Wave length dialog box item idx. */; int wtidx = (-1) /* Wave type dialog box item idx. */; int wrlidx = (-1) /* Wave ramp dialog box item idx. */; int wridx = (-1) /* Wave ramp dialog box item idx. */; int f3lidx = (-1) /* 3rd freq. dialog box item idx. */; int f3idx = (-1) /* 3rd freq. dialog box item idx. */; int f5lidx = (-1) /* 5th freq. dialog box item idx. */; int f5idx = (-1) /* 5th freq. dialog box item idx. */; int dlidx = (-1) /* Display lay. dialog box item idx. */; int cuidx = (-1) /* Coord. units dialog box item idx. */; double pairdist /* Pair distance */; double hdist /* Half pair distance */; double len1, len2 /* Current pair lengthes */; double curlen /* Current scan length */; double xs,ys /* Segment start coordinates */; double xe,ye /* Segment end coordinates */; double bx, by /* Base point coordinates */; double ws, we /* Wave elevation values */; double wr /* Wave elevation ratio */; double sx, sy /* Segment direction vector */; double slen /* Segment length */; double nx, ny /* Segment normal vector */; double scans, scane /* Scan segment range */; double segs, sege /* Scan sub segment range */; double scanz /* Scan zero line cross */; double step /* Scan step */; int boxmode /* Edit box mode */; int side /* Scan side */; int cnt /* Process count */; int i, j /* Loop control variables */; // Query last data if (varget(GV_TRCWAVELEN,cy)==0) TRCWAVELEN=cy; if (varget(GV_TRCWAVERAMP,cy)==0) TRCWAVERAMP=cy; if (varget(GV_TRCWAVEF3,cy)==0) TRCWAVEF3=cy; if (varget(GV_TRCWAVEF5,cy)==0) TRCWAVEF5=cy; if (varget(GV_TRCSLENOFF,lenoff)) lenoff=0.0; if (varget(GV_TRCWAVETYP,res)==0) TRCWAVETYP=res; if (varget(GV_TRCDISPLAY,res)==0) TRCDISPLAY=res; TRCDISPLAY&=(~0x0F); // Check if dialog box support if (bae_dialclr()) { // Get trace length offset if (askdist(lenoff,UPRTRCLSOFF,0)) // Invalid input value error(ERRINPVAL); // Get wave length if (askdist(TRCWAVELEN,UPRTRCWLEN,0)) // Invalid input value error(ERRINPVAL); // Ask for display layer bae_promptdialog(UPRSELGLAYER); if (ged_asklayer(TRCDISPLAY,3)) // Abort error_abort(); } else { cy=DIAL_TOPMARG; // Store trace length offset controls dial_label(0.0,cy,UPRDTRCLSOFF); loidx=dial_dist(5,lenoff,pcol,cy); // Store wave length controls dial_label(0.0,cy,UPRDTRCWLEN); wlidx=dial_dist(5,TRCWAVELEN,pcol,cy); // Store wave type controls dial_label(0.0,cy,UPRDTRCTYP); wtidx=bae_dialaddcontrol(PA_RBF,0,1,TRCWAVETYP,0.0,0.0,0.0, "",0,DIAL_LEFTMARG+pcol,cy,0.0,UPRDTRCTYPS); bae_dialaddcontrol(PA_RBN,1,1,0,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol+6.0,cy,0.0,UPRDTRCTYPT); cy+=DIAL_CTRVSTEP; // Store wave ramp factor controls wrlidx=dial_label(0.0,cy,UPRDTRCRAMP); wridx=bae_dialaddcontrol(PA_DBL|PA_CHKLL|PA_CHKUL|PA_HBRDREL, 0,2,0,0.0,100.0,TRCWAVERAMP,"",0,DIAL_LEFTMARG+pcol,cy, DIAL_RIGHTEMARG,""); cy+=DIAL_CTRVSTEP; // Store wave 3rd frequency factor controls f3lidx=dial_label(0.0,cy,UPRDTRCF3); f3idx=bae_dialaddcontrol(PA_DBL|PA_CHKLL|PA_CHKUL|PA_HBRDREL, 0,2,0,0.0,100.0,TRCWAVEF3,"",0,DIAL_LEFTMARG+pcol,cy, DIAL_RIGHTEMARG,""); cy+=DIAL_CTRVSTEP; // Store wave 5th frequency factor controls f5lidx=dial_label(0.0,cy,UPRDTRCF5); f5idx=bae_dialaddcontrol(PA_DBL|PA_CHKLL|PA_CHKUL|PA_HBRDREL, 0,2,0,0.0,100.0,TRCWAVEF5,"",0,DIAL_LEFTMARG+pcol,cy, DIAL_RIGHTEMARG,""); cy+=DIAL_CTRVSTEP; // Store display layer controls dial_label(0.0,cy,UPRDGLAYER); dlidx=dial_selbox(TRCDISPLAY,pcol,cy); for (i=0;i=0) // Query group name predicate if (lay_rulequery(RS_OCFIG,fig, RS_PCBSUBJ,RS_GROUPNAME, "?s",name)>0 && name==TRCDISPGNAME) { dfig=fig; ged_delelem(dfig); cnt++; } sprintf(msg,REPGRAFDEL,cnt); bae_prtdialog(msg); break; default : error_abort(); } // Stop if no further repeat requests } while (repflag); } // Store settings for next call varset(GV_TRCSLENOFF,lenoff); varset(GV_TRCWAVELEN,TRCWAVELEN); varset(GV_TRCWAVETYP,TRCWAVETYP); varset(GV_TRCWAVERAMP,TRCWAVERAMP); varset(GV_TRCWAVEF3,TRCWAVEF3); varset(GV_TRCWAVEF5,TRCWAVEF5); varset(GV_TRCDISPLAY,TRCDISPLAY); // Pick the differential pair if (pickpair(pairdist,0)) error(ERRTRCNPAIR); hdist=0.5*pairdist; if (lenoff<0.0) { len1=0.0; len2=(-lenoff); } else { len1=lenoff; len2=0.0; } layerfadein(TRCDISPLAY,COLFIN,1); // Save current state for undo bae_callmenu(MNU_BAESAVESTATE); // Scan both pair sides for (side=0;side<2;side++) { if (side==0) { pel=p1el; pen=p1en; curlen=len1; } else { pel=p2el; pen=p2en; curlen=len2; } // Scan trace elements for (pidx=0;pidxsege) scane=sege; ws=hdist*ampval(fmod(curlen+scans, TRCWAVELEN)/TRCWAVELEN); we=hdist*ampval(fmod(curlen+scane, TRCWAVELEN)/TRCWAVELEN); bx=xs+scans*sx+hdist*nx; by=ys+scans*sy+hdist*ny; bae_storepoint(bx,by,0); bae_storepoint(bx+ws*nx,by+ws*ny,0); // Check if sign change if (ws*we<0.0) { wr=ws/we; scanz=scans+ (wr*(scans-scane))/(1.0-wr); bx=xs+scanz*sx+hdist*nx; by=ys+scanz*sy+hdist*ny; bae_storepoint(bx,by,0); ged_storepoly(TRCDISPLAY|side, L_POLYDOCAREA,"",0); if (lay_lastfigelem(nfig)==0) rs_assfigstrpred(nfig, RS_GROUPNAME, TRCDISPGNAME,"",""); bae_clearpoints(); bae_storepoint(bx,by,0); } bx=xs+scane*sx+hdist*nx; by=ys+scane*sy+hdist*ny; bae_storepoint(bx+we*nx,by+we*ny,0); } } bae_storepoint(bx,by,0); ged_storepoly(TRCDISPLAY|side, L_POLYDOCAREA,"",0); if (lay_lastfigelem(nfig)==0) rs_assfigstrpred(nfig,RS_GROUPNAME, TRCDISPGNAME,"",""); // Update scan length curlen+=slen; } } } bae_prtdialog(REPDONE); } void paircheck() /* // Check differential pairs */ { index L_CNET net /* Connection index */; index L_ATTRIBUTE attr /* Attribute index */; STRINGS headl /* Menu header string list */; int headn /* Menu header string count */; STRINGS entryl /* Menu entry string list */; int entryn /* Menu entry string count */; string pairid /* Pair ID */; double pairdist /* Pair distance */; double cmpdist /* Compare distance tolerance */; double curdist /* Cur. distance */; double partrc /* Parallel trace percentage */; struct netpairdat swapbuf /* Net pair data swap buffer */; struct netptrc scantrc /* Current scan trace */; int trc1n /* 1st trace count */; struct ptdes p1l[] /* 1st trace point list */; int p1n /* 1st trace point count */; int trc2n /* 2nd trace count */; struct ptdes p2l[] /* 2nd trace point list */; int p2n /* 2nd trace point count */; int np1idx /* 1st net pair index */; int np2idx /* 2nd net pair index */; int t1idx /* 1st trace index */; int t2idx /* 2nd trace index */; int t2sidx /* 2nd trace start index */; int p1idx /* 1st path point index */; int p2idx /* 2nd path point index */; double xs1,ys1 /* 1st segment start coordinates */; double xe1,ye1 /* 1st segment end coordinates */; int lp1 /* 1st segment last point index */; double xs2,ys2 /* 2nd segment start coordinates */; double xe2,ye2 /* 2nd segment end coordinates */; int lp2 /* 2nd segment last point index */; double l1s, l1e /* 1st parallel sub segment data */; double l2s, l2e /* 2nd parallel sub segment data */; double vx, vy /* Segment direction vector */; double pickdist /* Pick distance */; int cnt /* Process count */; // Abort if invalid plan class if (ddbclass!=DDBCLLAY) error_class(); // Ask for display layer bae_promptdialog(UPRSELGLAYER); if (ged_asklayer(TRCDISPLAY,3)) // Abort error_abort(); // Scan differential pair marked nets forall (net) { forall (attr of net where attr.NAME=="$pairid") { pairid=attr.VALUE; netpdatl[netidatn].net=net; netpdatl[netidatn].pairdist=0.0; netpdatl[netidatn].pairid=pairid; netpdatl[netidatn].pairidx=(-1); netpdatl[netidatn].trcn=0; netpdatl[netidatn].parlen=0.0; netpdatl[netidatn].trclen=0.0; netpdatl[netidatn].viacnt=0; netidatl[netidatn]=netidatn; netidatn++; break; } } if (netidatn==0) error(ERRNOPAIR); // Scan matching net pairs for (np1idx=0;np1idx1) { // Report multiple matches entryn++; sprintf(entryl[entryn],ERRPMULTI,pairid); entryn++; for (np2idx=0;np2idx0;t2idx--) netpdatl[np1idx].trcl[t2idx]= netpdatl[np1idx].trcl[t2idx-1]; netpdatl[np1idx].trcl[0]=scantrc; xs1=xs2; ys1=ys2; } else if (dist(xs1,ys1,xs2,ys2)0;t2idx--) netpdatl[np1idx].trcl[t2idx]= netpdatl[np1idx].trcl[t2idx-1]; xs1=xe2; ys1=ye2; p2l=scantrc.pl; // Swap point order for (p2idx=0;p2idx=0;i--) bae_storepoint( e2l[i].x,e2l[i].y,e2l[i].typ!=0 ? (3-e2l[i].typ) : 0); if (ged_storepoly(TRCDISPLAY,L_POLYDOCAREA,"",0)==0) { if (lay_lastfigelem(nfig)==0) rs_assfigstrpred(nfig, RS_GROUPNAME,TRCPAIRGNAME+itoa(curlayer+1),"",""); } else { // Write both trace point lists bae_clearpoints(); for (i=0;iidx2 // Parameters : // int idx1 : First compare index // int idx2 : Second compare index */ { int num1, num2 /* Tree numbers */; // Get the tree numbers num1=netpdatl[idx1].net.NUMBER; num2=netpdatl[idx2].net.NUMBER; // Check if same number if (num1==num2) return(0); // Return compare result return(num1>1; pidx=netidatl[sidx]; // Test if part found if (tree==netpdatl[pidx].net.NUMBER) // Pair net found return(pidx); // Update the search area if (tree=0 && (netpidx=findpnet(viatree))>=0) netpdatl[netpidx].viacnt++; // Stop scan return(0); // Pad case DDBCLLPAD : // Stop scan return(0); } // Continue scan return(1); } static int dppathfunc( index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Tree length scan path function // Return value : // zero if done or (-1) on error // Parameters : // index L_LINE path : Path index // int layer : Path transformed layer code // int pathinws : Path in workspace flag // index L_LEVEL level : Path level */ { index L_POINT p /* Path point */; struct ptdes pl[] /* Path point list */; int netpidx /* Net pair data list index */; int trctree /* Trace tree number */; int pn = 0 /* Point count */; int tidx /* Trace index */; // Get the trace tree number from level if ((trctree=lay_getlevtreenum(level))<0 || (netpidx=findpnet(trctree))<0) // Ignore trace return(0); // Update the trace length netpdatl[netpidx].trclen+=pathlen(path,0.0,0.0); tidx=netpdatl[netpidx].trcn; netpdatl[netpidx].trcl[tidx].layer=layer; netpdatl[netpidx].trcl[tidx].width=path.WIDTH; forall (p of path) { pl[pn].x=p.X; pl[pn].y=p.Y; pl[pn].typ=p.TYP; pn++; } netpdatl[netpidx].trcl[tidx].pl=pl; netpdatl[netpidx].trcl[tidx].xs=pl[0].x; netpdatl[netpidx].trcl[tidx].ys=pl[0].y; netpdatl[netpidx].trcl[tidx].xe=pl[pn-1].x; netpdatl[netpidx].trcl[tidx].ye=pl[pn-1].y; netpdatl[netpidx].trcl[tidx].pn=pn; netpdatl[netpidx].trcl[tidx].ps=1; netpdatl[netpidx].trcn++; // Return without errors return(0); } void serppoly(int pmode,int side,double x,double y,double dx,double dy, double off,double len,double ele,double crn,int crnmode,int scrn,int ecrn, double serpgain,double serprad) /* // Create serpentine polygon // Parameters : // int pmode : Point store mode // int side : Serpentine side // double x, y : Serpentine segment position // double dx, dy : Serpentine segment normalized direction // double off : Serpentine start position offset // double len : Serpentine step length // double ele : Serpentine elevation // double crn : Serpentine corner radius/length // int crnmode : Serpentine corner mode // int scrn : Serpentine start corner flag // int ecrn : Serpentine end corner flag // double serpgain : Serpentine length gain return // double serprad : Serpentine used corner radius/length return */ { double bx, by /* Base point */; double nx, ny /* Normal vector */; double du /* Upper corner orth. segment offset */; double dl /* Lower corner orth. segment offset */; double r /* Corner radius/length */; int ldir, rdir /* Direction corner types */; // Init. length gain serpgain=0.0; // Clear the serpentine point list if (pmode==0) bae_clearpoints(); // Get the normal vector if (side) { nx=dy; ny=-dx; ldir=2; rdir=1; } else { nx=-dy; ny=dx; ldir=1; rdir=2; } // Get first serpentine base point bx=x+dx*off; by=y+dy*off; // Check if start corner if (scrn) { // Adjust corner size to elevation if (crn*2.0>ele) r=0.5*ele; else r=crn; // Add corner points bae_storepoint(bx-dx*r,by-dy*r,0); if (crnmode) bae_storepoint(bx-dx*r+nx*r,by-dy*r+ny*r,ldir); bae_storepoint(bx+nx*r,by+ny*r,0); // Adjust length gain serpgain+=trcserpgain*r; // Set the lower corner offset dl=r; } else { // Adjust corner size to elevation if (crn>ele) r=ele; else r=crn; // Add corner point bae_storepoint(bx,by,0); // Set the lower corner offset dl=0.0; } // Get the upper corner offset du=ele-r; // Add side step orthogonal gain and corner gain serpgain+=du-dl+trcserpgain*r; // Store first upper corner points bae_storepoint(bx+nx*du,by+ny*du,0); if (crnmode) bae_storepoint(bx+nx*du+dx*r,by+ny*du+dy*r,rdir); bae_storepoint(bx+nx*ele+dx*r,by+ny*ele+dy*r,0); // Check if end corner if (ecrn) { // Adjust second corner size to elevation if (crn*2.0>ele) r=0.5*ele; else r=crn; // Set the lower corner offset dl=r; } else { // Adjust second corner size to elevation if (crn>ele) r=ele; else r=crn; // Set the lower corner offset dl=0.0; } // Get second serpentine base point bx+=dx*len; by+=dy*len; // Get the upper corner offset du=ele-r; // Add side step orthogonal gain and corner gain serpgain+=du-dl+trcserpgain*r; // Store first upper corner points bae_storepoint(bx+nx*ele-dx*r,by+ny*ele-dy*r,0); if (crnmode) bae_storepoint(bx+nx*du-dx*r,by+ny*du-dy*r,rdir); bae_storepoint(bx+nx*du,by+ny*du,0); if (ecrn) { // Add corner points bae_storepoint(bx+nx*r,by+ny*r,0); if (crnmode) bae_storepoint(bx+dx*r+nx*r,by+dy*r+ny*r,ldir); bae_storepoint(bx+dx*r,by+dy*r,0); // Adjust length gain serpgain+=trcserpgain*r; } else { // Add corner point bae_storepoint(bx,by,0); } serprad=r; } double treepathlen(int netmode,int treenum,int trccnt=0,int viacnt=0, double minrad=0.0,double maxrad=0.0,double minwidth=0.0,double maxwidth=0.0) /* // Get tree path length function // Return value : // trace path length of given tree // Parameters : // int netmode : Net query mode // int treenum : Path tree number // int trccnt=0 : Trace count // int viacnt=0 : Via count // double minrad=0.0 : Min. arc radius // double maxrad=0.0 : Max. arc radius // double minwidth=0.0 : Min. trace width // double maxwidth=0.0 : Max. trace width */ { index L_FIGURE fig /* Figure list index */; index L_FIGURE pfig /* Path figure list index */; index L_UREF uref /* Unnamed reference (via) index */; index L_LINE path /* Path index */; index L_POINT p /* Path point */; double r /* Path radius */; double pminrad /* Path minimum radius */; double pmaxrad /* Path maximum radius */; double trclen = 0.0 /* Trace path length */; int layer /* Path layer */; int i /* Loop control variable */; if (netmode>1) { forall (fig where fig.GROUP && fig.TYP==L_FIGPATH) { path=fig.LINE; // Update the trace length trclen+=pathlen(path,pminrad,pmaxrad); // Update path width extrema if (trccnt==0) { minwidth=maxwidth=path.WIDTH; } else { if (minwidth>path.WIDTH) minwidth=path.WIDTH; if (maxwidthmaxrad) maxrad=pmaxrad; // Increment the trace count trccnt++; } // Get the via count forall (fig where fig.GROUP && fig.TYP==L_FIGUREF) viacnt++; // Scan via stackup data if (bae_swconfig(0)==BAE_HighEnd) forall (fig where fig.GROUP && fig.TYP==L_FIGUREF) { px=fig.X; py=fig.Y; laysidx1=layscnt; laysidx2=(-1); forall (pfig where pfig.GROUP && pfig.TYP==L_FIGPATH) { path=pfig.LINE; layer=trclayer(path.LAYER); r=0.5*path.WIDTH; forall (p of path) { if (p.TYP) continue; if (dist(p.X,p.Y,px,py)<=r) { for (i=0;ilaysidx2) laysidx2=i; break; } break; } } } if (laysidx1!=layscnt && laysidx2!=(-1) && laysidx1!=laysidx2) { trclen+=laysl[laysidx1].iso; for (i=laysidx1+1;ipath.WIDTH) minwidth=path.WIDTH; if (maxwidthmaxrad) maxrad=pmaxrad; // Increment the trace count trccnt++; } // Get the via count forall (uref where uref.TREE==treenum) viacnt++; // Also scan part level traces/vias curnetnum=treenum; forall (fig where fig.TYP==L_FIGNREF) { trcscnt=viascnt=0; trcslen=trcminrad=trcmaxrad=0.0; // Scan path level vias/traces if (lay_scanfelem(fig,0.0,0.0,0.0,0,0, tlmacfunc,NULL,tlpathfunc,NULL,NULL,NULL,NULL)) error_scan(); // Update path width extrema if (trcscnt) { if (trccnt==0) { minwidth=trcminwidth; maxwidth=trcmaxwidth; } else{ if (minwidth>trcminwidth) minwidth=trcminwidth; if (maxwidthmaxrad) maxrad=trcmaxrad; } // Update counters trccnt+=trcscnt; viacnt+=viascnt; } // Scan via stackup data if (bae_swconfig(0)==BAE_HighEnd) { trcslen=0.0; if (lay_scanall(0.0,0.0,0.0,0,0, tlsmacfunc,NULL,NULL,NULL,NULL,NULL,NULL)) error_scan(); trclen+=trcslen; } } // Return the trace path length return(trclen); } static int tlmacfunc(index L_MACRO macro,index L_POOL pool, int macinws,string refname,index L_LEVEL level) /* // Tree length scan macro scan function // Return value : // (-1) on scan error, 0 on scan stop, 1 on scan continue // Parameters : // index L_MACRO macro : Macro index // index L_POOL pool : Macro pool element // int macinws : Macro in workspace flag // string refname : Macro reference name // index L_LEVEL level : Macro level */ { int viatree /* Via tree number */; // Check class switch (macro.CLASS) { // Part case DDBCLLPRT : break; // Padstack case DDBCLLSTK : // Check if pin if (refname!="") break; // Get the via tree number from level if ((viatree=lay_getlevtreenum(level))<0) // Invalid level tree viatree=(-1); if (viatree==curnetnum) viascnt++; // Stop scan return(0); // Pad case DDBCLLPAD : // Stop scan return(0); } // Continue scan return(1); } static int tlpathfunc( index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Tree length scan path function // Return value : // zero if done or (-1) on error // Parameters : // index L_LINE path : Path index // int layer : Path transformed layer code // int pathinws : Path in workspace flag // index L_LEVEL level : Path level */ { double pminrad /* Path min. arc radius */; double pmaxrad /* Path max. arc radius */; int trctree /* Trace tree number */; // Get the trace tree number from level if ((trctree=lay_getlevtreenum(level))<0) // Invalid level tree trctree=(-1); if (trctree==curnetnum) { // Update the trace length trcslen+=pathlen(path,pminrad,pmaxrad); // Update path width extrema if (trcscnt==0) { trcminwidth=trcmaxwidth=path.WIDTH; } else { if (trcminwidth>path.WIDTH) trcminwidth=path.WIDTH; if (trcmaxwidthtrcmaxrad) trcmaxrad=pmaxrad; // Increment the trace count trcscnt++; } // Return without errors return(0); } static int tlsmacfunc(index L_MACRO macro,index L_POOL pool, int macinws,string refname,index L_LEVEL level) /* // Tree length stackup scan macro scan function // Return value : // (-1) on scan error, 0 on scan stop, 1 on scan continue // Parameters : // index L_MACRO macro : Macro index // index L_POOL pool : Macro pool element // int macinws : Macro in workspace flag // string refname : Macro reference name // index L_LEVEL level : Macro level */ { double a /* Via macro rotation angle */; int m /* Via macro mirror flag */; int l /* Via macro layer number */; int viatree /* Via tree number */; int i /* Loop control variable */; // Check class switch (macro.CLASS) { // Part case DDBCLLPRT : break; // Padstack case DDBCLLSTK : // Check if pin if (refname!="") break; // Get the via tree number from level if ((viatree=lay_getlevtreenum(level))<0) // Invalid level tree viatree=(-1); if (viatree==curnetnum) { // Get via macro coordinates lay_maccoords(px,py,a,m,l); laysidx1=layscnt; laysidx2=(-1); if (lay_scanall(0.0,0.0,0.0,0,1, NULL,NULL,tlspathfunc,NULL,NULL,NULL,NULL)) error_scan(); if (laysidx1!=layscnt && laysidx2!=(-1) && laysidx1!=laysidx2) { trcslen+=laysl[laysidx1].iso; for (i=laysidx1+1;ilaysidx2) laysidx2=i; break; } break; } } } // Return without errors return(0); } double pathlen(index L_LINE path,double minrad=0.0,double maxrad=0.0) /* // Get path length function // Return value : // trace path length of given path // Parameters : // int path : Path index // double minrad=0.0 : Min. arc radius // double maxrad=0.0 : Max. arc radius */ { index L_POINT p /* Point index */; double trclen = 0.0 /* Trace path length */; double arcrad /* Arc radius */; int arcflag = 0 /* Arc found flag */; int pc /* Path point count */; double x1,y1 /* Previous coordinates */; int t1 /* Previous point type */; double x2,y2 /* Pre-previous coordinates */; int t2 /* Pre-previous point type */; int sc = 0 /* Segment count */; // Init the path point count pc=0; // Loop for all path points forall (p of path) { // Increment the point counter pc++; // Check if arc segment if (p.TYP!=0) { // Get the arc radius arcrad=dist(p.X,p.Y,x1,y1); // Update min./max. values if (arcflag) { if (arcradmaxrad) maxrad=arcrad; } else { minrad=maxrad=arcrad; arcflag=1; } } // Get the segment length; update the trace length trclen+= segmentlen(pc,p.TYP,p.X,p.Y,t1,x1,y1,t2,x2,y2,sc); } // Return the trace path length return(trclen); } void zoomtonet(index L_CNET net,int laydisp) /* // Zoom to a signal specified by net number // Parameters : // index L_CNET net : Net index // int laydisp : Layer display flag */ { #define WEL 0.001 // Window enlarge length index L_LINE path /* Net trace path index */; index L_POINT point /* Point index */; int netnum = net.NUMBER /* Net number */; double lx,ly,ux,uy /* Trace boundaries */; int rangedis /* Range check disabled flag */; int layidx /* Layer index */; int layused[] /* Layer used flags */; for (layidx=0;layidxlx) zoomlx=lx; if (zoomuxly) zoomly=ly; if (zoomuyzoomux || zoomly-WEL>zoomuy) return; for (layidx=0;layidxx) zoomlx=x; if (zoomuxy) zoomly=y; if (zoomuypoint.X) zoomlx=point.X; if (zoomuxpoint.Y) zoomly=point.Y; if (zoomuy1 && n.UNRPOOL>=0) { // Init the unroutes counter and length curcnt=0; curalen=curhlen=curvlen=0.0; // Scan the unroutes pool if (lay_scanpool(n.UNRPOOL,0.0,0.0,0.0,0,1, NULL,NULL,pathfunc,NULL,NULL,layunrchk,NULL)) error_scan(); // Update the total unroutes counter and length turcnt+=curcnt; turalen+=curalen; turhlen+=curhlen; turvlen+=curvlen; } // Print the result sprintf(headl[0],REPUNRHD1,bae_planfname(),bae_planename()); sprintf(headl[2],REPUNRHD2); headl[3]=" "; sprintf(headl[4],REPUNRCNT,turcnt); sprintf(headl[5],REPUNRALL,frctdigs,baecvtl(turalen),UNITDES); sprintf(headl[6],REPUNRHV,frctdigs,baecvtl(turhlen+turvlen),UNITDES); sprintf(headl[7],REPUNRH,frctdigs,baecvtl(turhlen),UNITDES); sprintf(headl[8],REPUNRV,frctdigs,baecvtl(turvlen),UNITDES); headn=9; if (turcnt) { entryl[0]=UPRUNRLIST; entryn=1; } else { entryn=0; } // Activate the popup menu bae_setintpar(16,3072); if ((uinput=popupmenu(5,"",headl,headn,entryl,entryn, UINPOPABORT,0,0,1,headn+entryn+2,100,0,""))=="" || uinput==UINPOPABORT) return; // Report the directory list header headl[0]=REPUNRLIST; headn=1; // Loop thru the list of nets with unroutes pool links entryn=0; forall (n where n.PINN>1 && n.UNRPOOL>=0) { curnetname=n.NAME; curnetnum=n.NUMBER; // Scan the unroutes pool if (lay_scanpool(n.UNRPOOL,0.0,0.0,0.0,0,1, NULL,NULL,unrfunc,NULL,NULL,NULL,NULL)) error_scan(); } entryl[unrn]=""; for (i=0;i=0) ged_highlnet(treenum,0); break; } // Search selected error for (i=0;i1) { // De-highlight previously sel. tree if (treenum>=0) ged_highlnet(treenum,0); // Highl. the tree if ((treenum=unrl[i].netnum)>=0) ged_highlnet(treenum,1); } // Disable range check bae_getintpar(0,rangedis); bae_setintpar(0,1); // Zoom to error boundaries bae_clriactqueue(); xs=unrl[i].x1; ys=unrl[i].y1; xe=unrl[i].x2; ye=unrl[i].y2; if (xs==xe) { xs-=0.0001; xe+=0.0001; } if (ys==ye) { ys-=0.0001; ye+=0.0001; } bae_storemouseiact(1,xs,ys,0,LMB); bae_storemouseiact(1,xe,ye,0,LMB); call(MNU_BAEZOOMWND); // Restore old range check state bae_setintpar(0,rangedis); if (entryn==1) { bae_prtdialog(""); exit(0); } // Prompt for key press sprintf(uinput,REPUNRDISP,i+1, unrl[i].netname); bae_prtdialog(uinput); // Check if abort if ((c=getchr())==0x1b) { // De-highlight previously sel. tree if (treenum>=0) ged_highlnet(treenum,0); error_abort(); } // Check if next error request else if (c=='+') { i++; if (i>=entryn) i=0; } // Check if previous error request else if (c=='-') { i--; if (i<0) i=entryn-1; } else { break; } } break; } } error_abort(); } int pathfunc(index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Path scan function // Return value : // zero if done, or (-1) on error // Parameters : // index L_LINE path : Path index // int layer : Path transformed layer code // int pathinws : Path in workspace flag // index L_LEVEL level : Path level */ { index L_POINT p /* Point index */; double x1 = 0 /* Previous point X coordinate */; double y1 = 0 /* Previous point Y coordinate */; // Increment the current unroutes count curcnt++; // Loop thru the point list forall (p of path) { // Test the point index if (p>0) { // Get the segment length; update the result value curalen+=dist(p.X,p.Y,x1,y1); curhlen+=fabs(p.X-x1); curvlen+=fabs(p.Y-y1); } // Move current to previous point x1=p.X; y1=p.Y; } // Return without errors return(0); } int unrfunc(index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Unroute scan function // Return value : // zero if done, or (-1) on error // Parameters : // index L_LINE path : Path index // int layer : Path transformed layer code // int pathinws : Path in workspace flag // index L_LEVEL level : Path level */ { index L_POINT p /* Point index */; double x1 = 0 /* Previous point X coordinate */; double y1 = 0 /* Previous point Y coordinate */; // Loop thru the point list forall (p of path) { // Test the point index if (p>0) { unrl[unrn].x1=x1; unrl[unrn].y1=y1; unrl[unrn].x2=p.X; unrl[unrn].y2=p.Y; unrl[unrn].netname=curnetname; unrl[unrn].netnum=curnetnum; unrn++; break; } // Move current to previous point x1=p.X; y1=p.Y; } // Return without errors return(0); } int layunrchk(int layer) /* // Layer check scan function // Return value : // 1 if inside workspace, or zero otherwise // Parameters : // int layer : Layer number */ { // Test the layer; return the inside workspace flag return(layer==(-4)?1:0); } /*________________________________________________________________*/ // Parallel traces generation void trcparal() /* // Generate parallel traces */ { // Select parallel mode bae_defmenusel(-1); bae_promptdialog(UPRPFCT); switch (bae_askmenu(6, UPRPFCT1,UPRPFCT2,UPRPFCT3,UPRPFCT4,UPRPFCT5,UPRABORT)) { case 0 : trcparalequ(); break; case 1 : trcparalalt(); break; case 2 : trcpattern(); break; case 3 : trc2diffpair(); break; case 4 : trclaypair(); break; // Abort on default default : error_abort(); } } void trcparalequ() /* // Generate equidistant parallel traces */ { index L_FIGURE fig /* Figure list index */; index L_LINE path /* Trace index */; index L_POINT point /* Point index */; double xp, yp /* Pick point */; double spc /* Spacing */; double d /* Distance */; int tcnt /* Trace count */; int cmode /* Trace corner mode */; int first /* Picked trace start flag */; int side /* Trace side */; int repflag /* Dialog box repeat flag */; int res /* Dialog box selection result */; int cunits /* Coordinate display units */; double pcol = 25.0 /* Parameter column */; double cy /* Dialog box current y coordinate */; int spcidx = (-1) /* Spacing dialog box item idx. */; int cntidx = (-1) /* Count dialog box item idx. */; int cmidx = (-1) /* Corner mode dialog box item idx. */; int gridlock /* Grid lock flag */; int i /* Loop control variables */; // Query last data if (varget(GV_TRCPARSPC,spc)) if (bae_getgridlock()) bae_getinpgrid(spc,0.0); else lay_getplanchkparam(spc,0.0,0.0,0,"",-1,0); if (varget(GV_TRCPARCNT,tcnt)) tcnt=1; if (varget(GV_TRCRNDCRN,cmode)) cmode=1; // Check if dialog box support if (bae_dialclr()) { // Get parallel spacing if (askdist(spc,lay_defusrunit()?UPRPARTDI:UPRPARTDM,0) || spc==0.0) // Invalid input value error(ERRINPVAL); // Get parallel trace count if (askint(tcnt,UPRTRCCNT,5) || tcnt<1) // Invalid input value error(ERRINPVAL); // Get trace corner mode if ((cmode=bae_askmenu(3, UPRNRNDCORNER,UPRRNDCORNER,UPRABORT))<0 || cmode>1) error_abort(); } else { cy=DIAL_TOPMARG; // Store trace spacing controls dial_label(0.0,cy,UPRPARTD); spcidx=dial_dist(5,spc,pcol,cy); // Store trace count controls dial_label(0.0,cy,UPRTRCCNTD); cntidx=bae_dialaddcontrol(PA_INT|PA_CHKLL|PA_HBRDREL, 0,0,tcnt,0.0,0.0,0.0,"",30, DIAL_LEFTMARG+pcol,cy,DIAL_RIGHTEMARG,""); cy+=DIAL_CTRVSTEP; cmidx=dial_toggle(cmode,pcol,cy,UPRRNDCORNER); // Store the OK and abort button with seperator dial_hsep(cy); dial_okabort(cy); // Store coordinate unit controls cunits= bae_getcoorddisp() ? 2 : 0; bae_dialaddcontrol(PA_RBF,0,1,cunits,0.0,0.0,0.0, "",0,DIAL_LEFTMARG+pcol,cy-DIAL_BUTVSTEP-DIAL_SEPVSTEP,0.0, UPRDUNITMM); bae_dialaddcontrol(PA_RBN,2,2,0,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol+6.0,cy-DIAL_BUTVSTEP-DIAL_SEPVSTEP,0.0, UPRDUNITMIL); // Perform the dialog input loop repflag=1; do { // Display dialog box bae_setintpar(16,3024); switch (res=bae_dialaskparams(UPRTRCPAR, cunits,DIAL_LEFTMARG+pcol+13.0+DIAL_RIGHTSMARG,cy)) { // Done case 0 : bae_dialgetdata(spcidx,0,spc,""); bae_dialgetdata(cntidx,tcnt,0.0,""); bae_dialgetdata(cmidx,cmode,0.0,""); repflag=0; break; // Switch to mm units case 1 : cunits=0; break; // Switch to mil units case 2 : cunits=2; break; default : error_abort(); } // Stop if no further repeat requests } while (repflag); } // Store settings for next call varset(GV_TRCPARSPC,spc); varset(GV_TRCPARCNT,tcnt); varset(GV_TRCRNDCRN,cmode); // Free grid lock gridlock=bae_getgridlock(); bae_setgridlock(0); // Get the pick position bae_promptdialog(UPRSELPTRC); if (bae_inpoint(wsnx,wsny,xp,yp,0)) { // Restore grid lock bae_setgridlock(gridlock); error_abort(); } // Restore grid lock bae_setgridlock(gridlock); // Pick path bae_clriactqueue(); bae_storemouseiact(1,xp,yp,0,LMB); if (ged_pickelem(fig,L_FIGPATH)!=0) // No pick element found error(ERRNOPICK); // Select trace side bae_promptdialog(UPRTRCSID); if ((side=bae_askmenu(3,UPRTRCSID1,UPRTRCSID2,UPRABORT))<0 || side>1) error_abort(); // Loop for all path points path=fig.LINE; pointn=0; forall (point of path) { // Ignore double points if (pointn && point.X==pointl[pointn-1].x && point.Y==pointl[pointn-1].y && point.TYP==pointl[pointn-1].typ) continue; // Store current point pointl[pointn].x=point.X; pointl[pointn].y=point.Y; pointl[pointn].typ=point.TYP; pointn++; } // Check trace pick orientation first=((pointl[0].x-xp)*(pointl[0].x-xp)+ (pointl[0].y-yp)*(pointl[0].y-yp))< ((pointl[pointn-1].x-xp)*(pointl[pointn-1].x-xp)+ (pointl[pointn-1].y-yp)*(pointl[pointn-1].y-yp)) ? 1 : 0 ; // Check if direction swap required if ((first==1 && side==0) || (first==0 && side==1)) { i=pointn; forall (point of path) { // Ignore double points if (i!=pointn && point.X==pointl[i].x && point.Y==pointl[i].y && point.TYP==pointl[i].typ) continue; i--; pointl[i].x=point.X; pointl[i].y=point.Y; pointl[i].typ=point.TYP==0 ? 0 : 3-point.TYP ; } } // Check if processable path if (pointn<2) // Don't process error_abort(); // Save current state for undo bae_callmenu(MNU_BAESAVESTATE); // Loop for all parallel traces for (i=0,d=spc;i=npn-4) break; // Skip arc centers if (npl[i+4].typ!=0) continue; // Set next segment start nidx=i+3; } else { // Set next segment start nidx=i+2; } // Check if segments cross if (bae_crosssegseg(0, npl[i].x,npl[i].y,npl[i+1].x,npl[i+1].y, npl[nidx].x,npl[nidx].y, npl[nidx+1].x,npl[nidx+1].y,ex,ey)) { // Store the cross point npl[i+1].x=ex; npl[i+1].y=ey; // Delete cross segment points for (i+=2,nidx++;nidxTRCPARENDDIST) { // Store first point with offset if (bae_storepoint( lx+TRCPARENDDIST*(cx-lx)/d, ly+TRCPARENDDIST*(cy-ly)/d,ltyp)) return(-1); // Adjust new path count pcnt++; } } else if (lcnt>1) { // Store last point if (bae_storepoint(lx,ly,ltyp)) return(-1); // Adjust new path count pcnt++; } // Increment source path count lcnt++; // Check if last point if (lcntTRCPARENDDIST) { // Store last point with offset if (bae_storepoint( cx+TRCPARENDDIST*(lx-cx)/d, cy+TRCPARENDDIST*(ly-cy)/d,ctyp)) return(-1); // Adjust new path count pcnt++; } // Return without errors return(0); } void trcpattern() /* // Continue trace pattern */ { index L_FIGURE fig1, fig2 /* Figure list indeces */; index L_LINE path /* Trace index */; index L_POINT point /* Point index */; struct pointdes tpl1[] /* First trace point list */; int tpn1 = 0 /* First point count */; struct pointdes tpl2[] /* Second trace point list */; int tpn2 = 0 /* Second point count */; int tcnt /* Trace count */; int i, j /* Loop control variables */; if (varget(GV_TRCPATCNT,tcnt)) tcnt=1; // Get parallel trace count if (askint(tcnt,UPRPTRCCNT,5) || tcnt<1) // Invalid input value error(ERRINPVAL); varset(GV_TRCPATCNT,tcnt); // Pick first path bae_promptdialog(UPRSELPTRC1); if (ged_pickelem(fig1,L_FIGPATH)!=0) // No pick element found error(ERRNOPICK); // Pick second path bae_promptdialog(UPRSELPTRC2); if (ged_pickelem(fig2,L_FIGPATH)!=0) // No pick element found error(ERRNOPICK); // Check trace layers if (fig1.LAYER!=fig2.LAYER) error(ERRTRCPLAY); // Check trace sizes if (fig1.SIZE!=fig2.SIZE) error(ERRTRCPSIZ); // Get first path points path=fig1.LINE; tpn1=0; forall (point of path) { // Ignore double points if (tpn1 && point.X==tpl1[tpn1-1].x && point.Y==tpl1[tpn1-1].y && point.TYP==tpl1[tpn1-1].typ) continue; // Store current point tpl1[tpn1].x=point.X; tpl1[tpn1].y=point.Y; tpl1[tpn1].typ=point.TYP; tpn1++; } // Get second path points path=fig2.LINE; tpn2=0; forall (point of path) { // Ignore double points if (tpn2 && point.X==tpl2[tpn2-1].x && point.Y==tpl2[tpn2-1].y && point.TYP==tpl2[tpn2-1].typ) continue; // Store current point tpl2[tpn2].x=point.X; tpl2[tpn2].y=point.Y; tpl2[tpn2].typ=point.TYP; tpn2++; } // Check point counts if (tpn1!=tpn2) error(ERRTRCPCNT); // Check trace pick orientation if ( ((tpl1[0].x-tpl2[0].x)*(tpl1[0].x-tpl2[0].x)+ (tpl1[0].y-tpl2[0].y)*(tpl1[0].y-tpl2[0].y))> ((tpl1[0].x-tpl2[tpn2-1].x)*(tpl1[0].x-tpl2[tpn2-1].x)+ (tpl1[0].y-tpl2[tpn2-1].y)*(tpl1[0].y-tpl2[tpn2-1].y))) { i=tpn2; forall (point of path) { // Ignore double points if (i!=tpn2 && point.X==tpl2[i].x && point.Y==tpl2[i].y && point.TYP==tpl2[i].typ) continue; i--; tpl2[i].x=point.X; tpl2[i].y=point.Y; tpl2[i].typ=point.TYP==0 ? 0 : 3-point.TYP ; } } for (i=0;i1) error_abort(); } else { cy=DIAL_TOPMARG; // Store trace spacing controls dial_label(0.0,cy,UPRPARTD); spcidx=dial_dist(5,spc,pcol,cy); cmidx=dial_toggle(cmode,pcol,cy,UPRRNDCORNER); // Store the OK and abort button with seperator dial_hsep(cy); dial_okabort(cy); // Store coordinate unit controls cunits= bae_getcoorddisp() ? 2 : 0; bae_dialaddcontrol(PA_RBF,0,1,cunits,0.0,0.0,0.0, "",0,DIAL_LEFTMARG+pcol,cy-DIAL_BUTVSTEP-DIAL_SEPVSTEP,0.0, UPRDUNITMM); bae_dialaddcontrol(PA_RBN,2,2,0,0.0,0.0,0.0,"",0, DIAL_LEFTMARG+pcol+6.0,cy-DIAL_BUTVSTEP-DIAL_SEPVSTEP,0.0, UPRDUNITMIL); // Perform the dialog input loop repflag=1; do { // Display dialog box bae_setintpar(16,3093); switch (res=bae_dialaskparams(UPRTRCPAR, cunits,DIAL_LEFTMARG+pcol+13.0+DIAL_RIGHTSMARG,cy)) { // Done case 0 : bae_dialgetdata(spcidx,0,spc,""); bae_dialgetdata(cmidx,cmode,0.0,""); repflag=0; break; // Switch to mm units case 1 : cunits=0; break; // Switch to mil units case 2 : cunits=2; break; default : error_abort(); } // Stop if no further repeat requests } while (repflag); } // Store settings for next call varset(GV_TRCPARSPC,spc); varset(GV_TRCRNDCRN,cmode); // Perform input loop if (pickfullpath(UPRSELTRC,1)) error(ERRNOPICK); // Save current state for undo bae_callmenu(MNU_BAESAVESTATE); do { // Scan trace elements for (pidx=0;pidx=SIGLAYMAX) { sprintf(msg,ERRINVSLAY,lay1+1); error(msg); } // Scan for layer seperator for (sidx++;sidx=SIGLAYMAX) { sprintf(msg,ERRINVSLAY,lay2+1); error(msg); } if (tlayl[lay1]!=(-1) && tlayl[lay1]!=lay2) { sprintf(msg,ERRDBLSLAY,lay1+1, tlayl[lay1]+1,lay2+1); error(msg); } if (tlayl[lay2]!=(-1) && tlayl[lay2]!=lay1) { sprintf(msg,ERRDBLSLAY,lay2+1, tlayl[lay2]+1,lay1+1); error(msg); } // Store layer assignment tlayl[lay1]=lay2; tlayl[lay2]=lay1; lasscnt++; break; } } } } // Check if layer assignment(s) found if (lasscnt==0) error(ERRNOLAYASS); // Get group process mode mode forall (fig where fig.GROUP && fig.TYP==L_FIGPATH) { if ((grpmode=bae_askmenu(3, UPRTRCSING,UPRTRCGRP,UPRABORT))<0 || grpmode>1) error_abort(); break; } // Repetitively process traces while (1) { // Check if group element scan if (grpmode) { pidx=(-1); forall (fig where fig.GROUP && fig.TYP==L_FIGPATH) { pidx=0; break; } if (pidx<0) { screenredraw(); return; } } else { // Pick any path element bae_prtdialog(UPRSELTRC); if (ged_pickelem(fig,L_FIGPATH)) error(ERRNOPICK); } // Save current state for undo if (cflag==0) { bae_callmenu(MNU_BAESAVESTATE); cflag=1; } scanfullpath(fig,grpmode); trcabort=0; // Scan via data, check trace layers for (pidx=0;pidx=vmacn) { // Query the replacement padstacks if (lay_rulequery(RS_OCPOOL,mac,RS_PCBSUBJ, RS_PAIRSTK1,"?s",stk1)<1 || stk1=="") { if (grpmode) { trcabort=1; break; } else { errormsg(ERRNORPSTK,mac.NAME); } } if (lay_rulequery(RS_OCPOOL,mac,RS_PCBSUBJ, RS_PAIRSTK2,"?s",stk2)<1 || stk2=="") { if (grpmode) { trcabort=1; break; } else { errormsg(ERRNORPSTK,mac.NAME); } } // Add new via type vmacl[vmacn].stk1=stk1; vmacl[vmacn].stk2=stk2; vmacn++; } // Store via type reference pel[pidx].vmidx=vmidx; } else { // Check if layer assignment known lay1=trclayer(fig.LAYER); if (lay1<0 || lay1>SIGLAYMAX || tlayl[lay1]<0) { if (grpmode) { trcabort=1; break; } else { sprintf(msg,ERRNOSLAYASS,lay1+1); error(msg); } } } } if (trcabort) continue; // Scan own trace replacement path for (pidx=0;pidx=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); } continue; } // Get trace point list pointn=pel[pidx].pn; pointl=pel[pidx].pl; ppidx=pidx-1; bae_clearpoints(); // Check if first point if (ppidx<1 || pel[ppidx].fig.TYP!=L_FIGUREF) { // No via connection, store unchanged if (bae_storepoint( pointl[0].x,pointl[0].y,pointl[0].typ)) error(ERRPATH); } else { // Get the segment neighbour relation data ppidx--; x=pointl[0].x; y=pointl[0].y; // Get the start segment vector sx1=pointl[1].x-x; sy1=pointl[1].y-y; normvect(sx1,sy1,sl1); an=pel[ppidx].pn; // Get the end segment vector sx2=pel[ppidx].pl[an-2].x-x; sy2=pel[ppidx].pl[an-2].y-y; normvect(sx2,sy2,sl2); // Check the angle direction ang=fabs(fmod(atan2(sy2,sx2)+2.0*PI,2.0*PI)- fmod(atan2(sy1,sx1)+2.0*PI,2.0*PI)); if (fabs(ang)<=SMALLANG || fabs(ang-PI)<=SMALLANG) { if (bae_storepoint( x+grid*4.0*sy1,y-grid*4.0*sx1,0)) error(ERRPATH); // Check if small segments involved if (sl1<3.0*grid || sl2<3.0*grid) { // Create small diagonal if (bae_storepoint( x+grid*sy1,y-grid*sx1,0) || bae_storepoint( x+grid*sx1,y+grid*sy1,0)) error(ERRPATH); } else { // Create wide diagonal if (bae_storepoint( x+grid*4.0*sx1,y+grid*4.0*sy1,0)) error(ERRPATH); } } else { // Store via entry if (bae_storepoint(x+grid*(-4.0*sx1+2.0*sx2), y+grid*(-4.0*sy1+2.0*sy2),0) || bae_storepoint(x+grid*(-3.0*sx1+sx2), y+grid*(-3.0*sy1+sy2),0) || bae_storepoint(x+grid*(4.0*sx1+sx2), y+grid*(4.0*sy1+sy2),0) || bae_storepoint(x+grid*5.0*sx1, y+grid*5.0*sy1,0)) error(ERRPATH); } } // Store unchanged intermediate points for (i=1;i<(pointn-1);i++) if (bae_storepoint( pointl[i].x,pointl[i].y,pointl[i].typ)) error(ERRPATH); npidx=pidx+1; // Check if last point if (npidx>=(pen-1) || pel[npidx].fig.TYP!=L_FIGUREF) { // No via connection, store unchanged if (bae_storepoint( pointl[pointn-1].x,pointl[pointn-1].y, pointl[pointn-1].typ)) error(ERRPATH); } else { // Get the segment neighbour relation data npidx++; x=pointl[pointn-1].x; y=pointl[pointn-1].y; // Get the end segment vector sx1=pointl[pointn-2].x-x; sy1=pointl[pointn-2].y-y; normvect(sx1,sy1,sl1); // Get the end segment vector sx2=pel[npidx].pl[1].x-x; sy2=pel[npidx].pl[1].y-y; normvect(sx2,sy2,sl2); // Check the angle direction ang=fabs(fmod(atan2(sy2,sx2)+2.0*PI,2.0*PI)- fmod(atan2(sy1,sx1)+2.0*PI,2.0*PI)); if (fabs(ang)<=SMALLANG || fabs(ang-PI)<=SMALLANG) { vx=x+grid*4.0*sy2; vy=y-grid*4.0*sx2; // Check if small segments involved if (sl1<3.0*grid || sl2<3.0*grid) { // Create small diagonal if (bae_storepoint( x+grid*sx1,y+grid*sy1,0) || bae_storepoint( x+grid*sy2,y-grid*sx2,0)) error(ERRPATH); } else { // Create wide diagonal if (bae_storepoint( x+grid*4.0*sx1,y+grid*4.0*sy1,0)) error(ERRPATH); } if (bae_storepoint(vx,vy,0)) error(ERRPATH); } else { // Store via entry vx=x+grid*(2.0*sx1-4.0*sx2); vy=y+grid*(2.0*sy1-4.0*sy2); if (bae_storepoint(x+grid*(5.0*sx1), y+grid*(5.0*sy1),0) || bae_storepoint(x+grid*(4.0*sx1+sx2), y+grid*(4.0*sy1+sy2),0) || bae_storepoint(x+grid*(3.0*sx1+sx2), y+grid*(3.0*sy1+sy2),0) || bae_storepoint(x+grid*(2.0*sx1), y+grid*(2.0*sy1),0) || bae_storepoint(vx,vy,0)) error(ERRPATH); } } // Store trace if (ged_storepath(fig.LAYER,fig.SIZE)) error(ERRPATH); // Check if element should be fixed if (fig.FIXED && lay_lastfigelem(nfig)==0) ged_elemfixchg(nfig,fig.FIXED); // Transfer rules if (fig.RULEOBJID>=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); } // Scan alternate trace replacement path for (pidx=pen-1;pidx>=0;pidx--) { fig=pel[pidx].fig; if (fig.TYP==L_FIGUREF) { if (pidx!=(pen-1)) { stk2=vmacl[pel[pidx].vmidx].stk2; if (ged_storeuref(stk2,vx,vy,0.0,0,0)) errormsg(ERRPLCVIA,stk2); // Check if element should be fixed if (fig.FIXED && lay_lastfigelem(nfig)==0) ged_elemfixchg(nfig,fig.FIXED); // Transfer rules if (fig.RULEOBJID>=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); } continue; } // Get trace point list pointn=pel[pidx].pn; pointl=pel[pidx].pl; ppidx=pidx+1; bae_clearpoints(); // Check if last point if (ppidx>=(pen-1) || pel[ppidx].fig.TYP!=L_FIGUREF) { // No via connection, store unchanged if (bae_storepoint( pointl[pointn-1].x,pointl[pointn-1].y, pointl[pointn-1].typ)) error(ERRPATH); } else { // Get the segment neighbour relation data ppidx++; x=pointl[pointn-1].x; y=pointl[pointn-1].y; // Get the end segment vector sx1=pointl[pointn-2].x-x; sy1=pointl[pointn-2].y-y; normvect(sx1,sy1,sl1); // Get the end segment vector sx2=pel[ppidx].pl[1].x-x; sy2=pel[ppidx].pl[1].y-y; normvect(sx2,sy2,sl2); // Check the angle direction ang=fabs(fmod(atan2(sy2,sx2)+2.0*PI,2.0*PI)- fmod(atan2(sy1,sx1)+2.0*PI,2.0*PI)); if (fabs(ang)<=SMALLANG || fabs(ang-PI)<=SMALLANG) { if (bae_storepoint( x-grid*4.0*sy2,y+grid*4.0*sx2,0)) error(ERRPATH); // Check if small segments involved if (sl1<5.0*grid || sl2<5.0*grid) { // Create small diagonal if (bae_storepoint( x-grid*sy2,y+grid*sx2,0) || bae_storepoint( x+grid*sx1,y+grid*sy1,0)) error(ERRPATH); } else { // Create wide diagonal if (bae_storepoint( x+grid*4.0*sx1,y+grid*4.0*sy1,0)) error(ERRPATH); } } else { // Store via entry if (bae_storepoint(x+grid*(-4.0*sx1+2.0*sx2), y+grid*(-4.0*sy1+2.0*sy2),0) || bae_storepoint(x+grid*(-3.0*sx1+sx2), y+grid*(-3.0*sy1+sy2),0) || bae_storepoint(x+grid*(4.0*sx1+sx2), y+grid*(4.0*sy1+sy2),0) || bae_storepoint(x+grid*5.0*sx1, y+grid*5.0*sy1,0)) error(ERRPATH); } } // Store unchanged intermediate points for (i=pointn-2;i>0;i--) if (bae_storepoint( pointl[i].x,pointl[i].y,pointl[i].typ)) error(ERRPATH); // Check if first point npidx=pidx-1; if (npidx<1 || pel[npidx].fig.TYP!=L_FIGUREF) { // No via connection, store unchanged if (bae_storepoint( pointl[0].x,pointl[0].y,pointl[0].typ)) error(ERRPATH); } else { // Get the segment neighbour relation data npidx--; x=pointl[0].x; y=pointl[0].y; // Get the start segment vector sx1=pointl[1].x-x; sy1=pointl[1].y-y; normvect(sx1,sy1,sl1); an=pel[npidx].pn; // Get the end segment vector sx2=pel[npidx].pl[an-2].x-x; sy2=pel[npidx].pl[an-2].y-y; normvect(sx2,sy2,sl2); // Check the angle direction ang=fabs(fmod(atan2(sy2,sx2)+2.0*PI,2.0*PI)- fmod(atan2(sy1,sx1)+2.0*PI,2.0*PI)); if (fabs(ang)<=SMALLANG || fabs(ang-PI)<=SMALLANG) { // Check if small segments involved if (sl1<5.0*grid || sl2<5.0*grid) { if (bae_storepoint( x+grid*sx1,y+grid*sy1,0) || bae_storepoint( x-grid*sy1,y+grid*sx1,0)) error(ERRPATH); } else { // Create wide diagonal if (bae_storepoint( x+grid*4.0*sx1,y+grid*4.0*sy1,0)) error(ERRPATH); } vx=x-grid*4.0*sy1; vy=y+grid*4.0*sx1; if (bae_storepoint(vx,vy,0)) error(ERRPATH); } else { // Store via entry vx=x+grid*(2.0*sx1-4.0*sx2); vy=y+grid*(2.0*sy1-4.0*sy2); if (bae_storepoint(x+grid*(5.0*sx1), y+grid*(5.0*sy1),0) || bae_storepoint(x+grid*(4.0*sx1+sx2), y+grid*(4.0*sy1+sy2),0) || bae_storepoint(x+grid*(3.0*sx1+sx2), y+grid*(3.0*sy1+sy2),0) || bae_storepoint(x+grid*(2.0*sx1), y+grid*(2.0*sy1),0) || bae_storepoint(vx,vy,0)) error(ERRPATH); } } // Store trace if (ged_storepath( tlayl[trclayer(fig.LAYER)],fig.SIZE)) error(ERRPATH); // Check if element should be fixed if (fig.FIXED && lay_lastfigelem(nfig)==0) ged_elemfixchg(nfig,fig.FIXED); // Transfer rules if (fig.RULEOBJID>=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); } // Delete old trace elements for (pidx=0;pidx1) { // Store new path if (ged_storepath(fig.LAYER,fig.SIZE)) error(ERRPATH); // Check if path should be fixed if (fig.FIXED && lay_lastfigelem(nfig)==0) ged_elemfixchg(nfig,fig.FIXED); // Transfer rules if (fig.RULEOBJID>=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); } // Delete old path dfig=fig; if (ged_delelem(dfig)) error(ERRDELTRC); } // Done bae_prtdialog(REPDONE); // Screen redraw screenredraw(); } int trccutpathfunc(index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Path scan function // Return value : // 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 */ { int lcnt /* Path point count */; double lx = 0 /* Last X coordinate */; double ly = 0 /* Last Y coordinate */; int ltyp = 0 /* Last point type */; double cx,cy /* Current coordinates */; int ctyp /* Current point type */; int didx /* Drill list index */; double drillrad = 0 /* Drill radius */; double d /* Path point distance */; index L_POINT point /* Point index */; // Reset the path point count lcnt=0; // Loop for all path points forall (point of path) { // Get current coordinates cx=point.X; cy=point.Y; ctyp=point.TYP; // First segment ? if (lcnt==1 && drillrad!=0.0) { // Get first segment length d=sqrt((lx-cx)*(lx-cx)+(ly-cy)*(ly-cy)); // Length greater max. delete length ? if (d>drillrad) { // Store first point with offset if (bae_storepoint( lx+drillrad*(cx-lx)/d, ly+drillrad*(cy-ly)/d,ltyp)) return(-1); // Adjust new path count pcnt++; } } else if (lcnt>0) { // Store last point if (bae_storepoint(lx,ly,ltyp)) return(-1); // Adjust new path count pcnt++; } else { // Check if drill near first path point if ((didx=finddrill(cx,cy))!=(-1)) drillrad=drilll[didx].rad+path.WIDTH/2.0; else drillrad=0.0; } // Increment source path count lcnt++; // Check if last point if (lcntdrillrad) { // Store last point with offset if (bae_storepoint( cx+drillrad*(lx-cx)/d,cy+drillrad*(ly-cy)/d,ctyp)) return(-1); // Adjust new path count pcnt++; } // Return without errors return(0); } int trccutdrillfunc(index L_DRILL drill, double x,double y,int drillinws,int tree,index L_LEVEL level) /* // Insert drill sorted to drill list // Return value : // zero if done or (-1) on file error // Parameters : // index L_DRILL drill : Drill data block // double x : Drill X coordinate // double y : Drill Y coordinate // int drillinws : Drill in workspace flag // int tree : Drill tree number // index L_LEVEL level : Drill level */ { int inspos /* Drill list insert position */; int i /* Loop control variable */; // Find drill list insert position inspos=findinsdrill(x,y); // Move drills for (i=drilln;i>inspos;i--) drilll[i]=drilll[i-1]; // Store new drill data drilll[inspos].x=x; drilll[inspos].y=y; drilll[inspos].rad=drill.RAD; drilln++; // Adjust max. radius if (drill.RAD>drlmaxrad) drlmaxrad=drill.RAD; // Return without errors return(0); } int findinsdrill(double x,double y) /* // Search insertion point in coordinate sorted drill list // Return value : // drill list insertion point // Parameters : // double x : Drill X coordinate // double y : Drill Y coordinate */ { int slb = 0 /* Search lower boundary */; int sub = drilln-1 /* Search upper boundary */; int sidx /* Search index */; int compres /* Compare result */; // Loop until search area empty while (slb<=sub) { // Get the search index sidx=(slb+sub)>>1; // Compare drill data if (x==drilll[sidx].x) if (y==drilll[sidx].y) // Drill found return(sidx); else compres=ymaxlev) maxlev=lev; // "Allocate" level figure lists levfl[maxlev+1][0]=fig; levfn[maxlev+1]=0; for (levidx=maxlev;levidx>=0;levidx--) levfn[levidx]=0; if (partside==1) { ilaylb=0; ilayub=1+lay_planmidlaycnt(); } else { ilaylb=0; ilayub=partside; } // Build the level figure lists forall (fig where fig.TYP==L_FIGNREF || fig.TYP==L_FIGUREF) { // Test on program abort request checkabort(); if (fig.TYP==L_FIGNREF && lay_findconpart(fig.NAME,cpart)) continue; // Clear level list fln=0; // Scan figure list element levels if (lay_scanfelem(fig,0.0,0.0,0.0,0,0, lmacfunc,NULL,NULL,NULL,NULL,NULL,NULL)!=0) // Scan error error_scan(); // Store figure list element to connected levels for (i=0;i0) { levidx=fll[0]; levtfl[levidx][levtfn[levidx]]=fig; levtfn[levidx]++; } } // Loop for all paths forall (fig where fig.TYP==L_FIGPATH) { // Display process message proccnt++; sprintf(msg,REPCHKPATH,proccnt,totpcnt); // Print report in progress message bae_msgprogressrep(msg,PB_TYPPERC|PB_ABORT,totpcnt!=0 ? (10000*proccnt/totpcnt) : 10000,40); // Test on program abort request checkabort(); // Scan path data curcnt=0; if (lay_scanfelem(fig,0.0,0.0,0.0,0,1, NULL,NULL,dpathfunc,NULL,NULL,NULL,NULL)) error_scan(); if (curcnt<=1) continue; // Get the end point ranges slx=pxs-prad; sly=pys-prad; sux=pxs+prad; suy=pys+prad; elx=pxe-prad; ely=pye-prad; eux=pxe+prad; euy=pye+prad; // Scan figure list for getting the neighbour positions levidx=plevel; snflag=enflag=0; for (i=0;i=0 ? 1 : 0); return(0); } } // Continue scan return(1); } static int hpathfunc( index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Path hit scan function // Return value : // zero if done or (-1) on error // Parameters : // index L_LINE path : Path index // int layer : Path transformed layer code // int pathinws : Path in workspace flag // index L_LEVEL level : Path level */ { index L_POINT p /* Point index */; double lx, ly /* Last point coordinates */; int ltyp /* Last point type */; double cx, cy /* Current point coordinates */; int ctyp /* Current point type */; double pw = path.WIDTH /* Current path width */; int first = 1 /* First point flag */; if (level!=plevel) return(0); if (!snfound) { // Store start point dot bae_clearpoints(); bae_storepoint(pxs-prad,pys,0); bae_storepoint(pxs,pys,1); bae_storepoint(pxs+prad,pys,0); bae_storepoint(pxs,pys,1); // Check against all straight segments forall (p of path) { cx=p.X; cy=p.Y; ctyp=p.TYP; if (first) { first=0; } else { if (ltyp==0 && ctyp==0 && bae_crosslinepoly(cx,cy,lx,ly,pw)) { snfound=1; break; } } lx=cx; ly=cy; ltyp=ctyp; } } if (!enfound) { // Store end point dot bae_clearpoints(); bae_storepoint(pxe-prad,pye,0); bae_storepoint(pxe,pye,1); bae_storepoint(pxe+prad,pye,0); bae_storepoint(pxe,pye,1); // Check against all straight segments forall (p of path) { cx=p.X; cy=p.Y; ctyp=p.TYP; if (first) { first=0; } else { if (ltyp==0 && ctyp==0 && bae_crosslinepoly(cx,cy,lx,ly,pw)) { enfound=1; break; } } lx=cx; ly=cy; ltyp=ctyp; } } return((snfound==1 && enfound==1) ? (-1) : 0); } static int hpolyfunc(index L_POLY poly,int layer, int polyinws,int tree,index L_LEVEL level) /* // Path hit polygon scan function // Return value : // zero if done or (-1) on error // Parameters : // index L_POLY poly : Polygon index // int layer : Polygon layer // int polyinws : Polygon in workspace flag // int tree : Polygon tree // index L_LEVEL level : Polygon level */ { index L_POINT p /* Point index */; double d /* Point distance */; if (level!=plevel) return(0); // Store polygon points bae_cleardistpoly(); bae_clearpoints(); forall (p of poly) bae_storepoint(p.X,p.Y,p.TYP); if (bae_storedistpoly()) return(0); if (bae_querydist(pxs,pys,d)==0 && dilaylb && play1 && segidx!=(-1)) { // Clear internal point list bae_clearpoints(); // Store path start for (i=0;i<=segidx;i++) { if (bae_storepoint(pointl[i].x, pointl[i].y,pointl[i].typ)) error(ERRPATH); } if (segidx) { if (ged_storepath(fig.LAYER,fig.SIZE)) error(ERRPATH); // Check if path should be fixed if (fig.FIXED && lay_lastfigelem(nfig)==0) ged_elemfixchg(nfig,fig.FIXED); // Transfer rules if (fig.RULEOBJID>=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt( nfig,rl)) rs_error(-1); } // Clear internal point list bae_clearpoints(); // Store changed segment if (bae_storepoint(pointl[segidx].x, pointl[segidx].y,pointl[segidx].typ) || bae_storepoint(pointl[segidx+1].x, pointl[segidx+1].y,pointl[segidx+1].typ)) error(ERRPATH); if (ged_storepath(fig.LAYER,width)) error(ERRPATH); // Check if path should be fixed if (fig.FIXED && lay_lastfigelem(nfig)==0) ged_elemfixchg(nfig,fig.FIXED); // Transfer rules if (fig.RULEOBJID>=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); // Clear internal point list bae_clearpoints(); // Store path end for (i=(segidx+1);i=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt( nfig,rl)) rs_error(-1); } // Delete old path if (ged_delelem(fig)) error(ERRDELTRC); // Perform a screen re-display screenredraw(); } } else break; cnt++; // Free grid lock gridlock=bae_getgridlock(); bae_setgridlock(0); } // Restore grid lock bae_setgridlock(gridlock); // No pick element found if (cnt) bae_prtdialog(ERRNOPICK); else perror(ERRNOPICK); } int segfunc(index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Path segment scan function // Return value : // 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 */; double sp /* Segment pick distance */; double sl = 0 /* Segment length */; double sx,sy /* Segment vector */; double dx,dy /* Pick point vector */; double a,b /* Pick point rel. coordiantes */; int i /* Loop control variable */; // Loop for all path points forall (point of path) { // Store current coordinates pointl[pointn].x=point.X; pointl[pointn].y=point.Y; pointl[pointn].typ=point.TYP; pointn++; } // Get rectangular segment pick distance sp=path.WIDTH/2.0; // Scan segments for (i=1;isl || fabs(b)>sp) continue; // Store found segment first point index segidx=i-1; break; } // Return without errors return(0); } /*________________________________________________________________*/ // Power layer routines void trcpowlay() /* // Create power layer boundary polygons for selected traces */ { index L_FIGURE fig /* Figure list index */; index L_FIGURE dfig /* Delete figure list element */; index L_CNET net /* Netlist index */; string netname /* Net name */; string msg /* Grid message */; int grpmode /* Group mode (default none) */; int convmode /* Conversion mode */; int polytyp /* Polygon type */; int polylay /* Polygon layer */; int laytyp = 2 /* Layer type (default signal) */; int changes = 0 /* Changes count */; // Abort if invalid plan class if (ddbclass!=DDBCLLAY && ddbclass!=DDBCLLPRT) error_class(); // Select the element mode bae_defmenusel(-1); bae_promptdialog(UPRPROCMODE); switch (bae_askmenu(5,UPRELEM1,UPRELEM2,UPRELEM3,UPRELEM4,UPRABORT)) { // Convert single elements case 0 : grpmode=0; convmode=0; break; // Copy single elements case 1 : grpmode=0; convmode=1; break; // Convert group elements case 2 : grpmode=1; convmode=0; break; // Convert group elements case 3 : grpmode=1; convmode=1; break; // Abort case 4 : error_abort(); } // Get the power layer trace radius if (varget(GV_POWTRCRAD,tracerad)) tracerad=0.0; // Get the corner radius if (askdist(tracerad,lay_defusrunit()?UPRPRADI:UPRPRADM,0)) // Invalid input value error(ERRINPVAL); // Ask for polygon type bae_promptdialog(UPRPTYP); switch (bae_askmenu(7,polytypename(L_POLYCOPPASS), polytypename(L_POLYKEEPOUT),polytypename(L_POLYDOCLINE), polytypename(L_POLYDOCAREA),polytypename(L_POLYCOPACT), polytypename(L_POLYCOPFILL),UPRABORT)) { // Passive Copper case 0 : polytyp=L_POLYCOPPASS; break; // Keep Out Area case 1 : polytyp=L_POLYKEEPOUT; laytyp=0; break; // Documentary Line case 2 : polytyp=L_POLYDOCLINE; laytyp=3; break; // Documentary Area case 3 : polytyp=L_POLYDOCAREA; laytyp=3; break; // Active Copper case 4 : polytyp=L_POLYCOPACT; laytyp=4; break; // Copper Fill Area case 5 : polytyp=L_POLYCOPFILL; break; // Abort on last menu item case 6 : default : error_abort(); } // Set default layer polylay= ged_getlaydefmode()==2 ? ged_getlayerdefault() : ged_getpickpreflay(); // Ask for source layer bae_promptdialog(UPRSELDSTLAY); if (ged_asklayer(polylay,laytyp)) // Abort error_abort(); // Set new default layer ged_setlayerdefault(polylay); layerfadein(polylay,COLFIN,1); // Test if copper on power layer selected if (polylay>=POWLAYBASE && polylay0) { // Store power layer polygon if (ged_storepoly(polylay,polytyp,netname,0)) error(ERRPOLY); changes++; // Delete old path dfig=fig; if (convmode==0 && ged_delelem(dfig)) error(ERRDELTRC); } } } else { // Loop while pick element found while (bae_promptdialog(UPRSELTRC), ged_pickelem(fig,L_FIGPATH)==0) { if (lay_gettreeidx(fig.TREE,net)) netname=""; else netname=net.NAME; // Save current state for undo if (changes==0) bae_callmenu(MNU_BAESAVESTATE); // Clear the internal polygon point list bae_clearpoints(); pointfound=polytyp==L_POLYDOCLINE ? (-1) : 0; // Scan the path data if (lay_scanfelem(fig,0.0,0.0,0.0,1,0, NULL,NULL,powpathfunc,NULL,NULL,NULL,NULL)) error_scan(); // Check if path points found if (pointfound>0) { // Store power layer polygon if (ged_storepoly(polylay,polytyp,netname,0)) error(ERRPOLY); changes++; // Delete old path if (convmode==0 && ged_delelem(fig)) error(ERRDELTRC); } } } // Screen redraw screenredraw(); // Preserve power layer trace radius for next call varset(GV_POWTRCRAD,tracerad); if (!grpmode && changes==0) exit(0); // Done sprintf(msg,REPTRCCONV,changes); bae_prtdialog(msg); } int powpathfunc(index L_LINE path,int layer,int pathinws,index L_LEVEL level) /* // Path scan function; generates path boundary polygon // Return value : // zero if done, or (-1) on error // Parameters : // index L_LINE path : Path data // 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 x1,y1 /* 1st point coordinate buffers */; double ex,ey /* Extra point coordinate buffers */; double sl1,sl2 /* Segment lengthes */; double sx1,sx2 /* Segment x-coordinates */; double sy1,sy2 /* Segment y-coordinates */; double wx,wy /* Bisector vector coords. */; double wl /* 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 the path point list pointl[pointn].x=point.X; pointl[pointn].y=point.Y; pointl[pointn].typ=point.TYP; // Check double points if (pointn && point.X==pointl[pointn-1].x && point.Y==pointl[pointn-1].y) continue; // Check redundant points if (pointn>1 && point.TYP==0) { if (pointl[pointn-1].typ==0 && fabs(((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)))<=SMALLVAL) { 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 the point found flag pointfound= pointfound==(-1) ? 2 : 1; // Get real radius rad=tracerad+path.WIDTH/2.0; // Store start semicircle arc ex=pointl[0].x; ey=pointl[0].y; sx1=ex-pointl[1].x; sy1=ey-pointl[1].y; normvect(sx1,sy1,sl1); x1=ex+rad*sy1; y1=ey-rad*sx1; if (bae_storepoint(x1,y1,0)) return(-1); if (bae_storepoint(ex,ey,1)) return(-1); 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; if (pointl[i].typ) { if (bae_storepoint(x,y,pointl[i].typ)) return(-1); continue; } // Get the normalized data of first segment vector sx1=pointl[i-1].x-x; sy1=pointl[i-1].y-y; normvect(sx1,sy1,sl1); switch (pointl[i-1].typ) { case 1: if (bae_storepoint(x-rad*sx1,y-rad*sy1,0)) return(-1); continue; case 2: if (bae_storepoint(x+rad*sx1,y+rad*sy1,0)) return(-1); continue; default : } // Get the normalized data of second segment vector sx2=pointl[i+1].x-x; sy2=pointl[i+1].y-y; normvect(sx2,sy2,sl2); switch (pointl[i+1].typ) { case 1: if (bae_storepoint(x-rad*sx2,y-rad*sy2,0)) return(-1); continue; case 2: if (bae_storepoint(x+rad*sx2,y+rad*sy2,0)) return(-1); continue; default : } // Get the 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 the 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-rad*sy1,y+rad*sx1,0) || bae_storepoint(x,y,1) || bae_storepoint(x+rad*sy2,y-rad*sx2,0)) return(-1); } } // Store end semicircle arc 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); if (bae_storepoint(ex,ey,1)) return(-1); 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; if (pointl[i].typ) { if (bae_storepoint(x,y,3-pointl[i].typ)) return(-1); continue; } // Get the normalized data of first segment vector sx1=pointl[i-1].x-x; sy1=pointl[i-1].y-y; normvect(sx1,sy1,sl1); switch (pointl[i-1].typ) { case 1: if (bae_storepoint(x+rad*sx1,y+rad*sy1,0)) return(-1); continue; case 2: if (bae_storepoint(x-rad*sx1,y-rad*sy1,0)) return(-1); continue; default : } // Get the normalized data of second segment vector sx2=pointl[i+1].x-x; sy2=pointl[i+1].y-y; normvect(sx2,sy2,sl2); switch (pointl[i+1].typ) { case 1: if (bae_storepoint(x+rad*sx2,y+rad*sy2,0)) return(-1); continue; case 2: if (bae_storepoint(x-rad*sx2,y-rad*sy2,0)) return(-1); continue; default : } // Get the 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 the 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 (rang5) // Abort error_abort(); // Save current state for undo bae_callmenu(MNU_BAESAVESTATE); // Assign the trace edit display mode predicate rule rs_assplanintpred(RS_EDITWIDE,editwide,0,"lay_edit_wide_*"); // Done bae_prtdialog(""); } void viachkrange() /* // Via check grid range selection */ { int viachkn /* Via check grid range */; // Query the current via check grid range if (lay_rulequery( RS_OCPLAN,0,RS_PCBSUBJ,RS_VIACHKRANGE,"?d",viachkn)<1) // Set default via check range viachkn=0; // Set the default menu selection bae_defmenusel(viachkn); // Ask for via check range bae_promptdialog(UPRVFCT); if ((viachkn=bae_askmenu(7,UPRVFCT1,UPRVFCT2,UPRVFCT3, UPRVFCT4,UPRVFCT5,UPRVFCT6,UPRABORT))<0 || viachkn>5) // Abort error_abort(); // Save current state for undo bae_callmenu(MNU_BAESAVESTATE); // Assign the via check range predicate rule rs_assplanintpred(RS_VIACHKRANGE,viachkn,0,""); // Done bae_prtdialog(""); } void gridquery() /* // Query trace grid */ { index L_FIGURE fig /* Figure list index */; index L_LINE path /* Trace index */; index L_POINT point /* Point index */; string msg /* Grid message */; STRINGS headl /* Menu header string list */; int headn /* Menu header string count */; STRINGS entryl /* Menu entry string list */; int entryn /* Menu entry string count */; struct griddes { // Grid descriptor double val /* Grid value */; double shift /* Grid shift flag */; string msg /* Grid message */; int vio /* Grid violation flag */; } gridl[] = { // Standard grid list { cvtlength(1.0/20.0,1,0),0.0, REPGRID20,0 }, { cvtlength(1.0/40.0,1,0),0.0, REPGRID40,0 }, { cvtlength(1.0/50.0,1,0),0.0, REPGRID50,0 }, { cvtlength(1.0/60.0,1,0),cvtlength(1.0/120.0,1,0),REPGRID60,0 }, { cvtlength(1.0/80.0,1,0),0.0, REPGRID80,0 }, { cvtlength(1.0/100.0,1,0),0.0, REPGRID100,0 }, { cvtlength(1.0/120.0,1,0),0.0, REPGRID120,0 }, { cvtlength(1.0/160.0,1,0),0.0, REPGRID160,0 }, { cvtlength(1.0/200.0,1,0),0.0, REPGRID200,0 } }; int gridn = arylength(gridl) /* Grid count */; double grid /* Grid value */; double grido /* Grid compare offset */; double sgrid /* Snapped grid value */; double ugrid /* Snapped grid value */; double dx, dy /* Current segment vector */; double pdx, pdy /* Previous segment vector */; int pori /* Previous segment orientation */; double ndx, ndy /* Next segment vector */; int nori /* Next segment orientation */; int pn /* Standard path corner count */; double minx /* Minimum x step */; int first /* First point flag */; int pass /* Grid scan pass */; int i, j /* Loop control variables */; // Pick path bae_promptdialog(UPRSELTRC); if (ged_pickelem(fig,L_FIGPATH)!=0) error(ERRNOPICK); // Loop for all path points path=fig.LINE; for (pass=0;pass<3;pass++) { pointn=0; forall (point of path) { // Ignore double points if (pointn && point.X==pointl[pointn-1].x && point.Y==pointl[pointn-1].y && point.TYP==pointl[pointn-1].typ) continue; if (point.TYP) { bae_msgbox(2,ERRARCTRC,""); exit(0); } // Store current point pointl[pointn].x=point.X; pointl[pointn].y=point.Y; pointl[pointn].typ=point.TYP; pointn++; } if (pass<2) { pointl[0].typ=1; pointl[pointn-1].typ=1; } if (pass<1) { if (pointn>1) { pointl[1].typ=1; pointl[pointn-2].typ=1; } } for (i=1;i0) continue; if (i<=2 || i>=(pointn-2)) { pointl[i].typ=1; continue; } pdx=pointl[i-1].x-pointl[i-2].x; pdy=pointl[i-1].y-pointl[i-2].y; if (fabs(pdx)<=SMALLCVAL && fabs(pdy)<=SMALLCVAL) { pointl[i].typ=1; continue; } pori= fabs(pdx)<=SMALLCVAL ? 1 : 0; ndx=pointl[i+1].x-pointl[i].x; ndy=pointl[i+1].y-pointl[i].y; if (fabs(ndx)<=SMALLCVAL && fabs(ndy)<=SMALLCVAL) { pointl[i].typ=1; continue; } nori= fabs(ndx)<=SMALLCVAL ? 1 : 0; if (pori==nori) { pointl[i].typ=1; continue; } if (pori) pointl[i].x=pointl[i-1].x; else pointl[i].y=pointl[i-1].y; } for (i=pn=0;iSMALLCVAL) { gridl[j].vio=1; continue; } sgrid=grid*floor((pointl[i].y-grido)/grid+0.5); if (fabs(pointl[i].y-grido-sgrid)>SMALLCVAL) { gridl[j].vio=1; continue; } } } if (pn>1) break; } if (pn==0) { bae_msgbox(2,ERRGRIDETRC,""); exit(0); } // Print the result headl[0]=REPGRIDMATCH; headn=2; entryn=0; for (i=0;i1) { // Search shortest segment distance first=2; for (i=0;iSMALLCVAL) { minx=dx; first=0; } if ((first==1 || dySMALLCVAL) { minx=dy; first=0; } } pdx=pointl[i].x; pdy=pointl[i].y; } // Try segment length fractions as grid guess for (i=1;i<10;i++) { grid=minx/i; for (j=0;jgrid*0.005) break; sgrid=grid*floor(pointl[j].y/grid+0.5); if (fabs(pointl[j].y-sgrid)>grid*0.005) break; } if (j>=pointn) { sprintf(msg,REPGRIDTRC, bae_numstring(cvtlength(grid,0,2),3)); bae_msgbox(2,msg,""); exit(0); } } } bae_msgbox(2,ERRGRIDNTRC,""); exit(0); } // Activate the popup menu bae_setintpar(16,3073); popupmenu(0,"",headl,headn,entryl,entryn, "",0,1,1,headn+entryn+3,50,0,""); } void tracebeautify() /* // Beautify trace */ { struct gvaldes { // Grid value descriptor double gdim /* Grid dimension */; string name /* Grid menu name */; }; struct gvaldes gridvall[] = { // Layout grid list { 0.0254/10.0, UPREGRID01 }, { 0.0254/20.0, UPREGRID02 }, { 0.0254/40.0, UPREGRID03 }, { 0.0254/60.0, UPREGRID04 }, { 0.0254/80.0, UPREGRID05 }, { 0.0254/100.0, UPREGRID06 }, { 0.0254/120.0, UPREGRID07 }, { 0.0254/160.0, UPREGRID08 }, { 0.0254/200.0, UPREGRID09 }, { 0.0254/240.0, UPREGRID10 }, { 0.0254/480.0, UPREGRID11 }, { 0.00005, UPREMGRID01 }, { 0.0001, UPREMGRID02 }, { 0.000125, UPREMGRID03 }, { 0.00025, UPREMGRID04 }, { 0.0005, UPREMGRID05 }, { 0.000625, UPREMGRID06 }, { 0.0010, UPREMGRID07 }, { 0.00125, UPREMGRID08 }, { 0.002, UPREMGRID09 }, { 0.0025, UPREMGRID10 }, { 0.01, UPREMGRID11 }, { 0.0, UPRNGRID } }; int gridvaln = arylength(gridvall); index L_FIGURE fig /* Figure list index */; index L_FIGURE sfig /* Scan figure list index */; index L_LINE path /* Trace index */; index L_POINT point /* Point index */; struct pointdes pl[] /* Trace point list */; int pn /* Trace point count */; string msg /* Message string */; double pcol = 21.0 /* Parameter column */; double cy /* Dialog box current y coordinate */; int res /* Dialog box result */; int varidx /* INI variable index */; int slidx /* Scan length parameter index */; int tsidx /* Trace set parameter index */; int raidx /* Router area parameter index */; int faidx /* Fill area parameter index */; int elidx /* Chamfer list parameter index */; int eeidx /* Chamfer edit param. index */; int curgidx /* Current edge grid index */; int raflag /* Router area flag */; int faflag /* Fill area flag */; int idx /* Index query result */; double gix /* Input grid */; int cunits = bae_getcoorddisp() ? 2 : 0 /* Coordinate display units */; int repflag = 1 /* Report flag */; int pidx /* Path element index */; int curcount = 0 /* Current path count */; int totcount = 0 /* Total path count */; int changes = 0 /* Changes count */; int i /* Loop control variable */; // Get input grid bae_getinpgrid(gix,0.0); // Perform the input loop while (repflag) { bae_dialclr(); // Init. the y coordinate cy=DIAL_TOPMARG; // Store the grid scan controls dial_label(0.0,cy,UPRDSCANLEN); slidx=dial_dist(5,TRCBSCANLEN,pcol,cy); // Store the trace set controls dial_label(0.0,cy,UPRTRCSET); tsidx=dial_selbox(TRCBSTSET,pcol,cy); dial_sbentry(0,0,UPRTRCSING); dial_sbentry(0,1,UPRTRCGRP); dial_sbentry(0,2,UPRTRCALL); raidx=dial_toggle((TRCBFSTYP&1) ? 1 : 0,0.0,cy,UPRROUTFA); faidx=dial_toggle((TRCBFSTYP&2) ? 1 : 0,0.0,cy,UPRFILLFA); // Check the edge grid values for (curgidx=0;curgidx2) { ged_elemgrpchg(fig,1); totcount++; } } else { // Count processable traces forall (fig where fig.GROUP) if (fig.TYP!=L_FIGPATH || fig.FIXED!=0 || fig.LINE.PN<3) ged_elemgrpchg(fig,0); else totcount++; } // Process group elements forall (fig where fig.GROUP) { // Save current state for undo if (changes==0) bae_callmenu(MNU_BAESAVESTATE); sprintf(msg,REPTRCPROC,curcount,totcount); bae_prtdialog(msg); // Get the path level if (lay_scanfelem(fig,0.0,0.0,0.0,0,1, NULL,NULL,levpathfunc,NULL,NULL,NULL,NULL)) error_scan(); // Get the path point list path=fig.LINE; pn=0; forall (point of path) { // Store current point pl[pn].x=point.X; pl[pn].y=point.Y; pl[pn].typ=point.TYP; pn++; } // Process path sfig=fig; if ((res=stracebeautify(sfig,pl,pn,plevel))<0) break;; changes+=res; curcount++; } if (res>=0) bae_callmenu(MNU_GEDGRPRESE); } // Redraw the screen if (changes) bae_callmenu(MNU_BAEREDISPL); // Report changes sprintf(msg,REPTRCPROCDONE,changes); bae_prtdialog(msg); } int stracebeautify( index L_FIGURE fig, struct pointdes pl[],int pn,index L_LEVEL tlev) /* // Beautify single trace element // Returns: 1 if changed, 0 if not changed, (-1) on abort request // Parameters : // index L_FIGURE fig : Figure list index // struct pointdes pl[] : Trace point list // int pn : Trace point count // index L_LEVEL tlev : Trace level */ { index L_FIGURE nfig /* New figure list element */; double xs1,ys1 /* 1st segment start coordinates */; double xe1,ye1 /* 1st segment end coordinates */; double xc1,yc1 /* 1st segment check coordinates */; int lp1 /* 1st segment last point index */; int lpp /* 1st segment previous point index */; double xs2,ys2 /* 2nd segment start coordinates */; double xe2,ye2 /* 2nd segment end coordinates */; double xc2,yc2 /* 2nd segment check coordinates */; int lp2 /* 2nd segment last point index */; double sx1, sy1 /* 1st segment direction vector */; double slen1 /* 1st segment length */; double sx2, sy2 /* 2nd segment direction vector */; double slen2 /* 2nd segment length */; double x, y /* Cross point coordinates */; double trcwidth /* Trace width */; double cmpwidth /* Tiny segment compare width */; double ang /* Corner angle */; double dx1, dy1 /* Diagonal 1st point */; double dx2, dy2 /* Diagonal 2nd point */; double dstep /* Diagonal side step */; double ang1, ang2 /* Segment angles */; double dang /* Angle difference */; int lay /* Path layer */; int found /* Found optimization flag */; int anyopt /* Found any optimization flag */; int loopcnt = 0 /* Optimization loop counter */; int iloopcnt /* Inner loop counter */; int change /* Change flag */; int shift /* Point shift count */; int oldpmode /* Old polygon exclude mode */; int send /* Scan end index */; int i, j, k /* Loop control variables */; // Check type if (fig.TYP!=L_FIGPATH) return(0); // Get path data lay=fig.LAYER; trcwidth=fig.SIZE; cmpwidth=trcwidth*0.1; change=0; ged_getintpar(9,oldpmode); ged_setintpar(9,((TRCBFSTYP&1)==0 ? L_POLYROUTFA : 0)| ((TRCBFSTYP&2)==0 ? L_POLYFILLFA : 0)); // Loop while any optimization found do { anyopt=0; loopcnt++; // Scan for same direction path segments for (i=1;i<(pn-1);i++) { // Get the segment corner indices lp1=i-1; lp2=i+1; // Check if arc segment involved if (pl[i].typ || pl[lp1].typ || pl[lp2].typ) continue; // Get the first segment vector data xs1=pl[lp1].x; ys1=pl[lp1].y; xe1=pl[i].x; ye1=pl[i].y; ang1=fmod(atan2(ye1-ys1,xe1-xs1)+2.0*PI,2.0*PI); // Get the next segment vector data xs2=xe1; ys2=ye1; xe2=pl[lp2].x; ye2=pl[lp2].y; ang2=fmod(atan2(ye2-ys2,xe2-xs2)+2.0*PI,2.0*PI); dang=fabs(ang1-ang2); if (dang<=ODDANG || dang>=(2.0*PI-ODDANG)) { // Dismiss redundant segment point for (k=i;k<(pn-1);k++) pl[k]=pl[k+1]; pn--; // Trace point list changed change=1; } } // Scan for intermediate tiny path segments for (i=2;i<(pn-1);i++) { // Get the segment corner indices lp1=i-1; lp2=i+1; lpp=lp1-1; // Check if arc segment involved if (pl[i].typ || pl[lp1].typ || pl[lp2].typ || pl[lpp].typ) continue; // Check if tiny segment if (fabs(pl[i].x-pl[lp1].x)<=cmpwidth && fabs(pl[i].y-pl[lp1].y)<=cmpwidth) { // Get the previous segment vector data xs1=pl[lpp].x; ys1=pl[lpp].y; xe1=pl[lp1].x; ye1=pl[lp1].y; // Get the next segment vector data xs2=pl[i].x; ys2=pl[i].y; xe2=pl[lp2].x; ye2=pl[lp2].y; // Check if segments cross if (bae_crosssegseg(1, xs1,ys1,xe1,ye1,xs2,ys2,xe2,ye2,x,y)==1) { // Build the crosspoint corner segment pair bae_clearpoints(); bae_storepoint(xs1,ys1,0); bae_storepoint(x,y,0); bae_storepoint(xe2,ye2,0); // Check if valid position if (ged_drcpath(lay,trcwidth,tlev,1)==0) { // Replace first segment point pl[lp1].x=x; pl[lp1].y=y; // Dismiss second segment point for (k=i;k<(pn-1);k++) pl[k]=pl[k+1]; pn--; // Trace point list changed change=1; } } } } // Scan path segments for (i=1;i<(pn-1);i++) { // Get the segment start index lp1=i-1; // Check if arc segment if (pl[i].typ || pl[lp1].typ) continue; // Get the segment vector data xs1=pl[lp1].x; ys1=pl[lp1].y; // Loop while any optimization found iloopcnt=pn; do { // Check if diagonals enabled if (TRCBSCORNLEN<=SMALLVAL) break; // Assume no orthogonal step found=0; // Update segment end point xe1=pl[i].x; ye1=pl[i].y; // Get the segment vector sx1=xe1-xs1; sy1=ye1-ys1; // Check if orthogonal segment if (fabs(sx1)>SMALLCVAL && fabs(sy1)>SMALLCVAL) break; // Normalize the segment vector normvect(sx1,sy1,slen1); // Get the next segment j=i+1; // Check if arc segment if (pl[j].typ) break; // Get the segment vector data xs2=xe1; ys2=ye1; xe2=pl[j].x; ye2=pl[j].y; // Get the segment vector sx2=xe2-xs2; sy2=ye2-ys2; // Normalize the segment vector normvect(sx2,sy2,slen2); // Check if orthogonal segment if (fabs(sx2)>SMALLCVAL && fabs(sy2)>SMALLCVAL) break; // Check if same direction if (fabs(sx1)>SMALLCVAL && fabs(sx2)>SMALLCVAL) break; // Get smaller side if (slen1SMALLCVAL || fabs(dy2-ye2)>SMALLCVAL) { // Insert corner for (k=pn;k>(i+1);k--) pl[k]=pl[k-1]; pl[i+1].x=dx2; pl[i+1].y=dy2; pn++; } } // Trace point list changed change=1; // Restart scan with new corner found=1; anyopt=1; } iloopcnt--; } while (found && iloopcnt>=0); // Check if extended segment hits following segments iloopcnt=pn; do { // Assume no segment hit found=0; // Update segment end point xe1=pl[i].x; ye1=pl[i].y; // Get the segment vector sx1=xe1-xs1; sy1=ye1-ys1; // Check if odd angle ang=atan2(sy1,sx1); ang=fmod(ang+2.0*PI,0.25*PI); if (ang>ODDANG && ang<(0.25*PI-ODDANG)) // Avoid extension of odd angle break; // Normalize the segment vector normvect(sx1,sy1,slen1); // Get the check segment end xc1=xe1+sx1*TRCBSCANLEN; yc1=ye1+sy1*TRCBSCANLEN; // Get first segment corner angle ang=atan2(pl[i+1].y-ye1,pl[i+1].x-xe1)- atan2(ys1-ye1,xs1-xe1); ang=fmod(ang+2.0*PI,2.0*PI); // Check if acute angle overshot send=i+((ang<=(0.5*PI+SMALLANG) || ang>=(1.5*PI-SMALLANG)) ? 2 : 3); // Compare to further path segments for (j=pn-1;j>=send;j--) { // Get the segment start index lp2=j-1; // Check if arc segment if (pl[j].typ || pl[lp2].typ) continue; // Get the segment vector data xs2=pl[lp2].x; ys2=pl[lp2].y; xe2=pl[j].x; ye2=pl[j].y; // Get the segment vector sx2=xe2-xs2; sy2=ye2-ys2; // Check if odd angle ang=atan2(sy2,sx2); ang=fmod(ang+2.0*PI,0.25*PI); if (ang>ODDANG && ang<(0.25*PI-ODDANG)) // Avoid extension of odd angle continue; // Normalize the segment vector normvect(sx2,sy2,slen2); // Get the check segment end xc2=xs2-sx2*TRCBSCANLEN; yc2=ys2-sy2*TRCBSCANLEN; // Check if extended segments cross if (bae_crosssegseg(0, xs1,ys1,xc1,yc1,xc2,yc2,xe2,ye2,x,y)==1) { // Get the crosspoint corner angle ang= atan2(ye2-y,xe2-x)-atan2(ys1-y,xs1-x); ang=fmod(ang+2.0*PI,2.0*PI); // Check if acute angle if ((ang<0.7*PI || ang>1.3*PI) && !((fabs(xe2-x)<=SMALLVAL || fabs(ye2-y)<=SMALLVAL) && (fabs(xs1-x)<=SMALLVAL || fabs(ys1-y)<=SMALLVAL))) // Avoid acute angle continue; // Build the crosspoint corner seg. pair bae_clearpoints(); bae_storepoint(xs1,ys1,0); bae_storepoint(x,y,0); bae_storepoint(xe2,ye2,0); // Check if valid position if (ged_drcpath( lay,trcwidth,tlev,1)==0) { // Store new corner pl[i].x=x; pl[i].y=y; // Dismiss intermediate corners shift=j-i-1; for (k=i+1;k<(pn-shift);k++) pl[k]=pl[k+shift]; pn-=shift; // Trace point list changed change=1; // Restart scan with new corner found=1; anyopt=1; break; } } } iloopcnt--; } while (found && iloopcnt>=0); } // Abort on request if (kbhit()) { getchr(); if (verify(UPRFEXIT,0)) { ged_setintpar(9,oldpmode); return(-1); } } } while (anyopt && loopcntsplitgap && bae_storepoint( pointl[i-1].x+(pvlen-splitgap)*vx/vlen, pointl[i-1].y+(pvlen-splitgap)*vy/vlen, pointl[i-1].typ)) error(ERRPATH); // Save current state for undo if (cflag==0) { bae_callmenu(MNU_BAESAVESTATE); cflag=1; } if (ged_storepath(fig.LAYER,fig.LINE.WIDTH)) error(ERRPATH); // Check if path should be fixed if (fig.FIXED && lay_lastfigelem(nfig)==0) ged_elemfixchg(nfig,fig.FIXED); // Transfer rules if (fig.RULEOBJID>=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); // Store the second path half bae_clearpoints(); if ((pvlen+splitgap)=0 && lay_lastfigelem(nfig)==0) // Get rules if (rs_getfigrules(fig,rl)>0) // Attach rules if (lay_rulefigatt(nfig,rl)) rs_error(-1); // Delete element if (ged_delelem(fig)) error(ERRDELTRC); // Screen redraw screenredraw(); } // No pick bae_prtdialog(ERRNOPICK); } int picksegment(index L_FIGURE fig,int viaflag) /* // Pick a trace segment and build picked path point list // Return value : // zero if segment picked, (-1) if no pick segment found // Parameters : // index L_FIGURE fig : Figure list index // int viaflag : Via pick flag return */ { int gridlock /* Grid lock flag */; // Free grid lock gridlock=bae_getgridlock(); bae_setgridlock(0); // Pick segment segidx=(-1); bae_promptdialog(UPRSELSEG); if (bae_inpoint(wsnx,wsny,px,py,0)!=0) { // Restore grid lock bae_setgridlock(gridlock); return(-1); } // Restore grid lock bae_setgridlock(gridlock); // Pick via bae_clriactqueue(); bae_storemouseiact(1,px,py,0,LMB); if (ged_pickelem(fig,L_FIGUREF)==0) { px=fig.X; py=fig.Y; viaflag=1; } else { viaflag=0; } // Pick trace bae_clriactqueue(); bae_storemouseiact(1,px,py,0,LMB); if (ged_pickelem(fig,L_FIGPATH)!=0) return(-1); if (fig.FIXED&2) error(ERRTRCGLUED); // Clear the path point list pointn=0; // Scan path points of picked trace if (lay_scanfelem(fig,0.0,0.0,0.0,1,0, NULL,NULL,pathpickfunc,NULL,NULL,NULL,NULL)!=0) error_scan(); // Check if segment found return(segidx==(-1) ? (-1) : 0); } int pathpickfunc(index L_LINE path, int layer,int pathinws,index L_LEVEL level) /* // Path scan function // Return value : // 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 */; double lx /* Last X coordinate */; double ly /* Last Y coordinate */; int ltyp = 0 /* Last point type */; double cx,cy /* Current coordinates */; int ctyp /* Current point type */; double sx,sy /* Segment vector */; double d /* Segment distance value */; double curapert /* Pick aperture */; double curzoom /* Current zoom factor */; double rad = 0.5*path.WIDTH/* Path radius */; // Get the current zoom factor bae_getdblpar(2,curzoom); // Get the current pick aperture curapert=0.003/curzoom; if (rad>curapert) curapert=rad; // Loop for all path points forall (point of path) { // Get current path point coordinates cx=point.X; cy=point.Y; ctyp=point.TYP; // Ignore redundant path points if (pointn>0 && cx==lx && cy==ly) continue; // Store current path point pointl[pointn].x=cx; pointl[pointn].y=cy; pointl[pointn].typ=ctyp; // Check if not first point if (pointn>0 && ctyp==0 && ltyp==0) { // Get path segment polygon bae_cleardistpoly(); bae_clearpoints(); sx=cx-lx; sy=cy-ly; normvect(sx,sy,0.0); bae_storepoint(lx+rad*sy,ly-rad*sx,0); bae_storepoint(lx,ly,1); bae_storepoint(lx-rad*sy,ly+rad*sx,0); bae_storepoint(cx-rad*sy,cy+rad*sx,0); bae_storepoint(cx,cy,1); bae_storepoint(cx+rad*sy,cy-rad*sx,0); bae_storedistpoly(); if (bae_querydist(px,py,d)==0 && d=POWLAYBASE) laysl[layscnt].fill=1; if (laysl[layscnt].fill) fillcnt++; } // Check if ground layers defined if (gndchk && fillcnt==0) { bae_msgbox(2,ERRNOGNDLAY,""); exit(0); } } void trcimpedance(int setflag) /* // Trace impedance // Parameter : // int setflag : Set impedance flag */ { index L_FIGURE fig /* Figure list index */; index L_FIGURE nfig /* New figure list index */; string msgbuf /* Message buffer string */; double epsr /* Epsilon r value */; double epsrt /* Epsilon r top value */; double epsrb /* Epsilon r bottom value */; double h /* Board thickness */; double ht /* Board top thickness */; double hb /* Board bottom thickness */; int typ /* Connection type */; int layer /* Trace layer */; int lsidx /* Layer stackup index */; int tgidx /* Top ground layer index */; int bgidx /* Bottom ground layer index */; double imp /* Impedance value */; double w /* New path width */; int cflag = 0 /* Change flag */; // Loop while trace picked bae_prtdialog(UPRSELTRC); while (ged_pickelem(fig,L_FIGPATH)==0) { layer=trclayer(fig.LAYER); // Search trace layer in stackup for (lsidx=0;lsidx=layscnt) { sprintf(msgbuf,ERRNOLAYSTK,layername(layer)); bae_msgbox(2,msgbuf,""); continue; } // Check if ground layer trace if (laysl[lsidx].fill) { sprintf(msgbuf,ERRTRCGND,layername(layer)); bae_msgbox(2,msgbuf,""); continue; } // Search next ground layer above trace layer ht=laysl[lsidx].iso; epsrt=laysl[lsidx].epsr*ht; for (tgidx=lsidx+1;tgidx=0;bgidx--) { epsrb+=laysl[bgidx].epsr*laysl[bgidx].iso; hb+=laysl[bgidx].iso; if (laysl[bgidx].fill) break; } // Check if strip line if (tgidx=0) { typ=1; // Get the average epsilon r epsr=(epsrb+epsrt)/(hb+ht); h=hb+ht; } // Check if bottom side micro strip else if (bgidx>=0) { typ=0; // Get the average epsilon r epsr=epsrb/hb; h=hb; } // Check if top side micro strip else if (tgidx1.0) { // Get impedance value z=188.5/(sqrt(epsr)*(0.5*q+0.441+ (epsr+1.0)*(log(0.5*q+0.94)+1.451)/(2.0*PI*epsr)+ 0.082*(epsr-1)/(epsr*epsr))); } else { // Get impedance value z=60.0*(log(8.0/q)+q*q/32.0-0.5*(epsr-1.0)* (0.4516+0.2416/epsr)/(epsr+1.0))/sqrt(0.5*epsr+0.5); } } // Return impedance value return(z); } double calciwidth(double imp,double h,double epsr,int typ) /* // Calculate path width for given impedance // Returns: Path width // Parameters : // double imp : Requested impedance value // double h : Medium height // double epsr : Medium epsilon r // int typ : Connection type // 0 = micro strip // 1 = strip line */ { double w /* Width value */; double step /* Approximation step */; int i /* Loop variable */; // Init. approximation variables w=500.0*h; step=0.5*w; // Iterate width value for (i=0;i<32;i++) { if (calcimpedance(w,h,epsr,typ)>imp) w+=step; else w-=step; step*=0.5; } // Return width value return(w); } double coth(double val) /* // Calculate coth value // Returns: coth value // Parameters : // double val : Requested value */ { return((exp(val)+exp(-val))/(exp(val)-exp(-val))); } /*________________________________________________________________*/ // SQL/DB selection callback functions static int setloadfunc(string dstr,int dint,double ddbl, int dval,int dtype,string dtable,string dfield,int didx) /* // Setup function callback function // Return value : // zero if done or (-1) on data error // Parameters : // string dstr : String/Date data // int dint : Integer/Boolean data // double ddbl : Float data // int dval : Data valid flag // int dtype : Data type // string dtable : Data table name // string dfield : Data field name // int didx : Data output field index */ { // Store the current entry switch (didx) { // Power layer index case 1 : curidx=dint; break; // Store power layer definition case 2 : bae_storemenuiact(1,curidx,LMB); bae_storetextiact(1,dstr); break; } // Return without errors return(0); } int setnamefunc(string dstr,int dint,double ddbl, int dval,int dtype,string dtable,string dfield,int didx) /* // Setup name list callback function // Return value : // zero if done or (-1) on data error // Parameters : // string dstr : String/Date data // int dint : Integer/Boolean data // double ddbl : Float data // int dval : Data valid flag // int dtype : Data type // string dtable : Data table name // string dfield : Data field name // int didx : Data output field index */ { int i /* Loop control variable */; switch (didx) { // Name case 1 : for (i=setn;i>0;i--) if (setl[i-1]>dstr) setl[i]=setl[i-1]; else break; setl[i]=dstr; setn++; break; } // Return without errors return(0); } string selsetupname(int new,string setfname) /* // Perform a power layer setup name input // Return value : // Setup name string // Parameters : // int new : New setup name input // string setfname : Setup file name return */ { STRINGS hl /* Header list */; int hn /* Header count */; string setname /* Setup name */; string msg /* Message string */; int i /* Loop control variable */; // Select the DDB file if (bae_askddbfname(setfname,0,UPRSETFILE)) // Abort error_abort(); // Create/init database file if (sqlinit(setfname,0)==(-1) && sqlinit(setfname,1)==(-1)) // SQL/DB creation error errormsg(ERRDBINIT,setfname); // Create table in database if (sqlcmd(bae_planfname(),P_HELP,NULL)!=0) if (sqlcmd(setfname,P_CREATE,NULL)) // SQL/DB error (ignore table already defined error) sql_dberror(25); // Get setup entries setn=0; if (sqlcmd(setfname,PN_SELECT,setnamefunc)!=0) // SQL/DB error sql_dberror(0); // Select batch name hl[0]=REPSETLIST; hn=1; bae_setintpar(16,3074); if ((setname=popupmenu(1,UPRSETNAME,hl,hn,setl,setn, UINPOPABORT,0,1,1,hn+setn+2,0,0,""))==UINPOPABORT) // Aborted return(""); // Search setup if (new) { for (i=0;i>1; for (j=0;j0;k--) pel[k]=pel[k-1]; pel[0]=pathbuf; cn++; break; } } // Check if via found if (j0;k--) pel[k]=pel[k-1]; pel[0]=pathbuf; cn++; pickdist=pathbuf.fig.SIZE; // Direction swap required fig=pel[0].fig; path=fig.LINE; pn=k=pel[0].pn; forall (point of path) { x=point.X; y=point.Y; t=point.TYP; // Ignore double points if (k!=pn && x==pel[0].pl[k].x && y==pel[0].pl[k].y && t==pel[0].pl[k].typ) continue; k--; pel[0].pl[k].x=x; pel[0].pl[k].y=y; pel[0].pl[k].typ= t==0 ? 0 : 3-t ; } pel[0].xs=pel[0].pl[0].x; pel[0].ys=pel[0].pl[0].y; pel[0].xe=pel[0].pl[pn-1].x; pel[0].ye=pel[0].pl[pn-1].y; break; } // Check if path end match if (dist(pel[j].xe,pel[j].ye,xs,ys)<=pickdist) { // Move path to path chain start pathbuf=pel[j]; for (k=j;k>0;k--) pel[k]=pel[k-1]; pel[0]=pathbuf; cn++; pickdist=pathbuf.fig.SIZE; break; } } // Check if match found if (j>=pen) break; } // Scan path end chain for (i=cn;icn;k--) pel[k]=pel[k-1]; pel[cn]=pathbuf; cn++; break; } } // Check if via found if (jcn;k--) pel[k]=pel[k-1]; pel[cn]=pathbuf; cn++; pickdist=pathbuf.fig.SIZE; break; } // Check if path end match if (dist(pel[j].xe,pel[j].ye,xe,ye)<=pickdist) { // Move path to path chain start pathbuf=pel[j]; for (k=j;k>cn;k--) pel[k]=pel[k-1]; pel[cn]=pathbuf; pickdist=pathbuf.fig.SIZE; // Direction swap required fig=pel[cn].fig; path=fig.LINE; pn=k=pel[cn].pn; forall (point of path) { x=point.X; y=point.Y; t=point.TYP; // Ignore double points if (k!=pn && x==pel[cn].pl[k].x && y==pel[cn].pl[k].y && t==pel[cn].pl[k].typ) continue; k--; pel[cn].pl[k].x=x; pel[cn].pl[k].y=y; pel[cn].pl[k].typ= t==0 ? 0 : 3-t ; } pel[cn].xs=pel[cn].pl[0].x; pel[cn].ys=pel[cn].pl[0].y; pel[cn].xe=pel[cn].pl[pn-1].x; pel[cn].ye=pel[cn].pl[pn-1].y; cn++; break; } } // Check if match found if (j>=pen) break; } if (grpmode) for (i=0;i=(2.0*PI-ODDANG)) { // Dismiss redundant segment point for (j=i;j<(pn-1);j++) pel[pen].pl[j]=pel[pen].pl[j+1]; pn--; } } pel[pidx].fig=fig; pel[pidx].pn=pn; pel[pidx].plev=plevel; pel[pidx].xs=pel[pidx].pl[0].x; pel[pidx].ys=pel[pidx].pl[0].y; pel[pidx].xe=pel[pidx].pl[pn-1].x; pel[pidx].ye=pel[pidx].pl[pn-1].y; pel[pidx].offflag=0; // Return point count return(pn); } int pickpair(double pairdist,int checkglue) /* // Pick a differential pair path, build pick oriented path element lists // Return value : // 0 if pair picked, else (-1) // Parameter : // double pairdist : Pair distance return // int checkglue : Reject pick of glued path elements */ { index L_FIGURE fig /* Figure list index */; struct pointdes p1l[] /* 1st trace point list */; int p1n /* 1st trace point count */; struct pointdes p2l[] /* 2nd trace point list */; int p2n /* 2nd trace point count */; double xs1,ys1 /* 1st segment start coordinates */; double xe1,ye1 /* 1st segment end coordinates */; int lp1 /* 1st segment last point index */; double xs2,ys2 /* 2nd segment start coordinates */; double xe2,ye2 /* 2nd segment end coordinates */; int lp2 /* 2nd segment last point index */; double l1s, l1e /* 1st parallel sub segment data */; double l2s, l2e /* 2nd parallel sub segment data */; int lay1 /* First path layer */; double curdist /* Current segment distance */; int curside /* Current segment pair side */; int minfound = 0 /* Min. pair distance found flag */; int p1idx /* 1st path element index */; int p2idx /* 2nd path element index */; int side1 = 0 /* First path side */; int side2 = 0 /* Second path side */; int u1idx = 0 /* 1st path unknown side start index */; int u2idx = 0 /* 2nd path unknown side start index */; int sidx /* Segment pair info index */; int i, j, k /* Loop control variables */; // Get first trace of differential pair if (pickfullpath(UPRSELDTRC1,checkglue)) return(-1); // Store first trace p1el=pel; p1en=pen; // Get second trace of differential pair if (pickfullpath(UPRSELDTRC2,checkglue)) return(-1); // Store second trace p2el=pel; p2en=pen; // Scan first trace elements for (p1idx=0;p1idx=u1idx;k--) { if (p1el[k].fig.TYP==L_FIGUREF) break; p1el[k].side=curside; } for (;k>=u1idx;k--) p1el[k].side=side1; side1=curside; u1idx=p1idx+1; // Store side information to 1st path curside=1-curside; if (u2idx==0) side2=curside; for (k=p2idx;k>=u2idx;k--) { if (p2el[k].fig.TYP==L_FIGUREF) break; p2el[k].side=curside; } for (;k>=u2idx;k--) p2el[k].side=side2; side2=curside; u2idx=p2idx+1; } } } } } // Assume same side until end of trace for (i=u1idx;iODDANG && dang<(2.0*PI-ODDANG)) // Segments not parallel return(-1); // Normalize segment vectors normvect(sx1,sy1,slen1); normvect(sx2,sy2,slen2); // Check vector lengthes if (slen1(slen2+SMALLCVAL)) { // Get the second segment start normal crosspoint if (bae_crosssegseg( 1,xs2,ys2,xs2+nx2,ys2+ny2,xs1,ys1,xe1,ye1,cx,cy)==0) // Should not happen, treat as not parallel return(-1); // Get position on second segment vx=cx-xs1; vy=cy-ys1; if (fabs(sx1)(slen1+SMALLCVAL)) // Lines are parallel but not direct neighbours return(-1); // Store first segment sub segment start if (l1s<0.0) l1s=0.0; else if (l1s>slen1) l1s=slen1; l2s=0.0; } else { // Store second segment sub segment start if (l2s<0.0) l2s=0.0; else if (l2s>slen2) l2s=slen2; // Store first segment sub segment start l1s=0.0; } // Get the first segment end normal crosspoint if ( bae_crosssegseg(1,xe1,ye1,xe1+nx1,ye1+ny1,xs2,ys2,xe2,ye2,cx,cy)==0) // Should not happen, treat as not parallel return(-1); // Get position on second segment vx=cx-xs2; vy=cy-ys2; if (fabs(sx2)(slen2+SMALLCVAL)) { // Get the second segment end normal crosspoint if (bae_crosssegseg( 1,xe2,ye2,xe2+nx2,ye2+ny2,xs1,ys1,xe1,ye1,cx,cy)==0) // Should not happen, treat as not parallel return(-1); // Get position on second segment vx=cx-xs1; vy=cy-ys1; if (fabs(sx2)(slen1+SMALLCVAL)) // Lines are parallel but not direct neighbours return(-1); // Store first segment sub segment end if (l1e<0.0) l1e=0.0; else if (l1e>slen1) l1e=slen1; l2e=slen2; } else { // Store second segment sub segment end if (l2e<0.0) l2e=0.0; else if (l2e>slen2) l2e=slen2; // Store first segment sub segment end l1e=slen1; } return(0); } double arclength( double xs,double ys,double xc,double yc,double xe,double ye,int t) /* // Get the length of an arc segment // Return value : // segment length in meter // Parameters : // double xs, ys : Arc start coordinates // double xc, yc : Arc center coordinates // double xe, ye : Arc end coordinates // int t : Arc type */ { double ang1, ang2 /* Angle directions */; double arc /* Arc radian length value */; double r /* Arc radius */; // Get arc radius r=dist(xs,ys,xc,yc); // Get arc angles if (t==1) { ang1=angle(xc,yc,xs,ys); ang2=angle(xc,yc,xe,ye); } else { ang1=angle(xc,yc,xe,ye); ang2=angle(xc,yc,xs,ys); } arc= ang1<=ang2 ? ang2-ang1 : 2.0*PI+ang2-ang1; return(arc*r); } double ampval(double phase) /* // Calculate the amplitude value // Return value : // segment length in meter // Parameter : // double phase : Normalized phase value */ { double ramp /* Single ramp length */; double res /* Result value */; if (TRCWAVETYP==0) { phase*=2.0*PI; res=sin(phase); if (TRCWAVEF3!=0.0) res+=sin(phase*3.0)*TRCWAVEF3*0.01; if (TRCWAVEF5!=0.0) res+=sin(phase*5.0)*TRCWAVEF5*0.01; } else { ramp=TRCWAVERAMP*0.0025; if (phase0 && ((c=val[didx-1])==' ' || c=='\t')) didx--; // Get last (unit) characters c4= didx>=4 ? tolower(val[didx-4]) : '\0' ; c3= didx>=3 ? tolower(val[didx-3]) : '\0' ; c2= didx>=2 ? tolower(val[didx-2]) : '\0' ; c1= didx>=1 ? tolower(val[didx-1]) : '\0' ; // Get the units conversion factor if ((c4=='i' && c3=='n' && c2=='c' && c1=='h') || c1=='"' || c1=='\'') mulfac=25.4; else if (c3=='m' && c2=='i' && c1=='l') mulfac=0.0254; else if ((c2=='u' || c2=='\350' || c2=='\265') && c1=='m') mulfac=0.001; else mulfac=1.0; // Return the converted value return(cvtlength(mulfac*atof(convbuf),2,0)); } void checkabort() /* // Check for program abort request */ { int progressabort /* Progress bar abort flag */; // Test on program abort request if (kbhit()) { getchr(); if (verify(UPRPEXIT,0)) { bae_msgprogressterm(); error_abort(); } } bae_getintpar(43,progressabort); if (progressabort) { // Verify abort if (verify(UPRPEXIT,0)) { bae_msgprogressterm(); error_abort(); } bae_setintpar(43,0); } } // User Language program end