diff --git a/trunk/ulp/DESCRIPTION b/trunk/ulp/DESCRIPTION new file mode 100644 index 00000000..166f4987 --- /dev/null +++ b/trunk/ulp/DESCRIPTION @@ -0,0 +1,25 @@ + +User Language Programs +

+ULPs named ex-... are examples which demonstrate some features of the User Language. +They have no practical use. +

+All other programs are real applications which, of course, show the abilities of the +EAGLE User Language, too. +

+Please check our web pages for further interesting ULPs:
+http://www.cadsoftusa.com + + +User-Language-Programme +

+ULPs mit ex-... im Namen sind Beispiel-ULPs, die einige Funktionen der User-Language +erklären. Sie sind nicht für eine konkrete Anwendung geeignet. +

+Bei allen anderen Programmen handelt es sich um echte Anwendungen, die natürlich +auch als Beispiele für die Möglichkeiten der User-Language dienen. +

+Bitte sehen Sie auch auf unsere Internet-Seiten. Dort finden Sie weitere +nützliche ULPs:
+http://www.cadsoft.de + diff --git a/trunk/ulp/Felicitas_PCBSim.ulp b/trunk/ulp/Felicitas_PCBSim.ulp new file mode 100644 index 00000000..9002042e --- /dev/null +++ b/trunk/ulp/Felicitas_PCBSim.ulp @@ -0,0 +1,974 @@ +#usage "en:Felicitas PCBSim

" + "Pre-Layout Simulation (PreSim)
" + "

" + "RUN Felicitas_PCBSim /E | Export data.
" + "RUN Felicitas_PCBSim /I | Export attributes of selected instance.
" + "RUN Felicitas_PCBSim /S | Setup option
" + "RUN Felicitas_PCBSim /RELOAD | Import of simulation values." + "

" + "Wait on handshake by file polling." + "

" + "Author: alf@cadsoft.de" + , + "de:Felicitas PCBSim

" + "Pre-Layout Simulation (PreSim)
" + "

" + "RUN Felicitas_PCBSim /E | Daten-Export.
" + "RUN Felicitas_PCBSim /I | Exportiert nur die Attribute der selektierten Instanz.
" + "RUN Felicitas_PCBSim /S | Setup Option.
" + "RUN Felicitas_PCBSim /RELOAD | Import der simulierten Werte." + "

" + "Handshake erfolgt durch Datei-Polling." + "Um das ULP als Kontext einer Instanz (Symbol) zu starten, tragen Sie die unten stehende " + "Zeile in Ihre eagle.scr unter SCH: ein.
" + "SET CONTEXT instance 'PCBsim' 'RUN Felicitas_PCBSim /I';" + "

" + "Globale Attribute für die Übergabe von Werten (Design-Regeln) müssen mit 'FEL_' beginnen.
" + "Jedes globale Attribute wird mit \"@GLOBAL\" gekennzeichnet." + "

" + "Author: alf@cadsoft.de" + + +#require 6.0503 +string ULP_Version = "1.0.8"; // 1.0.2 | 2013-12-18 + // 1.0.3 | 2014-01-15 Netzliste mit allen Nicht-SUPPLY-Pins ausgeben. + // 1.0.4 | 2014-02-11 Globale Attrubte ausgeben. + // 1.0.5 | 2014-02-13 Globale Attrubte auch für ToPCBSim_SingleAttributes_txt ausgeben + // und wieder zurücklesen, inkl. aller geänderten Values und Part-Attribute. + // Home path in Linux wird richtig benutzt. + // 1.0.6 | 2014-02-17 MOVE Datei unter Windows jetzt mit Absoluten Pfad + // 1.0.7 | 2014-02-26 Anlegen des Ordner "/PCBSimExchange" unter Windows 8 berichtigt + // 1.0.8 | 2014-03-11 Usage geändert "RUN Felicitas_PCBSim" + // #require 6.0503 + +char Separator = '\t'; /* *************************************************************************** + Der Separator zum trennen der Parameter in der Zeile. + Es muß ein nicht druckbares Zeichen sein, aber nicht SPACE, + da in VALUES von Bauteilen und Attributen "SPACE" erlaubt ist. + Bauteilnamen, NET-Namen und ATTIBUTE-Namen sind immer groß geschrieben, + und können kein SPACE oder sonstige nicht druckbare ASCII-Zeichen anthalten. + ******************************************************************************/ +int Test = 0; +int PCBsim_running = 0; + +string Search_Felicitas_Execute; // "felicitas/pcbsim.exe"; + +string Exchange_Directory; + /* 2.2 Exchange Directory + The exchange directory can be given by a command line option ?-d?. + The environment variable PCBSIMEXCHANGE overwrites that default. + If neither a command line option is given nor the environment variable PCBSIMEXCHANGE is + set, the directory to exchange data defaults to + ? Windows: C:/Documents and Settings/Username/PCBSimExchange + ? Linux: ~/PCBSimExchange + */ +string UserHome[]; +int Ucnt = strsplit(UserHome, EAGLE_HOME, '/'); + +string OS_System = OS_SIGNATURE; + +if (strstr(OS_System, "Windows") == 0) { + OS_System = "Windows"; + Exchange_Directory = "/PCBSimExchange"; + Search_Felicitas_Execute = "pcbsim.exe"; // "PCBsim program Windows"; +} + +else if (OS_System == "Linux") { + // da der relative Pfad zum Homeverzeichnis ~/ u.U. Probleme machen kann, + // könnte man evtl. auch EAGLE_HOME benutzen. + //Exchange_Directory = "~/PCBSimExchange"; // 2014-02-12 Pfade nie mit / beenden + sprintf(Exchange_Directory, "%s", "/PCBSimExchange"); // 2014-02-12 Pfade immer mit / trennen + Search_Felicitas_Execute = "pcbsim"; // "PCBsim program Linux"; +} + +else if (OS_System == "MAC_OS") { + dlgMessageBox("Für MAC OS gibt es keine Version von PCBsim.", "OK"); + exit(-81); +} +else { + dlgMessageBox("Betriebssystem " + OS_SIGNATURE + " wird nicht unterstützt!", "OK"); + exit(-85); +} + +/* ***** PCBsim file definition ****** */ +string Logging_Directory = "logging"; + +string PCBSim_Present_txt = EAGLE_HOME + Exchange_Directory + "/PCBSim_Present.txt"; + /* + This file is created by PCBSim uppon start and deleted when closed. It + can be used by the CAD system to determine whether PCBSim is present or not. If in doubt, + use the command ?Ping? to determine whether PCBSim is till alive... + */ + /* ********************************************************************** + ***** PCBSim_Present.txt, 14/11/2013, 14:07:13 ***** + VERSION 1 01 Windows Beta version + @END + ********************************************************************** */ +string PCBSim_Busy_txt = EAGLE_HOME + Exchange_Directory + "/PCBSim_Busy.txt"; + /* + This file indicates that PCBSim is busy with a lenghty operation. It can be used to indicate the + status of PCBSim within the CAD system. If PCBSim is not busy anymore, it just erases that file. + The file is not logged. + It contains a message which might be used by the CAD system to display a status bar. An optional + status number is presented also. It contains an estimate on how much percent of the current task has + been done. + */ +string ToPCBSim_Command_txt = EAGLE_HOME + Exchange_Directory + "/ToPCBSim_Command.txt"; + /* + A file which contains special commands. Currently defined is + ?Version?, ?Close? and ?Ping?. Commands are NOT case sensitive. + */ +string FrPCBSim_Command_txt = EAGLE_HOME + Exchange_Directory + "/FrPCBSim_Command.txt"; + /* + The respond for special commands. Currently not used + */ +string ToPCBSim_Netlist_txt = EAGLE_HOME + Exchange_Directory + "/ToPCBSim_Netlist.txt"; + /* + Netlist written from the CAD system in order to start the simulation + with PCBSim. + */ +string ToPCBSim_AllAttributes_txt = EAGLE_HOME + Exchange_Directory + "/ToPCBSim_AllAttributes.txt"; + /* + All attributes of all components in the netlist. This file MUST + be written BEFORE ToPCBSim_Netlist.txt is written. + */ +string ToPCBSim_SingleAttributes_txt = EAGLE_HOME + Exchange_Directory + "/ToPCBSim_SingleAttributes.txt"; + /* + The attributes of a single component. It is written so that + PCBSim opens a dialog to edit the special properties of the component. For example IBIS + model, or transmission line properties. + */ +string FrPCBSim_SingleAttributes_txt = EAGLE_HOME + Exchange_Directory + "/FrPCBSim_SingleAttributes.txt"; + /* + The changed attributes of a single component. Those are used by the CAD system + to update the attributes after PCBSim has changed some properties. + */ +string FrPCBSim_AllAttributes_txt = EAGLE_HOME + Exchange_Directory + "/FrPCBSim_AllAttributes.txt"; + /* + The changed attributes of all components. This file might + contain changed attributes of a number of components. It is written after the simulation by + PCBSim and might contain changed values for termination resistors or other components. + */ + /* ************************************************************************************************ + A transaction is started by the CAD system writing one of the ?ToPCBSim...? files. PCBSim reacts + accordingly. When PCBSim is finished, it first writes any result files (FrPCBSim...) and then deletes + the files ?ToPCB...? from the directory (rather moves them to the logging directory). The deletion of + the files is the signal for the CAD system that PCBSim has finished. It can then process any + ?FrPCBSim...? files if there are any. + As soon as the CAD system has finished processing the ?FrPCBSim...? files, it moves them to the + logging directory. + After a complete transaction, the exchange directory is empty again. + ************************************************************************************************* */ + + +string Executable = ""; // Pfad-Dateiname zum Executable-Programm +string EagleExecute = EAGLE_PATH; + +int Ex_WaitOnHandShake = 1; // flag for response of external executable has changed the data file + +string FileNewTemp = "wtD"; // option for function output() for generate temporary file (script). +string FileAppend = "at"; // option for function output() append data to existing file. +string ScriptFile = ""; + +int ExportAll = 1; + +char SearchStartDrive = 'C'; // *** first Windows-System drive *** +string StartFolder; // the ground path +char SearchLastDrive = 'Z'; // 'Z' *** last Windows-System drive *** + +int SearchnRoot; +string SearchRoot[]; + +string SearchFiles[]; +int SearchStart, SearchEnd; +string a[]; +int SearchIs_UNC; +int CntSubDirIteration = 4; // maximal bis in den 4. Unterordner suchen + + +string GlobalAttribute = "@GLOBAL"; // Markierung der globalen Attribute des Schaltplan für die Definition der Design-Regeln im Schaltplan +int PCBsimGlobalAttributeCount = 10; // +int CntNewI = 0; +string NewInstancePart[]; + +string SearcheLibrary = "/felicitas/felicitas-simulation.lbr"; +string FelicitasSimulationLbr; +string Cmd = ""; + + + +/* ################## Functions ####################### */ +string showsyscommand(string command, string call, string debug) { + dlgDialog("show command") { + dlgLabel("Call from: " + call); + dlgLabel("Debug: " + debug); + dlgHBoxLayout dlgSpacing(800); + dlgHBoxLayout { + dlgLabel("system("); + dlgStringEdit(command); + dlgLabel(")"); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); exit(-209); } + dlgStretch(1); + } + }; + return command; +} + + +/* *************** file functions ********** */ +// change Eagle slash in path names to backslash for windows +string lash2backslash(string f) { + string s[]; + int cnt = strsplit(s, f, '/'); + return strjoin(s, '\\'); +} + +// change backslash in windows path names to Eagle slash +string backslash2lash(string f) { + string s[]; + int cnt = strsplit(s, f, '\\'); + return strjoin(s, '/'); +} + +int make_sub_dir(string root, string subdir) { /*** generate DOS command MKDIR ***/ + if (OS_System == "Windows") { /* ** generate DOS command MKDIR ** */ + string doscommand; + sprintf(doscommand, "CMD.EXE /C MKDIR \"%s%s\"", lash2backslash(root), lash2backslash(subdir)); + if (Test) doscommand = showsyscommand(doscommand, "(Test) make directory", ""); + system(doscommand); + } + + else { + string linuxshellscript; + // mkdir ist das offizielle Komando! + // md kann auch funktionieren, muß aber nicht! + // bei ~/... für den Home-Pfad darf man den Pfad nicht in " " einschliessen, + // sonst wird die Tilde ~ nicht ausgewertet! + // Wegen evtl. Leerzeichen im Pfad, ist es besser EAGLE_HOME + "/" als Pfad zu benutzen, eingeschlossen in " ". + string sd[], s; + int cnt = strsplit(sd, subdir, '/'); + string mk; + sprintf(mk, "mkdir %s%s", root, sd[0]); // setze den Grundpfad + for (int n = 1; n < cnt; n++) { + sprintf(s, "%s/%s\n", mk, sd[n] ); + mk += "/" + sd[n]; // der erweiterte Pfad ist jetzt der Grundpfad + linuxshellscript += s; + } + + if (Test) linuxshellscript = showsyscommand(linuxshellscript, "(Test) make directory", ""); + + system(linuxshellscript); + } + string f[]; + int n = fileglob(f, root + subdir); // prüfe ob das Verzeichnis angelegt werden konnte. + return n; +} + +void move_and_rename_to_logging(string f) { + if (OS_System == "Windows") { /* ** generate DOS command MKDIR ** */ + string doscommand; + /* + Um eine oder mehrere Dateien zu verschieben: + MOVE [/Y| /-Y] [Laufwerk:][Pfad]Datei1[,...] Ziel + + Um ein Verzeichnis umzubenennen: + MOVE [/Y| /-Y] [Laufwerk:][Pfad]Verz1 Verz2 + + [Laufwerk:][Pfad]Datei1 Bezeichnet den Pfad und den Namen der zu + verschiebenden Datei(en). + Ziel Bezeichnet den Zielort für die Datei. Das Ziel + kann ein Laufwerkbuchstabe mit Doppelpunkt, ein + Verzeichnisname oder eine Kombination beider sein. + Wenn Sie nur eine einzelne Datei verschieben, + können Sie auch einen Dateinamen angeben, um die + Datei beim Verschieben umzubenennen. + [Laufwerk:][Pfad]Verz1 Bezeichnet das umzubenennende Verzeichnis. + Verz2 Bezeichnet den neuen Namen des Verzeichnisses. + /Y Unterdrückt die Bestätigungsaufforderung zum + Überschreiben bestehender Zieldateien. + /-Y Fordert vor dem Überschreiben bestehender + Zieldateien zur Bestätigung auf. + Die Option /Y ist in der COPYCMD-Umgebungsvariablen eventuell voreingestellt. + */ + + string fext; // file extension + sprintf(fext, ".%s.txt", t2string(time(), "Uyyyy-MM-dd hh_mm_ss")); + sprintf(doscommand, "CMD.EXE /C MOVE \"%s\" \"%s\"", + lash2backslash(f), + lash2backslash(filedir(f)) + lash2backslash(Logging_Directory + "/" + filesetext(filename(f), fext)) // 2014-0217 + ); + if (Test) { + dlgDialog("(Test) move") { + dlgHBoxLayout dlgSpacing(900); + dlgTextEdit(doscommand); + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-305); } + } + }; + } + system(doscommand); + } + else { // move file for Linux + string linuxshellscript; + string fext; // file extension + sprintf(fext, ".%s.txt", t2string(time(), "Uyyyy-MM-dd hh_mm_ss")); + sprintf(linuxshellscript, "mv \"%s\" \"%s\"", // Linux braucht für das Ziel den kompletten Pfad + f, + filedir(f) + Logging_Directory + "/" + filesetext(filename(f), fext) // 2014-02-17 + ); + if (Test) { + dlgDialog("(Test) move") { + dlgHBoxLayout dlgSpacing(900); + dlgTextEdit(linuxshellscript); + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-328); } + } + }; + } + system(linuxshellscript); + } + return; +} + +int check_directory(string dir) { + string fdir[]; + return fileglob(fdir, dir); +} + +int check_exist_file(string path, string ckfile) { + return fileglob(SearchFiles, path + ckfile); +} + +// ein Windows-Laufwerk beginnt mit "Buchstabe:\" +// suche nach ":/" hinter dem Laufwerksbuchstaben +void check_windows_root(void) { + string drv; + for(int d = SearchStartDrive; d <= SearchLastDrive; d++) { + sprintf(drv, "%c:/", d); + if (check_exist_file(drv, "/")) { + SearchRoot[SearchnRoot] = drv; + SearchnRoot++; + } + } + return; +} + + +/* *********************** die Suchschleife ****************************************************** */ +// searchfile = die zu suchende Datei +// root = der Start-Pfad ab dem gesucht werden soll, inkl. Laufwerkbuchstabe unter Windows +// maxiteration = die Tiefe, Anzahl der Verzweigung (Unterordner) ab dem root Pfad. +/* *********************************************************************************************** */ +string file_search(string root, string searchfile, int maxiteration, string debugnum) { + if (!root) { + if (debugnum == "init") { + dlgMessageBox("RUN '" + filesetext(argv[0], "") + "' with option Setup: " + searchfile, "CANCEL"); + } + else { + if (dlgMessageBox(debugnum + "\nUnknown path of file : "+searchfile, "OK", "CANCEL") == 0) return ""; + } + exit(-374); + } + int len = strlen(root); + if (root[len-1] != '/') root += "/"; // root muß mit Slash enden! + if (!check_exist_file(root, "")) { // den Pfad prüfen + return ""; + } + // *** Betriebsystem feststellen *** + // ******* Windows Laufwerke ******* + if (root) { + SearchRoot[0] = root; + SearchnRoot = 1; + } + else { + check_windows_root(); // unter Windows die Laufwerke ermitteln + } + + int n, r; + SearchStart = 0; + SearchEnd = SearchnRoot; + int iteration = 1; + int finish = 0; + int cntf; + string searchfoundfile[]; + string h; + + do { + // 1. die Root-Ordner nach der Datei durchsuchen + for (r = SearchStart; r < SearchEnd; r++) { + status(SearchRoot[r]); // Anzeige des aktuellen Verzeichnisnamen + n = check_exist_file(SearchRoot[r], searchfile); // suche im Verzeichnis nach Datei + if (n) { + for (int f=0; f 1) { + s = ""; + for (int i = 0; i < cnt; i++) { + if (i == 0) { + if (t[i]) s += t[i]; + } + else if (i) s += "''" + t[i]; + } + } + return s; +} + +void readconfig(void) { // read configuration file of ULP + Executable = cfgget("ULP:felicitas.Executable"); + return; +} + +void saveconfig(void) { + cfgset("ULP:felicitas.Executable", Executable); + return; +} + +void call_system(string exportfile, string debug) { // DOS comand execute + string syscommand; + // Das executable und der Dateiname müssen in " " eingeschlossen werden, wegen Spaces im Pfad-Dateinamen! + sprintf(syscommand, "CMD.EXE /C \"%s\" \"%s\"", lash2backslash(Executable), lash2backslash(ToPCBSim_Netlist_txt)); + if (Test) syscommand = showsyscommand(syscommand, "(Test) call_system()", debug); + system(syscommand); // externes Programm starten + return; +} + +/* ************************************* + ********** Reload - Import ************ + ************************************* */ +// check if exist attribute and has changed the value +int checkatt(string p_name, string att_name, string att_value) { + sheet(S) { + S.instances(I) { + if (ingroup(I) || strupr(argv[1]) == "/E") { // mit Iption /E werden alle Parts geprüft/geändert + if (I.part.name == p_name) { + if (att_name == "VALUE") { + if (I.part.value == att_value) return 0; // value is the sam, do nothing + else return 1; // value is changed + } + else { + I.part.attributes(A) { + if (A.name == att_name) { + if (A.value == att_value) return 0; // value is the sam, do nothing + else return 1; // value is changed + } + } + return 1; // returns a new attribute from PCBsim + } + } + } + } + } + return 0; +} + +void set_attributes(string valuelines) { + string line[]; + int cntlines = strsplit(line, valuelines, '\n'); + string cmd, s; + for (int n = 0; n < cntlines; n++) { + string v[]; + int cnt = strsplit(v, line[n], Separator); + if (cnt > 1) { + if (v[0] == GlobalAttribute) { // 2014-02-12 set global attributes + sprintf(s, "ATTRIBUTE * '%s' '%s';\n", v[1], v[2]); + cmd+=s; + } + else if (checkatt(v[0], v[1], v[2])) { + if (v[1] == "VALUE") { + sprintf(s, "VALUE '%s' '%s';\n", v[0], v[2]); + cmd+=s; + } + else { + sprintf(s, "CHANGE DISPLAY OFF;\n"); + cmd+=s; + sprintf(s, "ATTRIBUTE '%s' '%s' '%s';\n", v[0], v[1], v[2]); + cmd+=s; + } + } + } + else { + if (v[0][0] == '*') { + // Nur die Kopfzeile (Kommentar), wird nicht ausgewertet + } + else if (v[0] == "@END") { + break; + } + } + } + if (Test) dlgDialog("(Test) Die Rückgabewerte") { + dlgHBoxLayout dlgSpacing(600); + dlgTextEdit(valuelines); + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); exit(-550); } + dlgStretch(1); + } + }; + exit(cmd); +} + +/* ************************************ + ********* Export functions *********** + ************************************ */ +int newpart(UL_INSTANCE I) { // 2014-02-12 check exits this part of instance on list + for (int n = 0; n < CntNewI; n++) { + if (NewInstancePart[n] == I.part.name) return 0; + } + NewInstancePart[CntNewI++] = I.part.name; + return 1; +} + +void ex_attrib_value(UL_INSTANCE I) { // 2014-02-12 + printf("%s%cVALUE%c%s\n", I.part.name, Separator, Separator , I.part.value); + I.part.attributes(A) { + if (A.name != "_EXTERNAL_") printf("%s%c%s%c%s\n", I.part.name, Separator, A.name, Separator, A.value); + } + return; +} + +void ex_draw_net_wire(UL_SEGMENT SEG, string netname) { + SEG.pinrefs(P) { + if (P.pin.direction != PIN_DIRECTION_SUP) { // 2014-01-15 keine Supply-Pins ausgeben + printf("@Part%c%s%c%s%c%s\n", Separator, P.part.name, Separator, P.pin.name, Separator, netname); + } + } + return; +} + +void ex_globalattribute(UL_SCHEMATIC SCH) { // 2014-02-11 + int cnta = 0; + SCH.attributes(A) { + if (strstr(A.name, "FEL_") == 0) { // nur Attribute die mit "FEL_" beginnen werden exportiert + cnta++; + printf("%s%c%s%c%s\n", GlobalAttribute, Separator, A.name, Separator, A.value); + } + } + if (cnta < PCBsimGlobalAttributeCount) { + dlgMessageBox("!Not enough global attributes \"FEL_...\" defined.\nFirst define global attributes for PCBsim (Design-Rules).", "OK"); + exit("ATTRIBUTE *"); + } +} + +void ex_attribute(UL_PART P) { // für Option /I nur die Attribute dieser Instance ausgeben + printf("%s%cVALUE%c%s\n", P.name, Separator, Separator, P.value); + P.attributes(A) { // Das Attribute _EXTERNAL_ wird nicht ausgegeben, da es speziell für Bauteile + // reserviert ist, die nur für Simulation oder Dokumentation vorgesehen sind, + // und daher kein Package besitzen dürfen, um nicht im Board zu erscheinen. + if (A.name != "_EXTERNAL_") printf("%s%c%s%c%s\n", P.name, Separator, A.name, Separator, A.value); + } + return; +} + +void ex_pinlist(UL_PART PA) { + /* + Definition der Pinlist: + Part-Name __Kennung__ Pin-Name Pad-Name Net-Name + Besitzt der Pin keinen Conntact (Pad) wird er mit *_PCBsim_* markiert. + Ist der Pin an keinem Net angeschlossen, wird er mit *_not_connected_* markiert. + */ + PA.instances(I) { + I.gate.symbol.pins(P) { + string netcontact = P.net; + if (!netcontact) netcontact = "*_not_connected_*"; // Pin ist an keinem Net angeschlossen + int cntcont = 0; // Contactzähler für die Pads + P.contacts(C) { + printf("%s%c__PinList__%c%s%c%s%c%s\n", PA.name, Separator, Separator, P.name, Separator, C.name, Separator, netcontact); + cntcont++; + } + if (!cntcont) { /* Pin hat keinen Contact zu einem PAD (also ohne Package), + dann wird als Kennung *_PCBsim_* ausgegeben. + */ + printf("%s%c__PinList__%c%s%c%s%c%s\n", PA.name, Separator, Separator, P.name, Separator, "*_PCBsim_*", Separator, netcontact); + } + } + } + return; +} + +/* **** EXPORT menu **** */ +void ex_setupmenu(void) { + string schexportname; + dlgDialog("Eagle-felicitas Setup") { + dlgHBoxLayout dlgSpacing(200); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); exit(-2); } + dlgStretch(1); + dlgLabel(ULP_Version); + } + }; + saveconfig(); + return; +} + + +void autosetupinfo(string dlgheader) { + dlgDialog(dlgheader) { + dlgGridLayout { + dlgCell( 0, 1) dlgLabel("Program:"); + dlgCell( 0, 2) dlgLabel(EAGLE_SIGNATURE); + dlgCell( 1, 1) dlgLabel("System:"); + dlgCell( 1, 2) dlgLabel(OS_SIGNATURE); + dlgCell( 2, 1) dlgLabel("Eagle Path:"); + dlgCell( 2, 2) dlgLabel(EAGLE_PATH); + dlgCell( 3, 1) dlgLabel("Eagle Dir:"); + dlgCell( 3, 2) dlgLabel(EAGLE_DIR); + dlgCell( 4, 1) dlgLabel("User Dir:"); + dlgCell( 4, 2) dlgLabel(EAGLE_HOME); + dlgCell( 5, 1) dlgLabel("


"); + dlgCell( 5, 2) dlgLabel("
"); + dlgCell( 6, 1) dlgLabel("Executable"); + dlgCell( 6, 2) dlgLabel(Executable); + dlgCell( 7, 1) dlgLabel("FelicitasLibDir"); + dlgCell( 7, 2) dlgLabel(FelicitasSimulationLbr); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + //dlgPushButton("-CANCEL") {dlgReject(); exit(-10); } + dlgStretch(1); + if (dlgheader == "Diagnose") { + dlgPushButton("Save") { + string rptfile = filesetext(argv[0], ".fel"); + output(rptfile, "wt") { + printf("Program:%c%s\n", Separator, EAGLE_SIGNATURE); + printf("System:%c%s\n", Separator, OS_SIGNATURE); + printf("Eagle Path:%c%s\n", Separator, EAGLE_PATH); + printf("Eagle Dir:%c%s\n", Separator, EAGLE_DIR); + printf("User Dir:%c%s\n", Separator, EAGLE_HOME); + printf("Executable:%c%s\n", Separator, Executable); + printf("FelicitasLibDir:%c%s\n", Separator, FelicitasSimulationLbr); + } + dlgMessageBox("Saved to:"+rptfile, "OK"); + } + } + } + }; + return; +} + +void reload(void) { + string frpcbsim_singleattributes_txt; + string frpcbsim_allattributes_txt; + int answer = 0; // für Datei-Hand-Shake + do { + if (check_exist_file(FrPCBSim_SingleAttributes_txt, "")) { + fileread(frpcbsim_singleattributes_txt, FrPCBSim_SingleAttributes_txt); + //move and rename to logging dir // = "FrPCBSim_SingleAttributes.txt"; + move_and_rename_to_logging(FrPCBSim_SingleAttributes_txt); + set_attributes(frpcbsim_singleattributes_txt); + answer = 1; + } + if (check_exist_file(FrPCBSim_AllAttributes_txt, "")) { + fileread(frpcbsim_allattributes_txt, FrPCBSim_AllAttributes_txt); + //move and rename to logging dir // = "FrPCBSim_SingleAttributes.txt"; + move_and_rename_to_logging(FrPCBSim_AllAttributes_txt); + set_attributes(frpcbsim_allattributes_txt); + answer = 1; + } + sleep(1); // 1 Sekunde warten, ohne CPU-Last + } while (!answer); + + exit(-718); // hier kommt das Programm niemals her. +} + +/* *********************** + ******** MAIN *********** + *********************** */ +readconfig(); + +if (!Executable || argv[1] == "/S") { + string rootpath[]; + if (OS_System == "Windows" ) { + rootpath[0] = "C:/Programme/"; + rootpath[1] = "C:/Program files (x86)/"; + rootpath[2] = "C:/Program files/"; + rootpath[3] = "D:/Program files (x86)/"; + rootpath[4] = "D:/Program files/"; + rootpath[5] = "E:/Programme"; + rootpath[6] = "C:/"; + } + else if (OS_System == "Linux" ) rootpath[0] = "//"; + else { + dlgMessageBox("!PCBsim runs not on MAC OS", "OK"); + exit(-740); + } + int nroot = 0; + do { + Executable = file_search(rootpath[nroot],Search_Felicitas_Execute, 3, "550"); + nroot++; + } while (!Executable && rootpath[nroot]); + + if (!Executable) { + dlgMessageBox("!felicitas (" + Search_Felicitas_Execute + ") not found.", "OK"); + Executable = dlgFileOpen(Search_Felicitas_Execute); + if (!Executable) exit(-751); + } + + int pos = strstr(EagleExecute, "bin/"); // nur den Hauptpfad zu den Unterordnern + string eagleroot = strsub(EagleExecute, 0, pos); + + // durchsuche alle Pfade nach der LBR + // string cfgdirlbr = cfgget("EAGLE:Directories.Lbr"); + // den Pfad unter Optionen Verzeichnisse zu den LBRs! + for (int fn = 0; path_lbr[fn]; fn++) { + //if (dlgMessageBox("Suche in " + path_lbr[fn] + " nach " + SearcheLibrary, "ok", "esc") != 0) exit(568); + FelicitasSimulationLbr = file_search( path_lbr[fn], SearcheLibrary, 1, "-644"); // die Symbole zum simulieren + if (FelicitasSimulationLbr) break; + } + if (!FelicitasSimulationLbr) { + dlgMessageBox("!Default felicitas simulation library " + SearcheLibrary + "\nnot found:\n" + EAGLE_DIR + "..\n\n" + + "Please check path: Controlpanel - Options - Libraries" , "CANCEL"); + // 2013-10-01 Pfadtrenner nach EAGLE_DIR und lbr... + exit(-768); + } + + autosetupinfo("Auto Setup Info"); + saveconfig(); + // die felicitas LBR in die USE-Liste eintragen! + string uselbr; + sprintf(uselbr, "USE -*;\nUSE '%s';", FelicitasSimulationLbr); + // Pfade immer in ' (Apostroph) einschließen, besonders bei Windows 7/8 64-Bit, + // da es den Ordner "Programm (x86)" gibt, und die Klammern () von Eagle als Koordinate ausgewertet werden! + // für die felicitas.lbr muß der absolute Pfad angegeben werden. + if (dlgMessageBox("Die USE-Liste ändern?\n\n" + uselbr, "OK", "CANCEL") != 0) exit(-780); + exit(uselbr); +} + +// 1. check exist used directory +if (!check_directory(EAGLE_HOME + Exchange_Directory + "/" + Logging_Directory)) { + if (!make_sub_dir(EAGLE_HOME, Exchange_Directory + "/" + Logging_Directory)) { // 2014-02-26 + if (dlgMessageBox("can't make directory :" + EAGLE_HOME + Exchange_Directory + "/" + Logging_Directory + "\nPlease check rights and the path.", "OK", "CANCEL810") != 0) exit(-788); + exit(-787); + } +} + +// 2. check is PCBsim running +if (check_exist_file(PCBSim_Present_txt, "")) { + string pcbsimpresent[]; + int n = fileread(pcbsimpresent, PCBSim_Present_txt); + // "VERSION 1 01 Windows Beta version" + //dlgMessageBox("PCBsim " + pcbsimpresent[1] + " is running!", "OK"); + PCBsim_running = 1; +} +else { + if (Test) dlgMessageBox("PCBsim start now!", "OK"); // die Meldung, das PCBsim jetzt zum ersten mal gestartet wird. + PCBsim_running = 0; +} + +// 3. check if PCBsim is busy +if (check_exist_file(PCBSim_Busy_txt, "")) { + string pcbsymbusy; + int n = fileread(pcbsymbusy, PCBSim_Busy_txt); + dlgMessageBox(pcbsymbusy + "\n\n" "Please try later.", "OK"); + exit(-809); + do { + sleep(1); // sleep 1 seconds to check if file time changed + } while (check_exist_file(PCBSim_Busy_txt, "")); + dlgMessageBox("PCBsym are now ready.", "OK"); + exit(-814); +} + +/* ***************************** + ******** main Import ********** + ***************************** */ +if (argv[1] == "/RELOAD") { /* **** Laden der berechneten Rückgabewerte **** */ + status("reload "); + string reload_text = argv[2]; + status("wait on PCBsim to reload " + reload_text); + int n = 0; + do { + sleep(1); // sleep 1 second to new check + n = check_exist_file(reload_text, ""); + if (Test) { + string h; + sprintf(h, "(Test) file %s are exist %d", reload_text, n); + if (dlgMessageBox(h, "ok", "esc") != 0) exit(-831); + } + } while(n); + status("start handshake.."); + reload(); +} + +/* ************************* + ******** Diagnostic ******* + ************************* */ +if (strupr(argv[1]) == "/?") { // 2013-10-01 + //autosetupinfo("Diagnose"); + dlgDialog("Help") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(200); + dlgTextView(usage); + } + dlgHBoxLayout { + dlgLabel("System: "+OS_SIGNATURE); + dlgStretch(1); + dlgLabel("ULP Version : " + ULP_Version); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("OK") dlgAccept(); + dlgStretch(1); + } + }; + exit(-862); +} + +/* ****************************** + ******** main Export *********** + ****************************** */ +if (strupr(argv[2]) == "/S") { + ex_setupmenu(); + exit(0); +} + +if(board) { + dlgMessageBox("Die Option der Board-Simulation ist noch nicht verfügbar!", "OK"); + exit(-875); +} +if (schematic) schematic(SCH) { + if (strupr(argv[1]) == "/E" || strupr(argv[1]) == "/I") { + if (Test) if (dlgMessageBox("(Test) Export Schematic to:\n" + ToPCBSim_Netlist_txt, "OK", "CANCEL") != 0) exit(-879); + sheet(S) { + if (strupr(argv[1]) == "/E") { + S.nets(N) { + N.segments(SEG) { + if(ingroup(SEG)) { + ExportAll = 0; + break; + } + } + if (!ExportAll) break; + } + output(ToPCBSim_AllAttributes_txt, "wt") { // make a new file + printf("***** %s, %s *****\n", ToPCBSim_AllAttributes_txt, t2string(time(), "Uyyyy/MM/dd, hh:mm:ss")); + ex_globalattribute(SCH); + S.instances(I) { + if (newpart(I)) { // 2014-02-12 export the Attributes of part only once + ex_attrib_value(I); + } + } + } + output(ToPCBSim_Netlist_txt, "wt") { + printf("***** %s, %s *****\n", ToPCBSim_Netlist_txt, t2string(time(), "Uyyyy/MM/dd, hh:mm:ss")); + printf("***** %s Version %s *****\n", filename(argv[0]), ULP_Version); + S.nets(N) N.segments(SEG) { + if (ingroup(SEG) || ExportAll) { + ex_draw_net_wire(SEG, N.name); + } + } + printf("@END"); + } + output(ToPCBSim_AllAttributes_txt, "at") printf("@END"); // write @END + } + else if (strupr(argv[1]) == "/I") { // nur die Attribute dieser Instance + S.instances(I) { + if (ingroup(I)) { + output(ToPCBSim_SingleAttributes_txt, "wt") { // make a new file + printf("***** %s, %s *****\n", ToPCBSim_SingleAttributes_txt, t2string(time(), "Uyyyy/MM/dd, hh:mm:ss")); + ex_globalattribute(SCH); // 2014-02-12 + ex_attribute(I.part); + ex_pinlist(I.part); + printf("@END"); // write @END + } + break; + } + } + } + + status(" ..waiting to return of "+filename(Executable)); + + if (Ex_WaitOnHandShake) { /* *** Handshake über Datei-Polling *** */ + status("wait on handshake of PCBsim"); + // Wenn PCBsim schon läuft, reicht es, wenn die Datei geschrieben wurde, + // ansonsten muß PCBsim gestartet und die Datei übergeben werden. + if (!PCBsim_running) { + string syscommand; + if (OS_System == "Windows") { + //sprintf(syscommand, "CMD.EXE /C \"%s\" \"%s\"", lash2backslash(Executable), lash2backslash(ToPCBSim_Netlist_txt)); + // *** call external programm, exit from call directly on WINDOWS XP *** + sprintf(syscommand, "\"%s\" \"%s\"", lash2backslash(Executable), lash2backslash(ToPCBSim_Netlist_txt)); + if (Test) syscommand = showsyscommand(syscommand, "(Test) Main /E xport SCH", "Ex_WaitOnHandShake"); + system(syscommand); // externes Programm starten + } + else if (OS_System == "Linux") { + sprintf(syscommand, "\"%s\" < \"%s\" &", Executable, ToPCBSim_Netlist_txt); // der Linux programm aufruf mit & + if (Test) syscommand = showsyscommand(syscommand, "(Test) Main /E xport SCH", "Ex_WaitOnHandShake"); + system(syscommand); // externes Programm starten + } + } + if (Test) if (dlgMessageBox("(Test) Jetzt Daten zurück lesen!", "OK", "ESC") != 0) exit(-948); + reload(); + exit(0); + } + else { + /* ***************************************************************************************** + Kein Handshake, das ULP wartet auf die Beendigung des aufgerufenen Programm (DOS-BOX) + und kehrt dann zum aufrufenden Fenster zurück. + Vorteil, das Fenster (Schaltplan) hat den Fokus wieder! + ****************************************************************************************** */ + if (OS_System == "Windows") { /* ** generate DOS command MKDIR ** */ + call_system(ToPCBSim_Netlist_txt, "NO handshake, wait on return from system call"); + } + else if (OS_System == "Linux") { + ; + } + reload(); + } + } + } +} +else { + dlgMessageBox("Start this ULP in a schematic!", "OK"); + exit(-971); +} + diff --git a/trunk/ulp/README b/trunk/ulp/README new file mode 100644 index 00000000..dbce6f21 --- /dev/null +++ b/trunk/ulp/README @@ -0,0 +1 @@ +Please see docs/pcbgcode.pdf. diff --git a/trunk/ulp/bom.ulp b/trunk/ulp/bom.ulp new file mode 100644 index 00000000..1603413e --- /dev/null +++ b/trunk/ulp/bom.ulp @@ -0,0 +1,694 @@ +#require 6.5100 + +// Revision history: +// +// 1.00 +// - Initial release +// +// 1.01 +// - Dialog mask for text or html output selection corrected +// +// 1.02 +// - CSV export added after a suggestion of Christian Schlittler +// - File extension for text file output changed from .bom to .txt +// +// 1.03 +// - Added missing description column in value mode. +// +// 1.04 +// - List also Packages bei Value +// +// 1.05 +// - 2012-03-01 change PartValue[], PartDevice[], PartPackage[], PartHeadline[], PartDescription[] to normal string. alf@cadsoft.de +// numeric strings with only numericasl characters, sorts up to 8 characters! +// +// 1.06 +// - 2012-05-25 support now populated variants +// switch on/off attributes +// is now the standard bom.ulp alf@cadsoft.de +// +// 1.07 +// - 2012-06-22 set correct variant +// +// 1.08 +// - 2012-11-08 list different values of attributes +// +// 1.09 +// - 2012-12-04 now can change the separator character for CSV files. +// change the character in line Separator = ','; +// +// 1.10 +// - 2014-08-07 extended to V7 hierarchical schematic +// +// Revision: 1.10 +// + +string Version = "1.10"; + +char Separator = ';'; // 2012-12-04 + + +#usage "en: Export a Bill Of Material\n" + "

" + "Generates a project's Bill Of Material  including the attributes introduced in" + " version 5.0.0." + "

" + "Author: support@cadsoft.de
" + "Modified to use the new attributes by Carsten Wille.
" + ".csv export added by Christian Schlittler." + "Select variant and switch on/off attributes alf@cadsoft.de", + "de: Stückliste exportieren\n" + "

" + "Erzeugt die Stückliste (Bill Of Material) eines Projekts, einschließlich der" + " mit Version 5.0.0 neu eingeführten Attribute." + "

" + "Autor: support@cadsoft.de
" + "Modifiziert von Carsten Wille, um die neuen Attribute zu nutzen.
" + "Export als .csv-Datei durch Christian Schlittler hinzugefügt." + "Auswählen von Bestückungs-Varianten und Attribute können ein/ausgeschaltet werden alf@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string HelpTextEN = + "How to generate the Bill Of Material\n" + "

\n" + "List type\n" + "

\n" + "The Bill Of Material can be generated either as a list\n" + "of parts (where every part is listed on a line of its own),\n" + "or as a list of values, where all parts with the same value are grouped\n" + "together in one line. Use the Parts and Values\n" + "radio buttons to select the list type.\n" + "

\n" + "Output format\n" + "

\n" + "Choose between pure ASCII Text format, CSV or HTML.\n" + ; + +string HelpTextDE = + "Erzeugen der Stückliste\n" + "

\n" + "Listen-Typ\n" + "

\n" + "Die Stückliste kann entweder als Liste der Bauteile generiert werden\n" + "(wobei jedes Bauteil in einer eigenen Zeile aufgeführt wird),\n" + "oder als Liste der Werte, wobei alle Bauteile mit dem gleichen Wert in einer Zeile\n" + "zusammengefasst werden. Mit den Radio-Buttons Bauteile und Werte\n" + "kann zwischen den beiden Listen-Typen gewählt werden.\n" + "

\n" + "Ausgabeformat\n" + "

\n" + "Wählen Sie zwischen reinem ASCII-Text, CSV oder HTML" + "-Format.\n" + ; + +string I18N[] = { + "en\v" + "de\v" + , + "


ERROR: No schematic!

\nThis program can only work in the schematic editor.\v" + "


FEHLER: Kein Schaltplan!

\nDieses Programm kann nur in einem Schaltplan verwendet" + " werden.\v" + , + "Part\tValue\tDevice\tPackage\tDescription\v" + "Bauteil\tWert\tDevice\tPackage\tDescription\v" + , + "Qty\tValue\tDevice\tPackage\tParts\v" // 2011-04-08 + "Menge\tWert\tDevice\tGehäuse\tBauteile\v" // 2011-04-08 + , + "Partlist exported from %s at %s\v" + "Stückliste exportiert aus %s am %s\v" + , + "Bill Of Material - Preview\v" + "Stückliste - Vorschau\v" + , + "-Close\v" + "-Schließen\v" + , + "Save Bill Of Material\v" + "Stückliste speichern\v" + , + "File '\v" + "Datei '\v" + , + "' exists\n\nOverwrite?\v" + "' existiert\n\nÜberschreiben?\v" + , + "+&Yes\v" + "+&Ja\v" + , + "-&No\v" + "-&Nein\v" + , + "&No\v" + "&Nein\v" + , + "Name already defined!\v" + "Name ist bereits definiert!\v" + , + " Header\v" + " Spaltenüberschrift\v" + , + "&Name:\v" + "&Name:\v" + , + "+OK\v" + "+OK\v" + , + "Name can't be empty!\v" + "Name kann nicht leer sein!\v" + , + "-Cancel\v" + "-Abbrechen\v" + , + "&Headers\v" + "&Spaltenüberschriften\v" + , + "Bill Of Material - Help\v" + "Stückliste - Hilfe\v" + , + "Bill Of Material\v" + "Stückliste\v" + , + "List type\v" + "Listen-Typ\v" + , + "&Parts\v" + "&Bauteile\v" + , + "&Values\v" + "&Werte\v" + , + "Output format\v" + "Ausgabeformat\v" + , + "&Text\v" + "&Text\v" + , + "&CSV\v" + "&CSV\v" + , + "&HTML\v" + "&HTML\v" + , + "+Vie&w\v" + "+&Vorschau\v" + , + "&Save...\v" + "&Speichern...\v" + , + "H&elp\v" + "H&ilfe\v" + , + "Current &variant \v" + "Aktuelle &Variante \v" + , + "List &attributes\v" + "&Attribute auflisten\v" + }; +int Language = strstr (I18N [0], language ()) / 3; + + +string tr (string s) +{ + string t = lookup (I18N, s, Language, '\v'); + return t ? t : s; +} + + +if (!schematic) +{ + dlgMessageBox (usage + tr ("


ERROR: No schematic!

\nThis program can only work in" + " the schematic editor.")); + exit (1); +} + +string SeparatorString; +int NumParts; +numeric string Lines[]; +numeric string PartName[]; +string PartValue[], PartDevice[], PartPackage[], PartHeadline[]; +numeric string PartDescription []; +int PartValueOn[]; +int Selected; + +string CurrentVariant = ""; +string Variants[] = { "" }; // 2012-04-16 +int cntVD = 0; +int VDsel = 0; + + +// cwi: Added arrays for an arbitraty number of attributes. +int UseAttributes = 1; +int FoundAttributes = 0; // # of different attribute names found in schematic. +numeric string AttributesList[]; // Sorted list of all attributes found in the schematic. +numeric string PartAttributes[]; // Adjusted list of attributes per part. + +enum { ltParts, ltValues }; // List Types +enum { ofText, ofCSV, ofHTML }; // Output Formats +int ListType = 0; +int OutputFormat = 0; + + +string StripWhiteSpace (string s) +{ + while (s && isspace (s[0])) + s = strsub (s, 1); + while (s && isspace (s[strlen (s) - 1])) + s = strsub (s, 0, strlen (s) - 1); + return s; +} + + +// Collect part data from the schematic. +// +// Arguments: - +// +// Returns: NumParts - # of found parts +// ParteName[] +// PartValue[] +// PartDevice[] +// PartPackage[] +// PartHeadline[] +// PartDescription [] +// PartValueOn[] - 0=part value off, 1= part value on, 2=override with attr. VAL +// FoundAttributes - # of different attribute names found in schematic. +// AttributesList[] - Sorted list of all attributes found in the schematic. +// PartAttributes[] - Adjusted list of attributes per part. + +void CollectPartData (string var) +{ + int Found = 0; + int i; + string attr[]; + + NumParts = 0; + + // First, collect the names of all available attributes. + FoundAttributes = 0; + if (UseAttributes) { + schematic (SCH) + { + SCH.allparts (P) // 2014-08-07 + { + if (P.device.package) + { + if (P.populate) + { + P.attributes (A) + { + if (0 == FoundAttributes) + { + // First one + AttributesList[0] = A.name; + FoundAttributes = 1; + } + else + { + Found = 0; + for (i = 0; i < FoundAttributes; i ++) + { + if (A.name == AttributesList[i]) + { + // Found an already listed atrribute + Found = 1; + break; + } + } + if (0 == Found) + { + // Attribute not listed, add at the end. + AttributesList[FoundAttributes] = A.name; + FoundAttributes ++; + } + } + } + } + } + } + } + sort (FoundAttributes, AttributesList); + } + // Second, collect all data + schematic (SCH) + { + SCH.allparts (P) + { + if (P.device.package) + { + if (P.populate) + { + PartName[NumParts] = P.name; + PartValue[NumParts] = P.value; + PartDevice[NumParts] = P.device.name; + PartPackage[NumParts] = P.device.package.name; + PartHeadline[NumParts] = P.device.headline; + PartDescription [NumParts] = P.device.description; + PartValueOn[NumParts] = P.device.value == "On"; + // Zero all strings + for (i = 0; i < FoundAttributes; i ++) + attr[i] = ""; + P.attributes(A) + { + for (i = 0; i < FoundAttributes; i ++) + if (A.name == AttributesList[i]) + { + attr[i] = A.value; + break; + } + if ("VALUE" == A.name && 0 < strlen (A.value)) + // Override old fashioned value information! + PartValueOn[NumParts] = 2; + } + PartAttributes[NumParts] = strjoin(attr, Separator); + NumParts ++; + } + } + } + } +} + + +void GeneratePartList(void) +{ + int NumLines = 0; + string attr[], s; + + if (UseAttributes) s = strjoin(AttributesList, '\t'); + Lines[NumLines ++] = tr ("Part\tValue\tDevice\tPackage\tDescription\t") + s; + for (int i = 0; i < NumParts; i ++) + { + strsplit (attr, PartAttributes[i], Separator); + if (UseAttributes) s = strjoin(attr, '\t'); + Lines[NumLines] = PartName[i] + "\t" + PartValue[i] + "\t" + PartDevice[i] + "\t" + + PartPackage[i] + "\t" + PartHeadline[i] + "\t" + s; + NumLines ++; + } + Lines[NumLines] = ""; +} + + +// Generate list with one entry per value. +// 'VALUE' is replaced by the value of attribute 'VAL', if existing. + +void GenerateValueList (void) +{ + int NumLines = 0; + int Index []; + string attr[], s, s_val; + + if (UseAttributes) s = strjoin(AttributesList, '\t'); + + // 2010-04-17 cwi: Included description. + Lines[NumLines ++] = tr ("Qty\tValue\tDevice\tPackage\tParts\tDescription\t") + s; // 2011-04-08 + sort (NumParts, Index, PartValue, PartDevice, PartPackage, PartAttributes, PartName, PartHeadline); // 2011-11-08 Partattribute jetzt nach Package alf@cadsoft.de + for (int n1 = 0, n2 = 0; ++ n2 <= NumParts; ) + { + int i1 = Index [n1]; + strsplit (attr, PartAttributes[i1], Separator); + if (UseAttributes) s = strjoin(attr, '\t'); + s_val = attr[i1]; + if (n2 < NumParts) + { + int i2 = Index [n2]; // 2012-11-08 + strsplit (attr, PartAttributes[i2], Separator); + if (PartValue[i1] == PartValue[i2] && PartDevice[i1] == PartDevice[i2] && PartAttributes[i1] == PartAttributes[i2]) // 2012-11-08 check diffent values of attributes + continue; + } + string Quantity; + sprintf (Quantity, "%d", n2 - n1); + Lines[NumLines] = Quantity + "\t" + PartValue[i1] + "\t" + PartDevice[i1] + "\t" + PartPackage[i1] + "\t"; + for (;;) + { + Lines[NumLines] += PartName[i1]; + if (++n1 < n2) + { + i1 = Index [n1]; + Lines[NumLines] += ", "; + } + else + break; + } + // cwi: add extra information from attributes + // 2010-04-17 cwi: Included description. + Lines[NumLines] += "\t" + PartHeadline[i1] + "\t" + s; + NumLines ++; + } + Lines[NumLines] = ""; +} + + +void GenerateList (void) +{ + switch (ListType) + { + case ltParts: GeneratePartList (); break; + case ltValues: GenerateValueList (); break; + } +} + + +string MakeListHeader (void) +{ + string s; + schematic(SCH) + sprintf (s, tr ("Partlist exported from %s at %s"), SCH.name, t2string (time ())); + return s; +} + + +string MakeListText(void) +{ + int l, Width []; + string List; + int numHeaders; + + for (l = 0; Lines[l]; l ++) + { + string a []; + for (int n = strsplit (a, Lines[l], '\t'); n --; ) + Width [n] = max (Width [n], strlen (a [n])); + } + + List = MakeListHeader () + "\n\n"; + + for (l = 0; Lines[l]; l ++) + { + string line, a []; + + int n = strsplit (a, Lines[l], '\t'); + if (l == 0) + numHeaders = n; + else + n = numHeaders; // for the hidden key! + for (int i = 0; i < n; i ++) + { + string s; + + sprintf (s, "%s%-*s", line ? " " : "", Width [i], a [i]); + line += s; + } + List += line + "\n"; + } + return List; +} + + +// 2008-11-24 Christian Schlittler: +// Make comma-serparated list, with all values double-quoted. + +string MakeListCSV (void) +{ + string List; + int numHeaders; + + for (int l = 0; Lines[l]; l ++) + { + string a []; + int n = strsplit (a, Lines[l], '\t'); + if (l == 0) + numHeaders = n; + else + n = numHeaders; // for the hidden key! + for (int i = 0; i < n; i ++) + List += "\"" + a[i] + "\"" + SeparatorString; + List += "\n"; + } + return List; +} + + +string MakeListHTML (void) +{ + string List; + int numHeaders; + + List = "" + MakeListHeader() + "\n

\n"; + List += "\n"; + for (int l = 0; Lines[l]; l++) + { + List += ""; + string a []; + int n = strsplit (a, Lines[l], '\t'); + if (l == 0) + numHeaders = n; + else + n = numHeaders; // for the hidden key! + for (int i = 0; i < n; i ++) + { + if (l == 0) + a[i] = "" + a[i] + ""; + List += ""; + } + List += "\n"; + } + List += "
" + a[i] + "
\n"; + return List; +} + + +string MakeList (void) +{ + switch (OutputFormat) + { + case ofText: return MakeListText(); break; + case ofCSV: return MakeListCSV(); break; + case ofHTML: return MakeListHTML(); break; + } + return ""; +} + + +void ViewList (void) +{ + dlgDialog (tr ("Bill Of Material - Preview")) + { + string s = MakeList (); + if (OutputFormat == ofText || OutputFormat == ofCSV) + s = "

" + s + "
"; + dlgHBoxLayout dlgSpacing (400); + dlgHBoxLayout + { + dlgVBoxLayout dlgSpacing (300); + dlgTextView (s); + } + dlgHBoxLayout + { + dlgStretch (1); + dlgPushButton (tr ("-Close")) dlgReject (); + } + }; +} + + +void SaveList (void) +{ + // 2008-11-24 cwi: + // - Added new format extension .csv + // - Changed from .bom to .txt for text format. + string FileName; + string FileExt; + + switch (OutputFormat) + { + case ofText: FileExt = ".txt"; break; + case ofHTML: FileExt = ".html"; break; + case ofCSV: FileExt = ".csv"; break; + } + schematic(SCH) FileName = filesetext (SCH.name, FileExt); + FileName = dlgFileSave (tr ("Save Bill Of Material"), FileName); + if (FileName) + { + string a []; + if (!fileglob (a, FileName) || dlgMessageBox (tr ("File '") + FileName + + tr ("' exists\n\nOverwrite?"), tr("+&Yes"), tr("-&No")) == 0) + { + output (FileName, "wt") + { + printf ("%s", MakeList ()); // using "%s" to avoid problems if list contains any '%' + } + } + } +} + + +void DisplayHelp (void) +{ + dlgDialog (tr ("Bill Of Material - Help")) + { + dlgHBoxLayout dlgSpacing (400); + dlgHBoxLayout + { + dlgVBoxLayout dlgSpacing (300); + dlgTextView (language () == "de" ? HelpTextDE : HelpTextEN); + } + dlgHBoxLayout + { + dlgStretch (1); + dlgPushButton (tr ("-Close")) + dlgReject (); + } + }; +} + + +schematic(SCH) { + sprintf(SeparatorString, "%c", Separator); + CurrentVariant = variant(); + SCH.variantdefs(VD) { + if (CurrentVariant == VD.name) VDsel = cntVD; + sprintf(Variants[cntVD], "%s", VD.name); + cntVD++; + } +} + +setvariant(CurrentVariant); +CollectPartData(CurrentVariant); +GenerateList(); + +dlgDialog (tr ("Bill Of Material")) +{ + dlgHBoxLayout { + dlgLabel(tr ("Current &variant ")); + dlgComboBox(Variants, VDsel) { + CurrentVariant = Variants[VDsel]; + setvariant(CurrentVariant); + CollectPartData(CurrentVariant); + GenerateList(); + } + dlgStretch(1); + } + dlgListView ("", Lines, Selected); + dlgHBoxLayout + { + dlgGroup(tr ("List type")) + { + dlgRadioButton(tr ("&Parts"), ListType) GeneratePartList (); + dlgRadioButton(tr ("&Values"), ListType) GenerateValueList (); + dlgCheckBox(tr ("List &attributes"), UseAttributes) { + if (!UseAttributes) { + NumParts = 0; + } + CollectPartData(CurrentVariant); + GenerateList(); + } + } + dlgGroup (tr ("Output format")) + { + // 2008-10-09: Entries swapped for correct function. + dlgRadioButton(tr ("&Text"), OutputFormat); + // 2008-11-24 cwi: New format added. + dlgRadioButton(tr ("&CSV"), OutputFormat); + dlgRadioButton(tr ("&HTML"), OutputFormat); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton (tr ("+Vie&w")) ViewList (); + dlgPushButton (tr ("&Save...")) SaveList (); + dlgPushButton (tr ("H&elp")) DisplayHelp (); + dlgPushButton (tr ("-Close")) dlgAccept (); + dlgStretch(1); + dlgLabel("Version " + Version); + } +}; diff --git a/trunk/ulp/cam2dxf.ulp b/trunk/ulp/cam2dxf.ulp new file mode 100644 index 00000000..95a3c196 --- /dev/null +++ b/trunk/ulp/cam2dxf.ulp @@ -0,0 +1,488 @@ +#usage "Convert a CAM job to a script to export DXF data\n" + "

" + "Usage: RUN cam2dxf [ filename ]" + "

" + "Tip: Assign a funktion key with

" + "ASSIGN Shift+Ctrl+Alt+P 'run cam2dxf;';" + "

" + "or" + "

" + "ASSIGN Shift+Ctrl+Alt+P 'run cam2dxf myjob.cam;';" + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +// CAM-Job token +string tok_job = "[CAM Processor Job]"; +string tok_Descrition = "Description="; +string description; +string descriptionLine[]; +int descrCnt; +string tok_Section = "Section="; +string tok_Sec_n = "[Sec_"; +string section[]; +string tok_Name = "Name="; +string sec_Name[]; +string tok_Prompt = "Prompt="; +string sec_Prompt[]; +string tok_Out_put = "Output="; +string sec_Out_put[]; + +string tok_Sheet = "Sheet="; +int sec_Sheet[]; +int sheetprint = 0; // 0 = All, 1 = From To, 2 = This section defined, 3 = Actual + +int sheetprint_from[]; +int sheetprint_to[]; +string actualsheet; + +string tok_Layers = "Layers="; +string sec_Layers[]; +string sec_usedlayer[]; +int absolutUsedLayer = 0; + +string lines[]; +int nLines; +string s; +string nu; +int sx = 0; + +int lVisible[]; +int useLayer[]; +string lNames[] = { " " }; +int lastsheet = 0; +string lastSH; + +string Unit = " -u MM"; +string AlwaysVertorFont = " -a"; +string UseWireWidth = " -w"; +string FillArea = " -f"; + +string help = usage+ "This ULP converts a CAM Job to a DXF Export script!

\n" + + "If the layer list is empty after starting this ULP,\n" + + "you did not start it from the proper editor window (SCH/BRD).

\n" + + "CAM jobs for the layout have to be started from the Layout Editor, " + + "jobs for a schematic from the Schematic Editor. " + + "CAM Jobs can be edited and saved by the CAM processor only."; + +string ulp_path ; +char bkslash = '/'; +int pos = strrchr(argv[0], bkslash); +if (pos >= 0) ulp_path = strsub(argv[0], 0, pos + 1); + +string cmd = ""; +int test = 0; +int Result = 0; + +// File handling +int n = 0; +string text; +string CAMfileName; +int nBytes; +int align; +string CAMfile; + +string Eagle =""; + +// *** functions *** + +void editsec(int sec) { + string num; + sprintf(num, "%d", sec); + dlgDialog("Section Editor") { + dlgLabel("Section " + num); + dlgHBoxLayout { + dlgPushButton("+&OK") dlgAccept(); + dlgPushButton("-&Cancel") dlgReject(); + dlgStretch(1); + } + }; + return; +} + +void commandPrint(string sectab) { + cmd += "RUN dxf -s " + sectab + Unit + AlwaysVertorFont + UseWireWidth + FillArea + ";\n"; + return; + } + +void viewDescript(void) { + string ds; + for (int n = 1 ; n < descrCnt; n++ ) { + if (ds[0] = ' ') { + ds = descriptionLine[n]; + ds[0] = ' '; + descriptionLine[n] = ds; + } + } + descriptionLine[0] = "" + descriptionLine[0] + ""; + ds = strjoin(descriptionLine, '\n'); + dlgMessageBox(ds, "OK"); + return; +} + +void readCam(void) { + sx = 0; + for (int sn = 0; sn < nLines; sn++) { + if( strstr(lines[sn], tok_Descrition) == 0) { + description = strsub(lines[sn], strlen(tok_Descrition) + 1, strlen(lines[sn]) - (strlen(tok_Descrition)+2) ); + descrCnt = strsplit (descriptionLine, description, '\\'); + } + + if( strstr(lines[sn], tok_Sec_n) == 0) { + sx = strtol( strsub(lines[sn], strstr(lines[sn], "_") + 1) ); + sprintf(nu, "%d", sx); + } + + if( strstr(lines[sn], tok_Name ) == 0) {; + sec_Name[sx] = strsub(lines[sn], strlen(tok_Name) + 1, strlen(lines[sn]) - (strlen(tok_Name)+2) ); + sheetprint_from[sx] = 1; + } + + if( strstr(lines[sn], tok_Prompt ) == 0) {; + sec_Prompt[sx] = strsub(lines[sn], strlen(tok_Prompt) + 1, strlen(lines[sn]) - (strlen(tok_Prompt)+2) ); + } + + if( strstr(lines[sn], tok_Out_put ) == 0) { + sec_Out_put[sx] = strsub(lines[sn], strlen(tok_Out_put) + 1, strlen(lines[sn]) - (strlen(tok_Out_put)+2) ); + } + + if( strstr(lines[sn], tok_Sheet ) == 0) { + sec_Sheet[sx] = strtod( strsub(lines[sn], strlen(tok_Sheet) , strlen(lines[sn]) - (strlen(tok_Sheet) ) ) ); + } + + // n Layers (max 255) + if( strstr(lines[sn], tok_Layers ) == 0) { + sec_Layers[sx] = strsub(lines[sn], strlen(tok_Layers) + 2, strlen(lines[sn]) - (strlen(tok_Layers)+3) ); + // hier noch die Layer + } + } + return; +} + +// main +if (argv[1]) { + CAMfileName = argv[1]; + string dir = filedir(CAMfileName); + if (filedir(CAMfileName)) ; + else CAMfileName = path_cam[0] + "/" + argv[1]; + } +else { + CAMfileName = dlgFileOpen("Select CAM File", path_cam[0]+"/*.cam", "*.*"); + } + +if (CAMfileName) { + nLines = fileread(lines, CAMfileName); + readCam(); + } +else exit (0); + +if(lines[0] != tok_job) { + dlgMessageBox(CAMfileName + "\nis not a EAGLE CAM-Job\n" + lines[0], "OK"); + exit (0); + } + +if (schematic) { + schematic(S) { + if (sheet) sheet(SH) sprintf(actualsheet, "%d", SH.number); + } + schematic(S) { + S.sheets(SH) { + if (lastsheet < SH.number) lastsheet = SH.number; + } + S.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + } + } + } + +if (board) { + board(B) { + B.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + } + } + } + + +// tabs menue +Result = dlgDialog("CAM-Job to Print-Command") { + //Define a container for tab pages + dlgTabWidget { + int tpn=1; + sheetprint_to[tpn] = lastsheet; + while (sec_Name[tpn]) { + dlgTabPage(sec_Name[tpn]) { + dlgLabel("JOB Name: " + CAMfileName); + dlgSpacing(10); + dlgStretch(0); + dlgHBoxLayout { + dlgStretch(0); + dlgSpacing(10); + dlgLabel(Eagle); + dlgSpacing(10); + if (board) { + dlgVBoxLayout { + dlgGroup("Suffix") dlgLabel(sec_Out_put[tpn]); + dlgStretch(1); + } + } + dlgStretch(0); + dlgHBoxLayout { + dlgStretch(0); + dlgVBoxLayout { + if (schematic) { + dlgStretch(0); + dlgGroup("Sheet") { + dlgVBoxLayout { + dlgHBoxLayout { + dlgRadioButton("&All ", sheetprint); + dlgLabel(" "); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("&From ", sheetprint); + dlgLabel("S&heet "); + dlgIntEdit(sheetprint_from[tpn], 1, lastsheet); + dlgLabel(" &to "); + dlgIntEdit(sheetprint_to[tpn], sheetprint_from[tpn], lastsheet); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("&# ", sheetprint); + string sl; + sprintf(sl, "%d/%d", sec_Sheet[tpn], lastsheet); + dlgLabel(sl + " (def. in section)"); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("Actua&l ", sheetprint); + dlgLabel(actualsheet); + dlgStretch(1); + } + } + } + } // if schematic + dlgStretch(1); + } + // *** Layer list to print *** + int Seleclayer; + string layer[] ; + int n = 0; + int ln = strsplit(layer, sec_Layers[tpn], ' '); + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (useLayer[num]) { + if(schematic) { + if (num >= 90) { + sprintf(sec_usedlayer[n], "%3s %s", layer[x], lNames[num]); + n++; + } + } + if(board) { + if (num < 90 || num > 100) { + sprintf(sec_usedlayer[n], "%3s %s", layer[x], lNames[num]); + n++; + } + } + } + } + sec_usedlayer[n] = ""; // clear last+1 + absolutUsedLayer = n; + dlgStretch(0); + dlgSpacing(10); + dlgVBoxLayout { + if (absolutUsedLayer) { + dlgHBoxLayout { dlgSpacing(100); } + dlgLabel("Printed layers"); + dlgListBox(sec_usedlayer, Seleclayer); + } + else { + dlgLabel(""); + dlgLabel("no Layers selected\nin this CAM-Job/Section!\nLoad a correct Job."); + } + } + dlgSpacing(10); + } + dlgStretch(1); + } + dlgStretch(1); + tpn++; + } + } // ************ End of TAB | SHEET *********** + dlgTabPage("&Help") { + dlgSpacing(10); + dlgHBoxLayout { + dlgSpacing(10); + dlgVBoxLayout { + dlgHBoxLayout { + dlgLabel(Eagle); + dlgSpacing(10); + dlgVBoxLayout { + dlgLabel(EAGLE_SIGNATURE); + dlgSpacing(10); + if (description) { + dlgHBoxLayout { + dlgPushButton("&Show Job Description") viewDescript(); + dlgStretch(1); + } + } + else dlgLabel("CAM Job description is EMPTY"); + } + dlgStretch(1); + } + dlgSpacing(10); + dlgLabel(help); + dlgStretch(1); + } + } + } + } // ************ End of all TABs *********** + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgPushButton("&Load CAM-File") { + CAMfileName = dlgFileOpen("select a File", path_cam[0]+"/*.cam", ""); + if (CAMfileName) { + exit ("run " + filesetext(argv[0], " ") + " '" + CAMfileName + "';\n"); + } + } + dlgStretch(1); + } + }; + +if (Result == 0) exit (0); + +if (test) cmd = "# generatet by " + argv[0] + " from " + CAMfileName + "\n"; + +for (int tpn = 1; tpn <= sx; tpn++) { + string layer[] ; + int n = 0; + int ln = strsplit(layer, sec_Layers[tpn], ' '); + if (test) cmd += "# Section: " + sec_Name[tpn] + "\n"; + if(board) { + cmd += "SET DISPLAY_MODE REAL;\n"; + cmd += "RATSNEST;\n"; + cmd += "DISPLAY NONE "; + + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (num < 90 || num > 100) { + if (useLayer[num]) { + sprintf(s, " %3s", layer[x]); + cmd += s; + if(num == 21) cmd += " -23 -25 -27 -51"; + if(num == 22) cmd += " -24 -26 -28 -52"; + n++; + } + } + } + cmd += ";\n"; + commandPrint(sec_Out_put[tpn]); + } + + if(schematic) { + cmd += "DISPLAY NONE "; + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (useLayer[num]) { + if (num >= 90) { + sprintf(s, " %3s", layer[x]); + cmd += s; + n++; + } + } + } + cmd += ";\n"; + string sh; + string shn; + switch (sheetprint) { + case 0 : schematic(S) { + S.sheets(SH) { + sprintf(sh, "EDIT '.s%d';\n", SH.number); + cmd += sh; + sprintf(shn, "_s%d", SH.number); + commandPrint(shn); + } + } + break; + + case 1 : for (int prn = sheetprint_from[tpn]; prn <= sheetprint_to[tpn]; prn++) { + sprintf(sh, "EDIT '.s%d';\n", prn); + cmd += sh; + sprintf(shn, "_s%d", prn); + commandPrint(shn); + } + break; + + case 2 : sprintf(sh, "EDIT '.s%d';\n", sec_Sheet[tpn]); + cmd += sh; + sprintf(shn, "_s%d", sec_Sheet[tpn]); + commandPrint(shn); + break; + + case 3 : sprintf(sh, "EDIT '.s%s';\n", actualsheet); + cmd += sh; + sprintf(shn, ".s%s", actualsheet); + commandPrint(shn); + break; + } + } + } + +cmd += "DISPLAY "; +if(board) { + for(int l = 1; l < 90; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + for(l = 100; l < 256; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + cmd += ";\n"; + } + +if(schematic) { + for(int l = 91; l < 256; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + cmd += ";\n"; + sprintf(s, "EDIT '.s%s';\n", actualsheet); + cmd += s; + } + +if (test) { if (dlgMessageBox(cmd, "OK", "ESC") != 0) exit (-1);} +exit (cmd); diff --git a/trunk/ulp/cam2image.ulp b/trunk/ulp/cam2image.ulp new file mode 100644 index 00000000..382985d2 --- /dev/null +++ b/trunk/ulp/cam2image.ulp @@ -0,0 +1,556 @@ +#usage "Convert a CAM job to a script to export IMAGE data" + "

" + "Usage: RUN cam2image [ filename monochrome resolution image type]" + "

" + "Tip: Assign a funktion key with" + "
" + "ASSIGN Shift+Ctrl+Alt+I 'run cam2image;';" + "
" + "or ASSIGN Shift+Ctrl+Alt+I 'run cam2image myjob.cam monochrome 150 .bmp;';" + "
" + "or ASSIGN Shift+Ctrl+Alt+I 'run cam2image myjob.cam color 300 .tif;';" + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +// Revision 1. 14.02.2005 Exdendet with .tif format alf@cadsoft.de +// Revision 2. 23.02.2005 Use correct file name in CAM-Job-Section alf@cadsoft.de + + +// CAM-Job token +string tok_job = "[CAM Processor Job]"; +string tok_Descrition = "Description="; +string description; +string descriptionLine[]; +int descrCnt; +string tok_Section = "Section="; +string tok_Sec_n = "[Sec_"; +string section[]; +string tok_Name = "Name="; +string sec_Name[]; +string tok_Prompt = "Prompt="; +string sec_Prompt[]; +string tok_Out_put = "Output="; +string sec_Out_put[]; + +string file_name; + +string tok_Sheet = "Sheet="; +int sec_Sheet[]; +int sheetprint = 0; // 0 = All, 1 = From To, 2 = This section defined, 3 = Actual + +int sheetprint_from[]; +int sheetprint_to[]; +string actualsheet; + +string tok_Layers = "Layers="; +string sec_Layers[]; +string sec_usedlayer[]; +int absolutUsedLayer = 0; + +string lines[]; +int nLines; +string s; +string nu; +int sx = 0; + +int lVisible[]; +int useLayer[]; +string lNames[] = { " " }; +int lastsheet = 0; +string lastSH; + +int Resolution = 75; // DPI +string monochrome = ""; +int sel_monochrome = 0; + + +string filetype[] = { + ".bmp", // Windows-Bitmap-Datei + ".png", // Portable-Network-Graphics-Datei + ".pbm", // Portable-Bitmap-Datei + ".pgm", // Portable-Grayscale-Bitmap-Datei + ".ppm", // Portable-Pixelmap-Datei + ".xbm", // X-Bitmap-Datei + ".xpm", // X-Pixmap-Datei + ".tif" // Tiff-Datei + }; + +int selfiletype = 0; + + +string help = usage+ "This ULP converts a CAM Job to a Export IMAGE!
\n" + + "If the layer list is empty after starting this ULP,
" + + "you did not start it from the proper editor window (SCH/BRD).
" + + "CAM jobs for the layout have to be started from the Layout Editor, " + + "jobs for a schematic from the Schematic Editor. " + + "CAM Jobs can be edited and saved by the CAM processor only.
"; + +string ulp_path ; +char bkslash = '/'; +int pos = strrchr(argv[0], bkslash); +if (pos >= 0) ulp_path = strsub(argv[0], 0, pos + 1); + +string cmd = ""; +int test = 0; +int Result = 0; + +// File handling +int n = 0; +string text; +string CAMfileName; +int nBytes; +int align; +string CAMfile; + +string Eagle =""; + +// *** functions *** + +void editsec(int sec) { + string num; + sprintf(num, "%d", sec); + dlgDialog("Section Editor") { + dlgLabel("Section " + num); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + }; + return; +} + +void commandPrint(string sectab) { + string h; + string Path = filedir(sectab); + string File_Name = filesetext(filename(sectab), ""); + string Extension = fileext(sectab); + string expfilename; + + if (Path) { // check filename in CAM-Job *** 23.02.2005 alf@cadsoft.de + if (!File_Name) { + expfilename = Path + filesetext(filename(file_name), "") + Extension; + } + else { + expfilename = Path + File_Name + Extension; + } + } + else { + expfilename = file_name + Extension; + } + sprintf(h, "EXPORT IMAGE '%s%s' %s %d;\n", expfilename, filetype[selfiletype], monochrome, Resolution); + cmd += h; + return; + } + +void viewDescript(void) { + string ds; + for (int n = 1 ; n < descrCnt; n++ ) { + if (ds[0] = ' ') { + ds = descriptionLine[n]; + ds[0] = ' '; + descriptionLine[n] = ds; + } + } + descriptionLine[0] = "" + descriptionLine[0] + ""; + ds = strjoin(descriptionLine, '\n'); + dlgMessageBox(ds, "OK"); + return; +} + +void readCam(void) { + sx = 0; + for (int sn = 0; sn < nLines; sn++) { + if( strstr(lines[sn], tok_Descrition) == 0) { + description = strsub(lines[sn], strlen(tok_Descrition) + 1, strlen(lines[sn]) - (strlen(tok_Descrition)+2) ); + descrCnt = strsplit (descriptionLine, description, '\\'); + } + + if( strstr(lines[sn], tok_Sec_n) == 0) { + sx = strtol( strsub(lines[sn], strstr(lines[sn], "_") + 1) ); + sprintf(nu, "%d", sx); + } + + if( strstr(lines[sn], tok_Name ) == 0) {; + sec_Name[sx] = strsub(lines[sn], strlen(tok_Name) + 1, strlen(lines[sn]) - (strlen(tok_Name)+2) ); + sheetprint_from[sx] = 1; + } + + if( strstr(lines[sn], tok_Prompt ) == 0) {; + sec_Prompt[sx] = strsub(lines[sn], strlen(tok_Prompt) + 1, strlen(lines[sn]) - (strlen(tok_Prompt)+2) ); + } + + if( strstr(lines[sn], tok_Out_put ) == 0) { + sec_Out_put[sx] = strsub(lines[sn], strlen(tok_Out_put) + 1, strlen(lines[sn]) - (strlen(tok_Out_put)+2) ); + } + + if( strstr(lines[sn], tok_Sheet ) == 0) { + sec_Sheet[sx] = strtod( strsub(lines[sn], strlen(tok_Sheet) , strlen(lines[sn]) - (strlen(tok_Sheet) ) ) ); + } + + // n Layers (max 255) + if( strstr(lines[sn], tok_Layers ) == 0) { + sec_Layers[sx] = strsub(lines[sn], strlen(tok_Layers) + 2, strlen(lines[sn]) - (strlen(tok_Layers)+3) ); + // hier noch die Layer + } + } + return; +} + +// main +int nt = 0; +do { + if(strlwr(argv[4]) == filetype[nt]) { + selfiletype = nt; + break; + } + nt++; +} while(filetype[nt]); + +if (argv[3]) Resolution = strtol(argv[3]); + +if (strupr(argv[2]) == "MONOCHROME") sel_monochrome = 1; + +if (argv[1]) { + CAMfileName = argv[1]; + string dir = filedir(CAMfileName); + if (filedir(CAMfileName)) ; + else CAMfileName = path_cam[0] + "/" + argv[1]; + } +else { + CAMfileName = dlgFileOpen("Select CAM File", path_cam[0]+"/*.cam", "*.*"); + } + +if (CAMfileName) { + nLines = fileread(lines, CAMfileName); + readCam(); + } +else exit (0); + +if(lines[0] != tok_job) { + dlgMessageBox(CAMfileName + "\nis not a EAGLE CAM-Job\n" + lines[0], "OK"); + exit (0); + } + +if (schematic) { + schematic(S) { + file_name = filesetext(S.name, ""); + if (sheet) sheet(SH) sprintf(actualsheet, "%d", SH.number); + } + schematic(S) { + S.sheets(SH) { + if (lastsheet < SH.number) lastsheet = SH.number; + } + S.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + } + } + } + +if (board) { + board(B) { + file_name = filesetext(B.name, ""); + B.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + } + } + } + + +// tabs menue +Result = dlgDialog("CAM-Job to EXPORT Image-Command") { + //Define a container for tab pages + dlgTabWidget { + int tpn=1; + sheetprint_to[tpn] = lastsheet; + while (sec_Name[tpn]) { + dlgTabPage(sec_Name[tpn]) { + dlgLabel("JOB Name: " + CAMfileName); + dlgSpacing(10); + dlgStretch(0); + dlgHBoxLayout { + dlgStretch(0); + dlgSpacing(10); + dlgLabel(Eagle); + dlgSpacing(10); + if (board) { + dlgVBoxLayout { + dlgGroup("File name/suffix") dlgLabel(sec_Out_put[tpn]); + dlgStretch(1); + } + } + dlgStretch(0); + dlgHBoxLayout { + dlgStretch(0); + dlgVBoxLayout { + if (schematic) { + dlgStretch(0); + dlgGroup("Sheet") { + dlgVBoxLayout { + dlgHBoxLayout { + dlgRadioButton("&All ", sheetprint); + dlgLabel(" "); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("&From ", sheetprint); + dlgLabel("S&heet "); + dlgIntEdit(sheetprint_from[tpn], 1, lastsheet); + dlgLabel(" &to "); + dlgIntEdit(sheetprint_to[tpn], sheetprint_from[tpn], lastsheet); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("&# ", sheetprint); + string sl; + sprintf(sl, "%d/%d", sec_Sheet[tpn], lastsheet); + dlgLabel(sl + " (def. in section)"); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("Actua&l ", sheetprint); + dlgLabel(actualsheet); + dlgStretch(1); + } + } + } + } // if schematic + dlgStretch(1); + } + // *** Layer list to print *** + int Seleclayer; + string layer[] ; + int n = 0; + int ln = strsplit(layer, sec_Layers[tpn], ' '); + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (useLayer[num]) { + if(schematic) { + if (num >= 90) { + sprintf(sec_usedlayer[n], "%3s %s", layer[x], lNames[num]); + n++; + } + } + if(board) { + if (num < 90 || num > 100) { + sprintf(sec_usedlayer[n], "%3s %s", layer[x], lNames[num]); + n++; + } + } + } + } + sec_usedlayer[n] = ""; // clear last+1 + absolutUsedLayer = n; + dlgStretch(0); + dlgSpacing(10); + dlgVBoxLayout { + if (absolutUsedLayer) { + dlgHBoxLayout { dlgSpacing(100); } + dlgLabel("Printed layers"); + dlgListBox(sec_usedlayer, Seleclayer); + } + else { + dlgLabel(""); + dlgLabel("no Layers selected\nin this CAM-Job/Section!\nLoad a correct Job."); + } + } + dlgSpacing(10); + } + dlgStretch(1); + } + dlgStretch(1); + tpn++; + } + } // ************ End of TAB | SHEET *********** + dlgTabPage("&Help") { + dlgSpacing(10); + dlgHBoxLayout { + dlgSpacing(10); + dlgVBoxLayout { + dlgHBoxLayout { + dlgLabel(Eagle); + dlgSpacing(10); + dlgVBoxLayout { + dlgLabel(EAGLE_SIGNATURE); + dlgSpacing(10); + if (description) { + dlgHBoxLayout { + dlgPushButton("&Show Job Description") viewDescript(); + dlgStretch(1); + } + } + else dlgLabel("CAM Job description is EMPTY"); + } + dlgStretch(1); + } + dlgSpacing(10); + dlgLabel(help); + dlgStretch(1); + } + } + } + } // ************ End of all TABs *********** + + + dlgHBoxLayout { + dlgLabel("FileType"); + dlgComboBox(filetype, selfiletype); + dlgSpacing(15); + dlgCheckBox("Monochrome", sel_monochrome); + dlgSpacing(15); + dlgLabel("Resolution DPI"); + dlgIntEdit(Resolution, 50, 600); + dlgStretch(1); + } + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgPushButton("&Load CAM-File") { + CAMfileName = dlgFileOpen("select a File", path_cam[0]+"/*.cam", ""); + if (CAMfileName) { + exit ("run '" + filesetext(argv[0], "") + "' '" + CAMfileName + "';\n"); + } + } + dlgStretch(1); + } + }; + +if (Result == 0) exit (0); +if (sel_monochrome) monochrome = "MONOCHROME"; +else monochrome = ""; + +if (test) cmd = "# generatet by " + argv[0] + " from " + CAMfileName + "\n"; + +for (int tpn = 1; tpn <= sx; tpn++) { + string layer[] ; + int n = 0; + int ln = strsplit(layer, sec_Layers[tpn], ' '); + if (test) cmd += "# Section: " + sec_Name[tpn] + "\n"; + if(board) { + cmd += "SET DISPLAY_MODE REAL;\n"; + cmd += "RATSNEST;\n"; + cmd += "DISPLAY NONE "; + + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (num < 90 || num > 100) { + if (useLayer[num]) { + sprintf(s, " %3s", layer[x]); + cmd += s; + if(num == 21) cmd += " -23 -25 -27 -51"; + if(num == 22) cmd += " -24 -26 -28 -52"; + n++; + } + } + } + cmd += ";\n"; + commandPrint(sec_Out_put[tpn]); + } + + if(schematic) { + cmd += "DISPLAY NONE "; + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (useLayer[num]) { + if (num >= 90) { + sprintf(s, " %3s", layer[x]); + cmd += s; + n++; + } + } + } + cmd += ";\n"; + string sh; + string shn; + switch (sheetprint) { + case 0 : schematic(S) { + S.sheets(SH) { + sprintf(sh, "EDIT '.s%d';\n", SH.number); + cmd += sh; + sprintf(shn, "_s%d", SH.number); + commandPrint(shn); + } + } + break; + + case 1 : for (int prn = sheetprint_from[tpn]; prn <= sheetprint_to[tpn]; prn++) { + sprintf(sh, "EDIT '.s%d';\n", prn); + cmd += sh; + sprintf(shn, "_s%d", prn); + commandPrint(shn); + } + break; + + case 2 : sprintf(sh, "EDIT '.s%d';\n", sec_Sheet[tpn]); + cmd += sh; + sprintf(shn, "_s%d", sec_Sheet[tpn]); + commandPrint(shn); + break; + + case 3 : sprintf(sh, "EDIT '.s%s';\n", actualsheet); + cmd += sh; + sprintf(shn, ".s%s", actualsheet); + commandPrint(shn); + break; + } + } + } + +cmd += "DISPLAY "; +if(board) { + for(int l = 1; l < 90; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + for(l = 100; l < 256; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + cmd += ";\n"; + } + +if(schematic) { + for(int l = 91; l < 256; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + cmd += ";\n"; + sprintf(s, "EDIT '.s%s';\n", actualsheet); + cmd += s; + } + +if (test) { dlgMessageBox(cmd, "OK", "Cancel"); exit (0);} +exit (cmd); diff --git a/trunk/ulp/cam2print-box-grey-optimize.bmp b/trunk/ulp/cam2print-box-grey-optimize.bmp new file mode 100644 index 00000000..74d4f3fa Binary files /dev/null and b/trunk/ulp/cam2print-box-grey-optimize.bmp differ diff --git a/trunk/ulp/cam2print-box-grey-poscoord.bmp b/trunk/ulp/cam2print-box-grey-poscoord.bmp new file mode 100644 index 00000000..8ce79cac Binary files /dev/null and b/trunk/ulp/cam2print-box-grey-poscoord.bmp differ diff --git a/trunk/ulp/cam2print-box-grey-quickplot.bmp b/trunk/ulp/cam2print-box-grey-quickplot.bmp new file mode 100644 index 00000000..b276d999 Binary files /dev/null and b/trunk/ulp/cam2print-box-grey-quickplot.bmp differ diff --git a/trunk/ulp/cam2print.ulp b/trunk/ulp/cam2print.ulp new file mode 100644 index 00000000..4ee23424 --- /dev/null +++ b/trunk/ulp/cam2print.ulp @@ -0,0 +1,789 @@ +#usage "Convert a CAM job to a PRINT command\n" + "

" + "Usage: RUN cam2print [ filename [ outputfile ]]
" + "Use PDF for outputfile to print in a PDF." + "

" + "Tip: Assign a funktion key with" + "
" + "ASSIGN Shift+Ctrl+Alt+P 'run cam2print.ulp;';" + "
" + "ASSIGN Shift+Ctrl+Alt+P 'run cam2print.ulp PDF;';" + "
" + "ASSIGN Shift+Ctrl+Alt+P 'run cam2print.ulp myjob.cam;';" + "
" + "ASSIGN Shift+Ctrl+Alt+P 'run cam2print.ulp myjob.cam PDF;';" + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +/* 2003-10-24 add "SET DISPLAY_MODE REAL;\n" on script end : alf@cadsoft.de */ +// 2006-03-01 add path and "/" to job file name. alf@cadsoft.de +// CAMfileName = path_cam[0] + "/" + argv[2]; +// 2008-03-25 print also layer 100 +// 2010-06-29 return string with ' "run 'ulpname' ... +// section name with language[..] +// option "PageLimit_all" deleted +// +// 2011-03-03 option "PageLimit_all" reactivated +// 2011-03-04 Scale factor corrected +// + + +string version = "1.0.6"; // alf@cadsoft.de + +string camFname; // the file name of sch/brd for option outputfile +if (schematic) schematic(S) camFname = filesetext(filename(S.name), ""); +if (board) board(B) camFname = filesetext(filename(B.name), ""); +string fileprintout = ""; + +// CAM-Job token +string tok_job = "[CAM Processor Job]"; +string tok_Descrition = "Description="; +string description; +string descriptionLine[]; +int descrCnt; +string tok_Section = "Section="; +string tok_Sec_n = "[Sec_"; +string section[]; +string tok_Name; +if (language() == "de") tok_Name = "Name[de]="; // 2010-06-29 +else tok_Name = "Name[en]="; + +string sec_Name[]; +string tok_Prompt = "Prompt="; +string sec_Prompt[]; +string tok_Device = "Device="; +string sec_Device[]; +string tok_Wheel = "Wheel="; +string sec_Wheel[]; +string tok_Rack = "Rack="; +string sec_Rack[]; +string tok_Scale = "Scale="; +real sec_Scale[]; +string tok_Out_put = "Output="; +string sec_Out_put[]; +string tok_Flags = "Flags="; +string sec_Flags[]; +int mirror[]; +int rotate[]; +int upside[]; +int poscoord[]; +int quickplot[]; +int optimize[]; +int fillpads[]; +int pageLimit[]; +string tok_Emulate = "Emulate="; +string sec_Emulate[]; +string tok_Offset = "Offset="; +string sec_Offset[]; +real offset_x[]; +real offset_y[]; +string tok_Sheet = "Sheet="; +int sec_Sheet[]; +int sheetprint = 3; // 0 = All, 1 = From To, 2 = This section defined, 3 = Actual + +int sheetprint_from[]; +int sheetprint_to[]; +string tok_Tolerance = "Tolerance="; +string sec_Tolerance[]; +string tolerance0[]; +string tolerance1[]; +string tolerance2[]; +string tolerance3[]; +string tolerance4[]; +string tolerance5[]; +string tok_Pen = "Pen"; +string sec_Pen[]; +string tok_Page = "Page="; +string sec_Page[]; +real page_Height[]; +real page_Width[]; +string tok_Layers = "Layers="; +string sec_Layers[]; +string sec_usedlayer[]; +string tok_Colors = "Colors="; +string sec_Colors[]; +int solid[]; +int black[]; + +string actualsheet; + +string lines[]; +int nLines; +string s; +string nu; +int sx = 0; + +int lVisible[]; +int useLayer[]; +string lNames[] = { " " }; +int lastsheet = 0; +string lastSH; + +/* +path_lbr[] Libraries +path_dru[] Design Rules +path_ulp[] User Language Programs +path_scr[] Scripts +path_cam[] CAM Jobs +path_epf[] Projects +*/ + +string help = usage+ "This ULP converts a CAM Job to a PRINT Script!

\n" + + "If the layer list is empty after starting this ULP,\n" + + "you did not start it from the proper editor window (SCH/BRD).
\n" + + "CAM jobs for the layout have to be started from the Layout Editor, " + + "jobs for a schematic from the Schematic Editor.
\n" + + "CAM Jobs can be edited and save only by the CAM processor."; + + +string PageLimit_all = ""; // 2011-03-03 reactivated + +string cmd = ""; +int test = 0; +int Result = 0; + +// File handling +int n = 0; +string text; +string CAMfileName; +int nBytes; +int align; +string CAMfile; + +string Eagle =""; + +// *** functions *** + +void editsec(int sec) { + string num; + sprintf(num, "%d", sec); + dlgDialog("Section Editor") { + dlgLabel("Section " + num); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-&Cancel") dlgReject(); + dlgStretch(1); + } + }; + return; +} + +void commandPrint(int sectab) { + cmd += "PRINT "; + + sprintf(s, " %.2f -%d", sec_Scale[sectab], pageLimit[sectab]); + cmd += s; + + if(black[sectab]) cmd += " BLACK"; + else cmd += " -BLACK"; + if(solid[sectab]) cmd += " SOLID"; + else cmd += " -SOLID"; + if(mirror[sectab]) cmd += " MIRROR"; + else cmd += " -MIRROR"; + if(rotate[sectab]) cmd += " ROTATE"; + else cmd += " -ROTATE"; + if(upside[sectab]) cmd += " UPSIDEDOWN"; + else cmd += " -UPSIDEDOWN"; + /* + if(poscoord[sectab]) ; // not use to print + if(quickplot[sectab]); // not use to print + if(optimize[sectab]); // not use to print + */ + if (fileprintout) { + cmd += " FILE '" + sec_Out_put[sectab] + ".pdf'"; + } + cmd += ";\n"; + return; + } + +void viewDescript(void) { + string ds; + for (int n = 1 ; n < descrCnt; n++ ) { + if (ds[0] == ' ') { + ds = descriptionLine[n]; + ds[0] = ' '; + descriptionLine[n] = ds; + } + } + descriptionLine[0] = "" + descriptionLine[0] + ""; + ds = strjoin(descriptionLine, '\n'); + dlgMessageBox(ds, "OK"); + return; +} + +void readCam(void) { + sx = 0; + for (int sn = 0; sn < nLines; sn++) { + if( strstr(lines[sn], tok_Descrition) == 0) { + description = strsub(lines[sn], strlen(tok_Descrition) + 1, strlen(lines[sn]) - (strlen(tok_Descrition)+2) ); + descrCnt = strsplit (descriptionLine, description, '\\'); + } + + if( strstr(lines[sn], tok_Sec_n) == 0) { + sx = strtol( strsub(lines[sn], strstr(lines[sn], "_") + 1) ); + sprintf(nu, "%d", sx); + } + + if( strstr(lines[sn], tok_Name ) == 0) {; + sec_Name[sx] = strsub(lines[sn], strlen(tok_Name) + 1, strlen(lines[sn]) - (strlen(tok_Name)+2) ); + sheetprint_from[sx] = 1; + } + + if( strstr(lines[sn], tok_Prompt ) == 0) {; + sec_Prompt[sx] = strsub(lines[sn], strlen(tok_Prompt) + 1, strlen(lines[sn]) - (strlen(tok_Prompt)+2) ); + } + + if( strstr(lines[sn], tok_Device ) == 0) { + sec_Device[sx] = strsub(lines[sn], strlen(tok_Device) + 1, strlen(lines[sn]) - (strlen(tok_Device)+2) ); + } + + if( strstr(lines[sn], tok_Wheel ) == 0) { + sec_Wheel[sx] = strsub(lines[sn], strlen(tok_Wheel) + 1, strlen(lines[sn]) - (strlen(tok_Wheel)+2) ); + } + + if( strstr(lines[sn], tok_Rack ) == 0) { + sec_Rack[sx] = strsub(lines[sn], strlen(tok_Rack) + 1, strlen(lines[sn]) - (strlen(tok_Rack)+2) ); + } + + if( strstr(lines[sn], tok_Scale ) == 0) { + sec_Scale[sx] = strtod(strsub(lines[sn], strlen(tok_Scale), strlen(lines[sn]) - (strlen(tok_Scale)) ) ); // 2011-03-04 + } + + if( strstr(lines[sn], tok_Out_put ) == 0) { + sec_Out_put[sx] = strsub(lines[sn], strlen(tok_Out_put) + 1, strlen(lines[sn]) - (strlen(tok_Out_put)+2) ); + int pos = strstr(sec_Out_put[sx], "%N"); + if (pos >= 0) { + sec_Out_put[sx] = strsub(sec_Out_put[sx], 0, pos) + camFname + strsub(sec_Out_put[sx], pos+2); + } + } + + if( strstr(lines[sn], tok_Flags ) == 0) { + sec_Flags[sx] = strsub(lines[sn], strlen(tok_Flags) + 1, strlen(lines[sn]) - (strlen(tok_Flags)+2) ); + string fl[]; + int fn = strsplit(fl, sec_Flags[sx], ' '); + mirror[sx] = strtol(fl[0]); + rotate[sx] = strtol(fl[1]); + upside[sx] = strtol(fl[2]); + poscoord[sx] = strtol(fl[3]); + quickplot[sx] = strtol(fl[4]); + optimize[sx] = strtol(fl[5]); + fillpads[sx] = strtol(fl[6]); + //Mirror Rotate Upside_down pos._Coord Quick_plot Optimize Fill_Pads + } + + if( strstr(lines[sn], tok_Emulate ) == 0) {; + // 3 Flags not used by printer + } + + // 2 real Values + if( strstr(lines[sn], tok_Offset ) == 0) { + sec_Offset[sx] = strsub(lines[sn], strlen(tok_Offset) + 1, strlen(lines[sn]) - (strlen(tok_Offset)+2) ); + offset_x[sx] = strtol(sec_Offset[sx]); + int oy = strstr(lines[sn], " "); + sec_Flags[sx] = strsub(lines[sn], oy + 1, strlen(lines[sn]) - (oy+2) ); + offset_y[sx] = strtol(sec_Offset[sx]); + } + + if( strstr(lines[sn], tok_Sheet ) == 0) { + sec_Sheet[sx] = strtod( strsub(lines[sn], strlen(tok_Sheet) , strlen(lines[sn]) - (strlen(tok_Sheet) ) ) ); + } + + if( strstr(lines[sn], tok_Tolerance ) == 0) { + sec_Tolerance[sx] = strsub(lines[sn], strlen(tok_Tolerance) + 1, strlen(lines[sn]) - (strlen(tok_Tolerance)+2) ); + string tol[] ; + int tn = strsplit(tol, sec_Tolerance[sx], ' '); + tolerance0[sx] = tol[0]; + tolerance1[sx] = tol[1]; + tolerance2[sx] = tol[2]; + tolerance3[sx] = tol[3]; + tolerance4[sx] = tol[4]; + tolerance5[sx] = tol[5]; + } + + if( strstr(lines[sn], tok_Pen ) == 0) { + // n Pen diameters not used by printer + } + + // x y Pages size + if( strstr(lines[sn], tok_Page ) == 0) { + page_Height[sx] = strtod( strsub(lines[sn], strlen(tok_Page) + 1, strlen(lines[sn]) - (strlen(tok_Page)+2) ) ); + int oy = strstr(lines[sn], " "); + page_Width[sx] = strtod( strsub(lines[sn], strlen(tok_Page) + 1, strlen(lines[sn]) - (oy+2) ) ); + } + + // n Layers (max 255) + if( strstr(lines[sn], tok_Layers ) == 0) { + sec_Layers[sx] = strsub(lines[sn], strlen(tok_Layers) + 2, strlen(lines[sn]) - (strlen(tok_Layers)+3) ); + // hier noch die Layer + } + + // n Layers (max 255) + if( strstr(lines[sn], tok_Colors ) == 0) { + sec_Colors[sx] = strsub(lines[sn], strlen(tok_Colors) + 1, strlen(lines[sn]) - (strlen(tok_Colors)+2) ); + string color[] ; + int cn = strsplit(color, sec_Colors[sx], ' '); + // not used by printer + } + solid[sx] = 1; + black[sx] = 1; + if (PageLimit_all) pageLimit[sx] = strtod(PageLimit_all); // PageLimit_all 2011-03-03 reactivated + } + return; +} + +string checkbackslash(string camname) { + int pos; + do { + pos = strchr(camname, '\\'); + if (pos >= 0) camname[pos] = '/'; + } while (pos >= 0); + return camname; +} + +// main +if (argc >= 1) { + if (argc == 2) { + CAMfileName = argv[1]; + if (argv[1] == "PDF") { + fileprintout = "PDF"; + CAMfileName = ""; + } + else PageLimit_all = argv[1]; // 2011-03-03 reactivated + } + else if (argc == 3) { + CAMfileName = argv[1]; + if (argv[2] == "PDF") fileprintout = "PDF"; + } + string f[]; + int cnt = fileglob(f, CAMfileName); + if (!cnt) CAMfileName = dlgFileOpen("select File", path_cam[0]+"/*.cam", "*.*"); +} +else CAMfileName = dlgFileOpen("select File", path_cam[0]+"/*.cam", "*.*"); + +if (CAMfileName) { + nLines = fileread(lines, CAMfileName); + readCam(); + } +else exit (0); + +if(lines[0] != tok_job) { + dlgMessageBox(CAMfileName + "\nis not a EAGLE CAM-Job\n" + lines[0], "OK"); + exit (0); + } + +if (schematic) { + schematic(S) { + camFname = filesetext(filename(S.name), ""); + if (sheet) sheet(SH) sprintf(actualsheet, "%d", SH.number); + } + schematic(S) { + S.sheets(SH) { + if (lastsheet < SH.number) lastsheet = SH.number; + } + S.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + } + } + } + +if (board) { + board(B) { + camFname = filesetext(filename(B.name), ""); + B.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + } + } + } + +// tabs menue +Result = dlgDialog("CAM-Job to Print-Command") { + //Define a container for tab pages + dlgTabWidget { //--- + int tpn=1; + sheetprint_to[tpn] = lastsheet; + while (sec_Name[tpn]) { //--- TabPages --- + dlgTabPage(sec_Name[tpn]) { + dlgHBoxLayout { dlgLabel("JOB Name: " + CAMfileName); } + dlgHBoxLayout { + dlgVBoxLayout { + dlgSpacing(10); + dlgHBoxLayout { + dlgGroup("Job section") { + dlgHBoxLayout { + dlgVBoxLayout { dlgLabel("Section"); dlgLabel("Prompt:"); } + dlgSpacing(10); + dlgVBoxLayout { + dlgHBoxLayout { dlgSpacing(250); } // dont delete this line + dlgLabel(sec_Name[tpn]); + dlgLabel(sec_Prompt[tpn]); + } + dlgStretch(1); + } + dlgStretch(1); + } + dlgStretch(1); + } + dlgStretch(0); + dlgSpacing(10); + dlgHBoxLayout { + dlgGroup("Output") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel("Device"); + dlgLabel("Scale"); + dlgLabel("File"); + } + dlgSpacing(10); + dlgVBoxLayout { + dlgHBoxLayout { dlgSpacing(250); } // dont delete this line + dlgHBoxLayout { dlgLabel(sec_Device[tpn]); } + dlgHBoxLayout { sprintf(s, "%g", sec_Scale[tpn]); dlgLabel(s); } + dlgHBoxLayout { dlgLabel(sec_Out_put[tpn]); } + dlgStretch(1); + } + dlgStretch(0); + } + dlgStretch(0); + } + dlgStretch(0); + } + dlgStretch(0); + dlgSpacing(10); + dlgHBoxLayout { + dlgGroup("Offset") { + dlgHBoxLayout { + dlgLabel("X"); + sprintf(s, "%g", offset_x[tpn]); + dlgSpacing(15); + dlgLabel(s); + } + dlgHBoxLayout { + dlgLabel("Y"); + sprintf(s, "%g", offset_y[tpn]); + dlgSpacing(15); + dlgLabel(s); + } + dlgHBoxLayout { + dlgSpacing(100); + } + } + dlgStretch(0); + dlgSpacing(10); + dlgGroup("Page") { + dlgHBoxLayout { + dlgLabel("Height"); + sprintf(s, "%g", page_Height[tpn]); + dlgSpacing(15); + dlgLabel(s); + } + dlgHBoxLayout { + dlgLabel("Width"); + sprintf(s, "%g", page_Width[tpn]); + dlgSpacing(18); + dlgLabel(s); + } + dlgHBoxLayout { + dlgSpacing(100); + } + } + } + dlgLabel(" "); + if (schematic) { + dlgStretch(0); + dlgGroup("Sheet") { + dlgVBoxLayout { + dlgHBoxLayout { + dlgRadioButton("&All ", sheetprint); + dlgLabel(" "); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("&From ", sheetprint); + dlgLabel("S&heet "); + dlgIntEdit(sheetprint_from[tpn], 1, lastsheet); + dlgLabel(" &to "); + dlgIntEdit(sheetprint_to[tpn], sheetprint_from[tpn], lastsheet); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("&# ", sheetprint); + string sl; + sprintf(sl, "%d/%d", sec_Sheet[tpn], lastsheet); + dlgLabel(sl); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("Actua&l ", sheetprint); + dlgLabel(actualsheet); + dlgStretch(1); + } + } + } + } // if schematic + + dlgStretch(1); + } + + dlgStretch(0); + dlgSpacing(15); + dlgHBoxLayout { + dlgStretch(0); + dlgVBoxLayout { + dlgSpacing(10); + dlgGroup("Style") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgCheckBox("&Mirror", mirror[tpn]); + dlgCheckBox("&Rotate", rotate[tpn]); + dlgCheckBox("&Upside down", upside[tpn]); + dlgLabel(""); + dlgLabel(""); + dlgLabel(""); + dlgCheckBox("&Fill pads (board)", fillpads[tpn]); + dlgCheckBox("&Black", black[tpn]); + dlgCheckBox("Soli&d", solid[tpn]); + } + dlgStretch(1); + dlgLabel(Eagle); + dlgStretch(0); + } + } + dlgStretch(1); + dlgSpacing(10); + dlgHBoxLayout { + dlgLabel("&Scale factor"); + dlgRealEdit(sec_Scale[tpn] , .01, 1000); + dlgStretch(1); + } + dlgHBoxLayout { + dlgLabel("&Page limit *"); + dlgSpacing(8); + dlgIntEdit(pageLimit[tpn] , 0, 100); + dlgStretch(1); + } + dlgLabel("* preset page limit for all pages start this ULP from command line by:
run " + filename(argv[0]) + " n
"); + } + // *** Layer list to print *** + int Seleclayer; + string layer[] ; + int n = 0; + int ln = strsplit(layer, sec_Layers[tpn], ' '); + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (useLayer[num]) { + if(schematic) { + if (num >= 90) { + sprintf(sec_usedlayer[n], "%3s %s", layer[x], lNames[num]); + n++; + } + } + if(board) { + if (num < 90 || num >= 100) { // incl. layer 100, 25.03.2008 + sprintf(sec_usedlayer[n], "%3s %s", layer[x], lNames[num]); + n++; + } + } + } + } + sec_usedlayer[n] = ""; // clear last+1 + dlgStretch(0); + dlgSpacing(10); + dlgVBoxLayout { + dlgHBoxLayout { dlgSpacing(100); } + dlgLabel("Printed layers"); + dlgListBox(sec_usedlayer, Seleclayer); + } + // *** Layer list to print *** + } + } + dlgSpacing(10); + dlgStretch(1); + tpn++; + } + } // end off while + // ************ End of TAB | SHEET *********** + dlgTabPage("&Help") { + dlgSpacing(10); + dlgHBoxLayout { + dlgSpacing(10); + dlgVBoxLayout { + dlgHBoxLayout { + dlgLabel(Eagle); + dlgSpacing(10); + dlgVBoxLayout { + dlgLabel(EAGLE_SIGNATURE); + dlgSpacing(10); + dlgLabel(checkbackslash(CAMfileName)); + if (description) { + dlgHBoxLayout { + dlgPushButton("&show Job-Description") viewDescript(); + dlgStretch(1); + } + } + else dlgLabel("CAM-Job description is EMPTY"); + } + dlgStretch(1); + } + dlgSpacing(10); + dlgLabel(help); + dlgStretch(1); + } + } + } + } // ************ End of all TABs *********** + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgPushButton("&Load CAM-File") { + CAMfileName = dlgFileOpen("select a File", path_cam[0]+"/*.cam", ""); + + + if (CAMfileName) { + string r; + sprintf(r, "run '%s' '%s' %s;\n", filesetext(argv[0], ""), CAMfileName, fileprintout); + exit (r); + } + } + dlgStretch(1); + } + }; + +if (Result == 0) exit (0); + +// make print command + if (test) cmd = "# generatet by " + argv[0] + " from " + CAMfileName + "\n"; + +for (int tpn = 1; tpn <= sx; tpn++) { + string layer[] ; + int n = 0; + int ln = strsplit(layer, sec_Layers[tpn], ' '); + if (test) cmd += "# Section: " + sec_Name[tpn] + "\n"; + if(board) { + if(fillpads[tpn]) { + cmd += "SET DISPLAY_MODE NODRILL;\n"; + } + else { + cmd += "SET DISPLAY_MODE REAL;\n"; + } + cmd += "RATSNEST;\n"; + cmd += "DISPLAY NONE "; + + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (num < 90 || num > 100) { + if (useLayer[num]) { + sprintf(s, " %s", layer[x]); + cmd += s; + if(num == 21) cmd += " -23 -25 -27 -51"; + if(num == 22) cmd += " -24 -26 -28 -52"; + n++; + } + } + } + cmd += ";\n"; + commandPrint(tpn); + } + + if(schematic) { + cmd += "DISPLAY NONE "; + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (useLayer[num]) { + if (num >= 90) { + sprintf(s, " %s", layer[x]); + cmd += s; + n++; + } + } + } + cmd += ";\n"; + string sh; + switch (sheetprint) { + case 0 : schematic(S) { + S.sheets(SH) { + sprintf(sh, "EDIT '.s%d';\n", SH.number); + cmd += sh; + commandPrint(tpn); + } + } + break; + + case 1 : for (int prn = sheetprint_from[tpn]; prn <= sheetprint_to[tpn]; prn++) { + sprintf(sh, "EDIT '.s%d';\n", prn); + cmd += sh; + commandPrint(tpn); + } + break; + + case 2 : sprintf(sh, "EDIT '.s%d';\n", sec_Sheet[tpn]); + cmd += sh; + commandPrint(tpn); + break; + + case 3 : sprintf(sh, "EDIT '.s%s';\n", actualsheet); + cmd += sh; + commandPrint(tpn); + break; + } + } + } + +cmd += "DISPLAY "; +if(board) { + for(int l = 1; l < 90; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + for(l = 100; l < 256; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + cmd += ";\nSET DISPLAY_MODE REAL;\n"; + } + +if(schematic) { + for(int l = 91; l < 256; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + cmd += ";\n"; + sprintf(s, "EDIT '.s%s';\n", actualsheet); + cmd += s; + } + +if (test) { if (dlgMessageBox(cmd, "OK", "Cancel") != 0) exit (-1);} +// output("c:/tmp/cam2print.scr", "wt") printf("%s", cmd); +exit (cmd); diff --git a/trunk/ulp/centroid-screamingcircuits-smd.ulp b/trunk/ulp/centroid-screamingcircuits-smd.ulp new file mode 100644 index 00000000..069518e9 --- /dev/null +++ b/trunk/ulp/centroid-screamingcircuits-smd.ulp @@ -0,0 +1,63 @@ +/* + * This EAGLE User Language Program creates the proper format + * Centroid file for assembly at Screaming Circuits including + * the reference designator, position, layer and orientation + * of each part + * + * www.screamingcircuits.com + * + */ + #usage "Create Centroid file for Screaming Circuits assembly

" + "Author www.screamingcircuits.com" + +string Version = "1.2.0"; // Version 1.2, March 22, 2012 +string fileMessage; + +string rotation(real Angle) +{ + string s; + sprintf(s, "%.1f", Angle); + int pos = strchr(s, '.'); + if (pos >= 0) if (s[pos + 1] == '0') s[pos] = 0; + return s; +} + +string side(int Mirror) +{ + string s; + + if (Mirror){ + s = "Bottom"; + } + else { + s = "Top"; + } + return s; +} + +if (!board) { + dlgMessageBox("


ERROR: This ULP will only operate in the board layout view.

Switch to the board layout editor and re-run."); + exit(1); +} + +if (board) board(B) { + output(filesetext(B.name, "_centroid.csv")) { + printf("Screaming Circuits SMD component position file.\n"); + printf("Created by Centroid_ScreamingCircuits_smd.ulp %s.\n\n", Version); + printf("Centroid Data for pc board: \"%s\" as of: %s\n", filename(B.name), t2string(time())); + printf("Measurements are in inches. Comma delimited\n"); + printf("Only surface mount components included\n\n"); + printf("%s,%s,%s,%s,%s\n", "RefDes", "Layer", "LocationX", "LocationY", "Rotation"); + B.elements(E) { + int isSmd; + isSmd = 0; + E.package.contacts(C) { if (C.smd) isSmd = 1; } + if (isSmd) printf("%s,%s,%5.3f,%5.3f,%s\n", E.name, side(E.mirror), u2inch(E.x), u2inch(E.y), rotation(E.angle)); + } + } + + fileMessage = "


Centroid file for Screaming Circuits PCB assembly.

Include this file in the .ZIP file along with your GERBER files and Bill of Materials:

" + filesetext(B.name, "_centroid.csv\n"); + + dlgMessageBox(fileMessage); +} + diff --git a/trunk/ulp/change-pad-in-lbr-1.bmp b/trunk/ulp/change-pad-in-lbr-1.bmp new file mode 100644 index 00000000..7cbc5e3d Binary files /dev/null and b/trunk/ulp/change-pad-in-lbr-1.bmp differ diff --git a/trunk/ulp/change-pad-in-lbr-x.bmp b/trunk/ulp/change-pad-in-lbr-x.bmp new file mode 100644 index 00000000..cb4429af Binary files /dev/null and b/trunk/ulp/change-pad-in-lbr-x.bmp differ diff --git a/trunk/ulp/change-pad-in-lbr.ulp b/trunk/ulp/change-pad-in-lbr.ulp new file mode 100644 index 00000000..384d770d --- /dev/null +++ b/trunk/ulp/change-pad-in-lbr.ulp @@ -0,0 +1,491 @@ +#usage "Change shape, diameter, flags and drill of all pads in a library\n" + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED +// Version 4.2 -- 20.04.2004 alf@cadsoft.de +// Version 4.3 -- 04.03.2005 alf@cadsoft.de +// Change Drill gerundet auf 1/10 mm +// wenn angegebenes Toleranzfenster eingehalten wird. +// Change Restring wenn angegebenes Toleranzfenster eingehalten wird. + +string drill_help = "Changes the drill diameter for all pads within the tolerances.
" + + "
"; + +string rounddrill_help = "Rounding the drill diameter to 1/10 mm.
Only for drill diameter of pads that are within the given tolerances.
" + + "
"; + +string restring_help = "Changes the restring of pads that are within the given range.
" + + "
"; + + +if (language() == "de") { + drill_help = "Ändert nur Bohrdurchmesser von PADs deren Wert innerhalb des Toleranzfensters liegt.
" + + "
"; + + rounddrill_help = "Bohrdurchmesser auf 1/10 mm runden.
Rundet nur Bohrdurchmesser von PADs deren Wert innerhalb des Toleranzfensters liegt.
" + + "
"; + + restring_help = "Ändert nur Restringe von Pads deren Wert innerhalb des Bereiches liegt.
" + + "
"; +} + + +string script_change = ""; + +int Result = 0; +string grid = "GRID MM FINEST;\n"; +string cmd, s; + + // *** flags for changes +int change_pac; +int cntPac = 0, cntContact = 0; + +int to_change[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +int begin = - 1; // *** pointer of flags +int P_firstpad = begin + 1; +int P_shape = P_firstpad + 1; +int P_drill = P_shape + 1; +int P_rounddrill = P_drill + 1; +int P_diameter = P_rounddrill + 1; +int P_restring = P_diameter + 1; +int P_stopmask = P_restring + 1; +int P_creammask = P_stopmask + 1; +int last = P_creammask + 1; + +int changefrom = P_drill; +int changeto = last - 1; + + +real change_values[] = { + 0, // Pad-First-Pin + 0, // Pad-Shape + 0, // Pad-Drill + 0, // Pad-Drill round + 0, // Pad-Diameter + 0, // Pad-Restring + 0, // Pad-Stop-Mask + 0, // Pad-Cream-Mask + 0 }; + +string tochange[] = { + "Change pad flag '&First' ", + "Change pad &shape", + "Change pad &drill", + "Round pad drill 1/&10 mm", + "Change pad dia&meter", + "Change pad &restring", + "Change pad s&top mask ON/OFF", + "Change pad &cream mask ON/OFF", + "" }; + +string menuchange[] = { + "Change Pad Flag 'First' ", + "Change Pad Shape", + "Change Pad Drill", + "Rounding Pad Drill 1/10 mm", + "Change Pad Diameter", + "Change Pad Restring", + "Change Pad Stop Mask ON/OFF", + "Change Pad Cream Mask ON/OFF", + "" }; + +real min_val[] = { + 0.0, // Pad-First-Pin + 0.0, // Pad-Shape + 0.0, // Pad-Drill + 0.0, // Pad-Drill round + 0.0, // Pad-Diameter + 0.0, // Pad-Restring + 0.0, // Pad-Stop-Mask + 0.0 // Pad-Cream-Mask + }; + +real max_val[] = { + 0, // Pad-First-Pin + 13.1, // Pad-Shape + 13.1, // Pad-Drill + 13.1, // Pad-Drill round + 13.1, // Pad-Diameter + 13.1, // Pad-Restring + 1, // Pad-Stop-Mask + 1, // Pad-Cream-Mask + 0 + }; + +string min_max[] = { + "", // Pad-First-Pin + "in the range of 0.0...13.1 mm", // Pad-Shape + "in the range of 0.0...13.1 mm", // Pad-Drill + "", // Pad-Drill round + "in the range of 0.0...13.1 mm", // Pad-Diameter + "in the range of 0.0...13.1 mm", // Pad-Restring + "in the range of 0 Off / 1 On", // Pad-Stop-Mask + "in the range of 0 Off / 1 On", // Pad-Cream-Mask + "" + }; + +string fist_pad_name = "1"; // change to A-Z alphabetical (example: for transistor emitter = E) +string first_onoff[] = { "OFF", "ON" }; +int flag_offon = 1; +string stop_onoff = "ON"; +string cream_onoff = "ON"; +int shape = 0; +int shape1 = 0; +int round_drill = 0; // to round pad drills to 1/10 mm +int mpercent = 2, ppercent = 5; +real minrestring = 0.0, maxrestring = 0.3; + +string pad1, padx; + +string shape_form[] = { // change Shape + "NONE", + "SQUARE", + "ROUND", + "OCTAGON", + "" }; + +int cntchrestring = 0; +int cntchdrill = 0; + + + +// *** function *** +void get_changemenue(string lib) { + Result = dlgDialog("Change PAD in Library") { + dlgLabel("(" + lib + ")"); + dlgStretch(0); + dlgHBoxLayout { + dlgGroup("Change") { + dlgCheckBox(tochange[P_firstpad], to_change[P_firstpad]); + dlgCheckBox(tochange[P_shape], to_change[P_shape]); + dlgHBoxLayout { + dlgCheckBox(tochange[P_drill], to_change[P_drill]) if (to_change[P_rounddrill]) to_change[P_rounddrill] = 0; + dlgSpacing(45); + dlgCheckBox(tochange[P_rounddrill], to_change[P_rounddrill]) if (to_change[P_drill]) to_change[P_drill] = 0; + dlgStretch(1); + } + dlgHBoxLayout { + dlgCheckBox(tochange[P_diameter], to_change[P_diameter]) if (to_change[P_restring]) to_change[P_restring] = 0; + dlgSpacing(20); + dlgCheckBox(tochange[P_restring], to_change[P_restring]) if (to_change[P_diameter]) to_change[P_diameter] = 0; + dlgStretch(1); + } + dlgCheckBox(tochange[P_stopmask], to_change[P_stopmask]); + dlgCheckBox(tochange[P_creammask], to_change[P_creammask]); + } + dlgStretch(1); + } + dlgStretch(1); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+Change") dlgAccept(); + dlgStretch(1); + dlgPushButton("-ESC") dlgReject(); + dlgStretch(0); + } + dlgStretch(0); + }; + if (Result == 0) exit (0); + + if (to_change[P_shape] || to_change[P_firstpad]) { + Result = dlgDialog("Change Pad Shape") { + if (to_change[P_firstpad]) { + dlgHBoxLayout { + dlgCheckBox(tochange[0], to_change[P_firstpad]); + dlgLabel(" b&y name "); + dlgStringEdit(fist_pad_name); + dlgLabel("&On/Off"); + dlgComboBox(first_onoff, flag_offon); + dlgStretch(1); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgGroup("Shape of Pin 1") { + dlgGridLayout { + dlgCell(2, 1) dlgRadioButton(shape_form[0], shape1); + dlgCell(3, 1) dlgRadioButton(shape_form[1], shape1); + dlgCell(4, 1) dlgRadioButton(shape_form[2], shape1); + dlgCell(5, 1) dlgRadioButton(shape_form[3], shape1); + } + } + dlgLabel(pad1); + dlgGroup("Shape of other pin(s)") { + dlgGridLayout { + dlgCell(2, 1) dlgRadioButton(shape_form[0], shape); + dlgCell(3, 1) dlgRadioButton(shape_form[1], shape); + dlgCell(4, 1) dlgRadioButton(shape_form[2], shape); + dlgCell(5, 1) dlgRadioButton(shape_form[3], shape); + } + } + dlgLabel(padx); + dlgStretch(1); + } + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + dlgPushButton("-ESC") dlgReject(); + dlgStretch(0); + } + }; + if (Result == 0) exit (0); + } + + for (int n = changefrom; n <= changeto; n++) { + if (to_change[n]) { + int todo = 1; + Result = dlgDialog(menuchange[n]) { + if (n == P_drill) { + dlgLabel(drill_help); + dlgHBoxLayout { + dlgGroup("Tolerance") { + dlgHBoxLayout { + dlgLabel(" &- %"); + dlgIntEdit(mpercent); + dlgLabel(" &+ %"); + dlgIntEdit(ppercent); + dlgStretch(1); + } + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgLabel("&Drill diameter "); + dlgRealEdit(change_values[n], min_val[n], max_val[n]); + dlgStretch(1); + } + todo = 0; + } + + if( n == P_rounddrill) { + dlgLabel(rounddrill_help); + dlgHBoxLayout { + dlgLabel(" &- %"); + dlgIntEdit(mpercent); + dlgLabel(" &+ %"); + dlgIntEdit(ppercent); + dlgStretch(1); + todo = 0; + } + } + + if( n == P_restring) { + dlgLabel(restring_help); + dlgHBoxLayout { + dlgGroup("Range") { + dlgHBoxLayout { + dlgLabel(" m&in "); + dlgRealEdit(minrestring); + dlgLabel(" m&ax "); + dlgRealEdit(maxrestring); + } + } + dlgLabel(" New &Restring "); + dlgRealEdit(change_values[n], min_val[n], max_val[n]); + dlgStretch(1); + } + todo = 0; + } + + if (todo) { + dlgHBoxLayout { + dlgRealEdit(change_values[n], min_val[n], max_val[n]); + dlgStretch(1); + } + } + + dlgVBoxLayout { + if (min_max[n]) dlgLabel(min_max[n]); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + dlgSpacing(100); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + } + } + }; + if (Result == 0) exit (0); + } + } + return; +} + + +// change First flag +void change_first(string onoff, int x, int y) { + sprintf(s, "Change FIRST %s (%.4f %.4f);\n", onoff, u2mm(x), u2mm(y)); + cmd += s; + return; +} + + +// change Pad Shape +void change_shape(string shape, int x, int y) { + sprintf(s, "Change SHAPE %s (%.4f %.4f);\n", shape, u2mm(x), u2mm(y)); + cmd += s; + return; +} + + +// change Drill Diameter +void change_prill(real diameter, int x, int y, int drill, string pac) { + real isdrill = u2mm(drill); + if (isdrill >= diameter - (diameter / 100 * mpercent) && isdrill <= diameter + (diameter / 100 * ppercent)) { + if (abs(diameter - isdrill) < 0.000001 ) return; + sprintf(s, "Change DRILL %.4f (%.4f %.4f);\n", diameter, u2mm(x), u2mm(y)); + cmd += s; + cntchdrill++; + } + return; +} + + +// change Drill Diameter rounded 1/10 mm +void change_prillround(real diameter, int x, int y, int drill) { + real isdrill = u2mm(drill); + real rval = round(isdrill * 10.0) / 10.0; + + if (abs(rval - isdrill) < 0.000001 ) return; + + if (isdrill >= rval - ((rval / 100) * mpercent) && isdrill <= rval + ((rval / 100) * ppercent)) { + cntchdrill++; + sprintf(s, "Change DRILL %.4f (%.4f %.4f);\n", rval, u2mm(x), u2mm(y)); + cmd += s; + } + return; +} + + +// change Pad Diameter +void change_pdiameter(real diameter, int x, int y) { + sprintf(s, "Change DIAMETER %.4f (%.4f %.4f);\n", diameter, u2mm(x), u2mm(y)); + cmd += s; + return; +} + + +// change Pad Restring +void change_restring(real mRestring, int diam, int x, int y, int drill) { + real isrestring = u2mm(diam) - u2mm(drill); + if (isrestring) isrestring /= 2; // ** do not device by zerro ** + if (isrestring < 0) isrestring = 0; // negativ parameter not allowed + if (isrestring >= minrestring && isrestring <= maxrestring) { + sprintf(s, "CHANGE DIAMETER %.4f (%.4f %.4f);\n", u2mm(drill) + 2 * mRestring, u2mm(x), u2mm(y)); + cmd += s; + cntchrestring++; + } + return; +} + + +// change Stop mask flag +void change_mask(string onoff, int x, int y) { + sprintf(s, "Change %s (%.4f %.4f);\n", onoff, u2mm(x), u2mm(y)); + cmd += s; + return; +} + + +// ******************************************************** +if (library) { + pad1 = ""; + padx = ""; + int n = 0; + library(L) { + get_changemenue(L.name); + + // *** check if a change parameter activ *** + if (!to_change[P_shape] && + !to_change[P_drill] && + !to_change[P_rounddrill] && + !to_change[P_diameter] && + !to_change[P_restring] && + !to_change[P_stopmask] && + !to_change[P_creammask] && + !to_change[P_firstpad]) exit (0); + + if (change_values[P_stopmask]) stop_onoff = "ON"; + else stop_onoff = "OFF"; + if (change_values[P_creammask]) cream_onoff = "ON"; + else cream_onoff = "OFF"; + + script_change = filesetext(L.name, "~~~.scr"); + + output(script_change, "wtD") { + printf("DISPLAY NONE 1 16 17;\n"); + int firstf = 1; + L.packages(P) { + cntPac++; + change_pac = 0; + cmd = ""; + P.contacts(C) { + cntContact++; + if (C.pad) { + if (to_change[P_shape] && (shape || shape1)){ + if (C.name == "1" && shape1) change_shape(shape_form[shape1], C.pad.x, C.pad.y); + else { if (shape) change_shape(shape_form[shape], C.pad.x, C.pad.y); } + } + if (to_change[P_firstpad]) { + if (C.name == fist_pad_name) { + change_first(first_onoff[flag_offon], C.x, C.y); + } + } + if (to_change[P_drill]) { + change_prill(change_values[P_drill], C.pad.x, C.pad.y, C.pad.drill, P.name); + } + if (to_change[P_rounddrill]) { + change_prillround(change_values[P_drill], C.pad.x, C.pad.y, C.pad.drill); + } + if (to_change[P_diameter]) { + change_pdiameter(change_values[P_diameter], C.pad.x, C.pad.y); + } + if (to_change[P_restring]) { + change_restring(change_values[P_restring], C.pad.diameter[LAYER_BOTTOM], C.pad.x, C.pad.y, C.pad.drill); + } + if (to_change[P_stopmask]) { + change_mask("STOP " + stop_onoff, C.pad.x, C.pad.y); + } + } + else if (C.smd) { + if (to_change[P_stopmask]) { + change_mask("STOP " + stop_onoff, C.smd.x, C.smd.y); + } + if (to_change[P_creammask]) { + change_mask("CREAM " + cream_onoff, C.smd.x, C.smd.y); + } + } + } + if (cmd) { + printf("EDIT %s.PAC;\n", P.name); + printf("%s",grid); + printf("%s",cmd); + } + } + // printf("GRID DEFAULT;\n"); + printf("DISPLAY NONE 1 16 17 20 21 29 31;\n"); + } + } + string sc; + s = ""; + if (cntchdrill) { + sprintf(s, "%d Drills to change!\n", cntchdrill); + sc += s; + } + if (cntchrestring) { + sprintf(s, "%d Pad-Restring to change!", cntchrestring); + sc += s; + } + if (sc) if (dlgMessageBox(sc, "Ok", "Cancel") != 0) exit(0); + + exit ("SCRIPT '" + script_change + "';\n"); +} + +else { + dlgMessageBox("! Start this ULP in a Library"); + exit (0); +} \ No newline at end of file diff --git a/trunk/ulp/change-prefix-sch.ulp b/trunk/ulp/change-prefix-sch.ulp new file mode 100644 index 00000000..0afd228b --- /dev/null +++ b/trunk/ulp/change-prefix-sch.ulp @@ -0,0 +1,146 @@ +#usage "Change PREFIX of parts in schematic

" + "RUN change-prefix-sch [old] [new]
" + "Author: alf@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string Version = "ULP Version 1.0.0"; // 2010.11.16 alf@cadsoft.de + +int actual_sheet = 0; + +string ChangeOldPrefix = argv[1]; +string ChangeNewPrefix = argv[2]; + +string cmd; +string s; + +int test = 0; +if (argv[3] == "?") test = 1; + +int GetNumberIndex(string Name) { + int l = strlen(Name) - 1; + for (int i = l; i >= 0; --i) { + if (!isdigit(Name[i])) + return i < l ? i + 1 : -1; + } + return 0; +} + + +string getprefix(string name) { // Prefix of Device + int num = GetNumberIndex(name); + if (num < 1) return name; + else { + string pfx = name; + pfx[num] = 0; + return pfx; + } +} + + +void setgridmilllayer (void) { + sprintf(s, "GRID MIL 100 OFF;\n"); + cmd += s; + sprintf(s, "DISPLAY NONE 94 -95 -96;\n"); + cmd += s; + return; +} + + +void restorevisiblelayer(UL_SCHEMATIC S) { + sprintf(s, "DISP NONE "); + cmd += s; + S.layers(L) { + if (L.visible) { + sprintf(s, "%d ", L.number); + cmd += s; + } + } + cmd += ";\n"; + return; +} + + +if (schematic) { + if (ChangeOldPrefix && ChangeNewPrefix) { // ist alter und neuer Prefix angegeben? + } + else { + int Result = dlgDialog("Change PREFIX Schematic") { + dlgHBoxLayout { + dlgLabel("Change &old PREFIX "); + dlgStringEdit(ChangeOldPrefix); + dlgLabel(" with &new PREFIX "); + dlgStringEdit(ChangeNewPrefix); + dlgStretch(1); + } + + dlgHBoxLayout { + dlgPushButton("+&OK") dlgAccept(); + dlgSpacing(15); + dlgPushButton("-Cancel") dlgReject(); + dlgSpacing(15); + dlgLabel(Version); + dlgStretch(1); + } + }; + if (!Result) exit (0); + } + ChangeOldPrefix = strupr(ChangeOldPrefix); + ChangeNewPrefix = strupr(ChangeNewPrefix); + + sheet(SH) actual_sheet = SH.number; // die aktuelle Schaltplanseite + + schematic(S) { + setgridmilllayer (); + int l = 1; + int chk; + int issheet = 0; + S.parts(P) { + if (P.device.package) { // nur Bauteiel mit Package, also keine Supply-Symbole etc. + int n = GetNumberIndex(P.name); + if (n > 0) { + if (getprefix(P.name) == ChangeOldPrefix) { + P.instances(I) { + if (I.sheet) { // kann keine Namen aendern von Parts, wenn das Gate nicht auf einer Seite platziert ist! + // Beachte ADD-Level REQUEST! + if (issheet != I.sheet) { + issheet = I.sheet; + sprintf(s, "EDIT .S%d;\n", I.sheet); + cmd += s; + } + sprintf(s, "NAME '%s' (%.4f %.4f);\n", ChangeNewPrefix + strsub(P.name, n), u2mil(I.x), u2mil(I.y) ); + cmd += s; + break; + } + } + } + } + } + } + + sprintf(s, "GRID MIL 100;\n"); + cmd += s; + sprintf(s, "EDIT .S%d;\n", actual_sheet); + cmd += s; + restorevisiblelayer(S); + + string fname = filesetext(S.name, "~change-prefix.scr"); + output(fname, "wtD") printf("%s", cmd); + if (test) { + dlgDialog("Script-Show") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-esc") { dlgReject(); exit(-999); } + dlgStretch(1); + } + }; + } + exit ("SCRIPT '" + fname + "';"); + } +} + +else { + dlgMessageBox("Start this ULP in a Schematic"); + exit (0); +} diff --git a/trunk/ulp/change-via-by-stack.ulp b/trunk/ulp/change-via-by-stack.ulp new file mode 100644 index 00000000..b2ef1829 --- /dev/null +++ b/trunk/ulp/change-via-by-stack.ulp @@ -0,0 +1,119 @@ +#usage "[de]Change Via by Stack (Start-Layer End-Layer)
" + "CHANGE VIA Drill/Diameter/Shape/Stack selektiert die Vias nur am Start-Layer." + "

" + "RUN change-via-by-stack Start-Layer End-Layer [[Drill [Diameter [NO] [Shape]]]] | [Newstart-Newend STACK]" + "

" + "RUN change-via-by-stack 1 2
" + "RUN change-via-by-stack 1 2 0.1 0.15
" + "RUN change-via-by-stack 1 2 0.1 0.15 SQUARE
" + "RUN change-via-by-stack 1 2 no square
" + "RUN change-via-by-stack 1 2 1-16 STACK
" + "Ändert Drill, Durchmesser, Shape bzw. Stacktiefe (Via-Länge) von Vias mit angegebener Stacktiefe.
" + "Wird die Option Drill bzw. Diameter nicht angegeben, so werden die " + "aktuell eingestellten (zuletzt mit CHANGE geänderten) Werte benutzt.
" + "Wird Shape nicht angegeben, bleibt die Form unverändert.
" + "Soll Drill bzw. Diameter nicht geändert werden, geben Sie die Option NO vor Shape an. " + "NO darf nicht angegeben werden, wenn Drill oder Diameter benutzt wird.
" + "Vor der Option STACK muß die neue Stacktiefe Start-End (z.B. 2-15) angegeben werden.
" + "Die Optionen können groß oder klein geschrieben werden." + "

" + "Author alf@cadsoft.de" + , + "[en]Change Via by Stack (Start-Layer End-Layer)
" + "Changes drill, diameter, shape or via stack (via length) of vias with a given via stack.
" + "If the options Drill and/or Diameter are not used, the ULP will take the " + "currently valid values (previously set with the CHANGE command).
" + "If the Shape option is not given, the via shapes stay unchanged.
" + "If you want to have Drill and Diameter unchanged, use the option NO " + "before the Shape option.
" + "You must not use NO, if Drill or Diameter are to be changed.
" + "Define the new via stack Start-End (for example: 2-15) before the STACK option.
" + "Upper or lower case letters does not matter here." + "

" + "Author alf@cadsoft.de" + + + +string Version = "Version 1.0"; // 2007.12.04 + +int via_start = strtod(argv[1]); +int via_end = strtod(argv[2]); +string v_shape; +string stack = ""; +string new_stack = ""; +string script; + +real v_drill = 0.0; +real v_diam = 0.0; +if (argv[3]) v_drill = strtod(argv[3]); +if (argv[4]) v_diam = strtod(argv[4]); + +void set_layer() { + printf("GRID MM FINEST;\n"); + printf("DISPLAY NONE;\nDISPLAY %d 18;\n", via_start ); + return; +} + +if (board) { + if (argc < 3) { + dlgMessageBox(usage + "

" + Version, "OK"); + exit(-1); + } + + if (argc == 5) { + stack = strupr(argv[4]); + if (stack == "STACK") new_stack = argv[3]; + else stack = ""; + } + + if (!stack) { + v_shape = strupr(argv[argc-1]); + if (v_shape == "ROUND" || v_shape == "SQUARE" || v_shape == "OCTAGON"); + else v_shape == ""; + } + + board(B) { + script = filesetext(B.name, ".scr"); + output(script, "wtD") { // temporäres file + set_layer(); + B.signals(S) { + S.vias(V) { + if (V.start == via_start && V.end == via_end) { + if (stack) printf("CHANGE VIA %s (%.4f %.4f);\n", new_stack, u2mm(V.x), u2mm(V.y) ); + else { + if (v_shape) printf("CHANGE SHAPE %s (%.4f %.4f);\n", v_shape, u2mm(V.x), u2mm(V.y) ); + if (strupr(argv[3]) != "NO") { + if (v_drill) printf("CHANGE DRIL %.4f (%.4f %.4f);\n", v_drill, u2mm(V.x), u2mm(V.y) ); + else printf("CHANGE DRIL (%.4f %.4f);\n", u2mm(V.x), u2mm(V.y) ); + if (v_diam) printf("CHANGE DIAM %.4f (%.4f %.4f);\n", v_diam, u2mm(V.x), u2mm(V.y) ); + else printf("CHANGE DIAM (%.4f %.4f);\n", u2mm(V.x), u2mm(V.y) ); + } + } + } + } + } + printf("GRID LAST;\n"); + printf("DISPLAY NONE "); + B.layers(L) if (L.visible) printf(" %d", L.number); + printf(";\n"); + } + } + +dlgDialog("test") { + string text; + int t = fileread(text, script); + dlgTextEdit(text); + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-1); } + dlgStretch(1); + } +}; + + exit("SCRIPT '" + script + "'\n"); +} + +else { + dlgMessageBox("Start this ULP in a Board", "OK"); + exit(0); +} \ No newline at end of file diff --git a/trunk/ulp/check-used-lbrs.ulp b/trunk/ulp/check-used-lbrs.ulp new file mode 100644 index 00000000..37dfb07b --- /dev/null +++ b/trunk/ulp/check-used-lbrs.ulp @@ -0,0 +1,106 @@ +#usage "List of components that no longer have a valid library component listed.

" + "Author: alf@cadsoft.de" + +string Version = "1.0.0"; // 2011-04-14 alf@cadsoft.de + + +string LbrName[]; +int Lcnt = 0; +string MissLbr[]; +int Mcnt = 0; +string NoExist[]; + +int Ln = 0; +do { + string l[]; + int cnt = fileglob(l, path_lbr[Ln]+"/*.lbr"); + Ln++; + if (cnt) { + for (int n = 0; n < cnt; n++) { + LbrName[Lcnt] = filename(l[n]); + Lcnt++; + } + } +} while (path_lbr[Ln]); + + +void test(void) { + int sel = -1; + int srt = 0; + dlgDialog("test") { + dlgHBoxLayout dlgSpacing(400); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgListView("Librarys", LbrName, sel, srt); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + +void showmiss(string header, string Listheader) { + for (int n = 0; n < Mcnt; n++) { + MissLbr[n] += "\t" + NoExist[n]; + } + int sl = -1; + int sel = -1; + dlgDialog(header) { + dlgHBoxLayout dlgSpacing(400); + dlgListView("LBRs searched in ", path_lbr, sl); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgListView(Listheader, MissLbr, sel); + } + dlgLabel("Note: This ULP works case sensitive!"); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + + +int checklibary(string name) { + int n; + for (n = 0; n < Lcnt; n++) { + if (name == LbrName[n]) return -1; // LBR in lirary list. + } + for (n = 0 ; n < Mcnt; n++) { + if (MissLbr[n] == name) return n; // LBR in missing LBR list. + } + MissLbr[Mcnt] = name; // add to missing LBR list. + Mcnt++; + return Mcnt -1; +} + + +if (schematic) { + schematic(SCH) { + SCH.parts(P) { + int no = checklibary(P.deviceset.library); + if (no >= 0) NoExist[no] += P.name + " "; + } + } + if (Mcnt) showmiss("Missing LBRs for used parts in Schematic", "Used libraries not found\tParts"); + exit(0); +} + +else if (board) { + board(B) { + B.elements(E) { + int no = checklibary(E.package.library); + if (no >= 0) NoExist[no] += E.name + " "; + } + } + if (Mcnt) showmiss("Missing LBRs for used elements in Board", "Used libraries not found\tElements"); + exit(0); +} + +dlgMessageBox("Start this ULP in a SCH or BRD!", "OK"); + diff --git a/trunk/ulp/clear-layer-in-lbr.ulp b/trunk/ulp/clear-layer-in-lbr.ulp new file mode 100644 index 00000000..663700ce --- /dev/null +++ b/trunk/ulp/clear-layer-in-lbr.ulp @@ -0,0 +1,89 @@ +#usage "This ULP generates a script to clear layer(s) in library.

" + "run clear-layer-in-lbr.ulp [YES] layer [layer] [layer] ....
" + "YES = clear without confirmation.
" + "Clear only layer in packages
" + "

" + "Author: support@cadsoft.de" + +// Version 1.01 -- 2008-04-10 changed GROUP ... (>x y); alf@cadsoft.de + +// ---------- parameter section ------------------------------------- + +string clrscript = "~clear~.scr"; +string scriptfile; + +int layer_visible[]; +int clear_layer[]; + +int cnt = 1; +int clear_outo = 0; +string s; + + +// **** main **** +if (library) { + string cmd; + if (argc < 2) { + dlgMessageBox("Start this ulp from command line with parameter

Usage:
" + usage, "OK"); + exit(0); + } + if (argv[1] == "YES") { cnt = 2; clear_outo = 1; } + for (int n = cnt; n <= argc; n++) { + clear_layer[n] = strtol(argv[n]); + cmd += argv[n] + "\n"; + } + + library(L) { + L.layers(LY) { + layer_visible[LY.number] = LY.visible; + } + scriptfile = filedir(L.name) + clrscript; + output(scriptfile, "wtD") { + printf("GRID MM FINEST;\nDISPLAY NONE "); + for (int n = cnt; n < argc; n++) { + printf(" %d", clear_layer[n]); + if (clear_layer[n] == 21) { + printf(" -23 -25 -27 -51"); + } + if (clear_layer[n] == 22) { + printf(" -24 -26 -28 -52"); + } + } + printf(";\n"); + + L.packages(P) { + // extended with .PAC ## 22.03.2005 support@cadsoft.de + sprintf(s, "Edit %s.PAC;\nCHANGE LAYER %d;\nRECT (%.4f %.4f)(%.4f %.4f);\nGROUP (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (>%.4f %.4f);\nDELETE (>%.4f %.4f);\n", + P.name, + clear_layer[cnt], + u2mm(P.area.x1)/2, u2mm(P.area.y1)/2, + u2mm(P.area.x2)/2, u2mm(P.area.y2)/2, + u2mm(P.area.x1), u2mm(P.area.y1), + u2mm(P.area.x2), u2mm(P.area.y1), + u2mm(P.area.x2), u2mm(P.area.y2), + u2mm(P.area.x1), u2mm(P.area.y2), + u2mm(P.area.x1), u2mm(P.area.y1), + u2mm(P.area.x1), u2mm(P.area.y1) ); + if (clear_outo) { + printf("%s", s); + } + else { + if (dlgMessageBox("clear layer(s) in package:\n" + P.name, "Yes", "+No") == 0) { + printf("%s", s); + } + } + } + printf("grid last;\n"); + printf("DISPLAY NONE "); + for (int l = 255; l ; l--) { + if (l == 99) l = 89; // *** no Symbol Layer *** + if (layer_visible[l]) printf(" %d", l); + } + } + } + exit("SCRIPT '" + scriptfile + "';"); +} + + +dlgMessageBox("Start this ULP from a Library", "OK"); +exit(0); diff --git a/trunk/ulp/cmd-change-brd-width.ulp b/trunk/ulp/cmd-change-brd-width.ulp new file mode 100644 index 00000000..e5ebe724 --- /dev/null +++ b/trunk/ulp/cmd-change-brd-width.ulp @@ -0,0 +1,286 @@ +#usage "This ULP changes the wire width of certain signals and do have " + "a wire width in between the minimum (minwidth) and maximum (maxwidth) values.

" + "Author alf@cadsoft.de" + // "NameOff = 1 switches off the checking of net names.

" + +string hilfe = + "Dieses ULP ändert die Leiterbahnbreite abhaengig vom Signalnamen und " + "der vorgegebenen min. max. Breite.

"; + //"! Mit NameOff kann die Netz-Namen-Ueberpruefung abgeschaltet werden.

"; + +// "THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED." + +// * 2005-03-02 alf@cadsoft.de +// 2008-06-03 alf@cadsoft.de display the same layers as in the beginning +// 2010-04-30 alf@cadsoft.de new button [Add all], [Del. All] + +string Version = "1.5.1"; // 2010-04-30 alf@cadsoft.de + +string help = usage; +if (language() == "de") help = hilfe; + + +int Gridval = 1; // 1=mm 2=mil 3=inch *** + // choose the value for the units you're working with +string grid_unit; + +real changewidth = 0.3; // gewuenschte Breite in *** + // enter desired width here + +real minwidth = 0.0; // Auswahl-Min-Breite in *** + // minimum width and +real maxwidth = 13.1; // Auswahl-Max-Breite in *** + // maximum width of tracks that will be taken into consideration. + +int NameOff = 0; // 0 = Breite abhaengig vom Netznamen aendern + // 0 = change width by name + // 1 = Breite unabhaengig vom Netznamen aendern + // 1 = change width without name + +string signals[] = { "" }; +int s = 0; +string chsignals[] = { "" }; +int chngsig = 0; +int lastSigCh = 0; +int decs; + +string list; + +string grid[] = { "MIC", "MM", "MIL", "INCH" }; +real maxwidthUnit[] = { 13100.0, 13.1, 516.0, 0.516 }; + + +int index[]; +int x1[], y1[], x2[], y2[], layer[]; +int usedlayer[]; +int n = 1; + +int lVisible[]; // 2008-06-03 alf@cadsoft.de + + +int found(string fnam) { + int fnd = 0; + do { + if (chsignals[fnd] == fnam) { + return 1; + break; + } + ++fnd; + } while (chsignals[fnd]); + return 0; +} + + +real fwidth(real ww) { + if (ww <= maxwidth && ww >= minwidth) return 1; + return 0; +} + + +void disp(int l) { + printf("DISPLAY NONE %d ;\n", l); + return; +} + +void clearlay() { + for (int ly = 0; ly <= 255; ly++) usedlayer[ly] = 0; + return; +} + + +void clearsig (int selct) { + for (int r = selct; r < lastSigCh; r++) { + chsignals[r] = chsignals[r + 1]; + } + chsignals[r + 1] = ""; + if (lastSigCh) lastSigCh--; + return; +} + + +void AddAll (void) { + for (int r = 0; r < s; r++) { + chsignals[r] = signals[r]; + } + chsignals[r] = ""; + lastSigCh = r; + return; +} + + +void DelAll (void) { + lastSigCh = 0; + chsignals[lastSigCh] = ""; + return; +} + + + +void AddList (string SigName) { + int found = 0; + for (int r = 0; r < lastSigCh; r++) { + if (chsignals[r] == SigName) { + found = 1; + break; + } + } + if (!found) { + chsignals[r] = SigName; + lastSigCh++; + } + return; +} + + +void menue() { + int cs; + int l; + int Result = dlgDialog("Change wire with") { + string slist[]; + dlgLabel(help); + // dlgSpacing(5); + dlgGridLayout { + dlgCell (0, 1) dlgSpacing(200); + dlgCell (0, 5) dlgSpacing(200); + dlgCell (1, 1) dlgLabel("&Signal list"); + dlgCell (2, 1) dlgComboBox(signals, chngsig); + dlgCell (2, 3) dlgPushButton("&Add -->>") AddList(signals[chngsig]); + dlgCell (3, 3) dlgPushButton("&Add all -->>") AddAll(); + dlgCell (1, 5) dlgLabel("Signals &to change"); + dlgCell (2, 5) dlgComboBox(chsignals, decs); + dlgCell (2, 6) dlgPushButton("&Delete") clearsig(decs); + dlgCell (3, 6) dlgPushButton("Del. all") DelAll(); + } + + dlgStretch(1); + dlgCheckBox("&Change without Signal name", NameOff); + + dlgHBoxLayout { + dlgGroup("between wire width : " + grid_unit) { + dlgHBoxLayout { + dlgLabel("Mi&n. "); dlgRealEdit(minwidth, 0.0, maxwidthUnit[Gridval]); + dlgLabel(" Ma&x. "); dlgRealEdit(maxwidth, minwidth, maxwidthUnit[Gridval]); + } + } + dlgLabel(" new wire &width "); + dlgRealEdit(changewidth); + dlgStretch(1); + } + + dlgHBoxLayout { + dlgPushButton("&OK") dlgAccept(); + dlgSpacing(20); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgLabel(Version); + } + dlgStretch(0); + }; + if (Result == 0) exit (0); + return; +} + + +if (board) board(B) { + B.layers(L) { + lVisible[L.number] = L.visible; + } + B.signals(S) { + signals[s] = S.name; + s++; + } + Gridval = B.grid.unit; + grid_unit = "Unit " + grid[Gridval]; + maxwidth = maxwidthUnit[Gridval]; + menue(); + + clearlay(); + string file = filesetext(B.name, "chnwidth.scr"); + output (file, "wtD") { + printf("# %s\n", Version); + printf("# %s\n\n", EAGLE_SIGNATURE); + printf("# exported from %s\n# at %s\n\n", B.name, t2string(time()) ); + printf("# This Script changed Wire Width between %.3f %s and %.3f %s to %.3f %s\n", + minwidth, grid[Gridval], maxwidth, grid[Gridval], changewidth, grid[Gridval]); + + printf("GRID %s FINEST;\n", grid[Gridval]); + + B.signals(S) { + if (found(S.name) || NameOff) { + real Wwidth; + + S.wires(W) { + switch (Gridval) { + case 0: Wwidth = u2mic(W.width); + break; + + case 1: Wwidth = u2mm(W.width); + break; + + case 2: Wwidth = u2mil(W.width); + break; + + case 3: Wwidth = u2inch(W.width); + break; + } + + if(fwidth(Wwidth)) { + x1[n] = W.x1; + y1[n] = W.y1; + x2[n] = W.x2; + y2[n] = W.y2; + layer[n] = W.layer; + ++n; + } + } + } + } + + sort(n, index, layer); + int dl = 0; + for (int i = 1; i < n; ++i) { + if(dl != layer[index[i]]) { + dl = layer[index[i]]; + disp(dl); + usedlayer[dl] = 1; + } + switch (Gridval) { + case 0: printf("CHANGE WIDTH %.3f (%.3f %.3f);\n", + changewidth, (u2mic(x1[index[i]]) + u2mic(x2[index[i]])) / 2, + (u2mic(y1[index[i]]) + u2mic(y2[index[i]])) / 2 ); + break; + + case 1: printf("CHANGE WIDTH %.3f (%.3f %.3f);\n", + changewidth, (u2mm(x1[index[i]]) + u2mm(x2[index[i]])) / 2, + (u2mm(y1[index[i]]) + u2mm(y2[index[i]])) / 2 ); + break; + + case 2: printf("CHANGE WIDTH %.3f (%.3f %.3f);\n", + changewidth, (u2mil(x1[index[i]]) + u2mil(x2[index[i]])) / 2, + (u2mil(y1[index[i]]) + u2mil(y2[index[i]])) / 2 ); + break; + + case 3: printf("CHANGE WIDTH %.3f (%.3f %.3f);\n", + changewidth, (u2inch(x1[index[i]]) + u2inch(x2[index[i]])) / 2, + (u2inch(y1[index[i]]) + u2inch(y2[index[i]])) / 2 ); + break; + } + } + printf(";\n"); + printf("DISPLAY NONE "); + for(int l = 1; l < 90; l++) { + if (lVisible[l]) { + printf(" %d", l); + } + } + for(l = 100; l < 256; l++) { + if (lVisible[l]) { + printf(" %d", l); + } + } + printf(";\nSET DISPLAY_MODE REAL;\nGRID LAST;\n"); + } + exit ("SCRIPT '" + file + "';"); +} +else dlgMessageBox("start this ULP in Board", "OK"); + diff --git a/trunk/ulp/cmd-change-class.ulp b/trunk/ulp/cmd-change-class.ulp new file mode 100644 index 00000000..a87a8162 --- /dev/null +++ b/trunk/ulp/cmd-change-class.ulp @@ -0,0 +1,117 @@ +#usage "Change Net-Classes in a board\n" + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string grid[] = { "MIC", "MM", "MIL", "INCH" }; +int Gridval = 1; // 0=mic 1=mm 2=mil 3=inch *** + // choose the value for the units you're working with + +string classes[] = { "nu", "nu", "nu", "nu", "nu", "nu", "nu", "nu", "" }; + int isclass; + int toclass; + +int index[]; +int x1[], y1[], layer[]; +int usedlayer[]; +int n = 1; + +string cmd, s; + +void disp(int l) { + sprintf(s, "DISPLAY NONE %d ;\n", l); + cmd += s; + return; + } + +void menue() { + int l; + int Result = dlgDialog("Change wire with") { + string slist[]; + dlgStretch(0); + dlgLabel("Current &Class in Board"); + dlgComboBox(classes, isclass); + dlgLabel("Change Class &to"); + dlgComboBox(classes, toclass); + dlgGroup("&Current Working Grid") { + dlgRadioButton("m&ic", Gridval); + dlgRadioButton("&mm", Gridval); + dlgRadioButton("mi&l", Gridval); + dlgRadioButton("inc&h", Gridval); + } + dlgStretch(1); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+&OK") dlgAccept(); + dlgStretch(1); + dlgPushButton("-&Cancel") dlgReject(); + dlgStretch(0); + } + dlgStretch(0); + }; + if (Result == 0) exit (0); + return; + } + +// main +if (board) board(B) { + B.classes(S) { + classes[S.number] = S.name; + } + menue(); + sprintf(s, "GRID %s FINEST;\n", grid[Gridval]); + cmd += s; + sprintf(s, "CHANGE CLASS %d;\n", toclass); + cmd += s; + B.signals(S) { + if (S.class.number == isclass) { + S.wires(W) { + x1[n] = W.x1; + y1[n] = W.y1; + layer[n] = W.layer; + n++; + break; + } + } + } + + sort(n, index, layer); + int dl = 0; + for (int i = 1; i < n; ++i) { + if(dl != layer[index[i]]) { + dl = layer[index[i]]; + disp(dl); + usedlayer[dl] = 1; + } + switch (Gridval) { + case 0: sprintf(s, "CHANGE CLASS %d (%.3f %.3f);\n", toclass, + u2mic(x1[index[i]]), u2mic(y1[index[i]]) ); + break; + + case 1: sprintf(s, "CHANGE CLASS %d (%.3f %.3f);\n", toclass, + u2mm(x1[index[i]]), u2mm(y1[index[i]]) ); + break; + + case 2: sprintf(s, "CHANGE CLASS %d (%.3f %.3f);\n", toclass, + u2mil(x1[index[i]]), u2mil(y1[index[i]]) ); + break; + + case 3: sprintf(s, "CHANGE CLASS %d (%.3f %.3f);\n", toclass, + u2inch(x1[index[i]]), u2inch(y1[index[i]]) ); + break; + } + cmd += s; + } + cmd += "DISPLAY "; + B.layers(L) { + if (L.visible) { + sprintf(s, "%d ",L.number); + cmd += s; + } + } + cmd += ";\nGRID LAST;\n"; + exit (cmd); + } + +else dlgMessageBox("Start this ULP in a Board", "OK"); diff --git a/trunk/ulp/cmd-change-swap-layer.ulp b/trunk/ulp/cmd-change-swap-layer.ulp new file mode 100644 index 00000000..545aca4f --- /dev/null +++ b/trunk/ulp/cmd-change-swap-layer.ulp @@ -0,0 +1,340 @@ +#usage "Change all objects from one layer to an other\n" + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string Help = "\nObjects in copper layers can be exchanged for\n" + + "other copper layers, but not for non-copper layers.\n" + + "Objects in non-copper layers can be exchanged for\n" + + "other non-copper layers, but not for copper layers."; + +string Version = "4.4"; // 2007.03.16 change also Layer 20 + +int isLayer = 1, toLayer = 16 ; +int swap = 0; +string usedLayer[] = { "NONE" }; +int usedLayerN[] = { 0 }; + +string Font[] = { "VECTOR", "PROPORTIONAL", "FIXED" } ; + +string Pour[] = { "SOLID", "HATCH" }; +string Orphans[] = { "OFF", "ON" }; +string Thermals[] = { "OFF", "ON" }; + +enum { type_wire, type_polygon }; + +string c, cmdheader, cmdripup, cmdwire; + +// check problem by crossing layer +int checkLayer(int is1, int to1, int swap) { + if (is1 == 0 || to1 == 0) return 1; + // do not change in Via - Pad - Signal - layer + for (int l = 17; l < 20; l++) { + if (is1 == l || to1 == l ) return l; + } + // you can not swap other to copper layer and back + if ( (is1 > 19 && to1 < 20 || is1 < 20 && to1 > 19) ) return 4; + // do not use duble + if (is1 == to1 ) return 2; + + // not use Originlayer + if (is1 == 23 || to1 == 23 ) return 23; + if (is1 == 24 || to1 == 24 ) return 23; + return 0; +} + +void delete(real x, real y, int type) { + if (isLayer > 16) { + sprintf(c, "DELETE (S%.4f %.4f);\n ", x, y ); + cmdripup += c; + } + else { + if (type == type_polygon) { + sprintf(c, "DELETE (S%.4f %.4f);\n", x, y ); + cmdripup += c; + } + else { + sprintf(c, "RIPUP (%.4f %.4f);\n", x, y ); + cmdripup += c; + } + } + return; +} + + +void ch_layer(int islay, int tolay, int display) { + real dx, dy; + board(B) { + B.signals(S) { + S.wires(W) { + if (W.layer == islay) { + delete(u2mm(W.x1 + W.x2) / 2, u2mm(W.y1 + W.y2) / 2, type_wire); + sprintf(c, "WIRE '%s' %.4f %+.1f (%.4f %.4f) (%.4f %.4f);\n", + S.name, u2mm(W.width), W.curve, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2)); + cmdwire += c; + } + } + S.polygons(P) { + if (P.layer == islay) { + if(islay < 17) { + sprintf(c, "CHANGE RANK %d;\n", P.rank); + cmdwire += c; + sprintf(c, "CHANGE ORPHANS %s;\n", Orphans[P.orphans]); + cmdwire += c; + sprintf(c, "CHANGE ISOLATE %.4f;\n", u2mm(P.isolate)); + cmdwire += c; + sprintf(c, "CHANGE SPACING %.4f;\n", u2mm(P.spacing)); + cmdwire += c; + sprintf(c, "CHANGE THERMAL %s;\n", Thermals[P.thermals]); + cmdwire += c; + sprintf(c, "CHANGE POUR %s;\n", Pour[P.pour]); + cmdwire += c; + } + int first = 1; + P.wires(W) { + if (first) { + dx = u2mm(W.x1); + dy = u2mm(W.y1); + delete(dx, dy, type_polygon); + sprintf(c, "POLYGON '%s' %.4f %+.1f (%.4f %.4f) (%.4f %.4f)\n", + S.name, u2mm(W.width), W.curve, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2)); + cmdwire += c; + first = 0; + } + else { + sprintf(c, " %+.1f (%.4f %.4f)\n", W.curve, u2mm(W.x2), u2mm(W.y2)); + cmdwire += c; + } + } + sprintf(c, ";\n"); // close the polygon + cmdwire += c; + } + } + } + B.wires(W) { + if (W.layer == islay) { + delete(u2mm(W.x1 + W.x2) / 2, u2mm(W.y1 + W.y2) / 2, type_wire); + sprintf(c, "WIRE %.1f %+.1f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(W.width), W.curve, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2)); + cmdwire += c; + } + } + B.polygons(P) { + if (P.layer == islay) { + if(islay < 17) { + sprintf(c, "CHANGE RANK %d;\n", P.rank); + cmdwire += c; + sprintf(c, "CHANGE ORPHANS %s;\n", Orphans[P.orphans]); + cmdwire += c; + sprintf(c, "CHANGE ISOLATE %.4f;\n", u2mm(P.isolate)); + cmdwire += c; + sprintf(c, "CHANGE SPACING %.4f;\n", u2mm(P.spacing)); + cmdwire += c; + sprintf(c, "CHANGE THERMAL %s;\n", Thermals[P.thermals]); + cmdwire += c; + sprintf(c, "CHANGE POUR %s;\n", Pour[P.pour]); + cmdwire += c; + } + int first = 1; + P.wires(W) { + if (first) { + dx = u2mm(W.x1); + dy = u2mm(W.y1); + delete(dx, dy, type_polygon); + sprintf(c, "POLYGON %.4f %+.1f (%.4f %.4f) (%.4f %.4f)\n", u2mm(P.width), + W.curve, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2)); + cmdwire += c; + first = 0; + } + else { + sprintf(c, " %+.1f (%.4f %.4f)\n", W.curve, u2mm(W.x2), u2mm(W.y2)); + cmdwire += c; + } + } + sprintf(c, ";\n"); // close the polygon + cmdwire += c; + } + } + B.circles(C) { + if (C.layer == islay) { + dx = u2mm(C.x + C.radius); + dy = u2mm(C.y); + delete(dx, dy, type_polygon); + sprintf(c, "CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), u2mm(C.x), u2mm(C.y), u2mm(C.x + C.radius), u2mm(C.y)); + cmdwire += c; + } + } + B.rectangles(R) { + if (R.layer == islay) { + dx = u2mm(R.x1); + dy = u2mm(R.y1); + delete(dx, dy, type_polygon); + sprintf(c, "RECT R%.1f (%.4f %.4f) (%.4f) (%.4f);\n", + R.angle, u2mm(R.x1), u2mm(R.y1), u2mm(R.x2), u2mm(R.y2) ); + cmdwire += c; + } + } + B.texts(T) { + if (T.layer == islay) { + dx = u2mm(T.x); + dy = u2mm(T.y); + delete(dx, dy, type_polygon); + string Mirror = ""; + string Spin = ""; + if (T.mirror) Mirror = "M"; + if (T.spin) Spin = "S"; + sprintf(c, "CH SIZE %.4f ;CH RATIO %d;CH FONT %s;\nTEXT '%s' %s%sR%.1f (%.4f %.4f);\n", + u2mm(T.size), T.ratio, Font[T.font], T.value, Spin, Mirror, T.angle, u2mm(T.x), u2mm(T.y)); + cmdwire += c; + } + } + } + return; +} + +void menue(void) { + int err = 0; + int isLay = 0; + int toLay = 0; + int swapLay = 0; + + dlgDialog("Change/Swap Layer to Layer") { + dlgGroup("Change layer") { + dlgHBoxLayout { + dlgLabel("&From A"); + dlgComboBox(usedLayer, isLay); + } + dlgHBoxLayout { + dlgLabel("&to B"); + dlgComboBox(usedLayer, toLay); + } + dlgLabel("\nOnly displayed layers is listed to select!"); + } + dlgCheckBox("Select if you want to SWAP layer A <-> B", swap); + dlgLabel(Help); + dlgLabel("Version "+Version); + dlgHBoxLayout { + dlgPushButton("+OK") { + isLayer = usedLayerN[isLay]; + toLayer = usedLayerN[toLay]; + int error = checkLayer(isLayer, toLayer, swap); + if (error) { + string h; + switch (error) { + case 1 : h = "Error: Select layer"; + break; + + case 2 : h = "Error: Select different layer"; + break; + + case 3 : h = "Error: Select layer"; + break; + + case 4 : h = "Error: Do not mix copper layers with drawing layers"; + break; + + case 5 : h = "Error: Missing Layer"; + break; + + case 6 : h = "Error: Same 'From' layer"; + break; + + case 7 : h = "Error: Same 'To' layer"; + break; + + case 17 : h = "Error: Do not use PAD layer"; + break; + + case 18 : h = "Error: Do not use VIA layer"; + break; + + case 19 : h = "Error: Do not use Signal layer"; + break; + + case 23 : h = "Error: Do not use Origin layer"; + break; + + default : sprintf(h, "Error select layer. #%d", error); + } + dlgMessageBox(h, "OK"); + } + else { + dlgAccept(); + return; + } + } + dlgStretch(1); + dlgPushButton("-&Cancel") { dlgReject(); exit (0);} + } + }; + return; +} + + +// main +if (board) board(B) { + string displayLayer = ";\nDISPLAY NONE "; + int lay = 0; + B.layers(L) { + if (L.number != 17 && L.number != 18 && L.number != 19 && L.number != 23 && L.number != 24) { // select no Pad, Via, Unrouted, tOrigin, bOrign Layer + if (L.visible) { + string l; + lay++; + usedLayer[lay] = L.name; + usedLayerN[lay] = L.number; + sprintf( l, " %d", L.number); + displayLayer += l; + } + } + } + displayLayer += ";\n"; + menue(); + sprintf(c, "GRID mm FINEST;\nSET WIRE_BEND 2;\n"); + cmdheader += c; + sprintf(c, "SET UNDO_LOG OFF;\n"); + cmdheader += c; + if (swap) { + sprintf(c, "DISPLAY NONE %d;\n", isLayer); + cmdripup += c; + cmdwire += c; + sprintf(c, "CHANGE LAYER %d;\n", toLayer); + cmdwire += c; + ch_layer(isLayer, toLayer, isLayer); + + sprintf(c, "DISPLAY NONE %d;\n", toLayer); + cmdripup += c; + cmdwire += c; + sprintf(c, "CHANGE LAYER %d;\n", isLayer); + cmdwire += c; + ch_layer(toLayer, isLayer, toLayer); + } + else { + sprintf(c, "DISPLAY NONE %d;\n", isLayer); + cmdripup += c; + cmdwire += c; + sprintf(c, "CHANGE LAYER %d;\n", toLayer); + cmdwire += c; + ch_layer(isLayer, toLayer, isLayer); + } + sprintf(c, ";\nGRID LAST;\nSET UNDO_LOG ON;\n"); + displayLayer += c; + if (argv[1] == "TEST") { + dlgDialog("test") { + dlgTextEdit(cmdheader); + dlgTextEdit(cmdripup); + dlgTextEdit(cmdwire); + dlgTextEdit(displayLayer); + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("-Cancel") { dlgAccept(); exit(0); } + } + }; + } + exit (cmdheader + cmdripup + cmdwire + displayLayer); +} +else { + dlgMessageBox("Run this ULP from a Board", "OK"); + exit (0); +} diff --git a/trunk/ulp/cmd-change-value-group.ulp b/trunk/ulp/cmd-change-value-group.ulp new file mode 100644 index 00000000..14c985eb --- /dev/null +++ b/trunk/ulp/cmd-change-value-group.ulp @@ -0,0 +1,65 @@ +#usage "en: Set values of all elements of a selected group.

" + "RUN cmd-change-value-group VALUE [PREFIX]
" + "support@cadsoft.de" + , + "de: Setzt die Values aller Bauteile einer definierten Gruppe.

" + "RUN cmd-change-value-group VALUE [PREFIX]
" + "support@cadsoft.de" + +#require 6.0500 + +string Version = "Version 1.0.1"; // 2013-08-22 alf@cadsoft.de + +string cmd, s; +string newValue = argv[1]; +string Prefix = strupr(argv[2]); +int grp = 0; + +if (!newValue) { + if (language() == "de") dlgMessageBox(usage + "

Kein VALUE angegeben.

", "OK"); + else dlgMessageBox(usage + "

No VALUE specified.

", "OK"); + exit(-1); +} + +int chkPref(string name, string pfix) { + if (!pfix) return 1; + else if (strstr(name, pfix) == 0) return 1; + return 0; +} + +if (sheet) { + sheet(S) { + S.instances(I) { + if (ingroup(I)) { + grp = 1; + if (chkPref(I.part.name, Prefix)) { + sprintf(s, "VALUE %s %s;\n", I.part.name, newValue); + cmd+= s; + } + } + } + } +} + +else if(board) { + board(B) { + B.elements(E) { + if (ingroup(E)) { + grp = 1; + if (chkPref(E.name, Prefix)) { + sprintf(s, "VALUE %s %s;\n", E.name, newValue); + cmd+= s; + } + } + } + } +} + +else dlgMessageBox("Starten Sie dieses ULP in einem SCH- oder BRD-Editor!", "OK"); + +if (!grp) { + if (language() == "de") dlgMessageBox("Keine Gruppe definiert!", "OK"); + else dlgMessageBox("No group selected!", "OK"); + exit(-1); +} +exit (cmd); \ No newline at end of file diff --git a/trunk/ulp/cmd-draw-group.bmp b/trunk/ulp/cmd-draw-group.bmp new file mode 100644 index 00000000..bd873fd0 Binary files /dev/null and b/trunk/ulp/cmd-draw-group.bmp differ diff --git a/trunk/ulp/cmd-draw-hole-ellipse-calcstep.bmp b/trunk/ulp/cmd-draw-hole-ellipse-calcstep.bmp new file mode 100644 index 00000000..f95fa72b Binary files /dev/null and b/trunk/ulp/cmd-draw-hole-ellipse-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-hole-ellipse-degstep.bmp b/trunk/ulp/cmd-draw-hole-ellipse-degstep.bmp new file mode 100644 index 00000000..7ede976b Binary files /dev/null and b/trunk/ulp/cmd-draw-hole-ellipse-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-hole-ellipse4-calcstep.bmp b/trunk/ulp/cmd-draw-hole-ellipse4-calcstep.bmp new file mode 100644 index 00000000..61d25427 Binary files /dev/null and b/trunk/ulp/cmd-draw-hole-ellipse4-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-hole-ellipse4-degstep.bmp b/trunk/ulp/cmd-draw-hole-ellipse4-degstep.bmp new file mode 100644 index 00000000..4df99489 Binary files /dev/null and b/trunk/ulp/cmd-draw-hole-ellipse4-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-hole-none-calcstep.bmp b/trunk/ulp/cmd-draw-hole-none-calcstep.bmp new file mode 100644 index 00000000..c7da8d07 Binary files /dev/null and b/trunk/ulp/cmd-draw-hole-none-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-hole-none-degstep.bmp b/trunk/ulp/cmd-draw-hole-none-degstep.bmp new file mode 100644 index 00000000..5eab66b2 Binary files /dev/null and b/trunk/ulp/cmd-draw-hole-none-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-hole-none.bmp b/trunk/ulp/cmd-draw-hole-none.bmp new file mode 100644 index 00000000..57d23f13 Binary files /dev/null and b/trunk/ulp/cmd-draw-hole-none.bmp differ diff --git a/trunk/ulp/cmd-draw-move-circle-match-calcstep.bmp b/trunk/ulp/cmd-draw-move-circle-match-calcstep.bmp new file mode 100644 index 00000000..54aa656a Binary files /dev/null and b/trunk/ulp/cmd-draw-move-circle-match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-circle-match-degstep.bmp b/trunk/ulp/cmd-draw-move-circle-match-degstep.bmp new file mode 100644 index 00000000..e2545b35 Binary files /dev/null and b/trunk/ulp/cmd-draw-move-circle-match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-circle-no_match-calcstep.bmp b/trunk/ulp/cmd-draw-move-circle-no_match-calcstep.bmp new file mode 100644 index 00000000..14abfa03 Binary files /dev/null and b/trunk/ulp/cmd-draw-move-circle-no_match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-circle-no_match-degstep.bmp b/trunk/ulp/cmd-draw-move-circle-no_match-degstep.bmp new file mode 100644 index 00000000..59308eae Binary files /dev/null and b/trunk/ulp/cmd-draw-move-circle-no_match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-ellipse-match-calcstep.bmp b/trunk/ulp/cmd-draw-move-ellipse-match-calcstep.bmp new file mode 100644 index 00000000..68406a8d Binary files /dev/null and b/trunk/ulp/cmd-draw-move-ellipse-match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-ellipse-match-degstep.bmp b/trunk/ulp/cmd-draw-move-ellipse-match-degstep.bmp new file mode 100644 index 00000000..f9ca5fe9 Binary files /dev/null and b/trunk/ulp/cmd-draw-move-ellipse-match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-ellipse-no_match-calcstep.bmp b/trunk/ulp/cmd-draw-move-ellipse-no_match-calcstep.bmp new file mode 100644 index 00000000..d764f79a Binary files /dev/null and b/trunk/ulp/cmd-draw-move-ellipse-no_match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-ellipse-no_match-degstep.bmp b/trunk/ulp/cmd-draw-move-ellipse-no_match-degstep.bmp new file mode 100644 index 00000000..99ca9316 Binary files /dev/null and b/trunk/ulp/cmd-draw-move-ellipse-no_match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-ellipse4-match-calcstep.bmp b/trunk/ulp/cmd-draw-move-ellipse4-match-calcstep.bmp new file mode 100644 index 00000000..640802ad Binary files /dev/null and b/trunk/ulp/cmd-draw-move-ellipse4-match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-ellipse4-match-degstep.bmp b/trunk/ulp/cmd-draw-move-ellipse4-match-degstep.bmp new file mode 100644 index 00000000..65c6c575 Binary files /dev/null and b/trunk/ulp/cmd-draw-move-ellipse4-match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-ellipse4-no_match-calcstep.bmp b/trunk/ulp/cmd-draw-move-ellipse4-no_match-calcstep.bmp new file mode 100644 index 00000000..b4b8f27d Binary files /dev/null and b/trunk/ulp/cmd-draw-move-ellipse4-no_match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-ellipse4-no_match-degstep.bmp b/trunk/ulp/cmd-draw-move-ellipse4-no_match-degstep.bmp new file mode 100644 index 00000000..995e6022 Binary files /dev/null and b/trunk/ulp/cmd-draw-move-ellipse4-no_match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-move-match-ellipse-none.bmp b/trunk/ulp/cmd-draw-move-match-ellipse-none.bmp new file mode 100644 index 00000000..26725bee Binary files /dev/null and b/trunk/ulp/cmd-draw-move-match-ellipse-none.bmp differ diff --git a/trunk/ulp/cmd-draw-move-match-none.bmp b/trunk/ulp/cmd-draw-move-match-none.bmp new file mode 100644 index 00000000..fa765d70 Binary files /dev/null and b/trunk/ulp/cmd-draw-move-match-none.bmp differ diff --git a/trunk/ulp/cmd-draw-move-no_match-ellipse-none.bmp b/trunk/ulp/cmd-draw-move-no_match-ellipse-none.bmp new file mode 100644 index 00000000..35abeb3d Binary files /dev/null and b/trunk/ulp/cmd-draw-move-no_match-ellipse-none.bmp differ diff --git a/trunk/ulp/cmd-draw-move-no_match-none.bmp b/trunk/ulp/cmd-draw-move-no_match-none.bmp new file mode 100644 index 00000000..30f819ab Binary files /dev/null and b/trunk/ulp/cmd-draw-move-no_match-none.bmp differ diff --git a/trunk/ulp/cmd-draw-pad-ellipse-calcstep.bmp b/trunk/ulp/cmd-draw-pad-ellipse-calcstep.bmp new file mode 100644 index 00000000..b3942a55 Binary files /dev/null and b/trunk/ulp/cmd-draw-pad-ellipse-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-pad-ellipse-degstep.bmp b/trunk/ulp/cmd-draw-pad-ellipse-degstep.bmp new file mode 100644 index 00000000..655d53f2 Binary files /dev/null and b/trunk/ulp/cmd-draw-pad-ellipse-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-pad-ellipse4-calcstep.bmp b/trunk/ulp/cmd-draw-pad-ellipse4-calcstep.bmp new file mode 100644 index 00000000..d7ae2d88 Binary files /dev/null and b/trunk/ulp/cmd-draw-pad-ellipse4-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-pad-ellipse4-degstep.bmp b/trunk/ulp/cmd-draw-pad-ellipse4-degstep.bmp new file mode 100644 index 00000000..39fd2219 Binary files /dev/null and b/trunk/ulp/cmd-draw-pad-ellipse4-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-pad-none-calcstep.bmp b/trunk/ulp/cmd-draw-pad-none-calcstep.bmp new file mode 100644 index 00000000..fa6b1d85 Binary files /dev/null and b/trunk/ulp/cmd-draw-pad-none-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-pad-none-degstep.bmp b/trunk/ulp/cmd-draw-pad-none-degstep.bmp new file mode 100644 index 00000000..e5d02a41 Binary files /dev/null and b/trunk/ulp/cmd-draw-pad-none-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-pad-none.bmp b/trunk/ulp/cmd-draw-pad-none.bmp new file mode 100644 index 00000000..8467799d Binary files /dev/null and b/trunk/ulp/cmd-draw-pad-none.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-circle-calcstep.bmp b/trunk/ulp/cmd-draw-polygon-circle-calcstep.bmp new file mode 100644 index 00000000..6ca77717 Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-circle-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-circle-degstep.bmp b/trunk/ulp/cmd-draw-polygon-circle-degstep.bmp new file mode 100644 index 00000000..638c7d6f Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-circle-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-contours-as-wire.ulp b/trunk/ulp/cmd-draw-polygon-contours-as-wire.ulp new file mode 100644 index 00000000..17bcfc85 --- /dev/null +++ b/trunk/ulp/cmd-draw-polygon-contours-as-wire.ulp @@ -0,0 +1,62 @@ +#usage "en: Draws the calculated contours of a polygon as WIRE.

" + "RUN cmd-draw-polygon-contours-as-wire SIGNALNAME [FILLING] [Layernumber]

" + "FILLING also draws the filling as wire.
" + "Layernumber the new layer of copy.
" + "support@cadsoft.de" + , + "de: Zeichnet die berechneten Konturen eines Polygons als WIRE.

" + "RUN cmd-draw-polygon-contours-as-wire SIGNALNAME [FILLING] [Layernumer]
" + "FILLING zeichnet auch die Füllung als WIRE.

" + "Layernumber ist der Layer in dem die Kopie erzeugt werden soll.
" + "support@cadsoft.de" + +string Version = "1.0.0"; // 2011-09-07 alf@cadsoft.de +string f; +string tempextension = "~.scr"; +int Ratsnest = 0; + +int Newlayer = strtol(argv[3]); + +if (!argv[1]) { + if (language() == "de") dlgMessageBox(usage + "

Geben Sie einen SIGNALNAMEN an.", "OK"); + else dlgMessageBox(usage + "

Missing SIGNALNAME.", "OK"); + exit(-1); +} + +if (board) { + board(B) { + f = filesetext(B.name, tempextension); + output(f, "wtD") { + printf("GRID MM;\nSET WIRE_BEND 2;\n"); + B.signals(S) { + if (S.name == strupr(argv[1]) ) { + S.polygons(P) { + if (P.layer == 1 || P.layer == 16) { + printf("CHANGE LAYER %d;\nCHANGE WIDTH %.4f;\n", P.layer, u2mm(P.width) ); + if (P.thermals) printf("CHANGE THERMAL ON;\n"); + else printf("CHANGE THERMAL OFF;\n"); + P.fillings(W) { + Ratsnest = 1; + break; + } + if (!Ratsnest) { + if (language() == "de") dlgMessageBox("!Starten Sie zuerst RATSNEST um die Füllung der Polygone zu berechnen.", "OK"); + else dlgMessageBox("!Start first RATSNEST to calculate polygons.", "OK"); + exit("RATSNEST"); + } + P.contours(W) { + if (Newlayer) printf("Layer %d;\nWIRE (%.4f %.4f) (%.4f %.4f);\n", Newlayer, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + else printf("WIRE '%s' (%.4f %.4f) (%.4f %.4f);\n", S.name, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + } + if (argv[2] == "FILLING") P.fillings(W) { + if (Newlayer) printf("Layer %d;\nWIRE (%.4f %.4f) (%.4f %.4f);\n", Newlayer, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + else printf("WIRE '%s' (%.4f %.4f) (%.4f %.4f);\n", S.name, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + } + } + } + } + } + } + } + exit("SCRIPT '" + f + "'"); +} diff --git a/trunk/ulp/cmd-draw-polygon-ellipse-calcdeg.bmp b/trunk/ulp/cmd-draw-polygon-ellipse-calcdeg.bmp new file mode 100644 index 00000000..b2ca08b4 Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse-calcdeg.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-ellipse-calcstep.bmp b/trunk/ulp/cmd-draw-polygon-ellipse-calcstep.bmp new file mode 100644 index 00000000..d1671961 Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-ellipse-degstep.bmp b/trunk/ulp/cmd-draw-polygon-ellipse-degstep.bmp new file mode 100644 index 00000000..aa2323be Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-ellipse-none.bmp b/trunk/ulp/cmd-draw-polygon-ellipse-none.bmp new file mode 100644 index 00000000..5ad8bce0 Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse-none.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-ellipse4-calcstep.bmp b/trunk/ulp/cmd-draw-polygon-ellipse4-calcstep.bmp new file mode 100644 index 00000000..826139b8 Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse4-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-ellipse4-degstep.bmp b/trunk/ulp/cmd-draw-polygon-ellipse4-degstep.bmp new file mode 100644 index 00000000..398a29cd Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse4-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-ellipse4-none.bmp b/trunk/ulp/cmd-draw-polygon-ellipse4-none.bmp new file mode 100644 index 00000000..b14f727c Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-ellipse4-none.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-none-calcstep.bmp b/trunk/ulp/cmd-draw-polygon-none-calcstep.bmp new file mode 100644 index 00000000..7ed1cf0d Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-none-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-polygon-none.bmp b/trunk/ulp/cmd-draw-polygon-none.bmp new file mode 100644 index 00000000..8a1be253 Binary files /dev/null and b/trunk/ulp/cmd-draw-polygon-none.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-circle-match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-circle-match-calcstep.bmp new file mode 100644 index 00000000..2ee501ab Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-circle-match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-circle-match-degstep.bmp b/trunk/ulp/cmd-draw-smd-circle-match-degstep.bmp new file mode 100644 index 00000000..b671eb12 Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-circle-match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-circle-no_match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-circle-no_match-calcstep.bmp new file mode 100644 index 00000000..d11a8373 Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-circle-no_match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-cricle-no_match-degstep.bmp b/trunk/ulp/cmd-draw-smd-cricle-no_match-degstep.bmp new file mode 100644 index 00000000..8658461c Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-cricle-no_match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-ellipse-match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse-match-calcstep.bmp new file mode 100644 index 00000000..c321cb69 Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse-match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-ellipse-match-degstap.bmp b/trunk/ulp/cmd-draw-smd-ellipse-match-degstap.bmp new file mode 100644 index 00000000..bf8503de Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse-match-degstap.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-ellipse-no_match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse-no_match-calcstep.bmp new file mode 100644 index 00000000..57f5ce2b Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse-no_match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-ellipse-no_match-degstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse-no_match-degstep.bmp new file mode 100644 index 00000000..ffb7b3f1 Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse-no_match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-ellipse4-match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse4-match-calcstep.bmp new file mode 100644 index 00000000..0f7ad8ca Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse4-match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-ellipse4-match-degstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse4-match-degstep.bmp new file mode 100644 index 00000000..4fafc5c3 Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse4-match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-ellipse4-no_match-calcstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse4-no_match-calcstep.bmp new file mode 100644 index 00000000..eb8e4f3a Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse4-no_match-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-ellipse4-no_match-degstep.bmp b/trunk/ulp/cmd-draw-smd-ellipse4-no_match-degstep.bmp new file mode 100644 index 00000000..d172797c Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-ellipse4-no_match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-match-degstep.bmp b/trunk/ulp/cmd-draw-smd-match-degstep.bmp new file mode 100644 index 00000000..b0386be0 Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-match-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-match-none.bmp b/trunk/ulp/cmd-draw-smd-match-none.bmp new file mode 100644 index 00000000..b084676d Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-match-none.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-no_match-degsetp.bmp b/trunk/ulp/cmd-draw-smd-no_match-degsetp.bmp new file mode 100644 index 00000000..a274a63f Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-no_match-degsetp.bmp differ diff --git a/trunk/ulp/cmd-draw-smd-no_match-none.bmp b/trunk/ulp/cmd-draw-smd-no_match-none.bmp new file mode 100644 index 00000000..2463bc4e Binary files /dev/null and b/trunk/ulp/cmd-draw-smd-no_match-none.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-calc-ellipse.bmp b/trunk/ulp/cmd-draw-wire-calc-ellipse.bmp new file mode 100644 index 00000000..0b7b2572 Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-calc-ellipse.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-calcstep-none.bmp b/trunk/ulp/cmd-draw-wire-calcstep-none.bmp new file mode 100644 index 00000000..c858135e Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-calcstep-none.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-circle-calcstep.bmp b/trunk/ulp/cmd-draw-wire-circle-calcstep.bmp new file mode 100644 index 00000000..ef597a8e Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-circle-calcstep.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-circle-degstep.bmp b/trunk/ulp/cmd-draw-wire-circle-degstep.bmp new file mode 100644 index 00000000..424ab584 Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-circle-degstep.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-clac-ellipse4.bmp b/trunk/ulp/cmd-draw-wire-clac-ellipse4.bmp new file mode 100644 index 00000000..73ec4d12 Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-clac-ellipse4.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-degstep-none.bmp b/trunk/ulp/cmd-draw-wire-degstep-none.bmp new file mode 100644 index 00000000..3bca32e9 Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-degstep-none.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-ellipse.bmp b/trunk/ulp/cmd-draw-wire-ellipse.bmp new file mode 100644 index 00000000..4e74965d Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-ellipse.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-none.bmp b/trunk/ulp/cmd-draw-wire-none.bmp new file mode 100644 index 00000000..5900e046 Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-none.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-step-ellipse.bmp b/trunk/ulp/cmd-draw-wire-step-ellipse.bmp new file mode 100644 index 00000000..b0d11e36 Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-step-ellipse.bmp differ diff --git a/trunk/ulp/cmd-draw-wire-step-ellipse4.bmp b/trunk/ulp/cmd-draw-wire-step-ellipse4.bmp new file mode 100644 index 00000000..e66f8b8c Binary files /dev/null and b/trunk/ulp/cmd-draw-wire-step-ellipse4.bmp differ diff --git a/trunk/ulp/cmd-draw.ulp b/trunk/ulp/cmd-draw.ulp new file mode 100644 index 00000000..8c4fb630 --- /dev/null +++ b/trunk/ulp/cmd-draw.ulp @@ -0,0 +1,1587 @@ +#usage "en: Command draw

Options:

" + "+ distance/radius
" + "Angle start [Angle step] [End angle]
" + "[Layer]
" + "[Wire & width]
" + "[Xcoordinate] [Ycoordinate] **
" + "[Polygon]
" + "[Pad || Smd || Via]
" + "[Width Length] SMD_dx SMD_dy
" + "[-Name] signal/pad/smd
" + "[Diameter] for Pad/Via, if used
" + "[Drill] for Pad/Via/Hole, if used
" + "[] define angle (in degrees) for step
" + "[/] define number of steps within start and end angle
" + "[Group] rotate and paste
" + "[rotate match]
" + "[MOVE] elements on place by order
start with name (only in Board)
" + "[Circle] emulate/draw a cricle with wire or polygon
" + "[full ellipse 0]
" + "[Ellipse factor] height = radius * f
" + "[1/4 ellipse] 90 degree, 1st quadrant
" + "
" + "** If MARK is set in PAC/BRD/SCH editor, coordinates are relativ.
" + "Parameters can be used in any order; not case sensitive." + "

" + "Author: alf@cadsoft.de ", + + "de: Command draw

Optionen:

" + "+ Distance/Radius
" + "Startwinkel [Winkelschritt oder Anzahl (# .)] [Endwinkel]
" + "[Layer]
" + "[Wre width] setzt die Breite (width) und den Befehl WIRE.
" + "Für Polygon muß W vor O angegeben werden.
" + "[X-Koordinate] [Y-Koordinate] **
" + "[Polygon]
" + "[Pad || Smd || Via]
" + "[Width Length] SMD_dx SMD_dy
" + "[-Name] Signal/Pad/Smd
" + "[Diameter] für Pad/Via, wenn benutzt
" + "[Drill] für Pad/Via/Hole, wenn benutzt
" + "[] Winkelschritt in Grad
" + "[/] berechnet den Winkel (End - Start / Anzahl
" + "[Group] Pasted die Gruppe rotiert.
" + "Die Gruppe kann vor dem Start des ULP definiert werden,
" + "oder das ULP selektiert alle sichtbaren Objekte als Gruppe.
" + "[Rotate match] dreht die Bauteile/Pad/Smd im selben Winkel
in dem sie angeordnet werden
" + "[MOVE] plaziert Elemente aufsteigend beginnend mit dem
angegebenen Namen (nur im Board nutzbar )
" + "[Circle] zeichnet einen Kreis oder Ellipse als Wire oder Polygon
je nach Option (W/O)
" + "[full ellipse 0] zeichnet eine volle Ellipse
" + "[Ellipse faktor] der Wert mit dem die Länge multipliziert wird
(Raduis * f) ergibt die Länge in y
" + "[1/4 ellipse] zeichnet nur den ersten Qudranten
einer Ellipse oder Kreises
" + "
" + "** Ist MARK im benutzten PAC/BRD/SCH Editor gesezt,
werden die Koordinaten relativ zur Marke benutzt.
" + "Die Parameter können in beliebiger Reihenfolge angegeben
und groß oder klein geschrieben werden." + "

" + "Author: alf@cadsoft.de " + +string Help = "" + + "RUN cmd-draw w0.4 -gnd x1.3 y2.56 +17.45 a115 n75 e180 # lTop
" + + "RUN cmd-draw w0.4 -gnd x1.3 y2.56 +17.45 a115 n75 e180 . lTop
" + + "RUN cmd-draw w0.4 -gnd x1.3 y2.56 +17.45 a115 ltop
" + + "RUN cmd-draw a0 e150.0 x30 y4 w0.2 n9 # o +2.27 -gnd l1
" + + "RUN cmd-draw a0 e50.0 x30 y4 w0.2 n9 o 0 f1.7 +2.27 -gnd l1
" + + "RUN cmd-draw w0.4 +1.5 -gnd a2 y2.56 l16
" + + "RUN cmd-draw +2.0 e270.0 n9.0 w0.2 x-2.54 y5.08
" + + "RUN cmd-draw x1 y3.33 l1 w.2 +4.77 # n5
" + + "RUN cmd-draw s -1 +9 n7 #
" + + "RUN cmd-draw r1.2 +19.9 n7 #
" + + "RUN cmd-draw r1.2 +9.5 n7 .
" + + "RUN cmd-draw +2.20 n9.0 w0.2 x-2.54 y-5.08 w.01 l1 O 0 f1.75
" + + "RUN cmd-draw +2.20 n9.0 w0.2 x-2.54 y-5.08 w.01 l1 O 4 f1.75
" + + "RUN cmd-draw s -1 +9 a22.5 m
" + + "RUN cmd-draw s i1.55 t2.7 -A +2.20 n20.0 x-2.54 y-5.08 l1 f1.75 m
" + + "RUN cmd-draw r.8 d1.4 v -A +4.20 n20.0 x-2.54 y-5.08 l1 f1.75
" + + "RUN cmd-draw g n33.333 # A0.0 e359.9
" + + "RUN cmd-draw G n33.333 . A0.0 e359.9
" + + "RUN cmd-draw +10 MOVE -R1 M a33 L16 N7 E322 .
"+ + "

" + + ""; + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#require 6.0400; + +string Help_Move = "MOVE, PAD, SMD can be used clockwise, too. " + + "In this case Angle step has to be negative. Is Angle start less than " + + "Angle end for negative Angle step, 360 will be added to Angle start." + + "Thus you are allowed to arrange elements clockwise."; + +string Mark_Info = "If MARK is set coordinates are relativ."; + + +if (language() == "de") { + Help_Move = "MOVE, PAD, SMD können auch rechtsdrehend benutzt werden. " + + "Dazu muß Angle step negativ sein.
" + + "Ist Angle start bei negativen Angle step " + + "kleiner als Angle end wird auf Angle start 360 aufaddiert.
" + + "Damit ist es möglich die Elemente rechtsdrehen anzuordnen."; + + Mark_Info = "Ist MARK gesetzt, dann sind die Koordinaten relativ zu der Marke."; +} + +string Label_Move = " "; + +int test = 1; + +string Version = " Version 2.01 "; // 2006-08-10 alf@cadsoft.de + // 2008-04-10 changed GROUP ... (>x y); alf@cadsoft.de + // 2008-05-06 SMD generierung mit Name berichtigt + // 2010-06-09 Generierung des PAD-Namen berichtigt. + // 2010-10-15 Startwinkel auf 720 erhöht, um Bauteile + // im Uhrzeigersinn mit größerem Endwinkel + // als 0.0 zu platzieren. + // Beispiel Start 620.0 End 260.1 + // Hier muß der Startwinkel 260+360 = 620 sein. + // Neue Option: Winkeloffset + // 2011-10-21 Option Group akzeptiert jetzt auch Radius = 0. + // die Gruppe wird jetzt gedreht gapastetd. + // Checkbox use selected, es wird die vor dem Start des ULP + // definirte Gruppe benutzt, oder das ULP definiert alle + // sichtbaren Objekte als Gruppe. + // 2012-04-12 min max Wert absolut und nicht mehr in Eagle-Internen Einheiten + // wegen der höheren Auflösung von V6 + // 2013-03-26 Auflösung und max. Werte an V6 und feinere Auflösung angepasst. + // 2013-08-05 Shape von VIA ausgeben, HOLE berichtigt. + // 2013-12-12 In #usage Zeilenumbruch
eingefügt. + +enum { DrawWIRE, // ** do not change this list ** + DrawPOLYGON, + DrawMOVE, // to place Elements in Board + DrawGROUP, // Group CUT paste, select all in group ** see also >> dlgGroup("Option") << + DrawHOLE, + DrawPAD, + DrawSMD + }; + +int DrawType = DrawWIRE; +string cmd_Draw_Info = ""; +string Draw_Info = " "; +string Name_used; +string require = " required "; +string Not_Used = " not used "; +string Can_Used = " can be used "; +if (library) Name_used = Not_Used; +else Name_used = Can_Used; + + +string Para = ""; +string SigName = ""; +string width = ""; +string layer = ""; +string Angle_step_used = Not_Used; +string Angle_end_used = Not_Used; + +real x1, y1, x2; +real StartAngle = 0.0; // start the rotated draw on degree +real AngleStep = 0.0; // angle step in degree to next element or steps at 90 for Ellipse +real EangleOffset = 0.0; // the rotation off the element self + offset +real EndAngle = 360.0; // end the rotated draw on degree +enum { None, Degreestep, Calcstep }; +int AngleStepTyp = None; // flag to calculate the anglestep from count (anglestep) +int RotateMatch = 0; // rotate element with same angle with rotate +int UseMarkedGroup = 0; + +enum { NONE, CIRCLE, FULL_ELLIPSE, ELLIPSE_4 }; +int Placeform = NONE; +real EllipsFactor = 1.0; // ratio x to y radius +real M_EllipsFactor = 1.0; // copy for menue + +//int polygon = 0; // draw ellipse as polygon +//int smd = 0; // place a smd on endpoint +real SMD_dx = 0; // SMD length +real SMD_dy = 0; // SMD width +string PadVia = ""; // draw Pad or Via as used in editor +string PAD_diameter = ""; // pad diameter +string Shapes[]; +int ShapeSelect = PAD_SHAPE_OFFSET+1; + +string Drill_Hole = ""; // drill diameter + +int grid = 1; +string GridUnit[] = { "MIC", "MM", "MIL", "INCH" }; +int gridunit; +real minx, maxx, miny, maxy; + +string Length_Distance_Radius = "&+ radius "; + + +int PressOk = 0; + +string s; +string h; +string Help_Err = " "; + +string Name1st, NameExt; // use as variable Label in Menu + +// ### functions ### +void Set_MinMax_Unit(int Grid) { // 2012-04-12 + switch(Grid) { + case GRID_UNIT_MIC : { // Micron + minx = -1990000; + maxx = 1990000; + miny = -1990000; + maxy = 1990000; + break; + } + case GRID_UNIT_MM : { // Millimeter + minx = -1990; + maxx = 1990; + miny = -1990; + maxy = 1990; + break; + } + case GRID_UNIT_MIL : { // Mil + minx = -78340; + maxx = 78340; + miny = -78340; + maxy = 78340; + break; + } + case GRID_UNIT_INCH : { // Inch + minx = -78.34; + maxx = 78.34; + miny = -78.34; + maxy = 78.34; + break; + } + } + return; +} + + +real u2u(int val) { + switch (gridunit) { + case GRID_UNIT_MIC : return u2mic(val); + case GRID_UNIT_MM : return u2mm(val); + case GRID_UNIT_MIL : return u2mil(val); + case GRID_UNIT_INCH : return u2inch(val); + } +} + + +void info(void) { + dlgDialog("cmd-draw HELP") { + dlgHBoxLayout { + dlgLabel(usage); + dlgVBoxLayout { + if (language() == "de") dlgLabel("Beispiele:"); + else dlgLabel("Examples:"); + dlgLabel(Help); + dlgStretch(1); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+Ok") dlgAccept(); + dlgStretch(1); + } + } + } + }; + return; +} + + +// *** analysis User Error *** +int error(void) { + int err = 0; + if (DrawType == DrawGROUP) { + if (!AngleStep || !AngleStep || !EndAngle) { Help_Err = "Angle start or Angle step or Angle end = 0"; return -1; } + if (!AngleStepTyp) { + if (AngleStepTyp && AngleStep == 0) { + Help_Err = "Missing parameter: Angle step"; + return -1; + } + Help_Err = "Select Angle step type :\n degree step\ncalc. steps."; + return -1; + } + return 0; + } + if (strtod(width) >= x2) { Help_Err = "Width > Radius"; err = -1; } + if (!x2) { Help_Err = "Radius = 0"; err = -1; } + if (DrawType == DrawSMD) { + if (layer == "1" || layer == "16") ; + else { err = -1; Help_Err = "Layer for SMD ?"; } + } + if (DrawType == DrawMOVE) { + if (!SigName) { Help_Err = "1.st Element name ?"; err = -1; } + } + if (AngleStepTyp && AngleStep == 0) { + err = -1; Help_Err = "Missing parameter: Angle step"; + } + return err; +} + + +// *** set info for Menu *** Pictures and Texts *** +void set_Draw_Info(void) { + Label_Move = " "; + if (DrawType == DrawWIRE) { + switch (AngleStepTyp) { + case None : + Angle_step_used = Not_Used; + Angle_end_used = Not_Used; + switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + + case Degreestep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + case Calcstep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + } + } + + else if(DrawType == DrawPOLYGON) { + Angle_step_used = require; + Angle_end_used = require; + switch (AngleStepTyp) { + case None : switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + case Degreestep : switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + case Calcstep : switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + } + } + + else if(DrawType == DrawMOVE) { + if (library || schematic) { + dlgMessageBox("! MOVE\nYou can use this function ponly in a Board.", "OK"); + } + else { + Label_Move = Help_Move; + switch (AngleStepTyp) { + case None : + Angle_step_used = Not_Used; + Angle_end_used = Not_Used; + switch (Placeform) { + case NONE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case CIRCLE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + } + break; + + case Degreestep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case CIRCLE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + } + break; + + case Calcstep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case CIRCLE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + } + break; + } + } + } + + else if(DrawType == DrawGROUP) { + Angle_step_used = require; + Angle_end_used = require; + cmd_Draw_Info = ""; + } + + else if(DrawType == DrawPAD) { + Label_Move = Help_Move; + switch (AngleStepTyp) { + case None : + Angle_step_used = Not_Used; + Angle_end_used = Not_Used; + switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + + case Degreestep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + + case Calcstep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + } + } + + else if(DrawType == DrawSMD) { + Label_Move = Help_Move; + switch (AngleStepTyp) { + case None : + Angle_step_used = Not_Used; + Angle_end_used = Not_Used; + switch (Placeform) { + case NONE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case CIRCLE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + } + break; + + case Degreestep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case CIRCLE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + } + break; + + case Calcstep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case CIRCLE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : if (!RotateMatch) cmd_Draw_Info = ""; + else cmd_Draw_Info = ""; + break; + } + } + } + + else if(DrawType == DrawHOLE) { + switch (AngleStepTyp) { + case None : + Angle_step_used = Not_Used; + Angle_end_used = Not_Used; + switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + + case Degreestep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + + case Calcstep : + Angle_step_used = require; + Angle_end_used = require; + switch (Placeform) { + case NONE : cmd_Draw_Info = ""; + break; + case CIRCLE : cmd_Draw_Info = ""; + break; + case FULL_ELLIPSE : cmd_Draw_Info = ""; + break; + case ELLIPSE_4 : cmd_Draw_Info = ""; + break; + } + break; + } + } + + if (DrawType == DrawGROUP) { + Angle_step_used = require; + Angle_end_used = require; + cmd_Draw_Info = ""; + RotateMatch = 1; + } + else if (DrawType != DrawMOVE && PadVia == "VIA") { + RotateMatch = 0; + } + return; +} + + + +// ****** main menu ****** +int menue(void) { + int RESULT; + if (Placeform == NONE) { + if (DrawType == DrawGROUP) Length_Distance_Radius = " not used "; // 2012-04-12 + else Length_Distance_Radius = "&+ radius "; + } + + Name1st = " "; + NameExt = " "; + if (board && DrawType == DrawMOVE) { + Name1st = " &- 1st. Element "; + NameExt = " name"; + } + if (board && DrawType == DrawWIRE) { + Name1st = " &- Signal "; + NameExt = " name"; + } + if (board && DrawType == DrawPOLYGON) { + Name1st = " &- Signal "; + NameExt = " name"; + } + if (library && DrawType == DrawPOLYGON) { + Name1st = " "; + NameExt = " "; + } + if (package && DrawType == DrawPAD) { + Name1st = " &- 1st. Pad "; + NameExt = " name"; + } + if (board && DrawType == DrawPAD) { + Name1st = " &- Signal "; + NameExt = " name"; + } + if (package && DrawType == DrawSMD) { + Name1st = " &- 1st. Smd "; + NameExt = " name"; + } + if (package && DrawType == DrawMOVE || package && DrawType == DrawWIRE) { + Name1st = " "; + NameExt = " "; + } + if ( schematic) { + Name1st = " &- Net name "; + NameExt = " "; + } + + RESULT = dlgDialog("Command Draw") { + dlgVBoxLayout { + dlgHBoxLayout { + dlgSpacing (8); + dlgLabel (Draw_Info, 1); + } + dlgHBoxLayout { + dlgGroup("Option") { + set_Draw_Info(); + dlgGridLayout { + + dlgCell( 1, 1) dlgHBoxLayout dlgSpacing(10); + dlgCell( 1, 4) dlgHBoxLayout dlgSpacing(10); + + if (DrawType == DrawWIRE || DrawType == DrawPOLYGON) { + dlgCell( 5, 2) dlgLabel( "&Width "); + dlgCell( 5, 3) dlgStringEdit( width); + } + if (DrawType == DrawWIRE || DrawType == DrawPOLYGON || DrawType == DrawSMD || DrawType == DrawMOVE) { + dlgCell( 5, 5) dlgLabel(" &Layer"); + dlgCell( 5, 6) dlgStringEdit(layer); + } + + dlgCell( 5, 8) dlgLabel(Name1st, 1); + if ( Name1st != " ") { + dlgCell( 5, 9) dlgStringEdit(SigName); // Signal-, Element-, Net-Name + } + dlgCell( 5, 10) dlgLabel(NameExt ,1); + + dlgCell( 7, 2) dlgLabel( "&X center coord. "); + dlgCell( 7, 3) dlgRealEdit( x1, minx, maxx); + dlgCell( 7, 5) dlgLabel( "&Y center coord. "); + dlgCell( 7, 6) dlgRealEdit( y1, miny, maxy); + dlgCell( 7, 8) dlgHBoxLayout { dlgLabel( Length_Distance_Radius, 1); dlgStretch(1); } + dlgCell( 7, 9) dlgHBoxLayout { dlgRealEdit( x2, 0, maxx); dlgStretch(1); } + + dlgCell( 8, 2) dlgLabel("Angle st&art "); + dlgCell( 8, 3) dlgRealEdit( StartAngle, 0.0, 720.0); // 2010-10-15 + dlgCell( 8, 5) dlgLabel("A&ngle step "); + dlgCell( 8, 6) dlgRealEdit( AngleStep, -360.0, 360.0); + dlgCell( 8, 7) dlgSpacing(12); + dlgCell( 8, 8) dlgLabel(" Angle &end "); + dlgCell( 8, 9) dlgRealEdit( EndAngle, 0.0, 720.0); + dlgCell( 8,10) dlgSpacing(50); + + dlgCell( 9, 0) dlgVBoxLayout dlgSpacing(12); + dlgCell( 9, 3) if(DrawType == DrawGROUP) { // 2011-10-21 + dlgCheckBox("Use selected group", UseMarkedGroup); + } + dlgCell( 9, 6) dlgLabel(Angle_step_used, 1); + dlgCell( 9, 9) dlgLabel(Angle_end_used, 1); + + + dlgCell( 5, 0) dlgRadioButton("Wire &1 ", DrawType) { + Draw_Info = " "; + if (library) Name_used = Not_Used; + else Name_used = " "; + //Length_Distance_Radius = "&+ radius "; + dlgReject(); + dlgAccept(); + } + dlgCell( 6, 0) dlgRadioButton("P&olygon ", DrawType) { + Draw_Info = " "; + if (library) Name_used = Not_Used; + else Name_used = " "; + //Length_Distance_Radius = "&+ radius "; + dlgAccept(); + } + dlgCell( 6, 9) dlgLabel(Name_used, 1); + + dlgCell( 7, 0) dlgRadioButton("&Move ", DrawType) { // 2006.07.06 alf@cadsoft.de + Draw_Info = "MOVE Elements by Name"; + Name_used = require; + //Length_Distance_Radius = "&+ radius "; + dlgAccept(); + } + + dlgCell( 8, 0) dlgRadioButton("&Group *", DrawType) { + Draw_Info = "GROUP CUT all elements displayed and PASTE (rotated)."; + Name_used = " "; + Length_Distance_Radius = "&+ distance "; + RotateMatch = 1; + dlgAccept(); + } + + if (board || package) { + dlgCell( 12, 0) dlgRadioButton("&Hole ", DrawType) { + Draw_Info = " "; + Name_used = " "; + Length_Distance_Radius = "%+ distance "; + dlgAccept(); + } + if (DrawType == DrawPAD || DrawType == DrawHOLE) { + if (DrawType == DrawHOLE) { + dlgCell( 12, 2) dlgLabel( " Hole d&rill "); + } + if (DrawType == DrawPAD) { + if (package) { + dlgCell( 12, 2) dlgLabel( " Pad d&rill "); + } + if (board) { + dlgCell( 12, 2) dlgLabel( " Via d&rill "); + } + } + dlgCell( 12, 3) dlgStringEdit( Drill_Hole); + } + } + + if (package) { + PadVia = "PAD"; + Shapes[PAD_SHAPE_SQUARE] = "Square"; + Shapes[PAD_SHAPE_ROUND] = "Round"; + Shapes[PAD_SHAPE_OCTAGON] = "Octagon"; + Shapes[PAD_SHAPE_LONG] = "Long"; + Shapes[PAD_SHAPE_OFFSET] = "Offset"; + Shapes[PAD_SHAPE_OFFSET+1] = " "; // last must be empty + + dlgCell( 13, 0) dlgRadioButton("&Pad ", DrawType) { + Draw_Info = " "; + Name_used = " can be used"; + Length_Distance_Radius = "&+ distance "; + dlgAccept(); + } + if (DrawType == DrawPAD) { + dlgCell( 13, 2) dlgLabel( " PAD &Diameter "); + dlgCell( 13, 3) dlgStringEdit( PAD_diameter); + dlgCell( 13, 5) dlgLabel( " Schape "); + dlgCell( 13, 6) dlgComboBox(Shapes, ShapeSelect); + } + dlgCell( 14, 0) dlgRadioButton("&Smd ", DrawType) { + Draw_Info = " "; + Name_used = " "; + Length_Distance_Radius = "&+ distance "; + dlgAccept(); + } + if (DrawType == DrawSMD) { + dlgCell( 14, 2) dlgLabel( " &Wide dx "); + dlgCell( 14, 3) dlgRealEdit( SMD_dx); + dlgCell( 14, 5) dlgLabel( " Heigh&t dy "); + dlgCell( 14, 6) dlgRealEdit( SMD_dy); + } + } + + if (board) { + PadVia = "VIA"; + Shapes[PAD_SHAPE_SQUARE] = "Square"; + Shapes[PAD_SHAPE_ROUND] = "Round"; + Shapes[PAD_SHAPE_OCTAGON] = "Octagon"; + Shapes[PAD_SHAPE_OCTAGON+1] = " "; + ShapeSelect = PAD_SHAPE_OCTAGON+1; + + dlgCell( 13, 0) dlgRadioButton("&Via ", DrawType) { // ** Via in Board / Pad in Package ** + Draw_Info = " "; + Name_used = " can be used"; + Length_Distance_Radius = "&+ distance "; + RotateMatch = 0; + dlgAccept(); + } + if (DrawType == DrawPAD) { + dlgCell( 13, 2) dlgLabel( " VIA &Diameter "); + dlgCell( 13, 3) dlgStringEdit( PAD_diameter); + dlgCell( 13, 5) dlgLabel( " Schape "); + dlgCell( 13, 6) dlgComboBox(Shapes, ShapeSelect); + } + } + } + } + dlgStretch(1); + } + dlgSpacing(8); + dlgHBoxLayout { + dlgLabel(cmd_Draw_Info, 1); // picture for info + dlgGroup("Angle step type") { + dlgRadioButton("Not used ", AngleStepTyp) set_Draw_Info(); + dlgRadioButton("& degree step ", AngleStepTyp) set_Draw_Info(); + dlgRadioButton("&/ calc. steps ", AngleStepTyp) set_Draw_Info(); + dlgLabel(" "); + if (DrawType == DrawMOVE || DrawType == DrawSMD ) { + dlgCheckBox("Rotate &item to match ", RotateMatch) { + set_Draw_Info(); + } + dlgHBoxLayout { + dlgLabel( " I&tem "); + dlgRealEdit(EangleOffset, 0.0, 359.9); + dlgLabel( " rotate offset"); + } + } + } + dlgGroup("Form") { + dlgHBoxLayout { + //set_Draw_Info(); + dlgRadioButton("Not &Used", Placeform) { + set_Draw_Info(); + if (EllipsFactor != 1.0) { + M_EllipsFactor = EllipsFactor; + EllipsFactor = 1; + } + } + dlgRadioButton("&Circle", Placeform) { + set_Draw_Info(); + if (EllipsFactor != 1.0) { + M_EllipsFactor = EllipsFactor; + EllipsFactor = 1; + } + } + dlgRadioButton("Full ellipse &0", Placeform) { + set_Draw_Info(); + if (EllipsFactor != 1.0) { + M_EllipsFactor = EllipsFactor; + } + else EllipsFactor = M_EllipsFactor; + } + dlgRadioButton("1/&4 ellipse", Placeform) { + set_Draw_Info(); + if (EllipsFactor != 1.0) { + M_EllipsFactor = EllipsFactor; + } + else EllipsFactor = M_EllipsFactor; + } + dlgStretch(1); + } + dlgSpacing(8); + dlgHBoxLayout { + dlgLabel( " Ellipse &factor y = x*f "); + dlgRealEdit( EllipsFactor, +0.01, +100.0); + } + } + dlgStretch(1); + } + } + + dlgHBoxLayout { + dlgLabel("Grid " + GridUnit[grid] + ""); + dlgSpacing(12); + dlgLabel(Mark_Info); + dlgStretch(1); + } + dlgLabel(Label_Move, 1); + dlgHBoxLayout { + dlgLabel("" + Help_Err + "", 1); + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+OK") { + dlgAccept(); + PressOk = 1; + } + dlgPushButton("-Cancel") { dlgReject(); exit(0); } + dlgStretch(1); + dlgLabel(Version); + dlgPushButton("Help") info(); + } + }; + return RESULT; +} + + +string getPrefix(string s) { + int l = strlen(s); + string prfx; + for (int n = 0; n <= l; n++) { + if (s[n] < '0' || s[n] > '9'); + else { + prfx = strsub(s, 0, n); + break; + } + } + return prfx; +} + + +int getNumber(string s) { + int l = strlen(s); + for (int n = 0; n <= l; n++) { + if (s[n] < '0' || s[n] > '9'); + else return strtol(strsub(s, n)); + } + return 0; +} + + +// if Element in Project +int exist(string e) { + board(B) { + B.elements(E) { + if (E.name == e) return 1; + } + } + return 0; +} + + +// ** draw wire Ellipse ** +string wireEllipse(void) { + string e; + real rad; + string xystart; + int start = 1; + for (real winkel = StartAngle; winkel <= EndAngle; winkel += AngleStep) { + rad = PI / 180 * winkel; + sprintf(h, "(R%.9f %.9f)\n", + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + e += h; + if (start) { + xystart = h; + start = 0; + } + } + if (DrawType == DrawPOLYGON && AngleStepTyp != None) { + e += xystart; + } + return e; +} + + +// *** generate Script to draw WIRE *** +void drawWire(void) { + if (board && SigName) SigName = "'"+SigName+"'"; + if (library) SigName = ""; + + real rad = PI / 180 * StartAngle; + real a; + + if (AngleStepTyp) { + switch(Placeform) { + case NONE : + for (a = StartAngle; a <= EndAngle; a += AngleStep) { + rad = PI / 180 * a; + sprintf(h, "WIRE %s %s (R%.9f %.9f) (R%.9f %.9f);\n", + width, SigName, + x1, y1, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + s += h; + } + break; + case CIRCLE : + sprintf(h, "WIRE %s %s ", width, SigName); + s += h; + for (a = StartAngle; a <= EndAngle; a += AngleStep) { + rad = PI / 180 * a; + sprintf(h, " (R%.9f %.9f) ", x1 + (cos(rad) * x2), y1 + (sin(rad) * x2 * EllipsFactor) ); + s += h; + } + s += ";\n"; + break; + case FULL_ELLIPSE : + sprintf(h, "WIRE %s %s ", width, SigName); + s += h; + s += wireEllipse() + ";\n"; + break; + case ELLIPSE_4 : + sprintf(h, "WIRE %s %s ", width, SigName); + s += h; + s += wireEllipse() + ";\n"; + break; + } + } + else { + sprintf(h, "WIRE %s %s (R%.9f %.9f) (R%.9f %.9f);\n", + width, SigName, + x1, y1, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + s += h; + } + return; +} + + +// ** draw Polygon *** +void drawPolygon(void) { + if (board && SigName) SigName = "'"+SigName+"'"; + if (library) SigName = ""; + + if((Placeform == FULL_ELLIPSE || Placeform == ELLIPSE_4) && EllipsFactor == 1.0) { + dlgMessageBox("!Da fehlt der Ellipsfaktor", "OK"); + exit(-2); + } + string ecmd; + + if (AngleStepTyp) { + switch(Placeform) { + case NONE : + sprintf(ecmd, "POLYGON %s %s ", width, SigName ); + s += ecmd; + s += wireEllipse(); + break; + case CIRCLE : + sprintf(ecmd, "POLYG %s %s ", width, SigName ); + s += ecmd; + s += wireEllipse(); + s += ";\n"; + break; + case FULL_ELLIPSE : + sprintf(ecmd, "Polygo %s %s ", width, SigName ); + s += ecmd; + s += wireEllipse(); + s += ";\n"; + break; + case ELLIPSE_4 : + sprintf(ecmd, "Polygon %s %s ", width, SigName ); + s += ecmd; + s += wireEllipse(); + s += ";\n"; + break; + } + } + else { + switch(Placeform) { + case NONE : + sprintf(ecmd, "POLy %s %s ", width, SigName ); + s += ecmd; + sprintf(ecmd, " (R%.9f %.9f)\n", x1, y1 ); + s += ecmd; + s += wireEllipse(); + s += ecmd +";\n"; + break; + case CIRCLE : + sprintf(ecmd, "POLY %s %s ", width, SigName ); + s += ecmd; + sprintf(ecmd, " (R%.9f %.9f)\n", x1, y1 ); + s += ecmd; + s += wireEllipse(); + s += ecmd; + s += ";\n"; + break; + case FULL_ELLIPSE : + sprintf(ecmd, "POlY %s %s ", width, SigName ); + s += ecmd; + sprintf(ecmd, " (R%.9f %.9f)\n", x1, y1 ); + s += ecmd; + s += wireEllipse(); + s += ecmd; + s += ";\n"; + break; + case ELLIPSE_4 : + sprintf(ecmd, "pOLYGON %s %s ", width, SigName ); + s += ecmd; + sprintf(ecmd, " (R%.9f %.9f)\n", x1, y1 ); + s += ecmd; + s += wireEllipse(); + s += ecmd; + s += ";\n"; + break; + } + } + return ; +} + + +// *** generate Script to MOVE packages *** +void drawMove(void) { + real rad = PI / 180 * StartAngle; + string Prefix = getPrefix(SigName); + int NameCount = getNumber(SigName); + string m = ""; + if (layer == "16") { + m = "M"; // to mirror the Element + } + + if (AngleStepTyp) { + if (AngleStep < 0) { + if (StartAngle < EndAngle) StartAngle+= 360; + for (real a = StartAngle; a > EndAngle; a += AngleStep) { + string eName; + sprintf(eName, "%s%d", Prefix, NameCount); + if (exist(eName)) { + rad = PI / 180 * a; + sprintf(h, "MOVE '%s' (R%.9f %.9f);\n", + eName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) + ); + s += h; + real ang = 0; + if (RotateMatch) { + if (m) ang = 180.0 - a; + else ang = a; + } + sprintf(h, "ROTATE =%sR%.2f '%s';\n", m, ang+EangleOffset, eName); + s += h; + NameCount++; + } + else break; + } + } + else { + for (real a = StartAngle; a < EndAngle; a += AngleStep) { + string eName; + sprintf(eName, "%s%d", Prefix, NameCount); + if (exist(eName)) { + rad = PI / 180 * a; + sprintf(h, "MOVE '%s' (R%.9f %.9f);\n", eName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + s += h; + real ang = 0; + if (RotateMatch) { + if (m) ang = 180.0 - a; + else ang = a; + } + sprintf(h, "ROTATE =%sR%.2f '%s';\n", m, ang, eName); + s += h; + NameCount++; + } + else break; + } + } + } + else { + if (exist(SigName)) { + sprintf(h, "MOVE '%s' (R%.9f %.9f);\n", SigName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + s += h; + real ang = StartAngle; + if (RotateMatch) { + if (m) ang = 180.0 - StartAngle; + else ang = StartAngle; + } + else ang = 0; + sprintf(h, "ROTATE =%sR%.2f '%s';\n", m, ang, SigName); + s += h; + } + } + return; +} + + +// *** generate Script to place SMDs *** +void drawSmd(void) { + if (SigName) SigName = "'"+SigName+"'"; + if (SMD_dx && SMD_dy) { + sprintf(h, "CHANGE SMD %.9f %.9f;\n", SMD_dx, SMD_dy); + s += h; + } + real rad = PI / 180 * StartAngle; + if (AngleStep) { + if (AngleStep < 0) { + if (StartAngle > EndAngle) StartAngle+= 360; + for (real a = StartAngle; a > EndAngle; a += AngleStep) { + rad = PI / 180 * a; + if (EAGLE_VERSION >= 4 && EAGLE_RELEASE >= 10 || EAGLE_VERSION >= 5) { + string rm = ""; + if (RotateMatch) sprintf(rm, "R%.2f", a); + sprintf(h, "SMD %s %s (R%.9f %.9f);\n", // 2008-05-06 + rm, + SigName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) + ); + s += h; + } + else { + sprintf(h, "SMD (R%.9f %.9f);\n", + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) + ); + s += h; + } + if (SigName) SigName = ""; // 2008-05-06 + } + } + else { + for (real a = StartAngle; a < EndAngle; a += AngleStep) { + rad = PI / 180 * a; + if (EAGLE_VERSION >= 4 && EAGLE_RELEASE >= 10 || EAGLE_VERSION >= 5) { + string rm; + if (RotateMatch) sprintf(rm, "R%.2f", a); + sprintf(h, "SMD %s %s (R%.9f %.9f);\n", // 2008-05-06 + rm, + SigName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) + ); + s += h; + if (SigName) SigName = ""; // 2008-05-06 + } + else { + sprintf(h, "SMD (R%.9f %.9f);\n", + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) + ); + s += h; + } + } + } + } + else { + if (EAGLE_VERSION >= 4 && EAGLE_RELEASE >= 10 || EAGLE_VERSION >= 5) { + string rm; + if (RotateMatch) sprintf(rm, "R%.2f", StartAngle); + + sprintf(h, "SMD %s %s (R%.9f %.9f);\n", // 2008-05-06 + rm, + SigName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) + ); + s+= h; + if (SigName) SigName = ""; // 2008-05-06 + } + else { + sprintf(h, "SMD (R%.9f %.9f);\n", + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) + ); + s+= h; + } + } + return ; +} + + +// *** generate Script to place PADs *** +void drawPad(void) { + if (SigName) SigName = "'"+SigName+"'"; + real rad = PI / 180 * StartAngle; + if (PadVia == "PAD" || PadVia == "VIA") { // 2013-08-05 change shape auch bei Via + if (ShapeSelect < PAD_SHAPE_OFFSET+1) + s += "CHANGE SHAPE " + Shapes[ShapeSelect] + ";\n"; + } + string Rotate_option = ""; + if (AngleStep) { + string h; + if (AngleStep < 0) { + if (StartAngle < EndAngle) StartAngle+= 360; + for (real a = StartAngle; a > EndAngle; a += AngleStep) { + rad = PI / 180 * a; + if (PadVia == "PAD") sprintf(Rotate_option, "R%.2f", a); + if (EAGLE_VERSION >= 4 && EAGLE_RELEASE >= 10 || EAGLE_VERSION >= 5) { + sprintf(h, "%s %s %s (R%.9f %.9f);\n", PadVia, Rotate_option, SigName, // 2010-06-09 alf + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + } + else { + sprintf(h, "%s %s (R%.9f %.9f);\n", PadVia, SigName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + } + s += h; + SigName = ""; + } + } + else { + for (real a = StartAngle; a < EndAngle; a += AngleStep) { + rad = PI / 180 * a; + if (PadVia == "PAD") sprintf(Rotate_option, "R%.2f", a); + if (EAGLE_VERSION >= 4 && EAGLE_RELEASE >= 10 || EAGLE_VERSION >= 5) { + sprintf(h, "%s %s %s (R%.9f %.9f);\n", // 2010-06-09 + PadVia, + Rotate_option, + SigName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + } + else { + sprintf(h, "%s '%s' (R%.9f %.9f);\n", + PadVia, + SigName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + } + s += h; + SigName = ""; + } + } + } + else { + if (PadVia == "PAD") sprintf(Rotate_option, "R%.2f", StartAngle); + if (EAGLE_VERSION >= 4 && EAGLE_RELEASE >= 10 || EAGLE_VERSION >= 5) { + sprintf(h, "%s %s %s (R%.9f %.9f);\n", // 2010-06-09 + PadVia, + Rotate_option, + SigName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + s+= h; + } + else { + sprintf(h, "%s '%s' (R%.9f %.9f);\n", // Via + PadVia, + SigName, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + s += h; + } + } + return ; +} + +// *** generate Script to place HOLEs *** +void drawHole(void) { + real rad = PI / 180 * StartAngle; + + sprintf(h, "HOLE %s ", Drill_Hole); + s += h; + if (Placeform == ELLIPSE_4) { + s += wireEllipse() + ";\n";; + } + else if (AngleStep) { + if (AngleStep < 0) { + if (StartAngle < EndAngle) StartAngle+= 360; + for (real a = StartAngle; a > EndAngle; a += AngleStep) { + rad = PI / 180 * a; + sprintf(h, " (R%.9f %.9f)\n", x1 + (cos(rad) * x2), y1 + (sin(rad) * x2 * EllipsFactor) ); // 2013-08-05 kein Semikolon + s += h; + } + s += ";\n"; + } + else { + for (real a = StartAngle; a < EndAngle; a += AngleStep) { + rad = PI / 180 * a; + sprintf(h, " (R%.9f %.9f)\n", x1 + (cos(rad) * x2), y1 + (sin(rad) * x2 * EllipsFactor) ); // 2013-08-05 kein Semikolon + s += h; + } + s += ";\n"; + } + } + else { + sprintf(h, "HOLE %s (R%.9f %.9f);\n", Drill_Hole, + x1 + (cos(rad) * x2), + y1 + (sin(rad) * x2 * EllipsFactor) ); + s += h; + } + return ; +} + + +void drawGroup(void) { + real groupdistance, m; + if (board) board(B) { + gridunit = (B.grid.unit); + m = abs(B.area.x2); + if (groupdistance < m) groupdistance = m; + m = abs(B.area.x1); + if (groupdistance < m) groupdistance = m; + m = abs(B.area.y2); + if (groupdistance < m) groupdistance = m; + m = abs(B.area.y1); + if (groupdistance < m) groupdistance = m; + } + if (library) library(L) { + gridunit = (L.grid.unit); + if (package) package(P) { + m = abs(P.area.x2); + if (groupdistance < m) groupdistance = m; + m = abs(P.area.x1); + if (groupdistance < m) groupdistance = m; + m = abs(P.area.y2); + if (groupdistance < m) groupdistance = m; + m = abs(P.area.y1); + if (groupdistance < m) groupdistance = m; + } + } + groupdistance = maxx; // maximum + if (!UseMarkedGroup) { // 2011-10-21 + sprintf(s, "GROUP (%.9f %.9f) (%.9f %.9f) (%.9f %.9f) (%.9f %.9f) (>%.9f %.9f);\n", + -groupdistance, -groupdistance, + groupdistance, -groupdistance, + groupdistance, groupdistance, + -groupdistance, groupdistance, + -groupdistance, -groupdistance + ); + } + sprintf(h, "CUT (R0 0);\n"); + s += h; + for (real a = StartAngle; a <= EndAngle-AngleStep; a += AngleStep) { + sprintf(h, "PASTE R%.2f (R0 0);\n", a); // 2011-10-21 + s += h; + } + return; +} + +void unknown(string m) { + if (dlgMessageBox("unknown parameter\n" + m, "OK", "Cancel" ) != 0) exit(-1); + return; +} + + +// ******* Main *************************************************************** +int n = 1; +if (argc > 1) { + do { + Para = strupr(argv[n]); + // *** Order of parameters can changed here *** + // *** Eagle-Parser cut character ' from argument *** + if (Para[0] == '+' ) { Para[0] = ' '; x2 = strtod(Para); } + else if (Para[0] == 'A' ) { Para[0] = ' '; StartAngle = strtod(Para); } + else if (Para[0] == 'N' ) { Para[0] = ' '; AngleStep = strtod(Para); } + else if (Para[0] == 'E' ) { Para[0] = ' '; EndAngle = strtod(Para); } + else if (Para[0] == 'L' ) { layer = strsub(Para, 1); } + else if (Para[0] == 'W' ) { Para[0] = ' '; width = Para; DrawType = DrawWIRE; } + else if (Para[0] == 'X' ) { Para[0] = ' '; x1 = strtod(Para); } + else if (Para[0] == 'Y' ) { Para[0] = ' '; y1 = strtod(Para); } + else if (Para[0] == 'O' ) { DrawType = DrawPOLYGON; } + else if (Para[0] == 'P' ) { PadVia = "PAD"; DrawType = DrawPAD; } + else if (Para[0] == 'V' ) { PadVia = "VIA"; DrawType = DrawPAD; } + else if (Para[0] == 'S' ) { DrawType = DrawSMD; } + else if (Para[0] == 'I' ) { Para[0] = ' '; SMD_dx = strtod(Para); } + else if (Para[0] == 'T' ) { Para[0] = ' '; SMD_dy = strtod(Para); } + else if (Para[0] == '-' ) { SigName = strsub(Para, 1); } + else if (Para[0] == 'D' ) { Para[0] = ' '; PAD_diameter = Para; } // Pad/Via diameter + else if (Para[0] == 'R' ) { Para[0] = ' '; Drill_Hole = Para; DrawType = DrawHOLE; } + else if (Para[0] == 0xb0) { AngleStepTyp = Degreestep; } // + else if (Para[0] == '/' ) { AngleStepTyp = Calcstep; } + else if (Para[0] == 'G' ) { DrawType = DrawGROUP; } + else if (strstr(Para, "MOVE") == 0) { DrawType = DrawMOVE; } // ** do not change order with next line ** + else if (Para[0] == 'M' ) { RotateMatch = 1; } // ** do not change order with prior line ** + else if (Para[0] == 'C' ) { Placeform = CIRCLE; } + else if (Para[0] == '0' ) { Para[0] = ' '; Placeform = FULL_ELLIPSE; } + else if (Para[0] == 'F' ) { Para[0] = ' '; EllipsFactor = strtod(Para); } + else if (Para[0] == '4' ) { Placeform = ELLIPSE_4; } + else unknown(Para); + n++; + } while (argv[n]); +} +else { + if (board) { + board(B) grid = B.grid.unit; + } + if (schematic) { schematic(S) grid = S.grid.unit; } + if (library) { + if (package || symbol) { + library(L) grid = L.grid.unit; + } + else { + dlgMessageBox("!Start this ULP in a Package or Symbol Editor", "OK"); + exit(0); + } + } + Set_MinMax_Unit(grid); + + int Result; + do { + Result = menue(); + if(PressOk) { + if (error()) { + string h; + sprintf(h, "error = %d", error()); + dlgMessageBox(h + " \n" + Help_Err, "OK"); + PressOk = 0; + } + } + } while(!PressOk); +} + +SigName = strupr(SigName); + +sprintf(s, "SET Wire_Bend 2;\n"); // *** Script header *** +if (layer) s += "CHANGE LAYER " + layer + ";\n"; +if (PAD_diameter) s += "CHANGE DIAMETER " + PAD_diameter + ";\n"; +if (Drill_Hole) s += "CHANGE DRILL " + Drill_Hole + ";\n"; +//if (SigName && DrawType == DrawSMD || DrawType == DrawSMD) s += "SMD " + SigName + ";\n"; // 2008.05.05 + +if (Placeform == ELLIPSE_4) { + if (EndAngle > 90.0) EndAngle = 90.0; + if (StartAngle > EndAngle) StartAngle = 0.0; +} + +switch(AngleStepTyp) { + case None : if (DrawType != DrawPOLYGON) { + AngleStep = 360; + } + break; + case Degreestep : if (!AngleStep) AngleStepTyp = None; + break; + case Calcstep : AngleStep = (EndAngle - StartAngle) / AngleStep; + break; +} + +switch(DrawType) { + case DrawWIRE : drawWire(); + break; + case DrawPOLYGON : drawPolygon(); + break; + case DrawMOVE : drawMove(); + break; + case DrawGROUP : drawGroup(); + break; + case DrawHOLE : drawHole(); + break; + case DrawPAD : drawPad(); + break; + case DrawSMD : drawSmd(); + break; +} + + +if (test) dlgDialog("Test") { + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgTextView(s); + } + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("ESC") { dlgReject(); exit(-1); } + dlgStretch(1); + dlgLabel(Version); + } + }; + +exit (s); + + diff --git a/trunk/ulp/cmd-net-list2sch.ulp b/trunk/ulp/cmd-net-list2sch.ulp new file mode 100644 index 00000000..3ab00563 --- /dev/null +++ b/trunk/ulp/cmd-net-list2sch.ulp @@ -0,0 +1,311 @@ +#usage "Import an EAGLE-Net-List into a schematic\n" + "

" + "Usage:
" + "RUN cmd-net-list2sch [netlist-file ]
" + "RUN cmd-net-list2sch [net part pin part pin ]
" + "RUN cmd-net-list2sch : Opens a file dialog to select the Net list file." + "

" + "Example:
" + "RUN cmd-net-list2sch hexapod.lst
" + "RUN cmd-net-list2sch IN1 R1 1 C1 2
" + "RUN cmd-net-list2sch clk ic1 9 ic3 15
" + "

" + "Attention:" + "In special situations it could happen that importing a netlist into a schematic " + "(in form of 'airwires' as it happens here) results in misconnections.
" + "This is the case if a net line overlaps a pin connection point.
" + "If this certain pin under the net should get connected later, EAGLE will connect to the net " + "instead of the pin under it.
" + "We want to avoid this problem in the ULP by drawing the net " + "line from the first pin with an offset of 50 mil. This way " + "diagonal net lines will be drawn
" + "and there will be hardly pins that lie under net lines.
" + "If a net has to be drawn on a further sheet of the schematic " + "EAGLE uses the diagonal offset of 50 mil and places an " + "additional LABEL." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string Hilfe = "

ACHTUNG:
\n" + "Das Einlesen einer Netzliste (Airwire) in den Schaltplan, " + + "kann in besonderen Situationen zu falschen Verbindungen führen.
" + + "Werden die Netze als Luftlinien zwischen den Bauteilpins gezeichnet, " + + "so kann es vorkommen, dass eine Netzlinie Bauteilpins überlagert.
" + + "Wird später dieser Pin unter der Linie an ein Netz angeschlossen " + + "so nimmt EAGLE das Netz als Kontaktpunkt und nicht den darunterliegenden Pin.
" + + "In diesem ULP wird versucht diese Problematik zu umgehen, in dem vom " + + "ersten Pin mit einem Offset (50mil) diagonal vom Pin weg, " + + "und dann direkt zum zweiten Pin gezeichnet wird.
" + + "Dadurch entstehen diagonale Luftlinien die nur in seltenen Fällen einen Pin " + + "überlagern.
" + + "Wird ein Netz auf einer anderen Schaltplanseite weitergeführt, " + + "so wird vom Pin um 50 Mil diagonal weggezeichnet und zusätzlich " + + "ein LABEL plaziert."; + +if (argc < 2) dlgMessageBox(usage + Hilfe, "OK"); + +string Version = "1.0.2"; // 2009-12-15 command RUN path/filename option with apostroph while space in path/filename + // check first if part place bevor run script. alf@cadsoft.de + // 2014-04-04 P.contacts(C) + +// Eagle NET-Command definition +string net_name = strupr(argv[1]); +string part_a = strupr(argv[2]); +string pin_a = strupr(argv[3]); +string part_b = strupr(argv[4]); +string pin_b = strupr(argv[5]); + +string cmd = ""; + +string lines[]; +int nLines; +//string s; + +// *** Eagle NET LIST definition *** +string tok_Net = "Net"; +string tok_Part = "Part"; +string tok_Pad = "Pad"; +string netlistLines[]; +string signalName; +int signalCnt = 0; +string NetListfileName; + +int cntP = 0; +string Parts[]; + + +// *** functions *** +int actSheet(UL_SHEET S) { + return S.number; +} + + +int partplaced(string partname) { // 2009-12-15 + for (int n = 0; n < cntP; n++) { + if (Parts[n] == partname) return 1; + } + return 0; +} + + +void readNetList(void) { + int sn = 0; + + for (sn = 0; sn < nLines; sn++) { // search for start line "Net Part Pin" in Eagle Netlist + if( (strstr(lines[sn], tok_Net) == 0) && (strstr(lines[sn], tok_Part) >= 8) && (strstr(lines[sn], tok_Pad) >= 16) ) { + sn++; + break; + } + } + if (sn == nLines) { + dlgMessageBox(NetListfileName + " is not a Eagle-Netlist", "OK"); + exit (0); + } + + string netName; + string par; + string pin; + string par_b; + string pin_b; + + do { + signalCnt = strsplit (netlistLines, lines[sn], ' '); + + if (signalCnt > 1) { + // init NET command + int ncnt = 1; + if (netlistLines[0]) { + netName = netlistLines[0]; + do { + if (netlistLines[ncnt]) { + par = netlistLines[ncnt]; + ncnt++; + break; + } + ncnt++; + } while (ncnt <= signalCnt); + do { + if (netlistLines[ncnt] ) { + pin = netlistLines[ncnt]; + ncnt++; + } + ncnt++; + } while (ncnt <= signalCnt); + } + + else { + do { + if (netlistLines[ncnt]) { + par_b = netlistLines[ncnt]; + ncnt++; + break; + } + ncnt++; + } while (ncnt <= signalCnt); + do { + if (netlistLines[ncnt] ) { + pin_b = netlistLines[ncnt]; + } + ncnt++; + } while (ncnt <= signalCnt); + if (partplaced(par)) { // 2009-12-15 alf@cadsoft.de + cmd += "RUN '" + argv[0] + "' " + netName + " " + par + " " + pin + " "; + cmd += par_b + " " + pin_b + ";\n"; + par = par_b; + pin = pin_b; + par_b = ""; + pin_b = ""; + } + else { + dlgMessageBox("! Part "+ par +" not foud.","OK"); + exit(-2); + } + } + } + sn++; + } while (sn <= nLines); + return; +} + +// *** MAIN *** +if (schematic) { + // run as net command + if (part_b && pin_b) { + int pinA_sheet = 0; + int pinB_sheet = 0; + int xA, yA, xB, yB; + string g = ";\nGRID LAST;\n"; + int actualsheet; + if (sheet) sheet(SH) actualsheet = SH.number; + + // *** Schematic coord. *** + schematic(S) { + cmd = "SET WIRE_BEND 2;\nGRID MIL FINEST 2 ;\n"; + S.sheets(SH) { + SH.parts(PA) { + if (PA.name == part_a ) { + PA.instances(IN) { + IN.gate.symbol.pins(P) { // Pin + int cntcontact = 0; + P.contacts(C) { // 2014-04-04 + cntcontact++; + } + if (cntcontact) { + string cp = P.contact.name; // PAD name von Connect/Pad + if (cp == pin_a) { + xA = P.x; + yA = P.y; + pinA_sheet = SH.number; + } + } + } + } + } + if (part_b) { + if (PA.name == part_b ) { + PA.instances(IN) { + IN.gate.symbol.pins(P) { // Pin + if (P.contact) { + string cp = P.contact.name; // PAD name von Connect/Pad + if (cp == pin_b) { + xB = P.x; + yB = P.y; + pinB_sheet = SH.number; + } + } + } + } + } + } + } + } + } + if (net_name) net_name = "'" + net_name + "'"; // place Name in ' ' for NET-Command + string s; + if ( (pinA_sheet != 0) && (pinB_sheet != 0) ) { + if (pinA_sheet == pinB_sheet) { + if (actualsheet != pinA_sheet) { + sprintf(s, "EDIT .s%d;\n", pinA_sheet); + cmd += s; + } + sprintf(s, "NET %s (%.3f %.3f)", net_name, u2mil(xA), u2mil(yA) ); + cmd += s; + sprintf(s, " (%.3f %.3f)", u2mil(xA)+50, u2mil(yA)-50 ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xB), u2mil(yB) ); + cmd += s; + exit (cmd + g); + } + else { + if (actualsheet != pinA_sheet) { + sprintf(s, "EDIT .s%d;\n", pinA_sheet); + cmd += s; + } + sprintf(s, "NET %s (%.3f %.3f)", net_name, u2mil(xA), u2mil(yA) ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xA)+50, u2mil(yA)+50 ); + cmd += s; + sprintf(s, "LABEL (%.3f %.3f)", u2mil(xA), u2mil(yA) ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xA)+50, u2mil(yA)+50 ); + cmd += s; + sprintf(s, "CHANGE LAYER 91 (%.3f %.3f);\n", u2mil(xA)+50, u2mil(yA)+50 ); + cmd += s; + + if (actualsheet != pinB_sheet) { + sprintf(s, "EDIT .s%d;\n", pinB_sheet); + cmd += s; + } + sprintf(s, "NET %s (%.3f %.3f)", net_name, u2mil(xB), u2mil(yB) ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xB)+50, u2mil(yB)+50 ); + cmd += s; + sprintf(s, "LABEL (%.3f %.3f)", u2mil(xB), u2mil(yB) ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xB)+50, u2mil(yB)+50 ); + cmd += s; + sprintf(s, "CHANGE LAYER 91 (%.3f %.3f);\n", u2mil(xB)+50, u2mil(yB)+50 ); + cmd += s; + exit (cmd + g); + } + } + else { + cmd = ""; + if (pinA_sheet == 0) cmd += "part " + part_a + " Pin " + pin_a + "\n"; + if (pinB_sheet == 0) cmd += "part " + part_b + " Pin " + pin_b + "\n"; + cmd += "not fond!"; + dlgMessageBox(cmd, "OK"); + exit (-1); + } + } + + // run as script converter + else { + schematic(S) { + S.parts(P) { + Parts[cntP] = P.name; + cntP++; + } + } + int n = 0; + string text; + int nBytes; + + if (argv[1]) NetListfileName = argv[1]; + else NetListfileName = dlgFileOpen("Select NETLIST File", "*.*", "*.*"); + + if (NetListfileName) { + nLines = fileread(lines, NetListfileName); + readNetList(); + } + output(NetListfileName + "x", "wtD") printf("%s", cmd); // D == temporary file + exit (cmd); + } +} + +else { + dlgMessageBox("Start this ULP from a schematic!", "OK"); + exit (0); +} diff --git a/trunk/ulp/cmd-netscript2sch.ulp b/trunk/ulp/cmd-netscript2sch.ulp new file mode 100644 index 00000000..2aea9bd6 --- /dev/null +++ b/trunk/ulp/cmd-netscript2sch.ulp @@ -0,0 +1,255 @@ +#usage "Import an EAGLE Netscript into a Schematic\n" + "

" + "Opens a file dialog to select a netscript file. " + "Some PCB systems allow to export an EAGLE netscript file in order to make " + "a layout in EAGLE. This ULP allows to use the netscript to generate an " + "EAGLE schematic, too. At least it can be used to draw all net connections " + "in the schematic easily, provided all parts have been placed before. " + "

" + "Attention:
" + "In special situations it could happen that importing a netlist " + "into a schematic (in form of 'airwires' as it happens here) " + "results in misconnections. This is the case if a net line " + "overlaps a pin connection point. If this certain pin under the " + "net should get connected later, EAGLE will connect to the net " + "instead of the pin under it.

" + "We want to avoid this problem in the ULP by drawing the net " + "line from the first pin with an offset of 50 mil. This way " + "diagonal net lines will be drawn and there will be hardly pins " + "that lie under net lines.

" + "If a net has to be drawn on a further sheet of the schematic " + "EAGLE uses the diagonal offset of 50 mil and places an " + "additional LABEL." + "

" + "Author: support@cadsoft.de" + +// 2006-01-26 -- modified #usage -- ric + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +/* German info + "ACHTUNG

\n" + "Das Einlesen einer Netzliste (Airwire) in den Schaltplan, " + "kann in besonderen Situationen zu falschen Verbindungen fuehren.

\n" + "Werden die Netze als "Luftlinien" zwischen den Bauteilpins gezeichnet, " + "so kann es vorkommen, dass eine Netzlinie Bauteilpins ueberlagert. " + "Wird spaeter dieser Pin unter der Linie an ein Netz angeschlossen " + "so nimmt EAGLE das Netz als Kontaktpunkt und nicht den " + "darunterliegenden Pin.

" + "In diesem ULP wird versucht diese Problematik zu umgehen, in dem vom " + "ersten Pin mit einem Offset (50mil) vom Pin weg " + "und dann zum zweiten Pin gezeichnet wird. Dadurch entstehen diagonale " + "Luftlinien die nur in seltenen Faellen einen Pin ueberlagern.

\n" + "Wird ein Netz auf einer anderen Schaltplanseite weitergefuehrt, " + "so wird vom Pin um 50 Mil diagonal weggezeichnet und zusaetzlich " + "ein LABEL plaziert.

\n" +*/ + +// Eagle NET-Command definition +string net_name = strupr(argv[1]); +string device_a = strupr(argv[2]); +string pin_a = strupr(argv[3]); +string device_b = strupr(argv[4]); +string pin_b = strupr(argv[5]); + +string cmd = ""; + +string lines[]; +int nLines; +string s; + +// *** Eagle NET-SCRIPT definition *** +string tok_Signal = "Signal"; +string signalLines[]; +string signalName; +int signalCnt = 0; +string tok_Change = "Change"; + +// *** functions *** + +int actSheet(UL_SHEET S) +{ + return S.number; +} + +void readNetList(void) +{ + int sn = 0; + do { + if( strstr(lines[sn], tok_Signal) == 0) { + signalCnt = strsplit (signalLines, lines[sn], '\''); + // init NET command + string netName = signalLines[1]; + string dev_a = signalLines[3]; + string pin_a = signalLines[5]; + string dev_b = ""; + string pin_b = ""; + // start NET command with run-cmd-net.ulp + sn++; + while (strstr(lines[sn], ";") < 0) { // end of Signallist + signalCnt = strsplit (signalLines, lines[sn], '\''); + string dev_b = signalLines[1]; + string pin_b = signalLines[3]; + cmd += "run " + argv[0] + " '" + netName + "' '" + dev_a + "' '" + pin_a + "' "; + cmd += "'" + dev_b + "' '" + pin_b + "' ;\n"; + dev_a = dev_b; + pin_a = pin_b; + sn++; + } + } + if( strstr(lines[sn], tok_Change) == 0) { + sprintf(s, "%s\n", lines[sn]); + cmd += s; + } + sn++; + } while (lines[sn]); + return; +} + +// *** MAIN *** +if (schematic) { + + // run as net command + if (device_b && pin_b) { + + int pinA_sheet = 0; + int pinB_sheet = 0; + int xA, yA, xB, yB; + string g = ";\nGRID LAST;\n"; + int actualsheet; + if (sheet) sheet(SH) actualsheet = SH.number; + + // *** Schematic coord. *** + schematic(S) { + cmd = "SET WIRE_BEND 2;\nGRID MIL 50 2 ;\n"; + S.sheets(SH) { + SH.parts(PA) { + if (PA.name == device_a ) { + PA.instances(IN) { + IN.gate.symbol.pins(P) { // Pin + if (P.contact) { + string cp = P.contact.name; // PAD name von Connect/Pad + if (cp == pin_a) { + xA = P.x; + yA = P.y; + pinA_sheet = SH.number; + } + } + } + } + } + if (device_b) { + if (PA.name == device_b ) { + PA.instances(IN) { + IN.gate.symbol.pins(P) { // Pin + if (P.contact) { + string cp = P.contact.name; // PAD name von Connect/Pad + if (cp == pin_b) { + xB = P.x; + yB = P.y; + pinB_sheet = SH.number; + } + } + } + } + } + } + } + } + } + if (net_name) net_name = "'" + net_name + "'"; + // place Name in ' ' for NET-Command + + string s; + if ( (pinA_sheet != 0) && (pinB_sheet != 0) ) { + if (pinA_sheet == pinB_sheet) { + if (actualsheet != pinA_sheet) { + sprintf(s, "EDIT .s%d;\n", pinA_sheet); + cmd += s; + } + sprintf(s, "NET %s (%.3f %.3f)", net_name, u2mil(xA), u2mil(yA) ); + cmd += s; + sprintf(s, " (%.3f %.3f)", u2mil(xA)+50, u2mil(yA)-50 ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xB), u2mil(yB) ); + cmd += s; + exit (cmd + g); + } + else { + if (actualsheet != pinA_sheet) { + sprintf(s, "EDIT .s%d;\n", pinA_sheet); + cmd += s; + } + sprintf(s, "NET %s (%.3f %.3f)", net_name, u2mil(xA), u2mil(yA) ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xA)+50, u2mil(yA)+50 ); + cmd += s; + sprintf(s, "LABEL (%.3f %.3f)", u2mil(xA), u2mil(yA) ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xA)+50, u2mil(yA)+50 ); + cmd += s; + sprintf(s, "CHANGE LAYER 91 (%.3f %.3f);\n", u2mil(xA)+50, u2mil(yA)+50 ); + cmd += s; + + if (actualsheet != pinB_sheet) { + sprintf(s, "EDIT .s%d;\n", pinB_sheet); + cmd += s; + } + sprintf(s, "NET %s (%.3f %.3f)", net_name, u2mil(xB), u2mil(yB) ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xB)+50, u2mil(yB)+50 ); + cmd += s; + sprintf(s, "LABEL (%.3f %.3f)", u2mil(xB), u2mil(yB) ); + cmd += s; + sprintf(s, " (%.3f %.3f);\n", u2mil(xB)+50, u2mil(yB)+50 ); + cmd += s; + sprintf(s, "CHANGE LAYER 91 (%.3f %.3f);\n", u2mil(xB)+50, u2mil(yB)+50 ); + cmd += s; + exit (cmd + g); + } + } + else { + cmd = ""; + if (pinA_sheet == 0) cmd += "Device " + device_a + " Pin " + pin_a + "\n"; + if (pinB_sheet == 0) cmd += "Device " + device_b + " Pin " + pin_b + "\n"; + cmd += "not fond!"; + dlgMessageBox(cmd, "OK"); + exit (-1); + } + } + + // run as script converter + else { + string ulp_path ; + char bkslash = '/'; + int pos = strrchr(argv[0], bkslash); + if (pos >= 0) { + ulp_path = strsub(argv[0], 0, pos + 1); + } + + // File handling + int n = 0; + string text; + string NetListfileName; + int nBytes; + + if (argv[1]) { + NetListfileName = argv[1]; + } + else { + NetListfileName = dlgFileOpen("Select Script File", "*.scr", "*.*"); + } + + if (NetListfileName) { + nLines = fileread(lines, NetListfileName); + readNetList(); + } + output(NetListfileName + "x", "wt") printf("%s", cmd); + + exit (cmd); + } + } +else { + dlgMessageBox("Start this ULP from a schematic!", "OK"); + exit (0); + } diff --git a/trunk/ulp/cmd-place-restrict-name-value.ulp b/trunk/ulp/cmd-place-restrict-name-value.ulp new file mode 100644 index 00000000..265d7629 --- /dev/null +++ b/trunk/ulp/cmd-place-restrict-name-value.ulp @@ -0,0 +1,162 @@ +#usage "Copy name and value into restrict layer\n" + "

" + "Generates a command sequence copying the name texts-wires and value texts-wires " + "of all elements of your layout into restrict layers (41 and 42)." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +int tNames = 25, bNames = 26; +real distance = 0.2; // distance Wire <> Text in Millimeter. +string cmd; +string h; +string scriptfile; + + +string help = "If the Autorouter shall avoid the NAME and VALUE text area\n" + + "we have to draw the texts as wires in the restrict layers.\n" + + "To let the Autorouter keep a minimum distance to the texts (wires)\n" + + "to avoid short circuits, we have to draw the text wires with a\n" + + "higher width which includes the respective minimum clearance.\n" + + "\n"+ + "German help text inside the ulp file.\n"; + + +/*string German help = "Kopiert die Texte 'Name' und 'Value' in die Restrict-Layer.\n" + + * "Soll der Autorouter unter den NAME- und VALUE-Texten\n" + + * "nicht routen, so muss der Text als Wire in die Restrict-Layer\n" + + * "kopiert werden.\n" + + * "Damit der Autorouter einen Abstand zu den Elementen (Textlinien)\n" + + * "einhaelt, sodass keine Kurzschluesse erzeugt werden, muss die Linienbreite\n" + + */ "um den entsprechenden Mindestabstand erweitert werden.\n"; + +void header(void) { + sprintf(cmd, "# Exported from %s by %s\n", scriptfile, EAGLE_SIGNATURE ); + sprintf(h, "# Distance = %.3f mm\n", distance); cmd += h; + cmd += "SET UNDO_LOG OFF;\n"; // advisable for speed reasons + cmd += "set wire_bend 2;\n"; + cmd += "GRID mm;\n"; +} + +// Distance menue +int menue(void) { + int d = dlgDialog("Place Text as Wire") { + dlgLabel(usage); + dlgLabel(help); + dlgHBoxLayout { + dlgLabel("&Distance [mm]"); + dlgRealEdit(distance); + } + dlgHBoxLayout { + dlgPushButton("+&OK") dlgAccept(); + dlgPushButton("-&Cancel") dlgReject(); + dlgStretch(1); + } + }; + return d; + } + +if (board) board(B) { + if (!menue()) exit (0); + scriptfile = filesetext(B.name, ".scr"); + header(); + distance *= 2; + B.elements(E) { + + E.texts(T) { // *** smased *** + if (T.layer == 25) { + sprintf(h, "Change Layer %d;\n", 41);cmd += h; + T.wires(W) { + sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + cmd += h; + } + } + if (T.layer == 26) { + sprintf(h, "Change Layer %d;\n", 42);cmd += h; + T.wires(W) { + sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + cmd += h; + } + } + if (T.layer == 27) { + sprintf(h, "Change Layer %d;\n", 41);cmd += h; + T.wires(W) { + sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + cmd += h; + } + } + if (T.layer == 28) { + sprintf(h, "Change Layer %d;\n", 42);cmd += h; + T.wires(W) { + sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + cmd += h; + } + } + } + + E.package.texts(T) { // *** non smased + if (T.layer == 25) { + sprintf(h, "Change Layer %d;\n", 41);cmd += h; + T.wires(W) { + sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + cmd += h; + } + } + if (T.layer == 26) { + sprintf(h, "Change Layer %d;\n", 42);cmd += h; + T.wires(W) { + sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + cmd += h; + } + } + if (T.layer == 27) { + sprintf(h, "Change Layer %d;\n", 41);cmd += h; + T.wires(W) { + sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + cmd += h; + } + } + if (T.layer == 28) { + sprintf(h, "Change Layer %d;\n", 42);cmd += h; + T.wires(W) { + sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mm(W.width) + distance, u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + cmd += h; + } + } + } + } +} +cmd += "SET UNDO_LOG ON;\n"; +cmd += "GRID LAST;\n"; + +// EditBox +int Result = dlgDialog("Copy Text in Restrict.Layer") { + dlgHBoxLayout { + dlgTextEdit(cmd); + dlgVBoxLayout { + dlgSpacing(300); + } + } + dlgHBoxLayout { + dlgSpacing(500); + } + dlgHBoxLayout { + dlgPushButton("+&Execute") dlgAccept(); + dlgPushButton("-&Cancel") dlgReject(); + dlgStretch(1); + } + }; +if (Result == 0) exit(0); + +output(scriptfile, "wt") printf("%s", cmd); + +exit("script '" + scriptfile + "';\nREMOVE '" + scriptfile + "';\n"); diff --git a/trunk/ulp/cmd-rename-in-lbr.ulp b/trunk/ulp/cmd-rename-in-lbr.ulp new file mode 100644 index 00000000..aaca4643 --- /dev/null +++ b/trunk/ulp/cmd-rename-in-lbr.ulp @@ -0,0 +1,45 @@ +#usage "Rename device/symbol/package in library\n" + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string edit = ""; +string toName = edit; + +if (library) library(L) { + + if (deviceset) deviceset(D) { + edit = D.name; + } + + if (symbol) symbol(S) { + edit = S.name; + } + if (package) package(P) { + edit = P.name; + } + +int Result = dlgDialog("RENAME") { + dlgStretch(0); + string h; + sprintf(h, "Rename

%s

to :", edit); + dlgLabel(h); + dlgStretch(0); + toName = edit; + dlgStringEdit(toName); + dlgStretch(0); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") { + dlgAccept(); + } + dlgStretch(1); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + }; + dlgStretch(1); + }; + if (Result == 0) exit (0); + exit("RENAME '" + edit + "' '" + toName +"'" ); +} diff --git a/trunk/ulp/cmd-renumber.ulp b/trunk/ulp/cmd-renumber.ulp new file mode 100644 index 00000000..43c94d5a --- /dev/null +++ b/trunk/ulp/cmd-renumber.ulp @@ -0,0 +1,664 @@ +#usage "Renumber board components\n" + "

" + "See Help of the ULP for further instructions." + "

" + "Author: support@cadsoft.de (based on original code from Michel Dagenais, jcmae@sympatico.ca)" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +// 16.06.2002 "Scan window"/"Unit" do not take effect in the current instance of the program -- alf@cadsoft.de + +string HelpText = + + "This ULP will renumber a board's components starting from any corner, renaming from suffix 1, either horizontally or vertically." + "

\n" + "If there are names like R01, the program will ask you if it may change those names. " + "Otherwise no renaming can be performed." + "

\n" + "Your board MUST be drawn on layer 20 (dimension) and all components MUST be inside it, otherwise the result is unpredictable.\n" + "

\n" + "

\n" + "Meaning of Parameters\n" + "

\n" + "Unit\n" + "

\n" + "Unit for the value entered in the Scan window.\n" + "

\n" + "Direction\n" + "

\n" + "Renumber direction.\n" + "

\n" + "Top Side: Start from\n" + "

\n" + "Renumber starting point for top (component) side.\n" + "

\n" + "Bottom Side: Start from\n" + "

\n" + "Renumber starting point for bottom (solder) side.\n" + "

\n" + "Scan window\n" + "

\n" + "Dimension of the user-defined window to determine row or column width for components scanning.\n" + "

\n" + "Bottom suffix\n" + "

\n" + "Renumbering starts at the component side.\n" + "If Bottom suffix is 0, the bottom component suffixes are continued in sequence.\n" + "If Bottom suffix is > 0, the bottom component suffixes start with this number, provided there is no overlapping with component names at the top side.\n" + "

\n" + "Show scripts\n" + "

\n" + "If this box is checked, the respective command scripts are shown before execution of Preview and Renumber.
\n" + "The Renumber Script can be saved.\n" + "

\n" + "Preview\n" + "

\n" + "Highlights all components in the order of the currently selected renumbering sequence.
\n" + "Please note that on fast computers Preview might be too fast to watch!\n" + "

\n" + "Renumber\n" + "

\n" + "Executes the renumber function and quits program.\n" + "

\n" + ; +//----------------------------------------------------------------------------------------- + +real window, win; +int sequence_bottom; +int dir; +int c_top; +int c_bottom; +enum {unitINCH, unitMM}; +int unit = unitINCH; +int show_script; +string params; + +if (!argv[1]) { // first program instance + //---- edit the following default values to your liking --------------------------------- + window = 0.4 ; // default scan window width + sequence_bottom = 100; // if no overlap, use this new suffix to start on bottom, + // otherwise continue in sequence + dir = 0; // 0 = horizontally, 1 = vertically + c_top = 0; // starting point for top side + c_bottom = 3; // starting point for bottom side + unit = unitINCH; // change to unitMM, if you want mm as default + show_script = 0; // 1 = show script file before execution + } +else { + if (argv[1] == "end") { // last program instance + dlgMessageBox("Renumber finished!", "&OK"); + exit(0); + } + sprintf (params, " %s", argv[1]); // other program instances + window = strtod(params); + for (int ix = 2; ix <= 7; ix++) { + string hx = ""; + sprintf (hx, " %s", argv[ix]); + params += hx; + } + sequence_bottom = strtol(argv[2]); + dir = strtol(argv[3]); + c_top = strtol(argv[4]); + c_bottom = strtol(argv[5]); + unit = strtol(argv[6]); + show_script = strtol(argv[7]); + if (unit == unitINCH) + win = window; + else + win = window / 25.4; + } + +//----------------------------------------------------------------------------------------- +string h, cmd; +int Result, tmp_int, i, j, z, length_of_name, number_prefix, largest_number_prefix; +int i_p_top, index_top[], old_suffix_top[], new_suffix_top[]; +real comp_x_abs_top[], comp_y_abs_top[]; +int i_p_bottom, index_bottom[], old_suffix_bottom[], new_suffix_bottom[]; +real comp_x_abs_bottom[], comp_y_abs_bottom[]; +int i_p_both, index_both[], old_suffix_both[], new_suffix_both[]; +real tmp_real, w, pcb_min_x, pcb_min_y, pcb_max_x, pcb_max_y, pcb_length, pcb_height; +string tmp_string, ref_name, last_prefix, prefix_top[], prefix_bottom[], prefix_both[]; +//----------------------------------------------------------------------------------------- + +void DisplayHelp(void) +{ + dlgDialog("Renumer Help") { + dlgHBoxLayout dlgSpacing(400); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(300); + dlgTextView(HelpText); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("-Close") dlgReject(); + } + }; +} +//----------------------------------------------------------------------------------------- + +string get_progname(void) { + string s = strsub(argv[0], 0, strlen(argv[0])-4); + string p = s; + char c = '/'; + int pos = strrchr(s, c); + if (pos >= 0) { + p = strsub(s, pos + 1); + } + return p; +} +//----------------------------------------------------------------------------------------- + +void renumber (void) { + cmd = ""; + h = ""; sprintf(h, ";\n"); cmd += h; + h = ""; sprintf(h, "Grid Inch;\n"); cmd += h; + h = ""; sprintf(h, "Display None;\n"); cmd += h; + h = ""; sprintf(h, "Window fit;\n"); cmd += h; + h = ""; sprintf(h, "Display 20 21 22 25 26 -27 -28;\n"); cmd += h; + for (i = 0; i < i_p_both; ++i) { + new_suffix_both[i] = i + 1 ; + } + sort (i_p_both, index_both, prefix_both, new_suffix_both, old_suffix_both); + for (j = 0; j < i_p_both; ++j) { // all parts ------------------------ + z = 1; + tmp_int = 1; + tmp_string = prefix_both[index_both[j]]; + for (i = j; prefix_both[index_both[i]] == tmp_string; ++i) { + if ((sequence_bottom > largest_number_prefix) && (new_suffix_both[index_both[i]] > i_p_top) && (tmp_int == 1)) { + z = sequence_bottom; + tmp_int = 0; + } + if ((new_suffix_both[index_both[i]] > 0) && (old_suffix_both[index_both[i]] != z)) { + new_suffix_both[index_both[i]] = z * -1; + } + else { + new_suffix_both[index_both[i]] = 0 ; + } + ++z; + if (i == i_p_both - 1) break; // added!!! + } + if (i == i_p_both - 1) break; // added!!! + j = i - 1; + } + for (i = 0; i < i_p_both; ++i) { + if (new_suffix_both[index_both[i]] < 0) { + h = ""; sprintf(h, "Name '%s%d' '$$%s%d';\n", prefix_both[index_both[i]], old_suffix_both[index_both[i]], prefix_both[index_both[i]], abs(new_suffix_both[index_both[i]])); cmd += h; + } + } + for (i = 0; i < i_p_both; ++i) { + if (new_suffix_both[index_both[i]] < 0) { + h = ""; sprintf(h, "Name '$$%s%d' '%s%d';\n", prefix_both[index_both[i]], abs(new_suffix_both[index_both[i]]), prefix_both[index_both[i]], abs(new_suffix_both[index_both[i]])); cmd += h; + } + } + h = ""; sprintf(h, "Grid Last;\n"); cmd += h; + if (show_script) { + Result = dlgDialog("Edit Commands") { + dlgVBoxLayout { + dlgLabel("Edit only if you are sure what you do!"); + dlgTextEdit(cmd); + } + dlgHBoxLayout { + dlgPushButton("+Ok") dlgAccept(); + dlgPushButton("-Quit") dlgReject(); + dlgPushButton("+Save") { + string dest = dlgFileSave("Save Script File", "renumber.scr", "*.scr"); + if (dest != "") output(dest, "wt") {printf(cmd);} + } + } + }; + if (!Result) exit(0); + } + cmd += "RUN "+get_progname()+" end"; + exit(cmd); +} +//-------------------------------------------------------------------------------- + +void preview(void) { + cmd = ""; + sprintf (params, " %f %d %d %d %d %d %d", + window, sequence_bottom, dir, c_top, c_bottom, unit, show_script); + h = ""; sprintf(h, ";\n"); cmd += h; + h = ""; sprintf(h, "Grid Inch;\n"); cmd += h; + h = ""; sprintf(h, "Display None;\n"); cmd += h; + h = ""; sprintf(h, "Window fit;\n"); cmd += h; + h = ""; sprintf(h, "Display 20 21 22 25 26 -27 -28;\n"); cmd += h; + for (i = 0; i < i_p_both; ++i) + { + h = ""; sprintf(h, "Show %s%d %s%d;\n", prefix_both[i], old_suffix_both[i], prefix_both[i], old_suffix_both[i]); cmd += h; + } + if (show_script) { + Result = dlgDialog("Edit Commands") { + dlgVBoxLayout { + dlgLabel("Edit only if you are sure what you do!"); + dlgTextEdit(cmd); + } + dlgHBoxLayout { + dlgPushButton("+Ok") dlgAccept(); + dlgPushButton("-Quit") dlgReject(); + } + }; + if (!Result) exit(0); + } + cmd += "RUN "+get_progname()+params; + exit(cmd); +} +//--- collect data --------------------------------------------------------------- + +void get_data(void) { +board(B) { // Get board size to determine ratio. + tmp_int = 1; + B.wires(W) { + if (W.layer == 20) { + if (tmp_int == 1) { + pcb_min_x = u2inch(W.x1); + pcb_min_y = u2inch(W.y1); + pcb_max_x = u2inch(W.x1); + pcb_max_y = u2inch(W.y1); + tmp_int = 0; + } + if (u2inch(W.x1) < pcb_min_x){pcb_min_x = u2inch(W.x1);} + if (u2inch(W.x1) > pcb_max_x){pcb_max_x = u2inch(W.x1);} + if (u2inch(W.x2) < pcb_min_x){pcb_min_x = u2inch(W.x2);} + if (u2inch(W.x2) > pcb_max_x){pcb_max_x = u2inch(W.x2);} + if (u2inch(W.y1) < pcb_min_y){pcb_min_y = u2inch(W.y1);} + if (u2inch(W.y1) > pcb_max_y){pcb_max_y = u2inch(W.y1);} + if (u2inch(W.y2) < pcb_min_y){pcb_min_y = u2inch(W.y2);} + if (u2inch(W.y2) > pcb_max_y){pcb_max_y = u2inch(W.y2);} + } + } + pcb_length = pcb_max_x - pcb_min_x; + pcb_height = pcb_max_y - pcb_min_y; + number_prefix = 1; + last_prefix = ""; + largest_number_prefix = 1; + B.elements(E) { + ref_name = E.name ; + if (!(strlen(ref_name)<=1 || isdigit(ref_name[0]))) { // exclude R, 04 etc. + length_of_name = strlen(ref_name) ; + prefix_top[i_p_top] = "" ; + new_suffix_top[i_p_top] = 0 ; + tmp_string = "" ; + if (isdigit(ref_name[length_of_name - 1]) && E.mirror == 0 ) { // on top & num suffix + for (i = strlen(ref_name) - 1; isdigit(ref_name[i]); --i); // find prefix + suffix + prefix_top[i_p_top] = strsub(ref_name, 0, i+1); // prefix + tmp_string = strsub(ref_name, i+1); // suffix + + if (prefix_top[i_p_top] == last_prefix) { + ++number_prefix; // inc as long as same prefix + } + else { + last_prefix = prefix_top[i_p_top]; + if (number_prefix > largest_number_prefix) { + largest_number_prefix = number_prefix; // update largest_n.. + number_prefix = 1; + } + } + old_suffix_top[i_p_top] = strtol(tmp_string) ; + switch (c_top) { + case 1: // Top-Right + { + comp_x_abs_top[i_p_top] = abs(u2inch(E.x) - pcb_max_x) ; + comp_y_abs_top[i_p_top] = abs(u2inch(E.y) - pcb_max_y) ; + break; + } + case 0: // Top-Left + { + comp_x_abs_top[i_p_top] = abs(u2inch(E.x) + abs(pcb_min_x)) ; + comp_y_abs_top[i_p_top] = abs(u2inch(E.y) - pcb_max_y) ; + break; + } + case 2: // Bottom-Left + { + comp_x_abs_top[i_p_top] = abs(u2inch(E.x) + abs(pcb_min_x)) ; + comp_y_abs_top[i_p_top] = abs(u2inch(E.y) + abs(pcb_min_y)) ; + break; + } + case 3: // Bottom-Right + + { + comp_x_abs_top[i_p_top] = abs(u2inch(E.x) - pcb_max_x) ; + comp_y_abs_top[i_p_top] = abs(u2inch(E.y) + abs(pcb_min_y)) ; + break; + } + default: // default is Top-Left Corner for Top side. + { + comp_x_abs_top[i_p_top] = abs(u2inch(E.x) + abs(pcb_min_x)) ; + comp_y_abs_top[i_p_top] = abs(u2inch(E.y) - pcb_max_y) ; + } + } + ++i_p_top ; + } + } + } + if (number_prefix > largest_number_prefix) { + largest_number_prefix = number_prefix; // update largest_n.. + number_prefix = 1; + } + } +if (dir == 1) { + sort (i_p_top, index_top, comp_x_abs_top, comp_y_abs_top, prefix_top, old_suffix_top, new_suffix_top) ; + j = 0 ; + do { + w = comp_x_abs_top[index_top[j]] + win; + for (i = j + 1; i < i_p_top; ++i) { + if (comp_x_abs_top[index_top[i]] > w) { + break ; + } + if (comp_y_abs_top[index_top[i]] < comp_y_abs_top[index_top[i - 1]]) { + tmp_real = comp_x_abs_top[index_top[i - 1]]; + comp_x_abs_top[index_top[i - 1]] = comp_x_abs_top[index_top[i]]; + comp_x_abs_top[index_top[i]] = tmp_real; + tmp_real = comp_y_abs_top[index_top[i - 1]]; + comp_y_abs_top[index_top[i - 1]] = comp_y_abs_top[index_top[i]]; + comp_y_abs_top[index_top[i]] = tmp_real; + tmp_string = prefix_top[index_top[i - 1]]; + prefix_top[index_top[i - 1]] = prefix_top[index_top[i]]; + prefix_top[index_top[i]] = tmp_string; + tmp_int = old_suffix_top[index_top[i - 1]]; + old_suffix_top[index_top[i - 1]] = old_suffix_top[index_top[i]]; + old_suffix_top[index_top[i]] = tmp_int; + tmp_int = new_suffix_top[index_top[i - 1]]; + new_suffix_top[index_top[i - 1]] = new_suffix_top[index_top[i]]; + new_suffix_top[index_top[i]] = tmp_int; + i = j ; + } + } + j = i ; + } while (j < i_p_top) ; + } +else { + sort (i_p_top, index_top, comp_y_abs_top, comp_x_abs_top, prefix_top, old_suffix_top, new_suffix_top) ; + j = 0 ; + do { + w = comp_y_abs_top[index_top[j]] + win; + for (i = j + 1; i < i_p_top; ++i) { + if (comp_y_abs_top[index_top[i]] > w) { + break ; + } + if (comp_x_abs_top[index_top[i]] < comp_x_abs_top[index_top[i - 1]]) { + tmp_real = comp_x_abs_top[index_top[i - 1]]; + comp_x_abs_top[index_top[i - 1]] = comp_x_abs_top[index_top[i]]; + comp_x_abs_top[index_top[i]] = tmp_real; + tmp_real = comp_y_abs_top[index_top[i - 1]]; + comp_y_abs_top[index_top[i - 1]] = comp_y_abs_top[index_top[i]]; + comp_y_abs_top[index_top[i]] = tmp_real; + tmp_string = prefix_top[index_top[i - 1]]; + prefix_top[index_top[i - 1]] = prefix_top[index_top[i]]; + prefix_top[index_top[i]] = tmp_string; + tmp_int = old_suffix_top[index_top[i - 1]]; + old_suffix_top[index_top[i - 1]] = old_suffix_top[index_top[i]]; + old_suffix_top[index_top[i]] = tmp_int; + tmp_int = new_suffix_top[index_top[i - 1]]; + new_suffix_top[index_top[i - 1]] = new_suffix_top[index_top[i]]; + new_suffix_top[index_top[i]] = tmp_int; + i = j ; + } + } + j = i ; + } while (j < i_p_top) ; + } +// Bottom side of board +board(B) { + B.elements(E) { + ref_name = E.name ; + if (!(strlen(ref_name)<=1 || isdigit(ref_name[0]))) { // exclude R, 04 etc. + length_of_name = strlen(ref_name) ; + prefix_bottom[i_p_bottom] = "" ; + new_suffix_bottom[i_p_bottom] = 0 ; + tmp_string = "" ; + if (isdigit(ref_name[length_of_name - 1]) && E.mirror == 1 ) { + for (i = strlen(ref_name) - 1; isdigit(ref_name[i]); --i); // find prefix + prefix_bottom[i_p_bottom] = strsub(ref_name, 0, i+1); + tmp_string = strsub(ref_name, i+1); // suffix + old_suffix_bottom[i_p_bottom] = strtol(tmp_string) ; + switch (c_bottom) + { + case 1: // Top-Right + { + comp_x_abs_bottom[i_p_bottom] = abs(u2inch(E.x) - pcb_max_x) ; + comp_y_abs_bottom[i_p_bottom] = abs(u2inch(E.y) - pcb_max_y) ; + break; + } + case 0: // Top-Left + { + comp_x_abs_bottom[i_p_bottom] = abs(u2inch(E.x) + abs(pcb_min_x)) ; + comp_y_abs_bottom[i_p_bottom] = abs(u2inch(E.y) - pcb_max_y) ; + break; + } + case 2: // Bottom-Left + { + comp_x_abs_bottom[i_p_bottom] = abs(u2inch(E.x) + abs(pcb_min_x)) ; + comp_y_abs_bottom[i_p_bottom] = abs(u2inch(E.y) + abs(pcb_min_y)) ; + break; + } + case 3: // Bottom-Right + { + comp_x_abs_bottom[i_p_bottom] = abs(u2inch(E.x) - pcb_max_x) ; + comp_y_abs_bottom[i_p_bottom] = abs(u2inch(E.y) + abs(pcb_min_y)) ; + break; + } + default: // default is Top-Right Corner for Bottom side. + { + comp_x_abs_bottom[i_p_bottom] = abs(u2inch(E.x) - pcb_max_x) ; + comp_y_abs_bottom[i_p_bottom] = abs(u2inch(E.y) - pcb_max_y) ; + } + } + ++i_p_bottom ; + } + } + } + } +if (dir == 1) { + sort (i_p_bottom, index_bottom, comp_x_abs_bottom, comp_y_abs_bottom, prefix_bottom, old_suffix_bottom, new_suffix_bottom) ; + j = 0 ; + do { + w = comp_x_abs_bottom[index_bottom[j]] + win; + for (i = j + 1; i < i_p_bottom; ++i) { + if (comp_x_abs_bottom[index_bottom[i]] > w) { + break ; + } + if (comp_y_abs_bottom[index_bottom[i]] < comp_y_abs_bottom[index_bottom[i - 1]]) { + tmp_real = comp_x_abs_bottom[index_bottom[i - 1]]; + comp_x_abs_bottom[index_bottom[i - 1]] = comp_x_abs_bottom[index_bottom[i]]; + comp_x_abs_bottom[index_bottom[i]] = tmp_real; + tmp_real = comp_y_abs_bottom[index_bottom[i - 1]]; + comp_y_abs_bottom[index_bottom[i - 1]] = comp_y_abs_bottom[index_bottom[i]]; + comp_y_abs_bottom[index_bottom[i]] = tmp_real; + tmp_string = prefix_bottom[index_bottom[i - 1]]; + prefix_bottom[index_bottom[i - 1]] = prefix_bottom[index_bottom[i]]; + prefix_bottom[index_bottom[i]] = tmp_string; + tmp_int = old_suffix_bottom[index_bottom[i - 1]]; + old_suffix_bottom[index_bottom[i - 1]] = old_suffix_bottom[index_bottom[i]]; + old_suffix_bottom[index_bottom[i]] = tmp_int; + tmp_int = new_suffix_bottom[index_bottom[i - 1]]; + new_suffix_bottom[index_bottom[i - 1]] = new_suffix_bottom[index_bottom[i]]; + new_suffix_bottom[index_bottom[i]] = tmp_int; + i = j ; + } + } + j = i ; + } while (j < i_p_bottom) ; + } +else { + sort (i_p_bottom, index_bottom, comp_y_abs_bottom, comp_x_abs_bottom, prefix_bottom, old_suffix_bottom, new_suffix_bottom) ; + j = 0 ; + do { + w = comp_y_abs_bottom[index_bottom[j]] + win; + for (i = j + 1; i < i_p_bottom; ++i) { + if (comp_y_abs_bottom[index_bottom[i]] > w) { + break ; + } + if (comp_x_abs_bottom[index_bottom[i]] < comp_x_abs_bottom[index_bottom[i - 1]]) { + tmp_real = comp_x_abs_bottom[index_bottom[i - 1]]; + comp_x_abs_bottom[index_bottom[i - 1]] = comp_x_abs_bottom[index_bottom[i]]; + comp_x_abs_bottom[index_bottom[i]] = tmp_real; + tmp_real = comp_y_abs_bottom[index_bottom[i - 1]]; + comp_y_abs_bottom[index_bottom[i - 1]] = comp_y_abs_bottom[index_bottom[i]]; + comp_y_abs_bottom[index_bottom[i]] = tmp_real; + tmp_string = prefix_bottom[index_bottom[i - 1]]; + prefix_bottom[index_bottom[i - 1]] = prefix_bottom[index_bottom[i]]; + prefix_bottom[index_bottom[i]] = tmp_string; + tmp_int = old_suffix_bottom[index_bottom[i - 1]]; + old_suffix_bottom[index_bottom[i - 1]] = old_suffix_bottom[index_bottom[i]]; + old_suffix_bottom[index_bottom[i]] = tmp_int; + tmp_int = new_suffix_bottom[index_bottom[i - 1]]; + new_suffix_bottom[index_bottom[i - 1]] = new_suffix_bottom[index_bottom[i]]; + new_suffix_bottom[index_bottom[i]] = tmp_int; + i = j ; + } + } + j = i ; + } while (j < i_p_bottom) ; + } +i_p_both = 0; +for (i = 0; i < i_p_top; ++i) { + prefix_both[i_p_both] = prefix_top[index_top[i]]; + old_suffix_both[i_p_both] = old_suffix_top[index_top[i]]; + new_suffix_both[i_p_both] = new_suffix_top[index_top[i]]; + ++i_p_both; + } +for (i = 0; i < i_p_bottom; ++i) { + prefix_both[i_p_both] = prefix_bottom[index_bottom[i]]; + old_suffix_both[i_p_both] = old_suffix_bottom[index_bottom[i]]; + new_suffix_both[i_p_both] = new_suffix_bottom[index_bottom[i]]; + ++i_p_both; + } +} +//-------------------------------------------------------------------------------- +// change names if necessary: R01 -> R100001 etc. + +string correct_name(string s) { +string s1, s2; +int i, j; + if (strlen(s) < 2 || isdigit(s[0])) + return s; // single character or name starts with 0 + if (!isdigit(s[strlen(s)-1])) // no suffix + return s; + for (i = 0; !isdigit(s[i]); ++i); // i points to first numeric character + for (j = strlen(s) - 1; isdigit(s[j]); --j); // j points to last non-numeric character + if ((i < strlen(s) -1) && s[i] == '0') { + s1 = strsub(s, 0, i); + s2 = strsub(s, i); + s = s1+"1000"+s2; + } + return s; +} +//-------------------------------------------------------------------------------- +void view_names(void) { + board(B) { + B.elements(P) { + h= ""; sprintf(h, "%s\n", P.name); + cmd += h; + } + } + + dlgDialog("Part names") { + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(300); + dlgTextView(cmd); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("-Close") dlgReject(); + } + }; +} +//-------------------------------------------------------------------------------- + +void check_names(void) { + int name_changed = 0; + string corr_name; + cmd = ";\n"; + board(B) { // replace R01 with R100001 etc. + B.elements(P) { + corr_name = correct_name(P.name); + if (corr_name != P.name) { + name_changed = 1; + h= ""; sprintf(h, "NAME '%s' '%s';\n", P.name, corr_name); + cmd += h; + } + } + } +if (name_changed) { + if (dlgMessageBox("Board contains packages with leading zero\nsuffixes (e.g. R01). Renumber cannot handle such names!\n\nChange automatically?", + "&OK", "&Quit") == 0) { + Result = dlgDialog("Changes") { + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(300); + dlgTextView(cmd); + } + dlgHBoxLayout { + dlgStretch(1); + dlgSpacing(40); + dlgPushButton("-OK") dlgAccept(); + dlgPushButton("-Close") dlgReject(); + } + }; + if (!Result) exit(0); + cmd += "RUN "+get_progname(); + exit(cmd); + } + else { + exit(0); + } + } + } +//--- main ----------------------------------------------------------------------- + +if (!board) { + dlgMessageBox(usage + "


ERROR: No board!

\nThis program can only work in the board editor."); + exit(1); + } + +dlgDialog("Renumber Components") { + dlgHBoxLayout { + dlgGroup("Unit") { + dlgRadioButton("&inch", unit); + dlgRadioButton("&mm", unit); + } + dlgGroup("Direction") { + dlgRadioButton("&Horizontal", dir); + dlgRadioButton("&Vertical", dir); + } + dlgGroup("Top Side: Start from") { + dlgGridLayout { + dlgCell(0, 0) dlgRadioButton("Top left", c_top); + dlgCell(0, 3) dlgRadioButton("Top right", c_top); + dlgCell(3, 0) dlgRadioButton("Bottom left ", c_top); + dlgCell(3, 3) dlgRadioButton("Bottom right", c_top); + } + } + dlgGroup("Bottom Side: Start from") { + dlgGridLayout { + dlgCell(0, 0) dlgRadioButton("Top left", c_bottom); + dlgCell(0, 3) dlgRadioButton("Top right", c_bottom); + dlgCell(3, 0) dlgRadioButton("Bottom left ", c_bottom); + dlgCell(3, 3) dlgRadioButton("Bottom right", c_bottom); + } + } + } +dlgHBoxLayout { + dlgRealEdit(window, 0.0, 99.0); + dlgLabel("Scan &window "); + dlgIntEdit(sequence_bottom, 0, 1000); + dlgLabel("Bottom suffix "); + dlgCheckBox("&Show scripts ", show_script); + dlgStretch(1); + } + dlgSpacing(30); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("&View names") view_names(); + dlgPushButton("+&Preview") { get_data(); + check_names(); + preview(); + } + dlgPushButton("&Renumber") { get_data(); + check_names(); + renumber(); + } + dlgPushButton("-&Quit") dlgReject(); + dlgSpacing(30); + dlgPushButton("&Help") DisplayHelp(); + } + }; diff --git a/trunk/ulp/cmd-showzoom.ulp b/trunk/ulp/cmd-showzoom.ulp new file mode 100644 index 00000000..e247f5b1 --- /dev/null +++ b/trunk/ulp/cmd-showzoom.ulp @@ -0,0 +1,91 @@ +#usage "Show object and zoom in\n" + "

" + "Implemented for parts and signals on a board. " + "Could be extended for schematics." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string h, cmd = "", sname = ""; +real x, y, zoom_win = 10; +int part = 1, xmin, xmax, ymin, ymax, found = 0; + +zoom_win = zoom_win/2; + +if (board) board(B) { + cmd = "grid mm finest;\n"; + int Result = dlgDialog("Show and zoom in") { + dlgHBoxLayout { + dlgGroup("Include") { + dlgRadioButton("&Signals", part); + dlgRadioButton("&Parts", part); + } + } + dlgLabel("&Enter Name"); + dlgStringEdit(sname); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; + if (Result == 0) exit (0); + + if (!part) { // if signals checked + B.signals(S) { + if (strupr(sname)==strupr(S.name)) { + found = 1; + S.wires(W) { + xmin = min(W.x1, W.x2); + ymin = min(W.y1, W.y2); + xmax = max(W.x1, W.x2); + ymax = max(W.y1, W.y2); + break; + } + S.wires(W) { + xmin = min(xmin, W.x1); + xmin = min(xmin, W.x2); + ymin = min(ymin, W.y1); + ymin = min(ymin, W.y2); + xmax = max(xmax, W.x1); + xmax = max(xmax, W.x2); + ymax = max(ymax, W.y1); + ymax = max(ymax, W.y2); + } + xmin = u2mm(xmin); + xmax = u2mm(xmax); + ymin = u2mm(ymin); + ymax = u2mm(ymax); + } + } + h = ""; + sprintf(h, "Window (%f %f)(%f %f);\n", + xmin-zoom_win, ymin-zoom_win, xmax+zoom_win, ymax+zoom_win); + } + + if (part) { // if parts checked + B.elements(E) { + if (strupr(sname)==strupr(E.name)) { + found = 1; + x = u2mm(E.x); + y = u2mm(E.y); + } + } + h = ""; + sprintf(h, "Window (%f %f)(%f %f);\n", + x-zoom_win, y-zoom_win, x+zoom_win, y+zoom_win); + } + + if (!found) { + dlgMessageBox("Name not found!", "&OK"); + exit(1); + } + cmd += h; + cmd += "Show " + sname + ";\n"; + cmd += "grid last;\n"; + exit(cmd); + } +else { + dlgMessageBox("No board loaded!"); + exit(1); + } diff --git a/trunk/ulp/cmd-snap-board.ulp b/trunk/ulp/cmd-snap-board.ulp new file mode 100644 index 00000000..b649dd39 --- /dev/null +++ b/trunk/ulp/cmd-snap-board.ulp @@ -0,0 +1,246 @@ +#usage "Snap objects in a board\n" + "

" + "Snaps components, wires and vias of the current " + "board to a given grid. " + "If 'Show script' is checked, you can edit the MOVE commands " + "before they are executed. So you are able to exclude certain " + "elements from the snap procedure." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string Version = "Version 1.1"; // 2009-01-28 move step by step + // 1. Packages + // 2. Vias + // 3. Wires alf@cadsoft.de + +real GridDist = 25.0; +enum { unitINCH, unitMIL, unitMM, unitMIC }; +string h, cmd = ""; +int unit = unitMIL; // predefined unit, can be changed to unitMM, unitINCH, unitMIC +int Result; +string Status = ""; +string script_name; + +int cntm = 0; // count unsnaped + +int n = 0, x[], y[], l[], UsedLayers[]; + + +real u2unit(int u) { + if (unit == unitMIL) return u2mil(u); + if (unit == unitMM) return u2mm(u); + if (unit == unitINCH) return u2inch(u); + if (unit == unitMIC) return u2mic(u); +} + + +real snap(int n) { // returns next grid point + return round(u2unit(n) / GridDist) * GridDist; +} + + +int isNew(int X, int Y, int L) { + for (int i = 0; i < n; i++) { + if (x[i] == X && y[i] == Y && (l[i] == L || l[i] == LAYER_VIAS )) return 0; + } + return 1; +} + + +void Move(int Layer) { + if (UsedLayers[Layer]) { + sprintf(h, "DISPLAY NONE %d;\n", Layer); + cmd += h; + // Snap the signal wires and vias: + for (int i = 0; i < n; i++) { + if (l[i] == Layer && (u2unit(x[i]) != snap(x[i]) || u2unit(y[i]) != snap(y[i]))) { + sprintf(h, "MOVE (%f %f) (%f %f);\n", u2unit(x[i]), u2unit(y[i]), snap(x[i]), snap(y[i])); + cmd += h; + cntm++; + } + } + } + return; +} + +real check_coord(int x, int y) { + real v1, v2; + v1 = snap(x) - u2unit(x); + v2 = snap(y) - u2unit(y); + if (v1) return v1; + else if(v2) return v2; + else return 0; +} + + +void snap_to_grid(void) { + board(B) { + script_name = filesetext(B.name, "~snap.scr"); + // Remember the active layers: + int ActiveLayers[]; + B.layers(L) { + ActiveLayers[L.number] = L.visible; + } + if (unit == unitMIL) { + sprintf(h, "GRID MIL FINEST;\n"); + cmd += h; + } + if (unit == unitMM) { + sprintf(h, "GRID MM FINEST;\n"); + cmd += h; + } + if (unit == unitINCH) { + sprintf(h, "GRID INCH FINEST;\n"); + cmd += h; + } + if (unit == unitMIC) { + sprintf(h, "GRID MIC FINEST;\n"); + cmd += h; + } + sprintf(h, "SET OPTIMIZING OFF;\n"); // 2009-01-28 + cmd += h; + if (!argv[1]) { // 1. snap elements + // Snap the elements: + B.elements(E) { + status("Element: "+E.name); + if (u2unit(E.x) != snap(E.x) || u2unit(E.y) != snap(E.y)) { + sprintf(h, "MOVE %s (%f %f);\n", E.name, snap(E.x), snap(E.y)); + cmd += h; + cntm++; + } + } + } + // snap check vias + if (argv[1] == "V") { // 2. snap vias + // Collect all (unique!) signal via coordinates: + B.signals(S) { + status("Signal: "+S.name); + S.vias(V) { + UsedLayers[LAYER_VIAS] = 1; + x[n] = V.x; + y[n] = V.y; + l[n] = LAYER_VIAS; + if(check_coord(V.x, V.y)) n++; + } + } + } + if (argv[1] == "E" && n) { + cmd = ""; + for (int vn = 0; vn < n; vn++) { + sprintf(h, "(%.4f %.4f);\n", u2unit(x[vn]), u2unit(y[vn]) ); + } + cmd+=h; + sprintf(h, "Kann %d VIAs nicht snapen\n", n); + dlgMessageBox(h+cmd, "OK"); + exit(-1); + } + // snap check wires + if (argv[1] == "W") { // 3. snap wires + // Collect all (unique!) signal wire coordinates: + B.signals(S) { + status("Signal: "+S.name); + S.wires(W) { + UsedLayers[W.layer] = 1; + if (isNew(W.x1, W.y1, W.layer)) { + x[n] = W.x1; + y[n] = W.y1; + l[n] = W.layer; + if (check_coord(W.x1, W.y1)) n++; + } + if (isNew(W.x2, W.y2, W.layer)) { + x[n] = W.x2; + y[n] = W.y2; + l[n] = W.layer; + if (check_coord(W.x2, W.y2)) n++; + } + } + } + } + + // Go through the used layers (this avoids problems with wires on different + // layers that are selected at the same coordinates): + for (int u = LAYER_TOP; u <= LAYER_BOTTOM; u++) { + Move(u); + } + Move(LAYER_VIAS); + + // Reactivate the active layers: + sprintf(h, "DISPLAY"); + cmd += h; + for (int j = 1; j < 256; j++) { + if (ActiveLayers[j]) { + sprintf(h, " %d", j); + cmd += h; + } + } + sprintf(h, ";\n"); + cmd += h; + if (!argv[1]) { + sprintf(h, "RUN '%s' 'V' %d %.4f;\n", argv[0], unit, GridDist); + } + else if (argv[1] == "V") { + sprintf(h, "RUN '%s' 'W' %d %.4f;\n", argv[0], unit, GridDist); + } + else if (argv[1] == "W") { + sprintf(h, "RUN '%s' 'E' %d %.4f;\n", argv[0], unit, GridDist); + } + else if (argv[1] == "E") { + exit(0); + } + } + return; +} + + +//---- main ---------------------------------------------------------------------- + +if (!board) { + dlgMessageBox(usage + "


ERROR: No board!

\nThis program can only work in the board editor."); + exit(1); +} + +if (argc == 4) { + unit = strtol(argv[2]); + GridDist = strtod(argv[3]); + snap_to_grid(); +} + +else { + dlgDialog("Snap Packages/Wires/Vias") { + dlgHBoxLayout { + dlgHBoxLayout { + dlgGroup("Unit") { + dlgRadioButton("&inch", unit); + dlgRadioButton("&mil", unit); + dlgRadioButton("&mm", unit); + dlgRadioButton("&mic", unit); + dlgSpacing(20); + dlgLabel("Snap grid "); + dlgRealEdit(GridDist, 0.0001, 1000); + } + } + dlgSpacing(10); + dlgVBoxLayout { + dlgSpacing(10); + dlgLabel(Status, 1); + dlgHBoxLayout { + dlgPushButton("+&Snap") { + Status = "Busy..."; + dlgRedisplay(); + snap_to_grid(); + dlgAccept(); + } + dlgPushButton("-&Cancel") exit(0); + } + dlgSpacing(7); + } + } + }; +} + +output(script_name, "wtD") printf(cmd); +string s; +sprintf(s, "SCRIPT '%s'\n;GRID LAST;\n%s;\n", script_name, h); +exit(s); diff --git a/trunk/ulp/cmd-snappads.ulp b/trunk/ulp/cmd-snappads.ulp new file mode 100644 index 00000000..0a7810a9 --- /dev/null +++ b/trunk/ulp/cmd-snappads.ulp @@ -0,0 +1,153 @@ +#usage "Snap pads and smds in a package\n" + "

" + "Snaps pads and SMDs in the package editor to a given grid " + "(different grids in x and y direction selectable)." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string h, cmd; +real GridDistH = 50.0, GridDistV = 50.0; +enum {unitINCH, unitMIL, unitMM, unitMIC}; +int unit = unitMIL; // predefined unit, can be changed to unitMM, unitINCH, unitMIC +int show_script; +int Result; +int sym = 1; +int version_4_0 = 0; + +// get project path, if in board or schematic, otherwise library path +string get_project_path() { +string s = "", p = "";; + if (library) { library(L) s = L.name;} + if (board) { board(B) s = B.name;} + if (schematic){ schematic(S) s = S.name;} + char c = '/'; + int pos = strrchr(s, c); + if (pos >= 0) { + p = strsub(s, 0, pos + 1); + } + return p; +} + +real u2unit(int u) { + if (unit == unitMIL) return u2mil(u); + if (unit == unitMM) return u2mm(u); + if (unit == unitINCH) return u2inch(u); + if (unit == unitMIC) return u2mic(u); +} + +real snapH(int n) { // returns next grid point + return round(u2unit(n) / GridDistH) * GridDistH; +} + +real snapV(int n) { // returns next grid point + return round(u2unit(n) / GridDistV) * GridDistV; +} + +void snappads(void) { + + if (unit == unitMIL) {h = ""; sprintf(h, "GRID MIL FINEST;\n"); cmd += h;} + if (unit == unitMM) {h = ""; sprintf(h, "GRID MM FINEST;\n"); cmd += h;} + if (unit == unitINCH) {h = ""; sprintf(h, "GRID INCH FINEST;\n"); cmd += h;} + if (unit == unitMIC) {h = ""; sprintf(h, "GRID MIC FINEST;\n"); cmd += h;} + h = ""; sprintf(h, "DISPLAY NONE TOP PADS;\n"); cmd += h; + + library(L) { + if (package) package(PAC) { + PAC.contacts(C) { + h = ""; + sprintf(h, "MOVE (%f %f) (%f %f);\n", u2unit(C.x), u2unit(C.y), snapH(C.x), snapV(C.y)); + cmd += h; + } + } + else { + dlgMessageBox("No package loaded!", "OK"); + } + } + h = ""; sprintf(h, "GRID LAST;\n"); cmd += h; + +/* left for test purposes + dlgDialog("Edit Commands") { + dlgVBoxLayout { + dlgLabel("Edit only if you are sure what you do!"); + dlgTextEdit(cmd); + dlgPushButton("+Ok") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; +*/ + +if (!version_4_0) { + exit(cmd); + } +else { + output(get_project_path()+"$$$.scr", "wt") printf("%s", cmd); + exit("SCRIPT '"+get_project_path()+"$$$.scr';\n"); + } +} + + +//------- main ----------- + +if ((EAGLE_VERSION == 4 && EAGLE_RELEASE == 0) || (EAGLE_VERSION == 3 && EAGLE_RELEASE >96)) + version_4_0 = 1; // used for workaround + +if (!library) { + dlgMessageBox(usage + "


ERROR: No package!

\nThis program can only work in the package editor."); + exit(1); + } + +library(L) { + if (package) package(PAC) { + } + else { + dlgMessageBox("No package loaded!", "OK"); + exit(1); + } + } + +while (1) { +dlgDialog("Snap") { + dlgHBoxLayout { + dlgHBoxLayout { + dlgGroup("Unit") { + dlgRadioButton("&inch", unit); + dlgRadioButton("&mil", unit); + dlgRadioButton("&mm", unit); + dlgRadioButton("&mic", unit); + dlgSpacing(20); + dlgLabel("Snap grid horizontal"); + dlgRealEdit(GridDistH, 0.0001, 1000); + if (!sym) { + dlgLabel("Snap grid vertical"); + dlgRealEdit(GridDistV, 0.0001, 1000); + } + } + } + dlgSpacing(10); + dlgVBoxLayout { + dlgSpacing(110); + if (!sym)dlgSpacing(35); + dlgHBoxLayout { + if (sym) { + dlgPushButton("Two Grids ") {sym = 0; + GridDistV = GridDistH; + dlgAccept(); + } + } + else { + + dlgPushButton("One Grid ") {sym = 1; + dlgAccept(); + } + } + dlgPushButton("+&Snap") {if (sym) GridDistV = GridDistH; + snappads(); + } + dlgPushButton("-&Cancel") exit(0); + } + } + } + }; +} diff --git a/trunk/ulp/connect-device-split-symbol.ulp b/trunk/ulp/connect-device-split-symbol.ulp new file mode 100644 index 00000000..46175681 --- /dev/null +++ b/trunk/ulp/connect-device-split-symbol.ulp @@ -0,0 +1,307 @@ +#usage "en: This ULP generates the CONNECT list for a new Device

" + "consisting of several Symbols (Gates), " + "which have been extracted from one big Symbol by GROUP CUT and PASTE.

" + "Example:
" + "It is possible to generate a Device with Symbol and Package from a BSDL or a text file (spreadsheet) with " + "the help of RUN make-symbol-device-package-bsdl. In case the Symbol becomes too big and does not " + "fit onto a single schematic sheet due to the number of pins, you can divide it into several smaller Symbols with " + "the commands GROUP, CUT, EDIT xx.sym, PASTE and so on. With the help of this ULP you can adopt the Connect " + "list from the 'original Device'.

" + "Please note:
" + "There must not be pins with same names. So it is impossible to use this ULP for Devices that consist of " + "several identical Symbols (gates like NAND or OP-AMP..).
" + "The chosen Package variant will be generated in the current Device. If this variant already exists, the " + "Connect list will be checked. If there are already connects between pins and pads, the ULP will exit with an error message. " + "

" + "librarian@cadsoft.de" + , + "de: Dieses ULP erstellt die CONNECT-Liste für ein neues Device

" + "aus mehreren Symbolen (Gates), " + "die mithilfe von GROUP CUT und PASTE aus einem großen Symbol entnommen wurden.

" + "Beispiel:
" + "Mit RUN make-symbol-device-package-bsdl kann mit einer BSDL- oder Textdatei (Tabelle) ein Device mit Symbol " + "und Package generiert werden. Falls das Symbol durch die Anzahl der Pins zu groß wird, " + "um es im Schaltplan auf eine Seite zu platzieren, kann mit GROUP - CUT - EDIT xx.sym - PASTE .... das Symbol in " + "mehrere kleinere Symbole aufgeteilt und mithilfe dieses ULPs die Connect-Liste vom 'Original-Device' übernommen werden.

" + "ACHTUNG:
" + "Es dürfen keine Pin-Namen doppelt vorkommen. So ist es z.B. nicht möglich dieses ULP für ein Device, das aus mehreren gleichen " + "Symbolen (Gates wie NAND oder OP-AMP) besteht, zu benutzen.
" + "Die gewählte Package-Variante wird im aktuellen Device erzeugt. Sollte die Variante schon vorhanden sein " + "wird die Connect-Liste überprüft. Sind Connects zwischen Pins und Pads vorhanden, so wird das ULP mit einer Fehlernummer beendet." + "

" + "librarian@cadsoft.de" + + + +string Version = "1.02"; // 1.00 - 2006.12.01 alf@cadsoft.de + // 1.01 - 2007.08.07 Abfrage der selektierten Variante darf nicht negativ sein. + // überprüft die Connectliste falls die Package-Variate schon angelegt ist + // 1.02 - 2008.04.24 Hinweis zum selektieren durch doppelklick + +string listv1 = "Select a &Device to get Connect list"; +string listv2 = "Select a Package &Variant"; +string listv3 = "double click in list"; +string listv4 = " "; + +if (language() == "de") { + listv1 = "Wählen Sie ein &Device für die Connectliste"; + listv2 = "Wählen Sie eine Package &Variante"; + listv3 = "doppelklick in Liste"; + listv4 = " "; +} + +string DeviceVariant, Pin_Name[], Pad_Name[]; +string DeviceSet; +string Device_Sets[]; +string Variant[]; +string Package[]; +string Device_Variant[], Device_Package[]; +int cntD = 0; +int cntConnect = 0; + +string actualpackage = " "; + +string cmd; +string DeviceDescription; + +string replacenewline(string nl) { + string a[]; + int n = strsplit(a, nl, '\n'); + if (n > 0) { + nl = ""; + for (int x = 0; x < n - 1; x++) { + nl += a[x] + "\\n"; + } + nl += a[x]; + } + return "'" + nl + "'"; +} + + +string checkVariant(string s) { + if (s == "''") s = "''''"; + return s; +} + + +void getPackage(int x) { + actualpackage = Device_Package[x]+".PAC"; + return; +} + + +void getVariant(int x) { + string p[], v[]; + int cnt; + cnt = strsplit(p, Package[x], ' '); + cnt = strsplit(v, Variant[x], ' '); + for (int n = 0; n < cnt; n++) { + Device_Variant[n] = v[n]; + Device_Package[n] = p[n]; + } + return; +} + + +string getPadName(string name) { + for (int n = 0; n < cntConnect; n++) { + if (name == Pin_Name[n]) return Pad_Name[n]; + } + return ""; +} + + +if (library) { + string file; + if (deviceset) { + deviceset(DEV) { + DeviceSet = DEV.name; + DEV.devices(D) { + cntConnect = 0; + D.gates(G) { + G.symbol.pins(P) { + cntConnect++; // count all pins + } + } + } + } + if (!cntConnect) { + if (language() == "de") { + dlgMessageBox("!Dieses Deviceset besitzt kein(e) Symbol(e)", "OK"); + } + else { + dlgMessageBox("!This Device set has no Symbol(s)", "OK"); + } + exit(0); + } + + int selD = -1; + int selV = -1; + library(L) { + L.devicesets(DEV) { // collect only devicesets with the same counts of connects as the actual deviceset + int cntC; + if (DEV.name != DeviceSet) { + DEV.devices(D) { + cntC = 0; + D.gates(G) { + G.symbol.pins(P) cntC++; + } + if (cntC == cntConnect) { + Device_Sets[cntD] = DEV.name; + Variant[cntD] += D.name + " "; // Package Variant + Package[cntD] += D.package.name + " "; + } + else { +// only for test / nur zum test +// sprintf(cmd , "%d Connects in %s : %d connects in %s", cntC, DEV.name, cntConnect, DeviceSet); +// if (dlgMessageBox(cmd, "OK", "esc") != 0) exit(-99); + } + } + if (cntC == cntConnect) cntD++; + } + } + string use_Device; + int listsel = 0; + string infodev; + sprintf(infodev, "%d Devivces found with %d connects", cntD, cntConnect); + do { + int RESULT = dlgDialog(filename(argv[0])) { + dlgHBoxLayout { + dlgLabel(DeviceSet+".DEV"); + //dlgLabel(" Variant:"+DeviceVariant); + } + dlgSpacing(8); + + dlgHBoxLayout { + dlgGridLayout { + dlgCell(0, 1) dlgLabel(listv1); + dlgCell(1, 1) dlgListView("Device", Device_Sets, selD, listsel) { + getVariant(selD); actualpackage = " "; + if (language() == "de") actualpackage = "doppelklick in Liste"; + else actualpackage = "double click in list"; + listv3 = " "; + } + dlgCell(0, 2) dlgSpacing(12); + dlgCell(0, 3) dlgLabel("Select a Package &Variant") ; + dlgCell(1, 3) dlgListView("Variant", Device_Variant, selV) getPackage(selV); + dlgCell(2, 1) dlgLabel(listv3, 1); + dlgCell(2, 3) dlgLabel(actualpackage, 1); + } + dlgStretch(1); + } + dlgLabel(infodev); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgPushButton("&Help") dlgMessageBox(usage); + } + }; + if (!RESULT) exit(0); + + if (selD < 0) { + if (language() == "de") { + dlgMessageBox("Kein DEVICE gewählt!", "OK"); + } + else { + dlgMessageBox("No DEVICE selected!", "OK"); + } + } + else { + // 2007.08.03 + if (selV < 0) { + if (language() == "de") { + dlgMessageBox("!Keine Variante gewählt.\nWählen Sie eine Variante.\nDurch doppelklick auf das Device wird die Spalte Variant angezeigt.", "OK"); + } + else { + dlgMessageBox("No package variant selected!\nTo display the variant colomn, select a Device with a double mouse click first.", "OK"); + } + } + } + } while (selD < 0 || selV < 0); + } + library(L) { + file = filesetext(L.name, "~connect.scr"); + L.devicesets(DEV) { + if (DEV.name == Device_Sets[selD]) { + DEV.devices(D) { + if (D.name == Device_Variant[selV]) { + int n = 0; + D.gates(G) { + G.symbol.pins(P) { + Pin_Name[n] = P.name; + Pad_Name[n] = P.contact.name; + n++; + } + } + } + } + DeviceDescription = DEV.description; + } + } + } + deviceset(DEV) { + int variant_not_used = 1; + int variant_exist = 0; + DEV.devices(D) { + if (D.name == Device_Variant[selV]) { + if (D.package) { // 2007.08.06 + variant_exist = 1; + D.gates(G) { + G.symbol.pins(P) { + if (P.contact) { + variant_not_used = 0; + break; + } + } + } + } + + if (variant_not_used == 0) { + string h; + if (language() == "de") { + sprintf(h, "Package-Variante %s
schon vorhanden und connected.
Benutzen Sie eine noch nicht vorhandene Variante in der Quelle,
oder löschen Sie die Variante im aktuellen Device!", D.name); + } + else { + sprintf(h, "Package-Variant %s
is already defined and connected.
Choose a a new variant in the source or delete this variant in the current Device.", D.name); + } + dlgMessageBox(h, "OK"); + exit(-1); + } + } + } + if (variant_not_used) { + output(file, "wtD") { + DEV.devices(D) { + if (!variant_exist) printf("PACKAGE %s %s;\n", Device_Package[selV], Device_Variant[selV]); + D.gates(G) { + G.symbol.pins(P) { + string pad = getPadName(P.name); + if (language() == "de") { + if (!pad) dlgMessageBox("Kein PAD gefunden für "+ P.name +"\nÜberprüfen Sie die Pinnamen der Symbole", "OK"); + } + else { + if (!pad) dlgMessageBox("No PAD found for "+ P.name +"\nCheck the Pin names of the Symbols", "OK"); + } + printf("CONNECT '%s.%s' '%s';\n", G.name, P.name, pad); // 2007.08.6 *** Namen in ' ' wegen Kommentarzeichen in Scripten "#" + } + } + string t[]; + printf("DESCRIPTION %s;\n", replacenewline(DeviceDescription+"
Connect-List generated from "+ Device_Sets[selD] +".DEV Variant "+ checkVariant(Device_Variant[selV]) +" with "+ filename(argv[0])+"")); + } + printf("WIN FIT;\n"); + } + exit("SCRIPT '"+ file + "';\n"); + } + } + } + else { + if (language() == "de") { + dlgMessageBox("Öffnen Sie ein Device.", "OK"); + } + else { + dlgMessageBox("Edit a Device.", "OK"); + } + } +} + +else dlgMessageBox("Start this ULP in a LBR (Device)", "OK"); diff --git a/trunk/ulp/copy-attribute-at-deviceset.ulp b/trunk/ulp/copy-attribute-at-deviceset.ulp new file mode 100644 index 00000000..09a1e742 --- /dev/null +++ b/trunk/ulp/copy-attribute-at-deviceset.ulp @@ -0,0 +1,87 @@ +#usage "Kopiere die Attribute der Devices in alle Package-Varianten, und benenne die 1. Variante um zu ''

" + "In den (Connect) Scripten von LT werden Package-Varianten angelegt, aber nur die erste " + "erhält die Attribute aus der importierten *.asy.
" + "In den Beispielschaltplänen, wird keine Package-Variante angegeben, deshalb muß ein Device im Deviceset " + "ein neutrales sein!
" + "Package-Variante == ''
" + "Author alf@cadsoft.de" + + +string Version = "1.0.0"; // 2012-10-05 alf@cadsoft.de +string Dev_AttributtesName[]; +string Dev_AttributtesValue[]; +int cntAttr = 0; + +string Cmd = ""; +string s; + +string checkname(string s) { + if (s == "''") return ""; + return s; +} + +void loopdeviceset(UL_DEVICESET DEV) { + int n; + DEV.devices(D) { + int numofattr = 0; + string t[]; + n = strsplit(t, D.technologies, ' '); + for (int i = 0; i < n; i++) { + D.attributes(A, t[i]) { + numofattr++; + } + } + if (numofattr > cntAttr) { + cntAttr = 0; + n = strsplit(t, D.technologies, ' '); + for (int i = 0; i < n; i++) { + D.attributes(A, t[i]) { + Dev_AttributtesName[cntAttr] = A.name; + Dev_AttributtesValue[cntAttr] = A.value; + cntAttr++; + } + } + } + } + int dcnt = 0; + DEV.devices(D) { + sprintf(s, "PACKAGE '%s';\n", checkname(D.name)); + Cmd += s; + sprintf(s, "TECHNOLOGY '';\n"); + Cmd += s; + for (n = 0; n < cntAttr; n++) { + sprintf(s, "ATTRIBUTE %s '%s';\n", Dev_AttributtesName[n], Dev_AttributtesValue[n]); + Cmd+= s; + } + if (!dcnt) { + string pacnam = checkname(D.name); + if (pacnam) { + sprintf(s, "PACKAGE -%s '''''';\n", pacnam); + Cmd+=s; + } + dcnt++; + } + } + return; +} + + +if (deviceset && !argv[1]) { + Cmd = ""; + deviceset(DEV) { + loopdeviceset(DEV); + } + //dlgMessageBox(Cmd, "ok"); + exit(Cmd); +} + +else if (library || deviceset && argv[1] == "/ALL") { + Cmd = ""; + library(L) L.devicesets(DEV) { + sprintf(s, "EDIT %s.DEV;\n", DEV.name); + Cmd+=s; + loopdeviceset(DEV); + //if (dlgMessageBox(Cmd, "ok", "esc") != 0) exit(Cmd); + } + exit(Cmd); +} \ No newline at end of file diff --git a/trunk/ulp/copy-layer-to-any-layer.ulp b/trunk/ulp/copy-layer-to-any-layer.ulp new file mode 100644 index 00000000..b8e722f6 --- /dev/null +++ b/trunk/ulp/copy-layer-to-any-layer.ulp @@ -0,0 +1,509 @@ +#usage "Copy Wire (Polygon Wire) to any layer

" + "This ULP copies copper wire and/or polygon from layer (1 or 16) of selected signals into " + "any layer in order.

" + "If the selected layer is not a copper layer, also RECT, CIRCLE and TEXT will be copied.
" + "Use:
" + "run copy-wire-to-any-layer.ulp [signalname] [signalname]
" + "run copy-wire-to-any-layer.ulp $nameoff$
" + "run copy-wire-to-any-layer.ulp -p [signalname] [signalname]
" + "run copy-wire-to-any-layer.ulp +p [signalname] [signalname]
" + "run copy-wire-to-any-layer.ulp -p -f [signalname] [signalname]
" + "run copy-wire-to-any-layer.ulp +p +f [signalname] [signalname]
" + "$nameoff$ switches off the checking of net names

" + "Options are case sensitive.
" + "$nameoff$ copy all signals.
" + "-p copies also polygons.
" + "+p copies only polygons.
" + "-f copies only polygon contour as polygon.
" + "-f copies polygon contour and filling as wire.
" + "
" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED. + +string Version = "Version 1.5"; // 2008-04-23 check is a polygon placed + // changed menu to copy to any layer + // 2008-05-05 renamed from "copy-wire-to-solder-mask.ulp" to + // "copy-wire-to-any-layer.ulp" + // 2008-10-24 renamed to copy-layer-to-any-layer.ulp + // copy also rect, circle, text and non copper layer + // 2009-01-28 check polygon filling on orphan + // 2009-04-28 copy also not copper layer with RECT, CIRCLE, TEXT + + +int NameOff = 0; // 0 = copy by signal name + // 1 = copy without signal name (all) +int PolygonOn = 1; // copy also polygon +int onlyPolygon = 0; +int fillPolygon = 0; // copy only polygon contour or copy polygon filling as wire 2006.01.20 alf +int PolygonAsPolygon = 1; // 2009.-04-28 alf +int PolygonContours = 0; +int ploycontourleft = 0; +int cntp = 0; +string isRatsnest; +string isLayer = ""; +int isLayerNb = 0; +string toLayer = ""; + +string fromName[], toName[]; + fromName[0] = ""; + toName[0] = ""; +int fromNumber; +int toNumber; +int fcntLay = 0; +int fromlNumber[]; + +int lNumber[]; +int cntLay = 0; +int selisLayer = 0, seltoLayer = 0; + +string signals[] = { "" }; +string chsignals[] = { "" }; +int chngsig = 0; +int lastSigCh = -1; +int decs; + +int n = 1; + +string cmd; +string c; + +string Tfont[] = { "VECTOR", "PROPORTIONAL", "FIXED" }; + + +// ************************************* +int found(string fnam) { + int fnd = 0; + do { + if (chsignals[fnd] == fnam) { + return 1; + break; + } + ++fnd; + } while (chsignals[fnd]); + return 0; +} + + +int getlayernumber(string isL) { + board(B) B.layers(L) if (L.name == isL) return (L.number); + return 0; +} + + +void changeLayer(void) { + sprintf(c, "CHANGE LAYER %d;\n", toNumber); + cmd+= c; + return; +} + + +int delfromList(int selct) { + if (lastSigCh >= 0) { + lastSigCh--; + for (int r = selct; r <= lastSigCh; r++) { + chsignals[r] = chsignals[r + 1]; + } + chsignals[lastSigCh + 1] = ""; + } + return selct; +} + +void AddList (string SigName) { + int nofound = 1; + for (int r = 0; r <= lastSigCh; r++) { + if (chsignals[r] == SigName) { + nofound = 0; + break; + } + } + if (nofound) { + lastSigCh++; + if (lastSigCh > 0) { + for (int x = lastSigCh; x > 0; x--) { + chsignals[x] = chsignals[x - 1]; + } + } + chsignals[0] = SigName; + } + return; +} + + +void AddArgument(int n) { + do { + AddList(strupr(argv[n])); + n++; + } while(argv[n]); + return; +} + + +// 2009-04-28 die print funktionen +void printW(UL_WIRE W) { + if (W.layer == fromNumber) { + sprintf(c, "WIRE %.4f (%.4f %.4f) %+.1f (%.4f %.4f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), W.curve, u2mm(W.x2), u2mm(W.y2) + ); + cmd+= c; + } + return; +} + + +void printC(UL_CIRCLE C) { + if (C.layer == fromNumber) { + sprintf(c, "CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), u2mm(C.x + C.radius), u2mm(C.y) + ); + cmd+= c; + } + return; +} + + +void printR(UL_RECTANGLE R) { + if (R.layer == fromNumber) { + sprintf(c, "RECT R%.1f (%.4f %.4f) (%.4f %.4f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), u2mm(R.x2), u2mm(R.y2) + ); + cmd+= c; + } + return; +} + + +void printT(UL_TEXT T) { + if (T.layer == fromNumber) { + string Spin = ""; + if (T.spin) Spin = "S"; + sprintf(c, "CHANGE SIZE %.4f;\n", u2mm(T.size) ); + cmd+= c; + sprintf(c, "CHANGE FONT %s;\n", Tfont[T.font] ); + cmd+= c; + sprintf(c, "TEXT %sR%.1f '%s' (%.4f %.4f);\n", + Spin, + T.angle, + T.value, u2mm(T.x), u2mm(T.y) + ); + cmd+= c; + } + return; +} + + +void printP(UL_POLYGON P) { + if (PolygonAsPolygon) { + if (PolygonContours) { + int i = -1; + int active; + int first = 0; + if (ploycontourleft) i = -1; + else i = 1; + do { + active = 0; + P.contours(W, i) { + active = i; + if (first != i) { + sprintf(c, "POLYGON %.4f (%.4f %.4f) %+.1f (%.4f %.4f) \n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + cmd+=c; + first = i; + } + else { + sprintf(c, " %+.1f (%.4f %.4f) \n", + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + cmd+=c; + } + } + if (ploycontourleft) i--; + else i++; + cmd += ";\n"; // close the polygon command + + } while (active); + } + else { + int first = 1; + P.wires(W) { + if (first) { + sprintf(c, "POLYGON %.4f (%.4f %.4f) %+.1f (%.4f %.4f) \n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + cmd+=c; + first = 0; + } + else { + sprintf(c, " %+.1f (%.4f %.4f) \n", + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + cmd+=c; + } + } + cmd += ";\n"; // close the polygon command + } + } + else { + P.contours(W) printW(W); + if (fillPolygon) P.fillings(W) printW(W); + } + return; +} + + +// die Contacts werden noch nicht ausgegeben 2009-04-28 alf +void printCon(UL_CONTACT C) { + if (C.smd) { + if (C.smd.layer == fromNumber) { +// angle + } + } + else { // Pad + if (fromNumber >= 1 && fromNumber <= 16) { +// diameter[fromNumber] +// shape[fromNumber] +// angle + } + } + return; +} + + + +// alle nicht Kupferlayer ausgeben +void copy_any_layer(void) { + board(B) { + B.wires(W) printW(W); + B.circles(C) printC(C); + B.rectangles(R) printR(R); + B.texts(T) printT(T); + B.polygons(P) printP(P); + + B.elements(E) { + E.package.wires(W) printW(W); + E.package.circles(C) printC(C); + E.package.rectangles(R) printR(R); + E.package.texts(T) printT(T); + E.package.polygons(P) printP(P); + E.package.contacts(C) printCon(C); + } + } + return; +} + + +void collectlayer(void) { + board(B) B.layers(L) { + if (L.used) { + fromName[fcntLay] = L.name; + fromlNumber[fcntLay] = L.number; + fcntLay++; + fromName[fcntLay] = ""; + fromlNumber[fcntLay] = 0; + } + toName[cntLay] = L.name; + lNumber[cntLay] = L.number; + cntLay++; + toName[cntLay] = ""; + lNumber[cntLay] = 0; + } + return; +} + +void menue() { + string tempSignal0 = signals[0]; + string tempSignal1 = signals[1]; + int srt = 0; + int tempNameOff = NameOff; + string CopyAllInfo = "also without signal name"; + if (argc > 1) { + if (argv[1] == "-p" || argv[1] == "+p" || argv[1] == "$nameoff$") { + if (argv[1] == "-p") PolygonOn = 1; + if (argv[1] == "+p") onlyPolygon = 1; + if (argv[2] == "-f") fillPolygon = 0; // 2006.01.20 alf + if (argv[2] == "+f") fillPolygon = 1; + if (argv[1] == "$nameoff$") { NameOff = 1; AddArgument(2); } + else if (argv[2] == "$nameoff$") { NameOff = 1; AddArgument(3); } + else AddArgument(2); + if (argv[2] == "$nameoff$") { NameOff = 1; AddArgument(3); } + else if (argv[3] == "$nameoff$") { NameOff = 1; AddArgument(4); } + else AddArgument(3); + } + else AddArgument(1); + } + else { + string slist[]; + int Result = dlgDialog(filename(argv[0])) { + dlgHBoxLayout dlgSpacing(250); + dlgHBoxLayout { + dlgCheckBox("&Copy all ", NameOff); + dlgLabel(CopyAllInfo, 1); + dlgStretch(1); + } + dlgSpacing(10); + dlgStretch(0); + dlgLabel("&Add signal to list"); + dlgComboBox(signals, chngsig) { AddList(signals[chngsig]); dlgRedisplay();} + dlgSpacing(12); + dlgLabel("&Delete signal from list"); + dlgComboBox(chsignals, decs) decs = delfromList(decs); + dlgGroup("Polygon") { + dlgCheckBox("Copy &polygon with signal name", PolygonOn); + dlgCheckBox("Copy &only polygons", onlyPolygon); + dlgGroup("wire/poly") { + dlgHBoxLayout { + dlgRadioButton("Copy polygon as &wire",PolygonAsPolygon); + dlgRadioButton("Copy polygon &as polygon",PolygonAsPolygon); + } + } + dlgGroup("outline/inner") { + dlgHBoxLayout { + dlgRadioButton("Copy polygon defintition",PolygonContours); + dlgRadioButton("Copy polygon contours",PolygonContours); + } + } + dlgGroup("outer/inner rotation") { + dlgHBoxLayout { + dlgRadioButton("left rotation (outer) contour", ploycontourleft); + dlgRadioButton("right rotation (inner) contour", ploycontourleft); + } + } + dlgHBoxLayout { + dlgRadioButton("Copy conto&ur", fillPolygon); + dlgRadioButton("Copy &filling", fillPolygon); + } + } + dlgHBoxLayout { + dlgListView("from Layer", fromName, selisLayer, srt) { + fromNumber = getlayernumber(fromName[selisLayer]); + if (fromNumber > 16) { + tempSignal0 = signals[0]; + tempSignal1 = signals[1]; + signals[0] = "Kein Kupferlayer"; + signals[1] = ""; + tempNameOff = NameOff; + NameOff = 1; + } + else if (signals[0] = "Kein Kupferlayer") { + signals[0] = tempSignal0; + signals[1] = tempSignal1; + NameOff = tempNameOff; + } + } + dlgListView("to Layer", toName, seltoLayer, srt) toNumber = getlayernumber(toName[seltoLayer]); + dlgStretch(1); + } + dlgLabel("If you want to change the default setting, type in the appropriate layer numbers here."); + dlgHBoxLayout { + dlgIntEdit(fromNumber); + dlgIntEdit(toNumber); + dlgStretch(1); + } + dlgSpacing(10); + dlgHBoxLayout { + dlgPushButton("+OK") { + if (!fromNumber || !toNumber) dlgMessageBox("!Select a valid layer", "OK"); + else if(fromNumber == toNumber) dlgMessageBox("!Select a differnt layer from <-> to", "OK"); + else if(fromNumber <= 16 && lastSigCh < 0 && !NameOff) dlgMessageBox("!Select one or more signal(s)", "OK"); + else dlgAccept(); + } + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgLabel(Version); + dlgStretch(1); + dlgPushButton("&Help") dlgMessageBox(usage, "OK"); + } + dlgStretch(0); + }; + if (Result == 0) exit (0); + } + isLayerNb = fromNumber; // 2009-04-24 + return; +} + + +// main +if (board) board(B) { + isRatsnest = "! Start RATSNEST first!"; + int cntPoly = 0; + B.signals(S) { + S.polygons(P) { + cntPoly++; + P.fillings(F) { + isRatsnest = ""; + break; + } + if (isRatsnest) { // check a orphan 2009-01-28 alf@cadsoft.de + P.wires(W) { + sprintf(isRatsnest, "Start RATSNEST and check polygon on (%.4f %.4f) mm!", u2mm(W.x1), u2mm(W.y1) ); + dlgMessageBox(isRatsnest, "OK"); + sprintf(isRatsnest, "GRID MM;\nWIN (%.4f %.4f);\nGRID LAST;\n", u2mm(W.x1), u2mm(W.y1) ); + exit(isRatsnest); + } + } + } + } + if (cntPoly) { + if (isRatsnest) { + dlgMessageBox(isRatsnest, "OK"); + exit(0); + } + } + int s = 0; + B.signals(S) { + signals[s] = S.name; + s++; + } + collectlayer(); + menue(); + sprintf(c, "GRID MM;\nSET WIRE_BEND 2;\nSET UNDO OFF;\n"); + cmd+= c; + changeLayer(); + if (isLayerNb > 16) copy_any_layer(); + else { + B.signals(S) { + if (found(S.name) || NameOff || onlyPolygon) { + if (!onlyPolygon) { + S.wires(W) { + if (fromNumber == W.layer) printW(W); + } + } + // ##### ACHTUNG ##### + // POLYGONE die kein *echtes* SIGNAL sind, also nicht an einen PAD oder SMD angebunden sind, + // werden nicht ausgegeben, weil signals(S) nur durch echte Signale läuft. + /**************************************************************************/ + if (PolygonOn) { + S.polygons(POL) { + if (fromNumber == POL.layer) { + printP(POL); + } + } + } + } + } + } + sprintf(c, "SET UNDO ON;\nGRID LAST;\n"); + cmd+= c; +dlgDialog("test") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") { dlgReject(); exit(-1); } + dlgStretch(1); + } +}; + exit (cmd); +} +else dlgMessageBox("! Start this ULP in a Board", "OK"); diff --git a/trunk/ulp/copy-silk-screen.ulp b/trunk/ulp/copy-silk-screen.ulp new file mode 100644 index 00000000..4220cca7 --- /dev/null +++ b/trunk/ulp/copy-silk-screen.ulp @@ -0,0 +1,264 @@ +#usage "Generate a copy of Name; Value; Place and Docu layers to user defined layer.\n" + "

" + "Generates a command sequence which copies the silk placement " + "of all elements of your layout into newly generated layers (+100). " + "After running the ULP you can GROUP, CUT and PASTE your layout " + "to get an array of several boards." + "

" + "The duplicated name texts in the new layers will not be changed. " + "Please notice that you have to deactivate layers 21 - 28 and 51 - 52, if you use " + "the CAM processor for example to generate gerber data. Instead, you have to activate " + "the new layers 121 - 152. Thus you get an identical silk screen for all " + "your layouts in this array." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +int offset = 100; +int tf = 0; +int tNames = 25, bNames = 26; +int tValues = 27, bValues = 28; +int tPlace = 21, tDocu = 51; +int bPlace = 22, bDocu = 52; +string cmd = "SET UNDO_LOG OFF;\n"; // advisable for speed reasons +string h; + +void header(void) { + sprintf(h, "layer %d _tNames;\n", tNames+offset); // here you can change the new + cmd += h; + sprintf(h, "layer %d _bNames;\n", bNames+offset); // layers names + cmd += h; + sprintf(h, "layer %d _tValues;\n", tValues+offset); // here you can change the new + cmd += h; + sprintf(h, "layer %d _bValues;\n", bValues+offset); // layers names + cmd += h; + sprintf(h, "layer %d _tPlace;\n", tPlace+offset); // here you can change the new + cmd += h; + sprintf(h, "layer %d _tDocu;\n", tDocu+offset); // layers names + cmd += h; + sprintf(h, "layer %d _bPlace;\n", bPlace+offset); // here you can change the new + cmd += h; + sprintf(h, "layer %d _bDocu;\n", bDocu+offset); // layers names + cmd += h; + sprintf(h, "set color_layer %d yellow;\n", tNames+offset); // and + cmd += h; + sprintf(h, "set color_layer %d magenta;\n", bNames+offset); // colors + cmd += h; + sprintf(h, "set wire_bend 2;\n"); + cmd += h; + sprintf(h, "\nGRID mil;\n\n"); + cmd += h; +} + +void DrawWire(UL_WIRE W) { + if (W.arc) { + h = ""; sprintf(h, "Arc CCW %.3f (%.3f %.3f) (%.3f %.3f) (%.3f %.3f);\n", + u2mil(W.width), + u2mil(W.arc.x1), u2mil(W.arc.y1), + u2mil(W.arc.xc + W.arc.xc - W.arc.x1), u2mil(W.arc.yc + W.arc.yc - W.arc.y1), + u2mil(W.arc.x2), u2mil(W.arc.y2)); + } + else { + cmd += h; + sprintf(h, "WIRE %.3f (%.3f %.3f) (%.3f %.3f);\n", + u2mil(W.width), u2mil(W.x1), u2mil(W.y1), u2mil(W.x2), u2mil(W.y2) ); + } + cmd += h; +} + + + +void DrawCircle(UL_CIRCLE C) +{ + sprintf(h, "CHANGE LAYER %d;\n", C.layer + offset ); + cmd += h; + sprintf(h, "Circle %f (%f %f) (%f %f);\n", + u2mil(C.width), + u2mil(C.x), u2mil(C.y), + u2mil(C.x + C.radius), u2mil(C.y)); + cmd += h; +} + +void DrawRectangle(UL_RECTANGLE R) +{ + sprintf(h, "CHANGE LAYER %d;\n", R.layer + offset ); + cmd += h; + sprintf(h, "Rect (%f %f) (%f %f);\n", + u2mil(R.x1), u2mil(R.y1), + u2mil(R.x2), u2mil(R.y2)); + cmd += h; +} + +void DrawPolygon(UL_POLYGON PL) +{ + sprintf(h, "CHANGE LAYER %d;\n", PL.layer + offset ); + cmd += h; + sprintf(h, "Change Isolate %f;\n", u2mil(PL.isolate)); + cmd += h; + sprintf(h, "Change Spacing %f;\n", u2mil(PL.spacing)); + cmd += h; + if (PL.orphans) { + sprintf(h, "Change Orphans On;\n"); + cmd += h; + } + else { + sprintf(h, "Change Orphans Off;\n"); + cmd += h; + } + if (PL.thermals) { + sprintf(h, "Change Thermals On;\n"); + cmd += h; + } + else { + sprintf(h, "Change Thermals Off;\n"); + cmd += h; + } + if (PL.pour == POLYGON_POUR_SOLID) { + sprintf(h, "Change Pour Solid;\n"); + cmd += h; + } + else { + sprintf(h, "Change Pour Hatch;\n"); + cmd += h; + } + sprintf(h, "Polygon %f ", u2mil(PL.width)); + cmd += h; + PL.wires(W) { + sprintf(h, "(%f %f) ", u2mil(W.x1), u2mil(W.y1)); cmd += h; /*start coord.*/ + break; + }; + PL.wires(W) { + sprintf(h, " %+f (%f %f)", W.curve, u2mil(W.x2), u2mil(W.y2)); + cmd += h; + }; + sprintf(h, ";\n"); cmd += h; + return; +} + +void DrawText(UL_TEXT T) { + string mir = ""; + if(T.mirror) mir = "M"; + sprintf(h, "CHANGE LAYER %d;\n", T.layer + offset ); + cmd += h; + sprintf(h, "Change Size %5.3f;\n", u2mil(T.size)); + cmd += h; + sprintf(h, "Text '%s' %sR%1.0f (%5.3f %5.3f);\n", + T.value, mir, T.angle, u2mil(T.x), u2mil(T.y)); + cmd += h; +} + +void DrawName(UL_TEXT T) { + string mir = ""; + if(T.mirror) mir = "M"; + sprintf(h, "CHANGE LAYER %d;\n", T.layer + offset ); + cmd += h; + sprintf(h, "Change Size %5.3f;\n", u2mil(T.size)); + cmd += h; + sprintf(h, "Text '%s' %sR%1.0f (%5.3f %5.3f);\n", + T.value, mir, T.angle, u2mil(T.x), u2mil(T.y)); + cmd += h; +} + +void DrawValue(UL_TEXT T) { + string mir = ""; + if(T.mirror) mir = "M"; + sprintf(h, "CHANGE LAYER %d;\n", T.layer + offset ); + cmd += h; + sprintf(h, "Change Size %5.3f;\n", u2mil(T.size)); + cmd += h; + sprintf(h, "Text '%s' %sR%1.0f (%5.3f %5.3f);\n", + T.value, mir, T.angle, u2mil(T.x), u2mil(T.y)); + cmd += h; +} + +if (board) { + board(B) { + header(); + B.elements(E) { + E.texts(T) { + if (T.layer == 25) { + h = "";sprintf(h, "Change Layer %d;\n", tNames+offset); + cmd += h; + sprintf(h, "Change Size %5.3f;\n", u2mil(T.size)); + cmd += h; + sprintf(h, "Text '%s' R%1.0f (%5.3f %5.3f);\n", + E.name, T.angle, u2mil(T.x), u2mil(T.y)); + cmd += h; + } + else if (T.layer == 26) { + h = "";sprintf(h, "Change Layer %d;\n", bNames+offset); + cmd += h; + tf = 0; + sprintf(h, "Change Size %5.3f;\n", u2mil(T.size)); + cmd += h; + sprintf(h, "Text '%s' MR%1.0f (%5.3f %5.3f);\n", + E.name, T.angle, u2mil(T.x), u2mil(T.y)); + cmd += h; + } + else if (T.layer == 27) { + h = "";sprintf(h, "Change Layer %d;\n", tValues+offset); + cmd += h; + sprintf(h, "Change Size %5.3f;\n", u2mil(T.size)); + cmd += h; + sprintf(h, "Text '%s' R%1.0f (%5.3f %5.3f);\n", + E.value, T.angle, u2mil(T.x), u2mil(T.y)); + cmd += h; + } + else if (T.layer == 28) { + h = "";sprintf(h, "Change Layer %d;\n", bValues+offset); + cmd += h; + tf = 0; + sprintf(h, "Change Size %5.3f;\n", u2mil(T.size)); + cmd += h; + sprintf(h, "Text '%s' MR%1.0f (%5.3f %5.3f);\n", + E.value, T.angle, u2mil(T.x), u2mil(T.y)); + cmd += h; + } + else if (T.layer == 21 || T.layer == 22 || T.layer == 51 || T.layer == 52 ) { + DrawText(T); + } + } + E.package.wires(W) { + if(W.layer == 21 || W.layer == 22 || W.layer == 51 || W.layer == 52) { + sprintf(h, "CHANGE LAYER %d;\n", W.layer + offset ); + cmd += h; + DrawWire(W); + } + } + E.package.circles(C) { + if(C.layer == 21 || C.layer == 22 || C.layer == 51 || C.layer == 52) { + DrawCircle(C); + } + } + E.package.rectangles(R) { + if(R.layer == 21 || R.layer == 22 || R.layer == 51 || R.layer == 52) { + DrawRectangle(R); + } + } + E.package.polygons(PL) { + if(PL.layer == 21 || PL.layer == 22 || PL.layer == 51 || PL.layer == 52) { + DrawPolygon(PL); + } + } + } + } + cmd += "SET UNDO_LOG ON;\n"; + + // EditBox + int Result = dlgDialog("Descriptions") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+&Execute") dlgAccept(); + dlgPushButton("-&Cancel") dlgReject(); + } + }; + if (Result == 0) exit(0); + + exit(cmd); +} + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); +} diff --git a/trunk/ulp/copy-text-as-wire.ulp b/trunk/ulp/copy-text-as-wire.ulp new file mode 100644 index 00000000..ebf32b0c --- /dev/null +++ b/trunk/ulp/copy-text-as-wire.ulp @@ -0,0 +1,120 @@ +#usage "Copy text (Layer) into layer\n" + "

" + "Generates a command sequence which copies the texts-wires " + "of texts of your layout into user layer(s)." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string Version = "1.01"; +// 2006.03.07 search text in Board-Layer outside Element alf@cadsoft.de + +int is_layer = 0; +int all_layer = 0; +int to_layer = 100; +string cmd; +string h; +string scriptfile; + +int use_layer[]; + +void header(void) { + sprintf(cmd, "# Exported from %s by %s\n", scriptfile, EAGLE_SIGNATURE ); + cmd += "SET UNDO_LOG OFF;\n"; // advisable for speed reasons + cmd += "set wire_bend 2;\n"; + cmd += "GRID mm;\n"; +} + + +void text(UL_TEXT T) { + T.wires(W) { + sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mm(W.width), u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2) ); + cmd += h; + } + return; +} + +void checklayer(UL_TEXT T) { + int layer = T.layer; + if (all_layer || T.layer == is_layer) { + if(!use_layer[layer]) { + sprintf(h, "Layer %d Text%d;\n", to_layer + layer, to_layer + layer); + cmd += h; + use_layer[layer] = 1; + } + sprintf(h, "Change Layer %d;\n", to_layer + layer); + cmd += h; + text(T); + } + return; +} + +// Distance menue +int menue(void) { + int d = dlgDialog("Place Text as Wire") { + dlgLabel(usage); + dlgHBoxLayout { + dlgLabel("this &Layer"); + dlgSpacing(10); + dlgIntEdit(is_layer); + dlgSpacing(10); + dlgCheckBox("&all Layer", all_layer); + dlgStretch(1); + } + dlgHBoxLayout { + dlgLabel("Layer &offset"); + dlgIntEdit(to_layer); + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+&OK") dlgAccept(); + dlgPushButton("-&Cancel") dlgReject(); + dlgStretch(1); + } + }; + return d; +} + +if (board) board(B) { + if (!menue()) exit (0); + scriptfile = filesetext(B.name, ".scr"); + header(); + B.texts(T) { // Texts // only search in Board 2006.03.07 alf@cadsoft.de + checklayer(T); + } + B.elements(E) { + E.texts(T) { // *** smased *** + checklayer(T); + } + E.package.texts(T) { // *** non smased + checklayer(T); + } + } +} +cmd += "SET UNDO_LOG ON;\n"; +cmd += "GRID LAST;\n"; + +// EditBox +int Result = dlgDialog("Copy TEXT as wire") { + dlgHBoxLayout { + dlgTextEdit(cmd); + dlgVBoxLayout { + dlgSpacing(300); + } + } + dlgHBoxLayout { + dlgSpacing(500); + } + dlgHBoxLayout { + dlgPushButton("+&Execute") dlgAccept(); + dlgPushButton("-&Cancel") dlgReject(); + dlgStretch(1); + } + }; +if (Result == 0) exit(0); + +output(scriptfile, "wt") printf("%s", cmd); + +exit("script '" + scriptfile + "';\nREMOVE '" + scriptfile + "';\n"); diff --git a/trunk/ulp/copy-wire-to-solder-mask.ulp b/trunk/ulp/copy-wire-to-solder-mask.ulp new file mode 100644 index 00000000..9a909009 --- /dev/null +++ b/trunk/ulp/copy-wire-to-solder-mask.ulp @@ -0,0 +1,381 @@ +#usage "Copy Wire (Polygon Wire) to any layer

" + "This ULP copies copper wire and/or polygon from layer (1 or 16) of selected signals into " + "the solder stop layers or any layer in order to keep it free from solder stop layer.

" + "Use:
" + "run copy-wire-to-solder-mask.ulp [signalname] [signalname]
" + "run copy-wire-to-solder-mask.ulp $nameoff$
" + "run copy-wire-to-solder-mask.ulp -p [signalname] [signalname]
" + "run copy-wire-to-solder-mask.ulp +p [signalname] [signalname]
" + "run copy-wire-to-solder-mask.ulp -p -f [signalname] [signalname]
" + "run copy-wire-to-solder-mask.ulp +p +f [signalname] [signalname]
" + "$nameoff$ switches off the checking of net names

" + "Options are case sensitive.
" + "$nameoff$ copy all signals.
" + "-p copies also polygons.
" + "+p copies only polygons.
" + "-f copies only polygon contour as polygon.
" + "-f copies polygon contour and filling as wire.
" + "
" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED. + +string Version = "ULP-Version: 1.5"; // 2008-04-23 check is a polygon placed + // changed menu to copy to any layer + // 2009-01-28 check polygon filling on orphan alf@cadsoft.de + // 2009-04-23 check menu parameter + // 2009-06-30 correct polygon export + + +int NameOff = 0; // 0 = copy by signal name + // 1 = copy without signal name (all) +int PolygonOn = 0; // copy also polygon +int onlyPolygon = 0; +int fillPolygon = 0; // copy only polygon contour or copy polygon filling as wire 2006.01.20 alf +int Player[]; +string poly[]; +int cntp = 0; +string isRatsnest; +string isLayer = "Top/Bottom"; // default layer +int isLayerNb = 0; +string toLayer = "t/bStop"; // default do Stop-Layer +int Lused[]; // 2009-04-23 + +string signals[] = { "" }; +string chsignals[] = { "" }; +int chngsig = 0; +int lastSigCh = -1; +int decs; + +int index[]; +int x1[], y1[], x2[], y2[], layer[]; +int Wwidth[]; +int n = 1; + +string cmd; +string c; + +int nbIslayer; +int nbTolayer; + +int test = 0; // 2009-06-30 for test menu + + +// ************************************* +string check(void) { // 2009-04-23 alf@cadsoft.de + int isLfound = 0; + int toLfound = 0; + nbIslayer = strtol(isLayer); + nbTolayer = strtol(toLayer); + + if (isLayer == "Top/Bottom") isLfound = -1; + else { + board(B) B.layers(L) { + if (nbIslayer == L.number || isLayer == L.name) { + isLfound = L.number; + nbIslayer = L.number; + break; + } + } + } + if (toLayer == "t/bStop") toLfound = -1; + else { + board(B) B.layers(L) { + if (nbTolayer == L.number || toLayer == L.name) { + toLfound = L.number; + nbTolayer = L.number; + break; + } + } + } + if (isLfound == -1); + else if (!isLfound) return "!Select a available layer number or name for Copy layer."; + else if (!Lused[isLfound]) return "!Not used layer Copy layer " + isLayer + "."; + + if (toLfound == -1); + else if (!toLfound) return "!Select a available layer number or name for to layer."; + else if (!Lused[toLfound]) return "!Not used layer to layer " + toLayer + "."; + + if (!NameOff && lastSigCh < 0 ) { + return "!No signal selected"; + } + return ""; +} + + +int found(string fnam) { + int fnd = 0; + do { + if (chsignals[fnd] == fnam) { + return 1; + break; + } + ++fnd; + } while (chsignals[fnd]); + return 0; +} + + +void changeLayer(int l) { + if (toLayer == "t/bStop") { + if (l == 1) sprintf(c, "CHANGE LAYER 29;\n"); + if (l == 16) sprintf(c, "CHANGE LAYER 30;\n"); + cmd+= c; + } + if (isLayer == "Top/Bottom") { // 2009-06-30 + if (l == 1) { + sprintf(c, "CHANGE LAYER 29;\n"); + cmd+= c; + } + if (l == 16) { + sprintf(c, "CHANGE LAYER 30;\n"); + cmd+= c; + } + } + else if (l == isLayerNb) { + sprintf(c, "CHANGE LAYER %s;\n", toLayer); // 2009-04-23 + cmd+= c; + } + return; +} + + +int delfromList(int selct) { + if (lastSigCh >= 0) { + lastSigCh--; + for (int r = selct; r <= lastSigCh; r++) { + chsignals[r] = chsignals[r + 1]; + } + chsignals[lastSigCh + 1] = ""; + } + return selct; +} + + +void AddList(string SigName) { + int nofound = 1; + for (int r = 0; r <= lastSigCh; r++) { + if (chsignals[r] == SigName) { + nofound = 0; + break; + } + } + if (nofound) { + lastSigCh++; + if (lastSigCh > 0) { + for (int x = lastSigCh; x > 0; x--) { + chsignals[x] = chsignals[x - 1]; + } + } + chsignals[0] = SigName; + } + return; +} + + +void AddArgument(int n) { + do { + AddList(strupr(argv[n])); + n++; + } while(argv[n]); + return; +} + + +void menue() { + if (argc > 1) { + if (argv[1] == "-p" || argv[1] == "+p" || argv[1] == "$nameoff$") { + if (argv[1] == "-p") PolygonOn = 1; + if (argv[1] == "+p") onlyPolygon = 1; + if (argv[2] == "-f") fillPolygon = 0; // 2006.01.20 alf + if (argv[2] == "+f") fillPolygon = 1; + if (argv[1] == "$nameoff$") { NameOff = 1; AddArgument(2); } + else if (argv[2] == "$nameoff$") { NameOff = 1; AddArgument(3); } + else AddArgument(2); + if (argv[2] == "$nameoff$") { NameOff = 1; AddArgument(3); } + else if (argv[3] == "$nameoff$") { NameOff = 1; AddArgument(4); } + else AddArgument(3); + } + else AddArgument(1); + } + else { + string slist[]; + int Result = dlgDialog("Copy wire to layer") { + dlgLabel(Version); + dlgHBoxLayout dlgSpacing(250); + dlgCheckBox("Copy &all (without signal name)", NameOff); + dlgSpacing(10); + dlgStretch(0); + dlgLabel("Add &signal to list"); + dlgComboBox(signals, chngsig) { AddList(signals[chngsig]); dlgRedisplay();} + dlgSpacing(30); + dlgLabel("&Delete signal from list"); + dlgComboBox(chsignals, decs) decs = delfromList(decs); + dlgGroup("Polygon") { + dlgCheckBox("Copy &polygon with signal name", PolygonOn); + dlgCheckBox("Copy &only polygons", onlyPolygon); + dlgHBoxLayout { + dlgRadioButton("Copy only &contour", fillPolygon); + dlgRadioButton("Copy with &filling", fillPolygon); + } + } + dlgHBoxLayout { + dlgLabel("Copy &layer "); + dlgStringEdit(isLayer); + dlgLabel(" &to layer "); + dlgStringEdit(toLayer); + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+OK") { + string error = check(); // 2009-04-23 alf@cadsoft.de + if(error) dlgMessageBox(error); + else dlgAccept(); + } + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgPushButton("&Help") dlgMessageBox(usage, "OK"); + } + dlgStretch(0); + }; + if (Result == 0) exit (0); + } + isLayerNb = nbIslayer; // 2009-04-23 + return; +} + + +// main +if (board) board(B) { + B.layers(L) Lused[L.number] = L.used; + isRatsnest = "! Start RATSNEST first!"; + int cntPoly = 0; + B.signals(S) { + S.polygons(P) { + cntPoly++; + P.fillings(F) { // check if run RATSNEST + isRatsnest = ""; + break; + } + if (isRatsnest) { // check a orphan 2009-01-28 alf@cadsoft.de + P.wires(W) { + sprintf(isRatsnest, "Start RATSNEST and check polygon on (%.4f %.4f) mm!", u2mm(W.x1), u2mm(W.y1) ); + dlgMessageBox(isRatsnest, "OK"); + sprintf(isRatsnest, "GRID MM;\nWIN (%.4f %.4f);\nGRID LAST;\n", u2mm(W.x1), u2mm(W.y1) ); + exit(isRatsnest); + } + } + } + } + if (cntPoly) { + if (isRatsnest) { + dlgMessageBox(isRatsnest, "OK"); + exit(0); + } + } + int s = 0; + B.signals(S) { + signals[s] = S.name; + s++; + } + menue(); + + sprintf(c, "GRID MM;\nSET WIRE_BEND 2;\nSET UNDO OFF;\n"); + cmd+= c; + B.signals(S) { + if (found(S.name) || NameOff || onlyPolygon) { + if (!onlyPolygon) { + S.wires(W) { + if ((isLayer == "Top/Bottom" && (W.layer == 1 || W.layer == 16)) || isLayerNb == W.layer) { // 2009-04-23 alf + x1[n] = W.x1; + y1[n] = W.y1; + x2[n] = W.x2; + y2[n] = W.y2; + Wwidth[n] = W.width; + layer[n] = W.layer; + ++n; + } + } + } + if ( (PolygonOn && NameOff) || (onlyPolygon && !NameOff && found(S.name)) || (PolygonOn && !NameOff && found(S.name)) ) { + S.polygons(POL) { + if (isLayer && (POL.layer == 1 || POL.layer == 16) || isLayerNb == POL.layer) { // 2009-06-30 alf + string p; + int startx, starty; + int first = 1; + Player[cntp] = POL.layer; + POL.contours(W) { + if (first) { + first = 0; + startx = W.x1; + starty = W.y1; + sprintf(poly[cntp], "WIRE %.4f (%.4f %.4f) (%.4f %.4f)", // 2009-06-30 + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + u2mm(W.x2), u2mm(W.y2) + ); + } + else { + sprintf(p, " (%.4f %.4f)", u2mm(W.x2), u2mm(W.y2) ); + poly[cntp] += p; + if (startx == W.x2 && starty == W.y2) { + sprintf(p, " (%.4f %.4f);\n", u2mm(startx), u2mm(starty) ); + poly[cntp] += p; + cntp++; + break; + } + } + } + if (fillPolygon) { // Polygon filling with wire 2009-06-30 + POL.fillings(W) { + x1[n] = W.x1; + y1[n] = W.y1; + x2[n] = W.x2; + y2[n] = W.y2; + Wwidth[n] = W.width; + layer[n] = W.layer; + ++n; + } + } + } + } + } + } + } + sort(n, index, layer); + int dl = 0; + for (int i = 1; i < n; i++) { + if(dl != layer[index[i]]) { + dl = layer[index[i]]; + changeLayer(dl); + } + sprintf(c, "WIRE %.4f (%.4f %.4f) (%.4f %.4f);\n", u2mm(Wwidth[index[i]]), + u2mm(x1[index[i]]), u2mm(y1[index[i]]), u2mm(x2[index[i]]), u2mm(y2[index[i]]) ); + cmd+= c; + } + sort(cntp, index, Player); + for ( i = 0; i < cntp; ++i) { + if(dl != Player[index[i]]) { + dl = Player[index[i]]; + changeLayer(dl); + } + sprintf(c, "WIRE %.4f (%.4f %.4f) (%.4f %.4f);\n", u2mm(Wwidth[index[i]]), + u2mm(x1[index[i]]), u2mm(y1[index[i]]), u2mm(x2[index[i]]), u2mm(y2[index[i]]) ); + cmd+= poly[index[i]]; + } + sprintf(c, "SET UNDO ON;\nGRID LAST;\n"); + cmd+= c; + if (test) { // 2009-06-30 + dlgDialog("test") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("Cancel") { dlgReject(); exit(-9); } + } + }; + } + exit (cmd); +} + +else dlgMessageBox("! Start this ULP in a Board", "OK"); + diff --git a/trunk/ulp/count.ulp b/trunk/ulp/count.ulp new file mode 100644 index 00000000..09783682 --- /dev/null +++ b/trunk/ulp/count.ulp @@ -0,0 +1,71 @@ +#usage "Count Pads, Vias, Smds and Holes of a board\n" + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +int i, j, k, h, l, s ; +i = j = k = h = l = 0; + +if (board) { +board(B) { + B.holes(L) { + h++; + } + + B.elements(E) { + E.package.holes(H) { + h++; + } + E.package.contacts(C) { + + if (C.pad) + i++ ; + if (C.smd && (C.smd.layer == 1)) + j++ ; + if (C.smd && (C.smd.layer == 16)) + l++; + } + } + + B.signals(S) { + S.vias(V) { + k++; + } + } + +string result; + + sprintf(result, + " Number of Pads: %d\n\ + Number of Vias: %d\n\ + Number of Smds: %d\n\ + Smds in Top: %d\n\ + Smds in Bot: %d\n\ + Number of holes: %d\n\ + Total number of drills: %d", i, k, j+l, j, l, h, i+k+h); + + dlgDialog("Layout Information") { + dlgVBoxLayout { + dlgHBoxLayout { + dlgSpacing(200);} + dlgTextView(result); + dlgPushButton("+Ok") dlgAccept(); + } + }; + + string fileName ; + + fileName = dlgFileSave("Save Statistic File", filesetext(B.name, ".txt"), "*.txt"); + if (fileName == "") exit(0); + + output(fileName) { + printf("%s",result); + } + } +} + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); + } diff --git a/trunk/ulp/del-devices.ulp b/trunk/ulp/del-devices.ulp new file mode 100644 index 00000000..25f77c03 --- /dev/null +++ b/trunk/ulp/del-devices.ulp @@ -0,0 +1,44 @@ +#usage "Delete devices\n" + "

" + "To delete a number of devices, run this ULP and " + "edit the commands in the appearing editor window." + "

" + "The remaining DELETE commands will be executed after clicking the " + "EXECUTE button." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + + +if (library) { +string cmd = "", h; + +cmd += "set undo_log off;\n"; +library(L) { + L.devicesets(D) { + h = ""; + sprintf(h,"REMOVE %s.dev;\n",D.name); + cmd += h; + } + } +cmd += "set undo_log on;\n"; + +// EditBox +int Result = dlgDialog("Edit and Execute") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+Execute") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; +if (!Result) + exit(0); + +exit(cmd); +} + +else { + dlgMessageBox("\n Start this ULP in a Library \n"); + exit (0); +} diff --git a/trunk/ulp/del-empty-devices.ulp b/trunk/ulp/del-empty-devices.ulp new file mode 100644 index 00000000..9fecdb85 --- /dev/null +++ b/trunk/ulp/del-empty-devices.ulp @@ -0,0 +1,50 @@ +#usage "Delete empty devices\n" + "

" + "To delete devices without a symbol from a library, " + "run this ULP and click EXECUTE." + "

" + "Before executing the DELETE commands you can edit them " + "in the appearing editor window." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +if (library) { +int empty; +string cmd = "", h; + +cmd += "set undo_log off;\n"; +library(L) { + L.devicesets(D) { + h = ""; + empty = 1; + D.gates(G) { + empty = 0; + } + if (empty) { // device w/o gates found! + sprintf(h,"REMOVE %s.dev;\n",D.name); + cmd += h; + } + } + } +cmd += "set undo_log on;\n"; + +// EditBox +int Result = dlgDialog("Edit and Execute") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+Execute") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; +if (!Result) + exit(0); + +exit(cmd); +} + +else { + dlgMessageBox("\n Start this ULP in a Library \n"); + exit (0); +} diff --git a/trunk/ulp/del-pack-sym.ulp b/trunk/ulp/del-pack-sym.ulp new file mode 100644 index 00000000..db04da6e --- /dev/null +++ b/trunk/ulp/del-pack-sym.ulp @@ -0,0 +1,94 @@ +#usage "Delete unused packages and symbols\n" + "

" + "To delete unused packages and symbols from a library, " + "run this ULP. You can edit the commands in " + "the appearing editor window." + "

" + "The remaining DELETE commands will be executed after " + "clicking the EXECUTE button." + "

" + "Packages and Symbols in use can't be deleted. To accept those " + "messages keep the Enter key pressed until the ULP has finished." + "

" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +if (library) { +string cmd = "", h; +int Result; + +//////////////// +// Checkboxes in Dialog +int pack = 1; +int sym = 1; + +//--------------------------------------------------- +Result = dlgDialog("Delete Packages/Symbols") { + dlgHBoxLayout { + dlgStretch(0); + dlgGroup("Delete") { + dlgStretch(0); + dlgGridLayout { + dlgCell(1, 1) { dlgSpacing(30); dlgCheckBox("&Packages", pack); }; + dlgCell(2, 1) { dlgSpacing(30); dlgCheckBox("&Symbols", sym); }; + } + } + dlgStretch(0); + dlgVBoxLayout { + dlgHBoxLayout { + dlgSpacing(20); + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + dlgHBoxLayout { + dlgSpacing(20); + dlgStretch(0); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + } + dlgStretch(1); + } + dlgStretch(1); + }; +if (Result == 0) exit (0); +//--------------------------------------------------- + +cmd += "set undo_log off;\n"; +library(L) { + if (pack) { + L.packages(P) { + h = ""; + sprintf(h,"REMOVE %s.pac;\n",P.name); + cmd += h; + } + } + if (sym) { + L.symbols(S) { + h = ""; + sprintf(h,"remove %s.sym;\n",S.name); + cmd += h; + } + } + } +cmd += "set undo_log on;\n"; + +// EditBox +Result = dlgDialog("edit and execute") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+Execute") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; +if (!Result) exit(0); + +exit(cmd); +} + +else { + dlgMessageBox("\n Start this ULP in a Library \n"); + exit (0); +} diff --git a/trunk/ulp/designlink-inc.ulp b/trunk/ulp/designlink-inc.ulp new file mode 100644 index 00000000..733d3833 --- /dev/null +++ b/trunk/ulp/designlink-inc.ulp @@ -0,0 +1,872 @@ +#usage "en: DesignLink " + "

" + "This is an include ULP needed from other DesignLink ULPs.
" + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#require 5.1001 + +string DIVersion = "1.0.7"; // 2010-07-27 reduce global variables + // 2010-08-12 1.0.1 alf@cadsoft.de + // 2010-08-15 1.0.2 alf@cadsoft.de + // techpacvar() berichtigt bei benutzter Platzhalterkombination "*?". + // 2010-08-24 1.0.3 alf@cadsoft.de + // 2010-08-30 1.0.4 alf@cadsoft.de + +string DILanguage = language(); + +// For Norway the search service expects the older "no" as language, not "nb" +if (DILanguage == "nb") + DILanguage = "no"; + +string DICountry = country(); + +if (DICountry == "GB") { + // According to ISO 3166 (http://www.iso.org/iso/english_country_names_and_code_elements) + // there is no "en_UK". Computers that use "English/Great Britain" have "en_GB". + // We set DICountry to the fake value of "UK" to work around this misconception in DesignLink: + DICountry = "UK"; + } + +// Debug stuff +int DIDebug = 0; +int DIDebugXfer = 0; // Debug data transfer +string DIDbgFile = "fdl-dbg.txt"; +string DIDbgMsg; + +// Configuration from eaglerc.usr +int DIInStock = cfgget("ULP:designlink.InStock") == "1"; +int DIRoHS = cfgget("ULP:designlink.RoHS") == "1"; +string DISearchHist[]; // History of search entries + +// Detect wether search params have changed +int DIInStockBef = DIInStock, DIRoHSBef = DIRoHS; +string DISearchKeyBef; + +string DICompany = ""; // Farnell or Newark +string DICurrency; +string DISearchURL = "api.element14.com"; // Unified to one URL since May 12 +string DIImageURL; // Still old style: One of 4 locations dependent on country :-((( +string DIShoppingURL; + +int DINrProducts; // nr of downloaded products +int DINrProductsTotal; // nr of prod. in Farnell database +int DINrAccessibleProducts; // nr of prod. that can actually be downloaded +string DISearchResult; // Total result returned from PF server (XML string) +string DIProducts[]; // Products returned from PF server (array of XML strings) +numeric string DIProductList[]; // Products converted to a list for displaying (part of information) +int DISearchOffset; // Offset in query +int DINrProductsPerPage = 50; // + +// Dialog data: +int DIProductOffset; +int DINrProductsInList; +string DIHtml = ""; +string DIAdvice = ""; // Advice for user needed In some cases (shopping cart or library processing) + // displayed when no match +string DIResInfo; // Info on search results +int DIProductSel = -1; // Product currently selected + +// Dialog logics +int DIMode = 1; // to redisplay dialog +int DISkipRem; // Switch, to skip the rest of the search through schematic or library +int DICancelSearch; +int DIShow; // Show EAGLE part/device + +// EAGLE attribute names +string DIAttOCFarnell = "OC_FARNELL"; // Attribute name of Farnell order code +string DIAttOCNewark = "OC_NEWARK"; // Attribute name of Newark order code +string DIAttOC = ""; // Attribute name of order code (one of the above, set later) +string DIAttMF = "MF"; // Attribute name of manufacturer name +string DIAttMPN = "MPN"; // Attribute name of manufacturer part name +string DIUnknown = "unknown"; // Attribute value if unknown order code + +int DISearchOptPac; // Add package name to search string + +// Search types +enum { DISearchByKeyword, DISearchByOC }; + +// The central search routine SingleSearch is used in 3 different ways +// with slightly different dialog and behaviour: +// - Initial Search when walking through schematic +// - Search again after order list is displayed +// - Search through a library (library processing tool) +enum { DIModeInitSearch, DIModeNewSearch, DIModeLbrSearch }; + +// Language support for dialogs: German/English +// Please keep to alphabetic sorting for better maintainability ! +string Dictionary[] = { + "de\v" + "en\v", + "Abbrechen\v" + "Cancel\v", + "Aktualisieren\v" + "Update\v", + "allgemeine Suche\v" + "general search\v", + "Anzahl Leiterplatten:\v" + "Number of PCBs:\v", + "Anzahl Positionen: \v" + "Number of list items: \v", + "Anzahl\tValue\tPackage\tOrdercode\tHersteller\tHerstellercode\tVerfügbarkeit\tPreis (ab)\tBeschreibung\v" // 2010-08-27 Value/Package "/" zu TAB geaendert + "Quantity\tValue\tPackage\tOrder code\tManufacturer\tManuf. Code\tAvailability\tPrice (from)\tDescription\v", // 2020-08-27 Value/Package "/" zu TAB geaendert + "Attribute - Anzeigeoptionen\v" + "Attributes - Display options\v", + "Auf Lager: \v" + "In stock: \v", + "Auswählen\v" + "Select\v", + "Bauteilsuche für \v" + "part search for \v", + "Beschreibung\v" + "Description\v", + "Bestellliste exportieren\v" + "Export order list\v", + "Bestellliste für \v" + "order list for \v", + "Bitte geben Sie unten einen Suchstring ein !\v" + "Please enter a search string below !\v", + "Bitte manuell suchen oder Part überspringen !\v" + "Please search manually or skip this part !\v", + "Bitte starten Sie vom Bibliotheks-Editor aus !\v" + "Please run this tool from the library editor !\v", + "Bitte starten Sie vom Schaltplan aus !\v" + "Please start from schematic !\v", + "Bitte wälen Sie einen Listeneintrag oder überspringen Sie dieses Bauteil !\v" + "Please select a list entry or skip this part !\v", + "Beenden\v" + "Close\v", + "Besuchen Sie\v" + "Visit\v", + " DesignLink Devicesuche und -anzeige - \v" + " DesignLink Device search and display - \v", + "Deviceset\tPackage\tTechnologie\tDevicename\tOrdercode-Typ\tOrdercode\tHerstellercode\tBeschreibung\v" + "Deviceset\tPackage\tTechnology\tDevice name\tOrder code type\tOrder code\tManuf. code\tDescription\v", + "Direkt zur Bestelliste\v" + "Directly to order list\v", + "Ergebnissen\v" + "results\v", + "Erzeugung der Package-Bilder zunächst !\v" + "Generating package images first !\v", + "Exportieren\v" + "Export\v", + "Export als Textdatei\v" + "Export as text file\v", + "Fehler bei Zugriff auf\v" + "Error while accessing\v", + "Hilfe\v" + "Help\v", + "Keine Anzeige\v" + "display none\v", + "Keine Treffer.\v" + "No matches.\v", + "Keine weiteren Produkte verfügbar!\v" + "No further products available!\v", + "+Manuelle Suche\v" + "+Manual Search\v", + "Mehr als ein Artikel zu diesem Ordercode gefunden!\v" + "Found more than one item fitting order code!\v", + "Mit Ordercodes: \v" + "With order codes: \v", + "Name anzeigen\v" + "only Name\v", + "Nächste\v" + "Next\v", + "Neue Suche\v" + "New search\v", + "Ordercode\tHersteller\tHerstellercode\tVerfügbarkeit\tPreis (ab)\tBeschreibung\v" + "Order code\tManufacturer\tManuf. code\tAvailability\tPrice (from)\tDescription\v", + "Ordercode-Zuweisung - \v" + "Order code embedding - \v", + "Ordercodes speichern\v" + "Save order codes\v", + "Prüfe Preis und Verfügbarkeit: \v" + "Check price and availability: \v", + "Selektion zum Warenkorb hinzufügen\v" + "Add selection to shopping cart\v", + "Speichere Ordercodes\v" + "Saving order codes\v", + "Speichern + Beenden\v" + "Save + Close\v", + "Suche\v" + "Searching\v", + "+Suchen\v" + "+Search\v", + "Suche nach \v" + "Searching for \v", + "Treffer pro Seite\v" + "Results per page\v", + "und Include \v" + "and include \v", + "Überspringen\v" + "Skip this\v", + "Verschiedene Versionen von \v" + "Different versions of \v", + "von\v" + "of\v", + "Vorige\v" + "Previous\v", + "Vorrätig\v" + "In stock\v", + "Wert anzeigen\v" + "only Value\v", + "Wert und Name anzeigen\v" + "Value and Name\v", + "Zum Warenkorb hinzufügen\v" + "Add to shopping cart\v", + "Zur Detailansicht oder erneuten Suche der Artikel bitte diese doppelklicken !\v" + "For detail view or new search of items please doubleclick them !\v", + "Zur Detailansicht oder Suche und Zuweisung eines Artikels bitte Device doppelklicken !\v" + "For detail view or search and assignment of a product please doubleclick device !\v", + "Zurück\v" + "Back\v" +}; + +string DIDlgLang = DILanguage; +if (DIDlgLang != "de") DIDlgLang = "en"; +int DILangIdx = strstr(Dictionary[0], DIDlgLang) / 3; + +// Translate, based on Dictionary +string tr(string s) { + string t = lookup(Dictionary, s, DILangIdx, '\v'); + return t ? t : s; +} +//----------------------------------------------------------------------------- + +// product list head vor various representations +string DIProductListHead = tr("Ordercode\tHersteller\tHerstellercode\tVerfügbarkeit\tPreis (ab)\tBeschreibung"); + +/************** Functions ****************************************************/ +void InitCfg(void) { + string hist = cfgget("ULP:designlink.SearchHistory"); + strsplit(DISearchHist, hist, '\t'); +} + +void SaveCfg(void) { + cfgset("ULP:designlink.SearchHistory", strjoin(DISearchHist, '\t')); +} + +void InitCountryData(void) +{ + string CountryData[] = { + "DE EUR 0 de.farnell.com", + "AT EUR 0 at.farnell.com", + "CH CHF 0 ch.farnell.com", + "UK GBP 0 uk.farnell.com", // actually this should be GB, see above + "BE EUR 0 be.farnell.com", + "FI EUR 0 fi.farnell.com", + "FR EUR 0 fr.farnell.com", + "NL EUR 0 nl.farnell.com", + "NO NOK 0 no.farnell.com", + "SE SEK 0 se.farnell.com", + "DK DKK 0 dk.farnell.com", + "IL USD 0 il.farnell.com", + "IT EUR 0 it.farnell.com", + "ES EUR 0 es.farnell.com", + "AU AUD 2 au.element14.com", + "NZ NZD 2 nz.element14.com", + "PT EUR 0 pt.farnell.com", + "IE EUR 0 ie.farnell.com", + "SI EUR 0 si.farnell.com", + "PL PLZ 0 pl.farnell.com", + "HU HUF 0 hu.farnell.com", + "SK EUR 0 sk.farnell.com", + "IN INR 0 in.element14.com", + "BG EUR 0 bg.farnell.com", + "RO RON 0 ro.farnell.com", + "CZ CZK 0 cz.farnell.com", + "EE EUR 0 ee.farnell.com", + "LV EUR 0 lv.farnell.com", + "TR EUR 0 tr.farnell.com", + "LT EUR 0 lr.farnell.com", + "RU RUB 0 ru.farnell.com", + "CN CNY 1 cn.element14.com", + "HK HKD 2 hk.element14.com", + "SG SGD 2 sg.element14.com", + "MY MYR 2 my.element14.com", + "PH PHP 2 ph.element14.com", + "KR KRW 2 kr.element14.com", + "TW TWD 2 tw.element14.com", + "TH THB 2 th.element14.com", + "CA CAD 3 canada.newark.com", + "MX MXN 3 mexico.newark.com", + "US USD 3 www.newark.com", + "AS USD 3 www.newark.com" + }; + + string OldURLs[] = { // After unification of Farnell's search APIs to only on they left this hidden dependency :-(( + "uk.farnell.com", + "cn.element14.com", + "au.element14.com", + "www.newark.com" + }; + + string rx = "^" + DICountry; + for (int i = 0; ; i++) { + string cd = CountryData[i]; + if (!cd) + break; + if (strxstr(cd, rx) == 0) { + DICurrency = strsub(cd, 3, 3); + int u = strtol(strsub(cd, 7, 1)); + DIImageURL = OldURLs[u]; + // In case the Newark server is the one we contact, we keep to Newark order codes + // Set device/part attribute keyword accordingly + DIAttOC = (u == 3) ? DIAttOCNewark : DIAttOCFarnell; + DICompany = (u == 3) ? "Newark" : "Farnell"; + DIShoppingURL = strsub(cd, 9); + break; + } + } + if (!DICurrency || !DISearchURL) { + string Msg; + sprintf(Msg, "Country '%s' not supported.", DICountry); + dlgMessageBox(Msg); + exit(1); + } +} + +string GetDesignLinkURL(void) +{ + return "https://" + DISearchURL + "/pffind/services/SearchService"; +} + +string GetImageURL(string Image, int Large, string vrnt) +{ + return Image && vrnt ? "http://" + DIImageURL + "/productimages/" + vrnt + (Large ? "standard" : "thumbnail") + Image : ""; +} + +string GetDataSheetURL(string Url) +{ + if (Url[0] == '/') + Url = "http://" + DISearchURL + Url; + return Url; +} + +string B2Str(int b) +{ + return b ? "true" : "false"; +} + +string I2Str(int i) { + string str; + sprintf(str, "%d", i); + return str; +} + +void Clear(void) +{ + DINrProducts = DINrProductsTotal = DINrAccessibleProducts = DIProductOffset = DISearchOffset = 0; + DIProductList[0] = ""; + DIProductSel = -1; +} + +int Search(string key, int search_type) +{ + string customerID = "CadSoft2", customerPW = "CadSoft2"; // Dummy credentials + string localKey = key, offset = I2Str(DISearchOffset); + + if (search_type == DISearchByKeyword) { + // Replace special characters with according XML notation. + string StrRepl[] = { // string replacements + "&", "&", // has to be the first one! + "<", "<", + ">", ">" + }; + int o = 0; + for (int x = 0; StrRepl[x]; ) { + o = strstr(localKey, StrRepl[x], o); + if (o >= 0) { + localKey = strsub(localKey, 0, o) + StrRepl[x + 1] + strsub(localKey, o + strlen(StrRepl[x])); + o += strlen(StrRepl[x + 1]); + } + else { + x += 2; + o = 0; + } + } + // Store current user settings in Eaglerc + cfgset("ULP:designlink.InStock", DIInStock ? "1" : "0"); + cfgset("ULP:designlink.RoHS", DIRoHS ? "1" : "0"); + } + // Build the XML query string (SOAP) + string TimeStamp = t2string(time(), "Uyyyy-MM-ddThh:mm:ss.000"); + string Signature = fdlsignature(((search_type == DISearchByKeyword) ? "searchByKeyword" : "searchByPremierFarnellPartNumber") + + TimeStamp, customerPW); + string Query = "\n" + " \n" + " \n" + " " + Signature + "\n" + " " + TimeStamp + "\n" + " " + DILanguage + "_" + DICountry + "\n" + " \n" + " \n" + " " + customerID + "\n" + " \n" + " \n" + " \n"; + // Differences in the query for both cases. Rest remains the same. + if (search_type == DISearchByKeyword) + Query += " \n" + " " + localKey + "\n" + " " + offset + "\n" + " " + I2Str(DINrProductsPerPage) + "\n" + " \n" + " " + B2Str(DIInStock) + "\n" + " " + B2Str(DIRoHS) + "\n" + " \n" + " \n"; + else + Query += " \n" + " " + localKey + "\n" + " \n"; + Query += " \n" + "\n"; + + DIHtml = tr("Suche") + " " + localKey + "" + " ..."; + if (!DIMode) dlgRedisplay(); // Omit Redisplay if we are not really in a dialog context ! + if (DIDebugXfer) + output("fdlQuery.html", "wb") printf("%s", Query); + + // Here we go ! + int rv = netpost(DISearchResult, GetDesignLinkURL() + "?callinfo.apiKey=" + + strsub("sf4kqy6u29tkt95gg5a3wej" + 122 + Signature, 0, 24), Query); + + if (DIDebugXfer) + output("fdlResponse.html", "wb") printf("%s", DISearchResult); + + // Error handling + if (rv < 0) { + string FaultString = ""; + if (strlen(DISearchResult) > 1) + FaultString = xmltext(DISearchResult, "soapenv:Envelope/soapenv:Body/soapenv:Fault/faultstring"); + // This indicates that a search by OC failed. Don't treat this as an error ! + // Accessing a record with an invalid key (from outside) must not throw an exception ! + if ((search_type == DISearchByOC) && (FaultString == "SearchServiceException")) { + DISearchResult = ""; + return 1; + } + if (FaultString) + DISearchResult = FaultString; + sprintf(DIHtml, tr("Fehler bei Zugriff auf") + " '%s':\n\n%s\n\n%s", GetDesignLinkURL(), neterror(), DISearchResult); + DISearchResult = ""; + return 0; + } + return 1; +} + +int FilteredSearch(string key, int search_type) +{ + int nrUnfiltProducts; + string unfiltProducts[]; + int nrProductsTarget; + int ret = 1; + + if (DIInStock != DIInStockBef || DIRoHS != DIRoHSBef || key != DISearchKeyBef) + Clear(); + + nrProductsTarget = DIProductOffset + DINrProductsPerPage; + if (nrProductsTarget < DINrProducts) return 1; + + while ((DISearchOffset < DINrAccessibleProducts || DISearchOffset == 0) && DINrProducts < nrProductsTarget) { + ret = Search(key, search_type); + if (ret == 0 || strlen(DISearchResult) <= 1) break; + DINrProductsTotal = strtol(xmltext(DISearchResult, "soapenv:Envelope/soapenv:Body/ns1:" + + (search_type == DISearchByKeyword ? "keywordSearchReturn" : "premierFarnellPartNumberReturn") + + "/ns1:numberOfResults")); + DINrAccessibleProducts = min(500, DINrProductsTotal); + nrUnfiltProducts = xmlelements(unfiltProducts, DISearchResult, "soapenv:Envelope/soapenv:Body/ns1:" + + (search_type == DISearchByKeyword ? "keywordSearchReturn" : "premierFarnellPartNumberReturn") + + "/ns1:products"); + // Filtering + for (int i = 0; i < nrUnfiltProducts; ++i) + if (search_type != DISearchByKeyword || DICompany == "Newark" || + strtol(xmltext(unfiltProducts[i], "ns1:products/ns1:stock/ns1:status")) != -4) // Product no longer stocked + DIProducts[DINrProducts++] = unfiltProducts[i]; + + DISearchOffset += DINrProductsPerPage; + if (search_type != DISearchByKeyword) break; // No repeated search nec. because no filtering + } + // Remember settings + DIInStockBef = DIInStock; + DIRoHSBef = DIRoHS; + DISearchKeyBef = key; + return ret; +} + +void Result2List(void) +{ + if (strlen(DISearchResult) <= 1) + return; + DINrProductsInList = min(DINrProducts - DIProductOffset, DINrProductsPerPage); + DIProductList[DINrProductsInList] = ""; + for (int i = DINrProductsInList; --i >= 0; ) { + int prIdx = DIProductOffset + i; + string Prices[]; + int nrPrices = xmlelements(Prices, DIProducts[prIdx], "ns1:products/ns1:prices"); + string Price; + for (int j = nrPrices; --j >= 0; ) { + string p1 = xmltext(Prices[j], "ns1:prices/ns1:cost"); + if (p1 && (!Price || strtod(p1) < strtod(Price))) + Price = p1; + } + DIProductList[i] = + xmltext(DIProducts[prIdx], "ns1:products/ns1:sku") + "\t" + + xmltext(DIProducts[prIdx], "ns1:products/ns1:vendorName") + "\t" + // + xmltext(DIProducts[prIdx], "ns1:products/ns1:productStatus") + "\t" // Filter criterion ? + + xmltext(DIProducts[prIdx], "ns1:products/ns1:translatedManufacturerPartNumber") + "\t" + + xmltext(DIProducts[prIdx], "ns1:products/ns1:inv") + "\t" + + Price + "\t" + + xmltext(DIProducts[prIdx], "ns1:products/ns1:displayName"); + } + // Update result info + DIResInfo = ""; + if (DINrProductsInList > 0) + // Rounded or exact value, dependent on where we are + sprintf(DIResInfo, "%d - %d " + tr("von") + + (DISearchOffset >= DINrProductsTotal ? "" : " ~") + " %d " + tr("Ergebnissen"), + DIProductOffset + 1, DIProductOffset + DINrProductsInList, + DISearchOffset >= DINrProductsTotal ? DINrProducts : DINrProductsTotal/10 * 10); + DIProductSel = -2; // the first item after sort +} + +// Display HTML content. +void ShowSelection(void) +{ + int huge_quantity = 1000000; // Indicator for "or higher"... + + if (!DINrProducts) { + DIHtml = tr("Keine Treffer.") + "

\n"; + DIHtml += DIAdvice; + return; + } + if (DIProductSel < 0) + return; + + string p = DIProducts[DIProductOffset + DIProductSel]; + if (p) { + string Attributes[]; + int nAttributes = xmlelements(Attributes, p, "ns1:products/ns1:attributes"); + + string AttributeList; + for (int i = 0; i < nAttributes; ++i) + AttributeList += "

  • " + xmltext(Attributes[i], "ns1:attributes/ns1:attributeLabel") + + ": " + xmltext(Attributes[i], "ns1:attributes/ns1:attributeValue") + + xmltext(Attributes[i], "ns1:attributes/ns1:attributeUnit") + + "
  • \n"; + string PricesList; + { + string Prices[]; + int nPrices = xmlelements(Prices, p, "ns1:products/ns1:prices"); + for (int j = 0; j < nPrices; ++j) { + string Cost = xmltext(Prices[j], "ns1:prices/ns1:cost"); + if (Cost) { + string n1 = xmltext(Prices[j], "ns1:prices/ns1:from"), + n2 = xmltext(Prices[j], "ns1:prices/ns1:to"); + if (strtol(n2) >= huge_quantity) + n2 = "+"; + else + n2 = " - " + n2 + " "; + PricesList += " \n" + " " + n1 + n2 + "\n" + " " + Cost + "\n" + " \n"; + } + } + } + DIHtml = "\n" + ; + + DIHtml += "

    " + xmltext(p, "ns1:products/ns1:displayName") + "

    "; + string ImageUrl = GetImageURL(xmltext(p, "ns1:products/ns1:image/ns1:baseName"), 1, xmltext(p, "ns1:products/ns1:image/ns1:vrntPath")), + DataSheet = xmlelement(p, "ns1:products/ns1:datasheets"); + DIHtml += "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
    \n"; + if (ImageUrl) + DIHtml += + " \n"; + if (DataSheet) + DIHtml += + "

    \n" + " \n" + " " + xmltext(DataSheet, "ns1:datasheets/ns1:description") + "\n" + "

    \n"; + DIHtml += "
    \n" + "
    \n" + "
    Manufacturer:
    \n" + "
    " + xmltext(p, "ns1:products/ns1:vendorName") + "
    \n" + "
    Order Code:
    \n" + "
    " + xmltext(p, "ns1:products/ns1:sku") + "
    \n" + "
    Manufacturer Part No:
    \n" + "
    " + xmltext(p, "ns1:products/ns1:translatedManufacturerPartNumber") + "
    \n" + "
    \n" + "

    RoHS: " + xmltext(p, "ns1:products/ns1:rohsStatusCode") + "

    \n" + "
    \n" + "
    Description
    \n" + "
    \n" + "
      \n" + "
    • " + xmltext(p, "ns1:products/ns1:displayName") + "
    • \n" + + AttributeList + + "
    \n" + "
    \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
    \n" + "

    Availability

    \n" + " \n" + " \n" + " \n" + " \n" + "
    \n" + "

    \n" + " Availability: " + xmltext(p, "ns1:products/ns1:inv") + "
    \n" + "

    \n" + "

    \n" + " Price For: " + xmltext(p, "ns1:products/ns1:packSize") + " " + xmltext(p, "ns1:products/ns1:unitOfMeasure") + + "

    \n" + "

    \n" + " Minimum Order Quantity: " + xmltext(p, "ns1:products/ns1:translatedMinimumOrderQuality") + + "

    \n" + "

    \n" + " Order Multiple: " + xmltext(p, "ns1:products/ns1:translatedMinimumOrderQuality") + + "

    \n" + "
    \n" + "
    \n" + "

    Price (" + DICurrency + ")

    \n" + " \n" + " \n" + " \n" + " \n" + " \n" + + PricesList + + "
    QtyList Price
    \n" + "
    \n" + "
    \n"; + } +} + +// Only search by keyword +void DoSearch(string keyword) +{ + if (FilteredSearch(keyword, DISearchByKeyword)) { + Result2List(); + ShowSelection(); + } + // Remember settings + DIInStockBef = DIInStock; + DIRoHSBef = DIRoHS; + DISearchKeyBef = keyword; +} + +string SingleSearch(int dlg_mode, string dlg_head, string description, string image, + int start_search_mode, string singlekey, string displaykey) { + // Without treating the help text here local maintenance of it is a nightmare ! + string help[] = { + "Bauteilsuche
    " + "Gehen Sie schrittweise durch die Bauteiltypen Ihres Schaltplans und suchen " + "nach passenden Artikeln in Farnell's Produktkatalog.
    " + "Pro Bauteiltyp werden zunächst Suchergebnisse anhand des Bauteil-Value angezeigt. " + "Befindet sich ein geeigneter Farnell-Artikel darunter, können Sie diesen " + "per Button oder Doppelklick auswählen.
    " + "Wenn nicht, können Sie eine beliebige manuelle Suche starten und dann auswählen.
    " + "Nach der Auswahl gelangen Sie zum nächsten Bauteiltyp. " + "Mit Überspringen kommen Sie ohne Auswahl weiter. " + "Bauteiltypen, die anhand des Value kein Suchergebnis liefern, werden automatisch übersprungen. " + "Wenn Sie alle Bauteiltypen durchgegangen sind oder auch mit dem Button Direkt zur Bestelliste " + "gelangen Sie zur Bestellliste, von der aus Sie direkt bei Farnell ordern können. " + "Sie können Ihre Auswahl vorher noch beliebig ändern. " + "

    Hersteller-Bibliotheken mit Ordercodes
    " + "Für Bauteile aus Hersteller-Bibliotheken, die bereits mit Farnell-Ordercodes versehen sind, " + "erübrigt sich diese Suche und der entsprechende Farnell-Artikel wird automatisch in die " + "Bestellliste übernommen. " + "

    Alternative Suche mit Value und Package
    " + "Anstatt nur mit dem Bauteil-Value können Sie die automatische Suche auch mit Value und Package " + "durchführen. Sie erreichen dies, in dem Sie
    " + filename(argv[0]) + " mit der Option " + "-sop (search option package) aufrufen." + "

    Hinweis zu Internet-Verbindungseinstellungen
    " + "Falls Sie über einen Proxy auf das Internet zugreifen, passen Sie bitte die Einstellungen " + "im Control Panel unter Hilfe / Auf Update prüfen / Konfigurieren entsprechend an." + , + "Part search
    " + + "Step through the part types of your schematic and search for according articles in " + + DICompany + "'s product catalog.
    " + + "For each part type, search results fitting to the part value are displayed at first. " + + "If there's an appropriate article from " + DICompany + " among them you can choose it by button or mouse click.
    "+ + "If not, you can start an arbitrary manual search and select then.
    " + + "After selection you get to the next part type. " + + "With Skip this you proceed without a choice. " + + "Part types with no search results based on the part value are skipped automatically. " + + "After going through all part types or by pressing Directly to order list " + + "you get to the order list where you can load it to a " + DICompany + " shopping cart. " + + "You can still change your selection before." + + "

    Manufacturer libraries with order codes
    " + + "This search is not necessary for parts from manufacturer libraries with " + DICompany + " order codes. " + + "The corresponding " + DICompany + " article is taken automatically to the order list." + + "

    Alternative search by value and package
    " + + "Instead of search by part value you can do the automatic search by value and package. " + + "You achieve this by starting " + filename(argv[0]) + " with option -sop (search option package)." + "

    Hint on internet settings
    " + "If you access the internet by a proxy, please adjust the settings in the Control Panel under " + "Help / Check for Update / Configure accordingly." + }; + DIProductSel = -1; + string key = displaykey; + int ok = 1; // Wether search worked or not + + if (!((start_search_mode == DISearchByOC) && (singlekey == DIUnknown))) { // Avoid search with an unknown OC ! + ok = FilteredSearch(singlekey, start_search_mode); + Result2List(); + } + + if (DINrProducts > 0) + DIProductSel = 0; + // If it's the initial search and no products have been found don't display the dialog (and go to next item) + // The same for initial search by OC: If OC is there, everything is clear. + // Search must have worked (ok=1). Otherwise user needs to be informed ! + if (ok && (dlg_mode == DIModeInitSearch) && ((DINrProducts == 0) || (start_search_mode == DISearchByOC)) ) + return (DINrProducts == 0) ? "" : DIProductList[0]; + else { + DIMode = 0; // For displaying search message + if (ok) ShowSelection(); // Prepares Html string for display + int dlg_ret = dlgDialog(dlg_head) { + dlgVBoxLayout { + if (dlg_mode == DIModeLbrSearch) { + dlgLabel("" + tr("Suche nach ") + (DICountry == "US" ? "NEWARK" : "FARNELL") + + " Code (" + GetDesignLinkURL() + ")"); + } + dlgHBoxLayout dlgSpacing(800); + dlgHBoxLayout { + dlgTextView(DIHtml); // Gleich anzeigen... + dlgVBoxLayout dlgSpacing(400); // flines + } + dlgListView(DIProductListHead ,DIProductList, DIProductSel) + if (dlgSelectionChanged()) ShowSelection(); + else dlgAccept(); + dlgGroup(tr("Beschreibung") + " EAGLE Part/Device:") { + dlgHBoxLayout { + dlgLabel(description); + if (image) dlgLabel(image); + } + } + dlgHBoxLayout { + dlgStringEdit(key, DISearchHist, 9); + dlgPushButton(tr("+Manuelle Suche")) { + Clear(); + DoSearch(key); + } + } + dlgHBoxLayout { + dlgPushButton(tr("Auswählen")) { + if (DIProductSel < 0) dlgMessageBox( + tr("Bitte wählen Sie einen Listeneintrag oder überspringen Sie dieses Bauteil !"), "OK"); + else dlgAccept(); + } + + dlgPushButton(tr("Überspringen")) { + DIProductSel = -1; + dlgAccept(); + } + dlgStretch(1); + if (dlg_mode == DIModeLbrSearch) { + dlgPushButton(tr("Vorige")) + if (DIProductOffset > 0) { + DIProductOffset -= DINrProductsPerPage; + DoSearch(key); + } + dlgLabel(DIResInfo, 1); + dlgPushButton(tr("Nächste")) //tr ! + if (DIProductOffset + DINrProductsPerPage < DINrAccessibleProducts) { + DIProductOffset += DINrProductsPerPage; + DoSearch(key); + } + else + dlgMessageBox(tr("Keine weiteren Produkte verfügbar!")); + dlgStretch(1); + } + if (dlg_mode == DIModeInitSearch) // In case of initial search offer help + dlgPushButton(tr("Hilfe") + "...") + dlgMessageBox(help[DILangIdx]); + string button_text; + if (dlg_mode == DIModeInitSearch) button_text = tr("Direkt zur Bestelliste"); + else button_text = tr("Zurück"); + dlgPushButton(button_text) { + dlgAccept(); + if (dlg_mode == DIModeInitSearch) DISkipRem = 1; + else DICancelSearch = 1; + } + } + } + }; + DIMode = 1; // Reset + // User pressed the "x" close button: + // This means: No selection, no change of data in case of search from order list + // In case of the initial search, assume/respect that the user wants to leave DL + // Pro: He should have a possibility to leave. Otherwise he'd have to go directly to orderlist + // first (involving unintended searches) before he can close. + // Con: He may click without being aware that all his previous decisions are lost. + // This is less likely as we are not providing a close button here. + if (dlg_ret == -1) { + if (dlg_mode == DIModeInitSearch) + exit(EXIT_SUCCESS); + DIProductSel = -1; + DICancelSearch = 1; + } + return (DIProductSel < 0 ? "" : DIProductList[DIProductSel]); + } +} + +// --- replace package and technology text holder ---- +string techpacvar(string devsetname, string devname, string tech, string pacname) { + if (tech == "''") tech = ""; + if (pacname == "''") pacname = ""; + if (devname == "''") devname = ""; + string s[]; + int cnt; + cnt = strsplit(s, devsetname, '*'); + if (cnt > 1) { + if (cnt == 2) { + if (!s[0]) { + devsetname = tech + s[1]; + } + else if (!s[1]) { + devsetname = s[0] + tech; + } + else devsetname = s[0] + tech + s[1]; + } + } + else devsetname += tech; + + cnt = strsplit(s, devsetname, '?'); + if (cnt > 1) { + if (cnt == 2) { + if (!s[0]) { + devsetname = devname + s[1]; + } + else if (!s[1]) { + devsetname = s[0] + devname; + } + else devsetname = s[0] + devname + s[1]; + } + } + else devsetname += devname; + return devsetname; +} diff --git a/trunk/ulp/designlink-lbr.ulp b/trunk/ulp/designlink-lbr.ulp new file mode 100644 index 00000000..9183030a --- /dev/null +++ b/trunk/ulp/designlink-lbr.ulp @@ -0,0 +1,394 @@ +#usage "en: DesignLink Library Tool\n" + "

    " + "ULP for embedding Farnell and/or Newark order codes and related data to EAGLE library devices." + "

    " + "Usage: run designlink-lbr [-both_oc]|[-sop]\n" + "

    " + "Options:" + "

    " + "-both_oc: This lets you search both in Farnell and Newark databases and embed both order codes.
    \n" + "-sop : Search option package. By default searching for Farnell parts " + "is done with device name and technology. With this option the " + "package name is taken additionally for getting more accurate results.\n" + "

    " + "Author: support@cadsoft.de", + "de: DesignLink Library Tool\n" + "

    " + "ULP für die Zuweisung von Farnell- und/oder Newark-Ordercodes und verwandte Daten zu EAGLE-Devices." + "

    " + "Usage: run designlink-lbr [-both_oc]|[-sop]\n" + "

    " + "Optionen:" + "

    " + "-both_oc: Damit können Sie sowohl in der Farnell- als auch in der Newark-Datenbank suchen" + " und Ordercodes zuweisen.
    \n" + "-sop : Search option package. Fuer die Produktsuche zu einem Bauteil wird " + "standardmässig der Value verwendet. Mit dieser Option wird mit " + "Value und Packagebezeichnung gesucht, um genauere Ergebnisse zu erzielen.\n" + "

    " + "Author: support@cadsoft.de" + +#require 5.1001 + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#include "designlink-inc.ulp" + +string Version = "1.0.7"; +string NotAssigned = "not assigned"; +string LibName; +int NrDev = 0; +string DevFullName[]; +string DevSet[]; +string DevName[]; +string DevPkg[]; +string DevTech[]; +string DevDesc[]; +int DevOCIdx[]; +string DevOC[]; +string DevMF[]; +string DevMPN[]; +string DevProdDesc[]; +string DevImgLink[]; +numeric string DevList[]; + +// For transferring OCs to other library +int Transfer = 0; +string NewLibPath; + + +if (DIVersion != Version) { + dlgMessageBox(tr("Verschiedene Versionen von ") + filename(argv[0]) + " (" + Version + ") " + + tr("und Include ") + "designlink-inc.ulp (" + DIVersion + ") !\n"); +} + +InitCountryData(); +InitCfg(); + +DIAdvice = "\n " + tr("Bitte manuell suchen oder Part überspringen !") + "\n"; +DISkipRem = 0; // For processing the libraries we don't want to skip the unfound parts by default + +// Cool string replace function... +string StrRep(string str, string a, string b) { + int la = strlen(a), lb = strlen(b); + if (la == 0) return str; // Makes no sense. Should be treated as an error ! + for (int pos = strstr(str, a); pos >= 0; pos = strstr(str, a, pos + lb)) { + str = strsub(str, 0, pos) + b + strsub(str, pos + la); + } + return str; +} + +// Windows uses backslashes for directories which have to be backslashed which have to be backslashed... +string SetWeirdBackSlashesForWindows(string ReasonblePathWithSlashes) { + return StrRep(ReasonblePathWithSlashes, "/", "\\\\"); +} + +string ImgFile(string s) { + return StrRep(s, "/", "@") + ".png"; +} + +void InitFarnellNewark(int idx) { + DILanguage = "en"; + DICountry = (idx == 0) ? "UK" : "US"; + InitCountryData(); +} + +void FillDevListRow(int idx) { + sprintf(DevList[idx], "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s", DevSet[idx], DevPkg[idx], + DevTech[idx], DevFullName[idx], DICompany, DevOC[idx], DevMPN[idx], DevProdDesc[idx]); +} + +void SearchDev(int sel_idx) { + DISkipRem = 0; + Clear(); + + // Prepare country settings, Farnell/Newark + InitFarnellNewark(DevOCIdx[sel_idx]); + // Go ahead ! + // translate to German !!! + string product = SingleSearch(DIModeLbrSearch, tr(" DesignLink Devicesuche und -anzeige - ") + LibName, + DevDesc[sel_idx], DevImgLink[sel_idx], + (DevOC[sel_idx] == NotAssigned) ? DISearchByKeyword : DISearchByOC, + (DevOC[sel_idx] == NotAssigned) ? DevFullName[sel_idx] : DevOC[sel_idx], + DevFullName[sel_idx]); + // Cancel: Nothing to do. Reset Flag. + if (DICancelSearch) { + DICancelSearch = 0; + return; + } + if (product != "") { + string s[]; + strsplit(s, product, '\t'); + DevOC[sel_idx] = s[0]; + DevMF[sel_idx] = s[1]; + DevMPN[sel_idx] = s[2]; + DevProdDesc[sel_idx] = s[5]; + } + else { + DevOC[sel_idx] = DIUnknown; + DevMF[sel_idx] = ""; + DevMPN[sel_idx] = ""; + DevProdDesc[sel_idx] = ""; + } + FillDevListRow(sel_idx); +} + +// Save the stuff ! +string SaveAttributes() { + string cmds, cmd; + // Transfer option + if (Transfer) sprintf(cmd, "OPEN '%s';\n", NewLibPath); cmds += cmd; + //------------------------------------------------------------------- + for (int i = 0; i < NrDev; i++) { + if (DevOC[i] != NotAssigned) { + InitFarnellNewark(DevOCIdx[i]); + sprintf(cmd, "EDIT %s.dev;\n", DevSet[i]); cmds += cmd; + sprintf(cmd, "PACKAGE '%s';\n", (DevName[i] == "''") ? "" : DevName[i]); cmds += cmd; + sprintf(cmd, "TECHNOLOGY '%s';\n", (DevTech[i] == "''") ? "" : DevTech[i]); cmds += cmd; + sprintf(cmd, "ATTRIBUTE %s '%s';\n", DIAttOC, DevOC[i]); cmds += cmd; + sprintf(cmd, "ATTRIBUTE %s '%s';\n", DIAttMF, DevMF[i]); cmds += cmd; + sprintf(cmd, "ATTRIBUTE %s '%s';\n", DIAttMPN, DevMPN[i]); cmds += cmd; + } + } + cmds += "WRITE;\n"; + return cmds; +} + +// ------------ Library Device -------------------- +if (!library) { + dlgMessageBox(tr("Bitte starten Sie vom Bibliotheks-Editor aus !")); + exit(EXIT_FAILURE); +} + +library(L) { + // Parsing arguments: + int both_oc, export, skip_exp; + // Statistic stuff + int statistics; + string st_opt_list = "-st_list"; + string st_opt_idx = "-st_idx"; + string st_opt_nr_dev = "-st_nr_dev"; + string st_opt_nr_oc_f = "-st_nr_oc_f"; + string st_opt_nr_oc_n = "-st_nr_oc_n"; + string st_opt_nr_not_ass = "-st_nr_not_ass"; + // The parameters themselves + string st_list; + int st_idx = -1; + int st_all_nr_dev; + int st_all_nr_oc_f; + int st_all_nr_oc_n; + int st_all_nr_not_ass; + int st_nr_oc_f; + int st_nr_oc_n; + int st_nr_not_ass; + + for (int i = 1; i <= argc; ++i) { + if (argv[i] == "-sop") DISearchOptPac = 1; + if (argv[i] == "-both_oc") both_oc = 1; + if (argv[i] == "-skip_exp") skip_exp = 1; + // Transfer option: Not supported officially. Used internally. + if (strsub(argv[i], 0, 9) == "-transfer") { + Transfer = 1; + NewLibPath = strsub(argv[i], 9); // Full path + } + // Statistic function: Also for internal use. + if (strsub(argv[i], 0, strlen(st_opt_list)) == st_opt_list) { + statistics = 1; + both_oc = 1; // In that case we want it for both order codes + skip_exp = 1; // In that case we don't want the images exported + st_list = strsub(argv[i], strlen(st_opt_list)); // Full path + } + if (strsub(argv[i], 0, strlen(st_opt_idx)) == st_opt_idx) + st_idx = strtol(strsub(argv[i], strlen(st_opt_idx))); + if (strsub(argv[i], 0, strlen(st_opt_nr_dev)) == st_opt_nr_dev) + st_all_nr_dev = strtol(strsub(argv[i], strlen(st_opt_nr_dev))); + if (strsub(argv[i], 0, strlen(st_opt_nr_oc_f)) == st_opt_nr_oc_f) + st_all_nr_oc_f = strtol(strsub(argv[i], strlen(st_opt_nr_oc_f))); + if (strsub(argv[i], 0, strlen(st_opt_nr_oc_n)) == st_opt_nr_oc_n) + st_all_nr_oc_n = strtol(strsub(argv[i], strlen(st_opt_nr_oc_n))); + if (strsub(argv[i], 0, strlen(st_opt_nr_not_ass)) == st_opt_nr_not_ass) + st_all_nr_not_ass = strtol(strsub(argv[i], strlen(st_opt_nr_not_ass))); + } + if (Transfer && !NewLibPath) { + dlgMessageBox("Missing transfer library path !"); + exit(EXIT_FAILURE); + } + if (statistics && !st_list) { + dlgMessageBox("Missing library list for statistics !"); + exit(EXIT_FAILURE); + } + // Optional generation of image files + // If not specified to skip the export check if it's necessary: + if (!skip_exp) { + string cmds, cmd; + string img_dir = filesetext(L.name, ""); + string matches[]; + int dir_error; + if (!fileglob(matches, img_dir)) { + // Need to use CMD for Windows (?) + if (system("CMD /C \"mkdir \"" + SetWeirdBackSlashesForWindows(img_dir) + "\"\"") != 0) { + dlgMessageBox("Creating image directory " + SetWeirdBackSlashesForWindows(img_dir) + " failed !"); + dir_error = 1; + } + export = 1; + } + L.packages(P) { + string img_file = ImgFile(P.name); + if (!fileglob(matches, img_dir + "/" + img_file)) { + export = 1; + real large = u2inch(P.area.x2 - P.area.x1); + if (P.area.y2 - P.area.y1 > large) + large = u2inch(P.area.y2 - P.area.y1); + large = max(0.01, large); // use a minimum size to avoid 0 (in case of empty package) + real f = max(50, min(1.0 / large * 150, 2400.0)); // max. 2 Inch long + sprintf(cmd, "EDIT %s.PAC;\nEXPORT IMAGE '%s' %.0f;\n", P.name, img_dir + "/" + img_file, f); + cmds += cmd; + } + } + if (export && !dir_error) { + dlgMessageBox(tr("Erzeugung der Package-Bilder zunächst !")); + cmds += "RUN '" + argv[0] + "' -skip_exp"; // Run again without doing the export ! + for (int i = 1; i <= argc; ++i) cmds += " " + argv[i]; + exit(cmds); + } + } + //------------------------------------------------------------------------ + // We don't use those flags here. Set them to false + DIInStock = 0; + DIRoHS = 0; + LibName = filename(L.name); + string dev_list_head = tr("Deviceset\tPackage\tTechnologie\tDevicename\tOrdercode-Typ\tOrdercode\tHerstellercode\tBeschreibung"); + + L.devicesets(DS) { + DS.devices(D) { + if (D.package) { + string t[]; + int n = strsplit(t, D.technologies, ' '); + for (int i = 0; i < n; i++) { + string full_name = techpacvar(DS.name, D.name, t[i], D.package.name); + // Same problem like for package names + string description = " Deviceset: " + DS.name + " " + + " Package: " + (D.package.name ? D.package.name : "---") + + " Technology: " + t[i] + + " Device name: " + full_name + "

    " + + DS.description; + string image = ""; + + for (int j = 0; j < (both_oc ? 2 : 1); j++) { + DevSet[NrDev] = DS.name; + DevName[NrDev] = D.name; + DevPkg[NrDev] = D.package.name; + DevTech[NrDev] = t[i]; + DevFullName[NrDev] = full_name; + InitFarnellNewark(j); + DevOCIdx[NrDev] = j; + DevOC[NrDev] = NotAssigned; + DevMF[NrDev] = ""; + DevMPN[NrDev] = ""; + D.attributes(A, t[i]) + if ((A.name == DIAttOC) && (A.value != "")) DevOC[NrDev] = A.value; + else if (A.name == DIAttMPN) DevMPN[NrDev] = A.value; + else if (A.name == DIAttMF) DevMF[NrDev] = A.value; + if (DevOC[NrDev] == NotAssigned) { + DevMPN[NrDev] = ""; + DevMF[NrDev] = ""; + } + DevDesc[NrDev] = description; // lot of memory ? + DevImgLink[NrDev] = image; + DevProdDesc[NrDev] = ""; + // For statistic purpose: + if (statistics && (st_idx >= 0)) + if (DevOC[NrDev] == NotAssigned) ++st_nr_not_ass; + else if (DevOC[NrDev] != DIUnknown) + if (DevOCIdx[NrDev] == 0) ++st_nr_oc_f; + else ++st_nr_oc_n; + FillDevListRow(NrDev++); + } + } + } + } + } + // Process Statistics + if (statistics) { + string res_file = filedir(st_list) + "stat_lbr.txt"; + if (st_idx >= 0) { + output(res_file, "wba") + printf("%-40s:%6d %6d %6d %6d %6d\n", LibName, NrDev/2, st_nr_oc_f, st_nr_oc_n, + NrDev - st_nr_oc_f - st_nr_oc_n, st_nr_not_ass); + st_all_nr_dev += NrDev/2; + st_all_nr_oc_f += st_nr_oc_f; + st_all_nr_oc_n += st_nr_oc_n; + st_all_nr_not_ass += st_nr_not_ass; + } + else + output(res_file, "wt") printf("Library Order Code Statistics.\n\n" + "Name #Devices #Farnell OCs #Newark OCs #Without OCs #Not assigned\n" + "-----------------------------------------------------------------------------------------------------\n"); + // Read name of next library: + ++st_idx; + string lines[]; + int nr_l = fileread(lines, st_list); + int i, idx = -1; + for ( ; (i < nr_l) && (idx < st_idx); ++i) + if ((lines[i] != "") && (strchr(lines[i], '#') == -1)) ++idx; + string next_lbr = ((idx == st_idx) ? lines[--i] : ""); + // Run again with next library + if (next_lbr != "") { + string cmd; + sprintf(cmd, "OPEN '%s';RUN '%s' %s%s %s%d %s%d %s%d %s%d %s%d ;", next_lbr, argv[0], + st_opt_list, st_list, + st_opt_idx, st_idx, + st_opt_nr_dev, st_all_nr_dev, + st_opt_nr_oc_f, st_all_nr_oc_f, + st_opt_nr_oc_n, st_all_nr_oc_n, + st_opt_nr_not_ass, st_all_nr_not_ass); + exit(cmd); + } + // Print total numbers + else { + output(res_file, "wba") { + int nr_without = 2 * st_all_nr_dev - st_all_nr_oc_f - st_all_nr_oc_n; + printf("=====================================================================================================\n"); + printf("%-40s:%6d %6d %6d %6d %6d\n", "Total absolute", st_all_nr_dev, + st_all_nr_oc_f, st_all_nr_oc_n, nr_without, st_all_nr_not_ass); + printf("%-40s: %3.1f %3.1f %3.1f %3.1f %3.1f \n", "Total percentages", 100.0, + real(st_all_nr_oc_f)/st_all_nr_dev * 100, real(st_all_nr_oc_n)/st_all_nr_dev * 100, + real(nr_without)/(2 * st_all_nr_dev) * 100, real(st_all_nr_not_ass)/(2 * st_all_nr_dev) *100); + printf("=====================================================================================================\n"); + } + exit(EXIT_SUCCESS); + } + } + // Master dialog + int save = 1, sel_idx = -1; + int ret = dlgDialog("DesignLink " + tr("Ordercode-Zuweisung - ") + LibName) { + dlgHBoxLayout dlgSpacing(800); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgVBoxLayout { + dlgListView(dev_list_head, DevList, sel_idx) + SearchDev(sel_idx); + dlgLabel(tr("Zur Detailansicht oder Suche und Zuweisung eines Artikels bitte Device doppelklicken !")); + dlgHBoxLayout { + dlgStretch(1); + dlgCheckBox(tr("Ordercodes speichern"), save); + dlgPushButton(tr("Exportieren") + "...") { + string file = dlgFileSave(tr("Export als Textdatei"), filesetext(L.name,".txt")); + if (file) output(file, "wt") { + printf("%s\n", dev_list_head); + for (int i = 0; i < NrDev; ++i) + printf("%s\n", DevList[i]); + } + } + dlgPushButton(tr("Beenden")) dlgAccept(); + } + } + } + }; // Warum hier der ';' ? + SaveCfg(); + if (ret == -1) exit(1); + if (save) { + status(tr("Speichere Ordercodes") + " ..."); // This can take a little time for large files + exit(SaveAttributes()); + } +} diff --git a/trunk/ulp/designlink-order.ulp b/trunk/ulp/designlink-order.ulp new file mode 100644 index 00000000..c0db8323 --- /dev/null +++ b/trunk/ulp/designlink-order.ulp @@ -0,0 +1,603 @@ +#usage "en: DesignLink Search and Order\n" + "

    " + "With this ULP you can do a general product search or a search for all parts " + "of your schematic, check price and availability and order directly at Farnell. " + "Found order codes can be saved as attributes. " + "The order list can be exported." + "

    " + "Usage: run designlink-order [-general]|[-sop]" + "

    " + "Options:
    " + "" + "" + "" + "
    -generalGeneral product search. Without this option search is done " + "for all parts of a schematic.
    -sopSearch option package. By default, for a product search the part " + "value is used. With this option value and package name are used.
    " + "

    " + "Author: support@cadsoft.de

    ", + "de: DesignLink Suche und Bestellung\n" + "

    " + "Mit diesem ULP können Sie eine allgemeine Produktsuche oder eine Suche für " + "alle Bauteile Ihres Schaltplans durchführen, Preis und Verfügbarkeit prüfen " + "und direkt bei Farnell bestellen. " + "Gefundene Ordercodes können als Attribute gespeichert werden. " + "Die Bestelliste kann exportiert werden." + "

    " + "Usage: run designlink-order [-general]|[-sop]" + "

    " + "Optionen:
    " + "" + "" + "" + "
    -generalAllgemeine Produktsuche. Ohne diese Option erfolgt die " + "Suche für alle Bauteile eines Schaltplans.
    -sopSearch option package. Für die Produktsuche zu einem Bauteil wird " + "standardmässig der Value verwendet. Mit dieser Option wird mit " + "Value und Packagebezeichnung gesucht.
    " + "

    " + "Autor: support@cadsoft.de

    " + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#require 7.0101 // uses UL_PART.module* members + +#include "designlink-inc.ulp" + +string Version = "1.0.7"; // 2010-08-13: Part of beta 5.10.1 + // 2010-08-24: Checkbox Ordercode speichern + // 2010-08-30: Value und Package in Liste mit TAB getrennt, nicht mehr mit " " + // clipDeviceDescription, nur Headerzeile anzeigen + +if (DIVersion != Version) + dlgMessageBox(tr("Verschiedene Versionen von ") + filename(argv[0]) + " (" + Version + ") " + + tr("und Include ") + "designlink-inc.ulp (" + DIVersion + ") !\n"); + +string SchPartName[]; // name, sheet, coordinates of every part to save attributes into schematic +numeric string SchPartSheet[]; // string needed for sorting + +int Icnt = 0; + +int CntSchPart = 0; +string SchParts[]; // the collected parts, value:partname+sheet \t partname... +string SchPartModule[]; // The part's module (if any) +string SchPartModPart[]; // The part's corresponding part in module +string SchPartValue[]; +string SchPartPackage[]; +string SchPartDescription[]; // The part's device description +int SchQuantPart[]; +string SchFilename; +string OrderCode[]; +string OrderCodes[]; + +string SchPartAttOC[]; // the existing Farnell or Newark order code +string SchPartAttMF[]; // the existing Manufacturer name +string SchPartAttMPN[]; // the existing Manufacturer Part Number +int PCBcount = 1; // PCB multiplyer +int CntBasketLines = 0; // positions to order +int CntInStock = 0; +string NrPositions; +numeric string PartCode[]; +string PartCodeHeader = tr("Anzahl\tValue\tPackage\tOrdercode\tHersteller\tHerstellercode\tVerfügbarkeit\tPreis (ab)\tBeschreibung"); // 2020-08-27 "/" zu TAB geändert Value\tPackage + +// Debug stuff +void DbgWriteCode(string scode, int index) { + output(DIDbgFile, "wt") + for (int nw = 0; nw < DINrProductsInList; nw++) { + printf("%s\n", DIProductList[nw]); + } + return; +} + +void DbgWritePartCode(void) { + output(DIDbgFile, "wt") { + printf("\n"); + printf("%s\n", PartCodeHeader); + for (int n = 0; n < CntSchPart; n++) { + printf("%s\n", PartCode[n]); + } + printf("*end*"); + } + return; +} +// End Debug stuff + +/************** Functions ****************************************************************/ +string GetBasket() { // 2010-08-09 alf + string basket; + CntBasketLines = 0; + CntInStock = 0; + string firsttilde = ""; + string s[]; + for (int n = 0; n < CntSchPart; n++) { + // WSP: Könnte man nicht alleine mit PartCode arbeiten ? + int cnt = strsplit(s, PartCode[n], '\t'); + int partcnt = strtol(s[0]); + int availcnt = strtol(s[6]); // 2010-08-30 + // Wenn ein Code vorhanden ist + if (OrderCode[n] && OrderCode[n] != DIUnknown) { + CntBasketLines++; + // Bestellen, wenn das Produkt auf Lager ist ! + if (availcnt > 0) { + CntInStock++; + string h; + sprintf(h, "%s%s~%d", firsttilde, OrderCode[n], partcnt); + basket += h; + firsttilde = "~"; + } + } + } + sprintf(NrPositions, "%s%d %s%d %s%d", + tr("Anzahl Positionen: "), CntSchPart, + tr("Mit Ordercodes: "), CntBasketLines, + tr("Auf Lager: "), CntInStock + ); + string xbasket; + sprintf(xbasket, "%s ", + DIShoppingURL, basket, tr("Zum Warenkorb hinzufügen")); + return xbasket; +} + + +string GetShoppingURL() { + string url, order_str = ""; + if (DIProductSel >= 0) { + string s[]; + strsplit(s, DIProductList[DIProductSel], '\t'); + order_str = s[0] + "~1"; // Only one piece + } + sprintf(url, "%s", + DIShoppingURL, order_str, tr("Selektion zum Warenkorb hinzufügen")); + return url; +} + + +string GetDescription(int idx) { + string description = " Value: " + (SchPartValue[idx] ? SchPartValue[idx] : "---") + " " + + " Package: " + (SchPartPackage[idx] ? SchPartPackage[idx] : "---"); + if (SchPartDescription[idx]) description += "
    " + SchPartDescription[idx]; + return description; +} + +// Replace the Quantity with the multiple of number of pcbs +void UpdateQuantity(int nr_pcbs) { + for (int i = 0; i < CntSchPart; i++) { + string s[]; + int cnt = strsplit(s, PartCode[i], '\t'); + sprintf(PartCode[i], "%d", SchQuantPart[i] * nr_pcbs); + for (int j = 1; j < cnt; j++) + PartCode[i] += "\t" + s[j]; + } + return; +} + + +int NewSearch(int point) { + DISkipRem = 0; // reset DISkipRem + string s[]; + int cnts = strsplit(s, PartCode[point], '\t'); + Clear(); + + string farnell_part = SingleSearch(DIModeNewSearch, DICompany + " DesignLink " + tr("Bauteilsuche für ") + SchFilename, + GetDescription(point), "", DISearchByOC, s[3], + (s[3] == DIUnknown) ? SchPartValue[point] : s[3]); // Initially suggest part value for search if OC is unknown + // Cancel: Nothing to do. Reset Flag. + if (DICancelSearch) { + DICancelSearch = 0; + return 0; + } + else if (farnell_part != "") { + string o[]; + strsplit(o, farnell_part, '\t'); + OrderCode[point] = o[0]; + SchPartAttOC[point] = o[0]; + sprintf(PartCode[point], "%d\t%s\t%s\t%s\t%s", + SchQuantPart[point] * PCBcount, + SchPartValue[point], + SchPartPackage[point], + farnell_part, + SchParts[point] + ); + } + else { + OrderCode[point] = DIUnknown; + SchPartAttOC[point] = DIUnknown; + sprintf(PartCode[point], "%d\t%s\t%s\t%s\t\t\t\t\t\t%s", // 2010-08-27 + SchQuantPart[point] * PCBcount, + SchPartValue[point], + SchPartPackage[point], + SchPartAttOC[point], + SchParts[point] + ); + } + return 0; +} + + +void GetOrderCode(void) { + DIAdvice = "\n " + tr("Bitte manuell suchen oder Part überspringen !") + "\n"; // If no result + string actVal = ""; + string actPac = ""; + string s[]; + string description = ""; + for (int n = 0; n < CntSchPart; n++) { + Clear(); + string farnell_part = ""; + string sch_key = (SchPartValue[n]) ? SchPartValue[n] : SchPartPackage[n]; // Fall, dass Value leer beachten ! + if (DISearchOptPac && SchPartValue[n] && SchPartPackage[n]) sch_key += " " + SchPartPackage[n]; // 2010-08-28 aus Space muss später TAB werden + if (!SchPartAttOC[n]) { + + // Do the actual Search (if the user doesn't want to skip the rest) + status(tr("Suche") + " " + sch_key); + if (!DISkipRem) { + farnell_part = SingleSearch(DIModeInitSearch, DICompany + " DesignLink " + tr("Bauteilsuche für ") + SchFilename, + GetDescription(n), "", DISearchByKeyword, sch_key, sch_key); + } + strsplit(s, farnell_part, '\t'); + + if (DIDebug) output(DIDbgFile, "wt") printf("\n%s\n", sch_key); + OrderCode[n] = s[0]; // farnell order code + if (!farnell_part) { + OrderCode[n] = DIUnknown; + sprintf(PartCode[n], "%d\t%s\t%s\t%s\t\t\t\t\t\t%s", // 2010-08-27 es wird immer Value und Package aus dem SCH benutzt + SchQuantPart[n], SchPartValue[n], SchPartPackage[n], OrderCode[n], SchParts[n] + ); + } + else { + sprintf(PartCode[n], "%d\t%s\t%s\t%s\t%s", // 2010-08-27 es wird immer Value und Package aus dem SCH benutzt + SchQuantPart[n], SchPartValue[n], SchPartPackage[n], farnell_part, SchParts[n] + ); + } + if (DIDebug) DbgWriteCode(sch_key, n); + } + else { // 2010-08-05 if order code exists, fill line + if (SchPartAttOC[n] == DIUnknown) { + sprintf(PartCode[n], "%d\t%s\t%s\t%s\t\t\t\t\t\t%s", // 2010-08-28 space zu TAB geändert + SchQuantPart[n], + SchPartValue[n], SchPartPackage[n], + SchPartAttOC[n], + SchParts[n] + ); + } + else { + status(tr("Prüfe Preis und Verfügbarkeit: ") + SchPartAttOC[n]); // to see eagle/ulp is running + farnell_part = SingleSearch(DIModeInitSearch, DICompany + " DesignLink " + tr("Bauteilsuche für ") + SchFilename, + GetDescription(n), "", DISearchByOC, SchPartAttOC[n], SchPartAttOC[n]); + // Normal case: Search by OC was successful, the part is returned + // Special case: The OC is not (no longer) valid. + // The user can choose s.th. by manual search. We take this instead. + // Or if he skips the part, set the stuff to "unknown" + if (farnell_part) { + strsplit(s, farnell_part, '\t'); + OrderCode[n] = s[0]; + SchPartAttOC[n] = s[0]; + sprintf(PartCode[n], "%d\t%s\t%s\t%s\t%s", // 2010-08-27 space zu TAB geändert + SchQuantPart[n], SchPartValue[n], SchPartPackage[n], farnell_part, SchParts[n] + ); + } + else { + OrderCode[n] = DIUnknown; + SchPartAttOC[n] = DIUnknown; + sprintf(PartCode[n], "%d\t%s\t%s\t%s\t%s\t%s\t\t\t\t%s", // 2010-08-27 Space zu TAB geändert + SchQuantPart[n], + SchPartValue[n], SchPartPackage[n], + SchPartAttOC[n], + SchPartAttMF[n], + SchPartAttMPN[n], + SchParts[n] + ); + } + } + } + } + DISkipRem = 0; // Reset after run through all parts is finished + return; +} + +string SaveAttributes() { // 2010-08-09 alf + string cmd, h; + + // Display of attributes. Useful feature. Do we add that ? + // => Too much stuff visible. Texts cover each other + // CHANGE DISPLAY OFF | VALUE | NAME | BOTH + //string attdisplay[] = { "OFF", "VALUE", "NAME", "BOTH" }; + //int attdisplayoption = 0; + //dlgDialog(filename(argv[0])) { + // dlgGroup(tr("Attribute - Anzeigeoptionen")) { + // dlgRadioButton(tr("&Keine Anzeige"), attdisplayoption); + // dlgRadioButton(tr("&Wert anzeigen"), attdisplayoption); + // dlgRadioButton(tr("&Name anzeigen"), attdisplayoption); + // dlgRadioButton(tr("Wert &und Name anzeigen"), attdisplayoption); + // } + // dlgHBoxLayout { + // dlgStretch(1); + // dlgPushButton("+OK") dlgAccept(); + // dlgStretch(1); + // } + //}; + + // We turn off visibility of attributes + cmd += "CHANGE DISPLAY OFF;\n"; + + int index[]; + // Sortiert nach Modul, dann nach Sheet, dann nach Partname. reduziert lediglich das Herumspringen beim Speichern. + sort(CntSchPart, index , SchPartModule, SchPartSheet, SchParts); + for (int n = 0; n < CntSchPart; n++) { + string l[]; // split line + int cntl = strsplit(l, PartCode[index[n]], '\t'); // 2010-08-27 s[1] is the value, s[2] is the package + string r[]; // split row + int cntr = strsplit(r, l[cntl-1], ' '); + for (int np = 0; np < cntr; np++) { + for (int i = 0; i < Icnt; i++) { + if (SchPartName[i] == r[np]) { + // Bei einem hierarchischen Part muß ins Modul gegangen werden und das entspr. Part im Modul behandelt werden ! + string pname = (SchPartModule[i] == "") ? SchPartName[i] : SchPartModPart[i]; + // 0=Quant., 1=Value, 2=Package, 3=Ordercode Farnell, 4=Manufacturer Name, 5=Manuf. Code, 6=Verfügbarkeit, 7=Preis, 8=Beschreibung, 8=Value, 9=Partnames + sprintf(h, "EDIT %s.%s%s;\n", SchPartModule[i], (SchPartModule[i] == "") ? "s" : "m", SchPartSheet[i]); cmd += h; + sprintf(h, "ATTRIBUTE %s %s '%s';\n", pname, DIAttOC, l[3]); cmd += h; + sprintf(h, "ATTRIBUTE %s %s '%s';\n", pname, DIAttMF, l[4]); cmd += h; + sprintf(h, "ATTRIBUTE %s %s '%s';\n", pname, DIAttMPN, l[5]); cmd += h; + break; + } + } + } + } + cmd += "WRITE;\n"; + +// //Debug stuff for checking command sequence +// dlgDialog(tr("Rückgabe Script")) { +// dlgHBoxLayout dlgSpacing(800); +// dlgHBoxLayout { +// dlgVBoxLayout dlgSpacing(600); +// dlgTextEdit(cmd); +// } +// dlgHBoxLayout { +// dlgStretch(1); +// dlgPushButton(tr("OK")) dlgAccept(); +// dlgPushButton(tr("CANCEL")) { dlgReject(); exit(-2); } +// dlgStretch(1); +// } +// }; + return cmd; +} + + +string clipDeviceDescription(string partdescription) { + int pos = strstr(partdescription, "

    "); + if (pos > 0) { + return strsub(partdescription, 0, pos); // 2010-08-30 nur headerzeile anzeigen + } + return partdescription; +} + + +//---Here we go: Main section--------------------------------- + +// Get arguments if any +int OptGeneral = 0; // Means general search => Extended "old" DL interface is launched +for (int i = 1; i <= argc; ++i) { + if (argv[i] == "-sop") DISearchOptPac = 1; + if (argv[i] == "-general") OptGeneral = 1; +} + +// Init stuff +InitCountryData(); +InitCfg(); +// ------------ Schematic Part -------------------- +if (schematic && (!OptGeneral)) { + // Keep help here locally " + string help[] = { + "Bestellliste
    " + "Die Bestellliste ist eine Stückliste all Ihrer Bauteile, die Sie für die " + "Fertigung der Leiterplatte benötigen. Je nach vorheriger Suche und Auswahl " + "sind den einzelnen Positionen Farnell-Artikel mit Ordercodes zugeordnet. " + "Per Doppelklick auf die einzelnen Positionen gelangen Sie zur Detailansicht " + "der Artikel und können mit manueller Suche und Auswahl diese " + "nochmal ändern oder rückgängig machen. Auf dieselbe Art können Sie auch für Bauteile, " + "denen Sie noch keinen Farnell-Artikel zugeordnet haben, eine Auswahl treffen. " + "Sie können für Ihre Bestellung eine beliebige Anzahl von Leiterplatten vorgeben " + "(in entprechendes Feld eingeben, Aktualisieren drücken).
    " + "Mit dem Link Zum Warenkorb hinzufügen " + "gelangen Sie schliesslich zur landesspezifischen Einkaufsseite von Farnell, " + "wo alle entsprechenden Produkte in einen Warenkorb gelegt werden, " + "soweit Sie auf Lager sind.
    " + "Alles Weitere (Bestellung, Bezahlung) können Sie dort erledigen." + "

    Ordercodes speichern, Bestellliste exportieren
    " + "Wollen Sie die Ordercodes zu einem späteren Zeitpunkt wiederverwenden, " + "z.B. nachdem Sie Änderungen am Schaltplan vorgenommen haben, " + "können Sie diese durch Ankreuzen der entsprechenden Checkbox im Schaltplan speichern. " + "Beim nächsten Bestellvorgang brauchen Sie dann nur noch Produkte für die neuen " + "Bauteile auszusuchen.
    " + "Verwenden Sie Bauteile aus Hersteller-Bibliotheken, die bereits mit Farnell-Ordercodes " + "versehen sind, erübrigt sich auch diese Suche. Die entsprechenden Farnell-Artikel werden " + "automatisch in die Bestellliste aufgenommen.
    " + "Sie können die Bestellliste auch als Textdatei exportieren, z.B. zur Weiterverarbeitung " + "in anderen Systemen." + , + "Order list
    " + "The order list is a list of all the parts that you need for manufacturing your PCB. " + + "The individual positions are related to " + DICompany + " articles with order codes, " + + "depending on your previous search and selection. By doubleclicking the items you get a " + + "detail view, can change them once more by manual search and selection or cancel the " + + "previous selection. " + + "The same way you can make a choice for parts that have not been assigned " + DICompany + " articles yet. " + + "You can specifiy the number of PCBs for your order (enter in according field, press " + + "update).
    " + + "Pressing the link add to shopping cart directs you to " + DICompany +"'s country specific " + + "shopping site and all your products are put into a shopping cart, depending on availability. " + + "You can finish all further steps (order, payment) on this site. " + + "

    Saving the order codes
    " + + "If you want to reuse the order codes later, e.g. after changes of the schematic, you can " + + "save them to schematic with the according checkbox.
    " + + "Next time you order, you just need to select the articles for the new parts.
    " + + "If you use parts from manufacturer libraries with " + DICompany + " order codes this selection " + + "is also not necessary. The related articles are taken automatically to the order list.
    " + "You can also export the order list as a text file, e.g. for processing in other systems." + }; + // We don't use those flags here. + DIInStock = 0; + DIRoHS = 0; + int saveatt = 1; // Flag for option save the attributes + schematic(SCH) { + SchFilename = filename(SCH.name); + Icnt = 0; + SCH.allparts(P) { + if (P.device.package) { + // For virtual parts get the module name and module part's name + if (P.modulepart) { + SchPartModule[Icnt] = P.module.name; + SchPartModPart[Icnt] = P.modulepart.name; + P.modulepart.instances(I) { + sprintf(SchPartSheet[Icnt], "%d", I.sheet); + if (I.sheet != 0) break; + } + } + else + P.instances(I) { + sprintf(SchPartSheet[Icnt], "%d", I.sheet); + if (I.sheet != 0) break; + } + SchPartName[Icnt] = P.name; + Icnt++; + int found = 0; + for (int n = 0; n < CntSchPart; n++) + if (P.value == SchPartValue[n] && P.device.package.name == SchPartPackage[n]) { + SchQuantPart[n]++; + SchParts[n] += " " + P.name; + found = 1; + break; + } + if (!found) { + SchParts[CntSchPart] = P.value + "\t" + P.name; + SchPartValue[CntSchPart] = P.value; + SchPartPackage[CntSchPart] = P.device.package.name; + SchPartDescription[n] = clipDeviceDescription(P.deviceset.description); + SchPartAttOC[CntSchPart] = P.attribute[DIAttOC]; + SchPartAttMF[CntSchPart] = P.attribute[DIAttMF]; + SchPartAttMPN[CntSchPart] = P.attribute[DIAttMPN]; + SchQuantPart[CntSchPart] = 1; // Quantity + CntSchPart++; + } + } + } + GetOrderCode(); + if (DIDebug) DbgWritePartCode(); + string basket = GetBasket(); + int pcsel = -1; + sprintf(NrPositions, "%s%d %s%d %s%d", tr("Anzahl Positionen: "), CntSchPart, + tr("Mit Ordercodes: "), CntBasketLines, tr("Auf Lager: "), CntInStock); + dlgDialog(DICompany + " DesignLink " + tr("Bestellliste für ") + SchFilename) { + dlgHBoxLayout dlgSpacing(800); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgVBoxLayout { + dlgListView(PartCodeHeader, PartCode, pcsel) { + NewSearch(pcsel); + basket = GetBasket(); // Warenkorb aktualisieren + } + dlgLabel(tr("Zur Detailansicht oder erneuten Suche der Artikel bitte diese doppelklicken !")); + dlgHBoxLayout { + dlgLabel(tr("Anzahl Leiterplatten:")); + dlgIntEdit(PCBcount, 1, 1000000); + dlgPushButton(tr("Aktualisieren")) { + UpdateQuantity(PCBcount); + basket = GetBasket(); + } + dlgSpacing(10); + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(280); + dlgLabel(NrPositions, 1); + } + dlgSpacing(10); + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing((DIDlgLang = "de") ? 160 : 150); + dlgLabel(basket, 1); + } + dlgCheckBox(tr("Ordercodes speichern"), saveatt); + dlgPushButton(tr("Exportieren") + "...") { + string file = dlgFileSave(tr("Bestellliste exportieren"), filesetext(filesetext(SCH.name,"") + "-order", ".txt")); + if (file) output(file, "wt") { + printf("Order list for %s\n", SCH.name); + printf("Exported from EAGLE with DesignLink\n\n"); + printf("%s\n", PartCodeHeader); + for (int i = 0; i < CntSchPart; ++i) { + string str[]; + strsplit(str, PartCode[i], '\t'); + printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + str[0], str[1], str[2], str[3], str[4], str[5], str[6], str[7], str[8]); + } + } + } + dlgPushButton(tr("Hilfe") + "...") + dlgMessageBox(help[DILangIdx]); + dlgPushButton(tr("Beenden")) dlgAccept(); + } + } + } + }; + } + SaveCfg(); + if (saveatt) { + status(tr("Ordercodes speichern") + "..."); // This can take a little time for large files + exit(SaveAttributes()); + } +} + +else if (OptGeneral) { + DIHtml = "
    " + tr("Bitte geben Sie unten einen Suchstring ein !") + "
    "; + DIMode = 0; // Display search message + dlgDialog(DICompany + " DesignLink " + tr("allgemeine Suche")) { + string keyword = ""; + string url = GetShoppingURL(); + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(800); + dlgHBoxLayout { + dlgTextView(DIHtml); + dlgVBoxLayout dlgSpacing(400); + } + dlgListView(DIProductListHead, DIProductList, DIProductSel) + if (dlgSelectionChanged()) { + ShowSelection(); + url = GetShoppingURL(); + } + dlgHBoxLayout { + dlgCheckBox(tr("Vorrätig"), DIInStock); + dlgCheckBox("RoHS", DIRoHS); + dlgStretch(1); + dlgPushButton(tr("Vorige")) + if (DIProductOffset > 0) { + DIProductOffset -= DINrProductsPerPage; + DoSearch(keyword); + url = GetShoppingURL(); + } + dlgLabel(DIResInfo, 1); + dlgPushButton(tr("Nächste")) + if (DIProductOffset + DINrProductsPerPage < DINrAccessibleProducts) { + DIProductOffset += DINrProductsPerPage; + DoSearch(keyword); + url = GetShoppingURL(); + } + else + dlgMessageBox(tr("Keine weiteren Produkte verfügbar!")); + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(238); + dlgHBoxLayout { + dlgSpacing(35); + dlgLabel(url, 1); + } + } + } + dlgHBoxLayout { + dlgStringEdit(keyword, DISearchHist, 9); + dlgPushButton(tr("+Suchen")) { + DoSearch(keyword); + url = GetShoppingURL(); + } + dlgPushButton(tr("Beenden")) dlgReject(); + } + } + }; // The ; is necessary here. Is this a bug of ULP ? + SaveCfg(); +} +else + dlgMessageBox(tr("Bitte starten Sie vom Schaltplan aus !")); + diff --git a/trunk/ulp/dif40.ulp b/trunk/ulp/dif40.ulp new file mode 100644 index 00000000..deb27056 --- /dev/null +++ b/trunk/ulp/dif40.ulp @@ -0,0 +1,441 @@ +#usage "Export DIF 4.0 format

    " + "This format is used for production and test purposes. It has been defined by Digitaltest GmbH.

    " + "Run the ULP from the board editor and get the file boardname.dif.

    " + "Please have a look at the \"user definable parameters\" section of the program." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + + +// 2005-02-28: Corrected output for mirrored components +// Added "File Save" dialog +// by support@cadsoft.de +// 2005-11-09: Corrected Y Coordinate, was always minus +// 2008-05-27: Corrected relativ coordinates if package rotate in 0.1 degree +// by alf@cadsoft.de + + +string REVISION = "2.00"; + +////////////////// user definable parameters //////////////////////////////////////////////// +int pad_layer = 1; // change to 16 if pad parameters should be taken from bottom layer +int nr_of_layers = 2; +int fill_polygons = 1; // set to 0 if polygons are not to be filled + // if set to 1, please make sure the width parameter of the polygons + // is >> 0 + // make also sure the polygon filling is visible in EAGLE +///////////////////////////////////////////////////////////////////////////////////////////// + + +string difversion = "4.0"; +string jobname, pcbname, + shapename[], // package names + t[]; // padtypes + +real ang2, x, y; +int nr_of_nets = 0, nr_of_comps = 0, i, new, sx, dummy_pad_code; + +//----------------------------------------------------- +string validname (string s) { + int i; + for (i = 0; s[i]; i++) { + if (s[i] == ',') s[i] = '_'; + if (s[i] == ';') s[i] = '_'; + if (s[i] == ')') s[i] = '_'; + // add further substitutions here + } + return s; +} +//----------------------------------------------------- +int u2u(int x) { // resolution 1/10000 mm + // return u2mil(x); // mil + return x; +} +//----------------------------------------------------- +int u2x(int x) { + return u2u(x); +} +//----------------------------------------------------- +int u2y(int x) { + return u2u(x); // correct sign, was always minus 2005.11.09 alf@cadsoft.de +} +//----------------------------------------------------- +real deg2arc(int x) { // degree to arc + return x*PI/180; +} +//----------------------------------------------------- +int u2ang(real x) { + if (x > 360) + x = x -360; + return x; +} +//---------------------------------------------------- +void relco (UL_ELEMENT E, int xt, int yt) { // change if finer rotation possible + xt = xt - E.x; yt = yt - E.y; // move part origin to 0,0 + if (E.mirror) { // flip back if mirrored + x = -x; + } + if (E.angle == 0) { // rotate to zero position + x = xt; y = yt; + } + if (E.angle == 90) { + x = yt; y = -xt; + } + if (E.angle == 180) { + x = -xt; y = -yt; + } + if (E.angle == 270) { + x = -yt; y = xt; + } + } +//----------------------------------------------------- +string padtype(UL_PACKAGE P, UL_CONTACT C) { + string s; + int pdi; + if (C.pad) { + pdi = u2u(C.pad.diameter[pad_layer]); + sprintf(s, "pad_%d_%d_%d", C.pad.shape[pad_layer], u2u(C.pad.diameter[pad_layer]), u2u(C.pad.drill)); + } + if (C.smd) { + sprintf(s, "smd_%d_%d", u2x(C.smd.dx), u2y(C.smd.dy)); + } + return s; +} +//----------------------------------------------------- +int padindex(UL_PACKAGE P,UL_CONTACT C) { + int i = 0; + for (i = 0; t[i]; i++) { + if (t[i] == padtype(P,C)) + return i+1; + } + return i; // should not be possible +} +//----------------------------------------------------- +string viatype(UL_VIA V) { + string s; + int pdi; + pdi = u2u(V.diameter[pad_layer]); + sprintf(s, "pad_%d_%d_%d", V.shape[pad_layer], u2u(V.diameter[pad_layer]), u2u(V.drill)); + return s; +} +//----------------------------------------------------- +int viaindex(UL_VIA V) { + int i = 0; + for (i = 0; t[i]; i++) { + if (t[i] == viatype(V)) + return i+1; + } + return i; // should not be possible +} +//----------------------------------------------------- +int realnet(UL_SIGNAL S) { + S.contactrefs(S) + return 1; + return 0; +} + +////////////////////////////////////////////////////// +void create_environment () { + int t = time(); + printf(" { ENVIRONMENT\n"); + printf(" { SOURCE \"EAGLE %d.%02d %s Revision %s\" }\n", EAGLE_VERSION, EAGLE_RELEASE, filename(argv[0]),REVISION); + printf(" { VERSION %s }\n", difversion); + printf(" { DATE %d/%d/%d }\n", t2day(t),t2month(t)+1,t2year(t)); + printf(" { TIME %d:%d:%d }\n", t2hour(t),t2minute(t),t2second(t)); + printf(" { UNITS 1/10000 mm }\n"); + printf(" { LAYER %d }\n", nr_of_layers); + printf(" { TOP_LAYER 1 }\n"); + printf(" { BOTTOM_LAYER 16 }\n"); + printf(" { NO_NET %d }\n", nr_of_nets); + printf(" { NO_COMP %d }\n", nr_of_comps); + printf(" }\n"); +} +////////////////////////////////////////////////////// +void board_data(UL_BOARD B) { + int i = 0; + printf (" { BOARD\n"); + printf (" { F\n"); + B.wires(W) { // if board outline as wires in board + i++; + if (W.layer == LAYER_DIMENSION) { + printf(" { L (%d,%d) (%d,%d) }\n", u2x(W.x1), u2y(W.y1), u2x(W.x2), u2y(W.y2)); + } + } + + if (i == 0) { // board contains no dim wires, try packages + B.elements(E) { + E.package.wires(W) { + if (W.layer == LAYER_DIMENSION) { + printf(" { L (%d,%d) (%d,%d) }\n", u2x(W.x1), u2y(W.y1), u2x(W.x2), u2y(W.y2)); + } + } + } + } + + printf (" }\n"); + printf (" }\n"); +} +////////////////////////////////////////////////////// +void components(UL_BOARD B) { + int i, pic_nr; + string devname = ""; + printf (" { COMPONENTS\n"); + B.elements(E) { + if (E.package) { + printf(" { COMP\n"); + printf(" { COMP_DEF\n"); + printf(" { NAME %s }\n", E.name); + printf(" { PART_NR %s }\n", validname(E.package.name)+"_"+validname(E.package.library)); + printf(" }\n"); + printf(" { PIN_DEF\n"); + int issmd = 0; + E.package.contacts(C) { + printf(" { PIN %s { NET %s } }\n", C.name, C.signal); + if (C.smd) issmd = 1; + } + // find picture code + for (i=0; shapename[i] != validname(E.package.name)+"_"+validname(E.package.library); i++) { + } + pic_nr = i; + printf(" }\n"); + printf(" { PICTURE\n"); + printf(" { ORIGIN (%d,%d) }\n", u2x(E.x), u2y(E.y)); + printf(" { PIC %d }\n", pic_nr); + printf(" { ROTATION %d }\n", u2ang(E.angle)); + int mside = 1; + if (E.mirror) { + mside = 2; + } + printf(" { M_SIDE %d }\n", mside); + if (issmd) { + printf(" { KIND SMD }\n"); + } + + /* implement later if necessary + E.texts(T) { + printf(" { TEXT\n"); + printf(" }\n"); + } + */ + + printf(" }\n"); + printf(" }\n"); + } + } + printf(" }\n"); +} +////////////////////////////////////////////////////// +void pad_symbols(UL_BOARD B) { + int i, j = 0, new; // j+1 = pad index; t[] contains padtypes + printf (" { PAD_DEF\n"); + B.elements(E) { + E.package.contacts(C) { + if (1 /* C.pad */) { + new = 1; // padtype not generated yet + for (i = 0; t[i]; i++) { + if (t[i] == padtype(E.package, C)) + new = 0; // padtype exists + } + if (new) { + t[j] = padtype(E.package, C); + j++; + if (C.pad) + printf(" { PAD %d\n { SIZE %d }\n { DRILL %d }\n }\n", + j,abs(u2u(C.pad.diameter[pad_layer])),abs(u2u(C.pad.drill))); + if (C.smd) + printf(" { PAD %d\n { SIZE %d }\n { DRILL 0 }\n }\n", + j, min(abs(u2x(C.smd.dx)), abs(u2y(C.smd.dy)))); + } + } + } + } + B.signals(S) { + S.vias(V) { + new = 1; + for (i = 0; t[i]; i++) { + if (t[i] == viatype(V)) + new = 0; // padtype exists + } + if (new) { + t[j] = viatype(V); + j++; + + dummy_pad_code = j; // find pad code for dummy pad + + printf(" { PAD %d\n { SIZE %d }\n { DRILL %d }\n }\n", + j,u2u(V.diameter[pad_layer]),u2u(V.drill)); + + + } + } + } + printf (" }\n"); +} + +////////////////////////////////////////////////////// +// 2008-05-27: Corrected relativ coordinates if package rotate in 0.1 degree alf@cadsoft.de + +void picturePackage(UL_PACKAGE P, int ox, int oy) { + real angle, delta = 15; + + P.wires(W) { + if (W.layer == LAYER_TPLACE || W.layer == LAYER_TDOCU || W.layer == LAYER_BPLACE || W.layer == LAYER_BDOCU) { + if (W.arc) { + // process arcs (done with wire segments) + printf(" { L (%d,%d)\n", u2x(W.arc.x1-ox), u2y(W.arc.y1-oy)); + angle = W.arc.angle1 + delta; + while (angle < W.arc.angle2) { + printf(" (%d,%d)\n", + u2x((W.arc.xc-ox+W.arc.radius) * cos(deg2arc(angle))), + u2y((W.arc.yc-oy+W.arc.radius) * sin(deg2arc(angle)))); + angle += delta; + } + + printf(" (%d,%d)\n }\n", u2x(W.arc.x2-ox), u2y(W.arc.y2-oy)); + } + else { + printf(" { Linie (%d,%d) ", u2x(W.x1-ox), u2y(W.y1-oy)); + printf("(%d,%d) }\n", u2x(W.x2-ox), u2y(W.y2-oy)); + } + } + } + P.circles(W) { + if (W.layer == LAYER_TPLACE || W.layer == LAYER_TDOCU || W.layer == LAYER_BPLACE || W.layer == LAYER_BDOCU) { + printf(" { L (%d,%d)\n", u2x(W.x-ox+W.radius), u2y(W.y-oy)); + angle = 0; + while (angle < 360) { + printf(" (%d,%d)\n", u2x((W.x-ox+W.radius) * cos(deg2arc(angle))), u2y((W.y-oy+W.radius) * sin(deg2arc(angle)))); + angle += delta; + } + printf(" (%d,%d)\n }\n", u2x(W.x-ox+W.radius), u2y(W.y-oy)); + } + } + P.rectangles(W) { + if (W.layer == LAYER_TPLACE || W.layer == LAYER_TDOCU || W.layer == LAYER_BPLACE || W.layer == LAYER_BDOCU) { + printf(" { L (%d,%d)\n", u2x(W.x1-ox), u2y(W.y1-oy)); + printf(" (%d,%d)\n", u2x(W.x2-ox), u2y(W.y1-oy)); + printf(" (%d,%d)\n", u2x(W.x2-ox), u2y(W.y2-oy)); + printf(" (%d,%d)\n", u2x(W.x1-ox), u2y(W.y2-oy)); + printf(" (%d,%d)\n }\n", u2x(W.x1-ox), u2y(W.y1-oy)); + } + } + int nr_of_pins = 0; + P.contacts(C) { nr_of_pins++;} + if (nr_of_pins) { + printf(" { PINS %d\n", nr_of_pins); + } + P.contacts(C) { + printf(" (%d,%d) %d\n", u2x(C.x-ox), u2y(C.y-oy), padindex(P, C)); // Pin IDs + } + if (nr_of_pins) { + printf(" }\n"); + } + printf(" { SPECIFIC \"%s\" }\n", validname(P.name)+"_"+validname(P.library)); // PACK.NAME + printf(" }\n"); // end pic n + return; +} + + +////////////////////////////////////////////////////// +void pictures(UL_BOARD B) { + printf ("{ PIC_LIB\n"); + sx=0; + B.elements(E) { + if (E.package) { + new = 1; // padtype not generated yet + for (i = 0; shapename[i]; i++) { + if (shapename[i] == validname(E.package.name)+"_"+validname(E.package.library)) + new = 0; // ident. package exists + } + if (new) { + shapename[sx] = validname(E.package.name)+"_"+validname(E.package.library); + printf(" { PIC %d\n",sx++); // PACKAGE NR + picturePackage(E.package, E.x, E.y); + } + } + } + + printf(" { PIC 999\n"); + printf(" { R (0, 0) }\n"); + printf(" { PINS 1 (0, 0) %d }\n", dummy_pad_code); + printf(" }\n"); + + printf("}\n"); +} + +////////////////////////////////////////////////////// +void nets(UL_BOARD B) { + printf(" { NET_DEF\n"); + B.signals(S) { + if (realnet(S)) { + printf(" { NET %s\n", S.name); + S.wires(W) { + printf(" { W (%d, %d) %d %d (%d %d) %d %d }\n", u2x(W.x1), u2y(W.y1), W.layer, u2u(W.width), u2x(W.x2), u2y(W.y2), W.layer, u2u(W.width)); + } + + S.polygons(P) { + P.contours(W) { + printf(" { W (%d, %d) %d %d (%d %d) %d %d }\n", u2x(W.x1), u2y(W.y1), W.layer, u2u(W.width), u2x(W.x2), u2y(W.y2), W.layer, u2u(W.width)); + } + if (fill_polygons) { + P.fillings(W) { + printf(" { W (%d, %d) %d %d (%d %d) %d %d }\n", u2x(W.x1), u2y(W.y1), W.layer, u2u(W.width), u2x(W.x2), u2y(W.y2), W.layer, u2u(W.width)); + } + } + } + + S.vias(V) { + printf(" { V (%d, %d) %d 1, 15 }\n", u2x(V.x), u2y(V.y), viaindex(V)); + } + printf(" }\n"); + } + } + printf(" }\n"); +} + +////////////////////////////////////////////////////// +void net_comp_count(UL_BOARD B) { + nr_of_nets = 0; + nr_of_comps = 0; + B.signals(S) { + if (realnet(S)) { + nr_of_nets++; + } + } + B.elements(E) { + if (E.package) { + nr_of_comps++; + } + } +} + +////////////////////////////////////////////////////// + +if (board) board(B) { + jobname = filename(filesetext(B.name, "")); + pcbname = filename(filesetext(B.name, "")); + + string fileName = dlgFileSave("Save DIF 4.0 File", filesetext(B.name, ".dif"), "*.dif"); + if (fileName == "") exit(0); + + output(fileName) { + printf("{ JOB %s\n", jobname); + printf(" { PCB %s\n", pcbname); + net_comp_count(B); + create_environment(); + board_data(B); + pad_symbols(B); + pictures(B); + nets(B); + components(B); + printf(" }\n"); + printf("}\n"); + } + } + + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); + } diff --git a/trunk/ulp/dl-Millefori.dru b/trunk/ulp/dl-Millefori.dru new file mode 100644 index 00000000..759424d5 --- /dev/null +++ b/trunk/ulp/dl-Millefori.dru @@ -0,0 +1,69 @@ +description[de] = EAGLE Design Rules\n

    \nDie Standard-Design-Rules sind so gewählt, dass sie für \ndie meisten Anwendungen passen. Sollte ihre Platine \nbesondere Anforderungen haben, treffen Sie die erforderlichen\nEinstellungen hier und speichern die Design Rules unter \neinem neuen Namen ab. +description[en] = EAGLE Design Rules\n

    \nThe default Design Rules have been set to cover\na wide range of applications. Your particular design\nmay have different requirements, so please make the\nnecessary adjustments and save your customized\ndesign rules under a new name. +layerSetup = (1*16) +mtCopper = 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm +mtIsolate = 1.5mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm +mdWireWire = 8mil +mdWirePad = 8mil +mdWireVia = 8mil +mdPadPad = 8mil +mdPadVia = 8mil +mdViaVia = 8mil +mdSmdPad = 8mil +mdSmdVia = 8mil +mdSmdSmd = 8mil +mdViaViaSameLayer = 8mil +mnLayersViaInSmd = 2 +mdCopperDimension = 40mil +mdDrill = 8mil +mdSmdStop = 0mil +msWidth = 10mil +msDrill = 24mil +msMicroVia = 9.99mm +msBlindViaRatio = 0.500000 +rvPadTop = 0.250000 +rvPadInner = 0.250000 +rvPadBottom = 0.250000 +rvViaOuter = 0.250000 +rvViaInner = 0.250000 +rvMicroViaOuter = 0.250000 +rvMicroViaInner = 0.250000 +rlMinPadTop = 10mil +rlMaxPadTop = 20mil +rlMinPadInner = 10mil +rlMaxPadInner = 20mil +rlMinPadBottom = 10mil +rlMaxPadBottom = 20mil +rlMinViaOuter = 8mil +rlMaxViaOuter = 20mil +rlMinViaInner = 8mil +rlMaxViaInner = 20mil +rlMinMicroViaOuter = 4mil +rlMaxMicroViaOuter = 20mil +rlMinMicroViaInner = 4mil +rlMaxMicroViaInner = 20mil +psTop = -1 +psBottom = -1 +psFirst = -1 +psElongationLong = 100 +psElongationOffset = 100 +mvStopFrame = 1.000000 +mvCreamFrame = 0.000000 +mlMinStopFrame = 4mil +mlMaxStopFrame = 4mil +mlMinCreamFrame = 0mil +mlMaxCreamFrame = 0mil +mlViaStopLimit = 0mil +srRoundness = 0.000000 +srMinRoundness = 0mil +srMaxRoundness = 0mil +slThermalIsolate = 10mil +slThermalsForVias = 0 +dpMaxLengthDifference = 10mm +dpGapFactor = 2.500000 +checkGrid = 0 +checkAngle = 0 +checkFont = 1 +checkRestrict = 1 +useDiameter = 13 +maxErrors = 50 diff --git a/trunk/ulp/dl-untitled.dru b/trunk/ulp/dl-untitled.dru new file mode 100644 index 00000000..759424d5 --- /dev/null +++ b/trunk/ulp/dl-untitled.dru @@ -0,0 +1,69 @@ +description[de] = EAGLE Design Rules\n

    \nDie Standard-Design-Rules sind so gewählt, dass sie für \ndie meisten Anwendungen passen. Sollte ihre Platine \nbesondere Anforderungen haben, treffen Sie die erforderlichen\nEinstellungen hier und speichern die Design Rules unter \neinem neuen Namen ab. +description[en] = EAGLE Design Rules\n

    \nThe default Design Rules have been set to cover\na wide range of applications. Your particular design\nmay have different requirements, so please make the\nnecessary adjustments and save your customized\ndesign rules under a new name. +layerSetup = (1*16) +mtCopper = 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm 0.035mm +mtIsolate = 1.5mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm 0.15mm 0.2mm +mdWireWire = 8mil +mdWirePad = 8mil +mdWireVia = 8mil +mdPadPad = 8mil +mdPadVia = 8mil +mdViaVia = 8mil +mdSmdPad = 8mil +mdSmdVia = 8mil +mdSmdSmd = 8mil +mdViaViaSameLayer = 8mil +mnLayersViaInSmd = 2 +mdCopperDimension = 40mil +mdDrill = 8mil +mdSmdStop = 0mil +msWidth = 10mil +msDrill = 24mil +msMicroVia = 9.99mm +msBlindViaRatio = 0.500000 +rvPadTop = 0.250000 +rvPadInner = 0.250000 +rvPadBottom = 0.250000 +rvViaOuter = 0.250000 +rvViaInner = 0.250000 +rvMicroViaOuter = 0.250000 +rvMicroViaInner = 0.250000 +rlMinPadTop = 10mil +rlMaxPadTop = 20mil +rlMinPadInner = 10mil +rlMaxPadInner = 20mil +rlMinPadBottom = 10mil +rlMaxPadBottom = 20mil +rlMinViaOuter = 8mil +rlMaxViaOuter = 20mil +rlMinViaInner = 8mil +rlMaxViaInner = 20mil +rlMinMicroViaOuter = 4mil +rlMaxMicroViaOuter = 20mil +rlMinMicroViaInner = 4mil +rlMaxMicroViaInner = 20mil +psTop = -1 +psBottom = -1 +psFirst = -1 +psElongationLong = 100 +psElongationOffset = 100 +mvStopFrame = 1.000000 +mvCreamFrame = 0.000000 +mlMinStopFrame = 4mil +mlMaxStopFrame = 4mil +mlMinCreamFrame = 0mil +mlMaxCreamFrame = 0mil +mlViaStopLimit = 0mil +srRoundness = 0.000000 +srMinRoundness = 0mil +srMaxRoundness = 0mil +slThermalIsolate = 10mil +slThermalsForVias = 0 +dpMaxLengthDifference = 10mm +dpGapFactor = 2.500000 +checkGrid = 0 +checkAngle = 0 +checkFont = 1 +checkRestrict = 1 +useDiameter = 13 +maxErrors = 50 diff --git a/trunk/ulp/docs/artistic-license.txt b/trunk/ulp/docs/artistic-license.txt new file mode 100644 index 00000000..eb310598 --- /dev/null +++ b/trunk/ulp/docs/artistic-license.txt @@ -0,0 +1,51 @@ +The Artistic License + +Preamble + +The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. + +Definitions: + +"Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. +"Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. +"Copyright Holder" is whoever is named in the copyright or copyrights for the package. +"You" is you, if you're thinking about copying or distributing this Package. +"Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) +"Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: + +a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. + +b) use the modified Package only within your corporation or organization. + +c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. + +d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: + +a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. + +b) accompany the distribution with the machine-readable source of the Package with your modifications. + +c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. + +d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. + +6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. + +7. User Language Program subroutines and GCODE supplied by you and linked into this Package shall not be considered part of this Package. + +8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. + +9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +The End + diff --git a/trunk/ulp/docs/changelog.txt b/trunk/ulp/docs/changelog.txt new file mode 100644 index 00000000..a7d3a08a --- /dev/null +++ b/trunk/ulp/docs/changelog.txt @@ -0,0 +1,29 @@ +3.6.0.4 16-Jan-2013 John +Forgot to bump version numbers in ULPs. +Forgot to update changelog.txt. +I think the rakefile is finally creating the .zip file correctly. + +3.6.0.3 John +Went back to the old way of determining the path after the new way crashed and burned on Windows if there were spaces in the path (which is nearly always). + +3.6.0.2 02-Jan-2013 John +Moved pcbgcode.pdf and pcbgcode.tex into the docs folder. +Removed old documentation. + +Zip file now does not contain docs/figs/*, to save ~2MB in file size. + +Zip is now created in a pcb-gcode-version folder so files will unarchive into a folder. + +3.6.0.1 16-Dec-2012 John +Changed math.h to work with Eagle 5 or 6. Updated math.ulp to perform more tests on math.h to ensure conversions work correctly. + +Removed progress menu options in pcb-gcode-setup.ulp, as no one uses them, and it can confuse new users. + +Changed Isolation|Default label to Minimum. Globally changed DEFAULT_ISOLATE variable to ISO_MIN. + +Added a drill sub for the examples/04151_lcdi2c.drl file so it wouldn't complain about the 0.086in drill. +Added name of drill rack file to drill not found message in drill.h. + +Added a Single pass option. Maximum and Step size labels are changed to "not used" when Single pass is on. + +The path to pcb-gcode is no longer required to be the first entry in Eagle's Control Panel | Options | Directories. Should save some new users some trouble. diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.bot.drill.tap b/trunk/ulp/docs/examples/04151_lcdi2c.bot.drill.tap new file mode 100644 index 00000000..c7d06ace --- /dev/null +++ b/trunk/ulp/docs/examples/04151_lcdi2c.bot.drill.tap @@ -0,0 +1,130 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +( Tool| Size | Min Sub | Max Sub | Count ) +( T02 | 0.813mm 0.0320in | 0.0320in | 0.0320in | 49 ) +( T03 | 1.016mm 0.0400in | 0.0400in | 0.0400in | 17 ) +( T06 | 2.159mm 0.0850in | 0.0850in | 0.1250in | 5 ) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T02 ; 0.0320 +G01 Z0.0000 F10 +M06 T01 ; 0.0320 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.4100 Y1.0000 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.5100 Y1.0000 +G82 X-0.6000 Y0.2700 +G82 X-0.7234 Y0.6709 +G82 X-0.7628 Y0.7891 +G82 X-0.8000 Y0.3700 +G82 X-0.8021 Y0.6709 +G82 X-0.8415 Y0.7891 +G82 X-0.8809 Y0.6709 +G82 X-0.9202 Y0.7891 +G82 X-1.1000 Y0.2700 +G82 X-1.1300 Y1.1800 +G82 X-1.2300 Y1.1800 +G82 X-1.2700 Y0.2300 +G82 X-1.2700 Y0.3400 +G82 X-1.2700 Y0.4400 +G82 X-1.2700 Y0.5400 +G82 X-1.2700 Y0.6400 +G82 X-1.2700 Y0.7400 +G82 X-1.2700 Y0.8400 +G82 X-1.2700 Y0.9400 +G82 X-1.2700 Y1.0400 +G82 X-1.3700 Y0.2300 +G82 X-1.3900 Y1.1700 +G82 X-1.4400 Y1.2450 +G82 X-1.4900 Y1.1700 +G82 X-1.5700 Y0.3400 +G82 X-1.5700 Y0.4400 +G82 X-1.5700 Y0.5400 +G82 X-1.5700 Y0.6400 +G82 X-1.5700 Y0.7400 +G82 X-1.5700 Y0.8400 +G82 X-1.5700 Y0.9400 +G82 X-1.5700 Y1.0400 +G82 X-1.7500 Y1.1200 +G82 X-1.7500 Y1.2200 +G82 X-1.8000 Y0.4800 +G82 X-1.8000 Y0.6800 +G82 X-1.8500 Y0.1500 +G82 X-1.8500 Y0.2500 +G82 X-1.8500 Y0.3500 +G82 X-1.9200 Y0.4800 +G82 X-1.9200 Y0.6800 +G82 X-2.0400 Y0.4800 +G82 X-2.0400 Y0.6800 +G82 X-2.1500 Y0.1500 +G82 X-2.1500 Y0.2500 +G82 X-2.1500 Y0.3500 +M05 +G00 Z1.0000 +M06 T03 ; 0.0400 +G01 Z0.0000 F10 +M06 T02 ; 0.0400 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.1900 Y0.4000 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.1900 Y0.5000 +G82 X-0.1900 Y0.6000 +G82 X-0.1900 Y0.7000 +G82 X-0.1900 Y0.8000 +G82 X-0.1900 Y0.9000 +G82 X-0.1900 Y1.0000 +G82 X-0.2900 Y0.4000 +G82 X-0.2900 Y0.5000 +G82 X-0.2900 Y0.6000 +G82 X-0.2900 Y0.7000 +G82 X-0.2900 Y0.8000 +G82 X-0.2900 Y0.9000 +G82 X-0.2900 Y1.0000 +G82 X-2.0000 Y1.0300 +G82 X-2.3000 Y1.0300 +M05 +G00 Z1.0000 +M06 T06 ; 0.0850 +G01 Z0.0000 F10 +M06 T03 ; 0.0850 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.1500 Y0.1300 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.1500 Y1.1900 +G82 X-0.5029 Y0.7576 +G82 X-1.1171 Y0.7576 +T01 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.bot.etch.tap b/trunk/ulp/docs/examples/04151_lcdi2c.bot.etch.tap new file mode 100644 index 00000000..bdc5ffd2 --- /dev/null +++ b/trunk/ulp/docs/examples/04151_lcdi2c.bot.etch.tap @@ -0,0 +1,5982 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-1.3311 Y0.8601 +G01 Z-0.0070 F10 +G01 X-1.3211 Y0.8701 F20 +G01 X-1.3081 Y0.8755 +G01 X-1.2319 Y0.8755 +G01 X-1.2189 Y0.8701 +G01 X-1.2089 Y0.8601 +G01 X-1.2085 Y0.8592 +G01 X-1.1552 Y0.9125 +G01 X-1.1448 Y0.9125 +G01 X-0.4948 Y0.9125 +G01 X-0.4875 Y0.9052 +G01 X-0.3448 Y0.7625 +G01 X-0.3084 Y0.7625 +G01 X-0.3295 Y0.7836 +G01 X-0.3295 Y0.7875 +G01 X-0.3301 Y0.7875 +G01 X-0.3303 Y0.7873 +G01 X-0.3352 Y0.7875 +G01 X-0.3402 Y0.7875 +G01 X-0.3404 Y0.7877 +G01 X-0.3406 Y0.7877 +G01 X-0.3440 Y0.7913 +G01 X-0.3475 Y0.7948 +G01 X-0.3475 Y0.7951 +G01 X-0.4704 Y0.9275 +G01 X-1.2058 Y0.9275 +G01 X-1.2089 Y0.9199 +G01 X-1.2189 Y0.9099 +G01 X-1.2319 Y0.9045 +G01 X-1.3081 Y0.9045 +G01 X-1.3211 Y0.9099 +G01 X-1.3311 Y0.9199 +G01 X-1.3325 Y0.9233 +G01 X-1.3325 Y0.8567 +G01 X-1.3311 Y0.8601 +G00 Z0.1000 +G00 X-0.1702 Y0.5365 +G01 Z-0.0070 F10 +G01 X-0.1710 Y0.5368 F20 +G01 X-0.1525 Y0.5184 +G01 X-0.1525 Y0.5435 +G01 X-0.1630 Y0.5394 +G01 X-0.1648 Y0.5375 +G01 X-0.1676 Y0.5375 +G01 X-0.1702 Y0.5365 +G00 Z0.1000 +G00 X-0.2084 Y0.8625 +G01 Z-0.0070 F10 +G01 X-0.2295 Y0.8836 F20 +G01 X-0.2295 Y0.9164 +G01 X-0.2268 Y0.9191 +G01 X-0.2452 Y0.9375 +G01 X-0.2716 Y0.9375 +G01 X-0.2505 Y0.9164 +G01 X-0.2505 Y0.8836 +G01 X-0.2532 Y0.8809 +G01 X-0.2348 Y0.8625 +G01 X-0.2084 Y0.8625 +G00 Z0.1000 +G00 X-0.2295 Y0.6836 +G01 Z-0.0070 F10 +G01 X-0.2295 Y0.7164 F20 +G01 X-0.2064 Y0.7395 +G01 X-0.1736 Y0.7395 +G01 X-0.1505 Y0.7164 +G01 X-0.1505 Y0.6836 +G01 X-0.1641 Y0.6700 +G01 X-0.1425 Y0.6862 +G01 X-0.1425 Y0.8137 +G01 X-0.1641 Y0.8299 +G01 X-0.1505 Y0.8164 +G01 X-0.1505 Y0.7836 +G01 X-0.1736 Y0.7605 +G01 X-0.2064 Y0.7605 +G01 X-0.2091 Y0.7632 +G01 X-0.2275 Y0.7448 +G01 X-0.2348 Y0.7375 +G01 X-0.2716 Y0.7375 +G01 X-0.2505 Y0.7164 +G01 X-0.2505 Y0.6836 +G01 X-0.2716 Y0.6625 +G01 X-0.2084 Y0.6625 +G01 X-0.2295 Y0.6836 +G00 Z0.1000 +G00 X-0.2505 Y0.6164 +G01 Z-0.0070 F10 +G01 X-0.2505 Y0.5836 F20 +G01 X-0.2716 Y0.5625 +G01 X-0.2084 Y0.5625 +G01 X-0.2295 Y0.5836 +G01 X-0.2295 Y0.6164 +G01 X-0.2084 Y0.6375 +G01 X-0.2716 Y0.6375 +G01 X-0.2505 Y0.6164 +G00 Z0.1000 +G00 X-0.2064 Y0.4395 +G01 Z-0.0070 F10 +G01 X-0.1736 Y0.4395 F20 +G01 X-0.1525 Y0.4184 +G01 X-0.1525 Y0.4816 +G01 X-0.1736 Y0.4605 +G01 X-0.2064 Y0.4605 +G01 X-0.2091 Y0.4632 +G01 X-0.2275 Y0.4448 +G01 X-0.2275 Y0.4184 +G01 X-0.2064 Y0.4395 +G00 Z0.1000 +G00 X-1.5319 Y0.7045 +G01 Z-0.0070 F10 +G01 X-1.6081 Y0.7045 F20 +G01 X-1.6211 Y0.7099 +G01 X-1.6311 Y0.7199 +G01 X-1.6322 Y0.7225 +G01 X-1.6398 Y0.7225 +G01 X-1.6475 Y0.7148 +G01 X-1.6475 Y0.5748 +G01 X-1.6548 Y0.5675 +G01 X-1.6848 Y0.5375 +G01 X-1.6952 Y0.5375 +G01 X-2.0648 Y0.5375 +G01 X-2.0975 Y0.5048 +G01 X-2.0975 Y0.4702 +G01 X-2.0548 Y0.4275 +G01 X-2.0248 Y0.4275 +G01 X-2.0175 Y0.4202 +G01 X-1.9975 Y0.4002 +G01 X-1.9975 Y0.3898 +G01 X-1.9975 Y0.1852 +G01 X-1.9048 Y0.0925 +G01 X-0.5402 Y0.0925 +G01 X-0.2525 Y0.3802 +G01 X-0.2525 Y0.3816 +G01 X-0.2736 Y0.3605 +G01 X-0.3064 Y0.3605 +G01 X-0.3091 Y0.3632 +G01 X-0.5675 Y0.1048 +G01 X-0.5748 Y0.0975 +G01 X-1.4548 Y0.0975 +G01 X-1.4652 Y0.0975 +G01 X-1.5025 Y0.1348 +G01 X-1.5025 Y0.1452 +G01 X-1.5025 Y0.6194 +G01 X-1.5029 Y0.6240 +G01 X-1.5025 Y0.6245 +G01 X-1.5025 Y0.6252 +G01 X-1.4992 Y0.6284 +G01 X-1.4775 Y0.6545 +G01 X-1.4775 Y0.7953 +G01 X-1.5057 Y0.8275 +G01 X-1.5089 Y0.8199 +G01 X-1.5189 Y0.8099 +G01 X-1.5319 Y0.8045 +G01 X-1.6081 Y0.8045 +G01 X-1.6211 Y0.8099 +G01 X-1.6311 Y0.8199 +G01 X-1.6365 Y0.8329 +G01 X-1.6365 Y0.8471 +G01 X-1.6311 Y0.8601 +G01 X-1.6211 Y0.8701 +G01 X-1.6081 Y0.8755 +G01 X-1.5319 Y0.8755 +G01 X-1.5189 Y0.8701 +G01 X-1.5089 Y0.8601 +G01 X-1.5058 Y0.8525 +G01 X-1.5047 Y0.8525 +G01 X-1.5043 Y0.8528 +G01 X-1.4996 Y0.8525 +G01 X-1.4948 Y0.8525 +G01 X-1.4945 Y0.8522 +G01 X-1.4940 Y0.8521 +G01 X-1.4909 Y0.8485 +G01 X-1.4875 Y0.8452 +G01 X-1.4875 Y0.8447 +G01 X-1.4559 Y0.8086 +G01 X-1.4525 Y0.8052 +G01 X-1.4525 Y0.8047 +G01 X-1.4522 Y0.8043 +G01 X-1.4525 Y0.7996 +G01 X-1.4525 Y0.6506 +G01 X-1.4521 Y0.6460 +G01 X-1.4525 Y0.6455 +G01 X-1.4525 Y0.6448 +G01 X-1.4558 Y0.6416 +G01 X-1.4775 Y0.6155 +G01 X-1.4775 Y0.1452 +G01 X-1.4548 Y0.1225 +G01 X-0.5852 Y0.1225 +G01 X-0.3268 Y0.3809 +G01 X-0.3295 Y0.3836 +G01 X-0.3295 Y0.4164 +G01 X-0.3064 Y0.4395 +G01 X-0.2736 Y0.4395 +G01 X-0.2525 Y0.4184 +G01 X-0.2525 Y0.4448 +G01 X-0.2525 Y0.4552 +G01 X-0.2268 Y0.4809 +G01 X-0.2295 Y0.4836 +G01 X-0.2295 Y0.5164 +G01 X-0.2084 Y0.5375 +G01 X-0.2716 Y0.5375 +G01 X-0.2505 Y0.5164 +G01 X-0.2505 Y0.4836 +G01 X-0.2736 Y0.4605 +G01 X-0.3064 Y0.4605 +G01 X-0.3091 Y0.4632 +G01 X-0.3675 Y0.4048 +G01 X-0.3675 Y0.3648 +G01 X-0.3748 Y0.3575 +G01 X-0.5975 Y0.1348 +G01 X-0.6048 Y0.1275 +G01 X-1.4252 Y0.1275 +G01 X-1.4325 Y0.1348 +G01 X-1.4625 Y0.1648 +G01 X-1.4625 Y0.1752 +G01 X-1.4625 Y0.5991 +G01 X-1.4631 Y0.6034 +G01 X-1.4625 Y0.6042 +G01 X-1.4625 Y0.6052 +G01 X-1.4595 Y0.6082 +G01 X-1.4475 Y0.6242 +G01 X-1.4475 Y0.8251 +G01 X-1.4955 Y0.8775 +G01 X-1.6148 Y0.8775 +G01 X-1.6375 Y0.8548 +G01 X-1.6375 Y0.8152 +G01 X-1.6248 Y0.8025 +G01 X-1.5029 Y0.8025 +G01 X-1.5010 Y0.8035 +G01 X-1.4980 Y0.8025 +G01 X-1.4948 Y0.8025 +G01 X-1.4932 Y0.8009 +G01 X-1.4911 Y0.8002 +G01 X-1.4897 Y0.7974 +G01 X-1.4875 Y0.7952 +G01 X-1.4875 Y0.7929 +G01 X-1.4847 Y0.7874 +G01 X-1.4825 Y0.7852 +G01 X-1.4825 Y0.7829 +G01 X-1.4815 Y0.7810 +G01 X-1.4825 Y0.7780 +G01 X-1.4825 Y0.6706 +G01 X-1.4821 Y0.6660 +G01 X-1.4825 Y0.6655 +G01 X-1.4825 Y0.6648 +G01 X-1.4858 Y0.6616 +G01 X-1.5035 Y0.6403 +G01 X-1.5035 Y0.6329 +G01 X-1.5089 Y0.6199 +G01 X-1.5189 Y0.6099 +G01 X-1.5319 Y0.6045 +G01 X-1.6081 Y0.6045 +G01 X-1.6211 Y0.6099 +G01 X-1.6311 Y0.6199 +G01 X-1.6365 Y0.6329 +G01 X-1.6365 Y0.6471 +G01 X-1.6311 Y0.6601 +G01 X-1.6211 Y0.6701 +G01 X-1.6081 Y0.6755 +G01 X-1.5319 Y0.6755 +G01 X-1.5189 Y0.6701 +G01 X-1.5147 Y0.6659 +G01 X-1.5075 Y0.6745 +G01 X-1.5075 Y0.7233 +G01 X-1.5089 Y0.7199 +G01 X-1.5189 Y0.7099 +G01 X-1.5319 Y0.7045 +G00 Z0.1000 +G00 X-1.5319 Y0.3045 +G01 Z-0.0070 F10 +G01 X-1.5878 Y0.3045 F20 +G01 X-1.7407 Y0.1516 +G01 X-1.7436 Y0.1481 +G01 X-1.7443 Y0.1480 +G01 X-1.7448 Y0.1475 +G01 X-1.7494 Y0.1475 +G01 X-1.7835 Y0.1441 +G01 X-1.7835 Y0.1429 +G01 X-1.7889 Y0.1299 +G01 X-1.7989 Y0.1199 +G01 X-1.8119 Y0.1145 +G01 X-1.8881 Y0.1145 +G01 X-1.9011 Y0.1199 +G01 X-1.9111 Y0.1299 +G01 X-1.9165 Y0.1429 +G01 X-1.9165 Y0.1571 +G01 X-1.9163 Y0.1575 +G01 X-1.9746 Y0.2075 +G01 X-1.9752 Y0.2075 +G01 X-1.9785 Y0.2108 +G01 X-1.9821 Y0.2139 +G01 X-1.9821 Y0.2144 +G01 X-1.9825 Y0.2148 +G01 X-1.9825 Y0.2195 +G01 X-1.9829 Y0.2242 +G01 X-1.9825 Y0.2246 +G01 X-1.9825 Y0.3953 +G01 X-2.0255 Y0.4445 +G01 X-2.0547 Y0.4445 +G01 X-2.0755 Y0.4653 +G01 X-2.0755 Y0.4947 +G01 X-2.0547 Y0.5155 +G01 X-2.0253 Y0.5155 +G01 X-2.0045 Y0.4947 +G01 X-2.0045 Y0.4653 +G01 X-2.0077 Y0.4621 +G01 X-1.9609 Y0.4086 +G01 X-1.9575 Y0.4052 +G01 X-1.9575 Y0.4047 +G01 X-1.9572 Y0.4043 +G01 X-1.9575 Y0.3996 +G01 X-1.9575 Y0.2257 +G01 X-1.9026 Y0.1786 +G01 X-1.9011 Y0.1801 +G01 X-1.8881 Y0.1855 +G01 X-1.8119 Y0.1855 +G01 X-1.7989 Y0.1801 +G01 X-1.7889 Y0.1701 +G01 X-1.7883 Y0.1687 +G01 X-1.7557 Y0.1720 +G01 X-1.6187 Y0.3089 +G01 X-1.6211 Y0.3099 +G01 X-1.6311 Y0.3199 +G01 X-1.6365 Y0.3329 +G01 X-1.6365 Y0.3471 +G01 X-1.6311 Y0.3601 +G01 X-1.6211 Y0.3701 +G01 X-1.6081 Y0.3755 +G01 X-1.5319 Y0.3755 +G01 X-1.5189 Y0.3701 +G01 X-1.5089 Y0.3601 +G01 X-1.5035 Y0.3471 +G01 X-1.5035 Y0.3329 +G01 X-1.5089 Y0.3199 +G01 X-1.5189 Y0.3099 +G01 X-1.5319 Y0.3045 +G00 Z0.1000 +G00 X-1.5319 Y0.4045 +G01 Z-0.0070 F10 +G01 X-1.6081 Y0.4045 F20 +G01 X-1.6211 Y0.4099 +G01 X-1.6311 Y0.4199 +G01 X-1.6342 Y0.4275 +G01 X-1.6348 Y0.4275 +G01 X-1.7906 Y0.2718 +G01 X-1.7889 Y0.2701 +G01 X-1.7835 Y0.2571 +G01 X-1.7835 Y0.2429 +G01 X-1.7889 Y0.2299 +G01 X-1.7989 Y0.2199 +G01 X-1.8119 Y0.2145 +G01 X-1.8881 Y0.2145 +G01 X-1.9011 Y0.2199 +G01 X-1.9111 Y0.2299 +G01 X-1.9165 Y0.2429 +G01 X-1.9165 Y0.2566 +G01 X-1.9347 Y0.2725 +G01 X-1.9352 Y0.2725 +G01 X-1.9385 Y0.2759 +G01 X-1.9421 Y0.2790 +G01 X-1.9422 Y0.2795 +G01 X-1.9425 Y0.2798 +G01 X-1.9425 Y0.2846 +G01 X-1.9428 Y0.2893 +G01 X-1.9425 Y0.2897 +G01 X-1.9425 Y0.4523 +G01 X-1.9555 Y0.4653 +G01 X-1.9555 Y0.4947 +G01 X-1.9347 Y0.5155 +G01 X-1.9053 Y0.5155 +G01 X-1.8845 Y0.4947 +G01 X-1.8845 Y0.4653 +G01 X-1.9053 Y0.4445 +G01 X-1.9175 Y0.4445 +G01 X-1.9175 Y0.2907 +G01 X-1.9031 Y0.2781 +G01 X-1.9011 Y0.2801 +G01 X-1.8881 Y0.2855 +G01 X-1.8122 Y0.2855 +G01 X-1.6452 Y0.4525 +G01 X-1.6348 Y0.4525 +G01 X-1.6342 Y0.4525 +G01 X-1.6311 Y0.4601 +G01 X-1.6211 Y0.4701 +G01 X-1.6081 Y0.4755 +G01 X-1.5319 Y0.4755 +G01 X-1.5189 Y0.4701 +G01 X-1.5089 Y0.4601 +G01 X-1.5035 Y0.4471 +G01 X-1.5035 Y0.4329 +G01 X-1.5089 Y0.4199 +G01 X-1.5189 Y0.4099 +G01 X-1.5319 Y0.4045 +G00 Z0.1000 +G00 X-1.5319 Y0.5045 +G01 Z-0.0070 F10 +G01 X-1.6081 Y0.5045 F20 +G01 X-1.6211 Y0.5099 +G01 X-1.6268 Y0.5156 +G01 X-1.6675 Y0.4748 +G01 X-1.6748 Y0.4675 +G01 X-1.7645 Y0.4675 +G01 X-1.7645 Y0.4653 +G01 X-1.7853 Y0.4445 +G01 X-1.8078 Y0.4445 +G01 X-1.8375 Y0.4148 +G01 X-1.8375 Y0.3855 +G01 X-1.8119 Y0.3855 +G01 X-1.7989 Y0.3801 +G01 X-1.7889 Y0.3701 +G01 X-1.7835 Y0.3571 +G01 X-1.7835 Y0.3429 +G01 X-1.7889 Y0.3299 +G01 X-1.7989 Y0.3199 +G01 X-1.8119 Y0.3145 +G01 X-1.8881 Y0.3145 +G01 X-1.9011 Y0.3199 +G01 X-1.9111 Y0.3299 +G01 X-1.9165 Y0.3429 +G01 X-1.9165 Y0.3571 +G01 X-1.9111 Y0.3701 +G01 X-1.9011 Y0.3801 +G01 X-1.8881 Y0.3855 +G01 X-1.8625 Y0.3855 +G01 X-1.8625 Y0.4252 +G01 X-1.8552 Y0.4325 +G01 X-1.8289 Y0.4587 +G01 X-1.8355 Y0.4653 +G01 X-1.8355 Y0.4947 +G01 X-1.8147 Y0.5155 +G01 X-1.7853 Y0.5155 +G01 X-1.7645 Y0.4947 +G01 X-1.7645 Y0.4925 +G01 X-1.6852 Y0.4925 +G01 X-1.6365 Y0.5412 +G01 X-1.6365 Y0.5471 +G01 X-1.6311 Y0.5601 +G01 X-1.6211 Y0.5701 +G01 X-1.6081 Y0.5755 +G01 X-1.5319 Y0.5755 +G01 X-1.5189 Y0.5701 +G01 X-1.5089 Y0.5601 +G01 X-1.5035 Y0.5471 +G01 X-1.5035 Y0.5329 +G01 X-1.5089 Y0.5199 +G01 X-1.5189 Y0.5099 +G01 X-1.5319 Y0.5045 +G00 Z0.1000 +G00 X-0.8060 Y0.8581 +G01 Z-0.0070 F10 +G01 X-0.8060 Y0.7820 F20 +G01 X-0.8114 Y0.7689 +G01 X-0.8214 Y0.7590 +G01 X-0.8325 Y0.7544 +G01 X-0.8325 Y0.7498 +G01 X-0.8398 Y0.7425 +G01 X-0.8698 Y0.7125 +G01 X-0.8802 Y0.7125 +G01 X-0.9098 Y0.7125 +G01 X-0.9448 Y0.6775 +G01 X-0.9552 Y0.6775 +G01 X-1.3248 Y0.6775 +G01 X-1.3475 Y0.6548 +G01 X-1.3475 Y0.6152 +G01 X-1.3078 Y0.5755 +G01 X-1.2319 Y0.5755 +G01 X-1.2189 Y0.5701 +G01 X-1.2089 Y0.5601 +G01 X-1.2035 Y0.5471 +G01 X-1.2035 Y0.5329 +G01 X-1.2089 Y0.5199 +G01 X-1.2189 Y0.5099 +G01 X-1.2319 Y0.5045 +G01 X-1.3081 Y0.5045 +G01 X-1.3211 Y0.5099 +G01 X-1.3311 Y0.5199 +G01 X-1.3365 Y0.5329 +G01 X-1.3365 Y0.5471 +G01 X-1.3311 Y0.5601 +G01 X-1.3294 Y0.5618 +G01 X-1.3725 Y0.6048 +G01 X-1.3725 Y0.6152 +G01 X-1.3725 Y0.6652 +G01 X-1.3652 Y0.6725 +G01 X-1.3352 Y0.7025 +G01 X-1.3248 Y0.7025 +G01 X-0.9552 Y0.7025 +G01 X-0.9275 Y0.7302 +G01 X-0.9202 Y0.7375 +G01 X-0.8802 Y0.7375 +G01 X-0.8596 Y0.7581 +G01 X-0.8616 Y0.7590 +G01 X-0.8716 Y0.7689 +G01 X-0.8770 Y0.7820 +G01 X-0.8770 Y0.8581 +G01 X-0.8716 Y0.8712 +G01 X-0.8616 Y0.8811 +G01 X-0.8486 Y0.8866 +G01 X-0.8344 Y0.8866 +G01 X-0.8214 Y0.8811 +G01 X-0.8114 Y0.8712 +G01 X-0.8060 Y0.8581 +G00 Z0.1000 +G00 X-0.7589 Y0.6019 +G01 Z-0.0070 F10 +G01 X-0.7589 Y0.6780 F20 +G01 X-0.7535 Y0.6911 +G01 X-0.7435 Y0.7010 +G01 X-0.7304 Y0.7064 +G01 X-0.7163 Y0.7064 +G01 X-0.7033 Y0.7010 +G01 X-0.6933 Y0.6911 +G01 X-0.6879 Y0.6780 +G01 X-0.6879 Y0.6019 +G01 X-0.6933 Y0.5888 +G01 X-0.7033 Y0.5789 +G01 X-0.7075 Y0.5771 +G01 X-0.7075 Y0.5698 +G01 X-0.7148 Y0.5625 +G01 X-0.8398 Y0.4375 +G01 X-0.8502 Y0.4375 +G01 X-1.2035 Y0.4375 +G01 X-1.2035 Y0.4329 +G01 X-1.2089 Y0.4199 +G01 X-1.2189 Y0.4099 +G01 X-1.2319 Y0.4045 +G01 X-1.3081 Y0.4045 +G01 X-1.3211 Y0.4099 +G01 X-1.3311 Y0.4199 +G01 X-1.3365 Y0.4329 +G01 X-1.3365 Y0.4471 +G01 X-1.3311 Y0.4601 +G01 X-1.3211 Y0.4701 +G01 X-1.3081 Y0.4755 +G01 X-1.2319 Y0.4755 +G01 X-1.2189 Y0.4701 +G01 X-1.2113 Y0.4625 +G01 X-0.8502 Y0.4625 +G01 X-0.7366 Y0.5760 +G01 X-0.7435 Y0.5789 +G01 X-0.7535 Y0.5888 +G01 X-0.7589 Y0.6019 +G00 Z0.1000 +G00 X-0.8847 Y0.8581 +G01 Z-0.0070 F10 +G01 X-0.8847 Y0.7820 F20 +G01 X-0.8901 Y0.7689 +G01 X-0.9001 Y0.7590 +G01 X-0.9132 Y0.7536 +G01 X-0.9273 Y0.7536 +G01 X-0.9403 Y0.7590 +G01 X-0.9503 Y0.7689 +G01 X-0.9557 Y0.7820 +G01 X-0.9557 Y0.8075 +G01 X-1.1598 Y0.8075 +G01 X-1.1898 Y0.7775 +G01 X-1.2002 Y0.7775 +G01 X-1.3352 Y0.7775 +G01 X-1.3425 Y0.7848 +G01 X-1.3575 Y0.7998 +G01 X-1.3575 Y0.8102 +G01 X-1.3575 Y0.9798 +G01 X-1.5025 Y1.1248 +G01 X-1.5025 Y1.1345 +G01 X-1.5047 Y1.1345 +G01 X-1.5255 Y1.1553 +G01 X-1.5255 Y1.1847 +G01 X-1.5239 Y1.1863 +G01 X-1.5252 Y1.1875 +G01 X-1.7080 Y1.1875 +G01 X-1.7110 Y1.1865 +G01 X-1.7129 Y1.1875 +G01 X-1.7152 Y1.1875 +G01 X-1.7231 Y1.1797 +G01 X-1.7405 Y1.1725 +G01 X-1.7594 Y1.1725 +G01 X-1.7769 Y1.1797 +G01 X-1.7903 Y1.1931 +G01 X-1.7975 Y1.2105 +G01 X-1.7975 Y1.2294 +G01 X-1.7903 Y1.2469 +G01 X-1.7769 Y1.2603 +G01 X-1.7594 Y1.2675 +G01 X-1.7405 Y1.2675 +G01 X-1.7231 Y1.2603 +G01 X-1.7097 Y1.2469 +G01 X-1.7025 Y1.2294 +G01 X-1.7025 Y1.2125 +G01 X-1.5148 Y1.2125 +G01 X-1.5075 Y1.2052 +G01 X-1.5063 Y1.2039 +G01 X-1.5047 Y1.2055 +G01 X-1.4753 Y1.2055 +G01 X-1.4545 Y1.1847 +G01 X-1.4545 Y1.1553 +G01 X-1.4753 Y1.1345 +G01 X-1.4768 Y1.1345 +G01 X-1.3448 Y1.0025 +G01 X-1.3348 Y1.0025 +G01 X-0.5455 Y1.0025 +G01 X-0.5455 Y1.0147 +G01 X-0.5247 Y1.0355 +G01 X-0.4953 Y1.0355 +G01 X-0.4745 Y1.0147 +G01 X-0.4745 Y0.9853 +G01 X-0.4953 Y0.9645 +G01 X-0.5247 Y0.9645 +G01 X-0.5377 Y0.9775 +G01 X-1.3325 Y0.9775 +G01 X-1.3325 Y0.9567 +G01 X-1.3311 Y0.9601 +G01 X-1.3211 Y0.9701 +G01 X-1.3081 Y0.9755 +G01 X-1.2319 Y0.9755 +G01 X-1.2189 Y0.9701 +G01 X-1.2089 Y0.9601 +G01 X-1.2058 Y0.9525 +G01 X-0.4699 Y0.9525 +G01 X-0.4697 Y0.9527 +G01 X-0.4648 Y0.9525 +G01 X-0.4598 Y0.9525 +G01 X-0.4596 Y0.9523 +G01 X-0.4594 Y0.9523 +G01 X-0.4560 Y0.9487 +G01 X-0.4525 Y0.9452 +G01 X-0.4525 Y0.9449 +G01 X-0.3296 Y0.8125 +G01 X-0.3295 Y0.8164 +G01 X-0.3064 Y0.8395 +G01 X-0.2736 Y0.8395 +G01 X-0.2505 Y0.8164 +G01 X-0.2505 Y0.7836 +G01 X-0.2716 Y0.7625 +G01 X-0.2452 Y0.7625 +G01 X-0.2268 Y0.7809 +G01 X-0.2295 Y0.7836 +G01 X-0.2295 Y0.8164 +G01 X-0.2084 Y0.8375 +G01 X-0.2348 Y0.8375 +G01 X-0.2452 Y0.8375 +G01 X-0.2709 Y0.8632 +G01 X-0.2736 Y0.8605 +G01 X-0.3064 Y0.8605 +G01 X-0.3295 Y0.8836 +G01 X-0.3295 Y0.9164 +G01 X-0.3084 Y0.9375 +G01 X-0.4352 Y0.9375 +G01 X-0.4425 Y0.9448 +G01 X-0.4725 Y0.9748 +G01 X-0.4725 Y0.9852 +G01 X-0.4725 Y1.0148 +G01 X-0.4952 Y1.0375 +G01 X-1.2035 Y1.0375 +G01 X-1.2035 Y1.0329 +G01 X-1.2089 Y1.0199 +G01 X-1.2189 Y1.0099 +G01 X-1.2319 Y1.0045 +G01 X-1.3081 Y1.0045 +G01 X-1.3211 Y1.0099 +G01 X-1.3311 Y1.0199 +G01 X-1.3365 Y1.0329 +G01 X-1.3365 Y1.0471 +G01 X-1.3311 Y1.0601 +G01 X-1.3211 Y1.0701 +G01 X-1.3081 Y1.0755 +G01 X-1.2319 Y1.0755 +G01 X-1.2189 Y1.0701 +G01 X-1.2113 Y1.0625 +G01 X-0.4952 Y1.0625 +G01 X-0.4848 Y1.0625 +G01 X-0.4548 Y1.0325 +G01 X-0.4475 Y1.0252 +G01 X-0.4475 Y0.9852 +G01 X-0.4248 Y0.9625 +G01 X-0.3084 Y0.9625 +G01 X-0.3234 Y0.9775 +G01 X-0.3823 Y0.9775 +G01 X-0.3953 Y0.9645 +G01 X-0.4247 Y0.9645 +G01 X-0.4455 Y0.9853 +G01 X-0.4455 Y1.0147 +G01 X-0.4339 Y1.0263 +G01 X-0.5052 Y1.0975 +G01 X-1.1548 Y1.0975 +G01 X-1.1652 Y1.0975 +G01 X-1.2052 Y1.1376 +G01 X-1.2103 Y1.1325 +G01 X-1.2497 Y1.1325 +G01 X-1.2647 Y1.1476 +G01 X-1.2975 Y1.1148 +G01 X-1.3048 Y1.1075 +G01 X-1.4148 Y1.1075 +G01 X-1.4252 Y1.1075 +G01 X-1.4452 Y1.1275 +G01 X-1.4525 Y1.1348 +G01 X-1.4525 Y1.2095 +G01 X-1.4547 Y1.2095 +G01 X-1.4755 Y1.2303 +G01 X-1.4755 Y1.2597 +G01 X-1.4739 Y1.2613 +G01 X-1.4902 Y1.2775 +G01 X-1.7648 Y1.2775 +G01 X-1.8075 Y1.2348 +G01 X-1.8075 Y1.1952 +G01 X-1.7747 Y1.1624 +G01 X-1.7697 Y1.1675 +G01 X-1.7303 Y1.1675 +G01 X-1.7025 Y1.1397 +G01 X-1.7025 Y1.1003 +G01 X-1.7303 Y1.0725 +G01 X-1.7697 Y1.0725 +G01 X-1.7975 Y1.1003 +G01 X-1.7975 Y1.1397 +G01 X-1.7924 Y1.1447 +G01 X-1.8252 Y1.1775 +G01 X-2.2948 Y1.1775 +G01 X-2.3975 Y1.0748 +G01 X-2.3975 Y0.9952 +G01 X-2.3548 Y0.9525 +G01 X-2.1952 Y0.9525 +G01 X-2.1125 Y1.0352 +G01 X-2.1125 Y1.0652 +G01 X-2.1052 Y1.0725 +G01 X-2.0452 Y1.1325 +G01 X-2.0348 Y1.1325 +G01 X-1.9648 Y1.1325 +G01 X-1.9575 Y1.1252 +G01 X-1.9075 Y1.0752 +G01 X-1.9075 Y1.0648 +G01 X-1.9075 Y0.9902 +G01 X-1.8848 Y0.9675 +G01 X-1.7948 Y0.9675 +G01 X-1.7352 Y0.9675 +G01 X-1.6702 Y1.0325 +G01 X-1.6598 Y1.0325 +G01 X-1.6363 Y1.0325 +G01 X-1.6365 Y1.0329 +G01 X-1.6365 Y1.0471 +G01 X-1.6311 Y1.0601 +G01 X-1.6211 Y1.0701 +G01 X-1.6081 Y1.0755 +G01 X-1.5319 Y1.0755 +G01 X-1.5189 Y1.0701 +G01 X-1.5089 Y1.0601 +G01 X-1.5035 Y1.0471 +G01 X-1.5035 Y1.0329 +G01 X-1.5040 Y1.0318 +G01 X-1.5011 Y1.0287 +G01 X-1.4975 Y1.0252 +G01 X-1.4975 Y1.0250 +G01 X-1.3960 Y0.9187 +G01 X-1.3925 Y0.9152 +G01 X-1.3925 Y0.9150 +G01 X-1.3924 Y0.9149 +G01 X-1.3925 Y0.9098 +G01 X-1.3925 Y0.5502 +G01 X-1.3875 Y0.5452 +G01 X-1.3875 Y0.5348 +G01 X-1.3925 Y0.5298 +G01 X-1.3925 Y0.5025 +G01 X-0.8902 Y0.5025 +G01 X-0.8163 Y0.5764 +G01 X-0.8222 Y0.5789 +G01 X-0.8322 Y0.5888 +G01 X-0.8376 Y0.6019 +G01 X-0.8376 Y0.6780 +G01 X-0.8322 Y0.6911 +G01 X-0.8222 Y0.7010 +G01 X-0.8092 Y0.7064 +G01 X-0.7951 Y0.7064 +G01 X-0.7820 Y0.7010 +G01 X-0.7720 Y0.6911 +G01 X-0.7666 Y0.6780 +G01 X-0.7666 Y0.6019 +G01 X-0.7720 Y0.5888 +G01 X-0.7820 Y0.5789 +G01 X-0.7875 Y0.5766 +G01 X-0.7875 Y0.5698 +G01 X-0.8798 Y0.4775 +G01 X-0.8902 Y0.4775 +G01 X-1.3925 Y0.4775 +G01 X-1.3925 Y0.3552 +G01 X-1.3648 Y0.3275 +G01 X-1.3575 Y0.3202 +G01 X-1.3575 Y0.2655 +G01 X-1.3553 Y0.2655 +G01 X-1.3345 Y0.2447 +G01 X-1.3345 Y0.2222 +G01 X-1.3048 Y0.1925 +G01 X-1.0352 Y0.1925 +G01 X-0.9552 Y0.2725 +G01 X-0.9448 Y0.2725 +G01 X-0.6665 Y0.2725 +G01 X-0.6665 Y0.2771 +G01 X-0.6611 Y0.2901 +G01 X-0.6511 Y0.3001 +G01 X-0.6381 Y0.3055 +G01 X-0.5619 Y0.3055 +G01 X-0.5489 Y0.3001 +G01 X-0.5389 Y0.2901 +G01 X-0.5335 Y0.2771 +G01 X-0.5335 Y0.2629 +G01 X-0.5389 Y0.2499 +G01 X-0.5489 Y0.2399 +G01 X-0.5619 Y0.2345 +G01 X-0.6381 Y0.2345 +G01 X-0.6511 Y0.2399 +G01 X-0.6587 Y0.2475 +G01 X-0.9448 Y0.2475 +G01 X-1.0175 Y0.1748 +G01 X-1.0248 Y0.1675 +G01 X-1.3048 Y0.1675 +G01 X-1.3152 Y0.1675 +G01 X-1.3487 Y0.2011 +G01 X-1.3553 Y0.1945 +G01 X-1.3847 Y0.1945 +G01 X-1.4055 Y0.2153 +G01 X-1.4055 Y0.2447 +G01 X-1.3847 Y0.2655 +G01 X-1.3825 Y0.2655 +G01 X-1.3825 Y0.3098 +G01 X-1.4175 Y0.3448 +G01 X-1.4175 Y0.3552 +G01 X-1.4175 Y0.4952 +G01 X-1.4175 Y0.5298 +G01 X-1.4175 Y0.5348 +G01 X-1.4175 Y0.9050 +G01 X-1.5153 Y1.0075 +G01 X-1.5247 Y1.0075 +G01 X-1.5319 Y1.0045 +G01 X-1.6081 Y1.0045 +G01 X-1.6153 Y1.0075 +G01 X-1.6598 Y1.0075 +G01 X-1.7175 Y0.9498 +G01 X-1.7248 Y0.9425 +G01 X-1.7875 Y0.9425 +G01 X-1.7875 Y0.7155 +G01 X-1.7853 Y0.7155 +G01 X-1.7645 Y0.6947 +G01 X-1.7645 Y0.6653 +G01 X-1.7853 Y0.6445 +G01 X-1.8147 Y0.6445 +G01 X-1.8277 Y0.6575 +G01 X-1.8923 Y0.6575 +G01 X-1.9053 Y0.6445 +G01 X-1.9347 Y0.6445 +G01 X-1.9477 Y0.6575 +G01 X-2.0123 Y0.6575 +G01 X-2.0253 Y0.6445 +G01 X-2.0547 Y0.6445 +G01 X-2.0755 Y0.6653 +G01 X-2.0755 Y0.6947 +G01 X-2.0547 Y0.7155 +G01 X-2.0253 Y0.7155 +G01 X-2.0045 Y0.6947 +G01 X-2.0045 Y0.6825 +G01 X-1.9555 Y0.6825 +G01 X-1.9555 Y0.6947 +G01 X-1.9347 Y0.7155 +G01 X-1.9053 Y0.7155 +G01 X-1.8845 Y0.6947 +G01 X-1.8845 Y0.6825 +G01 X-1.8355 Y0.6825 +G01 X-1.8355 Y0.6947 +G01 X-1.8147 Y0.7155 +G01 X-1.8125 Y0.7155 +G01 X-1.8125 Y0.9425 +G01 X-1.8848 Y0.9425 +G01 X-1.8952 Y0.9425 +G01 X-1.9325 Y0.9798 +G01 X-1.9325 Y0.9902 +G01 X-1.9325 Y1.0648 +G01 X-1.9752 Y1.1075 +G01 X-2.0348 Y1.1075 +G01 X-2.0875 Y1.0548 +G01 X-2.0875 Y1.0352 +G01 X-2.0875 Y1.0248 +G01 X-2.1775 Y0.9348 +G01 X-2.1848 Y0.9275 +G01 X-2.3548 Y0.9275 +G01 X-2.3652 Y0.9275 +G01 X-2.4152 Y0.9775 +G01 X-2.4225 Y0.9848 +G01 X-2.4225 Y1.0748 +G01 X-2.4225 Y1.0852 +G01 X-2.3125 Y1.1952 +G01 X-2.3052 Y1.2025 +G01 X-1.8325 Y1.2025 +G01 X-1.8325 Y1.2348 +G01 X-1.8325 Y1.2452 +G01 X-1.7825 Y1.2952 +G01 X-1.7752 Y1.3025 +G01 X-1.4798 Y1.3025 +G01 X-1.4725 Y1.2952 +G01 X-1.4563 Y1.2789 +G01 X-1.4547 Y1.2805 +G01 X-1.4253 Y1.2805 +G01 X-1.4045 Y1.2597 +G01 X-1.4045 Y1.2303 +G01 X-1.4253 Y1.2095 +G01 X-1.4275 Y1.2095 +G01 X-1.4275 Y1.1452 +G01 X-1.4148 Y1.1325 +G01 X-1.3152 Y1.1325 +G01 X-1.2809 Y1.1668 +G01 X-1.2802 Y1.1689 +G01 X-1.2775 Y1.1702 +G01 X-1.2775 Y1.1997 +G01 X-1.2497 Y1.2275 +G01 X-1.2103 Y1.2275 +G01 X-1.1825 Y1.1997 +G01 X-1.1825 Y1.1603 +G01 X-1.1876 Y1.1552 +G01 X-1.1548 Y1.1225 +G01 X-0.4948 Y1.1225 +G01 X-0.4875 Y1.1152 +G01 X-0.4078 Y1.0355 +G01 X-0.3953 Y1.0355 +G01 X-0.3745 Y1.0147 +G01 X-0.3745 Y1.0025 +G01 X-0.3295 Y1.0025 +G01 X-0.3295 Y1.0164 +G01 X-0.3064 Y1.0395 +G01 X-0.2736 Y1.0395 +G01 X-0.2505 Y1.0164 +G01 X-0.2505 Y0.9836 +G01 X-0.2716 Y0.9625 +G01 X-0.2452 Y0.9625 +G01 X-0.2348 Y0.9625 +G01 X-0.2091 Y0.9368 +G01 X-0.2064 Y0.9395 +G01 X-0.1736 Y0.9395 +G01 X-0.1505 Y0.9164 +G01 X-0.1505 Y0.8836 +G01 X-0.1716 Y0.8625 +G01 X-0.1709 Y0.8625 +G01 X-0.1666 Y0.8631 +G01 X-0.1658 Y0.8625 +G01 X-0.1648 Y0.8625 +G01 X-0.1618 Y0.8595 +G01 X-0.1258 Y0.8325 +G01 X-0.1248 Y0.8325 +G01 X-0.1218 Y0.8295 +G01 X-0.1184 Y0.8269 +G01 X-0.1182 Y0.8259 +G01 X-0.1175 Y0.8252 +G01 X-0.1175 Y0.8209 +G01 X-0.1169 Y0.8166 +G01 X-0.1175 Y0.8158 +G01 X-0.1175 Y0.6842 +G01 X-0.1169 Y0.6834 +G01 X-0.1175 Y0.6791 +G01 X-0.1175 Y0.6748 +G01 X-0.1182 Y0.6741 +G01 X-0.1184 Y0.6731 +G01 X-0.1218 Y0.6705 +G01 X-0.1248 Y0.6675 +G01 X-0.1258 Y0.6675 +G01 X-0.1618 Y0.6405 +G01 X-0.1648 Y0.6375 +G01 X-0.1658 Y0.6375 +G01 X-0.1666 Y0.6369 +G01 X-0.1709 Y0.6375 +G01 X-0.1716 Y0.6375 +G01 X-0.1505 Y0.6164 +G01 X-0.1505 Y0.5836 +G01 X-0.1711 Y0.5630 +G01 X-0.1520 Y0.5706 +G01 X-0.1502 Y0.5725 +G01 X-0.1125 Y0.6102 +G01 X-0.1125 Y0.9096 +G01 X-0.1701 Y0.9640 +G01 X-0.1736 Y0.9605 +G01 X-0.2064 Y0.9605 +G01 X-0.2295 Y0.9836 +G01 X-0.2295 Y1.0164 +G01 X-0.2243 Y1.0216 +G01 X-0.3502 Y1.1475 +G01 X-1.0880 Y1.1475 +G01 X-1.0910 Y1.1465 +G01 X-1.0929 Y1.1475 +G01 X-1.0952 Y1.1475 +G01 X-1.1031 Y1.1397 +G01 X-1.1205 Y1.1325 +G01 X-1.1394 Y1.1325 +G01 X-1.1569 Y1.1397 +G01 X-1.1703 Y1.1531 +G01 X-1.1775 Y1.1705 +G01 X-1.1775 Y1.1894 +G01 X-1.1715 Y1.2039 +G01 X-1.2052 Y1.2375 +G01 X-1.2448 Y1.2375 +G01 X-1.3148 Y1.1675 +G01 X-1.3252 Y1.1675 +G01 X-1.3545 Y1.1675 +G01 X-1.3545 Y1.1553 +G01 X-1.3753 Y1.1345 +G01 X-1.4047 Y1.1345 +G01 X-1.4255 Y1.1553 +G01 X-1.4255 Y1.1847 +G01 X-1.4047 Y1.2055 +G01 X-1.3753 Y1.2055 +G01 X-1.3623 Y1.1925 +G01 X-1.3252 Y1.1925 +G01 X-1.2625 Y1.2552 +G01 X-1.2552 Y1.2625 +G01 X-1.2052 Y1.2625 +G01 X-1.1948 Y1.2625 +G01 X-1.1539 Y1.2215 +G01 X-1.1394 Y1.2275 +G01 X-1.1205 Y1.2275 +G01 X-1.1031 Y1.2203 +G01 X-1.0897 Y1.2069 +G01 X-1.0825 Y1.1894 +G01 X-1.0825 Y1.1725 +G01 X-0.3502 Y1.1725 +G01 X-0.3398 Y1.1725 +G01 X-0.2066 Y1.0393 +G01 X-0.2064 Y1.0395 +G01 X-0.1736 Y1.0395 +G01 X-0.1505 Y1.0164 +G01 X-0.1505 Y0.9836 +G01 X-0.1524 Y0.9817 +G01 X-0.0950 Y0.9275 +G01 X-0.0948 Y0.9275 +G01 X-0.0913 Y0.9239 +G01 X-0.0877 Y0.9205 +G01 X-0.0876 Y0.9203 +G01 X-0.0875 Y0.9202 +G01 X-0.0875 Y0.9151 +G01 X-0.0874 Y0.9102 +G01 X-0.0875 Y0.9100 +G01 X-0.0875 Y0.5998 +G01 X-0.0948 Y0.5925 +G01 X-0.1275 Y0.5598 +G01 X-0.1275 Y0.3652 +G01 X-0.1275 Y0.3548 +G01 X-0.4748 Y0.0075 +G01 X-0.4852 Y0.0075 +G01 X-2.2352 Y0.0075 +G01 X-2.2425 Y0.0148 +G01 X-2.3352 Y0.1075 +G01 X-2.3425 Y0.1148 +G01 X-2.3425 Y0.3448 +G01 X-2.3425 Y0.3552 +G01 X-2.3425 Y0.7748 +G01 X-2.3425 Y0.7852 +G01 X-2.2802 Y0.8475 +G01 X-2.2698 Y0.8475 +G01 X-2.1902 Y0.8475 +G01 X-2.0424 Y0.9953 +G01 X-2.0545 Y1.0074 +G01 X-2.0545 Y1.0526 +G01 X-2.0226 Y1.0845 +G01 X-1.9774 Y1.0845 +G01 X-1.9455 Y1.0526 +G01 X-1.9455 Y1.0074 +G01 X-1.9774 Y0.9755 +G01 X-2.0226 Y0.9755 +G01 X-2.0247 Y0.9776 +G01 X-2.1725 Y0.8298 +G01 X-2.1798 Y0.8225 +G01 X-2.2698 Y0.8225 +G01 X-2.3175 Y0.7748 +G01 X-2.3175 Y0.3625 +G01 X-2.2142 Y0.3625 +G01 X-2.2111 Y0.3701 +G01 X-2.2011 Y0.3801 +G01 X-2.1881 Y0.3855 +G01 X-2.1119 Y0.3855 +G01 X-2.0989 Y0.3801 +G01 X-2.0889 Y0.3701 +G01 X-2.0835 Y0.3571 +G01 X-2.0835 Y0.3429 +G01 X-2.0889 Y0.3299 +G01 X-2.0989 Y0.3199 +G01 X-2.1013 Y0.3189 +G01 X-2.0975 Y0.3152 +G01 X-2.0975 Y0.3048 +G01 X-2.0975 Y0.2787 +G01 X-2.0889 Y0.2701 +G01 X-2.0835 Y0.2571 +G01 X-2.0835 Y0.2429 +G01 X-2.0889 Y0.2299 +G01 X-2.0989 Y0.2199 +G01 X-2.1013 Y0.2189 +G01 X-2.0975 Y0.2152 +G01 X-2.0975 Y0.2048 +G01 X-2.0975 Y0.1787 +G01 X-2.0889 Y0.1701 +G01 X-2.0835 Y0.1571 +G01 X-2.0835 Y0.1429 +G01 X-2.0889 Y0.1299 +G01 X-2.0989 Y0.1199 +G01 X-2.1119 Y0.1145 +G01 X-2.1881 Y0.1145 +G01 X-2.2011 Y0.1199 +G01 X-2.2111 Y0.1299 +G01 X-2.2165 Y0.1429 +G01 X-2.2165 Y0.1571 +G01 X-2.2111 Y0.1701 +G01 X-2.2011 Y0.1801 +G01 X-2.1881 Y0.1855 +G01 X-2.1225 Y0.1855 +G01 X-2.1225 Y0.2048 +G01 X-2.1322 Y0.2145 +G01 X-2.1881 Y0.2145 +G01 X-2.2011 Y0.2199 +G01 X-2.2111 Y0.2299 +G01 X-2.2165 Y0.2429 +G01 X-2.2165 Y0.2571 +G01 X-2.2111 Y0.2701 +G01 X-2.2011 Y0.2801 +G01 X-2.1881 Y0.2855 +G01 X-2.1225 Y0.2855 +G01 X-2.1225 Y0.3048 +G01 X-2.1322 Y0.3145 +G01 X-2.1881 Y0.3145 +G01 X-2.2011 Y0.3199 +G01 X-2.2111 Y0.3299 +G01 X-2.2142 Y0.3375 +G01 X-2.3175 Y0.3375 +G01 X-2.3175 Y0.1252 +G01 X-2.2248 Y0.0325 +G01 X-0.4852 Y0.0325 +G01 X-0.1525 Y0.3652 +G01 X-0.1525 Y0.3816 +G01 X-0.1736 Y0.3605 +G01 X-0.1818 Y0.3605 +G01 X-0.4975 Y0.0448 +G01 X-0.5048 Y0.0375 +G01 X-2.0502 Y0.0375 +G01 X-2.0575 Y0.0448 +G01 X-2.0702 Y0.0575 +G01 X-2.0775 Y0.0648 +G01 X-2.0775 Y0.3735 +G01 X-2.1540 Y0.4275 +G01 X-2.1552 Y0.4275 +G01 X-2.1581 Y0.4304 +G01 X-2.1614 Y0.4328 +G01 X-2.1616 Y0.4340 +G01 X-2.1625 Y0.4348 +G01 X-2.1625 Y0.4389 +G01 X-2.1632 Y0.4430 +G01 X-2.1625 Y0.4440 +G01 X-2.1625 Y0.5248 +G01 X-2.1625 Y0.5352 +G01 X-2.0952 Y0.6025 +G01 X-2.0848 Y0.6025 +G01 X-1.7552 Y0.6025 +G01 X-1.7225 Y0.6352 +G01 X-1.7225 Y0.9152 +G01 X-1.7152 Y0.9225 +G01 X-1.6925 Y0.9452 +G01 X-1.6852 Y0.9525 +G01 X-1.6342 Y0.9525 +G01 X-1.6311 Y0.9601 +G01 X-1.6211 Y0.9701 +G01 X-1.6081 Y0.9755 +G01 X-1.5319 Y0.9755 +G01 X-1.5189 Y0.9701 +G01 X-1.5089 Y0.9601 +G01 X-1.5035 Y0.9471 +G01 X-1.5035 Y0.9329 +G01 X-1.5089 Y0.9199 +G01 X-1.5189 Y0.9099 +G01 X-1.5319 Y0.9045 +G01 X-1.6081 Y0.9045 +G01 X-1.6211 Y0.9099 +G01 X-1.6311 Y0.9199 +G01 X-1.6342 Y0.9275 +G01 X-1.6748 Y0.9275 +G01 X-1.6975 Y0.9048 +G01 X-1.6975 Y0.6352 +G01 X-1.6975 Y0.6248 +G01 X-1.7375 Y0.5848 +G01 X-1.7448 Y0.5775 +G01 X-2.0848 Y0.5775 +G01 X-2.1375 Y0.5248 +G01 X-2.1375 Y0.4465 +G01 X-2.0610 Y0.3925 +G01 X-2.0598 Y0.3925 +G01 X-2.0569 Y0.3896 +G01 X-2.0536 Y0.3872 +G01 X-2.0534 Y0.3860 +G01 X-2.0525 Y0.3852 +G01 X-2.0525 Y0.3811 +G01 X-2.0518 Y0.3770 +G01 X-2.0525 Y0.3760 +G01 X-2.0525 Y0.0752 +G01 X-2.0398 Y0.0625 +G01 X-0.5152 Y0.0625 +G01 X-0.2118 Y0.3659 +G01 X-0.2275 Y0.3816 +G01 X-0.2275 Y0.3802 +G01 X-0.2275 Y0.3698 +G01 X-0.5298 Y0.0675 +G01 X-0.5402 Y0.0675 +G01 X-1.9152 Y0.0675 +G01 X-1.9225 Y0.0748 +G01 X-2.0152 Y0.1675 +G01 X-2.0225 Y0.1748 +G01 X-2.0225 Y0.3898 +G01 X-2.0352 Y0.4025 +G01 X-2.0548 Y0.4025 +G01 X-2.0652 Y0.4025 +G01 X-2.1225 Y0.4598 +G01 X-2.1225 Y0.4702 +G01 X-2.1225 Y0.5152 +G01 X-2.1152 Y0.5225 +G01 X-2.0825 Y0.5552 +G01 X-2.0752 Y0.5625 +G01 X-1.6952 Y0.5625 +G01 X-1.6725 Y0.5852 +G01 X-1.6725 Y0.7148 +G01 X-1.6725 Y0.7252 +G01 X-1.6575 Y0.7402 +G01 X-1.6502 Y0.7475 +G01 X-1.6363 Y0.7475 +G01 X-1.6311 Y0.7601 +G01 X-1.6211 Y0.7701 +G01 X-1.6081 Y0.7755 +G01 X-1.5319 Y0.7755 +G01 X-1.5189 Y0.7701 +G01 X-1.5089 Y0.7601 +G01 X-1.5075 Y0.7567 +G01 X-1.5075 Y0.7770 +G01 X-1.5077 Y0.7775 +G01 X-1.6248 Y0.7775 +G01 X-1.6352 Y0.7775 +G01 X-1.6552 Y0.7975 +G01 X-1.6625 Y0.8048 +G01 X-1.6625 Y0.8548 +G01 X-1.6625 Y0.8652 +G01 X-1.6325 Y0.8952 +G01 X-1.6252 Y0.9025 +G01 X-1.4949 Y0.9025 +G01 X-1.4946 Y0.9027 +G01 X-1.4897 Y0.9025 +G01 X-1.4848 Y0.9025 +G01 X-1.4846 Y0.9023 +G01 X-1.4843 Y0.9023 +G01 X-1.4810 Y0.8987 +G01 X-1.4775 Y0.8952 +G01 X-1.4775 Y0.8949 +G01 X-1.4260 Y0.8386 +G01 X-1.4225 Y0.8352 +G01 X-1.4225 Y0.8349 +G01 X-1.4223 Y0.8346 +G01 X-1.4225 Y0.8297 +G01 X-1.4225 Y0.6209 +G01 X-1.4219 Y0.6166 +G01 X-1.4225 Y0.6158 +G01 X-1.4225 Y0.6148 +G01 X-1.4255 Y0.6118 +G01 X-1.4375 Y0.5958 +G01 X-1.4375 Y0.1752 +G01 X-1.4148 Y0.1525 +G01 X-0.6152 Y0.1525 +G01 X-0.3925 Y0.3752 +G01 X-0.3925 Y0.4048 +G01 X-0.3925 Y0.4152 +G01 X-0.3268 Y0.4809 +G01 X-0.3295 Y0.4836 +G01 X-0.3295 Y0.5164 +G01 X-0.3084 Y0.5375 +G01 X-0.3298 Y0.5375 +G01 X-0.5125 Y0.3548 +G01 X-0.5198 Y0.3475 +G01 X-0.6498 Y0.3475 +G01 X-0.6925 Y0.3048 +G01 X-0.6998 Y0.2975 +G01 X-0.9248 Y0.2975 +G01 X-0.9352 Y0.2975 +G01 X-0.9748 Y0.2975 +G01 X-1.0048 Y0.2675 +G01 X-1.0152 Y0.2675 +G01 X-1.0335 Y0.2675 +G01 X-1.0335 Y0.2629 +G01 X-1.0389 Y0.2499 +G01 X-1.0489 Y0.2399 +G01 X-1.0619 Y0.2345 +G01 X-1.1381 Y0.2345 +G01 X-1.1511 Y0.2399 +G01 X-1.1611 Y0.2499 +G01 X-1.1665 Y0.2629 +G01 X-1.1665 Y0.2771 +G01 X-1.1660 Y0.2783 +G01 X-1.2085 Y0.3208 +G01 X-1.2089 Y0.3199 +G01 X-1.2189 Y0.3099 +G01 X-1.2319 Y0.3045 +G01 X-1.2475 Y0.3045 +G01 X-1.2475 Y0.2577 +G01 X-1.2345 Y0.2447 +G01 X-1.2345 Y0.2153 +G01 X-1.2553 Y0.1945 +G01 X-1.2847 Y0.1945 +G01 X-1.3055 Y0.2153 +G01 X-1.3055 Y0.2447 +G01 X-1.2847 Y0.2655 +G01 X-1.2725 Y0.2655 +G01 X-1.2725 Y0.3045 +G01 X-1.3081 Y0.3045 +G01 X-1.3211 Y0.3099 +G01 X-1.3311 Y0.3199 +G01 X-1.3365 Y0.3329 +G01 X-1.3365 Y0.3471 +G01 X-1.3311 Y0.3601 +G01 X-1.3211 Y0.3701 +G01 X-1.3081 Y0.3755 +G01 X-1.2319 Y0.3755 +G01 X-1.2189 Y0.3701 +G01 X-1.2089 Y0.3601 +G01 X-1.2064 Y0.3541 +G01 X-1.1518 Y0.2994 +G01 X-1.1511 Y0.3001 +G01 X-1.1381 Y0.3055 +G01 X-1.0619 Y0.3055 +G01 X-1.0489 Y0.3001 +G01 X-1.0413 Y0.2925 +G01 X-1.0152 Y0.2925 +G01 X-0.9852 Y0.3225 +G01 X-0.9748 Y0.3225 +G01 X-0.9375 Y0.3225 +G01 X-0.9375 Y0.4252 +G01 X-0.9302 Y0.4325 +G01 X-0.9198 Y0.4325 +G01 X-0.8202 Y0.4325 +G01 X-0.6825 Y0.5702 +G01 X-0.6825 Y0.6848 +G01 X-0.7525 Y0.7549 +G01 X-0.7557 Y0.7536 +G01 X-0.7698 Y0.7536 +G01 X-0.7829 Y0.7590 +G01 X-0.7928 Y0.7689 +G01 X-0.7983 Y0.7820 +G01 X-0.7983 Y0.8581 +G01 X-0.7928 Y0.8712 +G01 X-0.7829 Y0.8811 +G01 X-0.7698 Y0.8866 +G01 X-0.7557 Y0.8866 +G01 X-0.7426 Y0.8811 +G01 X-0.7327 Y0.8712 +G01 X-0.7273 Y0.8581 +G01 X-0.7273 Y0.7820 +G01 X-0.7323 Y0.7699 +G01 X-0.6575 Y0.6952 +G01 X-0.6575 Y0.6848 +G01 X-0.6575 Y0.5702 +G01 X-0.6575 Y0.5598 +G01 X-0.8025 Y0.4148 +G01 X-0.8098 Y0.4075 +G01 X-0.9125 Y0.4075 +G01 X-0.9125 Y0.3225 +G01 X-0.7102 Y0.3225 +G01 X-0.6602 Y0.3725 +G01 X-0.6498 Y0.3725 +G01 X-0.5302 Y0.3725 +G01 X-0.3402 Y0.5625 +G01 X-0.3298 Y0.5625 +G01 X-0.3084 Y0.5625 +G01 X-0.3295 Y0.5836 +G01 X-0.3295 Y0.6164 +G01 X-0.3084 Y0.6375 +G01 X-0.3348 Y0.6375 +G01 X-0.4675 Y0.5048 +G01 X-0.4675 Y0.4998 +G01 X-0.5425 Y0.4248 +G01 X-0.5498 Y0.4175 +G01 X-0.6898 Y0.4175 +G01 X-0.7335 Y0.3738 +G01 X-0.7335 Y0.3629 +G01 X-0.7389 Y0.3499 +G01 X-0.7489 Y0.3399 +G01 X-0.7619 Y0.3345 +G01 X-0.8381 Y0.3345 +G01 X-0.8511 Y0.3399 +G01 X-0.8611 Y0.3499 +G01 X-0.8665 Y0.3629 +G01 X-0.8665 Y0.3771 +G01 X-0.8611 Y0.3901 +G01 X-0.8511 Y0.4001 +G01 X-0.8381 Y0.4055 +G01 X-0.7619 Y0.4055 +G01 X-0.7489 Y0.4001 +G01 X-0.7457 Y0.3969 +G01 X-0.7002 Y0.4425 +G01 X-0.6898 Y0.4425 +G01 X-0.5602 Y0.4425 +G01 X-0.4925 Y0.5102 +G01 X-0.4925 Y0.5152 +G01 X-0.4852 Y0.5225 +G01 X-0.3452 Y0.6625 +G01 X-0.3348 Y0.6625 +G01 X-0.3084 Y0.6625 +G01 X-0.3295 Y0.6836 +G01 X-0.3295 Y0.7164 +G01 X-0.3084 Y0.7375 +G01 X-0.3448 Y0.7375 +G01 X-0.3552 Y0.7375 +G01 X-0.5052 Y0.8875 +G01 X-1.1448 Y0.8875 +G01 X-1.1975 Y0.8348 +G01 X-1.2048 Y0.8275 +G01 X-1.2058 Y0.8275 +G01 X-1.2089 Y0.8199 +G01 X-1.2189 Y0.8099 +G01 X-1.2319 Y0.8045 +G01 X-1.3081 Y0.8045 +G01 X-1.3211 Y0.8099 +G01 X-1.3311 Y0.8199 +G01 X-1.3325 Y0.8233 +G01 X-1.3325 Y0.8102 +G01 X-1.3248 Y0.8025 +G01 X-1.2002 Y0.8025 +G01 X-1.1775 Y0.8252 +G01 X-1.1702 Y0.8325 +G01 X-0.9557 Y0.8325 +G01 X-0.9557 Y0.8581 +G01 X-0.9503 Y0.8712 +G01 X-0.9403 Y0.8811 +G01 X-0.9273 Y0.8866 +G01 X-0.9132 Y0.8866 +G01 X-0.9001 Y0.8811 +G01 X-0.8901 Y0.8712 +G01 X-0.8847 Y0.8581 +G00 Z0.1000 +G00 X-1.2319 Y0.6045 +G01 Z-0.0070 F10 +G01 X-1.3081 Y0.6045 F20 +G01 X-1.3211 Y0.6099 +G01 X-1.3311 Y0.6199 +G01 X-1.3365 Y0.6329 +G01 X-1.3365 Y0.6471 +G01 X-1.3311 Y0.6601 +G01 X-1.3211 Y0.6701 +G01 X-1.3081 Y0.6755 +G01 X-1.2319 Y0.6755 +G01 X-1.2189 Y0.6701 +G01 X-1.2089 Y0.6601 +G01 X-1.2035 Y0.6471 +G01 X-1.2035 Y0.6425 +G01 X-0.9164 Y0.6425 +G01 X-0.9164 Y0.6780 +G01 X-0.9110 Y0.6911 +G01 X-0.9010 Y0.7010 +G01 X-0.8879 Y0.7064 +G01 X-0.8738 Y0.7064 +G01 X-0.8608 Y0.7010 +G01 X-0.8508 Y0.6911 +G01 X-0.8454 Y0.6780 +G01 X-0.8454 Y0.6019 +G01 X-0.8508 Y0.5888 +G01 X-0.8608 Y0.5789 +G01 X-0.8738 Y0.5734 +G01 X-0.8879 Y0.5734 +G01 X-0.9010 Y0.5789 +G01 X-0.9110 Y0.5888 +G01 X-0.9164 Y0.6019 +G01 X-0.9164 Y0.6175 +G01 X-1.2113 Y0.6175 +G01 X-1.2189 Y0.6099 +G01 X-1.2319 Y0.6045 +G00 Z0.1000 +G00 X-2.3545 Y1.0074 +G01 Z-0.0070 F10 +G01 X-2.3545 Y1.0526 F20 +G01 X-2.3226 Y1.0845 +G01 X-2.2774 Y1.0845 +G01 X-2.2455 Y1.0526 +G01 X-2.2455 Y1.0522 +G01 X-2.1825 Y1.1152 +G01 X-2.1752 Y1.1225 +G01 X-2.1652 Y1.1225 +G01 X-2.1225 Y1.1652 +G01 X-2.1152 Y1.1725 +G01 X-1.9252 Y1.1725 +G01 X-1.9148 Y1.1725 +G01 X-1.7748 Y1.0325 +G01 X-1.7252 Y1.0325 +G01 X-1.6452 Y1.1125 +G01 X-1.6348 Y1.1125 +G01 X-1.5048 Y1.1125 +G01 X-1.4975 Y1.1052 +G01 X-1.4675 Y1.0752 +G01 X-1.4675 Y1.0648 +G01 X-1.4675 Y1.0450 +G01 X-1.3660 Y0.9387 +G01 X-1.3625 Y0.9352 +G01 X-1.3625 Y0.9350 +G01 X-1.3624 Y0.9349 +G01 X-1.3625 Y0.9298 +G01 X-1.3625 Y0.7757 +G01 X-1.3354 Y0.7525 +G01 X-1.3342 Y0.7525 +G01 X-1.3311 Y0.7601 +G01 X-1.3211 Y0.7701 +G01 X-1.3081 Y0.7755 +G01 X-1.2319 Y0.7755 +G01 X-1.2189 Y0.7701 +G01 X-1.2089 Y0.7601 +G01 X-1.2035 Y0.7471 +G01 X-1.2035 Y0.7329 +G01 X-1.2089 Y0.7199 +G01 X-1.2189 Y0.7099 +G01 X-1.2319 Y0.7045 +G01 X-1.3081 Y0.7045 +G01 X-1.3211 Y0.7099 +G01 X-1.3311 Y0.7199 +G01 X-1.3342 Y0.7275 +G01 X-1.3395 Y0.7275 +G01 X-1.3442 Y0.7271 +G01 X-1.3446 Y0.7275 +G01 X-1.3452 Y0.7275 +G01 X-1.3485 Y0.7309 +G01 X-1.3796 Y0.7575 +G01 X-1.3802 Y0.7575 +G01 X-1.3835 Y0.7608 +G01 X-1.3871 Y0.7639 +G01 X-1.3871 Y0.7644 +G01 X-1.3875 Y0.7648 +G01 X-1.3875 Y0.7695 +G01 X-1.3879 Y0.7742 +G01 X-1.3875 Y0.7746 +G01 X-1.3875 Y0.9250 +G01 X-1.4890 Y1.0313 +G01 X-1.4925 Y1.0348 +G01 X-1.4925 Y1.0350 +G01 X-1.4926 Y1.0351 +G01 X-1.4925 Y1.0402 +G01 X-1.4925 Y1.0648 +G01 X-1.5152 Y1.0875 +G01 X-1.6348 Y1.0875 +G01 X-1.7075 Y1.0148 +G01 X-1.7148 Y1.0075 +G01 X-1.7748 Y1.0075 +G01 X-1.7852 Y1.0075 +G01 X-1.9252 Y1.1475 +G01 X-2.1048 Y1.1475 +G01 X-2.1475 Y1.1048 +G01 X-2.1548 Y1.0975 +G01 X-2.1648 Y1.0975 +G01 X-2.2375 Y1.0248 +G01 X-2.2448 Y1.0175 +G01 X-2.2455 Y1.0175 +G01 X-2.2455 Y1.0074 +G01 X-2.2774 Y0.9755 +G01 X-2.3226 Y0.9755 +G01 X-2.3545 Y1.0074 +G00 Z0.1000 +G00 X-0.2188 Y0.3659 +G01 Z-0.0070 F10 +G01 X-0.2225 Y0.3696 F20 +G01 X-0.2225 Y0.3677 +G01 X-0.5228 Y0.0675 +G01 X-0.5172 Y0.0675 +G01 X-0.2188 Y0.3659 +G00 Z0.1000 +G00 X-2.3595 Y1.0054 +G01 Z-0.0070 F10 +G01 X-2.3595 Y1.0546 F20 +G01 X-2.3246 Y1.0895 +G01 X-2.2754 Y1.0895 +G01 X-2.2453 Y1.0594 +G01 X-2.1875 Y1.1172 +G01 X-2.1772 Y1.1275 +G01 X-2.1672 Y1.1275 +G01 X-2.1275 Y1.1672 +G01 X-2.1222 Y1.1725 +G01 X-2.2927 Y1.1725 +G01 X-2.3925 Y1.0727 +G01 X-2.3925 Y0.9972 +G01 X-2.3527 Y0.9575 +G01 X-2.1972 Y0.9575 +G01 X-2.1175 Y1.0372 +G01 X-2.1175 Y1.0672 +G01 X-2.1072 Y1.0775 +G01 X-2.0472 Y1.1375 +G01 X-2.0327 Y1.1375 +G01 X-1.9627 Y1.1375 +G01 X-1.9525 Y1.1272 +G01 X-1.9025 Y1.0772 +G01 X-1.9025 Y1.0627 +G01 X-1.9025 Y0.9922 +G01 X-1.8827 Y0.9725 +G01 X-1.7927 Y0.9725 +G01 X-1.7372 Y0.9725 +G01 X-1.6722 Y1.0375 +G01 X-1.6577 Y1.0375 +G01 X-1.6415 Y1.0375 +G01 X-1.6415 Y1.0481 +G01 X-1.6353 Y1.0629 +G01 X-1.6239 Y1.0743 +G01 X-1.6091 Y1.0805 +G01 X-1.5309 Y1.0805 +G01 X-1.5161 Y1.0743 +G01 X-1.5047 Y1.0629 +G01 X-1.4985 Y1.0481 +G01 X-1.4985 Y1.0333 +G01 X-1.4975 Y1.0322 +G01 X-1.4925 Y1.0272 +G01 X-1.4925 Y1.0270 +G01 X-1.3925 Y0.9222 +G01 X-1.3925 Y0.9230 +G01 X-1.4925 Y1.0278 +G01 X-1.4975 Y1.0327 +G01 X-1.4975 Y1.0330 +G01 X-1.4977 Y1.0332 +G01 X-1.4975 Y1.0402 +G01 X-1.4975 Y1.0627 +G01 X-1.5172 Y1.0825 +G01 X-1.6327 Y1.0825 +G01 X-1.7025 Y1.0127 +G01 X-1.7127 Y1.0025 +G01 X-1.7727 Y1.0025 +G01 X-1.7872 Y1.0025 +G01 X-1.9272 Y1.1425 +G01 X-2.1027 Y1.1425 +G01 X-2.1425 Y1.1027 +G01 X-2.1527 Y1.0925 +G01 X-2.1628 Y1.0925 +G01 X-2.2325 Y1.0228 +G01 X-2.2405 Y1.0148 +G01 X-2.2405 Y1.0054 +G01 X-2.2754 Y0.9705 +G01 X-2.3246 Y0.9705 +G01 X-2.3595 Y1.0054 +G00 Z0.1000 +G00 X-1.9031 Y0.2847 +G01 Z-0.0070 F10 +G01 X-1.8891 Y0.2905 F20 +G01 X-1.8142 Y0.2905 +G01 X-1.6472 Y0.4575 +G01 X-1.6376 Y0.4575 +G01 X-1.6353 Y0.4629 +G01 X-1.6239 Y0.4743 +G01 X-1.6091 Y0.4805 +G01 X-1.5309 Y0.4805 +G01 X-1.5161 Y0.4743 +G01 X-1.5075 Y0.4658 +G01 X-1.5075 Y0.5142 +G01 X-1.5161 Y0.5057 +G01 X-1.5309 Y0.4995 +G01 X-1.6091 Y0.4995 +G01 X-1.6239 Y0.5057 +G01 X-1.6268 Y0.5085 +G01 X-1.6625 Y0.4728 +G01 X-1.6727 Y0.4625 +G01 X-1.7602 Y0.4625 +G01 X-1.7832 Y0.4395 +G01 X-1.8058 Y0.4395 +G01 X-1.8325 Y0.4127 +G01 X-1.8325 Y0.3905 +G01 X-1.8109 Y0.3905 +G01 X-1.7961 Y0.3843 +G01 X-1.7847 Y0.3729 +G01 X-1.7785 Y0.3581 +G01 X-1.7785 Y0.3419 +G01 X-1.7847 Y0.3271 +G01 X-1.7961 Y0.3157 +G01 X-1.8109 Y0.3095 +G01 X-1.8891 Y0.3095 +G01 X-1.9039 Y0.3157 +G01 X-1.9125 Y0.3242 +G01 X-1.9125 Y0.2929 +G01 X-1.9031 Y0.2847 +G00 Z0.1000 +G00 X-1.9525 Y0.4072 +G01 Z-0.0070 F10 +G01 X-1.9525 Y0.4066 F20 +G01 X-1.9521 Y0.4061 +G01 X-1.9525 Y0.3994 +G01 X-1.9525 Y0.2280 +G01 X-1.9023 Y0.1850 +G01 X-1.8891 Y0.1905 +G01 X-1.8109 Y0.1905 +G01 X-1.7961 Y0.1843 +G01 X-1.7857 Y0.1740 +G01 X-1.7580 Y0.1768 +G01 X-1.6265 Y0.3082 +G01 X-1.6353 Y0.3171 +G01 X-1.6415 Y0.3319 +G01 X-1.6415 Y0.3481 +G01 X-1.6353 Y0.3629 +G01 X-1.6239 Y0.3743 +G01 X-1.6091 Y0.3805 +G01 X-1.5309 Y0.3805 +G01 X-1.5161 Y0.3743 +G01 X-1.5075 Y0.3658 +G01 X-1.5075 Y0.4142 +G01 X-1.5161 Y0.4057 +G01 X-1.5309 Y0.3995 +G01 X-1.6091 Y0.3995 +G01 X-1.6239 Y0.4057 +G01 X-1.6353 Y0.4171 +G01 X-1.6362 Y0.4191 +G01 X-1.7840 Y0.2713 +G01 X-1.7785 Y0.2581 +G01 X-1.7785 Y0.2419 +G01 X-1.7847 Y0.2271 +G01 X-1.7961 Y0.2157 +G01 X-1.8109 Y0.2095 +G01 X-1.8891 Y0.2095 +G01 X-1.9039 Y0.2157 +G01 X-1.9153 Y0.2271 +G01 X-1.9215 Y0.2419 +G01 X-1.9215 Y0.2543 +G01 X-1.9366 Y0.2675 +G01 X-1.9372 Y0.2675 +G01 X-1.9420 Y0.2722 +G01 X-1.9470 Y0.2766 +G01 X-1.9470 Y0.2773 +G01 X-1.9475 Y0.2777 +G01 X-1.9475 Y0.2844 +G01 X-1.9479 Y0.2911 +G01 X-1.9475 Y0.2916 +G01 X-1.9475 Y0.4502 +G01 X-1.9605 Y0.4632 +G01 X-1.9605 Y0.4968 +G01 X-1.9368 Y0.5205 +G01 X-1.9032 Y0.5205 +G01 X-1.8795 Y0.4968 +G01 X-1.8795 Y0.4632 +G01 X-1.9032 Y0.4395 +G01 X-1.9125 Y0.4395 +G01 X-1.9125 Y0.3758 +G01 X-1.9039 Y0.3843 +G01 X-1.8891 Y0.3905 +G01 X-1.8675 Y0.3905 +G01 X-1.8675 Y0.4272 +G01 X-1.8572 Y0.4375 +G01 X-1.8360 Y0.4587 +G01 X-1.8405 Y0.4632 +G01 X-1.8405 Y0.4968 +G01 X-1.8168 Y0.5205 +G01 X-1.7832 Y0.5205 +G01 X-1.7602 Y0.4975 +G01 X-1.6872 Y0.4975 +G01 X-1.6415 Y0.5432 +G01 X-1.6415 Y0.5481 +G01 X-1.6353 Y0.5629 +G01 X-1.6239 Y0.5743 +G01 X-1.6091 Y0.5805 +G01 X-1.5309 Y0.5805 +G01 X-1.5161 Y0.5743 +G01 X-1.5075 Y0.5658 +G01 X-1.5075 Y0.6142 +G01 X-1.5161 Y0.6057 +G01 X-1.5309 Y0.5995 +G01 X-1.6091 Y0.5995 +G01 X-1.6239 Y0.6057 +G01 X-1.6353 Y0.6171 +G01 X-1.6415 Y0.6319 +G01 X-1.6415 Y0.6481 +G01 X-1.6353 Y0.6629 +G01 X-1.6239 Y0.6743 +G01 X-1.6091 Y0.6805 +G01 X-1.5309 Y0.6805 +G01 X-1.5161 Y0.6743 +G01 X-1.5150 Y0.6733 +G01 X-1.5125 Y0.6763 +G01 X-1.5125 Y0.7092 +G01 X-1.5161 Y0.7057 +G01 X-1.5309 Y0.6995 +G01 X-1.6091 Y0.6995 +G01 X-1.6239 Y0.7057 +G01 X-1.6353 Y0.7171 +G01 X-1.6355 Y0.7175 +G01 X-1.6377 Y0.7175 +G01 X-1.6425 Y0.7127 +G01 X-1.6425 Y0.5727 +G01 X-1.6527 Y0.5625 +G01 X-1.6827 Y0.5325 +G01 X-1.6972 Y0.5325 +G01 X-2.0627 Y0.5325 +G01 X-2.0925 Y0.5028 +G01 X-2.0925 Y0.4722 +G01 X-2.0527 Y0.4325 +G01 X-2.0227 Y0.4325 +G01 X-2.0142 Y0.4240 +G01 X-2.0278 Y0.4395 +G01 X-2.0568 Y0.4395 +G01 X-2.0805 Y0.4632 +G01 X-2.0805 Y0.4968 +G01 X-2.0568 Y0.5205 +G01 X-2.0232 Y0.5205 +G01 X-1.9995 Y0.4968 +G01 X-1.9995 Y0.4632 +G01 X-2.0009 Y0.4619 +G01 X-1.9572 Y0.4120 +G01 X-1.9525 Y0.4072 +G00 Z0.1000 +G00 X-1.8109 Y0.1095 +G01 Z-0.0070 F10 +G01 X-1.8891 Y0.1095 F20 +G01 X-1.9039 Y0.1157 +G01 X-1.9153 Y0.1271 +G01 X-1.9215 Y0.1419 +G01 X-1.9215 Y0.1554 +G01 X-1.9765 Y0.2025 +G01 X-1.9772 Y0.2025 +G01 X-1.9819 Y0.2072 +G01 X-1.9869 Y0.2114 +G01 X-1.9869 Y0.2122 +G01 X-1.9875 Y0.2127 +G01 X-1.9875 Y0.2193 +G01 X-1.9880 Y0.2259 +G01 X-1.9875 Y0.2265 +G01 X-1.9875 Y0.3934 +G01 X-1.9925 Y0.3991 +G01 X-1.9925 Y0.3877 +G01 X-1.9925 Y0.1872 +G01 X-1.9028 Y0.0975 +G01 X-1.4722 Y0.0975 +G01 X-1.5075 Y0.1327 +G01 X-1.5075 Y0.1472 +G01 X-1.5075 Y0.3142 +G01 X-1.5161 Y0.3057 +G01 X-1.5309 Y0.2995 +G01 X-1.5857 Y0.2995 +G01 X-1.7370 Y0.1482 +G01 X-1.7410 Y0.1433 +G01 X-1.7420 Y0.1432 +G01 X-1.7427 Y0.1425 +G01 X-1.7491 Y0.1425 +G01 X-1.7795 Y0.1395 +G01 X-1.7847 Y0.1271 +G01 X-1.7961 Y0.1157 +G01 X-1.8109 Y0.1095 +G00 Z0.1000 +G00 X-1.3495 Y1.1532 +G01 Z-0.0070 F10 +G01 X-1.3652 Y1.1375 F20 +G01 X-1.3172 Y1.1375 +G01 X-1.2853 Y1.1694 +G01 X-1.2843 Y1.1724 +G01 X-1.2825 Y1.1733 +G01 X-1.2825 Y1.1928 +G01 X-1.3127 Y1.1625 +G01 X-1.3272 Y1.1625 +G01 X-1.3495 Y1.1625 +G01 X-1.3495 Y1.1532 +G00 Z0.1000 +G00 X-1.2427 Y1.2325 +G01 Z-0.0070 F10 +G01 X-1.2428 Y1.2325 F20 +G01 X-1.2083 Y1.2325 +G01 X-1.1777 Y1.2020 +G01 X-1.1774 Y1.2027 +G01 X-1.2072 Y1.2325 +G01 X-1.2427 Y1.2325 +G00 Z0.1000 +G00 X-1.1985 Y0.4319 +G01 Z-0.0070 F10 +G01 X-1.2047 Y0.4171 F20 +G01 X-1.2161 Y0.4057 +G01 X-1.2309 Y0.3995 +G01 X-1.3091 Y0.3995 +G01 X-1.3239 Y0.4057 +G01 X-1.3353 Y0.4171 +G01 X-1.3415 Y0.4319 +G01 X-1.3415 Y0.4481 +G01 X-1.3353 Y0.4629 +G01 X-1.3258 Y0.4725 +G01 X-1.3875 Y0.4725 +G01 X-1.3875 Y0.3572 +G01 X-1.3627 Y0.3325 +G01 X-1.3525 Y0.3222 +G01 X-1.3525 Y0.2698 +G01 X-1.3295 Y0.2468 +G01 X-1.3295 Y0.2242 +G01 X-1.3027 Y0.1975 +G01 X-1.2948 Y0.1975 +G01 X-1.3105 Y0.2132 +G01 X-1.3105 Y0.2468 +G01 X-1.2868 Y0.2705 +G01 X-1.2775 Y0.2705 +G01 X-1.2775 Y0.2995 +G01 X-1.3091 Y0.2995 +G01 X-1.3239 Y0.3057 +G01 X-1.3353 Y0.3171 +G01 X-1.3415 Y0.3319 +G01 X-1.3415 Y0.3481 +G01 X-1.3353 Y0.3629 +G01 X-1.3239 Y0.3743 +G01 X-1.3091 Y0.3805 +G01 X-1.2309 Y0.3805 +G01 X-1.2161 Y0.3743 +G01 X-1.2047 Y0.3629 +G01 X-1.2022 Y0.3569 +G01 X-1.1509 Y0.3056 +G01 X-1.1391 Y0.3105 +G01 X-1.0609 Y0.3105 +G01 X-1.0461 Y0.3043 +G01 X-1.0392 Y0.2975 +G01 X-1.0172 Y0.2975 +G01 X-0.9872 Y0.3275 +G01 X-0.9727 Y0.3275 +G01 X-0.9425 Y0.3275 +G01 X-0.9425 Y0.4272 +G01 X-0.9372 Y0.4325 +G01 X-1.1985 Y0.4325 +G01 X-1.1985 Y0.4319 +G00 Z0.1000 +G00 X-0.8222 Y0.4375 +G01 Z-0.0070 F10 +G01 X-0.6875 Y0.5722 F20 +G01 X-0.6875 Y0.5898 +G01 X-0.6891 Y0.5860 +G01 X-0.7004 Y0.5746 +G01 X-0.7025 Y0.5738 +G01 X-0.7025 Y0.5677 +G01 X-0.7127 Y0.5575 +G01 X-0.8328 Y0.4375 +G01 X-0.8222 Y0.4375 +G00 Z0.1000 +G00 X-0.7463 Y0.5746 +G01 Z-0.0070 F10 +G01 X-0.7577 Y0.5860 F20 +G01 X-0.7628 Y0.5982 +G01 X-0.7678 Y0.5860 +G01 X-0.7792 Y0.5746 +G01 X-0.7825 Y0.5732 +G01 X-0.7825 Y0.5677 +G01 X-0.8777 Y0.4725 +G01 X-0.8922 Y0.4725 +G01 X-1.2142 Y0.4725 +G01 X-1.2092 Y0.4675 +G01 X-0.8522 Y0.4675 +G01 X-0.7455 Y0.5743 +G01 X-0.7463 Y0.5746 +G00 Z0.1000 +G00 X-0.3975 Y0.3772 +G01 Z-0.0070 F10 +G01 X-0.3975 Y0.4027 F20 +G01 X-0.3975 Y0.4172 +G01 X-0.3338 Y0.4809 +G01 X-0.3345 Y0.4816 +G01 X-0.3345 Y0.5184 +G01 X-0.3204 Y0.5325 +G01 X-0.3277 Y0.5325 +G01 X-0.5075 Y0.3527 +G01 X-0.5177 Y0.3425 +G01 X-0.6477 Y0.3425 +G01 X-0.6875 Y0.3027 +G01 X-0.6977 Y0.2925 +G01 X-0.9227 Y0.2925 +G01 X-0.9372 Y0.2925 +G01 X-0.9727 Y0.2925 +G01 X-1.0027 Y0.2625 +G01 X-1.0172 Y0.2625 +G01 X-1.0285 Y0.2625 +G01 X-1.0285 Y0.2619 +G01 X-1.0347 Y0.2471 +G01 X-1.0461 Y0.2357 +G01 X-1.0609 Y0.2295 +G01 X-1.1391 Y0.2295 +G01 X-1.1539 Y0.2357 +G01 X-1.1653 Y0.2471 +G01 X-1.1715 Y0.2619 +G01 X-1.1715 Y0.2767 +G01 X-1.2082 Y0.3135 +G01 X-1.2161 Y0.3057 +G01 X-1.2309 Y0.2995 +G01 X-1.2425 Y0.2995 +G01 X-1.2425 Y0.2598 +G01 X-1.2295 Y0.2468 +G01 X-1.2295 Y0.2132 +G01 X-1.2452 Y0.1975 +G01 X-1.0372 Y0.1975 +G01 X-0.9572 Y0.2775 +G01 X-0.9427 Y0.2775 +G01 X-0.6715 Y0.2775 +G01 X-0.6715 Y0.2781 +G01 X-0.6653 Y0.2929 +G01 X-0.6539 Y0.3043 +G01 X-0.6391 Y0.3105 +G01 X-0.5609 Y0.3105 +G01 X-0.5461 Y0.3043 +G01 X-0.5347 Y0.2929 +G01 X-0.5285 Y0.2781 +G01 X-0.5285 Y0.2619 +G01 X-0.5347 Y0.2471 +G01 X-0.5461 Y0.2357 +G01 X-0.5609 Y0.2295 +G01 X-0.6391 Y0.2295 +G01 X-0.6539 Y0.2357 +G01 X-0.6608 Y0.2425 +G01 X-0.9427 Y0.2425 +G01 X-1.0125 Y0.1727 +G01 X-1.0227 Y0.1625 +G01 X-1.3027 Y0.1625 +G01 X-1.3172 Y0.1625 +G01 X-1.3487 Y0.1940 +G01 X-1.3532 Y0.1895 +G01 X-1.3868 Y0.1895 +G01 X-1.4105 Y0.2132 +G01 X-1.4105 Y0.2468 +G01 X-1.3875 Y0.2698 +G01 X-1.3875 Y0.3077 +G01 X-1.4225 Y0.3427 +G01 X-1.4225 Y0.3572 +G01 X-1.4225 Y0.4972 +G01 X-1.4225 Y0.5277 +G01 X-1.4225 Y0.5327 +G01 X-1.4225 Y0.6075 +G01 X-1.4325 Y0.5942 +G01 X-1.4325 Y0.1772 +G01 X-1.4127 Y0.1575 +G01 X-0.6172 Y0.1575 +G01 X-0.3975 Y0.3772 +G00 Z0.1000 +G00 X-0.2084 Y0.4445 +G01 Z-0.0070 F10 +G01 X-0.1716 Y0.4445 F20 +G01 X-0.1575 Y0.4304 +G01 X-0.1575 Y0.4696 +G01 X-0.1716 Y0.4555 +G01 X-0.2084 Y0.4555 +G01 X-0.2091 Y0.4562 +G01 X-0.2225 Y0.4427 +G01 X-0.2225 Y0.4304 +G01 X-0.2084 Y0.4445 +G00 Z0.1000 +G00 X-0.5422 Y0.0975 +G01 Z-0.0070 F10 +G01 X-0.2842 Y0.3555 F20 +G01 X-0.3084 Y0.3555 +G01 X-0.3091 Y0.3562 +G01 X-0.5625 Y0.1027 +G01 X-0.5678 Y0.0975 +G01 X-0.5422 Y0.0975 +G00 Z0.1000 +G00 X-0.2575 Y0.4427 +G01 Z-0.0070 F10 +G01 X-0.2575 Y0.4572 F20 +G01 X-0.2338 Y0.4809 +G01 X-0.2345 Y0.4816 +G01 X-0.2345 Y0.5184 +G01 X-0.2204 Y0.5325 +G01 X-0.2596 Y0.5325 +G01 X-0.2455 Y0.5184 +G01 X-0.2455 Y0.4816 +G01 X-0.2716 Y0.4555 +G01 X-0.3084 Y0.4555 +G01 X-0.3091 Y0.4562 +G01 X-0.3625 Y0.4027 +G01 X-0.3625 Y0.3627 +G01 X-0.3727 Y0.3525 +G01 X-0.5925 Y0.1327 +G01 X-0.5978 Y0.1275 +G01 X-0.5872 Y0.1275 +G01 X-0.3338 Y0.3809 +G01 X-0.3345 Y0.3816 +G01 X-0.3345 Y0.4184 +G01 X-0.3084 Y0.4445 +G01 X-0.2716 Y0.4445 +G01 X-0.2575 Y0.4304 +G01 X-0.2575 Y0.4427 +G00 Z0.1000 +G00 X-1.5047 Y0.8171 +G01 Z-0.0070 F10 +G01 X-1.5142 Y0.8075 F20 +G01 X-1.5041 Y0.8075 +G01 X-1.5013 Y0.8089 +G01 X-1.4972 Y0.8075 +G01 X-1.4948 Y0.8075 +G01 X-1.5042 Y0.8182 +G01 X-1.5047 Y0.8171 +G00 Z0.1000 +G00 X-1.4525 Y0.8232 +G01 Z-0.0070 F10 +G01 X-1.4977 Y0.8725 F20 +G01 X-1.5142 Y0.8725 +G01 X-1.5047 Y0.8629 +G01 X-1.5025 Y0.8577 +G01 X-1.4994 Y0.8575 +G01 X-1.4927 Y0.8575 +G01 X-1.4923 Y0.8570 +G01 X-1.4916 Y0.8570 +G01 X-1.4872 Y0.8520 +G01 X-1.4825 Y0.8472 +G01 X-1.4825 Y0.8466 +G01 X-1.4525 Y0.8123 +G01 X-1.4525 Y0.8232 +G00 Z0.1000 +G00 X-1.4825 Y0.6577 +G01 Z-0.0070 F10 +G01 X-1.4985 Y0.6385 F20 +G01 X-1.4985 Y0.6371 +G01 X-1.4825 Y0.6563 +G01 X-1.4825 Y0.6577 +G00 Z0.1000 +G00 X-0.4872 Y0.0375 +G01 Z-0.0070 F10 +G01 X-0.1575 Y0.3672 F20 +G01 X-0.1575 Y0.3696 +G01 X-0.1716 Y0.3555 +G01 X-0.1797 Y0.3555 +G01 X-0.4925 Y0.0427 +G01 X-0.4978 Y0.0375 +G01 X-0.4872 Y0.0375 +G00 Z0.1000 +G00 X-0.1575 Y0.5304 +G01 Z-0.0070 F10 +G01 X-0.1575 Y0.5362 F20 +G01 X-0.1602 Y0.5351 +G01 X-0.1612 Y0.5341 +G01 X-0.1575 Y0.5304 +G00 Z0.1000 +G00 X-0.8579 Y0.7053 +G01 Z-0.0070 F10 +G01 X-0.8465 Y0.6939 F20 +G01 X-0.8415 Y0.6817 +G01 X-0.8365 Y0.6939 +G01 X-0.8251 Y0.7053 +G01 X-0.8102 Y0.7114 +G01 X-0.7941 Y0.7114 +G01 X-0.7792 Y0.7053 +G01 X-0.7678 Y0.6939 +G01 X-0.7628 Y0.6817 +G01 X-0.7577 Y0.6939 +G01 X-0.7463 Y0.7053 +G01 X-0.7314 Y0.7114 +G01 X-0.7162 Y0.7114 +G01 X-0.7537 Y0.7490 +G01 X-0.7547 Y0.7486 +G01 X-0.7708 Y0.7486 +G01 X-0.7857 Y0.7547 +G01 X-0.7971 Y0.7661 +G01 X-0.8021 Y0.7783 +G01 X-0.8072 Y0.7661 +G01 X-0.8186 Y0.7547 +G01 X-0.8275 Y0.7510 +G01 X-0.8275 Y0.7477 +G01 X-0.8377 Y0.7375 +G01 X-0.8664 Y0.7088 +G01 X-0.8579 Y0.7053 +G00 Z0.1000 +G00 X-0.3254 Y0.9725 +G01 Z-0.0070 F10 +G01 X-0.3802 Y0.9725 F20 +G01 X-0.3852 Y0.9675 +G01 X-0.3204 Y0.9675 +G01 X-0.3254 Y0.9725 +G00 Z0.1000 +G00 X-0.8072 Y0.8740 +G01 Z-0.0070 F10 +G01 X-0.8021 Y0.8618 F20 +G01 X-0.7971 Y0.8740 +G01 X-0.7886 Y0.8825 +G01 X-0.8157 Y0.8825 +G01 X-0.8072 Y0.8740 +G00 Z0.1000 +G00 X-0.8859 Y0.8740 +G01 Z-0.0070 F10 +G01 X-0.8809 Y0.8618 F20 +G01 X-0.8758 Y0.8740 +G01 X-0.8673 Y0.8825 +G01 X-0.8944 Y0.8825 +G01 X-0.8859 Y0.8740 +G00 Z0.1000 +G00 X-0.1455 Y0.6184 +G01 Z-0.0070 F10 +G01 X-0.1455 Y0.5842 F20 +G01 X-0.1175 Y0.6122 +G01 X-0.1175 Y0.6675 +G01 X-0.1185 Y0.6667 +G01 X-0.1227 Y0.6625 +G01 X-0.1242 Y0.6625 +G01 X-0.1585 Y0.6367 +G01 X-0.1612 Y0.6341 +G01 X-0.1455 Y0.6184 +G00 Z0.1000 +G00 X-0.1227 Y0.8375 +G01 Z-0.0070 F10 +G01 X-0.1185 Y0.8333 F20 +G01 X-0.1175 Y0.8325 +G01 X-0.1175 Y0.9075 +G01 X-0.1700 Y0.9571 +G01 X-0.1716 Y0.9555 +G01 X-0.2084 Y0.9555 +G01 X-0.2345 Y0.9816 +G01 X-0.2345 Y1.0184 +G01 X-0.2313 Y1.0216 +G01 X-0.3522 Y1.1425 +G01 X-1.0872 Y1.1425 +G01 X-1.0913 Y1.1411 +G01 X-1.0935 Y1.1422 +G01 X-1.1003 Y1.1355 +G01 X-1.1196 Y1.1275 +G01 X-1.1404 Y1.1275 +G01 X-1.1597 Y1.1355 +G01 X-1.1745 Y1.1503 +G01 X-1.1777 Y1.1580 +G01 X-1.1805 Y1.1552 +G01 X-1.1527 Y1.1275 +G01 X-0.4927 Y1.1275 +G01 X-0.4825 Y1.1172 +G01 X-0.4058 Y1.0405 +G01 X-0.3932 Y1.0405 +G01 X-0.3695 Y1.0168 +G01 X-0.3695 Y1.0075 +G01 X-0.3345 Y1.0075 +G01 X-0.3345 Y1.0184 +G01 X-0.3084 Y1.0445 +G01 X-0.2716 Y1.0445 +G01 X-0.2455 Y1.0184 +G01 X-0.2455 Y0.9816 +G01 X-0.2596 Y0.9675 +G01 X-0.2472 Y0.9675 +G01 X-0.2327 Y0.9675 +G01 X-0.2091 Y0.9438 +G01 X-0.2084 Y0.9445 +G01 X-0.1716 Y0.9445 +G01 X-0.1455 Y0.9184 +G01 X-0.1455 Y0.8816 +G01 X-0.1612 Y0.8659 +G01 X-0.1585 Y0.8633 +G01 X-0.1242 Y0.8375 +G01 X-0.1227 Y0.8375 +G00 Z0.1000 +G00 X-0.3084 Y0.8445 +G01 Z-0.0070 F10 +G01 X-0.2716 Y0.8445 F20 +G01 X-0.2455 Y0.8184 +G01 X-0.2455 Y0.7816 +G01 X-0.2596 Y0.7675 +G01 X-0.2472 Y0.7675 +G01 X-0.2338 Y0.7809 +G01 X-0.2345 Y0.7816 +G01 X-0.2345 Y0.8184 +G01 X-0.2204 Y0.8325 +G01 X-0.2327 Y0.8325 +G01 X-0.2472 Y0.8325 +G01 X-0.2709 Y0.8562 +G01 X-0.2716 Y0.8555 +G01 X-0.3084 Y0.8555 +G01 X-0.3345 Y0.8816 +G01 X-0.3345 Y0.9184 +G01 X-0.3204 Y0.9325 +G01 X-0.4342 Y0.9325 +G01 X-0.3312 Y0.8217 +G01 X-0.3084 Y0.8445 +G00 Z0.1000 +G00 X-0.2204 Y0.8675 +G01 Z-0.0070 F10 +G01 X-0.2345 Y0.8816 F20 +G01 X-0.2345 Y0.9184 +G01 X-0.2338 Y0.9191 +G01 X-0.2472 Y0.9325 +G01 X-0.2596 Y0.9325 +G01 X-0.2455 Y0.9184 +G01 X-0.2455 Y0.8816 +G01 X-0.2462 Y0.8809 +G01 X-0.2327 Y0.8675 +G01 X-0.2204 Y0.8675 +G00 Z0.1000 +G00 X-0.2455 Y0.6184 +G01 Z-0.0070 F10 +G01 X-0.2455 Y0.5816 F20 +G01 X-0.2596 Y0.5675 +G01 X-0.2204 Y0.5675 +G01 X-0.2345 Y0.5816 +G01 X-0.2345 Y0.6184 +G01 X-0.2204 Y0.6325 +G01 X-0.2596 Y0.6325 +G01 X-0.2455 Y0.6184 +G00 Z0.1000 +G00 X-0.7285 Y0.3619 +G01 Z-0.0070 F10 +G01 X-0.7347 Y0.3471 F20 +G01 X-0.7461 Y0.3357 +G01 X-0.7609 Y0.3295 +G01 X-0.8391 Y0.3295 +G01 X-0.8539 Y0.3357 +G01 X-0.8653 Y0.3471 +G01 X-0.8715 Y0.3619 +G01 X-0.8715 Y0.3781 +G01 X-0.8653 Y0.3929 +G01 X-0.8558 Y0.4025 +G01 X-0.9075 Y0.4025 +G01 X-0.9075 Y0.3275 +G01 X-0.7122 Y0.3275 +G01 X-0.6622 Y0.3775 +G01 X-0.6477 Y0.3775 +G01 X-0.5322 Y0.3775 +G01 X-0.3422 Y0.5675 +G01 X-0.3277 Y0.5675 +G01 X-0.3204 Y0.5675 +G01 X-0.3345 Y0.5816 +G01 X-0.3345 Y0.6184 +G01 X-0.3204 Y0.6325 +G01 X-0.3327 Y0.6325 +G01 X-0.4625 Y0.5027 +G01 X-0.4625 Y0.4977 +G01 X-0.5375 Y0.4227 +G01 X-0.5477 Y0.4125 +G01 X-0.6877 Y0.4125 +G01 X-0.7285 Y0.3717 +G01 X-0.7285 Y0.3619 +G00 Z0.1000 +G00 X-0.3345 Y0.6816 +G01 Z-0.0070 F10 +G01 X-0.3345 Y0.7184 F20 +G01 X-0.3204 Y0.7325 +G01 X-0.3427 Y0.7325 +G01 X-0.3572 Y0.7325 +G01 X-0.5072 Y0.8825 +G01 X-0.7369 Y0.8825 +G01 X-0.7284 Y0.8740 +G01 X-0.7223 Y0.8591 +G01 X-0.7223 Y0.7810 +G01 X-0.7264 Y0.7711 +G01 X-0.6525 Y0.6972 +G01 X-0.6525 Y0.6827 +G01 X-0.6525 Y0.5722 +G01 X-0.6525 Y0.5577 +G01 X-0.7975 Y0.4127 +G01 X-0.7998 Y0.4105 +G01 X-0.7609 Y0.4105 +G01 X-0.7461 Y0.4043 +G01 X-0.7457 Y0.4040 +G01 X-0.7022 Y0.4475 +G01 X-0.6877 Y0.4475 +G01 X-0.5622 Y0.4475 +G01 X-0.4975 Y0.5122 +G01 X-0.4975 Y0.5172 +G01 X-0.4872 Y0.5275 +G01 X-0.3472 Y0.6675 +G01 X-0.3327 Y0.6675 +G01 X-0.3204 Y0.6675 +G01 X-0.3345 Y0.6816 +G00 Z0.1000 +G00 X-0.1716 Y0.7555 +G01 Z-0.0070 F10 +G01 X-0.2084 Y0.7555 F20 +G01 X-0.2091 Y0.7562 +G01 X-0.2225 Y0.7427 +G01 X-0.2327 Y0.7325 +G01 X-0.2596 Y0.7325 +G01 X-0.2455 Y0.7184 +G01 X-0.2455 Y0.6816 +G01 X-0.2596 Y0.6675 +G01 X-0.2204 Y0.6675 +G01 X-0.2345 Y0.6816 +G01 X-0.2345 Y0.7184 +G01 X-0.2084 Y0.7445 +G01 X-0.1716 Y0.7445 +G01 X-0.1475 Y0.7204 +G01 X-0.1475 Y0.7796 +G01 X-0.1716 Y0.7555 +G00 Z0.1000 +G00 X-1.2309 Y0.5995 +G01 Z-0.0070 F10 +G01 X-1.3091 Y0.5995 F20 +G01 X-1.3239 Y0.6057 +G01 X-1.3353 Y0.6171 +G01 X-1.3415 Y0.6319 +G01 X-1.3415 Y0.6481 +G01 X-1.3375 Y0.6578 +G01 X-1.3425 Y0.6527 +G01 X-1.3425 Y0.6172 +G01 X-1.3058 Y0.5805 +G01 X-1.2309 Y0.5805 +G01 X-1.2161 Y0.5743 +G01 X-1.2047 Y0.5629 +G01 X-1.1985 Y0.5481 +G01 X-1.1985 Y0.5319 +G01 X-1.2047 Y0.5171 +G01 X-1.2142 Y0.5075 +G01 X-0.8922 Y0.5075 +G01 X-0.8251 Y0.5746 +G01 X-0.8365 Y0.5860 +G01 X-0.8415 Y0.5982 +G01 X-0.8465 Y0.5860 +G01 X-0.8579 Y0.5746 +G01 X-0.8728 Y0.5684 +G01 X-0.8889 Y0.5684 +G01 X-0.9038 Y0.5746 +G01 X-0.9152 Y0.5860 +G01 X-0.9214 Y0.6009 +G01 X-0.9214 Y0.6125 +G01 X-1.2092 Y0.6125 +G01 X-1.2161 Y0.6057 +G01 X-1.2309 Y0.5995 +G00 Z0.1000 +G00 X-0.9214 Y0.6790 +G01 Z-0.0070 F10 +G01 X-0.9152 Y0.6939 F20 +G01 X-0.9038 Y0.7053 +G01 X-0.8984 Y0.7075 +G01 X-0.9077 Y0.7075 +G01 X-0.9427 Y0.6725 +G01 X-0.9572 Y0.6725 +G01 X-1.2142 Y0.6725 +G01 X-1.2047 Y0.6629 +G01 X-1.1985 Y0.6481 +G01 X-1.1985 Y0.6475 +G01 X-0.9214 Y0.6475 +G01 X-0.9214 Y0.6790 +G00 Z0.1000 +G00 X-1.3258 Y1.0075 +G01 Z-0.0070 F10 +G01 X-1.3353 Y1.0171 F20 +G01 X-1.3415 Y1.0319 +G01 X-1.3415 Y1.0481 +G01 X-1.3353 Y1.0629 +G01 X-1.3239 Y1.0743 +G01 X-1.3091 Y1.0805 +G01 X-1.2309 Y1.0805 +G01 X-1.2161 Y1.0743 +G01 X-1.2092 Y1.0675 +G01 X-0.4972 Y1.0675 +G01 X-0.4827 Y1.0675 +G01 X-0.4527 Y1.0375 +G01 X-0.4425 Y1.0272 +G01 X-0.4425 Y1.0248 +G01 X-0.4410 Y1.0263 +G01 X-0.5072 Y1.0925 +G01 X-1.1527 Y1.0925 +G01 X-1.1672 Y1.0925 +G01 X-1.2052 Y1.1305 +G01 X-1.2083 Y1.1275 +G01 X-1.2517 Y1.1275 +G01 X-1.2647 Y1.1405 +G01 X-1.2925 Y1.1128 +G01 X-1.3027 Y1.1025 +G01 X-1.4127 Y1.1025 +G01 X-1.4272 Y1.1025 +G01 X-1.4472 Y1.1225 +G01 X-1.4575 Y1.1327 +G01 X-1.4575 Y1.1452 +G01 X-1.4690 Y1.1337 +G01 X-1.3427 Y1.0075 +G01 X-1.3327 Y1.0075 +G01 X-1.3258 Y1.0075 +G00 Z0.1000 +G00 X-1.3575 Y0.7780 +G01 Z-0.0070 F10 +G01 X-1.3365 Y0.7601 F20 +G01 X-1.3353 Y0.7629 +G01 X-1.3258 Y0.7725 +G01 X-1.3372 Y0.7725 +G01 X-1.3475 Y0.7827 +G01 X-1.3575 Y0.7928 +G01 X-1.3575 Y0.7780 +G00 Z0.1000 +G00 X-0.9607 Y0.8591 +G01 Z-0.0070 F10 +G01 X-0.9546 Y0.8740 F20 +G01 X-0.9461 Y0.8825 +G01 X-1.1427 Y0.8825 +G01 X-1.1925 Y0.8327 +G01 X-1.2022 Y0.8231 +G01 X-1.2047 Y0.8171 +G01 X-1.2142 Y0.8075 +G01 X-1.2022 Y0.8075 +G01 X-1.1825 Y0.8272 +G01 X-1.1722 Y0.8375 +G01 X-0.9607 Y0.8375 +G01 X-0.9607 Y0.8591 +G00 Z0.1000 +G00 X-1.2047 Y0.7629 +G01 Z-0.0070 F10 +G01 X-1.1985 Y0.7481 F20 +G01 X-1.1985 Y0.7319 +G01 X-1.2047 Y0.7171 +G01 X-1.2142 Y0.7075 +G01 X-0.9572 Y0.7075 +G01 X-0.9325 Y0.7322 +G01 X-0.9222 Y0.7425 +G01 X-0.8822 Y0.7425 +G01 X-0.8672 Y0.7575 +G01 X-0.8758 Y0.7661 +G01 X-0.8809 Y0.7783 +G01 X-0.8859 Y0.7661 +G01 X-0.8973 Y0.7547 +G01 X-0.9122 Y0.7486 +G01 X-0.9283 Y0.7486 +G01 X-0.9432 Y0.7547 +G01 X-0.9546 Y0.7661 +G01 X-0.9607 Y0.7810 +G01 X-0.9607 Y0.8025 +G01 X-1.1577 Y0.8025 +G01 X-1.1877 Y0.7725 +G01 X-1.2022 Y0.7725 +G01 X-1.2142 Y0.7725 +G01 X-1.2047 Y0.7629 +G00 Z0.1000 +G00 X-1.5075 Y1.1227 +G01 Z-0.0070 F10 +G01 X-1.5075 Y1.1302 F20 +G01 X-1.5305 Y1.1532 +G01 X-1.5305 Y1.1825 +G01 X-1.7072 Y1.1825 +G01 X-1.7113 Y1.1811 +G01 X-1.7135 Y1.1822 +G01 X-1.7203 Y1.1755 +G01 X-1.7280 Y1.1723 +G01 X-1.6975 Y1.1417 +G01 X-1.6975 Y1.0983 +G01 X-1.7283 Y1.0675 +G01 X-1.7717 Y1.0675 +G01 X-1.8025 Y1.0983 +G01 X-1.8025 Y1.1417 +G01 X-1.7995 Y1.1447 +G01 X-1.8272 Y1.1725 +G01 X-1.9078 Y1.1725 +G01 X-1.7727 Y1.0375 +G01 X-1.7272 Y1.0375 +G01 X-1.6472 Y1.1175 +G01 X-1.6327 Y1.1175 +G01 X-1.5027 Y1.1175 +G01 X-1.4925 Y1.1072 +G01 X-1.4625 Y1.0772 +G01 X-1.4625 Y1.0627 +G01 X-1.4625 Y1.0470 +G01 X-1.3625 Y0.9422 +G01 X-1.3625 Y0.9777 +G01 X-1.5075 Y1.1227 +G00 Z0.1000 +G00 X-1.3258 Y0.9725 +G01 Z-0.0070 F10 +G01 X-1.3275 Y0.9725 F20 +G01 X-1.3275 Y0.9708 +G01 X-1.3258 Y0.9725 +G00 Z0.1000 +G00 X-1.2309 Y0.8995 +G01 Z-0.0070 F10 +G01 X-1.3091 Y0.8995 F20 +G01 X-1.3239 Y0.9057 +G01 X-1.3275 Y0.9092 +G01 X-1.3275 Y0.8708 +G01 X-1.3239 Y0.8743 +G01 X-1.3091 Y0.8805 +G01 X-1.2309 Y0.8805 +G01 X-1.2161 Y0.8743 +G01 X-1.2082 Y0.8665 +G01 X-1.1572 Y0.9175 +G01 X-1.1427 Y0.9175 +G01 X-0.4927 Y0.9175 +G01 X-0.4825 Y0.9072 +G01 X-0.3427 Y0.7675 +G01 X-0.3204 Y0.7675 +G01 X-0.3345 Y0.7816 +G01 X-0.3345 Y0.7825 +G01 X-0.3353 Y0.7825 +G01 X-0.3422 Y0.7825 +G01 X-0.3425 Y0.7828 +G01 X-0.3429 Y0.7828 +G01 X-0.3476 Y0.7879 +G01 X-0.3525 Y0.7927 +G01 X-0.3525 Y0.7931 +G01 X-0.4726 Y0.9225 +G01 X-1.2024 Y0.9225 +G01 X-1.2047 Y0.9171 +G01 X-1.2161 Y0.9057 +G01 X-1.2309 Y0.8995 +G00 Z0.1000 +G00 X-1.2047 Y0.9629 +G01 Z-0.0070 F10 +G01 X-1.2024 Y0.9575 F20 +G01 X-0.4719 Y0.9575 +G01 X-0.4716 Y0.9578 +G01 X-0.4647 Y0.9575 +G01 X-0.4622 Y0.9575 +G01 X-0.4775 Y0.9727 +G01 X-0.4775 Y0.9752 +G01 X-0.4932 Y0.9595 +G01 X-0.5268 Y0.9595 +G01 X-0.5398 Y0.9725 +G01 X-1.2142 Y0.9725 +G01 X-1.2047 Y0.9629 +G00 Z0.1000 +G00 X-0.5505 Y1.0168 +G01 Z-0.0070 F10 +G01 X-0.5348 Y1.0325 F20 +G01 X-1.1985 Y1.0325 +G01 X-1.1985 Y1.0319 +G01 X-1.2047 Y1.0171 +G01 X-1.2142 Y1.0075 +G01 X-0.5505 Y1.0075 +G01 X-0.5505 Y1.0168 +G00 Z0.1000 +G00 X-1.4732 Y1.2105 +G01 Z-0.0070 F10 +G01 X-1.4575 Y1.1948 F20 +G01 X-1.4575 Y1.2052 +G01 X-1.4805 Y1.2282 +G01 X-1.4805 Y1.2607 +G01 X-1.4922 Y1.2725 +G01 X-1.7627 Y1.2725 +G01 X-1.7644 Y1.2709 +G01 X-1.7604 Y1.2725 +G01 X-1.7396 Y1.2725 +G01 X-1.7203 Y1.2645 +G01 X-1.7055 Y1.2497 +G01 X-1.6975 Y1.2304 +G01 X-1.6975 Y1.2175 +G01 X-1.5127 Y1.2175 +G01 X-1.5058 Y1.2105 +G01 X-1.4732 Y1.2105 +G00 Z0.1000 +G00 X-1.3875 Y0.5522 +G01 Z-0.0070 F10 +G01 X-1.3825 Y0.5472 F20 +G01 X-1.3825 Y0.5327 +G01 X-1.3875 Y0.5277 +G01 X-1.3875 Y0.5075 +G01 X-1.3258 Y0.5075 +G01 X-1.3353 Y0.5171 +G01 X-1.3415 Y0.5319 +G01 X-1.3415 Y0.5481 +G01 X-1.3360 Y0.5613 +G01 X-1.3775 Y0.6027 +G01 X-1.3775 Y0.6172 +G01 X-1.3775 Y0.6672 +G01 X-1.3672 Y0.6775 +G01 X-1.3372 Y0.7075 +G01 X-1.3258 Y0.7075 +G01 X-1.3353 Y0.7171 +G01 X-1.3376 Y0.7225 +G01 X-1.3393 Y0.7225 +G01 X-1.3459 Y0.7220 +G01 X-1.3465 Y0.7225 +G01 X-1.3472 Y0.7225 +G01 X-1.3519 Y0.7271 +G01 X-1.3815 Y0.7525 +G01 X-1.3822 Y0.7525 +G01 X-1.3869 Y0.7572 +G01 X-1.3875 Y0.7577 +G01 X-1.3875 Y0.5522 +G00 Z0.1000 +G00 X-1.5125 Y0.7708 +G01 Z-0.0070 F10 +G01 X-1.5125 Y0.7725 F20 +G01 X-1.5142 Y0.7725 +G01 X-1.5125 Y0.7708 +G00 Z0.1000 +G00 X-1.4322 Y0.1275 +G01 Z-0.0070 F10 +G01 X-1.4375 Y0.1327 F20 +G01 X-1.4675 Y0.1627 +G01 X-1.4675 Y0.1772 +G01 X-1.4675 Y0.5987 +G01 X-1.4683 Y0.6047 +G01 X-1.4675 Y0.6058 +G01 X-1.4675 Y0.6072 +G01 X-1.4633 Y0.6115 +G01 X-1.4525 Y0.6258 +G01 X-1.4525 Y0.6377 +G01 X-1.4725 Y0.6137 +G01 X-1.4725 Y0.1472 +G01 X-1.4527 Y0.1275 +G01 X-1.4322 Y0.1275 +G00 Z0.1000 +G00 X-1.7720 Y1.1723 +G01 Z-0.0070 F10 +G01 X-1.7797 Y1.1755 F20 +G01 X-1.7945 Y1.1903 +G01 X-1.8025 Y1.2096 +G01 X-1.8025 Y1.2304 +G01 X-1.8009 Y1.2344 +G01 X-1.8025 Y1.2327 +G01 X-1.8025 Y1.1972 +G01 X-1.7747 Y1.1695 +G01 X-1.7720 Y1.1723 +G00 Z0.1000 +G00 X-2.0847 Y0.1271 +G01 Z-0.0070 F10 +G01 X-2.0961 Y0.1157 F20 +G01 X-2.1109 Y0.1095 +G01 X-2.1891 Y0.1095 +G01 X-2.2039 Y0.1157 +G01 X-2.2153 Y0.1271 +G01 X-2.2215 Y0.1419 +G01 X-2.2215 Y0.1581 +G01 X-2.2153 Y0.1729 +G01 X-2.2039 Y0.1843 +G01 X-2.1891 Y0.1905 +G01 X-2.1275 Y0.1905 +G01 X-2.1275 Y0.2027 +G01 X-2.1342 Y0.2095 +G01 X-2.1891 Y0.2095 +G01 X-2.2039 Y0.2157 +G01 X-2.2153 Y0.2271 +G01 X-2.2215 Y0.2419 +G01 X-2.2215 Y0.2581 +G01 X-2.2153 Y0.2729 +G01 X-2.2039 Y0.2843 +G01 X-2.1891 Y0.2905 +G01 X-2.1275 Y0.2905 +G01 X-2.1275 Y0.3027 +G01 X-2.1342 Y0.3095 +G01 X-2.1891 Y0.3095 +G01 X-2.2039 Y0.3157 +G01 X-2.2153 Y0.3271 +G01 X-2.2176 Y0.3325 +G01 X-2.3125 Y0.3325 +G01 X-2.3125 Y0.1272 +G01 X-2.2228 Y0.0375 +G01 X-2.0572 Y0.0375 +G01 X-2.0625 Y0.0427 +G01 X-2.0722 Y0.0525 +G01 X-2.0825 Y0.0627 +G01 X-2.0825 Y0.1323 +G01 X-2.0847 Y0.1271 +G00 Z0.1000 +G00 X-2.0847 Y0.2271 +G01 Z-0.0070 F10 +G01 X-2.0935 Y0.2182 F20 +G01 X-2.0925 Y0.2172 +G01 X-2.0925 Y0.2027 +G01 X-2.0925 Y0.1808 +G01 X-2.0847 Y0.1729 +G01 X-2.0825 Y0.1677 +G01 X-2.0825 Y0.2323 +G01 X-2.0847 Y0.2271 +G00 Z0.1000 +G00 X-2.0847 Y0.3271 +G01 Z-0.0070 F10 +G01 X-2.0935 Y0.3182 F20 +G01 X-2.0925 Y0.3172 +G01 X-2.0925 Y0.3027 +G01 X-2.0925 Y0.2808 +G01 X-2.0847 Y0.2729 +G01 X-2.0825 Y0.2677 +G01 X-2.0825 Y0.3323 +G01 X-2.0847 Y0.3271 +G00 Z0.1000 +G00 X-2.0825 Y0.3677 +G01 Z-0.0070 F10 +G01 X-2.0825 Y0.3709 F20 +G01 X-2.0844 Y0.3723 +G01 X-2.0825 Y0.3677 +G00 Z0.1000 +G00 X-2.0577 Y0.3975 +G01 Z-0.0070 F10 +G01 X-2.0537 Y0.3934 F20 +G01 X-2.0490 Y0.3901 +G01 X-2.0487 Y0.3884 +G01 X-2.0475 Y0.3872 +G01 X-2.0475 Y0.3815 +G01 X-2.0465 Y0.3758 +G01 X-2.0475 Y0.3744 +G01 X-2.0475 Y0.0772 +G01 X-2.0378 Y0.0675 +G01 X-1.9222 Y0.0675 +G01 X-1.9275 Y0.0727 +G01 X-2.0172 Y0.1625 +G01 X-2.0275 Y0.1727 +G01 X-2.0275 Y0.3877 +G01 X-2.0372 Y0.3975 +G01 X-2.0527 Y0.3975 +G01 X-2.0595 Y0.3975 +G01 X-2.0577 Y0.3975 +G00 Z0.1000 +G00 X-2.1275 Y0.4577 +G01 Z-0.0070 F10 +G01 X-2.1275 Y0.4722 F20 +G01 X-2.1275 Y0.5172 +G01 X-2.1172 Y0.5275 +G01 X-2.0875 Y0.5572 +G01 X-2.0772 Y0.5675 +G01 X-1.6972 Y0.5675 +G01 X-1.6775 Y0.5872 +G01 X-1.6775 Y0.7127 +G01 X-1.6775 Y0.7272 +G01 X-1.6625 Y0.7422 +G01 X-1.6522 Y0.7525 +G01 X-1.6397 Y0.7525 +G01 X-1.6353 Y0.7629 +G01 X-1.6258 Y0.7725 +G01 X-1.6372 Y0.7725 +G01 X-1.6572 Y0.7925 +G01 X-1.6675 Y0.8027 +G01 X-1.6675 Y0.8527 +G01 X-1.6675 Y0.8672 +G01 X-1.6375 Y0.8972 +G01 X-1.6272 Y0.9075 +G01 X-1.6258 Y0.9075 +G01 X-1.6353 Y0.9171 +G01 X-1.6376 Y0.9225 +G01 X-1.6727 Y0.9225 +G01 X-1.6925 Y0.9027 +G01 X-1.6925 Y0.6372 +G01 X-1.6925 Y0.6227 +G01 X-1.7325 Y0.5827 +G01 X-1.7427 Y0.5725 +G01 X-2.0827 Y0.5725 +G01 X-2.1325 Y0.5227 +G01 X-2.1325 Y0.4491 +G01 X-2.0859 Y0.4162 +G01 X-2.1275 Y0.4577 +G00 Z0.1000 +G00 X-2.1572 Y0.4225 +G01 Z-0.0070 F10 +G01 X-2.1613 Y0.4266 F20 +G01 X-2.1660 Y0.4299 +G01 X-2.1663 Y0.4316 +G01 X-2.1675 Y0.4327 +G01 X-2.1675 Y0.4385 +G01 X-2.1685 Y0.4442 +G01 X-2.1675 Y0.4455 +G01 X-2.1675 Y0.5227 +G01 X-2.1675 Y0.5372 +G01 X-2.0972 Y0.6075 +G01 X-2.0827 Y0.6075 +G01 X-1.7572 Y0.6075 +G01 X-1.7275 Y0.6372 +G01 X-1.7275 Y0.9172 +G01 X-1.7172 Y0.9275 +G01 X-1.6975 Y0.9472 +G01 X-1.6872 Y0.9575 +G01 X-1.6376 Y0.9575 +G01 X-1.6353 Y0.9629 +G01 X-1.6239 Y0.9743 +G01 X-1.6091 Y0.9805 +G01 X-1.5309 Y0.9805 +G01 X-1.5161 Y0.9743 +G01 X-1.5047 Y0.9629 +G01 X-1.4985 Y0.9481 +G01 X-1.4985 Y0.9319 +G01 X-1.5047 Y0.9171 +G01 X-1.5142 Y0.9075 +G01 X-1.4968 Y0.9075 +G01 X-1.4965 Y0.9078 +G01 X-1.4896 Y0.9075 +G01 X-1.4827 Y0.9075 +G01 X-1.4824 Y0.9072 +G01 X-1.4820 Y0.9072 +G01 X-1.4774 Y0.9021 +G01 X-1.4725 Y0.8972 +G01 X-1.4725 Y0.8968 +G01 X-1.4225 Y0.8423 +G01 X-1.4225 Y0.9030 +G01 X-1.5175 Y1.0025 +G01 X-1.5237 Y1.0025 +G01 X-1.5309 Y0.9995 +G01 X-1.6091 Y0.9995 +G01 X-1.6163 Y1.0025 +G01 X-1.6577 Y1.0025 +G01 X-1.7125 Y0.9477 +G01 X-1.7227 Y0.9375 +G01 X-1.7825 Y0.9375 +G01 X-1.7825 Y0.7198 +G01 X-1.7595 Y0.6968 +G01 X-1.7595 Y0.6632 +G01 X-1.7832 Y0.6395 +G01 X-1.8168 Y0.6395 +G01 X-1.8298 Y0.6525 +G01 X-1.8902 Y0.6525 +G01 X-1.9032 Y0.6395 +G01 X-1.9368 Y0.6395 +G01 X-1.9498 Y0.6525 +G01 X-2.0102 Y0.6525 +G01 X-2.0232 Y0.6395 +G01 X-2.0568 Y0.6395 +G01 X-2.0805 Y0.6632 +G01 X-2.0805 Y0.6968 +G01 X-2.0568 Y0.7205 +G01 X-2.0232 Y0.7205 +G01 X-1.9995 Y0.6968 +G01 X-1.9995 Y0.6875 +G01 X-1.9605 Y0.6875 +G01 X-1.9605 Y0.6968 +G01 X-1.9368 Y0.7205 +G01 X-1.9032 Y0.7205 +G01 X-1.8795 Y0.6968 +G01 X-1.8795 Y0.6875 +G01 X-1.8405 Y0.6875 +G01 X-1.8405 Y0.6968 +G01 X-1.8175 Y0.7198 +G01 X-1.8175 Y0.9375 +G01 X-1.8827 Y0.9375 +G01 X-1.8972 Y0.9375 +G01 X-1.9375 Y0.9777 +G01 X-1.9375 Y0.9922 +G01 X-1.9375 Y1.0627 +G01 X-1.9772 Y1.1025 +G01 X-2.0327 Y1.1025 +G01 X-2.0825 Y1.0527 +G01 X-2.0825 Y1.0372 +G01 X-2.0825 Y1.0227 +G01 X-2.1725 Y0.9327 +G01 X-2.1827 Y0.9225 +G01 X-2.3527 Y0.9225 +G01 X-2.3672 Y0.9225 +G01 X-2.4172 Y0.9725 +G01 X-2.4275 Y0.9827 +G01 X-2.4275 Y1.0727 +G01 X-2.4275 Y1.0872 +G01 X-2.3175 Y1.1972 +G01 X-2.3072 Y1.2075 +G01 X-1.8375 Y1.2075 +G01 X-1.8375 Y1.2327 +G01 X-1.8375 Y1.2472 +G01 X-1.7875 Y1.2972 +G01 X-1.7772 Y1.3075 +G01 X-1.4777 Y1.3075 +G01 X-1.4675 Y1.2972 +G01 X-1.4557 Y1.2855 +G01 X-1.4232 Y1.2855 +G01 X-1.3995 Y1.2618 +G01 X-1.3995 Y1.2282 +G01 X-1.4225 Y1.2052 +G01 X-1.4225 Y1.1948 +G01 X-1.4068 Y1.2105 +G01 X-1.3732 Y1.2105 +G01 X-1.3602 Y1.1975 +G01 X-1.3272 Y1.1975 +G01 X-1.2675 Y1.2572 +G01 X-1.2572 Y1.2675 +G01 X-1.2072 Y1.2675 +G01 X-1.1927 Y1.2675 +G01 X-1.1527 Y1.2274 +G01 X-1.1404 Y1.2325 +G01 X-1.1196 Y1.2325 +G01 X-1.1003 Y1.2245 +G01 X-1.0855 Y1.2097 +G01 X-1.0775 Y1.1904 +G01 X-1.0775 Y1.1775 +G01 X-0.3522 Y1.1775 +G01 X-0.3377 Y1.1775 +G01 X-0.2048 Y1.0445 +G01 X-0.1716 Y1.0445 +G01 X-0.1455 Y1.0184 +G01 X-0.1455 Y0.9820 +G01 X-0.0930 Y0.9325 +G01 X-0.0927 Y0.9325 +G01 X-0.0878 Y0.9276 +G01 X-0.0827 Y0.9227 +G01 X-0.0827 Y0.9224 +G01 X-0.0825 Y0.9222 +G01 X-0.0825 Y0.9153 +G01 X-0.0823 Y0.9083 +G01 X-0.0825 Y0.9080 +G01 X-0.0825 Y0.5977 +G01 X-0.0927 Y0.5875 +G01 X-0.1225 Y0.5578 +G01 X-0.1225 Y0.3672 +G01 X-0.1225 Y0.3527 +G01 X-0.4727 Y0.0025 +G01 X-0.4872 Y0.0025 +G01 X-2.2372 Y0.0025 +G01 X-2.2475 Y0.0127 +G01 X-2.3372 Y0.1025 +G01 X-2.3475 Y0.1127 +G01 X-2.3475 Y0.3427 +G01 X-2.3475 Y0.3572 +G01 X-2.3475 Y0.7727 +G01 X-2.3475 Y0.7872 +G01 X-2.2822 Y0.8525 +G01 X-2.2677 Y0.8525 +G01 X-2.1922 Y0.8525 +G01 X-2.0494 Y0.9953 +G01 X-2.0595 Y1.0054 +G01 X-2.0595 Y1.0546 +G01 X-2.0246 Y1.0895 +G01 X-1.9754 Y1.0895 +G01 X-1.9405 Y1.0546 +G01 X-1.9405 Y1.0054 +G01 X-1.9754 Y0.9705 +G01 X-2.0246 Y0.9705 +G01 X-2.1675 Y0.8277 +G01 X-2.1777 Y0.8175 +G01 X-2.2677 Y0.8175 +G01 X-2.3125 Y0.7727 +G01 X-2.3125 Y0.3675 +G01 X-2.2176 Y0.3675 +G01 X-2.2153 Y0.3729 +G01 X-2.2039 Y0.3843 +G01 X-2.1891 Y0.3905 +G01 X-2.1109 Y0.3905 +G01 X-2.1092 Y0.3898 +G01 X-2.1556 Y0.4225 +G01 X-2.1572 Y0.4225 +G00 Z0.1000 +G00 X-1.7025 Y0.9493 +G01 Z-0.0070 F10 +G01 X-1.6893 Y0.9625 F20 +G01 X-1.6409 Y0.9625 +G01 X-1.6396 Y0.9658 +G01 X-1.6268 Y0.9786 +G01 X-1.6101 Y0.9855 +G01 X-1.5299 Y0.9855 +G01 X-1.5132 Y0.9786 +G01 X-1.5004 Y0.9658 +G01 X-1.4935 Y0.9491 +G01 X-1.4935 Y0.9309 +G01 X-1.5004 Y0.9142 +G01 X-1.5022 Y0.9125 +G01 X-1.4987 Y0.9125 +G01 X-1.4983 Y0.9129 +G01 X-1.4895 Y0.9125 +G01 X-1.4807 Y0.9125 +G01 X-1.4803 Y0.9121 +G01 X-1.4797 Y0.9121 +G01 X-1.4737 Y0.9056 +G01 X-1.4675 Y0.8993 +G01 X-1.4675 Y0.8987 +G01 X-1.4275 Y0.8551 +G01 X-1.4275 Y0.9010 +G01 X-1.5196 Y0.9975 +G01 X-1.5227 Y0.9975 +G01 X-1.5299 Y0.9945 +G01 X-1.6101 Y0.9945 +G01 X-1.6173 Y0.9975 +G01 X-1.6557 Y0.9975 +G01 X-1.7075 Y0.9457 +G01 X-1.7207 Y0.9325 +G01 X-1.7775 Y0.9325 +G01 X-1.7775 Y0.7218 +G01 X-1.7545 Y0.6988 +G01 X-1.7545 Y0.6612 +G01 X-1.7812 Y0.6345 +G01 X-1.8188 Y0.6345 +G01 X-1.8318 Y0.6475 +G01 X-1.8882 Y0.6475 +G01 X-1.9012 Y0.6345 +G01 X-1.9388 Y0.6345 +G01 X-1.9518 Y0.6475 +G01 X-2.0082 Y0.6475 +G01 X-2.0212 Y0.6345 +G01 X-2.0588 Y0.6345 +G01 X-2.0855 Y0.6612 +G01 X-2.0855 Y0.6988 +G01 X-2.0588 Y0.7255 +G01 X-2.0212 Y0.7255 +G01 X-1.9945 Y0.6988 +G01 X-1.9945 Y0.6925 +G01 X-1.9655 Y0.6925 +G01 X-1.9655 Y0.6988 +G01 X-1.9388 Y0.7255 +G01 X-1.9012 Y0.7255 +G01 X-1.8745 Y0.6988 +G01 X-1.8745 Y0.6925 +G01 X-1.8455 Y0.6925 +G01 X-1.8455 Y0.6988 +G01 X-1.8225 Y0.7218 +G01 X-1.8225 Y0.9325 +G01 X-1.8807 Y0.9325 +G01 X-1.8993 Y0.9325 +G01 X-1.9425 Y0.9757 +G01 X-1.9425 Y0.9943 +G01 X-1.9425 Y0.9963 +G01 X-1.9733 Y0.9655 +G01 X-2.0227 Y0.9655 +G01 X-2.1625 Y0.8257 +G01 X-2.1757 Y0.8125 +G01 X-2.2657 Y0.8125 +G01 X-2.3075 Y0.7707 +G01 X-2.3075 Y0.3725 +G01 X-2.2209 Y0.3725 +G01 X-2.2196 Y0.3758 +G01 X-2.2068 Y0.3886 +G01 X-2.1901 Y0.3955 +G01 X-2.1260 Y0.3955 +G01 X-2.1571 Y0.4175 +G01 X-2.1593 Y0.4175 +G01 X-2.1646 Y0.4227 +G01 X-2.1706 Y0.4270 +G01 X-2.1710 Y0.4291 +G01 X-2.1725 Y0.4307 +G01 X-2.1725 Y0.4381 +G01 X-2.1738 Y0.4454 +G01 X-2.1725 Y0.4471 +G01 X-2.1725 Y0.5207 +G01 X-2.1725 Y0.5393 +G01 X-2.0993 Y0.6125 +G01 X-2.0807 Y0.6125 +G01 X-1.7593 Y0.6125 +G01 X-1.7325 Y0.6393 +G01 X-1.7325 Y0.9193 +G01 X-1.7193 Y0.9325 +G01 X-1.7025 Y0.9493 +G00 Z0.1000 +G00 X-2.0875 Y0.3172 +G01 Z-0.0070 F10 +G01 X-2.0875 Y0.3007 F20 +G01 X-2.0875 Y0.2828 +G01 X-2.0875 Y0.3172 +G00 Z0.1000 +G00 X-2.0875 Y0.2172 +G01 Z-0.0070 F10 +G01 X-2.0875 Y0.2007 F20 +G01 X-2.0875 Y0.1828 +G01 X-2.0875 Y0.2172 +G00 Z0.1000 +G00 X-2.0932 Y0.1114 +G01 Z-0.0070 F10 +G01 X-2.1099 Y0.1045 F20 +G01 X-2.1901 Y0.1045 +G01 X-2.2068 Y0.1114 +G01 X-2.2196 Y0.1242 +G01 X-2.2265 Y0.1409 +G01 X-2.2265 Y0.1591 +G01 X-2.2196 Y0.1758 +G01 X-2.2068 Y0.1886 +G01 X-2.1901 Y0.1955 +G01 X-2.1325 Y0.1955 +G01 X-2.1325 Y0.2007 +G01 X-2.1363 Y0.2045 +G01 X-2.1901 Y0.2045 +G01 X-2.2068 Y0.2114 +G01 X-2.2196 Y0.2242 +G01 X-2.2265 Y0.2409 +G01 X-2.2265 Y0.2591 +G01 X-2.2196 Y0.2758 +G01 X-2.2068 Y0.2886 +G01 X-2.1901 Y0.2955 +G01 X-2.1325 Y0.2955 +G01 X-2.1325 Y0.3007 +G01 X-2.1363 Y0.3045 +G01 X-2.1901 Y0.3045 +G01 X-2.2068 Y0.3114 +G01 X-2.2196 Y0.3242 +G01 X-2.2209 Y0.3275 +G01 X-2.3075 Y0.3275 +G01 X-2.3075 Y0.1293 +G01 X-2.2207 Y0.0425 +G01 X-2.0693 Y0.0425 +G01 X-2.0743 Y0.0475 +G01 X-2.0875 Y0.0607 +G01 X-2.0875 Y0.1172 +G01 X-2.0932 Y0.1114 +G00 Z0.1000 +G00 X-2.0357 Y0.0725 +G01 Z-0.0070 F10 +G01 X-1.9343 Y0.0725 F20 +G01 X-2.0193 Y0.1575 +G01 X-2.0325 Y0.1707 +G01 X-2.0325 Y0.3857 +G01 X-2.0393 Y0.3925 +G01 X-2.0443 Y0.3925 +G01 X-2.0440 Y0.3909 +G01 X-2.0425 Y0.3893 +G01 X-2.0425 Y0.3819 +G01 X-2.0412 Y0.3746 +G01 X-2.0425 Y0.3729 +G01 X-2.0425 Y0.0793 +G01 X-2.0357 Y0.0725 +G00 Z0.1000 +G00 X-1.6993 Y0.5725 +G01 Z-0.0070 F10 +G01 X-1.6825 Y0.5893 F20 +G01 X-1.6825 Y0.7107 +G01 X-1.6825 Y0.7293 +G01 X-1.6675 Y0.7443 +G01 X-1.6543 Y0.7575 +G01 X-1.6430 Y0.7575 +G01 X-1.6396 Y0.7658 +G01 X-1.6378 Y0.7675 +G01 X-1.6393 Y0.7675 +G01 X-1.6593 Y0.7875 +G01 X-1.6725 Y0.8007 +G01 X-1.6725 Y0.8507 +G01 X-1.6725 Y0.8693 +G01 X-1.6425 Y0.8993 +G01 X-1.6336 Y0.9082 +G01 X-1.6396 Y0.9142 +G01 X-1.6409 Y0.9175 +G01 X-1.6707 Y0.9175 +G01 X-1.6875 Y0.9007 +G01 X-1.6875 Y0.6393 +G01 X-1.6875 Y0.6207 +G01 X-1.7275 Y0.5807 +G01 X-1.7357 Y0.5725 +G01 X-1.6993 Y0.5725 +G00 Z0.1000 +G00 X-1.3487 Y0.1869 +G01 Z-0.0070 F10 +G01 X-1.3512 Y0.1845 F20 +G01 X-1.3888 Y0.1845 +G01 X-1.4155 Y0.2112 +G01 X-1.4155 Y0.2488 +G01 X-1.3925 Y0.2718 +G01 X-1.3925 Y0.3057 +G01 X-1.4275 Y0.3407 +G01 X-1.4275 Y0.3593 +G01 X-1.4275 Y0.4993 +G01 X-1.4275 Y0.5257 +G01 X-1.4275 Y0.5307 +G01 X-1.4275 Y0.5925 +G01 X-1.4275 Y0.1793 +G01 X-1.4107 Y0.1625 +G01 X-1.3243 Y0.1625 +G01 X-1.3487 Y0.1869 +G00 Z0.1000 +G00 X-0.5554 Y0.2264 +G01 Z-0.0070 F10 +G01 X-0.5599 Y0.2245 F20 +G01 X-0.6401 Y0.2245 +G01 X-0.6568 Y0.2314 +G01 X-0.6628 Y0.2375 +G01 X-0.9407 Y0.2375 +G01 X-1.0075 Y0.1707 +G01 X-1.0157 Y0.1625 +G01 X-0.6193 Y0.1625 +G01 X-0.5554 Y0.2264 +G00 Z0.1000 +G00 X-0.1695 Y0.4495 +G01 Z-0.0070 F10 +G01 X-0.1625 Y0.4425 F20 +G01 X-0.1625 Y0.4575 +G01 X-0.1695 Y0.4505 +G01 X-0.2077 Y0.4505 +G01 X-0.2087 Y0.4495 +G01 X-0.1695 Y0.4495 +G00 Z0.1000 +G00 X-0.2395 Y0.5205 +G01 Z-0.0070 F10 +G01 X-0.2325 Y0.5275 F20 +G01 X-0.2475 Y0.5275 +G01 X-0.2405 Y0.5205 +G01 X-0.2405 Y0.4813 +G01 X-0.2395 Y0.4823 +G01 X-0.2395 Y0.5205 +G00 Z0.1000 +G00 X-0.2695 Y0.4505 +G01 Z-0.0070 F10 +G01 X-0.3077 Y0.4505 F20 +G01 X-0.3087 Y0.4495 +G01 X-0.2695 Y0.4495 +G01 X-0.2625 Y0.4425 +G01 X-0.2625 Y0.4575 +G01 X-0.2695 Y0.4505 +G00 Z0.1000 +G00 X-0.8817 Y0.8768 +G01 Z-0.0070 F10 +G01 X-0.8809 Y0.8749 F20 +G01 X-0.8801 Y0.8768 +G01 X-0.8794 Y0.8775 +G01 X-0.8823 Y0.8775 +G01 X-0.8817 Y0.8768 +G00 Z0.1000 +G00 X-0.8029 Y0.8768 +G01 Z-0.0070 F10 +G01 X-0.8021 Y0.8749 F20 +G01 X-0.8013 Y0.8768 +G01 X-0.8006 Y0.8775 +G01 X-0.8036 Y0.8775 +G01 X-0.8029 Y0.8768 +G00 Z0.1000 +G00 X-0.2395 Y0.9795 +G01 Z-0.0070 F10 +G01 X-0.2395 Y1.0205 F20 +G01 X-0.2384 Y1.0216 +G01 X-0.3543 Y1.1375 +G01 X-1.0864 Y1.1375 +G01 X-1.0917 Y1.1357 +G01 X-1.0926 Y1.1361 +G01 X-1.0962 Y1.1325 +G01 X-0.4907 Y1.1325 +G01 X-0.4775 Y1.1193 +G01 X-0.4037 Y1.0455 +G01 X-0.3912 Y1.0455 +G01 X-0.3645 Y1.0188 +G01 X-0.3645 Y1.0125 +G01 X-0.3395 Y1.0125 +G01 X-0.3395 Y1.0205 +G01 X-0.3105 Y1.0495 +G01 X-0.2695 Y1.0495 +G01 X-0.2405 Y1.0205 +G01 X-0.2405 Y0.9795 +G01 X-0.2475 Y0.9725 +G01 X-0.2325 Y0.9725 +G01 X-0.2395 Y0.9795 +G00 Z0.1000 +G00 X-2.1343 Y1.1675 +G01 Z-0.0070 F10 +G01 X-2.2907 Y1.1675 F20 +G01 X-2.3875 Y1.0707 +G01 X-2.3875 Y0.9993 +G01 X-2.3507 Y0.9625 +G01 X-2.1993 Y0.9625 +G01 X-2.1225 Y1.0393 +G01 X-2.1225 Y1.0693 +G01 X-2.1093 Y1.0825 +G01 X-2.0543 Y1.1375 +G01 X-2.1007 Y1.1375 +G01 X-2.1375 Y1.1007 +G01 X-2.1507 Y1.0875 +G01 X-2.1607 Y1.0875 +G01 X-2.2275 Y1.0207 +G01 X-2.2355 Y1.0127 +G01 X-2.2355 Y1.0033 +G01 X-2.2733 Y0.9655 +G01 X-2.3267 Y0.9655 +G01 X-2.3645 Y1.0033 +G01 X-2.3645 Y1.0567 +G01 X-2.3267 Y1.0945 +G01 X-2.2733 Y1.0945 +G01 X-2.2453 Y1.0665 +G01 X-2.1925 Y1.1193 +G01 X-2.1793 Y1.1325 +G01 X-2.1693 Y1.1325 +G01 X-2.1343 Y1.1675 +G00 Z0.1000 +G00 X-1.5355 Y1.1512 +G01 Z-0.0070 F10 +G01 X-1.5355 Y1.1775 F20 +G01 X-1.7064 Y1.1775 +G01 X-1.7117 Y1.1757 +G01 X-1.7126 Y1.1761 +G01 X-1.7174 Y1.1713 +G01 X-1.7192 Y1.1705 +G01 X-1.6925 Y1.1438 +G01 X-1.6925 Y1.0962 +G01 X-1.7262 Y1.0625 +G01 X-1.7738 Y1.0625 +G01 X-1.8075 Y1.0962 +G01 X-1.8075 Y1.1438 +G01 X-1.8066 Y1.1447 +G01 X-1.8293 Y1.1675 +G01 X-1.8957 Y1.1675 +G01 X-1.7707 Y1.0425 +G01 X-1.7293 Y1.0425 +G01 X-1.6493 Y1.1225 +G01 X-1.6307 Y1.1225 +G01 X-1.5125 Y1.1225 +G01 X-1.5125 Y1.1282 +G01 X-1.5355 Y1.1512 +G00 Z0.1000 +G00 X-1.3396 Y1.0142 +G01 Z-0.0070 F10 +G01 X-1.3465 Y1.0309 F20 +G01 X-1.3465 Y1.0491 +G01 X-1.3396 Y1.0658 +G01 X-1.3268 Y1.0786 +G01 X-1.3101 Y1.0855 +G01 X-1.2299 Y1.0855 +G01 X-1.2132 Y1.0786 +G01 X-1.2071 Y1.0725 +G01 X-0.4993 Y1.0725 +G01 X-0.4943 Y1.0725 +G01 X-0.5093 Y1.0875 +G01 X-1.1507 Y1.0875 +G01 X-1.1693 Y1.0875 +G01 X-1.2052 Y1.1234 +G01 X-1.2062 Y1.1225 +G01 X-1.2538 Y1.1225 +G01 X-1.2647 Y1.1334 +G01 X-1.2875 Y1.1107 +G01 X-1.3007 Y1.0975 +G01 X-1.4107 Y1.0975 +G01 X-1.4257 Y1.0975 +G01 X-1.3407 Y1.0125 +G01 X-1.3378 Y1.0125 +G01 X-1.3396 Y1.0142 +G00 Z0.1000 +G00 X-1.3525 Y0.7803 +G01 Z-0.0070 F10 +G01 X-1.3501 Y0.7783 F20 +G01 X-1.3525 Y0.7807 +G01 X-1.3525 Y0.7803 +G00 Z0.1000 +G00 X-0.9657 Y0.8601 +G01 Z-0.0070 F10 +G01 X-0.9588 Y0.8768 F20 +G01 X-0.9581 Y0.8775 +G01 X-1.1407 Y0.8775 +G01 X-1.1875 Y0.8307 +G01 X-1.1979 Y0.8202 +G01 X-1.1989 Y0.8179 +G01 X-1.1875 Y0.8293 +G01 X-1.1743 Y0.8425 +G01 X-0.9657 Y0.8425 +G01 X-0.9657 Y0.8601 +G00 Z0.1000 +G00 X-1.2004 Y0.7658 +G01 Z-0.0070 F10 +G01 X-1.1935 Y0.7491 F20 +G01 X-1.1935 Y0.7309 +G01 X-1.2004 Y0.7142 +G01 X-1.2022 Y0.7125 +G01 X-0.9593 Y0.7125 +G01 X-0.9375 Y0.7343 +G01 X-0.9283 Y0.7436 +G01 X-0.9293 Y0.7436 +G01 X-0.9460 Y0.7505 +G01 X-0.9588 Y0.7633 +G01 X-0.9657 Y0.7800 +G01 X-0.9657 Y0.7975 +G01 X-1.1557 Y0.7975 +G01 X-1.1857 Y0.7675 +G01 X-1.2022 Y0.7675 +G01 X-1.2004 Y0.7658 +G00 Z0.1000 +G00 X-1.4575 Y1.0657 +G01 Z-0.0070 F10 +G01 X-1.4575 Y1.0607 F20 +G01 X-1.4575 Y1.0490 +G01 X-1.3675 Y0.9547 +G01 X-1.3675 Y0.9757 +G01 X-1.4575 Y1.0657 +G00 Z0.1000 +G00 X-1.2299 Y0.8945 +G01 Z-0.0070 F10 +G01 X-1.3101 Y0.8945 F20 +G01 X-1.3225 Y0.8997 +G01 X-1.3225 Y0.8803 +G01 X-1.3101 Y0.8855 +G01 X-1.2299 Y0.8855 +G01 X-1.2132 Y0.8786 +G01 X-1.2082 Y0.8736 +G01 X-1.1643 Y0.9175 +G01 X-1.1991 Y0.9175 +G01 X-1.2004 Y0.9142 +G01 X-1.2132 Y0.9014 +G01 X-1.2299 Y0.8945 +G00 Z0.1000 +G00 X-1.2004 Y0.9658 +G01 Z-0.0070 F10 +G01 X-1.1991 Y0.9625 F20 +G01 X-0.5368 Y0.9625 +G01 X-0.5418 Y0.9675 +G01 X-1.2022 Y0.9675 +G01 X-1.2004 Y0.9658 +G00 Z0.1000 +G00 X-0.5555 Y1.0188 +G01 Z-0.0070 F10 +G01 X-0.5468 Y1.0275 F20 +G01 X-1.1949 Y1.0275 +G01 X-1.2004 Y1.0142 +G01 X-1.2022 Y1.0125 +G01 X-0.5555 Y1.0125 +G01 X-0.5555 Y1.0188 +G00 Z0.1000 +G00 X-1.4748 Y1.2155 +G01 Z-0.0070 F10 +G01 X-1.4855 Y1.2262 F20 +G01 X-1.4855 Y1.2587 +G01 X-1.4943 Y1.2675 +G01 X-1.7162 Y1.2675 +G01 X-1.7013 Y1.2526 +G01 X-1.6925 Y1.2314 +G01 X-1.6925 Y1.2225 +G01 X-1.5107 Y1.2225 +G01 X-1.5037 Y1.2155 +G01 X-1.4748 Y1.2155 +G00 Z0.1000 +G00 X-1.9557 Y1.1375 +G01 Z-0.0070 F10 +G01 X-1.9475 Y1.1293 F20 +G01 X-1.8975 Y1.0793 +G01 X-1.8975 Y1.0607 +G01 X-1.8975 Y0.9943 +G01 X-1.8807 Y0.9775 +G01 X-1.7907 Y0.9775 +G01 X-1.7393 Y0.9775 +G01 X-1.7193 Y0.9975 +G01 X-1.7707 Y0.9975 +G01 X-1.7893 Y0.9975 +G01 X-1.9293 Y1.1375 +G01 X-1.9557 Y1.1375 +G00 Z0.1000 +G00 X-1.6557 Y1.0425 +G01 Z-0.0070 F10 +G01 X-1.6465 Y1.0425 F20 +G01 X-1.6465 Y1.0491 +G01 X-1.6396 Y1.0658 +G01 X-1.6278 Y1.0775 +G01 X-1.6307 Y1.0775 +G01 X-1.6657 Y1.0425 +G01 X-1.6557 Y1.0425 +G00 Z0.1000 +G00 X-1.3825 Y0.5543 +G01 Z-0.0070 F10 +G01 X-1.3775 Y0.5493 F20 +G01 X-1.3775 Y0.5307 +G01 X-1.3825 Y0.5257 +G01 X-1.3825 Y0.5125 +G01 X-1.3378 Y0.5125 +G01 X-1.3396 Y0.5142 +G01 X-1.3465 Y0.5309 +G01 X-1.3465 Y0.5491 +G01 X-1.3419 Y0.5601 +G01 X-1.3825 Y0.6007 +G01 X-1.3825 Y0.6193 +G01 X-1.3825 Y0.6693 +G01 X-1.3693 Y0.6825 +G01 X-1.3393 Y0.7125 +G01 X-1.3378 Y0.7125 +G01 X-1.3396 Y0.7142 +G01 X-1.3409 Y0.7174 +G01 X-1.3476 Y0.7169 +G01 X-1.3483 Y0.7175 +G01 X-1.3493 Y0.7175 +G01 X-1.3553 Y0.7235 +G01 X-1.3825 Y0.7468 +G01 X-1.3825 Y0.5543 +G00 Z0.1000 +G00 X-0.4775 Y0.9093 +G01 Z-0.0070 F10 +G01 X-0.3407 Y0.7725 F20 +G01 X-0.3325 Y0.7725 +G01 X-0.3375 Y0.7775 +G01 X-0.3443 Y0.7775 +G01 X-0.3447 Y0.7778 +G01 X-0.3451 Y0.7779 +G01 X-0.3512 Y0.7844 +G01 X-0.3575 Y0.7907 +G01 X-0.3575 Y0.7912 +G01 X-0.4748 Y0.9175 +G01 X-0.4857 Y0.9175 +G01 X-0.4775 Y0.9093 +G00 Z0.1000 +G00 X-0.4787 Y0.9669 +G01 Z-0.0070 F10 +G01 X-0.4832 Y0.9625 F20 +G01 X-0.4743 Y0.9625 +G01 X-0.4787 Y0.9669 +G00 Z0.1000 +G00 X-0.1695 Y0.7505 +G01 Z-0.0070 F10 +G01 X-0.2077 Y0.7505 F20 +G01 X-0.2087 Y0.7495 +G01 X-0.1695 Y0.7495 +G01 X-0.1525 Y0.7325 +G01 X-0.1525 Y0.7675 +G01 X-0.1695 Y0.7505 +G00 Z0.1000 +G00 X-0.2395 Y0.9177 +G01 Z-0.0070 F10 +G01 X-0.2405 Y0.9187 F20 +G01 X-0.2405 Y0.8823 +G01 X-0.2395 Y0.8813 +G01 X-0.2395 Y0.9177 +G00 Z0.1000 +G00 X-0.2405 Y0.8205 +G01 Z-0.0070 F10 +G01 X-0.2405 Y0.7813 F20 +G01 X-0.2395 Y0.7823 +G01 X-0.2395 Y0.8205 +G01 X-0.2325 Y0.8275 +G01 X-0.2475 Y0.8275 +G01 X-0.2405 Y0.8205 +G00 Z0.1000 +G00 X-0.3105 Y0.8495 +G01 Z-0.0070 F10 +G01 X-0.2713 Y0.8495 F20 +G01 X-0.2723 Y0.8505 +G01 X-0.3105 Y0.8505 +G01 X-0.3395 Y0.8795 +G01 X-0.3395 Y0.9205 +G01 X-0.3325 Y0.9275 +G01 X-0.4227 Y0.9275 +G01 X-0.3311 Y0.8289 +G01 X-0.3105 Y0.8495 +G00 Z0.1000 +G00 X-0.1225 Y0.8425 +G01 Z-0.0070 F10 +G01 X-0.1225 Y0.9053 F20 +G01 X-0.1704 Y0.9505 +G01 X-0.2087 Y0.9505 +G01 X-0.2077 Y0.9495 +G01 X-0.1695 Y0.9495 +G01 X-0.1405 Y0.9205 +G01 X-0.1405 Y0.8795 +G01 X-0.1539 Y0.8661 +G01 X-0.1225 Y0.8425 +G00 Z0.1000 +G00 X-0.2395 Y0.6795 +G01 Z-0.0070 F10 +G01 X-0.2395 Y0.7205 F20 +G01 X-0.2325 Y0.7275 +G01 X-0.2475 Y0.7275 +G01 X-0.2405 Y0.7205 +G01 X-0.2405 Y0.6795 +G01 X-0.2475 Y0.6725 +G01 X-0.2325 Y0.6725 +G01 X-0.2395 Y0.6795 +G00 Z0.1000 +G00 X-0.3395 Y0.6795 +G01 Z-0.0070 F10 +G01 X-0.3395 Y0.7205 F20 +G01 X-0.3325 Y0.7275 +G01 X-0.3407 Y0.7275 +G01 X-0.3593 Y0.7275 +G01 X-0.5093 Y0.8775 +G01 X-0.7249 Y0.8775 +G01 X-0.7242 Y0.8768 +G01 X-0.7173 Y0.8601 +G01 X-0.7173 Y0.7800 +G01 X-0.7205 Y0.7723 +G01 X-0.6475 Y0.6993 +G01 X-0.6475 Y0.6807 +G01 X-0.6475 Y0.5743 +G01 X-0.6475 Y0.5557 +G01 X-0.7877 Y0.4155 +G01 X-0.7599 Y0.4155 +G01 X-0.7468 Y0.4100 +G01 X-0.7043 Y0.4525 +G01 X-0.6857 Y0.4525 +G01 X-0.5643 Y0.4525 +G01 X-0.5025 Y0.5143 +G01 X-0.5025 Y0.5193 +G01 X-0.4893 Y0.5325 +G01 X-0.3493 Y0.6725 +G01 X-0.3325 Y0.6725 +G01 X-0.3395 Y0.6795 +G00 Z0.1000 +G00 X-0.7235 Y0.3609 +G01 Z-0.0070 F10 +G01 X-0.7304 Y0.3442 F20 +G01 X-0.7422 Y0.3325 +G01 X-0.7143 Y0.3325 +G01 X-0.6643 Y0.3825 +G01 X-0.6457 Y0.3825 +G01 X-0.5343 Y0.3825 +G01 X-0.3443 Y0.5725 +G01 X-0.3325 Y0.5725 +G01 X-0.3395 Y0.5795 +G01 X-0.3395 Y0.6187 +G01 X-0.4575 Y0.5007 +G01 X-0.4575 Y0.4957 +G01 X-0.5325 Y0.4207 +G01 X-0.5457 Y0.4075 +G01 X-0.6857 Y0.4075 +G01 X-0.7235 Y0.3697 +G01 X-0.7235 Y0.3609 +G00 Z0.1000 +G00 X-0.2405 Y0.6205 +G01 Z-0.0070 F10 +G01 X-0.2405 Y0.5795 F20 +G01 X-0.2475 Y0.5725 +G01 X-0.2325 Y0.5725 +G01 X-0.2395 Y0.5795 +G01 X-0.2395 Y0.6205 +G01 X-0.2325 Y0.6275 +G01 X-0.2475 Y0.6275 +G01 X-0.2405 Y0.6205 +G00 Z0.1000 +G00 X-0.1405 Y0.6205 +G01 Z-0.0070 F10 +G01 X-0.1405 Y0.5963 F20 +G01 X-0.1225 Y0.6143 +G01 X-0.1225 Y0.6575 +G01 X-0.1539 Y0.6339 +G01 X-0.1405 Y0.6205 +G00 Z0.1000 +G00 X-1.3445 Y1.1512 +G01 Z-0.0070 F10 +G01 X-1.3532 Y1.1425 F20 +G01 X-1.3193 Y1.1425 +G01 X-1.2897 Y1.1722 +G01 X-1.2884 Y1.1760 +G01 X-1.2875 Y1.1764 +G01 X-1.2875 Y1.1807 +G01 X-1.3107 Y1.1575 +G01 X-1.3293 Y1.1575 +G01 X-1.3445 Y1.1575 +G01 X-1.3445 Y1.1512 +G00 Z0.1000 +G00 X-0.3395 Y0.5137 +G01 Z-0.0070 F10 +G01 X-0.5025 Y0.3507 F20 +G01 X-0.5157 Y0.3375 +G01 X-0.6457 Y0.3375 +G01 X-0.6825 Y0.3007 +G01 X-0.6957 Y0.2875 +G01 X-0.9207 Y0.2875 +G01 X-0.9393 Y0.2875 +G01 X-0.9707 Y0.2875 +G01 X-1.0007 Y0.2575 +G01 X-1.0193 Y0.2575 +G01 X-1.0249 Y0.2575 +G01 X-1.0304 Y0.2442 +G01 X-1.0432 Y0.2314 +G01 X-1.0599 Y0.2245 +G01 X-1.1401 Y0.2245 +G01 X-1.1568 Y0.2314 +G01 X-1.1696 Y0.2442 +G01 X-1.1765 Y0.2609 +G01 X-1.1765 Y0.2747 +G01 X-1.2082 Y0.3064 +G01 X-1.2132 Y0.3014 +G01 X-1.2299 Y0.2945 +G01 X-1.2375 Y0.2945 +G01 X-1.2375 Y0.2618 +G01 X-1.2245 Y0.2488 +G01 X-1.2245 Y0.2112 +G01 X-1.2332 Y0.2025 +G01 X-1.0393 Y0.2025 +G01 X-0.9593 Y0.2825 +G01 X-0.9407 Y0.2825 +G01 X-0.6751 Y0.2825 +G01 X-0.6696 Y0.2958 +G01 X-0.6568 Y0.3086 +G01 X-0.6401 Y0.3155 +G01 X-0.5599 Y0.3155 +G01 X-0.5432 Y0.3086 +G01 X-0.5304 Y0.2958 +G01 X-0.5235 Y0.2791 +G01 X-0.5235 Y0.2609 +G01 X-0.5254 Y0.2564 +G01 X-0.4025 Y0.3793 +G01 X-0.4025 Y0.4007 +G01 X-0.4025 Y0.4193 +G01 X-0.3395 Y0.4823 +G01 X-0.3395 Y0.5137 +G00 Z0.1000 +G00 X-1.2132 Y0.6014 +G01 Z-0.0070 F10 +G01 X-1.2299 Y0.5945 F20 +G01 X-1.3101 Y0.5945 +G01 X-1.3146 Y0.5964 +G01 X-1.3037 Y0.5855 +G01 X-1.2299 Y0.5855 +G01 X-1.2132 Y0.5786 +G01 X-1.2004 Y0.5658 +G01 X-1.1935 Y0.5491 +G01 X-1.1935 Y0.5309 +G01 X-1.2004 Y0.5142 +G01 X-1.2022 Y0.5125 +G01 X-0.8943 Y0.5125 +G01 X-0.8322 Y0.5746 +G01 X-0.8407 Y0.5832 +G01 X-0.8415 Y0.5851 +G01 X-0.8423 Y0.5832 +G01 X-0.8551 Y0.5704 +G01 X-0.8718 Y0.5634 +G01 X-0.8899 Y0.5634 +G01 X-0.9066 Y0.5704 +G01 X-0.9194 Y0.5832 +G01 X-0.9264 Y0.5999 +G01 X-0.9264 Y0.6075 +G01 X-1.2071 Y0.6075 +G01 X-1.2132 Y0.6014 +G00 Z0.1000 +G00 X-1.2022 Y0.6675 +G01 Z-0.0070 F10 +G01 X-1.2004 Y0.6658 F20 +G01 X-1.1949 Y0.6525 +G01 X-0.9264 Y0.6525 +G01 X-0.9264 Y0.6800 +G01 X-0.9251 Y0.6831 +G01 X-0.9407 Y0.6675 +G01 X-0.9593 Y0.6675 +G01 X-1.2022 Y0.6675 +G00 Z0.1000 +G00 X-0.8551 Y0.7095 +G01 Z-0.0070 F10 +G01 X-0.8423 Y0.6967 F20 +G01 X-0.8415 Y0.6948 +G01 X-0.8407 Y0.6967 +G01 X-0.8279 Y0.7095 +G01 X-0.8112 Y0.7164 +G01 X-0.7931 Y0.7164 +G01 X-0.7764 Y0.7095 +G01 X-0.7636 Y0.6967 +G01 X-0.7628 Y0.6948 +G01 X-0.7620 Y0.6967 +G01 X-0.7492 Y0.7095 +G01 X-0.7324 Y0.7164 +G01 X-0.7283 Y0.7164 +G01 X-0.7554 Y0.7436 +G01 X-0.7718 Y0.7436 +G01 X-0.7885 Y0.7505 +G01 X-0.8013 Y0.7633 +G01 X-0.8021 Y0.7652 +G01 X-0.8029 Y0.7633 +G01 X-0.8157 Y0.7505 +G01 X-0.8225 Y0.7477 +G01 X-0.8225 Y0.7457 +G01 X-0.8357 Y0.7325 +G01 X-0.8576 Y0.7106 +G01 X-0.8551 Y0.7095 +G00 Z0.1000 +G00 X-0.8801 Y0.7633 +G01 Z-0.0070 F10 +G01 X-0.8809 Y0.7652 F20 +G01 X-0.8817 Y0.7633 +G01 X-0.8945 Y0.7505 +G01 X-0.9017 Y0.7475 +G01 X-0.8843 Y0.7475 +G01 X-0.8743 Y0.7575 +G01 X-0.8801 Y0.7633 +G00 Z0.1000 +G00 X-0.8578 Y0.3325 +G01 Z-0.0070 F10 +G01 X-0.8696 Y0.3442 F20 +G01 X-0.8765 Y0.3609 +G01 X-0.8765 Y0.3791 +G01 X-0.8696 Y0.3958 +G01 X-0.8678 Y0.3975 +G01 X-0.9025 Y0.3975 +G01 X-0.9025 Y0.3325 +G01 X-0.8578 Y0.3325 +G00 Z0.1000 +G00 X-1.2004 Y0.4142 +G01 Z-0.0070 F10 +G01 X-1.2132 Y0.4014 F20 +G01 X-1.2299 Y0.3945 +G01 X-1.3101 Y0.3945 +G01 X-1.3268 Y0.4014 +G01 X-1.3396 Y0.4142 +G01 X-1.3465 Y0.4309 +G01 X-1.3465 Y0.4491 +G01 X-1.3396 Y0.4658 +G01 X-1.3378 Y0.4675 +G01 X-1.3825 Y0.4675 +G01 X-1.3825 Y0.3593 +G01 X-1.3607 Y0.3375 +G01 X-1.3475 Y0.3243 +G01 X-1.3475 Y0.2718 +G01 X-1.3245 Y0.2488 +G01 X-1.3245 Y0.2263 +G01 X-1.3155 Y0.2173 +G01 X-1.3155 Y0.2488 +G01 X-1.2888 Y0.2755 +G01 X-1.2825 Y0.2755 +G01 X-1.2825 Y0.2945 +G01 X-1.3101 Y0.2945 +G01 X-1.3268 Y0.3014 +G01 X-1.3396 Y0.3142 +G01 X-1.3465 Y0.3309 +G01 X-1.3465 Y0.3491 +G01 X-1.3396 Y0.3658 +G01 X-1.3268 Y0.3786 +G01 X-1.3101 Y0.3855 +G01 X-1.2299 Y0.3855 +G01 X-1.2132 Y0.3786 +G01 X-1.2004 Y0.3658 +G01 X-1.1979 Y0.3597 +G01 X-1.1497 Y0.3115 +G01 X-1.1401 Y0.3155 +G01 X-1.0599 Y0.3155 +G01 X-1.0432 Y0.3086 +G01 X-1.0372 Y0.3025 +G01 X-1.0193 Y0.3025 +G01 X-0.9893 Y0.3325 +G01 X-0.9707 Y0.3325 +G01 X-0.9475 Y0.3325 +G01 X-0.9475 Y0.4275 +G01 X-1.1949 Y0.4275 +G01 X-1.2004 Y0.4142 +G00 Z0.1000 +G00 X-0.6925 Y0.5743 +G01 Z-0.0070 F10 +G01 X-0.6925 Y0.5755 F20 +G01 X-0.6975 Y0.5705 +G01 X-0.6975 Y0.5693 +G01 X-0.6925 Y0.5743 +G00 Z0.1000 +G00 X-0.7620 Y0.5832 +G01 Z-0.0070 F10 +G01 X-0.7628 Y0.5851 F20 +G01 X-0.7636 Y0.5832 +G01 X-0.7764 Y0.5704 +G01 X-0.7775 Y0.5699 +G01 X-0.7775 Y0.5657 +G01 X-0.8707 Y0.4725 +G01 X-0.8543 Y0.4725 +G01 X-0.7528 Y0.5740 +G01 X-0.7620 Y0.5832 +G00 Z0.1000 +G00 X-1.8099 Y0.1045 +G01 Z-0.0070 F10 +G01 X-1.8901 Y0.1045 F20 +G01 X-1.9068 Y0.1114 +G01 X-1.9196 Y0.1242 +G01 X-1.9265 Y0.1409 +G01 X-1.9265 Y0.1531 +G01 X-1.9783 Y0.1975 +G01 X-1.9793 Y0.1975 +G01 X-1.9853 Y0.2035 +G01 X-1.9875 Y0.2054 +G01 X-1.9875 Y0.1893 +G01 X-1.9007 Y0.1025 +G01 X-1.4843 Y0.1025 +G01 X-1.5125 Y0.1307 +G01 X-1.5125 Y0.1493 +G01 X-1.5125 Y0.3022 +G01 X-1.5132 Y0.3014 +G01 X-1.5299 Y0.2945 +G01 X-1.5837 Y0.2945 +G01 X-1.7333 Y0.1449 +G01 X-1.7385 Y0.1385 +G01 X-1.7398 Y0.1384 +G01 X-1.7407 Y0.1375 +G01 X-1.7489 Y0.1375 +G01 X-1.7761 Y0.1348 +G01 X-1.7804 Y0.1242 +G01 X-1.7932 Y0.1114 +G01 X-1.8099 Y0.1045 +G00 Z0.1000 +G00 X-1.9525 Y0.4482 +G01 Z-0.0070 F10 +G01 X-1.9655 Y0.4612 F20 +G01 X-1.9655 Y0.4988 +G01 X-1.9388 Y0.5255 +G01 X-1.9012 Y0.5255 +G01 X-1.8745 Y0.4988 +G01 X-1.8745 Y0.4612 +G01 X-1.9012 Y0.4345 +G01 X-1.9075 Y0.4345 +G01 X-1.9075 Y0.3878 +G01 X-1.9068 Y0.3886 +G01 X-1.8901 Y0.3955 +G01 X-1.8725 Y0.3955 +G01 X-1.8725 Y0.4293 +G01 X-1.8593 Y0.4425 +G01 X-1.8431 Y0.4587 +G01 X-1.8455 Y0.4612 +G01 X-1.8455 Y0.4988 +G01 X-1.8188 Y0.5255 +G01 X-1.7812 Y0.5255 +G01 X-1.7582 Y0.5025 +G01 X-1.6893 Y0.5025 +G01 X-1.6465 Y0.5453 +G01 X-1.6465 Y0.5491 +G01 X-1.6396 Y0.5658 +G01 X-1.6268 Y0.5786 +G01 X-1.6101 Y0.5855 +G01 X-1.5299 Y0.5855 +G01 X-1.5132 Y0.5786 +G01 X-1.5125 Y0.5778 +G01 X-1.5125 Y0.6022 +G01 X-1.5132 Y0.6014 +G01 X-1.5299 Y0.5945 +G01 X-1.6101 Y0.5945 +G01 X-1.6268 Y0.6014 +G01 X-1.6375 Y0.6122 +G01 X-1.6375 Y0.5707 +G01 X-1.6507 Y0.5575 +G01 X-1.6807 Y0.5275 +G01 X-1.6993 Y0.5275 +G01 X-2.0607 Y0.5275 +G01 X-2.0875 Y0.5007 +G01 X-2.0875 Y0.4743 +G01 X-2.0855 Y0.4723 +G01 X-2.0855 Y0.4988 +G01 X-2.0588 Y0.5255 +G01 X-2.0212 Y0.5255 +G01 X-1.9945 Y0.4988 +G01 X-1.9945 Y0.4622 +G01 X-1.9536 Y0.4154 +G01 X-1.9525 Y0.4143 +G01 X-1.9525 Y0.4482 +G00 Z0.1000 +G00 X-1.8901 Y0.1955 +G01 Z-0.0070 F10 +G01 X-1.8099 Y0.1955 F20 +G01 X-1.7932 Y0.1886 +G01 X-1.7839 Y0.1792 +G01 X-1.7602 Y0.1816 +G01 X-1.6336 Y0.3082 +G01 X-1.6396 Y0.3142 +G01 X-1.6465 Y0.3309 +G01 X-1.6465 Y0.3491 +G01 X-1.6396 Y0.3658 +G01 X-1.6268 Y0.3786 +G01 X-1.6101 Y0.3855 +G01 X-1.5299 Y0.3855 +G01 X-1.5132 Y0.3786 +G01 X-1.5125 Y0.3778 +G01 X-1.5125 Y0.4022 +G01 X-1.5132 Y0.4014 +G01 X-1.5299 Y0.3945 +G01 X-1.6101 Y0.3945 +G01 X-1.6268 Y0.4014 +G01 X-1.6368 Y0.4114 +G01 X-1.7781 Y0.2701 +G01 X-1.7735 Y0.2591 +G01 X-1.7735 Y0.2409 +G01 X-1.7804 Y0.2242 +G01 X-1.7932 Y0.2114 +G01 X-1.8099 Y0.2045 +G01 X-1.8901 Y0.2045 +G01 X-1.9068 Y0.2114 +G01 X-1.9196 Y0.2242 +G01 X-1.9265 Y0.2409 +G01 X-1.9265 Y0.2520 +G01 X-1.9385 Y0.2625 +G01 X-1.9393 Y0.2625 +G01 X-1.9454 Y0.2686 +G01 X-1.9475 Y0.2704 +G01 X-1.9475 Y0.2303 +G01 X-1.9014 Y0.1908 +G01 X-1.8901 Y0.1955 +G00 Z0.1000 +G00 X-1.9021 Y0.2905 +G01 Z-0.0070 F10 +G01 X-1.8901 Y0.2955 F20 +G01 X-1.8163 Y0.2955 +G01 X-1.8054 Y0.3064 +G01 X-1.8099 Y0.3045 +G01 X-1.8901 Y0.3045 +G01 X-1.9068 Y0.3114 +G01 X-1.9075 Y0.3122 +G01 X-1.9075 Y0.2952 +G01 X-1.9021 Y0.2905 +G00 Z0.1000 +G00 X-1.6268 Y0.6786 +G01 Z-0.0070 F10 +G01 X-1.6101 Y0.6855 F20 +G01 X-1.5299 Y0.6855 +G01 X-1.5175 Y0.6803 +G01 X-1.5175 Y0.6997 +G01 X-1.5299 Y0.6945 +G01 X-1.6101 Y0.6945 +G01 X-1.6268 Y0.7014 +G01 X-1.6368 Y0.7114 +G01 X-1.6375 Y0.7107 +G01 X-1.6375 Y0.6678 +G01 X-1.6268 Y0.6786 +G00 Z0.1000 +G00 X-0.3395 Y0.4187 +G01 Z-0.0070 F10 +G01 X-0.3575 Y0.4007 F20 +G01 X-0.3575 Y0.3643 +G01 X-0.3395 Y0.3823 +G01 X-0.3395 Y0.4187 +G00 Z0.1000 +G00 X-0.5443 Y0.1025 +G01 Z-0.0070 F10 +G01 X-0.2963 Y0.3505 F20 +G01 X-0.3077 Y0.3505 +G01 X-0.5557 Y0.1025 +G01 X-0.5443 Y0.1025 +G00 Z0.1000 +G00 X-1.4999 Y0.8675 +G01 Z-0.0070 F10 +G01 X-1.5022 Y0.8675 F20 +G01 X-1.5004 Y0.8658 +G01 X-1.4991 Y0.8625 +G01 X-1.4953 Y0.8625 +G01 X-1.4999 Y0.8675 +G00 Z0.1000 +G00 X-1.4443 Y0.1325 +G01 Z-0.0070 F10 +G01 X-1.4675 Y0.1557 F20 +G01 X-1.4675 Y0.1493 +G01 X-1.4507 Y0.1325 +G01 X-1.4443 Y0.1325 +G00 Z0.1000 +G00 X-1.6396 Y0.4658 +G01 Z-0.0070 F10 +G01 X-1.6268 Y0.4786 F20 +G01 X-1.6101 Y0.4855 +G01 X-1.5299 Y0.4855 +G01 X-1.5132 Y0.4786 +G01 X-1.5125 Y0.4778 +G01 X-1.5125 Y0.5022 +G01 X-1.5132 Y0.5014 +G01 X-1.5299 Y0.4945 +G01 X-1.6101 Y0.4945 +G01 X-1.6268 Y0.5014 +G01 X-1.6575 Y0.4707 +G01 X-1.6707 Y0.4575 +G01 X-1.7582 Y0.4575 +G01 X-1.7812 Y0.4345 +G01 X-1.8037 Y0.4345 +G01 X-1.8275 Y0.4107 +G01 X-1.8275 Y0.3955 +G01 X-1.8099 Y0.3955 +G01 X-1.7932 Y0.3886 +G01 X-1.7804 Y0.3758 +G01 X-1.7735 Y0.3591 +G01 X-1.7735 Y0.3409 +G01 X-1.7754 Y0.3364 +G01 X-1.6493 Y0.4625 +G01 X-1.6409 Y0.4625 +G01 X-1.6396 Y0.4658 +G00 Z0.1000 +G00 X-2.1943 Y0.8575 +G01 Z-0.0070 F10 +G01 X-2.0565 Y0.9953 F20 +G01 X-2.0645 Y1.0033 +G01 X-2.0645 Y1.0567 +G01 X-2.0267 Y1.0945 +G01 X-1.9763 Y1.0945 +G01 X-1.9793 Y1.0975 +G01 X-2.0307 Y1.0975 +G01 X-2.0775 Y1.0507 +G01 X-2.0775 Y1.0393 +G01 X-2.0775 Y1.0207 +G01 X-2.1675 Y0.9307 +G01 X-2.1807 Y0.9175 +G01 X-2.3507 Y0.9175 +G01 X-2.3693 Y0.9175 +G01 X-2.4193 Y0.9675 +G01 X-2.4325 Y0.9807 +G01 X-2.4325 Y1.0707 +G01 X-2.4325 Y1.0893 +G01 X-2.3225 Y1.1993 +G01 X-2.3093 Y1.2125 +G01 X-1.8425 Y1.2125 +G01 X-1.8425 Y1.2307 +G01 X-1.8425 Y1.2493 +G01 X-1.7925 Y1.2993 +G01 X-1.7793 Y1.3125 +G01 X-1.4757 Y1.3125 +G01 X-1.4625 Y1.2993 +G01 X-1.4537 Y1.2905 +G01 X-1.4212 Y1.2905 +G01 X-1.3945 Y1.2638 +G01 X-1.3945 Y1.2262 +G01 X-1.4052 Y1.2155 +G01 X-1.3712 Y1.2155 +G01 X-1.3582 Y1.2025 +G01 X-1.3293 Y1.2025 +G01 X-1.2725 Y1.2593 +G01 X-1.2593 Y1.2725 +G01 X-1.2093 Y1.2725 +G01 X-1.1907 Y1.2725 +G01 X-1.1515 Y1.2333 +G01 X-1.1414 Y1.2375 +G01 X-1.1186 Y1.2375 +G01 X-1.0974 Y1.2287 +G01 X-1.0813 Y1.2126 +G01 X-1.0725 Y1.1914 +G01 X-1.0725 Y1.1825 +G01 X-0.3543 Y1.1825 +G01 X-0.3357 Y1.1825 +G01 X-0.2027 Y1.0495 +G01 X-0.1695 Y1.0495 +G01 X-0.1405 Y1.0205 +G01 X-0.1405 Y0.9842 +G01 X-0.0911 Y0.9375 +G01 X-0.0907 Y0.9375 +G01 X-0.0843 Y0.9311 +G01 X-0.0778 Y0.9250 +G01 X-0.0778 Y0.9246 +G01 X-0.0775 Y0.9243 +G01 X-0.0775 Y0.9153 +G01 X-0.0772 Y0.9063 +G01 X-0.0775 Y0.9061 +G01 X-0.0775 Y0.5957 +G01 X-0.0907 Y0.5825 +G01 X-0.1175 Y0.5557 +G01 X-0.1175 Y0.3693 +G01 X-0.1175 Y0.3507 +G01 X-0.4707 Y-0.0025 +G01 X-0.4893 Y-0.0025 +G01 X-2.2393 Y-0.0025 +G01 X-2.2525 Y0.0107 +G01 X-2.3393 Y0.0975 +G01 X-2.3525 Y0.1107 +G01 X-2.3525 Y0.3407 +G01 X-2.3525 Y0.3593 +G01 X-2.3525 Y0.7707 +G01 X-2.3525 Y0.7893 +G01 X-2.2843 Y0.8575 +G01 X-2.2657 Y0.8575 +G01 X-2.1943 Y0.8575 +G00 Z0.1000 +G00 X-1.3515 Y0.3500 +G01 Z-0.0070 F10 +G01 X-1.3438 Y0.3686 F20 +G01 X-1.3296 Y0.3828 +G01 X-1.3122 Y0.3900 +G01 X-1.3296 Y0.3972 +G01 X-1.3438 Y0.4114 +G01 X-1.3515 Y0.4300 +G01 X-1.3515 Y0.4500 +G01 X-1.3463 Y0.4625 +G01 X-1.3775 Y0.4625 +G01 X-1.3775 Y0.3614 +G01 X-1.3544 Y0.3383 +G01 X-1.3515 Y0.3354 +G01 X-1.3515 Y0.3500 +G00 Z0.1000 +G00 X-1.5278 Y0.9900 +G01 Z-0.0070 F10 +G01 X-1.5139 Y0.9843 F20 +G01 X-1.5217 Y0.9925 +G01 X-1.5278 Y0.9900 +G00 Z0.1000 +G00 X-1.3110 Y0.2895 +G01 Z-0.0070 F10 +G01 X-1.3296 Y0.2972 F20 +G01 X-1.3425 Y0.3101 +G01 X-1.3425 Y0.2739 +G01 X-1.3200 Y0.2514 +G01 X-1.2909 Y0.2805 +G01 X-1.2875 Y0.2805 +G01 X-1.2875 Y0.2895 +G01 X-1.3110 Y0.2895 +G00 Z0.1000 +G00 X-1.3395 Y1.1491 +G01 Z-0.0070 F10 +G01 X-1.3411 Y1.1475 F20 +G01 X-1.3214 Y1.1475 +G01 X-1.3164 Y1.1525 +G01 X-1.3255 Y1.1525 +G01 X-1.3395 Y1.1525 +G01 X-1.3395 Y1.1491 +G00 Z0.1000 +G00 X-0.1629 Y0.7500 +G01 Z-0.0070 F10 +G01 X-0.1575 Y0.7446 F20 +G01 X-0.1575 Y0.7554 +G01 X-0.1629 Y0.7500 +G00 Z0.1000 +G00 X-0.1355 Y0.8774 +G01 Z-0.0070 F10 +G01 X-0.1463 Y0.8666 F20 +G01 X-0.1275 Y0.8525 +G01 X-0.1275 Y0.9031 +G01 X-0.1355 Y0.9107 +G01 X-0.1355 Y0.8774 +G00 Z0.1000 +G00 X-0.1355 Y0.6226 +G01 Z-0.0070 F10 +G01 X-0.1355 Y0.6084 F20 +G01 X-0.1275 Y0.6164 +G01 X-0.1275 Y0.6475 +G01 X-0.1463 Y0.6334 +G01 X-0.1355 Y0.6226 +G00 Z0.1000 +G00 X-0.9314 Y0.6697 +G01 Z-0.0070 F10 +G01 X-0.9344 Y0.6667 F20 +G01 X-0.9445 Y0.6625 +G01 X-0.9555 Y0.6625 +G01 X-1.1937 Y0.6625 +G01 X-1.1916 Y0.6575 +G01 X-0.9314 Y0.6575 +G01 X-0.9314 Y0.6697 +G00 Z0.1000 +G00 X-1.2104 Y0.5972 +G01 Z-0.0070 F10 +G01 X-1.2278 Y0.5900 F20 +G01 X-1.2104 Y0.5828 +G01 X-1.1962 Y0.5686 +G01 X-1.1885 Y0.5500 +G01 X-1.1885 Y0.5300 +G01 X-1.1937 Y0.5175 +G01 X-0.8964 Y0.5175 +G01 X-0.8392 Y0.5746 +G01 X-0.8415 Y0.5769 +G01 X-0.8523 Y0.5661 +G01 X-0.8708 Y0.5584 +G01 X-0.8909 Y0.5584 +G01 X-0.9095 Y0.5661 +G01 X-0.9237 Y0.5803 +G01 X-0.9314 Y0.5989 +G01 X-0.9314 Y0.6025 +G01 X-1.2051 Y0.6025 +G01 X-1.2104 Y0.5972 +G00 Z0.1000 +G00 X-0.3171 Y0.8500 +G01 Z-0.0070 F10 +G01 X-0.3445 Y0.8774 F20 +G01 X-0.3445 Y0.9225 +G01 X-0.4112 Y0.9225 +G01 X-0.3310 Y0.8361 +G01 X-0.3171 Y0.8500 +G00 Z0.1000 +G00 X-0.5605 Y1.0209 +G01 Z-0.0070 F10 +G01 X-0.5589 Y1.0225 F20 +G01 X-1.1916 Y1.0225 +G01 X-1.1937 Y1.0175 +G01 X-0.5605 Y1.0175 +G01 X-0.5605 Y1.0209 +G00 Z0.1000 +G00 X-1.1962 Y0.9114 +G01 Z-0.0070 F10 +G01 X-1.2104 Y0.8972 F20 +G01 X-1.2278 Y0.8900 +G01 X-1.2104 Y0.8828 +G01 X-1.2082 Y0.8806 +G01 X-1.1764 Y0.9125 +G01 X-1.1957 Y0.9125 +G01 X-1.1962 Y0.9114 +G00 Z0.1000 +G00 X-0.9707 Y0.8611 +G01 Z-0.0070 F10 +G01 X-0.9660 Y0.8725 F20 +G01 X-1.1386 Y0.8725 +G01 X-1.1636 Y0.8475 +G01 X-0.9707 Y0.8475 +G01 X-0.9707 Y0.8611 +G00 Z0.1000 +G00 X-0.9488 Y0.7462 +G01 Z-0.0070 F10 +G01 X-0.9630 Y0.7604 F20 +G01 X-0.9707 Y0.7790 +G01 X-0.9707 Y0.7925 +G01 X-1.1536 Y0.7925 +G01 X-1.1794 Y0.7667 +G01 X-1.1895 Y0.7625 +G01 X-1.1937 Y0.7625 +G01 X-1.1885 Y0.7500 +G01 X-1.1885 Y0.7300 +G01 X-1.1937 Y0.7175 +G01 X-0.9614 Y0.7175 +G01 X-0.9383 Y0.7406 +G01 X-0.9374 Y0.7415 +G01 X-0.9488 Y0.7462 +G00 Z0.1000 +G00 X-0.7123 Y0.8611 +G01 Z-0.0070 F10 +G01 X-0.7123 Y0.7790 F20 +G01 X-0.7146 Y0.7734 +G01 X-0.6467 Y0.7056 +G01 X-0.6425 Y0.6955 +G01 X-0.6425 Y0.6845 +G01 X-0.6425 Y0.5705 +G01 X-0.6425 Y0.5595 +G01 X-0.6467 Y0.5494 +G01 X-0.7756 Y0.4205 +G01 X-0.7590 Y0.4205 +G01 X-0.7479 Y0.4159 +G01 X-0.7106 Y0.4533 +G01 X-0.7005 Y0.4575 +G01 X-0.6895 Y0.4575 +G01 X-0.5664 Y0.4575 +G01 X-0.5068 Y0.5170 +G01 X-0.5033 Y0.5256 +G01 X-0.4956 Y0.5333 +G01 X-0.3556 Y0.6733 +G01 X-0.3455 Y0.6775 +G01 X-0.3445 Y0.6775 +G01 X-0.3445 Y0.7225 +G01 X-0.3555 Y0.7225 +G01 X-0.3656 Y0.7267 +G01 X-0.5114 Y0.8725 +G01 X-0.7170 Y0.8725 +G01 X-0.7123 Y0.8611 +G00 Z0.1000 +G00 X-0.7185 Y0.3600 +G01 Z-0.0070 F10 +G01 X-0.7262 Y0.3414 F20 +G01 X-0.7301 Y0.3375 +G01 X-0.7164 Y0.3375 +G01 X-0.6706 Y0.3833 +G01 X-0.6605 Y0.3875 +G01 X-0.6495 Y0.3875 +G01 X-0.5364 Y0.3875 +G01 X-0.3506 Y0.5733 +G01 X-0.3434 Y0.5763 +G01 X-0.3445 Y0.5774 +G01 X-0.3445 Y0.6066 +G01 X-0.4532 Y0.4980 +G01 X-0.4567 Y0.4894 +G01 X-0.5317 Y0.4144 +G01 X-0.5394 Y0.4067 +G01 X-0.5495 Y0.4025 +G01 X-0.6836 Y0.4025 +G01 X-0.7185 Y0.3676 +G01 X-0.7185 Y0.3600 +G00 Z0.1000 +G00 X-1.3122 Y0.8900 +G01 Z-0.0070 F10 +G01 X-1.3175 Y0.8922 F20 +G01 X-1.3175 Y0.8878 +G01 X-1.3122 Y0.8900 +G00 Z0.1000 +G00 X-1.4525 Y1.0510 +G01 Z-0.0070 F10 +G01 X-1.3725 Y0.9672 F20 +G01 X-1.3725 Y0.9736 +G01 X-1.4525 Y1.0536 +G01 X-1.4525 Y1.0510 +G00 Z0.1000 +G00 X-0.5114 Y1.0825 +G01 Z-0.0070 F10 +G01 X-1.1545 Y1.0825 F20 +G01 X-1.1655 Y1.0825 +G01 X-1.1756 Y1.0867 +G01 X-1.2064 Y1.1175 +G01 X-1.2559 Y1.1175 +G01 X-1.2647 Y1.1264 +G01 X-1.2867 Y1.1044 +G01 X-1.2944 Y1.0967 +G01 X-1.3045 Y1.0925 +G01 X-1.4136 Y1.0925 +G01 X-1.3515 Y1.0304 +G01 X-1.3515 Y1.0500 +G01 X-1.3438 Y1.0686 +G01 X-1.3296 Y1.0828 +G01 X-1.3110 Y1.0905 +G01 X-1.2290 Y1.0905 +G01 X-1.2104 Y1.0828 +G01 X-1.2051 Y1.0775 +G01 X-0.5064 Y1.0775 +G01 X-0.5114 Y1.0825 +G00 Z0.1000 +G00 X-2.1464 Y1.1625 +G01 Z-0.0070 F10 +G01 X-2.2886 Y1.1625 F20 +G01 X-2.3825 Y1.0686 +G01 X-2.3825 Y1.0014 +G01 X-2.3486 Y0.9675 +G01 X-2.3358 Y0.9675 +G01 X-2.3695 Y1.0012 +G01 X-2.3695 Y1.0588 +G01 X-2.3288 Y1.0995 +G01 X-2.2712 Y1.0995 +G01 X-2.2453 Y1.0736 +G01 X-2.1933 Y1.1256 +G01 X-2.1856 Y1.1333 +G01 X-2.1755 Y1.1375 +G01 X-2.1714 Y1.1375 +G01 X-2.1464 Y1.1625 +G00 Z0.1000 +G00 X-2.2305 Y1.0012 +G01 Z-0.0070 F10 +G01 X-2.2642 Y0.9675 F20 +G01 X-2.2014 Y0.9675 +G01 X-2.1275 Y1.0414 +G01 X-2.1275 Y1.0655 +G01 X-2.1233 Y1.0756 +G01 X-2.1156 Y1.0833 +G01 X-2.0664 Y1.1325 +G01 X-2.0986 Y1.1325 +G01 X-2.1367 Y1.0944 +G01 X-2.1444 Y1.0867 +G01 X-2.1545 Y1.0825 +G01 X-2.1586 Y1.0825 +G01 X-2.2267 Y1.0144 +G01 X-2.2305 Y1.0106 +G01 X-2.2305 Y1.0012 +G00 Z0.1000 +G00 X-1.5405 Y1.1491 +G01 Z-0.0070 F10 +G01 X-1.5405 Y1.1725 F20 +G01 X-1.7055 Y1.1725 +G01 X-1.7065 Y1.1722 +G01 X-1.7092 Y1.1724 +G01 X-1.7116 Y1.1700 +G01 X-1.6875 Y1.1459 +G01 X-1.6875 Y1.0941 +G01 X-1.7241 Y1.0575 +G01 X-1.7759 Y1.0575 +G01 X-1.8125 Y1.0941 +G01 X-1.8125 Y1.1436 +G01 X-1.8314 Y1.1625 +G01 X-1.8836 Y1.1625 +G01 X-1.7686 Y1.0475 +G01 X-1.7314 Y1.0475 +G01 X-1.6556 Y1.1233 +G01 X-1.6455 Y1.1275 +G01 X-1.6345 Y1.1275 +G01 X-1.5189 Y1.1275 +G01 X-1.5405 Y1.1491 +G00 Z0.1000 +G00 X-1.4869 Y1.2205 +G01 Z-0.0070 F10 +G01 X-1.4905 Y1.2241 F20 +G01 X-1.4905 Y1.2566 +G01 X-1.4964 Y1.2625 +G01 X-1.7041 Y1.2625 +G01 X-1.6970 Y1.2554 +G01 X-1.6875 Y1.2324 +G01 X-1.6875 Y1.2275 +G01 X-1.5145 Y1.2275 +G01 X-1.5044 Y1.2233 +G01 X-1.5016 Y1.2205 +G01 X-1.4869 Y1.2205 +G00 Z0.1000 +G00 X-1.9436 Y1.1325 +G01 Z-0.0070 F10 +G01 X-1.8967 Y1.0856 F20 +G01 X-1.8925 Y1.0755 +G01 X-1.8925 Y1.0645 +G01 X-1.8925 Y0.9964 +G01 X-1.8786 Y0.9825 +G01 X-1.7945 Y0.9825 +G01 X-1.7414 Y0.9825 +G01 X-1.7314 Y0.9925 +G01 X-1.7745 Y0.9925 +G01 X-1.7855 Y0.9925 +G01 X-1.7956 Y0.9967 +G01 X-1.9314 Y1.1325 +G01 X-1.9436 Y1.1325 +G00 Z0.1000 +G00 X-1.6515 Y1.0475 +G01 Z-0.0070 F10 +G01 X-1.6515 Y1.0496 F20 +G01 X-1.6536 Y1.0475 +G01 X-1.6515 Y1.0475 +G00 Z0.1000 +G00 X-1.3775 Y0.6814 +G01 Z-0.0070 F10 +G01 X-1.3756 Y0.6833 F20 +G01 X-1.3461 Y0.7128 +G01 X-1.3495 Y0.7142 +G01 X-1.3537 Y0.7156 +G01 X-1.3546 Y0.7163 +G01 X-1.3556 Y0.7167 +G01 X-1.3587 Y0.7198 +G01 X-1.3775 Y0.7359 +G01 X-1.3775 Y0.6814 +G00 Z0.1000 +G00 X-0.8129 Y0.7462 +G01 Z-0.0070 F10 +G01 X-0.8201 Y0.7433 F20 +G01 X-0.8217 Y0.7394 +G01 X-0.8294 Y0.7317 +G01 X-0.8498 Y0.7113 +G01 X-0.8415 Y0.7030 +G01 X-0.8307 Y0.7138 +G01 X-0.8122 Y0.7214 +G01 X-0.7921 Y0.7214 +G01 X-0.7735 Y0.7138 +G01 X-0.7628 Y0.7030 +G01 X-0.7520 Y0.7138 +G01 X-0.7383 Y0.7194 +G01 X-0.7574 Y0.7386 +G01 X-0.7728 Y0.7386 +G01 X-0.7914 Y0.7462 +G01 X-0.8021 Y0.7570 +G01 X-0.8129 Y0.7462 +G00 Z0.1000 +G00 X-1.3775 Y0.5564 +G01 Z-0.0070 F10 +G01 X-1.3767 Y0.5556 F20 +G01 X-1.3725 Y0.5455 +G01 X-1.3725 Y0.5345 +G01 X-1.3767 Y0.5244 +G01 X-1.3775 Y0.5236 +G01 X-1.3775 Y0.5175 +G01 X-1.3463 Y0.5175 +G01 X-1.3515 Y0.5300 +G01 X-1.3515 Y0.5500 +G01 X-1.3478 Y0.5589 +G01 X-1.3775 Y0.5886 +G01 X-1.3775 Y0.5564 +G00 Z0.1000 +G00 X-1.0216 Y0.2525 +G01 Z-0.0070 F10 +G01 X-1.0262 Y0.2414 F20 +G01 X-1.0404 Y0.2272 +G01 X-1.0590 Y0.2195 +G01 X-1.1410 Y0.2195 +G01 X-1.1596 Y0.2272 +G01 X-1.1738 Y0.2414 +G01 X-1.1815 Y0.2600 +G01 X-1.1815 Y0.2726 +G01 X-1.2082 Y0.2994 +G01 X-1.2104 Y0.2972 +G01 X-1.2290 Y0.2895 +G01 X-1.2325 Y0.2895 +G01 X-1.2325 Y0.2639 +G01 X-1.2195 Y0.2509 +G01 X-1.2195 Y0.2091 +G01 X-1.2211 Y0.2075 +G01 X-1.0414 Y0.2075 +G01 X-0.9664 Y0.2825 +G01 X-0.9686 Y0.2825 +G01 X-0.9944 Y0.2567 +G01 X-1.0045 Y0.2525 +G01 X-1.0155 Y0.2525 +G01 X-1.0216 Y0.2525 +G00 Z0.1000 +G00 X-0.8738 Y0.3414 +G01 Z-0.0070 F10 +G01 X-0.8815 Y0.3600 F20 +G01 X-0.8815 Y0.3800 +G01 X-0.8763 Y0.3925 +G01 X-0.8975 Y0.3925 +G01 X-0.8975 Y0.3375 +G01 X-0.8699 Y0.3375 +G01 X-0.8738 Y0.3414 +G00 Z0.1000 +G00 X-0.7628 Y0.5769 +G01 Z-0.0070 F10 +G01 X-0.7735 Y0.5661 F20 +G01 X-0.7740 Y0.5659 +G01 X-0.7767 Y0.5594 +G01 X-0.8586 Y0.4775 +G01 X-0.8564 Y0.4775 +G01 X-0.7599 Y0.5740 +G01 X-0.7628 Y0.5769 +G00 Z0.1000 +G00 X-1.1962 Y0.4114 +G01 Z-0.0070 F10 +G01 X-1.2104 Y0.3972 F20 +G01 X-1.2278 Y0.3900 +G01 X-1.2104 Y0.3828 +G01 X-1.1962 Y0.3686 +G01 X-1.1937 Y0.3626 +G01 X-1.1485 Y0.3174 +G01 X-1.1410 Y0.3205 +G01 X-1.0590 Y0.3205 +G01 X-1.0404 Y0.3128 +G01 X-1.0351 Y0.3075 +G01 X-1.0214 Y0.3075 +G01 X-0.9956 Y0.3333 +G01 X-0.9855 Y0.3375 +G01 X-0.9745 Y0.3375 +G01 X-0.9525 Y0.3375 +G01 X-0.9525 Y0.4225 +G01 X-1.1916 Y0.4225 +G01 X-1.1962 Y0.4114 +G00 Z0.1000 +G00 X-1.5278 Y0.6900 +G01 Z-0.0070 F10 +G01 X-1.5225 Y0.6878 F20 +G01 X-1.5225 Y0.6922 +G01 X-1.5278 Y0.6900 +G00 Z0.1000 +G00 X-1.4325 Y0.8990 +G01 Z-0.0070 F10 +G01 X-1.4941 Y0.9635 F20 +G01 X-1.4885 Y0.9500 +G01 X-1.4885 Y0.9300 +G01 X-1.4936 Y0.9177 +G01 X-1.4894 Y0.9175 +G01 X-1.4845 Y0.9175 +G01 X-1.4840 Y0.9173 +G01 X-1.4833 Y0.9172 +G01 X-1.4789 Y0.9152 +G01 X-1.4744 Y0.9133 +G01 X-1.4740 Y0.9129 +G01 X-1.4734 Y0.9126 +G01 X-1.4701 Y0.9090 +G01 X-1.4667 Y0.9056 +G01 X-1.4664 Y0.9050 +G01 X-1.4325 Y0.8680 +G01 X-1.4325 Y0.8990 +G00 Z0.1000 +G00 X-0.5694 Y0.2195 +G01 Z-0.0070 F10 +G01 X-0.6410 Y0.2195 F20 +G01 X-0.6596 Y0.2272 +G01 X-0.6649 Y0.2325 +G01 X-0.9386 Y0.2325 +G01 X-1.0036 Y0.1675 +G01 X-0.6214 Y0.1675 +G01 X-0.5694 Y0.2195 +G00 Z0.1000 +G00 X-1.3487 Y0.1799 +G01 Z-0.0070 F10 +G01 X-1.3491 Y0.1795 F20 +G01 X-1.3909 Y0.1795 +G01 X-1.4205 Y0.2091 +G01 X-1.4205 Y0.2509 +G01 X-1.3975 Y0.2739 +G01 X-1.3975 Y0.3036 +G01 X-1.4225 Y0.3286 +G01 X-1.4225 Y0.1814 +G01 X-1.4086 Y0.1675 +G01 X-1.3364 Y0.1675 +G01 X-1.3487 Y0.1799 +G00 Z0.1000 +G00 X-0.6784 Y0.2875 +G01 Z-0.0070 F10 +G01 X-0.6738 Y0.2986 F20 +G01 X-0.6596 Y0.3128 +G01 X-0.6410 Y0.3205 +G01 X-0.5590 Y0.3205 +G01 X-0.5404 Y0.3128 +G01 X-0.5262 Y0.2986 +G01 X-0.5185 Y0.2800 +G01 X-0.5185 Y0.2704 +G01 X-0.4075 Y0.3814 +G01 X-0.4075 Y0.4045 +G01 X-0.4075 Y0.4155 +G01 X-0.4033 Y0.4256 +G01 X-0.3445 Y0.4844 +G01 X-0.3445 Y0.5016 +G01 X-0.5017 Y0.3444 +G01 X-0.5094 Y0.3367 +G01 X-0.5195 Y0.3325 +G01 X-0.6436 Y0.3325 +G01 X-0.6817 Y0.2944 +G01 X-0.6886 Y0.2875 +G01 X-0.6784 Y0.2875 +G00 Z0.1000 +G00 X-0.4836 Y1.1325 +G01 Z-0.0070 F10 +G01 X-0.4767 Y1.1256 F20 +G01 X-0.4016 Y1.0505 +G01 X-0.3891 Y1.0505 +G01 X-0.3595 Y1.0209 +G01 X-0.3595 Y1.0175 +G01 X-0.3445 Y1.0175 +G01 X-0.3445 Y1.0226 +G01 X-0.3126 Y1.0545 +G01 X-0.2784 Y1.0545 +G01 X-0.3564 Y1.1325 +G01 X-0.4836 Y1.1325 +G00 Z0.1000 +G00 X-1.5278 Y0.3900 +G01 Z-0.0070 F10 +G01 X-1.5175 Y0.3857 F20 +G01 X-1.5175 Y0.3942 +G01 X-1.5278 Y0.3900 +G00 Z0.1000 +G00 X-1.5278 Y0.4900 +G01 Z-0.0070 F10 +G01 X-1.5175 Y0.4857 F20 +G01 X-1.5175 Y0.4942 +G01 X-1.5278 Y0.4900 +G00 Z0.1000 +G00 X-1.5278 Y0.5900 +G01 Z-0.0070 F10 +G01 X-1.5175 Y0.5857 F20 +G01 X-1.5175 Y0.5942 +G01 X-1.5278 Y0.5900 +G00 Z0.1000 +G00 X-1.6515 Y0.5474 +G01 Z-0.0070 F10 +G01 X-1.6515 Y0.5496 F20 +G01 X-1.6744 Y0.5267 +G01 X-1.6845 Y0.5225 +G01 X-1.6955 Y0.5225 +G01 X-1.7711 Y0.5225 +G01 X-1.7561 Y0.5075 +G01 X-1.6914 Y0.5075 +G01 X-1.6515 Y0.5474 +G00 Z0.1000 +G00 X-1.8910 Y0.4005 +G01 Z-0.0070 F10 +G01 X-1.8775 Y0.4005 F20 +G01 X-1.8775 Y0.4255 +G01 X-1.8733 Y0.4356 +G01 X-1.8656 Y0.4433 +G01 X-1.8501 Y0.4587 +G01 X-1.8505 Y0.4591 +G01 X-1.8505 Y0.5009 +G01 X-1.8289 Y0.5225 +G01 X-1.8911 Y0.5225 +G01 X-1.8695 Y0.5009 +G01 X-1.8695 Y0.4591 +G01 X-1.8991 Y0.4295 +G01 X-1.9025 Y0.4295 +G01 X-1.9025 Y0.3957 +G01 X-1.8910 Y0.4005 +G00 Z0.1000 +G00 X-1.9004 Y0.1966 +G01 Z-0.0070 F10 +G01 X-1.8922 Y0.2000 F20 +G01 X-1.9096 Y0.2072 +G01 X-1.9238 Y0.2214 +G01 X-1.9315 Y0.2400 +G01 X-1.9315 Y0.2498 +G01 X-1.9425 Y0.2594 +G01 X-1.9425 Y0.2326 +G01 X-1.9004 Y0.1966 +G00 Z0.1000 +G00 X-1.9705 Y0.4591 +G01 Z-0.0070 F10 +G01 X-1.9705 Y0.5009 F20 +G01 X-1.9489 Y0.5225 +G01 X-2.0111 Y0.5225 +G01 X-1.9895 Y0.5009 +G01 X-1.9895 Y0.4640 +G01 X-1.9575 Y0.4275 +G01 X-1.9575 Y0.4461 +G01 X-1.9705 Y0.4591 +G00 Z0.1000 +G00 X-1.9825 Y0.1914 +G01 Z-0.0070 F10 +G01 X-1.9315 Y0.1404 F20 +G01 X-1.9315 Y0.1508 +G01 X-1.9825 Y0.1945 +G01 X-1.9825 Y0.1914 +G00 Z0.1000 +G00 X-1.9012 Y0.2963 +G01 Z-0.0070 F10 +G01 X-1.8922 Y0.3000 F20 +G01 X-1.9025 Y0.3042 +G01 X-1.9025 Y0.2975 +G01 X-1.9012 Y0.2963 +G00 Z0.1000 +G00 X-1.7762 Y0.1214 +G01 Z-0.0070 F10 +G01 X-1.7901 Y0.1075 F20 +G01 X-1.4964 Y0.1075 +G01 X-1.5133 Y0.1244 +G01 X-1.5175 Y0.1345 +G01 X-1.5175 Y0.1455 +G01 X-1.5175 Y0.2942 +G01 X-1.5290 Y0.2895 +G01 X-1.5816 Y0.2895 +G01 X-1.7296 Y0.1415 +G01 X-1.7322 Y0.1384 +G01 X-1.7334 Y0.1377 +G01 X-1.7344 Y0.1367 +G01 X-1.7382 Y0.1351 +G01 X-1.7418 Y0.1332 +G01 X-1.7432 Y0.1330 +G01 X-1.7445 Y0.1325 +G01 X-1.7486 Y0.1325 +G01 X-1.7726 Y0.1301 +G01 X-1.7762 Y0.1214 +G00 Z0.1000 +G00 X-1.7685 Y0.2600 +G01 Z-0.0070 F10 +G01 X-1.7685 Y0.2400 F20 +G01 X-1.7762 Y0.2214 +G01 X-1.7904 Y0.2072 +G01 X-1.8078 Y0.2000 +G01 X-1.7904 Y0.1928 +G01 X-1.7820 Y0.1844 +G01 X-1.7625 Y0.1864 +G01 X-1.6406 Y0.3082 +G01 X-1.6438 Y0.3114 +G01 X-1.6515 Y0.3300 +G01 X-1.6515 Y0.3500 +G01 X-1.6438 Y0.3686 +G01 X-1.6296 Y0.3828 +G01 X-1.6122 Y0.3900 +G01 X-1.6296 Y0.3972 +G01 X-1.6368 Y0.4044 +G01 X-1.7722 Y0.2689 +G01 X-1.7685 Y0.2600 +G00 Z0.1000 +G00 X-1.8090 Y0.4005 +G01 Z-0.0070 F10 +G01 X-1.7904 Y0.3928 F20 +G01 X-1.7762 Y0.3786 +G01 X-1.7685 Y0.3600 +G01 X-1.7685 Y0.3504 +G01 X-1.6556 Y0.4633 +G01 X-1.6455 Y0.4675 +G01 X-1.6443 Y0.4675 +G01 X-1.6438 Y0.4686 +G01 X-1.6296 Y0.4828 +G01 X-1.6122 Y0.4900 +G01 X-1.6256 Y0.4955 +G01 X-1.6567 Y0.4644 +G01 X-1.6644 Y0.4567 +G01 X-1.6745 Y0.4525 +G01 X-1.7561 Y0.4525 +G01 X-1.7791 Y0.4295 +G01 X-1.8016 Y0.4295 +G01 X-1.8225 Y0.4086 +G01 X-1.8225 Y0.4005 +G01 X-1.8090 Y0.4005 +G00 Z0.1000 +G00 X-0.3445 Y0.4066 +G01 Z-0.0070 F10 +G01 X-0.3525 Y0.3986 F20 +G01 X-0.3525 Y0.3764 +G01 X-0.3445 Y0.3844 +G01 X-0.3445 Y0.4066 +G00 Z0.1000 +G00 X-1.6683 Y0.7506 +G01 Z-0.0070 F10 +G01 X-1.6606 Y0.7583 F20 +G01 X-1.6505 Y0.7625 +G01 X-1.6463 Y0.7625 +G01 X-1.6447 Y0.7663 +G01 X-1.6456 Y0.7667 +G01 X-1.6656 Y0.7867 +G01 X-1.6733 Y0.7944 +G01 X-1.6775 Y0.8045 +G01 X-1.6775 Y0.8545 +G01 X-1.6775 Y0.8655 +G01 X-1.6733 Y0.8756 +G01 X-1.6433 Y0.9056 +G01 X-1.6406 Y0.9082 +G01 X-1.6438 Y0.9114 +G01 X-1.6443 Y0.9125 +G01 X-1.6686 Y0.9125 +G01 X-1.6825 Y0.8986 +G01 X-1.6825 Y0.7364 +G01 X-1.6683 Y0.7506 +G00 Z0.1000 +G00 X-1.7614 Y0.6175 +G01 Z-0.0070 F10 +G01 X-1.7375 Y0.6414 F20 +G01 X-1.7375 Y0.9155 +G01 X-1.7333 Y0.9256 +G01 X-1.7314 Y0.9275 +G01 X-1.7725 Y0.9275 +G01 X-1.7725 Y0.7239 +G01 X-1.7495 Y0.7009 +G01 X-1.7495 Y0.6591 +G01 X-1.7791 Y0.6295 +G01 X-1.8209 Y0.6295 +G01 X-1.8339 Y0.6425 +G01 X-1.8861 Y0.6425 +G01 X-1.8991 Y0.6295 +G01 X-1.9409 Y0.6295 +G01 X-1.9539 Y0.6425 +G01 X-2.0061 Y0.6425 +G01 X-2.0191 Y0.6295 +G01 X-2.0609 Y0.6295 +G01 X-2.0905 Y0.6591 +G01 X-2.0905 Y0.7009 +G01 X-2.0609 Y0.7305 +G01 X-2.0191 Y0.7305 +G01 X-1.9895 Y0.7009 +G01 X-1.9895 Y0.6975 +G01 X-1.9705 Y0.6975 +G01 X-1.9705 Y0.7009 +G01 X-1.9409 Y0.7305 +G01 X-1.8991 Y0.7305 +G01 X-1.8695 Y0.7009 +G01 X-1.8695 Y0.6975 +G01 X-1.8505 Y0.6975 +G01 X-1.8505 Y0.7009 +G01 X-1.8275 Y0.7239 +G01 X-1.8275 Y0.9275 +G01 X-1.8845 Y0.9275 +G01 X-1.8955 Y0.9275 +G01 X-1.9056 Y0.9317 +G01 X-1.9433 Y0.9694 +G01 X-1.9475 Y0.9795 +G01 X-1.9475 Y0.9842 +G01 X-1.9712 Y0.9605 +G01 X-2.0206 Y0.9605 +G01 X-2.1617 Y0.8194 +G01 X-2.1694 Y0.8117 +G01 X-2.1795 Y0.8075 +G01 X-2.2636 Y0.8075 +G01 X-2.3025 Y0.7686 +G01 X-2.3025 Y0.3775 +G01 X-2.2243 Y0.3775 +G01 X-2.2238 Y0.3786 +G01 X-2.2096 Y0.3928 +G01 X-2.1910 Y0.4005 +G01 X-2.1417 Y0.4005 +G01 X-2.1633 Y0.4158 +G01 X-2.1656 Y0.4167 +G01 X-2.1678 Y0.4189 +G01 X-2.1703 Y0.4207 +G01 X-2.1716 Y0.4227 +G01 X-2.1733 Y0.4244 +G01 X-2.1745 Y0.4273 +G01 X-2.1762 Y0.4299 +G01 X-2.1766 Y0.4323 +G01 X-2.1775 Y0.4345 +G01 X-2.1775 Y0.4377 +G01 X-2.1780 Y0.4407 +G01 X-2.1775 Y0.4431 +G01 X-2.1775 Y0.5245 +G01 X-2.1775 Y0.5355 +G01 X-2.1733 Y0.5456 +G01 X-2.1056 Y0.6133 +G01 X-2.0955 Y0.6175 +G01 X-2.0845 Y0.6175 +G01 X-1.7614 Y0.6175 +G00 Z0.1000 +G00 X-2.1090 Y0.0995 +G01 Z-0.0070 F10 +G01 X-2.1910 Y0.0995 F20 +G01 X-2.2096 Y0.1072 +G01 X-2.2238 Y0.1214 +G01 X-2.2315 Y0.1400 +G01 X-2.2315 Y0.1600 +G01 X-2.2238 Y0.1786 +G01 X-2.2096 Y0.1928 +G01 X-2.1922 Y0.2000 +G01 X-2.2096 Y0.2072 +G01 X-2.2238 Y0.2214 +G01 X-2.2315 Y0.2400 +G01 X-2.2315 Y0.2600 +G01 X-2.2238 Y0.2786 +G01 X-2.2096 Y0.2928 +G01 X-2.1922 Y0.3000 +G01 X-2.2096 Y0.3072 +G01 X-2.2238 Y0.3214 +G01 X-2.2243 Y0.3225 +G01 X-2.3025 Y0.3225 +G01 X-2.3025 Y0.1314 +G01 X-2.2186 Y0.0475 +G01 X-2.0814 Y0.0475 +G01 X-2.0883 Y0.0544 +G01 X-2.0925 Y0.0645 +G01 X-2.0925 Y0.1063 +G01 X-2.1090 Y0.0995 +G00 Z0.1000 +G00 X-2.0375 Y0.3836 +G01 Z-0.0070 F10 +G01 X-2.0375 Y0.3836 F20 +G01 X-2.0375 Y0.3823 +G01 X-2.0375 Y0.3836 +G00 Z0.1000 +G00 X-2.0336 Y0.0775 +G01 Z-0.0070 F10 +G01 X-1.9464 Y0.0775 F20 +G01 X-2.0256 Y0.1567 +G01 X-2.0333 Y0.1644 +G01 X-2.0375 Y0.1745 +G01 X-2.0375 Y0.3770 +G01 X-2.0375 Y0.0814 +G01 X-2.0336 Y0.0775 +G00 Z0.1000 +G00 X-1.7014 Y0.5775 +G01 Z-0.0070 F10 +G01 X-1.6875 Y0.5914 F20 +G01 X-1.6875 Y0.6136 +G01 X-1.7236 Y0.5775 +G01 X-1.7014 Y0.5775 +G00 Z0.1000 +G00 X-1.6438 Y0.9686 +G01 Z-0.0070 F10 +G01 X-1.6296 Y0.9828 F20 +G01 X-1.6122 Y0.9900 +G01 X-1.6183 Y0.9925 +G01 X-1.6536 Y0.9925 +G01 X-1.6786 Y0.9675 +G01 X-1.6443 Y0.9675 +G01 X-1.6438 Y0.9686 +G00 Z0.1000 +G00 X-1.6296 Y0.5828 +G01 Z-0.0070 F10 +G01 X-1.6122 Y0.5900 F20 +G01 X-1.6296 Y0.5972 +G01 X-1.6325 Y0.6001 +G01 X-1.6325 Y0.5799 +G01 X-1.6296 Y0.5828 +G00 Z0.1000 +G00 X-1.6296 Y0.6828 +G01 Z-0.0070 F10 +G01 X-1.6122 Y0.6900 F20 +G01 X-1.6296 Y0.6972 +G01 X-1.6325 Y0.7001 +G01 X-1.6325 Y0.6799 +G01 X-1.6296 Y0.6828 +G00 Z0.1000 +G00 X-2.1964 Y0.8625 +G01 Z-0.0070 F10 +G01 X-2.0636 Y0.9953 F20 +G01 X-2.0695 Y1.0012 +G01 X-2.0695 Y1.0516 +G01 X-2.0725 Y1.0486 +G01 X-2.0725 Y1.0355 +G01 X-2.0725 Y1.0245 +G01 X-2.0767 Y1.0144 +G01 X-2.1667 Y0.9244 +G01 X-2.1744 Y0.9167 +G01 X-2.1845 Y0.9125 +G01 X-2.3545 Y0.9125 +G01 X-2.3655 Y0.9125 +G01 X-2.3756 Y0.9167 +G01 X-2.4256 Y0.9667 +G01 X-2.4333 Y0.9744 +G01 X-2.4375 Y0.9845 +G01 X-2.4375 Y1.0745 +G01 X-2.4375 Y1.0855 +G01 X-2.4333 Y1.0956 +G01 X-2.3233 Y1.2056 +G01 X-2.3156 Y1.2133 +G01 X-2.3055 Y1.2175 +G01 X-1.8475 Y1.2175 +G01 X-1.8475 Y1.2345 +G01 X-1.8475 Y1.2455 +G01 X-1.8433 Y1.2556 +G01 X-1.7933 Y1.3056 +G01 X-1.7856 Y1.3133 +G01 X-1.7755 Y1.3175 +G01 X-1.4795 Y1.3175 +G01 X-1.4694 Y1.3133 +G01 X-1.4617 Y1.3056 +G01 X-1.4516 Y1.2955 +G01 X-1.4191 Y1.2955 +G01 X-1.3895 Y1.2659 +G01 X-1.3895 Y1.2241 +G01 X-1.3931 Y1.2205 +G01 X-1.3691 Y1.2205 +G01 X-1.3561 Y1.2075 +G01 X-1.3314 Y1.2075 +G01 X-1.2733 Y1.2656 +G01 X-1.2656 Y1.2733 +G01 X-1.2555 Y1.2775 +G01 X-1.2055 Y1.2775 +G01 X-1.1945 Y1.2775 +G01 X-1.1844 Y1.2733 +G01 X-1.1503 Y1.2392 +G01 X-1.1424 Y1.2425 +G01 X-1.1176 Y1.2425 +G01 X-1.0946 Y1.2330 +G01 X-1.0770 Y1.2154 +G01 X-1.0675 Y1.1924 +G01 X-1.0675 Y1.1875 +G01 X-0.3505 Y1.1875 +G01 X-0.3395 Y1.1875 +G01 X-0.3294 Y1.1833 +G01 X-0.2006 Y1.0545 +G01 X-0.1674 Y1.0545 +G01 X-0.1355 Y1.0226 +G01 X-0.1355 Y0.9863 +G01 X-0.0848 Y0.9385 +G01 X-0.0844 Y0.9383 +G01 X-0.0808 Y0.9347 +G01 X-0.0771 Y0.9312 +G01 X-0.0770 Y0.9309 +G01 X-0.0767 Y0.9306 +G01 X-0.0747 Y0.9258 +G01 X-0.0727 Y0.9213 +G01 X-0.0727 Y0.9208 +G01 X-0.0725 Y0.9205 +G01 X-0.0725 Y0.9154 +G01 X-0.0724 Y0.9103 +G01 X-0.0725 Y0.9099 +G01 X-0.0725 Y0.5995 +G01 X-0.0767 Y0.5894 +G01 X-0.0844 Y0.5817 +G01 X-0.1125 Y0.5536 +G01 X-0.1125 Y0.3655 +G01 X-0.1125 Y0.3545 +G01 X-0.1167 Y0.3444 +G01 X-0.4644 Y-0.0033 +G01 X-0.4745 Y-0.0075 +G01 X-0.4855 Y-0.0075 +G01 X-2.2355 Y-0.0075 +G01 X-2.2456 Y-0.0033 +G01 X-2.2533 Y0.0044 +G01 X-2.3456 Y0.0967 +G01 X-2.3533 Y0.1044 +G01 X-2.3575 Y0.1145 +G01 X-2.3575 Y0.3445 +G01 X-2.3575 Y0.3555 +G01 X-2.3575 Y0.7745 +G01 X-2.3575 Y0.7855 +G01 X-2.3533 Y0.7956 +G01 X-2.2906 Y0.8583 +G01 X-2.2805 Y0.8625 +G01 X-2.2695 Y0.8625 +G01 X-2.1964 Y0.8625 +G00 Z0.1000 +G00 X-1.7635 Y0.2610 +G01 Z-0.0070 F10 +G01 X-1.7635 Y0.2390 F20 +G01 X-1.7719 Y0.2186 +G01 X-1.7876 Y0.2029 +G01 X-1.7947 Y0.2000 +G01 X-1.7876 Y0.1970 +G01 X-1.7802 Y0.1896 +G01 X-1.7648 Y0.1912 +G01 X-1.6477 Y0.3082 +G01 X-1.6480 Y0.3086 +G01 X-1.6565 Y0.3290 +G01 X-1.6565 Y0.3510 +G01 X-1.6480 Y0.3714 +G01 X-1.6324 Y0.3870 +G01 X-1.6253 Y0.3900 +G01 X-1.6324 Y0.3929 +G01 X-1.6368 Y0.3973 +G01 X-1.7663 Y0.2678 +G01 X-1.7635 Y0.2610 +G00 Z0.1000 +G00 X-1.7719 Y0.1186 +G01 Z-0.0070 F10 +G01 X-1.7780 Y0.1125 F20 +G01 X-1.5085 Y0.1125 +G01 X-1.5175 Y0.1216 +G01 X-1.5225 Y0.1335 +G01 X-1.5225 Y0.1465 +G01 X-1.5225 Y0.2868 +G01 X-1.5280 Y0.2845 +G01 X-1.5795 Y0.2845 +G01 X-1.7259 Y0.1382 +G01 X-1.7289 Y0.1344 +G01 X-1.7304 Y0.1336 +G01 X-1.7316 Y0.1324 +G01 X-1.7361 Y0.1306 +G01 X-1.7403 Y0.1283 +G01 X-1.7420 Y0.1281 +G01 X-1.7435 Y0.1275 +G01 X-1.7484 Y0.1275 +G01 X-1.7691 Y0.1254 +G01 X-1.7719 Y0.1186 +G00 Z0.1000 +G00 X-1.8080 Y0.4055 +G01 Z-0.0070 F10 +G01 X-1.7876 Y0.3970 F20 +G01 X-1.7719 Y0.3814 +G01 X-1.7639 Y0.3620 +G01 X-1.6785 Y0.4475 +G01 X-1.7540 Y0.4475 +G01 X-1.7770 Y0.4245 +G01 X-1.7995 Y0.4245 +G01 X-1.8175 Y0.4065 +G01 X-1.8175 Y0.4055 +G01 X-1.8080 Y0.4055 +G00 Z0.1000 +G00 X-1.9755 Y0.4570 +G01 Z-0.0070 F10 +G01 X-1.9755 Y0.5030 F20 +G01 X-1.9610 Y0.5175 +G01 X-1.9990 Y0.5175 +G01 X-1.9845 Y0.5030 +G01 X-1.9845 Y0.4659 +G01 X-1.9625 Y0.4408 +G01 X-1.9625 Y0.4440 +G01 X-1.9755 Y0.4570 +G00 Z0.1000 +G00 X-1.9334 Y0.2314 +G01 Z-0.0070 F10 +G01 X-1.9365 Y0.2390 F20 +G01 X-1.9365 Y0.2475 +G01 X-1.9375 Y0.2484 +G01 X-1.9375 Y0.2349 +G01 X-1.9334 Y0.2314 +G00 Z0.1000 +G00 X-1.8555 Y0.5030 +G01 Z-0.0070 F10 +G01 X-1.8410 Y0.5175 F20 +G01 X-1.8790 Y0.5175 +G01 X-1.8645 Y0.5030 +G01 X-1.8645 Y0.4570 +G01 X-1.8970 Y0.4245 +G01 X-1.8975 Y0.4245 +G01 X-1.8975 Y0.4032 +G01 X-1.8920 Y0.4055 +G01 X-1.8825 Y0.4055 +G01 X-1.8825 Y0.4265 +G01 X-1.8775 Y0.4384 +G01 X-1.8684 Y0.4475 +G01 X-1.8555 Y0.4605 +G01 X-1.8555 Y0.5030 +G00 Z0.1000 +G00 X-1.6885 Y0.5175 +G01 Z-0.0070 F10 +G01 X-1.6965 Y0.5175 F20 +G01 X-1.7590 Y0.5175 +G01 X-1.7540 Y0.5125 +G01 X-1.6935 Y0.5125 +G01 X-1.6885 Y0.5175 +G00 Z0.1000 +G00 X-2.1080 Y0.0945 +G01 Z-0.0070 F10 +G01 X-2.1920 Y0.0945 F20 +G01 X-2.2124 Y0.1029 +G01 X-2.2280 Y0.1186 +G01 X-2.2365 Y0.1390 +G01 X-2.2365 Y0.1610 +G01 X-2.2280 Y0.1814 +G01 X-2.2124 Y0.1970 +G01 X-2.2053 Y0.2000 +G01 X-2.2124 Y0.2029 +G01 X-2.2280 Y0.2186 +G01 X-2.2365 Y0.2390 +G01 X-2.2365 Y0.2610 +G01 X-2.2280 Y0.2814 +G01 X-2.2124 Y0.2970 +G01 X-2.2053 Y0.3000 +G01 X-2.2124 Y0.3029 +G01 X-2.2270 Y0.3175 +G01 X-2.2975 Y0.3175 +G01 X-2.2975 Y0.1335 +G01 X-2.2165 Y0.0525 +G01 X-2.0929 Y0.0525 +G01 X-2.0975 Y0.0635 +G01 X-2.0975 Y0.0988 +G01 X-2.1080 Y0.0945 +G00 Z0.1000 +G00 X-2.0315 Y0.0825 +G01 Z-0.0070 F10 +G01 X-1.9585 Y0.0825 F20 +G01 X-2.0284 Y0.1524 +G01 X-2.0325 Y0.1565 +G01 X-2.0325 Y0.0835 +G01 X-2.0315 Y0.0825 +G00 Z0.1000 +G00 X-1.6253 Y0.6900 +G01 Z-0.0070 F10 +G01 X-1.6275 Y0.6909 F20 +G01 X-1.6275 Y0.6891 +G01 X-1.6253 Y0.6900 +G00 Z0.1000 +G00 X-1.6324 Y0.9870 +G01 Z-0.0070 F10 +G01 X-1.6313 Y0.9875 F20 +G01 X-1.6515 Y0.9875 +G01 X-1.6665 Y0.9725 +G01 X-1.6470 Y0.9725 +G01 X-1.6324 Y0.9870 +G00 Z0.1000 +G00 X-1.6485 Y0.9075 +G01 Z-0.0070 F10 +G01 X-1.6665 Y0.9075 F20 +G01 X-1.6775 Y0.8965 +G01 X-1.6775 Y0.8785 +G01 X-1.6485 Y0.9075 +G00 Z0.1000 +G00 X-1.6725 Y0.7534 +G01 Z-0.0070 F10 +G01 X-1.6634 Y0.7625 F20 +G01 X-1.6529 Y0.7669 +G01 X-1.6684 Y0.7824 +G01 X-1.6775 Y0.7915 +G01 X-1.6775 Y0.7485 +G01 X-1.6725 Y0.7534 +G00 Z0.1000 +G00 X-1.7635 Y0.6225 +G01 Z-0.0070 F10 +G01 X-1.7425 Y0.6435 F20 +G01 X-1.7425 Y0.9165 +G01 X-1.7400 Y0.9225 +G01 X-1.7675 Y0.9225 +G01 X-1.7675 Y0.7260 +G01 X-1.7445 Y0.7030 +G01 X-1.7445 Y0.6570 +G01 X-1.7770 Y0.6245 +G01 X-1.8230 Y0.6245 +G01 X-1.8360 Y0.6375 +G01 X-1.8840 Y0.6375 +G01 X-1.8970 Y0.6245 +G01 X-1.9430 Y0.6245 +G01 X-1.9560 Y0.6375 +G01 X-2.0040 Y0.6375 +G01 X-2.0170 Y0.6245 +G01 X-2.0630 Y0.6245 +G01 X-2.0955 Y0.6570 +G01 X-2.0955 Y0.7030 +G01 X-2.0630 Y0.7355 +G01 X-2.0170 Y0.7355 +G01 X-1.9845 Y0.7030 +G01 X-1.9845 Y0.7025 +G01 X-1.9755 Y0.7025 +G01 X-1.9755 Y0.7030 +G01 X-1.9430 Y0.7355 +G01 X-1.8970 Y0.7355 +G01 X-1.8645 Y0.7030 +G01 X-1.8645 Y0.7025 +G01 X-1.8555 Y0.7025 +G01 X-1.8555 Y0.7030 +G01 X-1.8325 Y0.7260 +G01 X-1.8325 Y0.9225 +G01 X-1.8835 Y0.9225 +G01 X-1.8965 Y0.9225 +G01 X-1.9084 Y0.9274 +G01 X-1.9475 Y0.9666 +G01 X-1.9506 Y0.9740 +G01 X-1.9691 Y0.9555 +G01 X-2.0185 Y0.9555 +G01 X-2.1574 Y0.8166 +G01 X-2.1666 Y0.8074 +G01 X-2.1785 Y0.8025 +G01 X-2.2615 Y0.8025 +G01 X-2.2975 Y0.7665 +G01 X-2.2975 Y0.3825 +G01 X-2.2270 Y0.3825 +G01 X-2.2124 Y0.3970 +G01 X-2.1920 Y0.4055 +G01 X-2.1575 Y0.4055 +G01 X-2.1658 Y0.4114 +G01 X-2.1684 Y0.4124 +G01 X-2.1710 Y0.4151 +G01 X-2.1740 Y0.4172 +G01 X-2.1755 Y0.4196 +G01 X-2.1775 Y0.4216 +G01 X-2.1790 Y0.4250 +G01 X-2.1809 Y0.4281 +G01 X-2.1814 Y0.4309 +G01 X-2.1825 Y0.4335 +G01 X-2.1825 Y0.4372 +G01 X-2.1831 Y0.4409 +G01 X-2.1825 Y0.4436 +G01 X-2.1825 Y0.5235 +G01 X-2.1825 Y0.5365 +G01 X-2.1775 Y0.5484 +G01 X-2.1084 Y0.6175 +G01 X-2.0965 Y0.6225 +G01 X-2.0835 Y0.6225 +G01 X-1.7635 Y0.6225 +G00 Z0.1000 +G00 X-1.7035 Y0.5825 +G01 Z-0.0070 F10 +G01 X-1.6925 Y0.5935 F20 +G01 X-1.6925 Y0.6015 +G01 X-1.7115 Y0.5825 +G01 X-1.7035 Y0.5825 +G00 Z0.1000 +G00 X-1.6253 Y0.5900 +G01 Z-0.0070 F10 +G01 X-1.6275 Y0.5909 F20 +G01 X-1.6275 Y0.5891 +G01 X-1.6253 Y0.5900 +G00 Z0.1000 +G00 X-1.2076 Y0.5929 +G01 Z-0.0070 F10 +G01 X-1.2147 Y0.5900 F20 +G01 X-1.2076 Y0.5870 +G01 X-1.1919 Y0.5714 +G01 X-1.1835 Y0.5510 +G01 X-1.1835 Y0.5290 +G01 X-1.1862 Y0.5225 +G01 X-0.8985 Y0.5225 +G01 X-0.8659 Y0.5551 +G01 X-0.8698 Y0.5534 +G01 X-0.8919 Y0.5534 +G01 X-0.9123 Y0.5619 +G01 X-0.9279 Y0.5775 +G01 X-0.9362 Y0.5975 +G01 X-1.2030 Y0.5975 +G01 X-1.2076 Y0.5929 +G00 Z0.1000 +G00 X-0.7135 Y0.3590 +G01 Z-0.0070 F10 +G01 X-0.7203 Y0.3425 F20 +G01 X-0.7185 Y0.3425 +G01 X-0.6734 Y0.3875 +G01 X-0.6615 Y0.3925 +G01 X-0.6485 Y0.3925 +G01 X-0.5385 Y0.3925 +G01 X-0.3534 Y0.5775 +G01 X-0.3495 Y0.5792 +G01 X-0.3495 Y0.5945 +G01 X-0.4489 Y0.4951 +G01 X-0.4524 Y0.4866 +G01 X-0.5274 Y0.4116 +G01 X-0.5366 Y0.4024 +G01 X-0.5485 Y0.3975 +G01 X-0.6815 Y0.3975 +G01 X-0.7135 Y0.3655 +G01 X-0.7135 Y0.3590 +G00 Z0.1000 +G00 X-0.7073 Y0.8621 +G01 Z-0.0070 F10 +G01 X-0.7073 Y0.7780 F20 +G01 X-0.7087 Y0.7746 +G01 X-0.6424 Y0.7084 +G01 X-0.6375 Y0.6965 +G01 X-0.6375 Y0.6835 +G01 X-0.6375 Y0.5715 +G01 X-0.6375 Y0.5585 +G01 X-0.6424 Y0.5466 +G01 X-0.7635 Y0.4255 +G01 X-0.7580 Y0.4255 +G01 X-0.7491 Y0.4218 +G01 X-0.7134 Y0.4575 +G01 X-0.7015 Y0.4625 +G01 X-0.6885 Y0.4625 +G01 X-0.5685 Y0.4625 +G01 X-0.5111 Y0.5199 +G01 X-0.5075 Y0.5284 +G01 X-0.4984 Y0.5375 +G01 X-0.3584 Y0.6775 +G01 X-0.3495 Y0.6812 +G01 X-0.3495 Y0.7175 +G01 X-0.3565 Y0.7175 +G01 X-0.3684 Y0.7224 +G01 X-0.5135 Y0.8675 +G01 X-0.7095 Y0.8675 +G01 X-0.7073 Y0.8621 +G00 Z0.1000 +G00 X-0.9757 Y0.8621 +G01 Z-0.0070 F10 +G01 X-0.9735 Y0.8675 F20 +G01 X-1.1365 Y0.8675 +G01 X-1.1515 Y0.8525 +G01 X-0.9757 Y0.8525 +G01 X-0.9757 Y0.8621 +G00 Z0.1000 +G00 X-0.9517 Y0.7420 +G01 Z-0.0070 F10 +G01 X-0.9673 Y0.7576 F20 +G01 X-0.9757 Y0.7780 +G01 X-0.9757 Y0.7875 +G01 X-1.1515 Y0.7875 +G01 X-1.1766 Y0.7624 +G01 X-1.1865 Y0.7583 +G01 X-1.1835 Y0.7510 +G01 X-1.1835 Y0.7290 +G01 X-1.1862 Y0.7225 +G01 X-0.9635 Y0.7225 +G01 X-0.9462 Y0.7397 +G01 X-0.9517 Y0.7420 +G00 Z0.1000 +G00 X-0.3241 Y0.8500 +G01 Z-0.0070 F10 +G01 X-0.3495 Y0.8754 F20 +G01 X-0.3495 Y0.9175 +G01 X-0.3998 Y0.9175 +G01 X-0.3308 Y0.8433 +G01 X-0.3241 Y0.8500 +G00 Z0.1000 +G00 X-1.2076 Y0.8929 +G01 Z-0.0070 F10 +G01 X-1.2147 Y0.8900 F20 +G01 X-1.2085 Y0.8874 +G01 X-1.1885 Y0.9075 +G01 X-1.1930 Y0.9075 +G01 X-1.2076 Y0.8929 +G00 Z0.1000 +G00 X-1.2085 Y1.1125 +G01 Z-0.0070 F10 +G01 X-1.2580 Y1.1125 F20 +G01 X-1.2647 Y1.1193 +G01 X-1.2824 Y1.1016 +G01 X-1.2885 Y1.0955 +G01 X-1.2280 Y1.0955 +G01 X-1.2076 Y1.0870 +G01 X-1.2030 Y1.0825 +G01 X-1.1785 Y1.0825 +G01 X-1.2085 Y1.1125 +G00 Z0.1000 +G00 X-0.8101 Y0.7420 +G01 Z-0.0070 F10 +G01 X-0.8163 Y0.7394 F20 +G01 X-0.8174 Y0.7366 +G01 X-0.8266 Y0.7274 +G01 X-0.8427 Y0.7113 +G01 X-0.8415 Y0.7101 +G01 X-0.8336 Y0.7180 +G01 X-0.8132 Y0.7264 +G01 X-0.7911 Y0.7264 +G01 X-0.7707 Y0.7180 +G01 X-0.7628 Y0.7101 +G01 X-0.7548 Y0.7180 +G01 X-0.7471 Y0.7212 +G01 X-0.7595 Y0.7336 +G01 X-0.7738 Y0.7336 +G01 X-0.7942 Y0.7420 +G01 X-0.8021 Y0.7499 +G01 X-0.8101 Y0.7420 +G00 Z0.1000 +G00 X-1.0219 Y0.2386 +G01 Z-0.0070 F10 +G01 X-1.0376 Y0.2229 F20 +G01 X-1.0580 Y0.2145 +G01 X-1.1420 Y0.2145 +G01 X-1.1624 Y0.2229 +G01 X-1.1780 Y0.2386 +G01 X-1.1865 Y0.2590 +G01 X-1.1865 Y0.2705 +G01 X-1.2085 Y0.2926 +G01 X-1.2275 Y0.2847 +G01 X-1.2275 Y0.2660 +G01 X-1.2145 Y0.2530 +G01 X-1.2145 Y0.2125 +G01 X-1.0435 Y0.2125 +G01 X-1.0085 Y0.2475 +G01 X-1.0165 Y0.2475 +G01 X-1.0182 Y0.2475 +G01 X-1.0219 Y0.2386 +G00 Z0.1000 +G00 X-0.8865 Y0.3590 +G01 Z-0.0070 F10 +G01 X-0.8865 Y0.3810 F20 +G01 X-0.8838 Y0.3875 +G01 X-0.8925 Y0.3875 +G01 X-0.8925 Y0.3425 +G01 X-0.8797 Y0.3425 +G01 X-0.8865 Y0.3590 +G00 Z0.1000 +G00 X-1.1919 Y0.4086 +G01 Z-0.0070 F10 +G01 X-1.2076 Y0.3929 F20 +G01 X-1.2147 Y0.3900 +G01 X-1.2076 Y0.3870 +G01 X-1.1919 Y0.3714 +G01 X-1.1895 Y0.3654 +G01 X-1.1473 Y0.3233 +G01 X-1.1420 Y0.3255 +G01 X-1.0580 Y0.3255 +G01 X-1.0376 Y0.3170 +G01 X-1.0330 Y0.3125 +G01 X-1.0235 Y0.3125 +G01 X-0.9984 Y0.3375 +G01 X-0.9865 Y0.3425 +G01 X-0.9735 Y0.3425 +G01 X-0.9575 Y0.3425 +G01 X-0.9575 Y0.4175 +G01 X-1.1882 Y0.4175 +G01 X-1.1919 Y0.4086 +G00 Z0.1000 +G00 X-1.4375 Y0.8970 +G01 Z-0.0070 F10 +G01 X-1.4835 Y0.9452 F20 +G01 X-1.4835 Y0.9290 +G01 X-1.4862 Y0.9225 +G01 X-1.4835 Y0.9225 +G01 X-1.4829 Y0.9222 +G01 X-1.4821 Y0.9222 +G01 X-1.4769 Y0.9197 +G01 X-1.4716 Y0.9175 +G01 X-1.4711 Y0.9170 +G01 X-1.4704 Y0.9167 +G01 X-1.4665 Y0.9125 +G01 X-1.4624 Y0.9084 +G01 X-1.4622 Y0.9077 +G01 X-1.4375 Y0.8808 +G01 X-1.4375 Y0.8970 +G00 Z0.1000 +G00 X-0.6420 Y0.2145 +G01 Z-0.0070 F10 +G01 X-0.6624 Y0.2229 F20 +G01 X-0.6670 Y0.2275 +G01 X-0.9365 Y0.2275 +G01 X-0.9915 Y0.1725 +G01 X-0.6235 Y0.1725 +G01 X-0.5815 Y0.2145 +G01 X-0.6420 Y0.2145 +G00 Z0.1000 +G00 X-1.3505 Y0.1745 +G01 Z-0.0070 F10 +G01 X-1.3930 Y0.1745 F20 +G01 X-1.4175 Y0.1990 +G01 X-1.4175 Y0.1835 +G01 X-1.4065 Y0.1725 +G01 X-1.3485 Y0.1725 +G01 X-1.3505 Y0.1745 +G00 Z0.1000 +G00 X-1.4025 Y0.2760 +G01 Z-0.0070 F10 +G01 X-1.4025 Y0.3015 F20 +G01 X-1.4175 Y0.3165 +G01 X-1.4175 Y0.2610 +G01 X-1.4025 Y0.2760 +G00 Z0.1000 +G00 X-0.6420 Y0.3255 +G01 Z-0.0070 F10 +G01 X-0.5580 Y0.3255 F20 +G01 X-0.5376 Y0.3170 +G01 X-0.5219 Y0.3014 +G01 X-0.5139 Y0.2820 +G01 X-0.4125 Y0.3835 +G01 X-0.4125 Y0.4035 +G01 X-0.4125 Y0.4165 +G01 X-0.4075 Y0.4284 +G01 X-0.3495 Y0.4865 +G01 X-0.3495 Y0.4895 +G01 X-0.4974 Y0.3416 +G01 X-0.5066 Y0.3324 +G01 X-0.5185 Y0.3275 +G01 X-0.6415 Y0.3275 +G01 X-0.6446 Y0.3244 +G01 X-0.6420 Y0.3255 +G00 Z0.1000 +G00 X-0.4715 Y1.1275 +G01 Z-0.0070 F10 +G01 X-0.3995 Y1.0555 F20 +G01 X-0.3870 Y1.0555 +G01 X-0.3545 Y1.0230 +G01 X-0.3545 Y1.0225 +G01 X-0.3495 Y1.0225 +G01 X-0.3495 Y1.0246 +G01 X-0.3146 Y1.0595 +G01 X-0.2905 Y1.0595 +G01 X-0.3585 Y1.1275 +G01 X-0.4715 Y1.1275 +G00 Z0.1000 +G00 X-0.1325 Y0.8734 +G01 Z-0.0070 F10 +G01 X-0.1387 Y0.8671 F20 +G01 X-0.1325 Y0.8625 +G01 X-0.1325 Y0.8734 +G00 Z0.1000 +G00 X-0.1325 Y0.6266 +G01 Z-0.0070 F10 +G01 X-0.1325 Y0.6375 F20 +G01 X-0.1387 Y0.6328 +G01 X-0.1325 Y0.6266 +G00 Z0.1000 +G00 X-1.3565 Y1.0510 +G01 Z-0.0070 F10 +G01 X-1.3480 Y1.0714 F20 +G01 X-1.3324 Y1.0870 +G01 X-1.3313 Y1.0875 +G01 X-1.4015 Y1.0875 +G01 X-1.3565 Y1.0425 +G01 X-1.3565 Y1.0510 +G00 Z0.1000 +G00 X-1.5455 Y1.1470 +G01 Z-0.0070 F10 +G01 X-1.5455 Y1.1675 F20 +G01 X-1.7020 Y1.1675 +G01 X-1.6825 Y1.1480 +G01 X-1.6825 Y1.1035 +G01 X-1.6584 Y1.1275 +G01 X-1.6465 Y1.1325 +G01 X-1.6335 Y1.1325 +G01 X-1.5310 Y1.1325 +G01 X-1.5455 Y1.1470 +G00 Z0.1000 +G00 X-1.4955 Y1.2255 +G01 Z-0.0070 F10 +G01 X-1.4955 Y1.2545 F20 +G01 X-1.4985 Y1.2575 +G01 X-1.6925 Y1.2575 +G01 X-1.6825 Y1.2334 +G01 X-1.6825 Y1.2325 +G01 X-1.5135 Y1.2325 +G01 X-1.5016 Y1.2275 +G01 X-1.4995 Y1.2255 +G01 X-1.4955 Y1.2255 +G00 Z0.1000 +G00 X-2.1585 Y1.1575 +G01 Z-0.0070 F10 +G01 X-2.2865 Y1.1575 F20 +G01 X-2.3775 Y1.0665 +G01 X-2.3775 Y1.0035 +G01 X-2.3745 Y1.0005 +G01 X-2.3745 Y1.0609 +G01 X-2.3309 Y1.1045 +G01 X-2.2691 Y1.1045 +G01 X-2.2453 Y1.0807 +G01 X-2.1975 Y1.1284 +G01 X-2.1884 Y1.1375 +G01 X-2.1765 Y1.1425 +G01 X-2.1735 Y1.1425 +G01 X-2.1585 Y1.1575 +G00 Z0.1000 +G00 X-2.2255 Y0.9991 +G01 Z-0.0070 F10 +G01 X-2.2521 Y0.9725 F20 +G01 X-2.2035 Y0.9725 +G01 X-2.1325 Y1.0435 +G01 X-2.1325 Y1.0665 +G01 X-2.1275 Y1.0784 +G01 X-2.1184 Y1.0875 +G01 X-2.0785 Y1.1275 +G01 X-2.0965 Y1.1275 +G01 X-2.1324 Y1.0916 +G01 X-2.1416 Y1.0824 +G01 X-2.1535 Y1.0775 +G01 X-2.1565 Y1.0775 +G01 X-2.2224 Y1.0116 +G01 X-2.2255 Y1.0085 +G01 X-2.2255 Y0.9991 +G00 Z0.1000 +G00 X-1.8175 Y1.1415 +G01 Z-0.0070 F10 +G01 X-1.8335 Y1.1575 F20 +G01 X-1.8715 Y1.1575 +G01 X-1.8175 Y1.1035 +G01 X-1.8175 Y1.1415 +G00 Z0.1000 +G00 X-1.8875 Y1.0765 +G01 Z-0.0070 F10 +G01 X-1.8875 Y1.0635 F20 +G01 X-1.8875 Y0.9985 +G01 X-1.8765 Y0.9875 +G01 X-1.7935 Y0.9875 +G01 X-1.7435 Y0.9875 +G01 X-1.7735 Y0.9875 +G01 X-1.7865 Y0.9875 +G01 X-1.7984 Y0.9924 +G01 X-1.8911 Y1.0851 +G01 X-1.8875 Y1.0765 +G00 Z0.1000 +G00 X-1.7335 Y1.0525 +G01 Z-0.0070 F10 +G01 X-1.7335 Y1.0525 F20 +G01 X-1.7665 Y1.0525 +G01 X-1.7335 Y1.0525 +G00 Z0.1000 +G00 X-1.3725 Y0.6935 +G01 Z-0.0070 F10 +G01 X-1.3552 Y0.7108 F20 +G01 X-1.3562 Y0.7111 +G01 X-1.3572 Y0.7120 +G01 X-1.3584 Y0.7124 +G01 X-1.3621 Y0.7161 +G01 X-1.3725 Y0.7251 +G01 X-1.3725 Y0.6935 +G00 Z0.1000 +G00 X-1.3725 Y0.5585 +G01 Z-0.0070 F10 +G01 X-1.3724 Y0.5584 F20 +G01 X-1.3675 Y0.5465 +G01 X-1.3675 Y0.5335 +G01 X-1.3721 Y0.5225 +G01 X-1.3538 Y0.5225 +G01 X-1.3565 Y0.5290 +G01 X-1.3565 Y0.5510 +G01 X-1.3537 Y0.5578 +G01 X-1.3725 Y0.5765 +G01 X-1.3725 Y0.5585 +G00 Z0.1000 +G00 X-1.3200 Y0.2585 +G01 Z-0.0070 F10 +G01 X-1.2940 Y0.2845 F20 +G01 X-1.3120 Y0.2845 +G01 X-1.3324 Y0.2929 +G01 X-1.3375 Y0.2980 +G01 X-1.3375 Y0.2760 +G01 X-1.3200 Y0.2585 +G00 Z0.1000 +G00 X-1.3565 Y0.3510 +G01 Z-0.0070 F10 +G01 X-1.3480 Y0.3714 F20 +G01 X-1.3324 Y0.3870 +G01 X-1.3253 Y0.3900 +G01 X-1.3324 Y0.3929 +G01 X-1.3480 Y0.4086 +G01 X-1.3565 Y0.4290 +G01 X-1.3565 Y0.4510 +G01 X-1.3538 Y0.4575 +G01 X-1.3725 Y0.4575 +G01 X-1.3725 Y0.3635 +G01 X-1.3565 Y0.3475 +G01 X-1.3565 Y0.3510 +G00 Z0.1000 +G00 X-2.1985 Y0.8675 +G01 Z-0.0070 F10 +G01 X-2.0707 Y0.9953 F20 +G01 X-2.0745 Y0.9991 +G01 X-2.0745 Y1.0095 +G01 X-2.1624 Y0.9216 +G01 X-2.1716 Y0.9124 +G01 X-2.1835 Y0.9075 +G01 X-2.3535 Y0.9075 +G01 X-2.3665 Y0.9075 +G01 X-2.3784 Y0.9124 +G01 X-2.4284 Y0.9624 +G01 X-2.4375 Y0.9716 +G01 X-2.4425 Y0.9835 +G01 X-2.4425 Y1.0735 +G01 X-2.4425 Y1.0865 +G01 X-2.4375 Y1.0984 +G01 X-2.3275 Y1.2084 +G01 X-2.3184 Y1.2175 +G01 X-2.3065 Y1.2225 +G01 X-1.8525 Y1.2225 +G01 X-1.8525 Y1.2335 +G01 X-1.8525 Y1.2465 +G01 X-1.8475 Y1.2584 +G01 X-1.7975 Y1.3084 +G01 X-1.7884 Y1.3175 +G01 X-1.7765 Y1.3225 +G01 X-1.4785 Y1.3225 +G01 X-1.4666 Y1.3175 +G01 X-1.4574 Y1.3084 +G01 X-1.4495 Y1.3005 +G01 X-1.4170 Y1.3005 +G01 X-1.3845 Y1.2680 +G01 X-1.3845 Y1.2255 +G01 X-1.3670 Y1.2255 +G01 X-1.3540 Y1.2125 +G01 X-1.3335 Y1.2125 +G01 X-1.2775 Y1.2684 +G01 X-1.2684 Y1.2775 +G01 X-1.2565 Y1.2825 +G01 X-1.2065 Y1.2825 +G01 X-1.1935 Y1.2825 +G01 X-1.1816 Y1.2775 +G01 X-1.1492 Y1.2451 +G01 X-1.1434 Y1.2475 +G01 X-1.1166 Y1.2475 +G01 X-1.0918 Y1.2372 +G01 X-1.0728 Y1.2182 +G01 X-1.0625 Y1.1934 +G01 X-1.0625 Y1.1925 +G01 X-0.3515 Y1.1925 +G01 X-0.3385 Y1.1925 +G01 X-0.3266 Y1.1875 +G01 X-0.1985 Y1.0595 +G01 X-0.1654 Y1.0595 +G01 X-0.1305 Y1.0246 +G01 X-0.1305 Y0.9885 +G01 X-0.0820 Y0.9427 +G01 X-0.0816 Y0.9425 +G01 X-0.0773 Y0.9383 +G01 X-0.0730 Y0.9342 +G01 X-0.0728 Y0.9337 +G01 X-0.0724 Y0.9334 +G01 X-0.0702 Y0.9279 +G01 X-0.0677 Y0.9224 +G01 X-0.0677 Y0.9219 +G01 X-0.0675 Y0.9215 +G01 X-0.0675 Y0.9155 +G01 X-0.0673 Y0.9095 +G01 X-0.0675 Y0.9090 +G01 X-0.0675 Y0.5985 +G01 X-0.0724 Y0.5866 +G01 X-0.0816 Y0.5774 +G01 X-0.1075 Y0.5515 +G01 X-0.1075 Y0.3665 +G01 X-0.1075 Y0.3535 +G01 X-0.1124 Y0.3416 +G01 X-0.4616 Y-0.0075 +G01 X-0.4735 Y-0.0125 +G01 X-0.4865 Y-0.0125 +G01 X-2.2365 Y-0.0125 +G01 X-2.2484 Y-0.0075 +G01 X-2.2575 Y0.0016 +G01 X-2.3484 Y0.0924 +G01 X-2.3575 Y0.1016 +G01 X-2.3625 Y0.1135 +G01 X-2.3625 Y0.3435 +G01 X-2.3625 Y0.3565 +G01 X-2.3625 Y0.7735 +G01 X-2.3625 Y0.7865 +G01 X-2.3575 Y0.7984 +G01 X-2.2934 Y0.8625 +G01 X-2.2815 Y0.8675 +G01 X-2.2685 Y0.8675 +G01 X-2.1985 Y0.8675 +G00 Z0.1000 +G82 X-0.1500 Y1.1900 Z-0.0110 F10 R0.1000 P1.000000 +G82 X-0.1500 Y0.1300 +G82 X-1.2700 Y0.2300 +G82 X-1.3700 Y0.2300 +G82 X-0.5100 Y1.0000 +G82 X-0.4100 Y1.0000 +G82 X-1.1300 Y1.1800 +G82 X-1.2300 Y1.1800 +G82 X-1.7500 Y1.2200 +G82 X-1.7500 Y1.1200 +G82 X-1.5700 Y0.3400 +G82 X-1.5700 Y0.4400 +G82 X-1.5700 Y0.5400 +G82 X-1.5700 Y0.6400 +G82 X-1.5700 Y0.7400 +G82 X-1.5700 Y0.8400 +G82 X-1.5700 Y0.9400 +G82 X-1.5700 Y1.0400 +G82 X-1.2700 Y1.0400 +G82 X-1.2700 Y0.9400 +G82 X-1.2700 Y0.8400 +G82 X-1.2700 Y0.7400 +G82 X-1.2700 Y0.6400 +G82 X-1.2700 Y0.5400 +G82 X-1.2700 Y0.4400 +G82 X-1.2700 Y0.3400 +G82 X-1.3900 Y1.1700 +G82 X-1.4400 Y1.2450 +G82 X-1.4900 Y1.1700 +G82 X-0.6000 Y0.2700 +G82 X-1.1000 Y0.2700 +G82 X-0.8000 Y0.3700 +G82 X-1.8000 Y0.6800 +G82 X-1.8000 Y0.4800 +G82 X-1.9200 Y0.6800 +G82 X-1.9200 Y0.4800 +G82 X-2.0400 Y0.6800 +G82 X-2.0400 Y0.4800 +G82 X-2.1500 Y0.1500 +G82 X-2.1500 Y0.2500 +G82 X-2.1500 Y0.3500 +G82 X-1.8500 Y0.3500 +G82 X-1.8500 Y0.2500 +G82 X-1.8500 Y0.1500 +G82 X-2.0000 Y1.0300 +G82 X-2.3000 Y1.0300 +G82 X-0.7234 Y0.6709 +G82 X-0.7628 Y0.7891 +G82 X-0.8021 Y0.6709 +G82 X-0.8415 Y0.7891 +G82 X-0.8809 Y0.6709 +G82 X-0.9202 Y0.7891 +G82 X-1.1171 Y0.7576 +G82 X-0.5029 Y0.7576 +G82 X-0.2900 Y1.0000 +G82 X-0.1900 Y1.0000 +G82 X-0.2900 Y0.9000 +G82 X-0.1900 Y0.9000 +G82 X-0.2900 Y0.8000 +G82 X-0.1900 Y0.8000 +G82 X-0.2900 Y0.7000 +G82 X-0.1900 Y0.7000 +G82 X-0.2900 Y0.6000 +G82 X-0.1900 Y0.6000 +G82 X-0.2900 Y0.5000 +G82 X-0.1900 Y0.5000 +G82 X-0.2900 Y0.4000 +G82 X-0.1900 Y0.4000 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.bot.mill.tap b/trunk/ulp/docs/examples/04151_lcdi2c.bot.mill.tap new file mode 100644 index 00000000..e57bc889 --- /dev/null +++ b/trunk/ulp/docs/examples/04151_lcdi2c.bot.mill.tap @@ -0,0 +1,46 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0100 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G01 X-0.0100 Y-0.0100 +G01 X-2.7900 Y-0.0100 +G01 X-2.7900 Y1.3300 +G00 Z0.1000 +G00 X0.0100 Y1.3200 +G01 Z-0.0100 F10 +G01 X0.0100 Y0.0000 F20 +G00 Z0.1000 +G00 X0.0100 Y1.3300 +G01 Z-0.0100 F10 +G01 X-2.7900 Y1.3300 F20 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.bot.text.tap b/trunk/ulp/docs/examples/04151_lcdi2c.bot.text.tap new file mode 100644 index 00000000..24866e60 --- /dev/null +++ b/trunk/ulp/docs/examples/04151_lcdi2c.bot.text.tap @@ -0,0 +1,93 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0050 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-2.5800 Y0.1407 +G01 Z-0.0050 F10 +G01 X-2.6701 Y0.1407 F20 +G01 X-2.6926 Y0.1632 +G01 X-2.6926 Y0.2082 +G01 X-2.6701 Y0.2308 +G01 X-2.5800 Y0.2308 +G01 X-2.5575 Y0.2082 +G01 X-2.5575 Y0.1632 +G01 X-2.5800 Y0.1407 +G01 X-2.6701 Y0.2308 +G00 Z0.1000 +G00 X-2.5575 Y0.3463 +G01 Z-0.0050 F10 +G01 X-2.6926 Y0.3463 F20 +G01 X-2.6251 Y0.2788 +G01 X-2.6251 Y0.3689 +G00 Z0.1000 +G00 X-2.6476 Y0.4169 +G01 Z-0.0050 F10 +G01 X-2.6926 Y0.4619 F20 +G01 X-2.5575 Y0.4619 +G00 Z0.1000 +G00 X-2.5575 Y0.4169 +G01 Z-0.0050 F10 +G01 X-2.5575 Y0.5070 F20 +G00 Z0.1000 +G00 X-2.6926 Y0.6451 +G01 Z-0.0050 F10 +G01 X-2.6926 Y0.5550 F20 +G01 X-2.6251 Y0.5550 +G01 X-2.6476 Y0.6001 +G01 X-2.6476 Y0.6226 +G01 X-2.6251 Y0.6451 +G01 X-2.5800 Y0.6451 +G01 X-2.5575 Y0.6226 +G01 X-2.5575 Y0.5775 +G01 X-2.5800 Y0.5550 +G00 Z0.1000 +G00 X-2.6476 Y0.6931 +G01 Z-0.0050 F10 +G01 X-2.6926 Y0.7382 F20 +G01 X-2.5575 Y0.7382 +G00 Z0.1000 +G00 X-2.5575 Y0.6931 +G01 Z-0.0050 F10 +G01 X-2.5575 Y0.7832 F20 +G00 Z0.1000 +G00 X-2.5575 Y0.9694 +G01 Z-0.0050 F10 +G01 X-2.6476 Y0.9694 F20 +G01 X-2.6926 Y1.0144 +G01 X-2.6476 Y1.0594 +G01 X-2.5575 Y1.0594 +G00 Z0.1000 +G00 X-2.6251 Y0.9694 +G01 Z-0.0050 F10 +G01 X-2.6251 Y1.0594 F20 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.brd b/trunk/ulp/docs/examples/04151_lcdi2c.brd new file mode 100644 index 00000000..60d37332 Binary files /dev/null and b/trunk/ulp/docs/examples/04151_lcdi2c.brd differ diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.drl b/trunk/ulp/docs/examples/04151_lcdi2c.drl new file mode 100644 index 00000000..1753e72d --- /dev/null +++ b/trunk/ulp/docs/examples/04151_lcdi2c.drl @@ -0,0 +1,27 @@ +# +# Sample drill rack file for the enabtmr board. +# +# Drill is the size of the drill bit. +# Min is the smallest hole the bit will be used for. +# Max is the largest hole the bit will be used for. +# +# Each value can have a "unit of measure" added to it, +# such as 0.500mm . If you do not provide the unit of measure, +# values over 0.250 are considered millimeters, and +# values under 0.250 are considered inches. For example: +# 0.400 would be considered 0.400 mm. +# 0.125 would be considered 0.125 inches. +# +# Please note that you must use a TAB character +# between each setting on a line. +# +# Tip: Set the TAB size of your editor to 12 characters. +# +tool drill_size minimum maximum length +T01 0.500mm 0.000in 0.025in 1.5in +T02 0.032in 0.025in 0.035in 1.5in +T03 0.040in 0.035in 0.045in 1.5in +T04 0.050in 0.045in 0.055in 1.5in +T05 0.062in 0.055in 0.070in 1.5in +T06 0.085in 0.070in 0.125in 1.5in +T07 0.125in 0.100in 0.125in 1.5in diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.sch b/trunk/ulp/docs/examples/04151_lcdi2c.sch new file mode 100644 index 00000000..720db951 Binary files /dev/null and b/trunk/ulp/docs/examples/04151_lcdi2c.sch differ diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.top.drill.tap b/trunk/ulp/docs/examples/04151_lcdi2c.top.drill.tap new file mode 100644 index 00000000..b3646281 --- /dev/null +++ b/trunk/ulp/docs/examples/04151_lcdi2c.top.drill.tap @@ -0,0 +1,278 @@ +(.../src/pcbgcode-work/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/16/12 2:10 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0030 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0002) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +( Tool| Size | Min Sub | Max Sub | Count ) +( T02 | 0.813mm 0.0320in | 0.0320in | 0.0320in | 49 ) +( T03 | 1.016mm 0.0400in | 0.0400in | 0.0400in | 17 ) +( T03 | 2.184mm 0.0860in | 0.0400in | 0.0400in | 17 ) +( T07 | 3.175mm 0.1250in | 0.1250in | 0.1250in | 3 ) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T02 ; 0.0320 +G01 Z0.0000 F10 +M06 T01 ; 0.0320 +G00 Z0.1000 +M03 +G04 P3.000000 +G00 X0.4100 Y1.0000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.5100 Y1.0000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.6000 Y0.2700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.7234 Y0.6709 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.7628 Y0.7891 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.8000 Y0.3700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.8021 Y0.6709 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.8415 Y0.7891 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.8809 Y0.6709 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.9202 Y0.7891 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.1000 Y0.2700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.1300 Y1.1800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2300 Y1.1800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.2300 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.3400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.4400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.5400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.6400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.7400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.8400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.9400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y1.0400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.3700 Y0.2300 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.3900 Y1.1700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.4400 Y1.2450 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.4900 Y1.1700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.3400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.4400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.5400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.6400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.7400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.8400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.9400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y1.0400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.7500 Y1.1200 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.7500 Y1.2200 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8000 Y0.4800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8000 Y0.6800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8500 Y0.1500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8500 Y0.2500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8500 Y0.3500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.9200 Y0.4800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.9200 Y0.6800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.0400 Y0.4800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.0400 Y0.6800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.1500 Y0.1500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.1500 Y0.2500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.1500 Y0.3500 +G01 Z-0.0320 F10 +G00 Z0.1000 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T03 ; 0.0400 +G01 Z0.0000 F10 +M06 T02 ; 0.0400 +G00 Z0.1000 +M03 +G04 P3.000000 +G00 X0.1900 Y0.4000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.5000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.6000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.7000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.8000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.9000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y1.0000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.4000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.5000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.6000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.7000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.8000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.9000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y1.0000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.0000 Y1.0300 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.3000 Y1.0300 +G01 Z-0.0320 F10 +G00 Z0.1000 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T03 ; 0.0860 +G01 Z0.0000 F10 +M06 T03 ; 0.0860 +G00 Z0.1000 +M03 +G04 P3.000000 +G00 X0.5029 Y0.7576 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.1171 Y0.7576 +G01 Z-0.0320 F10 +G00 Z0.1000 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T07 ; 0.1250 +G01 Z0.0000 F10 +M06 T04 ; 0.1250 +G00 Z0.1000 +M03 +G04 P3.000000 +G00 X0.1500 Y0.1300 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1500 Y1.1900 +G01 Z-0.0320 F10 +G00 Z0.1000 +T01 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.top.etch.tap b/trunk/ulp/docs/examples/04151_lcdi2c.top.etch.tap new file mode 100644 index 00000000..65c135ba --- /dev/null +++ b/trunk/ulp/docs/examples/04151_lcdi2c.top.etch.tap @@ -0,0 +1,4707 @@ +(.../src/pcbgcode-work/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/16/12 4:41 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0030 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, bottom outlines, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X0.8356 Y0.6023 +G01 Z-0.0070 F10 +G01 X0.8356 Y0.6776 F20 +G01 X0.8305 Y0.6899 +G01 X0.8211 Y0.6993 +G01 X0.8088 Y0.7044 +G01 X0.7955 Y0.7044 +G01 X0.7831 Y0.6993 +G01 X0.7737 Y0.6899 +G01 X0.7686 Y0.6776 +G01 X0.7686 Y0.6023 +G01 X0.7737 Y0.5900 +G01 X0.7831 Y0.5805 +G01 X0.7955 Y0.5754 +G01 X0.8088 Y0.5754 +G01 X0.8211 Y0.5805 +G01 X0.8305 Y0.5900 +G01 X0.8356 Y0.6023 +G00 Z0.1000 +G00 X0.8080 Y0.8577 +G01 Z-0.0070 F10 +G01 X0.8080 Y0.7824 F20 +G01 X0.8131 Y0.7701 +G01 X0.8225 Y0.7607 +G01 X0.8348 Y0.7556 +G01 X0.8482 Y0.7556 +G01 X0.8605 Y0.7607 +G01 X0.8699 Y0.7701 +G01 X0.8750 Y0.7824 +G01 X0.8750 Y0.8577 +G01 X0.8699 Y0.8700 +G01 X0.8605 Y0.8795 +G01 X0.8482 Y0.8846 +G01 X0.8348 Y0.8846 +G01 X0.8225 Y0.8795 +G01 X0.8131 Y0.8700 +G01 X0.8080 Y0.8577 +G00 Z0.1000 +G00 X0.7569 Y0.6023 +G01 Z-0.0070 F10 +G01 X0.7569 Y0.6776 F20 +G01 X0.7518 Y0.6899 +G01 X0.7424 Y0.6993 +G01 X0.7300 Y0.7044 +G01 X0.7167 Y0.7044 +G01 X0.7044 Y0.6993 +G01 X0.6950 Y0.6899 +G01 X0.6899 Y0.6776 +G01 X0.6899 Y0.6023 +G01 X0.6950 Y0.5900 +G01 X0.7044 Y0.5805 +G01 X0.7167 Y0.5754 +G01 X0.7300 Y0.5754 +G01 X0.7424 Y0.5805 +G01 X0.7518 Y0.5900 +G01 X0.7569 Y0.6023 +G00 Z0.1000 +G00 X0.9144 Y0.6023 +G01 Z-0.0070 F10 +G01 X0.9144 Y0.6776 F20 +G01 X0.9093 Y0.6899 +G01 X0.8998 Y0.6993 +G01 X0.8875 Y0.7044 +G01 X0.8742 Y0.7044 +G01 X0.8619 Y0.6993 +G01 X0.8525 Y0.6899 +G01 X0.8474 Y0.6776 +G01 X0.8474 Y0.6023 +G01 X0.8525 Y0.5900 +G01 X0.8619 Y0.5805 +G01 X0.8742 Y0.5754 +G01 X0.8875 Y0.5754 +G01 X0.8998 Y0.5805 +G01 X0.9093 Y0.5900 +G01 X0.9144 Y0.6023 +G00 Z0.1000 +G00 X0.8867 Y0.8577 +G01 Z-0.0070 F10 +G01 X0.8867 Y0.7824 F20 +G01 X0.8918 Y0.7701 +G01 X0.9013 Y0.7607 +G01 X0.9136 Y0.7556 +G01 X0.9269 Y0.7556 +G01 X0.9392 Y0.7607 +G01 X0.9486 Y0.7701 +G01 X0.9537 Y0.7824 +G01 X0.9537 Y0.8577 +G01 X0.9486 Y0.8700 +G01 X0.9392 Y0.8795 +G01 X0.9269 Y0.8846 +G01 X0.9136 Y0.8846 +G01 X0.9013 Y0.8795 +G01 X0.8918 Y0.8700 +G01 X0.8867 Y0.8577 +G00 Z0.1000 +G00 X0.7293 Y0.8577 +G01 Z-0.0070 F10 +G01 X0.7293 Y0.7824 F20 +G01 X0.7344 Y0.7701 +G01 X0.7438 Y0.7607 +G01 X0.7561 Y0.7556 +G01 X0.7694 Y0.7556 +G01 X0.7817 Y0.7607 +G01 X0.7912 Y0.7701 +G01 X0.7963 Y0.7824 +G01 X0.7963 Y0.8577 +G01 X0.7912 Y0.8700 +G01 X0.7817 Y0.8795 +G01 X0.7694 Y0.8846 +G01 X0.7561 Y0.8846 +G01 X0.7438 Y0.8795 +G01 X0.7344 Y0.8700 +G01 X0.7293 Y0.8577 +G00 Z0.1000 +G00 X1.5323 Y0.3065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.3065 F20 +G01 X1.6200 Y0.3116 +G01 X1.6294 Y0.3210 +G01 X1.6345 Y0.3333 +G01 X1.6345 Y0.3467 +G01 X1.6294 Y0.3590 +G01 X1.6200 Y0.3684 +G01 X1.6077 Y0.3735 +G01 X1.5323 Y0.3735 +G01 X1.5200 Y0.3684 +G01 X1.5106 Y0.3590 +G01 X1.5055 Y0.3467 +G01 X1.5055 Y0.3333 +G01 X1.5106 Y0.3210 +G01 X1.5200 Y0.3116 +G01 X1.5323 Y0.3065 +G00 Z0.1000 +G00 X1.5323 Y0.4065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.4065 F20 +G01 X1.6200 Y0.4116 +G01 X1.6294 Y0.4210 +G01 X1.6345 Y0.4333 +G01 X1.6345 Y0.4467 +G01 X1.6294 Y0.4590 +G01 X1.6200 Y0.4684 +G01 X1.6077 Y0.4735 +G01 X1.5323 Y0.4735 +G01 X1.5200 Y0.4684 +G01 X1.5106 Y0.4590 +G01 X1.5055 Y0.4467 +G01 X1.5055 Y0.4333 +G01 X1.5106 Y0.4210 +G01 X1.5200 Y0.4116 +G01 X1.5323 Y0.4065 +G00 Z0.1000 +G00 X1.5323 Y0.5065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.5065 F20 +G01 X1.6200 Y0.5116 +G01 X1.6294 Y0.5210 +G01 X1.6345 Y0.5333 +G01 X1.6345 Y0.5467 +G01 X1.6294 Y0.5590 +G01 X1.6200 Y0.5684 +G01 X1.6077 Y0.5735 +G01 X1.5323 Y0.5735 +G01 X1.5200 Y0.5684 +G01 X1.5106 Y0.5590 +G01 X1.5055 Y0.5467 +G01 X1.5055 Y0.5333 +G01 X1.5106 Y0.5210 +G01 X1.5200 Y0.5116 +G01 X1.5323 Y0.5065 +G00 Z0.1000 +G00 X1.5323 Y0.6065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.6065 F20 +G01 X1.6200 Y0.6116 +G01 X1.6294 Y0.6210 +G01 X1.6345 Y0.6333 +G01 X1.6345 Y0.6467 +G01 X1.6294 Y0.6590 +G01 X1.6200 Y0.6684 +G01 X1.6077 Y0.6735 +G01 X1.5323 Y0.6735 +G01 X1.5200 Y0.6684 +G01 X1.5106 Y0.6590 +G01 X1.5055 Y0.6467 +G01 X1.5055 Y0.6333 +G01 X1.5106 Y0.6210 +G01 X1.5200 Y0.6116 +G01 X1.5323 Y0.6065 +G00 Z0.1000 +G00 X1.5323 Y0.7065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.7065 F20 +G01 X1.6200 Y0.7116 +G01 X1.6294 Y0.7210 +G01 X1.6345 Y0.7333 +G01 X1.6345 Y0.7467 +G01 X1.6294 Y0.7590 +G01 X1.6200 Y0.7684 +G01 X1.6077 Y0.7735 +G01 X1.5323 Y0.7735 +G01 X1.5200 Y0.7684 +G01 X1.5106 Y0.7590 +G01 X1.5055 Y0.7467 +G01 X1.5055 Y0.7333 +G01 X1.5106 Y0.7210 +G01 X1.5200 Y0.7116 +G01 X1.5323 Y0.7065 +G00 Z0.1000 +G00 X1.5323 Y0.8065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.8065 F20 +G01 X1.6200 Y0.8116 +G01 X1.6294 Y0.8210 +G01 X1.6345 Y0.8333 +G01 X1.6345 Y0.8467 +G01 X1.6294 Y0.8590 +G01 X1.6200 Y0.8684 +G01 X1.6077 Y0.8735 +G01 X1.5323 Y0.8735 +G01 X1.5200 Y0.8684 +G01 X1.5106 Y0.8590 +G01 X1.5055 Y0.8467 +G01 X1.5055 Y0.8333 +G01 X1.5106 Y0.8210 +G01 X1.5200 Y0.8116 +G01 X1.5323 Y0.8065 +G00 Z0.1000 +G00 X1.5323 Y0.9065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.9065 F20 +G01 X1.6200 Y0.9116 +G01 X1.6294 Y0.9210 +G01 X1.6345 Y0.9333 +G01 X1.6345 Y0.9467 +G01 X1.6294 Y0.9590 +G01 X1.6200 Y0.9684 +G01 X1.6077 Y0.9735 +G01 X1.5323 Y0.9735 +G01 X1.5200 Y0.9684 +G01 X1.5106 Y0.9590 +G01 X1.5055 Y0.9467 +G01 X1.5055 Y0.9333 +G01 X1.5106 Y0.9210 +G01 X1.5200 Y0.9116 +G01 X1.5323 Y0.9065 +G00 Z0.1000 +G00 X1.5323 Y1.0065 +G01 Z-0.0070 F10 +G01 X1.6077 Y1.0065 F20 +G01 X1.6200 Y1.0116 +G01 X1.6294 Y1.0210 +G01 X1.6345 Y1.0333 +G01 X1.6345 Y1.0467 +G01 X1.6294 Y1.0590 +G01 X1.6200 Y1.0684 +G01 X1.6077 Y1.0735 +G01 X1.5323 Y1.0735 +G01 X1.5200 Y1.0684 +G01 X1.5106 Y1.0590 +G01 X1.5055 Y1.0467 +G01 X1.5055 Y1.0333 +G01 X1.5106 Y1.0210 +G01 X1.5200 Y1.0116 +G01 X1.5323 Y1.0065 +G00 Z0.1000 +G00 X1.2323 Y1.0065 +G01 Z-0.0070 F10 +G01 X1.3077 Y1.0065 F20 +G01 X1.3200 Y1.0116 +G01 X1.3294 Y1.0210 +G01 X1.3345 Y1.0333 +G01 X1.3345 Y1.0467 +G01 X1.3294 Y1.0590 +G01 X1.3200 Y1.0684 +G01 X1.3077 Y1.0735 +G01 X1.2323 Y1.0735 +G01 X1.2200 Y1.0684 +G01 X1.2106 Y1.0590 +G01 X1.2055 Y1.0467 +G01 X1.2055 Y1.0333 +G01 X1.2106 Y1.0210 +G01 X1.2200 Y1.0116 +G01 X1.2323 Y1.0065 +G00 Z0.1000 +G00 X1.2323 Y0.9065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.9065 F20 +G01 X1.3200 Y0.9116 +G01 X1.3294 Y0.9210 +G01 X1.3345 Y0.9333 +G01 X1.3345 Y0.9467 +G01 X1.3294 Y0.9590 +G01 X1.3200 Y0.9684 +G01 X1.3077 Y0.9735 +G01 X1.2323 Y0.9735 +G01 X1.2200 Y0.9684 +G01 X1.2106 Y0.9590 +G01 X1.2055 Y0.9467 +G01 X1.2055 Y0.9333 +G01 X1.2106 Y0.9210 +G01 X1.2200 Y0.9116 +G01 X1.2323 Y0.9065 +G00 Z0.1000 +G00 X1.2323 Y0.8065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.8065 F20 +G01 X1.3200 Y0.8116 +G01 X1.3294 Y0.8210 +G01 X1.3345 Y0.8333 +G01 X1.3345 Y0.8467 +G01 X1.3294 Y0.8590 +G01 X1.3200 Y0.8684 +G01 X1.3077 Y0.8735 +G01 X1.2323 Y0.8735 +G01 X1.2200 Y0.8684 +G01 X1.2106 Y0.8590 +G01 X1.2055 Y0.8467 +G01 X1.2055 Y0.8333 +G01 X1.2106 Y0.8210 +G01 X1.2200 Y0.8116 +G01 X1.2323 Y0.8065 +G00 Z0.1000 +G00 X1.2323 Y0.7065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.7065 F20 +G01 X1.3200 Y0.7116 +G01 X1.3294 Y0.7210 +G01 X1.3345 Y0.7333 +G01 X1.3345 Y0.7467 +G01 X1.3294 Y0.7590 +G01 X1.3200 Y0.7684 +G01 X1.3077 Y0.7735 +G01 X1.2323 Y0.7735 +G01 X1.2200 Y0.7684 +G01 X1.2106 Y0.7590 +G01 X1.2055 Y0.7467 +G01 X1.2055 Y0.7333 +G01 X1.2106 Y0.7210 +G01 X1.2200 Y0.7116 +G01 X1.2323 Y0.7065 +G00 Z0.1000 +G00 X1.2323 Y0.6065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.6065 F20 +G01 X1.3200 Y0.6116 +G01 X1.3294 Y0.6210 +G01 X1.3345 Y0.6333 +G01 X1.3345 Y0.6467 +G01 X1.3294 Y0.6590 +G01 X1.3200 Y0.6684 +G01 X1.3077 Y0.6735 +G01 X1.2323 Y0.6735 +G01 X1.2200 Y0.6684 +G01 X1.2106 Y0.6590 +G01 X1.2055 Y0.6467 +G01 X1.2055 Y0.6333 +G01 X1.2106 Y0.6210 +G01 X1.2200 Y0.6116 +G01 X1.2323 Y0.6065 +G00 Z0.1000 +G00 X1.2323 Y0.5065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.5065 F20 +G01 X1.3200 Y0.5116 +G01 X1.3294 Y0.5210 +G01 X1.3345 Y0.5333 +G01 X1.3345 Y0.5467 +G01 X1.3294 Y0.5590 +G01 X1.3200 Y0.5684 +G01 X1.3077 Y0.5735 +G01 X1.2323 Y0.5735 +G01 X1.2200 Y0.5684 +G01 X1.2106 Y0.5590 +G01 X1.2055 Y0.5467 +G01 X1.2055 Y0.5333 +G01 X1.2106 Y0.5210 +G01 X1.2200 Y0.5116 +G01 X1.2323 Y0.5065 +G00 Z0.1000 +G00 X1.2323 Y0.4065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.4065 F20 +G01 X1.3200 Y0.4116 +G01 X1.3294 Y0.4210 +G01 X1.3345 Y0.4333 +G01 X1.3345 Y0.4467 +G01 X1.3294 Y0.4590 +G01 X1.3200 Y0.4684 +G01 X1.3077 Y0.4735 +G01 X1.2323 Y0.4735 +G01 X1.2200 Y0.4684 +G01 X1.2106 Y0.4590 +G01 X1.2055 Y0.4467 +G01 X1.2055 Y0.4333 +G01 X1.2106 Y0.4210 +G01 X1.2200 Y0.4116 +G01 X1.2323 Y0.4065 +G00 Z0.1000 +G00 X1.2323 Y0.3065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.3065 F20 +G01 X1.3200 Y0.3116 +G01 X1.3294 Y0.3210 +G01 X1.3345 Y0.3333 +G01 X1.3345 Y0.3467 +G01 X1.3294 Y0.3590 +G01 X1.3200 Y0.3684 +G01 X1.3077 Y0.3735 +G01 X1.2323 Y0.3735 +G01 X1.2200 Y0.3684 +G01 X1.2106 Y0.3590 +G01 X1.2055 Y0.3467 +G01 X1.2055 Y0.3333 +G01 X1.2106 Y0.3210 +G01 X1.2200 Y0.3116 +G01 X1.2323 Y0.3065 +G00 Z0.1000 +G00 X0.3275 Y0.9845 +G01 Z-0.0070 F10 +G01 X0.3275 Y1.0155 F20 +G01 X0.3055 Y1.0375 +G01 X0.2745 Y1.0375 +G01 X0.2525 Y1.0155 +G01 X0.2525 Y0.9845 +G01 X0.2745 Y0.9625 +G01 X0.3055 Y0.9625 +G01 X0.3275 Y0.9845 +G00 Z0.1000 +G00 X0.3275 Y0.8845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.9155 F20 +G01 X0.3055 Y0.9375 +G01 X0.2745 Y0.9375 +G01 X0.2525 Y0.9155 +G01 X0.2525 Y0.8845 +G01 X0.2745 Y0.8625 +G01 X0.3055 Y0.8625 +G01 X0.3275 Y0.8845 +G00 Z0.1000 +G00 X0.3275 Y0.7845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.8155 F20 +G01 X0.3055 Y0.8375 +G01 X0.2745 Y0.8375 +G01 X0.2525 Y0.8155 +G01 X0.2525 Y0.7845 +G01 X0.2745 Y0.7625 +G01 X0.3055 Y0.7625 +G01 X0.3275 Y0.7845 +G00 Z0.1000 +G00 X0.3275 Y0.6845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.7155 F20 +G01 X0.3055 Y0.7375 +G01 X0.2745 Y0.7375 +G01 X0.2525 Y0.7155 +G01 X0.2525 Y0.6845 +G01 X0.2745 Y0.6625 +G01 X0.3055 Y0.6625 +G01 X0.3275 Y0.6845 +G00 Z0.1000 +G00 X0.3275 Y0.5845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.6155 F20 +G01 X0.3055 Y0.6375 +G01 X0.2745 Y0.6375 +G01 X0.2525 Y0.6155 +G01 X0.2525 Y0.5845 +G01 X0.2745 Y0.5625 +G01 X0.3055 Y0.5625 +G01 X0.3275 Y0.5845 +G00 Z0.1000 +G00 X0.3275 Y0.4845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.5155 F20 +G01 X0.3055 Y0.5375 +G01 X0.2745 Y0.5375 +G01 X0.2525 Y0.5155 +G01 X0.2525 Y0.4845 +G01 X0.2745 Y0.4625 +G01 X0.3055 Y0.4625 +G01 X0.3275 Y0.4845 +G00 Z0.1000 +G00 X0.2275 Y0.9845 +G01 Z-0.0070 F10 +G01 X0.2275 Y1.0155 F20 +G01 X0.2055 Y1.0375 +G01 X0.1745 Y1.0375 +G01 X0.1525 Y1.0155 +G01 X0.1525 Y0.9845 +G01 X0.1745 Y0.9625 +G01 X0.2055 Y0.9625 +G01 X0.2275 Y0.9845 +G00 Z0.1000 +G00 X0.2275 Y0.8845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.9155 F20 +G01 X0.2055 Y0.9375 +G01 X0.1745 Y0.9375 +G01 X0.1525 Y0.9155 +G01 X0.1525 Y0.8845 +G01 X0.1745 Y0.8625 +G01 X0.2055 Y0.8625 +G01 X0.2275 Y0.8845 +G00 Z0.1000 +G00 X0.2275 Y0.7845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.8155 F20 +G01 X0.2055 Y0.8375 +G01 X0.1745 Y0.8375 +G01 X0.1525 Y0.8155 +G01 X0.1525 Y0.7845 +G01 X0.1745 Y0.7625 +G01 X0.2055 Y0.7625 +G01 X0.2275 Y0.7845 +G00 Z0.1000 +G00 X0.2275 Y0.6845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.7155 F20 +G01 X0.2055 Y0.7375 +G01 X0.1745 Y0.7375 +G01 X0.1525 Y0.7155 +G01 X0.1525 Y0.6845 +G01 X0.1745 Y0.6625 +G01 X0.2055 Y0.6625 +G01 X0.2275 Y0.6845 +G00 Z0.1000 +G00 X0.2275 Y0.5845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.6155 F20 +G01 X0.2055 Y0.6375 +G01 X0.1745 Y0.6375 +G01 X0.1525 Y0.6155 +G01 X0.1525 Y0.5845 +G01 X0.1745 Y0.5625 +G01 X0.2055 Y0.5625 +G01 X0.2275 Y0.5845 +G00 Z0.1000 +G00 X0.2275 Y0.4845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.5155 F20 +G01 X0.2055 Y0.5375 +G01 X0.1745 Y0.5375 +G01 X0.1525 Y0.5155 +G01 X0.1525 Y0.4845 +G01 X0.1745 Y0.4625 +G01 X0.2055 Y0.4625 +G01 X0.2275 Y0.4845 +G00 Z0.1000 +G00 X0.3275 Y0.3845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.4155 F20 +G01 X0.3055 Y0.4375 +G01 X0.2745 Y0.4375 +G01 X0.2525 Y0.4155 +G01 X0.2525 Y0.3845 +G01 X0.2745 Y0.3625 +G01 X0.3055 Y0.3625 +G01 X0.3275 Y0.3845 +G00 Z0.1000 +G00 X0.2275 Y0.3845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.4155 F20 +G01 X0.2055 Y0.4375 +G01 X0.1745 Y0.4375 +G01 X0.1525 Y0.4155 +G01 X0.1525 Y0.3845 +G01 X0.1745 Y0.3625 +G01 X0.2055 Y0.3625 +G01 X0.2275 Y0.3845 +G00 Z0.1000 +G00 X0.8377 Y0.4035 +G01 Z-0.0070 F10 +G01 X0.7623 Y0.4035 F20 +G01 X0.7500 Y0.3984 +G01 X0.7406 Y0.3890 +G01 X0.7355 Y0.3767 +G01 X0.7355 Y0.3633 +G01 X0.7406 Y0.3510 +G01 X0.7500 Y0.3416 +G01 X0.7623 Y0.3365 +G01 X0.8377 Y0.3365 +G01 X0.8500 Y0.3416 +G01 X0.8594 Y0.3510 +G01 X0.8645 Y0.3633 +G01 X0.8645 Y0.3767 +G01 X0.8594 Y0.3890 +G01 X0.8500 Y0.3984 +G01 X0.8377 Y0.4035 +G00 Z0.1000 +G00 X1.1377 Y0.3035 +G01 Z-0.0070 F10 +G01 X1.0623 Y0.3035 F20 +G01 X1.0500 Y0.2984 +G01 X1.0406 Y0.2890 +G01 X1.0355 Y0.2767 +G01 X1.0355 Y0.2633 +G01 X1.0406 Y0.2510 +G01 X1.0500 Y0.2416 +G01 X1.0623 Y0.2365 +G01 X1.1377 Y0.2365 +G01 X1.1500 Y0.2416 +G01 X1.1594 Y0.2510 +G01 X1.1645 Y0.2633 +G01 X1.1645 Y0.2767 +G01 X1.1594 Y0.2890 +G01 X1.1500 Y0.2984 +G01 X1.1377 Y0.3035 +G00 Z0.1000 +G00 X0.6377 Y0.3035 +G01 Z-0.0070 F10 +G01 X0.5623 Y0.3035 F20 +G01 X0.5500 Y0.2984 +G01 X0.5406 Y0.2890 +G01 X0.5355 Y0.2767 +G01 X0.5355 Y0.2633 +G01 X0.5406 Y0.2510 +G01 X0.5500 Y0.2416 +G01 X0.5623 Y0.2365 +G01 X0.6377 Y0.2365 +G01 X0.6500 Y0.2416 +G01 X0.6594 Y0.2510 +G01 X0.6645 Y0.2633 +G01 X0.6645 Y0.2767 +G01 X0.6594 Y0.2890 +G01 X0.6500 Y0.2984 +G01 X0.6377 Y0.3035 +G00 Z0.1000 +G00 X2.1123 Y0.1165 +G01 Z-0.0070 F10 +G01 X2.1877 Y0.1165 F20 +G01 X2.2000 Y0.1216 +G01 X2.2094 Y0.1310 +G01 X2.2145 Y0.1433 +G01 X2.2145 Y0.1567 +G01 X2.2094 Y0.1690 +G01 X2.2000 Y0.1784 +G01 X2.1877 Y0.1835 +G01 X2.1123 Y0.1835 +G01 X2.1000 Y0.1784 +G01 X2.0906 Y0.1690 +G01 X2.0855 Y0.1567 +G01 X2.0855 Y0.1433 +G01 X2.0906 Y0.1310 +G01 X2.1000 Y0.1216 +G01 X2.1123 Y0.1165 +G00 Z0.1000 +G00 X2.1123 Y0.2165 +G01 Z-0.0070 F10 +G01 X2.1877 Y0.2165 F20 +G01 X2.2000 Y0.2216 +G01 X2.2094 Y0.2310 +G01 X2.2145 Y0.2433 +G01 X2.2145 Y0.2567 +G01 X2.2094 Y0.2690 +G01 X2.2000 Y0.2784 +G01 X2.1877 Y0.2835 +G01 X2.1123 Y0.2835 +G01 X2.1000 Y0.2784 +G01 X2.0906 Y0.2690 +G01 X2.0855 Y0.2567 +G01 X2.0855 Y0.2433 +G01 X2.0906 Y0.2310 +G01 X2.1000 Y0.2216 +G01 X2.1123 Y0.2165 +G00 Z0.1000 +G00 X2.1123 Y0.3165 +G01 Z-0.0070 F10 +G01 X2.1877 Y0.3165 F20 +G01 X2.2000 Y0.3216 +G01 X2.2094 Y0.3310 +G01 X2.2145 Y0.3433 +G01 X2.2145 Y0.3567 +G01 X2.2094 Y0.3690 +G01 X2.2000 Y0.3784 +G01 X2.1877 Y0.3835 +G01 X2.1123 Y0.3835 +G01 X2.1000 Y0.3784 +G01 X2.0906 Y0.3690 +G01 X2.0855 Y0.3567 +G01 X2.0855 Y0.3433 +G01 X2.0906 Y0.3310 +G01 X2.1000 Y0.3216 +G01 X2.1123 Y0.3165 +G00 Z0.1000 +G00 X1.8123 Y0.3165 +G01 Z-0.0070 F10 +G01 X1.8877 Y0.3165 F20 +G01 X1.9000 Y0.3216 +G01 X1.9094 Y0.3310 +G01 X1.9145 Y0.3433 +G01 X1.9145 Y0.3567 +G01 X1.9094 Y0.3690 +G01 X1.9000 Y0.3784 +G01 X1.8877 Y0.3835 +G01 X1.8123 Y0.3835 +G01 X1.8000 Y0.3784 +G01 X1.7906 Y0.3690 +G01 X1.7855 Y0.3567 +G01 X1.7855 Y0.3433 +G01 X1.7906 Y0.3310 +G01 X1.8000 Y0.3216 +G01 X1.8123 Y0.3165 +G00 Z0.1000 +G00 X1.8123 Y0.2165 +G01 Z-0.0070 F10 +G01 X1.8877 Y0.2165 F20 +G01 X1.9000 Y0.2216 +G01 X1.9094 Y0.2310 +G01 X1.9145 Y0.2433 +G01 X1.9145 Y0.2567 +G01 X1.9094 Y0.2690 +G01 X1.9000 Y0.2784 +G01 X1.8877 Y0.2835 +G01 X1.8123 Y0.2835 +G01 X1.8000 Y0.2784 +G01 X1.7906 Y0.2690 +G01 X1.7855 Y0.2567 +G01 X1.7855 Y0.2433 +G01 X1.7906 Y0.2310 +G01 X1.8000 Y0.2216 +G01 X1.8123 Y0.2165 +G00 Z0.1000 +G00 X1.8123 Y0.1165 +G01 Z-0.0070 F10 +G01 X1.8877 Y0.1165 F20 +G01 X1.9000 Y0.1216 +G01 X1.9094 Y0.1310 +G01 X1.9145 Y0.1433 +G01 X1.9145 Y0.1567 +G01 X1.9094 Y0.1690 +G01 X1.9000 Y0.1784 +G01 X1.8877 Y0.1835 +G01 X1.8123 Y0.1835 +G01 X1.8000 Y0.1784 +G01 X1.7906 Y0.1690 +G01 X1.7855 Y0.1567 +G01 X1.7855 Y0.1433 +G01 X1.7906 Y0.1310 +G01 X1.8000 Y0.1216 +G01 X1.8123 Y0.1165 +G00 Z0.1000 +G00 X1.8335 Y0.6661 +G01 Z-0.0070 F10 +G01 X1.8335 Y0.6939 F20 +G01 X1.8139 Y0.7135 +G01 X1.7861 Y0.7135 +G01 X1.7665 Y0.6939 +G01 X1.7665 Y0.6661 +G01 X1.7861 Y0.6465 +G01 X1.8139 Y0.6465 +G01 X1.8335 Y0.6661 +G00 Z0.1000 +G00 X1.8335 Y0.4661 +G01 Z-0.0070 F10 +G01 X1.8335 Y0.4939 F20 +G01 X1.8139 Y0.5135 +G01 X1.7861 Y0.5135 +G01 X1.7665 Y0.4939 +G01 X1.7665 Y0.4661 +G01 X1.7861 Y0.4465 +G01 X1.8139 Y0.4465 +G01 X1.8335 Y0.4661 +G00 Z0.1000 +G00 X1.9535 Y0.6661 +G01 Z-0.0070 F10 +G01 X1.9535 Y0.6939 F20 +G01 X1.9339 Y0.7135 +G01 X1.9061 Y0.7135 +G01 X1.8865 Y0.6939 +G01 X1.8865 Y0.6661 +G01 X1.9061 Y0.6465 +G01 X1.9339 Y0.6465 +G01 X1.9535 Y0.6661 +G00 Z0.1000 +G00 X1.9535 Y0.4661 +G01 Z-0.0070 F10 +G01 X1.9535 Y0.4939 F20 +G01 X1.9339 Y0.5135 +G01 X1.9061 Y0.5135 +G01 X1.8865 Y0.4939 +G01 X1.8865 Y0.4661 +G01 X1.9061 Y0.4465 +G01 X1.9339 Y0.4465 +G01 X1.9535 Y0.4661 +G00 Z0.1000 +G00 X2.0735 Y0.6661 +G01 Z-0.0070 F10 +G01 X2.0735 Y0.6939 F20 +G01 X2.0539 Y0.7135 +G01 X2.0261 Y0.7135 +G01 X2.0065 Y0.6939 +G01 X2.0065 Y0.6661 +G01 X2.0261 Y0.6465 +G01 X2.0539 Y0.6465 +G01 X2.0735 Y0.6661 +G00 Z0.1000 +G00 X2.0735 Y0.4661 +G01 Z-0.0070 F10 +G01 X2.0735 Y0.4939 F20 +G01 X2.0539 Y0.5135 +G01 X2.0261 Y0.5135 +G01 X2.0065 Y0.4939 +G01 X2.0065 Y0.4661 +G01 X2.0261 Y0.4465 +G01 X2.0539 Y0.4465 +G01 X2.0735 Y0.4661 +G00 Z0.1000 +G00 X1.3035 Y0.2161 +G01 Z-0.0070 F10 +G01 X1.3035 Y0.2439 F20 +G01 X1.2839 Y0.2635 +G01 X1.2561 Y0.2635 +G01 X1.2365 Y0.2439 +G01 X1.2365 Y0.2161 +G01 X1.2561 Y0.1965 +G01 X1.2839 Y0.1965 +G01 X1.3035 Y0.2161 +G00 Z0.1000 +G00 X1.4035 Y0.2161 +G01 Z-0.0070 F10 +G01 X1.4035 Y0.2439 F20 +G01 X1.3839 Y0.2635 +G01 X1.3561 Y0.2635 +G01 X1.3365 Y0.2439 +G01 X1.3365 Y0.2161 +G01 X1.3561 Y0.1965 +G01 X1.3839 Y0.1965 +G01 X1.4035 Y0.2161 +G00 Z0.1000 +G00 X2.3525 Y1.0083 +G01 Z-0.0070 F10 +G01 X2.3525 Y1.0517 F20 +G01 X2.3217 Y1.0825 +G01 X2.2783 Y1.0825 +G01 X2.2475 Y1.0517 +G01 X2.2475 Y1.0083 +G01 X2.2783 Y0.9775 +G01 X2.3217 Y0.9775 +G01 X2.3525 Y1.0083 +G00 Z0.1000 +G00 X2.0525 Y1.0083 +G01 Z-0.0070 F10 +G01 X2.0525 Y1.0517 F20 +G01 X2.0217 Y1.0825 +G01 X1.9783 Y1.0825 +G01 X1.9475 Y1.0517 +G01 X1.9475 Y1.0083 +G01 X1.9783 Y0.9775 +G01 X2.0217 Y0.9775 +G01 X2.0525 Y1.0083 +G00 Z0.1000 +G00 X0.5435 Y0.9861 +G01 Z-0.0070 F10 +G01 X0.5435 Y1.0139 F20 +G01 X0.5239 Y1.0335 +G01 X0.4961 Y1.0335 +G01 X0.4765 Y1.0139 +G01 X0.4765 Y0.9861 +G01 X0.4961 Y0.9665 +G01 X0.5239 Y0.9665 +G01 X0.5435 Y0.9861 +G00 Z0.1000 +G00 X0.4435 Y0.9861 +G01 Z-0.0070 F10 +G01 X0.4435 Y1.0139 F20 +G01 X0.4239 Y1.0335 +G01 X0.3961 Y1.0335 +G01 X0.3765 Y1.0139 +G01 X0.3765 Y0.9861 +G01 X0.3961 Y0.9665 +G01 X0.4239 Y0.9665 +G01 X0.4435 Y0.9861 +G00 Z0.1000 +G00 X1.4235 Y1.1561 +G01 Z-0.0070 F10 +G01 X1.4235 Y1.1839 F20 +G01 X1.4039 Y1.2035 +G01 X1.3761 Y1.2035 +G01 X1.3565 Y1.1839 +G01 X1.3565 Y1.1561 +G01 X1.3761 Y1.1365 +G01 X1.4039 Y1.1365 +G01 X1.4235 Y1.1561 +G00 Z0.1000 +G00 X1.4735 Y1.2311 +G01 Z-0.0070 F10 +G01 X1.4735 Y1.2589 F20 +G01 X1.4539 Y1.2785 +G01 X1.4261 Y1.2785 +G01 X1.4065 Y1.2589 +G01 X1.4065 Y1.2311 +G01 X1.4261 Y1.2115 +G01 X1.4539 Y1.2115 +G01 X1.4735 Y1.2311 +G00 Z0.1000 +G00 X1.5235 Y1.1561 +G01 Z-0.0070 F10 +G01 X1.5235 Y1.1839 F20 +G01 X1.5039 Y1.2035 +G01 X1.4761 Y1.2035 +G01 X1.4565 Y1.1839 +G01 X1.4565 Y1.1561 +G01 X1.4761 Y1.1365 +G01 X1.5039 Y1.1365 +G01 X1.5235 Y1.1561 +G00 Z0.1000 +G00 X1.1755 Y1.1709 +G01 Z-0.0070 F10 +G01 X1.1755 Y1.1891 F20 +G01 X1.1686 Y1.2058 +G01 X1.1558 Y1.2186 +G01 X1.1391 Y1.2255 +G01 X1.1209 Y1.2255 +G01 X1.1042 Y1.2186 +G01 X1.0914 Y1.2058 +G01 X1.0845 Y1.1891 +G01 X1.0845 Y1.1709 +G01 X1.0914 Y1.1542 +G01 X1.1042 Y1.1414 +G01 X1.1209 Y1.1345 +G01 X1.1391 Y1.1345 +G01 X1.1558 Y1.1414 +G01 X1.1686 Y1.1542 +G01 X1.1755 Y1.1709 +G00 Z0.1000 +G00 X1.2755 Y1.1612 +G01 Z-0.0070 F10 +G01 X1.2755 Y1.1988 F20 +G01 X1.2488 Y1.2255 +G01 X1.2112 Y1.2255 +G01 X1.1845 Y1.1988 +G01 X1.1845 Y1.1612 +G01 X1.2112 Y1.1345 +G01 X1.2488 Y1.1345 +G01 X1.2755 Y1.1612 +G00 Z0.1000 +G00 X1.7955 Y1.2109 +G01 Z-0.0070 F10 +G01 X1.7955 Y1.2291 F20 +G01 X1.7886 Y1.2458 +G01 X1.7758 Y1.2586 +G01 X1.7591 Y1.2655 +G01 X1.7409 Y1.2655 +G01 X1.7242 Y1.2586 +G01 X1.7114 Y1.2458 +G01 X1.7045 Y1.2291 +G01 X1.7045 Y1.2109 +G01 X1.7114 Y1.1942 +G01 X1.7242 Y1.1814 +G01 X1.7409 Y1.1745 +G01 X1.7591 Y1.1745 +G01 X1.7758 Y1.1814 +G01 X1.7886 Y1.1942 +G01 X1.7955 Y1.2109 +G00 Z0.1000 +G00 X1.7955 Y1.1012 +G01 Z-0.0070 F10 +G01 X1.7955 Y1.1388 F20 +G01 X1.7688 Y1.1655 +G01 X1.7312 Y1.1655 +G01 X1.7045 Y1.1388 +G01 X1.7045 Y1.1012 +G01 X1.7312 Y1.0745 +G01 X1.7688 Y1.0745 +G01 X1.7955 Y1.1012 +G00 Z0.1000 +G00 X1.8005 Y1.2100 +G01 Z-0.0070 F10 +G01 X1.8005 Y1.2300 F20 +G01 X1.7928 Y1.2486 +G01 X1.7786 Y1.2628 +G01 X1.7600 Y1.2705 +G01 X1.7400 Y1.2705 +G01 X1.7214 Y1.2628 +G01 X1.7072 Y1.2486 +G01 X1.6995 Y1.2300 +G01 X1.6995 Y1.2100 +G01 X1.7072 Y1.1914 +G01 X1.7214 Y1.1772 +G01 X1.7376 Y1.1705 +G01 X1.7291 Y1.1705 +G01 X1.6995 Y1.1409 +G01 X1.6995 Y1.0991 +G01 X1.7291 Y1.0695 +G01 X1.7709 Y1.0695 +G01 X1.8005 Y1.0991 +G01 X1.8005 Y1.1409 +G01 X1.7709 Y1.1705 +G01 X1.7624 Y1.1705 +G01 X1.7786 Y1.1772 +G01 X1.7928 Y1.1914 +G01 X1.8005 Y1.2100 +G00 Z0.1000 +G00 X1.4785 Y1.2291 +G01 Z-0.0070 F10 +G01 X1.4785 Y1.2609 F20 +G01 X1.4559 Y1.2835 +G01 X1.4241 Y1.2835 +G01 X1.4015 Y1.2609 +G01 X1.4015 Y1.2291 +G01 X1.4241 Y1.2065 +G01 X1.4559 Y1.2065 +G01 X1.4785 Y1.2291 +G00 Z0.1000 +G00 X0.8406 Y0.6013 +G01 Z-0.0070 F10 +G01 X0.8406 Y0.6786 F20 +G01 X0.8348 Y0.6928 +G01 X0.8239 Y0.7036 +G01 X0.8098 Y0.7094 +G01 X0.7945 Y0.7094 +G01 X0.7803 Y0.7036 +G01 X0.7695 Y0.6928 +G01 X0.7636 Y0.6786 +G01 X0.7636 Y0.6013 +G01 X0.7695 Y0.5871 +G01 X0.7803 Y0.5763 +G01 X0.7945 Y0.5704 +G01 X0.8098 Y0.5704 +G01 X0.8239 Y0.5763 +G01 X0.8348 Y0.5871 +G01 X0.8406 Y0.6013 +G00 Z0.1000 +G00 X0.8030 Y0.8587 +G01 Z-0.0070 F10 +G01 X0.8030 Y0.7814 F20 +G01 X0.8089 Y0.7672 +G01 X0.8197 Y0.7564 +G01 X0.8338 Y0.7506 +G01 X0.8492 Y0.7506 +G01 X0.8633 Y0.7564 +G01 X0.8741 Y0.7672 +G01 X0.8800 Y0.7814 +G01 X0.8800 Y0.8587 +G01 X0.8741 Y0.8729 +G01 X0.8633 Y0.8837 +G01 X0.8492 Y0.8896 +G01 X0.8338 Y0.8896 +G01 X0.8197 Y0.8837 +G01 X0.8089 Y0.8729 +G01 X0.8030 Y0.8587 +G00 Z0.1000 +G00 X0.7619 Y0.6013 +G01 Z-0.0070 F10 +G01 X0.7619 Y0.6786 F20 +G01 X0.7560 Y0.6928 +G01 X0.7452 Y0.7036 +G01 X0.7310 Y0.7094 +G01 X0.7157 Y0.7094 +G01 X0.7016 Y0.7036 +G01 X0.6907 Y0.6928 +G01 X0.6849 Y0.6786 +G01 X0.6849 Y0.6013 +G01 X0.6907 Y0.5871 +G01 X0.7016 Y0.5763 +G01 X0.7157 Y0.5704 +G01 X0.7310 Y0.5704 +G01 X0.7452 Y0.5763 +G01 X0.7560 Y0.5871 +G01 X0.7619 Y0.6013 +G00 Z0.1000 +G00 X0.9194 Y0.6013 +G01 Z-0.0070 F10 +G01 X0.9194 Y0.6786 F20 +G01 X0.9135 Y0.6928 +G01 X0.9027 Y0.7036 +G01 X0.8885 Y0.7094 +G01 X0.8732 Y0.7094 +G01 X0.8591 Y0.7036 +G01 X0.8482 Y0.6928 +G01 X0.8424 Y0.6786 +G01 X0.8424 Y0.6013 +G01 X0.8482 Y0.5871 +G01 X0.8591 Y0.5763 +G01 X0.8732 Y0.5704 +G01 X0.8885 Y0.5704 +G01 X0.9027 Y0.5763 +G01 X0.9135 Y0.5871 +G01 X0.9194 Y0.6013 +G00 Z0.1000 +G00 X0.8817 Y0.8587 +G01 Z-0.0070 F10 +G01 X0.8817 Y0.7814 F20 +G01 X0.8876 Y0.7672 +G01 X0.8984 Y0.7564 +G01 X0.9126 Y0.7506 +G01 X0.9279 Y0.7506 +G01 X0.9420 Y0.7564 +G01 X0.9529 Y0.7672 +G01 X0.9587 Y0.7814 +G01 X0.9587 Y0.8587 +G01 X0.9529 Y0.8729 +G01 X0.9420 Y0.8837 +G01 X0.9279 Y0.8896 +G01 X0.9126 Y0.8896 +G01 X0.8984 Y0.8837 +G01 X0.8876 Y0.8729 +G01 X0.8817 Y0.8587 +G00 Z0.1000 +G00 X0.7243 Y0.8587 +G01 Z-0.0070 F10 +G01 X0.7243 Y0.7814 F20 +G01 X0.7301 Y0.7672 +G01 X0.7409 Y0.7564 +G01 X0.7551 Y0.7506 +G01 X0.7704 Y0.7506 +G01 X0.7846 Y0.7564 +G01 X0.7954 Y0.7672 +G01 X0.8013 Y0.7814 +G01 X0.8013 Y0.8587 +G01 X0.7954 Y0.8729 +G01 X0.7846 Y0.8837 +G01 X0.7704 Y0.8896 +G01 X0.7551 Y0.8896 +G01 X0.7409 Y0.8837 +G01 X0.7301 Y0.8729 +G01 X0.7243 Y0.8587 +G00 Z0.1000 +G00 X1.5313 Y0.3015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.3015 F20 +G01 X1.6228 Y0.3074 +G01 X1.6336 Y0.3182 +G01 X1.6395 Y0.3323 +G01 X1.6395 Y0.3477 +G01 X1.6336 Y0.3618 +G01 X1.6228 Y0.3726 +G01 X1.6087 Y0.3785 +G01 X1.5313 Y0.3785 +G01 X1.5172 Y0.3726 +G01 X1.5064 Y0.3618 +G01 X1.5005 Y0.3477 +G01 X1.5005 Y0.3323 +G01 X1.5064 Y0.3182 +G01 X1.5172 Y0.3074 +G01 X1.5313 Y0.3015 +G00 Z0.1000 +G00 X1.5313 Y0.4015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.4015 F20 +G01 X1.6228 Y0.4074 +G01 X1.6336 Y0.4182 +G01 X1.6395 Y0.4323 +G01 X1.6395 Y0.4477 +G01 X1.6336 Y0.4618 +G01 X1.6228 Y0.4726 +G01 X1.6087 Y0.4785 +G01 X1.5313 Y0.4785 +G01 X1.5172 Y0.4726 +G01 X1.5064 Y0.4618 +G01 X1.5005 Y0.4477 +G01 X1.5005 Y0.4323 +G01 X1.5064 Y0.4182 +G01 X1.5172 Y0.4074 +G01 X1.5313 Y0.4015 +G00 Z0.1000 +G00 X1.5313 Y0.5015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.5015 F20 +G01 X1.6228 Y0.5074 +G01 X1.6336 Y0.5182 +G01 X1.6395 Y0.5323 +G01 X1.6395 Y0.5477 +G01 X1.6336 Y0.5618 +G01 X1.6228 Y0.5726 +G01 X1.6087 Y0.5785 +G01 X1.5313 Y0.5785 +G01 X1.5172 Y0.5726 +G01 X1.5064 Y0.5618 +G01 X1.5005 Y0.5477 +G01 X1.5005 Y0.5323 +G01 X1.5064 Y0.5182 +G01 X1.5172 Y0.5074 +G01 X1.5313 Y0.5015 +G00 Z0.1000 +G00 X1.5313 Y0.6015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.6015 F20 +G01 X1.6228 Y0.6074 +G01 X1.6336 Y0.6182 +G01 X1.6395 Y0.6323 +G01 X1.6395 Y0.6477 +G01 X1.6336 Y0.6618 +G01 X1.6228 Y0.6726 +G01 X1.6087 Y0.6785 +G01 X1.5313 Y0.6785 +G01 X1.5172 Y0.6726 +G01 X1.5064 Y0.6618 +G01 X1.5005 Y0.6477 +G01 X1.5005 Y0.6323 +G01 X1.5064 Y0.6182 +G01 X1.5172 Y0.6074 +G01 X1.5313 Y0.6015 +G00 Z0.1000 +G00 X1.5313 Y0.7015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.7015 F20 +G01 X1.6228 Y0.7074 +G01 X1.6336 Y0.7182 +G01 X1.6395 Y0.7323 +G01 X1.6395 Y0.7477 +G01 X1.6336 Y0.7618 +G01 X1.6228 Y0.7726 +G01 X1.6087 Y0.7785 +G01 X1.5313 Y0.7785 +G01 X1.5172 Y0.7726 +G01 X1.5064 Y0.7618 +G01 X1.5005 Y0.7477 +G01 X1.5005 Y0.7323 +G01 X1.5064 Y0.7182 +G01 X1.5172 Y0.7074 +G01 X1.5313 Y0.7015 +G00 Z0.1000 +G00 X1.5313 Y0.8015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.8015 F20 +G01 X1.6228 Y0.8074 +G01 X1.6336 Y0.8182 +G01 X1.6395 Y0.8323 +G01 X1.6395 Y0.8477 +G01 X1.6336 Y0.8618 +G01 X1.6228 Y0.8726 +G01 X1.6087 Y0.8785 +G01 X1.5313 Y0.8785 +G01 X1.5172 Y0.8726 +G01 X1.5064 Y0.8618 +G01 X1.5005 Y0.8477 +G01 X1.5005 Y0.8323 +G01 X1.5064 Y0.8182 +G01 X1.5172 Y0.8074 +G01 X1.5313 Y0.8015 +G00 Z0.1000 +G00 X1.5313 Y0.9015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.9015 F20 +G01 X1.6228 Y0.9074 +G01 X1.6336 Y0.9182 +G01 X1.6395 Y0.9323 +G01 X1.6395 Y0.9477 +G01 X1.6336 Y0.9618 +G01 X1.6228 Y0.9726 +G01 X1.6087 Y0.9785 +G01 X1.5313 Y0.9785 +G01 X1.5172 Y0.9726 +G01 X1.5064 Y0.9618 +G01 X1.5005 Y0.9477 +G01 X1.5005 Y0.9323 +G01 X1.5064 Y0.9182 +G01 X1.5172 Y0.9074 +G01 X1.5313 Y0.9015 +G00 Z0.1000 +G00 X1.5313 Y1.0015 +G01 Z-0.0070 F10 +G01 X1.6087 Y1.0015 F20 +G01 X1.6228 Y1.0074 +G01 X1.6336 Y1.0182 +G01 X1.6395 Y1.0323 +G01 X1.6395 Y1.0477 +G01 X1.6336 Y1.0618 +G01 X1.6228 Y1.0726 +G01 X1.6087 Y1.0785 +G01 X1.5313 Y1.0785 +G01 X1.5172 Y1.0726 +G01 X1.5064 Y1.0618 +G01 X1.5005 Y1.0477 +G01 X1.5005 Y1.0323 +G01 X1.5064 Y1.0182 +G01 X1.5172 Y1.0074 +G01 X1.5313 Y1.0015 +G00 Z0.1000 +G00 X1.2313 Y1.0015 +G01 Z-0.0070 F10 +G01 X1.3087 Y1.0015 F20 +G01 X1.3228 Y1.0074 +G01 X1.3336 Y1.0182 +G01 X1.3395 Y1.0323 +G01 X1.3395 Y1.0477 +G01 X1.3336 Y1.0618 +G01 X1.3228 Y1.0726 +G01 X1.3087 Y1.0785 +G01 X1.2313 Y1.0785 +G01 X1.2172 Y1.0726 +G01 X1.2064 Y1.0618 +G01 X1.2005 Y1.0477 +G01 X1.2005 Y1.0323 +G01 X1.2064 Y1.0182 +G01 X1.2172 Y1.0074 +G01 X1.2313 Y1.0015 +G00 Z0.1000 +G00 X1.2313 Y0.9015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.9015 F20 +G01 X1.3228 Y0.9074 +G01 X1.3336 Y0.9182 +G01 X1.3395 Y0.9323 +G01 X1.3395 Y0.9477 +G01 X1.3336 Y0.9618 +G01 X1.3228 Y0.9726 +G01 X1.3087 Y0.9785 +G01 X1.2313 Y0.9785 +G01 X1.2172 Y0.9726 +G01 X1.2064 Y0.9618 +G01 X1.2005 Y0.9477 +G01 X1.2005 Y0.9323 +G01 X1.2064 Y0.9182 +G01 X1.2172 Y0.9074 +G01 X1.2313 Y0.9015 +G00 Z0.1000 +G00 X1.2313 Y0.8015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.8015 F20 +G01 X1.3228 Y0.8074 +G01 X1.3336 Y0.8182 +G01 X1.3395 Y0.8323 +G01 X1.3395 Y0.8477 +G01 X1.3336 Y0.8618 +G01 X1.3228 Y0.8726 +G01 X1.3087 Y0.8785 +G01 X1.2313 Y0.8785 +G01 X1.2172 Y0.8726 +G01 X1.2064 Y0.8618 +G01 X1.2005 Y0.8477 +G01 X1.2005 Y0.8323 +G01 X1.2064 Y0.8182 +G01 X1.2172 Y0.8074 +G01 X1.2313 Y0.8015 +G00 Z0.1000 +G00 X1.2313 Y0.7015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.7015 F20 +G01 X1.3228 Y0.7074 +G01 X1.3336 Y0.7182 +G01 X1.3395 Y0.7323 +G01 X1.3395 Y0.7477 +G01 X1.3336 Y0.7618 +G01 X1.3228 Y0.7726 +G01 X1.3087 Y0.7785 +G01 X1.2313 Y0.7785 +G01 X1.2172 Y0.7726 +G01 X1.2064 Y0.7618 +G01 X1.2005 Y0.7477 +G01 X1.2005 Y0.7323 +G01 X1.2064 Y0.7182 +G01 X1.2172 Y0.7074 +G01 X1.2313 Y0.7015 +G00 Z0.1000 +G00 X1.2313 Y0.6015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.6015 F20 +G01 X1.3228 Y0.6074 +G01 X1.3336 Y0.6182 +G01 X1.3395 Y0.6323 +G01 X1.3395 Y0.6477 +G01 X1.3336 Y0.6618 +G01 X1.3228 Y0.6726 +G01 X1.3087 Y0.6785 +G01 X1.2313 Y0.6785 +G01 X1.2172 Y0.6726 +G01 X1.2064 Y0.6618 +G01 X1.2005 Y0.6477 +G01 X1.2005 Y0.6323 +G01 X1.2064 Y0.6182 +G01 X1.2172 Y0.6074 +G01 X1.2313 Y0.6015 +G00 Z0.1000 +G00 X1.2313 Y0.5015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.5015 F20 +G01 X1.3228 Y0.5074 +G01 X1.3336 Y0.5182 +G01 X1.3395 Y0.5323 +G01 X1.3395 Y0.5477 +G01 X1.3336 Y0.5618 +G01 X1.3228 Y0.5726 +G01 X1.3087 Y0.5785 +G01 X1.2313 Y0.5785 +G01 X1.2172 Y0.5726 +G01 X1.2064 Y0.5618 +G01 X1.2005 Y0.5477 +G01 X1.2005 Y0.5323 +G01 X1.2064 Y0.5182 +G01 X1.2172 Y0.5074 +G01 X1.2313 Y0.5015 +G00 Z0.1000 +G00 X1.2313 Y0.4015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.4015 F20 +G01 X1.3228 Y0.4074 +G01 X1.3336 Y0.4182 +G01 X1.3395 Y0.4323 +G01 X1.3395 Y0.4477 +G01 X1.3336 Y0.4618 +G01 X1.3228 Y0.4726 +G01 X1.3087 Y0.4785 +G01 X1.2313 Y0.4785 +G01 X1.2172 Y0.4726 +G01 X1.2064 Y0.4618 +G01 X1.2005 Y0.4477 +G01 X1.2005 Y0.4323 +G01 X1.2064 Y0.4182 +G01 X1.2172 Y0.4074 +G01 X1.2313 Y0.4015 +G00 Z0.1000 +G00 X1.2313 Y0.3015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.3015 F20 +G01 X1.3228 Y0.3074 +G01 X1.3336 Y0.3182 +G01 X1.3395 Y0.3323 +G01 X1.3395 Y0.3477 +G01 X1.3336 Y0.3618 +G01 X1.3228 Y0.3726 +G01 X1.3087 Y0.3785 +G01 X1.2313 Y0.3785 +G01 X1.2172 Y0.3726 +G01 X1.2064 Y0.3618 +G01 X1.2005 Y0.3477 +G01 X1.2005 Y0.3323 +G01 X1.2064 Y0.3182 +G01 X1.2172 Y0.3074 +G01 X1.2313 Y0.3015 +G00 Z0.1000 +G00 X0.3325 Y0.9824 +G01 Z-0.0070 F10 +G01 X0.3325 Y1.0176 F20 +G01 X0.3076 Y1.0425 +G01 X0.2724 Y1.0425 +G01 X0.2475 Y1.0176 +G01 X0.2475 Y0.9824 +G01 X0.2724 Y0.9575 +G01 X0.3076 Y0.9575 +G01 X0.3325 Y0.9824 +G00 Z0.1000 +G00 X0.3325 Y0.8824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.9176 F20 +G01 X0.3076 Y0.9425 +G01 X0.2724 Y0.9425 +G01 X0.2475 Y0.9176 +G01 X0.2475 Y0.8824 +G01 X0.2724 Y0.8575 +G01 X0.3076 Y0.8575 +G01 X0.3325 Y0.8824 +G00 Z0.1000 +G00 X0.3325 Y0.7824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.8176 F20 +G01 X0.3076 Y0.8425 +G01 X0.2724 Y0.8425 +G01 X0.2475 Y0.8176 +G01 X0.2475 Y0.7824 +G01 X0.2724 Y0.7575 +G01 X0.3076 Y0.7575 +G01 X0.3325 Y0.7824 +G00 Z0.1000 +G00 X0.3325 Y0.6824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.7176 F20 +G01 X0.3076 Y0.7425 +G01 X0.2724 Y0.7425 +G01 X0.2475 Y0.7176 +G01 X0.2475 Y0.6824 +G01 X0.2724 Y0.6575 +G01 X0.3076 Y0.6575 +G01 X0.3325 Y0.6824 +G00 Z0.1000 +G00 X0.3325 Y0.5824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.6176 F20 +G01 X0.3076 Y0.6425 +G01 X0.2724 Y0.6425 +G01 X0.2475 Y0.6176 +G01 X0.2475 Y0.5824 +G01 X0.2724 Y0.5575 +G01 X0.3076 Y0.5575 +G01 X0.3325 Y0.5824 +G00 Z0.1000 +G00 X0.3325 Y0.4824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.5176 F20 +G01 X0.3076 Y0.5425 +G01 X0.2724 Y0.5425 +G01 X0.2475 Y0.5176 +G01 X0.2475 Y0.4824 +G01 X0.2724 Y0.4575 +G01 X0.3076 Y0.4575 +G01 X0.3325 Y0.4824 +G00 Z0.1000 +G00 X0.2325 Y0.9824 +G01 Z-0.0070 F10 +G01 X0.2325 Y1.0176 F20 +G01 X0.2076 Y1.0425 +G01 X0.1724 Y1.0425 +G01 X0.1475 Y1.0176 +G01 X0.1475 Y0.9824 +G01 X0.1724 Y0.9575 +G01 X0.2076 Y0.9575 +G01 X0.2325 Y0.9824 +G00 Z0.1000 +G00 X0.2325 Y0.8824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.9176 F20 +G01 X0.2076 Y0.9425 +G01 X0.1724 Y0.9425 +G01 X0.1475 Y0.9176 +G01 X0.1475 Y0.8824 +G01 X0.1724 Y0.8575 +G01 X0.2076 Y0.8575 +G01 X0.2325 Y0.8824 +G00 Z0.1000 +G00 X0.2325 Y0.7824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.8176 F20 +G01 X0.2076 Y0.8425 +G01 X0.1724 Y0.8425 +G01 X0.1475 Y0.8176 +G01 X0.1475 Y0.7824 +G01 X0.1724 Y0.7575 +G01 X0.2076 Y0.7575 +G01 X0.2325 Y0.7824 +G00 Z0.1000 +G00 X0.2325 Y0.6824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.7176 F20 +G01 X0.2076 Y0.7425 +G01 X0.1724 Y0.7425 +G01 X0.1475 Y0.7176 +G01 X0.1475 Y0.6824 +G01 X0.1724 Y0.6575 +G01 X0.2076 Y0.6575 +G01 X0.2325 Y0.6824 +G00 Z0.1000 +G00 X0.2325 Y0.5824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.6176 F20 +G01 X0.2076 Y0.6425 +G01 X0.1724 Y0.6425 +G01 X0.1475 Y0.6176 +G01 X0.1475 Y0.5824 +G01 X0.1724 Y0.5575 +G01 X0.2076 Y0.5575 +G01 X0.2325 Y0.5824 +G00 Z0.1000 +G00 X0.2325 Y0.4824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.5176 F20 +G01 X0.2076 Y0.5425 +G01 X0.1724 Y0.5425 +G01 X0.1475 Y0.5176 +G01 X0.1475 Y0.4824 +G01 X0.1724 Y0.4575 +G01 X0.2076 Y0.4575 +G01 X0.2325 Y0.4824 +G00 Z0.1000 +G00 X0.3325 Y0.3824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.4176 F20 +G01 X0.3076 Y0.4425 +G01 X0.2724 Y0.4425 +G01 X0.2475 Y0.4176 +G01 X0.2475 Y0.3824 +G01 X0.2724 Y0.3575 +G01 X0.3076 Y0.3575 +G01 X0.3325 Y0.3824 +G00 Z0.1000 +G00 X0.2325 Y0.3824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.4176 F20 +G01 X0.2076 Y0.4425 +G01 X0.1724 Y0.4425 +G01 X0.1475 Y0.4176 +G01 X0.1475 Y0.3824 +G01 X0.1724 Y0.3575 +G01 X0.2076 Y0.3575 +G01 X0.2325 Y0.3824 +G00 Z0.1000 +G00 X0.8387 Y0.4085 +G01 Z-0.0070 F10 +G01 X0.7613 Y0.4085 F20 +G01 X0.7472 Y0.4026 +G01 X0.7364 Y0.3918 +G01 X0.7305 Y0.3777 +G01 X0.7305 Y0.3623 +G01 X0.7364 Y0.3482 +G01 X0.7472 Y0.3374 +G01 X0.7613 Y0.3315 +G01 X0.8387 Y0.3315 +G01 X0.8528 Y0.3374 +G01 X0.8636 Y0.3482 +G01 X0.8695 Y0.3623 +G01 X0.8695 Y0.3777 +G01 X0.8636 Y0.3918 +G01 X0.8528 Y0.4026 +G01 X0.8387 Y0.4085 +G00 Z0.1000 +G00 X1.1387 Y0.3085 +G01 Z-0.0070 F10 +G01 X1.0613 Y0.3085 F20 +G01 X1.0472 Y0.3026 +G01 X1.0364 Y0.2918 +G01 X1.0305 Y0.2777 +G01 X1.0305 Y0.2623 +G01 X1.0364 Y0.2482 +G01 X1.0472 Y0.2374 +G01 X1.0613 Y0.2315 +G01 X1.1387 Y0.2315 +G01 X1.1528 Y0.2374 +G01 X1.1636 Y0.2482 +G01 X1.1695 Y0.2623 +G01 X1.1695 Y0.2777 +G01 X1.1636 Y0.2918 +G01 X1.1528 Y0.3026 +G01 X1.1387 Y0.3085 +G00 Z0.1000 +G00 X0.6387 Y0.3085 +G01 Z-0.0070 F10 +G01 X0.5613 Y0.3085 F20 +G01 X0.5472 Y0.3026 +G01 X0.5364 Y0.2918 +G01 X0.5305 Y0.2777 +G01 X0.5305 Y0.2623 +G01 X0.5364 Y0.2482 +G01 X0.5472 Y0.2374 +G01 X0.5613 Y0.2315 +G01 X0.6387 Y0.2315 +G01 X0.6528 Y0.2374 +G01 X0.6636 Y0.2482 +G01 X0.6695 Y0.2623 +G01 X0.6695 Y0.2777 +G01 X0.6636 Y0.2918 +G01 X0.6528 Y0.3026 +G01 X0.6387 Y0.3085 +G00 Z0.1000 +G00 X2.1113 Y0.1115 +G01 Z-0.0070 F10 +G01 X2.1887 Y0.1115 F20 +G01 X2.2028 Y0.1174 +G01 X2.2136 Y0.1282 +G01 X2.2195 Y0.1423 +G01 X2.2195 Y0.1577 +G01 X2.2136 Y0.1718 +G01 X2.2028 Y0.1826 +G01 X2.1887 Y0.1885 +G01 X2.1113 Y0.1885 +G01 X2.0972 Y0.1826 +G01 X2.0864 Y0.1718 +G01 X2.0805 Y0.1577 +G01 X2.0805 Y0.1423 +G01 X2.0864 Y0.1282 +G01 X2.0972 Y0.1174 +G01 X2.1113 Y0.1115 +G00 Z0.1000 +G00 X2.1113 Y0.2115 +G01 Z-0.0070 F10 +G01 X2.1887 Y0.2115 F20 +G01 X2.2028 Y0.2174 +G01 X2.2136 Y0.2282 +G01 X2.2195 Y0.2423 +G01 X2.2195 Y0.2577 +G01 X2.2136 Y0.2718 +G01 X2.2028 Y0.2826 +G01 X2.1887 Y0.2885 +G01 X2.1113 Y0.2885 +G01 X2.0972 Y0.2826 +G01 X2.0864 Y0.2718 +G01 X2.0805 Y0.2577 +G01 X2.0805 Y0.2423 +G01 X2.0864 Y0.2282 +G01 X2.0972 Y0.2174 +G01 X2.1113 Y0.2115 +G00 Z0.1000 +G00 X2.1113 Y0.3115 +G01 Z-0.0070 F10 +G01 X2.1887 Y0.3115 F20 +G01 X2.2028 Y0.3174 +G01 X2.2136 Y0.3282 +G01 X2.2195 Y0.3423 +G01 X2.2195 Y0.3577 +G01 X2.2136 Y0.3718 +G01 X2.2028 Y0.3826 +G01 X2.1887 Y0.3885 +G01 X2.1113 Y0.3885 +G01 X2.0972 Y0.3826 +G01 X2.0864 Y0.3718 +G01 X2.0805 Y0.3577 +G01 X2.0805 Y0.3423 +G01 X2.0864 Y0.3282 +G01 X2.0972 Y0.3174 +G01 X2.1113 Y0.3115 +G00 Z0.1000 +G00 X1.8113 Y0.3115 +G01 Z-0.0070 F10 +G01 X1.8887 Y0.3115 F20 +G01 X1.9028 Y0.3174 +G01 X1.9136 Y0.3282 +G01 X1.9195 Y0.3423 +G01 X1.9195 Y0.3577 +G01 X1.9136 Y0.3718 +G01 X1.9028 Y0.3826 +G01 X1.8887 Y0.3885 +G01 X1.8113 Y0.3885 +G01 X1.7972 Y0.3826 +G01 X1.7864 Y0.3718 +G01 X1.7805 Y0.3577 +G01 X1.7805 Y0.3423 +G01 X1.7864 Y0.3282 +G01 X1.7972 Y0.3174 +G01 X1.8113 Y0.3115 +G00 Z0.1000 +G00 X1.8113 Y0.2115 +G01 Z-0.0070 F10 +G01 X1.8887 Y0.2115 F20 +G01 X1.9028 Y0.2174 +G01 X1.9136 Y0.2282 +G01 X1.9195 Y0.2423 +G01 X1.9195 Y0.2577 +G01 X1.9136 Y0.2718 +G01 X1.9028 Y0.2826 +G01 X1.8887 Y0.2885 +G01 X1.8113 Y0.2885 +G01 X1.7972 Y0.2826 +G01 X1.7864 Y0.2718 +G01 X1.7805 Y0.2577 +G01 X1.7805 Y0.2423 +G01 X1.7864 Y0.2282 +G01 X1.7972 Y0.2174 +G01 X1.8113 Y0.2115 +G00 Z0.1000 +G00 X1.8113 Y0.1115 +G01 Z-0.0070 F10 +G01 X1.8887 Y0.1115 F20 +G01 X1.9028 Y0.1174 +G01 X1.9136 Y0.1282 +G01 X1.9195 Y0.1423 +G01 X1.9195 Y0.1577 +G01 X1.9136 Y0.1718 +G01 X1.9028 Y0.1826 +G01 X1.8887 Y0.1885 +G01 X1.8113 Y0.1885 +G01 X1.7972 Y0.1826 +G01 X1.7864 Y0.1718 +G01 X1.7805 Y0.1577 +G01 X1.7805 Y0.1423 +G01 X1.7864 Y0.1282 +G01 X1.7972 Y0.1174 +G01 X1.8113 Y0.1115 +G00 Z0.1000 +G00 X1.8385 Y0.6641 +G01 Z-0.0070 F10 +G01 X1.8385 Y0.6959 F20 +G01 X1.8159 Y0.7185 +G01 X1.7841 Y0.7185 +G01 X1.7615 Y0.6959 +G01 X1.7615 Y0.6641 +G01 X1.7841 Y0.6415 +G01 X1.8159 Y0.6415 +G01 X1.8385 Y0.6641 +G00 Z0.1000 +G00 X1.8385 Y0.4641 +G01 Z-0.0070 F10 +G01 X1.8385 Y0.4959 F20 +G01 X1.8159 Y0.5185 +G01 X1.7841 Y0.5185 +G01 X1.7615 Y0.4959 +G01 X1.7615 Y0.4641 +G01 X1.7841 Y0.4415 +G01 X1.8159 Y0.4415 +G01 X1.8385 Y0.4641 +G00 Z0.1000 +G00 X1.9585 Y0.6641 +G01 Z-0.0070 F10 +G01 X1.9585 Y0.6959 F20 +G01 X1.9359 Y0.7185 +G01 X1.9041 Y0.7185 +G01 X1.8815 Y0.6959 +G01 X1.8815 Y0.6641 +G01 X1.9041 Y0.6415 +G01 X1.9359 Y0.6415 +G01 X1.9585 Y0.6641 +G00 Z0.1000 +G00 X1.9585 Y0.4641 +G01 Z-0.0070 F10 +G01 X1.9585 Y0.4959 F20 +G01 X1.9359 Y0.5185 +G01 X1.9041 Y0.5185 +G01 X1.8815 Y0.4959 +G01 X1.8815 Y0.4641 +G01 X1.9041 Y0.4415 +G01 X1.9359 Y0.4415 +G01 X1.9585 Y0.4641 +G00 Z0.1000 +G00 X2.0785 Y0.6641 +G01 Z-0.0070 F10 +G01 X2.0785 Y0.6959 F20 +G01 X2.0559 Y0.7185 +G01 X2.0241 Y0.7185 +G01 X2.0015 Y0.6959 +G01 X2.0015 Y0.6641 +G01 X2.0241 Y0.6415 +G01 X2.0559 Y0.6415 +G01 X2.0785 Y0.6641 +G00 Z0.1000 +G00 X2.0785 Y0.4641 +G01 Z-0.0070 F10 +G01 X2.0785 Y0.4959 F20 +G01 X2.0559 Y0.5185 +G01 X2.0241 Y0.5185 +G01 X2.0015 Y0.4959 +G01 X2.0015 Y0.4641 +G01 X2.0241 Y0.4415 +G01 X2.0559 Y0.4415 +G01 X2.0785 Y0.4641 +G00 Z0.1000 +G00 X1.3085 Y0.2141 +G01 Z-0.0070 F10 +G01 X1.3085 Y0.2459 F20 +G01 X1.2859 Y0.2685 +G01 X1.2541 Y0.2685 +G01 X1.2315 Y0.2459 +G01 X1.2315 Y0.2141 +G01 X1.2541 Y0.1915 +G01 X1.2859 Y0.1915 +G01 X1.3085 Y0.2141 +G00 Z0.1000 +G00 X1.4085 Y0.2141 +G01 Z-0.0070 F10 +G01 X1.4085 Y0.2459 F20 +G01 X1.3859 Y0.2685 +G01 X1.3541 Y0.2685 +G01 X1.3315 Y0.2459 +G01 X1.3315 Y0.2141 +G01 X1.3541 Y0.1915 +G01 X1.3859 Y0.1915 +G01 X1.4085 Y0.2141 +G00 Z0.1000 +G00 X2.3575 Y1.0062 +G01 Z-0.0070 F10 +G01 X2.3575 Y1.0538 F20 +G01 X2.3238 Y1.0875 +G01 X2.2762 Y1.0875 +G01 X2.2425 Y1.0538 +G01 X2.2425 Y1.0062 +G01 X2.2762 Y0.9725 +G01 X2.3238 Y0.9725 +G01 X2.3575 Y1.0062 +G00 Z0.1000 +G00 X2.0575 Y1.0062 +G01 Z-0.0070 F10 +G01 X2.0575 Y1.0538 F20 +G01 X2.0238 Y1.0875 +G01 X1.9762 Y1.0875 +G01 X1.9425 Y1.0538 +G01 X1.9425 Y1.0062 +G01 X1.9762 Y0.9725 +G01 X2.0238 Y0.9725 +G01 X2.0575 Y1.0062 +G00 Z0.1000 +G00 X0.5485 Y0.9841 +G01 Z-0.0070 F10 +G01 X0.5485 Y1.0159 F20 +G01 X0.5259 Y1.0385 +G01 X0.4941 Y1.0385 +G01 X0.4715 Y1.0159 +G01 X0.4715 Y0.9841 +G01 X0.4941 Y0.9615 +G01 X0.5259 Y0.9615 +G01 X0.5485 Y0.9841 +G00 Z0.1000 +G00 X0.4485 Y0.9841 +G01 Z-0.0070 F10 +G01 X0.4485 Y1.0159 F20 +G01 X0.4259 Y1.0385 +G01 X0.3941 Y1.0385 +G01 X0.3715 Y1.0159 +G01 X0.3715 Y0.9841 +G01 X0.3941 Y0.9615 +G01 X0.4259 Y0.9615 +G01 X0.4485 Y0.9841 +G00 Z0.1000 +G00 X1.4285 Y1.1541 +G01 Z-0.0070 F10 +G01 X1.4285 Y1.1859 F20 +G01 X1.4059 Y1.2085 +G01 X1.3741 Y1.2085 +G01 X1.3515 Y1.1859 +G01 X1.3515 Y1.1541 +G01 X1.3741 Y1.1315 +G01 X1.4059 Y1.1315 +G01 X1.4285 Y1.1541 +G00 Z0.1000 +G00 X1.5285 Y1.1541 +G01 Z-0.0070 F10 +G01 X1.5285 Y1.1859 F20 +G01 X1.5059 Y1.2085 +G01 X1.4741 Y1.2085 +G01 X1.4515 Y1.1859 +G01 X1.4515 Y1.1541 +G01 X1.4741 Y1.1315 +G01 X1.5059 Y1.1315 +G01 X1.5285 Y1.1541 +G00 Z0.1000 +G00 X1.1728 Y1.2086 +G01 Z-0.0070 F10 +G01 X1.1586 Y1.2228 F20 +G01 X1.1400 Y1.2305 +G01 X1.1200 Y1.2305 +G01 X1.1014 Y1.2228 +G01 X1.0872 Y1.2086 +G01 X1.0795 Y1.1900 +G01 X1.0795 Y1.1700 +G01 X1.0872 Y1.1514 +G01 X1.1014 Y1.1372 +G01 X1.1200 Y1.1295 +G01 X1.1400 Y1.1295 +G01 X1.1586 Y1.1372 +G01 X1.1728 Y1.1514 +G01 X1.1795 Y1.1676 +G01 X1.1795 Y1.1591 +G01 X1.2091 Y1.1295 +G01 X1.2509 Y1.1295 +G01 X1.2805 Y1.1591 +G01 X1.2805 Y1.2009 +G01 X1.2509 Y1.2305 +G01 X1.2091 Y1.2305 +G01 X1.1795 Y1.2009 +G01 X1.1795 Y1.1924 +G01 X1.1728 Y1.2086 +G00 Z0.1000 +G00 X1.8055 Y1.2090 +G01 Z-0.0070 F10 +G01 X1.8055 Y1.2310 F20 +G01 X1.7970 Y1.2514 +G01 X1.7814 Y1.2670 +G01 X1.7610 Y1.2755 +G01 X1.7390 Y1.2755 +G01 X1.7186 Y1.2670 +G01 X1.7029 Y1.2514 +G01 X1.6945 Y1.2310 +G01 X1.6945 Y1.2090 +G01 X1.7029 Y1.1886 +G01 X1.7186 Y1.1729 +G01 X1.7227 Y1.1712 +G01 X1.6945 Y1.1430 +G01 X1.6945 Y1.0970 +G01 X1.7270 Y1.0645 +G01 X1.7730 Y1.0645 +G01 X1.8055 Y1.0970 +G01 X1.8055 Y1.1430 +G01 X1.7773 Y1.1712 +G01 X1.7814 Y1.1729 +G01 X1.7970 Y1.1886 +G01 X1.8055 Y1.2090 +G00 Z0.1000 +G00 X1.4835 Y1.2270 +G01 Z-0.0070 F10 +G01 X1.4835 Y1.2630 F20 +G01 X1.4580 Y1.2885 +G01 X1.4220 Y1.2885 +G01 X1.3965 Y1.2630 +G01 X1.3965 Y1.2270 +G01 X1.4220 Y1.2015 +G01 X1.4580 Y1.2015 +G01 X1.4835 Y1.2270 +G00 Z0.1000 +G00 X0.8390 Y0.6956 +G01 Z-0.0070 F10 +G01 X0.8268 Y0.7078 F20 +G01 X0.8108 Y0.7144 +G01 X0.7935 Y0.7144 +G01 X0.7775 Y0.7078 +G01 X0.7652 Y0.6956 +G01 X0.7628 Y0.6896 +G01 X0.7603 Y0.6956 +G01 X0.7480 Y0.7078 +G01 X0.7320 Y0.7144 +G01 X0.7147 Y0.7144 +G01 X0.6987 Y0.7078 +G01 X0.6865 Y0.6956 +G01 X0.6799 Y0.6796 +G01 X0.6799 Y0.6003 +G01 X0.6865 Y0.5843 +G01 X0.6987 Y0.5721 +G01 X0.7147 Y0.5654 +G01 X0.7320 Y0.5654 +G01 X0.7480 Y0.5721 +G01 X0.7603 Y0.5843 +G01 X0.7628 Y0.5903 +G01 X0.7652 Y0.5843 +G01 X0.7775 Y0.5721 +G01 X0.7935 Y0.5654 +G01 X0.8108 Y0.5654 +G01 X0.8268 Y0.5721 +G01 X0.8390 Y0.5843 +G01 X0.8415 Y0.5903 +G01 X0.8440 Y0.5843 +G01 X0.8562 Y0.5721 +G01 X0.8722 Y0.5654 +G01 X0.8895 Y0.5654 +G01 X0.9055 Y0.5721 +G01 X0.9177 Y0.5843 +G01 X0.9244 Y0.6003 +G01 X0.9244 Y0.6796 +G01 X0.9177 Y0.6956 +G01 X0.9055 Y0.7078 +G01 X0.8895 Y0.7144 +G01 X0.8722 Y0.7144 +G01 X0.8562 Y0.7078 +G01 X0.8440 Y0.6956 +G01 X0.8415 Y0.6896 +G01 X0.8390 Y0.6956 +G00 Z0.1000 +G00 X0.8046 Y0.7644 +G01 Z-0.0070 F10 +G01 X0.8169 Y0.7522 F20 +G01 X0.8328 Y0.7456 +G01 X0.8501 Y0.7456 +G01 X0.8661 Y0.7522 +G01 X0.8784 Y0.7644 +G01 X0.8809 Y0.7704 +G01 X0.8834 Y0.7644 +G01 X0.8956 Y0.7522 +G01 X0.9116 Y0.7456 +G01 X0.9289 Y0.7456 +G01 X0.9449 Y0.7522 +G01 X0.9571 Y0.7644 +G01 X0.9637 Y0.7804 +G01 X0.9637 Y0.8597 +G01 X0.9571 Y0.8757 +G01 X0.9449 Y0.8879 +G01 X0.9289 Y0.8946 +G01 X0.9116 Y0.8946 +G01 X0.8956 Y0.8879 +G01 X0.8834 Y0.8757 +G01 X0.8809 Y0.8697 +G01 X0.8784 Y0.8757 +G01 X0.8661 Y0.8879 +G01 X0.8501 Y0.8946 +G01 X0.8328 Y0.8946 +G01 X0.8169 Y0.8879 +G01 X0.8046 Y0.8757 +G01 X0.8021 Y0.8697 +G01 X0.7996 Y0.8757 +G01 X0.7874 Y0.8879 +G01 X0.7714 Y0.8946 +G01 X0.7541 Y0.8946 +G01 X0.7381 Y0.8879 +G01 X0.7259 Y0.8757 +G01 X0.7193 Y0.8597 +G01 X0.7193 Y0.7804 +G01 X0.7259 Y0.7644 +G01 X0.7381 Y0.7522 +G01 X0.7541 Y0.7456 +G01 X0.7714 Y0.7456 +G01 X0.7874 Y0.7522 +G01 X0.7996 Y0.7644 +G01 X0.8021 Y0.7704 +G01 X0.8046 Y0.7644 +G00 Z0.1000 +G00 X1.5303 Y0.2965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.2965 F20 +G01 X1.6256 Y0.3031 +G01 X1.6379 Y0.3154 +G01 X1.6445 Y0.3313 +G01 X1.6445 Y0.3487 +G01 X1.6379 Y0.3646 +G01 X1.6256 Y0.3769 +G01 X1.6097 Y0.3835 +G01 X1.5303 Y0.3835 +G01 X1.5144 Y0.3769 +G01 X1.5021 Y0.3646 +G01 X1.4955 Y0.3487 +G01 X1.4955 Y0.3313 +G01 X1.5021 Y0.3154 +G01 X1.5144 Y0.3031 +G01 X1.5303 Y0.2965 +G00 Z0.1000 +G00 X1.5303 Y0.3965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.3965 F20 +G01 X1.6256 Y0.4031 +G01 X1.6379 Y0.4154 +G01 X1.6445 Y0.4313 +G01 X1.6445 Y0.4487 +G01 X1.6379 Y0.4646 +G01 X1.6256 Y0.4769 +G01 X1.6097 Y0.4835 +G01 X1.5303 Y0.4835 +G01 X1.5144 Y0.4769 +G01 X1.5021 Y0.4646 +G01 X1.4955 Y0.4487 +G01 X1.4955 Y0.4313 +G01 X1.5021 Y0.4154 +G01 X1.5144 Y0.4031 +G01 X1.5303 Y0.3965 +G00 Z0.1000 +G00 X1.5303 Y0.4965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.4965 F20 +G01 X1.6256 Y0.5031 +G01 X1.6379 Y0.5154 +G01 X1.6445 Y0.5313 +G01 X1.6445 Y0.5487 +G01 X1.6379 Y0.5646 +G01 X1.6256 Y0.5769 +G01 X1.6097 Y0.5835 +G01 X1.5303 Y0.5835 +G01 X1.5144 Y0.5769 +G01 X1.5021 Y0.5646 +G01 X1.4955 Y0.5487 +G01 X1.4955 Y0.5313 +G01 X1.5021 Y0.5154 +G01 X1.5144 Y0.5031 +G01 X1.5303 Y0.4965 +G00 Z0.1000 +G00 X1.5303 Y0.5965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.5965 F20 +G01 X1.6256 Y0.6031 +G01 X1.6379 Y0.6154 +G01 X1.6445 Y0.6313 +G01 X1.6445 Y0.6487 +G01 X1.6379 Y0.6646 +G01 X1.6256 Y0.6769 +G01 X1.6097 Y0.6835 +G01 X1.5303 Y0.6835 +G01 X1.5144 Y0.6769 +G01 X1.5021 Y0.6646 +G01 X1.4955 Y0.6487 +G01 X1.4955 Y0.6313 +G01 X1.5021 Y0.6154 +G01 X1.5144 Y0.6031 +G01 X1.5303 Y0.5965 +G00 Z0.1000 +G00 X1.5303 Y0.6965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.6965 F20 +G01 X1.6256 Y0.7031 +G01 X1.6379 Y0.7154 +G01 X1.6445 Y0.7313 +G01 X1.6445 Y0.7487 +G01 X1.6379 Y0.7646 +G01 X1.6256 Y0.7769 +G01 X1.6097 Y0.7835 +G01 X1.5303 Y0.7835 +G01 X1.5144 Y0.7769 +G01 X1.5021 Y0.7646 +G01 X1.4955 Y0.7487 +G01 X1.4955 Y0.7313 +G01 X1.5021 Y0.7154 +G01 X1.5144 Y0.7031 +G01 X1.5303 Y0.6965 +G00 Z0.1000 +G00 X1.5303 Y0.7965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.7965 F20 +G01 X1.6256 Y0.8031 +G01 X1.6379 Y0.8154 +G01 X1.6445 Y0.8313 +G01 X1.6445 Y0.8487 +G01 X1.6379 Y0.8646 +G01 X1.6256 Y0.8769 +G01 X1.6097 Y0.8835 +G01 X1.5303 Y0.8835 +G01 X1.5144 Y0.8769 +G01 X1.5021 Y0.8646 +G01 X1.4955 Y0.8487 +G01 X1.4955 Y0.8313 +G01 X1.5021 Y0.8154 +G01 X1.5144 Y0.8031 +G01 X1.5303 Y0.7965 +G00 Z0.1000 +G00 X1.5303 Y0.8965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.8965 F20 +G01 X1.6256 Y0.9031 +G01 X1.6379 Y0.9154 +G01 X1.6445 Y0.9313 +G01 X1.6445 Y0.9487 +G01 X1.6379 Y0.9646 +G01 X1.6256 Y0.9769 +G01 X1.6097 Y0.9835 +G01 X1.5303 Y0.9835 +G01 X1.5144 Y0.9769 +G01 X1.5021 Y0.9646 +G01 X1.4955 Y0.9487 +G01 X1.4955 Y0.9313 +G01 X1.5021 Y0.9154 +G01 X1.5144 Y0.9031 +G01 X1.5303 Y0.8965 +G00 Z0.1000 +G00 X1.5303 Y0.9965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.9965 F20 +G01 X1.6256 Y1.0031 +G01 X1.6379 Y1.0154 +G01 X1.6445 Y1.0313 +G01 X1.6445 Y1.0487 +G01 X1.6379 Y1.0646 +G01 X1.6256 Y1.0769 +G01 X1.6097 Y1.0835 +G01 X1.5303 Y1.0835 +G01 X1.5144 Y1.0769 +G01 X1.5021 Y1.0646 +G01 X1.4955 Y1.0487 +G01 X1.4955 Y1.0313 +G01 X1.5021 Y1.0154 +G01 X1.5144 Y1.0031 +G01 X1.5303 Y0.9965 +G00 Z0.1000 +G00 X1.2303 Y0.9965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.9965 F20 +G01 X1.3256 Y1.0031 +G01 X1.3379 Y1.0154 +G01 X1.3445 Y1.0313 +G01 X1.3445 Y1.0487 +G01 X1.3379 Y1.0646 +G01 X1.3256 Y1.0769 +G01 X1.3097 Y1.0835 +G01 X1.2303 Y1.0835 +G01 X1.2144 Y1.0769 +G01 X1.2021 Y1.0646 +G01 X1.1955 Y1.0487 +G01 X1.1955 Y1.0313 +G01 X1.2021 Y1.0154 +G01 X1.2144 Y1.0031 +G01 X1.2303 Y0.9965 +G00 Z0.1000 +G00 X1.2303 Y0.8965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.8965 F20 +G01 X1.3256 Y0.9031 +G01 X1.3379 Y0.9154 +G01 X1.3445 Y0.9313 +G01 X1.3445 Y0.9487 +G01 X1.3379 Y0.9646 +G01 X1.3256 Y0.9769 +G01 X1.3097 Y0.9835 +G01 X1.2303 Y0.9835 +G01 X1.2144 Y0.9769 +G01 X1.2021 Y0.9646 +G01 X1.1955 Y0.9487 +G01 X1.1955 Y0.9313 +G01 X1.2021 Y0.9154 +G01 X1.2144 Y0.9031 +G01 X1.2303 Y0.8965 +G00 Z0.1000 +G00 X1.2303 Y0.7965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.7965 F20 +G01 X1.3256 Y0.8031 +G01 X1.3379 Y0.8154 +G01 X1.3445 Y0.8313 +G01 X1.3445 Y0.8487 +G01 X1.3379 Y0.8646 +G01 X1.3256 Y0.8769 +G01 X1.3097 Y0.8835 +G01 X1.2303 Y0.8835 +G01 X1.2144 Y0.8769 +G01 X1.2021 Y0.8646 +G01 X1.1955 Y0.8487 +G01 X1.1955 Y0.8313 +G01 X1.2021 Y0.8154 +G01 X1.2144 Y0.8031 +G01 X1.2303 Y0.7965 +G00 Z0.1000 +G00 X1.2303 Y0.6965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.6965 F20 +G01 X1.3256 Y0.7031 +G01 X1.3379 Y0.7154 +G01 X1.3445 Y0.7313 +G01 X1.3445 Y0.7487 +G01 X1.3379 Y0.7646 +G01 X1.3256 Y0.7769 +G01 X1.3097 Y0.7835 +G01 X1.2303 Y0.7835 +G01 X1.2144 Y0.7769 +G01 X1.2021 Y0.7646 +G01 X1.1955 Y0.7487 +G01 X1.1955 Y0.7313 +G01 X1.2021 Y0.7154 +G01 X1.2144 Y0.7031 +G01 X1.2303 Y0.6965 +G00 Z0.1000 +G00 X1.2303 Y0.5965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.5965 F20 +G01 X1.3256 Y0.6031 +G01 X1.3379 Y0.6154 +G01 X1.3445 Y0.6313 +G01 X1.3445 Y0.6487 +G01 X1.3379 Y0.6646 +G01 X1.3256 Y0.6769 +G01 X1.3097 Y0.6835 +G01 X1.2303 Y0.6835 +G01 X1.2144 Y0.6769 +G01 X1.2021 Y0.6646 +G01 X1.1955 Y0.6487 +G01 X1.1955 Y0.6313 +G01 X1.2021 Y0.6154 +G01 X1.2144 Y0.6031 +G01 X1.2303 Y0.5965 +G00 Z0.1000 +G00 X1.2303 Y0.4965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.4965 F20 +G01 X1.3256 Y0.5031 +G01 X1.3379 Y0.5154 +G01 X1.3445 Y0.5313 +G01 X1.3445 Y0.5487 +G01 X1.3379 Y0.5646 +G01 X1.3256 Y0.5769 +G01 X1.3097 Y0.5835 +G01 X1.2303 Y0.5835 +G01 X1.2144 Y0.5769 +G01 X1.2021 Y0.5646 +G01 X1.1955 Y0.5487 +G01 X1.1955 Y0.5313 +G01 X1.2021 Y0.5154 +G01 X1.2144 Y0.5031 +G01 X1.2303 Y0.4965 +G00 Z0.1000 +G00 X1.2303 Y0.3965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.3965 F20 +G01 X1.3256 Y0.4031 +G01 X1.3379 Y0.4154 +G01 X1.3445 Y0.4313 +G01 X1.3445 Y0.4487 +G01 X1.3379 Y0.4646 +G01 X1.3256 Y0.4769 +G01 X1.3097 Y0.4835 +G01 X1.2303 Y0.4835 +G01 X1.2144 Y0.4769 +G01 X1.2021 Y0.4646 +G01 X1.1955 Y0.4487 +G01 X1.1955 Y0.4313 +G01 X1.2021 Y0.4154 +G01 X1.2144 Y0.4031 +G01 X1.2303 Y0.3965 +G00 Z0.1000 +G00 X1.2303 Y0.2965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.2965 F20 +G01 X1.3256 Y0.3031 +G01 X1.3379 Y0.3154 +G01 X1.3445 Y0.3313 +G01 X1.3445 Y0.3487 +G01 X1.3379 Y0.3646 +G01 X1.3256 Y0.3769 +G01 X1.3097 Y0.3835 +G01 X1.2303 Y0.3835 +G01 X1.2144 Y0.3769 +G01 X1.2021 Y0.3646 +G01 X1.1955 Y0.3487 +G01 X1.1955 Y0.3313 +G01 X1.2021 Y0.3154 +G01 X1.2144 Y0.3031 +G01 X1.2303 Y0.2965 +G00 Z0.1000 +G00 X0.3375 Y0.9803 +G01 Z-0.0070 F10 +G01 X0.3375 Y1.0197 F20 +G01 X0.3097 Y1.0475 +G01 X0.2703 Y1.0475 +G01 X0.2425 Y1.0197 +G01 X0.2425 Y0.9803 +G01 X0.2703 Y0.9525 +G01 X0.3097 Y0.9525 +G01 X0.3375 Y0.9803 +G00 Z0.1000 +G00 X0.3375 Y0.8803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.9197 F20 +G01 X0.3097 Y0.9475 +G01 X0.2703 Y0.9475 +G01 X0.2425 Y0.9197 +G01 X0.2425 Y0.8803 +G01 X0.2703 Y0.8525 +G01 X0.3097 Y0.8525 +G01 X0.3375 Y0.8803 +G00 Z0.1000 +G00 X0.3375 Y0.7803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.8197 F20 +G01 X0.3097 Y0.8475 +G01 X0.2703 Y0.8475 +G01 X0.2425 Y0.8197 +G01 X0.2425 Y0.7803 +G01 X0.2703 Y0.7525 +G01 X0.3097 Y0.7525 +G01 X0.3375 Y0.7803 +G00 Z0.1000 +G00 X0.3375 Y0.6803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.7197 F20 +G01 X0.3097 Y0.7475 +G01 X0.2703 Y0.7475 +G01 X0.2425 Y0.7197 +G01 X0.2425 Y0.6803 +G01 X0.2703 Y0.6525 +G01 X0.3097 Y0.6525 +G01 X0.3375 Y0.6803 +G00 Z0.1000 +G00 X0.3375 Y0.5803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.6197 F20 +G01 X0.3097 Y0.6475 +G01 X0.2703 Y0.6475 +G01 X0.2425 Y0.6197 +G01 X0.2425 Y0.5803 +G01 X0.2703 Y0.5525 +G01 X0.3097 Y0.5525 +G01 X0.3375 Y0.5803 +G00 Z0.1000 +G00 X0.3375 Y0.4803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.5197 F20 +G01 X0.3097 Y0.5475 +G01 X0.2703 Y0.5475 +G01 X0.2425 Y0.5197 +G01 X0.2425 Y0.4803 +G01 X0.2703 Y0.4525 +G01 X0.3097 Y0.4525 +G01 X0.3375 Y0.4803 +G00 Z0.1000 +G00 X0.2375 Y0.9803 +G01 Z-0.0070 F10 +G01 X0.2375 Y1.0197 F20 +G01 X0.2097 Y1.0475 +G01 X0.1703 Y1.0475 +G01 X0.1425 Y1.0197 +G01 X0.1425 Y0.9803 +G01 X0.1703 Y0.9525 +G01 X0.2097 Y0.9525 +G01 X0.2375 Y0.9803 +G00 Z0.1000 +G00 X0.2375 Y0.8803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.9197 F20 +G01 X0.2097 Y0.9475 +G01 X0.1703 Y0.9475 +G01 X0.1425 Y0.9197 +G01 X0.1425 Y0.8803 +G01 X0.1703 Y0.8525 +G01 X0.2097 Y0.8525 +G01 X0.2375 Y0.8803 +G00 Z0.1000 +G00 X0.2375 Y0.7803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.8197 F20 +G01 X0.2097 Y0.8475 +G01 X0.1703 Y0.8475 +G01 X0.1425 Y0.8197 +G01 X0.1425 Y0.7803 +G01 X0.1703 Y0.7525 +G01 X0.2097 Y0.7525 +G01 X0.2375 Y0.7803 +G00 Z0.1000 +G00 X0.2375 Y0.6803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.7197 F20 +G01 X0.2097 Y0.7475 +G01 X0.1703 Y0.7475 +G01 X0.1425 Y0.7197 +G01 X0.1425 Y0.6803 +G01 X0.1703 Y0.6525 +G01 X0.2097 Y0.6525 +G01 X0.2375 Y0.6803 +G00 Z0.1000 +G00 X0.2375 Y0.5803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.6197 F20 +G01 X0.2097 Y0.6475 +G01 X0.1703 Y0.6475 +G01 X0.1425 Y0.6197 +G01 X0.1425 Y0.5803 +G01 X0.1703 Y0.5525 +G01 X0.2097 Y0.5525 +G01 X0.2375 Y0.5803 +G00 Z0.1000 +G00 X0.2375 Y0.4803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.5197 F20 +G01 X0.2097 Y0.5475 +G01 X0.1703 Y0.5475 +G01 X0.1425 Y0.5197 +G01 X0.1425 Y0.4803 +G01 X0.1703 Y0.4525 +G01 X0.2097 Y0.4525 +G01 X0.2375 Y0.4803 +G00 Z0.1000 +G00 X0.3375 Y0.3803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.4197 F20 +G01 X0.3097 Y0.4475 +G01 X0.2703 Y0.4475 +G01 X0.2425 Y0.4197 +G01 X0.2425 Y0.3803 +G01 X0.2703 Y0.3525 +G01 X0.3097 Y0.3525 +G01 X0.3375 Y0.3803 +G00 Z0.1000 +G00 X0.2375 Y0.3803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.4197 F20 +G01 X0.2097 Y0.4475 +G01 X0.1703 Y0.4475 +G01 X0.1425 Y0.4197 +G01 X0.1425 Y0.3803 +G01 X0.1703 Y0.3525 +G01 X0.2097 Y0.3525 +G01 X0.2375 Y0.3803 +G00 Z0.1000 +G00 X0.8397 Y0.4135 +G01 Z-0.0070 F10 +G01 X0.7603 Y0.4135 F20 +G01 X0.7444 Y0.4069 +G01 X0.7321 Y0.3946 +G01 X0.7255 Y0.3787 +G01 X0.7255 Y0.3613 +G01 X0.7321 Y0.3454 +G01 X0.7444 Y0.3331 +G01 X0.7603 Y0.3265 +G01 X0.8397 Y0.3265 +G01 X0.8556 Y0.3331 +G01 X0.8679 Y0.3454 +G01 X0.8745 Y0.3613 +G01 X0.8745 Y0.3787 +G01 X0.8679 Y0.3946 +G01 X0.8556 Y0.4069 +G01 X0.8397 Y0.4135 +G00 Z0.1000 +G00 X1.1397 Y0.3135 +G01 Z-0.0070 F10 +G01 X1.0603 Y0.3135 F20 +G01 X1.0444 Y0.3069 +G01 X1.0321 Y0.2946 +G01 X1.0255 Y0.2787 +G01 X1.0255 Y0.2613 +G01 X1.0321 Y0.2454 +G01 X1.0444 Y0.2331 +G01 X1.0603 Y0.2265 +G01 X1.1397 Y0.2265 +G01 X1.1556 Y0.2331 +G01 X1.1679 Y0.2454 +G01 X1.1745 Y0.2613 +G01 X1.1745 Y0.2787 +G01 X1.1679 Y0.2946 +G01 X1.1556 Y0.3069 +G01 X1.1397 Y0.3135 +G00 Z0.1000 +G00 X0.6397 Y0.3135 +G01 Z-0.0070 F10 +G01 X0.5603 Y0.3135 F20 +G01 X0.5444 Y0.3069 +G01 X0.5321 Y0.2946 +G01 X0.5255 Y0.2787 +G01 X0.5255 Y0.2613 +G01 X0.5321 Y0.2454 +G01 X0.5444 Y0.2331 +G01 X0.5603 Y0.2265 +G01 X0.6397 Y0.2265 +G01 X0.6556 Y0.2331 +G01 X0.6679 Y0.2454 +G01 X0.6745 Y0.2613 +G01 X0.6745 Y0.2787 +G01 X0.6679 Y0.2946 +G01 X0.6556 Y0.3069 +G01 X0.6397 Y0.3135 +G00 Z0.1000 +G00 X2.1103 Y0.1065 +G01 Z-0.0070 F10 +G01 X2.1897 Y0.1065 F20 +G01 X2.2056 Y0.1131 +G01 X2.2179 Y0.1254 +G01 X2.2245 Y0.1413 +G01 X2.2245 Y0.1587 +G01 X2.2179 Y0.1746 +G01 X2.2056 Y0.1869 +G01 X2.1897 Y0.1935 +G01 X2.1103 Y0.1935 +G01 X2.0944 Y0.1869 +G01 X2.0821 Y0.1746 +G01 X2.0755 Y0.1587 +G01 X2.0755 Y0.1413 +G01 X2.0821 Y0.1254 +G01 X2.0944 Y0.1131 +G01 X2.1103 Y0.1065 +G00 Z0.1000 +G00 X2.1103 Y0.2065 +G01 Z-0.0070 F10 +G01 X2.1897 Y0.2065 F20 +G01 X2.2056 Y0.2131 +G01 X2.2179 Y0.2254 +G01 X2.2245 Y0.2413 +G01 X2.2245 Y0.2587 +G01 X2.2179 Y0.2746 +G01 X2.2056 Y0.2869 +G01 X2.1897 Y0.2935 +G01 X2.1103 Y0.2935 +G01 X2.0944 Y0.2869 +G01 X2.0821 Y0.2746 +G01 X2.0755 Y0.2587 +G01 X2.0755 Y0.2413 +G01 X2.0821 Y0.2254 +G01 X2.0944 Y0.2131 +G01 X2.1103 Y0.2065 +G00 Z0.1000 +G00 X2.1103 Y0.3065 +G01 Z-0.0070 F10 +G01 X2.1897 Y0.3065 F20 +G01 X2.2056 Y0.3131 +G01 X2.2179 Y0.3254 +G01 X2.2245 Y0.3413 +G01 X2.2245 Y0.3587 +G01 X2.2179 Y0.3746 +G01 X2.2056 Y0.3869 +G01 X2.1897 Y0.3935 +G01 X2.1103 Y0.3935 +G01 X2.0944 Y0.3869 +G01 X2.0821 Y0.3746 +G01 X2.0755 Y0.3587 +G01 X2.0755 Y0.3413 +G01 X2.0821 Y0.3254 +G01 X2.0944 Y0.3131 +G01 X2.1103 Y0.3065 +G00 Z0.1000 +G00 X1.8103 Y0.3065 +G01 Z-0.0070 F10 +G01 X1.8897 Y0.3065 F20 +G01 X1.9056 Y0.3131 +G01 X1.9179 Y0.3254 +G01 X1.9245 Y0.3413 +G01 X1.9245 Y0.3587 +G01 X1.9179 Y0.3746 +G01 X1.9056 Y0.3869 +G01 X1.8897 Y0.3935 +G01 X1.8103 Y0.3935 +G01 X1.7944 Y0.3869 +G01 X1.7821 Y0.3746 +G01 X1.7755 Y0.3587 +G01 X1.7755 Y0.3413 +G01 X1.7821 Y0.3254 +G01 X1.7944 Y0.3131 +G01 X1.8103 Y0.3065 +G00 Z0.1000 +G00 X1.8103 Y0.2065 +G01 Z-0.0070 F10 +G01 X1.8897 Y0.2065 F20 +G01 X1.9056 Y0.2131 +G01 X1.9179 Y0.2254 +G01 X1.9245 Y0.2413 +G01 X1.9245 Y0.2587 +G01 X1.9179 Y0.2746 +G01 X1.9056 Y0.2869 +G01 X1.8897 Y0.2935 +G01 X1.8103 Y0.2935 +G01 X1.7944 Y0.2869 +G01 X1.7821 Y0.2746 +G01 X1.7755 Y0.2587 +G01 X1.7755 Y0.2413 +G01 X1.7821 Y0.2254 +G01 X1.7944 Y0.2131 +G01 X1.8103 Y0.2065 +G00 Z0.1000 +G00 X1.8103 Y0.1065 +G01 Z-0.0070 F10 +G01 X1.8897 Y0.1065 F20 +G01 X1.9056 Y0.1131 +G01 X1.9179 Y0.1254 +G01 X1.9245 Y0.1413 +G01 X1.9245 Y0.1587 +G01 X1.9179 Y0.1746 +G01 X1.9056 Y0.1869 +G01 X1.8897 Y0.1935 +G01 X1.8103 Y0.1935 +G01 X1.7944 Y0.1869 +G01 X1.7821 Y0.1746 +G01 X1.7755 Y0.1587 +G01 X1.7755 Y0.1413 +G01 X1.7821 Y0.1254 +G01 X1.7944 Y0.1131 +G01 X1.8103 Y0.1065 +G00 Z0.1000 +G00 X1.8435 Y0.6620 +G01 Z-0.0070 F10 +G01 X1.8435 Y0.6980 F20 +G01 X1.8180 Y0.7235 +G01 X1.7820 Y0.7235 +G01 X1.7565 Y0.6980 +G01 X1.7565 Y0.6620 +G01 X1.7820 Y0.6365 +G01 X1.8180 Y0.6365 +G01 X1.8435 Y0.6620 +G00 Z0.1000 +G00 X1.8435 Y0.4620 +G01 Z-0.0070 F10 +G01 X1.8435 Y0.4980 F20 +G01 X1.8180 Y0.5235 +G01 X1.7820 Y0.5235 +G01 X1.7565 Y0.4980 +G01 X1.7565 Y0.4620 +G01 X1.7820 Y0.4365 +G01 X1.8180 Y0.4365 +G01 X1.8435 Y0.4620 +G00 Z0.1000 +G00 X1.9635 Y0.6620 +G01 Z-0.0070 F10 +G01 X1.9635 Y0.6980 F20 +G01 X1.9380 Y0.7235 +G01 X1.9020 Y0.7235 +G01 X1.8765 Y0.6980 +G01 X1.8765 Y0.6620 +G01 X1.9020 Y0.6365 +G01 X1.9380 Y0.6365 +G01 X1.9635 Y0.6620 +G00 Z0.1000 +G00 X1.9635 Y0.4620 +G01 Z-0.0070 F10 +G01 X1.9635 Y0.4980 F20 +G01 X1.9380 Y0.5235 +G01 X1.9020 Y0.5235 +G01 X1.8765 Y0.4980 +G01 X1.8765 Y0.4620 +G01 X1.9020 Y0.4365 +G01 X1.9380 Y0.4365 +G01 X1.9635 Y0.4620 +G00 Z0.1000 +G00 X2.0835 Y0.6620 +G01 Z-0.0070 F10 +G01 X2.0835 Y0.6980 F20 +G01 X2.0580 Y0.7235 +G01 X2.0220 Y0.7235 +G01 X1.9965 Y0.6980 +G01 X1.9965 Y0.6620 +G01 X2.0220 Y0.6365 +G01 X2.0580 Y0.6365 +G01 X2.0835 Y0.6620 +G00 Z0.1000 +G00 X2.0835 Y0.4620 +G01 Z-0.0070 F10 +G01 X2.0835 Y0.4980 F20 +G01 X2.0580 Y0.5235 +G01 X2.0220 Y0.5235 +G01 X1.9965 Y0.4980 +G01 X1.9965 Y0.4620 +G01 X2.0220 Y0.4365 +G01 X2.0580 Y0.4365 +G01 X2.0835 Y0.4620 +G00 Z0.1000 +G00 X1.3135 Y0.2120 +G01 Z-0.0070 F10 +G01 X1.3135 Y0.2480 F20 +G01 X1.2880 Y0.2735 +G01 X1.2520 Y0.2735 +G01 X1.2265 Y0.2480 +G01 X1.2265 Y0.2120 +G01 X1.2520 Y0.1865 +G01 X1.2880 Y0.1865 +G01 X1.3135 Y0.2120 +G00 Z0.1000 +G00 X1.4135 Y0.2120 +G01 Z-0.0070 F10 +G01 X1.4135 Y0.2480 F20 +G01 X1.3880 Y0.2735 +G01 X1.3520 Y0.2735 +G01 X1.3265 Y0.2480 +G01 X1.3265 Y0.2120 +G01 X1.3520 Y0.1865 +G01 X1.3880 Y0.1865 +G01 X1.4135 Y0.2120 +G00 Z0.1000 +G00 X2.3625 Y1.0041 +G01 Z-0.0070 F10 +G01 X2.3625 Y1.0559 F20 +G01 X2.3259 Y1.0925 +G01 X2.2741 Y1.0925 +G01 X2.2375 Y1.0559 +G01 X2.2375 Y1.0041 +G01 X2.2741 Y0.9675 +G01 X2.3259 Y0.9675 +G01 X2.3625 Y1.0041 +G00 Z0.1000 +G00 X2.0625 Y1.0041 +G01 Z-0.0070 F10 +G01 X2.0625 Y1.0559 F20 +G01 X2.0259 Y1.0925 +G01 X1.9741 Y1.0925 +G01 X1.9375 Y1.0559 +G01 X1.9375 Y1.0041 +G01 X1.9741 Y0.9675 +G01 X2.0259 Y0.9675 +G01 X2.0625 Y1.0041 +G00 Z0.1000 +G00 X0.5535 Y0.9820 +G01 Z-0.0070 F10 +G01 X0.5535 Y1.0180 F20 +G01 X0.5280 Y1.0435 +G01 X0.4920 Y1.0435 +G01 X0.4665 Y1.0180 +G01 X0.4665 Y0.9820 +G01 X0.4920 Y0.9565 +G01 X0.5280 Y0.9565 +G01 X0.5535 Y0.9820 +G00 Z0.1000 +G00 X0.4535 Y0.9820 +G01 Z-0.0070 F10 +G01 X0.4535 Y1.0180 F20 +G01 X0.4280 Y1.0435 +G01 X0.3920 Y1.0435 +G01 X0.3665 Y1.0180 +G01 X0.3665 Y0.9820 +G01 X0.3920 Y0.9565 +G01 X0.4280 Y0.9565 +G01 X0.4535 Y0.9820 +G00 Z0.1000 +G00 X1.4335 Y1.1520 +G01 Z-0.0070 F10 +G01 X1.4335 Y1.1880 F20 +G01 X1.4080 Y1.2135 +G01 X1.3720 Y1.2135 +G01 X1.3465 Y1.1880 +G01 X1.3465 Y1.1520 +G01 X1.3720 Y1.1265 +G01 X1.4080 Y1.1265 +G01 X1.4335 Y1.1520 +G00 Z0.1000 +G00 X1.5335 Y1.1520 +G01 Z-0.0070 F10 +G01 X1.5335 Y1.1880 F20 +G01 X1.5080 Y1.2135 +G01 X1.4720 Y1.2135 +G01 X1.4465 Y1.1880 +G01 X1.4465 Y1.1520 +G01 X1.4720 Y1.1265 +G01 X1.5080 Y1.1265 +G01 X1.5335 Y1.1520 +G00 Z0.1000 +G00 X1.1770 Y1.2114 +G01 Z-0.0070 F10 +G01 X1.1614 Y1.2270 F20 +G01 X1.1410 Y1.2355 +G01 X1.1190 Y1.2355 +G01 X1.0986 Y1.2270 +G01 X1.0829 Y1.2114 +G01 X1.0745 Y1.1910 +G01 X1.0745 Y1.1690 +G01 X1.0829 Y1.1486 +G01 X1.0986 Y1.1329 +G01 X1.1190 Y1.1245 +G01 X1.1410 Y1.1245 +G01 X1.1614 Y1.1329 +G01 X1.1770 Y1.1486 +G01 X1.1788 Y1.1527 +G01 X1.2070 Y1.1245 +G01 X1.2530 Y1.1245 +G01 X1.2855 Y1.1570 +G01 X1.2855 Y1.2030 +G01 X1.2530 Y1.2355 +G01 X1.2070 Y1.2355 +G01 X1.1788 Y1.2073 +G01 X1.1770 Y1.2114 +G00 Z0.1000 +G00 X0.2400 Y0.9758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.9500 F20 +G01 X0.2400 Y0.9242 +G01 X0.2142 Y0.9500 +G01 X0.2400 Y0.9758 +G00 Z0.1000 +G00 X0.2400 Y0.7758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.7500 F20 +G01 X0.2400 Y0.7242 +G01 X0.2142 Y0.7500 +G01 X0.2400 Y0.7758 +G00 Z0.1000 +G00 X0.2400 Y0.5758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.5500 F20 +G01 X0.2400 Y0.5242 +G01 X0.2142 Y0.5500 +G01 X0.2400 Y0.5758 +G00 Z0.1000 +G00 X0.2400 Y0.4758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.4500 F20 +G01 X0.2400 Y0.4242 +G01 X0.2142 Y0.4500 +G01 X0.2400 Y0.4758 +G00 Z0.1000 +G00 X0.2400 Y0.6758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.6500 F20 +G01 X0.2400 Y0.6242 +G01 X0.2142 Y0.6500 +G01 X0.2400 Y0.6758 +G00 Z0.1000 +G00 X0.2400 Y0.8758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.8500 F20 +G01 X0.2400 Y0.8242 +G01 X0.2142 Y0.8500 +G01 X0.2400 Y0.8758 +G00 Z0.1000 +G00 X1.8105 Y1.2080 +G01 Z-0.0070 F10 +G01 X1.8105 Y1.2320 F20 +G01 X1.8013 Y1.2543 +G01 X1.7843 Y1.2713 +G01 X1.7620 Y1.2805 +G01 X1.7380 Y1.2805 +G01 X1.7157 Y1.2713 +G01 X1.6987 Y1.2543 +G01 X1.6895 Y1.2320 +G01 X1.6895 Y1.2080 +G01 X1.6987 Y1.1857 +G01 X1.7144 Y1.1700 +G01 X1.6895 Y1.1451 +G01 X1.6895 Y1.0949 +G01 X1.7249 Y1.0595 +G01 X1.7751 Y1.0595 +G01 X1.8105 Y1.0949 +G01 X1.8105 Y1.1451 +G01 X1.7856 Y1.1700 +G01 X1.8013 Y1.1857 +G01 X1.8105 Y1.2080 +G00 Z0.1000 +G00 X0.3425 Y0.9783 +G01 Z-0.0070 F10 +G01 X0.3425 Y1.0217 F20 +G01 X0.3117 Y1.0525 +G01 X0.2683 Y1.0525 +G01 X0.2400 Y1.0242 +G01 X0.2117 Y1.0525 +G01 X0.1683 Y1.0525 +G01 X0.1375 Y1.0217 +G01 X0.1375 Y0.9783 +G01 X0.1658 Y0.9500 +G01 X0.1375 Y0.9217 +G01 X0.1375 Y0.8783 +G01 X0.1658 Y0.8500 +G01 X0.1375 Y0.8217 +G01 X0.1375 Y0.7783 +G01 X0.1658 Y0.7500 +G01 X0.1375 Y0.7217 +G01 X0.1375 Y0.6783 +G01 X0.1658 Y0.6500 +G01 X0.1375 Y0.6217 +G01 X0.1375 Y0.5783 +G01 X0.1658 Y0.5500 +G01 X0.1375 Y0.5217 +G01 X0.1375 Y0.4783 +G01 X0.1658 Y0.4500 +G01 X0.1375 Y0.4217 +G01 X0.1375 Y0.3783 +G01 X0.1683 Y0.3475 +G01 X0.2117 Y0.3475 +G01 X0.2400 Y0.3758 +G01 X0.2683 Y0.3475 +G01 X0.3117 Y0.3475 +G01 X0.3425 Y0.3783 +G01 X0.3425 Y0.4217 +G01 X0.3142 Y0.4500 +G01 X0.3425 Y0.4783 +G01 X0.3425 Y0.5217 +G01 X0.3142 Y0.5500 +G01 X0.3425 Y0.5783 +G01 X0.3425 Y0.6217 +G01 X0.3142 Y0.6500 +G01 X0.3425 Y0.6783 +G01 X0.3425 Y0.7217 +G01 X0.3142 Y0.7500 +G01 X0.3425 Y0.7783 +G01 X0.3425 Y0.8217 +G01 X0.3142 Y0.8500 +G01 X0.3425 Y0.8783 +G01 X0.3425 Y0.9217 +G01 X0.3142 Y0.9500 +G01 X0.3425 Y0.9783 +G00 Z0.1000 +G00 X1.2294 Y0.2915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.2915 F20 +G01 X1.3285 Y0.2989 +G01 X1.3421 Y0.3125 +G01 X1.3495 Y0.3304 +G01 X1.3495 Y0.3496 +G01 X1.3421 Y0.3675 +G01 X1.3285 Y0.3811 +G01 X1.3106 Y0.3885 +G01 X1.2294 Y0.3885 +G01 X1.2115 Y0.3811 +G01 X1.1979 Y0.3675 +G01 X1.1905 Y0.3496 +G01 X1.1905 Y0.3304 +G01 X1.1979 Y0.3125 +G01 X1.2115 Y0.2989 +G01 X1.2294 Y0.2915 +G00 Z0.1000 +G00 X1.2294 Y0.3915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.3915 F20 +G01 X1.3285 Y0.3989 +G01 X1.3421 Y0.4125 +G01 X1.3495 Y0.4304 +G01 X1.3495 Y0.4496 +G01 X1.3421 Y0.4675 +G01 X1.3285 Y0.4811 +G01 X1.3106 Y0.4885 +G01 X1.2294 Y0.4885 +G01 X1.2115 Y0.4811 +G01 X1.1979 Y0.4675 +G01 X1.1905 Y0.4496 +G01 X1.1905 Y0.4304 +G01 X1.1979 Y0.4125 +G01 X1.2115 Y0.3989 +G01 X1.2294 Y0.3915 +G00 Z0.1000 +G00 X1.2294 Y0.4915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.4915 F20 +G01 X1.3285 Y0.4989 +G01 X1.3421 Y0.5125 +G01 X1.3495 Y0.5304 +G01 X1.3495 Y0.5496 +G01 X1.3421 Y0.5675 +G01 X1.3285 Y0.5811 +G01 X1.3106 Y0.5885 +G01 X1.2294 Y0.5885 +G01 X1.2115 Y0.5811 +G01 X1.1979 Y0.5675 +G01 X1.1905 Y0.5496 +G01 X1.1905 Y0.5304 +G01 X1.1979 Y0.5125 +G01 X1.2115 Y0.4989 +G01 X1.2294 Y0.4915 +G00 Z0.1000 +G00 X1.2294 Y0.5915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.5915 F20 +G01 X1.3285 Y0.5989 +G01 X1.3421 Y0.6125 +G01 X1.3495 Y0.6304 +G01 X1.3495 Y0.6496 +G01 X1.3421 Y0.6675 +G01 X1.3285 Y0.6811 +G01 X1.3106 Y0.6885 +G01 X1.2294 Y0.6885 +G01 X1.2115 Y0.6811 +G01 X1.1979 Y0.6675 +G01 X1.1905 Y0.6496 +G01 X1.1905 Y0.6304 +G01 X1.1979 Y0.6125 +G01 X1.2115 Y0.5989 +G01 X1.2294 Y0.5915 +G00 Z0.1000 +G00 X1.2294 Y0.6915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.6915 F20 +G01 X1.3285 Y0.6989 +G01 X1.3421 Y0.7125 +G01 X1.3495 Y0.7304 +G01 X1.3495 Y0.7496 +G01 X1.3421 Y0.7675 +G01 X1.3285 Y0.7811 +G01 X1.3106 Y0.7885 +G01 X1.2294 Y0.7885 +G01 X1.2115 Y0.7811 +G01 X1.1979 Y0.7675 +G01 X1.1905 Y0.7496 +G01 X1.1905 Y0.7304 +G01 X1.1979 Y0.7125 +G01 X1.2115 Y0.6989 +G01 X1.2294 Y0.6915 +G00 Z0.1000 +G00 X1.2294 Y0.7915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.7915 F20 +G01 X1.3285 Y0.7989 +G01 X1.3421 Y0.8125 +G01 X1.3495 Y0.8304 +G01 X1.3495 Y0.8496 +G01 X1.3421 Y0.8675 +G01 X1.3285 Y0.8811 +G01 X1.3106 Y0.8885 +G01 X1.2294 Y0.8885 +G01 X1.2115 Y0.8811 +G01 X1.1979 Y0.8675 +G01 X1.1905 Y0.8496 +G01 X1.1905 Y0.8304 +G01 X1.1979 Y0.8125 +G01 X1.2115 Y0.7989 +G01 X1.2294 Y0.7915 +G00 Z0.1000 +G00 X1.2294 Y0.8915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.8915 F20 +G01 X1.3285 Y0.8989 +G01 X1.3421 Y0.9125 +G01 X1.3495 Y0.9304 +G01 X1.3495 Y0.9496 +G01 X1.3421 Y0.9675 +G01 X1.3285 Y0.9811 +G01 X1.3106 Y0.9885 +G01 X1.2294 Y0.9885 +G01 X1.2115 Y0.9811 +G01 X1.1979 Y0.9675 +G01 X1.1905 Y0.9496 +G01 X1.1905 Y0.9304 +G01 X1.1979 Y0.9125 +G01 X1.2115 Y0.8989 +G01 X1.2294 Y0.8915 +G00 Z0.1000 +G00 X1.2294 Y0.9915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.9915 F20 +G01 X1.3285 Y0.9989 +G01 X1.3421 Y1.0125 +G01 X1.3495 Y1.0304 +G01 X1.3495 Y1.0496 +G01 X1.3421 Y1.0675 +G01 X1.3285 Y1.0811 +G01 X1.3106 Y1.0885 +G01 X1.2294 Y1.0885 +G01 X1.2115 Y1.0811 +G01 X1.1979 Y1.0675 +G01 X1.1905 Y1.0496 +G01 X1.1905 Y1.0304 +G01 X1.1979 Y1.0125 +G01 X1.2115 Y0.9989 +G01 X1.2294 Y0.9915 +G00 Z0.1000 +G00 X1.5294 Y0.9915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.9915 F20 +G01 X1.6285 Y0.9989 +G01 X1.6421 Y1.0125 +G01 X1.6495 Y1.0304 +G01 X1.6495 Y1.0496 +G01 X1.6421 Y1.0675 +G01 X1.6285 Y1.0811 +G01 X1.6106 Y1.0885 +G01 X1.5294 Y1.0885 +G01 X1.5115 Y1.0811 +G01 X1.4979 Y1.0675 +G01 X1.4905 Y1.0496 +G01 X1.4905 Y1.0304 +G01 X1.4979 Y1.0125 +G01 X1.5115 Y0.9989 +G01 X1.5294 Y0.9915 +G00 Z0.1000 +G00 X1.5294 Y0.8915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.8915 F20 +G01 X1.6285 Y0.8989 +G01 X1.6421 Y0.9125 +G01 X1.6495 Y0.9304 +G01 X1.6495 Y0.9496 +G01 X1.6421 Y0.9675 +G01 X1.6285 Y0.9811 +G01 X1.6106 Y0.9885 +G01 X1.5294 Y0.9885 +G01 X1.5115 Y0.9811 +G01 X1.4979 Y0.9675 +G01 X1.4905 Y0.9496 +G01 X1.4905 Y0.9304 +G01 X1.4979 Y0.9125 +G01 X1.5115 Y0.8989 +G01 X1.5294 Y0.8915 +G00 Z0.1000 +G00 X1.5294 Y0.7915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.7915 F20 +G01 X1.6285 Y0.7989 +G01 X1.6421 Y0.8125 +G01 X1.6495 Y0.8304 +G01 X1.6495 Y0.8496 +G01 X1.6421 Y0.8675 +G01 X1.6285 Y0.8811 +G01 X1.6106 Y0.8885 +G01 X1.5294 Y0.8885 +G01 X1.5115 Y0.8811 +G01 X1.4979 Y0.8675 +G01 X1.4905 Y0.8496 +G01 X1.4905 Y0.8304 +G01 X1.4979 Y0.8125 +G01 X1.5115 Y0.7989 +G01 X1.5294 Y0.7915 +G00 Z0.1000 +G00 X1.5294 Y0.6915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.6915 F20 +G01 X1.6285 Y0.6989 +G01 X1.6421 Y0.7125 +G01 X1.6495 Y0.7304 +G01 X1.6495 Y0.7496 +G01 X1.6421 Y0.7675 +G01 X1.6285 Y0.7811 +G01 X1.6106 Y0.7885 +G01 X1.5294 Y0.7885 +G01 X1.5115 Y0.7811 +G01 X1.4979 Y0.7675 +G01 X1.4905 Y0.7496 +G01 X1.4905 Y0.7304 +G01 X1.4979 Y0.7125 +G01 X1.5115 Y0.6989 +G01 X1.5294 Y0.6915 +G00 Z0.1000 +G00 X1.5294 Y0.5915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.5915 F20 +G01 X1.6285 Y0.5989 +G01 X1.6421 Y0.6125 +G01 X1.6495 Y0.6304 +G01 X1.6495 Y0.6496 +G01 X1.6421 Y0.6675 +G01 X1.6285 Y0.6811 +G01 X1.6106 Y0.6885 +G01 X1.5294 Y0.6885 +G01 X1.5115 Y0.6811 +G01 X1.4979 Y0.6675 +G01 X1.4905 Y0.6496 +G01 X1.4905 Y0.6304 +G01 X1.4979 Y0.6125 +G01 X1.5115 Y0.5989 +G01 X1.5294 Y0.5915 +G00 Z0.1000 +G00 X1.5294 Y0.4915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.4915 F20 +G01 X1.6285 Y0.4989 +G01 X1.6421 Y0.5125 +G01 X1.6495 Y0.5304 +G01 X1.6495 Y0.5496 +G01 X1.6421 Y0.5675 +G01 X1.6285 Y0.5811 +G01 X1.6106 Y0.5885 +G01 X1.5294 Y0.5885 +G01 X1.5115 Y0.5811 +G01 X1.4979 Y0.5675 +G01 X1.4905 Y0.5496 +G01 X1.4905 Y0.5304 +G01 X1.4979 Y0.5125 +G01 X1.5115 Y0.4989 +G01 X1.5294 Y0.4915 +G00 Z0.1000 +G00 X1.5294 Y0.3915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.3915 F20 +G01 X1.6285 Y0.3989 +G01 X1.6421 Y0.4125 +G01 X1.6495 Y0.4304 +G01 X1.6495 Y0.4496 +G01 X1.6421 Y0.4675 +G01 X1.6285 Y0.4811 +G01 X1.6106 Y0.4885 +G01 X1.5294 Y0.4885 +G01 X1.5115 Y0.4811 +G01 X1.4979 Y0.4675 +G01 X1.4905 Y0.4496 +G01 X1.4905 Y0.4304 +G01 X1.4979 Y0.4125 +G01 X1.5115 Y0.3989 +G01 X1.5294 Y0.3915 +G00 Z0.1000 +G00 X1.5294 Y0.2915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.2915 F20 +G01 X1.6285 Y0.2989 +G01 X1.6421 Y0.3125 +G01 X1.6495 Y0.3304 +G01 X1.6495 Y0.3496 +G01 X1.6421 Y0.3675 +G01 X1.6285 Y0.3811 +G01 X1.6106 Y0.3885 +G01 X1.5294 Y0.3885 +G01 X1.5115 Y0.3811 +G01 X1.4979 Y0.3675 +G01 X1.4905 Y0.3496 +G01 X1.4905 Y0.3304 +G01 X1.4979 Y0.3125 +G01 X1.5115 Y0.2989 +G01 X1.5294 Y0.2915 +G00 Z0.1000 +G00 X0.8140 Y0.7479 +G01 Z-0.0070 F10 +G01 X0.8318 Y0.7406 F20 +G01 X0.8511 Y0.7406 +G01 X0.8690 Y0.7479 +G01 X0.8809 Y0.7598 +G01 X0.8928 Y0.7479 +G01 X0.9106 Y0.7406 +G01 X0.9299 Y0.7406 +G01 X0.9477 Y0.7479 +G01 X0.9614 Y0.7616 +G01 X0.9687 Y0.7794 +G01 X0.9687 Y0.8607 +G01 X0.9614 Y0.8785 +G01 X0.9477 Y0.8922 +G01 X0.9299 Y0.8996 +G01 X0.9106 Y0.8996 +G01 X0.8928 Y0.8922 +G01 X0.8809 Y0.8803 +G01 X0.8690 Y0.8922 +G01 X0.8511 Y0.8996 +G01 X0.8318 Y0.8996 +G01 X0.8140 Y0.8922 +G01 X0.8021 Y0.8803 +G01 X0.7902 Y0.8922 +G01 X0.7724 Y0.8996 +G01 X0.7531 Y0.8996 +G01 X0.7353 Y0.8922 +G01 X0.7216 Y0.8785 +G01 X0.7143 Y0.8607 +G01 X0.7143 Y0.7794 +G01 X0.7216 Y0.7616 +G01 X0.7353 Y0.7479 +G01 X0.7531 Y0.7406 +G01 X0.7724 Y0.7406 +G01 X0.7902 Y0.7479 +G01 X0.8021 Y0.7598 +G01 X0.8140 Y0.7479 +G00 Z0.1000 +G00 X0.8296 Y0.7121 +G01 Z-0.0070 F10 +G01 X0.8118 Y0.7194 F20 +G01 X0.7925 Y0.7194 +G01 X0.7746 Y0.7121 +G01 X0.7628 Y0.7002 +G01 X0.7509 Y0.7121 +G01 X0.7330 Y0.7194 +G01 X0.7137 Y0.7194 +G01 X0.6959 Y0.7121 +G01 X0.6823 Y0.6984 +G01 X0.6749 Y0.6806 +G01 X0.6749 Y0.5993 +G01 X0.6823 Y0.5815 +G01 X0.6959 Y0.5678 +G01 X0.7137 Y0.5604 +G01 X0.7330 Y0.5604 +G01 X0.7509 Y0.5678 +G01 X0.7628 Y0.5797 +G01 X0.7746 Y0.5678 +G01 X0.7925 Y0.5604 +G01 X0.8118 Y0.5604 +G01 X0.8296 Y0.5678 +G01 X0.8415 Y0.5797 +G01 X0.8534 Y0.5678 +G01 X0.8712 Y0.5604 +G01 X0.8905 Y0.5604 +G01 X0.9083 Y0.5678 +G01 X0.9220 Y0.5815 +G01 X0.9294 Y0.5993 +G01 X0.9294 Y0.6806 +G01 X0.9220 Y0.6984 +G01 X0.9083 Y0.7121 +G01 X0.8905 Y0.7194 +G01 X0.8712 Y0.7194 +G01 X0.8534 Y0.7121 +G01 X0.8415 Y0.7002 +G01 X0.8296 Y0.7121 +G00 Z0.1000 +G00 X0.8406 Y0.4185 +G01 Z-0.0070 F10 +G01 X0.7594 Y0.4185 F20 +G01 X0.7415 Y0.4111 +G01 X0.7279 Y0.3975 +G01 X0.7205 Y0.3796 +G01 X0.7205 Y0.3604 +G01 X0.7279 Y0.3425 +G01 X0.7415 Y0.3289 +G01 X0.7594 Y0.3215 +G01 X0.8406 Y0.3215 +G01 X0.8585 Y0.3289 +G01 X0.8721 Y0.3425 +G01 X0.8795 Y0.3604 +G01 X0.8795 Y0.3796 +G01 X0.8721 Y0.3975 +G01 X0.8585 Y0.4111 +G01 X0.8406 Y0.4185 +G00 Z0.1000 +G00 X1.1406 Y0.3185 +G01 Z-0.0070 F10 +G01 X1.0594 Y0.3185 F20 +G01 X1.0415 Y0.3111 +G01 X1.0279 Y0.2975 +G01 X1.0205 Y0.2796 +G01 X1.0205 Y0.2604 +G01 X1.0279 Y0.2425 +G01 X1.0415 Y0.2289 +G01 X1.0594 Y0.2215 +G01 X1.1406 Y0.2215 +G01 X1.1585 Y0.2289 +G01 X1.1721 Y0.2425 +G01 X1.1795 Y0.2604 +G01 X1.1795 Y0.2796 +G01 X1.1721 Y0.2975 +G01 X1.1585 Y0.3111 +G01 X1.1406 Y0.3185 +G00 Z0.1000 +G00 X0.6406 Y0.3185 +G01 Z-0.0070 F10 +G01 X0.5594 Y0.3185 F20 +G01 X0.5415 Y0.3111 +G01 X0.5279 Y0.2975 +G01 X0.5205 Y0.2796 +G01 X0.5205 Y0.2604 +G01 X0.5279 Y0.2425 +G01 X0.5415 Y0.2289 +G01 X0.5594 Y0.2215 +G01 X0.6406 Y0.2215 +G01 X0.6585 Y0.2289 +G01 X0.6721 Y0.2425 +G01 X0.6795 Y0.2604 +G01 X0.6795 Y0.2796 +G01 X0.6721 Y0.2975 +G01 X0.6585 Y0.3111 +G01 X0.6406 Y0.3185 +G00 Z0.1000 +G00 X2.1094 Y0.1015 +G01 Z-0.0070 F10 +G01 X2.1906 Y0.1015 F20 +G01 X2.2085 Y0.1089 +G01 X2.2221 Y0.1225 +G01 X2.2295 Y0.1404 +G01 X2.2295 Y0.1596 +G01 X2.2221 Y0.1775 +G01 X2.2085 Y0.1911 +G01 X2.1906 Y0.1985 +G01 X2.1094 Y0.1985 +G01 X2.0915 Y0.1911 +G01 X2.0779 Y0.1775 +G01 X2.0705 Y0.1596 +G01 X2.0705 Y0.1404 +G01 X2.0779 Y0.1225 +G01 X2.0915 Y0.1089 +G01 X2.1094 Y0.1015 +G00 Z0.1000 +G00 X2.1094 Y0.2015 +G01 Z-0.0070 F10 +G01 X2.1906 Y0.2015 F20 +G01 X2.2085 Y0.2089 +G01 X2.2221 Y0.2225 +G01 X2.2295 Y0.2404 +G01 X2.2295 Y0.2596 +G01 X2.2221 Y0.2775 +G01 X2.2085 Y0.2911 +G01 X2.1906 Y0.2985 +G01 X2.1094 Y0.2985 +G01 X2.0915 Y0.2911 +G01 X2.0779 Y0.2775 +G01 X2.0705 Y0.2596 +G01 X2.0705 Y0.2404 +G01 X2.0779 Y0.2225 +G01 X2.0915 Y0.2089 +G01 X2.1094 Y0.2015 +G00 Z0.1000 +G00 X2.1094 Y0.3015 +G01 Z-0.0070 F10 +G01 X2.1906 Y0.3015 F20 +G01 X2.2085 Y0.3089 +G01 X2.2221 Y0.3225 +G01 X2.2295 Y0.3404 +G01 X2.2295 Y0.3596 +G01 X2.2221 Y0.3775 +G01 X2.2085 Y0.3911 +G01 X2.1906 Y0.3985 +G01 X2.1094 Y0.3985 +G01 X2.0915 Y0.3911 +G01 X2.0779 Y0.3775 +G01 X2.0705 Y0.3596 +G01 X2.0705 Y0.3404 +G01 X2.0779 Y0.3225 +G01 X2.0915 Y0.3089 +G01 X2.1094 Y0.3015 +G00 Z0.1000 +G00 X1.8094 Y0.3015 +G01 Z-0.0070 F10 +G01 X1.8906 Y0.3015 F20 +G01 X1.9085 Y0.3089 +G01 X1.9221 Y0.3225 +G01 X1.9295 Y0.3404 +G01 X1.9295 Y0.3596 +G01 X1.9221 Y0.3775 +G01 X1.9085 Y0.3911 +G01 X1.8906 Y0.3985 +G01 X1.8094 Y0.3985 +G01 X1.7915 Y0.3911 +G01 X1.7779 Y0.3775 +G01 X1.7705 Y0.3596 +G01 X1.7705 Y0.3404 +G01 X1.7779 Y0.3225 +G01 X1.7915 Y0.3089 +G01 X1.8094 Y0.3015 +G00 Z0.1000 +G00 X1.8094 Y0.2015 +G01 Z-0.0070 F10 +G01 X1.8906 Y0.2015 F20 +G01 X1.9085 Y0.2089 +G01 X1.9221 Y0.2225 +G01 X1.9295 Y0.2404 +G01 X1.9295 Y0.2596 +G01 X1.9221 Y0.2775 +G01 X1.9085 Y0.2911 +G01 X1.8906 Y0.2985 +G01 X1.8094 Y0.2985 +G01 X1.7915 Y0.2911 +G01 X1.7779 Y0.2775 +G01 X1.7705 Y0.2596 +G01 X1.7705 Y0.2404 +G01 X1.7779 Y0.2225 +G01 X1.7915 Y0.2089 +G01 X1.8094 Y0.2015 +G00 Z0.1000 +G00 X1.8094 Y0.1015 +G01 Z-0.0070 F10 +G01 X1.8906 Y0.1015 F20 +G01 X1.9085 Y0.1089 +G01 X1.9221 Y0.1225 +G01 X1.9295 Y0.1404 +G01 X1.9295 Y0.1596 +G01 X1.9221 Y0.1775 +G01 X1.9085 Y0.1911 +G01 X1.8906 Y0.1985 +G01 X1.8094 Y0.1985 +G01 X1.7915 Y0.1911 +G01 X1.7779 Y0.1775 +G01 X1.7705 Y0.1596 +G01 X1.7705 Y0.1404 +G01 X1.7779 Y0.1225 +G01 X1.7915 Y0.1089 +G01 X1.8094 Y0.1015 +G00 Z0.1000 +G00 X1.8485 Y0.6599 +G01 Z-0.0070 F10 +G01 X1.8485 Y0.7001 F20 +G01 X1.8201 Y0.7285 +G01 X1.7799 Y0.7285 +G01 X1.7515 Y0.7001 +G01 X1.7515 Y0.6599 +G01 X1.7799 Y0.6315 +G01 X1.8201 Y0.6315 +G01 X1.8485 Y0.6599 +G00 Z0.1000 +G00 X1.8485 Y0.4599 +G01 Z-0.0070 F10 +G01 X1.8485 Y0.5001 F20 +G01 X1.8201 Y0.5285 +G01 X1.7799 Y0.5285 +G01 X1.7515 Y0.5001 +G01 X1.7515 Y0.4599 +G01 X1.7799 Y0.4315 +G01 X1.8201 Y0.4315 +G01 X1.8485 Y0.4599 +G00 Z0.1000 +G00 X1.9685 Y0.6599 +G01 Z-0.0070 F10 +G01 X1.9685 Y0.7001 F20 +G01 X1.9401 Y0.7285 +G01 X1.8999 Y0.7285 +G01 X1.8715 Y0.7001 +G01 X1.8715 Y0.6599 +G01 X1.8999 Y0.6315 +G01 X1.9401 Y0.6315 +G01 X1.9685 Y0.6599 +G00 Z0.1000 +G00 X1.9685 Y0.4599 +G01 Z-0.0070 F10 +G01 X1.9685 Y0.5001 F20 +G01 X1.9401 Y0.5285 +G01 X1.8999 Y0.5285 +G01 X1.8715 Y0.5001 +G01 X1.8715 Y0.4599 +G01 X1.8999 Y0.4315 +G01 X1.9401 Y0.4315 +G01 X1.9685 Y0.4599 +G00 Z0.1000 +G00 X2.0885 Y0.6599 +G01 Z-0.0070 F10 +G01 X2.0885 Y0.7001 F20 +G01 X2.0601 Y0.7285 +G01 X2.0199 Y0.7285 +G01 X1.9915 Y0.7001 +G01 X1.9915 Y0.6599 +G01 X2.0199 Y0.6315 +G01 X2.0601 Y0.6315 +G01 X2.0885 Y0.6599 +G00 Z0.1000 +G00 X2.0885 Y0.4599 +G01 Z-0.0070 F10 +G01 X2.0885 Y0.5001 F20 +G01 X2.0601 Y0.5285 +G01 X2.0199 Y0.5285 +G01 X1.9915 Y0.5001 +G01 X1.9915 Y0.4599 +G01 X2.0199 Y0.4315 +G01 X2.0601 Y0.4315 +G01 X2.0885 Y0.4599 +G00 Z0.1000 +G00 X1.3185 Y0.2099 +G01 Z-0.0070 F10 +G01 X1.3185 Y0.2501 F20 +G01 X1.2901 Y0.2785 +G01 X1.2499 Y0.2785 +G01 X1.2215 Y0.2501 +G01 X1.2215 Y0.2099 +G01 X1.2499 Y0.1815 +G01 X1.2901 Y0.1815 +G01 X1.3185 Y0.2099 +G00 Z0.1000 +G00 X1.4185 Y0.2099 +G01 Z-0.0070 F10 +G01 X1.4185 Y0.2501 F20 +G01 X1.3901 Y0.2785 +G01 X1.3499 Y0.2785 +G01 X1.3215 Y0.2501 +G01 X1.3215 Y0.2099 +G01 X1.3499 Y0.1815 +G01 X1.3901 Y0.1815 +G01 X1.4185 Y0.2099 +G00 Z0.1000 +G00 X2.3675 Y1.0020 +G01 Z-0.0070 F10 +G01 X2.3675 Y1.0580 F20 +G01 X2.3280 Y1.0975 +G01 X2.2720 Y1.0975 +G01 X2.2325 Y1.0580 +G01 X2.2325 Y1.0020 +G01 X2.2720 Y0.9625 +G01 X2.3280 Y0.9625 +G01 X2.3675 Y1.0020 +G00 Z0.1000 +G00 X2.0675 Y1.0020 +G01 Z-0.0070 F10 +G01 X2.0675 Y1.0580 F20 +G01 X2.0280 Y1.0975 +G01 X1.9720 Y1.0975 +G01 X1.9325 Y1.0580 +G01 X1.9325 Y1.0020 +G01 X1.9720 Y0.9625 +G01 X2.0280 Y0.9625 +G01 X2.0675 Y1.0020 +G00 Z0.1000 +G00 X0.5585 Y0.9799 +G01 Z-0.0070 F10 +G01 X0.5585 Y1.0201 F20 +G01 X0.5301 Y1.0485 +G01 X0.4899 Y1.0485 +G01 X0.4615 Y1.0201 +G01 X0.4615 Y0.9799 +G01 X0.4899 Y0.9515 +G01 X0.5301 Y0.9515 +G01 X0.5585 Y0.9799 +G00 Z0.1000 +G00 X0.4585 Y0.9799 +G01 Z-0.0070 F10 +G01 X0.4585 Y1.0201 F20 +G01 X0.4301 Y1.0485 +G01 X0.3899 Y1.0485 +G01 X0.3615 Y1.0201 +G01 X0.3615 Y0.9799 +G01 X0.3899 Y0.9515 +G01 X0.4301 Y0.9515 +G01 X0.4585 Y0.9799 +G00 Z0.1000 +G00 X1.4385 Y1.1499 +G01 Z-0.0070 F10 +G01 X1.4385 Y1.1901 F20 +G01 X1.4321 Y1.1965 +G01 X1.4479 Y1.1965 +G01 X1.4415 Y1.1901 +G01 X1.4415 Y1.1499 +G01 X1.4699 Y1.1215 +G01 X1.5101 Y1.1215 +G01 X1.5385 Y1.1499 +G01 X1.5385 Y1.1901 +G01 X1.5101 Y1.2185 +G01 X1.4821 Y1.2185 +G01 X1.4885 Y1.2249 +G01 X1.4885 Y1.2651 +G01 X1.4601 Y1.2935 +G01 X1.4199 Y1.2935 +G01 X1.3915 Y1.2651 +G01 X1.3915 Y1.2249 +G01 X1.3979 Y1.2185 +G01 X1.3699 Y1.2185 +G01 X1.3415 Y1.1901 +G01 X1.3415 Y1.1499 +G01 X1.3699 Y1.1215 +G01 X1.4101 Y1.1215 +G01 X1.4385 Y1.1499 +G00 Z0.1000 +G00 X1.1643 Y1.2313 +G01 Z-0.0070 F10 +G01 X1.1420 Y1.2405 F20 +G01 X1.1180 Y1.2405 +G01 X1.0957 Y1.2313 +G01 X1.0787 Y1.2143 +G01 X1.0695 Y1.1920 +G01 X1.0695 Y1.1680 +G01 X1.0787 Y1.1457 +G01 X1.0957 Y1.1287 +G01 X1.1180 Y1.1195 +G01 X1.1420 Y1.1195 +G01 X1.1643 Y1.1287 +G01 X1.1800 Y1.1444 +G01 X1.2049 Y1.1195 +G01 X1.2551 Y1.1195 +G01 X1.2905 Y1.1549 +G01 X1.2905 Y1.2051 +G01 X1.2551 Y1.2405 +G01 X1.2049 Y1.2405 +G01 X1.1800 Y1.2156 +G01 X1.1643 Y1.2313 +G00 Z0.1000 +G00 X0.2400 Y0.9687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.9500 F20 +G01 X0.2400 Y0.9313 +G01 X0.2213 Y0.9500 +G01 X0.2400 Y0.9687 +G00 Z0.1000 +G00 X0.2400 Y0.7687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.7500 F20 +G01 X0.2400 Y0.7313 +G01 X0.2213 Y0.7500 +G01 X0.2400 Y0.7687 +G00 Z0.1000 +G00 X0.2400 Y0.5687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.5500 F20 +G01 X0.2400 Y0.5313 +G01 X0.2213 Y0.5500 +G01 X0.2400 Y0.5687 +G00 Z0.1000 +G00 X0.2400 Y0.4687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.4500 F20 +G01 X0.2400 Y0.4313 +G01 X0.2213 Y0.4500 +G01 X0.2400 Y0.4687 +G00 Z0.1000 +G00 X0.2400 Y0.6687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.6500 F20 +G01 X0.2400 Y0.6313 +G01 X0.2213 Y0.6500 +G01 X0.2400 Y0.6687 +G00 Z0.1000 +G00 X0.2400 Y0.8687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.8500 F20 +G01 X0.2400 Y0.8313 +G01 X0.2213 Y0.8500 +G01 X0.2400 Y0.8687 +G00 Z0.1000 +G00 X1.8155 Y1.2070 +G01 Z-0.0070 F10 +G01 X1.8155 Y1.2330 F20 +G01 X1.8055 Y1.2571 +G01 X1.7871 Y1.2755 +G01 X1.7630 Y1.2855 +G01 X1.7370 Y1.2855 +G01 X1.7129 Y1.2755 +G01 X1.6945 Y1.2571 +G01 X1.6845 Y1.2330 +G01 X1.6845 Y1.2070 +G01 X1.6945 Y1.1829 +G01 X1.7074 Y1.1700 +G01 X1.6845 Y1.1471 +G01 X1.6845 Y1.0929 +G01 X1.7229 Y1.0545 +G01 X1.7771 Y1.0545 +G01 X1.8155 Y1.0929 +G01 X1.8155 Y1.1471 +G01 X1.7926 Y1.1700 +G01 X1.8055 Y1.1829 +G01 X1.8155 Y1.2070 +G00 Z0.1000 +G00 X0.5635 Y0.9778 +G01 Z-0.0070 F10 +G01 X0.5635 Y1.0222 F20 +G01 X0.5322 Y1.0535 +G01 X0.4878 Y1.0535 +G01 X0.4600 Y1.0257 +G01 X0.4322 Y1.0535 +G01 X0.3878 Y1.0535 +G01 X0.3565 Y1.0222 +G01 X0.3565 Y0.9778 +G01 X0.3878 Y0.9465 +G01 X0.4322 Y0.9465 +G01 X0.4600 Y0.9743 +G01 X0.4878 Y0.9465 +G01 X0.5322 Y0.9465 +G01 X0.5635 Y0.9778 +G00 Z0.1000 +G00 X2.0725 Y1.0000 +G01 Z-0.0070 F10 +G01 X2.0725 Y1.0600 F20 +G01 X2.0300 Y1.1025 +G01 X1.9700 Y1.1025 +G01 X1.9275 Y1.0600 +G01 X1.9275 Y1.0000 +G01 X1.9700 Y0.9575 +G01 X2.0300 Y0.9575 +G01 X2.0725 Y1.0000 +G00 Z0.1000 +G00 X2.3725 Y1.0000 +G01 Z-0.0070 F10 +G01 X2.3725 Y1.0600 F20 +G01 X2.3300 Y1.1025 +G01 X2.2700 Y1.1025 +G01 X2.2275 Y1.0600 +G01 X2.2275 Y1.0000 +G01 X2.2700 Y0.9575 +G01 X2.3300 Y0.9575 +G01 X2.3725 Y1.0000 +G00 Z0.1000 +G00 X0.3475 Y0.9762 +G01 Z-0.0070 F10 +G01 X0.3475 Y1.0238 F20 +G01 X0.3138 Y1.0575 +G01 X0.2662 Y1.0575 +G01 X0.2400 Y1.0313 +G01 X0.2138 Y1.0575 +G01 X0.1662 Y1.0575 +G01 X0.1325 Y1.0238 +G01 X0.1325 Y0.9762 +G01 X0.1587 Y0.9500 +G01 X0.1325 Y0.9238 +G01 X0.1325 Y0.8762 +G01 X0.1587 Y0.8500 +G01 X0.1325 Y0.8238 +G01 X0.1325 Y0.7762 +G01 X0.1587 Y0.7500 +G01 X0.1325 Y0.7238 +G01 X0.1325 Y0.6762 +G01 X0.1587 Y0.6500 +G01 X0.1325 Y0.6238 +G01 X0.1325 Y0.5762 +G01 X0.1587 Y0.5500 +G01 X0.1325 Y0.5238 +G01 X0.1325 Y0.4762 +G01 X0.1587 Y0.4500 +G01 X0.1325 Y0.4238 +G01 X0.1325 Y0.3762 +G01 X0.1662 Y0.3425 +G01 X0.2138 Y0.3425 +G01 X0.2400 Y0.3687 +G01 X0.2662 Y0.3425 +G01 X0.3138 Y0.3425 +G01 X0.3475 Y0.3762 +G01 X0.3475 Y0.4238 +G01 X0.3213 Y0.4500 +G01 X0.3475 Y0.4762 +G01 X0.3475 Y0.5238 +G01 X0.3213 Y0.5500 +G01 X0.3475 Y0.5762 +G01 X0.3475 Y0.6238 +G01 X0.3213 Y0.6500 +G01 X0.3475 Y0.6762 +G01 X0.3475 Y0.7238 +G01 X0.3213 Y0.7500 +G01 X0.3475 Y0.7762 +G01 X0.3475 Y0.8238 +G01 X0.3213 Y0.8500 +G01 X0.3475 Y0.8762 +G01 X0.3475 Y0.9238 +G01 X0.3213 Y0.9500 +G01 X0.3475 Y0.9762 +G00 Z0.1000 +G00 X1.5284 Y0.2865 +G01 Z-0.0070 F10 +G01 X1.6116 Y0.2865 F20 +G01 X1.6313 Y0.2946 +G01 X1.6464 Y0.3097 +G01 X1.6545 Y0.3294 +G01 X1.6545 Y0.3506 +G01 X1.6464 Y0.3703 +G01 X1.6313 Y0.3854 +G01 X1.6201 Y0.3900 +G01 X1.6313 Y0.3946 +G01 X1.6464 Y0.4097 +G01 X1.6545 Y0.4294 +G01 X1.6545 Y0.4506 +G01 X1.6464 Y0.4703 +G01 X1.6313 Y0.4854 +G01 X1.6201 Y0.4900 +G01 X1.6313 Y0.4946 +G01 X1.6464 Y0.5097 +G01 X1.6545 Y0.5294 +G01 X1.6545 Y0.5506 +G01 X1.6464 Y0.5703 +G01 X1.6313 Y0.5854 +G01 X1.6201 Y0.5900 +G01 X1.6313 Y0.5946 +G01 X1.6464 Y0.6097 +G01 X1.6545 Y0.6294 +G01 X1.6545 Y0.6506 +G01 X1.6464 Y0.6703 +G01 X1.6313 Y0.6854 +G01 X1.6201 Y0.6900 +G01 X1.6313 Y0.6946 +G01 X1.6464 Y0.7097 +G01 X1.6545 Y0.7294 +G01 X1.6545 Y0.7506 +G01 X1.6464 Y0.7703 +G01 X1.6313 Y0.7854 +G01 X1.6201 Y0.7900 +G01 X1.6313 Y0.7946 +G01 X1.6464 Y0.8097 +G01 X1.6545 Y0.8294 +G01 X1.6545 Y0.8506 +G01 X1.6464 Y0.8703 +G01 X1.6313 Y0.8854 +G01 X1.6201 Y0.8900 +G01 X1.6313 Y0.8946 +G01 X1.6464 Y0.9097 +G01 X1.6545 Y0.9294 +G01 X1.6545 Y0.9506 +G01 X1.6464 Y0.9703 +G01 X1.6313 Y0.9854 +G01 X1.6201 Y0.9900 +G01 X1.6313 Y0.9946 +G01 X1.6464 Y1.0097 +G01 X1.6545 Y1.0294 +G01 X1.6545 Y1.0506 +G01 X1.6464 Y1.0703 +G01 X1.6313 Y1.0854 +G01 X1.6116 Y1.0935 +G01 X1.5284 Y1.0935 +G01 X1.5087 Y1.0854 +G01 X1.4936 Y1.0703 +G01 X1.4855 Y1.0506 +G01 X1.4855 Y1.0294 +G01 X1.4936 Y1.0097 +G01 X1.5087 Y0.9946 +G01 X1.5199 Y0.9900 +G01 X1.5087 Y0.9854 +G01 X1.4936 Y0.9703 +G01 X1.4855 Y0.9506 +G01 X1.4855 Y0.9294 +G01 X1.4936 Y0.9097 +G01 X1.5087 Y0.8946 +G01 X1.5199 Y0.8900 +G01 X1.5087 Y0.8854 +G01 X1.4936 Y0.8703 +G01 X1.4855 Y0.8506 +G01 X1.4855 Y0.8294 +G01 X1.4936 Y0.8097 +G01 X1.5087 Y0.7946 +G01 X1.5199 Y0.7900 +G01 X1.5087 Y0.7854 +G01 X1.4936 Y0.7703 +G01 X1.4855 Y0.7506 +G01 X1.4855 Y0.7294 +G01 X1.4936 Y0.7097 +G01 X1.5087 Y0.6946 +G01 X1.5199 Y0.6900 +G01 X1.5087 Y0.6854 +G01 X1.4936 Y0.6703 +G01 X1.4855 Y0.6506 +G01 X1.4855 Y0.6294 +G01 X1.4936 Y0.6097 +G01 X1.5087 Y0.5946 +G01 X1.5199 Y0.5900 +G01 X1.5087 Y0.5854 +G01 X1.4936 Y0.5703 +G01 X1.4855 Y0.5506 +G01 X1.4855 Y0.5294 +G01 X1.4936 Y0.5097 +G01 X1.5087 Y0.4946 +G01 X1.5199 Y0.4900 +G01 X1.5087 Y0.4854 +G01 X1.4936 Y0.4703 +G01 X1.4855 Y0.4506 +G01 X1.4855 Y0.4294 +G01 X1.4936 Y0.4097 +G01 X1.5087 Y0.3946 +G01 X1.5199 Y0.3900 +G01 X1.5087 Y0.3854 +G01 X1.4936 Y0.3703 +G01 X1.4855 Y0.3506 +G01 X1.4855 Y0.3294 +G01 X1.4936 Y0.3097 +G01 X1.5087 Y0.2946 +G01 X1.5284 Y0.2865 +G00 Z0.1000 +G00 X0.8112 Y0.7437 +G01 Z-0.0070 F10 +G01 X0.8309 Y0.7356 F20 +G01 X0.8521 Y0.7356 +G01 X0.8718 Y0.7437 +G01 X0.8809 Y0.7528 +G01 X0.8899 Y0.7437 +G01 X0.9096 Y0.7356 +G01 X0.9309 Y0.7356 +G01 X0.9505 Y0.7437 +G01 X0.9656 Y0.7587 +G01 X0.9737 Y0.7784 +G01 X0.9737 Y0.8617 +G01 X0.9656 Y0.8814 +G01 X0.9505 Y0.8964 +G01 X0.9309 Y0.9046 +G01 X0.9096 Y0.9046 +G01 X0.8899 Y0.8964 +G01 X0.8809 Y0.8873 +G01 X0.8718 Y0.8964 +G01 X0.8521 Y0.9046 +G01 X0.8309 Y0.9046 +G01 X0.8112 Y0.8964 +G01 X0.8021 Y0.8873 +G01 X0.7931 Y0.8964 +G01 X0.7734 Y0.9046 +G01 X0.7521 Y0.9046 +G01 X0.7324 Y0.8964 +G01 X0.7174 Y0.8814 +G01 X0.7093 Y0.8617 +G01 X0.7093 Y0.7784 +G01 X0.7174 Y0.7587 +G01 X0.7324 Y0.7437 +G01 X0.7521 Y0.7356 +G01 X0.7734 Y0.7356 +G01 X0.7931 Y0.7437 +G01 X0.8021 Y0.7528 +G01 X0.8112 Y0.7437 +G00 Z0.1000 +G00 X0.8324 Y0.7163 +G01 Z-0.0070 F10 +G01 X0.8128 Y0.7244 F20 +G01 X0.7915 Y0.7244 +G01 X0.7718 Y0.7163 +G01 X0.7628 Y0.7072 +G01 X0.7537 Y0.7163 +G01 X0.7340 Y0.7244 +G01 X0.7127 Y0.7244 +G01 X0.6931 Y0.7163 +G01 X0.6780 Y0.7012 +G01 X0.6699 Y0.6816 +G01 X0.6699 Y0.5983 +G01 X0.6780 Y0.5786 +G01 X0.6931 Y0.5636 +G01 X0.7127 Y0.5554 +G01 X0.7340 Y0.5554 +G01 X0.7537 Y0.5636 +G01 X0.7628 Y0.5727 +G01 X0.7718 Y0.5636 +G01 X0.7915 Y0.5554 +G01 X0.8128 Y0.5554 +G01 X0.8324 Y0.5636 +G01 X0.8415 Y0.5727 +G01 X0.8506 Y0.5636 +G01 X0.8702 Y0.5554 +G01 X0.8915 Y0.5554 +G01 X0.9112 Y0.5636 +G01 X0.9262 Y0.5786 +G01 X0.9344 Y0.5983 +G01 X0.9344 Y0.6816 +G01 X0.9262 Y0.7012 +G01 X0.9112 Y0.7163 +G01 X0.8915 Y0.7244 +G01 X0.8702 Y0.7244 +G01 X0.8506 Y0.7163 +G01 X0.8415 Y0.7072 +G01 X0.8324 Y0.7163 +G00 Z0.1000 +G00 X1.3313 Y0.9946 +G01 Z-0.0070 F10 +G01 X1.3464 Y1.0097 F20 +G01 X1.3545 Y1.0294 +G01 X1.3545 Y1.0506 +G01 X1.3464 Y1.0703 +G01 X1.3313 Y1.0854 +G01 X1.3116 Y1.0935 +G01 X1.2284 Y1.0935 +G01 X1.2087 Y1.0854 +G01 X1.1936 Y1.0703 +G01 X1.1855 Y1.0506 +G01 X1.1855 Y1.0294 +G01 X1.1936 Y1.0097 +G01 X1.2087 Y0.9946 +G01 X1.2199 Y0.9900 +G01 X1.2087 Y0.9854 +G01 X1.1936 Y0.9703 +G01 X1.1855 Y0.9506 +G01 X1.1855 Y0.9294 +G01 X1.1936 Y0.9097 +G01 X1.2087 Y0.8946 +G01 X1.2199 Y0.8900 +G01 X1.2087 Y0.8854 +G01 X1.1936 Y0.8703 +G01 X1.1855 Y0.8506 +G01 X1.1855 Y0.8294 +G01 X1.1936 Y0.8097 +G01 X1.2087 Y0.7946 +G01 X1.2199 Y0.7900 +G01 X1.2087 Y0.7854 +G01 X1.1936 Y0.7703 +G01 X1.1855 Y0.7506 +G01 X1.1855 Y0.7294 +G01 X1.1936 Y0.7097 +G01 X1.2087 Y0.6946 +G01 X1.2199 Y0.6900 +G01 X1.2087 Y0.6854 +G01 X1.1936 Y0.6703 +G01 X1.1855 Y0.6506 +G01 X1.1855 Y0.6294 +G01 X1.1936 Y0.6097 +G01 X1.2087 Y0.5946 +G01 X1.2199 Y0.5900 +G01 X1.2087 Y0.5854 +G01 X1.1936 Y0.5703 +G01 X1.1855 Y0.5506 +G01 X1.1855 Y0.5294 +G01 X1.1936 Y0.5097 +G01 X1.2087 Y0.4946 +G01 X1.2199 Y0.4900 +G01 X1.2087 Y0.4854 +G01 X1.1936 Y0.4703 +G01 X1.1855 Y0.4506 +G01 X1.1855 Y0.4294 +G01 X1.1936 Y0.4097 +G01 X1.2087 Y0.3946 +G01 X1.2199 Y0.3900 +G01 X1.2087 Y0.3854 +G01 X1.1936 Y0.3703 +G01 X1.1855 Y0.3506 +G01 X1.1855 Y0.3294 +G01 X1.1936 Y0.3097 +G01 X1.2087 Y0.2946 +G01 X1.2284 Y0.2865 +G01 X1.3116 Y0.2865 +G01 X1.3313 Y0.2946 +G01 X1.3464 Y0.3097 +G01 X1.3545 Y0.3294 +G01 X1.3545 Y0.3506 +G01 X1.3464 Y0.3703 +G01 X1.3313 Y0.3854 +G01 X1.3201 Y0.3900 +G01 X1.3313 Y0.3946 +G01 X1.3464 Y0.4097 +G01 X1.3545 Y0.4294 +G01 X1.3545 Y0.4506 +G01 X1.3464 Y0.4703 +G01 X1.3313 Y0.4854 +G01 X1.3201 Y0.4900 +G01 X1.3313 Y0.4946 +G01 X1.3464 Y0.5097 +G01 X1.3545 Y0.5294 +G01 X1.3545 Y0.5506 +G01 X1.3464 Y0.5703 +G01 X1.3313 Y0.5854 +G01 X1.3201 Y0.5900 +G01 X1.3313 Y0.5946 +G01 X1.3464 Y0.6097 +G01 X1.3545 Y0.6294 +G01 X1.3545 Y0.6506 +G01 X1.3464 Y0.6703 +G01 X1.3313 Y0.6854 +G01 X1.3201 Y0.6900 +G01 X1.3313 Y0.6946 +G01 X1.3464 Y0.7097 +G01 X1.3545 Y0.7294 +G01 X1.3545 Y0.7506 +G01 X1.3464 Y0.7703 +G01 X1.3313 Y0.7854 +G01 X1.3201 Y0.7900 +G01 X1.3313 Y0.7946 +G01 X1.3464 Y0.8097 +G01 X1.3545 Y0.8294 +G01 X1.3545 Y0.8506 +G01 X1.3464 Y0.8703 +G01 X1.3313 Y0.8854 +G01 X1.3201 Y0.8900 +G01 X1.3313 Y0.8946 +G01 X1.3464 Y0.9097 +G01 X1.3545 Y0.9294 +G01 X1.3545 Y0.9506 +G01 X1.3464 Y0.9703 +G01 X1.3313 Y0.9854 +G01 X1.3201 Y0.9900 +G01 X1.3313 Y0.9946 +G00 Z0.1000 +G00 X0.8416 Y0.4235 +G01 Z-0.0070 F10 +G01 X0.7584 Y0.4235 F20 +G01 X0.7387 Y0.4154 +G01 X0.7236 Y0.4003 +G01 X0.7155 Y0.3806 +G01 X0.7155 Y0.3594 +G01 X0.7236 Y0.3397 +G01 X0.7387 Y0.3246 +G01 X0.7584 Y0.3165 +G01 X0.8416 Y0.3165 +G01 X0.8613 Y0.3246 +G01 X0.8764 Y0.3397 +G01 X0.8845 Y0.3594 +G01 X0.8845 Y0.3806 +G01 X0.8764 Y0.4003 +G01 X0.8613 Y0.4154 +G01 X0.8416 Y0.4235 +G00 Z0.1000 +G00 X1.1416 Y0.3235 +G01 Z-0.0070 F10 +G01 X1.0584 Y0.3235 F20 +G01 X1.0387 Y0.3154 +G01 X1.0236 Y0.3003 +G01 X1.0155 Y0.2806 +G01 X1.0155 Y0.2594 +G01 X1.0236 Y0.2397 +G01 X1.0387 Y0.2246 +G01 X1.0584 Y0.2165 +G01 X1.1416 Y0.2165 +G01 X1.1613 Y0.2246 +G01 X1.1764 Y0.2397 +G01 X1.1845 Y0.2594 +G01 X1.1845 Y0.2806 +G01 X1.1764 Y0.3003 +G01 X1.1613 Y0.3154 +G01 X1.1416 Y0.3235 +G00 Z0.1000 +G00 X0.6416 Y0.3235 +G01 Z-0.0070 F10 +G01 X0.5584 Y0.3235 F20 +G01 X0.5387 Y0.3154 +G01 X0.5236 Y0.3003 +G01 X0.5155 Y0.2806 +G01 X0.5155 Y0.2594 +G01 X0.5236 Y0.2397 +G01 X0.5387 Y0.2246 +G01 X0.5584 Y0.2165 +G01 X0.6416 Y0.2165 +G01 X0.6613 Y0.2246 +G01 X0.6764 Y0.2397 +G01 X0.6845 Y0.2594 +G01 X0.6845 Y0.2806 +G01 X0.6764 Y0.3003 +G01 X0.6613 Y0.3154 +G01 X0.6416 Y0.3235 +G00 Z0.1000 +G00 X2.1084 Y0.0965 +G01 Z-0.0070 F10 +G01 X2.1916 Y0.0965 F20 +G01 X2.2113 Y0.1046 +G01 X2.2264 Y0.1197 +G01 X2.2345 Y0.1394 +G01 X2.2345 Y0.1606 +G01 X2.2264 Y0.1803 +G01 X2.2113 Y0.1954 +G01 X2.2001 Y0.2000 +G01 X2.2113 Y0.2046 +G01 X2.2264 Y0.2197 +G01 X2.2345 Y0.2394 +G01 X2.2345 Y0.2606 +G01 X2.2264 Y0.2803 +G01 X2.2113 Y0.2954 +G01 X2.2001 Y0.3000 +G01 X2.2113 Y0.3046 +G01 X2.2264 Y0.3197 +G01 X2.2345 Y0.3394 +G01 X2.2345 Y0.3606 +G01 X2.2264 Y0.3803 +G01 X2.2113 Y0.3954 +G01 X2.1916 Y0.4035 +G01 X2.1084 Y0.4035 +G01 X2.0887 Y0.3954 +G01 X2.0736 Y0.3803 +G01 X2.0655 Y0.3606 +G01 X2.0655 Y0.3394 +G01 X2.0736 Y0.3197 +G01 X2.0887 Y0.3046 +G01 X2.0999 Y0.3000 +G01 X2.0887 Y0.2954 +G01 X2.0736 Y0.2803 +G01 X2.0655 Y0.2606 +G01 X2.0655 Y0.2394 +G01 X2.0736 Y0.2197 +G01 X2.0887 Y0.2046 +G01 X2.0999 Y0.2000 +G01 X2.0887 Y0.1954 +G01 X2.0736 Y0.1803 +G01 X2.0655 Y0.1606 +G01 X2.0655 Y0.1394 +G01 X2.0736 Y0.1197 +G01 X2.0887 Y0.1046 +G01 X2.1084 Y0.0965 +G00 Z0.1000 +G00 X1.9113 Y0.3046 +G01 Z-0.0070 F10 +G01 X1.9264 Y0.3197 F20 +G01 X1.9345 Y0.3394 +G01 X1.9345 Y0.3606 +G01 X1.9264 Y0.3803 +G01 X1.9113 Y0.3954 +G01 X1.8916 Y0.4035 +G01 X1.8084 Y0.4035 +G01 X1.7887 Y0.3954 +G01 X1.7736 Y0.3803 +G01 X1.7655 Y0.3606 +G01 X1.7655 Y0.3394 +G01 X1.7736 Y0.3197 +G01 X1.7887 Y0.3046 +G01 X1.7999 Y0.3000 +G01 X1.7887 Y0.2954 +G01 X1.7736 Y0.2803 +G01 X1.7655 Y0.2606 +G01 X1.7655 Y0.2394 +G01 X1.7736 Y0.2197 +G01 X1.7887 Y0.2046 +G01 X1.7999 Y0.2000 +G01 X1.7887 Y0.1954 +G01 X1.7736 Y0.1803 +G01 X1.7655 Y0.1606 +G01 X1.7655 Y0.1394 +G01 X1.7736 Y0.1197 +G01 X1.7887 Y0.1046 +G01 X1.8084 Y0.0965 +G01 X1.8916 Y0.0965 +G01 X1.9113 Y0.1046 +G01 X1.9264 Y0.1197 +G01 X1.9345 Y0.1394 +G01 X1.9345 Y0.1606 +G01 X1.9264 Y0.1803 +G01 X1.9113 Y0.1954 +G01 X1.9001 Y0.2000 +G01 X1.9113 Y0.2046 +G01 X1.9264 Y0.2197 +G01 X1.9345 Y0.2394 +G01 X1.9345 Y0.2606 +G01 X1.9264 Y0.2803 +G01 X1.9113 Y0.2954 +G01 X1.9001 Y0.3000 +G01 X1.9113 Y0.3046 +G00 Z0.1000 +G00 X1.8535 Y0.6578 +G01 Z-0.0070 F10 +G01 X1.8535 Y0.7022 F20 +G01 X1.8222 Y0.7335 +G01 X1.7778 Y0.7335 +G01 X1.7465 Y0.7022 +G01 X1.7465 Y0.6578 +G01 X1.7778 Y0.6265 +G01 X1.8222 Y0.6265 +G01 X1.8535 Y0.6578 +G00 Z0.1000 +G00 X1.8535 Y0.4578 +G01 Z-0.0070 F10 +G01 X1.8535 Y0.5022 F20 +G01 X1.8222 Y0.5335 +G01 X1.7778 Y0.5335 +G01 X1.7465 Y0.5022 +G01 X1.7465 Y0.4578 +G01 X1.7778 Y0.4265 +G01 X1.8222 Y0.4265 +G01 X1.8535 Y0.4578 +G00 Z0.1000 +G00 X1.9735 Y0.6578 +G01 Z-0.0070 F10 +G01 X1.9735 Y0.7022 F20 +G01 X1.9422 Y0.7335 +G01 X1.8978 Y0.7335 +G01 X1.8665 Y0.7022 +G01 X1.8665 Y0.6578 +G01 X1.8978 Y0.6265 +G01 X1.9422 Y0.6265 +G01 X1.9735 Y0.6578 +G00 Z0.1000 +G00 X1.9735 Y0.4578 +G01 Z-0.0070 F10 +G01 X1.9735 Y0.5022 F20 +G01 X1.9422 Y0.5335 +G01 X1.8978 Y0.5335 +G01 X1.8665 Y0.5022 +G01 X1.8665 Y0.4578 +G01 X1.8978 Y0.4265 +G01 X1.9422 Y0.4265 +G01 X1.9735 Y0.4578 +G00 Z0.1000 +G00 X2.0935 Y0.6578 +G01 Z-0.0070 F10 +G01 X2.0935 Y0.7022 F20 +G01 X2.0622 Y0.7335 +G01 X2.0178 Y0.7335 +G01 X1.9865 Y0.7022 +G01 X1.9865 Y0.6578 +G01 X2.0178 Y0.6265 +G01 X2.0622 Y0.6265 +G01 X2.0935 Y0.6578 +G00 Z0.1000 +G00 X2.0935 Y0.4578 +G01 Z-0.0070 F10 +G01 X2.0935 Y0.5022 F20 +G01 X2.0622 Y0.5335 +G01 X2.0178 Y0.5335 +G01 X1.9865 Y0.5022 +G01 X1.9865 Y0.4578 +G01 X2.0178 Y0.4265 +G01 X2.0622 Y0.4265 +G01 X2.0935 Y0.4578 +G00 Z0.1000 +G00 X1.2922 Y0.2835 +G01 Z-0.0070 F10 +G01 X1.2478 Y0.2835 F20 +G01 X1.2165 Y0.2522 +G01 X1.2165 Y0.2078 +G01 X1.2478 Y0.1765 +G01 X1.2922 Y0.1765 +G01 X1.3200 Y0.2043 +G01 X1.3478 Y0.1765 +G01 X1.3922 Y0.1765 +G01 X1.4235 Y0.2078 +G01 X1.4235 Y0.2522 +G01 X1.3922 Y0.2835 +G01 X1.3478 Y0.2835 +G01 X1.3200 Y0.2557 +G01 X1.2922 Y0.2835 +G00 Z0.1000 +G00 X1.4935 Y1.2672 +G01 Z-0.0070 F10 +G01 X1.4622 Y1.2985 F20 +G01 X1.4178 Y1.2985 +G01 X1.3865 Y1.2672 +G01 X1.3865 Y1.2235 +G01 X1.3678 Y1.2235 +G01 X1.3365 Y1.1922 +G01 X1.3365 Y1.1478 +G01 X1.3678 Y1.1165 +G01 X1.4122 Y1.1165 +G01 X1.4400 Y1.1443 +G01 X1.4678 Y1.1165 +G01 X1.5122 Y1.1165 +G01 X1.5435 Y1.1478 +G01 X1.5435 Y1.1922 +G01 X1.5122 Y1.2235 +G01 X1.4935 Y1.2235 +G01 X1.4935 Y1.2672 +G00 Z0.1000 +G00 X1.1671 Y1.2355 +G01 Z-0.0070 F10 +G01 X1.1430 Y1.2455 F20 +G01 X1.1170 Y1.2455 +G01 X1.0929 Y1.2355 +G01 X1.0745 Y1.2171 +G01 X1.0645 Y1.1930 +G01 X1.0645 Y1.1670 +G01 X1.0745 Y1.1429 +G01 X1.0929 Y1.1245 +G01 X1.1170 Y1.1145 +G01 X1.1430 Y1.1145 +G01 X1.1671 Y1.1245 +G01 X1.1800 Y1.1374 +G01 X1.2029 Y1.1145 +G01 X1.2571 Y1.1145 +G01 X1.2955 Y1.1529 +G01 X1.2955 Y1.2071 +G01 X1.2571 Y1.2455 +G01 X1.2029 Y1.2455 +G01 X1.1800 Y1.2226 +G01 X1.1671 Y1.2355 +G00 Z0.1000 +G00 X0.1500 Y1.1900 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1500 Y0.1300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.2300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.3700 Y0.2300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.5100 Y1.0000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.4100 Y1.0000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.1300 Y1.1800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2300 Y1.1800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.7500 Y1.2200 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.7500 Y1.1200 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.3400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.4400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.5400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.6400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.7400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.8400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.9400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y1.0400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y1.0400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.9400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.8400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.7400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.6400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.5400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.4400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.3400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.3900 Y1.1700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.4400 Y1.2450 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.4900 Y1.1700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.6000 Y0.2700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.1000 Y0.2700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.8000 Y0.3700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8000 Y0.6800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8000 Y0.4800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.9200 Y0.6800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.9200 Y0.4800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.0400 Y0.6800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.0400 Y0.4800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.1500 Y0.1500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.1500 Y0.2500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.1500 Y0.3500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8500 Y0.3500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8500 Y0.2500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8500 Y0.1500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.0000 Y1.0300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.3000 Y1.0300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.7234 Y0.6709 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.7628 Y0.7891 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.8021 Y0.6709 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.8415 Y0.7891 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.8809 Y0.6709 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.9202 Y0.7891 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.1171 Y0.7576 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.5029 Y0.7576 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y1.0000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y1.0000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.9000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.9000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.8000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.8000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.7000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.7000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.6000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.6000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.5000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.5000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.4000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.4000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.top.mill.tap b/trunk/ulp/docs/examples/04151_lcdi2c.top.mill.tap new file mode 100644 index 00000000..d41e9bcd --- /dev/null +++ b/trunk/ulp/docs/examples/04151_lcdi2c.top.mill.tap @@ -0,0 +1,46 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G01 X0.0100 Y-0.0100 +G01 X2.7900 Y-0.0100 +G01 X2.7900 Y1.3300 +G00 Z0.1000 +G00 X-0.0100 Y1.3200 +G01 Z-0.0100 F10 +G01 X-0.0100 Y0.0000 F20 +G00 Z0.1000 +G00 X-0.0100 Y1.3300 +G01 Z-0.0100 F10 +G01 X2.7900 Y1.3300 F20 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/04151_lcdi2c.top.text.tap b/trunk/ulp/docs/examples/04151_lcdi2c.top.text.tap new file mode 100644 index 00000000..20ccd74b --- /dev/null +++ b/trunk/ulp/docs/examples/04151_lcdi2c.top.text.tap @@ -0,0 +1,35 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0100 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/enabtmr.bot.drill.tap b/trunk/ulp/docs/examples/enabtmr.bot.drill.tap new file mode 100644 index 00000000..9501c375 --- /dev/null +++ b/trunk/ulp/docs/examples/enabtmr.bot.drill.tap @@ -0,0 +1,163 @@ +(.../src/pcbgcode-work/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode-work/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/16/12 5:51 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0050 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0030) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +( Tool| Size | Min Sub | Max Sub | Count ) +( T01 | 0.600mm 0.0236in | 0.0000in | 0.0000in | 0 ) +( T02 | 0.813mm 0.0320in | 0.0000in | 0.0000in | 0 ) +( T03 | 1.118mm 0.0440in | 0.0000in | 0.0000in | 0 ) +( T04 | 1.194mm 0.0470in | 0.0000in | 0.0000in | 0 ) +( T05 | 2.800mm 0.1102in | 0.0000in | 0.0000in | 0 ) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T01 ; 0.0236 +G01 Z0.0000 F10 +M06 T01 ; 0.0236 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-1.6400 Y1.2700 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-1.9000 Y0.5700 +G82 X-1.9700 Y1.4700 +G82 X-1.9700 Y1.7900 +G82 X-2.2100 Y1.4700 +G82 X-2.2100 Y1.7400 +G82 X-2.5100 Y0.4600 +G82 X-2.5100 Y0.9100 +M05 +G00 Z1.0000 +M06 T02 ; 0.0320 +G01 Z0.0000 F10 +M06 T02 ; 0.0320 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.5600 Y0.9100 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.5600 Y1.1100 +G82 X-0.7200 Y1.3100 +G82 X-0.7200 Y1.5100 +G82 X-0.7600 Y1.8600 +G82 X-0.7800 Y0.3400 +G82 X-0.7800 Y0.5400 +G82 X-0.9500 Y0.8100 +G82 X-0.9500 Y0.9100 +G82 X-0.9500 Y1.0100 +G82 X-0.9500 Y1.1100 +G82 X-0.9500 Y1.2100 +G82 X-0.9500 Y1.3100 +G82 X-0.9500 Y1.4100 +G82 X-1.2500 Y0.8100 +G82 X-1.2500 Y0.9100 +G82 X-1.2500 Y1.0100 +G82 X-1.2500 Y1.1100 +G82 X-1.2500 Y1.2100 +G82 X-1.2500 Y1.3100 +G82 X-1.2500 Y1.4100 +G82 X-1.3200 Y0.2000 +G82 X-1.3600 Y1.8600 +G82 X-1.4300 Y0.7100 +G82 X-1.4300 Y1.2100 +G82 X-1.5000 Y1.9100 +G82 X-1.5500 Y0.6600 +G82 X-1.7500 Y0.6600 +G82 X-1.7700 Y1.2000 +G82 X-1.7700 Y1.7000 +G82 X-1.8200 Y0.2000 +G82 X-1.9600 Y1.0100 +G82 X-1.9600 Y1.1100 +G82 X-1.9600 Y1.2100 +G82 X-1.9600 Y1.3100 +G82 X-2.0000 Y1.9100 +G82 X-2.1400 Y0.2600 +G82 X-2.2600 Y1.0100 +G82 X-2.2600 Y1.1100 +G82 X-2.2600 Y1.2100 +G82 X-2.2600 Y1.3100 +G82 X-2.3000 Y1.4400 +G82 X-2.3400 Y1.7400 +G82 X-2.3900 Y1.6650 +G82 X-2.4400 Y1.7400 +G82 X-2.6400 Y0.2600 +G82 X-2.6600 Y1.6100 +G82 X-2.6700 Y0.7500 +G82 X-2.6700 Y1.2500 +G82 X-2.6700 Y1.7200 +G82 X-2.6700 Y1.8200 +G82 X-2.9000 Y1.4400 +G82 X-2.9500 Y1.1300 +G82 X-2.9500 Y1.3300 +G82 X-3.1600 Y1.6100 +M05 +G00 Z1.0000 +M06 T03 ; 0.0440 +G01 Z0.0000 F10 +M06 T03 ; 0.0440 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-1.4200 Y0.3400 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-1.4200 Y0.5000 +G82 X-1.5000 Y1.3100 +G82 X-1.5000 Y1.7100 +G82 X-1.8200 Y0.3400 +G82 X-1.8200 Y0.5000 +G82 X-2.0100 Y0.2600 +G82 X-2.0100 Y0.6600 +M05 +G00 Z1.0000 +M06 T04 ; 0.0470 +G01 Z0.0000 F10 +M06 T04 ; 0.0470 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.2000 Y0.7116 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.2000 Y0.9084 +G82 X-0.2000 Y1.1116 +G82 X-0.2000 Y1.3084 +G82 X-0.2000 Y1.5916 +G82 X-0.2000 Y1.7884 +G82 X-2.9200 Y0.5516 +G82 X-2.9200 Y0.7484 +M05 +G00 Z1.0000 +M06 T05 ; 0.1102 +G01 Z0.0000 F10 +M06 T05 ; 0.1102 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.2200 Y0.1800 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.2300 Y2.0300 +G82 X-3.0700 Y0.1900 +G82 X-3.0700 Y2.0100 +T01 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/enabtmr.bot.etch.tap b/trunk/ulp/docs/examples/enabtmr.bot.etch.tap new file mode 100644 index 00000000..8a0f9c45 --- /dev/null +++ b/trunk/ulp/docs/examples/enabtmr.bot.etch.tap @@ -0,0 +1,15522 @@ +(.../src/pcbgcode-work/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode-work/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/16/12 5:50 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0050 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0030) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-0.4315 Y0.2844 +G01 Z-0.0070 F10 +G01 X-0.4315 Y0.2844 F20 +G01 X-0.4435 Y0.2555 +G01 X-0.4655 Y0.2335 +G01 X-0.4944 Y0.2215 +G01 X-0.5043 Y0.2215 +G01 X-0.5100 Y0.2215 +G01 X-0.5157 Y0.2215 +G01 X-1.0400 Y0.2215 +G01 X-1.0442 Y0.2211 +G01 X-1.0519 Y0.2179 +G01 X-1.0579 Y0.2119 +G01 X-1.0611 Y0.2042 +G01 X-1.0615 Y0.2000 +G01 X-1.0615 Y0.1970 +G01 X-1.0615 Y0.1943 +G01 X-1.0615 Y0.1443 +G01 X-1.0615 Y0.1344 +G01 X-1.0735 Y0.1055 +G01 X-1.0955 Y0.0835 +G01 X-1.1244 Y0.0715 +G01 X-1.1343 Y0.0715 +G01 X-1.6057 Y0.0715 +G01 X-1.6156 Y0.0715 +G01 X-1.6445 Y0.0835 +G01 X-1.6665 Y0.1055 +G01 X-1.6785 Y0.1344 +G01 X-1.6785 Y0.1443 +G01 X-1.6785 Y0.1509 +G01 X-1.6785 Y0.1557 +G01 X-1.6785 Y0.8657 +G01 X-1.6785 Y0.8756 +G01 X-1.6665 Y0.9045 +G01 X-1.6445 Y0.9265 +G01 X-1.6156 Y0.9385 +G01 X-1.6057 Y0.9385 +G01 X-1.6000 Y0.9385 +G01 X-1.5943 Y0.9385 +G01 X-1.3372 Y0.9385 +G01 X-1.3305 Y0.9452 +G01 X-1.3153 Y0.9515 +G01 X-1.1847 Y0.9515 +G01 X-1.1695 Y0.9452 +G01 X-1.1578 Y0.9335 +G01 X-1.1515 Y0.9183 +G01 X-1.1515 Y0.9017 +G01 X-1.1578 Y0.8865 +G01 X-1.1695 Y0.8748 +G01 X-1.1847 Y0.8685 +G01 X-1.3153 Y0.8685 +G01 X-1.3305 Y0.8748 +G01 X-1.3372 Y0.8815 +G01 X-1.5943 Y0.8815 +G01 X-1.6000 Y0.8815 +G01 X-1.6042 Y0.8811 +G01 X-1.6119 Y0.8779 +G01 X-1.6179 Y0.8719 +G01 X-1.6211 Y0.8642 +G01 X-1.6215 Y0.8600 +G01 X-1.6215 Y0.1557 +G01 X-1.6215 Y0.1508 +G01 X-1.6215 Y0.1500 +G01 X-1.6211 Y0.1458 +G01 X-1.6179 Y0.1381 +G01 X-1.6119 Y0.1321 +G01 X-1.6042 Y0.1289 +G01 X-1.6000 Y0.1285 +G01 X-1.1400 Y0.1285 +G01 X-1.1358 Y0.1289 +G01 X-1.1281 Y0.1321 +G01 X-1.1221 Y0.1381 +G01 X-1.1189 Y0.1458 +G01 X-1.1185 Y0.1500 +G01 X-1.1185 Y0.1943 +G01 X-1.1185 Y0.1970 +G01 X-1.1185 Y0.2057 +G01 X-1.1185 Y0.2156 +G01 X-1.1065 Y0.2445 +G01 X-1.0845 Y0.2665 +G01 X-1.0556 Y0.2785 +G01 X-1.0457 Y0.2785 +G01 X-0.5157 Y0.2785 +G01 X-0.5100 Y0.2785 +G01 X-0.5058 Y0.2789 +G01 X-0.4981 Y0.2821 +G01 X-0.4921 Y0.2881 +G01 X-0.4889 Y0.2958 +G01 X-0.4885 Y0.3000 +G01 X-0.4885 Y0.6543 +G01 X-0.4885 Y0.6553 +G01 X-0.4885 Y0.6657 +G01 X-0.4885 Y0.6756 +G01 X-0.4765 Y0.7045 +G01 X-0.4545 Y0.7265 +G01 X-0.4256 Y0.7385 +G01 X-0.4157 Y0.7385 +G01 X-0.4131 Y0.7385 +G01 X-0.4100 Y0.7385 +G01 X-0.4043 Y0.7385 +G01 X-0.3101 Y0.7385 +G01 X-0.3098 Y0.7393 +G01 X-0.2960 Y0.7531 +G01 X-0.2780 Y0.7606 +G01 X-0.1220 Y0.7606 +G01 X-0.1040 Y0.7531 +G01 X-0.0902 Y0.7393 +G01 X-0.0828 Y0.7213 +G01 X-0.0828 Y0.7018 +G01 X-0.0902 Y0.6838 +G01 X-0.1040 Y0.6700 +G01 X-0.1220 Y0.6626 +G01 X-0.2780 Y0.6626 +G01 X-0.2960 Y0.6700 +G01 X-0.3075 Y0.6815 +G01 X-0.4043 Y0.6815 +G01 X-0.4100 Y0.6815 +G01 X-0.4142 Y0.6811 +G01 X-0.4219 Y0.6779 +G01 X-0.4279 Y0.6719 +G01 X-0.4311 Y0.6642 +G01 X-0.4315 Y0.6600 +G01 X-0.4315 Y0.6553 +G01 X-0.4315 Y0.6543 +G01 X-0.4315 Y0.2943 +G01 X-0.4315 Y0.2844 +G00 Z0.1000 +G00 X-0.4036 Y0.8815 +G01 Z-0.0070 F10 +G01 X-0.4036 Y0.8815 F20 +G01 X-0.4288 Y0.8919 +G01 X-0.4481 Y0.9112 +G01 X-0.4585 Y0.9364 +G01 X-0.4585 Y0.9443 +G01 X-0.4585 Y0.9497 +G01 X-0.4585 Y0.9500 +G01 X-0.4585 Y0.9557 +G01 X-0.4585 Y0.9600 +G01 X-0.4589 Y0.9642 +G01 X-0.4621 Y0.9719 +G01 X-0.4681 Y0.9779 +G01 X-0.4758 Y0.9811 +G01 X-0.4800 Y0.9815 +G01 X-0.4857 Y0.9815 +G01 X-0.8628 Y0.9815 +G01 X-0.8695 Y0.9748 +G01 X-0.8847 Y0.9685 +G01 X-1.0153 Y0.9685 +G01 X-1.0305 Y0.9748 +G01 X-1.0422 Y0.9865 +G01 X-1.0485 Y1.0017 +G01 X-1.0485 Y1.0183 +G01 X-1.0422 Y1.0335 +G01 X-1.0305 Y1.0452 +G01 X-1.0153 Y1.0515 +G01 X-0.8847 Y1.0515 +G01 X-0.8695 Y1.0452 +G01 X-0.8628 Y1.0385 +G01 X-0.4857 Y1.0385 +G01 X-0.4800 Y1.0385 +G01 X-0.4798 Y1.0385 +G01 X-0.4743 Y1.0385 +G01 X-0.4644 Y1.0385 +G01 X-0.4355 Y1.0265 +G01 X-0.4135 Y1.0045 +G01 X-0.4015 Y0.9756 +G01 X-0.4015 Y0.9657 +G01 X-0.4015 Y0.9557 +G01 X-0.4015 Y0.9500 +G01 X-0.4013 Y0.9478 +G01 X-0.3996 Y0.9436 +G01 X-0.3964 Y0.9404 +G01 X-0.3922 Y0.9387 +G01 X-0.3900 Y0.9385 +G01 X-0.3075 Y0.9385 +G01 X-0.2960 Y0.9500 +G01 X-0.2780 Y0.9574 +G01 X-0.1220 Y0.9574 +G01 X-0.1040 Y0.9500 +G01 X-0.0902 Y0.9362 +G01 X-0.0828 Y0.9182 +G01 X-0.0828 Y0.8987 +G01 X-0.0902 Y0.8807 +G01 X-0.1040 Y0.8669 +G01 X-0.1220 Y0.8594 +G01 X-0.2780 Y0.8594 +G01 X-0.2960 Y0.8669 +G01 X-0.3098 Y0.8807 +G01 X-0.3101 Y0.8815 +G01 X-0.3957 Y0.8815 +G01 X-0.4036 Y0.8815 +G00 Z0.1000 +G00 X-0.4457 Y1.2385 +G01 Z-0.0070 F10 +G01 X-0.4400 Y1.2385 F20 +G01 X-0.4369 Y1.2385 +G01 X-0.4343 Y1.2385 +G01 X-0.4264 Y1.2385 +G01 X-0.4012 Y1.2281 +G01 X-0.3819 Y1.2088 +G01 X-0.3715 Y1.1836 +G01 X-0.3715 Y1.1757 +G01 X-0.3715 Y1.1690 +G01 X-0.3715 Y1.1643 +G01 X-0.3715 Y1.1616 +G01 X-0.3711 Y1.1574 +G01 X-0.3679 Y1.1496 +G01 X-0.3619 Y1.1437 +G01 X-0.3542 Y1.1405 +G01 X-0.3500 Y1.1401 +G01 X-0.3454 Y1.1401 +G01 X-0.3443 Y1.1401 +G01 X-0.3090 Y1.1401 +G01 X-0.2960 Y1.1531 +G01 X-0.2780 Y1.1606 +G01 X-0.1220 Y1.1606 +G01 X-0.1040 Y1.1531 +G01 X-0.0902 Y1.1393 +G01 X-0.0828 Y1.1213 +G01 X-0.0828 Y1.1018 +G01 X-0.0902 Y1.0838 +G01 X-0.1040 Y1.0700 +G01 X-0.1220 Y1.0626 +G01 X-0.2780 Y1.0626 +G01 X-0.2960 Y1.0700 +G01 X-0.3090 Y1.0831 +G01 X-0.3443 Y1.0831 +G01 X-0.3454 Y1.0831 +G01 X-0.3557 Y1.0831 +G01 X-0.3656 Y1.0831 +G01 X-0.3945 Y1.0950 +G01 X-0.4165 Y1.1171 +G01 X-0.4285 Y1.1460 +G01 X-0.4285 Y1.1559 +G01 X-0.4285 Y1.1643 +G01 X-0.4285 Y1.1690 +G01 X-0.4285 Y1.1700 +G01 X-0.4287 Y1.1722 +G01 X-0.4304 Y1.1764 +G01 X-0.4336 Y1.1796 +G01 X-0.4378 Y1.1813 +G01 X-0.4400 Y1.1815 +G01 X-0.4457 Y1.1815 +G01 X-0.8628 Y1.1815 +G01 X-0.8695 Y1.1748 +G01 X-0.8847 Y1.1685 +G01 X-1.0153 Y1.1685 +G01 X-1.0305 Y1.1748 +G01 X-1.0422 Y1.1865 +G01 X-1.0485 Y1.2017 +G01 X-1.0485 Y1.2183 +G01 X-1.0422 Y1.2335 +G01 X-1.0305 Y1.2452 +G01 X-1.0153 Y1.2515 +G01 X-0.8847 Y1.2515 +G01 X-0.8695 Y1.2452 +G01 X-0.8628 Y1.2385 +G01 X-0.4457 Y1.2385 +G00 Z0.1000 +G00 X-0.5744 Y1.4385 +G01 Z-0.0070 F10 +G01 X-0.5744 Y1.4385 F20 +G01 X-0.5455 Y1.4265 +G01 X-0.5235 Y1.4045 +G01 X-0.5115 Y1.3756 +G01 X-0.5115 Y1.3657 +G01 X-0.5115 Y1.3602 +G01 X-0.5115 Y1.3600 +G01 X-0.5115 Y1.3584 +G01 X-0.5111 Y1.3542 +G01 X-0.5079 Y1.3465 +G01 X-0.5019 Y1.3405 +G01 X-0.4942 Y1.3373 +G01 X-0.4900 Y1.3369 +G01 X-0.4892 Y1.3369 +G01 X-0.4843 Y1.3369 +G01 X-0.3090 Y1.3369 +G01 X-0.2960 Y1.3500 +G01 X-0.2780 Y1.3574 +G01 X-0.1220 Y1.3574 +G01 X-0.1040 Y1.3500 +G01 X-0.0902 Y1.3362 +G01 X-0.0828 Y1.3182 +G01 X-0.0828 Y1.2987 +G01 X-0.0902 Y1.2807 +G01 X-0.1040 Y1.2669 +G01 X-0.1220 Y1.2594 +G01 X-0.2780 Y1.2594 +G01 X-0.2960 Y1.2669 +G01 X-0.3090 Y1.2799 +G01 X-0.4843 Y1.2799 +G01 X-0.4892 Y1.2799 +G01 X-0.4900 Y1.2799 +G01 X-0.4957 Y1.2799 +G01 X-0.5056 Y1.2799 +G01 X-0.5345 Y1.2919 +G01 X-0.5565 Y1.3140 +G01 X-0.5685 Y1.3428 +G01 X-0.5685 Y1.3527 +G01 X-0.5685 Y1.3543 +G01 X-0.5685 Y1.3600 +G01 X-0.5689 Y1.3642 +G01 X-0.5721 Y1.3719 +G01 X-0.5781 Y1.3779 +G01 X-0.5858 Y1.3811 +G01 X-0.5900 Y1.3815 +G01 X-0.8628 Y1.3815 +G01 X-0.8695 Y1.3748 +G01 X-0.8847 Y1.3685 +G01 X-1.0153 Y1.3685 +G01 X-1.0305 Y1.3748 +G01 X-1.0422 Y1.3865 +G01 X-1.0485 Y1.4017 +G01 X-1.0485 Y1.4183 +G01 X-1.0422 Y1.4335 +G01 X-1.0305 Y1.4452 +G01 X-1.0153 Y1.4515 +G01 X-0.8847 Y1.4515 +G01 X-0.8695 Y1.4452 +G01 X-0.8628 Y1.4385 +G01 X-0.5843 Y1.4385 +G01 X-0.5744 Y1.4385 +G00 Z0.1000 +G00 X-2.5553 Y0.4412 +G01 Z-0.0070 F10 +G01 X-2.5553 Y0.4788 F20 +G01 X-2.5288 Y0.5053 +G01 X-2.4912 Y0.5053 +G01 X-2.4647 Y0.4788 +G01 X-2.4647 Y0.4412 +G01 X-2.4715 Y0.4344 +G01 X-2.4715 Y0.2677 +G01 X-2.4715 Y0.1900 +G01 X-2.4714 Y0.1882 +G01 X-2.4702 Y0.1848 +G01 X-2.4681 Y0.1819 +G01 X-2.4652 Y0.1797 +G01 X-2.4618 Y0.1786 +G01 X-2.4600 Y0.1785 +G01 X-2.4533 Y0.1785 +G01 X-2.4523 Y0.1785 +G01 X-1.8700 Y0.1785 +G01 X-1.8682 Y0.1786 +G01 X-1.8648 Y0.1797 +G01 X-1.8619 Y0.1819 +G01 X-1.8613 Y0.1826 +G01 X-1.8615 Y0.1828 +G01 X-1.8615 Y0.2172 +G01 X-1.8372 Y0.2415 +G01 X-1.8028 Y0.2415 +G01 X-1.7785 Y0.2172 +G01 X-1.7785 Y0.1828 +G01 X-1.7815 Y0.1798 +G01 X-1.7815 Y0.1760 +G01 X-1.7902 Y0.1493 +G01 X-1.8066 Y0.1266 +G01 X-1.8293 Y0.1102 +G01 X-1.8560 Y0.1015 +G01 X-1.8623 Y0.1015 +G01 X-2.4523 Y0.1015 +G01 X-2.4533 Y0.1015 +G01 X-2.4677 Y0.1015 +G01 X-2.4740 Y0.1015 +G01 X-2.5007 Y0.1102 +G01 X-2.5234 Y0.1266 +G01 X-2.5398 Y0.1493 +G01 X-2.5485 Y0.1760 +G01 X-2.5485 Y0.1823 +G01 X-2.5485 Y0.2315 +G01 X-2.6098 Y0.2315 +G01 X-2.6228 Y0.2185 +G01 X-2.6572 Y0.2185 +G01 X-2.6815 Y0.2428 +G01 X-2.6815 Y0.2772 +G01 X-2.6572 Y0.3015 +G01 X-2.6228 Y0.3015 +G01 X-2.6098 Y0.2885 +G01 X-2.5485 Y0.2885 +G01 X-2.5485 Y0.4344 +G01 X-2.5553 Y0.4412 +G00 Z0.1000 +G00 X-1.9315 Y1.4356 +G01 Z-0.0070 F10 +G01 X-1.9315 Y1.4356 F20 +G01 X-1.9315 Y1.4257 +G01 X-1.9315 Y1.3515 +G01 X-1.8947 Y1.3515 +G01 X-1.8795 Y1.3452 +G01 X-1.8678 Y1.3335 +G01 X-1.8615 Y1.3183 +G01 X-1.8615 Y1.3017 +G01 X-1.8678 Y1.2865 +G01 X-1.8795 Y1.2748 +G01 X-1.8947 Y1.2685 +G01 X-2.0253 Y1.2685 +G01 X-2.0405 Y1.2748 +G01 X-2.0522 Y1.2865 +G01 X-2.0585 Y1.3017 +G01 X-2.0585 Y1.3183 +G01 X-2.0522 Y1.3335 +G01 X-2.0405 Y1.3452 +G01 X-2.0253 Y1.3515 +G01 X-1.9885 Y1.3515 +G01 X-1.9885 Y1.4200 +G01 X-1.9889 Y1.4242 +G01 X-1.9894 Y1.4253 +G01 X-2.0047 Y1.4406 +G01 X-2.0058 Y1.4411 +G01 X-2.0100 Y1.4415 +G01 X-2.1744 Y1.4415 +G01 X-2.1912 Y1.4247 +G01 X-2.2288 Y1.4247 +G01 X-2.2355 Y1.4314 +G01 X-2.2540 Y1.4253 +G01 X-2.2540 Y1.4209 +G01 X-2.2809 Y1.3940 +G01 X-2.3191 Y1.3940 +G01 X-2.3460 Y1.4209 +G01 X-2.3460 Y1.4591 +G01 X-2.3191 Y1.4860 +G01 X-2.2809 Y1.4860 +G01 X-2.2737 Y1.4788 +G01 X-2.2553 Y1.4849 +G01 X-2.2553 Y1.4888 +G01 X-2.2288 Y1.5153 +G01 X-2.1912 Y1.5153 +G01 X-2.1744 Y1.4985 +G01 X-2.0056 Y1.4985 +G01 X-1.9888 Y1.5153 +G01 X-1.9512 Y1.5153 +G01 X-1.9247 Y1.4888 +G01 X-1.9247 Y1.4512 +G01 X-1.9341 Y1.4418 +G01 X-1.9315 Y1.4356 +G00 Z0.1000 +G00 X-1.3615 Y0.1828 +G01 Z-0.0070 F10 +G01 X-1.3615 Y0.2172 F20 +G01 X-1.3385 Y0.2402 +G01 X-1.3385 Y0.3115 +G01 X-1.3813 Y0.3115 +G01 X-1.3931 Y0.2997 +G01 X-1.4105 Y0.2925 +G01 X-1.4294 Y0.2925 +G01 X-1.4469 Y0.2997 +G01 X-1.4603 Y0.3131 +G01 X-1.4675 Y0.3305 +G01 X-1.4675 Y0.3494 +G01 X-1.4603 Y0.3669 +G01 X-1.4469 Y0.3803 +G01 X-1.4294 Y0.3875 +G01 X-1.4105 Y0.3875 +G01 X-1.3931 Y0.3803 +G01 X-1.3813 Y0.3685 +G01 X-1.3043 Y0.3685 +G01 X-0.8102 Y0.3685 +G01 X-0.7972 Y0.3815 +G01 X-0.7628 Y0.3815 +G01 X-0.7385 Y0.3572 +G01 X-0.7385 Y0.3228 +G01 X-0.7628 Y0.2985 +G01 X-0.7972 Y0.2985 +G01 X-0.8102 Y0.3115 +G01 X-1.2815 Y0.3115 +G01 X-1.2815 Y0.2202 +G01 X-1.2785 Y0.2172 +G01 X-1.2785 Y0.1828 +G01 X-1.3028 Y0.1585 +G01 X-1.3372 Y0.1585 +G01 X-1.3615 Y0.1828 +G00 Z0.1000 +G00 X-1.5415 Y1.8928 +G01 Z-0.0070 F10 +G01 X-1.5415 Y1.9272 F20 +G01 X-1.5172 Y1.9515 +G01 X-1.4828 Y1.9515 +G01 X-1.4585 Y1.9272 +G01 X-1.4585 Y1.8928 +G01 X-1.4715 Y1.8798 +G01 X-1.4715 Y1.7487 +G01 X-1.4597 Y1.7369 +G01 X-1.4525 Y1.7194 +G01 X-1.4525 Y1.7005 +G01 X-1.4534 Y1.6985 +G01 X-1.4516 Y1.6985 +G01 X-1.4475 Y1.6989 +G01 X-1.4459 Y1.6985 +G01 X-0.7757 Y1.6985 +G01 X-0.7700 Y1.6985 +G01 X-0.7665 Y1.6985 +G01 X-0.7643 Y1.6985 +G01 X-0.7544 Y1.6985 +G01 X-0.7255 Y1.6865 +G01 X-0.7035 Y1.6645 +G01 X-0.6915 Y1.6356 +G01 X-0.6915 Y1.6257 +G01 X-0.6915 Y1.5402 +G01 X-0.6785 Y1.5272 +G01 X-0.6785 Y1.4928 +G01 X-0.7028 Y1.4685 +G01 X-0.7372 Y1.4685 +G01 X-0.7615 Y1.4928 +G01 X-0.7615 Y1.5272 +G01 X-0.7485 Y1.5402 +G01 X-0.7485 Y1.6200 +G01 X-0.7489 Y1.6242 +G01 X-0.7521 Y1.6319 +G01 X-0.7581 Y1.6379 +G01 X-0.7658 Y1.6411 +G01 X-0.7700 Y1.6415 +G01 X-0.7757 Y1.6415 +G01 X-1.4484 Y1.6415 +G01 X-1.4614 Y1.6401 +G01 X-1.4896 Y1.6482 +G01 X-1.5075 Y1.6625 +G01 X-1.5094 Y1.6625 +G01 X-1.5269 Y1.6697 +G01 X-1.5403 Y1.6831 +G01 X-1.5475 Y1.7005 +G01 X-1.5475 Y1.7194 +G01 X-1.5403 Y1.7369 +G01 X-1.5285 Y1.7487 +G01 X-1.5285 Y1.8798 +G01 X-1.5415 Y1.8928 +G00 Z0.1000 +G00 X-1.7285 Y1.2172 +G01 Z-0.0070 F10 +G01 X-1.7285 Y1.1828 F20 +G01 X-1.7528 Y1.1585 +G01 X-1.7872 Y1.1585 +G01 X-1.8002 Y1.1715 +G01 X-1.8875 Y1.1715 +G01 X-1.8947 Y1.1685 +G01 X-2.0253 Y1.1685 +G01 X-2.0405 Y1.1748 +G01 X-2.0522 Y1.1865 +G01 X-2.0585 Y1.2017 +G01 X-2.0585 Y1.2183 +G01 X-2.0522 Y1.2335 +G01 X-2.0405 Y1.2452 +G01 X-2.0253 Y1.2515 +G01 X-1.8947 Y1.2515 +G01 X-1.8795 Y1.2452 +G01 X-1.8678 Y1.2335 +G01 X-1.8657 Y1.2285 +G01 X-1.8002 Y1.2285 +G01 X-1.7985 Y1.2302 +G01 X-1.7985 Y1.2815 +G01 X-1.8043 Y1.2815 +G01 X-1.8157 Y1.2815 +G01 X-1.8261 Y1.2858 +G01 X-1.8342 Y1.2939 +G01 X-1.8385 Y1.3043 +G01 X-1.8385 Y1.5343 +G01 X-1.8385 Y1.5400 +G01 X-1.8387 Y1.5422 +G01 X-1.8404 Y1.5464 +G01 X-1.8436 Y1.5496 +G01 X-1.8478 Y1.5513 +G01 X-1.8500 Y1.5515 +G01 X-1.8557 Y1.5515 +G01 X-2.3343 Y1.5515 +G01 X-2.3361 Y1.5515 +G01 X-2.3457 Y1.5515 +G01 X-2.3556 Y1.5515 +G01 X-2.3845 Y1.5635 +G01 X-2.4065 Y1.5855 +G01 X-2.4185 Y1.6144 +G01 X-2.4185 Y1.6243 +G01 X-2.4185 Y1.6348 +G01 X-2.4315 Y1.6478 +G01 X-2.4315 Y1.6822 +G01 X-2.4072 Y1.7065 +G01 X-2.3728 Y1.7065 +G01 X-2.3485 Y1.6822 +G01 X-2.3485 Y1.6478 +G01 X-2.3615 Y1.6348 +G01 X-2.3615 Y1.6300 +G01 X-2.3611 Y1.6258 +G01 X-2.3579 Y1.6181 +G01 X-2.3519 Y1.6121 +G01 X-2.3442 Y1.6089 +G01 X-2.3400 Y1.6085 +G01 X-2.3360 Y1.6085 +G01 X-2.3343 Y1.6085 +G01 X-1.8557 Y1.6085 +G01 X-1.8443 Y1.6085 +G01 X-1.8364 Y1.6085 +G01 X-1.8112 Y1.5981 +G01 X-1.7919 Y1.5788 +G01 X-1.7815 Y1.5536 +G01 X-1.7815 Y1.5457 +G01 X-1.7815 Y1.5401 +G01 X-1.7815 Y1.5400 +G01 X-1.7815 Y1.5343 +G01 X-1.7815 Y1.3385 +G01 X-1.7757 Y1.3385 +G01 X-1.7643 Y1.3385 +G01 X-1.6457 Y1.3385 +G01 X-1.6343 Y1.3385 +G01 X-1.5387 Y1.3385 +G01 X-1.5269 Y1.3503 +G01 X-1.5094 Y1.3575 +G01 X-1.4905 Y1.3575 +G01 X-1.4731 Y1.3503 +G01 X-1.4597 Y1.3369 +G01 X-1.4525 Y1.3194 +G01 X-1.4525 Y1.3005 +G01 X-1.4597 Y1.2831 +G01 X-1.4731 Y1.2697 +G01 X-1.4905 Y1.2625 +G01 X-1.5094 Y1.2625 +G01 X-1.5269 Y1.2697 +G01 X-1.5387 Y1.2815 +G01 X-1.5947 Y1.2815 +G01 X-1.5947 Y1.2512 +G01 X-1.6212 Y1.2247 +G01 X-1.6588 Y1.2247 +G01 X-1.6853 Y1.2512 +G01 X-1.6853 Y1.2815 +G01 X-1.7415 Y1.2815 +G01 X-1.7415 Y1.2302 +G01 X-1.7285 Y1.2172 +G00 Z0.1000 +G00 X-2.9915 Y1.1128 +G01 Z-0.0070 F10 +G01 X-2.9915 Y1.1472 F20 +G01 X-2.9672 Y1.1715 +G01 X-2.9328 Y1.1715 +G01 X-2.9085 Y1.1472 +G01 X-2.9085 Y1.1128 +G01 X-2.9215 Y1.0998 +G01 X-2.9215 Y1.0600 +G01 X-2.9211 Y1.0558 +G01 X-2.9179 Y1.0480 +G01 X-2.9119 Y1.0421 +G01 X-2.9042 Y1.0389 +G01 X-2.9000 Y1.0385 +G01 X-2.8950 Y1.0385 +G01 X-2.8943 Y1.0385 +G01 X-2.3472 Y1.0385 +G01 X-2.3405 Y1.0452 +G01 X-2.3253 Y1.0515 +G01 X-2.1947 Y1.0515 +G01 X-2.1795 Y1.0452 +G01 X-2.1678 Y1.0335 +G01 X-2.1615 Y1.0183 +G01 X-2.1615 Y1.0017 +G01 X-2.1678 Y0.9865 +G01 X-2.1795 Y0.9748 +G01 X-2.1947 Y0.9685 +G01 X-2.3253 Y0.9685 +G01 X-2.3405 Y0.9748 +G01 X-2.3472 Y0.9815 +G01 X-2.8943 Y0.9815 +G01 X-2.8950 Y0.9815 +G01 X-2.9057 Y0.9815 +G01 X-2.9156 Y0.9815 +G01 X-2.9445 Y0.9935 +G01 X-2.9665 Y1.0155 +G01 X-2.9785 Y1.0444 +G01 X-2.9785 Y1.0543 +G01 X-2.9785 Y1.0998 +G01 X-2.9915 Y1.1128 +G00 Z0.1000 +G00 X-2.6872 Y1.7615 +G01 Z-0.0070 F10 +G01 X-2.6528 Y1.7615 F20 +G01 X-2.6398 Y1.7485 +G01 X-2.6300 Y1.7485 +G01 X-2.6258 Y1.7489 +G01 X-2.6181 Y1.7521 +G01 X-2.6121 Y1.7581 +G01 X-2.6089 Y1.7658 +G01 X-2.6085 Y1.7700 +G01 X-2.6085 Y1.7730 +G01 X-2.6085 Y1.7757 +G01 X-2.6085 Y1.7857 +G01 X-2.6085 Y1.7956 +G01 X-2.5965 Y1.8245 +G01 X-2.5745 Y1.8465 +G01 X-2.5456 Y1.8585 +G01 X-2.5357 Y1.8585 +G01 X-2.3843 Y1.8585 +G01 X-2.3744 Y1.8585 +G01 X-2.3455 Y1.8465 +G01 X-2.3235 Y1.8245 +G01 X-2.3115 Y1.7956 +G01 X-2.3115 Y1.7857 +G01 X-2.3115 Y1.7702 +G01 X-2.3098 Y1.7685 +G01 X-2.2456 Y1.7685 +G01 X-2.2288 Y1.7853 +G01 X-2.1912 Y1.7853 +G01 X-2.1647 Y1.7588 +G01 X-2.1647 Y1.7212 +G01 X-2.1912 Y1.6947 +G01 X-2.2288 Y1.6947 +G01 X-2.2456 Y1.7115 +G01 X-2.3098 Y1.7115 +G01 X-2.3228 Y1.6985 +G01 X-2.3572 Y1.6985 +G01 X-2.3815 Y1.7228 +G01 X-2.3815 Y1.7572 +G01 X-2.3685 Y1.7702 +G01 X-2.3685 Y1.7800 +G01 X-2.3689 Y1.7842 +G01 X-2.3721 Y1.7919 +G01 X-2.3781 Y1.7979 +G01 X-2.3858 Y1.8011 +G01 X-2.3900 Y1.8015 +G01 X-2.5300 Y1.8015 +G01 X-2.5342 Y1.8011 +G01 X-2.5419 Y1.7979 +G01 X-2.5479 Y1.7919 +G01 X-2.5511 Y1.7842 +G01 X-2.5515 Y1.7800 +G01 X-2.5515 Y1.7757 +G01 X-2.5515 Y1.7730 +G01 X-2.5515 Y1.7643 +G01 X-2.5515 Y1.7544 +G01 X-2.5635 Y1.7255 +G01 X-2.5855 Y1.7035 +G01 X-2.6144 Y1.6915 +G01 X-2.6243 Y1.6915 +G01 X-2.6398 Y1.6915 +G01 X-2.6528 Y1.6785 +G01 X-2.6872 Y1.6785 +G01 X-2.7002 Y1.6915 +G01 X-2.7300 Y1.6915 +G01 X-2.7342 Y1.6911 +G01 X-2.7419 Y1.6879 +G01 X-2.7479 Y1.6819 +G01 X-2.7511 Y1.6742 +G01 X-2.7515 Y1.6700 +G01 X-2.7515 Y1.6656 +G01 X-2.7515 Y1.6643 +G01 X-2.7515 Y1.5943 +G01 X-2.7515 Y1.5864 +G01 X-2.7619 Y1.5612 +G01 X-2.7812 Y1.5419 +G01 X-2.8064 Y1.5315 +G01 X-2.8143 Y1.5315 +G01 X-2.8198 Y1.5315 +G01 X-2.8200 Y1.5315 +G01 X-2.8257 Y1.5315 +G01 X-2.9600 Y1.5315 +G01 X-2.9603 Y1.5315 +G01 X-2.9608 Y1.5312 +G01 X-2.9612 Y1.5308 +G01 X-2.9615 Y1.5303 +G01 X-2.9615 Y1.5300 +G01 X-2.9615 Y1.5243 +G01 X-2.9615 Y1.3715 +G01 X-2.9328 Y1.3715 +G01 X-2.9085 Y1.3472 +G01 X-2.9085 Y1.3128 +G01 X-2.9328 Y1.2885 +G01 X-2.9672 Y1.2885 +G01 X-2.9915 Y1.3128 +G01 X-2.9915 Y1.3146 +G01 X-3.0081 Y1.3312 +G01 X-3.0185 Y1.3564 +G01 X-3.0185 Y1.3643 +G01 X-3.0185 Y1.3665 +G01 X-3.0185 Y1.3700 +G01 X-3.0185 Y1.5243 +G01 X-3.0185 Y1.5300 +G01 X-3.0185 Y1.5416 +G01 X-3.0096 Y1.5631 +G01 X-2.9931 Y1.5796 +G01 X-2.9716 Y1.5885 +G01 X-2.9657 Y1.5885 +G01 X-2.8257 Y1.5885 +G01 X-2.8200 Y1.5885 +G01 X-2.8178 Y1.5887 +G01 X-2.8136 Y1.5904 +G01 X-2.8104 Y1.5936 +G01 X-2.8087 Y1.5978 +G01 X-2.8085 Y1.6000 +G01 X-2.8085 Y1.6643 +G01 X-2.8085 Y1.6656 +G01 X-2.8085 Y1.6757 +G01 X-2.8085 Y1.6856 +G01 X-2.7965 Y1.7145 +G01 X-2.7745 Y1.7365 +G01 X-2.7456 Y1.7485 +G01 X-2.7357 Y1.7485 +G01 X-2.7002 Y1.7485 +G01 X-2.6872 Y1.7615 +G00 Z0.1000 +G00 X-1.5915 Y0.6428 +G01 Z-0.0070 F10 +G01 X-1.5915 Y0.6772 F20 +G01 X-1.5785 Y0.6902 +G01 X-1.5785 Y0.7543 +G01 X-1.5785 Y0.7555 +G01 X-1.5785 Y0.7657 +G01 X-1.5785 Y0.7756 +G01 X-1.5665 Y0.8045 +G01 X-1.5445 Y0.8265 +G01 X-1.5156 Y0.8385 +G01 X-1.5057 Y0.8385 +G01 X-1.3372 Y0.8385 +G01 X-1.3305 Y0.8452 +G01 X-1.3153 Y0.8515 +G01 X-1.1847 Y0.8515 +G01 X-1.1695 Y0.8452 +G01 X-1.1578 Y0.8335 +G01 X-1.1515 Y0.8183 +G01 X-1.1515 Y0.8017 +G01 X-1.1578 Y0.7865 +G01 X-1.1695 Y0.7748 +G01 X-1.1847 Y0.7685 +G01 X-1.3153 Y0.7685 +G01 X-1.3305 Y0.7748 +G01 X-1.3372 Y0.7815 +G01 X-1.5000 Y0.7815 +G01 X-1.5042 Y0.7811 +G01 X-1.5119 Y0.7779 +G01 X-1.5179 Y0.7719 +G01 X-1.5211 Y0.7642 +G01 X-1.5215 Y0.7600 +G01 X-1.5215 Y0.7555 +G01 X-1.5215 Y0.7543 +G01 X-1.5215 Y0.6902 +G01 X-1.5085 Y0.6772 +G01 X-1.5085 Y0.6428 +G01 X-1.5328 Y0.6185 +G01 X-1.5672 Y0.6185 +G01 X-1.5915 Y0.6428 +G00 Z0.1000 +G00 X-0.5772 Y1.1515 +G01 Z-0.0070 F10 +G01 X-0.5428 Y1.1515 F20 +G01 X-0.5185 Y1.1272 +G01 X-0.5185 Y1.0928 +G01 X-0.5428 Y1.0685 +G01 X-0.5772 Y1.0685 +G01 X-0.5902 Y1.0815 +G01 X-0.8628 Y1.0815 +G01 X-0.8695 Y1.0748 +G01 X-0.8847 Y1.0685 +G01 X-1.0153 Y1.0685 +G01 X-1.0305 Y1.0748 +G01 X-1.0422 Y1.0865 +G01 X-1.0485 Y1.1017 +G01 X-1.0485 Y1.1183 +G01 X-1.0422 Y1.1335 +G01 X-1.0305 Y1.1452 +G01 X-1.0153 Y1.1515 +G01 X-0.8847 Y1.1515 +G01 X-0.8695 Y1.1452 +G01 X-0.8628 Y1.1385 +G01 X-0.5902 Y1.1385 +G01 X-0.5772 Y1.1515 +G00 Z0.1000 +G00 X-2.8420 Y0.5026 +G01 Z-0.0070 F10 +G01 X-2.9980 Y0.5026 F20 +G01 X-3.0160 Y0.5100 +G01 X-3.0298 Y0.5238 +G01 X-3.0372 Y0.5418 +G01 X-3.0372 Y0.5613 +G01 X-3.0298 Y0.5793 +G01 X-3.0160 Y0.5931 +G01 X-2.9980 Y0.6006 +G01 X-2.8420 Y0.6006 +G01 X-2.8240 Y0.5931 +G01 X-2.8102 Y0.5793 +G01 X-2.8099 Y0.5785 +G01 X-2.2757 Y0.5785 +G01 X-2.2700 Y0.5785 +G01 X-2.2678 Y0.5787 +G01 X-2.2636 Y0.5804 +G01 X-2.2604 Y0.5836 +G01 X-2.2587 Y0.5878 +G01 X-2.2585 Y0.5900 +G01 X-2.2585 Y0.5933 +G01 X-2.2585 Y0.5957 +G01 X-2.2585 Y0.7157 +G01 X-2.2585 Y0.7236 +G01 X-2.2481 Y0.7488 +G01 X-2.2288 Y0.7681 +G01 X-2.2036 Y0.7785 +G01 X-2.1957 Y0.7785 +G01 X-2.1906 Y0.7785 +G01 X-2.1900 Y0.7785 +G01 X-2.1843 Y0.7785 +G01 X-1.7857 Y0.7785 +G01 X-1.7800 Y0.7785 +G01 X-1.7758 Y0.7789 +G01 X-1.7681 Y0.7821 +G01 X-1.7621 Y0.7881 +G01 X-1.7589 Y0.7958 +G01 X-1.7585 Y0.8000 +G01 X-1.7585 Y0.9643 +G01 X-1.7585 Y0.9651 +G01 X-1.7585 Y0.9757 +G01 X-1.7585 Y0.9836 +G01 X-1.7481 Y1.0088 +G01 X-1.7288 Y1.0281 +G01 X-1.7036 Y1.0385 +G01 X-1.6957 Y1.0385 +G01 X-1.3372 Y1.0385 +G01 X-1.3305 Y1.0452 +G01 X-1.3153 Y1.0515 +G01 X-1.1847 Y1.0515 +G01 X-1.1695 Y1.0452 +G01 X-1.1578 Y1.0335 +G01 X-1.1515 Y1.0183 +G01 X-1.1515 Y1.0017 +G01 X-1.1578 Y0.9865 +G01 X-1.1695 Y0.9748 +G01 X-1.1847 Y0.9685 +G01 X-1.3153 Y0.9685 +G01 X-1.3305 Y0.9748 +G01 X-1.3372 Y0.9815 +G01 X-1.6900 Y0.9815 +G01 X-1.6922 Y0.9813 +G01 X-1.6964 Y0.9796 +G01 X-1.6996 Y0.9764 +G01 X-1.7013 Y0.9722 +G01 X-1.7015 Y0.9700 +G01 X-1.7015 Y0.9651 +G01 X-1.7015 Y0.9643 +G01 X-1.7015 Y0.7943 +G01 X-1.7015 Y0.7844 +G01 X-1.7135 Y0.7555 +G01 X-1.7355 Y0.7335 +G01 X-1.7644 Y0.7215 +G01 X-1.7743 Y0.7215 +G01 X-1.7767 Y0.7215 +G01 X-1.7800 Y0.7215 +G01 X-1.7857 Y0.7215 +G01 X-2.1843 Y0.7215 +G01 X-2.1900 Y0.7215 +G01 X-2.1922 Y0.7213 +G01 X-2.1964 Y0.7196 +G01 X-2.1996 Y0.7164 +G01 X-2.2013 Y0.7122 +G01 X-2.2015 Y0.7100 +G01 X-2.2015 Y0.5957 +G01 X-2.2015 Y0.5932 +G01 X-2.2015 Y0.5843 +G01 X-2.2015 Y0.5764 +G01 X-2.2119 Y0.5512 +G01 X-2.2312 Y0.5319 +G01 X-2.2564 Y0.5215 +G01 X-2.2643 Y0.5215 +G01 X-2.2689 Y0.5215 +G01 X-2.2700 Y0.5215 +G01 X-2.2757 Y0.5215 +G01 X-2.8125 Y0.5215 +G01 X-2.8240 Y0.5100 +G01 X-2.8420 Y0.5026 +G00 Z0.1000 +G00 X-1.3153 Y1.3515 +G01 Z-0.0070 F10 +G01 X-1.1847 Y1.3515 F20 +G01 X-1.1695 Y1.3452 +G01 X-1.1578 Y1.3335 +G01 X-1.1515 Y1.3183 +G01 X-1.1515 Y1.3017 +G01 X-1.1578 Y1.2865 +G01 X-1.1695 Y1.2748 +G01 X-1.1847 Y1.2685 +G01 X-1.3153 Y1.2685 +G01 X-1.3305 Y1.2748 +G01 X-1.3422 Y1.2865 +G01 X-1.3485 Y1.3017 +G01 X-1.3485 Y1.3183 +G01 X-1.3422 Y1.3335 +G01 X-1.3305 Y1.3452 +G01 X-1.3153 Y1.3515 +G00 Z0.1000 +G00 X-1.3153 Y1.2515 +G01 Z-0.0070 F10 +G01 X-1.1847 Y1.2515 F20 +G01 X-1.1695 Y1.2452 +G01 X-1.1578 Y1.2335 +G01 X-1.1515 Y1.2183 +G01 X-1.1515 Y1.2017 +G01 X-1.1578 Y1.1865 +G01 X-1.1695 Y1.1748 +G01 X-1.1847 Y1.1685 +G01 X-1.3153 Y1.1685 +G01 X-1.3305 Y1.1748 +G01 X-1.3422 Y1.1865 +G01 X-1.3485 Y1.2017 +G01 X-1.3485 Y1.2183 +G01 X-1.3422 Y1.2335 +G01 X-1.3305 Y1.2452 +G01 X-1.3153 Y1.2515 +G00 Z0.1000 +G00 X-1.3153 Y1.1515 +G01 Z-0.0070 F10 +G01 X-1.1847 Y1.1515 F20 +G01 X-1.1695 Y1.1452 +G01 X-1.1578 Y1.1335 +G01 X-1.1515 Y1.1183 +G01 X-1.1515 Y1.1017 +G01 X-1.1578 Y1.0865 +G01 X-1.1695 Y1.0748 +G01 X-1.1847 Y1.0685 +G01 X-1.3153 Y1.0685 +G01 X-1.3305 Y1.0748 +G01 X-1.3372 Y1.0815 +G01 X-1.7815 Y1.0815 +G01 X-1.7815 Y0.8743 +G01 X-1.7815 Y0.8644 +G01 X-1.7935 Y0.8355 +G01 X-1.8155 Y0.8135 +G01 X-1.8444 Y0.8015 +G01 X-1.8543 Y0.8015 +G01 X-2.2800 Y0.8015 +G01 X-2.2842 Y0.8011 +G01 X-2.2919 Y0.7979 +G01 X-2.2979 Y0.7919 +G01 X-2.3011 Y0.7842 +G01 X-2.3015 Y0.7800 +G01 X-2.3015 Y0.7543 +G01 X-2.3015 Y0.7504 +G01 X-2.3089 Y0.7325 +G01 X-2.3225 Y0.7189 +G01 X-2.3404 Y0.7115 +G01 X-2.3500 Y0.7115 +G01 X-2.3557 Y0.7115 +G01 X-2.6498 Y0.7115 +G01 X-2.6528 Y0.7085 +G01 X-2.6872 Y0.7085 +G01 X-2.7002 Y0.7215 +G01 X-2.8099 Y0.7215 +G01 X-2.8102 Y0.7207 +G01 X-2.8240 Y0.7069 +G01 X-2.8420 Y0.6994 +G01 X-2.9980 Y0.6994 +G01 X-3.0160 Y0.7069 +G01 X-3.0298 Y0.7207 +G01 X-3.0372 Y0.7387 +G01 X-3.0372 Y0.7582 +G01 X-3.0298 Y0.7762 +G01 X-3.0160 Y0.7900 +G01 X-2.9980 Y0.7974 +G01 X-2.8420 Y0.7974 +G01 X-2.8240 Y0.7900 +G01 X-2.8125 Y0.7785 +G01 X-2.7002 Y0.7785 +G01 X-2.6872 Y0.7915 +G01 X-2.6528 Y0.7915 +G01 X-2.6298 Y0.7685 +G01 X-2.3585 Y0.7685 +G01 X-2.3585 Y0.7857 +G01 X-2.3585 Y0.7956 +G01 X-2.3465 Y0.8245 +G01 X-2.3245 Y0.8465 +G01 X-2.2956 Y0.8585 +G01 X-2.2857 Y0.8585 +G01 X-1.8600 Y0.8585 +G01 X-1.8558 Y0.8589 +G01 X-1.8481 Y0.8621 +G01 X-1.8421 Y0.8681 +G01 X-1.8389 Y0.8758 +G01 X-1.8385 Y0.8800 +G01 X-1.8385 Y1.0815 +G01 X-1.8728 Y1.0815 +G01 X-1.8795 Y1.0748 +G01 X-1.8947 Y1.0685 +G01 X-2.0253 Y1.0685 +G01 X-2.0405 Y1.0748 +G01 X-2.0522 Y1.0865 +G01 X-2.0585 Y1.1017 +G01 X-2.0585 Y1.1183 +G01 X-2.0522 Y1.1335 +G01 X-2.0405 Y1.1452 +G01 X-2.0253 Y1.1515 +G01 X-1.8947 Y1.1515 +G01 X-1.8795 Y1.1452 +G01 X-1.8728 Y1.1385 +G01 X-1.8157 Y1.1385 +G01 X-1.8043 Y1.1385 +G01 X-1.3372 Y1.1385 +G01 X-1.3305 Y1.1452 +G01 X-1.3153 Y1.1515 +G00 Z0.1000 +G00 X-1.0153 Y0.9515 +G01 Z-0.0070 F10 +G01 X-0.8847 Y0.9515 F20 +G01 X-0.8695 Y0.9452 +G01 X-0.8628 Y0.9385 +G01 X-0.8357 Y0.9385 +G01 X-0.8336 Y0.9385 +G01 X-0.8243 Y0.9385 +G01 X-0.8144 Y0.9385 +G01 X-0.7855 Y0.9265 +G01 X-0.7635 Y0.9045 +G01 X-0.7515 Y0.8756 +G01 X-0.7515 Y0.8657 +G01 X-0.7515 Y0.5702 +G01 X-0.7385 Y0.5572 +G01 X-0.7385 Y0.5228 +G01 X-0.7628 Y0.4985 +G01 X-0.7972 Y0.4985 +G01 X-0.8215 Y0.5228 +G01 X-0.8215 Y0.5572 +G01 X-0.8085 Y0.5702 +G01 X-0.8085 Y0.8600 +G01 X-0.8089 Y0.8642 +G01 X-0.8121 Y0.8719 +G01 X-0.8181 Y0.8779 +G01 X-0.8258 Y0.8811 +G01 X-0.8300 Y0.8815 +G01 X-0.8337 Y0.8815 +G01 X-0.8357 Y0.8815 +G01 X-0.8628 Y0.8815 +G01 X-0.8695 Y0.8748 +G01 X-0.8847 Y0.8685 +G01 X-1.0153 Y0.8685 +G01 X-1.0305 Y0.8748 +G01 X-1.0422 Y0.8865 +G01 X-1.0485 Y0.9017 +G01 X-1.0485 Y0.9183 +G01 X-1.0422 Y0.9335 +G01 X-1.0305 Y0.9452 +G01 X-1.0153 Y0.9515 +G00 Z0.1000 +G00 X-1.0153 Y1.3515 +G01 Z-0.0070 F10 +G01 X-0.8847 Y1.3515 F20 +G01 X-0.8695 Y1.3452 +G01 X-0.8628 Y1.3385 +G01 X-0.7502 Y1.3385 +G01 X-0.7372 Y1.3515 +G01 X-0.7028 Y1.3515 +G01 X-0.6785 Y1.3272 +G01 X-0.6785 Y1.2928 +G01 X-0.7028 Y1.2685 +G01 X-0.7372 Y1.2685 +G01 X-0.7502 Y1.2815 +G01 X-0.8628 Y1.2815 +G01 X-0.8695 Y1.2748 +G01 X-0.8847 Y1.2685 +G01 X-1.0153 Y1.2685 +G01 X-1.0305 Y1.2748 +G01 X-1.0422 Y1.2865 +G01 X-1.0485 Y1.3017 +G01 X-1.0485 Y1.3183 +G01 X-1.0422 Y1.3335 +G01 X-1.0305 Y1.3452 +G01 X-1.0153 Y1.3515 +G00 Z0.1000 +G00 X-2.7015 Y1.5928 +G01 Z-0.0070 F10 +G01 X-2.7015 Y1.6272 F20 +G01 X-2.6772 Y1.6515 +G01 X-2.6428 Y1.6515 +G01 X-2.6298 Y1.6385 +G01 X-2.5285 Y1.6385 +G01 X-2.5285 Y1.7043 +G01 X-2.5285 Y1.7053 +G01 X-2.5285 Y1.7157 +G01 X-2.5285 Y1.7216 +G01 X-2.5196 Y1.7431 +G01 X-2.5031 Y1.7596 +G01 X-2.4816 Y1.7685 +G01 X-2.4757 Y1.7685 +G01 X-2.4702 Y1.7685 +G01 X-2.4572 Y1.7815 +G01 X-2.4228 Y1.7815 +G01 X-2.3985 Y1.7572 +G01 X-2.3985 Y1.7228 +G01 X-2.4228 Y1.6985 +G01 X-2.4572 Y1.6985 +G01 X-2.4702 Y1.7115 +G01 X-2.4703 Y1.7115 +G01 X-2.4708 Y1.7112 +G01 X-2.4712 Y1.7108 +G01 X-2.4715 Y1.7103 +G01 X-2.4715 Y1.7100 +G01 X-2.4715 Y1.7053 +G01 X-2.4715 Y1.7043 +G01 X-2.4715 Y1.6043 +G01 X-2.4758 Y1.5939 +G01 X-2.4839 Y1.5858 +G01 X-2.4915 Y1.5827 +G01 X-2.4915 Y1.4457 +G01 X-2.4915 Y1.4343 +G01 X-2.4915 Y1.2600 +G01 X-2.4911 Y1.2558 +G01 X-2.4879 Y1.2481 +G01 X-2.4819 Y1.2421 +G01 X-2.4742 Y1.2389 +G01 X-2.4700 Y1.2385 +G01 X-2.4663 Y1.2385 +G01 X-2.4643 Y1.2385 +G01 X-2.3472 Y1.2385 +G01 X-2.3405 Y1.2452 +G01 X-2.3253 Y1.2515 +G01 X-2.1947 Y1.2515 +G01 X-2.1795 Y1.2452 +G01 X-2.1678 Y1.2335 +G01 X-2.1615 Y1.2183 +G01 X-2.1615 Y1.2017 +G01 X-2.1678 Y1.1865 +G01 X-2.1795 Y1.1748 +G01 X-2.1947 Y1.1685 +G01 X-2.2315 Y1.1685 +G01 X-2.2315 Y1.1515 +G01 X-2.1947 Y1.1515 +G01 X-2.1795 Y1.1452 +G01 X-2.1678 Y1.1335 +G01 X-2.1615 Y1.1183 +G01 X-2.1615 Y1.1017 +G01 X-2.1678 Y1.0865 +G01 X-2.1795 Y1.0748 +G01 X-2.1947 Y1.0685 +G01 X-2.3253 Y1.0685 +G01 X-2.3405 Y1.0748 +G01 X-2.3522 Y1.0865 +G01 X-2.3585 Y1.1017 +G01 X-2.3585 Y1.1183 +G01 X-2.3522 Y1.1335 +G01 X-2.3405 Y1.1452 +G01 X-2.3253 Y1.1515 +G01 X-2.2885 Y1.1515 +G01 X-2.2885 Y1.1685 +G01 X-2.3253 Y1.1685 +G01 X-2.3405 Y1.1748 +G01 X-2.3472 Y1.1815 +G01 X-2.4643 Y1.1815 +G01 X-2.4664 Y1.1815 +G01 X-2.4757 Y1.1815 +G01 X-2.4856 Y1.1815 +G01 X-2.5145 Y1.1935 +G01 X-2.5365 Y1.2155 +G01 X-2.5485 Y1.2444 +G01 X-2.5485 Y1.2543 +G01 X-2.5485 Y1.4115 +G01 X-2.8634 Y1.4115 +G01 X-2.8739 Y1.4010 +G01 X-2.8908 Y1.3940 +G01 X-2.9091 Y1.3940 +G01 X-2.9261 Y1.4010 +G01 X-2.9390 Y1.4139 +G01 X-2.9460 Y1.4308 +G01 X-2.9460 Y1.4491 +G01 X-2.9390 Y1.4661 +G01 X-2.9261 Y1.4790 +G01 X-2.9091 Y1.4860 +G01 X-2.8908 Y1.4860 +G01 X-2.8739 Y1.4790 +G01 X-2.8634 Y1.4685 +G01 X-2.5485 Y1.4685 +G01 X-2.5485 Y1.5815 +G01 X-2.6298 Y1.5815 +G01 X-2.6428 Y1.5685 +G01 X-2.6772 Y1.5685 +G01 X-2.7015 Y1.5928 +G00 Z0.1000 +G00 X-2.0575 Y0.2505 +G01 Z-0.0070 F10 +G01 X-2.0575 Y0.2694 F20 +G01 X-2.0503 Y0.2869 +G01 X-2.0385 Y0.2987 +G01 X-2.0385 Y0.3056 +G01 X-2.0265 Y0.3345 +G01 X-2.0045 Y0.3565 +G01 X-1.9756 Y0.3685 +G01 X-1.9657 Y0.3685 +G01 X-1.8587 Y0.3685 +G01 X-1.8485 Y0.3787 +G01 X-1.8485 Y0.4613 +G01 X-1.8587 Y0.4715 +G01 X-1.8656 Y0.4715 +G01 X-1.8945 Y0.4835 +G01 X-1.9165 Y0.5055 +G01 X-1.9285 Y0.5344 +G01 X-1.9453 Y0.5512 +G01 X-1.9453 Y0.5888 +G01 X-1.9188 Y0.6153 +G01 X-1.8812 Y0.6153 +G01 X-1.8547 Y0.5888 +G01 X-1.8547 Y0.5512 +G01 X-1.8679 Y0.5381 +G01 X-1.8619 Y0.5321 +G01 X-1.8571 Y0.5301 +G01 X-1.8469 Y0.5403 +G01 X-1.8294 Y0.5475 +G01 X-1.8105 Y0.5475 +G01 X-1.7931 Y0.5403 +G01 X-1.7797 Y0.5269 +G01 X-1.7725 Y0.5094 +G01 X-1.7725 Y0.4905 +G01 X-1.7797 Y0.4731 +G01 X-1.7915 Y0.4613 +G01 X-1.7915 Y0.3787 +G01 X-1.7797 Y0.3669 +G01 X-1.7725 Y0.3494 +G01 X-1.7725 Y0.3305 +G01 X-1.7797 Y0.3131 +G01 X-1.7931 Y0.2997 +G01 X-1.8105 Y0.2925 +G01 X-1.8294 Y0.2925 +G01 X-1.8469 Y0.2997 +G01 X-1.8587 Y0.3115 +G01 X-1.9600 Y0.3115 +G01 X-1.9642 Y0.3111 +G01 X-1.9719 Y0.3079 +G01 X-1.9779 Y0.3019 +G01 X-1.9799 Y0.2971 +G01 X-1.9697 Y0.2869 +G01 X-1.9625 Y0.2694 +G01 X-1.9625 Y0.2505 +G01 X-1.9697 Y0.2331 +G01 X-1.9831 Y0.2197 +G01 X-2.0005 Y0.2125 +G01 X-2.0194 Y0.2125 +G01 X-2.0369 Y0.2197 +G01 X-2.0503 Y0.2331 +G01 X-2.0575 Y0.2505 +G00 Z0.1000 +G00 X-0.5856 Y1.5715 +G01 Z-0.0070 F10 +G01 X-0.5856 Y1.5715 F20 +G01 X-0.6145 Y1.5835 +G01 X-0.6365 Y1.6055 +G01 X-0.6485 Y1.6344 +G01 X-0.6485 Y1.6443 +G01 X-0.6485 Y1.6500 +G01 X-0.6485 Y1.6557 +G01 X-0.6485 Y1.7200 +G01 X-0.6487 Y1.7222 +G01 X-0.6504 Y1.7264 +G01 X-0.6536 Y1.7296 +G01 X-0.6578 Y1.7313 +G01 X-0.6600 Y1.7315 +G01 X-1.3043 Y1.7315 +G01 X-1.3055 Y1.7315 +G01 X-1.3157 Y1.7315 +G01 X-1.3256 Y1.7315 +G01 X-1.3545 Y1.7435 +G01 X-1.3765 Y1.7655 +G01 X-1.3885 Y1.7944 +G01 X-1.3885 Y1.8043 +G01 X-1.3885 Y1.8234 +G01 X-1.4060 Y1.8409 +G01 X-1.4060 Y1.8791 +G01 X-1.3885 Y1.8966 +G01 X-1.3885 Y1.9543 +G01 X-1.3885 Y1.9590 +G01 X-1.3885 Y1.9600 +G01 X-1.3889 Y1.9642 +G01 X-1.3921 Y1.9719 +G01 X-1.3981 Y1.9779 +G01 X-1.4058 Y1.9811 +G01 X-1.4100 Y1.9815 +G01 X-1.4157 Y1.9815 +G01 X-1.5643 Y1.9815 +G01 X-1.5700 Y1.9815 +G01 X-1.5742 Y1.9811 +G01 X-1.5819 Y1.9779 +G01 X-1.5879 Y1.9719 +G01 X-1.5911 Y1.9642 +G01 X-1.5915 Y1.9600 +G01 X-1.5915 Y1.7957 +G01 X-1.5915 Y1.7743 +G01 X-1.5915 Y1.6357 +G01 X-1.5915 Y1.6300 +G01 X-1.5911 Y1.6258 +G01 X-1.5879 Y1.6181 +G01 X-1.5819 Y1.6121 +G01 X-1.5742 Y1.6089 +G01 X-1.5700 Y1.6085 +G01 X-1.5694 Y1.6085 +G01 X-1.5643 Y1.6085 +G01 X-1.1443 Y1.6085 +G01 X-1.1344 Y1.6085 +G01 X-1.1055 Y1.5965 +G01 X-1.0835 Y1.5745 +G01 X-1.0715 Y1.5456 +G01 X-1.0715 Y1.5357 +G01 X-1.0715 Y1.5304 +G01 X-1.0715 Y1.5300 +G01 X-1.0715 Y1.5243 +G01 X-1.0715 Y0.8600 +G01 X-1.0711 Y0.8558 +G01 X-1.0679 Y0.8480 +G01 X-1.0619 Y0.8421 +G01 X-1.0542 Y0.8389 +G01 X-1.0500 Y0.8385 +G01 X-1.0450 Y0.8385 +G01 X-1.0443 Y0.8385 +G01 X-1.0372 Y0.8385 +G01 X-1.0305 Y0.8452 +G01 X-1.0153 Y0.8515 +G01 X-0.8847 Y0.8515 +G01 X-0.8695 Y0.8452 +G01 X-0.8578 Y0.8335 +G01 X-0.8515 Y0.8183 +G01 X-0.8515 Y0.8017 +G01 X-0.8578 Y0.7865 +G01 X-0.8695 Y0.7748 +G01 X-0.8847 Y0.7685 +G01 X-1.0153 Y0.7685 +G01 X-1.0305 Y0.7748 +G01 X-1.0372 Y0.7815 +G01 X-1.0443 Y0.7815 +G01 X-1.0450 Y0.7815 +G01 X-1.0557 Y0.7815 +G01 X-1.0656 Y0.7815 +G01 X-1.0945 Y0.7935 +G01 X-1.1165 Y0.8155 +G01 X-1.1285 Y0.8444 +G01 X-1.1285 Y0.8543 +G01 X-1.1285 Y1.5243 +G01 X-1.1285 Y1.5300 +G01 X-1.1289 Y1.5342 +G01 X-1.1321 Y1.5419 +G01 X-1.1381 Y1.5479 +G01 X-1.1458 Y1.5511 +G01 X-1.1500 Y1.5515 +G01 X-1.5643 Y1.5515 +G01 X-1.5694 Y1.5515 +G01 X-1.5757 Y1.5515 +G01 X-1.5856 Y1.5515 +G01 X-1.6145 Y1.5635 +G01 X-1.6365 Y1.5855 +G01 X-1.6485 Y1.6144 +G01 X-1.6485 Y1.6243 +G01 X-1.6485 Y1.6299 +G01 X-1.6485 Y1.6357 +G01 X-1.6485 Y1.7615 +G01 X-1.9344 Y1.7615 +G01 X-1.9512 Y1.7447 +G01 X-1.9888 Y1.7447 +G01 X-2.0153 Y1.7712 +G01 X-2.0153 Y1.8088 +G01 X-1.9888 Y1.8353 +G01 X-1.9512 Y1.8353 +G01 X-1.9344 Y1.8185 +G01 X-1.6485 Y1.8185 +G01 X-1.6485 Y1.9657 +G01 X-1.6485 Y1.9756 +G01 X-1.6365 Y2.0045 +G01 X-1.6145 Y2.0265 +G01 X-1.5856 Y2.0385 +G01 X-1.5757 Y2.0385 +G01 X-1.5707 Y2.0385 +G01 X-1.5700 Y2.0385 +G01 X-1.5643 Y2.0385 +G01 X-1.4157 Y2.0385 +G01 X-1.4100 Y2.0385 +G01 X-1.4065 Y2.0385 +G01 X-1.4043 Y2.0385 +G01 X-1.3944 Y2.0385 +G01 X-1.3655 Y2.0265 +G01 X-1.3435 Y2.0045 +G01 X-1.3315 Y1.9756 +G01 X-1.3315 Y1.9657 +G01 X-1.3315 Y1.9590 +G01 X-1.3315 Y1.9543 +G01 X-1.3315 Y1.8966 +G01 X-1.3140 Y1.8791 +G01 X-1.3140 Y1.8409 +G01 X-1.3315 Y1.8234 +G01 X-1.3315 Y1.8100 +G01 X-1.3311 Y1.8058 +G01 X-1.3279 Y1.7981 +G01 X-1.3219 Y1.7921 +G01 X-1.3142 Y1.7889 +G01 X-1.3100 Y1.7885 +G01 X-1.3055 Y1.7885 +G01 X-1.3043 Y1.7885 +G01 X-0.6543 Y1.7885 +G01 X-0.6464 Y1.7885 +G01 X-0.6212 Y1.7781 +G01 X-0.6019 Y1.7588 +G01 X-0.5915 Y1.7336 +G01 X-0.5915 Y1.7257 +G01 X-0.5915 Y1.6557 +G01 X-0.5915 Y1.6500 +G01 X-0.5911 Y1.6458 +G01 X-0.5879 Y1.6381 +G01 X-0.5819 Y1.6321 +G01 X-0.5742 Y1.6289 +G01 X-0.5700 Y1.6285 +G01 X-0.3006 Y1.6285 +G01 X-0.2960 Y1.6331 +G01 X-0.2780 Y1.6406 +G01 X-0.1220 Y1.6406 +G01 X-0.1040 Y1.6331 +G01 X-0.0902 Y1.6193 +G01 X-0.0828 Y1.6013 +G01 X-0.0828 Y1.5818 +G01 X-0.0902 Y1.5638 +G01 X-0.1040 Y1.5500 +G01 X-0.1220 Y1.5426 +G01 X-0.2780 Y1.5426 +G01 X-0.2960 Y1.5500 +G01 X-0.3098 Y1.5638 +G01 X-0.3130 Y1.5715 +G01 X-0.5757 Y1.5715 +G01 X-0.5856 Y1.5715 +G00 Z0.1000 +G00 X-2.9215 Y1.7664 +G01 Z-0.0070 F10 +G01 X-2.9215 Y1.7664 F20 +G01 X-2.9319 Y1.7412 +G01 X-2.9512 Y1.7219 +G01 X-2.9764 Y1.7115 +G01 X-2.9843 Y1.7115 +G01 X-2.9896 Y1.7115 +G01 X-2.9900 Y1.7115 +G01 X-2.9957 Y1.7115 +G01 X-3.1100 Y1.7115 +G01 X-3.1142 Y1.7111 +G01 X-3.1219 Y1.7079 +G01 X-3.1279 Y1.7019 +G01 X-3.1311 Y1.6942 +G01 X-3.1315 Y1.6900 +G01 X-3.1315 Y1.6850 +G01 X-3.1315 Y1.6843 +G01 X-3.1315 Y1.6402 +G01 X-3.1185 Y1.6272 +G01 X-3.1185 Y1.5928 +G01 X-3.1315 Y1.5798 +G01 X-3.1315 Y0.9600 +G01 X-3.1311 Y0.9558 +G01 X-3.1279 Y0.9481 +G01 X-3.1219 Y0.9421 +G01 X-3.1142 Y0.9389 +G01 X-3.1100 Y0.9385 +G01 X-3.1057 Y0.9385 +G01 X-3.1043 Y0.9385 +G01 X-2.5456 Y0.9385 +G01 X-2.5288 Y0.9553 +G01 X-2.4912 Y0.9553 +G01 X-2.4744 Y0.9385 +G01 X-2.1657 Y0.9385 +G01 X-2.1600 Y0.9385 +G01 X-2.1558 Y0.9389 +G01 X-2.1481 Y0.9421 +G01 X-2.1421 Y0.9481 +G01 X-2.1389 Y0.9558 +G01 X-2.1385 Y0.9600 +G01 X-2.1385 Y1.0657 +G01 X-2.1385 Y1.2782 +G01 X-2.1418 Y1.2815 +G01 X-2.1728 Y1.2815 +G01 X-2.1795 Y1.2748 +G01 X-2.1947 Y1.2685 +G01 X-2.3253 Y1.2685 +G01 X-2.3405 Y1.2748 +G01 X-2.3522 Y1.2865 +G01 X-2.3585 Y1.3017 +G01 X-2.3585 Y1.3183 +G01 X-2.3522 Y1.3335 +G01 X-2.3405 Y1.3452 +G01 X-2.3253 Y1.3515 +G01 X-2.1947 Y1.3515 +G01 X-2.1795 Y1.3452 +G01 X-2.1728 Y1.3385 +G01 X-2.1243 Y1.3385 +G01 X-2.1204 Y1.3385 +G01 X-2.1025 Y1.3311 +G01 X-2.0889 Y1.3175 +G01 X-2.0815 Y1.2996 +G01 X-2.0815 Y1.2957 +G01 X-2.0815 Y1.2843 +G01 X-2.0815 Y1.0657 +G01 X-2.0815 Y1.0518 +G01 X-2.0682 Y1.0385 +G01 X-2.0472 Y1.0385 +G01 X-2.0405 Y1.0452 +G01 X-2.0253 Y1.0515 +G01 X-1.8947 Y1.0515 +G01 X-1.8795 Y1.0452 +G01 X-1.8678 Y1.0335 +G01 X-1.8615 Y1.0183 +G01 X-1.8615 Y1.0017 +G01 X-1.8678 Y0.9865 +G01 X-1.8795 Y0.9748 +G01 X-1.8947 Y0.9685 +G01 X-2.0253 Y0.9685 +G01 X-2.0405 Y0.9748 +G01 X-2.0472 Y0.9815 +G01 X-2.0743 Y0.9815 +G01 X-2.0815 Y0.9815 +G01 X-2.0815 Y0.9543 +G01 X-2.0815 Y0.9444 +G01 X-2.0935 Y0.9155 +G01 X-2.1155 Y0.8935 +G01 X-2.1444 Y0.8815 +G01 X-2.1543 Y0.8815 +G01 X-2.1588 Y0.8815 +G01 X-2.1600 Y0.8815 +G01 X-2.1657 Y0.8815 +G01 X-2.4744 Y0.8815 +G01 X-2.4912 Y0.8647 +G01 X-2.5288 Y0.8647 +G01 X-2.5456 Y0.8815 +G01 X-3.1043 Y0.8815 +G01 X-3.1057 Y0.8815 +G01 X-3.1157 Y0.8815 +G01 X-3.1256 Y0.8815 +G01 X-3.1545 Y0.8935 +G01 X-3.1765 Y0.9155 +G01 X-3.1885 Y0.9444 +G01 X-3.1885 Y0.9543 +G01 X-3.1885 Y1.5798 +G01 X-3.2015 Y1.5928 +G01 X-3.2015 Y1.6272 +G01 X-3.1885 Y1.6402 +G01 X-3.1885 Y1.6843 +G01 X-3.1885 Y1.6850 +G01 X-3.1885 Y1.6957 +G01 X-3.1885 Y1.7056 +G01 X-3.1765 Y1.7345 +G01 X-3.1545 Y1.7565 +G01 X-3.1256 Y1.7685 +G01 X-3.1157 Y1.7685 +G01 X-2.9957 Y1.7685 +G01 X-2.9900 Y1.7685 +G01 X-2.9878 Y1.7687 +G01 X-2.9836 Y1.7704 +G01 X-2.9804 Y1.7736 +G01 X-2.9787 Y1.7778 +G01 X-2.9785 Y1.7800 +G01 X-2.9785 Y1.8543 +G01 X-2.9785 Y1.8559 +G01 X-2.9785 Y1.8657 +G01 X-2.9785 Y1.8756 +G01 X-2.9665 Y1.9045 +G01 X-2.9445 Y1.9265 +G01 X-2.9156 Y1.9385 +G01 X-2.9057 Y1.9385 +G01 X-2.0957 Y1.9385 +G01 X-2.0843 Y1.9385 +G01 X-2.0302 Y1.9385 +G01 X-2.0172 Y1.9515 +G01 X-1.9828 Y1.9515 +G01 X-1.9698 Y1.9385 +G01 X-1.7700 Y1.9385 +G01 X-1.7658 Y1.9389 +G01 X-1.7581 Y1.9421 +G01 X-1.7521 Y1.9481 +G01 X-1.7489 Y1.9558 +G01 X-1.7485 Y1.9600 +G01 X-1.7485 Y1.9644 +G01 X-1.7485 Y1.9657 +G01 X-1.7485 Y2.0657 +G01 X-1.7485 Y2.0756 +G01 X-1.7365 Y2.1045 +G01 X-1.7145 Y2.1265 +G01 X-1.6856 Y2.1385 +G01 X-1.6757 Y2.1385 +G01 X-1.6703 Y2.1385 +G01 X-1.6700 Y2.1385 +G01 X-1.6643 Y2.1385 +G01 X-1.2543 Y2.1385 +G01 X-1.2444 Y2.1385 +G01 X-1.2155 Y2.1265 +G01 X-1.1935 Y2.1045 +G01 X-1.1815 Y2.0756 +G01 X-1.1815 Y2.0657 +G01 X-1.1815 Y2.0606 +G01 X-1.1815 Y2.0600 +G01 X-1.1815 Y2.0543 +G01 X-1.1815 Y1.9157 +G01 X-1.1815 Y1.9100 +G01 X-1.1811 Y1.9058 +G01 X-1.1779 Y1.8981 +G01 X-1.1719 Y1.8921 +G01 X-1.1642 Y1.8889 +G01 X-1.1600 Y1.8885 +G01 X-1.1559 Y1.8885 +G01 X-1.1543 Y1.8885 +G01 X-0.7966 Y1.8885 +G01 X-0.7861 Y1.8990 +G01 X-0.7691 Y1.9060 +G01 X-0.7508 Y1.9060 +G01 X-0.7339 Y1.8990 +G01 X-0.7234 Y1.8885 +G01 X-0.2659 Y1.8885 +G01 X-0.2517 Y1.8885 +G01 X-0.2149 Y1.8733 +G01 X-0.1867 Y1.8451 +G01 X-0.1836 Y1.8374 +G01 X-0.1220 Y1.8374 +G01 X-0.1040 Y1.8300 +G01 X-0.0902 Y1.8162 +G01 X-0.0828 Y1.7982 +G01 X-0.0828 Y1.7787 +G01 X-0.0902 Y1.7607 +G01 X-0.1040 Y1.7469 +G01 X-0.1220 Y1.7394 +G01 X-0.2780 Y1.7394 +G01 X-0.2960 Y1.7469 +G01 X-0.3098 Y1.7607 +G01 X-0.3172 Y1.7787 +G01 X-0.3172 Y1.7982 +G01 X-0.3098 Y1.8162 +G01 X-0.2960 Y1.8300 +G01 X-0.2923 Y1.8315 +G01 X-0.7234 Y1.8315 +G01 X-0.7339 Y1.8210 +G01 X-0.7508 Y1.8140 +G01 X-0.7691 Y1.8140 +G01 X-0.7861 Y1.8210 +G01 X-0.7966 Y1.8315 +G01 X-1.1543 Y1.8315 +G01 X-1.1559 Y1.8315 +G01 X-1.1657 Y1.8315 +G01 X-1.1756 Y1.8315 +G01 X-1.2045 Y1.8435 +G01 X-1.2265 Y1.8655 +G01 X-1.2385 Y1.8944 +G01 X-1.2385 Y1.9043 +G01 X-1.2385 Y1.9060 +G01 X-1.2385 Y1.9100 +G01 X-1.2385 Y1.9157 +G01 X-1.2385 Y2.0543 +G01 X-1.2385 Y2.0600 +G01 X-1.2389 Y2.0642 +G01 X-1.2421 Y2.0719 +G01 X-1.2481 Y2.0779 +G01 X-1.2558 Y2.0811 +G01 X-1.2600 Y2.0815 +G01 X-1.6643 Y2.0815 +G01 X-1.6700 Y2.0815 +G01 X-1.6742 Y2.0811 +G01 X-1.6819 Y2.0779 +G01 X-1.6879 Y2.0719 +G01 X-1.6911 Y2.0642 +G01 X-1.6915 Y2.0600 +G01 X-1.6915 Y1.9657 +G01 X-1.6915 Y1.9644 +G01 X-1.6915 Y1.9543 +G01 X-1.6915 Y1.9444 +G01 X-1.7035 Y1.9155 +G01 X-1.7255 Y1.8935 +G01 X-1.7544 Y1.8815 +G01 X-1.7643 Y1.8815 +G01 X-1.9698 Y1.8815 +G01 X-1.9828 Y1.8685 +G01 X-2.0172 Y1.8685 +G01 X-2.0302 Y1.8815 +G01 X-2.0615 Y1.8815 +G01 X-2.0615 Y1.7500 +G01 X-2.0611 Y1.7458 +G01 X-2.0579 Y1.7381 +G01 X-2.0519 Y1.7321 +G01 X-2.0442 Y1.7289 +G01 X-2.0400 Y1.7285 +G01 X-2.0354 Y1.7285 +G01 X-2.0343 Y1.7285 +G01 X-1.8002 Y1.7285 +G01 X-1.7872 Y1.7415 +G01 X-1.7528 Y1.7415 +G01 X-1.7398 Y1.7285 +G01 X-1.7343 Y1.7285 +G01 X-1.7284 Y1.7285 +G01 X-1.7069 Y1.7196 +G01 X-1.6904 Y1.7031 +G01 X-1.6815 Y1.6816 +G01 X-1.6815 Y1.6757 +G01 X-1.6815 Y1.5100 +G01 X-1.6811 Y1.5058 +G01 X-1.6779 Y1.4981 +G01 X-1.6719 Y1.4921 +G01 X-1.6642 Y1.4889 +G01 X-1.6600 Y1.4885 +G01 X-1.6578 Y1.4885 +G01 X-1.6543 Y1.4885 +G01 X-1.4657 Y1.4885 +G01 X-1.4600 Y1.4885 +G01 X-1.4567 Y1.4885 +G01 X-1.4543 Y1.4885 +G01 X-1.4444 Y1.4885 +G01 X-1.4155 Y1.4765 +G01 X-1.3935 Y1.4545 +G01 X-1.3852 Y1.4345 +G01 X-1.3756 Y1.4385 +G01 X-1.3657 Y1.4385 +G01 X-1.3596 Y1.4385 +G01 X-1.3543 Y1.4385 +G01 X-1.3372 Y1.4385 +G01 X-1.3305 Y1.4452 +G01 X-1.3153 Y1.4515 +G01 X-1.1847 Y1.4515 +G01 X-1.1695 Y1.4452 +G01 X-1.1578 Y1.4335 +G01 X-1.1515 Y1.4183 +G01 X-1.1515 Y1.4017 +G01 X-1.1578 Y1.3865 +G01 X-1.1695 Y1.3748 +G01 X-1.1847 Y1.3685 +G01 X-1.3153 Y1.3685 +G01 X-1.3305 Y1.3748 +G01 X-1.3372 Y1.3815 +G01 X-1.3543 Y1.3815 +G01 X-1.3596 Y1.3815 +G01 X-1.3600 Y1.3815 +G01 X-1.3642 Y1.3811 +G01 X-1.3719 Y1.3779 +G01 X-1.3779 Y1.3719 +G01 X-1.3811 Y1.3642 +G01 X-1.3815 Y1.3600 +G01 X-1.3815 Y1.2543 +G01 X-1.3815 Y1.2450 +G01 X-1.3815 Y1.2351 +G01 X-1.3885 Y1.2182 +G01 X-1.3885 Y1.1928 +G01 X-1.4128 Y1.1685 +G01 X-1.4472 Y1.1685 +G01 X-1.4715 Y1.1928 +G01 X-1.4715 Y1.2272 +G01 X-1.4472 Y1.2515 +G01 X-1.4385 Y1.2515 +G01 X-1.4385 Y1.2543 +G01 X-1.4385 Y1.4100 +G01 X-1.4389 Y1.4142 +G01 X-1.4421 Y1.4219 +G01 X-1.4481 Y1.4279 +G01 X-1.4558 Y1.4311 +G01 X-1.4600 Y1.4315 +G01 X-1.4657 Y1.4315 +G01 X-1.6543 Y1.4315 +G01 X-1.6578 Y1.4315 +G01 X-1.6657 Y1.4315 +G01 X-1.6756 Y1.4315 +G01 X-1.7045 Y1.4435 +G01 X-1.7265 Y1.4655 +G01 X-1.7385 Y1.4944 +G01 X-1.7385 Y1.5043 +G01 X-1.7385 Y1.6700 +G01 X-1.7385 Y1.6703 +G01 X-1.7387 Y1.6708 +G01 X-1.7392 Y1.6712 +G01 X-1.7397 Y1.6715 +G01 X-1.7398 Y1.6715 +G01 X-1.7528 Y1.6585 +G01 X-1.7872 Y1.6585 +G01 X-1.7999 Y1.6712 +G01 X-1.8011 Y1.6715 +G01 X-2.0343 Y1.6715 +G01 X-2.0354 Y1.6715 +G01 X-2.0457 Y1.6715 +G01 X-2.0556 Y1.6715 +G01 X-2.0845 Y1.6835 +G01 X-2.1065 Y1.7055 +G01 X-2.1185 Y1.7344 +G01 X-2.1185 Y1.7443 +G01 X-2.1185 Y1.8815 +G01 X-2.9000 Y1.8815 +G01 X-2.9042 Y1.8811 +G01 X-2.9119 Y1.8779 +G01 X-2.9179 Y1.8719 +G01 X-2.9211 Y1.8642 +G01 X-2.9215 Y1.8600 +G01 X-2.9215 Y1.8559 +G01 X-2.9215 Y1.8543 +G01 X-2.9215 Y1.7743 +G01 X-2.9215 Y1.7664 +G00 Z0.1000 +G00 X-3.0985 Y1.6156 +G01 Z-0.0070 F10 +G01 X-3.0985 Y1.6156 F20 +G01 X-3.0865 Y1.6445 +G01 X-3.0645 Y1.6665 +G01 X-3.0356 Y1.6785 +G01 X-3.0257 Y1.6785 +G01 X-3.0197 Y1.6785 +G01 X-3.0143 Y1.6785 +G01 X-2.9000 Y1.6785 +G01 X-2.8997 Y1.6785 +G01 X-2.8992 Y1.6787 +G01 X-2.8987 Y1.6792 +G01 X-2.8985 Y1.6797 +G01 X-2.8985 Y1.6800 +G01 X-2.8985 Y1.6843 +G01 X-2.8985 Y1.6857 +G01 X-2.8985 Y1.7757 +G01 X-2.8985 Y1.7856 +G01 X-2.8865 Y1.8145 +G01 X-2.8645 Y1.8365 +G01 X-2.8356 Y1.8485 +G01 X-2.8257 Y1.8485 +G01 X-2.8204 Y1.8485 +G01 X-2.8200 Y1.8485 +G01 X-2.8143 Y1.8485 +G01 X-2.7002 Y1.8485 +G01 X-2.6872 Y1.8615 +G01 X-2.6528 Y1.8615 +G01 X-2.6285 Y1.8372 +G01 X-2.6285 Y1.8028 +G01 X-2.6528 Y1.7785 +G01 X-2.6872 Y1.7785 +G01 X-2.7002 Y1.7915 +G01 X-2.8143 Y1.7915 +G01 X-2.8200 Y1.7915 +G01 X-2.8242 Y1.7911 +G01 X-2.8319 Y1.7879 +G01 X-2.8379 Y1.7819 +G01 X-2.8411 Y1.7742 +G01 X-2.8415 Y1.7700 +G01 X-2.8415 Y1.6857 +G01 X-2.8415 Y1.6842 +G01 X-2.8415 Y1.6743 +G01 X-2.8415 Y1.6684 +G01 X-2.8504 Y1.6469 +G01 X-2.8669 Y1.6304 +G01 X-2.8884 Y1.6215 +G01 X-2.8943 Y1.6215 +G01 X-3.0143 Y1.6215 +G01 X-3.0198 Y1.6215 +G01 X-3.0200 Y1.6215 +G01 X-3.0242 Y1.6211 +G01 X-3.0319 Y1.6179 +G01 X-3.0379 Y1.6119 +G01 X-3.0411 Y1.6042 +G01 X-3.0415 Y1.6000 +G01 X-3.0415 Y1.2900 +G01 X-3.0411 Y1.2858 +G01 X-3.0379 Y1.2781 +G01 X-3.0319 Y1.2721 +G01 X-3.0242 Y1.2689 +G01 X-3.0200 Y1.2685 +G01 X-2.7228 Y1.2685 +G01 X-2.7200 Y1.2691 +G01 X-2.7172 Y1.2685 +G01 X-2.7143 Y1.2685 +G01 X-2.7117 Y1.2674 +G01 X-2.7113 Y1.2673 +G01 X-2.6872 Y1.2915 +G01 X-2.6528 Y1.2915 +G01 X-2.6285 Y1.2672 +G01 X-2.6285 Y1.2328 +G01 X-2.6528 Y1.2085 +G01 X-2.6783 Y1.2085 +G01 X-2.6999 Y1.2042 +G01 X-2.7251 Y1.2092 +G01 X-2.7286 Y1.2115 +G01 X-3.0257 Y1.2115 +G01 X-3.0356 Y1.2115 +G01 X-3.0645 Y1.2235 +G01 X-3.0865 Y1.2455 +G01 X-3.0985 Y1.2744 +G01 X-3.0985 Y1.2843 +G01 X-3.0985 Y1.6057 +G01 X-3.0985 Y1.6156 +G00 Z0.1000 +G00 X-2.1685 Y0.6256 +G01 Z-0.0070 F10 +G01 X-2.1685 Y0.6256 F20 +G01 X-2.1565 Y0.6545 +G01 X-2.1345 Y0.6765 +G01 X-2.1056 Y0.6885 +G01 X-2.0957 Y0.6885 +G01 X-2.0899 Y0.6885 +G01 X-2.0843 Y0.6885 +G01 X-2.0487 Y0.6885 +G01 X-2.0369 Y0.7003 +G01 X-2.0194 Y0.7075 +G01 X-2.0005 Y0.7075 +G01 X-1.9831 Y0.7003 +G01 X-1.9713 Y0.6885 +G01 X-1.7802 Y0.6885 +G01 X-1.7672 Y0.7015 +G01 X-1.7328 Y0.7015 +G01 X-1.7085 Y0.6772 +G01 X-1.7085 Y0.6428 +G01 X-1.7328 Y0.6185 +G01 X-1.7672 Y0.6185 +G01 X-1.7802 Y0.6315 +G01 X-1.9713 Y0.6315 +G01 X-1.9831 Y0.6197 +G01 X-2.0005 Y0.6125 +G01 X-2.0194 Y0.6125 +G01 X-2.0369 Y0.6197 +G01 X-2.0487 Y0.6315 +G01 X-2.0843 Y0.6315 +G01 X-2.0900 Y0.6315 +G01 X-2.0942 Y0.6311 +G01 X-2.1019 Y0.6279 +G01 X-2.1079 Y0.6219 +G01 X-2.1111 Y0.6142 +G01 X-2.1115 Y0.6100 +G01 X-2.1115 Y0.2902 +G01 X-2.0985 Y0.2772 +G01 X-2.0985 Y0.2428 +G01 X-2.1228 Y0.2185 +G01 X-2.1572 Y0.2185 +G01 X-2.1815 Y0.2428 +G01 X-2.1815 Y0.2772 +G01 X-2.1685 Y0.2902 +G01 X-2.1685 Y0.6157 +G01 X-2.1685 Y0.6256 +G00 Z0.1000 +G00 X-0.5315 Y0.4744 +G01 Z-0.0070 F10 +G01 X-0.5315 Y0.4744 F20 +G01 X-0.5435 Y0.4455 +G01 X-0.5655 Y0.4235 +G01 X-0.5944 Y0.4115 +G01 X-0.6043 Y0.4115 +G01 X-0.6100 Y0.4115 +G01 X-0.6157 Y0.4115 +G01 X-1.3757 Y0.4115 +G01 X-1.3856 Y0.4115 +G01 X-1.4145 Y0.4235 +G01 X-1.4365 Y0.4455 +G01 X-1.4415 Y0.4575 +G01 X-1.4469 Y0.4597 +G01 X-1.4603 Y0.4731 +G01 X-1.4675 Y0.4905 +G01 X-1.4675 Y0.5094 +G01 X-1.4603 Y0.5269 +G01 X-1.4585 Y0.5287 +G01 X-1.4585 Y0.6798 +G01 X-1.4715 Y0.6928 +G01 X-1.4715 Y0.7272 +G01 X-1.4472 Y0.7515 +G01 X-1.4128 Y0.7515 +G01 X-1.3885 Y0.7272 +G01 X-1.3885 Y0.6928 +G01 X-1.4015 Y0.6798 +G01 X-1.4015 Y0.5437 +G01 X-1.3931 Y0.5403 +G01 X-1.3797 Y0.5269 +G01 X-1.3725 Y0.5094 +G01 X-1.3725 Y0.4905 +G01 X-1.3797 Y0.4731 +G01 X-1.3811 Y0.4718 +G01 X-1.3742 Y0.4689 +G01 X-1.3700 Y0.4685 +G01 X-0.6157 Y0.4685 +G01 X-0.6100 Y0.4685 +G01 X-0.6058 Y0.4689 +G01 X-0.5981 Y0.4721 +G01 X-0.5921 Y0.4781 +G01 X-0.5889 Y0.4858 +G01 X-0.5885 Y0.4900 +G01 X-0.5885 Y0.8798 +G01 X-0.6015 Y0.8928 +G01 X-0.6015 Y0.9272 +G01 X-0.5772 Y0.9515 +G01 X-0.5428 Y0.9515 +G01 X-0.5185 Y0.9272 +G01 X-0.5185 Y0.8928 +G01 X-0.5315 Y0.8798 +G01 X-0.5315 Y0.4843 +G01 X-0.5315 Y0.4744 +G00 Z0.1000 +G00 X-0.4285 Y0.2838 +G01 Z-0.0070 F10 +G01 X-0.4285 Y0.2838 F20 +G01 X-0.4409 Y0.2538 +G01 X-0.4638 Y0.2309 +G01 X-0.4938 Y0.2185 +G01 X-0.5037 Y0.2185 +G01 X-0.5100 Y0.2185 +G01 X-0.5163 Y0.2185 +G01 X-1.0400 Y0.2185 +G01 X-1.0436 Y0.2181 +G01 X-1.0503 Y0.2154 +G01 X-1.0554 Y0.2103 +G01 X-1.0581 Y0.2036 +G01 X-1.0585 Y0.2000 +G01 X-1.0585 Y0.1964 +G01 X-1.0585 Y0.1937 +G01 X-1.0585 Y0.1437 +G01 X-1.0585 Y0.1338 +G01 X-1.0709 Y0.1038 +G01 X-1.0938 Y0.0809 +G01 X-1.1238 Y0.0685 +G01 X-1.1337 Y0.0685 +G01 X-1.1393 Y0.0685 +G01 X-1.1400 Y0.0685 +G01 X-1.1463 Y0.0685 +G01 X-1.5937 Y0.0685 +G01 X-1.6000 Y0.0685 +G01 X-1.6037 Y0.0685 +G01 X-1.6063 Y0.0685 +G01 X-1.6162 Y0.0685 +G01 X-1.6462 Y0.0809 +G01 X-1.6691 Y0.1038 +G01 X-1.6815 Y0.1338 +G01 X-1.6815 Y0.1437 +G01 X-1.6815 Y0.1511 +G01 X-1.6815 Y0.1563 +G01 X-1.6815 Y0.8663 +G01 X-1.6815 Y0.8762 +G01 X-1.6691 Y0.9062 +G01 X-1.6462 Y0.9291 +G01 X-1.6162 Y0.9415 +G01 X-1.6063 Y0.9415 +G01 X-1.6000 Y0.9415 +G01 X-1.5937 Y0.9415 +G01 X-1.3384 Y0.9415 +G01 X-1.3322 Y0.9477 +G01 X-1.3159 Y0.9545 +G01 X-1.1841 Y0.9545 +G01 X-1.1678 Y0.9477 +G01 X-1.1553 Y0.9352 +G01 X-1.1485 Y0.9189 +G01 X-1.1485 Y0.9011 +G01 X-1.1553 Y0.8848 +G01 X-1.1678 Y0.8723 +G01 X-1.1841 Y0.8655 +G01 X-1.3159 Y0.8655 +G01 X-1.3322 Y0.8723 +G01 X-1.3384 Y0.8785 +G01 X-1.5937 Y0.8785 +G01 X-1.6000 Y0.8785 +G01 X-1.6036 Y0.8781 +G01 X-1.6103 Y0.8754 +G01 X-1.6154 Y0.8703 +G01 X-1.6181 Y0.8636 +G01 X-1.6185 Y0.8600 +G01 X-1.6185 Y0.1563 +G01 X-1.6185 Y0.1511 +G01 X-1.6185 Y0.1500 +G01 X-1.6181 Y0.1464 +G01 X-1.6154 Y0.1397 +G01 X-1.6103 Y0.1346 +G01 X-1.6036 Y0.1319 +G01 X-1.6000 Y0.1315 +G01 X-1.5937 Y0.1315 +G01 X-1.1463 Y0.1315 +G01 X-1.1400 Y0.1315 +G01 X-1.1364 Y0.1319 +G01 X-1.1297 Y0.1346 +G01 X-1.1246 Y0.1397 +G01 X-1.1219 Y0.1464 +G01 X-1.1215 Y0.1500 +G01 X-1.1215 Y0.1937 +G01 X-1.1215 Y0.1964 +G01 X-1.1215 Y0.2063 +G01 X-1.1215 Y0.2162 +G01 X-1.1091 Y0.2462 +G01 X-1.0862 Y0.2691 +G01 X-1.0562 Y0.2815 +G01 X-1.0463 Y0.2815 +G01 X-0.5163 Y0.2815 +G01 X-0.5100 Y0.2815 +G01 X-0.5064 Y0.2819 +G01 X-0.4997 Y0.2846 +G01 X-0.4946 Y0.2897 +G01 X-0.4919 Y0.2964 +G01 X-0.4915 Y0.3000 +G01 X-0.4915 Y0.6537 +G01 X-0.4915 Y0.6548 +G01 X-0.4915 Y0.6663 +G01 X-0.4915 Y0.6762 +G01 X-0.4791 Y0.7062 +G01 X-0.4562 Y0.7291 +G01 X-0.4262 Y0.7415 +G01 X-0.4163 Y0.7415 +G01 X-0.4132 Y0.7415 +G01 X-0.4100 Y0.7415 +G01 X-0.4037 Y0.7415 +G01 X-0.3119 Y0.7415 +G01 X-0.2977 Y0.7557 +G01 X-0.2786 Y0.7636 +G01 X-0.1214 Y0.7636 +G01 X-0.1023 Y0.7557 +G01 X-0.0877 Y0.7410 +G01 X-0.0798 Y0.7219 +G01 X-0.0798 Y0.7012 +G01 X-0.0877 Y0.6821 +G01 X-0.1023 Y0.6675 +G01 X-0.1214 Y0.6596 +G01 X-0.2786 Y0.6596 +G01 X-0.2977 Y0.6675 +G01 X-0.3087 Y0.6785 +G01 X-0.4037 Y0.6785 +G01 X-0.4100 Y0.6785 +G01 X-0.4136 Y0.6781 +G01 X-0.4203 Y0.6754 +G01 X-0.4254 Y0.6703 +G01 X-0.4281 Y0.6636 +G01 X-0.4285 Y0.6600 +G01 X-0.4285 Y0.6548 +G01 X-0.4285 Y0.6537 +G01 X-0.4285 Y0.2937 +G01 X-0.4285 Y0.2838 +G00 Z0.1000 +G00 X-2.1715 Y0.6262 +G01 Z-0.0070 F10 +G01 X-2.1715 Y0.6262 F20 +G01 X-2.1591 Y0.6562 +G01 X-2.1362 Y0.6791 +G01 X-2.1062 Y0.6915 +G01 X-2.0963 Y0.6915 +G01 X-2.0897 Y0.6915 +G01 X-2.0837 Y0.6915 +G01 X-2.0499 Y0.6915 +G01 X-2.0386 Y0.7028 +G01 X-2.0200 Y0.7105 +G01 X-2.0000 Y0.7105 +G01 X-1.9814 Y0.7028 +G01 X-1.9701 Y0.6915 +G01 X-1.7814 Y0.6915 +G01 X-1.7684 Y0.7045 +G01 X-1.7316 Y0.7045 +G01 X-1.7055 Y0.6784 +G01 X-1.7055 Y0.6416 +G01 X-1.7316 Y0.6155 +G01 X-1.7684 Y0.6155 +G01 X-1.7814 Y0.6285 +G01 X-1.9701 Y0.6285 +G01 X-1.9814 Y0.6172 +G01 X-2.0000 Y0.6095 +G01 X-2.0200 Y0.6095 +G01 X-2.0386 Y0.6172 +G01 X-2.0499 Y0.6285 +G01 X-2.0837 Y0.6285 +G01 X-2.0898 Y0.6285 +G01 X-2.0900 Y0.6285 +G01 X-2.0936 Y0.6281 +G01 X-2.1003 Y0.6254 +G01 X-2.1054 Y0.6203 +G01 X-2.1081 Y0.6136 +G01 X-2.1085 Y0.6100 +G01 X-2.1085 Y0.2914 +G01 X-2.0955 Y0.2784 +G01 X-2.0955 Y0.2416 +G01 X-2.1216 Y0.2155 +G01 X-2.1584 Y0.2155 +G01 X-2.1845 Y0.2416 +G01 X-2.1845 Y0.2784 +G01 X-2.1715 Y0.2914 +G01 X-2.1715 Y0.6163 +G01 X-2.1715 Y0.6262 +G00 Z0.1000 +G00 X-3.1015 Y1.6162 +G01 Z-0.0070 F10 +G01 X-3.1015 Y1.6162 F20 +G01 X-3.0891 Y1.6462 +G01 X-3.0662 Y1.6691 +G01 X-3.0362 Y1.6815 +G01 X-3.0263 Y1.6815 +G01 X-3.0195 Y1.6815 +G01 X-3.0137 Y1.6815 +G01 X-2.9015 Y1.6815 +G01 X-2.9015 Y1.6848 +G01 X-2.9015 Y1.6863 +G01 X-2.9015 Y1.7763 +G01 X-2.9015 Y1.7862 +G01 X-2.8891 Y1.8162 +G01 X-2.8662 Y1.8391 +G01 X-2.8362 Y1.8515 +G01 X-2.8263 Y1.8515 +G01 X-2.8203 Y1.8515 +G01 X-2.8200 Y1.8515 +G01 X-2.8137 Y1.8515 +G01 X-2.7014 Y1.8515 +G01 X-2.6884 Y1.8645 +G01 X-2.6516 Y1.8645 +G01 X-2.6255 Y1.8384 +G01 X-2.6255 Y1.8016 +G01 X-2.6516 Y1.7755 +G01 X-2.6884 Y1.7755 +G01 X-2.7014 Y1.7885 +G01 X-2.8137 Y1.7885 +G01 X-2.8200 Y1.7885 +G01 X-2.8236 Y1.7881 +G01 X-2.8303 Y1.7854 +G01 X-2.8354 Y1.7803 +G01 X-2.8381 Y1.7736 +G01 X-2.8385 Y1.7700 +G01 X-2.8385 Y1.6863 +G01 X-2.8385 Y1.6848 +G01 X-2.8385 Y1.6737 +G01 X-2.8385 Y1.6678 +G01 X-2.8479 Y1.6452 +G01 X-2.8652 Y1.6279 +G01 X-2.8878 Y1.6185 +G01 X-2.8937 Y1.6185 +G01 X-3.0137 Y1.6185 +G01 X-3.0196 Y1.6185 +G01 X-3.0200 Y1.6185 +G01 X-3.0236 Y1.6181 +G01 X-3.0303 Y1.6154 +G01 X-3.0354 Y1.6103 +G01 X-3.0381 Y1.6036 +G01 X-3.0385 Y1.6000 +G01 X-3.0385 Y1.2900 +G01 X-3.0381 Y1.2864 +G01 X-3.0354 Y1.2797 +G01 X-3.0303 Y1.2746 +G01 X-3.0236 Y1.2719 +G01 X-3.0200 Y1.2715 +G01 X-3.0137 Y1.2715 +G01 X-2.7231 Y1.2715 +G01 X-2.7200 Y1.2721 +G01 X-2.7169 Y1.2715 +G01 X-2.7137 Y1.2715 +G01 X-2.7121 Y1.2708 +G01 X-2.6884 Y1.2945 +G01 X-2.6516 Y1.2945 +G01 X-2.6255 Y1.2684 +G01 X-2.6255 Y1.2316 +G01 X-2.6516 Y1.2055 +G01 X-2.6780 Y1.2055 +G01 X-2.6999 Y1.2011 +G01 X-2.7263 Y1.2063 +G01 X-2.7295 Y1.2085 +G01 X-3.0137 Y1.2085 +G01 X-3.0200 Y1.2085 +G01 X-3.0202 Y1.2085 +G01 X-3.0263 Y1.2085 +G01 X-3.0362 Y1.2085 +G01 X-3.0662 Y1.2209 +G01 X-3.0891 Y1.2438 +G01 X-3.1015 Y1.2738 +G01 X-3.1015 Y1.2837 +G01 X-3.1015 Y1.6063 +G01 X-3.1015 Y1.6162 +G00 Z0.1000 +G00 X-2.5583 Y0.4400 +G01 Z-0.0070 F10 +G01 X-2.5583 Y0.4800 F20 +G01 X-2.5300 Y0.5083 +G01 X-2.4900 Y0.5083 +G01 X-2.4617 Y0.4800 +G01 X-2.4617 Y0.4400 +G01 X-2.4685 Y0.4332 +G01 X-2.4685 Y0.2683 +G01 X-2.4685 Y0.1900 +G01 X-2.4684 Y0.1887 +G01 X-2.4676 Y0.1861 +G01 X-2.4660 Y0.1840 +G01 X-2.4639 Y0.1824 +G01 X-2.4613 Y0.1816 +G01 X-2.4600 Y0.1815 +G01 X-2.4528 Y0.1815 +G01 X-2.4517 Y0.1815 +G01 X-1.8700 Y0.1815 +G01 X-1.8687 Y0.1816 +G01 X-1.8661 Y0.1824 +G01 X-1.8645 Y0.1836 +G01 X-1.8645 Y0.2184 +G01 X-1.8384 Y0.2445 +G01 X-1.8016 Y0.2445 +G01 X-1.7755 Y0.2184 +G01 X-1.7755 Y0.1816 +G01 X-1.7785 Y0.1786 +G01 X-1.7785 Y0.1755 +G01 X-1.7875 Y0.1479 +G01 X-1.8045 Y0.1245 +G01 X-1.8279 Y0.1075 +G01 X-1.8555 Y0.0985 +G01 X-1.8617 Y0.0985 +G01 X-2.4517 Y0.0985 +G01 X-2.4528 Y0.0985 +G01 X-2.4683 Y0.0985 +G01 X-2.4745 Y0.0985 +G01 X-2.5021 Y0.1075 +G01 X-2.5255 Y0.1245 +G01 X-2.5425 Y0.1479 +G01 X-2.5515 Y0.1755 +G01 X-2.5515 Y0.1817 +G01 X-2.5515 Y0.2285 +G01 X-2.6086 Y0.2285 +G01 X-2.6216 Y0.2155 +G01 X-2.6584 Y0.2155 +G01 X-2.6845 Y0.2416 +G01 X-2.6845 Y0.2784 +G01 X-2.6584 Y0.3045 +G01 X-2.6216 Y0.3045 +G01 X-2.6086 Y0.2915 +G01 X-2.5515 Y0.2915 +G01 X-2.5515 Y0.4332 +G01 X-2.5583 Y0.4400 +G00 Z0.1000 +G00 X-1.9285 Y1.4362 +G01 Z-0.0070 F10 +G01 X-1.9285 Y1.4362 F20 +G01 X-1.9285 Y1.4263 +G01 X-1.9285 Y1.3545 +G01 X-1.8941 Y1.3545 +G01 X-1.8778 Y1.3477 +G01 X-1.8653 Y1.3352 +G01 X-1.8585 Y1.3189 +G01 X-1.8585 Y1.3011 +G01 X-1.8653 Y1.2848 +G01 X-1.8778 Y1.2723 +G01 X-1.8941 Y1.2655 +G01 X-2.0259 Y1.2655 +G01 X-2.0422 Y1.2723 +G01 X-2.0547 Y1.2848 +G01 X-2.0615 Y1.3011 +G01 X-2.0615 Y1.3189 +G01 X-2.0547 Y1.3352 +G01 X-2.0422 Y1.3477 +G01 X-2.0259 Y1.3545 +G01 X-1.9915 Y1.3545 +G01 X-1.9915 Y1.4200 +G01 X-1.9918 Y1.4235 +G01 X-2.0065 Y1.4382 +G01 X-2.0100 Y1.4385 +G01 X-2.1732 Y1.4385 +G01 X-2.1900 Y1.4217 +G01 X-2.2300 Y1.4217 +G01 X-2.2363 Y1.4280 +G01 X-2.2510 Y1.4231 +G01 X-2.2510 Y1.4197 +G01 X-2.2797 Y1.3910 +G01 X-2.3203 Y1.3910 +G01 X-2.3490 Y1.4197 +G01 X-2.3490 Y1.4603 +G01 X-2.3203 Y1.4890 +G01 X-2.2797 Y1.4890 +G01 X-2.2729 Y1.4822 +G01 X-2.2583 Y1.4871 +G01 X-2.2583 Y1.4900 +G01 X-2.2300 Y1.5183 +G01 X-2.1900 Y1.5183 +G01 X-2.1732 Y1.5015 +G01 X-2.0068 Y1.5015 +G01 X-1.9900 Y1.5183 +G01 X-1.9500 Y1.5183 +G01 X-1.9217 Y1.4900 +G01 X-1.9217 Y1.4500 +G01 X-1.9305 Y1.4411 +G01 X-1.9285 Y1.4362 +G00 Z0.1000 +G00 X-1.5445 Y1.8916 +G01 Z-0.0070 F10 +G01 X-1.5445 Y1.9284 F20 +G01 X-1.5184 Y1.9545 +G01 X-1.4816 Y1.9545 +G01 X-1.4555 Y1.9284 +G01 X-1.4555 Y1.8916 +G01 X-1.4685 Y1.8786 +G01 X-1.4685 Y1.7499 +G01 X-1.4572 Y1.7386 +G01 X-1.4495 Y1.7200 +G01 X-1.4495 Y1.7017 +G01 X-1.4472 Y1.7020 +G01 X-1.4455 Y1.7015 +G01 X-0.7763 Y1.7015 +G01 X-0.7700 Y1.7015 +G01 X-0.7664 Y1.7015 +G01 X-0.7637 Y1.7015 +G01 X-0.7538 Y1.7015 +G01 X-0.7238 Y1.6891 +G01 X-0.7009 Y1.6662 +G01 X-0.6885 Y1.6362 +G01 X-0.6885 Y1.6263 +G01 X-0.6885 Y1.5414 +G01 X-0.6755 Y1.5284 +G01 X-0.6755 Y1.4916 +G01 X-0.7016 Y1.4655 +G01 X-0.7384 Y1.4655 +G01 X-0.7645 Y1.4916 +G01 X-0.7645 Y1.5284 +G01 X-0.7515 Y1.5414 +G01 X-0.7515 Y1.6200 +G01 X-0.7518 Y1.6236 +G01 X-0.7546 Y1.6303 +G01 X-0.7597 Y1.6354 +G01 X-0.7664 Y1.6381 +G01 X-0.7700 Y1.6385 +G01 X-0.7763 Y1.6385 +G01 X-1.4483 Y1.6385 +G01 X-1.4617 Y1.6370 +G01 X-1.4910 Y1.6455 +G01 X-1.5085 Y1.6595 +G01 X-1.5100 Y1.6595 +G01 X-1.5286 Y1.6672 +G01 X-1.5428 Y1.6814 +G01 X-1.5505 Y1.7000 +G01 X-1.5505 Y1.7200 +G01 X-1.5428 Y1.7386 +G01 X-1.5315 Y1.7499 +G01 X-1.5315 Y1.8786 +G01 X-1.5445 Y1.8916 +G00 Z0.1000 +G00 X-2.9945 Y1.1116 +G01 Z-0.0070 F10 +G01 X-2.9945 Y1.1484 F20 +G01 X-2.9684 Y1.1745 +G01 X-2.9316 Y1.1745 +G01 X-2.9055 Y1.1484 +G01 X-2.9055 Y1.1116 +G01 X-2.9185 Y1.0986 +G01 X-2.9185 Y1.0600 +G01 X-2.9181 Y1.0564 +G01 X-2.9154 Y1.0497 +G01 X-2.9103 Y1.0446 +G01 X-2.9036 Y1.0419 +G01 X-2.9000 Y1.0415 +G01 X-2.8945 Y1.0415 +G01 X-2.8937 Y1.0415 +G01 X-2.3484 Y1.0415 +G01 X-2.3422 Y1.0477 +G01 X-2.3259 Y1.0545 +G01 X-2.1941 Y1.0545 +G01 X-2.1778 Y1.0477 +G01 X-2.1653 Y1.0352 +G01 X-2.1585 Y1.0189 +G01 X-2.1585 Y1.0011 +G01 X-2.1653 Y0.9848 +G01 X-2.1778 Y0.9723 +G01 X-2.1941 Y0.9655 +G01 X-2.3259 Y0.9655 +G01 X-2.3422 Y0.9723 +G01 X-2.3484 Y0.9785 +G01 X-2.8937 Y0.9785 +G01 X-2.8945 Y0.9785 +G01 X-2.9063 Y0.9785 +G01 X-2.9162 Y0.9785 +G01 X-2.9462 Y0.9909 +G01 X-2.9691 Y1.0138 +G01 X-2.9815 Y1.0438 +G01 X-2.9815 Y1.0537 +G01 X-2.9815 Y1.0986 +G01 X-2.9945 Y1.1116 +G00 Z0.1000 +G00 X-1.5945 Y0.6416 +G01 Z-0.0070 F10 +G01 X-1.5945 Y0.6784 F20 +G01 X-1.5815 Y0.6914 +G01 X-1.5815 Y0.7537 +G01 X-1.5815 Y0.7549 +G01 X-1.5815 Y0.7663 +G01 X-1.5815 Y0.7762 +G01 X-1.5691 Y0.8062 +G01 X-1.5462 Y0.8291 +G01 X-1.5162 Y0.8415 +G01 X-1.5063 Y0.8415 +G01 X-1.3384 Y0.8415 +G01 X-1.3322 Y0.8477 +G01 X-1.3159 Y0.8545 +G01 X-1.1841 Y0.8545 +G01 X-1.1678 Y0.8477 +G01 X-1.1553 Y0.8352 +G01 X-1.1485 Y0.8189 +G01 X-1.1485 Y0.8011 +G01 X-1.1553 Y0.7848 +G01 X-1.1678 Y0.7723 +G01 X-1.1841 Y0.7655 +G01 X-1.3159 Y0.7655 +G01 X-1.3322 Y0.7723 +G01 X-1.3384 Y0.7785 +G01 X-1.5000 Y0.7785 +G01 X-1.5036 Y0.7781 +G01 X-1.5103 Y0.7754 +G01 X-1.5154 Y0.7703 +G01 X-1.5181 Y0.7636 +G01 X-1.5185 Y0.7600 +G01 X-1.5185 Y0.7549 +G01 X-1.5185 Y0.7537 +G01 X-1.5185 Y0.6914 +G01 X-1.5055 Y0.6784 +G01 X-1.5055 Y0.6416 +G01 X-1.5316 Y0.6155 +G01 X-1.5684 Y0.6155 +G01 X-1.5945 Y0.6416 +G00 Z0.1000 +G00 X-0.7984 Y0.3845 +G01 Z-0.0070 F10 +G01 X-0.7616 Y0.3845 F20 +G01 X-0.7355 Y0.3584 +G01 X-0.7355 Y0.3216 +G01 X-0.7616 Y0.2955 +G01 X-0.7984 Y0.2955 +G01 X-0.8114 Y0.3085 +G01 X-1.2785 Y0.3085 +G01 X-1.2785 Y0.2214 +G01 X-1.2755 Y0.2184 +G01 X-1.2755 Y0.1816 +G01 X-1.3016 Y0.1555 +G01 X-1.3384 Y0.1555 +G01 X-1.3645 Y0.1816 +G01 X-1.3645 Y0.2184 +G01 X-1.3415 Y0.2414 +G01 X-1.3415 Y0.3085 +G01 X-1.3801 Y0.3085 +G01 X-1.3914 Y0.2972 +G01 X-1.4100 Y0.2895 +G01 X-1.4300 Y0.2895 +G01 X-1.4486 Y0.2972 +G01 X-1.4628 Y0.3114 +G01 X-1.4705 Y0.3300 +G01 X-1.4705 Y0.3500 +G01 X-1.4628 Y0.3686 +G01 X-1.4486 Y0.3828 +G01 X-1.4300 Y0.3905 +G01 X-1.4100 Y0.3905 +G01 X-1.3914 Y0.3828 +G01 X-1.3801 Y0.3715 +G01 X-1.3037 Y0.3715 +G01 X-0.8114 Y0.3715 +G01 X-0.7984 Y0.3845 +G00 Z0.1000 +G00 X-0.5784 Y1.1545 +G01 Z-0.0070 F10 +G01 X-0.5416 Y1.1545 F20 +G01 X-0.5155 Y1.1284 +G01 X-0.5155 Y1.0916 +G01 X-0.5416 Y1.0655 +G01 X-0.5784 Y1.0655 +G01 X-0.5914 Y1.0785 +G01 X-0.8616 Y1.0785 +G01 X-0.8678 Y1.0723 +G01 X-0.8841 Y1.0655 +G01 X-1.0159 Y1.0655 +G01 X-1.0322 Y1.0723 +G01 X-1.0447 Y1.0848 +G01 X-1.0515 Y1.1011 +G01 X-1.0515 Y1.1189 +G01 X-1.0447 Y1.1352 +G01 X-1.0322 Y1.1477 +G01 X-1.0159 Y1.1545 +G01 X-0.8841 Y1.1545 +G01 X-0.8678 Y1.1477 +G01 X-0.8616 Y1.1415 +G01 X-0.5914 Y1.1415 +G01 X-0.5784 Y1.1545 +G00 Z0.1000 +G00 X-1.3159 Y1.3545 +G01 Z-0.0070 F10 +G01 X-1.1841 Y1.3545 F20 +G01 X-1.1678 Y1.3477 +G01 X-1.1553 Y1.3352 +G01 X-1.1485 Y1.3189 +G01 X-1.1485 Y1.3011 +G01 X-1.1553 Y1.2848 +G01 X-1.1678 Y1.2723 +G01 X-1.1841 Y1.2655 +G01 X-1.3159 Y1.2655 +G01 X-1.3322 Y1.2723 +G01 X-1.3447 Y1.2848 +G01 X-1.3515 Y1.3011 +G01 X-1.3515 Y1.3189 +G01 X-1.3447 Y1.3352 +G01 X-1.3322 Y1.3477 +G01 X-1.3159 Y1.3545 +G00 Z0.1000 +G00 X-1.3159 Y1.2545 +G01 Z-0.0070 F10 +G01 X-1.1841 Y1.2545 F20 +G01 X-1.1678 Y1.2477 +G01 X-1.1553 Y1.2352 +G01 X-1.1485 Y1.2189 +G01 X-1.1485 Y1.2011 +G01 X-1.1553 Y1.1848 +G01 X-1.1678 Y1.1723 +G01 X-1.1841 Y1.1655 +G01 X-1.3159 Y1.1655 +G01 X-1.3322 Y1.1723 +G01 X-1.3447 Y1.1848 +G01 X-1.3515 Y1.2011 +G01 X-1.3515 Y1.2189 +G01 X-1.3447 Y1.2352 +G01 X-1.3322 Y1.2477 +G01 X-1.3159 Y1.2545 +G00 Z0.1000 +G00 X-1.3159 Y1.1545 +G01 Z-0.0070 F10 +G01 X-1.1841 Y1.1545 F20 +G01 X-1.1678 Y1.1477 +G01 X-1.1553 Y1.1352 +G01 X-1.1485 Y1.1189 +G01 X-1.1485 Y1.1011 +G01 X-1.1553 Y1.0848 +G01 X-1.1678 Y1.0723 +G01 X-1.1841 Y1.0655 +G01 X-1.3159 Y1.0655 +G01 X-1.3322 Y1.0723 +G01 X-1.3384 Y1.0785 +G01 X-1.7785 Y1.0785 +G01 X-1.7785 Y0.8737 +G01 X-1.7785 Y0.8638 +G01 X-1.7909 Y0.8338 +G01 X-1.8138 Y0.8109 +G01 X-1.8438 Y0.7985 +G01 X-1.8537 Y0.7985 +G01 X-1.8562 Y0.7985 +G01 X-1.8600 Y0.7985 +G01 X-1.8663 Y0.7985 +G01 X-2.2737 Y0.7985 +G01 X-2.2800 Y0.7985 +G01 X-2.2836 Y0.7981 +G01 X-2.2903 Y0.7954 +G01 X-2.2954 Y0.7903 +G01 X-2.2981 Y0.7836 +G01 X-2.2985 Y0.7800 +G01 X-2.2985 Y0.7537 +G01 X-2.2985 Y0.7498 +G01 X-2.3063 Y0.7308 +G01 X-2.3208 Y0.7163 +G01 X-2.3398 Y0.7085 +G01 X-2.3500 Y0.7085 +G01 X-2.3563 Y0.7085 +G01 X-2.6486 Y0.7085 +G01 X-2.6516 Y0.7055 +G01 X-2.6884 Y0.7055 +G01 X-2.7014 Y0.7185 +G01 X-2.8081 Y0.7185 +G01 X-2.8223 Y0.7043 +G01 X-2.8414 Y0.6964 +G01 X-2.9986 Y0.6964 +G01 X-3.0177 Y0.7043 +G01 X-3.0323 Y0.7190 +G01 X-3.0402 Y0.7381 +G01 X-3.0402 Y0.7588 +G01 X-3.0323 Y0.7779 +G01 X-3.0177 Y0.7925 +G01 X-2.9986 Y0.8004 +G01 X-2.8414 Y0.8004 +G01 X-2.8223 Y0.7925 +G01 X-2.8113 Y0.7815 +G01 X-2.7014 Y0.7815 +G01 X-2.6884 Y0.7945 +G01 X-2.6516 Y0.7945 +G01 X-2.6286 Y0.7715 +G01 X-2.3615 Y0.7715 +G01 X-2.3615 Y0.7863 +G01 X-2.3615 Y0.7962 +G01 X-2.3491 Y0.8262 +G01 X-2.3262 Y0.8491 +G01 X-2.2962 Y0.8615 +G01 X-2.2863 Y0.8615 +G01 X-2.2807 Y0.8615 +G01 X-2.2800 Y0.8615 +G01 X-2.2737 Y0.8615 +G01 X-1.8663 Y0.8615 +G01 X-1.8600 Y0.8615 +G01 X-1.8564 Y0.8619 +G01 X-1.8497 Y0.8646 +G01 X-1.8446 Y0.8697 +G01 X-1.8419 Y0.8764 +G01 X-1.8415 Y0.8800 +G01 X-1.8415 Y1.0785 +G01 X-1.8716 Y1.0785 +G01 X-1.8778 Y1.0723 +G01 X-1.8941 Y1.0655 +G01 X-2.0259 Y1.0655 +G01 X-2.0422 Y1.0723 +G01 X-2.0547 Y1.0848 +G01 X-2.0615 Y1.1011 +G01 X-2.0615 Y1.1189 +G01 X-2.0547 Y1.1352 +G01 X-2.0422 Y1.1477 +G01 X-2.0259 Y1.1545 +G01 X-1.8941 Y1.1545 +G01 X-1.8778 Y1.1477 +G01 X-1.8716 Y1.1415 +G01 X-1.8163 Y1.1415 +G01 X-1.8037 Y1.1415 +G01 X-1.3384 Y1.1415 +G01 X-1.3322 Y1.1477 +G01 X-1.3159 Y1.1545 +G00 Z0.1000 +G00 X-1.0159 Y0.9545 +G01 Z-0.0070 F10 +G01 X-0.8841 Y0.9545 F20 +G01 X-0.8678 Y0.9477 +G01 X-0.8616 Y0.9415 +G01 X-0.8363 Y0.9415 +G01 X-0.8342 Y0.9415 +G01 X-0.8237 Y0.9415 +G01 X-0.8138 Y0.9415 +G01 X-0.7838 Y0.9291 +G01 X-0.7609 Y0.9062 +G01 X-0.7485 Y0.8762 +G01 X-0.7485 Y0.8663 +G01 X-0.7485 Y0.5714 +G01 X-0.7355 Y0.5584 +G01 X-0.7355 Y0.5216 +G01 X-0.7616 Y0.4955 +G01 X-0.7984 Y0.4955 +G01 X-0.8245 Y0.5216 +G01 X-0.8245 Y0.5584 +G01 X-0.8115 Y0.5714 +G01 X-0.8115 Y0.8600 +G01 X-0.8119 Y0.8636 +G01 X-0.8146 Y0.8703 +G01 X-0.8197 Y0.8754 +G01 X-0.8264 Y0.8781 +G01 X-0.8300 Y0.8785 +G01 X-0.8342 Y0.8785 +G01 X-0.8363 Y0.8785 +G01 X-0.8616 Y0.8785 +G01 X-0.8678 Y0.8723 +G01 X-0.8841 Y0.8655 +G01 X-1.0159 Y0.8655 +G01 X-1.0322 Y0.8723 +G01 X-1.0447 Y0.8848 +G01 X-1.0515 Y0.9011 +G01 X-1.0515 Y0.9189 +G01 X-1.0447 Y0.9352 +G01 X-1.0322 Y0.9477 +G01 X-1.0159 Y0.9545 +G00 Z0.1000 +G00 X-1.0159 Y1.3545 +G01 Z-0.0070 F10 +G01 X-0.8841 Y1.3545 F20 +G01 X-0.8678 Y1.3477 +G01 X-0.8616 Y1.3415 +G01 X-0.7514 Y1.3415 +G01 X-0.7384 Y1.3545 +G01 X-0.7016 Y1.3545 +G01 X-0.6755 Y1.3284 +G01 X-0.6755 Y1.2916 +G01 X-0.7016 Y1.2655 +G01 X-0.7384 Y1.2655 +G01 X-0.7514 Y1.2785 +G01 X-0.8616 Y1.2785 +G01 X-0.8678 Y1.2723 +G01 X-0.8841 Y1.2655 +G01 X-1.0159 Y1.2655 +G01 X-1.0322 Y1.2723 +G01 X-1.0447 Y1.2848 +G01 X-1.0515 Y1.3011 +G01 X-1.0515 Y1.3189 +G01 X-1.0447 Y1.3352 +G01 X-1.0322 Y1.3477 +G01 X-1.0159 Y1.3545 +G00 Z0.1000 +G00 X-2.7045 Y1.5916 +G01 Z-0.0070 F10 +G01 X-2.7045 Y1.6284 F20 +G01 X-2.6784 Y1.6545 +G01 X-2.6416 Y1.6545 +G01 X-2.6286 Y1.6415 +G01 X-2.5315 Y1.6415 +G01 X-2.5315 Y1.7037 +G01 X-2.5315 Y1.7047 +G01 X-2.5315 Y1.7163 +G01 X-2.5315 Y1.7222 +G01 X-2.5221 Y1.7448 +G01 X-2.5048 Y1.7621 +G01 X-2.4822 Y1.7715 +G01 X-2.4763 Y1.7715 +G01 X-2.4714 Y1.7715 +G01 X-2.4584 Y1.7845 +G01 X-2.4216 Y1.7845 +G01 X-2.3955 Y1.7584 +G01 X-2.3955 Y1.7216 +G01 X-2.4076 Y1.7095 +G01 X-2.3724 Y1.7095 +G01 X-2.3845 Y1.7216 +G01 X-2.3845 Y1.7584 +G01 X-2.3715 Y1.7714 +G01 X-2.3715 Y1.7800 +G01 X-2.3719 Y1.7836 +G01 X-2.3746 Y1.7903 +G01 X-2.3797 Y1.7954 +G01 X-2.3864 Y1.7981 +G01 X-2.3900 Y1.7985 +G01 X-2.5300 Y1.7985 +G01 X-2.5336 Y1.7981 +G01 X-2.5403 Y1.7954 +G01 X-2.5454 Y1.7903 +G01 X-2.5481 Y1.7836 +G01 X-2.5485 Y1.7800 +G01 X-2.5485 Y1.7763 +G01 X-2.5485 Y1.7733 +G01 X-2.5485 Y1.7637 +G01 X-2.5485 Y1.7538 +G01 X-2.5609 Y1.7238 +G01 X-2.5838 Y1.7009 +G01 X-2.6138 Y1.6885 +G01 X-2.6237 Y1.6885 +G01 X-2.6386 Y1.6885 +G01 X-2.6516 Y1.6755 +G01 X-2.6884 Y1.6755 +G01 X-2.7014 Y1.6885 +G01 X-2.7300 Y1.6885 +G01 X-2.7336 Y1.6881 +G01 X-2.7403 Y1.6854 +G01 X-2.7454 Y1.6803 +G01 X-2.7481 Y1.6736 +G01 X-2.7485 Y1.6700 +G01 X-2.7485 Y1.6651 +G01 X-2.7485 Y1.6637 +G01 X-2.7485 Y1.5937 +G01 X-2.7485 Y1.5858 +G01 X-2.7594 Y1.5595 +G01 X-2.7795 Y1.5394 +G01 X-2.8058 Y1.5285 +G01 X-2.8137 Y1.5285 +G01 X-2.8198 Y1.5285 +G01 X-2.8200 Y1.5285 +G01 X-2.8263 Y1.5285 +G01 X-2.9585 Y1.5285 +G01 X-2.9585 Y1.5237 +G01 X-2.9585 Y1.3745 +G01 X-2.9316 Y1.3745 +G01 X-2.9055 Y1.3484 +G01 X-2.9055 Y1.3116 +G01 X-2.9316 Y1.2855 +G01 X-2.9684 Y1.2855 +G01 X-2.9945 Y1.3116 +G01 X-2.9945 Y1.3134 +G01 X-3.0106 Y1.3295 +G01 X-3.0215 Y1.3558 +G01 X-3.0215 Y1.3637 +G01 X-3.0215 Y1.3664 +G01 X-3.0215 Y1.3700 +G01 X-3.0215 Y1.5237 +G01 X-3.0215 Y1.5300 +G01 X-3.0215 Y1.5422 +G01 X-3.0121 Y1.5648 +G01 X-2.9948 Y1.5821 +G01 X-2.9722 Y1.5915 +G01 X-2.9663 Y1.5915 +G01 X-2.8263 Y1.5915 +G01 X-2.8200 Y1.5915 +G01 X-2.8183 Y1.5917 +G01 X-2.8153 Y1.5929 +G01 X-2.8129 Y1.5953 +G01 X-2.8117 Y1.5983 +G01 X-2.8115 Y1.6000 +G01 X-2.8115 Y1.6637 +G01 X-2.8115 Y1.6651 +G01 X-2.8115 Y1.6763 +G01 X-2.8115 Y1.6862 +G01 X-2.7991 Y1.7162 +G01 X-2.7762 Y1.7391 +G01 X-2.7462 Y1.7515 +G01 X-2.7363 Y1.7515 +G01 X-2.7014 Y1.7515 +G01 X-2.6884 Y1.7645 +G01 X-2.6516 Y1.7645 +G01 X-2.6386 Y1.7515 +G01 X-2.6300 Y1.7515 +G01 X-2.6264 Y1.7519 +G01 X-2.6197 Y1.7546 +G01 X-2.6146 Y1.7597 +G01 X-2.6119 Y1.7664 +G01 X-2.6115 Y1.7700 +G01 X-2.6115 Y1.7733 +G01 X-2.6115 Y1.7763 +G01 X-2.6115 Y1.7863 +G01 X-2.6115 Y1.7962 +G01 X-2.5991 Y1.8262 +G01 X-2.5762 Y1.8491 +G01 X-2.5462 Y1.8615 +G01 X-2.5363 Y1.8615 +G01 X-2.3837 Y1.8615 +G01 X-2.3738 Y1.8615 +G01 X-2.3438 Y1.8491 +G01 X-2.3209 Y1.8262 +G01 X-2.3085 Y1.7962 +G01 X-2.3085 Y1.7863 +G01 X-2.3085 Y1.7715 +G01 X-2.2468 Y1.7715 +G01 X-2.2300 Y1.7883 +G01 X-2.1900 Y1.7883 +G01 X-2.1617 Y1.7600 +G01 X-2.1617 Y1.7200 +G01 X-2.1900 Y1.6917 +G01 X-2.2300 Y1.6917 +G01 X-2.2468 Y1.7085 +G01 X-2.3086 Y1.7085 +G01 X-2.3216 Y1.6955 +G01 X-2.3576 Y1.6955 +G01 X-2.3455 Y1.6834 +G01 X-2.3455 Y1.6466 +G01 X-2.3585 Y1.6336 +G01 X-2.3585 Y1.6300 +G01 X-2.3581 Y1.6264 +G01 X-2.3554 Y1.6197 +G01 X-2.3503 Y1.6146 +G01 X-2.3436 Y1.6119 +G01 X-2.3400 Y1.6115 +G01 X-2.3355 Y1.6115 +G01 X-2.3337 Y1.6115 +G01 X-1.8563 Y1.6115 +G01 X-1.8437 Y1.6115 +G01 X-1.8358 Y1.6115 +G01 X-1.8095 Y1.6006 +G01 X-1.7894 Y1.5805 +G01 X-1.7785 Y1.5542 +G01 X-1.7785 Y1.5463 +G01 X-1.7785 Y1.5401 +G01 X-1.7785 Y1.5400 +G01 X-1.7785 Y1.5337 +G01 X-1.7785 Y1.3415 +G01 X-1.7763 Y1.3415 +G01 X-1.7637 Y1.3415 +G01 X-1.6463 Y1.3415 +G01 X-1.6337 Y1.3415 +G01 X-1.5399 Y1.3415 +G01 X-1.5286 Y1.3528 +G01 X-1.5100 Y1.3605 +G01 X-1.4900 Y1.3605 +G01 X-1.4714 Y1.3528 +G01 X-1.4572 Y1.3386 +G01 X-1.4495 Y1.3200 +G01 X-1.4495 Y1.3000 +G01 X-1.4572 Y1.2814 +G01 X-1.4714 Y1.2672 +G01 X-1.4900 Y1.2595 +G01 X-1.5100 Y1.2595 +G01 X-1.5286 Y1.2672 +G01 X-1.5399 Y1.2785 +G01 X-1.5917 Y1.2785 +G01 X-1.5917 Y1.2500 +G01 X-1.6200 Y1.2217 +G01 X-1.6600 Y1.2217 +G01 X-1.6883 Y1.2500 +G01 X-1.6883 Y1.2785 +G01 X-1.7385 Y1.2785 +G01 X-1.7385 Y1.2314 +G01 X-1.7255 Y1.2184 +G01 X-1.7255 Y1.1816 +G01 X-1.7516 Y1.1555 +G01 X-1.7884 Y1.1555 +G01 X-1.8014 Y1.1685 +G01 X-1.8869 Y1.1685 +G01 X-1.8941 Y1.1655 +G01 X-2.0259 Y1.1655 +G01 X-2.0422 Y1.1723 +G01 X-2.0547 Y1.1848 +G01 X-2.0615 Y1.2011 +G01 X-2.0615 Y1.2189 +G01 X-2.0547 Y1.2352 +G01 X-2.0422 Y1.2477 +G01 X-2.0259 Y1.2545 +G01 X-1.8941 Y1.2545 +G01 X-1.8778 Y1.2477 +G01 X-1.8653 Y1.2352 +G01 X-1.8637 Y1.2315 +G01 X-1.8015 Y1.2315 +G01 X-1.8015 Y1.2785 +G01 X-1.8037 Y1.2785 +G01 X-1.8163 Y1.2785 +G01 X-1.8278 Y1.2833 +G01 X-1.8367 Y1.2922 +G01 X-1.8415 Y1.3037 +G01 X-1.8415 Y1.5337 +G01 X-1.8415 Y1.5400 +G01 X-1.8417 Y1.5417 +G01 X-1.8429 Y1.5447 +G01 X-1.8453 Y1.5471 +G01 X-1.8483 Y1.5483 +G01 X-1.8500 Y1.5485 +G01 X-1.8563 Y1.5485 +G01 X-2.3337 Y1.5485 +G01 X-2.3355 Y1.5485 +G01 X-2.3463 Y1.5485 +G01 X-2.3562 Y1.5485 +G01 X-2.3862 Y1.5609 +G01 X-2.4091 Y1.5838 +G01 X-2.4215 Y1.6138 +G01 X-2.4215 Y1.6237 +G01 X-2.4215 Y1.6336 +G01 X-2.4345 Y1.6466 +G01 X-2.4345 Y1.6834 +G01 X-2.4224 Y1.6955 +G01 X-2.4584 Y1.6955 +G01 X-2.4685 Y1.7056 +G01 X-2.4685 Y1.7047 +G01 X-2.4685 Y1.7037 +G01 X-2.4685 Y1.6037 +G01 X-2.4733 Y1.5922 +G01 X-2.4822 Y1.5833 +G01 X-2.4885 Y1.5807 +G01 X-2.4885 Y1.4463 +G01 X-2.4885 Y1.4337 +G01 X-2.4885 Y1.2600 +G01 X-2.4881 Y1.2564 +G01 X-2.4854 Y1.2497 +G01 X-2.4803 Y1.2446 +G01 X-2.4736 Y1.2419 +G01 X-2.4700 Y1.2415 +G01 X-2.4658 Y1.2415 +G01 X-2.4637 Y1.2415 +G01 X-2.3484 Y1.2415 +G01 X-2.3422 Y1.2477 +G01 X-2.3259 Y1.2545 +G01 X-2.1941 Y1.2545 +G01 X-2.1778 Y1.2477 +G01 X-2.1653 Y1.2352 +G01 X-2.1585 Y1.2189 +G01 X-2.1585 Y1.2011 +G01 X-2.1653 Y1.1848 +G01 X-2.1778 Y1.1723 +G01 X-2.1941 Y1.1655 +G01 X-2.2285 Y1.1655 +G01 X-2.2285 Y1.1545 +G01 X-2.1941 Y1.1545 +G01 X-2.1778 Y1.1477 +G01 X-2.1653 Y1.1352 +G01 X-2.1585 Y1.1189 +G01 X-2.1585 Y1.1011 +G01 X-2.1653 Y1.0848 +G01 X-2.1778 Y1.0723 +G01 X-2.1941 Y1.0655 +G01 X-2.3259 Y1.0655 +G01 X-2.3422 Y1.0723 +G01 X-2.3547 Y1.0848 +G01 X-2.3615 Y1.1011 +G01 X-2.3615 Y1.1189 +G01 X-2.3547 Y1.1352 +G01 X-2.3422 Y1.1477 +G01 X-2.3259 Y1.1545 +G01 X-2.2915 Y1.1545 +G01 X-2.2915 Y1.1655 +G01 X-2.3259 Y1.1655 +G01 X-2.3422 Y1.1723 +G01 X-2.3484 Y1.1785 +G01 X-2.4637 Y1.1785 +G01 X-2.4658 Y1.1785 +G01 X-2.4763 Y1.1785 +G01 X-2.4862 Y1.1785 +G01 X-2.5162 Y1.1909 +G01 X-2.5391 Y1.2138 +G01 X-2.5515 Y1.2438 +G01 X-2.5515 Y1.2537 +G01 X-2.5515 Y1.4085 +G01 X-2.8622 Y1.4085 +G01 X-2.8722 Y1.3985 +G01 X-2.8903 Y1.3910 +G01 X-2.9097 Y1.3910 +G01 X-2.9278 Y1.3985 +G01 X-2.9415 Y1.4122 +G01 X-2.9490 Y1.4303 +G01 X-2.9490 Y1.4497 +G01 X-2.9415 Y1.4678 +G01 X-2.9278 Y1.4815 +G01 X-2.9097 Y1.4890 +G01 X-2.8903 Y1.4890 +G01 X-2.8722 Y1.4815 +G01 X-2.8622 Y1.4715 +G01 X-2.5515 Y1.4715 +G01 X-2.5515 Y1.5785 +G01 X-2.6286 Y1.5785 +G01 X-2.6416 Y1.5655 +G01 X-2.6784 Y1.5655 +G01 X-2.7045 Y1.5916 +G00 Z0.1000 +G00 X-2.0605 Y0.2500 +G01 Z-0.0070 F10 +G01 X-2.0605 Y0.2700 F20 +G01 X-2.0528 Y0.2886 +G01 X-2.0415 Y0.2999 +G01 X-2.0415 Y0.3062 +G01 X-2.0291 Y0.3362 +G01 X-2.0062 Y0.3591 +G01 X-1.9762 Y0.3715 +G01 X-1.9663 Y0.3715 +G01 X-1.8599 Y0.3715 +G01 X-1.8515 Y0.3799 +G01 X-1.8515 Y0.4601 +G01 X-1.8599 Y0.4685 +G01 X-1.8662 Y0.4685 +G01 X-1.8962 Y0.4809 +G01 X-1.9191 Y0.5038 +G01 X-1.9311 Y0.5327 +G01 X-1.9483 Y0.5500 +G01 X-1.9483 Y0.5900 +G01 X-1.9200 Y0.6183 +G01 X-1.8800 Y0.6183 +G01 X-1.8517 Y0.5900 +G01 X-1.8517 Y0.5500 +G01 X-1.8637 Y0.5380 +G01 X-1.8603 Y0.5346 +G01 X-1.8578 Y0.5336 +G01 X-1.8486 Y0.5428 +G01 X-1.8300 Y0.5505 +G01 X-1.8100 Y0.5505 +G01 X-1.7914 Y0.5428 +G01 X-1.7772 Y0.5286 +G01 X-1.7695 Y0.5100 +G01 X-1.7695 Y0.4900 +G01 X-1.7772 Y0.4714 +G01 X-1.7885 Y0.4601 +G01 X-1.7885 Y0.3799 +G01 X-1.7772 Y0.3686 +G01 X-1.7695 Y0.3500 +G01 X-1.7695 Y0.3300 +G01 X-1.7772 Y0.3114 +G01 X-1.7914 Y0.2972 +G01 X-1.8100 Y0.2895 +G01 X-1.8300 Y0.2895 +G01 X-1.8486 Y0.2972 +G01 X-1.8599 Y0.3085 +G01 X-1.9600 Y0.3085 +G01 X-1.9636 Y0.3081 +G01 X-1.9703 Y0.3054 +G01 X-1.9754 Y0.3003 +G01 X-1.9764 Y0.2978 +G01 X-1.9672 Y0.2886 +G01 X-1.9595 Y0.2700 +G01 X-1.9595 Y0.2500 +G01 X-1.9672 Y0.2314 +G01 X-1.9814 Y0.2172 +G01 X-2.0000 Y0.2095 +G01 X-2.0200 Y0.2095 +G01 X-2.0386 Y0.2172 +G01 X-2.0528 Y0.2314 +G01 X-2.0605 Y0.2500 +G00 Z0.1000 +G00 X-0.5862 Y1.5685 +G01 Z-0.0070 F10 +G01 X-0.5862 Y1.5685 F20 +G01 X-0.6162 Y1.5809 +G01 X-0.6391 Y1.6038 +G01 X-0.6515 Y1.6338 +G01 X-0.6515 Y1.6437 +G01 X-0.6515 Y1.6500 +G01 X-0.6515 Y1.6563 +G01 X-0.6515 Y1.7200 +G01 X-0.6517 Y1.7217 +G01 X-0.6529 Y1.7247 +G01 X-0.6553 Y1.7271 +G01 X-0.6583 Y1.7283 +G01 X-0.6600 Y1.7285 +G01 X-1.3037 Y1.7285 +G01 X-1.3050 Y1.7285 +G01 X-1.3163 Y1.7285 +G01 X-1.3262 Y1.7285 +G01 X-1.3562 Y1.7409 +G01 X-1.3791 Y1.7638 +G01 X-1.3915 Y1.7938 +G01 X-1.3915 Y1.8037 +G01 X-1.3915 Y1.8222 +G01 X-1.4090 Y1.8397 +G01 X-1.4090 Y1.8803 +G01 X-1.3915 Y1.8978 +G01 X-1.3915 Y1.9537 +G01 X-1.3915 Y1.9589 +G01 X-1.3915 Y1.9600 +G01 X-1.3919 Y1.9636 +G01 X-1.3946 Y1.9703 +G01 X-1.3997 Y1.9754 +G01 X-1.4064 Y1.9781 +G01 X-1.4100 Y1.9785 +G01 X-1.4163 Y1.9785 +G01 X-1.5637 Y1.9785 +G01 X-1.5700 Y1.9785 +G01 X-1.5736 Y1.9781 +G01 X-1.5803 Y1.9754 +G01 X-1.5854 Y1.9703 +G01 X-1.5881 Y1.9636 +G01 X-1.5885 Y1.9600 +G01 X-1.5885 Y1.7963 +G01 X-1.5885 Y1.7737 +G01 X-1.5885 Y1.6363 +G01 X-1.5885 Y1.6300 +G01 X-1.5881 Y1.6264 +G01 X-1.5854 Y1.6197 +G01 X-1.5803 Y1.6146 +G01 X-1.5736 Y1.6119 +G01 X-1.5700 Y1.6115 +G01 X-1.5693 Y1.6115 +G01 X-1.5637 Y1.6115 +G01 X-1.1437 Y1.6115 +G01 X-1.1338 Y1.6115 +G01 X-1.1038 Y1.5991 +G01 X-1.0809 Y1.5762 +G01 X-1.0685 Y1.5462 +G01 X-1.0685 Y1.5363 +G01 X-1.0685 Y1.5304 +G01 X-1.0685 Y1.5300 +G01 X-1.0685 Y1.5237 +G01 X-1.0685 Y0.8600 +G01 X-1.0681 Y0.8564 +G01 X-1.0654 Y0.8497 +G01 X-1.0603 Y0.8446 +G01 X-1.0536 Y0.8419 +G01 X-1.0500 Y0.8415 +G01 X-1.0445 Y0.8415 +G01 X-1.0437 Y0.8415 +G01 X-1.0384 Y0.8415 +G01 X-1.0322 Y0.8477 +G01 X-1.0159 Y0.8545 +G01 X-0.8841 Y0.8545 +G01 X-0.8678 Y0.8477 +G01 X-0.8553 Y0.8352 +G01 X-0.8485 Y0.8189 +G01 X-0.8485 Y0.8011 +G01 X-0.8553 Y0.7848 +G01 X-0.8678 Y0.7723 +G01 X-0.8841 Y0.7655 +G01 X-1.0159 Y0.7655 +G01 X-1.0322 Y0.7723 +G01 X-1.0384 Y0.7785 +G01 X-1.0437 Y0.7785 +G01 X-1.0445 Y0.7785 +G01 X-1.0563 Y0.7785 +G01 X-1.0662 Y0.7785 +G01 X-1.0962 Y0.7909 +G01 X-1.1191 Y0.8138 +G01 X-1.1315 Y0.8438 +G01 X-1.1315 Y0.8537 +G01 X-1.1315 Y1.5237 +G01 X-1.1315 Y1.5300 +G01 X-1.1319 Y1.5336 +G01 X-1.1346 Y1.5403 +G01 X-1.1397 Y1.5454 +G01 X-1.1464 Y1.5481 +G01 X-1.1500 Y1.5485 +G01 X-1.5637 Y1.5485 +G01 X-1.5694 Y1.5485 +G01 X-1.5763 Y1.5485 +G01 X-1.5862 Y1.5485 +G01 X-1.6162 Y1.5609 +G01 X-1.6391 Y1.5838 +G01 X-1.6515 Y1.6138 +G01 X-1.6515 Y1.6237 +G01 X-1.6515 Y1.6299 +G01 X-1.6515 Y1.6363 +G01 X-1.6515 Y1.7585 +G01 X-1.9332 Y1.7585 +G01 X-1.9500 Y1.7417 +G01 X-1.9900 Y1.7417 +G01 X-2.0183 Y1.7700 +G01 X-2.0183 Y1.8100 +G01 X-1.9900 Y1.8383 +G01 X-1.9500 Y1.8383 +G01 X-1.9332 Y1.8215 +G01 X-1.6515 Y1.8215 +G01 X-1.6515 Y1.9663 +G01 X-1.6515 Y1.9762 +G01 X-1.6391 Y2.0062 +G01 X-1.6162 Y2.0291 +G01 X-1.5862 Y2.0415 +G01 X-1.5763 Y2.0415 +G01 X-1.5707 Y2.0415 +G01 X-1.5700 Y2.0415 +G01 X-1.5637 Y2.0415 +G01 X-1.4163 Y2.0415 +G01 X-1.4100 Y2.0415 +G01 X-1.4063 Y2.0415 +G01 X-1.4037 Y2.0415 +G01 X-1.3938 Y2.0415 +G01 X-1.3638 Y2.0291 +G01 X-1.3409 Y2.0062 +G01 X-1.3285 Y1.9762 +G01 X-1.3285 Y1.9663 +G01 X-1.3285 Y1.9589 +G01 X-1.3285 Y1.9537 +G01 X-1.3285 Y1.8978 +G01 X-1.3110 Y1.8803 +G01 X-1.3110 Y1.8397 +G01 X-1.3285 Y1.8222 +G01 X-1.3285 Y1.8100 +G01 X-1.3281 Y1.8064 +G01 X-1.3254 Y1.7997 +G01 X-1.3203 Y1.7946 +G01 X-1.3136 Y1.7919 +G01 X-1.3100 Y1.7915 +G01 X-1.3050 Y1.7915 +G01 X-1.3037 Y1.7915 +G01 X-0.6537 Y1.7915 +G01 X-0.6458 Y1.7915 +G01 X-0.6195 Y1.7806 +G01 X-0.5994 Y1.7605 +G01 X-0.5885 Y1.7342 +G01 X-0.5885 Y1.7263 +G01 X-0.5885 Y1.6563 +G01 X-0.5885 Y1.6500 +G01 X-0.5881 Y1.6464 +G01 X-0.5854 Y1.6397 +G01 X-0.5803 Y1.6346 +G01 X-0.5736 Y1.6319 +G01 X-0.5700 Y1.6315 +G01 X-0.3019 Y1.6315 +G01 X-0.2977 Y1.6357 +G01 X-0.2786 Y1.6436 +G01 X-0.1214 Y1.6436 +G01 X-0.1023 Y1.6357 +G01 X-0.0877 Y1.6210 +G01 X-0.0798 Y1.6019 +G01 X-0.0798 Y1.5812 +G01 X-0.0877 Y1.5621 +G01 X-0.1023 Y1.5475 +G01 X-0.1214 Y1.5396 +G01 X-0.2786 Y1.5396 +G01 X-0.2977 Y1.5475 +G01 X-0.3123 Y1.5621 +G01 X-0.3150 Y1.5685 +G01 X-0.5763 Y1.5685 +G01 X-0.5862 Y1.5685 +G00 Z0.1000 +G00 X-2.9185 Y1.7658 +G01 Z-0.0070 F10 +G01 X-2.9185 Y1.7658 F20 +G01 X-2.9294 Y1.7395 +G01 X-2.9495 Y1.7194 +G01 X-2.9758 Y1.7085 +G01 X-2.9837 Y1.7085 +G01 X-2.9896 Y1.7085 +G01 X-2.9900 Y1.7085 +G01 X-2.9963 Y1.7085 +G01 X-3.1100 Y1.7085 +G01 X-3.1136 Y1.7081 +G01 X-3.1203 Y1.7054 +G01 X-3.1254 Y1.7003 +G01 X-3.1281 Y1.6936 +G01 X-3.1285 Y1.6900 +G01 X-3.1285 Y1.6845 +G01 X-3.1285 Y1.6837 +G01 X-3.1285 Y1.6414 +G01 X-3.1155 Y1.6284 +G01 X-3.1155 Y1.5916 +G01 X-3.1285 Y1.5786 +G01 X-3.1285 Y0.9600 +G01 X-3.1281 Y0.9564 +G01 X-3.1254 Y0.9497 +G01 X-3.1203 Y0.9446 +G01 X-3.1136 Y0.9419 +G01 X-3.1100 Y0.9415 +G01 X-3.1052 Y0.9415 +G01 X-3.1037 Y0.9415 +G01 X-2.5468 Y0.9415 +G01 X-2.5300 Y0.9583 +G01 X-2.4900 Y0.9583 +G01 X-2.4732 Y0.9415 +G01 X-2.1663 Y0.9415 +G01 X-2.1600 Y0.9415 +G01 X-2.1564 Y0.9419 +G01 X-2.1497 Y0.9446 +G01 X-2.1446 Y0.9497 +G01 X-2.1419 Y0.9564 +G01 X-2.1415 Y0.9600 +G01 X-2.1415 Y1.0663 +G01 X-2.1415 Y1.2769 +G01 X-2.1430 Y1.2785 +G01 X-2.1716 Y1.2785 +G01 X-2.1778 Y1.2723 +G01 X-2.1941 Y1.2655 +G01 X-2.3259 Y1.2655 +G01 X-2.3422 Y1.2723 +G01 X-2.3547 Y1.2848 +G01 X-2.3615 Y1.3011 +G01 X-2.3615 Y1.3189 +G01 X-2.3547 Y1.3352 +G01 X-2.3422 Y1.3477 +G01 X-2.3259 Y1.3545 +G01 X-2.1941 Y1.3545 +G01 X-2.1778 Y1.3477 +G01 X-2.1716 Y1.3415 +G01 X-2.1237 Y1.3415 +G01 X-2.1198 Y1.3415 +G01 X-2.1008 Y1.3337 +G01 X-2.0863 Y1.3192 +G01 X-2.0785 Y1.3002 +G01 X-2.0785 Y1.2963 +G01 X-2.0785 Y1.2837 +G01 X-2.0785 Y1.0663 +G01 X-2.0785 Y1.0530 +G01 X-2.0669 Y1.0415 +G01 X-2.0484 Y1.0415 +G01 X-2.0422 Y1.0477 +G01 X-2.0259 Y1.0545 +G01 X-1.8941 Y1.0545 +G01 X-1.8778 Y1.0477 +G01 X-1.8653 Y1.0352 +G01 X-1.8585 Y1.0189 +G01 X-1.8585 Y1.0011 +G01 X-1.8653 Y0.9848 +G01 X-1.8778 Y0.9723 +G01 X-1.8941 Y0.9655 +G01 X-2.0259 Y0.9655 +G01 X-2.0422 Y0.9723 +G01 X-2.0484 Y0.9785 +G01 X-2.0737 Y0.9785 +G01 X-2.0785 Y0.9785 +G01 X-2.0785 Y0.9537 +G01 X-2.0785 Y0.9438 +G01 X-2.0909 Y0.9138 +G01 X-2.1138 Y0.8909 +G01 X-2.1438 Y0.8785 +G01 X-2.1537 Y0.8785 +G01 X-2.1588 Y0.8785 +G01 X-2.1600 Y0.8785 +G01 X-2.1663 Y0.8785 +G01 X-2.4732 Y0.8785 +G01 X-2.4900 Y0.8617 +G01 X-2.5300 Y0.8617 +G01 X-2.5468 Y0.8785 +G01 X-3.1037 Y0.8785 +G01 X-3.1052 Y0.8785 +G01 X-3.1163 Y0.8785 +G01 X-3.1262 Y0.8785 +G01 X-3.1562 Y0.8909 +G01 X-3.1791 Y0.9138 +G01 X-3.1915 Y0.9438 +G01 X-3.1915 Y0.9537 +G01 X-3.1915 Y1.5786 +G01 X-3.2045 Y1.5916 +G01 X-3.2045 Y1.6284 +G01 X-3.1915 Y1.6414 +G01 X-3.1915 Y1.6837 +G01 X-3.1915 Y1.6845 +G01 X-3.1915 Y1.6963 +G01 X-3.1915 Y1.7062 +G01 X-3.1791 Y1.7362 +G01 X-3.1562 Y1.7591 +G01 X-3.1262 Y1.7715 +G01 X-3.1163 Y1.7715 +G01 X-2.9963 Y1.7715 +G01 X-2.9900 Y1.7715 +G01 X-2.9883 Y1.7717 +G01 X-2.9853 Y1.7729 +G01 X-2.9829 Y1.7753 +G01 X-2.9817 Y1.7783 +G01 X-2.9815 Y1.7800 +G01 X-2.9815 Y1.8537 +G01 X-2.9815 Y1.8554 +G01 X-2.9815 Y1.8663 +G01 X-2.9815 Y1.8762 +G01 X-2.9691 Y1.9062 +G01 X-2.9462 Y1.9291 +G01 X-2.9162 Y1.9415 +G01 X-2.9063 Y1.9415 +G01 X-2.0963 Y1.9415 +G01 X-2.0837 Y1.9415 +G01 X-2.0314 Y1.9415 +G01 X-2.0184 Y1.9545 +G01 X-1.9816 Y1.9545 +G01 X-1.9686 Y1.9415 +G01 X-1.7700 Y1.9415 +G01 X-1.7664 Y1.9419 +G01 X-1.7597 Y1.9446 +G01 X-1.7546 Y1.9497 +G01 X-1.7519 Y1.9564 +G01 X-1.7515 Y1.9600 +G01 X-1.7515 Y1.9649 +G01 X-1.7515 Y1.9663 +G01 X-1.7515 Y2.0663 +G01 X-1.7515 Y2.0762 +G01 X-1.7391 Y2.1062 +G01 X-1.7162 Y2.1291 +G01 X-1.6862 Y2.1415 +G01 X-1.6763 Y2.1415 +G01 X-1.6703 Y2.1415 +G01 X-1.6700 Y2.1415 +G01 X-1.6637 Y2.1415 +G01 X-1.2537 Y2.1415 +G01 X-1.2438 Y2.1415 +G01 X-1.2138 Y2.1291 +G01 X-1.1909 Y2.1062 +G01 X-1.1785 Y2.0762 +G01 X-1.1785 Y2.0663 +G01 X-1.1785 Y2.0607 +G01 X-1.1785 Y2.0600 +G01 X-1.1785 Y2.0537 +G01 X-1.1785 Y1.9163 +G01 X-1.1785 Y1.9100 +G01 X-1.1781 Y1.9064 +G01 X-1.1754 Y1.8997 +G01 X-1.1703 Y1.8946 +G01 X-1.1636 Y1.8919 +G01 X-1.1600 Y1.8915 +G01 X-1.1554 Y1.8915 +G01 X-1.1537 Y1.8915 +G01 X-0.7978 Y1.8915 +G01 X-0.7878 Y1.9015 +G01 X-0.7697 Y1.9090 +G01 X-0.7503 Y1.9090 +G01 X-0.7322 Y1.9015 +G01 X-0.7222 Y1.8915 +G01 X-0.2653 Y1.8915 +G01 X-0.2552 Y1.8915 +G01 X-0.2242 Y1.8814 +G01 X-0.1978 Y1.8622 +G01 X-0.1819 Y1.8404 +G01 X-0.1214 Y1.8404 +G01 X-0.1023 Y1.8325 +G01 X-0.0877 Y1.8179 +G01 X-0.0798 Y1.7988 +G01 X-0.0798 Y1.7781 +G01 X-0.0877 Y1.7590 +G01 X-0.1023 Y1.7443 +G01 X-0.1214 Y1.7364 +G01 X-0.2786 Y1.7364 +G01 X-0.2977 Y1.7443 +G01 X-0.3123 Y1.7590 +G01 X-0.3202 Y1.7781 +G01 X-0.3202 Y1.7988 +G01 X-0.3123 Y1.8179 +G01 X-0.3017 Y1.8285 +G01 X-0.7222 Y1.8285 +G01 X-0.7322 Y1.8185 +G01 X-0.7503 Y1.8110 +G01 X-0.7697 Y1.8110 +G01 X-0.7878 Y1.8185 +G01 X-0.7978 Y1.8285 +G01 X-1.1537 Y1.8285 +G01 X-1.1555 Y1.8285 +G01 X-1.1663 Y1.8285 +G01 X-1.1762 Y1.8285 +G01 X-1.2062 Y1.8409 +G01 X-1.2291 Y1.8638 +G01 X-1.2415 Y1.8938 +G01 X-1.2415 Y1.9037 +G01 X-1.2415 Y1.9059 +G01 X-1.2415 Y1.9100 +G01 X-1.2415 Y1.9163 +G01 X-1.2415 Y2.0537 +G01 X-1.2415 Y2.0600 +G01 X-1.2419 Y2.0636 +G01 X-1.2446 Y2.0703 +G01 X-1.2497 Y2.0754 +G01 X-1.2564 Y2.0781 +G01 X-1.2600 Y2.0785 +G01 X-1.6637 Y2.0785 +G01 X-1.6700 Y2.0785 +G01 X-1.6736 Y2.0781 +G01 X-1.6803 Y2.0754 +G01 X-1.6854 Y2.0703 +G01 X-1.6881 Y2.0636 +G01 X-1.6885 Y2.0600 +G01 X-1.6885 Y1.9663 +G01 X-1.6885 Y1.9649 +G01 X-1.6885 Y1.9537 +G01 X-1.6885 Y1.9438 +G01 X-1.7009 Y1.9138 +G01 X-1.7238 Y1.8909 +G01 X-1.7538 Y1.8785 +G01 X-1.7637 Y1.8785 +G01 X-1.9686 Y1.8785 +G01 X-1.9816 Y1.8655 +G01 X-2.0184 Y1.8655 +G01 X-2.0314 Y1.8785 +G01 X-2.0585 Y1.8785 +G01 X-2.0585 Y1.7500 +G01 X-2.0581 Y1.7464 +G01 X-2.0554 Y1.7397 +G01 X-2.0503 Y1.7346 +G01 X-2.0436 Y1.7319 +G01 X-2.0400 Y1.7315 +G01 X-2.0349 Y1.7315 +G01 X-2.0337 Y1.7315 +G01 X-1.8014 Y1.7315 +G01 X-1.7884 Y1.7445 +G01 X-1.7516 Y1.7445 +G01 X-1.7386 Y1.7315 +G01 X-1.7337 Y1.7315 +G01 X-1.7278 Y1.7315 +G01 X-1.7052 Y1.7221 +G01 X-1.6879 Y1.7048 +G01 X-1.6785 Y1.6822 +G01 X-1.6785 Y1.6763 +G01 X-1.6785 Y1.5100 +G01 X-1.6781 Y1.5064 +G01 X-1.6754 Y1.4997 +G01 X-1.6703 Y1.4946 +G01 X-1.6636 Y1.4919 +G01 X-1.6600 Y1.4915 +G01 X-1.6575 Y1.4915 +G01 X-1.6537 Y1.4915 +G01 X-1.4663 Y1.4915 +G01 X-1.4600 Y1.4915 +G01 X-1.4566 Y1.4915 +G01 X-1.4537 Y1.4915 +G01 X-1.4438 Y1.4915 +G01 X-1.4138 Y1.4791 +G01 X-1.3909 Y1.4562 +G01 X-1.3836 Y1.4384 +G01 X-1.3762 Y1.4415 +G01 X-1.3663 Y1.4415 +G01 X-1.3595 Y1.4415 +G01 X-1.3537 Y1.4415 +G01 X-1.3384 Y1.4415 +G01 X-1.3322 Y1.4477 +G01 X-1.3159 Y1.4545 +G01 X-1.1841 Y1.4545 +G01 X-1.1678 Y1.4477 +G01 X-1.1553 Y1.4352 +G01 X-1.1485 Y1.4189 +G01 X-1.1485 Y1.4011 +G01 X-1.1553 Y1.3848 +G01 X-1.1678 Y1.3723 +G01 X-1.1841 Y1.3655 +G01 X-1.3159 Y1.3655 +G01 X-1.3322 Y1.3723 +G01 X-1.3384 Y1.3785 +G01 X-1.3537 Y1.3785 +G01 X-1.3596 Y1.3785 +G01 X-1.3600 Y1.3785 +G01 X-1.3636 Y1.3781 +G01 X-1.3703 Y1.3754 +G01 X-1.3754 Y1.3703 +G01 X-1.3781 Y1.3636 +G01 X-1.3785 Y1.3600 +G01 X-1.3785 Y1.2537 +G01 X-1.3785 Y1.2444 +G01 X-1.3785 Y1.2345 +G01 X-1.3855 Y1.2176 +G01 X-1.3855 Y1.1916 +G01 X-1.4116 Y1.1655 +G01 X-1.4484 Y1.1655 +G01 X-1.4745 Y1.1916 +G01 X-1.4745 Y1.2284 +G01 X-1.4484 Y1.2545 +G01 X-1.4415 Y1.2545 +G01 X-1.4415 Y1.4100 +G01 X-1.4419 Y1.4136 +G01 X-1.4446 Y1.4203 +G01 X-1.4497 Y1.4254 +G01 X-1.4564 Y1.4281 +G01 X-1.4600 Y1.4285 +G01 X-1.4663 Y1.4285 +G01 X-1.6537 Y1.4285 +G01 X-1.6576 Y1.4285 +G01 X-1.6663 Y1.4285 +G01 X-1.6762 Y1.4285 +G01 X-1.7062 Y1.4409 +G01 X-1.7291 Y1.4638 +G01 X-1.7415 Y1.4938 +G01 X-1.7415 Y1.5037 +G01 X-1.7415 Y1.6656 +G01 X-1.7516 Y1.6555 +G01 X-1.7884 Y1.6555 +G01 X-1.8014 Y1.6685 +G01 X-2.0337 Y1.6685 +G01 X-2.0349 Y1.6685 +G01 X-2.0463 Y1.6685 +G01 X-2.0562 Y1.6685 +G01 X-2.0862 Y1.6809 +G01 X-2.1091 Y1.7038 +G01 X-2.1215 Y1.7338 +G01 X-2.1215 Y1.7437 +G01 X-2.1215 Y1.8785 +G01 X-2.9000 Y1.8785 +G01 X-2.9036 Y1.8781 +G01 X-2.9103 Y1.8754 +G01 X-2.9154 Y1.8703 +G01 X-2.9181 Y1.8636 +G01 X-2.9185 Y1.8600 +G01 X-2.9185 Y1.8554 +G01 X-2.9185 Y1.8537 +G01 X-2.9185 Y1.7737 +G01 X-2.9185 Y1.7658 +G00 Z0.1000 +G00 X-0.5285 Y0.4738 +G01 Z-0.0070 F10 +G01 X-0.5285 Y0.4738 F20 +G01 X-0.5409 Y0.4438 +G01 X-0.5638 Y0.4209 +G01 X-0.5938 Y0.4085 +G01 X-0.6037 Y0.4085 +G01 X-0.6100 Y0.4085 +G01 X-0.6163 Y0.4085 +G01 X-1.3763 Y0.4085 +G01 X-1.3862 Y0.4085 +G01 X-1.4162 Y0.4209 +G01 X-1.4391 Y0.4438 +G01 X-1.4438 Y0.4552 +G01 X-1.4486 Y0.4572 +G01 X-1.4628 Y0.4714 +G01 X-1.4705 Y0.4900 +G01 X-1.4705 Y0.5100 +G01 X-1.4628 Y0.5286 +G01 X-1.4615 Y0.5299 +G01 X-1.4615 Y0.6786 +G01 X-1.4745 Y0.6916 +G01 X-1.4745 Y0.7284 +G01 X-1.4484 Y0.7545 +G01 X-1.4116 Y0.7545 +G01 X-1.3855 Y0.7284 +G01 X-1.3855 Y0.6916 +G01 X-1.3985 Y0.6786 +G01 X-1.3985 Y0.5457 +G01 X-1.3914 Y0.5428 +G01 X-1.3772 Y0.5286 +G01 X-1.3695 Y0.5100 +G01 X-1.3695 Y0.4900 +G01 X-1.3765 Y0.4731 +G01 X-1.3736 Y0.4719 +G01 X-1.3700 Y0.4715 +G01 X-0.6163 Y0.4715 +G01 X-0.6100 Y0.4715 +G01 X-0.6064 Y0.4719 +G01 X-0.5997 Y0.4746 +G01 X-0.5946 Y0.4797 +G01 X-0.5919 Y0.4864 +G01 X-0.5915 Y0.4900 +G01 X-0.5915 Y0.8786 +G01 X-0.6045 Y0.8916 +G01 X-0.6045 Y0.9284 +G01 X-0.5784 Y0.9545 +G01 X-0.5416 Y0.9545 +G01 X-0.5155 Y0.9284 +G01 X-0.5155 Y0.8916 +G01 X-0.5285 Y0.8786 +G01 X-0.5285 Y0.4837 +G01 X-0.5285 Y0.4738 +G00 Z0.1000 +G00 X-1.6985 Y0.7838 +G01 Z-0.0070 F10 +G01 X-1.6985 Y0.7838 F20 +G01 X-1.7109 Y0.7538 +G01 X-1.7338 Y0.7309 +G01 X-1.7638 Y0.7185 +G01 X-1.7737 Y0.7185 +G01 X-1.7766 Y0.7185 +G01 X-1.7800 Y0.7185 +G01 X-1.7863 Y0.7185 +G01 X-2.1837 Y0.7185 +G01 X-2.1900 Y0.7185 +G01 X-2.1917 Y0.7183 +G01 X-2.1947 Y0.7171 +G01 X-2.1971 Y0.7147 +G01 X-2.1983 Y0.7117 +G01 X-2.1985 Y0.7100 +G01 X-2.1985 Y0.5963 +G01 X-2.1985 Y0.5938 +G01 X-2.1985 Y0.5837 +G01 X-2.1985 Y0.5758 +G01 X-2.2094 Y0.5495 +G01 X-2.2295 Y0.5294 +G01 X-2.2558 Y0.5185 +G01 X-2.2637 Y0.5185 +G01 X-2.2688 Y0.5185 +G01 X-2.2700 Y0.5185 +G01 X-2.2763 Y0.5185 +G01 X-2.8113 Y0.5185 +G01 X-2.8223 Y0.5075 +G01 X-2.8414 Y0.4996 +G01 X-2.9986 Y0.4996 +G01 X-3.0177 Y0.5075 +G01 X-3.0323 Y0.5221 +G01 X-3.0402 Y0.5412 +G01 X-3.0402 Y0.5619 +G01 X-3.0323 Y0.5810 +G01 X-3.0177 Y0.5957 +G01 X-2.9986 Y0.6036 +G01 X-2.8414 Y0.6036 +G01 X-2.8223 Y0.5957 +G01 X-2.8081 Y0.5815 +G01 X-2.2763 Y0.5815 +G01 X-2.2700 Y0.5815 +G01 X-2.2683 Y0.5817 +G01 X-2.2653 Y0.5829 +G01 X-2.2629 Y0.5853 +G01 X-2.2617 Y0.5883 +G01 X-2.2615 Y0.5900 +G01 X-2.2615 Y0.5938 +G01 X-2.2615 Y0.5963 +G01 X-2.2615 Y0.7163 +G01 X-2.2615 Y0.7242 +G01 X-2.2506 Y0.7505 +G01 X-2.2305 Y0.7706 +G01 X-2.2042 Y0.7815 +G01 X-2.1963 Y0.7815 +G01 X-2.1906 Y0.7815 +G01 X-2.1900 Y0.7815 +G01 X-2.1837 Y0.7815 +G01 X-1.7863 Y0.7815 +G01 X-1.7800 Y0.7815 +G01 X-1.7764 Y0.7819 +G01 X-1.7697 Y0.7846 +G01 X-1.7646 Y0.7897 +G01 X-1.7619 Y0.7964 +G01 X-1.7615 Y0.8000 +G01 X-1.7615 Y0.9637 +G01 X-1.7615 Y0.9645 +G01 X-1.7615 Y0.9763 +G01 X-1.7615 Y0.9842 +G01 X-1.7506 Y1.0105 +G01 X-1.7305 Y1.0306 +G01 X-1.7042 Y1.0415 +G01 X-1.6963 Y1.0415 +G01 X-1.6901 Y1.0415 +G01 X-1.6837 Y1.0415 +G01 X-1.3384 Y1.0415 +G01 X-1.3322 Y1.0477 +G01 X-1.3159 Y1.0545 +G01 X-1.1841 Y1.0545 +G01 X-1.1678 Y1.0477 +G01 X-1.1553 Y1.0352 +G01 X-1.1485 Y1.0189 +G01 X-1.1485 Y1.0011 +G01 X-1.1553 Y0.9848 +G01 X-1.1678 Y0.9723 +G01 X-1.1841 Y0.9655 +G01 X-1.3159 Y0.9655 +G01 X-1.3322 Y0.9723 +G01 X-1.3384 Y0.9785 +G01 X-1.6837 Y0.9785 +G01 X-1.6900 Y0.9785 +G01 X-1.6917 Y0.9783 +G01 X-1.6947 Y0.9771 +G01 X-1.6971 Y0.9747 +G01 X-1.6983 Y0.9717 +G01 X-1.6985 Y0.9700 +G01 X-1.6985 Y0.9645 +G01 X-1.6985 Y0.9637 +G01 X-1.6985 Y0.7937 +G01 X-1.6985 Y0.7838 +G00 Z0.1000 +G00 X-0.5738 Y1.4415 +G01 Z-0.0070 F10 +G01 X-0.5738 Y1.4415 F20 +G01 X-0.5438 Y1.4291 +G01 X-0.5209 Y1.4062 +G01 X-0.5085 Y1.3762 +G01 X-0.5085 Y1.3663 +G01 X-0.5085 Y1.3601 +G01 X-0.5085 Y1.3600 +G01 X-0.5085 Y1.3584 +G01 X-0.5081 Y1.3548 +G01 X-0.5054 Y1.3481 +G01 X-0.5003 Y1.3430 +G01 X-0.4936 Y1.3403 +G01 X-0.4900 Y1.3399 +G01 X-0.4882 Y1.3399 +G01 X-0.4837 Y1.3399 +G01 X-0.3103 Y1.3399 +G01 X-0.2977 Y1.3525 +G01 X-0.2786 Y1.3604 +G01 X-0.1214 Y1.3604 +G01 X-0.1023 Y1.3525 +G01 X-0.0877 Y1.3379 +G01 X-0.0798 Y1.3188 +G01 X-0.0798 Y1.2981 +G01 X-0.0877 Y1.2790 +G01 X-0.1023 Y1.2643 +G01 X-0.1214 Y1.2564 +G01 X-0.2786 Y1.2564 +G01 X-0.2977 Y1.2643 +G01 X-0.3103 Y1.2769 +G01 X-0.4837 Y1.2769 +G01 X-0.4882 Y1.2769 +G01 X-0.4900 Y1.2769 +G01 X-0.4963 Y1.2769 +G01 X-0.5062 Y1.2769 +G01 X-0.5362 Y1.2893 +G01 X-0.5591 Y1.3123 +G01 X-0.5715 Y1.3422 +G01 X-0.5715 Y1.3522 +G01 X-0.5715 Y1.3537 +G01 X-0.5715 Y1.3600 +G01 X-0.5719 Y1.3636 +G01 X-0.5746 Y1.3703 +G01 X-0.5797 Y1.3754 +G01 X-0.5864 Y1.3781 +G01 X-0.5900 Y1.3785 +G01 X-0.8616 Y1.3785 +G01 X-0.8678 Y1.3723 +G01 X-0.8841 Y1.3655 +G01 X-1.0159 Y1.3655 +G01 X-1.0322 Y1.3723 +G01 X-1.0447 Y1.3848 +G01 X-1.0515 Y1.4011 +G01 X-1.0515 Y1.4189 +G01 X-1.0447 Y1.4352 +G01 X-1.0322 Y1.4477 +G01 X-1.0159 Y1.4545 +G01 X-0.8841 Y1.4545 +G01 X-0.8678 Y1.4477 +G01 X-0.8616 Y1.4415 +G01 X-0.5837 Y1.4415 +G01 X-0.5738 Y1.4415 +G00 Z0.1000 +G00 X-0.4463 Y1.2415 +G01 Z-0.0070 F10 +G01 X-0.4400 Y1.2415 F20 +G01 X-0.4368 Y1.2415 +G01 X-0.4337 Y1.2415 +G01 X-0.4258 Y1.2415 +G01 X-0.3995 Y1.2306 +G01 X-0.3794 Y1.2105 +G01 X-0.3685 Y1.1842 +G01 X-0.3685 Y1.1763 +G01 X-0.3685 Y1.1616 +G01 X-0.3681 Y1.1580 +G01 X-0.3654 Y1.1513 +G01 X-0.3603 Y1.1462 +G01 X-0.3536 Y1.1434 +G01 X-0.3500 Y1.1431 +G01 X-0.3449 Y1.1431 +G01 X-0.3437 Y1.1431 +G01 X-0.3103 Y1.1431 +G01 X-0.2977 Y1.1557 +G01 X-0.2786 Y1.1636 +G01 X-0.1214 Y1.1636 +G01 X-0.1023 Y1.1557 +G01 X-0.0877 Y1.1410 +G01 X-0.0798 Y1.1219 +G01 X-0.0798 Y1.1012 +G01 X-0.0877 Y1.0821 +G01 X-0.1023 Y1.0675 +G01 X-0.1214 Y1.0596 +G01 X-0.2786 Y1.0596 +G01 X-0.2977 Y1.0675 +G01 X-0.3103 Y1.0801 +G01 X-0.3437 Y1.0801 +G01 X-0.3449 Y1.0801 +G01 X-0.3563 Y1.0801 +G01 X-0.3662 Y1.0801 +G01 X-0.3962 Y1.0925 +G01 X-0.4191 Y1.1154 +G01 X-0.4315 Y1.1454 +G01 X-0.4315 Y1.1553 +G01 X-0.4315 Y1.1700 +G01 X-0.4317 Y1.1717 +G01 X-0.4329 Y1.1747 +G01 X-0.4353 Y1.1771 +G01 X-0.4383 Y1.1783 +G01 X-0.4400 Y1.1785 +G01 X-0.4463 Y1.1785 +G01 X-0.8616 Y1.1785 +G01 X-0.8678 Y1.1723 +G01 X-0.8841 Y1.1655 +G01 X-1.0159 Y1.1655 +G01 X-1.0322 Y1.1723 +G01 X-1.0447 Y1.1848 +G01 X-1.0515 Y1.2011 +G01 X-1.0515 Y1.2189 +G01 X-1.0447 Y1.2352 +G01 X-1.0322 Y1.2477 +G01 X-1.0159 Y1.2545 +G01 X-0.8841 Y1.2545 +G01 X-0.8678 Y1.2477 +G01 X-0.8616 Y1.2415 +G01 X-0.4463 Y1.2415 +G00 Z0.1000 +G00 X-0.4042 Y0.8785 +G01 Z-0.0070 F10 +G01 X-0.4042 Y0.8785 F20 +G01 X-0.4305 Y0.8894 +G01 X-0.4506 Y0.9095 +G01 X-0.4615 Y0.9358 +G01 X-0.4615 Y0.9437 +G01 X-0.4615 Y0.9497 +G01 X-0.4615 Y0.9500 +G01 X-0.4615 Y0.9563 +G01 X-0.4615 Y0.9600 +G01 X-0.4619 Y0.9636 +G01 X-0.4646 Y0.9703 +G01 X-0.4697 Y0.9754 +G01 X-0.4764 Y0.9781 +G01 X-0.4800 Y0.9785 +G01 X-0.4863 Y0.9785 +G01 X-0.8616 Y0.9785 +G01 X-0.8678 Y0.9723 +G01 X-0.8841 Y0.9655 +G01 X-1.0159 Y0.9655 +G01 X-1.0322 Y0.9723 +G01 X-1.0447 Y0.9848 +G01 X-1.0515 Y1.0011 +G01 X-1.0515 Y1.0189 +G01 X-1.0447 Y1.0352 +G01 X-1.0322 Y1.0477 +G01 X-1.0159 Y1.0545 +G01 X-0.8841 Y1.0545 +G01 X-0.8678 Y1.0477 +G01 X-0.8616 Y1.0415 +G01 X-0.4863 Y1.0415 +G01 X-0.4800 Y1.0415 +G01 X-0.4799 Y1.0415 +G01 X-0.4737 Y1.0415 +G01 X-0.4638 Y1.0415 +G01 X-0.4338 Y1.0291 +G01 X-0.4109 Y1.0062 +G01 X-0.3985 Y0.9762 +G01 X-0.3985 Y0.9663 +G01 X-0.3985 Y0.9563 +G01 X-0.3985 Y0.9500 +G01 X-0.3983 Y0.9483 +G01 X-0.3971 Y0.9453 +G01 X-0.3947 Y0.9429 +G01 X-0.3917 Y0.9417 +G01 X-0.3900 Y0.9415 +G01 X-0.3087 Y0.9415 +G01 X-0.2977 Y0.9525 +G01 X-0.2786 Y0.9604 +G01 X-0.1214 Y0.9604 +G01 X-0.1023 Y0.9525 +G01 X-0.0877 Y0.9379 +G01 X-0.0798 Y0.9188 +G01 X-0.0798 Y0.8981 +G01 X-0.0877 Y0.8790 +G01 X-0.1023 Y0.8643 +G01 X-0.1214 Y0.8564 +G01 X-0.2786 Y0.8564 +G01 X-0.2977 Y0.8643 +G01 X-0.3119 Y0.8785 +G01 X-0.3963 Y0.8785 +G01 X-0.4042 Y0.8785 +G00 Z0.1000 +G00 X-0.4255 Y0.2832 +G01 Z-0.0070 F10 +G01 X-0.4255 Y0.2832 F20 +G01 X-0.4384 Y0.2521 +G01 X-0.4621 Y0.2284 +G01 X-0.4932 Y0.2155 +G01 X-0.5031 Y0.2155 +G01 X-0.5100 Y0.2155 +G01 X-0.5169 Y0.2155 +G01 X-1.0400 Y0.2155 +G01 X-1.0430 Y0.2152 +G01 X-1.0486 Y0.2129 +G01 X-1.0529 Y0.2086 +G01 X-1.0552 Y0.2030 +G01 X-1.0555 Y0.2000 +G01 X-1.0555 Y0.1958 +G01 X-1.0555 Y0.1931 +G01 X-1.0555 Y0.1431 +G01 X-1.0555 Y0.1332 +G01 X-1.0684 Y0.1021 +G01 X-1.0921 Y0.0784 +G01 X-1.1232 Y0.0655 +G01 X-1.1400 Y0.0655 +G01 X-1.1469 Y0.0655 +G01 X-1.5931 Y0.0655 +G01 X-1.6000 Y0.0655 +G01 X-1.6168 Y0.0655 +G01 X-1.6479 Y0.0784 +G01 X-1.6716 Y0.1021 +G01 X-1.6845 Y0.1332 +G01 X-1.6845 Y0.1431 +G01 X-1.6845 Y0.8669 +G01 X-1.6845 Y0.8768 +G01 X-1.6716 Y0.9079 +G01 X-1.6479 Y0.9316 +G01 X-1.6168 Y0.9445 +G01 X-1.6069 Y0.9445 +G01 X-1.6000 Y0.9445 +G01 X-1.5931 Y0.9445 +G01 X-1.3397 Y0.9445 +G01 X-1.3339 Y0.9503 +G01 X-1.3164 Y0.9575 +G01 X-1.1835 Y0.9575 +G01 X-1.1661 Y0.9503 +G01 X-1.1527 Y0.9369 +G01 X-1.1455 Y0.9194 +G01 X-1.1455 Y0.9005 +G01 X-1.1527 Y0.8831 +G01 X-1.1661 Y0.8697 +G01 X-1.1835 Y0.8625 +G01 X-1.3164 Y0.8625 +G01 X-1.3339 Y0.8697 +G01 X-1.3397 Y0.8755 +G01 X-1.5931 Y0.8755 +G01 X-1.6000 Y0.8755 +G01 X-1.6030 Y0.8752 +G01 X-1.6086 Y0.8729 +G01 X-1.6129 Y0.8686 +G01 X-1.6152 Y0.8630 +G01 X-1.6155 Y0.8600 +G01 X-1.6155 Y0.1500 +G01 X-1.6152 Y0.1470 +G01 X-1.6129 Y0.1414 +G01 X-1.6086 Y0.1371 +G01 X-1.6030 Y0.1348 +G01 X-1.6000 Y0.1345 +G01 X-1.5931 Y0.1345 +G01 X-1.1469 Y0.1345 +G01 X-1.1400 Y0.1345 +G01 X-1.1370 Y0.1348 +G01 X-1.1314 Y0.1371 +G01 X-1.1271 Y0.1414 +G01 X-1.1248 Y0.1470 +G01 X-1.1245 Y0.1500 +G01 X-1.1245 Y0.1931 +G01 X-1.1245 Y0.1958 +G01 X-1.1245 Y0.2069 +G01 X-1.1245 Y0.2168 +G01 X-1.1116 Y0.2479 +G01 X-1.0879 Y0.2716 +G01 X-1.0568 Y0.2845 +G01 X-1.0469 Y0.2845 +G01 X-0.5169 Y0.2845 +G01 X-0.5100 Y0.2845 +G01 X-0.5070 Y0.2848 +G01 X-0.5014 Y0.2871 +G01 X-0.4971 Y0.2914 +G01 X-0.4948 Y0.2970 +G01 X-0.4945 Y0.3000 +G01 X-0.4945 Y0.6531 +G01 X-0.4945 Y0.6542 +G01 X-0.4945 Y0.6669 +G01 X-0.4945 Y0.6768 +G01 X-0.4816 Y0.7079 +G01 X-0.4579 Y0.7316 +G01 X-0.4268 Y0.7445 +G01 X-0.4100 Y0.7445 +G01 X-0.4031 Y0.7445 +G01 X-0.3131 Y0.7445 +G01 X-0.2994 Y0.7582 +G01 X-0.2792 Y0.7666 +G01 X-0.1208 Y0.7666 +G01 X-0.1006 Y0.7582 +G01 X-0.0851 Y0.7427 +G01 X-0.0768 Y0.7225 +G01 X-0.0768 Y0.7006 +G01 X-0.0851 Y0.6804 +G01 X-0.1006 Y0.6649 +G01 X-0.1208 Y0.6566 +G01 X-0.2792 Y0.6566 +G01 X-0.2994 Y0.6649 +G01 X-0.3100 Y0.6755 +G01 X-0.4031 Y0.6755 +G01 X-0.4100 Y0.6755 +G01 X-0.4130 Y0.6752 +G01 X-0.4186 Y0.6729 +G01 X-0.4229 Y0.6686 +G01 X-0.4252 Y0.6630 +G01 X-0.4255 Y0.6600 +G01 X-0.4255 Y0.6542 +G01 X-0.4255 Y0.6531 +G01 X-0.4255 Y0.2931 +G01 X-0.4255 Y0.2832 +G00 Z0.1000 +G00 X-0.5732 Y1.4445 +G01 Z-0.0070 F10 +G01 X-0.5732 Y1.4445 F20 +G01 X-0.5421 Y1.4316 +G01 X-0.5184 Y1.4079 +G01 X-0.5055 Y1.3768 +G01 X-0.5055 Y1.3669 +G01 X-0.5055 Y1.3650 +G01 X-0.5055 Y1.3600 +G01 X-0.5055 Y1.3584 +G01 X-0.5052 Y1.3554 +G01 X-0.5029 Y1.3498 +G01 X-0.4986 Y1.3455 +G01 X-0.4930 Y1.3432 +G01 X-0.4900 Y1.3429 +G01 X-0.4873 Y1.3429 +G01 X-0.4831 Y1.3429 +G01 X-0.3115 Y1.3429 +G01 X-0.2994 Y1.3550 +G01 X-0.2792 Y1.3634 +G01 X-0.1208 Y1.3634 +G01 X-0.1006 Y1.3550 +G01 X-0.0851 Y1.3396 +G01 X-0.0768 Y1.3194 +G01 X-0.0768 Y1.2975 +G01 X-0.0851 Y1.2773 +G01 X-0.1006 Y1.2618 +G01 X-0.1208 Y1.2534 +G01 X-0.2792 Y1.2534 +G01 X-0.2994 Y1.2618 +G01 X-0.3115 Y1.2739 +G01 X-0.4831 Y1.2739 +G01 X-0.4874 Y1.2739 +G01 X-0.4969 Y1.2739 +G01 X-0.5068 Y1.2739 +G01 X-0.5379 Y1.2868 +G01 X-0.5616 Y1.3106 +G01 X-0.5745 Y1.3416 +G01 X-0.5745 Y1.3516 +G01 X-0.5745 Y1.3531 +G01 X-0.5745 Y1.3600 +G01 X-0.5748 Y1.3630 +G01 X-0.5771 Y1.3686 +G01 X-0.5814 Y1.3729 +G01 X-0.5870 Y1.3752 +G01 X-0.5900 Y1.3755 +G01 X-0.8603 Y1.3755 +G01 X-0.8661 Y1.3697 +G01 X-0.8835 Y1.3625 +G01 X-1.0164 Y1.3625 +G01 X-1.0339 Y1.3697 +G01 X-1.0473 Y1.3831 +G01 X-1.0545 Y1.4005 +G01 X-1.0545 Y1.4194 +G01 X-1.0473 Y1.4369 +G01 X-1.0339 Y1.4503 +G01 X-1.0164 Y1.4575 +G01 X-0.8835 Y1.4575 +G01 X-0.8661 Y1.4503 +G01 X-0.8603 Y1.4445 +G01 X-0.5831 Y1.4445 +G01 X-0.5732 Y1.4445 +G00 Z0.1000 +G00 X-1.6955 Y0.7832 +G01 Z-0.0070 F10 +G01 X-1.6955 Y0.7832 F20 +G01 X-1.7084 Y0.7521 +G01 X-1.7321 Y0.7284 +G01 X-1.7632 Y0.7155 +G01 X-1.7800 Y0.7155 +G01 X-1.7869 Y0.7155 +G01 X-2.1831 Y0.7155 +G01 X-2.1900 Y0.7155 +G01 X-2.1911 Y0.7154 +G01 X-2.1931 Y0.7146 +G01 X-2.1946 Y0.7131 +G01 X-2.1954 Y0.7111 +G01 X-2.1955 Y0.7100 +G01 X-2.1955 Y0.5969 +G01 X-2.1955 Y0.5944 +G01 X-2.1955 Y0.5831 +G01 X-2.1955 Y0.5752 +G01 X-2.2068 Y0.5478 +G01 X-2.2278 Y0.5268 +G01 X-2.2552 Y0.5155 +G01 X-2.2631 Y0.5155 +G01 X-2.2688 Y0.5155 +G01 X-2.2700 Y0.5155 +G01 X-2.2769 Y0.5155 +G01 X-2.8100 Y0.5155 +G01 X-2.8206 Y0.5049 +G01 X-2.8408 Y0.4966 +G01 X-2.9992 Y0.4966 +G01 X-3.0194 Y0.5049 +G01 X-3.0349 Y0.5204 +G01 X-3.0432 Y0.5406 +G01 X-3.0432 Y0.5625 +G01 X-3.0349 Y0.5827 +G01 X-3.0194 Y0.5982 +G01 X-2.9992 Y0.6066 +G01 X-2.8408 Y0.6066 +G01 X-2.8206 Y0.5982 +G01 X-2.8069 Y0.5845 +G01 X-2.2769 Y0.5845 +G01 X-2.2700 Y0.5845 +G01 X-2.2689 Y0.5846 +G01 X-2.2669 Y0.5854 +G01 X-2.2654 Y0.5869 +G01 X-2.2646 Y0.5889 +G01 X-2.2645 Y0.5900 +G01 X-2.2645 Y0.5944 +G01 X-2.2645 Y0.5969 +G01 X-2.2645 Y0.7169 +G01 X-2.2645 Y0.7248 +G01 X-2.2532 Y0.7522 +G01 X-2.2322 Y0.7732 +G01 X-2.2048 Y0.7845 +G01 X-2.1969 Y0.7845 +G01 X-2.1906 Y0.7845 +G01 X-2.1900 Y0.7845 +G01 X-2.1831 Y0.7845 +G01 X-1.7869 Y0.7845 +G01 X-1.7800 Y0.7845 +G01 X-1.7770 Y0.7848 +G01 X-1.7714 Y0.7871 +G01 X-1.7671 Y0.7914 +G01 X-1.7648 Y0.7970 +G01 X-1.7645 Y0.8000 +G01 X-1.7645 Y0.9631 +G01 X-1.7645 Y0.9640 +G01 X-1.7645 Y0.9769 +G01 X-1.7645 Y0.9848 +G01 X-1.7532 Y1.0122 +G01 X-1.7322 Y1.0331 +G01 X-1.7048 Y1.0445 +G01 X-1.6969 Y1.0445 +G01 X-1.6900 Y1.0445 +G01 X-1.6831 Y1.0445 +G01 X-1.3397 Y1.0445 +G01 X-1.3339 Y1.0503 +G01 X-1.3164 Y1.0575 +G01 X-1.1835 Y1.0575 +G01 X-1.1661 Y1.0503 +G01 X-1.1527 Y1.0369 +G01 X-1.1455 Y1.0194 +G01 X-1.1455 Y1.0005 +G01 X-1.1527 Y0.9831 +G01 X-1.1661 Y0.9697 +G01 X-1.1835 Y0.9625 +G01 X-1.3164 Y0.9625 +G01 X-1.3339 Y0.9697 +G01 X-1.3397 Y0.9755 +G01 X-1.6831 Y0.9755 +G01 X-1.6900 Y0.9755 +G01 X-1.6911 Y0.9754 +G01 X-1.6931 Y0.9746 +G01 X-1.6946 Y0.9731 +G01 X-1.6954 Y0.9711 +G01 X-1.6955 Y0.9700 +G01 X-1.6955 Y0.9640 +G01 X-1.6955 Y0.9631 +G01 X-1.6955 Y0.7931 +G01 X-1.6955 Y0.7832 +G00 Z0.1000 +G00 X-2.1745 Y0.6268 +G01 Z-0.0070 F10 +G01 X-2.1745 Y0.6268 F20 +G01 X-2.1616 Y0.6579 +G01 X-2.1379 Y0.6816 +G01 X-2.1068 Y0.6945 +G01 X-2.0969 Y0.6945 +G01 X-2.0895 Y0.6945 +G01 X-2.0831 Y0.6945 +G01 X-2.0512 Y0.6945 +G01 X-2.0403 Y0.7054 +G01 X-2.0206 Y0.7135 +G01 X-1.9994 Y0.7135 +G01 X-1.9797 Y0.7054 +G01 X-1.9688 Y0.6945 +G01 X-1.7827 Y0.6945 +G01 X-1.7697 Y0.7075 +G01 X-1.7303 Y0.7075 +G01 X-1.7025 Y0.6797 +G01 X-1.7025 Y0.6403 +G01 X-1.7303 Y0.6125 +G01 X-1.7697 Y0.6125 +G01 X-1.7827 Y0.6255 +G01 X-1.9688 Y0.6255 +G01 X-1.9797 Y0.6146 +G01 X-1.9994 Y0.6065 +G01 X-2.0206 Y0.6065 +G01 X-2.0403 Y0.6146 +G01 X-2.0512 Y0.6255 +G01 X-2.0831 Y0.6255 +G01 X-2.0895 Y0.6255 +G01 X-2.0900 Y0.6255 +G01 X-2.0930 Y0.6252 +G01 X-2.0986 Y0.6229 +G01 X-2.1029 Y0.6186 +G01 X-2.1052 Y0.6130 +G01 X-2.1055 Y0.6100 +G01 X-2.1055 Y0.2927 +G01 X-2.0925 Y0.2797 +G01 X-2.0925 Y0.2403 +G01 X-2.1203 Y0.2125 +G01 X-2.1597 Y0.2125 +G01 X-2.1875 Y0.2403 +G01 X-2.1875 Y0.2797 +G01 X-2.1745 Y0.2927 +G01 X-2.1745 Y0.6169 +G01 X-2.1745 Y0.6268 +G00 Z0.1000 +G00 X-3.1045 Y1.6168 +G01 Z-0.0070 F10 +G01 X-3.1045 Y1.6168 F20 +G01 X-3.0916 Y1.6479 +G01 X-3.0679 Y1.6716 +G01 X-3.0368 Y1.6845 +G01 X-3.0269 Y1.6845 +G01 X-3.0193 Y1.6845 +G01 X-3.0131 Y1.6845 +G01 X-2.9045 Y1.6845 +G01 X-2.9045 Y1.6853 +G01 X-2.9045 Y1.6869 +G01 X-2.9045 Y1.7769 +G01 X-2.9045 Y1.7868 +G01 X-2.8916 Y1.8179 +G01 X-2.8679 Y1.8416 +G01 X-2.8368 Y1.8545 +G01 X-2.8200 Y1.8545 +G01 X-2.8131 Y1.8545 +G01 X-2.7027 Y1.8545 +G01 X-2.6897 Y1.8675 +G01 X-2.6503 Y1.8675 +G01 X-2.6225 Y1.8397 +G01 X-2.6225 Y1.8003 +G01 X-2.6503 Y1.7725 +G01 X-2.6897 Y1.7725 +G01 X-2.7027 Y1.7855 +G01 X-2.8131 Y1.7855 +G01 X-2.8200 Y1.7855 +G01 X-2.8230 Y1.7852 +G01 X-2.8286 Y1.7829 +G01 X-2.8329 Y1.7786 +G01 X-2.8352 Y1.7730 +G01 X-2.8355 Y1.7700 +G01 X-2.8355 Y1.6869 +G01 X-2.8355 Y1.6853 +G01 X-2.8355 Y1.6731 +G01 X-2.8355 Y1.6672 +G01 X-2.8453 Y1.6435 +G01 X-2.8635 Y1.6253 +G01 X-2.8872 Y1.6155 +G01 X-2.8931 Y1.6155 +G01 X-3.0131 Y1.6155 +G01 X-3.0194 Y1.6155 +G01 X-3.0200 Y1.6155 +G01 X-3.0230 Y1.6152 +G01 X-3.0286 Y1.6129 +G01 X-3.0329 Y1.6086 +G01 X-3.0352 Y1.6030 +G01 X-3.0355 Y1.6000 +G01 X-3.0355 Y1.2900 +G01 X-3.0352 Y1.2870 +G01 X-3.0329 Y1.2814 +G01 X-3.0286 Y1.2771 +G01 X-3.0230 Y1.2748 +G01 X-3.0200 Y1.2745 +G01 X-3.0131 Y1.2745 +G01 X-2.7234 Y1.2745 +G01 X-2.7200 Y1.2752 +G01 X-2.7166 Y1.2745 +G01 X-2.7131 Y1.2745 +G01 X-2.7128 Y1.2744 +G01 X-2.6897 Y1.2975 +G01 X-2.6503 Y1.2975 +G01 X-2.6225 Y1.2697 +G01 X-2.6225 Y1.2303 +G01 X-2.6503 Y1.2025 +G01 X-2.6777 Y1.2025 +G01 X-2.6999 Y1.1981 +G01 X-2.7275 Y1.2035 +G01 X-2.7304 Y1.2055 +G01 X-3.0131 Y1.2055 +G01 X-3.0200 Y1.2055 +G01 X-3.0368 Y1.2055 +G01 X-3.0679 Y1.2184 +G01 X-3.0916 Y1.2421 +G01 X-3.1045 Y1.2732 +G01 X-3.1045 Y1.2831 +G01 X-3.1045 Y1.6069 +G01 X-3.1045 Y1.6168 +G00 Z0.1000 +G00 X-1.9255 Y1.4368 +G01 Z-0.0070 F10 +G01 X-1.9255 Y1.4368 F20 +G01 X-1.9255 Y1.4269 +G01 X-1.9255 Y1.3575 +G01 X-1.8935 Y1.3575 +G01 X-1.8761 Y1.3503 +G01 X-1.8627 Y1.3369 +G01 X-1.8555 Y1.3194 +G01 X-1.8555 Y1.3005 +G01 X-1.8627 Y1.2831 +G01 X-1.8761 Y1.2697 +G01 X-1.8935 Y1.2625 +G01 X-2.0264 Y1.2625 +G01 X-2.0439 Y1.2697 +G01 X-2.0573 Y1.2831 +G01 X-2.0645 Y1.3005 +G01 X-2.0645 Y1.3194 +G01 X-2.0573 Y1.3369 +G01 X-2.0439 Y1.3503 +G01 X-2.0264 Y1.3575 +G01 X-1.9945 Y1.3575 +G01 X-1.9945 Y1.4200 +G01 X-1.9947 Y1.4221 +G01 X-2.0078 Y1.4353 +G01 X-2.0100 Y1.4355 +G01 X-2.1719 Y1.4355 +G01 X-2.1887 Y1.4187 +G01 X-2.2313 Y1.4187 +G01 X-2.2371 Y1.4246 +G01 X-2.2480 Y1.4210 +G01 X-2.2480 Y1.4185 +G01 X-2.2785 Y1.3880 +G01 X-2.3215 Y1.3880 +G01 X-2.3520 Y1.4185 +G01 X-2.3520 Y1.4615 +G01 X-2.3215 Y1.4920 +G01 X-2.2785 Y1.4920 +G01 X-2.2721 Y1.4857 +G01 X-2.2613 Y1.4893 +G01 X-2.2613 Y1.4913 +G01 X-2.2313 Y1.5213 +G01 X-2.1887 Y1.5213 +G01 X-2.1719 Y1.5045 +G01 X-2.0081 Y1.5045 +G01 X-1.9913 Y1.5213 +G01 X-1.9487 Y1.5213 +G01 X-1.9187 Y1.4913 +G01 X-1.9187 Y1.4487 +G01 X-1.9270 Y1.4404 +G01 X-1.9255 Y1.4368 +G00 Z0.1000 +G00 X-2.6875 Y0.2403 +G01 Z-0.0070 F10 +G01 X-2.6875 Y0.2797 F20 +G01 X-2.6597 Y0.3075 +G01 X-2.6203 Y0.3075 +G01 X-2.6073 Y0.2945 +G01 X-2.5545 Y0.2945 +G01 X-2.5545 Y0.4319 +G01 X-2.5613 Y0.4387 +G01 X-2.5613 Y0.4813 +G01 X-2.5313 Y0.5113 +G01 X-2.4887 Y0.5113 +G01 X-2.4587 Y0.4813 +G01 X-2.4587 Y0.4387 +G01 X-2.4655 Y0.4319 +G01 X-2.4655 Y0.2689 +G01 X-2.4655 Y0.1900 +G01 X-2.4654 Y0.1891 +G01 X-2.4649 Y0.1875 +G01 X-2.4639 Y0.1861 +G01 X-2.4625 Y0.1851 +G01 X-2.4609 Y0.1846 +G01 X-2.4600 Y0.1845 +G01 X-2.4522 Y0.1845 +G01 X-2.4511 Y0.1845 +G01 X-1.8700 Y0.1845 +G01 X-1.8691 Y0.1846 +G01 X-1.8675 Y0.1851 +G01 X-1.8675 Y0.2197 +G01 X-1.8397 Y0.2475 +G01 X-1.8003 Y0.2475 +G01 X-1.7725 Y0.2197 +G01 X-1.7725 Y0.1803 +G01 X-1.7755 Y0.1773 +G01 X-1.7755 Y0.1750 +G01 X-1.7848 Y0.1466 +G01 X-1.8023 Y0.1224 +G01 X-1.8266 Y0.1048 +G01 X-1.8550 Y0.0955 +G01 X-1.8611 Y0.0955 +G01 X-2.4511 Y0.0955 +G01 X-2.4522 Y0.0955 +G01 X-2.4689 Y0.0955 +G01 X-2.4750 Y0.0955 +G01 X-2.5034 Y0.1048 +G01 X-2.5276 Y0.1223 +G01 X-2.5452 Y0.1466 +G01 X-2.5545 Y0.1750 +G01 X-2.5545 Y0.1811 +G01 X-2.5545 Y0.2255 +G01 X-2.6073 Y0.2255 +G01 X-2.6203 Y0.2125 +G01 X-2.6597 Y0.2125 +G01 X-2.6875 Y0.2403 +G00 Z0.1000 +G00 X-2.3264 Y1.0575 +G01 Z-0.0070 F10 +G01 X-2.1935 Y1.0575 F20 +G01 X-2.1761 Y1.0503 +G01 X-2.1627 Y1.0369 +G01 X-2.1555 Y1.0194 +G01 X-2.1555 Y1.0005 +G01 X-2.1627 Y0.9831 +G01 X-2.1761 Y0.9697 +G01 X-2.1935 Y0.9625 +G01 X-2.3264 Y0.9625 +G01 X-2.3439 Y0.9697 +G01 X-2.3497 Y0.9755 +G01 X-2.8931 Y0.9755 +G01 X-2.8939 Y0.9755 +G01 X-2.9069 Y0.9755 +G01 X-2.9168 Y0.9755 +G01 X-2.9479 Y0.9884 +G01 X-2.9716 Y1.0121 +G01 X-2.9845 Y1.0432 +G01 X-2.9845 Y1.0531 +G01 X-2.9845 Y1.0973 +G01 X-2.9975 Y1.1103 +G01 X-2.9975 Y1.1497 +G01 X-2.9697 Y1.1775 +G01 X-2.9303 Y1.1775 +G01 X-2.9025 Y1.1497 +G01 X-2.9025 Y1.1103 +G01 X-2.9155 Y1.0973 +G01 X-2.9155 Y1.0600 +G01 X-2.9152 Y1.0570 +G01 X-2.9129 Y1.0514 +G01 X-2.9086 Y1.0471 +G01 X-2.9030 Y1.0448 +G01 X-2.9000 Y1.0445 +G01 X-2.8939 Y1.0445 +G01 X-2.8931 Y1.0445 +G01 X-2.3497 Y1.0445 +G01 X-2.3439 Y1.0503 +G01 X-2.3264 Y1.0575 +G00 Z0.1000 +G00 X-1.5303 Y1.3554 +G01 Z-0.0070 F10 +G01 X-1.5106 Y1.3635 F20 +G01 X-1.4894 Y1.3635 +G01 X-1.4697 Y1.3554 +G01 X-1.4546 Y1.3403 +G01 X-1.4465 Y1.3206 +G01 X-1.4465 Y1.2994 +G01 X-1.4546 Y1.2797 +G01 X-1.4697 Y1.2646 +G01 X-1.4894 Y1.2565 +G01 X-1.5106 Y1.2565 +G01 X-1.5303 Y1.2646 +G01 X-1.5412 Y1.2755 +G01 X-1.5887 Y1.2755 +G01 X-1.5887 Y1.2487 +G01 X-1.6187 Y1.2187 +G01 X-1.6613 Y1.2187 +G01 X-1.6913 Y1.2487 +G01 X-1.6913 Y1.2755 +G01 X-1.7355 Y1.2755 +G01 X-1.7355 Y1.2327 +G01 X-1.7225 Y1.2197 +G01 X-1.7225 Y1.1803 +G01 X-1.7503 Y1.1525 +G01 X-1.7897 Y1.1525 +G01 X-1.8027 Y1.1655 +G01 X-1.8863 Y1.1655 +G01 X-1.8935 Y1.1625 +G01 X-2.0264 Y1.1625 +G01 X-2.0439 Y1.1697 +G01 X-2.0573 Y1.1831 +G01 X-2.0645 Y1.2005 +G01 X-2.0645 Y1.2194 +G01 X-2.0573 Y1.2369 +G01 X-2.0439 Y1.2503 +G01 X-2.0264 Y1.2575 +G01 X-1.8935 Y1.2575 +G01 X-1.8761 Y1.2503 +G01 X-1.8627 Y1.2369 +G01 X-1.8617 Y1.2345 +G01 X-1.8045 Y1.2345 +G01 X-1.8045 Y1.2755 +G01 X-1.8169 Y1.2755 +G01 X-1.8295 Y1.2808 +G01 X-1.8392 Y1.2905 +G01 X-1.8445 Y1.3031 +G01 X-1.8445 Y1.5331 +G01 X-1.8445 Y1.5400 +G01 X-1.8446 Y1.5411 +G01 X-1.8454 Y1.5431 +G01 X-1.8469 Y1.5446 +G01 X-1.8489 Y1.5454 +G01 X-1.8500 Y1.5455 +G01 X-1.8569 Y1.5455 +G01 X-2.3331 Y1.5455 +G01 X-2.3350 Y1.5455 +G01 X-2.3469 Y1.5455 +G01 X-2.3568 Y1.5455 +G01 X-2.3879 Y1.5584 +G01 X-2.4116 Y1.5821 +G01 X-2.4245 Y1.6132 +G01 X-2.4245 Y1.6231 +G01 X-2.4245 Y1.6323 +G01 X-2.4375 Y1.6453 +G01 X-2.4375 Y1.6847 +G01 X-2.4297 Y1.6925 +G01 X-2.4597 Y1.6925 +G01 X-2.4655 Y1.6983 +G01 X-2.4655 Y1.6031 +G01 X-2.4708 Y1.5905 +G01 X-2.4805 Y1.5808 +G01 X-2.4855 Y1.5787 +G01 X-2.4855 Y1.4469 +G01 X-2.4855 Y1.4331 +G01 X-2.4855 Y1.2600 +G01 X-2.4852 Y1.2570 +G01 X-2.4829 Y1.2514 +G01 X-2.4786 Y1.2471 +G01 X-2.4730 Y1.2448 +G01 X-2.4700 Y1.2445 +G01 X-2.4652 Y1.2445 +G01 X-2.4631 Y1.2445 +G01 X-2.3497 Y1.2445 +G01 X-2.3439 Y1.2503 +G01 X-2.3264 Y1.2575 +G01 X-2.1935 Y1.2575 +G01 X-2.1761 Y1.2503 +G01 X-2.1627 Y1.2369 +G01 X-2.1555 Y1.2194 +G01 X-2.1555 Y1.2005 +G01 X-2.1627 Y1.1831 +G01 X-2.1761 Y1.1697 +G01 X-2.1935 Y1.1625 +G01 X-2.2255 Y1.1625 +G01 X-2.2255 Y1.1575 +G01 X-2.1935 Y1.1575 +G01 X-2.1761 Y1.1503 +G01 X-2.1627 Y1.1369 +G01 X-2.1555 Y1.1194 +G01 X-2.1555 Y1.1005 +G01 X-2.1627 Y1.0831 +G01 X-2.1761 Y1.0697 +G01 X-2.1935 Y1.0625 +G01 X-2.3264 Y1.0625 +G01 X-2.3439 Y1.0697 +G01 X-2.3573 Y1.0831 +G01 X-2.3645 Y1.1005 +G01 X-2.3645 Y1.1194 +G01 X-2.3573 Y1.1369 +G01 X-2.3439 Y1.1503 +G01 X-2.3264 Y1.1575 +G01 X-2.2945 Y1.1575 +G01 X-2.2945 Y1.1625 +G01 X-2.3264 Y1.1625 +G01 X-2.3439 Y1.1697 +G01 X-2.3497 Y1.1755 +G01 X-2.4631 Y1.1755 +G01 X-2.4652 Y1.1755 +G01 X-2.4769 Y1.1755 +G01 X-2.4868 Y1.1755 +G01 X-2.5179 Y1.1884 +G01 X-2.5416 Y1.2121 +G01 X-2.5545 Y1.2432 +G01 X-2.5545 Y1.2531 +G01 X-2.5545 Y1.4055 +G01 X-2.8610 Y1.4055 +G01 X-2.8705 Y1.3959 +G01 X-2.8897 Y1.3880 +G01 X-2.9103 Y1.3880 +G01 X-2.9295 Y1.3959 +G01 X-2.9441 Y1.4105 +G01 X-2.9520 Y1.4297 +G01 X-2.9520 Y1.4503 +G01 X-2.9441 Y1.4695 +G01 X-2.9295 Y1.4841 +G01 X-2.9103 Y1.4920 +G01 X-2.8897 Y1.4920 +G01 X-2.8705 Y1.4841 +G01 X-2.8610 Y1.4745 +G01 X-2.5545 Y1.4745 +G01 X-2.5545 Y1.5755 +G01 X-2.6273 Y1.5755 +G01 X-2.6403 Y1.5625 +G01 X-2.6797 Y1.5625 +G01 X-2.7075 Y1.5903 +G01 X-2.7075 Y1.6297 +G01 X-2.6797 Y1.6575 +G01 X-2.6403 Y1.6575 +G01 X-2.6273 Y1.6445 +G01 X-2.5345 Y1.6445 +G01 X-2.5345 Y1.7031 +G01 X-2.5345 Y1.7042 +G01 X-2.5345 Y1.7169 +G01 X-2.5345 Y1.7228 +G01 X-2.5247 Y1.7465 +G01 X-2.5065 Y1.7647 +G01 X-2.4828 Y1.7745 +G01 X-2.4769 Y1.7745 +G01 X-2.4727 Y1.7745 +G01 X-2.4597 Y1.7875 +G01 X-2.4203 Y1.7875 +G01 X-2.3925 Y1.7597 +G01 X-2.3925 Y1.7203 +G01 X-2.4003 Y1.7125 +G01 X-2.3797 Y1.7125 +G01 X-2.3875 Y1.7203 +G01 X-2.3875 Y1.7597 +G01 X-2.3745 Y1.7727 +G01 X-2.3745 Y1.7800 +G01 X-2.3748 Y1.7830 +G01 X-2.3771 Y1.7886 +G01 X-2.3814 Y1.7929 +G01 X-2.3870 Y1.7952 +G01 X-2.3900 Y1.7955 +G01 X-2.5300 Y1.7955 +G01 X-2.5330 Y1.7952 +G01 X-2.5386 Y1.7929 +G01 X-2.5429 Y1.7886 +G01 X-2.5452 Y1.7830 +G01 X-2.5455 Y1.7800 +G01 X-2.5455 Y1.7769 +G01 X-2.5455 Y1.7736 +G01 X-2.5455 Y1.7631 +G01 X-2.5455 Y1.7532 +G01 X-2.5584 Y1.7221 +G01 X-2.5821 Y1.6984 +G01 X-2.6132 Y1.6855 +G01 X-2.6231 Y1.6855 +G01 X-2.6373 Y1.6855 +G01 X-2.6503 Y1.6725 +G01 X-2.6897 Y1.6725 +G01 X-2.7027 Y1.6855 +G01 X-2.7300 Y1.6855 +G01 X-2.7330 Y1.6852 +G01 X-2.7386 Y1.6829 +G01 X-2.7429 Y1.6786 +G01 X-2.7452 Y1.6730 +G01 X-2.7455 Y1.6700 +G01 X-2.7455 Y1.6647 +G01 X-2.7455 Y1.6631 +G01 X-2.7455 Y1.5931 +G01 X-2.7455 Y1.5852 +G01 X-2.7568 Y1.5578 +G01 X-2.7778 Y1.5368 +G01 X-2.8052 Y1.5255 +G01 X-2.8131 Y1.5255 +G01 X-2.8198 Y1.5255 +G01 X-2.8200 Y1.5255 +G01 X-2.8269 Y1.5255 +G01 X-2.9555 Y1.5255 +G01 X-2.9555 Y1.5231 +G01 X-2.9555 Y1.3775 +G01 X-2.9303 Y1.3775 +G01 X-2.9025 Y1.3497 +G01 X-2.9025 Y1.3103 +G01 X-2.9303 Y1.2825 +G01 X-2.9697 Y1.2825 +G01 X-2.9975 Y1.3103 +G01 X-2.9975 Y1.3121 +G01 X-3.0132 Y1.3278 +G01 X-3.0245 Y1.3552 +G01 X-3.0245 Y1.3631 +G01 X-3.0245 Y1.3662 +G01 X-3.0245 Y1.3700 +G01 X-3.0245 Y1.5231 +G01 X-3.0245 Y1.5300 +G01 X-3.0245 Y1.5301 +G01 X-3.0245 Y1.5369 +G01 X-3.0245 Y1.5428 +G01 X-3.0147 Y1.5665 +G01 X-2.9965 Y1.5847 +G01 X-2.9728 Y1.5945 +G01 X-2.9669 Y1.5945 +G01 X-2.8269 Y1.5945 +G01 X-2.8200 Y1.5945 +G01 X-2.8189 Y1.5946 +G01 X-2.8169 Y1.5954 +G01 X-2.8154 Y1.5969 +G01 X-2.8146 Y1.5989 +G01 X-2.8145 Y1.6000 +G01 X-2.8145 Y1.6631 +G01 X-2.8145 Y1.6647 +G01 X-2.8145 Y1.6769 +G01 X-2.8145 Y1.6868 +G01 X-2.8016 Y1.7179 +G01 X-2.7779 Y1.7416 +G01 X-2.7468 Y1.7545 +G01 X-2.7369 Y1.7545 +G01 X-2.7027 Y1.7545 +G01 X-2.6897 Y1.7675 +G01 X-2.6503 Y1.7675 +G01 X-2.6373 Y1.7545 +G01 X-2.6300 Y1.7545 +G01 X-2.6270 Y1.7548 +G01 X-2.6214 Y1.7571 +G01 X-2.6171 Y1.7614 +G01 X-2.6148 Y1.7670 +G01 X-2.6145 Y1.7700 +G01 X-2.6145 Y1.7736 +G01 X-2.6145 Y1.7769 +G01 X-2.6145 Y1.7869 +G01 X-2.6145 Y1.7968 +G01 X-2.6016 Y1.8279 +G01 X-2.5779 Y1.8516 +G01 X-2.5468 Y1.8645 +G01 X-2.5369 Y1.8645 +G01 X-2.3831 Y1.8645 +G01 X-2.3732 Y1.8645 +G01 X-2.3421 Y1.8516 +G01 X-2.3184 Y1.8279 +G01 X-2.3055 Y1.7968 +G01 X-2.3055 Y1.7869 +G01 X-2.3055 Y1.7745 +G01 X-2.2481 Y1.7745 +G01 X-2.2313 Y1.7913 +G01 X-2.1887 Y1.7913 +G01 X-2.1587 Y1.7613 +G01 X-2.1587 Y1.7187 +G01 X-2.1887 Y1.6887 +G01 X-2.2313 Y1.6887 +G01 X-2.2481 Y1.7055 +G01 X-2.3073 Y1.7055 +G01 X-2.3203 Y1.6925 +G01 X-2.3503 Y1.6925 +G01 X-2.3425 Y1.6847 +G01 X-2.3425 Y1.6453 +G01 X-2.3555 Y1.6323 +G01 X-2.3555 Y1.6300 +G01 X-2.3552 Y1.6270 +G01 X-2.3529 Y1.6214 +G01 X-2.3486 Y1.6171 +G01 X-2.3430 Y1.6148 +G01 X-2.3400 Y1.6145 +G01 X-2.3350 Y1.6145 +G01 X-2.3331 Y1.6145 +G01 X-1.8569 Y1.6145 +G01 X-1.8431 Y1.6145 +G01 X-1.8352 Y1.6145 +G01 X-1.8078 Y1.6031 +G01 X-1.7868 Y1.5822 +G01 X-1.7755 Y1.5548 +G01 X-1.7755 Y1.5469 +G01 X-1.7755 Y1.5401 +G01 X-1.7755 Y1.5331 +G01 X-1.7755 Y1.3445 +G01 X-1.7631 Y1.3445 +G01 X-1.6469 Y1.3445 +G01 X-1.6331 Y1.3445 +G01 X-1.5412 Y1.3445 +G01 X-1.5303 Y1.3554 +G00 Z0.1000 +G00 X-1.5535 Y1.6994 +G01 Z-0.0070 F10 +G01 X-1.5535 Y1.7206 F20 +G01 X-1.5454 Y1.7403 +G01 X-1.5345 Y1.7512 +G01 X-1.5345 Y1.8773 +G01 X-1.5475 Y1.8903 +G01 X-1.5475 Y1.9297 +G01 X-1.5197 Y1.9575 +G01 X-1.4803 Y1.9575 +G01 X-1.4525 Y1.9297 +G01 X-1.4525 Y1.8903 +G01 X-1.4655 Y1.8773 +G01 X-1.4655 Y1.7512 +G01 X-1.4546 Y1.7403 +G01 X-1.4465 Y1.7206 +G01 X-1.4465 Y1.7049 +G01 X-1.4451 Y1.7045 +G01 X-0.7769 Y1.7045 +G01 X-0.7700 Y1.7045 +G01 X-0.7532 Y1.7045 +G01 X-0.7221 Y1.6916 +G01 X-0.6984 Y1.6679 +G01 X-0.6855 Y1.6368 +G01 X-0.6855 Y1.6269 +G01 X-0.6855 Y1.5427 +G01 X-0.6725 Y1.5297 +G01 X-0.6725 Y1.4903 +G01 X-0.7003 Y1.4625 +G01 X-0.7397 Y1.4625 +G01 X-0.7675 Y1.4903 +G01 X-0.7675 Y1.5297 +G01 X-0.7545 Y1.5427 +G01 X-0.7545 Y1.6200 +G01 X-0.7548 Y1.6230 +G01 X-0.7571 Y1.6286 +G01 X-0.7614 Y1.6329 +G01 X-0.7670 Y1.6352 +G01 X-0.7700 Y1.6355 +G01 X-0.7769 Y1.6355 +G01 X-1.4481 Y1.6355 +G01 X-1.4620 Y1.6340 +G01 X-1.4924 Y1.6428 +G01 X-1.5096 Y1.6565 +G01 X-1.5106 Y1.6565 +G01 X-1.5303 Y1.6646 +G01 X-1.5454 Y1.6797 +G01 X-1.5535 Y1.6994 +G00 Z0.1000 +G00 X-1.4735 Y0.3294 +G01 Z-0.0070 F10 +G01 X-1.4735 Y0.3506 F20 +G01 X-1.4654 Y0.3703 +G01 X-1.4503 Y0.3854 +G01 X-1.4306 Y0.3935 +G01 X-1.4094 Y0.3935 +G01 X-1.3897 Y0.3854 +G01 X-1.3788 Y0.3745 +G01 X-1.3031 Y0.3745 +G01 X-0.8127 Y0.3745 +G01 X-0.7997 Y0.3875 +G01 X-0.7603 Y0.3875 +G01 X-0.7325 Y0.3597 +G01 X-0.7325 Y0.3203 +G01 X-0.7603 Y0.2925 +G01 X-0.7997 Y0.2925 +G01 X-0.8127 Y0.3055 +G01 X-1.2755 Y0.3055 +G01 X-1.2755 Y0.2227 +G01 X-1.2725 Y0.2197 +G01 X-1.2725 Y0.1803 +G01 X-1.3003 Y0.1525 +G01 X-1.3397 Y0.1525 +G01 X-1.3675 Y0.1803 +G01 X-1.3675 Y0.2197 +G01 X-1.3445 Y0.2427 +G01 X-1.3445 Y0.3055 +G01 X-1.3788 Y0.3055 +G01 X-1.3897 Y0.2946 +G01 X-1.4094 Y0.2865 +G01 X-1.4306 Y0.2865 +G01 X-1.4503 Y0.2946 +G01 X-1.4654 Y0.3097 +G01 X-1.4735 Y0.3294 +G00 Z0.1000 +G00 X-2.0635 Y0.2494 +G01 Z-0.0070 F10 +G01 X-2.0635 Y0.2706 F20 +G01 X-2.0554 Y0.2903 +G01 X-2.0445 Y0.3012 +G01 X-2.0445 Y0.3068 +G01 X-2.0316 Y0.3379 +G01 X-2.0079 Y0.3616 +G01 X-1.9768 Y0.3745 +G01 X-1.9669 Y0.3745 +G01 X-1.8612 Y0.3745 +G01 X-1.8545 Y0.3812 +G01 X-1.8545 Y0.4588 +G01 X-1.8612 Y0.4655 +G01 X-1.8668 Y0.4655 +G01 X-1.8979 Y0.4784 +G01 X-1.9216 Y0.5021 +G01 X-1.9336 Y0.5310 +G01 X-1.9513 Y0.5487 +G01 X-1.9513 Y0.5913 +G01 X-1.9213 Y0.6213 +G01 X-1.8787 Y0.6213 +G01 X-1.8487 Y0.5913 +G01 X-1.8487 Y0.5487 +G01 X-1.8595 Y0.5380 +G01 X-1.8586 Y0.5371 +G01 X-1.8503 Y0.5454 +G01 X-1.8306 Y0.5535 +G01 X-1.8094 Y0.5535 +G01 X-1.7897 Y0.5454 +G01 X-1.7746 Y0.5303 +G01 X-1.7665 Y0.5106 +G01 X-1.7665 Y0.4894 +G01 X-1.7746 Y0.4697 +G01 X-1.7855 Y0.4588 +G01 X-1.7855 Y0.3812 +G01 X-1.7746 Y0.3703 +G01 X-1.7665 Y0.3506 +G01 X-1.7665 Y0.3294 +G01 X-1.7746 Y0.3097 +G01 X-1.7897 Y0.2946 +G01 X-1.8094 Y0.2865 +G01 X-1.8306 Y0.2865 +G01 X-1.8503 Y0.2946 +G01 X-1.8612 Y0.3055 +G01 X-1.9600 Y0.3055 +G01 X-1.9630 Y0.3052 +G01 X-1.9686 Y0.3029 +G01 X-1.9729 Y0.2986 +G01 X-1.9646 Y0.2903 +G01 X-1.9565 Y0.2706 +G01 X-1.9565 Y0.2494 +G01 X-1.9646 Y0.2297 +G01 X-1.9797 Y0.2146 +G01 X-1.9994 Y0.2065 +G01 X-2.0206 Y0.2065 +G01 X-2.0403 Y0.2146 +G01 X-2.0554 Y0.2297 +G01 X-2.0635 Y0.2494 +G00 Z0.1000 +G00 X-3.2075 Y1.5903 +G01 Z-0.0070 F10 +G01 X-3.2075 Y1.6297 F20 +G01 X-3.1945 Y1.6427 +G01 X-3.1945 Y1.6969 +G01 X-3.1945 Y1.7068 +G01 X-3.1816 Y1.7379 +G01 X-3.1579 Y1.7616 +G01 X-3.1268 Y1.7745 +G01 X-3.1169 Y1.7745 +G01 X-2.9969 Y1.7745 +G01 X-2.9900 Y1.7745 +G01 X-2.9889 Y1.7746 +G01 X-2.9869 Y1.7754 +G01 X-2.9854 Y1.7769 +G01 X-2.9846 Y1.7789 +G01 X-2.9845 Y1.7800 +G01 X-2.9845 Y1.8531 +G01 X-2.9845 Y1.8549 +G01 X-2.9845 Y1.8669 +G01 X-2.9845 Y1.8768 +G01 X-2.9716 Y1.9079 +G01 X-2.9479 Y1.9316 +G01 X-2.9168 Y1.9445 +G01 X-2.9069 Y1.9445 +G01 X-2.0969 Y1.9445 +G01 X-2.0831 Y1.9445 +G01 X-2.0327 Y1.9445 +G01 X-2.0197 Y1.9575 +G01 X-1.9803 Y1.9575 +G01 X-1.9673 Y1.9445 +G01 X-1.7700 Y1.9445 +G01 X-1.7670 Y1.9448 +G01 X-1.7614 Y1.9471 +G01 X-1.7571 Y1.9514 +G01 X-1.7548 Y1.9570 +G01 X-1.7545 Y1.9600 +G01 X-1.7545 Y1.9654 +G01 X-1.7545 Y1.9669 +G01 X-1.7545 Y2.0669 +G01 X-1.7545 Y2.0768 +G01 X-1.7416 Y2.1079 +G01 X-1.7179 Y2.1316 +G01 X-1.6868 Y2.1445 +G01 X-1.6700 Y2.1445 +G01 X-1.6631 Y2.1445 +G01 X-1.2531 Y2.1445 +G01 X-1.2432 Y2.1445 +G01 X-1.2121 Y2.1316 +G01 X-1.1884 Y2.1079 +G01 X-1.1755 Y2.0768 +G01 X-1.1755 Y2.0600 +G01 X-1.1755 Y2.0531 +G01 X-1.1755 Y1.9169 +G01 X-1.1755 Y1.9100 +G01 X-1.1752 Y1.9070 +G01 X-1.1729 Y1.9014 +G01 X-1.1686 Y1.8971 +G01 X-1.1630 Y1.8948 +G01 X-1.1600 Y1.8945 +G01 X-1.1559 Y1.8945 +G01 X-1.1531 Y1.8945 +G01 X-0.7990 Y1.8945 +G01 X-0.7895 Y1.9041 +G01 X-0.7703 Y1.9120 +G01 X-0.7497 Y1.9120 +G01 X-0.7305 Y1.9041 +G01 X-0.7210 Y1.8945 +G01 X-0.2647 Y1.8945 +G01 X-0.2548 Y1.8945 +G01 X-0.2228 Y1.8841 +G01 X-0.1956 Y1.8644 +G01 X-0.1804 Y1.8434 +G01 X-0.1208 Y1.8434 +G01 X-0.1006 Y1.8350 +G01 X-0.0851 Y1.8196 +G01 X-0.0768 Y1.7994 +G01 X-0.0768 Y1.7775 +G01 X-0.0851 Y1.7573 +G01 X-0.1006 Y1.7418 +G01 X-0.1208 Y1.7334 +G01 X-0.2792 Y1.7334 +G01 X-0.2994 Y1.7418 +G01 X-0.3149 Y1.7573 +G01 X-0.3232 Y1.7775 +G01 X-0.3232 Y1.7994 +G01 X-0.3149 Y1.8196 +G01 X-0.3089 Y1.8255 +G01 X-0.7210 Y1.8255 +G01 X-0.7305 Y1.8159 +G01 X-0.7497 Y1.8080 +G01 X-0.7703 Y1.8080 +G01 X-0.7895 Y1.8159 +G01 X-0.7990 Y1.8255 +G01 X-1.1531 Y1.8255 +G01 X-1.1559 Y1.8255 +G01 X-1.1669 Y1.8255 +G01 X-1.1768 Y1.8255 +G01 X-1.2079 Y1.8384 +G01 X-1.2316 Y1.8621 +G01 X-1.2445 Y1.8932 +G01 X-1.2445 Y1.9100 +G01 X-1.2445 Y1.9169 +G01 X-1.2445 Y2.0531 +G01 X-1.2445 Y2.0600 +G01 X-1.2448 Y2.0630 +G01 X-1.2471 Y2.0686 +G01 X-1.2514 Y2.0729 +G01 X-1.2570 Y2.0752 +G01 X-1.2600 Y2.0755 +G01 X-1.6631 Y2.0755 +G01 X-1.6700 Y2.0755 +G01 X-1.6730 Y2.0752 +G01 X-1.6786 Y2.0729 +G01 X-1.6829 Y2.0686 +G01 X-1.6852 Y2.0630 +G01 X-1.6855 Y2.0600 +G01 X-1.6855 Y1.9669 +G01 X-1.6855 Y1.9654 +G01 X-1.6855 Y1.9531 +G01 X-1.6855 Y1.9432 +G01 X-1.6984 Y1.9121 +G01 X-1.7221 Y1.8884 +G01 X-1.7532 Y1.8755 +G01 X-1.7631 Y1.8755 +G01 X-1.9673 Y1.8755 +G01 X-1.9803 Y1.8625 +G01 X-2.0197 Y1.8625 +G01 X-2.0327 Y1.8755 +G01 X-2.0555 Y1.8755 +G01 X-2.0555 Y1.7500 +G01 X-2.0552 Y1.7470 +G01 X-2.0529 Y1.7414 +G01 X-2.0486 Y1.7371 +G01 X-2.0430 Y1.7348 +G01 X-2.0400 Y1.7345 +G01 X-2.0343 Y1.7345 +G01 X-2.0331 Y1.7345 +G01 X-1.8027 Y1.7345 +G01 X-1.7897 Y1.7475 +G01 X-1.7503 Y1.7475 +G01 X-1.7373 Y1.7345 +G01 X-1.7331 Y1.7345 +G01 X-1.7272 Y1.7345 +G01 X-1.7035 Y1.7247 +G01 X-1.6853 Y1.7065 +G01 X-1.6755 Y1.6828 +G01 X-1.6755 Y1.6769 +G01 X-1.6755 Y1.5100 +G01 X-1.6752 Y1.5070 +G01 X-1.6729 Y1.5014 +G01 X-1.6686 Y1.4971 +G01 X-1.6630 Y1.4948 +G01 X-1.6600 Y1.4945 +G01 X-1.6573 Y1.4945 +G01 X-1.6531 Y1.4945 +G01 X-1.4669 Y1.4945 +G01 X-1.4600 Y1.4945 +G01 X-1.4432 Y1.4945 +G01 X-1.4121 Y1.4816 +G01 X-1.3884 Y1.4579 +G01 X-1.3819 Y1.4424 +G01 X-1.3768 Y1.4445 +G01 X-1.3669 Y1.4445 +G01 X-1.3595 Y1.4445 +G01 X-1.3531 Y1.4445 +G01 X-1.3397 Y1.4445 +G01 X-1.3339 Y1.4503 +G01 X-1.3164 Y1.4575 +G01 X-1.1835 Y1.4575 +G01 X-1.1661 Y1.4503 +G01 X-1.1527 Y1.4369 +G01 X-1.1455 Y1.4194 +G01 X-1.1455 Y1.4005 +G01 X-1.1527 Y1.3831 +G01 X-1.1661 Y1.3697 +G01 X-1.1835 Y1.3625 +G01 X-1.3164 Y1.3625 +G01 X-1.3339 Y1.3697 +G01 X-1.3397 Y1.3755 +G01 X-1.3531 Y1.3755 +G01 X-1.3595 Y1.3755 +G01 X-1.3600 Y1.3755 +G01 X-1.3630 Y1.3752 +G01 X-1.3686 Y1.3729 +G01 X-1.3729 Y1.3686 +G01 X-1.3752 Y1.3630 +G01 X-1.3755 Y1.3600 +G01 X-1.3755 Y1.2531 +G01 X-1.3755 Y1.2438 +G01 X-1.3755 Y1.2339 +G01 X-1.3825 Y1.2170 +G01 X-1.3825 Y1.1903 +G01 X-1.4103 Y1.1625 +G01 X-1.4497 Y1.1625 +G01 X-1.4775 Y1.1903 +G01 X-1.4775 Y1.2297 +G01 X-1.4497 Y1.2575 +G01 X-1.4445 Y1.2575 +G01 X-1.4445 Y1.4100 +G01 X-1.4448 Y1.4130 +G01 X-1.4471 Y1.4186 +G01 X-1.4514 Y1.4229 +G01 X-1.4570 Y1.4252 +G01 X-1.4600 Y1.4255 +G01 X-1.4669 Y1.4255 +G01 X-1.6531 Y1.4255 +G01 X-1.6573 Y1.4255 +G01 X-1.6669 Y1.4255 +G01 X-1.6768 Y1.4255 +G01 X-1.7079 Y1.4384 +G01 X-1.7316 Y1.4621 +G01 X-1.7445 Y1.4932 +G01 X-1.7445 Y1.5031 +G01 X-1.7445 Y1.6583 +G01 X-1.7503 Y1.6525 +G01 X-1.7897 Y1.6525 +G01 X-1.8027 Y1.6655 +G01 X-2.0331 Y1.6655 +G01 X-2.0344 Y1.6655 +G01 X-2.0469 Y1.6655 +G01 X-2.0568 Y1.6655 +G01 X-2.0879 Y1.6784 +G01 X-2.1116 Y1.7021 +G01 X-2.1245 Y1.7332 +G01 X-2.1245 Y1.7431 +G01 X-2.1245 Y1.8755 +G01 X-2.9000 Y1.8755 +G01 X-2.9030 Y1.8752 +G01 X-2.9086 Y1.8729 +G01 X-2.9129 Y1.8686 +G01 X-2.9152 Y1.8630 +G01 X-2.9155 Y1.8600 +G01 X-2.9155 Y1.8548 +G01 X-2.9155 Y1.8531 +G01 X-2.9155 Y1.7731 +G01 X-2.9155 Y1.7652 +G01 X-2.9268 Y1.7378 +G01 X-2.9478 Y1.7168 +G01 X-2.9752 Y1.7055 +G01 X-2.9831 Y1.7055 +G01 X-2.9897 Y1.7055 +G01 X-2.9900 Y1.7055 +G01 X-2.9969 Y1.7055 +G01 X-3.1100 Y1.7055 +G01 X-3.1130 Y1.7052 +G01 X-3.1186 Y1.7029 +G01 X-3.1229 Y1.6986 +G01 X-3.1252 Y1.6930 +G01 X-3.1255 Y1.6900 +G01 X-3.1255 Y1.6427 +G01 X-3.1125 Y1.6297 +G01 X-3.1125 Y1.5903 +G01 X-3.1255 Y1.5773 +G01 X-3.1255 Y0.9600 +G01 X-3.1252 Y0.9570 +G01 X-3.1229 Y0.9514 +G01 X-3.1186 Y0.9471 +G01 X-3.1130 Y0.9448 +G01 X-3.1100 Y0.9445 +G01 X-3.1047 Y0.9445 +G01 X-3.1031 Y0.9445 +G01 X-2.5481 Y0.9445 +G01 X-2.5313 Y0.9613 +G01 X-2.4887 Y0.9613 +G01 X-2.4719 Y0.9445 +G01 X-2.1669 Y0.9445 +G01 X-2.1600 Y0.9445 +G01 X-2.1570 Y0.9448 +G01 X-2.1514 Y0.9471 +G01 X-2.1471 Y0.9514 +G01 X-2.1448 Y0.9570 +G01 X-2.1445 Y0.9600 +G01 X-2.1445 Y1.0669 +G01 X-2.1445 Y1.2755 +G01 X-2.1703 Y1.2755 +G01 X-2.1761 Y1.2697 +G01 X-2.1935 Y1.2625 +G01 X-2.3264 Y1.2625 +G01 X-2.3439 Y1.2697 +G01 X-2.3573 Y1.2831 +G01 X-2.3645 Y1.3005 +G01 X-2.3645 Y1.3194 +G01 X-2.3573 Y1.3369 +G01 X-2.3439 Y1.3503 +G01 X-2.3264 Y1.3575 +G01 X-2.1935 Y1.3575 +G01 X-2.1761 Y1.3503 +G01 X-2.1703 Y1.3445 +G01 X-2.1231 Y1.3445 +G01 X-2.1192 Y1.3445 +G01 X-2.0991 Y1.3362 +G01 X-2.0838 Y1.3209 +G01 X-2.0755 Y1.3008 +G01 X-2.0755 Y1.2969 +G01 X-2.0755 Y1.2831 +G01 X-2.0755 Y1.0669 +G01 X-2.0755 Y1.0543 +G01 X-2.0657 Y1.0445 +G01 X-2.0497 Y1.0445 +G01 X-2.0439 Y1.0503 +G01 X-2.0264 Y1.0575 +G01 X-1.8935 Y1.0575 +G01 X-1.8761 Y1.0503 +G01 X-1.8627 Y1.0369 +G01 X-1.8555 Y1.0194 +G01 X-1.8555 Y1.0005 +G01 X-1.8627 Y0.9831 +G01 X-1.8761 Y0.9697 +G01 X-1.8935 Y0.9625 +G01 X-2.0264 Y0.9625 +G01 X-2.0439 Y0.9697 +G01 X-2.0497 Y0.9755 +G01 X-2.0731 Y0.9755 +G01 X-2.0755 Y0.9755 +G01 X-2.0755 Y0.9531 +G01 X-2.0755 Y0.9432 +G01 X-2.0884 Y0.9121 +G01 X-2.1121 Y0.8884 +G01 X-2.1432 Y0.8755 +G01 X-2.1600 Y0.8755 +G01 X-2.1669 Y0.8755 +G01 X-2.4719 Y0.8755 +G01 X-2.4887 Y0.8587 +G01 X-2.5313 Y0.8587 +G01 X-2.5481 Y0.8755 +G01 X-3.1031 Y0.8755 +G01 X-3.1047 Y0.8755 +G01 X-3.1169 Y0.8755 +G01 X-3.1268 Y0.8755 +G01 X-3.1579 Y0.8884 +G01 X-3.1816 Y0.9121 +G01 X-3.1945 Y0.9432 +G01 X-3.1945 Y0.9531 +G01 X-3.1945 Y1.5773 +G01 X-3.2075 Y1.5903 +G00 Z0.1000 +G00 X-1.3164 Y0.8575 +G01 Z-0.0070 F10 +G01 X-1.1835 Y0.8575 F20 +G01 X-1.1661 Y0.8503 +G01 X-1.1527 Y0.8369 +G01 X-1.1455 Y0.8194 +G01 X-1.1455 Y0.8005 +G01 X-1.1527 Y0.7831 +G01 X-1.1661 Y0.7697 +G01 X-1.1835 Y0.7625 +G01 X-1.3164 Y0.7625 +G01 X-1.3339 Y0.7697 +G01 X-1.3397 Y0.7755 +G01 X-1.5000 Y0.7755 +G01 X-1.5030 Y0.7752 +G01 X-1.5086 Y0.7729 +G01 X-1.5129 Y0.7686 +G01 X-1.5152 Y0.7630 +G01 X-1.5155 Y0.7600 +G01 X-1.5155 Y0.7544 +G01 X-1.5155 Y0.7531 +G01 X-1.5155 Y0.6927 +G01 X-1.5025 Y0.6797 +G01 X-1.5025 Y0.6403 +G01 X-1.5303 Y0.6125 +G01 X-1.5697 Y0.6125 +G01 X-1.5975 Y0.6403 +G01 X-1.5975 Y0.6797 +G01 X-1.5845 Y0.6927 +G01 X-1.5845 Y0.7531 +G01 X-1.5845 Y0.7544 +G01 X-1.5845 Y0.7669 +G01 X-1.5845 Y0.7768 +G01 X-1.5716 Y0.8079 +G01 X-1.5479 Y0.8316 +G01 X-1.5168 Y0.8445 +G01 X-1.5069 Y0.8445 +G01 X-1.3397 Y0.8445 +G01 X-1.3339 Y0.8503 +G01 X-1.3164 Y0.8575 +G00 Z0.1000 +G00 X-1.0164 Y1.2575 +G01 Z-0.0070 F10 +G01 X-0.8835 Y1.2575 F20 +G01 X-0.8661 Y1.2503 +G01 X-0.8603 Y1.2445 +G01 X-0.4469 Y1.2445 +G01 X-0.4400 Y1.2445 +G01 X-0.4367 Y1.2445 +G01 X-0.4331 Y1.2445 +G01 X-0.4252 Y1.2445 +G01 X-0.3978 Y1.2332 +G01 X-0.3768 Y1.2122 +G01 X-0.3655 Y1.1848 +G01 X-0.3655 Y1.1769 +G01 X-0.3655 Y1.1616 +G01 X-0.3652 Y1.1586 +G01 X-0.3629 Y1.1530 +G01 X-0.3586 Y1.1487 +G01 X-0.3530 Y1.1464 +G01 X-0.3500 Y1.1461 +G01 X-0.3443 Y1.1461 +G01 X-0.3431 Y1.1461 +G01 X-0.3115 Y1.1461 +G01 X-0.2994 Y1.1582 +G01 X-0.2792 Y1.1666 +G01 X-0.1208 Y1.1666 +G01 X-0.1006 Y1.1582 +G01 X-0.0851 Y1.1427 +G01 X-0.0768 Y1.1225 +G01 X-0.0768 Y1.1006 +G01 X-0.0851 Y1.0804 +G01 X-0.1006 Y1.0649 +G01 X-0.1208 Y1.0566 +G01 X-0.2792 Y1.0566 +G01 X-0.2994 Y1.0649 +G01 X-0.3115 Y1.0771 +G01 X-0.3431 Y1.0771 +G01 X-0.3444 Y1.0771 +G01 X-0.3569 Y1.0771 +G01 X-0.3668 Y1.0771 +G01 X-0.3979 Y1.0899 +G01 X-0.4216 Y1.1137 +G01 X-0.4345 Y1.1448 +G01 X-0.4345 Y1.1547 +G01 X-0.4345 Y1.1700 +G01 X-0.4346 Y1.1711 +G01 X-0.4354 Y1.1731 +G01 X-0.4369 Y1.1746 +G01 X-0.4389 Y1.1754 +G01 X-0.4400 Y1.1755 +G01 X-0.4469 Y1.1755 +G01 X-0.8603 Y1.1755 +G01 X-0.8661 Y1.1697 +G01 X-0.8835 Y1.1625 +G01 X-1.0164 Y1.1625 +G01 X-1.0339 Y1.1697 +G01 X-1.0473 Y1.1831 +G01 X-1.0545 Y1.2005 +G01 X-1.0545 Y1.2194 +G01 X-1.0473 Y1.2369 +G01 X-1.0339 Y1.2503 +G01 X-1.0164 Y1.2575 +G00 Z0.1000 +G00 X-1.0164 Y1.1575 +G01 Z-0.0070 F10 +G01 X-0.8835 Y1.1575 F20 +G01 X-0.8661 Y1.1503 +G01 X-0.8603 Y1.1445 +G01 X-0.5927 Y1.1445 +G01 X-0.5797 Y1.1575 +G01 X-0.5403 Y1.1575 +G01 X-0.5125 Y1.1297 +G01 X-0.5125 Y1.0903 +G01 X-0.5403 Y1.0625 +G01 X-0.5797 Y1.0625 +G01 X-0.5927 Y1.0755 +G01 X-0.8603 Y1.0755 +G01 X-0.8661 Y1.0697 +G01 X-0.8835 Y1.0625 +G01 X-1.0164 Y1.0625 +G01 X-1.0339 Y1.0697 +G01 X-1.0473 Y1.0831 +G01 X-1.0545 Y1.1005 +G01 X-1.0545 Y1.1194 +G01 X-1.0473 Y1.1369 +G01 X-1.0339 Y1.1503 +G01 X-1.0164 Y1.1575 +G00 Z0.1000 +G00 X-1.0164 Y1.0575 +G01 Z-0.0070 F10 +G01 X-0.8835 Y1.0575 F20 +G01 X-0.8661 Y1.0503 +G01 X-0.8603 Y1.0445 +G01 X-0.4869 Y1.0445 +G01 X-0.4809 Y1.0445 +G01 X-0.4800 Y1.0445 +G01 X-0.4632 Y1.0445 +G01 X-0.4321 Y1.0316 +G01 X-0.4084 Y1.0079 +G01 X-0.3955 Y0.9768 +G01 X-0.3955 Y0.9669 +G01 X-0.3955 Y0.9569 +G01 X-0.3955 Y0.9500 +G01 X-0.3954 Y0.9489 +G01 X-0.3946 Y0.9469 +G01 X-0.3931 Y0.9454 +G01 X-0.3911 Y0.9446 +G01 X-0.3900 Y0.9445 +G01 X-0.3100 Y0.9445 +G01 X-0.2994 Y0.9550 +G01 X-0.2792 Y0.9634 +G01 X-0.1208 Y0.9634 +G01 X-0.1006 Y0.9550 +G01 X-0.0851 Y0.9396 +G01 X-0.0768 Y0.9194 +G01 X-0.0768 Y0.8975 +G01 X-0.0851 Y0.8773 +G01 X-0.1006 Y0.8618 +G01 X-0.1208 Y0.8534 +G01 X-0.2792 Y0.8534 +G01 X-0.2994 Y0.8618 +G01 X-0.3131 Y0.8755 +G01 X-0.3969 Y0.8755 +G01 X-0.4048 Y0.8755 +G01 X-0.4322 Y0.8868 +G01 X-0.4532 Y0.9078 +G01 X-0.4645 Y0.9352 +G01 X-0.4645 Y0.9431 +G01 X-0.4645 Y0.9497 +G01 X-0.4645 Y0.9500 +G01 X-0.4645 Y0.9569 +G01 X-0.4645 Y0.9600 +G01 X-0.4648 Y0.9630 +G01 X-0.4671 Y0.9686 +G01 X-0.4714 Y0.9729 +G01 X-0.4770 Y0.9752 +G01 X-0.4800 Y0.9755 +G01 X-0.4810 Y0.9755 +G01 X-0.4869 Y0.9755 +G01 X-0.8603 Y0.9755 +G01 X-0.8661 Y0.9697 +G01 X-0.8835 Y0.9625 +G01 X-1.0164 Y0.9625 +G01 X-1.0339 Y0.9697 +G01 X-1.0473 Y0.9831 +G01 X-1.0545 Y1.0005 +G01 X-1.0545 Y1.0194 +G01 X-1.0473 Y1.0369 +G01 X-1.0339 Y1.0503 +G01 X-1.0164 Y1.0575 +G00 Z0.1000 +G00 X-1.3164 Y1.2575 +G01 Z-0.0070 F10 +G01 X-1.1835 Y1.2575 F20 +G01 X-1.1661 Y1.2503 +G01 X-1.1527 Y1.2369 +G01 X-1.1455 Y1.2194 +G01 X-1.1455 Y1.2005 +G01 X-1.1527 Y1.1831 +G01 X-1.1661 Y1.1697 +G01 X-1.1835 Y1.1625 +G01 X-1.3164 Y1.1625 +G01 X-1.3339 Y1.1697 +G01 X-1.3473 Y1.1831 +G01 X-1.3545 Y1.2005 +G01 X-1.3545 Y1.2194 +G01 X-1.3473 Y1.2369 +G01 X-1.3339 Y1.2503 +G01 X-1.3164 Y1.2575 +G00 Z0.1000 +G00 X-1.3164 Y1.3575 +G01 Z-0.0070 F10 +G01 X-1.1835 Y1.3575 F20 +G01 X-1.1661 Y1.3503 +G01 X-1.1527 Y1.3369 +G01 X-1.1455 Y1.3194 +G01 X-1.1455 Y1.3005 +G01 X-1.1527 Y1.2831 +G01 X-1.1661 Y1.2697 +G01 X-1.1835 Y1.2625 +G01 X-1.3164 Y1.2625 +G01 X-1.3339 Y1.2697 +G01 X-1.3473 Y1.2831 +G01 X-1.3545 Y1.3005 +G01 X-1.3545 Y1.3194 +G01 X-1.3473 Y1.3369 +G01 X-1.3339 Y1.3503 +G01 X-1.3164 Y1.3575 +G00 Z0.1000 +G00 X-0.7397 Y1.3575 +G01 Z-0.0070 F10 +G01 X-0.7003 Y1.3575 F20 +G01 X-0.6725 Y1.3297 +G01 X-0.6725 Y1.2903 +G01 X-0.7003 Y1.2625 +G01 X-0.7397 Y1.2625 +G01 X-0.7527 Y1.2755 +G01 X-0.8603 Y1.2755 +G01 X-0.8661 Y1.2697 +G01 X-0.8835 Y1.2625 +G01 X-1.0164 Y1.2625 +G01 X-1.0339 Y1.2697 +G01 X-1.0473 Y1.2831 +G01 X-1.0545 Y1.3005 +G01 X-1.0545 Y1.3194 +G01 X-1.0473 Y1.3369 +G01 X-1.0339 Y1.3503 +G01 X-1.0164 Y1.3575 +G01 X-0.8835 Y1.3575 +G01 X-0.8661 Y1.3503 +G01 X-0.8603 Y1.3445 +G01 X-0.7527 Y1.3445 +G01 X-0.7397 Y1.3575 +G00 Z0.1000 +G00 X-0.8275 Y0.5203 +G01 Z-0.0070 F10 +G01 X-0.8275 Y0.5597 F20 +G01 X-0.8145 Y0.5727 +G01 X-0.8145 Y0.8600 +G01 X-0.8148 Y0.8630 +G01 X-0.8171 Y0.8686 +G01 X-0.8214 Y0.8729 +G01 X-0.8270 Y0.8752 +G01 X-0.8300 Y0.8755 +G01 X-0.8348 Y0.8755 +G01 X-0.8369 Y0.8755 +G01 X-0.8603 Y0.8755 +G01 X-0.8661 Y0.8697 +G01 X-0.8835 Y0.8625 +G01 X-1.0164 Y0.8625 +G01 X-1.0339 Y0.8697 +G01 X-1.0473 Y0.8831 +G01 X-1.0545 Y0.9005 +G01 X-1.0545 Y0.9194 +G01 X-1.0473 Y0.9369 +G01 X-1.0339 Y0.9503 +G01 X-1.0164 Y0.9575 +G01 X-0.8835 Y0.9575 +G01 X-0.8661 Y0.9503 +G01 X-0.8603 Y0.9445 +G01 X-0.8369 Y0.9445 +G01 X-0.8348 Y0.9445 +G01 X-0.8231 Y0.9445 +G01 X-0.8132 Y0.9445 +G01 X-0.7821 Y0.9316 +G01 X-0.7584 Y0.9079 +G01 X-0.7455 Y0.8768 +G01 X-0.7455 Y0.8669 +G01 X-0.7455 Y0.5727 +G01 X-0.7325 Y0.5597 +G01 X-0.7325 Y0.5203 +G01 X-0.7603 Y0.4925 +G01 X-0.7997 Y0.4925 +G01 X-0.8275 Y0.5203 +G00 Z0.1000 +G00 X-0.5868 Y1.5655 +G01 Z-0.0070 F10 +G01 X-0.5868 Y1.5655 F20 +G01 X-0.6179 Y1.5784 +G01 X-0.6416 Y1.6021 +G01 X-0.6545 Y1.6332 +G01 X-0.6545 Y1.6431 +G01 X-0.6545 Y1.6500 +G01 X-0.6545 Y1.6569 +G01 X-0.6545 Y1.7200 +G01 X-0.6546 Y1.7211 +G01 X-0.6554 Y1.7231 +G01 X-0.6569 Y1.7246 +G01 X-0.6589 Y1.7254 +G01 X-0.6600 Y1.7255 +G01 X-1.3031 Y1.7255 +G01 X-1.3045 Y1.7255 +G01 X-1.3169 Y1.7255 +G01 X-1.3268 Y1.7255 +G01 X-1.3579 Y1.7384 +G01 X-1.3816 Y1.7621 +G01 X-1.3945 Y1.7932 +G01 X-1.3945 Y1.8031 +G01 X-1.3945 Y1.8210 +G01 X-1.4120 Y1.8385 +G01 X-1.4120 Y1.8815 +G01 X-1.3945 Y1.8990 +G01 X-1.3945 Y1.9531 +G01 X-1.3945 Y1.9588 +G01 X-1.3945 Y1.9600 +G01 X-1.3948 Y1.9630 +G01 X-1.3971 Y1.9686 +G01 X-1.4014 Y1.9729 +G01 X-1.4070 Y1.9752 +G01 X-1.4100 Y1.9755 +G01 X-1.4169 Y1.9755 +G01 X-1.5631 Y1.9755 +G01 X-1.5700 Y1.9755 +G01 X-1.5730 Y1.9752 +G01 X-1.5786 Y1.9729 +G01 X-1.5829 Y1.9686 +G01 X-1.5852 Y1.9630 +G01 X-1.5855 Y1.9600 +G01 X-1.5855 Y1.7969 +G01 X-1.5855 Y1.7731 +G01 X-1.5855 Y1.6369 +G01 X-1.5855 Y1.6300 +G01 X-1.5852 Y1.6270 +G01 X-1.5829 Y1.6214 +G01 X-1.5786 Y1.6171 +G01 X-1.5730 Y1.6148 +G01 X-1.5700 Y1.6145 +G01 X-1.5692 Y1.6145 +G01 X-1.5631 Y1.6145 +G01 X-1.1431 Y1.6145 +G01 X-1.1332 Y1.6145 +G01 X-1.1021 Y1.6016 +G01 X-1.0784 Y1.5779 +G01 X-1.0655 Y1.5468 +G01 X-1.0655 Y1.5300 +G01 X-1.0655 Y1.5231 +G01 X-1.0655 Y0.8600 +G01 X-1.0652 Y0.8570 +G01 X-1.0629 Y0.8514 +G01 X-1.0586 Y0.8471 +G01 X-1.0530 Y0.8448 +G01 X-1.0500 Y0.8445 +G01 X-1.0439 Y0.8445 +G01 X-1.0431 Y0.8445 +G01 X-1.0397 Y0.8445 +G01 X-1.0339 Y0.8503 +G01 X-1.0164 Y0.8575 +G01 X-0.8835 Y0.8575 +G01 X-0.8661 Y0.8503 +G01 X-0.8527 Y0.8369 +G01 X-0.8455 Y0.8194 +G01 X-0.8455 Y0.8005 +G01 X-0.8527 Y0.7831 +G01 X-0.8661 Y0.7697 +G01 X-0.8835 Y0.7625 +G01 X-1.0164 Y0.7625 +G01 X-1.0339 Y0.7697 +G01 X-1.0397 Y0.7755 +G01 X-1.0431 Y0.7755 +G01 X-1.0439 Y0.7755 +G01 X-1.0569 Y0.7755 +G01 X-1.0668 Y0.7755 +G01 X-1.0979 Y0.7884 +G01 X-1.1216 Y0.8121 +G01 X-1.1345 Y0.8432 +G01 X-1.1345 Y0.8531 +G01 X-1.1345 Y1.5231 +G01 X-1.1345 Y1.5300 +G01 X-1.1348 Y1.5330 +G01 X-1.1371 Y1.5386 +G01 X-1.1414 Y1.5429 +G01 X-1.1470 Y1.5452 +G01 X-1.1500 Y1.5455 +G01 X-1.5631 Y1.5455 +G01 X-1.5693 Y1.5455 +G01 X-1.5769 Y1.5455 +G01 X-1.5868 Y1.5455 +G01 X-1.6179 Y1.5584 +G01 X-1.6416 Y1.5821 +G01 X-1.6545 Y1.6132 +G01 X-1.6545 Y1.6231 +G01 X-1.6545 Y1.6271 +G01 X-1.6545 Y1.6300 +G01 X-1.6545 Y1.6369 +G01 X-1.6545 Y1.7555 +G01 X-1.9319 Y1.7555 +G01 X-1.9487 Y1.7387 +G01 X-1.9913 Y1.7387 +G01 X-2.0213 Y1.7687 +G01 X-2.0213 Y1.8113 +G01 X-1.9913 Y1.8413 +G01 X-1.9487 Y1.8413 +G01 X-1.9319 Y1.8245 +G01 X-1.6545 Y1.8245 +G01 X-1.6545 Y1.9669 +G01 X-1.6545 Y1.9768 +G01 X-1.6416 Y2.0079 +G01 X-1.6179 Y2.0316 +G01 X-1.5868 Y2.0445 +G01 X-1.5700 Y2.0445 +G01 X-1.5631 Y2.0445 +G01 X-1.4169 Y2.0445 +G01 X-1.4100 Y2.0445 +G01 X-1.3932 Y2.0445 +G01 X-1.3621 Y2.0316 +G01 X-1.3384 Y2.0079 +G01 X-1.3255 Y1.9768 +G01 X-1.3255 Y1.9669 +G01 X-1.3255 Y1.9588 +G01 X-1.3255 Y1.9531 +G01 X-1.3255 Y1.8990 +G01 X-1.3080 Y1.8815 +G01 X-1.3080 Y1.8385 +G01 X-1.3255 Y1.8210 +G01 X-1.3255 Y1.8100 +G01 X-1.3252 Y1.8070 +G01 X-1.3229 Y1.8014 +G01 X-1.3186 Y1.7971 +G01 X-1.3130 Y1.7948 +G01 X-1.3100 Y1.7945 +G01 X-1.3045 Y1.7945 +G01 X-1.3031 Y1.7945 +G01 X-0.6531 Y1.7945 +G01 X-0.6452 Y1.7945 +G01 X-0.6178 Y1.7832 +G01 X-0.5968 Y1.7622 +G01 X-0.5855 Y1.7348 +G01 X-0.5855 Y1.7269 +G01 X-0.5855 Y1.6569 +G01 X-0.5855 Y1.6500 +G01 X-0.5852 Y1.6470 +G01 X-0.5829 Y1.6414 +G01 X-0.5786 Y1.6371 +G01 X-0.5730 Y1.6348 +G01 X-0.5700 Y1.6345 +G01 X-0.3031 Y1.6345 +G01 X-0.2994 Y1.6382 +G01 X-0.2792 Y1.6466 +G01 X-0.1208 Y1.6466 +G01 X-0.1006 Y1.6382 +G01 X-0.0851 Y1.6227 +G01 X-0.0768 Y1.6025 +G01 X-0.0768 Y1.5806 +G01 X-0.0851 Y1.5604 +G01 X-0.1006 Y1.5449 +G01 X-0.1208 Y1.5366 +G01 X-0.2792 Y1.5366 +G01 X-0.2994 Y1.5449 +G01 X-0.3149 Y1.5604 +G01 X-0.3170 Y1.5655 +G01 X-0.5769 Y1.5655 +G01 X-0.5868 Y1.5655 +G00 Z0.1000 +G00 X-0.5255 Y0.4732 +G01 Z-0.0070 F10 +G01 X-0.5255 Y0.4732 F20 +G01 X-0.5384 Y0.4421 +G01 X-0.5621 Y0.4184 +G01 X-0.5932 Y0.4055 +G01 X-0.6031 Y0.4055 +G01 X-0.6100 Y0.4055 +G01 X-0.6169 Y0.4055 +G01 X-1.3769 Y0.4055 +G01 X-1.3868 Y0.4055 +G01 X-1.4179 Y0.4184 +G01 X-1.4416 Y0.4421 +G01 X-1.4461 Y0.4529 +G01 X-1.4503 Y0.4546 +G01 X-1.4654 Y0.4697 +G01 X-1.4735 Y0.4894 +G01 X-1.4735 Y0.5106 +G01 X-1.4654 Y0.5303 +G01 X-1.4645 Y0.5312 +G01 X-1.4645 Y0.6773 +G01 X-1.4775 Y0.6903 +G01 X-1.4775 Y0.7297 +G01 X-1.4497 Y0.7575 +G01 X-1.4103 Y0.7575 +G01 X-1.3825 Y0.7297 +G01 X-1.3825 Y0.6903 +G01 X-1.3955 Y0.6773 +G01 X-1.3955 Y0.5478 +G01 X-1.3897 Y0.5454 +G01 X-1.3746 Y0.5303 +G01 X-1.3665 Y0.5106 +G01 X-1.3665 Y0.4894 +G01 X-1.3726 Y0.4747 +G01 X-1.3700 Y0.4745 +G01 X-0.6169 Y0.4745 +G01 X-0.6100 Y0.4745 +G01 X-0.6070 Y0.4748 +G01 X-0.6014 Y0.4771 +G01 X-0.5971 Y0.4814 +G01 X-0.5948 Y0.4870 +G01 X-0.5945 Y0.4900 +G01 X-0.5945 Y0.8773 +G01 X-0.6075 Y0.8903 +G01 X-0.6075 Y0.9297 +G01 X-0.5797 Y0.9575 +G01 X-0.5403 Y0.9575 +G01 X-0.5125 Y0.9297 +G01 X-0.5125 Y0.8903 +G01 X-0.5255 Y0.8773 +G01 X-0.5255 Y0.4831 +G01 X-0.5255 Y0.4732 +G00 Z0.1000 +G00 X-2.3645 Y0.7968 +G01 Z-0.0070 F10 +G01 X-2.3645 Y0.7968 F20 +G01 X-2.3516 Y0.8279 +G01 X-2.3279 Y0.8516 +G01 X-2.2968 Y0.8645 +G01 X-2.2800 Y0.8645 +G01 X-2.2731 Y0.8645 +G01 X-1.8669 Y0.8645 +G01 X-1.8600 Y0.8645 +G01 X-1.8570 Y0.8648 +G01 X-1.8514 Y0.8671 +G01 X-1.8471 Y0.8714 +G01 X-1.8448 Y0.8770 +G01 X-1.8445 Y0.8800 +G01 X-1.8445 Y0.8869 +G01 X-1.8445 Y1.0755 +G01 X-1.8703 Y1.0755 +G01 X-1.8761 Y1.0697 +G01 X-1.8935 Y1.0625 +G01 X-2.0264 Y1.0625 +G01 X-2.0439 Y1.0697 +G01 X-2.0573 Y1.0831 +G01 X-2.0645 Y1.1005 +G01 X-2.0645 Y1.1194 +G01 X-2.0573 Y1.1369 +G01 X-2.0439 Y1.1503 +G01 X-2.0264 Y1.1575 +G01 X-1.8935 Y1.1575 +G01 X-1.8761 Y1.1503 +G01 X-1.8703 Y1.1445 +G01 X-1.8031 Y1.1445 +G01 X-1.3397 Y1.1445 +G01 X-1.3339 Y1.1503 +G01 X-1.3164 Y1.1575 +G01 X-1.1835 Y1.1575 +G01 X-1.1661 Y1.1503 +G01 X-1.1527 Y1.1369 +G01 X-1.1455 Y1.1194 +G01 X-1.1455 Y1.1005 +G01 X-1.1527 Y1.0831 +G01 X-1.1661 Y1.0697 +G01 X-1.1835 Y1.0625 +G01 X-1.3164 Y1.0625 +G01 X-1.3339 Y1.0697 +G01 X-1.3397 Y1.0755 +G01 X-1.7755 Y1.0755 +G01 X-1.7755 Y0.8869 +G01 X-1.7755 Y0.8800 +G01 X-1.7755 Y0.8632 +G01 X-1.7884 Y0.8321 +G01 X-1.8121 Y0.8084 +G01 X-1.8432 Y0.7955 +G01 X-1.8600 Y0.7955 +G01 X-1.8669 Y0.7955 +G01 X-2.2731 Y0.7955 +G01 X-2.2800 Y0.7955 +G01 X-2.2830 Y0.7952 +G01 X-2.2886 Y0.7929 +G01 X-2.2929 Y0.7886 +G01 X-2.2952 Y0.7830 +G01 X-2.2955 Y0.7800 +G01 X-2.2955 Y0.7531 +G01 X-2.2955 Y0.7492 +G01 X-2.3038 Y0.7291 +G01 X-2.3191 Y0.7138 +G01 X-2.3392 Y0.7055 +G01 X-2.3500 Y0.7055 +G01 X-2.3569 Y0.7055 +G01 X-2.6473 Y0.7055 +G01 X-2.6503 Y0.7025 +G01 X-2.6897 Y0.7025 +G01 X-2.7027 Y0.7155 +G01 X-2.8069 Y0.7155 +G01 X-2.8206 Y0.7018 +G01 X-2.8408 Y0.6934 +G01 X-2.9992 Y0.6934 +G01 X-3.0194 Y0.7018 +G01 X-3.0349 Y0.7173 +G01 X-3.0432 Y0.7375 +G01 X-3.0432 Y0.7594 +G01 X-3.0349 Y0.7796 +G01 X-3.0194 Y0.7950 +G01 X-2.9992 Y0.8034 +G01 X-2.8408 Y0.8034 +G01 X-2.8206 Y0.7950 +G01 X-2.8100 Y0.7845 +G01 X-2.7027 Y0.7845 +G01 X-2.6897 Y0.7975 +G01 X-2.6503 Y0.7975 +G01 X-2.6273 Y0.7745 +G01 X-2.3645 Y0.7745 +G01 X-2.3645 Y0.7869 +G01 X-2.3645 Y0.7968 +G00 Z0.1000 +G00 X-2.3869 Y1.7155 +G01 Z-0.0070 F10 +G01 X-2.3900 Y1.7186 F20 +G01 X-2.3931 Y1.7155 +G01 X-2.3869 Y1.7155 +G00 Z0.1000 +G00 X-1.7195 Y1.2209 +G01 Z-0.0070 F10 +G01 X-1.7195 Y1.1791 F20 +G01 X-1.7491 Y1.1495 +G01 X-1.7909 Y1.1495 +G01 X-1.8039 Y1.1625 +G01 X-1.8857 Y1.1625 +G01 X-1.8918 Y1.1600 +G01 X-1.8744 Y1.1528 +G01 X-1.8691 Y1.1475 +G01 X-1.8175 Y1.1475 +G01 X-1.8025 Y1.1475 +G01 X-1.3409 Y1.1475 +G01 X-1.3356 Y1.1528 +G01 X-1.3182 Y1.1600 +G01 X-1.3356 Y1.1672 +G01 X-1.3498 Y1.1814 +G01 X-1.3575 Y1.2000 +G01 X-1.3575 Y1.2200 +G01 X-1.3498 Y1.2386 +G01 X-1.3356 Y1.2528 +G01 X-1.3182 Y1.2600 +G01 X-1.3356 Y1.2672 +G01 X-1.3498 Y1.2814 +G01 X-1.3575 Y1.3000 +G01 X-1.3575 Y1.3200 +G01 X-1.3498 Y1.3386 +G01 X-1.3356 Y1.3528 +G01 X-1.3182 Y1.3600 +G01 X-1.3356 Y1.3672 +G01 X-1.3409 Y1.3725 +G01 X-1.3525 Y1.3725 +G01 X-1.3595 Y1.3725 +G01 X-1.3600 Y1.3725 +G01 X-1.3624 Y1.3723 +G01 X-1.3669 Y1.3704 +G01 X-1.3704 Y1.3669 +G01 X-1.3723 Y1.3624 +G01 X-1.3725 Y1.3600 +G01 X-1.3725 Y1.2525 +G01 X-1.3725 Y1.2433 +G01 X-1.3725 Y1.2333 +G01 X-1.3795 Y1.2164 +G01 X-1.3795 Y1.1891 +G01 X-1.4091 Y1.1595 +G01 X-1.4509 Y1.1595 +G01 X-1.4805 Y1.1891 +G01 X-1.4805 Y1.2309 +G01 X-1.4509 Y1.2605 +G01 X-1.4475 Y1.2605 +G01 X-1.4475 Y1.2891 +G01 X-1.4521 Y1.2780 +G01 X-1.4680 Y1.2621 +G01 X-1.4888 Y1.2535 +G01 X-1.5112 Y1.2535 +G01 X-1.5320 Y1.2621 +G01 X-1.5424 Y1.2725 +G01 X-1.5857 Y1.2725 +G01 X-1.5857 Y1.2475 +G01 X-1.6175 Y1.2157 +G01 X-1.6625 Y1.2157 +G01 X-1.6943 Y1.2475 +G01 X-1.6943 Y1.2725 +G01 X-1.7325 Y1.2725 +G01 X-1.7325 Y1.2339 +G01 X-1.7195 Y1.2209 +G00 Z0.1000 +G00 X-1.8175 Y1.2725 +G01 Z-0.0070 F10 +G01 X-1.8312 Y1.2782 F20 +G01 X-1.8418 Y1.2888 +G01 X-1.8475 Y1.3025 +G01 X-1.8475 Y1.5325 +G01 X-1.8475 Y1.5400 +G01 X-1.8475 Y1.5405 +G01 X-1.8479 Y1.5414 +G01 X-1.8486 Y1.5421 +G01 X-1.8495 Y1.5425 +G01 X-1.8500 Y1.5425 +G01 X-2.3325 Y1.5425 +G01 X-2.3343 Y1.5425 +G01 X-2.3475 Y1.5425 +G01 X-2.3574 Y1.5425 +G01 X-2.3896 Y1.5558 +G01 X-2.4142 Y1.5804 +G01 X-2.4275 Y1.6126 +G01 X-2.4275 Y1.6225 +G01 X-2.4275 Y1.6311 +G01 X-2.4405 Y1.6441 +G01 X-2.4405 Y1.6859 +G01 X-2.4369 Y1.6895 +G01 X-2.4609 Y1.6895 +G01 X-2.4625 Y1.6911 +G01 X-2.4625 Y1.6025 +G01 X-2.4682 Y1.5888 +G01 X-2.4788 Y1.5782 +G01 X-2.4825 Y1.5767 +G01 X-2.4825 Y1.4475 +G01 X-2.4825 Y1.4325 +G01 X-2.4825 Y1.2600 +G01 X-2.4823 Y1.2576 +G01 X-2.4804 Y1.2531 +G01 X-2.4769 Y1.2496 +G01 X-2.4724 Y1.2477 +G01 X-2.4700 Y1.2475 +G01 X-2.4643 Y1.2475 +G01 X-2.4625 Y1.2475 +G01 X-2.3509 Y1.2475 +G01 X-2.3456 Y1.2528 +G01 X-2.3282 Y1.2600 +G01 X-2.3456 Y1.2672 +G01 X-2.3598 Y1.2814 +G01 X-2.3675 Y1.3000 +G01 X-2.3675 Y1.3200 +G01 X-2.3598 Y1.3386 +G01 X-2.3456 Y1.3528 +G01 X-2.3270 Y1.3605 +G01 X-2.1930 Y1.3605 +G01 X-2.1744 Y1.3528 +G01 X-2.1691 Y1.3475 +G01 X-2.1225 Y1.3475 +G01 X-2.1186 Y1.3475 +G01 X-2.0974 Y1.3387 +G01 X-2.0813 Y1.3226 +G01 X-2.0725 Y1.3014 +G01 X-2.0725 Y1.2975 +G01 X-2.0725 Y1.2825 +G01 X-2.0725 Y1.0675 +G01 X-2.0725 Y1.0555 +G01 X-2.0645 Y1.0475 +G01 X-2.0509 Y1.0475 +G01 X-2.0456 Y1.0528 +G01 X-2.0282 Y1.0600 +G01 X-2.0456 Y1.0672 +G01 X-2.0598 Y1.0814 +G01 X-2.0675 Y1.1000 +G01 X-2.0675 Y1.1200 +G01 X-2.0598 Y1.1386 +G01 X-2.0456 Y1.1528 +G01 X-2.0282 Y1.1600 +G01 X-2.0456 Y1.1672 +G01 X-2.0598 Y1.1814 +G01 X-2.0675 Y1.2000 +G01 X-2.0675 Y1.2200 +G01 X-2.0598 Y1.2386 +G01 X-2.0456 Y1.2528 +G01 X-2.0282 Y1.2600 +G01 X-2.0456 Y1.2672 +G01 X-2.0598 Y1.2814 +G01 X-2.0675 Y1.3000 +G01 X-2.0675 Y1.3200 +G01 X-2.0598 Y1.3386 +G01 X-2.0456 Y1.3528 +G01 X-2.0270 Y1.3605 +G01 X-1.9975 Y1.3605 +G01 X-1.9975 Y1.4200 +G01 X-1.9976 Y1.4208 +G01 X-2.0092 Y1.4324 +G01 X-2.0100 Y1.4325 +G01 X-2.1707 Y1.4325 +G01 X-2.1875 Y1.4157 +G01 X-2.2325 Y1.4157 +G01 X-2.2380 Y1.4212 +G01 X-2.2450 Y1.4188 +G01 X-2.2450 Y1.4172 +G01 X-2.2772 Y1.3850 +G01 X-2.3228 Y1.3850 +G01 X-2.3550 Y1.4172 +G01 X-2.3550 Y1.4628 +G01 X-2.3228 Y1.4950 +G01 X-2.2772 Y1.4950 +G01 X-2.2713 Y1.4891 +G01 X-2.2643 Y1.4914 +G01 X-2.2643 Y1.4925 +G01 X-2.2325 Y1.5243 +G01 X-2.1875 Y1.5243 +G01 X-2.1707 Y1.5075 +G01 X-2.0093 Y1.5075 +G01 X-1.9925 Y1.5243 +G01 X-1.9475 Y1.5243 +G01 X-1.9157 Y1.4925 +G01 X-1.9157 Y1.4475 +G01 X-1.9235 Y1.4397 +G01 X-1.9225 Y1.4374 +G01 X-1.9225 Y1.4275 +G01 X-1.9225 Y1.3605 +G01 X-1.8930 Y1.3605 +G01 X-1.8744 Y1.3528 +G01 X-1.8602 Y1.3386 +G01 X-1.8525 Y1.3200 +G01 X-1.8525 Y1.3000 +G01 X-1.8602 Y1.2814 +G01 X-1.8744 Y1.2672 +G01 X-1.8918 Y1.2600 +G01 X-1.8744 Y1.2528 +G01 X-1.8602 Y1.2386 +G01 X-1.8597 Y1.2375 +G01 X-1.8075 Y1.2375 +G01 X-1.8075 Y1.2725 +G01 X-1.8175 Y1.2725 +G00 Z0.1000 +G00 X-2.4775 Y1.7775 +G01 Z-0.0070 F10 +G01 X-2.4739 Y1.7775 F20 +G01 X-2.4609 Y1.7905 +G01 X-2.4191 Y1.7905 +G01 X-2.3900 Y1.7614 +G01 X-2.3775 Y1.7739 +G01 X-2.3775 Y1.7800 +G01 X-2.3777 Y1.7824 +G01 X-2.3796 Y1.7869 +G01 X-2.3831 Y1.7904 +G01 X-2.3876 Y1.7923 +G01 X-2.3900 Y1.7925 +G01 X-2.5300 Y1.7925 +G01 X-2.5324 Y1.7923 +G01 X-2.5369 Y1.7904 +G01 X-2.5404 Y1.7869 +G01 X-2.5423 Y1.7824 +G01 X-2.5425 Y1.7800 +G01 X-2.5425 Y1.7775 +G01 X-2.5425 Y1.7739 +G01 X-2.5425 Y1.7625 +G01 X-2.5425 Y1.7526 +G01 X-2.5558 Y1.7204 +G01 X-2.5804 Y1.6958 +G01 X-2.6126 Y1.6825 +G01 X-2.6225 Y1.6825 +G01 X-2.6361 Y1.6825 +G01 X-2.6491 Y1.6695 +G01 X-2.6909 Y1.6695 +G01 X-2.7039 Y1.6825 +G01 X-2.7300 Y1.6825 +G01 X-2.7324 Y1.6823 +G01 X-2.7369 Y1.6804 +G01 X-2.7404 Y1.6769 +G01 X-2.7423 Y1.6724 +G01 X-2.7425 Y1.6700 +G01 X-2.7425 Y1.6642 +G01 X-2.7425 Y1.6625 +G01 X-2.7425 Y1.5925 +G01 X-2.7425 Y1.5846 +G01 X-2.7543 Y1.5561 +G01 X-2.7761 Y1.5343 +G01 X-2.8046 Y1.5225 +G01 X-2.8125 Y1.5225 +G01 X-2.8197 Y1.5225 +G01 X-2.8200 Y1.5225 +G01 X-2.8275 Y1.5225 +G01 X-2.9525 Y1.5225 +G01 X-2.9525 Y1.4570 +G01 X-2.9466 Y1.4712 +G01 X-2.9312 Y1.4866 +G01 X-2.9109 Y1.4950 +G01 X-2.8891 Y1.4950 +G01 X-2.8688 Y1.4866 +G01 X-2.8597 Y1.4775 +G01 X-2.5575 Y1.4775 +G01 X-2.5575 Y1.5725 +G01 X-2.6261 Y1.5725 +G01 X-2.6391 Y1.5595 +G01 X-2.6809 Y1.5595 +G01 X-2.7105 Y1.5891 +G01 X-2.7105 Y1.6309 +G01 X-2.6809 Y1.6605 +G01 X-2.6391 Y1.6605 +G01 X-2.6261 Y1.6475 +G01 X-2.5375 Y1.6475 +G01 X-2.5375 Y1.7025 +G01 X-2.5375 Y1.7035 +G01 X-2.5375 Y1.7175 +G01 X-2.5375 Y1.7234 +G01 X-2.5272 Y1.7482 +G01 X-2.5082 Y1.7672 +G01 X-2.4834 Y1.7775 +G01 X-2.4775 Y1.7775 +G00 Z0.1000 +G00 X-2.8688 Y1.3934 +G01 Z-0.0070 F10 +G01 X-2.8891 Y1.3850 F20 +G01 X-2.9109 Y1.3850 +G01 X-2.9312 Y1.3934 +G01 X-2.9466 Y1.4088 +G01 X-2.9525 Y1.4230 +G01 X-2.9525 Y1.3805 +G01 X-2.9291 Y1.3805 +G01 X-2.8995 Y1.3509 +G01 X-2.8995 Y1.3091 +G01 X-2.9291 Y1.2795 +G01 X-2.9709 Y1.2795 +G01 X-3.0005 Y1.3091 +G01 X-3.0005 Y1.3109 +G01 X-3.0157 Y1.3261 +G01 X-3.0275 Y1.3546 +G01 X-3.0275 Y1.3625 +G01 X-3.0275 Y1.3661 +G01 X-3.0275 Y1.3700 +G01 X-3.0275 Y1.5225 +G01 X-3.0275 Y1.5300 +G01 X-3.0275 Y1.5301 +G01 X-3.0275 Y1.5375 +G01 X-3.0275 Y1.5434 +G01 X-3.0172 Y1.5682 +G01 X-2.9982 Y1.5872 +G01 X-2.9734 Y1.5975 +G01 X-2.9675 Y1.5975 +G01 X-2.8275 Y1.5975 +G01 X-2.8200 Y1.5975 +G01 X-2.8195 Y1.5975 +G01 X-2.8186 Y1.5979 +G01 X-2.8179 Y1.5986 +G01 X-2.8175 Y1.5995 +G01 X-2.8175 Y1.6000 +G01 X-2.8175 Y1.6625 +G01 X-2.8175 Y1.6642 +G01 X-2.8175 Y1.6775 +G01 X-2.8175 Y1.6874 +G01 X-2.8042 Y1.7196 +G01 X-2.7796 Y1.7442 +G01 X-2.7474 Y1.7575 +G01 X-2.7375 Y1.7575 +G01 X-2.7039 Y1.7575 +G01 X-2.6914 Y1.7700 +G01 X-2.7039 Y1.7825 +G01 X-2.8125 Y1.7825 +G01 X-2.8200 Y1.7825 +G01 X-2.8224 Y1.7823 +G01 X-2.8269 Y1.7804 +G01 X-2.8304 Y1.7769 +G01 X-2.8323 Y1.7724 +G01 X-2.8325 Y1.7700 +G01 X-2.8325 Y1.6875 +G01 X-2.8325 Y1.6859 +G01 X-2.8325 Y1.6725 +G01 X-2.8325 Y1.6666 +G01 X-2.8428 Y1.6418 +G01 X-2.8618 Y1.6228 +G01 X-2.8866 Y1.6125 +G01 X-2.8925 Y1.6125 +G01 X-3.0125 Y1.6125 +G01 X-3.0191 Y1.6125 +G01 X-3.0200 Y1.6125 +G01 X-3.0224 Y1.6123 +G01 X-3.0269 Y1.6104 +G01 X-3.0304 Y1.6069 +G01 X-3.0323 Y1.6024 +G01 X-3.0325 Y1.6000 +G01 X-3.0325 Y1.2900 +G01 X-3.0323 Y1.2876 +G01 X-3.0304 Y1.2831 +G01 X-3.0269 Y1.2796 +G01 X-3.0224 Y1.2777 +G01 X-3.0200 Y1.2775 +G01 X-3.0125 Y1.2775 +G01 X-2.7237 Y1.2775 +G01 X-2.7200 Y1.2782 +G01 X-2.7163 Y1.2775 +G01 X-2.7139 Y1.2775 +G01 X-2.6909 Y1.3005 +G01 X-2.6491 Y1.3005 +G01 X-2.6195 Y1.2709 +G01 X-2.6195 Y1.2291 +G01 X-2.6491 Y1.1995 +G01 X-2.6774 Y1.1995 +G01 X-2.6999 Y1.1950 +G01 X-2.7286 Y1.2007 +G01 X-2.7314 Y1.2025 +G01 X-3.0125 Y1.2025 +G01 X-3.0200 Y1.2025 +G01 X-3.0374 Y1.2025 +G01 X-3.0696 Y1.2158 +G01 X-3.0942 Y1.2404 +G01 X-3.1075 Y1.2726 +G01 X-3.1075 Y1.2825 +G01 X-3.1075 Y1.6075 +G01 X-3.1075 Y1.6174 +G01 X-3.0942 Y1.6496 +G01 X-3.0696 Y1.6742 +G01 X-3.0374 Y1.6875 +G01 X-3.0275 Y1.6875 +G01 X-3.0190 Y1.6875 +G01 X-3.0125 Y1.6875 +G01 X-2.9075 Y1.6875 +G01 X-2.9075 Y1.7775 +G01 X-2.9075 Y1.7874 +G01 X-2.8942 Y1.8196 +G01 X-2.8696 Y1.8442 +G01 X-2.8374 Y1.8575 +G01 X-2.8200 Y1.8575 +G01 X-2.8125 Y1.8575 +G01 X-2.7039 Y1.8575 +G01 X-2.6909 Y1.8705 +G01 X-2.6491 Y1.8705 +G01 X-2.6195 Y1.8409 +G01 X-2.6195 Y1.7991 +G01 X-2.6486 Y1.7700 +G01 X-2.6361 Y1.7575 +G01 X-2.6300 Y1.7575 +G01 X-2.6276 Y1.7577 +G01 X-2.6231 Y1.7596 +G01 X-2.6196 Y1.7631 +G01 X-2.6177 Y1.7676 +G01 X-2.6175 Y1.7700 +G01 X-2.6175 Y1.7739 +G01 X-2.6175 Y1.7775 +G01 X-2.6175 Y1.7875 +G01 X-2.6175 Y1.7974 +G01 X-2.6042 Y1.8296 +G01 X-2.5796 Y1.8542 +G01 X-2.5474 Y1.8675 +G01 X-2.5375 Y1.8675 +G01 X-2.3825 Y1.8675 +G01 X-2.3726 Y1.8675 +G01 X-2.3404 Y1.8542 +G01 X-2.3158 Y1.8296 +G01 X-2.3025 Y1.7974 +G01 X-2.3025 Y1.7875 +G01 X-2.3025 Y1.7775 +G01 X-2.2493 Y1.7775 +G01 X-2.2325 Y1.7943 +G01 X-2.1875 Y1.7943 +G01 X-2.1557 Y1.7625 +G01 X-2.1557 Y1.7175 +G01 X-2.1875 Y1.6857 +G01 X-2.2325 Y1.6857 +G01 X-2.2493 Y1.7025 +G01 X-2.3061 Y1.7025 +G01 X-2.3191 Y1.6895 +G01 X-2.3431 Y1.6895 +G01 X-2.3395 Y1.6859 +G01 X-2.3395 Y1.6441 +G01 X-2.3525 Y1.6311 +G01 X-2.3525 Y1.6300 +G01 X-2.3523 Y1.6276 +G01 X-2.3504 Y1.6231 +G01 X-2.3469 Y1.6196 +G01 X-2.3424 Y1.6177 +G01 X-2.3400 Y1.6175 +G01 X-2.3343 Y1.6175 +G01 X-2.3325 Y1.6175 +G01 X-1.8425 Y1.6175 +G01 X-1.8346 Y1.6175 +G01 X-1.8061 Y1.6057 +G01 X-1.7843 Y1.5839 +G01 X-1.7725 Y1.5554 +G01 X-1.7725 Y1.5475 +G01 X-1.7725 Y1.5400 +G01 X-1.7725 Y1.5325 +G01 X-1.7725 Y1.3475 +G01 X-1.7625 Y1.3475 +G01 X-1.6475 Y1.3475 +G01 X-1.6325 Y1.3475 +G01 X-1.5424 Y1.3475 +G01 X-1.5320 Y1.3579 +G01 X-1.5112 Y1.3665 +G01 X-1.4888 Y1.3665 +G01 X-1.4680 Y1.3579 +G01 X-1.4521 Y1.3420 +G01 X-1.4475 Y1.3309 +G01 X-1.4475 Y1.4100 +G01 X-1.4477 Y1.4124 +G01 X-1.4496 Y1.4169 +G01 X-1.4531 Y1.4204 +G01 X-1.4576 Y1.4223 +G01 X-1.4600 Y1.4225 +G01 X-1.4675 Y1.4225 +G01 X-1.6525 Y1.4225 +G01 X-1.6571 Y1.4225 +G01 X-1.6675 Y1.4225 +G01 X-1.6774 Y1.4225 +G01 X-1.7096 Y1.4358 +G01 X-1.7342 Y1.4604 +G01 X-1.7475 Y1.4926 +G01 X-1.7475 Y1.5025 +G01 X-1.7475 Y1.6511 +G01 X-1.7491 Y1.6495 +G01 X-1.7909 Y1.6495 +G01 X-1.8039 Y1.6625 +G01 X-2.0325 Y1.6625 +G01 X-2.0338 Y1.6625 +G01 X-2.0475 Y1.6625 +G01 X-2.0574 Y1.6625 +G01 X-2.0896 Y1.6758 +G01 X-2.1142 Y1.7004 +G01 X-2.1275 Y1.7326 +G01 X-2.1275 Y1.7425 +G01 X-2.1275 Y1.8725 +G01 X-2.9000 Y1.8725 +G01 X-2.9024 Y1.8723 +G01 X-2.9069 Y1.8704 +G01 X-2.9104 Y1.8669 +G01 X-2.9123 Y1.8624 +G01 X-2.9125 Y1.8600 +G01 X-2.9125 Y1.8543 +G01 X-2.9125 Y1.8525 +G01 X-2.9125 Y1.7725 +G01 X-2.9125 Y1.7646 +G01 X-2.9243 Y1.7361 +G01 X-2.9461 Y1.7143 +G01 X-2.9746 Y1.7025 +G01 X-2.9825 Y1.7025 +G01 X-2.9897 Y1.7025 +G01 X-2.9900 Y1.7025 +G01 X-2.9975 Y1.7025 +G01 X-3.1100 Y1.7025 +G01 X-3.1124 Y1.7023 +G01 X-3.1169 Y1.7004 +G01 X-3.1204 Y1.6969 +G01 X-3.1223 Y1.6924 +G01 X-3.1225 Y1.6900 +G01 X-3.1225 Y1.6825 +G01 X-3.1225 Y1.6439 +G01 X-3.1095 Y1.6309 +G01 X-3.1095 Y1.5891 +G01 X-3.1225 Y1.5761 +G01 X-3.1225 Y0.9600 +G01 X-3.1223 Y0.9576 +G01 X-3.1204 Y0.9531 +G01 X-3.1169 Y0.9496 +G01 X-3.1124 Y0.9477 +G01 X-3.1100 Y0.9475 +G01 X-3.1041 Y0.9475 +G01 X-3.1025 Y0.9475 +G01 X-2.5493 Y0.9475 +G01 X-2.5325 Y0.9643 +G01 X-2.4875 Y0.9643 +G01 X-2.4707 Y0.9475 +G01 X-2.1675 Y0.9475 +G01 X-2.1600 Y0.9475 +G01 X-2.1576 Y0.9477 +G01 X-2.1531 Y0.9496 +G01 X-2.1496 Y0.9531 +G01 X-2.1477 Y0.9576 +G01 X-2.1475 Y0.9600 +G01 X-2.1475 Y1.0675 +G01 X-2.1475 Y1.2725 +G01 X-2.1691 Y1.2725 +G01 X-2.1744 Y1.2672 +G01 X-2.1918 Y1.2600 +G01 X-2.1744 Y1.2528 +G01 X-2.1602 Y1.2386 +G01 X-2.1525 Y1.2200 +G01 X-2.1525 Y1.2000 +G01 X-2.1602 Y1.1814 +G01 X-2.1744 Y1.1672 +G01 X-2.1918 Y1.1600 +G01 X-2.1744 Y1.1528 +G01 X-2.1602 Y1.1386 +G01 X-2.1525 Y1.1200 +G01 X-2.1525 Y1.1000 +G01 X-2.1602 Y1.0814 +G01 X-2.1744 Y1.0672 +G01 X-2.1918 Y1.0600 +G01 X-2.1744 Y1.0528 +G01 X-2.1602 Y1.0386 +G01 X-2.1525 Y1.0200 +G01 X-2.1525 Y1.0000 +G01 X-2.1602 Y0.9814 +G01 X-2.1744 Y0.9672 +G01 X-2.1930 Y0.9595 +G01 X-2.3270 Y0.9595 +G01 X-2.3456 Y0.9672 +G01 X-2.3509 Y0.9725 +G01 X-2.9075 Y0.9725 +G01 X-2.9174 Y0.9725 +G01 X-2.9496 Y0.9858 +G01 X-2.9742 Y1.0104 +G01 X-2.9875 Y1.0426 +G01 X-2.9875 Y1.0525 +G01 X-2.9875 Y1.0961 +G01 X-3.0005 Y1.1091 +G01 X-3.0005 Y1.1509 +G01 X-2.9709 Y1.1805 +G01 X-2.9291 Y1.1805 +G01 X-2.8995 Y1.1509 +G01 X-2.8995 Y1.1091 +G01 X-2.9125 Y1.0961 +G01 X-2.9125 Y1.0600 +G01 X-2.9123 Y1.0576 +G01 X-2.9104 Y1.0531 +G01 X-2.9069 Y1.0496 +G01 X-2.9024 Y1.0477 +G01 X-2.9000 Y1.0475 +G01 X-2.3509 Y1.0475 +G01 X-2.3456 Y1.0528 +G01 X-2.3282 Y1.0600 +G01 X-2.3456 Y1.0672 +G01 X-2.3598 Y1.0814 +G01 X-2.3675 Y1.1000 +G01 X-2.3675 Y1.1200 +G01 X-2.3598 Y1.1386 +G01 X-2.3456 Y1.1528 +G01 X-2.3282 Y1.1600 +G01 X-2.3456 Y1.1672 +G01 X-2.3509 Y1.1725 +G01 X-2.4625 Y1.1725 +G01 X-2.4643 Y1.1725 +G01 X-2.4775 Y1.1725 +G01 X-2.4874 Y1.1725 +G01 X-2.5196 Y1.1858 +G01 X-2.5442 Y1.2104 +G01 X-2.5575 Y1.2426 +G01 X-2.5575 Y1.2525 +G01 X-2.5575 Y1.4025 +G01 X-2.8597 Y1.4025 +G01 X-2.8688 Y1.3934 +G00 Z0.1000 +G00 X-0.4225 Y0.2826 +G01 Z-0.0070 F10 +G01 X-0.4225 Y0.2826 F20 +G01 X-0.4358 Y0.2504 +G01 X-0.4604 Y0.2258 +G01 X-0.4926 Y0.2125 +G01 X-0.5025 Y0.2125 +G01 X-0.5100 Y0.2125 +G01 X-0.5175 Y0.2125 +G01 X-1.0400 Y0.2125 +G01 X-1.0424 Y0.2123 +G01 X-1.0469 Y0.2104 +G01 X-1.0504 Y0.2069 +G01 X-1.0523 Y0.2024 +G01 X-1.0525 Y0.2000 +G01 X-1.0525 Y0.1947 +G01 X-1.0525 Y0.1925 +G01 X-1.0525 Y0.1425 +G01 X-1.0525 Y0.1326 +G01 X-1.0658 Y0.1004 +G01 X-1.0904 Y0.0758 +G01 X-1.1226 Y0.0625 +G01 X-1.1400 Y0.0625 +G01 X-1.1475 Y0.0625 +G01 X-1.5925 Y0.0625 +G01 X-1.6000 Y0.0625 +G01 X-1.6174 Y0.0625 +G01 X-1.6496 Y0.0758 +G01 X-1.6742 Y0.1004 +G01 X-1.6875 Y0.1326 +G01 X-1.6875 Y0.1425 +G01 X-1.6875 Y0.8675 +G01 X-1.6875 Y0.8774 +G01 X-1.6742 Y0.9096 +G01 X-1.6496 Y0.9342 +G01 X-1.6174 Y0.9475 +G01 X-1.6075 Y0.9475 +G01 X-1.5992 Y0.9475 +G01 X-1.5925 Y0.9475 +G01 X-1.3409 Y0.9475 +G01 X-1.3356 Y0.9528 +G01 X-1.3182 Y0.9600 +G01 X-1.3356 Y0.9672 +G01 X-1.3409 Y0.9725 +G01 X-1.6825 Y0.9725 +G01 X-1.6900 Y0.9725 +G01 X-1.6905 Y0.9725 +G01 X-1.6914 Y0.9721 +G01 X-1.6921 Y0.9714 +G01 X-1.6925 Y0.9705 +G01 X-1.6925 Y0.9700 +G01 X-1.6925 Y0.9625 +G01 X-1.6925 Y0.8075 +G01 X-1.6925 Y0.8000 +G01 X-1.6925 Y0.7826 +G01 X-1.7058 Y0.7504 +G01 X-1.7304 Y0.7258 +G01 X-1.7626 Y0.7125 +G01 X-1.7800 Y0.7125 +G01 X-1.7875 Y0.7125 +G01 X-1.9891 Y0.7125 +G01 X-1.9780 Y0.7079 +G01 X-1.9676 Y0.6975 +G01 X-1.7839 Y0.6975 +G01 X-1.7709 Y0.7105 +G01 X-1.7291 Y0.7105 +G01 X-1.6995 Y0.6809 +G01 X-1.6995 Y0.6391 +G01 X-1.7291 Y0.6095 +G01 X-1.7709 Y0.6095 +G01 X-1.7839 Y0.6225 +G01 X-1.8757 Y0.6225 +G01 X-1.8457 Y0.5925 +G01 X-1.8457 Y0.5505 +G01 X-1.8312 Y0.5565 +G01 X-1.8088 Y0.5565 +G01 X-1.7880 Y0.5479 +G01 X-1.7721 Y0.5320 +G01 X-1.7635 Y0.5112 +G01 X-1.7635 Y0.4888 +G01 X-1.7721 Y0.4680 +G01 X-1.7825 Y0.4576 +G01 X-1.7825 Y0.3824 +G01 X-1.7721 Y0.3720 +G01 X-1.7635 Y0.3512 +G01 X-1.7635 Y0.3288 +G01 X-1.7721 Y0.3080 +G01 X-1.7880 Y0.2921 +G01 X-1.8088 Y0.2835 +G01 X-1.8312 Y0.2835 +G01 X-1.8520 Y0.2921 +G01 X-1.8624 Y0.3025 +G01 X-1.9600 Y0.3025 +G01 X-1.9624 Y0.3023 +G01 X-1.9669 Y0.3004 +G01 X-1.9687 Y0.2986 +G01 X-1.9621 Y0.2920 +G01 X-1.9535 Y0.2712 +G01 X-1.9535 Y0.2488 +G01 X-1.9621 Y0.2280 +G01 X-1.9780 Y0.2121 +G01 X-1.9988 Y0.2035 +G01 X-2.0212 Y0.2035 +G01 X-2.0420 Y0.2121 +G01 X-2.0579 Y0.2280 +G01 X-2.0665 Y0.2488 +G01 X-2.0665 Y0.2712 +G01 X-2.0579 Y0.2920 +G01 X-2.0475 Y0.3024 +G01 X-2.0475 Y0.3074 +G01 X-2.0342 Y0.3396 +G01 X-2.0096 Y0.3642 +G01 X-1.9774 Y0.3775 +G01 X-1.9675 Y0.3775 +G01 X-1.8624 Y0.3775 +G01 X-1.8575 Y0.3824 +G01 X-1.8575 Y0.4576 +G01 X-1.8624 Y0.4625 +G01 X-1.8674 Y0.4625 +G01 X-1.8996 Y0.4758 +G01 X-1.9242 Y0.5004 +G01 X-1.9362 Y0.5294 +G01 X-1.9543 Y0.5475 +G01 X-1.9543 Y0.5925 +G01 X-1.9243 Y0.6225 +G01 X-1.9676 Y0.6225 +G01 X-1.9780 Y0.6121 +G01 X-1.9988 Y0.6035 +G01 X-2.0212 Y0.6035 +G01 X-2.0420 Y0.6121 +G01 X-2.0524 Y0.6225 +G01 X-2.0825 Y0.6225 +G01 X-2.0891 Y0.6225 +G01 X-2.0900 Y0.6225 +G01 X-2.0924 Y0.6223 +G01 X-2.0969 Y0.6204 +G01 X-2.1004 Y0.6169 +G01 X-2.1023 Y0.6124 +G01 X-2.1025 Y0.6100 +G01 X-2.1025 Y0.2939 +G01 X-2.0895 Y0.2809 +G01 X-2.0895 Y0.2391 +G01 X-2.1191 Y0.2095 +G01 X-2.1609 Y0.2095 +G01 X-2.1905 Y0.2391 +G01 X-2.1905 Y0.2809 +G01 X-2.1775 Y0.2939 +G01 X-2.1775 Y0.6175 +G01 X-2.1775 Y0.6274 +G01 X-2.1642 Y0.6596 +G01 X-2.1396 Y0.6842 +G01 X-2.1074 Y0.6975 +G01 X-2.0975 Y0.6975 +G01 X-2.0890 Y0.6975 +G01 X-2.0825 Y0.6975 +G01 X-2.0524 Y0.6975 +G01 X-2.0420 Y0.7079 +G01 X-2.0309 Y0.7125 +G01 X-2.1825 Y0.7125 +G01 X-2.1900 Y0.7125 +G01 X-2.1905 Y0.7125 +G01 X-2.1914 Y0.7121 +G01 X-2.1921 Y0.7114 +G01 X-2.1925 Y0.7105 +G01 X-2.1925 Y0.7100 +G01 X-2.1925 Y0.5975 +G01 X-2.1925 Y0.5955 +G01 X-2.1925 Y0.5825 +G01 X-2.1925 Y0.5746 +G01 X-2.2043 Y0.5461 +G01 X-2.2261 Y0.5243 +G01 X-2.2546 Y0.5125 +G01 X-2.2625 Y0.5125 +G01 X-2.2690 Y0.5125 +G01 X-2.2700 Y0.5125 +G01 X-2.2775 Y0.5125 +G01 X-2.4857 Y0.5125 +G01 X-2.4557 Y0.4825 +G01 X-2.4557 Y0.4375 +G01 X-2.4625 Y0.4307 +G01 X-2.4625 Y0.2694 +G01 X-2.4625 Y0.1900 +G01 X-2.4625 Y0.1896 +G01 X-2.4622 Y0.1889 +G01 X-2.4618 Y0.1882 +G01 X-2.4611 Y0.1878 +G01 X-2.4604 Y0.1875 +G01 X-2.4600 Y0.1875 +G01 X-2.4517 Y0.1875 +G01 X-2.4505 Y0.1875 +G01 X-1.8705 Y0.1875 +G01 X-1.8705 Y0.2209 +G01 X-1.8409 Y0.2505 +G01 X-1.7991 Y0.2505 +G01 X-1.7695 Y0.2209 +G01 X-1.7695 Y0.1791 +G01 X-1.7725 Y0.1761 +G01 X-1.7725 Y0.1746 +G01 X-1.7820 Y0.1452 +G01 X-1.8002 Y0.1202 +G01 X-1.8252 Y0.1020 +G01 X-1.8546 Y0.0925 +G01 X-1.8605 Y0.0925 +G01 X-2.4505 Y0.0925 +G01 X-2.4517 Y0.0925 +G01 X-2.4694 Y0.0925 +G01 X-2.4754 Y0.0925 +G01 X-2.5048 Y0.1020 +G01 X-2.5298 Y0.1202 +G01 X-2.5479 Y0.1452 +G01 X-2.5575 Y0.1746 +G01 X-2.5575 Y0.1805 +G01 X-2.5575 Y0.2225 +G01 X-2.6061 Y0.2225 +G01 X-2.6191 Y0.2095 +G01 X-2.6609 Y0.2095 +G01 X-2.6905 Y0.2391 +G01 X-2.6905 Y0.2809 +G01 X-2.6609 Y0.3105 +G01 X-2.6191 Y0.3105 +G01 X-2.6061 Y0.2975 +G01 X-2.5575 Y0.2975 +G01 X-2.5575 Y0.4307 +G01 X-2.5643 Y0.4375 +G01 X-2.5643 Y0.4825 +G01 X-2.5343 Y0.5125 +G01 X-2.8088 Y0.5125 +G01 X-2.8189 Y0.5024 +G01 X-2.8402 Y0.4936 +G01 X-2.9998 Y0.4936 +G01 X-3.0211 Y0.5024 +G01 X-3.0374 Y0.5187 +G01 X-3.0462 Y0.5400 +G01 X-3.0462 Y0.5631 +G01 X-3.0374 Y0.5844 +G01 X-3.0211 Y0.6007 +G01 X-2.9998 Y0.6096 +G01 X-2.8402 Y0.6096 +G01 X-2.8189 Y0.6007 +G01 X-2.8057 Y0.5875 +G01 X-2.2775 Y0.5875 +G01 X-2.2700 Y0.5875 +G01 X-2.2695 Y0.5875 +G01 X-2.2686 Y0.5879 +G01 X-2.2679 Y0.5886 +G01 X-2.2675 Y0.5895 +G01 X-2.2675 Y0.5900 +G01 X-2.2675 Y0.5955 +G01 X-2.2675 Y0.5975 +G01 X-2.2675 Y0.7175 +G01 X-2.2675 Y0.7254 +G01 X-2.2557 Y0.7539 +G01 X-2.2339 Y0.7757 +G01 X-2.2054 Y0.7875 +G01 X-2.1975 Y0.7875 +G01 X-2.1904 Y0.7875 +G01 X-2.1900 Y0.7875 +G01 X-2.1825 Y0.7875 +G01 X-1.7875 Y0.7875 +G01 X-1.7800 Y0.7875 +G01 X-1.7776 Y0.7877 +G01 X-1.7731 Y0.7896 +G01 X-1.7696 Y0.7931 +G01 X-1.7677 Y0.7976 +G01 X-1.7675 Y0.8000 +G01 X-1.7675 Y0.8075 +G01 X-1.7675 Y0.9625 +G01 X-1.7675 Y0.9700 +G01 X-1.7675 Y0.9702 +G01 X-1.7675 Y0.9775 +G01 X-1.7675 Y0.9854 +G01 X-1.7557 Y1.0139 +G01 X-1.7339 Y1.0357 +G01 X-1.7054 Y1.0475 +G01 X-1.6975 Y1.0475 +G01 X-1.6900 Y1.0475 +G01 X-1.6825 Y1.0475 +G01 X-1.3409 Y1.0475 +G01 X-1.3356 Y1.0528 +G01 X-1.3182 Y1.0600 +G01 X-1.3356 Y1.0672 +G01 X-1.3409 Y1.0725 +G01 X-1.7725 Y1.0725 +G01 X-1.7725 Y0.8875 +G01 X-1.7725 Y0.8800 +G01 X-1.7725 Y0.8626 +G01 X-1.7858 Y0.8304 +G01 X-1.8104 Y0.8058 +G01 X-1.8426 Y0.7925 +G01 X-1.8525 Y0.7925 +G01 X-2.2725 Y0.7925 +G01 X-2.2800 Y0.7925 +G01 X-2.2824 Y0.7923 +G01 X-2.2869 Y0.7904 +G01 X-2.2904 Y0.7869 +G01 X-2.2923 Y0.7824 +G01 X-2.2925 Y0.7800 +G01 X-2.2925 Y0.7525 +G01 X-2.2925 Y0.7486 +G01 X-2.3013 Y0.7274 +G01 X-2.3174 Y0.7113 +G01 X-2.3386 Y0.7025 +G01 X-2.3500 Y0.7025 +G01 X-2.3575 Y0.7025 +G01 X-2.6461 Y0.7025 +G01 X-2.6491 Y0.6995 +G01 X-2.6909 Y0.6995 +G01 X-2.7039 Y0.7125 +G01 X-2.8057 Y0.7125 +G01 X-2.8189 Y0.6993 +G01 X-2.8402 Y0.6904 +G01 X-2.9998 Y0.6904 +G01 X-3.0211 Y0.6993 +G01 X-3.0374 Y0.7156 +G01 X-3.0462 Y0.7369 +G01 X-3.0462 Y0.7600 +G01 X-3.0374 Y0.7813 +G01 X-3.0211 Y0.7976 +G01 X-2.9998 Y0.8064 +G01 X-2.8402 Y0.8064 +G01 X-2.8189 Y0.7976 +G01 X-2.8088 Y0.7875 +G01 X-2.7039 Y0.7875 +G01 X-2.6909 Y0.8005 +G01 X-2.6491 Y0.8005 +G01 X-2.6261 Y0.7775 +G01 X-2.3675 Y0.7775 +G01 X-2.3675 Y0.7875 +G01 X-2.3675 Y0.7974 +G01 X-2.3542 Y0.8296 +G01 X-2.3296 Y0.8542 +G01 X-2.2974 Y0.8675 +G01 X-2.2800 Y0.8675 +G01 X-2.2725 Y0.8675 +G01 X-1.8600 Y0.8675 +G01 X-1.8576 Y0.8677 +G01 X-1.8531 Y0.8696 +G01 X-1.8496 Y0.8731 +G01 X-1.8477 Y0.8776 +G01 X-1.8475 Y0.8800 +G01 X-1.8475 Y0.8875 +G01 X-1.8475 Y1.0725 +G01 X-1.8691 Y1.0725 +G01 X-1.8744 Y1.0672 +G01 X-1.8918 Y1.0600 +G01 X-1.8744 Y1.0528 +G01 X-1.8602 Y1.0386 +G01 X-1.8525 Y1.0200 +G01 X-1.8525 Y1.0000 +G01 X-1.8602 Y0.9814 +G01 X-1.8744 Y0.9672 +G01 X-1.8930 Y0.9595 +G01 X-2.0270 Y0.9595 +G01 X-2.0456 Y0.9672 +G01 X-2.0509 Y0.9725 +G01 X-2.0725 Y0.9725 +G01 X-2.0725 Y0.9525 +G01 X-2.0725 Y0.9426 +G01 X-2.0858 Y0.9104 +G01 X-2.1104 Y0.8858 +G01 X-2.1426 Y0.8725 +G01 X-2.1600 Y0.8725 +G01 X-2.1675 Y0.8725 +G01 X-2.4707 Y0.8725 +G01 X-2.4875 Y0.8557 +G01 X-2.5325 Y0.8557 +G01 X-2.5493 Y0.8725 +G01 X-3.1025 Y0.8725 +G01 X-3.1041 Y0.8725 +G01 X-3.1175 Y0.8725 +G01 X-3.1274 Y0.8725 +G01 X-3.1596 Y0.8858 +G01 X-3.1842 Y0.9104 +G01 X-3.1975 Y0.9426 +G01 X-3.1975 Y0.9525 +G01 X-3.1975 Y1.5761 +G01 X-3.2105 Y1.5891 +G01 X-3.2105 Y1.6309 +G01 X-3.1975 Y1.6439 +G01 X-3.1975 Y1.6825 +G01 X-3.1975 Y1.6900 +G01 X-3.1975 Y1.7074 +G01 X-3.1842 Y1.7396 +G01 X-3.1596 Y1.7642 +G01 X-3.1274 Y1.7775 +G01 X-3.1175 Y1.7775 +G01 X-2.9975 Y1.7775 +G01 X-2.9900 Y1.7775 +G01 X-2.9895 Y1.7775 +G01 X-2.9886 Y1.7779 +G01 X-2.9879 Y1.7786 +G01 X-2.9875 Y1.7795 +G01 X-2.9875 Y1.7800 +G01 X-2.9875 Y1.8525 +G01 X-2.9875 Y1.8543 +G01 X-2.9875 Y1.8675 +G01 X-2.9875 Y1.8774 +G01 X-2.9742 Y1.9096 +G01 X-2.9496 Y1.9342 +G01 X-2.9174 Y1.9475 +G01 X-2.9075 Y1.9475 +G01 X-2.0975 Y1.9475 +G01 X-2.0825 Y1.9475 +G01 X-2.0339 Y1.9475 +G01 X-2.0209 Y1.9605 +G01 X-1.9791 Y1.9605 +G01 X-1.9661 Y1.9475 +G01 X-1.7700 Y1.9475 +G01 X-1.7676 Y1.9477 +G01 X-1.7631 Y1.9496 +G01 X-1.7596 Y1.9531 +G01 X-1.7577 Y1.9576 +G01 X-1.7575 Y1.9600 +G01 X-1.7575 Y1.9660 +G01 X-1.7575 Y1.9675 +G01 X-1.7575 Y2.0675 +G01 X-1.7575 Y2.0774 +G01 X-1.7442 Y2.1096 +G01 X-1.7196 Y2.1342 +G01 X-1.6874 Y2.1475 +G01 X-1.6700 Y2.1475 +G01 X-1.6625 Y2.1475 +G01 X-1.2525 Y2.1475 +G01 X-1.2426 Y2.1475 +G01 X-1.2104 Y2.1342 +G01 X-1.1858 Y2.1096 +G01 X-1.1725 Y2.0774 +G01 X-1.1725 Y2.0600 +G01 X-1.1725 Y2.0525 +G01 X-1.1725 Y1.9100 +G01 X-1.1723 Y1.9076 +G01 X-1.1704 Y1.9031 +G01 X-1.1669 Y1.8996 +G01 X-1.1624 Y1.8977 +G01 X-1.1600 Y1.8975 +G01 X-1.1554 Y1.8975 +G01 X-1.1525 Y1.8975 +G01 X-0.8003 Y1.8975 +G01 X-0.7912 Y1.9066 +G01 X-0.7709 Y1.9150 +G01 X-0.7491 Y1.9150 +G01 X-0.7288 Y1.9066 +G01 X-0.7197 Y1.8975 +G01 X-0.2641 Y1.8975 +G01 X-0.2543 Y1.8975 +G01 X-0.2214 Y1.8868 +G01 X-0.1935 Y1.8665 +G01 X-0.1789 Y1.8464 +G01 X-0.1202 Y1.8464 +G01 X-0.0989 Y1.8376 +G01 X-0.0826 Y1.8213 +G01 X-0.0738 Y1.8000 +G01 X-0.0738 Y1.7769 +G01 X-0.0826 Y1.7556 +G01 X-0.0989 Y1.7393 +G01 X-0.1202 Y1.7304 +G01 X-0.2798 Y1.7304 +G01 X-0.3011 Y1.7393 +G01 X-0.3174 Y1.7556 +G01 X-0.3262 Y1.7769 +G01 X-0.3262 Y1.8000 +G01 X-0.3174 Y1.8213 +G01 X-0.3162 Y1.8225 +G01 X-0.7197 Y1.8225 +G01 X-0.7288 Y1.8134 +G01 X-0.7491 Y1.8050 +G01 X-0.7709 Y1.8050 +G01 X-0.7912 Y1.8134 +G01 X-0.8003 Y1.8225 +G01 X-1.1525 Y1.8225 +G01 X-1.1554 Y1.8225 +G01 X-1.1675 Y1.8225 +G01 X-1.1774 Y1.8225 +G01 X-1.2096 Y1.8358 +G01 X-1.2342 Y1.8604 +G01 X-1.2475 Y1.8926 +G01 X-1.2475 Y1.9100 +G01 X-1.2475 Y2.0525 +G01 X-1.2475 Y2.0600 +G01 X-1.2477 Y2.0624 +G01 X-1.2496 Y2.0669 +G01 X-1.2531 Y2.0704 +G01 X-1.2576 Y2.0723 +G01 X-1.2600 Y2.0725 +G01 X-1.6625 Y2.0725 +G01 X-1.6700 Y2.0725 +G01 X-1.6724 Y2.0723 +G01 X-1.6769 Y2.0704 +G01 X-1.6804 Y2.0669 +G01 X-1.6823 Y2.0624 +G01 X-1.6825 Y2.0600 +G01 X-1.6825 Y1.9675 +G01 X-1.6825 Y1.9659 +G01 X-1.6825 Y1.9525 +G01 X-1.6825 Y1.9426 +G01 X-1.6958 Y1.9104 +G01 X-1.7204 Y1.8858 +G01 X-1.7526 Y1.8725 +G01 X-1.7625 Y1.8725 +G01 X-1.9661 Y1.8725 +G01 X-1.9791 Y1.8595 +G01 X-2.0209 Y1.8595 +G01 X-2.0339 Y1.8725 +G01 X-2.0525 Y1.8725 +G01 X-2.0525 Y1.7500 +G01 X-2.0523 Y1.7476 +G01 X-2.0504 Y1.7431 +G01 X-2.0469 Y1.7396 +G01 X-2.0424 Y1.7377 +G01 X-2.0400 Y1.7375 +G01 X-2.0338 Y1.7375 +G01 X-2.0325 Y1.7375 +G01 X-1.9943 Y1.7375 +G01 X-2.0243 Y1.7675 +G01 X-2.0243 Y1.8125 +G01 X-1.9925 Y1.8443 +G01 X-1.9475 Y1.8443 +G01 X-1.9307 Y1.8275 +G01 X-1.6575 Y1.8275 +G01 X-1.6575 Y1.9675 +G01 X-1.6575 Y1.9774 +G01 X-1.6442 Y2.0096 +G01 X-1.6196 Y2.0342 +G01 X-1.5874 Y2.0475 +G01 X-1.5700 Y2.0475 +G01 X-1.5625 Y2.0475 +G01 X-1.4175 Y2.0475 +G01 X-1.4100 Y2.0475 +G01 X-1.3926 Y2.0475 +G01 X-1.3604 Y2.0342 +G01 X-1.3358 Y2.0096 +G01 X-1.3225 Y1.9774 +G01 X-1.3225 Y1.9675 +G01 X-1.3225 Y1.9587 +G01 X-1.3225 Y1.9525 +G01 X-1.3225 Y1.9003 +G01 X-1.3050 Y1.8828 +G01 X-1.3050 Y1.8372 +G01 X-1.3225 Y1.8197 +G01 X-1.3225 Y1.8100 +G01 X-1.3223 Y1.8076 +G01 X-1.3204 Y1.8031 +G01 X-1.3169 Y1.7996 +G01 X-1.3124 Y1.7977 +G01 X-1.3100 Y1.7975 +G01 X-1.3040 Y1.7975 +G01 X-1.3025 Y1.7975 +G01 X-0.6525 Y1.7975 +G01 X-0.6446 Y1.7975 +G01 X-0.6161 Y1.7857 +G01 X-0.5943 Y1.7639 +G01 X-0.5825 Y1.7354 +G01 X-0.5825 Y1.7275 +G01 X-0.5825 Y1.6575 +G01 X-0.5825 Y1.6500 +G01 X-0.5823 Y1.6476 +G01 X-0.5804 Y1.6431 +G01 X-0.5769 Y1.6396 +G01 X-0.5724 Y1.6377 +G01 X-0.5700 Y1.6375 +G01 X-0.3043 Y1.6375 +G01 X-0.3011 Y1.6407 +G01 X-0.2798 Y1.6496 +G01 X-0.1202 Y1.6496 +G01 X-0.0989 Y1.6407 +G01 X-0.0826 Y1.6244 +G01 X-0.0738 Y1.6031 +G01 X-0.0738 Y1.5800 +G01 X-0.0826 Y1.5587 +G01 X-0.0989 Y1.5424 +G01 X-0.1202 Y1.5336 +G01 X-0.2798 Y1.5336 +G01 X-0.3011 Y1.5424 +G01 X-0.3174 Y1.5587 +G01 X-0.3190 Y1.5625 +G01 X-0.5775 Y1.5625 +G01 X-0.5874 Y1.5625 +G01 X-0.6196 Y1.5758 +G01 X-0.6442 Y1.6004 +G01 X-0.6575 Y1.6326 +G01 X-0.6575 Y1.6425 +G01 X-0.6575 Y1.6500 +G01 X-0.6575 Y1.6575 +G01 X-0.6575 Y1.7200 +G01 X-0.6575 Y1.7205 +G01 X-0.6579 Y1.7214 +G01 X-0.6586 Y1.7221 +G01 X-0.6595 Y1.7225 +G01 X-0.6600 Y1.7225 +G01 X-1.3025 Y1.7225 +G01 X-1.3041 Y1.7225 +G01 X-1.3175 Y1.7225 +G01 X-1.3274 Y1.7225 +G01 X-1.3596 Y1.7358 +G01 X-1.3842 Y1.7604 +G01 X-1.3975 Y1.7926 +G01 X-1.3975 Y1.8025 +G01 X-1.3975 Y1.8197 +G01 X-1.4150 Y1.8372 +G01 X-1.4150 Y1.8828 +G01 X-1.3975 Y1.9003 +G01 X-1.3975 Y1.9525 +G01 X-1.3975 Y1.9587 +G01 X-1.3975 Y1.9600 +G01 X-1.3977 Y1.9624 +G01 X-1.3996 Y1.9669 +G01 X-1.4031 Y1.9704 +G01 X-1.4076 Y1.9723 +G01 X-1.4100 Y1.9725 +G01 X-1.4175 Y1.9725 +G01 X-1.5625 Y1.9725 +G01 X-1.5700 Y1.9725 +G01 X-1.5724 Y1.9723 +G01 X-1.5769 Y1.9704 +G01 X-1.5804 Y1.9669 +G01 X-1.5823 Y1.9624 +G01 X-1.5825 Y1.9600 +G01 X-1.5825 Y1.7975 +G01 X-1.5825 Y1.7725 +G01 X-1.5825 Y1.6375 +G01 X-1.5825 Y1.6300 +G01 X-1.5823 Y1.6276 +G01 X-1.5804 Y1.6231 +G01 X-1.5769 Y1.6196 +G01 X-1.5724 Y1.6177 +G01 X-1.5700 Y1.6175 +G01 X-1.5692 Y1.6175 +G01 X-1.5625 Y1.6175 +G01 X-1.1425 Y1.6175 +G01 X-1.1326 Y1.6175 +G01 X-1.1004 Y1.6042 +G01 X-1.0758 Y1.5796 +G01 X-1.0625 Y1.5474 +G01 X-1.0625 Y1.5300 +G01 X-1.0625 Y1.5225 +G01 X-1.0625 Y0.8600 +G01 X-1.0623 Y0.8576 +G01 X-1.0604 Y0.8531 +G01 X-1.0569 Y0.8496 +G01 X-1.0524 Y0.8477 +G01 X-1.0500 Y0.8475 +G01 X-1.0434 Y0.8475 +G01 X-1.0425 Y0.8475 +G01 X-1.0409 Y0.8475 +G01 X-1.0356 Y0.8528 +G01 X-1.0182 Y0.8600 +G01 X-1.0356 Y0.8672 +G01 X-1.0498 Y0.8814 +G01 X-1.0575 Y0.9000 +G01 X-1.0575 Y0.9200 +G01 X-1.0498 Y0.9386 +G01 X-1.0356 Y0.9528 +G01 X-1.0182 Y0.9600 +G01 X-1.0356 Y0.9672 +G01 X-1.0498 Y0.9814 +G01 X-1.0575 Y1.0000 +G01 X-1.0575 Y1.0200 +G01 X-1.0498 Y1.0386 +G01 X-1.0356 Y1.0528 +G01 X-1.0182 Y1.0600 +G01 X-1.0356 Y1.0672 +G01 X-1.0498 Y1.0814 +G01 X-1.0575 Y1.1000 +G01 X-1.0575 Y1.1200 +G01 X-1.0498 Y1.1386 +G01 X-1.0356 Y1.1528 +G01 X-1.0182 Y1.1600 +G01 X-1.0356 Y1.1672 +G01 X-1.0498 Y1.1814 +G01 X-1.0575 Y1.2000 +G01 X-1.0575 Y1.2200 +G01 X-1.0498 Y1.2386 +G01 X-1.0356 Y1.2528 +G01 X-1.0182 Y1.2600 +G01 X-1.0356 Y1.2672 +G01 X-1.0498 Y1.2814 +G01 X-1.0575 Y1.3000 +G01 X-1.0575 Y1.3200 +G01 X-1.0498 Y1.3386 +G01 X-1.0356 Y1.3528 +G01 X-1.0182 Y1.3600 +G01 X-1.0356 Y1.3672 +G01 X-1.0498 Y1.3814 +G01 X-1.0575 Y1.4000 +G01 X-1.0575 Y1.4200 +G01 X-1.0498 Y1.4386 +G01 X-1.0356 Y1.4528 +G01 X-1.0170 Y1.4605 +G01 X-0.8830 Y1.4605 +G01 X-0.8644 Y1.4528 +G01 X-0.8591 Y1.4475 +G01 X-0.5825 Y1.4475 +G01 X-0.5726 Y1.4475 +G01 X-0.5404 Y1.4342 +G01 X-0.5158 Y1.4096 +G01 X-0.5025 Y1.3774 +G01 X-0.5025 Y1.3675 +G01 X-0.5025 Y1.3600 +G01 X-0.5025 Y1.3584 +G01 X-0.5023 Y1.3560 +G01 X-0.5004 Y1.3515 +G01 X-0.4969 Y1.3480 +G01 X-0.4924 Y1.3462 +G01 X-0.4900 Y1.3459 +G01 X-0.4854 Y1.3459 +G01 X-0.4825 Y1.3459 +G01 X-0.3128 Y1.3459 +G01 X-0.3011 Y1.3576 +G01 X-0.2798 Y1.3664 +G01 X-0.1202 Y1.3664 +G01 X-0.0989 Y1.3576 +G01 X-0.0826 Y1.3413 +G01 X-0.0738 Y1.3200 +G01 X-0.0738 Y1.2969 +G01 X-0.0826 Y1.2756 +G01 X-0.0989 Y1.2593 +G01 X-0.1202 Y1.2504 +G01 X-0.2798 Y1.2504 +G01 X-0.3011 Y1.2593 +G01 X-0.3128 Y1.2709 +G01 X-0.4825 Y1.2709 +G01 X-0.4854 Y1.2709 +G01 X-0.4975 Y1.2709 +G01 X-0.5074 Y1.2709 +G01 X-0.5396 Y1.2842 +G01 X-0.5642 Y1.3089 +G01 X-0.5775 Y1.3410 +G01 X-0.5775 Y1.3510 +G01 X-0.5775 Y1.3525 +G01 X-0.5775 Y1.3600 +G01 X-0.5777 Y1.3624 +G01 X-0.5796 Y1.3669 +G01 X-0.5831 Y1.3704 +G01 X-0.5876 Y1.3723 +G01 X-0.5900 Y1.3725 +G01 X-0.8591 Y1.3725 +G01 X-0.8644 Y1.3672 +G01 X-0.8818 Y1.3600 +G01 X-0.8644 Y1.3528 +G01 X-0.8591 Y1.3475 +G01 X-0.7539 Y1.3475 +G01 X-0.7409 Y1.3605 +G01 X-0.6991 Y1.3605 +G01 X-0.6695 Y1.3309 +G01 X-0.6695 Y1.2891 +G01 X-0.6991 Y1.2595 +G01 X-0.7409 Y1.2595 +G01 X-0.7539 Y1.2725 +G01 X-0.8591 Y1.2725 +G01 X-0.8644 Y1.2672 +G01 X-0.8818 Y1.2600 +G01 X-0.8644 Y1.2528 +G01 X-0.8591 Y1.2475 +G01 X-0.4475 Y1.2475 +G01 X-0.4400 Y1.2475 +G01 X-0.4325 Y1.2475 +G01 X-0.4246 Y1.2475 +G01 X-0.3961 Y1.2357 +G01 X-0.3743 Y1.2139 +G01 X-0.3625 Y1.1854 +G01 X-0.3625 Y1.1775 +G01 X-0.3625 Y1.1616 +G01 X-0.3623 Y1.1591 +G01 X-0.3604 Y1.1546 +G01 X-0.3569 Y1.1512 +G01 X-0.3524 Y1.1493 +G01 X-0.3500 Y1.1491 +G01 X-0.3437 Y1.1491 +G01 X-0.3425 Y1.1491 +G01 X-0.3128 Y1.1491 +G01 X-0.3011 Y1.1607 +G01 X-0.2798 Y1.1696 +G01 X-0.1202 Y1.1696 +G01 X-0.0989 Y1.1607 +G01 X-0.0826 Y1.1444 +G01 X-0.0738 Y1.1231 +G01 X-0.0738 Y1.1000 +G01 X-0.0826 Y1.0787 +G01 X-0.0989 Y1.0624 +G01 X-0.1202 Y1.0536 +G01 X-0.2798 Y1.0536 +G01 X-0.3011 Y1.0624 +G01 X-0.3128 Y1.0741 +G01 X-0.3425 Y1.0741 +G01 X-0.3437 Y1.0741 +G01 X-0.3575 Y1.0741 +G01 X-0.3674 Y1.0741 +G01 X-0.3996 Y1.0874 +G01 X-0.4242 Y1.1120 +G01 X-0.4375 Y1.1442 +G01 X-0.4375 Y1.1541 +G01 X-0.4375 Y1.1700 +G01 X-0.4375 Y1.1705 +G01 X-0.4379 Y1.1714 +G01 X-0.4386 Y1.1721 +G01 X-0.4395 Y1.1725 +G01 X-0.4400 Y1.1725 +G01 X-0.4475 Y1.1725 +G01 X-0.8591 Y1.1725 +G01 X-0.8644 Y1.1672 +G01 X-0.8818 Y1.1600 +G01 X-0.8644 Y1.1528 +G01 X-0.8591 Y1.1475 +G01 X-0.5939 Y1.1475 +G01 X-0.5809 Y1.1605 +G01 X-0.5391 Y1.1605 +G01 X-0.5095 Y1.1309 +G01 X-0.5095 Y1.0891 +G01 X-0.5391 Y1.0595 +G01 X-0.5809 Y1.0595 +G01 X-0.5939 Y1.0725 +G01 X-0.8591 Y1.0725 +G01 X-0.8644 Y1.0672 +G01 X-0.8818 Y1.0600 +G01 X-0.8644 Y1.0528 +G01 X-0.8591 Y1.0475 +G01 X-0.4875 Y1.0475 +G01 X-0.4839 Y1.0475 +G01 X-0.4725 Y1.0475 +G01 X-0.4626 Y1.0475 +G01 X-0.4304 Y1.0342 +G01 X-0.4058 Y1.0096 +G01 X-0.3925 Y0.9774 +G01 X-0.3925 Y0.9675 +G01 X-0.3925 Y0.9575 +G01 X-0.3925 Y0.9500 +G01 X-0.3925 Y0.9495 +G01 X-0.3921 Y0.9486 +G01 X-0.3914 Y0.9479 +G01 X-0.3905 Y0.9475 +G01 X-0.3900 Y0.9475 +G01 X-0.3112 Y0.9475 +G01 X-0.3011 Y0.9576 +G01 X-0.2798 Y0.9664 +G01 X-0.1202 Y0.9664 +G01 X-0.0989 Y0.9576 +G01 X-0.0826 Y0.9413 +G01 X-0.0738 Y0.9200 +G01 X-0.0738 Y0.8969 +G01 X-0.0826 Y0.8756 +G01 X-0.0989 Y0.8593 +G01 X-0.1202 Y0.8504 +G01 X-0.2798 Y0.8504 +G01 X-0.3011 Y0.8593 +G01 X-0.3143 Y0.8725 +G01 X-0.3975 Y0.8725 +G01 X-0.4054 Y0.8725 +G01 X-0.4339 Y0.8843 +G01 X-0.4557 Y0.9061 +G01 X-0.4675 Y0.9346 +G01 X-0.4675 Y0.9425 +G01 X-0.4675 Y0.9499 +G01 X-0.4675 Y0.9575 +G01 X-0.4675 Y0.9600 +G01 X-0.4677 Y0.9624 +G01 X-0.4696 Y0.9669 +G01 X-0.4731 Y0.9704 +G01 X-0.4776 Y0.9723 +G01 X-0.4800 Y0.9725 +G01 X-0.4839 Y0.9725 +G01 X-0.4875 Y0.9725 +G01 X-0.8591 Y0.9725 +G01 X-0.8644 Y0.9672 +G01 X-0.8818 Y0.9600 +G01 X-0.8644 Y0.9528 +G01 X-0.8591 Y0.9475 +G01 X-0.8375 Y0.9475 +G01 X-0.8353 Y0.9475 +G01 X-0.8225 Y0.9475 +G01 X-0.8126 Y0.9475 +G01 X-0.7804 Y0.9342 +G01 X-0.7558 Y0.9096 +G01 X-0.7425 Y0.8774 +G01 X-0.7425 Y0.8675 +G01 X-0.7425 Y0.5739 +G01 X-0.7295 Y0.5609 +G01 X-0.7295 Y0.5191 +G01 X-0.7591 Y0.4895 +G01 X-0.8009 Y0.4895 +G01 X-0.8305 Y0.5191 +G01 X-0.8305 Y0.5609 +G01 X-0.8175 Y0.5739 +G01 X-0.8175 Y0.8600 +G01 X-0.8177 Y0.8624 +G01 X-0.8196 Y0.8669 +G01 X-0.8231 Y0.8704 +G01 X-0.8276 Y0.8723 +G01 X-0.8300 Y0.8725 +G01 X-0.8353 Y0.8725 +G01 X-0.8375 Y0.8725 +G01 X-0.8591 Y0.8725 +G01 X-0.8644 Y0.8672 +G01 X-0.8818 Y0.8600 +G01 X-0.8644 Y0.8528 +G01 X-0.8502 Y0.8386 +G01 X-0.8425 Y0.8200 +G01 X-0.8425 Y0.8000 +G01 X-0.8502 Y0.7814 +G01 X-0.8644 Y0.7672 +G01 X-0.8830 Y0.7595 +G01 X-1.0170 Y0.7595 +G01 X-1.0356 Y0.7672 +G01 X-1.0409 Y0.7725 +G01 X-1.0425 Y0.7725 +G01 X-1.0434 Y0.7725 +G01 X-1.0575 Y0.7725 +G01 X-1.0674 Y0.7725 +G01 X-1.0996 Y0.7858 +G01 X-1.1242 Y0.8104 +G01 X-1.1375 Y0.8426 +G01 X-1.1375 Y0.8525 +G01 X-1.1375 Y1.5225 +G01 X-1.1375 Y1.5300 +G01 X-1.1377 Y1.5324 +G01 X-1.1396 Y1.5369 +G01 X-1.1431 Y1.5404 +G01 X-1.1476 Y1.5423 +G01 X-1.1500 Y1.5425 +G01 X-1.5625 Y1.5425 +G01 X-1.5692 Y1.5425 +G01 X-1.5775 Y1.5425 +G01 X-1.5874 Y1.5425 +G01 X-1.6196 Y1.5558 +G01 X-1.6442 Y1.5804 +G01 X-1.6575 Y1.6126 +G01 X-1.6575 Y1.6225 +G01 X-1.6575 Y1.6270 +G01 X-1.6575 Y1.6300 +G01 X-1.6575 Y1.6375 +G01 X-1.6575 Y1.7525 +G01 X-1.9307 Y1.7525 +G01 X-1.9457 Y1.7375 +G01 X-1.8039 Y1.7375 +G01 X-1.7909 Y1.7505 +G01 X-1.7491 Y1.7505 +G01 X-1.7361 Y1.7375 +G01 X-1.7325 Y1.7375 +G01 X-1.7266 Y1.7375 +G01 X-1.7018 Y1.7272 +G01 X-1.6828 Y1.7082 +G01 X-1.6725 Y1.6834 +G01 X-1.6725 Y1.6775 +G01 X-1.6725 Y1.6646 +G01 X-1.6725 Y1.6625 +G01 X-1.6725 Y1.5100 +G01 X-1.6723 Y1.5076 +G01 X-1.6704 Y1.5031 +G01 X-1.6669 Y1.4996 +G01 X-1.6624 Y1.4977 +G01 X-1.6600 Y1.4975 +G01 X-1.6571 Y1.4975 +G01 X-1.6525 Y1.4975 +G01 X-1.4675 Y1.4975 +G01 X-1.4600 Y1.4975 +G01 X-1.4426 Y1.4975 +G01 X-1.4104 Y1.4842 +G01 X-1.3858 Y1.4596 +G01 X-1.3803 Y1.4463 +G01 X-1.3774 Y1.4475 +G01 X-1.3675 Y1.4475 +G01 X-1.3594 Y1.4475 +G01 X-1.3525 Y1.4475 +G01 X-1.3409 Y1.4475 +G01 X-1.3356 Y1.4528 +G01 X-1.3170 Y1.4605 +G01 X-1.1830 Y1.4605 +G01 X-1.1644 Y1.4528 +G01 X-1.1502 Y1.4386 +G01 X-1.1425 Y1.4200 +G01 X-1.1425 Y1.4000 +G01 X-1.1502 Y1.3814 +G01 X-1.1644 Y1.3672 +G01 X-1.1818 Y1.3600 +G01 X-1.1644 Y1.3528 +G01 X-1.1502 Y1.3386 +G01 X-1.1425 Y1.3200 +G01 X-1.1425 Y1.3000 +G01 X-1.1502 Y1.2814 +G01 X-1.1644 Y1.2672 +G01 X-1.1818 Y1.2600 +G01 X-1.1644 Y1.2528 +G01 X-1.1502 Y1.2386 +G01 X-1.1425 Y1.2200 +G01 X-1.1425 Y1.2000 +G01 X-1.1502 Y1.1814 +G01 X-1.1644 Y1.1672 +G01 X-1.1818 Y1.1600 +G01 X-1.1644 Y1.1528 +G01 X-1.1502 Y1.1386 +G01 X-1.1425 Y1.1200 +G01 X-1.1425 Y1.1000 +G01 X-1.1502 Y1.0814 +G01 X-1.1644 Y1.0672 +G01 X-1.1818 Y1.0600 +G01 X-1.1644 Y1.0528 +G01 X-1.1502 Y1.0386 +G01 X-1.1425 Y1.0200 +G01 X-1.1425 Y1.0000 +G01 X-1.1502 Y0.9814 +G01 X-1.1644 Y0.9672 +G01 X-1.1818 Y0.9600 +G01 X-1.1644 Y0.9528 +G01 X-1.1502 Y0.9386 +G01 X-1.1425 Y0.9200 +G01 X-1.1425 Y0.9000 +G01 X-1.1502 Y0.8814 +G01 X-1.1644 Y0.8672 +G01 X-1.1818 Y0.8600 +G01 X-1.1644 Y0.8528 +G01 X-1.1502 Y0.8386 +G01 X-1.1425 Y0.8200 +G01 X-1.1425 Y0.8000 +G01 X-1.1502 Y0.7814 +G01 X-1.1644 Y0.7672 +G01 X-1.1830 Y0.7595 +G01 X-1.3170 Y0.7595 +G01 X-1.3356 Y0.7672 +G01 X-1.3409 Y0.7725 +G01 X-1.5000 Y0.7725 +G01 X-1.5024 Y0.7723 +G01 X-1.5069 Y0.7704 +G01 X-1.5104 Y0.7669 +G01 X-1.5123 Y0.7624 +G01 X-1.5125 Y0.7600 +G01 X-1.5125 Y0.7539 +G01 X-1.5125 Y0.7525 +G01 X-1.5125 Y0.6939 +G01 X-1.4995 Y0.6809 +G01 X-1.4995 Y0.6391 +G01 X-1.5291 Y0.6095 +G01 X-1.5709 Y0.6095 +G01 X-1.6005 Y0.6391 +G01 X-1.6005 Y0.6809 +G01 X-1.5875 Y0.6939 +G01 X-1.5875 Y0.7525 +G01 X-1.5875 Y0.7539 +G01 X-1.5875 Y0.7675 +G01 X-1.5875 Y0.7774 +G01 X-1.5742 Y0.8096 +G01 X-1.5496 Y0.8342 +G01 X-1.5174 Y0.8475 +G01 X-1.5075 Y0.8475 +G01 X-1.3409 Y0.8475 +G01 X-1.3356 Y0.8528 +G01 X-1.3182 Y0.8600 +G01 X-1.3356 Y0.8672 +G01 X-1.3409 Y0.8725 +G01 X-1.5925 Y0.8725 +G01 X-1.5993 Y0.8725 +G01 X-1.6000 Y0.8725 +G01 X-1.6024 Y0.8723 +G01 X-1.6069 Y0.8704 +G01 X-1.6104 Y0.8669 +G01 X-1.6123 Y0.8624 +G01 X-1.6125 Y0.8600 +G01 X-1.6125 Y0.1500 +G01 X-1.6123 Y0.1476 +G01 X-1.6104 Y0.1431 +G01 X-1.6069 Y0.1396 +G01 X-1.6024 Y0.1377 +G01 X-1.6000 Y0.1375 +G01 X-1.5925 Y0.1375 +G01 X-1.1475 Y0.1375 +G01 X-1.1400 Y0.1375 +G01 X-1.1376 Y0.1377 +G01 X-1.1331 Y0.1396 +G01 X-1.1296 Y0.1431 +G01 X-1.1277 Y0.1476 +G01 X-1.1275 Y0.1500 +G01 X-1.1275 Y0.1925 +G01 X-1.1275 Y0.1947 +G01 X-1.1275 Y0.2075 +G01 X-1.1275 Y0.2174 +G01 X-1.1142 Y0.2496 +G01 X-1.0896 Y0.2742 +G01 X-1.0574 Y0.2875 +G01 X-1.0475 Y0.2875 +G01 X-0.5175 Y0.2875 +G01 X-0.5100 Y0.2875 +G01 X-0.5076 Y0.2877 +G01 X-0.5031 Y0.2896 +G01 X-0.4996 Y0.2931 +G01 X-0.4977 Y0.2976 +G01 X-0.4975 Y0.3000 +G01 X-0.4975 Y0.6525 +G01 X-0.4975 Y0.6536 +G01 X-0.4975 Y0.6675 +G01 X-0.4975 Y0.6774 +G01 X-0.4842 Y0.7096 +G01 X-0.4596 Y0.7342 +G01 X-0.4274 Y0.7475 +G01 X-0.4100 Y0.7475 +G01 X-0.3143 Y0.7475 +G01 X-0.3011 Y0.7607 +G01 X-0.2798 Y0.7696 +G01 X-0.1202 Y0.7696 +G01 X-0.0989 Y0.7607 +G01 X-0.0826 Y0.7444 +G01 X-0.0738 Y0.7231 +G01 X-0.0738 Y0.7000 +G01 X-0.0826 Y0.6787 +G01 X-0.0989 Y0.6624 +G01 X-0.1202 Y0.6536 +G01 X-0.2798 Y0.6536 +G01 X-0.3011 Y0.6624 +G01 X-0.3112 Y0.6725 +G01 X-0.4100 Y0.6725 +G01 X-0.4124 Y0.6723 +G01 X-0.4169 Y0.6704 +G01 X-0.4204 Y0.6669 +G01 X-0.4223 Y0.6624 +G01 X-0.4225 Y0.6600 +G01 X-0.4225 Y0.6536 +G01 X-0.4225 Y0.6525 +G01 X-0.4225 Y0.2925 +G01 X-0.4225 Y0.2826 +G00 Z0.1000 +G00 X-0.5225 Y0.4726 +G01 Z-0.0070 F10 +G01 X-0.5225 Y0.4726 F20 +G01 X-0.5358 Y0.4404 +G01 X-0.5604 Y0.4158 +G01 X-0.5926 Y0.4025 +G01 X-0.6025 Y0.4025 +G01 X-0.6108 Y0.4025 +G01 X-0.6175 Y0.4025 +G01 X-1.3775 Y0.4025 +G01 X-1.3874 Y0.4025 +G01 X-1.4196 Y0.4158 +G01 X-1.4442 Y0.4404 +G01 X-1.4484 Y0.4506 +G01 X-1.4520 Y0.4521 +G01 X-1.4679 Y0.4680 +G01 X-1.4765 Y0.4888 +G01 X-1.4765 Y0.5112 +G01 X-1.4679 Y0.5320 +G01 X-1.4675 Y0.5324 +G01 X-1.4675 Y0.6761 +G01 X-1.4805 Y0.6891 +G01 X-1.4805 Y0.7309 +G01 X-1.4509 Y0.7605 +G01 X-1.4091 Y0.7605 +G01 X-1.3795 Y0.7309 +G01 X-1.3795 Y0.6891 +G01 X-1.3925 Y0.6761 +G01 X-1.3925 Y0.5498 +G01 X-1.3880 Y0.5479 +G01 X-1.3721 Y0.5320 +G01 X-1.3635 Y0.5112 +G01 X-1.3635 Y0.4888 +G01 X-1.3682 Y0.4775 +G01 X-0.6175 Y0.4775 +G01 X-0.6107 Y0.4775 +G01 X-0.6100 Y0.4775 +G01 X-0.6076 Y0.4777 +G01 X-0.6031 Y0.4796 +G01 X-0.5996 Y0.4831 +G01 X-0.5977 Y0.4876 +G01 X-0.5975 Y0.4900 +G01 X-0.5975 Y0.8761 +G01 X-0.6105 Y0.8891 +G01 X-0.6105 Y0.9309 +G01 X-0.5809 Y0.9605 +G01 X-0.5391 Y0.9605 +G01 X-0.5095 Y0.9309 +G01 X-0.5095 Y0.8891 +G01 X-0.5225 Y0.8761 +G01 X-0.5225 Y0.4825 +G01 X-0.5225 Y0.4726 +G00 Z0.1000 +G00 X-1.5565 Y1.6988 +G01 Z-0.0070 F10 +G01 X-1.5565 Y1.7212 F20 +G01 X-1.5479 Y1.7420 +G01 X-1.5375 Y1.7524 +G01 X-1.5375 Y1.8761 +G01 X-1.5505 Y1.8891 +G01 X-1.5505 Y1.9309 +G01 X-1.5209 Y1.9605 +G01 X-1.4791 Y1.9605 +G01 X-1.4495 Y1.9309 +G01 X-1.4495 Y1.8891 +G01 X-1.4625 Y1.8761 +G01 X-1.4625 Y1.7524 +G01 X-1.4521 Y1.7420 +G01 X-1.4435 Y1.7212 +G01 X-1.4435 Y1.7075 +G01 X-0.7625 Y1.7075 +G01 X-0.7526 Y1.7075 +G01 X-0.7204 Y1.6942 +G01 X-0.6958 Y1.6696 +G01 X-0.6825 Y1.6374 +G01 X-0.6825 Y1.6275 +G01 X-0.6825 Y1.5439 +G01 X-0.6695 Y1.5309 +G01 X-0.6695 Y1.4891 +G01 X-0.6991 Y1.4595 +G01 X-0.7409 Y1.4595 +G01 X-0.7705 Y1.4891 +G01 X-0.7705 Y1.5309 +G01 X-0.7575 Y1.5439 +G01 X-0.7575 Y1.6200 +G01 X-0.7577 Y1.6224 +G01 X-0.7596 Y1.6269 +G01 X-0.7631 Y1.6304 +G01 X-0.7676 Y1.6323 +G01 X-0.7700 Y1.6325 +G01 X-1.4480 Y1.6325 +G01 X-1.4622 Y1.6309 +G01 X-1.4938 Y1.6401 +G01 X-1.5106 Y1.6535 +G01 X-1.5112 Y1.6535 +G01 X-1.5320 Y1.6621 +G01 X-1.5479 Y1.6780 +G01 X-1.5565 Y1.6988 +G00 Z0.1000 +G00 X-1.3705 Y0.1791 +G01 Z-0.0070 F10 +G01 X-1.3705 Y0.2209 F20 +G01 X-1.3475 Y0.2439 +G01 X-1.3475 Y0.3025 +G01 X-1.3776 Y0.3025 +G01 X-1.3880 Y0.2921 +G01 X-1.4088 Y0.2835 +G01 X-1.4312 Y0.2835 +G01 X-1.4520 Y0.2921 +G01 X-1.4679 Y0.3080 +G01 X-1.4765 Y0.3288 +G01 X-1.4765 Y0.3512 +G01 X-1.4679 Y0.3720 +G01 X-1.4520 Y0.3879 +G01 X-1.4312 Y0.3965 +G01 X-1.4088 Y0.3965 +G01 X-1.3880 Y0.3879 +G01 X-1.3776 Y0.3775 +G01 X-1.3175 Y0.3775 +G01 X-0.8139 Y0.3775 +G01 X-0.8009 Y0.3905 +G01 X-0.7591 Y0.3905 +G01 X-0.7295 Y0.3609 +G01 X-0.7295 Y0.3191 +G01 X-0.7591 Y0.2895 +G01 X-0.8009 Y0.2895 +G01 X-0.8139 Y0.3025 +G01 X-1.2725 Y0.3025 +G01 X-1.2725 Y0.2239 +G01 X-1.2695 Y0.2209 +G01 X-1.2695 Y0.1791 +G01 X-1.2991 Y0.1495 +G01 X-1.3409 Y0.1495 +G01 X-1.3705 Y0.1791 +G00 Z0.1000 +G00 X-1.9664 Y0.7005 +G01 Z-0.0070 F10 +G01 X-1.7852 Y0.7005 F20 +G01 X-1.7761 Y0.7095 +G01 X-1.9754 Y0.7095 +G01 X-1.9664 Y0.7005 +G00 Z0.1000 +G00 X-1.4457 Y1.5005 +G01 Z-0.0070 F10 +G01 X-1.4457 Y1.5005 F20 +G01 X-1.4184 Y1.4916 +G01 X-1.3952 Y1.4748 +G01 X-1.3784 Y1.4516 +G01 X-1.3776 Y1.4494 +G01 X-1.3743 Y1.4505 +G01 X-1.3681 Y1.4505 +G01 X-1.3607 Y1.4505 +G01 X-1.3600 Y1.4505 +G01 X-1.3519 Y1.4505 +G01 X-1.3422 Y1.4505 +G01 X-1.3373 Y1.4554 +G01 X-1.3176 Y1.4635 +G01 X-1.1824 Y1.4635 +G01 X-1.1627 Y1.4554 +G01 X-1.1476 Y1.4403 +G01 X-1.1405 Y1.4230 +G01 X-1.1405 Y1.5219 +G01 X-1.1405 Y1.5300 +G01 X-1.1406 Y1.5315 +G01 X-1.1415 Y1.5343 +G01 X-1.1433 Y1.5367 +G01 X-1.1457 Y1.5385 +G01 X-1.1485 Y1.5394 +G01 X-1.1500 Y1.5395 +G01 X-1.5619 Y1.5395 +G01 X-1.5685 Y1.5395 +G01 X-1.5781 Y1.5395 +G01 X-1.5843 Y1.5395 +G01 X-1.6116 Y1.5484 +G01 X-1.6348 Y1.5652 +G01 X-1.6516 Y1.5884 +G01 X-1.6605 Y1.6157 +G01 X-1.6605 Y1.6219 +G01 X-1.6605 Y1.6299 +G01 X-1.6605 Y1.6381 +G01 X-1.6605 Y1.7495 +G01 X-1.7438 Y1.7495 +G01 X-1.7348 Y1.7405 +G01 X-1.7319 Y1.7405 +G01 X-1.7260 Y1.7405 +G01 X-1.7001 Y1.7298 +G01 X-1.6802 Y1.7099 +G01 X-1.6695 Y1.6840 +G01 X-1.6695 Y1.6781 +G01 X-1.6695 Y1.6658 +G01 X-1.6695 Y1.6619 +G01 X-1.6695 Y1.5100 +G01 X-1.6694 Y1.5085 +G01 X-1.6685 Y1.5057 +G01 X-1.6667 Y1.5033 +G01 X-1.6643 Y1.5015 +G01 X-1.6615 Y1.5006 +G01 X-1.6600 Y1.5005 +G01 X-1.6534 Y1.5005 +G01 X-1.6519 Y1.5005 +G01 X-1.4519 Y1.5005 +G01 X-1.4457 Y1.5005 +G00 Z0.1000 +G00 X-1.7961 Y1.7495 +G01 Z-0.0070 F10 +G01 X-1.9294 Y1.7495 F20 +G01 X-1.9385 Y1.7405 +G01 X-1.8052 Y1.7405 +G01 X-1.7961 Y1.7495 +G00 Z0.1000 +G00 X-2.6165 Y1.8422 +G01 Z-0.0070 F10 +G01 X-2.6165 Y1.8066 F20 +G01 X-2.6116 Y1.8216 +G01 X-2.5948 Y1.8448 +G01 X-2.5716 Y1.8616 +G01 X-2.5474 Y1.8695 +G01 X-2.6438 Y1.8695 +G01 X-2.6165 Y1.8422 +G00 Z0.1000 +G00 X-2.6205 Y1.7939 +G01 Z-0.0070 F10 +G01 X-2.6443 Y1.7700 F20 +G01 X-2.6348 Y1.7605 +G01 X-2.6300 Y1.7605 +G01 X-2.6285 Y1.7606 +G01 X-2.6257 Y1.7615 +G01 X-2.6233 Y1.7633 +G01 X-2.6215 Y1.7657 +G01 X-2.6206 Y1.7685 +G01 X-2.6205 Y1.7700 +G01 X-2.6205 Y1.7765 +G01 X-2.6205 Y1.7781 +G01 X-2.6205 Y1.7881 +G01 X-2.6205 Y1.7939 +G00 Z0.1000 +G00 X-2.1576 Y1.0797 +G01 Z-0.0070 F10 +G01 X-2.1727 Y1.0646 F20 +G01 X-2.1839 Y1.0600 +G01 X-2.1727 Y1.0554 +G01 X-2.1576 Y1.0403 +G01 X-2.1505 Y1.0230 +G01 X-2.1505 Y1.0970 +G01 X-2.1576 Y1.0797 +G00 Z0.1000 +G00 X-2.1727 Y1.2646 +G01 Z-0.0070 F10 +G01 X-2.1839 Y1.2600 F20 +G01 X-2.1727 Y1.2554 +G01 X-2.1576 Y1.2403 +G01 X-2.1505 Y1.2230 +G01 X-2.1505 Y1.2695 +G01 X-2.1678 Y1.2695 +G01 X-2.1727 Y1.2646 +G00 Z0.1000 +G00 X-2.1576 Y1.1797 +G01 Z-0.0070 F10 +G01 X-2.1727 Y1.1646 F20 +G01 X-2.1839 Y1.1600 +G01 X-2.1727 Y1.1554 +G01 X-2.1576 Y1.1403 +G01 X-2.1505 Y1.1230 +G01 X-2.1505 Y1.1970 +G01 X-2.1576 Y1.1797 +G00 Z0.1000 +G00 X-2.0632 Y1.0505 +G01 Z-0.0070 F10 +G01 X-2.0522 Y1.0505 F20 +G01 X-2.0473 Y1.0554 +G01 X-2.0361 Y1.0600 +G01 X-2.0473 Y1.0646 +G01 X-2.0624 Y1.0797 +G01 X-2.0695 Y1.0970 +G01 X-2.0695 Y1.0568 +G01 X-2.0632 Y1.0505 +G00 Z0.1000 +G00 X-2.0624 Y1.1403 +G01 Z-0.0070 F10 +G01 X-2.0473 Y1.1554 F20 +G01 X-2.0361 Y1.1600 +G01 X-2.0473 Y1.1646 +G01 X-2.0624 Y1.1797 +G01 X-2.0695 Y1.1970 +G01 X-2.0695 Y1.1230 +G01 X-2.0624 Y1.1403 +G00 Z0.1000 +G00 X-2.0624 Y1.2403 +G01 Z-0.0070 F10 +G01 X-2.0473 Y1.2554 F20 +G01 X-2.0361 Y1.2600 +G01 X-2.0473 Y1.2646 +G01 X-2.0624 Y1.2797 +G01 X-2.0695 Y1.2970 +G01 X-2.0695 Y1.2819 +G01 X-2.0695 Y1.2230 +G01 X-2.0624 Y1.2403 +G00 Z0.1000 +G00 X-1.8181 Y1.2695 +G01 Z-0.0070 F10 +G01 X-1.8329 Y1.2757 F20 +G01 X-1.8443 Y1.2871 +G01 X-1.8495 Y1.2995 +G01 X-1.8495 Y1.2994 +G01 X-1.8576 Y1.2797 +G01 X-1.8727 Y1.2646 +G01 X-1.8839 Y1.2600 +G01 X-1.8727 Y1.2554 +G01 X-1.8578 Y1.2405 +G01 X-1.8105 Y1.2405 +G01 X-1.8105 Y1.2695 +G01 X-1.8181 Y1.2695 +G00 Z0.1000 +G00 X-1.8576 Y0.9797 +G01 Z-0.0070 F10 +G01 X-1.8727 Y0.9646 F20 +G01 X-1.8924 Y0.9565 +G01 X-2.0276 Y0.9565 +G01 X-2.0473 Y0.9646 +G01 X-2.0522 Y0.9695 +G01 X-2.0695 Y0.9695 +G01 X-2.0695 Y0.9519 +G01 X-2.0695 Y0.9457 +G01 X-2.0784 Y0.9184 +G01 X-2.0952 Y0.8952 +G01 X-2.1184 Y0.8784 +G01 X-2.1426 Y0.8705 +G01 X-1.8600 Y0.8705 +G01 X-1.8585 Y0.8706 +G01 X-1.8557 Y0.8715 +G01 X-1.8533 Y0.8733 +G01 X-1.8515 Y0.8757 +G01 X-1.8506 Y0.8785 +G01 X-1.8505 Y0.8800 +G01 X-1.8505 Y0.9970 +G01 X-1.8576 Y0.9797 +G00 Z0.1000 +G00 X-1.8727 Y1.0646 +G01 Z-0.0070 F10 +G01 X-1.8839 Y1.0600 F20 +G01 X-1.8727 Y1.0554 +G01 X-1.8576 Y1.0403 +G01 X-1.8505 Y1.0230 +G01 X-1.8505 Y1.0695 +G01 X-1.8678 Y1.0695 +G01 X-1.8727 Y1.0646 +G00 Z0.1000 +G00 X-1.8052 Y1.1595 +G01 Z-0.0070 F10 +G01 X-1.8827 Y1.1595 F20 +G01 X-1.8727 Y1.1554 +G01 X-1.8678 Y1.1505 +G01 X-1.8181 Y1.1505 +G01 X-1.8019 Y1.1505 +G01 X-1.7961 Y1.1505 +G01 X-1.8052 Y1.1595 +G00 Z0.1000 +G00 X-1.7165 Y1.2222 +G01 Z-0.0070 F10 +G01 X-1.7165 Y1.1778 F20 +G01 X-1.7438 Y1.1505 +G01 X-1.3422 Y1.1505 +G01 X-1.3373 Y1.1554 +G01 X-1.3261 Y1.1600 +G01 X-1.3373 Y1.1646 +G01 X-1.3524 Y1.1797 +G01 X-1.3605 Y1.1994 +G01 X-1.3605 Y1.2206 +G01 X-1.3524 Y1.2403 +G01 X-1.3373 Y1.2554 +G01 X-1.3261 Y1.2600 +G01 X-1.3373 Y1.2646 +G01 X-1.3524 Y1.2797 +G01 X-1.3605 Y1.2994 +G01 X-1.3605 Y1.3206 +G01 X-1.3524 Y1.3403 +G01 X-1.3373 Y1.3554 +G01 X-1.3261 Y1.3600 +G01 X-1.3373 Y1.3646 +G01 X-1.3422 Y1.3695 +G01 X-1.3519 Y1.3695 +G01 X-1.3600 Y1.3695 +G01 X-1.3615 Y1.3694 +G01 X-1.3643 Y1.3685 +G01 X-1.3667 Y1.3667 +G01 X-1.3685 Y1.3643 +G01 X-1.3694 Y1.3615 +G01 X-1.3695 Y1.3600 +G01 X-1.3695 Y1.2681 +G01 X-1.3695 Y1.2588 +G01 X-1.3695 Y1.2577 +G01 X-1.3695 Y1.2427 +G01 X-1.3695 Y1.2388 +G01 X-1.3757 Y1.2158 +G01 X-1.3765 Y1.2143 +G01 X-1.3765 Y1.1878 +G01 X-1.4078 Y1.1565 +G01 X-1.4522 Y1.1565 +G01 X-1.4835 Y1.1878 +G01 X-1.4835 Y1.2322 +G01 X-1.4522 Y1.2635 +G01 X-1.4505 Y1.2635 +G01 X-1.4505 Y1.2681 +G01 X-1.4505 Y1.2754 +G01 X-1.4663 Y1.2596 +G01 X-1.4882 Y1.2505 +G01 X-1.5118 Y1.2505 +G01 X-1.5337 Y1.2596 +G01 X-1.5436 Y1.2695 +G01 X-1.5827 Y1.2695 +G01 X-1.5827 Y1.2463 +G01 X-1.6163 Y1.2127 +G01 X-1.6637 Y1.2127 +G01 X-1.6973 Y1.2463 +G01 X-1.6973 Y1.2695 +G01 X-1.7295 Y1.2695 +G01 X-1.7295 Y1.2352 +G01 X-1.7165 Y1.2222 +G00 Z0.1000 +G00 X-2.4795 Y1.4481 +G01 Z-0.0070 F10 +G01 X-2.4795 Y1.4319 F20 +G01 X-2.4795 Y1.2600 +G01 X-2.4794 Y1.2585 +G01 X-2.4785 Y1.2557 +G01 X-2.4767 Y1.2533 +G01 X-2.4743 Y1.2515 +G01 X-2.4715 Y1.2506 +G01 X-2.4700 Y1.2505 +G01 X-2.4633 Y1.2505 +G01 X-2.4619 Y1.2505 +G01 X-2.3522 Y1.2505 +G01 X-2.3473 Y1.2554 +G01 X-2.3361 Y1.2600 +G01 X-2.3473 Y1.2646 +G01 X-2.3624 Y1.2797 +G01 X-2.3705 Y1.2994 +G01 X-2.3705 Y1.3206 +G01 X-2.3624 Y1.3403 +G01 X-2.3473 Y1.3554 +G01 X-2.3276 Y1.3635 +G01 X-2.1924 Y1.3635 +G01 X-2.1727 Y1.3554 +G01 X-2.1678 Y1.3505 +G01 X-2.1381 Y1.3505 +G01 X-2.1219 Y1.3505 +G01 X-2.1180 Y1.3505 +G01 X-2.0957 Y1.3413 +G01 X-2.0787 Y1.3243 +G01 X-2.0705 Y1.3044 +G01 X-2.0705 Y1.3206 +G01 X-2.0624 Y1.3403 +G01 X-2.0473 Y1.3554 +G01 X-2.0276 Y1.3635 +G01 X-2.0005 Y1.3635 +G01 X-2.0005 Y1.4119 +G01 X-2.0005 Y1.4195 +G01 X-2.0105 Y1.4295 +G01 X-2.0181 Y1.4295 +G01 X-2.1694 Y1.4295 +G01 X-2.1863 Y1.4127 +G01 X-2.2337 Y1.4127 +G01 X-2.2388 Y1.4177 +G01 X-2.2420 Y1.4166 +G01 X-2.2420 Y1.4160 +G01 X-2.2760 Y1.3820 +G01 X-2.3240 Y1.3820 +G01 X-2.3580 Y1.4160 +G01 X-2.3580 Y1.4640 +G01 X-2.3240 Y1.4980 +G01 X-2.2760 Y1.4980 +G01 X-2.2705 Y1.4925 +G01 X-2.2673 Y1.4936 +G01 X-2.2673 Y1.4937 +G01 X-2.2337 Y1.5273 +G01 X-2.1863 Y1.5273 +G01 X-2.1694 Y1.5105 +G01 X-2.0181 Y1.5105 +G01 X-2.0105 Y1.5105 +G01 X-1.9937 Y1.5273 +G01 X-1.9463 Y1.5273 +G01 X-1.9127 Y1.4937 +G01 X-1.9127 Y1.4463 +G01 X-1.9208 Y1.4382 +G01 X-1.9195 Y1.4343 +G01 X-1.9195 Y1.4281 +G01 X-1.9195 Y1.4237 +G01 X-1.9195 Y1.4200 +G01 X-1.9195 Y1.4119 +G01 X-1.9195 Y1.3635 +G01 X-1.8924 Y1.3635 +G01 X-1.8727 Y1.3554 +G01 X-1.8576 Y1.3403 +G01 X-1.8505 Y1.3230 +G01 X-1.8505 Y1.5319 +G01 X-1.8505 Y1.5395 +G01 X-2.3319 Y1.5395 +G01 X-2.3337 Y1.5395 +G01 X-2.3481 Y1.5395 +G01 X-2.3543 Y1.5395 +G01 X-2.3816 Y1.5484 +G01 X-2.4048 Y1.5652 +G01 X-2.4216 Y1.5884 +G01 X-2.4305 Y1.6157 +G01 X-2.4305 Y1.6219 +G01 X-2.4305 Y1.6298 +G01 X-2.4435 Y1.6428 +G01 X-2.4435 Y1.6865 +G01 X-2.4595 Y1.6865 +G01 X-2.4595 Y1.6019 +G01 X-2.4657 Y1.5871 +G01 X-2.4771 Y1.5757 +G01 X-2.4795 Y1.5747 +G01 X-2.4795 Y1.4481 +G00 Z0.1000 +G00 X-2.7135 Y1.5878 +G01 Z-0.0070 F10 +G01 X-2.7135 Y1.6322 F20 +G01 X-2.6822 Y1.6635 +G01 X-2.6378 Y1.6635 +G01 X-2.6248 Y1.6505 +G01 X-2.5405 Y1.6505 +G01 X-2.5405 Y1.7019 +G01 X-2.5405 Y1.7100 +G01 X-2.5405 Y1.7181 +G01 X-2.5405 Y1.7240 +G01 X-2.5298 Y1.7499 +G01 X-2.5099 Y1.7698 +G01 X-2.4840 Y1.7805 +G01 X-2.4781 Y1.7805 +G01 X-2.4752 Y1.7805 +G01 X-2.4661 Y1.7895 +G01 X-2.5219 Y1.7895 +G01 X-2.5300 Y1.7895 +G01 X-2.5315 Y1.7894 +G01 X-2.5343 Y1.7885 +G01 X-2.5367 Y1.7867 +G01 X-2.5385 Y1.7843 +G01 X-2.5394 Y1.7815 +G01 X-2.5395 Y1.7800 +G01 X-2.5395 Y1.7781 +G01 X-2.5395 Y1.7765 +G01 X-2.5395 Y1.7619 +G01 X-2.5395 Y1.7557 +G01 X-2.5484 Y1.7284 +G01 X-2.5652 Y1.7052 +G01 X-2.5884 Y1.6884 +G01 X-2.6157 Y1.6795 +G01 X-2.6219 Y1.6795 +G01 X-2.6348 Y1.6795 +G01 X-2.6478 Y1.6665 +G01 X-2.6922 Y1.6665 +G01 X-2.7052 Y1.6795 +G01 X-2.7219 Y1.6795 +G01 X-2.7300 Y1.6795 +G01 X-2.7315 Y1.6794 +G01 X-2.7343 Y1.6785 +G01 X-2.7367 Y1.6767 +G01 X-2.7385 Y1.6743 +G01 X-2.7394 Y1.6715 +G01 X-2.7395 Y1.6700 +G01 X-2.7395 Y1.6631 +G01 X-2.7395 Y1.6619 +G01 X-2.7395 Y1.5919 +G01 X-2.7395 Y1.5840 +G01 X-2.7518 Y1.5544 +G01 X-2.7744 Y1.5318 +G01 X-2.8040 Y1.5195 +G01 X-2.8119 Y1.5195 +G01 X-2.8200 Y1.5195 +G01 X-2.8281 Y1.5195 +G01 X-2.9495 Y1.5195 +G01 X-2.9495 Y1.4720 +G01 X-2.9492 Y1.4729 +G01 X-2.9329 Y1.4892 +G01 X-2.9115 Y1.4980 +G01 X-2.8885 Y1.4980 +G01 X-2.8671 Y1.4892 +G01 X-2.8585 Y1.4805 +G01 X-2.5605 Y1.4805 +G01 X-2.5605 Y1.5695 +G01 X-2.6248 Y1.5695 +G01 X-2.6378 Y1.5565 +G01 X-2.6822 Y1.5565 +G01 X-2.7135 Y1.5878 +G00 Z0.1000 +G00 X-1.1476 Y0.9797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y0.9646 F20 +G01 X-1.1739 Y0.9600 +G01 X-1.1627 Y0.9554 +G01 X-1.1476 Y0.9403 +G01 X-1.1405 Y0.9230 +G01 X-1.1405 Y0.9970 +G01 X-1.1476 Y0.9797 +G00 Z0.1000 +G00 X-1.1476 Y1.0797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y1.0646 F20 +G01 X-1.1739 Y1.0600 +G01 X-1.1627 Y1.0554 +G01 X-1.1476 Y1.0403 +G01 X-1.1405 Y1.0230 +G01 X-1.1405 Y1.0970 +G01 X-1.1476 Y1.0797 +G00 Z0.1000 +G00 X-1.1476 Y1.1797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y1.1646 F20 +G01 X-1.1739 Y1.1600 +G01 X-1.1627 Y1.1554 +G01 X-1.1476 Y1.1403 +G01 X-1.1405 Y1.1230 +G01 X-1.1405 Y1.1970 +G01 X-1.1476 Y1.1797 +G00 Z0.1000 +G00 X-1.1476 Y1.2797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y1.2646 F20 +G01 X-1.1739 Y1.2600 +G01 X-1.1627 Y1.2554 +G01 X-1.1476 Y1.2403 +G01 X-1.1405 Y1.2230 +G01 X-1.1405 Y1.2970 +G01 X-1.1476 Y1.2797 +G00 Z0.1000 +G00 X-1.1476 Y1.3797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y1.3646 F20 +G01 X-1.1739 Y1.3600 +G01 X-1.1627 Y1.3554 +G01 X-1.1476 Y1.3403 +G01 X-1.1405 Y1.3230 +G01 X-1.1405 Y1.3970 +G01 X-1.1476 Y1.3797 +G00 Z0.1000 +G00 X-1.0524 Y1.3403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y1.3554 F20 +G01 X-1.0261 Y1.3600 +G01 X-1.0373 Y1.3646 +G01 X-1.0524 Y1.3797 +G01 X-1.0595 Y1.3970 +G01 X-1.0595 Y1.3230 +G01 X-1.0524 Y1.3403 +G00 Z0.1000 +G00 X-1.0524 Y1.2403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y1.2554 F20 +G01 X-1.0261 Y1.2600 +G01 X-1.0373 Y1.2646 +G01 X-1.0524 Y1.2797 +G01 X-1.0595 Y1.2970 +G01 X-1.0595 Y1.2230 +G01 X-1.0524 Y1.2403 +G00 Z0.1000 +G00 X-1.0524 Y1.1403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y1.1554 F20 +G01 X-1.0261 Y1.1600 +G01 X-1.0373 Y1.1646 +G01 X-1.0524 Y1.1797 +G01 X-1.0595 Y1.1970 +G01 X-1.0595 Y1.1230 +G01 X-1.0524 Y1.1403 +G00 Z0.1000 +G00 X-1.0524 Y1.0403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y1.0554 F20 +G01 X-1.0261 Y1.0600 +G01 X-1.0373 Y1.0646 +G01 X-1.0524 Y1.0797 +G01 X-1.0595 Y1.0970 +G01 X-1.0595 Y1.0230 +G01 X-1.0524 Y1.0403 +G00 Z0.1000 +G00 X-1.0524 Y0.9403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y0.9554 F20 +G01 X-1.0261 Y0.9600 +G01 X-1.0373 Y0.9646 +G01 X-1.0524 Y0.9797 +G01 X-1.0595 Y0.9970 +G01 X-1.0595 Y0.9230 +G01 X-1.0524 Y0.9403 +G00 Z0.1000 +G00 X-1.0594 Y0.8585 +G01 Z-0.0070 F10 +G01 X-1.0585 Y0.8557 F20 +G01 X-1.0567 Y0.8533 +G01 X-1.0543 Y0.8515 +G01 X-1.0515 Y0.8506 +G01 X-1.0500 Y0.8505 +G01 X-1.0429 Y0.8505 +G01 X-1.0422 Y0.8505 +G01 X-1.0373 Y0.8554 +G01 X-1.0261 Y0.8600 +G01 X-1.0373 Y0.8646 +G01 X-1.0524 Y0.8797 +G01 X-1.0595 Y0.8970 +G01 X-1.0595 Y0.8600 +G01 X-1.0594 Y0.8585 +G00 Z0.1000 +G00 X-3.0281 Y1.6905 +G01 Z-0.0070 F10 +G01 X-3.0200 Y1.6905 F20 +G01 X-3.0119 Y1.6905 +G01 X-2.9105 Y1.6905 +G01 X-2.9105 Y1.7616 +G01 X-2.9218 Y1.7344 +G01 X-2.9444 Y1.7118 +G01 X-2.9740 Y1.6995 +G01 X-2.9819 Y1.6995 +G01 X-2.9893 Y1.6995 +G01 X-2.9900 Y1.6995 +G01 X-2.9981 Y1.6995 +G01 X-3.1100 Y1.6995 +G01 X-3.1115 Y1.6994 +G01 X-3.1143 Y1.6985 +G01 X-3.1167 Y1.6967 +G01 X-3.1185 Y1.6943 +G01 X-3.1194 Y1.6915 +G01 X-3.1195 Y1.6900 +G01 X-3.1195 Y1.6831 +G01 X-3.1195 Y1.6819 +G01 X-3.1195 Y1.6452 +G01 X-3.1065 Y1.6322 +G01 X-3.1065 Y1.6266 +G01 X-3.1016 Y1.6416 +G01 X-3.0848 Y1.6648 +G01 X-3.0616 Y1.6816 +G01 X-3.0343 Y1.6905 +G01 X-3.0281 Y1.6905 +G00 Z0.1000 +G00 X-2.3443 Y1.6215 +G01 Z-0.0070 F10 +G01 X-2.3415 Y1.6206 F20 +G01 X-2.3400 Y1.6205 +G01 X-2.3336 Y1.6205 +G01 X-2.3319 Y1.6205 +G01 X-1.8419 Y1.6205 +G01 X-1.8340 Y1.6205 +G01 X-1.8044 Y1.6082 +G01 X-1.7818 Y1.5856 +G01 X-1.7695 Y1.5560 +G01 X-1.7695 Y1.5481 +G01 X-1.7695 Y1.5400 +G01 X-1.7695 Y1.5319 +G01 X-1.7695 Y1.3505 +G01 X-1.7619 Y1.3505 +G01 X-1.6481 Y1.3505 +G01 X-1.6319 Y1.3505 +G01 X-1.5436 Y1.3505 +G01 X-1.5337 Y1.3604 +G01 X-1.5118 Y1.3695 +G01 X-1.4882 Y1.3695 +G01 X-1.4663 Y1.3604 +G01 X-1.4505 Y1.3446 +G01 X-1.4505 Y1.4019 +G01 X-1.4505 Y1.4100 +G01 X-1.4506 Y1.4115 +G01 X-1.4515 Y1.4143 +G01 X-1.4533 Y1.4167 +G01 X-1.4557 Y1.4185 +G01 X-1.4585 Y1.4194 +G01 X-1.4600 Y1.4195 +G01 X-1.6519 Y1.4195 +G01 X-1.6534 Y1.4195 +G01 X-1.6681 Y1.4195 +G01 X-1.6743 Y1.4195 +G01 X-1.7016 Y1.4284 +G01 X-1.7248 Y1.4452 +G01 X-1.7416 Y1.4684 +G01 X-1.7505 Y1.4957 +G01 X-1.7505 Y1.5019 +G01 X-1.7505 Y1.6465 +G01 X-1.7922 Y1.6465 +G01 X-1.8052 Y1.6595 +G01 X-2.0319 Y1.6595 +G01 X-2.0400 Y1.6595 +G01 X-2.0412 Y1.6595 +G01 X-2.0481 Y1.6595 +G01 X-2.0543 Y1.6595 +G01 X-2.0816 Y1.6684 +G01 X-2.1048 Y1.6852 +G01 X-2.1216 Y1.7084 +G01 X-2.1305 Y1.7357 +G01 X-2.1305 Y1.7419 +G01 X-2.1305 Y1.7496 +G01 X-2.1305 Y1.7500 +G01 X-2.1305 Y1.7581 +G01 X-2.1305 Y1.8695 +G01 X-2.3726 Y1.8695 +G01 X-2.3484 Y1.8616 +G01 X-2.3252 Y1.8448 +G01 X-2.3084 Y1.8216 +G01 X-2.2995 Y1.7943 +G01 X-2.2995 Y1.7881 +G01 X-2.2995 Y1.7805 +G01 X-2.2505 Y1.7805 +G01 X-2.2337 Y1.7973 +G01 X-2.1863 Y1.7973 +G01 X-2.1527 Y1.7637 +G01 X-2.1527 Y1.7163 +G01 X-2.1863 Y1.6827 +G01 X-2.2337 Y1.6827 +G01 X-2.2505 Y1.6995 +G01 X-2.3048 Y1.6995 +G01 X-2.3178 Y1.6865 +G01 X-2.3365 Y1.6865 +G01 X-2.3365 Y1.6428 +G01 X-2.3495 Y1.6299 +G01 X-2.3494 Y1.6285 +G01 X-2.3485 Y1.6257 +G01 X-2.3467 Y1.6233 +G01 X-2.3443 Y1.6215 +G00 Z0.1000 +G00 X-2.6922 Y1.3035 +G01 Z-0.0070 F10 +G01 X-2.6478 Y1.3035 F20 +G01 X-2.6165 Y1.2722 +G01 X-2.6165 Y1.2278 +G01 X-2.6478 Y1.1965 +G01 X-2.6772 Y1.1965 +G01 X-2.6999 Y1.1919 +G01 X-2.7298 Y1.1979 +G01 X-2.7323 Y1.1995 +G01 X-3.0119 Y1.1995 +G01 X-3.0129 Y1.1995 +G01 X-3.0281 Y1.1995 +G01 X-3.0343 Y1.1995 +G01 X-3.0616 Y1.2084 +G01 X-3.0848 Y1.2252 +G01 X-3.1016 Y1.2484 +G01 X-3.1105 Y1.2757 +G01 X-3.1105 Y1.2819 +G01 X-3.1105 Y1.5838 +G01 X-3.1195 Y1.5748 +G01 X-3.1195 Y0.9600 +G01 X-3.1194 Y0.9585 +G01 X-3.1185 Y0.9557 +G01 X-3.1167 Y0.9533 +G01 X-3.1143 Y0.9515 +G01 X-3.1115 Y0.9506 +G01 X-3.1100 Y0.9505 +G01 X-3.1050 Y0.9505 +G01 X-3.1019 Y0.9505 +G01 X-2.5505 Y0.9505 +G01 X-2.5337 Y0.9673 +G01 X-2.4863 Y0.9673 +G01 X-2.4694 Y0.9505 +G01 X-2.1681 Y0.9505 +G01 X-2.1600 Y0.9505 +G01 X-2.1585 Y0.9506 +G01 X-2.1557 Y0.9515 +G01 X-2.1533 Y0.9533 +G01 X-2.1515 Y0.9557 +G01 X-2.1506 Y0.9585 +G01 X-2.1505 Y0.9600 +G01 X-2.1505 Y0.9970 +G01 X-2.1576 Y0.9797 +G01 X-2.1727 Y0.9646 +G01 X-2.1924 Y0.9565 +G01 X-2.3276 Y0.9565 +G01 X-2.3473 Y0.9646 +G01 X-2.3522 Y0.9695 +G01 X-2.8919 Y0.9695 +G01 X-2.8929 Y0.9695 +G01 X-2.9081 Y0.9695 +G01 X-2.9143 Y0.9695 +G01 X-2.9416 Y0.9784 +G01 X-2.9648 Y0.9952 +G01 X-2.9816 Y1.0184 +G01 X-2.9905 Y1.0457 +G01 X-2.9905 Y1.0519 +G01 X-2.9905 Y1.0948 +G01 X-3.0035 Y1.1078 +G01 X-3.0035 Y1.1522 +G01 X-2.9722 Y1.1835 +G01 X-2.9278 Y1.1835 +G01 X-2.8965 Y1.1522 +G01 X-2.8965 Y1.1078 +G01 X-2.9095 Y1.0948 +G01 X-2.9095 Y1.0600 +G01 X-2.9094 Y1.0585 +G01 X-2.9085 Y1.0557 +G01 X-2.9067 Y1.0533 +G01 X-2.9043 Y1.0515 +G01 X-2.9015 Y1.0506 +G01 X-2.9000 Y1.0505 +G01 X-2.8929 Y1.0505 +G01 X-2.8919 Y1.0505 +G01 X-2.3522 Y1.0505 +G01 X-2.3473 Y1.0554 +G01 X-2.3361 Y1.0600 +G01 X-2.3473 Y1.0646 +G01 X-2.3624 Y1.0797 +G01 X-2.3705 Y1.0994 +G01 X-2.3705 Y1.1206 +G01 X-2.3624 Y1.1403 +G01 X-2.3473 Y1.1554 +G01 X-2.3361 Y1.1600 +G01 X-2.3473 Y1.1646 +G01 X-2.3522 Y1.1695 +G01 X-2.4619 Y1.1695 +G01 X-2.4633 Y1.1695 +G01 X-2.4781 Y1.1695 +G01 X-2.4843 Y1.1695 +G01 X-2.5116 Y1.1784 +G01 X-2.5348 Y1.1952 +G01 X-2.5516 Y1.2184 +G01 X-2.5605 Y1.2457 +G01 X-2.5605 Y1.2519 +G01 X-2.5605 Y1.3995 +G01 X-2.8585 Y1.3995 +G01 X-2.8671 Y1.3908 +G01 X-2.8885 Y1.3820 +G01 X-2.9115 Y1.3820 +G01 X-2.9329 Y1.3908 +G01 X-2.9492 Y1.4071 +G01 X-2.9495 Y1.4080 +G01 X-2.9495 Y1.3835 +G01 X-2.9278 Y1.3835 +G01 X-2.8965 Y1.3522 +G01 X-2.8965 Y1.3078 +G01 X-2.9238 Y1.2805 +G01 X-2.7240 Y1.2805 +G01 X-2.7200 Y1.2813 +G01 X-2.7160 Y1.2805 +G01 X-2.7152 Y1.2805 +G01 X-2.6922 Y1.3035 +G00 Z0.1000 +G00 X-3.0294 Y1.2885 +G01 Z-0.0070 F10 +G01 X-3.0285 Y1.2857 F20 +G01 X-3.0267 Y1.2833 +G01 X-3.0243 Y1.2815 +G01 X-3.0215 Y1.2806 +G01 X-3.0200 Y1.2805 +G01 X-3.0129 Y1.2805 +G01 X-3.0119 Y1.2805 +G01 X-2.9761 Y1.2805 +G01 X-3.0035 Y1.3078 +G01 X-3.0035 Y1.3097 +G01 X-3.0182 Y1.3244 +G01 X-3.0295 Y1.3516 +G01 X-3.0295 Y1.2900 +G01 X-3.0294 Y1.2885 +G00 Z0.1000 +G00 X-3.0198 Y1.5699 +G01 Z-0.0070 F10 +G01 X-3.0198 Y1.5699 F20 +G01 X-2.9999 Y1.5898 +G01 X-2.9740 Y1.6005 +G01 X-2.9681 Y1.6005 +G01 X-2.8281 Y1.6005 +G01 X-2.8205 Y1.6005 +G01 X-2.8205 Y1.6619 +G01 X-2.8205 Y1.6631 +G01 X-2.8205 Y1.6781 +G01 X-2.8205 Y1.6843 +G01 X-2.8116 Y1.7116 +G01 X-2.7948 Y1.7348 +G01 X-2.7716 Y1.7516 +G01 X-2.7443 Y1.7605 +G01 X-2.7381 Y1.7605 +G01 X-2.7337 Y1.7605 +G01 X-2.7300 Y1.7605 +G01 X-2.7219 Y1.7605 +G01 X-2.7052 Y1.7605 +G01 X-2.6957 Y1.7700 +G01 X-2.7052 Y1.7795 +G01 X-2.8119 Y1.7795 +G01 X-2.8200 Y1.7795 +G01 X-2.8215 Y1.7794 +G01 X-2.8243 Y1.7785 +G01 X-2.8267 Y1.7767 +G01 X-2.8285 Y1.7743 +G01 X-2.8294 Y1.7715 +G01 X-2.8295 Y1.7700 +G01 X-2.8295 Y1.6881 +G01 X-2.8295 Y1.6861 +G01 X-2.8295 Y1.6719 +G01 X-2.8295 Y1.6660 +G01 X-2.8402 Y1.6401 +G01 X-2.8601 Y1.6202 +G01 X-2.8860 Y1.6095 +G01 X-2.8919 Y1.6095 +G01 X-3.0119 Y1.6095 +G01 X-3.0200 Y1.6095 +G01 X-3.0215 Y1.6094 +G01 X-3.0243 Y1.6085 +G01 X-3.0267 Y1.6067 +G01 X-3.0285 Y1.6043 +G01 X-3.0294 Y1.6015 +G01 X-3.0295 Y1.6000 +G01 X-3.0295 Y1.5464 +G01 X-3.0198 Y1.5699 +G00 Z0.1000 +G00 X-2.8281 Y1.8605 +G01 Z-0.0070 F10 +G01 X-2.8204 Y1.8605 F20 +G01 X-2.8200 Y1.8605 +G01 X-2.8119 Y1.8605 +G01 X-2.7052 Y1.8605 +G01 X-2.6961 Y1.8695 +G01 X-2.9000 Y1.8695 +G01 X-2.9015 Y1.8694 +G01 X-2.9043 Y1.8685 +G01 X-2.9067 Y1.8667 +G01 X-2.9085 Y1.8643 +G01 X-2.9094 Y1.8615 +G01 X-2.9095 Y1.8600 +G01 X-2.9095 Y1.8550 +G01 X-2.9095 Y1.8519 +G01 X-2.9095 Y1.7874 +G01 X-2.9016 Y1.8116 +G01 X-2.8848 Y1.8348 +G01 X-2.8616 Y1.8516 +G01 X-2.8343 Y1.8605 +G01 X-2.8281 Y1.8605 +G00 Z0.1000 +G00 X-2.3900 Y1.7657 +G01 Z-0.0070 F10 +G01 X-2.3805 Y1.7752 F20 +G01 X-2.3805 Y1.7800 +G01 X-2.3806 Y1.7815 +G01 X-2.3815 Y1.7843 +G01 X-2.3833 Y1.7867 +G01 X-2.3857 Y1.7885 +G01 X-2.3885 Y1.7894 +G01 X-2.3900 Y1.7895 +G01 X-2.4138 Y1.7895 +G01 X-2.3900 Y1.7657 +G00 Z0.1000 +G00 X-1.7784 Y0.8384 +G01 Z-0.0070 F10 +G01 X-1.7784 Y0.8384 F20 +G01 X-1.7952 Y0.8152 +G01 X-1.8184 Y0.7984 +G01 X-1.8426 Y0.7905 +G01 X-1.7800 Y0.7905 +G01 X-1.7785 Y0.7906 +G01 X-1.7757 Y0.7915 +G01 X-1.7733 Y0.7933 +G01 X-1.7715 Y0.7957 +G01 X-1.7706 Y0.7985 +G01 X-1.7705 Y0.8000 +G01 X-1.7705 Y0.8626 +G01 X-1.7784 Y0.8384 +G00 Z0.1000 +G00 X-1.6981 Y1.0505 +G01 Z-0.0070 F10 +G01 X-1.6873 Y1.0505 F20 +G01 X-1.6819 Y1.0505 +G01 X-1.3422 Y1.0505 +G01 X-1.3373 Y1.0554 +G01 X-1.3261 Y1.0600 +G01 X-1.3373 Y1.0646 +G01 X-1.3422 Y1.0695 +G01 X-1.7695 Y1.0695 +G01 X-1.7695 Y0.9884 +G01 X-1.7582 Y1.0156 +G01 X-1.7356 Y1.0382 +G01 X-1.7060 Y1.0505 +G01 X-1.6981 Y1.0505 +G00 Z0.1000 +G00 X-1.6081 Y0.9505 +G01 Z-0.0070 F10 +G01 X-1.6006 Y0.9505 F20 +G01 X-1.6000 Y0.9505 +G01 X-1.5919 Y0.9505 +G01 X-1.3422 Y0.9505 +G01 X-1.3373 Y0.9554 +G01 X-1.3261 Y0.9600 +G01 X-1.3373 Y0.9646 +G01 X-1.3422 Y0.9695 +G01 X-1.6819 Y0.9695 +G01 X-1.6874 Y0.9695 +G01 X-1.6895 Y0.9695 +G01 X-1.6895 Y0.9646 +G01 X-1.6895 Y0.9619 +G01 X-1.6895 Y0.8774 +G01 X-1.6816 Y0.9016 +G01 X-1.6648 Y0.9248 +G01 X-1.6416 Y0.9416 +G01 X-1.6143 Y0.9505 +G01 X-1.6081 Y0.9505 +G00 Z0.1000 +G00 X-0.4195 Y0.2857 +G01 Z-0.0070 F10 +G01 X-0.4195 Y0.2857 F20 +G01 X-0.4284 Y0.2584 +G01 X-0.4452 Y0.2352 +G01 X-0.4684 Y0.2184 +G01 X-0.4957 Y0.2095 +G01 X-0.5019 Y0.2095 +G01 X-0.5094 Y0.2095 +G01 X-0.5100 Y0.2095 +G01 X-0.5181 Y0.2095 +G01 X-1.0400 Y0.2095 +G01 X-1.0415 Y0.2094 +G01 X-1.0443 Y0.2085 +G01 X-1.0467 Y0.2067 +G01 X-1.0485 Y0.2043 +G01 X-1.0494 Y0.2015 +G01 X-1.0495 Y0.2000 +G01 X-1.0495 Y0.1930 +G01 X-1.0495 Y0.1919 +G01 X-1.0495 Y0.1419 +G01 X-1.0495 Y0.1357 +G01 X-1.0584 Y0.1084 +G01 X-1.0752 Y0.0852 +G01 X-1.0984 Y0.0684 +G01 X-1.1257 Y0.0595 +G01 X-1.1319 Y0.0595 +G01 X-1.1400 Y0.0595 +G01 X-1.1481 Y0.0595 +G01 X-1.6081 Y0.0595 +G01 X-1.6143 Y0.0595 +G01 X-1.6416 Y0.0684 +G01 X-1.6648 Y0.0852 +G01 X-1.6816 Y0.1084 +G01 X-1.6905 Y0.1357 +G01 X-1.6905 Y0.1419 +G01 X-1.6905 Y0.1498 +G01 X-1.6905 Y0.1500 +G01 X-1.6905 Y0.1581 +G01 X-1.6905 Y0.7826 +G01 X-1.6984 Y0.7584 +G01 X-1.7152 Y0.7352 +G01 X-1.7384 Y0.7184 +G01 X-1.7534 Y0.7135 +G01 X-1.7278 Y0.7135 +G01 X-1.6965 Y0.6822 +G01 X-1.6965 Y0.6378 +G01 X-1.7278 Y0.6065 +G01 X-1.7722 Y0.6065 +G01 X-1.7852 Y0.6195 +G01 X-1.8685 Y0.6195 +G01 X-1.8427 Y0.5937 +G01 X-1.8427 Y0.5550 +G01 X-1.8318 Y0.5595 +G01 X-1.8082 Y0.5595 +G01 X-1.7863 Y0.5504 +G01 X-1.7696 Y0.5337 +G01 X-1.7605 Y0.5118 +G01 X-1.7605 Y0.4882 +G01 X-1.7696 Y0.4663 +G01 X-1.7795 Y0.4564 +G01 X-1.7795 Y0.3836 +G01 X-1.7696 Y0.3737 +G01 X-1.7605 Y0.3518 +G01 X-1.7605 Y0.3282 +G01 X-1.7696 Y0.3063 +G01 X-1.7863 Y0.2896 +G01 X-1.8082 Y0.2805 +G01 X-1.8318 Y0.2805 +G01 X-1.8537 Y0.2896 +G01 X-1.8636 Y0.2995 +G01 X-1.9600 Y0.2995 +G01 X-1.9615 Y0.2994 +G01 X-1.9643 Y0.2985 +G01 X-1.9596 Y0.2937 +G01 X-1.9505 Y0.2718 +G01 X-1.9505 Y0.2482 +G01 X-1.9596 Y0.2263 +G01 X-1.9763 Y0.2096 +G01 X-1.9982 Y0.2005 +G01 X-2.0218 Y0.2005 +G01 X-2.0437 Y0.2096 +G01 X-2.0604 Y0.2263 +G01 X-2.0695 Y0.2482 +G01 X-2.0695 Y0.2718 +G01 X-2.0604 Y0.2937 +G01 X-2.0505 Y0.3036 +G01 X-2.0505 Y0.3043 +G01 X-2.0416 Y0.3316 +G01 X-2.0248 Y0.3548 +G01 X-2.0016 Y0.3716 +G01 X-1.9743 Y0.3805 +G01 X-1.9681 Y0.3805 +G01 X-1.8636 Y0.3805 +G01 X-1.8605 Y0.3836 +G01 X-1.8605 Y0.4564 +G01 X-1.8636 Y0.4595 +G01 X-1.8643 Y0.4595 +G01 X-1.8916 Y0.4684 +G01 X-1.9148 Y0.4852 +G01 X-1.9316 Y0.5084 +G01 X-1.9375 Y0.5265 +G01 X-1.9573 Y0.5463 +G01 X-1.9573 Y0.5937 +G01 X-1.9315 Y0.6195 +G01 X-1.9664 Y0.6195 +G01 X-1.9763 Y0.6096 +G01 X-1.9982 Y0.6005 +G01 X-2.0218 Y0.6005 +G01 X-2.0437 Y0.6096 +G01 X-2.0536 Y0.6195 +G01 X-2.0900 Y0.6195 +G01 X-2.0915 Y0.6194 +G01 X-2.0943 Y0.6185 +G01 X-2.0967 Y0.6167 +G01 X-2.0985 Y0.6143 +G01 X-2.0994 Y0.6115 +G01 X-2.0995 Y0.6100 +G01 X-2.0995 Y0.6019 +G01 X-2.0995 Y0.2952 +G01 X-2.0865 Y0.2822 +G01 X-2.0865 Y0.2378 +G01 X-2.1178 Y0.2065 +G01 X-2.1622 Y0.2065 +G01 X-2.1935 Y0.2378 +G01 X-2.1935 Y0.2822 +G01 X-2.1805 Y0.2952 +G01 X-2.1805 Y0.6019 +G01 X-2.1805 Y0.6100 +G01 X-2.1805 Y0.6131 +G01 X-2.1805 Y0.6181 +G01 X-2.1805 Y0.6243 +G01 X-2.1716 Y0.6516 +G01 X-2.1548 Y0.6748 +G01 X-2.1316 Y0.6916 +G01 X-2.1043 Y0.7005 +G01 X-2.0981 Y0.7005 +G01 X-2.0536 Y0.7005 +G01 X-2.0446 Y0.7095 +G01 X-2.1819 Y0.7095 +G01 X-2.1895 Y0.7095 +G01 X-2.1895 Y0.5981 +G01 X-2.1895 Y0.5967 +G01 X-2.1895 Y0.5819 +G01 X-2.1895 Y0.5740 +G01 X-2.2018 Y0.5444 +G01 X-2.2244 Y0.5218 +G01 X-2.2540 Y0.5095 +G01 X-2.2619 Y0.5095 +G01 X-2.2696 Y0.5095 +G01 X-2.2700 Y0.5095 +G01 X-2.2781 Y0.5095 +G01 X-2.4785 Y0.5095 +G01 X-2.4527 Y0.4837 +G01 X-2.4527 Y0.4363 +G01 X-2.4595 Y0.4294 +G01 X-2.4595 Y0.2700 +G01 X-2.4595 Y0.1905 +G01 X-2.4514 Y0.1905 +G01 X-2.4500 Y0.1905 +G01 X-1.8735 Y0.1905 +G01 X-1.8735 Y0.2222 +G01 X-1.8422 Y0.2535 +G01 X-1.7978 Y0.2535 +G01 X-1.7665 Y0.2222 +G01 X-1.7665 Y0.1778 +G01 X-1.7695 Y0.1748 +G01 X-1.7695 Y0.1741 +G01 X-1.7793 Y0.1438 +G01 X-1.7981 Y0.1181 +G01 X-1.8238 Y0.0993 +G01 X-1.8541 Y0.0895 +G01 X-1.8600 Y0.0895 +G01 X-2.4500 Y0.0895 +G01 X-2.4514 Y0.0895 +G01 X-2.4700 Y0.0895 +G01 X-2.4759 Y0.0895 +G01 X-2.5062 Y0.0993 +G01 X-2.5319 Y0.1181 +G01 X-2.5507 Y0.1438 +G01 X-2.5605 Y0.1741 +G01 X-2.5605 Y0.1900 +G01 X-2.5605 Y0.2195 +G01 X-2.6048 Y0.2195 +G01 X-2.6178 Y0.2065 +G01 X-2.6622 Y0.2065 +G01 X-2.6935 Y0.2378 +G01 X-2.6935 Y0.2822 +G01 X-2.6622 Y0.3135 +G01 X-2.6178 Y0.3135 +G01 X-2.6048 Y0.3005 +G01 X-2.5605 Y0.3005 +G01 X-2.5605 Y0.4294 +G01 X-2.5673 Y0.4363 +G01 X-2.5673 Y0.4837 +G01 X-2.5415 Y0.5095 +G01 X-2.8076 Y0.5095 +G01 X-2.8172 Y0.4999 +G01 X-2.8396 Y0.4906 +G01 X-3.0004 Y0.4906 +G01 X-3.0228 Y0.4999 +G01 X-3.0400 Y0.5170 +G01 X-3.0492 Y0.5394 +G01 X-3.0492 Y0.5637 +G01 X-3.0400 Y0.5861 +G01 X-3.0228 Y0.6033 +G01 X-3.0004 Y0.6126 +G01 X-2.8396 Y0.6126 +G01 X-2.8172 Y0.6033 +G01 X-2.8044 Y0.5905 +G01 X-2.2781 Y0.5905 +G01 X-2.2705 Y0.5905 +G01 X-2.2705 Y0.5967 +G01 X-2.2705 Y0.5981 +G01 X-2.2705 Y0.7181 +G01 X-2.2705 Y0.7260 +G01 X-2.2582 Y0.7556 +G01 X-2.2356 Y0.7782 +G01 X-2.2084 Y0.7895 +G01 X-2.2719 Y0.7895 +G01 X-2.2800 Y0.7895 +G01 X-2.2815 Y0.7894 +G01 X-2.2843 Y0.7885 +G01 X-2.2867 Y0.7867 +G01 X-2.2885 Y0.7843 +G01 X-2.2894 Y0.7815 +G01 X-2.2895 Y0.7800 +G01 X-2.2895 Y0.7519 +G01 X-2.2895 Y0.7480 +G01 X-2.2987 Y0.7257 +G01 X-2.3157 Y0.7087 +G01 X-2.3380 Y0.6995 +G01 X-2.3419 Y0.6995 +G01 X-2.3500 Y0.6995 +G01 X-2.3581 Y0.6995 +G01 X-2.6448 Y0.6995 +G01 X-2.6478 Y0.6965 +G01 X-2.6922 Y0.6965 +G01 X-2.7052 Y0.7095 +G01 X-2.8044 Y0.7095 +G01 X-2.8172 Y0.6967 +G01 X-2.8396 Y0.6874 +G01 X-3.0004 Y0.6874 +G01 X-3.0228 Y0.6967 +G01 X-3.0400 Y0.7139 +G01 X-3.0492 Y0.7363 +G01 X-3.0492 Y0.7606 +G01 X-3.0400 Y0.7830 +G01 X-3.0228 Y0.8001 +G01 X-3.0004 Y0.8094 +G01 X-2.8396 Y0.8094 +G01 X-2.8172 Y0.8001 +G01 X-2.8076 Y0.7905 +G01 X-2.7052 Y0.7905 +G01 X-2.6922 Y0.8035 +G01 X-2.6478 Y0.8035 +G01 X-2.6248 Y0.7805 +G01 X-2.3705 Y0.7805 +G01 X-2.3705 Y0.7881 +G01 X-2.3705 Y0.7943 +G01 X-2.3616 Y0.8216 +G01 X-2.3448 Y0.8448 +G01 X-2.3216 Y0.8616 +G01 X-2.2974 Y0.8695 +G01 X-2.4694 Y0.8695 +G01 X-2.4863 Y0.8527 +G01 X-2.5337 Y0.8527 +G01 X-2.5505 Y0.8695 +G01 X-3.1019 Y0.8695 +G01 X-3.1051 Y0.8695 +G01 X-3.1181 Y0.8695 +G01 X-3.1243 Y0.8695 +G01 X-3.1516 Y0.8784 +G01 X-3.1748 Y0.8952 +G01 X-3.1916 Y0.9184 +G01 X-3.2005 Y0.9457 +G01 X-3.2005 Y0.9519 +G01 X-3.2005 Y1.5748 +G01 X-3.2135 Y1.5878 +G01 X-3.2135 Y1.6322 +G01 X-3.2005 Y1.6452 +G01 X-3.2005 Y1.6819 +G01 X-3.2005 Y1.6831 +G01 X-3.2005 Y1.6981 +G01 X-3.2005 Y1.7043 +G01 X-3.1916 Y1.7316 +G01 X-3.1748 Y1.7548 +G01 X-3.1516 Y1.7716 +G01 X-3.1243 Y1.7805 +G01 X-3.1181 Y1.7805 +G01 X-3.1137 Y1.7805 +G01 X-3.1100 Y1.7805 +G01 X-2.9981 Y1.7805 +G01 X-2.9905 Y1.7805 +G01 X-2.9905 Y1.8519 +G01 X-2.9905 Y1.8551 +G01 X-2.9905 Y1.8681 +G01 X-2.9905 Y1.8743 +G01 X-2.9816 Y1.9016 +G01 X-2.9648 Y1.9248 +G01 X-2.9416 Y1.9416 +G01 X-2.9143 Y1.9505 +G01 X-2.9081 Y1.9505 +G01 X-2.0819 Y1.9505 +G01 X-2.0352 Y1.9505 +G01 X-2.0222 Y1.9635 +G01 X-1.9778 Y1.9635 +G01 X-1.9648 Y1.9505 +G01 X-1.7700 Y1.9505 +G01 X-1.7685 Y1.9506 +G01 X-1.7657 Y1.9515 +G01 X-1.7633 Y1.9533 +G01 X-1.7615 Y1.9557 +G01 X-1.7606 Y1.9585 +G01 X-1.7605 Y1.9600 +G01 X-1.7605 Y1.9643 +G01 X-1.7605 Y1.9681 +G01 X-1.7605 Y2.0519 +G01 X-1.7605 Y2.0600 +G01 X-1.7605 Y2.0681 +G01 X-1.7605 Y2.0743 +G01 X-1.7516 Y2.1016 +G01 X-1.7348 Y2.1248 +G01 X-1.7116 Y2.1416 +G01 X-1.6843 Y2.1505 +G01 X-1.6781 Y2.1505 +G01 X-1.2519 Y2.1505 +G01 X-1.2457 Y2.1505 +G01 X-1.2184 Y2.1416 +G01 X-1.1952 Y2.1248 +G01 X-1.1784 Y2.1016 +G01 X-1.1695 Y2.0743 +G01 X-1.1695 Y2.0681 +G01 X-1.1695 Y2.0600 +G01 X-1.1695 Y2.0519 +G01 X-1.1695 Y1.9100 +G01 X-1.1694 Y1.9085 +G01 X-1.1685 Y1.9057 +G01 X-1.1667 Y1.9033 +G01 X-1.1643 Y1.9015 +G01 X-1.1615 Y1.9006 +G01 X-1.1600 Y1.9005 +G01 X-1.1519 Y1.9005 +G01 X-0.8015 Y1.9005 +G01 X-0.7929 Y1.9092 +G01 X-0.7715 Y1.9180 +G01 X-0.7485 Y1.9180 +G01 X-0.7271 Y1.9092 +G01 X-0.7185 Y1.9005 +G01 X-0.2635 Y1.9005 +G01 X-0.2538 Y1.9005 +G01 X-0.2201 Y1.8895 +G01 X-0.1913 Y1.8687 +G01 X-0.1774 Y1.8494 +G01 X-0.1196 Y1.8494 +G01 X-0.0972 Y1.8401 +G01 X-0.0800 Y1.8230 +G01 X-0.0708 Y1.8006 +G01 X-0.0708 Y1.7763 +G01 X-0.0800 Y1.7539 +G01 X-0.0972 Y1.7367 +G01 X-0.1196 Y1.7274 +G01 X-0.2804 Y1.7274 +G01 X-0.3028 Y1.7367 +G01 X-0.3200 Y1.7539 +G01 X-0.3292 Y1.7763 +G01 X-0.3292 Y1.8006 +G01 X-0.3214 Y1.8195 +G01 X-0.7185 Y1.8195 +G01 X-0.7271 Y1.8108 +G01 X-0.7485 Y1.8020 +G01 X-0.7715 Y1.8020 +G01 X-0.7929 Y1.8108 +G01 X-0.8015 Y1.8195 +G01 X-1.1519 Y1.8195 +G01 X-1.1600 Y1.8195 +G01 X-1.1603 Y1.8195 +G01 X-1.1681 Y1.8195 +G01 X-1.1743 Y1.8195 +G01 X-1.2016 Y1.8284 +G01 X-1.2248 Y1.8452 +G01 X-1.2416 Y1.8684 +G01 X-1.2505 Y1.8957 +G01 X-1.2505 Y1.9019 +G01 X-1.2505 Y2.0519 +G01 X-1.2505 Y2.0600 +G01 X-1.2506 Y2.0615 +G01 X-1.2515 Y2.0643 +G01 X-1.2533 Y2.0667 +G01 X-1.2557 Y2.0685 +G01 X-1.2585 Y2.0694 +G01 X-1.2600 Y2.0695 +G01 X-1.6700 Y2.0695 +G01 X-1.6715 Y2.0694 +G01 X-1.6743 Y2.0685 +G01 X-1.6767 Y2.0667 +G01 X-1.6785 Y2.0643 +G01 X-1.6794 Y2.0615 +G01 X-1.6795 Y2.0600 +G01 X-1.6795 Y2.0519 +G01 X-1.6795 Y1.9681 +G01 X-1.6795 Y1.9642 +G01 X-1.6795 Y1.9519 +G01 X-1.6795 Y1.9457 +G01 X-1.6884 Y1.9184 +G01 X-1.7052 Y1.8952 +G01 X-1.7284 Y1.8784 +G01 X-1.7557 Y1.8695 +G01 X-1.7619 Y1.8695 +G01 X-1.9648 Y1.8695 +G01 X-1.9778 Y1.8565 +G01 X-2.0222 Y1.8565 +G01 X-2.0352 Y1.8695 +G01 X-2.0495 Y1.8695 +G01 X-2.0495 Y1.7581 +G01 X-2.0495 Y1.7500 +G01 X-2.0494 Y1.7485 +G01 X-2.0485 Y1.7457 +G01 X-2.0467 Y1.7433 +G01 X-2.0443 Y1.7415 +G01 X-2.0415 Y1.7406 +G01 X-2.0400 Y1.7405 +G01 X-2.0319 Y1.7405 +G01 X-2.0015 Y1.7405 +G01 X-2.0273 Y1.7663 +G01 X-2.0273 Y1.8137 +G01 X-1.9937 Y1.8473 +G01 X-1.9463 Y1.8473 +G01 X-1.9294 Y1.8305 +G01 X-1.6605 Y1.8305 +G01 X-1.6605 Y1.9681 +G01 X-1.6605 Y1.9743 +G01 X-1.6516 Y2.0016 +G01 X-1.6348 Y2.0248 +G01 X-1.6116 Y2.0416 +G01 X-1.5843 Y2.0505 +G01 X-1.5781 Y2.0505 +G01 X-1.5704 Y2.0505 +G01 X-1.5700 Y2.0505 +G01 X-1.5619 Y2.0505 +G01 X-1.4181 Y2.0505 +G01 X-1.4100 Y2.0505 +G01 X-1.4019 Y2.0505 +G01 X-1.3957 Y2.0505 +G01 X-1.3684 Y2.0416 +G01 X-1.3452 Y2.0248 +G01 X-1.3284 Y2.0016 +G01 X-1.3195 Y1.9743 +G01 X-1.3195 Y1.9681 +G01 X-1.3195 Y1.9015 +G01 X-1.3020 Y1.8840 +G01 X-1.3020 Y1.8360 +G01 X-1.3195 Y1.8185 +G01 X-1.3195 Y1.8100 +G01 X-1.3194 Y1.8085 +G01 X-1.3185 Y1.8057 +G01 X-1.3167 Y1.8033 +G01 X-1.3143 Y1.8015 +G01 X-1.3115 Y1.8006 +G01 X-1.3100 Y1.8005 +G01 X-1.3033 Y1.8005 +G01 X-1.3019 Y1.8005 +G01 X-0.6519 Y1.8005 +G01 X-0.6440 Y1.8005 +G01 X-0.6144 Y1.7882 +G01 X-0.5918 Y1.7656 +G01 X-0.5795 Y1.7360 +G01 X-0.5795 Y1.7281 +G01 X-0.5795 Y1.6500 +G01 X-0.5794 Y1.6485 +G01 X-0.5785 Y1.6457 +G01 X-0.5767 Y1.6433 +G01 X-0.5743 Y1.6415 +G01 X-0.5715 Y1.6406 +G01 X-0.5700 Y1.6405 +G01 X-0.5619 Y1.6405 +G01 X-0.3056 Y1.6405 +G01 X-0.3028 Y1.6433 +G01 X-0.2804 Y1.6526 +G01 X-0.1196 Y1.6526 +G01 X-0.0972 Y1.6433 +G01 X-0.0800 Y1.6261 +G01 X-0.0708 Y1.6037 +G01 X-0.0708 Y1.5794 +G01 X-0.0800 Y1.5570 +G01 X-0.0972 Y1.5399 +G01 X-0.1196 Y1.5306 +G01 X-0.2804 Y1.5306 +G01 X-0.3028 Y1.5399 +G01 X-0.3200 Y1.5570 +G01 X-0.3210 Y1.5595 +G01 X-0.5619 Y1.5595 +G01 X-0.5700 Y1.5595 +G01 X-0.5730 Y1.5595 +G01 X-0.5781 Y1.5595 +G01 X-0.5843 Y1.5595 +G01 X-0.6116 Y1.5684 +G01 X-0.6348 Y1.5852 +G01 X-0.6516 Y1.6084 +G01 X-0.6605 Y1.6357 +G01 X-0.6605 Y1.6419 +G01 X-0.6605 Y1.7195 +G01 X-1.3019 Y1.7195 +G01 X-1.3033 Y1.7195 +G01 X-1.3181 Y1.7195 +G01 X-1.3243 Y1.7195 +G01 X-1.3516 Y1.7284 +G01 X-1.3748 Y1.7452 +G01 X-1.3916 Y1.7684 +G01 X-1.4005 Y1.7957 +G01 X-1.4005 Y1.8019 +G01 X-1.4005 Y1.8185 +G01 X-1.4180 Y1.8360 +G01 X-1.4180 Y1.8840 +G01 X-1.4005 Y1.9015 +G01 X-1.4005 Y1.9600 +G01 X-1.4006 Y1.9615 +G01 X-1.4015 Y1.9643 +G01 X-1.4033 Y1.9667 +G01 X-1.4057 Y1.9685 +G01 X-1.4085 Y1.9694 +G01 X-1.4100 Y1.9695 +G01 X-1.4181 Y1.9695 +G01 X-1.5619 Y1.9695 +G01 X-1.5700 Y1.9695 +G01 X-1.5715 Y1.9694 +G01 X-1.5743 Y1.9685 +G01 X-1.5767 Y1.9667 +G01 X-1.5785 Y1.9643 +G01 X-1.5794 Y1.9615 +G01 X-1.5795 Y1.9600 +G01 X-1.5795 Y1.7981 +G01 X-1.5795 Y1.7719 +G01 X-1.5795 Y1.6381 +G01 X-1.5795 Y1.6300 +G01 X-1.5794 Y1.6285 +G01 X-1.5785 Y1.6257 +G01 X-1.5767 Y1.6233 +G01 X-1.5743 Y1.6215 +G01 X-1.5715 Y1.6206 +G01 X-1.5700 Y1.6205 +G01 X-1.5684 Y1.6205 +G01 X-1.5619 Y1.6205 +G01 X-1.1419 Y1.6205 +G01 X-1.1357 Y1.6205 +G01 X-1.1084 Y1.6116 +G01 X-1.0852 Y1.5948 +G01 X-1.0684 Y1.5716 +G01 X-1.0595 Y1.5443 +G01 X-1.0595 Y1.5381 +G01 X-1.0595 Y1.5304 +G01 X-1.0595 Y1.5300 +G01 X-1.0595 Y1.5219 +G01 X-1.0595 Y1.4230 +G01 X-1.0524 Y1.4403 +G01 X-1.0373 Y1.4554 +G01 X-1.0176 Y1.4635 +G01 X-0.8824 Y1.4635 +G01 X-0.8627 Y1.4554 +G01 X-0.8578 Y1.4505 +G01 X-0.5981 Y1.4505 +G01 X-0.5900 Y1.4505 +G01 X-0.5869 Y1.4505 +G01 X-0.5819 Y1.4505 +G01 X-0.5757 Y1.4505 +G01 X-0.5484 Y1.4416 +G01 X-0.5252 Y1.4248 +G01 X-0.5084 Y1.4016 +G01 X-0.4995 Y1.3743 +G01 X-0.4995 Y1.3681 +G01 X-0.4995 Y1.3584 +G01 X-0.4994 Y1.3569 +G01 X-0.4985 Y1.3541 +G01 X-0.4967 Y1.3517 +G01 X-0.4943 Y1.3500 +G01 X-0.4915 Y1.3490 +G01 X-0.4900 Y1.3489 +G01 X-0.4835 Y1.3489 +G01 X-0.4819 Y1.3489 +G01 X-0.3140 Y1.3489 +G01 X-0.3028 Y1.3601 +G01 X-0.2804 Y1.3694 +G01 X-0.1196 Y1.3694 +G01 X-0.0972 Y1.3601 +G01 X-0.0800 Y1.3430 +G01 X-0.0708 Y1.3206 +G01 X-0.0708 Y1.2963 +G01 X-0.0800 Y1.2739 +G01 X-0.0972 Y1.2567 +G01 X-0.1196 Y1.2474 +G01 X-0.2804 Y1.2474 +G01 X-0.3028 Y1.2567 +G01 X-0.3140 Y1.2679 +G01 X-0.4819 Y1.2679 +G01 X-0.4835 Y1.2679 +G01 X-0.4981 Y1.2679 +G01 X-0.5043 Y1.2679 +G01 X-0.5316 Y1.2768 +G01 X-0.5548 Y1.2936 +G01 X-0.5716 Y1.3168 +G01 X-0.5805 Y1.3441 +G01 X-0.5805 Y1.3504 +G01 X-0.5805 Y1.3600 +G01 X-0.5806 Y1.3615 +G01 X-0.5815 Y1.3643 +G01 X-0.5833 Y1.3667 +G01 X-0.5857 Y1.3685 +G01 X-0.5885 Y1.3694 +G01 X-0.5900 Y1.3695 +G01 X-0.5981 Y1.3695 +G01 X-0.8578 Y1.3695 +G01 X-0.8627 Y1.3646 +G01 X-0.8739 Y1.3600 +G01 X-0.8627 Y1.3554 +G01 X-0.8578 Y1.3505 +G01 X-0.7552 Y1.3505 +G01 X-0.7422 Y1.3635 +G01 X-0.6978 Y1.3635 +G01 X-0.6665 Y1.3322 +G01 X-0.6665 Y1.2878 +G01 X-0.6978 Y1.2565 +G01 X-0.7422 Y1.2565 +G01 X-0.7552 Y1.2695 +G01 X-0.8578 Y1.2695 +G01 X-0.8627 Y1.2646 +G01 X-0.8739 Y1.2600 +G01 X-0.8627 Y1.2554 +G01 X-0.8578 Y1.2505 +G01 X-0.4319 Y1.2505 +G01 X-0.4240 Y1.2505 +G01 X-0.3944 Y1.2382 +G01 X-0.3718 Y1.2156 +G01 X-0.3595 Y1.1860 +G01 X-0.3595 Y1.1781 +G01 X-0.3595 Y1.1701 +G01 X-0.3595 Y1.1700 +G01 X-0.3595 Y1.1619 +G01 X-0.3595 Y1.1616 +G01 X-0.3594 Y1.1601 +G01 X-0.3585 Y1.1573 +G01 X-0.3567 Y1.1549 +G01 X-0.3543 Y1.1531 +G01 X-0.3515 Y1.1522 +G01 X-0.3500 Y1.1521 +G01 X-0.3489 Y1.1521 +G01 X-0.3419 Y1.1521 +G01 X-0.3140 Y1.1521 +G01 X-0.3028 Y1.1633 +G01 X-0.2804 Y1.1726 +G01 X-0.1196 Y1.1726 +G01 X-0.0972 Y1.1633 +G01 X-0.0800 Y1.1461 +G01 X-0.0708 Y1.1237 +G01 X-0.0708 Y1.0994 +G01 X-0.0800 Y1.0770 +G01 X-0.0972 Y1.0599 +G01 X-0.1196 Y1.0506 +G01 X-0.2804 Y1.0506 +G01 X-0.3028 Y1.0599 +G01 X-0.3140 Y1.0711 +G01 X-0.3419 Y1.0711 +G01 X-0.3489 Y1.0711 +G01 X-0.3500 Y1.0711 +G01 X-0.3581 Y1.0711 +G01 X-0.3643 Y1.0711 +G01 X-0.3916 Y1.0799 +G01 X-0.4148 Y1.0968 +G01 X-0.4316 Y1.1200 +G01 X-0.4405 Y1.1472 +G01 X-0.4405 Y1.1535 +G01 X-0.4405 Y1.1619 +G01 X-0.4405 Y1.1695 +G01 X-0.8578 Y1.1695 +G01 X-0.8627 Y1.1646 +G01 X-0.8739 Y1.1600 +G01 X-0.8627 Y1.1554 +G01 X-0.8578 Y1.1505 +G01 X-0.5952 Y1.1505 +G01 X-0.5822 Y1.1635 +G01 X-0.5378 Y1.1635 +G01 X-0.5065 Y1.1322 +G01 X-0.5065 Y1.0878 +G01 X-0.5378 Y1.0565 +G01 X-0.5822 Y1.0565 +G01 X-0.5952 Y1.0695 +G01 X-0.8578 Y1.0695 +G01 X-0.8627 Y1.0646 +G01 X-0.8739 Y1.0600 +G01 X-0.8627 Y1.0554 +G01 X-0.8578 Y1.0505 +G01 X-0.4881 Y1.0505 +G01 X-0.4866 Y1.0505 +G01 X-0.4719 Y1.0505 +G01 X-0.4657 Y1.0505 +G01 X-0.4384 Y1.0416 +G01 X-0.4152 Y1.0248 +G01 X-0.3984 Y1.0016 +G01 X-0.3895 Y0.9743 +G01 X-0.3895 Y0.9681 +G01 X-0.3895 Y0.9505 +G01 X-0.3819 Y0.9505 +G01 X-0.3124 Y0.9505 +G01 X-0.3028 Y0.9601 +G01 X-0.2804 Y0.9694 +G01 X-0.1196 Y0.9694 +G01 X-0.0972 Y0.9601 +G01 X-0.0800 Y0.9430 +G01 X-0.0708 Y0.9206 +G01 X-0.0708 Y0.8963 +G01 X-0.0800 Y0.8739 +G01 X-0.0972 Y0.8567 +G01 X-0.1196 Y0.8474 +G01 X-0.2804 Y0.8474 +G01 X-0.3028 Y0.8567 +G01 X-0.3156 Y0.8695 +G01 X-0.3819 Y0.8695 +G01 X-0.3900 Y0.8695 +G01 X-0.3935 Y0.8695 +G01 X-0.3981 Y0.8695 +G01 X-0.4060 Y0.8695 +G01 X-0.4356 Y0.8818 +G01 X-0.4582 Y0.9044 +G01 X-0.4705 Y0.9340 +G01 X-0.4705 Y0.9419 +G01 X-0.4705 Y0.9600 +G01 X-0.4706 Y0.9615 +G01 X-0.4715 Y0.9643 +G01 X-0.4733 Y0.9667 +G01 X-0.4757 Y0.9685 +G01 X-0.4785 Y0.9694 +G01 X-0.4800 Y0.9695 +G01 X-0.4866 Y0.9695 +G01 X-0.4881 Y0.9695 +G01 X-0.8578 Y0.9695 +G01 X-0.8627 Y0.9646 +G01 X-0.8739 Y0.9600 +G01 X-0.8627 Y0.9554 +G01 X-0.8578 Y0.9505 +G01 X-0.8381 Y0.9505 +G01 X-0.8342 Y0.9505 +G01 X-0.8219 Y0.9505 +G01 X-0.8157 Y0.9505 +G01 X-0.7884 Y0.9416 +G01 X-0.7652 Y0.9248 +G01 X-0.7484 Y0.9016 +G01 X-0.7395 Y0.8743 +G01 X-0.7395 Y0.8681 +G01 X-0.7395 Y0.5752 +G01 X-0.7265 Y0.5622 +G01 X-0.7265 Y0.5178 +G01 X-0.7578 Y0.4865 +G01 X-0.8022 Y0.4865 +G01 X-0.8335 Y0.5178 +G01 X-0.8335 Y0.5622 +G01 X-0.8205 Y0.5752 +G01 X-0.8205 Y0.8600 +G01 X-0.8206 Y0.8615 +G01 X-0.8215 Y0.8643 +G01 X-0.8233 Y0.8667 +G01 X-0.8257 Y0.8685 +G01 X-0.8285 Y0.8694 +G01 X-0.8300 Y0.8695 +G01 X-0.8343 Y0.8695 +G01 X-0.8381 Y0.8695 +G01 X-0.8578 Y0.8695 +G01 X-0.8627 Y0.8646 +G01 X-0.8739 Y0.8600 +G01 X-0.8627 Y0.8554 +G01 X-0.8476 Y0.8403 +G01 X-0.8395 Y0.8206 +G01 X-0.8395 Y0.7994 +G01 X-0.8476 Y0.7797 +G01 X-0.8627 Y0.7646 +G01 X-0.8824 Y0.7565 +G01 X-1.0176 Y0.7565 +G01 X-1.0373 Y0.7646 +G01 X-1.0422 Y0.7695 +G01 X-1.0429 Y0.7695 +G01 X-1.0581 Y0.7695 +G01 X-1.0643 Y0.7695 +G01 X-1.0916 Y0.7784 +G01 X-1.1148 Y0.7952 +G01 X-1.1316 Y0.8184 +G01 X-1.1405 Y0.8457 +G01 X-1.1405 Y0.8519 +G01 X-1.1405 Y0.8970 +G01 X-1.1476 Y0.8797 +G01 X-1.1627 Y0.8646 +G01 X-1.1739 Y0.8600 +G01 X-1.1627 Y0.8554 +G01 X-1.1476 Y0.8403 +G01 X-1.1395 Y0.8206 +G01 X-1.1395 Y0.7994 +G01 X-1.1476 Y0.7797 +G01 X-1.1627 Y0.7646 +G01 X-1.1824 Y0.7565 +G01 X-1.3176 Y0.7565 +G01 X-1.3373 Y0.7646 +G01 X-1.3422 Y0.7695 +G01 X-1.5000 Y0.7695 +G01 X-1.5015 Y0.7694 +G01 X-1.5043 Y0.7685 +G01 X-1.5067 Y0.7667 +G01 X-1.5085 Y0.7643 +G01 X-1.5094 Y0.7615 +G01 X-1.5095 Y0.7600 +G01 X-1.5095 Y0.7537 +G01 X-1.5095 Y0.7519 +G01 X-1.5095 Y0.6952 +G01 X-1.4965 Y0.6822 +G01 X-1.4965 Y0.6378 +G01 X-1.5278 Y0.6065 +G01 X-1.5722 Y0.6065 +G01 X-1.6035 Y0.6378 +G01 X-1.6035 Y0.6822 +G01 X-1.5905 Y0.6952 +G01 X-1.5905 Y0.7519 +G01 X-1.5905 Y0.7538 +G01 X-1.5905 Y0.7681 +G01 X-1.5905 Y0.7743 +G01 X-1.5816 Y0.8016 +G01 X-1.5648 Y0.8248 +G01 X-1.5416 Y0.8416 +G01 X-1.5143 Y0.8505 +G01 X-1.5081 Y0.8505 +G01 X-1.3422 Y0.8505 +G01 X-1.3373 Y0.8554 +G01 X-1.3261 Y0.8600 +G01 X-1.3373 Y0.8646 +G01 X-1.3422 Y0.8695 +G01 X-1.5919 Y0.8695 +G01 X-1.6000 Y0.8695 +G01 X-1.6015 Y0.8694 +G01 X-1.6043 Y0.8685 +G01 X-1.6067 Y0.8667 +G01 X-1.6085 Y0.8643 +G01 X-1.6094 Y0.8615 +G01 X-1.6095 Y0.8600 +G01 X-1.6095 Y0.1581 +G01 X-1.6095 Y0.1500 +G01 X-1.6094 Y0.1485 +G01 X-1.6085 Y0.1457 +G01 X-1.6067 Y0.1433 +G01 X-1.6043 Y0.1415 +G01 X-1.6015 Y0.1406 +G01 X-1.6000 Y0.1405 +G01 X-1.1481 Y0.1405 +G01 X-1.1400 Y0.1405 +G01 X-1.1385 Y0.1406 +G01 X-1.1357 Y0.1415 +G01 X-1.1333 Y0.1433 +G01 X-1.1315 Y0.1457 +G01 X-1.1306 Y0.1485 +G01 X-1.1305 Y0.1500 +G01 X-1.1305 Y0.1919 +G01 X-1.1305 Y0.1930 +G01 X-1.1305 Y0.2081 +G01 X-1.1305 Y0.2143 +G01 X-1.1216 Y0.2416 +G01 X-1.1048 Y0.2648 +G01 X-1.0816 Y0.2816 +G01 X-1.0543 Y0.2905 +G01 X-1.0481 Y0.2905 +G01 X-0.8061 Y0.2905 +G01 X-0.8152 Y0.2995 +G01 X-1.2695 Y0.2995 +G01 X-1.2695 Y0.2252 +G01 X-1.2665 Y0.2222 +G01 X-1.2665 Y0.1778 +G01 X-1.2978 Y0.1465 +G01 X-1.3422 Y0.1465 +G01 X-1.3735 Y0.1778 +G01 X-1.3735 Y0.2222 +G01 X-1.3505 Y0.2452 +G01 X-1.3505 Y0.2995 +G01 X-1.3764 Y0.2995 +G01 X-1.3863 Y0.2896 +G01 X-1.4082 Y0.2805 +G01 X-1.4318 Y0.2805 +G01 X-1.4537 Y0.2896 +G01 X-1.4704 Y0.3063 +G01 X-1.4795 Y0.3282 +G01 X-1.4795 Y0.3518 +G01 X-1.4704 Y0.3737 +G01 X-1.4537 Y0.3904 +G01 X-1.4318 Y0.3995 +G01 X-1.4082 Y0.3995 +G01 X-1.3863 Y0.3904 +G01 X-1.3764 Y0.3805 +G01 X-1.3181 Y0.3805 +G01 X-1.3019 Y0.3805 +G01 X-0.8152 Y0.3805 +G01 X-0.8022 Y0.3935 +G01 X-0.7578 Y0.3935 +G01 X-0.7265 Y0.3622 +G01 X-0.7265 Y0.3178 +G01 X-0.7538 Y0.2905 +G01 X-0.5181 Y0.2905 +G01 X-0.5100 Y0.2905 +G01 X-0.5085 Y0.2906 +G01 X-0.5057 Y0.2915 +G01 X-0.5033 Y0.2933 +G01 X-0.5015 Y0.2957 +G01 X-0.5006 Y0.2985 +G01 X-0.5005 Y0.3000 +G01 X-0.5005 Y0.6519 +G01 X-0.5005 Y0.6542 +G01 X-0.5005 Y0.6681 +G01 X-0.5005 Y0.6743 +G01 X-0.4916 Y0.7016 +G01 X-0.4748 Y0.7248 +G01 X-0.4516 Y0.7416 +G01 X-0.4243 Y0.7505 +G01 X-0.4181 Y0.7505 +G01 X-0.3156 Y0.7505 +G01 X-0.3028 Y0.7633 +G01 X-0.2804 Y0.7726 +G01 X-0.1196 Y0.7726 +G01 X-0.0972 Y0.7633 +G01 X-0.0800 Y0.7461 +G01 X-0.0708 Y0.7237 +G01 X-0.0708 Y0.6994 +G01 X-0.0800 Y0.6770 +G01 X-0.0972 Y0.6599 +G01 X-0.1196 Y0.6506 +G01 X-0.2804 Y0.6506 +G01 X-0.3028 Y0.6599 +G01 X-0.3124 Y0.6695 +G01 X-0.4100 Y0.6695 +G01 X-0.4115 Y0.6694 +G01 X-0.4143 Y0.6685 +G01 X-0.4167 Y0.6667 +G01 X-0.4185 Y0.6643 +G01 X-0.4194 Y0.6615 +G01 X-0.4195 Y0.6600 +G01 X-0.4195 Y0.6542 +G01 X-0.4195 Y0.6519 +G01 X-0.4195 Y0.2919 +G01 X-0.4195 Y0.2857 +G00 Z0.1000 +G00 X-0.5195 Y0.4981 +G01 Z-0.0070 F10 +G01 X-0.5195 Y0.4900 F20 +G01 X-0.5195 Y0.4870 +G01 X-0.5195 Y0.4819 +G01 X-0.5195 Y0.4757 +G01 X-0.5284 Y0.4484 +G01 X-0.5452 Y0.4252 +G01 X-0.5684 Y0.4084 +G01 X-0.5957 Y0.3995 +G01 X-0.6019 Y0.3995 +G01 X-1.3781 Y0.3995 +G01 X-1.3843 Y0.3995 +G01 X-1.4116 Y0.4084 +G01 X-1.4348 Y0.4252 +G01 X-1.4516 Y0.4484 +G01 X-1.4517 Y0.4488 +G01 X-1.4537 Y0.4496 +G01 X-1.4704 Y0.4663 +G01 X-1.4795 Y0.4882 +G01 X-1.4795 Y0.5118 +G01 X-1.4705 Y0.5336 +G01 X-1.4705 Y0.6748 +G01 X-1.4835 Y0.6878 +G01 X-1.4835 Y0.7322 +G01 X-1.4522 Y0.7635 +G01 X-1.4078 Y0.7635 +G01 X-1.3765 Y0.7322 +G01 X-1.3765 Y0.6878 +G01 X-1.3895 Y0.6748 +G01 X-1.3895 Y0.5518 +G01 X-1.3863 Y0.5504 +G01 X-1.3696 Y0.5337 +G01 X-1.3605 Y0.5118 +G01 X-1.3605 Y0.4882 +G01 X-1.3637 Y0.4805 +G01 X-0.6100 Y0.4805 +G01 X-0.6085 Y0.4806 +G01 X-0.6057 Y0.4815 +G01 X-0.6033 Y0.4833 +G01 X-0.6015 Y0.4857 +G01 X-0.6006 Y0.4885 +G01 X-0.6005 Y0.4900 +G01 X-0.6005 Y0.4981 +G01 X-0.6005 Y0.8748 +G01 X-0.6135 Y0.8878 +G01 X-0.6135 Y0.9322 +G01 X-0.5822 Y0.9635 +G01 X-0.5378 Y0.9635 +G01 X-0.5065 Y0.9322 +G01 X-0.5065 Y0.8878 +G01 X-0.5195 Y0.8748 +G01 X-0.5195 Y0.4981 +G00 Z0.1000 +G00 X-1.5535 Y1.8878 +G01 Z-0.0070 F10 +G01 X-1.5535 Y1.9322 F20 +G01 X-1.5222 Y1.9635 +G01 X-1.4778 Y1.9635 +G01 X-1.4465 Y1.9322 +G01 X-1.4465 Y1.8878 +G01 X-1.4595 Y1.8748 +G01 X-1.4595 Y1.7536 +G01 X-1.4496 Y1.7437 +G01 X-1.4405 Y1.7218 +G01 X-1.4405 Y1.7105 +G01 X-0.7619 Y1.7105 +G01 X-0.7557 Y1.7105 +G01 X-0.7284 Y1.7016 +G01 X-0.7052 Y1.6848 +G01 X-0.6884 Y1.6616 +G01 X-0.6795 Y1.6343 +G01 X-0.6795 Y1.6281 +G01 X-0.6795 Y1.6205 +G01 X-0.6795 Y1.6200 +G01 X-0.6795 Y1.6119 +G01 X-0.6795 Y1.5452 +G01 X-0.6665 Y1.5322 +G01 X-0.6665 Y1.4878 +G01 X-0.6978 Y1.4565 +G01 X-0.7422 Y1.4565 +G01 X-0.7735 Y1.4878 +G01 X-0.7735 Y1.5322 +G01 X-0.7605 Y1.5452 +G01 X-0.7605 Y1.6119 +G01 X-0.7605 Y1.6200 +G01 X-0.7606 Y1.6215 +G01 X-0.7615 Y1.6243 +G01 X-0.7633 Y1.6267 +G01 X-0.7657 Y1.6285 +G01 X-0.7685 Y1.6294 +G01 X-0.7700 Y1.6295 +G01 X-1.4478 Y1.6295 +G01 X-1.4625 Y1.6279 +G01 X-1.4953 Y1.6374 +G01 X-1.5117 Y1.6505 +G01 X-1.5118 Y1.6505 +G01 X-1.5337 Y1.6596 +G01 X-1.5504 Y1.6763 +G01 X-1.5595 Y1.6982 +G01 X-1.5595 Y1.7218 +G01 X-1.5504 Y1.7437 +G01 X-1.5405 Y1.7536 +G01 X-1.5405 Y1.8748 +G01 X-1.5535 Y1.8878 +G00 Z0.1000 +G00 X-1.6987 Y1.0535 +G01 Z-0.0070 F10 +G01 X-1.6866 Y1.0535 F20 +G01 X-1.6813 Y1.0535 +G01 X-1.3434 Y1.0535 +G01 X-1.3390 Y1.0579 +G01 X-1.3339 Y1.0600 +G01 X-1.3390 Y1.0621 +G01 X-1.3434 Y1.0665 +G01 X-1.7665 Y1.0665 +G01 X-1.7665 Y1.0035 +G01 X-1.7608 Y1.0173 +G01 X-1.7373 Y1.0408 +G01 X-1.7066 Y1.0535 +G01 X-1.6987 Y1.0535 +G00 Z0.1000 +G00 X-1.7757 Y0.8370 +G01 Z-0.0070 F10 +G01 X-1.7757 Y0.8370 F20 +G01 X-1.7931 Y0.8131 +G01 X-1.8170 Y0.7957 +G01 X-1.8237 Y0.7935 +G01 X-1.7800 Y0.7935 +G01 X-1.7790 Y0.7936 +G01 X-1.7770 Y0.7942 +G01 X-1.7754 Y0.7954 +G01 X-1.7742 Y0.7970 +G01 X-1.7736 Y0.7990 +G01 X-1.7735 Y0.8000 +G01 X-1.7735 Y0.8437 +G01 X-1.7757 Y0.8370 +G00 Z0.1000 +G00 X-1.4452 Y1.5035 +G01 Z-0.0070 F10 +G01 X-1.4452 Y1.5035 F20 +G01 X-1.4170 Y1.4943 +G01 X-1.3931 Y1.4769 +G01 X-1.3758 Y1.4532 +G01 X-1.3748 Y1.4535 +G01 X-1.3600 Y1.4535 +G01 X-1.3513 Y1.4535 +G01 X-1.3434 Y1.4535 +G01 X-1.3390 Y1.4579 +G01 X-1.3182 Y1.4665 +G01 X-1.1818 Y1.4665 +G01 X-1.1610 Y1.4579 +G01 X-1.1451 Y1.4420 +G01 X-1.1435 Y1.4381 +G01 X-1.1435 Y1.5213 +G01 X-1.1435 Y1.5300 +G01 X-1.1436 Y1.5310 +G01 X-1.1442 Y1.5329 +G01 X-1.1454 Y1.5346 +G01 X-1.1470 Y1.5358 +G01 X-1.1490 Y1.5364 +G01 X-1.1500 Y1.5365 +G01 X-1.5613 Y1.5365 +G01 X-1.5684 Y1.5365 +G01 X-1.5787 Y1.5365 +G01 X-1.5848 Y1.5365 +G01 X-1.6130 Y1.5457 +G01 X-1.6369 Y1.5631 +G01 X-1.6543 Y1.5870 +G01 X-1.6635 Y1.6152 +G01 X-1.6635 Y1.6213 +G01 X-1.6635 Y1.6256 +G01 X-1.6635 Y1.6300 +G01 X-1.6635 Y1.6387 +G01 X-1.6635 Y1.7465 +G01 X-1.7366 Y1.7465 +G01 X-1.7336 Y1.7435 +G01 X-1.7313 Y1.7435 +G01 X-1.7254 Y1.7435 +G01 X-1.6984 Y1.7323 +G01 X-1.6777 Y1.7116 +G01 X-1.6665 Y1.6846 +G01 X-1.6665 Y1.6787 +G01 X-1.6665 Y1.6654 +G01 X-1.6665 Y1.6613 +G01 X-1.6665 Y1.5100 +G01 X-1.6664 Y1.5090 +G01 X-1.6658 Y1.5070 +G01 X-1.6646 Y1.5054 +G01 X-1.6629 Y1.5042 +G01 X-1.6610 Y1.5036 +G01 X-1.6600 Y1.5035 +G01 X-1.6529 Y1.5035 +G01 X-1.6513 Y1.5035 +G01 X-1.4513 Y1.5035 +G01 X-1.4452 Y1.5035 +G00 Z0.1000 +G00 X-1.8034 Y1.7465 +G01 Z-0.0070 F10 +G01 X-1.9282 Y1.7465 F20 +G01 X-1.9312 Y1.7435 +G01 X-1.8064 Y1.7435 +G01 X-1.8034 Y1.7465 +G00 Z0.1000 +G00 X-2.6135 Y1.8434 +G01 Z-0.0070 F10 +G01 X-2.6135 Y1.8241 F20 +G01 X-2.5969 Y1.8469 +G01 X-2.5730 Y1.8643 +G01 X-2.5663 Y1.8665 +G01 X-2.6366 Y1.8665 +G01 X-2.6135 Y1.8434 +G00 Z0.1000 +G00 X-2.6401 Y1.7700 +G01 Z-0.0070 F10 +G01 X-2.6336 Y1.7635 F20 +G01 X-2.6300 Y1.7635 +G01 X-2.6290 Y1.7636 +G01 X-2.6270 Y1.7642 +G01 X-2.6254 Y1.7654 +G01 X-2.6242 Y1.7670 +G01 X-2.6236 Y1.7690 +G01 X-2.6235 Y1.7700 +G01 X-2.6235 Y1.7771 +G01 X-2.6235 Y1.7787 +G01 X-2.6235 Y1.7866 +G01 X-2.6401 Y1.7700 +G00 Z0.1000 +G00 X-2.1710 Y1.2621 +G01 Z-0.0070 F10 +G01 X-2.1761 Y1.2600 F20 +G01 X-2.1710 Y1.2579 +G01 X-2.1551 Y1.2420 +G01 X-2.1535 Y1.2381 +G01 X-2.1535 Y1.2665 +G01 X-2.1666 Y1.2665 +G01 X-2.1710 Y1.2621 +G00 Z0.1000 +G00 X-2.1551 Y1.1780 +G01 Z-0.0070 F10 +G01 X-2.1710 Y1.1621 F20 +G01 X-2.1761 Y1.1600 +G01 X-2.1710 Y1.1579 +G01 X-2.1551 Y1.1420 +G01 X-2.1535 Y1.1381 +G01 X-2.1535 Y1.1819 +G01 X-2.1551 Y1.1780 +G00 Z0.1000 +G00 X-2.1551 Y1.0780 +G01 Z-0.0070 F10 +G01 X-2.1710 Y1.0621 F20 +G01 X-2.1761 Y1.0600 +G01 X-2.1710 Y1.0579 +G01 X-2.1551 Y1.0420 +G01 X-2.1535 Y1.0381 +G01 X-2.1535 Y1.0513 +G01 X-2.1535 Y1.0819 +G01 X-2.1551 Y1.0780 +G00 Z0.1000 +G00 X-2.0620 Y1.0535 +G01 Z-0.0070 F10 +G01 X-2.0534 Y1.0535 F20 +G01 X-2.0490 Y1.0579 +G01 X-2.0439 Y1.0600 +G01 X-2.0490 Y1.0621 +G01 X-2.0649 Y1.0780 +G01 X-2.0665 Y1.0819 +G01 X-2.0665 Y1.0580 +G01 X-2.0620 Y1.0535 +G00 Z0.1000 +G00 X-2.0649 Y1.1420 +G01 Z-0.0070 F10 +G01 X-2.0490 Y1.1579 F20 +G01 X-2.0439 Y1.1600 +G01 X-2.0490 Y1.1621 +G01 X-2.0649 Y1.1780 +G01 X-2.0665 Y1.1819 +G01 X-2.0665 Y1.1381 +G01 X-2.0649 Y1.1420 +G00 Z0.1000 +G00 X-2.0649 Y1.2420 +G01 Z-0.0070 F10 +G01 X-2.0490 Y1.2579 F20 +G01 X-2.0439 Y1.2600 +G01 X-2.0490 Y1.2621 +G01 X-2.0649 Y1.2780 +G01 X-2.0665 Y1.2819 +G01 X-2.0665 Y1.2381 +G01 X-2.0649 Y1.2420 +G00 Z0.1000 +G00 X-2.9302 Y1.3865 +G01 Z-0.0070 F10 +G01 X-2.9346 Y1.3883 F20 +G01 X-2.9465 Y1.4002 +G01 X-2.9465 Y1.3865 +G01 X-2.9302 Y1.3865 +G00 Z0.1000 +G00 X-1.1451 Y0.9780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y0.9621 F20 +G01 X-1.1661 Y0.9600 +G01 X-1.1610 Y0.9579 +G01 X-1.1451 Y0.9420 +G01 X-1.1435 Y0.9381 +G01 X-1.1435 Y0.9819 +G01 X-1.1451 Y0.9780 +G00 Z0.1000 +G00 X-1.1451 Y1.0780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y1.0621 F20 +G01 X-1.1661 Y1.0600 +G01 X-1.1610 Y1.0579 +G01 X-1.1451 Y1.0420 +G01 X-1.1435 Y1.0381 +G01 X-1.1435 Y1.0819 +G01 X-1.1451 Y1.0780 +G00 Z0.1000 +G00 X-1.1451 Y1.1780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y1.1621 F20 +G01 X-1.1661 Y1.1600 +G01 X-1.1610 Y1.1579 +G01 X-1.1451 Y1.1420 +G01 X-1.1435 Y1.1381 +G01 X-1.1435 Y1.1819 +G01 X-1.1451 Y1.1780 +G00 Z0.1000 +G00 X-1.1451 Y1.2780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y1.2621 F20 +G01 X-1.1661 Y1.2600 +G01 X-1.1610 Y1.2579 +G01 X-1.1451 Y1.2420 +G01 X-1.1435 Y1.2381 +G01 X-1.1435 Y1.2819 +G01 X-1.1451 Y1.2780 +G00 Z0.1000 +G00 X-1.1451 Y1.3780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y1.3621 F20 +G01 X-1.1661 Y1.3600 +G01 X-1.1610 Y1.3579 +G01 X-1.1451 Y1.3420 +G01 X-1.1435 Y1.3381 +G01 X-1.1435 Y1.3819 +G01 X-1.1451 Y1.3780 +G00 Z0.1000 +G00 X-1.0549 Y1.3420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y1.3579 F20 +G01 X-1.0339 Y1.3600 +G01 X-1.0390 Y1.3621 +G01 X-1.0549 Y1.3780 +G01 X-1.0565 Y1.3819 +G01 X-1.0565 Y1.3381 +G01 X-1.0549 Y1.3420 +G00 Z0.1000 +G00 X-1.0549 Y1.2420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y1.2579 F20 +G01 X-1.0339 Y1.2600 +G01 X-1.0390 Y1.2621 +G01 X-1.0549 Y1.2780 +G01 X-1.0565 Y1.2819 +G01 X-1.0565 Y1.2381 +G01 X-1.0549 Y1.2420 +G00 Z0.1000 +G00 X-1.0549 Y1.1420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y1.1579 F20 +G01 X-1.0339 Y1.1600 +G01 X-1.0390 Y1.1621 +G01 X-1.0549 Y1.1780 +G01 X-1.0565 Y1.1819 +G01 X-1.0565 Y1.1381 +G01 X-1.0549 Y1.1420 +G00 Z0.1000 +G00 X-1.0549 Y1.0420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y1.0579 F20 +G01 X-1.0339 Y1.0600 +G01 X-1.0390 Y1.0621 +G01 X-1.0549 Y1.0780 +G01 X-1.0565 Y1.0819 +G01 X-1.0565 Y1.0381 +G01 X-1.0549 Y1.0420 +G00 Z0.1000 +G00 X-1.0549 Y0.9420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y0.9579 F20 +G01 X-1.0339 Y0.9600 +G01 X-1.0390 Y0.9621 +G01 X-1.0549 Y0.9780 +G01 X-1.0565 Y0.9819 +G01 X-1.0565 Y0.9381 +G01 X-1.0549 Y0.9420 +G00 Z0.1000 +G00 X-1.0564 Y0.8590 +G01 Z-0.0070 F10 +G01 X-1.0558 Y0.8570 F20 +G01 X-1.0546 Y0.8554 +G01 X-1.0529 Y0.8542 +G01 X-1.0510 Y0.8536 +G01 X-1.0500 Y0.8535 +G01 X-1.0434 Y0.8535 +G01 X-1.0390 Y0.8579 +G01 X-1.0339 Y0.8600 +G01 X-1.0390 Y0.8621 +G01 X-1.0549 Y0.8780 +G01 X-1.0565 Y0.8819 +G01 X-1.0565 Y0.8600 +G01 X-1.0564 Y0.8590 +G00 Z0.1000 +G00 X-1.9651 Y0.7035 +G01 Z-0.0070 F10 +G01 X-1.7864 Y0.7035 F20 +G01 X-1.7834 Y0.7065 +G01 X-1.9681 Y0.7065 +G01 X-1.9651 Y0.7035 +G00 Z0.1000 +G00 X-2.7064 Y1.8635 +G01 Z-0.0070 F10 +G01 X-2.7034 Y1.8665 F20 +G01 X-2.9000 Y1.8665 +G01 X-2.9010 Y1.8664 +G01 X-2.9029 Y1.8658 +G01 X-2.9046 Y1.8646 +G01 X-2.9058 Y1.8629 +G01 X-2.9064 Y1.8610 +G01 X-2.9065 Y1.8600 +G01 X-2.9065 Y1.8544 +G01 X-2.9065 Y1.8513 +G01 X-2.9065 Y1.8063 +G01 X-2.9043 Y1.8130 +G01 X-2.8869 Y1.8369 +G01 X-2.8630 Y1.8543 +G01 X-2.8348 Y1.8635 +G01 X-2.8200 Y1.8635 +G01 X-2.8113 Y1.8635 +G01 X-2.7064 Y1.8635 +G00 Z0.1000 +G00 X-3.0223 Y1.5716 +G01 Z-0.0070 F10 +G01 X-3.0223 Y1.5716 F20 +G01 X-3.0016 Y1.5923 +G01 X-2.9746 Y1.6035 +G01 X-2.9687 Y1.6035 +G01 X-2.8287 Y1.6035 +G01 X-2.8235 Y1.6035 +G01 X-2.8235 Y1.6613 +G01 X-2.8235 Y1.6626 +G01 X-2.8235 Y1.6787 +G01 X-2.8235 Y1.6848 +G01 X-2.8143 Y1.7130 +G01 X-2.7969 Y1.7369 +G01 X-2.7730 Y1.7543 +G01 X-2.7448 Y1.7635 +G01 X-2.7300 Y1.7635 +G01 X-2.7064 Y1.7635 +G01 X-2.6999 Y1.7700 +G01 X-2.7064 Y1.7765 +G01 X-2.8113 Y1.7765 +G01 X-2.8200 Y1.7765 +G01 X-2.8210 Y1.7764 +G01 X-2.8229 Y1.7758 +G01 X-2.8246 Y1.7746 +G01 X-2.8258 Y1.7729 +G01 X-2.8264 Y1.7710 +G01 X-2.8265 Y1.7700 +G01 X-2.8265 Y1.6887 +G01 X-2.8265 Y1.6867 +G01 X-2.8265 Y1.6713 +G01 X-2.8265 Y1.6654 +G01 X-2.8377 Y1.6384 +G01 X-2.8584 Y1.6177 +G01 X-2.8854 Y1.6065 +G01 X-2.8913 Y1.6065 +G01 X-3.0113 Y1.6065 +G01 X-3.0200 Y1.6065 +G01 X-3.0210 Y1.6064 +G01 X-3.0229 Y1.6058 +G01 X-3.0246 Y1.6046 +G01 X-3.0258 Y1.6029 +G01 X-3.0264 Y1.6010 +G01 X-3.0265 Y1.6000 +G01 X-3.0265 Y1.5615 +G01 X-3.0223 Y1.5716 +G00 Z0.1000 +G00 X-3.0264 Y1.2890 +G01 Z-0.0070 F10 +G01 X-3.0258 Y1.2870 F20 +G01 X-3.0246 Y1.2854 +G01 X-3.0229 Y1.2842 +G01 X-3.0210 Y1.2836 +G01 X-3.0200 Y1.2835 +G01 X-2.9834 Y1.2835 +G01 X-3.0065 Y1.3066 +G01 X-3.0065 Y1.3084 +G01 X-3.0208 Y1.3227 +G01 X-3.0265 Y1.3365 +G01 X-3.0265 Y1.2900 +G01 X-3.0264 Y1.2890 +G00 Z0.1000 +G00 X-1.8334 Y1.6235 +G01 Z-0.0070 F10 +G01 X-1.8334 Y1.6235 F20 +G01 X-1.8027 Y1.6108 +G01 X-1.7792 Y1.5873 +G01 X-1.7665 Y1.5566 +G01 X-1.7665 Y1.5487 +G01 X-1.7665 Y1.5400 +G01 X-1.7665 Y1.5314 +G01 X-1.7665 Y1.3535 +G01 X-1.7613 Y1.3535 +G01 X-1.6487 Y1.3535 +G01 X-1.6313 Y1.3535 +G01 X-1.5449 Y1.3535 +G01 X-1.5354 Y1.3630 +G01 X-1.5124 Y1.3725 +G01 X-1.4876 Y1.3725 +G01 X-1.4646 Y1.3630 +G01 X-1.4535 Y1.3519 +G01 X-1.4535 Y1.4013 +G01 X-1.4535 Y1.4100 +G01 X-1.4536 Y1.4110 +G01 X-1.4542 Y1.4129 +G01 X-1.4554 Y1.4146 +G01 X-1.4570 Y1.4158 +G01 X-1.4590 Y1.4164 +G01 X-1.4600 Y1.4165 +G01 X-1.6513 Y1.4165 +G01 X-1.6529 Y1.4165 +G01 X-1.6687 Y1.4165 +G01 X-1.6748 Y1.4165 +G01 X-1.7030 Y1.4257 +G01 X-1.7269 Y1.4431 +G01 X-1.7443 Y1.4670 +G01 X-1.7535 Y1.4952 +G01 X-1.7535 Y1.5013 +G01 X-1.7535 Y1.6435 +G01 X-1.7934 Y1.6435 +G01 X-1.8064 Y1.6565 +G01 X-2.0313 Y1.6565 +G01 X-2.0400 Y1.6565 +G01 X-2.0548 Y1.6565 +G01 X-2.0830 Y1.6657 +G01 X-2.1069 Y1.6831 +G01 X-2.1243 Y1.7070 +G01 X-2.1335 Y1.7352 +G01 X-2.1335 Y1.7500 +G01 X-2.1335 Y1.7587 +G01 X-2.1335 Y1.8665 +G01 X-2.3537 Y1.8665 +G01 X-2.3470 Y1.8643 +G01 X-2.3231 Y1.8469 +G01 X-2.3057 Y1.8230 +G01 X-2.2965 Y1.7948 +G01 X-2.2965 Y1.7887 +G01 X-2.2965 Y1.7835 +G01 X-2.2518 Y1.7835 +G01 X-2.2350 Y1.8003 +G01 X-2.1850 Y1.8003 +G01 X-2.1497 Y1.7650 +G01 X-2.1497 Y1.7150 +G01 X-2.1850 Y1.6797 +G01 X-2.2350 Y1.6797 +G01 X-2.2518 Y1.6965 +G01 X-2.3036 Y1.6965 +G01 X-2.3166 Y1.6835 +G01 X-2.3335 Y1.6835 +G01 X-2.3335 Y1.6416 +G01 X-2.3463 Y1.6288 +G01 X-2.3458 Y1.6270 +G01 X-2.3446 Y1.6254 +G01 X-2.3429 Y1.6242 +G01 X-2.3410 Y1.6236 +G01 X-2.3400 Y1.6235 +G01 X-2.3331 Y1.6235 +G01 X-2.3313 Y1.6235 +G01 X-1.8413 Y1.6235 +G01 X-1.8334 Y1.6235 +G00 Z0.1000 +G00 X-2.4787 Y1.7835 +G01 Z-0.0070 F10 +G01 X-2.4764 Y1.7835 F20 +G01 X-2.4734 Y1.7865 +G01 X-2.5213 Y1.7865 +G01 X-2.5300 Y1.7865 +G01 X-2.5310 Y1.7864 +G01 X-2.5329 Y1.7858 +G01 X-2.5346 Y1.7846 +G01 X-2.5358 Y1.7829 +G01 X-2.5364 Y1.7810 +G01 X-2.5365 Y1.7800 +G01 X-2.5365 Y1.7787 +G01 X-2.5365 Y1.7770 +G01 X-2.5365 Y1.7613 +G01 X-2.5365 Y1.7552 +G01 X-2.5457 Y1.7270 +G01 X-2.5631 Y1.7031 +G01 X-2.5870 Y1.6857 +G01 X-2.6152 Y1.6765 +G01 X-2.6213 Y1.6765 +G01 X-2.6336 Y1.6765 +G01 X-2.6436 Y1.6665 +G01 X-2.6366 Y1.6665 +G01 X-2.6236 Y1.6535 +G01 X-2.5435 Y1.6535 +G01 X-2.5435 Y1.7013 +G01 X-2.5435 Y1.7076 +G01 X-2.5435 Y1.7100 +G01 X-2.5435 Y1.7187 +G01 X-2.5435 Y1.7246 +G01 X-2.5323 Y1.7516 +G01 X-2.5116 Y1.7723 +G01 X-2.4846 Y1.7835 +G01 X-2.4787 Y1.7835 +G00 Z0.1000 +G00 X-2.4765 Y1.4313 +G01 Z-0.0070 F10 +G01 X-2.4765 Y1.2600 F20 +G01 X-2.4764 Y1.2590 +G01 X-2.4758 Y1.2570 +G01 X-2.4746 Y1.2554 +G01 X-2.4729 Y1.2542 +G01 X-2.4710 Y1.2536 +G01 X-2.4700 Y1.2535 +G01 X-2.4627 Y1.2535 +G01 X-2.4613 Y1.2535 +G01 X-2.3534 Y1.2535 +G01 X-2.3490 Y1.2579 +G01 X-2.3439 Y1.2600 +G01 X-2.3490 Y1.2621 +G01 X-2.3649 Y1.2780 +G01 X-2.3735 Y1.2988 +G01 X-2.3735 Y1.3212 +G01 X-2.3649 Y1.3420 +G01 X-2.3490 Y1.3579 +G01 X-2.3282 Y1.3665 +G01 X-2.1918 Y1.3665 +G01 X-2.1710 Y1.3579 +G01 X-2.1666 Y1.3535 +G01 X-2.1387 Y1.3535 +G01 X-2.1300 Y1.3535 +G01 X-2.1274 Y1.3535 +G01 X-2.1213 Y1.3535 +G01 X-2.1174 Y1.3535 +G01 X-2.0940 Y1.3438 +G01 X-2.0762 Y1.3260 +G01 X-2.0735 Y1.3195 +G01 X-2.0735 Y1.3212 +G01 X-2.0649 Y1.3420 +G01 X-2.0490 Y1.3579 +G01 X-2.0282 Y1.3665 +G01 X-2.0035 Y1.3665 +G01 X-2.0035 Y1.4113 +G01 X-2.0035 Y1.4182 +G01 X-2.0118 Y1.4265 +G01 X-2.0187 Y1.4265 +G01 X-2.1682 Y1.4265 +G01 X-2.1850 Y1.4097 +G01 X-2.2350 Y1.4097 +G01 X-2.2395 Y1.4142 +G01 X-2.2747 Y1.3790 +G01 X-2.3253 Y1.3790 +G01 X-2.3610 Y1.4147 +G01 X-2.3610 Y1.4653 +G01 X-2.3253 Y1.5010 +G01 X-2.2747 Y1.5010 +G01 X-2.2697 Y1.4959 +G01 X-2.2691 Y1.4961 +G01 X-2.2350 Y1.5303 +G01 X-2.1850 Y1.5303 +G01 X-2.1682 Y1.5135 +G01 X-2.0187 Y1.5135 +G01 X-2.0118 Y1.5135 +G01 X-1.9950 Y1.5303 +G01 X-1.9450 Y1.5303 +G01 X-1.9097 Y1.4950 +G01 X-1.9097 Y1.4450 +G01 X-1.9173 Y1.4374 +G01 X-1.9165 Y1.4348 +G01 X-1.9165 Y1.4200 +G01 X-1.9165 Y1.4113 +G01 X-1.9165 Y1.3665 +G01 X-1.8918 Y1.3665 +G01 X-1.8710 Y1.3579 +G01 X-1.8551 Y1.3420 +G01 X-1.8535 Y1.3381 +G01 X-1.8535 Y1.5313 +G01 X-1.8535 Y1.5365 +G01 X-2.3313 Y1.5365 +G01 X-2.3331 Y1.5365 +G01 X-2.3487 Y1.5365 +G01 X-2.3548 Y1.5365 +G01 X-2.3830 Y1.5457 +G01 X-2.4069 Y1.5631 +G01 X-2.4243 Y1.5870 +G01 X-2.4335 Y1.6152 +G01 X-2.4335 Y1.6213 +G01 X-2.4335 Y1.6286 +G01 X-2.4465 Y1.6416 +G01 X-2.4465 Y1.6835 +G01 X-2.4565 Y1.6835 +G01 X-2.4565 Y1.6013 +G01 X-2.4631 Y1.5854 +G01 X-2.4754 Y1.5731 +G01 X-2.4765 Y1.5726 +G01 X-2.4765 Y1.4313 +G00 Z0.1000 +G00 X-2.6366 Y1.5535 +G01 Z-0.0070 F10 +G01 X-2.6834 Y1.5535 F20 +G01 X-2.7165 Y1.5866 +G01 X-2.7165 Y1.6334 +G01 X-2.6864 Y1.6635 +G01 X-2.6934 Y1.6635 +G01 X-2.7064 Y1.6765 +G01 X-2.7300 Y1.6765 +G01 X-2.7310 Y1.6764 +G01 X-2.7329 Y1.6758 +G01 X-2.7346 Y1.6746 +G01 X-2.7358 Y1.6729 +G01 X-2.7364 Y1.6710 +G01 X-2.7365 Y1.6700 +G01 X-2.7365 Y1.6626 +G01 X-2.7365 Y1.6613 +G01 X-2.7365 Y1.5913 +G01 X-2.7365 Y1.5834 +G01 X-2.7492 Y1.5527 +G01 X-2.7727 Y1.5292 +G01 X-2.8034 Y1.5165 +G01 X-2.8113 Y1.5165 +G01 X-2.8200 Y1.5165 +G01 X-2.8287 Y1.5165 +G01 X-2.9465 Y1.5165 +G01 X-2.9465 Y1.4798 +G01 X-2.9346 Y1.4917 +G01 X-2.9121 Y1.5010 +G01 X-2.8879 Y1.5010 +G01 X-2.8654 Y1.4917 +G01 X-2.8572 Y1.4835 +G01 X-2.5635 Y1.4835 +G01 X-2.5635 Y1.5665 +G01 X-2.6236 Y1.5665 +G01 X-2.6366 Y1.5535 +G00 Z0.1000 +G00 X-2.6934 Y1.3065 +G01 Z-0.0070 F10 +G01 X-2.6466 Y1.3065 F20 +G01 X-2.6135 Y1.2734 +G01 X-2.6135 Y1.2266 +G01 X-2.6466 Y1.1935 +G01 X-2.6769 Y1.1935 +G01 X-2.6999 Y1.1889 +G01 X-2.7310 Y1.1950 +G01 X-2.7332 Y1.1965 +G01 X-3.0287 Y1.1965 +G01 X-3.0348 Y1.1965 +G01 X-3.0630 Y1.2057 +G01 X-3.0869 Y1.2231 +G01 X-3.1043 Y1.2470 +G01 X-3.1135 Y1.2752 +G01 X-3.1135 Y1.2813 +G01 X-3.1135 Y1.5766 +G01 X-3.1165 Y1.5736 +G01 X-3.1165 Y0.9600 +G01 X-3.1164 Y0.9590 +G01 X-3.1158 Y0.9570 +G01 X-3.1146 Y0.9554 +G01 X-3.1129 Y0.9542 +G01 X-3.1110 Y0.9536 +G01 X-3.1100 Y0.9535 +G01 X-3.1044 Y0.9535 +G01 X-3.1013 Y0.9535 +G01 X-2.5518 Y0.9535 +G01 X-2.5388 Y0.9665 +G01 X-2.9087 Y0.9665 +G01 X-2.9148 Y0.9665 +G01 X-2.9430 Y0.9757 +G01 X-2.9669 Y0.9931 +G01 X-2.9843 Y1.0170 +G01 X-2.9935 Y1.0452 +G01 X-2.9935 Y1.0513 +G01 X-2.9935 Y1.0936 +G01 X-3.0065 Y1.1066 +G01 X-3.0065 Y1.1534 +G01 X-2.9734 Y1.1865 +G01 X-2.9266 Y1.1865 +G01 X-2.8935 Y1.1534 +G01 X-2.8935 Y1.1066 +G01 X-2.9065 Y1.0936 +G01 X-2.9065 Y1.0600 +G01 X-2.9064 Y1.0590 +G01 X-2.9058 Y1.0570 +G01 X-2.9046 Y1.0554 +G01 X-2.9029 Y1.0542 +G01 X-2.9010 Y1.0536 +G01 X-2.9000 Y1.0535 +G01 X-2.3534 Y1.0535 +G01 X-2.3490 Y1.0579 +G01 X-2.3439 Y1.0600 +G01 X-2.3490 Y1.0621 +G01 X-2.3649 Y1.0780 +G01 X-2.3735 Y1.0988 +G01 X-2.3735 Y1.1212 +G01 X-2.3649 Y1.1420 +G01 X-2.3490 Y1.1579 +G01 X-2.3439 Y1.1600 +G01 X-2.3490 Y1.1621 +G01 X-2.3534 Y1.1665 +G01 X-2.4613 Y1.1665 +G01 X-2.4627 Y1.1665 +G01 X-2.4787 Y1.1665 +G01 X-2.4848 Y1.1665 +G01 X-2.5130 Y1.1757 +G01 X-2.5369 Y1.1931 +G01 X-2.5543 Y1.2170 +G01 X-2.5635 Y1.2452 +G01 X-2.5635 Y1.2513 +G01 X-2.5635 Y1.3965 +G01 X-2.8572 Y1.3965 +G01 X-2.8654 Y1.3883 +G01 X-2.8879 Y1.3790 +G01 X-2.9121 Y1.3790 +G01 X-2.9240 Y1.3839 +G01 X-2.8935 Y1.3534 +G01 X-2.8935 Y1.3066 +G01 X-2.9166 Y1.2835 +G01 X-2.7243 Y1.2835 +G01 X-2.7200 Y1.2843 +G01 X-2.7163 Y1.2836 +G01 X-2.6934 Y1.3065 +G00 Z0.1000 +G00 X-1.8551 Y1.2780 +G01 Z-0.0070 F10 +G01 X-1.8710 Y1.2621 F20 +G01 X-1.8761 Y1.2600 +G01 X-1.8710 Y1.2579 +G01 X-1.8566 Y1.2435 +G01 X-1.8135 Y1.2435 +G01 X-1.8135 Y1.2665 +G01 X-1.8187 Y1.2665 +G01 X-1.8346 Y1.2731 +G01 X-1.8469 Y1.2854 +G01 X-1.8495 Y1.2916 +G01 X-1.8551 Y1.2780 +G00 Z0.1000 +G00 X-1.8551 Y0.9780 +G01 Z-0.0070 F10 +G01 X-1.8710 Y0.9621 F20 +G01 X-1.8918 Y0.9535 +G01 X-2.0282 Y0.9535 +G01 X-2.0490 Y0.9621 +G01 X-2.0534 Y0.9665 +G01 X-2.0665 Y0.9665 +G01 X-2.0665 Y0.9513 +G01 X-2.0665 Y0.9452 +G01 X-2.0757 Y0.9170 +G01 X-2.0931 Y0.8931 +G01 X-2.1170 Y0.8757 +G01 X-2.1237 Y0.8735 +G01 X-1.8600 Y0.8735 +G01 X-1.8590 Y0.8736 +G01 X-1.8570 Y0.8742 +G01 X-1.8554 Y0.8754 +G01 X-1.8542 Y0.8770 +G01 X-1.8536 Y0.8790 +G01 X-1.8535 Y0.8800 +G01 X-1.8535 Y0.9819 +G01 X-1.8551 Y0.9780 +G00 Z0.1000 +G00 X-1.8710 Y1.0621 +G01 Z-0.0070 F10 +G01 X-1.8761 Y1.0600 F20 +G01 X-1.8710 Y1.0579 +G01 X-1.8551 Y1.0420 +G01 X-1.8535 Y1.0381 +G01 X-1.8535 Y1.0665 +G01 X-1.8666 Y1.0665 +G01 X-1.8710 Y1.0621 +G00 Z0.1000 +G00 X-1.8064 Y1.1565 +G01 Z-0.0070 F10 +G01 X-1.8696 Y1.1565 F20 +G01 X-1.8666 Y1.1535 +G01 X-1.8187 Y1.1535 +G01 X-1.8034 Y1.1535 +G01 X-1.8064 Y1.1565 +G00 Z0.1000 +G00 X-1.7135 Y1.2234 +G01 Z-0.0070 F10 +G01 X-1.7135 Y1.1766 F20 +G01 X-1.7366 Y1.1535 +G01 X-1.3434 Y1.1535 +G01 X-1.3390 Y1.1579 +G01 X-1.3339 Y1.1600 +G01 X-1.3390 Y1.1621 +G01 X-1.3549 Y1.1780 +G01 X-1.3635 Y1.1988 +G01 X-1.3635 Y1.2212 +G01 X-1.3549 Y1.2420 +G01 X-1.3390 Y1.2579 +G01 X-1.3339 Y1.2600 +G01 X-1.3390 Y1.2621 +G01 X-1.3549 Y1.2780 +G01 X-1.3635 Y1.2988 +G01 X-1.3635 Y1.3212 +G01 X-1.3549 Y1.3420 +G01 X-1.3390 Y1.3579 +G01 X-1.3339 Y1.3600 +G01 X-1.3390 Y1.3621 +G01 X-1.3434 Y1.3665 +G01 X-1.3513 Y1.3665 +G01 X-1.3600 Y1.3665 +G01 X-1.3610 Y1.3664 +G01 X-1.3629 Y1.3658 +G01 X-1.3646 Y1.3646 +G01 X-1.3658 Y1.3629 +G01 X-1.3664 Y1.3610 +G01 X-1.3665 Y1.3600 +G01 X-1.3665 Y1.2687 +G01 X-1.3665 Y1.2594 +G01 X-1.3665 Y1.2583 +G01 X-1.3665 Y1.2421 +G01 X-1.3665 Y1.2384 +G01 X-1.3729 Y1.2146 +G01 X-1.3735 Y1.2135 +G01 X-1.3735 Y1.1866 +G01 X-1.4066 Y1.1535 +G01 X-1.4534 Y1.1535 +G01 X-1.4865 Y1.1866 +G01 X-1.4865 Y1.2334 +G01 X-1.4535 Y1.2664 +G01 X-1.4535 Y1.2681 +G01 X-1.4646 Y1.2570 +G01 X-1.4876 Y1.2475 +G01 X-1.5124 Y1.2475 +G01 X-1.5354 Y1.2570 +G01 X-1.5449 Y1.2665 +G01 X-1.5797 Y1.2665 +G01 X-1.5797 Y1.2450 +G01 X-1.6150 Y1.2097 +G01 X-1.6650 Y1.2097 +G01 X-1.7003 Y1.2450 +G01 X-1.7003 Y1.2665 +G01 X-1.7265 Y1.2665 +G01 X-1.7265 Y1.2364 +G01 X-1.7135 Y1.2234 +G00 Z0.1000 +G00 X-2.4682 Y0.9535 +G01 Z-0.0070 F10 +G01 X-2.1687 Y0.9535 F20 +G01 X-2.1600 Y0.9535 +G01 X-2.1590 Y0.9536 +G01 X-2.1570 Y0.9542 +G01 X-2.1554 Y0.9554 +G01 X-2.1542 Y0.9570 +G01 X-2.1536 Y0.9590 +G01 X-2.1535 Y0.9600 +G01 X-2.1535 Y0.9819 +G01 X-2.1551 Y0.9780 +G01 X-2.1710 Y0.9621 +G01 X-2.1918 Y0.9535 +G01 X-2.3282 Y0.9535 +G01 X-2.3490 Y0.9621 +G01 X-2.3534 Y0.9665 +G01 X-2.4812 Y0.9665 +G01 X-2.4682 Y0.9535 +G00 Z0.1000 +G00 X-3.0287 Y1.6935 +G01 Z-0.0070 F10 +G01 X-3.0200 Y1.6935 F20 +G01 X-3.0113 Y1.6935 +G01 X-2.9135 Y1.6935 +G01 X-2.9135 Y1.7465 +G01 X-2.9192 Y1.7327 +G01 X-2.9427 Y1.7092 +G01 X-2.9734 Y1.6965 +G01 X-2.9900 Y1.6965 +G01 X-2.9987 Y1.6965 +G01 X-3.1100 Y1.6965 +G01 X-3.1110 Y1.6964 +G01 X-3.1129 Y1.6958 +G01 X-3.1146 Y1.6946 +G01 X-3.1158 Y1.6929 +G01 X-3.1164 Y1.6910 +G01 X-3.1165 Y1.6900 +G01 X-3.1165 Y1.6825 +G01 X-3.1165 Y1.6813 +G01 X-3.1165 Y1.6464 +G01 X-3.1065 Y1.6364 +G01 X-3.1043 Y1.6430 +G01 X-3.0869 Y1.6669 +G01 X-3.0630 Y1.6843 +G01 X-3.0348 Y1.6935 +G01 X-3.0287 Y1.6935 +G00 Z0.1000 +G00 X-1.3434 Y0.9535 +G01 Z-0.0070 F10 +G01 X-1.3390 Y0.9579 F20 +G01 X-1.3339 Y0.9600 +G01 X-1.3390 Y0.9621 +G01 X-1.3434 Y0.9665 +G01 X-1.6813 Y0.9665 +G01 X-1.6865 Y0.9665 +G01 X-1.6865 Y0.9638 +G01 X-1.6865 Y0.9613 +G01 X-1.6865 Y0.8963 +G01 X-1.6843 Y0.9030 +G01 X-1.6669 Y0.9269 +G01 X-1.6430 Y0.9443 +G01 X-1.6148 Y0.9535 +G01 X-1.6000 Y0.9535 +G01 X-1.5913 Y0.9535 +G01 X-1.3434 Y0.9535 +G00 Z0.1000 +G00 X-2.3870 Y1.7858 +G01 Z-0.0070 F10 +G01 X-2.3890 Y1.7864 F20 +G01 X-2.3900 Y1.7865 +G01 X-2.4066 Y1.7865 +G01 X-2.3900 Y1.7699 +G01 X-2.3835 Y1.7764 +G01 X-2.3835 Y1.7800 +G01 X-2.3836 Y1.7810 +G01 X-2.3842 Y1.7829 +G01 X-2.3854 Y1.7846 +G01 X-2.3870 Y1.7858 +G00 Z0.1000 +G00 X-1.9766 Y1.8535 +G01 Z-0.0070 F10 +G01 X-2.0234 Y1.8535 F20 +G01 X-2.0364 Y1.8665 +G01 X-2.0465 Y1.8665 +G01 X-2.0465 Y1.7587 +G01 X-2.0465 Y1.7500 +G01 X-2.0464 Y1.7490 +G01 X-2.0458 Y1.7470 +G01 X-2.0446 Y1.7454 +G01 X-2.0429 Y1.7442 +G01 X-2.0410 Y1.7436 +G01 X-2.0400 Y1.7435 +G01 X-2.0313 Y1.7435 +G01 X-2.0088 Y1.7435 +G01 X-2.0303 Y1.7650 +G01 X-2.0303 Y1.8150 +G01 X-1.9950 Y1.8503 +G01 X-1.9450 Y1.8503 +G01 X-1.9282 Y1.8335 +G01 X-1.6635 Y1.8335 +G01 X-1.6635 Y1.9687 +G01 X-1.6635 Y1.9748 +G01 X-1.6543 Y2.0030 +G01 X-1.6369 Y2.0269 +G01 X-1.6130 Y2.0443 +G01 X-1.5848 Y2.0535 +G01 X-1.5700 Y2.0535 +G01 X-1.5613 Y2.0535 +G01 X-1.4187 Y2.0535 +G01 X-1.4100 Y2.0535 +G01 X-1.4013 Y2.0535 +G01 X-1.3952 Y2.0535 +G01 X-1.3670 Y2.0443 +G01 X-1.3431 Y2.0269 +G01 X-1.3257 Y2.0030 +G01 X-1.3165 Y1.9748 +G01 X-1.3165 Y1.9687 +G01 X-1.3165 Y1.9028 +G01 X-1.2990 Y1.8853 +G01 X-1.2990 Y1.8347 +G01 X-1.3165 Y1.8172 +G01 X-1.3165 Y1.8100 +G01 X-1.3164 Y1.8090 +G01 X-1.3158 Y1.8070 +G01 X-1.3146 Y1.8054 +G01 X-1.3129 Y1.8042 +G01 X-1.3110 Y1.8036 +G01 X-1.3100 Y1.8035 +G01 X-1.3028 Y1.8035 +G01 X-1.3013 Y1.8035 +G01 X-0.7830 Y1.8035 +G01 X-0.7946 Y1.8083 +G01 X-0.8028 Y1.8165 +G01 X-1.1513 Y1.8165 +G01 X-1.1600 Y1.8165 +G01 X-1.1748 Y1.8165 +G01 X-1.2030 Y1.8257 +G01 X-1.2269 Y1.8431 +G01 X-1.2443 Y1.8670 +G01 X-1.2535 Y1.8952 +G01 X-1.2535 Y1.9013 +G01 X-1.2535 Y2.0513 +G01 X-1.2535 Y2.0598 +G01 X-1.2535 Y2.0600 +G01 X-1.2536 Y2.0610 +G01 X-1.2542 Y2.0629 +G01 X-1.2554 Y2.0646 +G01 X-1.2570 Y2.0658 +G01 X-1.2590 Y2.0664 +G01 X-1.2600 Y2.0665 +G01 X-1.6700 Y2.0665 +G01 X-1.6710 Y2.0664 +G01 X-1.6730 Y2.0658 +G01 X-1.6746 Y2.0646 +G01 X-1.6758 Y2.0629 +G01 X-1.6764 Y2.0610 +G01 X-1.6765 Y2.0600 +G01 X-1.6765 Y1.9687 +G01 X-1.6765 Y1.9649 +G01 X-1.6765 Y1.9513 +G01 X-1.6765 Y1.9452 +G01 X-1.6857 Y1.9170 +G01 X-1.7031 Y1.8931 +G01 X-1.7270 Y1.8757 +G01 X-1.7552 Y1.8665 +G01 X-1.7613 Y1.8665 +G01 X-1.9636 Y1.8665 +G01 X-1.9766 Y1.8535 +G00 Z0.1000 +G00 X-0.4165 Y0.2852 +G01 Z-0.0070 F10 +G01 X-0.4165 Y0.2852 F20 +G01 X-0.4257 Y0.2570 +G01 X-0.4431 Y0.2331 +G01 X-0.4670 Y0.2157 +G01 X-0.4952 Y0.2065 +G01 X-0.5100 Y0.2065 +G01 X-0.5187 Y0.2065 +G01 X-1.0400 Y0.2065 +G01 X-1.0410 Y0.2064 +G01 X-1.0430 Y0.2058 +G01 X-1.0446 Y0.2046 +G01 X-1.0458 Y0.2029 +G01 X-1.0464 Y0.2010 +G01 X-1.0465 Y0.2000 +G01 X-1.0465 Y0.1924 +G01 X-1.0465 Y0.1913 +G01 X-1.0465 Y0.1413 +G01 X-1.0465 Y0.1352 +G01 X-1.0557 Y0.1070 +G01 X-1.0731 Y0.0831 +G01 X-1.0970 Y0.0657 +G01 X-1.1252 Y0.0565 +G01 X-1.1313 Y0.0565 +G01 X-1.1400 Y0.0565 +G01 X-1.1487 Y0.0565 +G01 X-1.6087 Y0.0565 +G01 X-1.6148 Y0.0565 +G01 X-1.6430 Y0.0657 +G01 X-1.6669 Y0.0831 +G01 X-1.6843 Y0.1070 +G01 X-1.6935 Y0.1352 +G01 X-1.6935 Y0.1413 +G01 X-1.6935 Y0.1434 +G01 X-1.6935 Y0.1500 +G01 X-1.6935 Y0.1587 +G01 X-1.6935 Y0.7637 +G01 X-1.6957 Y0.7570 +G01 X-1.7131 Y0.7331 +G01 X-1.7359 Y0.7165 +G01 X-1.7266 Y0.7165 +G01 X-1.6935 Y0.6834 +G01 X-1.6935 Y0.6366 +G01 X-1.7266 Y0.6035 +G01 X-1.7734 Y0.6035 +G01 X-1.7864 Y0.6165 +G01 X-1.8612 Y0.6165 +G01 X-1.8397 Y0.5950 +G01 X-1.8397 Y0.5595 +G01 X-1.8324 Y0.5625 +G01 X-1.8076 Y0.5625 +G01 X-1.7846 Y0.5530 +G01 X-1.7670 Y0.5354 +G01 X-1.7575 Y0.5124 +G01 X-1.7575 Y0.4876 +G01 X-1.7670 Y0.4646 +G01 X-1.7765 Y0.4551 +G01 X-1.7765 Y0.3849 +G01 X-1.7670 Y0.3754 +G01 X-1.7575 Y0.3524 +G01 X-1.7575 Y0.3276 +G01 X-1.7670 Y0.3046 +G01 X-1.7846 Y0.2870 +G01 X-1.8076 Y0.2775 +G01 X-1.8324 Y0.2775 +G01 X-1.8554 Y0.2870 +G01 X-1.8649 Y0.2965 +G01 X-1.9513 Y0.2965 +G01 X-1.9581 Y0.2965 +G01 X-1.9570 Y0.2954 +G01 X-1.9475 Y0.2724 +G01 X-1.9475 Y0.2476 +G01 X-1.9570 Y0.2246 +G01 X-1.9746 Y0.2070 +G01 X-1.9976 Y0.1975 +G01 X-2.0224 Y0.1975 +G01 X-2.0454 Y0.2070 +G01 X-2.0630 Y0.2246 +G01 X-2.0725 Y0.2476 +G01 X-2.0725 Y0.2724 +G01 X-2.0630 Y0.2954 +G01 X-2.0535 Y0.3049 +G01 X-2.0443 Y0.3330 +G01 X-2.0269 Y0.3569 +G01 X-2.0030 Y0.3743 +G01 X-1.9748 Y0.3835 +G01 X-1.9600 Y0.3835 +G01 X-1.9513 Y0.3835 +G01 X-1.8649 Y0.3835 +G01 X-1.8635 Y0.3849 +G01 X-1.8635 Y0.4551 +G01 X-1.8649 Y0.4565 +G01 X-1.8930 Y0.4657 +G01 X-1.9169 Y0.4831 +G01 X-1.9343 Y0.5070 +G01 X-1.9401 Y0.5249 +G01 X-1.9603 Y0.5450 +G01 X-1.9603 Y0.5950 +G01 X-1.9388 Y0.6165 +G01 X-1.9651 Y0.6165 +G01 X-1.9746 Y0.6070 +G01 X-1.9976 Y0.5975 +G01 X-2.0224 Y0.5975 +G01 X-2.0454 Y0.6070 +G01 X-2.0549 Y0.6165 +G01 X-2.0900 Y0.6165 +G01 X-2.0910 Y0.6164 +G01 X-2.0929 Y0.6158 +G01 X-2.0946 Y0.6146 +G01 X-2.0958 Y0.6129 +G01 X-2.0964 Y0.6110 +G01 X-2.0965 Y0.6100 +G01 X-2.0965 Y0.6013 +G01 X-2.0965 Y0.2964 +G01 X-2.0835 Y0.2834 +G01 X-2.0835 Y0.2366 +G01 X-2.1166 Y0.2035 +G01 X-2.1634 Y0.2035 +G01 X-2.1965 Y0.2366 +G01 X-2.1965 Y0.2834 +G01 X-2.1835 Y0.2964 +G01 X-2.1835 Y0.6013 +G01 X-2.1835 Y0.6100 +G01 X-2.1835 Y0.6248 +G01 X-2.1743 Y0.6530 +G01 X-2.1569 Y0.6769 +G01 X-2.1330 Y0.6943 +G01 X-2.1048 Y0.7035 +G01 X-2.0987 Y0.7035 +G01 X-2.0549 Y0.7035 +G01 X-2.0519 Y0.7065 +G01 X-2.1813 Y0.7065 +G01 X-2.1865 Y0.7065 +G01 X-2.1865 Y0.5987 +G01 X-2.1865 Y0.5973 +G01 X-2.1865 Y0.5813 +G01 X-2.1865 Y0.5734 +G01 X-2.1992 Y0.5427 +G01 X-2.2227 Y0.5192 +G01 X-2.2534 Y0.5065 +G01 X-2.2700 Y0.5065 +G01 X-2.2787 Y0.5065 +G01 X-2.4712 Y0.5065 +G01 X-2.4497 Y0.4850 +G01 X-2.4497 Y0.4350 +G01 X-2.4565 Y0.4282 +G01 X-2.4565 Y0.2706 +G01 X-2.4565 Y0.1935 +G01 X-2.4508 Y0.1935 +G01 X-2.4494 Y0.1935 +G01 X-1.8765 Y0.1935 +G01 X-1.8765 Y0.2234 +G01 X-1.8434 Y0.2565 +G01 X-1.7966 Y0.2565 +G01 X-1.7635 Y0.2234 +G01 X-1.7635 Y0.1766 +G01 X-1.7665 Y0.1736 +G01 X-1.7766 Y0.1424 +G01 X-1.7959 Y0.1159 +G01 X-1.8224 Y0.0966 +G01 X-1.8536 Y0.0865 +G01 X-1.8594 Y0.0865 +G01 X-2.4494 Y0.0865 +G01 X-2.4508 Y0.0865 +G01 X-2.4706 Y0.0865 +G01 X-2.4764 Y0.0865 +G01 X-2.5076 Y0.0966 +G01 X-2.5341 Y0.1159 +G01 X-2.5534 Y0.1424 +G01 X-2.5635 Y0.1736 +G01 X-2.5635 Y0.1794 +G01 X-2.5635 Y0.2165 +G01 X-2.6036 Y0.2165 +G01 X-2.6166 Y0.2035 +G01 X-2.6634 Y0.2035 +G01 X-2.6965 Y0.2366 +G01 X-2.6965 Y0.2834 +G01 X-2.6634 Y0.3165 +G01 X-2.6166 Y0.3165 +G01 X-2.6036 Y0.3035 +G01 X-2.5635 Y0.3035 +G01 X-2.5635 Y0.4282 +G01 X-2.5703 Y0.4350 +G01 X-2.5703 Y0.4850 +G01 X-2.5488 Y0.5065 +G01 X-2.8063 Y0.5065 +G01 X-2.8155 Y0.4973 +G01 X-2.8390 Y0.4876 +G01 X-3.0010 Y0.4876 +G01 X-3.0245 Y0.4973 +G01 X-3.0425 Y0.5153 +G01 X-3.0522 Y0.5388 +G01 X-3.0522 Y0.5643 +G01 X-3.0425 Y0.5878 +G01 X-3.0245 Y0.6058 +G01 X-3.0010 Y0.6156 +G01 X-2.8390 Y0.6156 +G01 X-2.8155 Y0.6058 +G01 X-2.8032 Y0.5935 +G01 X-2.2787 Y0.5935 +G01 X-2.2735 Y0.5935 +G01 X-2.2735 Y0.5973 +G01 X-2.2735 Y0.5987 +G01 X-2.2735 Y0.7187 +G01 X-2.2735 Y0.7266 +G01 X-2.2608 Y0.7573 +G01 X-2.2373 Y0.7808 +G01 X-2.2235 Y0.7865 +G01 X-2.2713 Y0.7865 +G01 X-2.2800 Y0.7865 +G01 X-2.2810 Y0.7864 +G01 X-2.2829 Y0.7858 +G01 X-2.2846 Y0.7846 +G01 X-2.2858 Y0.7829 +G01 X-2.2864 Y0.7810 +G01 X-2.2865 Y0.7800 +G01 X-2.2865 Y0.7513 +G01 X-2.2865 Y0.7474 +G01 X-2.2962 Y0.7240 +G01 X-2.3140 Y0.7062 +G01 X-2.3374 Y0.6965 +G01 X-2.3413 Y0.6965 +G01 X-2.3500 Y0.6965 +G01 X-2.3587 Y0.6965 +G01 X-2.6436 Y0.6965 +G01 X-2.6466 Y0.6935 +G01 X-2.6934 Y0.6935 +G01 X-2.7064 Y0.7065 +G01 X-2.8032 Y0.7065 +G01 X-2.8155 Y0.6942 +G01 X-2.8390 Y0.6844 +G01 X-3.0010 Y0.6844 +G01 X-3.0245 Y0.6942 +G01 X-3.0425 Y0.7122 +G01 X-3.0522 Y0.7357 +G01 X-3.0522 Y0.7612 +G01 X-3.0425 Y0.7847 +G01 X-3.0245 Y0.8027 +G01 X-3.0010 Y0.8124 +G01 X-2.8390 Y0.8124 +G01 X-2.8155 Y0.8027 +G01 X-2.8063 Y0.7935 +G01 X-2.7064 Y0.7935 +G01 X-2.6934 Y0.8065 +G01 X-2.6466 Y0.8065 +G01 X-2.6236 Y0.7835 +G01 X-2.3735 Y0.7835 +G01 X-2.3735 Y0.7887 +G01 X-2.3735 Y0.7948 +G01 X-2.3643 Y0.8230 +G01 X-2.3469 Y0.8469 +G01 X-2.3230 Y0.8643 +G01 X-2.3163 Y0.8665 +G01 X-2.4682 Y0.8665 +G01 X-2.4850 Y0.8497 +G01 X-2.5350 Y0.8497 +G01 X-2.5518 Y0.8665 +G01 X-3.1013 Y0.8665 +G01 X-3.1044 Y0.8665 +G01 X-3.1187 Y0.8665 +G01 X-3.1248 Y0.8665 +G01 X-3.1530 Y0.8757 +G01 X-3.1769 Y0.8931 +G01 X-3.1943 Y0.9170 +G01 X-3.2035 Y0.9452 +G01 X-3.2035 Y0.9513 +G01 X-3.2035 Y1.5736 +G01 X-3.2165 Y1.5866 +G01 X-3.2165 Y1.6334 +G01 X-3.2035 Y1.6464 +G01 X-3.2035 Y1.6813 +G01 X-3.2035 Y1.6825 +G01 X-3.2035 Y1.6987 +G01 X-3.2035 Y1.7048 +G01 X-3.1943 Y1.7330 +G01 X-3.1769 Y1.7569 +G01 X-3.1530 Y1.7743 +G01 X-3.1248 Y1.7835 +G01 X-3.1187 Y1.7835 +G01 X-2.9987 Y1.7835 +G01 X-2.9935 Y1.7835 +G01 X-2.9935 Y1.8513 +G01 X-2.9935 Y1.8544 +G01 X-2.9935 Y1.8687 +G01 X-2.9935 Y1.8748 +G01 X-2.9843 Y1.9030 +G01 X-2.9669 Y1.9269 +G01 X-2.9430 Y1.9443 +G01 X-2.9148 Y1.9535 +G01 X-2.9087 Y1.9535 +G01 X-2.0813 Y1.9535 +G01 X-2.0364 Y1.9535 +G01 X-2.0234 Y1.9665 +G01 X-1.9766 Y1.9665 +G01 X-1.9636 Y1.9535 +G01 X-1.7700 Y1.9535 +G01 X-1.7690 Y1.9536 +G01 X-1.7670 Y1.9542 +G01 X-1.7654 Y1.9554 +G01 X-1.7642 Y1.9570 +G01 X-1.7636 Y1.9590 +G01 X-1.7635 Y1.9600 +G01 X-1.7635 Y1.9650 +G01 X-1.7635 Y1.9687 +G01 X-1.7635 Y2.0687 +G01 X-1.7635 Y2.0748 +G01 X-1.7543 Y2.1030 +G01 X-1.7369 Y2.1269 +G01 X-1.7130 Y2.1443 +G01 X-1.6848 Y2.1535 +G01 X-1.6787 Y2.1535 +G01 X-1.2513 Y2.1535 +G01 X-1.2452 Y2.1535 +G01 X-1.2170 Y2.1443 +G01 X-1.1931 Y2.1269 +G01 X-1.1757 Y2.1030 +G01 X-1.1665 Y2.0748 +G01 X-1.1665 Y2.0687 +G01 X-1.1665 Y2.0597 +G01 X-1.1665 Y2.0513 +G01 X-1.1665 Y1.9100 +G01 X-1.1664 Y1.9090 +G01 X-1.1658 Y1.9070 +G01 X-1.1646 Y1.9054 +G01 X-1.1629 Y1.9042 +G01 X-1.1610 Y1.9036 +G01 X-1.1600 Y1.9035 +G01 X-1.1513 Y1.9035 +G01 X-0.8028 Y1.9035 +G01 X-0.7946 Y1.9117 +G01 X-0.7721 Y1.9210 +G01 X-0.7479 Y1.9210 +G01 X-0.7254 Y1.9117 +G01 X-0.7172 Y1.9035 +G01 X-0.2629 Y1.9035 +G01 X-0.2533 Y1.9035 +G01 X-0.2187 Y1.8922 +G01 X-0.1892 Y1.8708 +G01 X-0.1758 Y1.8524 +G01 X-0.1190 Y1.8524 +G01 X-0.0955 Y1.8427 +G01 X-0.0775 Y1.8247 +G01 X-0.0678 Y1.8012 +G01 X-0.0678 Y1.7757 +G01 X-0.0775 Y1.7522 +G01 X-0.0955 Y1.7342 +G01 X-0.1190 Y1.7244 +G01 X-0.2810 Y1.7244 +G01 X-0.3045 Y1.7342 +G01 X-0.3225 Y1.7522 +G01 X-0.3322 Y1.7757 +G01 X-0.3322 Y1.8012 +G01 X-0.3259 Y1.8165 +G01 X-0.7172 Y1.8165 +G01 X-0.7254 Y1.8083 +G01 X-0.7370 Y1.8035 +G01 X-0.6513 Y1.8035 +G01 X-0.6434 Y1.8035 +G01 X-0.6127 Y1.7908 +G01 X-0.5892 Y1.7673 +G01 X-0.5765 Y1.7366 +G01 X-0.5765 Y1.7287 +G01 X-0.5765 Y1.6500 +G01 X-0.5764 Y1.6490 +G01 X-0.5758 Y1.6470 +G01 X-0.5746 Y1.6454 +G01 X-0.5729 Y1.6442 +G01 X-0.5710 Y1.6436 +G01 X-0.5700 Y1.6435 +G01 X-0.5613 Y1.6435 +G01 X-0.3068 Y1.6435 +G01 X-0.3045 Y1.6458 +G01 X-0.2810 Y1.6556 +G01 X-0.1190 Y1.6556 +G01 X-0.0955 Y1.6458 +G01 X-0.0775 Y1.6278 +G01 X-0.0678 Y1.6043 +G01 X-0.0678 Y1.5788 +G01 X-0.0775 Y1.5553 +G01 X-0.0955 Y1.5373 +G01 X-0.1190 Y1.5276 +G01 X-0.2810 Y1.5276 +G01 X-0.3045 Y1.5373 +G01 X-0.3225 Y1.5553 +G01 X-0.3230 Y1.5565 +G01 X-0.5613 Y1.5565 +G01 X-0.5700 Y1.5565 +G01 X-0.5848 Y1.5565 +G01 X-0.6130 Y1.5657 +G01 X-0.6369 Y1.5831 +G01 X-0.6543 Y1.6070 +G01 X-0.6635 Y1.6352 +G01 X-0.6635 Y1.6413 +G01 X-0.6635 Y1.7165 +G01 X-1.3013 Y1.7165 +G01 X-1.3028 Y1.7165 +G01 X-1.3187 Y1.7165 +G01 X-1.3248 Y1.7165 +G01 X-1.3530 Y1.7257 +G01 X-1.3769 Y1.7431 +G01 X-1.3943 Y1.7670 +G01 X-1.4035 Y1.7952 +G01 X-1.4035 Y1.8013 +G01 X-1.4035 Y1.8172 +G01 X-1.4210 Y1.8347 +G01 X-1.4210 Y1.8853 +G01 X-1.4035 Y1.9028 +G01 X-1.4035 Y1.9600 +G01 X-1.4036 Y1.9610 +G01 X-1.4042 Y1.9630 +G01 X-1.4054 Y1.9646 +G01 X-1.4070 Y1.9658 +G01 X-1.4090 Y1.9664 +G01 X-1.4100 Y1.9665 +G01 X-1.4187 Y1.9665 +G01 X-1.5613 Y1.9665 +G01 X-1.5700 Y1.9665 +G01 X-1.5710 Y1.9664 +G01 X-1.5729 Y1.9658 +G01 X-1.5746 Y1.9646 +G01 X-1.5758 Y1.9629 +G01 X-1.5764 Y1.9610 +G01 X-1.5765 Y1.9600 +G01 X-1.5765 Y1.7987 +G01 X-1.5765 Y1.7713 +G01 X-1.5765 Y1.6387 +G01 X-1.5765 Y1.6300 +G01 X-1.5764 Y1.6290 +G01 X-1.5758 Y1.6270 +G01 X-1.5746 Y1.6254 +G01 X-1.5729 Y1.6242 +G01 X-1.5710 Y1.6236 +G01 X-1.5700 Y1.6235 +G01 X-1.5683 Y1.6235 +G01 X-1.5613 Y1.6235 +G01 X-1.1413 Y1.6235 +G01 X-1.1352 Y1.6235 +G01 X-1.1070 Y1.6143 +G01 X-1.0831 Y1.5969 +G01 X-1.0657 Y1.5730 +G01 X-1.0565 Y1.5448 +G01 X-1.0565 Y1.5300 +G01 X-1.0565 Y1.5213 +G01 X-1.0565 Y1.4381 +G01 X-1.0549 Y1.4420 +G01 X-1.0390 Y1.4579 +G01 X-1.0182 Y1.4665 +G01 X-0.8818 Y1.4665 +G01 X-0.8610 Y1.4579 +G01 X-0.8566 Y1.4535 +G01 X-0.5987 Y1.4535 +G01 X-0.5900 Y1.4535 +G01 X-0.5752 Y1.4535 +G01 X-0.5470 Y1.4443 +G01 X-0.5231 Y1.4269 +G01 X-0.5057 Y1.4030 +G01 X-0.4965 Y1.3748 +G01 X-0.4965 Y1.3687 +G01 X-0.4965 Y1.3584 +G01 X-0.4964 Y1.3574 +G01 X-0.4958 Y1.3555 +G01 X-0.4946 Y1.3538 +G01 X-0.4929 Y1.3526 +G01 X-0.4910 Y1.3520 +G01 X-0.4900 Y1.3519 +G01 X-0.4829 Y1.3519 +G01 X-0.4813 Y1.3519 +G01 X-0.3153 Y1.3519 +G01 X-0.3045 Y1.3627 +G01 X-0.2810 Y1.3724 +G01 X-0.1190 Y1.3724 +G01 X-0.0955 Y1.3627 +G01 X-0.0775 Y1.3447 +G01 X-0.0678 Y1.3212 +G01 X-0.0678 Y1.2957 +G01 X-0.0775 Y1.2722 +G01 X-0.0955 Y1.2542 +G01 X-0.1190 Y1.2444 +G01 X-0.2810 Y1.2444 +G01 X-0.3045 Y1.2542 +G01 X-0.3153 Y1.2649 +G01 X-0.4813 Y1.2649 +G01 X-0.4829 Y1.2649 +G01 X-0.4987 Y1.2649 +G01 X-0.5048 Y1.2649 +G01 X-0.5330 Y1.2741 +G01 X-0.5569 Y1.2915 +G01 X-0.5743 Y1.3154 +G01 X-0.5835 Y1.3436 +G01 X-0.5835 Y1.3498 +G01 X-0.5835 Y1.3600 +G01 X-0.5836 Y1.3610 +G01 X-0.5842 Y1.3630 +G01 X-0.5854 Y1.3646 +G01 X-0.5870 Y1.3658 +G01 X-0.5890 Y1.3664 +G01 X-0.5900 Y1.3665 +G01 X-0.5987 Y1.3665 +G01 X-0.8566 Y1.3665 +G01 X-0.8610 Y1.3621 +G01 X-0.8661 Y1.3600 +G01 X-0.8610 Y1.3579 +G01 X-0.8566 Y1.3535 +G01 X-0.7564 Y1.3535 +G01 X-0.7434 Y1.3665 +G01 X-0.6966 Y1.3665 +G01 X-0.6635 Y1.3334 +G01 X-0.6635 Y1.2866 +G01 X-0.6966 Y1.2535 +G01 X-0.7434 Y1.2535 +G01 X-0.7564 Y1.2665 +G01 X-0.8566 Y1.2665 +G01 X-0.8610 Y1.2621 +G01 X-0.8661 Y1.2600 +G01 X-0.8610 Y1.2579 +G01 X-0.8566 Y1.2535 +G01 X-0.4313 Y1.2535 +G01 X-0.4234 Y1.2535 +G01 X-0.3927 Y1.2408 +G01 X-0.3692 Y1.2173 +G01 X-0.3565 Y1.1866 +G01 X-0.3565 Y1.1787 +G01 X-0.3565 Y1.1717 +G01 X-0.3565 Y1.1700 +G01 X-0.3565 Y1.1616 +G01 X-0.3564 Y1.1606 +G01 X-0.3558 Y1.1586 +G01 X-0.3546 Y1.1570 +G01 X-0.3529 Y1.1558 +G01 X-0.3510 Y1.1551 +G01 X-0.3500 Y1.1551 +G01 X-0.3466 Y1.1551 +G01 X-0.3413 Y1.1551 +G01 X-0.3153 Y1.1551 +G01 X-0.3045 Y1.1658 +G01 X-0.2810 Y1.1756 +G01 X-0.1190 Y1.1756 +G01 X-0.0955 Y1.1658 +G01 X-0.0775 Y1.1478 +G01 X-0.0678 Y1.1243 +G01 X-0.0678 Y1.0988 +G01 X-0.0775 Y1.0753 +G01 X-0.0955 Y1.0573 +G01 X-0.1190 Y1.0476 +G01 X-0.2810 Y1.0476 +G01 X-0.3045 Y1.0573 +G01 X-0.3153 Y1.0681 +G01 X-0.3413 Y1.0681 +G01 X-0.3467 Y1.0681 +G01 X-0.3587 Y1.0681 +G01 X-0.3648 Y1.0681 +G01 X-0.3930 Y1.0772 +G01 X-0.4169 Y1.0946 +G01 X-0.4343 Y1.1186 +G01 X-0.4435 Y1.1468 +G01 X-0.4435 Y1.1529 +G01 X-0.4435 Y1.1613 +G01 X-0.4435 Y1.1665 +G01 X-0.8566 Y1.1665 +G01 X-0.8610 Y1.1621 +G01 X-0.8661 Y1.1600 +G01 X-0.8610 Y1.1579 +G01 X-0.8566 Y1.1535 +G01 X-0.5964 Y1.1535 +G01 X-0.5834 Y1.1665 +G01 X-0.5366 Y1.1665 +G01 X-0.5035 Y1.1334 +G01 X-0.5035 Y1.0866 +G01 X-0.5366 Y1.0535 +G01 X-0.5834 Y1.0535 +G01 X-0.5964 Y1.0665 +G01 X-0.8566 Y1.0665 +G01 X-0.8610 Y1.0621 +G01 X-0.8661 Y1.0600 +G01 X-0.8610 Y1.0579 +G01 X-0.8566 Y1.0535 +G01 X-0.4887 Y1.0535 +G01 X-0.4872 Y1.0535 +G01 X-0.4713 Y1.0535 +G01 X-0.4652 Y1.0535 +G01 X-0.4370 Y1.0443 +G01 X-0.4131 Y1.0269 +G01 X-0.3957 Y1.0030 +G01 X-0.3865 Y0.9748 +G01 X-0.3865 Y0.9687 +G01 X-0.3865 Y0.9535 +G01 X-0.3813 Y0.9535 +G01 X-0.3137 Y0.9535 +G01 X-0.3045 Y0.9627 +G01 X-0.2810 Y0.9724 +G01 X-0.1190 Y0.9724 +G01 X-0.0955 Y0.9627 +G01 X-0.0775 Y0.9447 +G01 X-0.0678 Y0.9212 +G01 X-0.0678 Y0.8957 +G01 X-0.0775 Y0.8722 +G01 X-0.0955 Y0.8542 +G01 X-0.1190 Y0.8444 +G01 X-0.2810 Y0.8444 +G01 X-0.3045 Y0.8542 +G01 X-0.3168 Y0.8665 +G01 X-0.3813 Y0.8665 +G01 X-0.3900 Y0.8665 +G01 X-0.4066 Y0.8665 +G01 X-0.4373 Y0.8792 +G01 X-0.4608 Y0.9027 +G01 X-0.4735 Y0.9334 +G01 X-0.4735 Y0.9413 +G01 X-0.4735 Y0.9600 +G01 X-0.4736 Y0.9610 +G01 X-0.4742 Y0.9629 +G01 X-0.4754 Y0.9646 +G01 X-0.4770 Y0.9658 +G01 X-0.4790 Y0.9664 +G01 X-0.4800 Y0.9665 +G01 X-0.4872 Y0.9665 +G01 X-0.4887 Y0.9665 +G01 X-0.8566 Y0.9665 +G01 X-0.8610 Y0.9621 +G01 X-0.8661 Y0.9600 +G01 X-0.8610 Y0.9579 +G01 X-0.8566 Y0.9535 +G01 X-0.8387 Y0.9535 +G01 X-0.8349 Y0.9535 +G01 X-0.8213 Y0.9535 +G01 X-0.8152 Y0.9535 +G01 X-0.7870 Y0.9443 +G01 X-0.7631 Y0.9269 +G01 X-0.7457 Y0.9030 +G01 X-0.7365 Y0.8748 +G01 X-0.7365 Y0.8687 +G01 X-0.7365 Y0.5764 +G01 X-0.7235 Y0.5634 +G01 X-0.7235 Y0.5166 +G01 X-0.7566 Y0.4835 +G01 X-0.8034 Y0.4835 +G01 X-0.8365 Y0.5166 +G01 X-0.8365 Y0.5634 +G01 X-0.8235 Y0.5764 +G01 X-0.8235 Y0.8600 +G01 X-0.8236 Y0.8610 +G01 X-0.8242 Y0.8629 +G01 X-0.8254 Y0.8646 +G01 X-0.8270 Y0.8658 +G01 X-0.8290 Y0.8664 +G01 X-0.8300 Y0.8665 +G01 X-0.8350 Y0.8665 +G01 X-0.8387 Y0.8665 +G01 X-0.8566 Y0.8665 +G01 X-0.8610 Y0.8621 +G01 X-0.8661 Y0.8600 +G01 X-0.8610 Y0.8579 +G01 X-0.8451 Y0.8420 +G01 X-0.8365 Y0.8212 +G01 X-0.8365 Y0.7988 +G01 X-0.8451 Y0.7780 +G01 X-0.8610 Y0.7621 +G01 X-0.8818 Y0.7535 +G01 X-1.0182 Y0.7535 +G01 X-1.0390 Y0.7621 +G01 X-1.0434 Y0.7665 +G01 X-1.0587 Y0.7665 +G01 X-1.0648 Y0.7665 +G01 X-1.0930 Y0.7757 +G01 X-1.1169 Y0.7931 +G01 X-1.1343 Y0.8170 +G01 X-1.1435 Y0.8452 +G01 X-1.1435 Y0.8513 +G01 X-1.1435 Y0.8819 +G01 X-1.1451 Y0.8780 +G01 X-1.1610 Y0.8621 +G01 X-1.1661 Y0.8600 +G01 X-1.1610 Y0.8579 +G01 X-1.1451 Y0.8420 +G01 X-1.1365 Y0.8212 +G01 X-1.1365 Y0.7988 +G01 X-1.1451 Y0.7780 +G01 X-1.1610 Y0.7621 +G01 X-1.1818 Y0.7535 +G01 X-1.3182 Y0.7535 +G01 X-1.3390 Y0.7621 +G01 X-1.3434 Y0.7665 +G01 X-1.5000 Y0.7665 +G01 X-1.5010 Y0.7664 +G01 X-1.5029 Y0.7658 +G01 X-1.5046 Y0.7646 +G01 X-1.5058 Y0.7629 +G01 X-1.5064 Y0.7610 +G01 X-1.5065 Y0.7600 +G01 X-1.5065 Y0.7532 +G01 X-1.5065 Y0.7513 +G01 X-1.5065 Y0.6964 +G01 X-1.4935 Y0.6834 +G01 X-1.4935 Y0.6366 +G01 X-1.5266 Y0.6035 +G01 X-1.5734 Y0.6035 +G01 X-1.6065 Y0.6366 +G01 X-1.6065 Y0.6834 +G01 X-1.5935 Y0.6964 +G01 X-1.5935 Y0.7513 +G01 X-1.5935 Y0.7532 +G01 X-1.5935 Y0.7687 +G01 X-1.5935 Y0.7748 +G01 X-1.5843 Y0.8030 +G01 X-1.5669 Y0.8269 +G01 X-1.5430 Y0.8443 +G01 X-1.5148 Y0.8535 +G01 X-1.5087 Y0.8535 +G01 X-1.3434 Y0.8535 +G01 X-1.3390 Y0.8579 +G01 X-1.3339 Y0.8600 +G01 X-1.3390 Y0.8621 +G01 X-1.3434 Y0.8665 +G01 X-1.5913 Y0.8665 +G01 X-1.6000 Y0.8665 +G01 X-1.6010 Y0.8664 +G01 X-1.6029 Y0.8658 +G01 X-1.6046 Y0.8646 +G01 X-1.6058 Y0.8629 +G01 X-1.6064 Y0.8610 +G01 X-1.6065 Y0.8600 +G01 X-1.6065 Y0.1587 +G01 X-1.6065 Y0.1500 +G01 X-1.6064 Y0.1490 +G01 X-1.6058 Y0.1470 +G01 X-1.6046 Y0.1454 +G01 X-1.6029 Y0.1442 +G01 X-1.6010 Y0.1436 +G01 X-1.6000 Y0.1435 +G01 X-1.1487 Y0.1435 +G01 X-1.1400 Y0.1435 +G01 X-1.1390 Y0.1436 +G01 X-1.1370 Y0.1442 +G01 X-1.1354 Y0.1454 +G01 X-1.1342 Y0.1470 +G01 X-1.1336 Y0.1490 +G01 X-1.1335 Y0.1500 +G01 X-1.1335 Y0.1913 +G01 X-1.1335 Y0.1924 +G01 X-1.1335 Y0.2087 +G01 X-1.1335 Y0.2148 +G01 X-1.1243 Y0.2430 +G01 X-1.1069 Y0.2669 +G01 X-1.0830 Y0.2843 +G01 X-1.0548 Y0.2935 +G01 X-1.0487 Y0.2935 +G01 X-0.8134 Y0.2935 +G01 X-0.8164 Y0.2965 +G01 X-1.2665 Y0.2965 +G01 X-1.2665 Y0.2264 +G01 X-1.2635 Y0.2234 +G01 X-1.2635 Y0.1766 +G01 X-1.2966 Y0.1435 +G01 X-1.3434 Y0.1435 +G01 X-1.3765 Y0.1766 +G01 X-1.3765 Y0.2234 +G01 X-1.3535 Y0.2464 +G01 X-1.3535 Y0.2965 +G01 X-1.3751 Y0.2965 +G01 X-1.3846 Y0.2870 +G01 X-1.4076 Y0.2775 +G01 X-1.4324 Y0.2775 +G01 X-1.4554 Y0.2870 +G01 X-1.4730 Y0.3046 +G01 X-1.4825 Y0.3276 +G01 X-1.4825 Y0.3524 +G01 X-1.4730 Y0.3754 +G01 X-1.4554 Y0.3930 +G01 X-1.4324 Y0.4025 +G01 X-1.4076 Y0.4025 +G01 X-1.3846 Y0.3930 +G01 X-1.3751 Y0.3835 +G01 X-1.3187 Y0.3835 +G01 X-1.3013 Y0.3835 +G01 X-0.8164 Y0.3835 +G01 X-0.8034 Y0.3965 +G01 X-0.7566 Y0.3965 +G01 X-0.7235 Y0.3634 +G01 X-0.7235 Y0.3166 +G01 X-0.7466 Y0.2935 +G01 X-0.5187 Y0.2935 +G01 X-0.5100 Y0.2935 +G01 X-0.5090 Y0.2936 +G01 X-0.5070 Y0.2942 +G01 X-0.5054 Y0.2954 +G01 X-0.5042 Y0.2970 +G01 X-0.5036 Y0.2990 +G01 X-0.5035 Y0.3000 +G01 X-0.5035 Y0.6513 +G01 X-0.5035 Y0.6535 +G01 X-0.5035 Y0.6687 +G01 X-0.5035 Y0.6748 +G01 X-0.4943 Y0.7030 +G01 X-0.4769 Y0.7269 +G01 X-0.4530 Y0.7443 +G01 X-0.4248 Y0.7535 +G01 X-0.4187 Y0.7535 +G01 X-0.3168 Y0.7535 +G01 X-0.3045 Y0.7658 +G01 X-0.2810 Y0.7756 +G01 X-0.1190 Y0.7756 +G01 X-0.0955 Y0.7658 +G01 X-0.0775 Y0.7478 +G01 X-0.0678 Y0.7243 +G01 X-0.0678 Y0.6988 +G01 X-0.0775 Y0.6753 +G01 X-0.0955 Y0.6573 +G01 X-0.1190 Y0.6476 +G01 X-0.2810 Y0.6476 +G01 X-0.3045 Y0.6573 +G01 X-0.3137 Y0.6665 +G01 X-0.4100 Y0.6665 +G01 X-0.4110 Y0.6664 +G01 X-0.4129 Y0.6658 +G01 X-0.4146 Y0.6646 +G01 X-0.4158 Y0.6629 +G01 X-0.4164 Y0.6610 +G01 X-0.4165 Y0.6600 +G01 X-0.4165 Y0.6535 +G01 X-0.4165 Y0.6513 +G01 X-0.4165 Y0.2913 +G01 X-0.4165 Y0.2852 +G00 Z0.1000 +G00 X-1.5625 Y1.6976 +G01 Z-0.0070 F10 +G01 X-1.5625 Y1.7224 F20 +G01 X-1.5530 Y1.7454 +G01 X-1.5435 Y1.7549 +G01 X-1.5435 Y1.8736 +G01 X-1.5565 Y1.8866 +G01 X-1.5565 Y1.9334 +G01 X-1.5234 Y1.9665 +G01 X-1.4766 Y1.9665 +G01 X-1.4435 Y1.9334 +G01 X-1.4435 Y1.8866 +G01 X-1.4565 Y1.8736 +G01 X-1.4565 Y1.7549 +G01 X-1.4470 Y1.7454 +G01 X-1.4375 Y1.7224 +G01 X-1.4375 Y1.7135 +G01 X-0.7613 Y1.7135 +G01 X-0.7552 Y1.7135 +G01 X-0.7270 Y1.7043 +G01 X-0.7031 Y1.6869 +G01 X-0.6857 Y1.6630 +G01 X-0.6765 Y1.6348 +G01 X-0.6765 Y1.6200 +G01 X-0.6765 Y1.6113 +G01 X-0.6765 Y1.5464 +G01 X-0.6635 Y1.5334 +G01 X-0.6635 Y1.4866 +G01 X-0.6966 Y1.4535 +G01 X-0.7434 Y1.4535 +G01 X-0.7765 Y1.4866 +G01 X-0.7765 Y1.5334 +G01 X-0.7635 Y1.5464 +G01 X-0.7635 Y1.6113 +G01 X-0.7635 Y1.6200 +G01 X-0.7636 Y1.6210 +G01 X-0.7642 Y1.6229 +G01 X-0.7654 Y1.6246 +G01 X-0.7670 Y1.6258 +G01 X-0.7690 Y1.6264 +G01 X-0.7700 Y1.6265 +G01 X-1.4476 Y1.6265 +G01 X-1.4592 Y1.6252 +G01 X-1.4867 Y1.6309 +G01 X-1.5111 Y1.6448 +G01 X-1.5143 Y1.6483 +G01 X-1.5354 Y1.6570 +G01 X-1.5530 Y1.6746 +G01 X-1.5625 Y1.6976 +G00 Z0.1000 +G00 X-0.5165 Y0.4987 +G01 Z-0.0070 F10 +G01 X-0.5165 Y0.4900 F20 +G01 X-0.5165 Y0.4752 +G01 X-0.5257 Y0.4470 +G01 X-0.5431 Y0.4231 +G01 X-0.5670 Y0.4057 +G01 X-0.5952 Y0.3965 +G01 X-0.6013 Y0.3965 +G01 X-1.3787 Y0.3965 +G01 X-1.3848 Y0.3965 +G01 X-1.4130 Y0.4057 +G01 X-1.4369 Y0.4231 +G01 X-1.4539 Y0.4464 +G01 X-1.4554 Y0.4470 +G01 X-1.4730 Y0.4646 +G01 X-1.4825 Y0.4876 +G01 X-1.4825 Y0.5124 +G01 X-1.4735 Y0.5342 +G01 X-1.4735 Y0.6736 +G01 X-1.4865 Y0.6866 +G01 X-1.4865 Y0.7334 +G01 X-1.4534 Y0.7665 +G01 X-1.4066 Y0.7665 +G01 X-1.3735 Y0.7334 +G01 X-1.3735 Y0.6866 +G01 X-1.3865 Y0.6736 +G01 X-1.3865 Y0.5538 +G01 X-1.3846 Y0.5530 +G01 X-1.3670 Y0.5354 +G01 X-1.3575 Y0.5124 +G01 X-1.3575 Y0.4876 +G01 X-1.3592 Y0.4835 +G01 X-0.6100 Y0.4835 +G01 X-0.6090 Y0.4836 +G01 X-0.6070 Y0.4842 +G01 X-0.6054 Y0.4854 +G01 X-0.6042 Y0.4870 +G01 X-0.6036 Y0.4890 +G01 X-0.6035 Y0.4900 +G01 X-0.6035 Y0.4987 +G01 X-0.6035 Y0.8736 +G01 X-0.6165 Y0.8866 +G01 X-0.6165 Y0.9334 +G01 X-0.5834 Y0.9665 +G01 X-0.5366 Y0.9665 +G01 X-0.5035 Y0.9334 +G01 X-0.5035 Y0.8866 +G01 X-0.5165 Y0.8736 +G01 X-0.5165 Y0.4987 +G00 Z0.1000 +G00 X-2.6105 Y1.8446 +G01 Z-0.0070 F10 +G01 X-2.6105 Y1.8334 F20 +G01 X-2.5991 Y1.8491 +G01 X-2.5792 Y1.8635 +G01 X-2.6294 Y1.8635 +G01 X-2.6105 Y1.8446 +G00 Z0.1000 +G00 X-2.6359 Y1.7700 +G01 Z-0.0070 F10 +G01 X-2.6324 Y1.7665 F20 +G01 X-2.6300 Y1.7665 +G01 X-2.6295 Y1.7665 +G01 X-2.6284 Y1.7669 +G01 X-2.6275 Y1.7675 +G01 X-2.6269 Y1.7684 +G01 X-2.6265 Y1.7695 +G01 X-2.6265 Y1.7700 +G01 X-2.6265 Y1.7775 +G01 X-2.6265 Y1.7792 +G01 X-2.6265 Y1.7794 +G01 X-2.6359 Y1.7700 +G00 Z0.1000 +G00 X-2.3884 Y1.7831 +G01 Z-0.0070 F10 +G01 X-2.3895 Y1.7835 F20 +G01 X-2.3900 Y1.7835 +G01 X-2.3994 Y1.7835 +G01 X-2.3900 Y1.7741 +G01 X-2.3865 Y1.7776 +G01 X-2.3865 Y1.7800 +G01 X-2.3865 Y1.7805 +G01 X-2.3869 Y1.7816 +G01 X-2.3875 Y1.7825 +G01 X-2.3884 Y1.7831 +G00 Z0.1000 +G00 X-2.4670 Y0.9565 +G01 Z-0.0070 F10 +G01 X-2.3433 Y0.9565 F20 +G01 X-2.3507 Y0.9596 +G01 X-2.3546 Y0.9635 +G01 X-2.4740 Y0.9635 +G01 X-2.4670 Y0.9565 +G00 Z0.1000 +G00 X-1.5461 Y1.3565 +G01 Z-0.0070 F10 +G01 X-1.5371 Y1.3655 F20 +G01 X-1.5130 Y1.3755 +G01 X-1.4870 Y1.3755 +G01 X-1.4629 Y1.3655 +G01 X-1.4565 Y1.3591 +G01 X-1.4565 Y1.4007 +G01 X-1.4565 Y1.4100 +G01 X-1.4565 Y1.4105 +G01 X-1.4569 Y1.4116 +G01 X-1.4575 Y1.4125 +G01 X-1.4584 Y1.4131 +G01 X-1.4595 Y1.4135 +G01 X-1.4600 Y1.4135 +G01 X-1.6507 Y1.4135 +G01 X-1.6524 Y1.4135 +G01 X-1.6692 Y1.4135 +G01 X-1.6753 Y1.4135 +G01 X-1.7044 Y1.4229 +G01 X-1.7291 Y1.4409 +G01 X-1.7470 Y1.4656 +G01 X-1.7565 Y1.4947 +G01 X-1.7565 Y1.5007 +G01 X-1.7565 Y1.6405 +G01 X-1.7946 Y1.6405 +G01 X-1.8076 Y1.6535 +G01 X-2.0307 Y1.6535 +G01 X-2.0400 Y1.6535 +G01 X-2.0412 Y1.6535 +G01 X-2.0492 Y1.6535 +G01 X-2.0553 Y1.6535 +G01 X-2.0844 Y1.6629 +G01 X-2.1091 Y1.6809 +G01 X-2.1270 Y1.7056 +G01 X-2.1365 Y1.7347 +G01 X-2.1365 Y1.7407 +G01 X-2.1365 Y1.7496 +G01 X-2.1365 Y1.7500 +G01 X-2.1365 Y1.7592 +G01 X-2.1365 Y1.8635 +G01 X-2.3408 Y1.8635 +G01 X-2.3209 Y1.8491 +G01 X-2.3029 Y1.8244 +G01 X-2.2935 Y1.7953 +G01 X-2.2935 Y1.7893 +G01 X-2.2935 Y1.7865 +G01 X-2.2530 Y1.7865 +G01 X-2.2362 Y1.8033 +G01 X-2.1838 Y1.8033 +G01 X-2.1467 Y1.7662 +G01 X-2.1467 Y1.7138 +G01 X-2.1838 Y1.6767 +G01 X-2.2362 Y1.6767 +G01 X-2.2530 Y1.6935 +G01 X-2.3024 Y1.6935 +G01 X-2.3154 Y1.6805 +G01 X-2.3305 Y1.6805 +G01 X-2.3305 Y1.6404 +G01 X-2.3428 Y1.6280 +G01 X-2.3425 Y1.6275 +G01 X-2.3416 Y1.6269 +G01 X-2.3405 Y1.6265 +G01 X-2.3400 Y1.6265 +G01 X-2.3326 Y1.6265 +G01 X-2.3307 Y1.6265 +G01 X-1.8407 Y1.6265 +G01 X-1.8328 Y1.6265 +G01 X-1.8010 Y1.6133 +G01 X-1.7767 Y1.5890 +G01 X-1.7635 Y1.5572 +G01 X-1.7635 Y1.5493 +G01 X-1.7635 Y1.5400 +G01 X-1.7635 Y1.5308 +G01 X-1.7635 Y1.3565 +G01 X-1.7607 Y1.3565 +G01 X-1.6492 Y1.3565 +G01 X-1.6307 Y1.3565 +G01 X-1.5461 Y1.3565 +G00 Z0.1000 +G00 X-2.8637 Y1.3857 +G01 Z-0.0070 F10 +G01 X-2.8873 Y1.3760 F20 +G01 X-2.9119 Y1.3760 +G01 X-2.8905 Y1.3546 +G01 X-2.8905 Y1.3054 +G01 X-2.9094 Y1.2865 +G01 X-2.7246 Y1.2865 +G01 X-2.7201 Y1.2874 +G01 X-2.7173 Y1.2869 +G01 X-2.6946 Y1.3095 +G01 X-2.6454 Y1.3095 +G01 X-2.6105 Y1.2746 +G01 X-2.6105 Y1.2254 +G01 X-2.6454 Y1.1905 +G01 X-2.6766 Y1.1905 +G01 X-2.6999 Y1.1858 +G01 X-2.7321 Y1.1922 +G01 X-2.7341 Y1.1935 +G01 X-3.0292 Y1.1935 +G01 X-3.0353 Y1.1935 +G01 X-3.0644 Y1.2029 +G01 X-3.0891 Y1.2209 +G01 X-3.1070 Y1.2456 +G01 X-3.1135 Y1.2655 +G01 X-3.1135 Y0.9600 +G01 X-3.1135 Y0.9595 +G01 X-3.1131 Y0.9584 +G01 X-3.1125 Y0.9575 +G01 X-3.1116 Y0.9569 +G01 X-3.1105 Y0.9565 +G01 X-3.1100 Y0.9565 +G01 X-3.1040 Y0.9565 +G01 X-3.1007 Y0.9565 +G01 X-2.5530 Y0.9565 +G01 X-2.5460 Y0.9635 +G01 X-2.9092 Y0.9635 +G01 X-2.9153 Y0.9635 +G01 X-2.9444 Y0.9729 +G01 X-2.9691 Y0.9909 +G01 X-2.9870 Y1.0156 +G01 X-2.9965 Y1.0447 +G01 X-2.9965 Y1.0507 +G01 X-2.9965 Y1.0924 +G01 X-3.0095 Y1.1054 +G01 X-3.0095 Y1.1546 +G01 X-2.9746 Y1.1895 +G01 X-2.9254 Y1.1895 +G01 X-2.8905 Y1.1546 +G01 X-2.8905 Y1.1054 +G01 X-2.9035 Y1.0924 +G01 X-2.9035 Y1.0600 +G01 X-2.9035 Y1.0594 +G01 X-2.9031 Y1.0584 +G01 X-2.9025 Y1.0575 +G01 X-2.9016 Y1.0569 +G01 X-2.9005 Y1.0565 +G01 X-2.9000 Y1.0565 +G01 X-2.3546 Y1.0565 +G01 X-2.3511 Y1.0600 +G01 X-2.3674 Y1.0763 +G01 X-2.3765 Y1.0982 +G01 X-2.3765 Y1.1218 +G01 X-2.3674 Y1.1437 +G01 X-2.3511 Y1.1600 +G01 X-2.3546 Y1.1635 +G01 X-2.4607 Y1.1635 +G01 X-2.4622 Y1.1635 +G01 X-2.4792 Y1.1635 +G01 X-2.4853 Y1.1635 +G01 X-2.5144 Y1.1729 +G01 X-2.5391 Y1.1909 +G01 X-2.5570 Y1.2156 +G01 X-2.5665 Y1.2447 +G01 X-2.5665 Y1.2507 +G01 X-2.5665 Y1.3935 +G01 X-2.8560 Y1.3935 +G01 X-2.8637 Y1.3857 +G00 Z0.1000 +G00 X-2.5609 Y1.7009 +G01 Z-0.0070 F10 +G01 X-2.5609 Y1.7009 F20 +G01 X-2.5856 Y1.6829 +G01 X-2.6147 Y1.6735 +G01 X-2.6207 Y1.6735 +G01 X-2.6324 Y1.6735 +G01 X-2.6364 Y1.6695 +G01 X-2.6354 Y1.6695 +G01 X-2.6224 Y1.6565 +G01 X-2.5465 Y1.6565 +G01 X-2.5465 Y1.7007 +G01 X-2.5465 Y1.7074 +G01 X-2.5465 Y1.7100 +G01 X-2.5465 Y1.7192 +G01 X-2.5465 Y1.7208 +G01 X-2.5609 Y1.7009 +G00 Z0.1000 +G00 X-2.5207 Y1.7835 +G01 Z-0.0070 F10 +G01 X-2.5300 Y1.7835 F20 +G01 X-2.5305 Y1.7835 +G01 X-2.5316 Y1.7831 +G01 X-2.5325 Y1.7825 +G01 X-2.5331 Y1.7816 +G01 X-2.5335 Y1.7805 +G01 X-2.5335 Y1.7800 +G01 X-2.5335 Y1.7792 +G01 X-2.5335 Y1.7775 +G01 X-2.5335 Y1.7607 +G01 X-2.5335 Y1.7547 +G01 X-2.5133 Y1.7748 +G01 X-2.4924 Y1.7835 +G01 X-2.5207 Y1.7835 +G00 Z0.1000 +G00 X-2.4495 Y1.6404 +G01 Z-0.0070 F10 +G01 X-2.4495 Y1.6805 F20 +G01 X-2.4535 Y1.6805 +G01 X-2.4535 Y1.6007 +G01 X-2.4606 Y1.5837 +G01 X-2.4735 Y1.5707 +G01 X-2.4735 Y1.4307 +G01 X-2.4735 Y1.2600 +G01 X-2.4735 Y1.2595 +G01 X-2.4731 Y1.2584 +G01 X-2.4725 Y1.2575 +G01 X-2.4716 Y1.2569 +G01 X-2.4705 Y1.2565 +G01 X-2.4700 Y1.2565 +G01 X-2.4622 Y1.2565 +G01 X-2.4607 Y1.2565 +G01 X-2.3546 Y1.2565 +G01 X-2.3511 Y1.2600 +G01 X-2.3674 Y1.2763 +G01 X-2.3765 Y1.2982 +G01 X-2.3765 Y1.3218 +G01 X-2.3674 Y1.3437 +G01 X-2.3507 Y1.3604 +G01 X-2.3288 Y1.3695 +G01 X-2.1912 Y1.3695 +G01 X-2.1693 Y1.3604 +G01 X-2.1654 Y1.3565 +G01 X-2.1392 Y1.3565 +G01 X-2.1300 Y1.3565 +G01 X-2.1273 Y1.3565 +G01 X-2.1207 Y1.3565 +G01 X-2.1168 Y1.3565 +G01 X-2.0923 Y1.3464 +G01 X-2.0739 Y1.3280 +G01 X-2.0674 Y1.3437 +G01 X-2.0507 Y1.3604 +G01 X-2.0288 Y1.3695 +G01 X-2.0065 Y1.3695 +G01 X-2.0065 Y1.4107 +G01 X-2.0065 Y1.4170 +G01 X-2.0130 Y1.4235 +G01 X-2.0192 Y1.4235 +G01 X-2.1670 Y1.4235 +G01 X-2.1838 Y1.4067 +G01 X-2.2362 Y1.4067 +G01 X-2.2395 Y1.4100 +G01 X-2.2735 Y1.3760 +G01 X-2.3265 Y1.3760 +G01 X-2.3640 Y1.4135 +G01 X-2.3640 Y1.4665 +G01 X-2.3265 Y1.5040 +G01 X-2.2735 Y1.5040 +G01 X-2.2695 Y1.5000 +G01 X-2.2362 Y1.5333 +G01 X-2.1838 Y1.5333 +G01 X-2.1670 Y1.5165 +G01 X-2.0192 Y1.5165 +G01 X-2.0130 Y1.5165 +G01 X-1.9962 Y1.5333 +G01 X-1.9438 Y1.5333 +G01 X-1.9067 Y1.4962 +G01 X-1.9067 Y1.4438 +G01 X-1.9139 Y1.4366 +G01 X-1.9135 Y1.4353 +G01 X-1.9135 Y1.4292 +G01 X-1.9135 Y1.4239 +G01 X-1.9135 Y1.4200 +G01 X-1.9135 Y1.4107 +G01 X-1.9135 Y1.3695 +G01 X-1.8912 Y1.3695 +G01 X-1.8693 Y1.3604 +G01 X-1.8565 Y1.3476 +G01 X-1.8565 Y1.5307 +G01 X-1.8565 Y1.5335 +G01 X-2.3307 Y1.5335 +G01 X-2.3326 Y1.5335 +G01 X-2.3492 Y1.5335 +G01 X-2.3553 Y1.5335 +G01 X-2.3844 Y1.5429 +G01 X-2.4091 Y1.5609 +G01 X-2.4270 Y1.5856 +G01 X-2.4365 Y1.6147 +G01 X-2.4365 Y1.6207 +G01 X-2.4365 Y1.6274 +G01 X-2.4495 Y1.6404 +G00 Z0.1000 +G00 X-2.6354 Y1.5505 +G01 Z-0.0070 F10 +G01 X-2.6846 Y1.5505 F20 +G01 X-2.7195 Y1.5854 +G01 X-2.7195 Y1.6346 +G01 X-2.6936 Y1.6605 +G01 X-2.6946 Y1.6605 +G01 X-2.7076 Y1.6735 +G01 X-2.7300 Y1.6735 +G01 X-2.7305 Y1.6735 +G01 X-2.7316 Y1.6731 +G01 X-2.7325 Y1.6725 +G01 X-2.7331 Y1.6716 +G01 X-2.7335 Y1.6705 +G01 X-2.7335 Y1.6700 +G01 X-2.7335 Y1.6621 +G01 X-2.7335 Y1.6607 +G01 X-2.7335 Y1.5907 +G01 X-2.7335 Y1.5828 +G01 X-2.7467 Y1.5510 +G01 X-2.7710 Y1.5267 +G01 X-2.8028 Y1.5135 +G01 X-2.8107 Y1.5135 +G01 X-2.8200 Y1.5135 +G01 X-2.8292 Y1.5135 +G01 X-2.9435 Y1.5135 +G01 X-2.9435 Y1.4870 +G01 X-2.9363 Y1.4943 +G01 X-2.9127 Y1.5040 +G01 X-2.8873 Y1.5040 +G01 X-2.8637 Y1.4943 +G01 X-2.8560 Y1.4865 +G01 X-2.5665 Y1.4865 +G01 X-2.5665 Y1.5635 +G01 X-2.6224 Y1.5635 +G01 X-2.6354 Y1.5505 +G00 Z0.1000 +G00 X-1.8192 Y1.2635 +G01 Z-0.0070 F10 +G01 X-1.8363 Y1.2706 F20 +G01 X-1.8494 Y1.2837 +G01 X-1.8495 Y1.2838 +G01 X-1.8526 Y1.2763 +G01 X-1.8689 Y1.2600 +G01 X-1.8554 Y1.2465 +G01 X-1.8165 Y1.2465 +G01 X-1.8165 Y1.2635 +G01 X-1.8192 Y1.2635 +G00 Z0.1000 +G00 X-2.9165 Y1.7314 +G01 Z-0.0070 F10 +G01 X-2.9167 Y1.7310 F20 +G01 X-2.9167 Y1.7310 +G01 X-2.9410 Y1.7067 +G01 X-2.9656 Y1.6965 +G01 X-2.9165 Y1.6965 +G01 X-2.9165 Y1.7314 +G00 Z0.1000 +G00 X-3.0225 Y1.2875 +G01 Z-0.0070 F10 +G01 X-3.0216 Y1.2869 F20 +G01 X-3.0205 Y1.2865 +G01 X-3.0200 Y1.2865 +G01 X-2.9906 Y1.2865 +G01 X-3.0095 Y1.3054 +G01 X-3.0095 Y1.3072 +G01 X-3.0233 Y1.3210 +G01 X-3.0235 Y1.3214 +G01 X-3.0235 Y1.2900 +G01 X-3.0235 Y1.2894 +G01 X-3.0231 Y1.2884 +G01 X-3.0225 Y1.2875 +G00 Z0.1000 +G00 X-3.0033 Y1.5948 +G01 Z-0.0070 F10 +G01 X-3.0033 Y1.5948 F20 +G01 X-2.9824 Y1.6035 +G01 X-3.0107 Y1.6035 +G01 X-3.0200 Y1.6035 +G01 X-3.0205 Y1.6035 +G01 X-3.0216 Y1.6031 +G01 X-3.0225 Y1.6025 +G01 X-3.0231 Y1.6016 +G01 X-3.0235 Y1.6005 +G01 X-3.0235 Y1.6000 +G01 X-3.0235 Y1.5747 +G01 X-3.0033 Y1.5948 +G00 Z0.1000 +G00 X-3.1100 Y1.6935 +G01 Z-0.0070 F10 +G01 X-3.1105 Y1.6935 F20 +G01 X-3.1105 Y1.6935 +G01 X-3.1116 Y1.6931 +G01 X-3.1125 Y1.6925 +G01 X-3.1131 Y1.6916 +G01 X-3.1135 Y1.6905 +G01 X-3.1135 Y1.6900 +G01 X-3.1135 Y1.6820 +G01 X-3.1135 Y1.6807 +G01 X-3.1135 Y1.6476 +G01 X-3.1078 Y1.6420 +G01 X-3.1070 Y1.6444 +G01 X-3.0891 Y1.6691 +G01 X-3.0644 Y1.6870 +G01 X-3.0445 Y1.6935 +G01 X-3.1100 Y1.6935 +G00 Z0.1000 +G00 X-2.8292 Y1.6065 +G01 Z-0.0070 F10 +G01 X-2.8265 Y1.6065 F20 +G01 X-2.8265 Y1.6576 +G01 X-2.8351 Y1.6367 +G01 X-2.8567 Y1.6151 +G01 X-2.8776 Y1.6065 +G01 X-2.8292 Y1.6065 +G00 Z0.1000 +G00 X-2.8170 Y1.7144 +G01 Z-0.0070 F10 +G01 X-2.8170 Y1.7144 F20 +G01 X-2.7991 Y1.7391 +G01 X-2.7744 Y1.7570 +G01 X-2.7453 Y1.7665 +G01 X-2.7392 Y1.7665 +G01 X-2.7339 Y1.7665 +G01 X-2.7300 Y1.7665 +G01 X-2.7076 Y1.7665 +G01 X-2.7041 Y1.7700 +G01 X-2.7076 Y1.7735 +G01 X-2.8107 Y1.7735 +G01 X-2.8200 Y1.7735 +G01 X-2.8205 Y1.7735 +G01 X-2.8216 Y1.7731 +G01 X-2.8225 Y1.7725 +G01 X-2.8231 Y1.7716 +G01 X-2.8235 Y1.7705 +G01 X-2.8235 Y1.7700 +G01 X-2.8235 Y1.6945 +G01 X-2.8170 Y1.7144 +G00 Z0.1000 +G00 X-2.9000 Y1.8635 +G01 Z-0.0070 F10 +G01 X-2.9005 Y1.8635 F20 +G01 X-2.9016 Y1.8631 +G01 X-2.9025 Y1.8625 +G01 X-2.9031 Y1.8616 +G01 X-2.9035 Y1.8605 +G01 X-2.9035 Y1.8600 +G01 X-2.9035 Y1.8540 +G01 X-2.9035 Y1.8507 +G01 X-2.9035 Y1.8192 +G01 X-2.8891 Y1.8391 +G01 X-2.8644 Y1.8570 +G01 X-2.8445 Y1.8635 +G01 X-2.9000 Y1.8635 +G00 Z0.1000 +G00 X-2.4467 Y0.4862 +G01 Z-0.0070 F10 +G01 X-2.4467 Y0.4338 F20 +G01 X-2.4535 Y0.4270 +G01 X-2.4535 Y0.2712 +G01 X-2.4535 Y0.1965 +G01 X-2.4503 Y0.1965 +G01 X-2.4488 Y0.1965 +G01 X-2.0278 Y0.1965 +G01 X-2.0471 Y0.2045 +G01 X-2.0655 Y0.2229 +G01 X-2.0755 Y0.2470 +G01 X-2.0755 Y0.2730 +G01 X-2.0655 Y0.2971 +G01 X-2.0561 Y0.3065 +G01 X-2.0470 Y0.3344 +G01 X-2.0291 Y0.3591 +G01 X-2.0044 Y0.3770 +G01 X-1.9753 Y0.3865 +G01 X-1.9693 Y0.3865 +G01 X-1.9608 Y0.3865 +G01 X-1.9600 Y0.3865 +G01 X-1.9507 Y0.3865 +G01 X-1.8665 Y0.3865 +G01 X-1.8665 Y0.4539 +G01 X-1.8944 Y0.4629 +G01 X-1.9191 Y0.4809 +G01 X-1.9370 Y0.5056 +G01 X-1.9428 Y0.5232 +G01 X-1.9633 Y0.5438 +G01 X-1.9633 Y0.5962 +G01 X-1.9460 Y0.6135 +G01 X-1.9639 Y0.6135 +G01 X-1.9729 Y0.6045 +G01 X-1.9970 Y0.5945 +G01 X-2.0230 Y0.5945 +G01 X-2.0471 Y0.6045 +G01 X-2.0561 Y0.6135 +G01 X-2.0900 Y0.6135 +G01 X-2.0905 Y0.6135 +G01 X-2.0916 Y0.6131 +G01 X-2.0925 Y0.6125 +G01 X-2.0931 Y0.6116 +G01 X-2.0935 Y0.6105 +G01 X-2.0935 Y0.6100 +G01 X-2.0935 Y0.6007 +G01 X-2.0935 Y0.2976 +G01 X-2.0805 Y0.2846 +G01 X-2.0805 Y0.2354 +G01 X-2.1154 Y0.2005 +G01 X-2.1646 Y0.2005 +G01 X-2.1995 Y0.2354 +G01 X-2.1995 Y0.2846 +G01 X-2.1865 Y0.2976 +G01 X-2.1865 Y0.5656 +G01 X-2.1967 Y0.5410 +G01 X-2.2210 Y0.5167 +G01 X-2.2528 Y0.5035 +G01 X-2.2607 Y0.5035 +G01 X-2.2663 Y0.5035 +G01 X-2.2700 Y0.5035 +G01 X-2.2792 Y0.5035 +G01 X-2.4640 Y0.5035 +G01 X-2.4467 Y0.4862 +G00 Z0.1000 +G00 X-0.8589 Y1.3600 +G01 Z-0.0070 F10 +G01 X-0.8554 Y1.3565 F20 +G01 X-0.7576 Y1.3565 +G01 X-0.7506 Y1.3635 +G01 X-0.8554 Y1.3635 +G01 X-0.8589 Y1.3600 +G00 Z0.1000 +G00 X-0.7795 Y1.4854 +G01 Z-0.0070 F10 +G01 X-0.7795 Y1.5346 F20 +G01 X-0.7665 Y1.5476 +G01 X-0.7665 Y1.6107 +G01 X-0.7665 Y1.6200 +G01 X-0.7665 Y1.6205 +G01 X-0.7669 Y1.6216 +G01 X-0.7675 Y1.6225 +G01 X-0.7684 Y1.6231 +G01 X-0.7695 Y1.6235 +G01 X-0.7700 Y1.6235 +G01 X-1.1255 Y1.6235 +G01 X-1.1056 Y1.6170 +G01 X-1.0809 Y1.5991 +G01 X-1.0629 Y1.5744 +G01 X-1.0535 Y1.5453 +G01 X-1.0535 Y1.5393 +G01 X-1.0535 Y1.5305 +G01 X-1.0535 Y1.5300 +G01 X-1.0535 Y1.5207 +G01 X-1.0535 Y1.4476 +G01 X-1.0407 Y1.4604 +G01 X-1.0188 Y1.4695 +G01 X-0.8812 Y1.4695 +G01 X-0.8593 Y1.4604 +G01 X-0.8554 Y1.4565 +G01 X-0.7506 Y1.4565 +G01 X-0.7795 Y1.4854 +G00 Z0.1000 +G00 X-0.8589 Y1.1600 +G01 Z-0.0070 F10 +G01 X-0.8554 Y1.1565 F20 +G01 X-0.5976 Y1.1565 +G01 X-0.5906 Y1.1635 +G01 X-0.8554 Y1.1635 +G01 X-0.8589 Y1.1600 +G00 Z0.1000 +G00 X-0.7576 Y1.2635 +G01 Z-0.0070 F10 +G01 X-0.8554 Y1.2635 F20 +G01 X-0.8589 Y1.2600 +G01 X-0.8554 Y1.2565 +G01 X-0.7506 Y1.2565 +G01 X-0.7576 Y1.2635 +G00 Z0.1000 +G00 X-1.6092 Y0.9565 +G01 Z-0.0070 F10 +G01 X-1.6004 Y0.9565 F20 +G01 X-1.6000 Y0.9565 +G01 X-1.5907 Y0.9565 +G01 X-1.3446 Y0.9565 +G01 X-1.3411 Y0.9600 +G01 X-1.3446 Y0.9635 +G01 X-1.6807 Y0.9635 +G01 X-1.6835 Y0.9635 +G01 X-1.6835 Y0.9631 +G01 X-1.6835 Y0.9607 +G01 X-1.6835 Y0.9092 +G01 X-1.6691 Y0.9291 +G01 X-1.6444 Y0.9470 +G01 X-1.6153 Y0.9565 +G01 X-1.6093 Y0.9565 +G00 Z0.1000 +G00 X-1.7109 Y0.7309 +G01 Z-0.0070 F10 +G01 X-1.7109 Y0.7309 F20 +G01 X-1.7266 Y0.7195 +G01 X-1.7254 Y0.7195 +G01 X-1.6965 Y0.6906 +G01 X-1.6965 Y0.7508 +G01 X-1.7109 Y0.7309 +G00 Z0.1000 +G00 X-1.5965 Y0.6976 +G01 Z-0.0070 F10 +G01 X-1.5965 Y0.7507 F20 +G01 X-1.5965 Y0.7527 +G01 X-1.5965 Y0.7692 +G01 X-1.5965 Y0.7753 +G01 X-1.5870 Y0.8044 +G01 X-1.5691 Y0.8291 +G01 X-1.5444 Y0.8470 +G01 X-1.5153 Y0.8565 +G01 X-1.5093 Y0.8565 +G01 X-1.3446 Y0.8565 +G01 X-1.3411 Y0.8600 +G01 X-1.3446 Y0.8635 +G01 X-1.5907 Y0.8635 +G01 X-1.6000 Y0.8635 +G01 X-1.6005 Y0.8635 +G01 X-1.6016 Y0.8631 +G01 X-1.6025 Y0.8625 +G01 X-1.6031 Y0.8616 +G01 X-1.6035 Y0.8605 +G01 X-1.6035 Y0.8600 +G01 X-1.6035 Y0.6906 +G01 X-1.5965 Y0.6976 +G00 Z0.1000 +G00 X-1.2635 Y0.2935 +G01 Z-0.0070 F10 +G01 X-1.2635 Y0.2276 F20 +G01 X-1.2605 Y0.2246 +G01 X-1.2605 Y0.1754 +G01 X-1.2894 Y0.1465 +G01 X-1.1492 Y0.1465 +G01 X-1.1402 Y0.1465 +G01 X-1.1400 Y0.1465 +G01 X-1.1395 Y0.1465 +G01 X-1.1384 Y0.1469 +G01 X-1.1375 Y0.1475 +G01 X-1.1369 Y0.1484 +G01 X-1.1365 Y0.1495 +G01 X-1.1365 Y0.1500 +G01 X-1.1365 Y0.2092 +G01 X-1.1365 Y0.2153 +G01 X-1.1270 Y0.2444 +G01 X-1.1091 Y0.2691 +G01 X-1.0844 Y0.2870 +G01 X-1.0645 Y0.2935 +G01 X-1.2635 Y0.2935 +G00 Z0.1000 +G00 X-1.3795 Y0.1754 +G01 Z-0.0070 F10 +G01 X-1.3795 Y0.2246 F20 +G01 X-1.3565 Y0.2476 +G01 X-1.3565 Y0.2935 +G01 X-1.3739 Y0.2935 +G01 X-1.3829 Y0.2845 +G01 X-1.4070 Y0.2745 +G01 X-1.4330 Y0.2745 +G01 X-1.4571 Y0.2845 +G01 X-1.4755 Y0.3029 +G01 X-1.4855 Y0.3270 +G01 X-1.4855 Y0.3530 +G01 X-1.4755 Y0.3771 +G01 X-1.4571 Y0.3955 +G01 X-1.4330 Y0.4055 +G01 X-1.4179 Y0.4055 +G01 X-1.4391 Y0.4209 +G01 X-1.4558 Y0.4439 +G01 X-1.4571 Y0.4445 +G01 X-1.4755 Y0.4629 +G01 X-1.4855 Y0.4870 +G01 X-1.4855 Y0.5130 +G01 X-1.4765 Y0.5348 +G01 X-1.4765 Y0.6724 +G01 X-1.4895 Y0.6854 +G01 X-1.4895 Y0.7346 +G01 X-1.4606 Y0.7635 +G01 X-1.5000 Y0.7635 +G01 X-1.5005 Y0.7635 +G01 X-1.5016 Y0.7631 +G01 X-1.5025 Y0.7625 +G01 X-1.5031 Y0.7616 +G01 X-1.5035 Y0.7605 +G01 X-1.5035 Y0.7600 +G01 X-1.5035 Y0.7527 +G01 X-1.5035 Y0.7507 +G01 X-1.5035 Y0.6976 +G01 X-1.4905 Y0.6846 +G01 X-1.4905 Y0.6354 +G01 X-1.5254 Y0.6005 +G01 X-1.5746 Y0.6005 +G01 X-1.6035 Y0.6294 +G01 X-1.6035 Y0.1592 +G01 X-1.6035 Y0.1500 +G01 X-1.6035 Y0.1495 +G01 X-1.6031 Y0.1484 +G01 X-1.6025 Y0.1475 +G01 X-1.6016 Y0.1469 +G01 X-1.6005 Y0.1465 +G01 X-1.6000 Y0.1465 +G01 X-1.3506 Y0.1465 +G01 X-1.3795 Y0.1754 +G00 Z0.1000 +G00 X-0.5976 Y1.0635 +G01 Z-0.0070 F10 +G01 X-0.8554 Y1.0635 F20 +G01 X-0.8589 Y1.0600 +G01 X-0.8554 Y1.0565 +G01 X-0.5906 Y1.0565 +G01 X-0.5976 Y1.0635 +G00 Z0.1000 +G00 X-0.8589 Y0.9600 +G01 Z-0.0070 F10 +G01 X-0.8554 Y0.9565 F20 +G01 X-0.8392 Y0.9565 +G01 X-0.8353 Y0.9565 +G01 X-0.8207 Y0.9565 +G01 X-0.8147 Y0.9565 +G01 X-0.7856 Y0.9470 +G01 X-0.7609 Y0.9291 +G01 X-0.7429 Y0.9044 +G01 X-0.7335 Y0.8753 +G01 X-0.7335 Y0.8693 +G01 X-0.7335 Y0.5776 +G01 X-0.7205 Y0.5646 +G01 X-0.7205 Y0.5154 +G01 X-0.7494 Y0.4865 +G01 X-0.6100 Y0.4865 +G01 X-0.6094 Y0.4865 +G01 X-0.6084 Y0.4869 +G01 X-0.6075 Y0.4875 +G01 X-0.6069 Y0.4884 +G01 X-0.6065 Y0.4895 +G01 X-0.6065 Y0.4900 +G01 X-0.6065 Y0.4992 +G01 X-0.6065 Y0.8724 +G01 X-0.6195 Y0.8854 +G01 X-0.6195 Y0.9346 +G01 X-0.5906 Y0.9635 +G01 X-0.8554 Y0.9635 +G01 X-0.8589 Y0.9600 +G00 Z0.1000 +G00 X-1.1589 Y0.8600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y0.8476 F20 +G01 X-1.1465 Y0.8507 +G01 X-1.1465 Y0.8724 +G01 X-1.1589 Y0.8600 +G00 Z0.1000 +G00 X-1.0411 Y0.9600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y0.9724 F20 +G01 X-1.0535 Y0.9476 +G01 X-1.0411 Y0.9600 +G00 Z0.1000 +G00 X-1.0411 Y1.0600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y1.0724 F20 +G01 X-1.0535 Y1.0476 +G01 X-1.0411 Y1.0600 +G00 Z0.1000 +G00 X-1.0411 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y1.1724 F20 +G01 X-1.0535 Y1.1476 +G01 X-1.0411 Y1.1600 +G00 Z0.1000 +G00 X-1.0411 Y1.2600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y1.2724 F20 +G01 X-1.0535 Y1.2476 +G01 X-1.0411 Y1.2600 +G00 Z0.1000 +G00 X-1.0411 Y1.3600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y1.3724 F20 +G01 X-1.0535 Y1.3476 +G01 X-1.0411 Y1.3600 +G00 Z0.1000 +G00 X-1.1589 Y1.3600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y1.3476 F20 +G01 X-1.1465 Y1.3724 +G01 X-1.1589 Y1.3600 +G00 Z0.1000 +G00 X-1.1589 Y1.2600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y1.2476 F20 +G01 X-1.1465 Y1.2724 +G01 X-1.1589 Y1.2600 +G00 Z0.1000 +G00 X-1.1589 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y1.1476 F20 +G01 X-1.1465 Y1.1724 +G01 X-1.1589 Y1.1600 +G00 Z0.1000 +G00 X-1.1589 Y1.0600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y1.0476 F20 +G01 X-1.1465 Y1.0724 +G01 X-1.1589 Y1.0600 +G00 Z0.1000 +G00 X-1.1589 Y0.9600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y0.9476 F20 +G01 X-1.1465 Y0.9724 +G01 X-1.1589 Y0.9600 +G00 Z0.1000 +G00 X-1.0525 Y0.8575 +G01 Z-0.0070 F10 +G01 X-1.0516 Y0.8569 F20 +G01 X-1.0505 Y0.8565 +G01 X-1.0500 Y0.8565 +G01 X-1.0446 Y0.8565 +G01 X-1.0411 Y0.8600 +G01 X-1.0535 Y0.8724 +G01 X-1.0535 Y0.8600 +G01 X-1.0535 Y0.8594 +G01 X-1.0531 Y0.8584 +G01 X-1.0525 Y0.8575 +G00 Z0.1000 +G00 X-2.0511 Y1.2600 +G01 Z-0.0070 F10 +G01 X-2.0635 Y1.2724 F20 +G01 X-2.0635 Y1.2476 +G01 X-2.0511 Y1.2600 +G00 Z0.1000 +G00 X-2.0511 Y1.1600 +G01 Z-0.0070 F10 +G01 X-2.0635 Y1.1724 F20 +G01 X-2.0635 Y1.1476 +G01 X-2.0511 Y1.1600 +G00 Z0.1000 +G00 X-2.1689 Y1.1600 +G01 Z-0.0070 F10 +G01 X-2.1565 Y1.1476 F20 +G01 X-2.1565 Y1.1724 +G01 X-2.1689 Y1.1600 +G00 Z0.1000 +G00 X-2.1689 Y1.2600 +G01 Z-0.0070 F10 +G01 X-2.1565 Y1.2476 F20 +G01 X-2.1565 Y1.2635 +G01 X-2.1654 Y1.2635 +G01 X-2.1689 Y1.2600 +G00 Z0.1000 +G00 X-2.1692 Y0.9565 +G01 Z-0.0070 F10 +G01 X-2.1600 Y0.9565 F20 +G01 X-2.1595 Y0.9565 +G01 X-2.1584 Y0.9569 +G01 X-2.1575 Y0.9575 +G01 X-2.1569 Y0.9584 +G01 X-2.1565 Y0.9595 +G01 X-2.1565 Y0.9600 +G01 X-2.1565 Y0.9724 +G01 X-2.1693 Y0.9596 +G01 X-2.1767 Y0.9565 +G01 X-2.1692 Y0.9565 +G00 Z0.1000 +G00 X-2.1689 Y1.0600 +G01 Z-0.0070 F10 +G01 X-2.1565 Y1.0476 F20 +G01 X-2.1565 Y1.0507 +G01 X-2.1565 Y1.0724 +G01 X-2.1689 Y1.0600 +G00 Z0.1000 +G00 X-2.0607 Y1.0565 +G01 Z-0.0070 F10 +G01 X-2.0546 Y1.0565 F20 +G01 X-2.0511 Y1.0600 +G01 X-2.0635 Y1.0724 +G01 X-2.0635 Y1.0593 +G01 X-2.0607 Y1.0565 +G00 Z0.1000 +G00 X-1.3574 Y1.3437 +G01 Z-0.0070 F10 +G01 X-1.3411 Y1.3600 F20 +G01 X-1.3446 Y1.3635 +G01 X-1.3507 Y1.3635 +G01 X-1.3600 Y1.3635 +G01 X-1.3605 Y1.3635 +G01 X-1.3616 Y1.3631 +G01 X-1.3625 Y1.3625 +G01 X-1.3631 Y1.3616 +G01 X-1.3635 Y1.3605 +G01 X-1.3635 Y1.3600 +G01 X-1.3635 Y1.3291 +G01 X-1.3574 Y1.3437 +G00 Z0.1000 +G00 X-2.0435 Y1.7592 +G01 Z-0.0070 F10 +G01 X-2.0435 Y1.7500 F20 +G01 X-2.0435 Y1.7495 +G01 X-2.0431 Y1.7484 +G01 X-2.0425 Y1.7475 +G01 X-2.0416 Y1.7469 +G01 X-2.0405 Y1.7465 +G01 X-2.0400 Y1.7465 +G01 X-2.0307 Y1.7465 +G01 X-2.0160 Y1.7465 +G01 X-2.0333 Y1.7638 +G01 X-2.0333 Y1.8162 +G01 X-1.9990 Y1.8505 +G01 X-2.0246 Y1.8505 +G01 X-2.0376 Y1.8635 +G01 X-2.0435 Y1.8635 +G01 X-2.0435 Y1.7592 +G00 Z0.1000 +G00 X-1.9726 Y1.8533 +G01 Z-0.0070 F10 +G01 X-1.9438 Y1.8533 F20 +G01 X-1.9270 Y1.8365 +G01 X-1.6665 Y1.8365 +G01 X-1.6665 Y1.9692 +G01 X-1.6665 Y1.9753 +G01 X-1.6570 Y2.0044 +G01 X-1.6391 Y2.0291 +G01 X-1.6144 Y2.0470 +G01 X-1.5853 Y2.0565 +G01 X-1.5793 Y2.0565 +G01 X-1.5705 Y2.0565 +G01 X-1.5700 Y2.0565 +G01 X-1.5607 Y2.0565 +G01 X-1.4192 Y2.0565 +G01 X-1.4100 Y2.0565 +G01 X-1.4007 Y2.0565 +G01 X-1.3947 Y2.0565 +G01 X-1.3656 Y2.0470 +G01 X-1.3409 Y2.0291 +G01 X-1.3229 Y2.0044 +G01 X-1.3135 Y1.9753 +G01 X-1.3135 Y1.9693 +G01 X-1.3135 Y1.9040 +G01 X-1.2960 Y1.8865 +G01 X-1.2960 Y1.8335 +G01 X-1.3135 Y1.8160 +G01 X-1.3135 Y1.8100 +G01 X-1.3135 Y1.8095 +G01 X-1.3131 Y1.8084 +G01 X-1.3125 Y1.8075 +G01 X-1.3116 Y1.8069 +G01 X-1.3105 Y1.8065 +G01 X-1.3100 Y1.8065 +G01 X-1.3023 Y1.8065 +G01 X-1.3007 Y1.8065 +G01 X-0.7970 Y1.8065 +G01 X-0.8040 Y1.8135 +G01 X-1.1507 Y1.8135 +G01 X-1.1600 Y1.8135 +G01 X-1.1602 Y1.8135 +G01 X-1.1692 Y1.8135 +G01 X-1.1753 Y1.8135 +G01 X-1.2044 Y1.8229 +G01 X-1.2291 Y1.8409 +G01 X-1.2470 Y1.8656 +G01 X-1.2565 Y1.8947 +G01 X-1.2565 Y1.9007 +G01 X-1.2565 Y2.0507 +G01 X-1.2565 Y2.0598 +G01 X-1.2565 Y2.0600 +G01 X-1.2565 Y2.0605 +G01 X-1.2569 Y2.0616 +G01 X-1.2575 Y2.0625 +G01 X-1.2584 Y2.0631 +G01 X-1.2595 Y2.0635 +G01 X-1.2600 Y2.0635 +G01 X-1.6700 Y2.0635 +G01 X-1.6705 Y2.0635 +G01 X-1.6716 Y2.0631 +G01 X-1.6725 Y2.0625 +G01 X-1.6731 Y2.0616 +G01 X-1.6735 Y2.0605 +G01 X-1.6735 Y2.0600 +G01 X-1.6735 Y1.9692 +G01 X-1.6735 Y1.9653 +G01 X-1.6735 Y1.9507 +G01 X-1.6735 Y1.9447 +G01 X-1.6829 Y1.9156 +G01 X-1.7009 Y1.8909 +G01 X-1.7256 Y1.8729 +G01 X-1.7547 Y1.8635 +G01 X-1.7607 Y1.8635 +G01 X-1.9624 Y1.8635 +G01 X-1.9726 Y1.8533 +G00 Z0.1000 +G00 X-1.6635 Y1.5095 +G01 Z-0.0070 F10 +G01 X-1.6631 Y1.5084 F20 +G01 X-1.6625 Y1.5075 +G01 X-1.6616 Y1.5069 +G01 X-1.6605 Y1.5065 +G01 X-1.6600 Y1.5065 +G01 X-1.6524 Y1.5065 +G01 X-1.6507 Y1.5065 +G01 X-1.4507 Y1.5065 +G01 X-1.4447 Y1.5065 +G01 X-1.4156 Y1.4970 +G01 X-1.3909 Y1.4791 +G01 X-1.3745 Y1.4565 +G01 X-1.3693 Y1.4565 +G01 X-1.3606 Y1.4565 +G01 X-1.3600 Y1.4565 +G01 X-1.3507 Y1.4565 +G01 X-1.3446 Y1.4565 +G01 X-1.3407 Y1.4604 +G01 X-1.3188 Y1.4695 +G01 X-1.1812 Y1.4695 +G01 X-1.1593 Y1.4604 +G01 X-1.1465 Y1.4476 +G01 X-1.1465 Y1.5207 +G01 X-1.1465 Y1.5300 +G01 X-1.1465 Y1.5305 +G01 X-1.1469 Y1.5316 +G01 X-1.1475 Y1.5325 +G01 X-1.1484 Y1.5331 +G01 X-1.1495 Y1.5335 +G01 X-1.1500 Y1.5335 +G01 X-1.5607 Y1.5335 +G01 X-1.5683 Y1.5335 +G01 X-1.5792 Y1.5335 +G01 X-1.5853 Y1.5335 +G01 X-1.6144 Y1.5429 +G01 X-1.6391 Y1.5609 +G01 X-1.6570 Y1.5856 +G01 X-1.6635 Y1.6055 +G01 X-1.6635 Y1.5100 +G01 X-1.6635 Y1.5095 +G00 Z0.1000 +G00 X-1.6665 Y1.7435 +G01 Z-0.0070 F10 +G01 X-1.7176 Y1.7435 F20 +G01 X-1.6967 Y1.7348 +G01 X-1.6751 Y1.7133 +G01 X-1.6665 Y1.6924 +G01 X-1.6665 Y1.7435 +G00 Z0.1000 +G00 X-1.3544 Y1.7229 +G01 Z-0.0070 F10 +G01 X-1.3544 Y1.7229 F20 +G01 X-1.3791 Y1.7409 +G01 X-1.3970 Y1.7656 +G01 X-1.4065 Y1.7947 +G01 X-1.4065 Y1.8007 +G01 X-1.4065 Y1.8160 +G01 X-1.4240 Y1.8335 +G01 X-1.4240 Y1.8865 +G01 X-1.4065 Y1.9040 +G01 X-1.4065 Y1.9600 +G01 X-1.4065 Y1.9605 +G01 X-1.4069 Y1.9616 +G01 X-1.4075 Y1.9625 +G01 X-1.4084 Y1.9631 +G01 X-1.4095 Y1.9635 +G01 X-1.4100 Y1.9635 +G01 X-1.4192 Y1.9635 +G01 X-1.4694 Y1.9635 +G01 X-1.4405 Y1.9346 +G01 X-1.4405 Y1.8854 +G01 X-1.4535 Y1.8724 +G01 X-1.4535 Y1.7561 +G01 X-1.4445 Y1.7471 +G01 X-1.4345 Y1.7230 +G01 X-1.4345 Y1.7165 +G01 X-1.3345 Y1.7165 +G01 X-1.3544 Y1.7229 +G00 Z0.1000 +G00 X-1.4895 Y1.1854 +G01 Z-0.0070 F10 +G01 X-1.4895 Y1.2346 F20 +G01 X-1.4744 Y1.2497 +G01 X-1.4870 Y1.2445 +G01 X-1.5130 Y1.2445 +G01 X-1.5371 Y1.2545 +G01 X-1.5461 Y1.2635 +G01 X-1.5767 Y1.2635 +G01 X-1.5767 Y1.2438 +G01 X-1.6138 Y1.2067 +G01 X-1.6662 Y1.2067 +G01 X-1.7033 Y1.2438 +G01 X-1.7033 Y1.2635 +G01 X-1.7235 Y1.2635 +G01 X-1.7235 Y1.2376 +G01 X-1.7105 Y1.2246 +G01 X-1.7105 Y1.1754 +G01 X-1.7294 Y1.1565 +G01 X-1.4606 Y1.1565 +G01 X-1.4895 Y1.1854 +G00 Z0.1000 +G00 X-1.3411 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.3574 Y1.1763 F20 +G01 X-1.3665 Y1.1982 +G01 X-1.3665 Y1.2218 +G01 X-1.3574 Y1.2437 +G01 X-1.3411 Y1.2600 +G01 X-1.3574 Y1.2763 +G01 X-1.3635 Y1.2909 +G01 X-1.3635 Y1.2692 +G01 X-1.3635 Y1.2600 +G01 X-1.3635 Y1.2588 +G01 X-1.3635 Y1.2415 +G01 X-1.3635 Y1.2380 +G01 X-1.3701 Y1.2135 +G01 X-1.3705 Y1.2127 +G01 X-1.3705 Y1.1854 +G01 X-1.3994 Y1.1565 +G01 X-1.3446 Y1.1565 +G01 X-1.3411 Y1.1600 +G00 Z0.1000 +G00 X-1.8654 Y1.0635 +G01 Z-0.0070 F10 +G01 X-1.8689 Y1.0600 F20 +G01 X-1.8565 Y1.0476 +G01 X-1.8565 Y1.0635 +G01 X-1.8654 Y1.0635 +G00 Z0.1000 +G00 X-1.7909 Y0.8109 +G01 Z-0.0070 F10 +G01 X-1.7909 Y0.8109 F20 +G01 X-1.8108 Y0.7965 +G01 X-1.7800 Y0.7965 +G01 X-1.7795 Y0.7965 +G01 X-1.7784 Y0.7969 +G01 X-1.7775 Y0.7975 +G01 X-1.7769 Y0.7984 +G01 X-1.7765 Y0.7995 +G01 X-1.7765 Y0.8000 +G01 X-1.7765 Y0.8308 +G01 X-1.7909 Y0.8109 +G00 Z0.1000 +G00 X-1.6992 Y1.0565 +G01 Z-0.0070 F10 +G01 X-1.6876 Y1.0565 F20 +G01 X-1.6807 Y1.0565 +G01 X-1.3446 Y1.0565 +G01 X-1.3411 Y1.0600 +G01 X-1.3446 Y1.0635 +G01 X-1.7635 Y1.0635 +G01 X-1.7635 Y1.0186 +G01 X-1.7633 Y1.0190 +G01 X-1.7390 Y1.0433 +G01 X-1.7072 Y1.0565 +G01 X-1.6992 Y1.0565 +G00 Z0.1000 +G00 X-2.1770 Y0.6544 +G01 Z-0.0070 F10 +G01 X-2.1770 Y0.6544 F20 +G01 X-2.1591 Y0.6791 +G01 X-2.1344 Y0.6970 +G01 X-2.1145 Y0.7035 +G01 X-2.1807 Y0.7035 +G01 X-2.1835 Y0.7035 +G01 X-2.1835 Y0.6345 +G01 X-2.1770 Y0.6544 +G00 Z0.1000 +G00 X-1.8565 Y0.9724 +G01 Z-0.0070 F10 +G01 X-1.8693 Y0.9596 F20 +G01 X-1.8912 Y0.9505 +G01 X-2.0288 Y0.9505 +G01 X-2.0507 Y0.9596 +G01 X-2.0546 Y0.9635 +G01 X-2.0635 Y0.9635 +G01 X-2.0635 Y0.9507 +G01 X-2.0635 Y0.9447 +G01 X-2.0729 Y0.9156 +G01 X-2.0909 Y0.8909 +G01 X-2.1108 Y0.8765 +G01 X-1.8600 Y0.8765 +G01 X-1.8595 Y0.8765 +G01 X-1.8584 Y0.8769 +G01 X-1.8575 Y0.8775 +G01 X-1.8569 Y0.8784 +G01 X-1.8565 Y0.8795 +G01 X-1.8565 Y0.8800 +G01 X-1.8565 Y0.9724 +G00 Z0.1000 +G00 X-1.5655 Y1.6970 +G01 Z-0.0070 F10 +G01 X-1.5655 Y1.7230 F20 +G01 X-1.5555 Y1.7471 +G01 X-1.5465 Y1.7561 +G01 X-1.5465 Y1.8724 +G01 X-1.5595 Y1.8854 +G01 X-1.5595 Y1.9346 +G01 X-1.5306 Y1.9635 +G01 X-1.5607 Y1.9635 +G01 X-1.5700 Y1.9635 +G01 X-1.5705 Y1.9635 +G01 X-1.5716 Y1.9631 +G01 X-1.5725 Y1.9625 +G01 X-1.5731 Y1.9616 +G01 X-1.5735 Y1.9605 +G01 X-1.5735 Y1.9600 +G01 X-1.5735 Y1.7992 +G01 X-1.5735 Y1.7707 +G01 X-1.5735 Y1.6392 +G01 X-1.5735 Y1.6300 +G01 X-1.5735 Y1.6295 +G01 X-1.5731 Y1.6284 +G01 X-1.5725 Y1.6275 +G01 X-1.5716 Y1.6269 +G01 X-1.5705 Y1.6265 +G01 X-1.5700 Y1.6265 +G01 X-1.5682 Y1.6265 +G01 X-1.5607 Y1.6265 +G01 X-1.4802 Y1.6265 +G01 X-1.4878 Y1.6281 +G01 X-1.5130 Y1.6424 +G01 X-1.5161 Y1.6458 +G01 X-1.5371 Y1.6545 +G01 X-1.5555 Y1.6729 +G01 X-1.5655 Y1.6970 +G00 Z0.1000 +G00 X-0.8395 Y0.5154 +G01 Z-0.0070 F10 +G01 X-0.8395 Y0.5646 F20 +G01 X-0.8265 Y0.5776 +G01 X-0.8265 Y0.8600 +G01 X-0.8265 Y0.8605 +G01 X-0.8269 Y0.8616 +G01 X-0.8275 Y0.8625 +G01 X-0.8284 Y0.8631 +G01 X-0.8295 Y0.8635 +G01 X-0.8300 Y0.8635 +G01 X-0.8353 Y0.8635 +G01 X-0.8392 Y0.8635 +G01 X-0.8554 Y0.8635 +G01 X-0.8589 Y0.8600 +G01 X-0.8426 Y0.8437 +G01 X-0.8335 Y0.8218 +G01 X-0.8335 Y0.7982 +G01 X-0.8426 Y0.7763 +G01 X-0.8593 Y0.7596 +G01 X-0.8812 Y0.7505 +G01 X-1.0188 Y0.7505 +G01 X-1.0407 Y0.7596 +G01 X-1.0446 Y0.7635 +G01 X-1.0592 Y0.7635 +G01 X-1.0653 Y0.7635 +G01 X-1.0944 Y0.7729 +G01 X-1.1191 Y0.7909 +G01 X-1.1335 Y0.8108 +G01 X-1.1335 Y0.7982 +G01 X-1.1426 Y0.7763 +G01 X-1.1593 Y0.7596 +G01 X-1.1812 Y0.7505 +G01 X-1.3188 Y0.7505 +G01 X-1.3407 Y0.7596 +G01 X-1.3446 Y0.7635 +G01 X-1.3994 Y0.7635 +G01 X-1.3705 Y0.7346 +G01 X-1.3705 Y0.6854 +G01 X-1.3835 Y0.6724 +G01 X-1.3835 Y0.5558 +G01 X-1.3829 Y0.5555 +G01 X-1.3645 Y0.5371 +G01 X-1.3545 Y0.5130 +G01 X-1.3545 Y0.4870 +G01 X-1.3547 Y0.4865 +G01 X-0.8106 Y0.4865 +G01 X-0.8395 Y0.5154 +G00 Z0.1000 +G00 X-1.3809 Y0.3935 +G01 Z-0.0070 F10 +G01 X-1.3739 Y0.3865 F20 +G01 X-1.3192 Y0.3865 +G01 X-1.3007 Y0.3865 +G01 X-0.8176 Y0.3865 +G01 X-0.8106 Y0.3935 +G01 X-1.3792 Y0.3935 +G01 X-1.3809 Y0.3935 +G00 Z0.1000 +G00 X-2.9400 Y1.3895 +G01 Z-0.0070 F10 +G01 X-2.9435 Y1.3930 F20 +G01 X-2.9435 Y1.3895 +G01 X-2.9400 Y1.3895 +G00 Z0.1000 +G00 X-0.2816 Y1.3754 +G01 Z-0.0070 F10 +G01 X-0.1184 Y1.3754 F20 +G01 X-0.0938 Y1.3652 +G01 X-0.0750 Y1.3464 +G01 X-0.0648 Y1.3218 +G01 X-0.0648 Y1.2951 +G01 X-0.0750 Y1.2705 +G01 X-0.0938 Y1.2516 +G01 X-0.1184 Y1.2414 +G01 X-0.2816 Y1.2414 +G01 X-0.3062 Y1.2516 +G01 X-0.3165 Y1.2619 +G01 X-0.4807 Y1.2619 +G01 X-0.4823 Y1.2619 +G01 X-0.4992 Y1.2619 +G01 X-0.5053 Y1.2619 +G01 X-0.5344 Y1.2714 +G01 X-0.5591 Y1.2893 +G01 X-0.5770 Y1.3141 +G01 X-0.5865 Y1.3431 +G01 X-0.5865 Y1.3492 +G01 X-0.5865 Y1.3600 +G01 X-0.5865 Y1.3605 +G01 X-0.5869 Y1.3616 +G01 X-0.5875 Y1.3625 +G01 X-0.5884 Y1.3631 +G01 X-0.5894 Y1.3635 +G01 X-0.5900 Y1.3635 +G01 X-0.5992 Y1.3635 +G01 X-0.6894 Y1.3635 +G01 X-0.6605 Y1.3346 +G01 X-0.6605 Y1.2854 +G01 X-0.6894 Y1.2565 +G01 X-0.4307 Y1.2565 +G01 X-0.4228 Y1.2565 +G01 X-0.3910 Y1.2433 +G01 X-0.3667 Y1.2190 +G01 X-0.3535 Y1.1872 +G01 X-0.3535 Y1.1792 +G01 X-0.3535 Y1.1700 +G01 X-0.3535 Y1.1616 +G01 X-0.3535 Y1.1610 +G01 X-0.3531 Y1.1600 +G01 X-0.3525 Y1.1591 +G01 X-0.3516 Y1.1585 +G01 X-0.3505 Y1.1581 +G01 X-0.3500 Y1.1581 +G01 X-0.3451 Y1.1581 +G01 X-0.3407 Y1.1581 +G01 X-0.3165 Y1.1581 +G01 X-0.3062 Y1.1684 +G01 X-0.2816 Y1.1786 +G01 X-0.1184 Y1.1786 +G01 X-0.0938 Y1.1684 +G01 X-0.0750 Y1.1495 +G01 X-0.0648 Y1.1249 +G01 X-0.0648 Y1.0982 +G01 X-0.0750 Y1.0736 +G01 X-0.0938 Y1.0548 +G01 X-0.1184 Y1.0446 +G01 X-0.2816 Y1.0446 +G01 X-0.3062 Y1.0548 +G01 X-0.3165 Y1.0651 +G01 X-0.3407 Y1.0651 +G01 X-0.3452 Y1.0651 +G01 X-0.3592 Y1.0651 +G01 X-0.3653 Y1.0651 +G01 X-0.3944 Y1.0745 +G01 X-0.4191 Y1.0925 +G01 X-0.4370 Y1.1172 +G01 X-0.4465 Y1.1463 +G01 X-0.4465 Y1.1523 +G01 X-0.4465 Y1.1607 +G01 X-0.4465 Y1.1635 +G01 X-0.5294 Y1.1635 +G01 X-0.5005 Y1.1346 +G01 X-0.5005 Y1.0854 +G01 X-0.5294 Y1.0565 +G01 X-0.4892 Y1.0565 +G01 X-0.4878 Y1.0565 +G01 X-0.4707 Y1.0565 +G01 X-0.4647 Y1.0565 +G01 X-0.4356 Y1.0470 +G01 X-0.4109 Y1.0291 +G01 X-0.3929 Y1.0044 +G01 X-0.3835 Y0.9753 +G01 X-0.3835 Y0.9693 +G01 X-0.3835 Y0.9565 +G01 X-0.3149 Y0.9565 +G01 X-0.3062 Y0.9652 +G01 X-0.2816 Y0.9754 +G01 X-0.1184 Y0.9754 +G01 X-0.0938 Y0.9652 +G01 X-0.0750 Y0.9464 +G01 X-0.0648 Y0.9218 +G01 X-0.0648 Y0.8951 +G01 X-0.0750 Y0.8705 +G01 X-0.0938 Y0.8516 +G01 X-0.1184 Y0.8414 +G01 X-0.2816 Y0.8414 +G01 X-0.3062 Y0.8516 +G01 X-0.3181 Y0.8635 +G01 X-0.3992 Y0.8635 +G01 X-0.4072 Y0.8635 +G01 X-0.4390 Y0.8767 +G01 X-0.4633 Y0.9010 +G01 X-0.4765 Y0.9328 +G01 X-0.4765 Y0.9407 +G01 X-0.4765 Y0.9600 +G01 X-0.4765 Y0.9605 +G01 X-0.4769 Y0.9616 +G01 X-0.4775 Y0.9625 +G01 X-0.4784 Y0.9631 +G01 X-0.4795 Y0.9635 +G01 X-0.4800 Y0.9635 +G01 X-0.4878 Y0.9635 +G01 X-0.4892 Y0.9635 +G01 X-0.5294 Y0.9635 +G01 X-0.5005 Y0.9346 +G01 X-0.5005 Y0.8854 +G01 X-0.5135 Y0.8724 +G01 X-0.5135 Y0.4992 +G01 X-0.5135 Y0.4900 +G01 X-0.5135 Y0.4868 +G01 X-0.5135 Y0.4807 +G01 X-0.5135 Y0.4747 +G01 X-0.5229 Y0.4456 +G01 X-0.5409 Y0.4209 +G01 X-0.5656 Y0.4030 +G01 X-0.5947 Y0.3935 +G01 X-0.6007 Y0.3935 +G01 X-0.7494 Y0.3935 +G01 X-0.7205 Y0.3646 +G01 X-0.7205 Y0.3154 +G01 X-0.7394 Y0.2965 +G01 X-0.5192 Y0.2965 +G01 X-0.5100 Y0.2965 +G01 X-0.5095 Y0.2965 +G01 X-0.5084 Y0.2969 +G01 X-0.5075 Y0.2975 +G01 X-0.5069 Y0.2984 +G01 X-0.5065 Y0.2995 +G01 X-0.5065 Y0.3000 +G01 X-0.5065 Y0.6507 +G01 X-0.5065 Y0.6528 +G01 X-0.5065 Y0.6692 +G01 X-0.5065 Y0.6753 +G01 X-0.4970 Y0.7044 +G01 X-0.4791 Y0.7291 +G01 X-0.4544 Y0.7470 +G01 X-0.4253 Y0.7565 +G01 X-0.4193 Y0.7565 +G01 X-0.3181 Y0.7565 +G01 X-0.3062 Y0.7684 +G01 X-0.2816 Y0.7786 +G01 X-0.1184 Y0.7786 +G01 X-0.0938 Y0.7684 +G01 X-0.0750 Y0.7495 +G01 X-0.0648 Y0.7249 +G01 X-0.0648 Y0.6982 +G01 X-0.0750 Y0.6736 +G01 X-0.0938 Y0.6548 +G01 X-0.1184 Y0.6446 +G01 X-0.2816 Y0.6446 +G01 X-0.3062 Y0.6548 +G01 X-0.3149 Y0.6635 +G01 X-0.4100 Y0.6635 +G01 X-0.4105 Y0.6635 +G01 X-0.4116 Y0.6631 +G01 X-0.4125 Y0.6625 +G01 X-0.4131 Y0.6616 +G01 X-0.4135 Y0.6605 +G01 X-0.4135 Y0.6600 +G01 X-0.4135 Y0.6528 +G01 X-0.4135 Y0.6507 +G01 X-0.4135 Y0.2907 +G01 X-0.4135 Y0.2847 +G01 X-0.4229 Y0.2556 +G01 X-0.4409 Y0.2309 +G01 X-0.4656 Y0.2129 +G01 X-0.4947 Y0.2035 +G01 X-0.5007 Y0.2035 +G01 X-0.5096 Y0.2035 +G01 X-0.5100 Y0.2035 +G01 X-0.5192 Y0.2035 +G01 X-1.0400 Y0.2035 +G01 X-1.0405 Y0.2035 +G01 X-1.0416 Y0.2031 +G01 X-1.0425 Y0.2025 +G01 X-1.0431 Y0.2016 +G01 X-1.0435 Y0.2005 +G01 X-1.0435 Y0.2000 +G01 X-1.0435 Y0.1407 +G01 X-1.0435 Y0.1347 +G01 X-1.0529 Y0.1056 +G01 X-1.0709 Y0.0809 +G01 X-1.0956 Y0.0629 +G01 X-1.1247 Y0.0535 +G01 X-1.1307 Y0.0535 +G01 X-1.1403 Y0.0535 +G01 X-1.1492 Y0.0535 +G01 X-1.6092 Y0.0535 +G01 X-1.6153 Y0.0535 +G01 X-1.6444 Y0.0629 +G01 X-1.6691 Y0.0809 +G01 X-1.6870 Y0.1056 +G01 X-1.6965 Y0.1347 +G01 X-1.6965 Y0.1407 +G01 X-1.6965 Y0.1500 +G01 X-1.6965 Y0.1592 +G01 X-1.6965 Y0.6294 +G01 X-1.7254 Y0.6005 +G01 X-1.7746 Y0.6005 +G01 X-1.7876 Y0.6135 +G01 X-1.8540 Y0.6135 +G01 X-1.8367 Y0.5962 +G01 X-1.8367 Y0.5640 +G01 X-1.8330 Y0.5655 +G01 X-1.8070 Y0.5655 +G01 X-1.7829 Y0.5555 +G01 X-1.7645 Y0.5371 +G01 X-1.7545 Y0.5130 +G01 X-1.7545 Y0.4870 +G01 X-1.7645 Y0.4629 +G01 X-1.7735 Y0.4539 +G01 X-1.7735 Y0.3861 +G01 X-1.7645 Y0.3771 +G01 X-1.7545 Y0.3530 +G01 X-1.7545 Y0.3270 +G01 X-1.7645 Y0.3029 +G01 X-1.7829 Y0.2845 +G01 X-1.8070 Y0.2745 +G01 X-1.8330 Y0.2745 +G01 X-1.8571 Y0.2845 +G01 X-1.8661 Y0.2935 +G01 X-1.9507 Y0.2935 +G01 X-1.9530 Y0.2935 +G01 X-1.9445 Y0.2730 +G01 X-1.9445 Y0.2470 +G01 X-1.9545 Y0.2229 +G01 X-1.9729 Y0.2045 +G01 X-1.9922 Y0.1965 +G01 X-1.8795 Y0.1965 +G01 X-1.8795 Y0.2246 +G01 X-1.8446 Y0.2595 +G01 X-1.7954 Y0.2595 +G01 X-1.7605 Y0.2246 +G01 X-1.7605 Y0.1754 +G01 X-1.7639 Y0.1720 +G01 X-1.7739 Y0.1411 +G01 X-1.7938 Y0.1138 +G01 X-1.8210 Y0.0939 +G01 X-1.8531 Y0.0835 +G01 X-1.8588 Y0.0835 +G01 X-2.4488 Y0.0835 +G01 X-2.4503 Y0.0835 +G01 X-2.4712 Y0.0835 +G01 X-2.4769 Y0.0835 +G01 X-2.5089 Y0.0939 +G01 X-2.5362 Y0.1138 +G01 X-2.5561 Y0.1410 +G01 X-2.5665 Y0.1731 +G01 X-2.5665 Y0.1788 +G01 X-2.5665 Y0.2135 +G01 X-2.6024 Y0.2135 +G01 X-2.6154 Y0.2005 +G01 X-2.6646 Y0.2005 +G01 X-2.6995 Y0.2354 +G01 X-2.6995 Y0.2846 +G01 X-2.6646 Y0.3195 +G01 X-2.6154 Y0.3195 +G01 X-2.6024 Y0.3065 +G01 X-2.5665 Y0.3065 +G01 X-2.5665 Y0.4270 +G01 X-2.5733 Y0.4338 +G01 X-2.5733 Y0.4862 +G01 X-2.5560 Y0.5035 +G01 X-2.8051 Y0.5035 +G01 X-2.8138 Y0.4948 +G01 X-2.8384 Y0.4846 +G01 X-3.0016 Y0.4846 +G01 X-3.0262 Y0.4948 +G01 X-3.0450 Y0.5136 +G01 X-3.0552 Y0.5382 +G01 X-3.0552 Y0.5649 +G01 X-3.0450 Y0.5895 +G01 X-3.0262 Y0.6084 +G01 X-3.0016 Y0.6186 +G01 X-2.8384 Y0.6186 +G01 X-2.8138 Y0.6084 +G01 X-2.8019 Y0.5965 +G01 X-2.2792 Y0.5965 +G01 X-2.2765 Y0.5965 +G01 X-2.2765 Y0.5979 +G01 X-2.2765 Y0.5992 +G01 X-2.2765 Y0.7192 +G01 X-2.2765 Y0.7272 +G01 X-2.2633 Y0.7590 +G01 X-2.2390 Y0.7833 +G01 X-2.2386 Y0.7835 +G01 X-2.2707 Y0.7835 +G01 X-2.2800 Y0.7835 +G01 X-2.2805 Y0.7835 +G01 X-2.2816 Y0.7831 +G01 X-2.2825 Y0.7825 +G01 X-2.2831 Y0.7816 +G01 X-2.2835 Y0.7805 +G01 X-2.2835 Y0.7800 +G01 X-2.2835 Y0.7507 +G01 X-2.2835 Y0.7468 +G01 X-2.2936 Y0.7223 +G01 X-2.3123 Y0.7036 +G01 X-2.3368 Y0.6935 +G01 X-2.3407 Y0.6935 +G01 X-2.3500 Y0.6935 +G01 X-2.3592 Y0.6935 +G01 X-2.6424 Y0.6935 +G01 X-2.6454 Y0.6905 +G01 X-2.6946 Y0.6905 +G01 X-2.7076 Y0.7035 +G01 X-2.8019 Y0.7035 +G01 X-2.8138 Y0.6916 +G01 X-2.8384 Y0.6814 +G01 X-3.0016 Y0.6814 +G01 X-3.0262 Y0.6916 +G01 X-3.0450 Y0.7105 +G01 X-3.0552 Y0.7351 +G01 X-3.0552 Y0.7618 +G01 X-3.0450 Y0.7864 +G01 X-3.0262 Y0.8052 +G01 X-3.0016 Y0.8154 +G01 X-2.8384 Y0.8154 +G01 X-2.8138 Y0.8052 +G01 X-2.8051 Y0.7965 +G01 X-2.7076 Y0.7965 +G01 X-2.6946 Y0.8095 +G01 X-2.6454 Y0.8095 +G01 X-2.6224 Y0.7865 +G01 X-2.3765 Y0.7865 +G01 X-2.3765 Y0.7892 +G01 X-2.3765 Y0.7953 +G01 X-2.3670 Y0.8244 +G01 X-2.3491 Y0.8491 +G01 X-2.3292 Y0.8635 +G01 X-2.4670 Y0.8635 +G01 X-2.4838 Y0.8467 +G01 X-2.5362 Y0.8467 +G01 X-2.5530 Y0.8635 +G01 X-3.1007 Y0.8635 +G01 X-3.1040 Y0.8635 +G01 X-3.1192 Y0.8635 +G01 X-3.1253 Y0.8635 +G01 X-3.1544 Y0.8729 +G01 X-3.1791 Y0.8909 +G01 X-3.1970 Y0.9156 +G01 X-3.2065 Y0.9447 +G01 X-3.2065 Y0.9507 +G01 X-3.2065 Y1.5724 +G01 X-3.2195 Y1.5854 +G01 X-3.2195 Y1.6346 +G01 X-3.2065 Y1.6476 +G01 X-3.2065 Y1.6807 +G01 X-3.2065 Y1.6820 +G01 X-3.2065 Y1.6992 +G01 X-3.2065 Y1.7053 +G01 X-3.1970 Y1.7344 +G01 X-3.1791 Y1.7591 +G01 X-3.1544 Y1.7770 +G01 X-3.1253 Y1.7865 +G01 X-3.1193 Y1.7865 +G01 X-2.9992 Y1.7865 +G01 X-2.9965 Y1.7865 +G01 X-2.9965 Y1.8507 +G01 X-2.9965 Y1.8540 +G01 X-2.9965 Y1.8692 +G01 X-2.9965 Y1.8753 +G01 X-2.9870 Y1.9044 +G01 X-2.9691 Y1.9291 +G01 X-2.9444 Y1.9470 +G01 X-2.9153 Y1.9565 +G01 X-2.9093 Y1.9565 +G01 X-2.0807 Y1.9565 +G01 X-2.0376 Y1.9565 +G01 X-2.0246 Y1.9695 +G01 X-1.9754 Y1.9695 +G01 X-1.9624 Y1.9565 +G01 X-1.7700 Y1.9565 +G01 X-1.7695 Y1.9565 +G01 X-1.7684 Y1.9569 +G01 X-1.7675 Y1.9575 +G01 X-1.7669 Y1.9584 +G01 X-1.7665 Y1.9595 +G01 X-1.7665 Y1.9600 +G01 X-1.7665 Y1.9653 +G01 X-1.7665 Y1.9692 +G01 X-1.7665 Y2.0692 +G01 X-1.7665 Y2.0753 +G01 X-1.7570 Y2.1044 +G01 X-1.7391 Y2.1291 +G01 X-1.7144 Y2.1470 +G01 X-1.6853 Y2.1565 +G01 X-1.6793 Y2.1565 +G01 X-1.2507 Y2.1565 +G01 X-1.2447 Y2.1565 +G01 X-1.2156 Y2.1470 +G01 X-1.1909 Y2.1291 +G01 X-1.1729 Y2.1044 +G01 X-1.1635 Y2.0753 +G01 X-1.1635 Y2.0693 +G01 X-1.1635 Y2.0597 +G01 X-1.1635 Y2.0507 +G01 X-1.1635 Y1.9100 +G01 X-1.1635 Y1.9095 +G01 X-1.1631 Y1.9084 +G01 X-1.1625 Y1.9075 +G01 X-1.1616 Y1.9069 +G01 X-1.1605 Y1.9065 +G01 X-1.1600 Y1.9065 +G01 X-1.1507 Y1.9065 +G01 X-0.8040 Y1.9065 +G01 X-0.7963 Y1.9143 +G01 X-0.7727 Y1.9240 +G01 X-0.7473 Y1.9240 +G01 X-0.7237 Y1.9143 +G01 X-0.7160 Y1.9065 +G01 X-0.2623 Y1.9065 +G01 X-0.2529 Y1.9065 +G01 X-0.2173 Y1.8949 +G01 X-0.1870 Y1.8730 +G01 X-0.1743 Y1.8554 +G01 X-0.1184 Y1.8554 +G01 X-0.0938 Y1.8452 +G01 X-0.0750 Y1.8264 +G01 X-0.0648 Y1.8018 +G01 X-0.0648 Y1.7751 +G01 X-0.0750 Y1.7505 +G01 X-0.0938 Y1.7316 +G01 X-0.1184 Y1.7214 +G01 X-0.2816 Y1.7214 +G01 X-0.3062 Y1.7316 +G01 X-0.3250 Y1.7505 +G01 X-0.3352 Y1.7751 +G01 X-0.3352 Y1.8018 +G01 X-0.3304 Y1.8135 +G01 X-0.7160 Y1.8135 +G01 X-0.7230 Y1.8065 +G01 X-0.6507 Y1.8065 +G01 X-0.6428 Y1.8065 +G01 X-0.6110 Y1.7933 +G01 X-0.5867 Y1.7690 +G01 X-0.5735 Y1.7372 +G01 X-0.5735 Y1.7292 +G01 X-0.5735 Y1.6500 +G01 X-0.5735 Y1.6494 +G01 X-0.5731 Y1.6484 +G01 X-0.5725 Y1.6475 +G01 X-0.5716 Y1.6469 +G01 X-0.5705 Y1.6465 +G01 X-0.5700 Y1.6465 +G01 X-0.5607 Y1.6465 +G01 X-0.3081 Y1.6465 +G01 X-0.3062 Y1.6484 +G01 X-0.2816 Y1.6586 +G01 X-0.1184 Y1.6586 +G01 X-0.0938 Y1.6484 +G01 X-0.0750 Y1.6295 +G01 X-0.0648 Y1.6049 +G01 X-0.0648 Y1.5782 +G01 X-0.0750 Y1.5536 +G01 X-0.0938 Y1.5348 +G01 X-0.1184 Y1.5246 +G01 X-0.2816 Y1.5246 +G01 X-0.3062 Y1.5348 +G01 X-0.3249 Y1.5535 +G01 X-0.5607 Y1.5535 +G01 X-0.5700 Y1.5535 +G01 X-0.5732 Y1.5535 +G01 X-0.5792 Y1.5535 +G01 X-0.5853 Y1.5535 +G01 X-0.6144 Y1.5629 +G01 X-0.6391 Y1.5809 +G01 X-0.6570 Y1.6056 +G01 X-0.6665 Y1.6347 +G01 X-0.6665 Y1.6407 +G01 X-0.6665 Y1.7135 +G01 X-0.7455 Y1.7135 +G01 X-0.7256 Y1.7070 +G01 X-0.7009 Y1.6891 +G01 X-0.6829 Y1.6644 +G01 X-0.6735 Y1.6353 +G01 X-0.6735 Y1.6293 +G01 X-0.6735 Y1.6205 +G01 X-0.6735 Y1.6200 +G01 X-0.6735 Y1.6107 +G01 X-0.6735 Y1.5476 +G01 X-0.6605 Y1.5346 +G01 X-0.6605 Y1.4854 +G01 X-0.6894 Y1.4565 +G01 X-0.5992 Y1.4565 +G01 X-0.5900 Y1.4565 +G01 X-0.5869 Y1.4565 +G01 X-0.5807 Y1.4565 +G01 X-0.5747 Y1.4565 +G01 X-0.5456 Y1.4470 +G01 X-0.5209 Y1.4291 +G01 X-0.5029 Y1.4044 +G01 X-0.4935 Y1.3753 +G01 X-0.4935 Y1.3693 +G01 X-0.4935 Y1.3584 +G01 X-0.4935 Y1.3579 +G01 X-0.4931 Y1.3568 +G01 X-0.4925 Y1.3559 +G01 X-0.4916 Y1.3553 +G01 X-0.4905 Y1.3550 +G01 X-0.4900 Y1.3549 +G01 X-0.4823 Y1.3549 +G01 X-0.4807 Y1.3549 +G01 X-0.3165 Y1.3549 +G01 X-0.3062 Y1.3652 +G01 X-0.2816 Y1.3754 +G00 Z0.1000 +G00 X-2.3898 Y1.7804 +G01 Z-0.0070 F10 +G01 X-2.3899 Y1.7805 F20 +G01 X-2.3900 Y1.7805 +G01 X-2.3921 Y1.7805 +G01 X-2.3900 Y1.7784 +G01 X-2.3895 Y1.7789 +G01 X-2.3895 Y1.7800 +G01 X-2.3896 Y1.7802 +G01 X-2.3896 Y1.7804 +G01 X-2.3898 Y1.7804 +G00 Z0.1000 +G00 X-1.8500 Y1.2746 +G01 Z-0.0070 F10 +G01 X-1.8646 Y1.2600 F20 +G01 X-1.8541 Y1.2495 +G01 X-1.8195 Y1.2495 +G01 X-1.8195 Y1.2605 +G01 X-1.8198 Y1.2605 +G01 X-1.8380 Y1.2680 +G01 X-1.8484 Y1.2784 +G01 X-1.8500 Y1.2746 +G00 Z0.1000 +G00 X-1.3726 Y0.3895 +G01 Z-0.0070 F10 +G01 X-1.3198 Y0.3895 F20 +G01 X-1.3001 Y0.3895 +G01 X-0.8189 Y0.3895 +G01 X-0.8179 Y0.3905 +G01 X-1.3736 Y0.3905 +G01 X-1.3726 Y0.3895 +G00 Z0.1000 +G00 X-0.8425 Y0.5141 +G01 Z-0.0070 F10 +G01 X-0.8425 Y0.5659 F20 +G01 X-0.8295 Y0.5789 +G01 X-0.8295 Y0.8600 +G01 X-0.8296 Y0.8602 +G01 X-0.8296 Y0.8604 +G01 X-0.8298 Y0.8604 +G01 X-0.8299 Y0.8605 +G01 X-0.8369 Y0.8605 +G01 X-0.8398 Y0.8605 +G01 X-0.8541 Y0.8605 +G01 X-0.8546 Y0.8600 +G01 X-0.8400 Y0.8454 +G01 X-0.8305 Y0.8224 +G01 X-0.8305 Y0.7976 +G01 X-0.8400 Y0.7746 +G01 X-0.8576 Y0.7570 +G01 X-0.8806 Y0.7475 +G01 X-1.0194 Y0.7475 +G01 X-1.0424 Y0.7570 +G01 X-1.0459 Y0.7605 +G01 X-1.0598 Y0.7605 +G01 X-1.0658 Y0.7605 +G01 X-1.0957 Y0.7702 +G01 X-1.1212 Y0.7888 +G01 X-1.1305 Y0.8015 +G01 X-1.1305 Y0.7976 +G01 X-1.1400 Y0.7746 +G01 X-1.1576 Y0.7570 +G01 X-1.1806 Y0.7475 +G01 X-1.3194 Y0.7475 +G01 X-1.3424 Y0.7570 +G01 X-1.3459 Y0.7605 +G01 X-1.3921 Y0.7605 +G01 X-1.3675 Y0.7359 +G01 X-1.3675 Y0.6841 +G01 X-1.3805 Y0.6711 +G01 X-1.3805 Y0.5574 +G01 X-1.3619 Y0.5388 +G01 X-1.3515 Y0.5136 +G01 X-1.3515 Y0.4895 +G01 X-0.8179 Y0.4895 +G01 X-0.8425 Y0.5141 +G00 Z0.1000 +G00 X-2.6959 Y1.3125 +G01 Z-0.0070 F10 +G01 X-2.6441 Y1.3125 F20 +G01 X-2.6075 Y1.2759 +G01 X-2.6075 Y1.2241 +G01 X-2.6441 Y1.1875 +G01 X-2.6763 Y1.1875 +G01 X-2.6999 Y1.1828 +G01 X-2.7333 Y1.1894 +G01 X-2.7350 Y1.1905 +G01 X-2.9221 Y1.1905 +G01 X-2.8875 Y1.1559 +G01 X-2.8875 Y1.1041 +G01 X-2.9005 Y1.0911 +G01 X-2.9005 Y1.0600 +G01 X-2.9004 Y1.0598 +G01 X-2.9004 Y1.0596 +G01 X-2.9002 Y1.0596 +G01 X-2.9001 Y1.0595 +G01 X-2.8986 Y1.0595 +G01 X-2.8901 Y1.0595 +G01 X-2.3559 Y1.0595 +G01 X-2.3554 Y1.0600 +G01 X-2.3700 Y1.0746 +G01 X-2.3795 Y1.0976 +G01 X-2.3795 Y1.1224 +G01 X-2.3700 Y1.1454 +G01 X-2.3554 Y1.1600 +G01 X-2.3559 Y1.1605 +G01 X-2.4601 Y1.1605 +G01 X-2.4615 Y1.1605 +G01 X-2.4798 Y1.1605 +G01 X-2.4858 Y1.1605 +G01 X-2.5157 Y1.1702 +G01 X-2.5412 Y1.1888 +G01 X-2.5598 Y1.2143 +G01 X-2.5695 Y1.2442 +G01 X-2.5695 Y1.2501 +G01 X-2.5695 Y1.3905 +G01 X-2.8547 Y1.3905 +G01 X-2.8620 Y1.3832 +G01 X-2.8867 Y1.3730 +G01 X-2.9046 Y1.3730 +G01 X-2.8875 Y1.3559 +G01 X-2.8875 Y1.3041 +G01 X-2.9021 Y1.2895 +G01 X-2.7249 Y1.2895 +G01 X-2.7201 Y1.2905 +G01 X-2.7183 Y1.2901 +G01 X-2.6959 Y1.3125 +G00 Z0.1000 +G00 X-2.6341 Y1.5475 +G01 Z-0.0070 F10 +G01 X-2.6859 Y1.5475 F20 +G01 X-2.7225 Y1.5841 +G01 X-2.7225 Y1.6359 +G01 X-2.6984 Y1.6600 +G01 X-2.7089 Y1.6705 +G01 X-2.7300 Y1.6705 +G01 X-2.7302 Y1.6704 +G01 X-2.7304 Y1.6704 +G01 X-2.7304 Y1.6702 +G01 X-2.7305 Y1.6701 +G01 X-2.7305 Y1.6614 +G01 X-2.7305 Y1.6601 +G01 X-2.7305 Y1.5901 +G01 X-2.7305 Y1.5858 +G01 X-2.7393 Y1.5589 +G01 X-2.7559 Y1.5359 +G01 X-2.7789 Y1.5193 +G01 X-2.8058 Y1.5105 +G01 X-2.8101 Y1.5105 +G01 X-2.8200 Y1.5105 +G01 X-2.8298 Y1.5105 +G01 X-2.9405 Y1.5105 +G01 X-2.9405 Y1.4942 +G01 X-2.9379 Y1.4968 +G01 X-2.9133 Y1.5070 +G01 X-2.8867 Y1.5070 +G01 X-2.8620 Y1.4968 +G01 X-2.8547 Y1.4895 +G01 X-2.5695 Y1.4895 +G01 X-2.5695 Y1.5605 +G01 X-2.6211 Y1.5605 +G01 X-2.6341 Y1.5475 +G00 Z0.1000 +G00 X-2.4705 Y1.4498 +G01 Z-0.0070 F10 +G01 X-2.4705 Y1.4301 F20 +G01 X-2.4705 Y1.2600 +G01 X-2.4704 Y1.2598 +G01 X-2.4704 Y1.2596 +G01 X-2.4702 Y1.2596 +G01 X-2.4701 Y1.2595 +G01 X-2.4615 Y1.2595 +G01 X-2.4601 Y1.2595 +G01 X-2.3559 Y1.2595 +G01 X-2.3554 Y1.2600 +G01 X-2.3700 Y1.2746 +G01 X-2.3795 Y1.2976 +G01 X-2.3795 Y1.3224 +G01 X-2.3700 Y1.3454 +G01 X-2.3524 Y1.3630 +G01 X-2.3294 Y1.3725 +G01 X-2.1906 Y1.3725 +G01 X-2.1676 Y1.3630 +G01 X-2.1641 Y1.3595 +G01 X-2.1398 Y1.3595 +G01 X-2.1300 Y1.3595 +G01 X-2.1273 Y1.3595 +G01 X-2.1201 Y1.3595 +G01 X-2.1162 Y1.3595 +G01 X-2.0906 Y1.3489 +G01 X-2.0750 Y1.3333 +G01 X-2.0700 Y1.3454 +G01 X-2.0524 Y1.3630 +G01 X-2.0294 Y1.3725 +G01 X-2.0095 Y1.3725 +G01 X-2.0095 Y1.4101 +G01 X-2.0095 Y1.4157 +G01 X-2.0143 Y1.4205 +G01 X-2.0198 Y1.4205 +G01 X-2.1657 Y1.4205 +G01 X-2.1825 Y1.4037 +G01 X-2.2375 Y1.4037 +G01 X-2.2395 Y1.4057 +G01 X-2.2722 Y1.3730 +G01 X-2.3277 Y1.3730 +G01 X-2.3670 Y1.4122 +G01 X-2.3670 Y1.4677 +G01 X-2.3277 Y1.5070 +G01 X-2.2722 Y1.5070 +G01 X-2.2695 Y1.5043 +G01 X-2.2433 Y1.5305 +G01 X-2.3301 Y1.5305 +G01 X-2.3318 Y1.5305 +G01 X-2.3498 Y1.5305 +G01 X-2.3558 Y1.5305 +G01 X-2.3857 Y1.5402 +G01 X-2.4112 Y1.5588 +G01 X-2.4298 Y1.5843 +G01 X-2.4395 Y1.6142 +G01 X-2.4395 Y1.6201 +G01 X-2.4395 Y1.6261 +G01 X-2.4505 Y1.6371 +G01 X-2.4505 Y1.6001 +G01 X-2.4580 Y1.5820 +G01 X-2.4705 Y1.5695 +G01 X-2.4705 Y1.4498 +G00 Z0.1000 +G00 X-2.5201 Y1.7805 +G01 Z-0.0070 F10 +G01 X-2.5300 Y1.7805 F20 +G01 X-2.5301 Y1.7805 +G01 X-2.5302 Y1.7804 +G01 X-2.5304 Y1.7804 +G01 X-2.5304 Y1.7802 +G01 X-2.5305 Y1.7801 +G01 X-2.5305 Y1.7798 +G01 X-2.5305 Y1.7782 +G01 X-2.5305 Y1.7619 +G01 X-2.5150 Y1.7774 +G01 X-2.5075 Y1.7805 +G01 X-2.5201 Y1.7805 +G00 Z0.1000 +G00 X-2.5588 Y1.6988 +G01 Z-0.0070 F10 +G01 X-2.5588 Y1.6988 F20 +G01 X-2.5843 Y1.6802 +G01 X-2.6142 Y1.6705 +G01 X-2.6201 Y1.6705 +G01 X-2.6311 Y1.6705 +G01 X-2.6316 Y1.6700 +G01 X-2.6211 Y1.6595 +G01 X-2.5495 Y1.6595 +G01 X-2.5495 Y1.7001 +G01 X-2.5495 Y1.7044 +G01 X-2.5495 Y1.7115 +G01 X-2.5588 Y1.6988 +G00 Z0.1000 +G00 X-2.1657 Y1.5195 +G01 Z-0.0070 F10 +G01 X-2.0198 Y1.5195 F20 +G01 X-2.0143 Y1.5195 +G01 X-2.0033 Y1.5305 +G01 X-2.1767 Y1.5305 +G01 X-2.1657 Y1.5195 +G00 Z0.1000 +G00 X-1.9037 Y1.4975 +G01 Z-0.0070 F10 +G01 X-1.9037 Y1.4425 F20 +G01 X-1.9105 Y1.4357 +G01 X-1.9105 Y1.4200 +G01 X-1.9105 Y1.4101 +G01 X-1.9105 Y1.3725 +G01 X-1.8906 Y1.3725 +G01 X-1.8676 Y1.3630 +G01 X-1.8595 Y1.3549 +G01 X-1.8595 Y1.5301 +G01 X-1.8595 Y1.5305 +G01 X-1.9367 Y1.5305 +G01 X-1.9037 Y1.4975 +G00 Z0.1000 +G00 X-1.8322 Y1.6295 +G01 Z-0.0070 F10 +G01 X-1.8322 Y1.6295 F20 +G01 X-1.7993 Y1.6159 +G01 X-1.7741 Y1.5907 +G01 X-1.7605 Y1.5578 +G01 X-1.7605 Y1.5499 +G01 X-1.7605 Y1.5400 +G01 X-1.7605 Y1.5302 +G01 X-1.7605 Y1.3595 +G01 X-1.7601 Y1.3595 +G01 X-1.6498 Y1.3595 +G01 X-1.6301 Y1.3595 +G01 X-1.5474 Y1.3595 +G01 X-1.5388 Y1.3681 +G01 X-1.5136 Y1.3785 +G01 X-1.4864 Y1.3785 +G01 X-1.4612 Y1.3681 +G01 X-1.4595 Y1.3664 +G01 X-1.4595 Y1.4001 +G01 X-1.4595 Y1.4100 +G01 X-1.4596 Y1.4102 +G01 X-1.4596 Y1.4104 +G01 X-1.4598 Y1.4104 +G01 X-1.4599 Y1.4105 +G01 X-1.6501 Y1.4105 +G01 X-1.6517 Y1.4105 +G01 X-1.6698 Y1.4105 +G01 X-1.6758 Y1.4105 +G01 X-1.7057 Y1.4202 +G01 X-1.7312 Y1.4388 +G01 X-1.7498 Y1.4643 +G01 X-1.7595 Y1.4942 +G01 X-1.7595 Y1.5001 +G01 X-1.7595 Y1.6375 +G01 X-1.7959 Y1.6375 +G01 X-1.8089 Y1.6505 +G01 X-2.0301 Y1.6505 +G01 X-2.0400 Y1.6505 +G01 X-2.0558 Y1.6505 +G01 X-2.0857 Y1.6602 +G01 X-2.1112 Y1.6788 +G01 X-2.1298 Y1.7043 +G01 X-2.1395 Y1.7342 +G01 X-2.1395 Y1.7500 +G01 X-2.1395 Y1.7598 +G01 X-2.1395 Y1.8605 +G01 X-2.3315 Y1.8605 +G01 X-2.3188 Y1.8512 +G01 X-2.3002 Y1.8257 +G01 X-2.2905 Y1.7958 +G01 X-2.2905 Y1.7898 +G01 X-2.2905 Y1.7895 +G01 X-2.2543 Y1.7895 +G01 X-2.2375 Y1.8063 +G01 X-2.1825 Y1.8063 +G01 X-2.1437 Y1.7675 +G01 X-2.1437 Y1.7125 +G01 X-2.1825 Y1.6737 +G01 X-2.2375 Y1.6737 +G01 X-2.2543 Y1.6905 +G01 X-2.3011 Y1.6905 +G01 X-2.3141 Y1.6775 +G01 X-2.3275 Y1.6775 +G01 X-2.3275 Y1.6391 +G01 X-2.3371 Y1.6295 +G01 X-2.3318 Y1.6295 +G01 X-2.3301 Y1.6295 +G01 X-1.8401 Y1.6295 +G01 X-1.8322 Y1.6295 +G00 Z0.1000 +G00 X-3.0125 Y1.1041 +G01 Z-0.0070 F10 +G01 X-3.0125 Y1.1559 F20 +G01 X-2.9779 Y1.1905 +G01 X-3.0101 Y1.1905 +G01 X-3.0186 Y1.1905 +G01 X-3.0200 Y1.1905 +G01 X-3.0358 Y1.1905 +G01 X-3.0657 Y1.2002 +G01 X-3.0912 Y1.2188 +G01 X-3.1098 Y1.2443 +G01 X-3.1105 Y1.2466 +G01 X-3.1105 Y0.9600 +G01 X-3.1104 Y0.9598 +G01 X-3.1104 Y0.9596 +G01 X-3.1102 Y0.9596 +G01 X-3.1101 Y0.9595 +G01 X-3.1029 Y0.9595 +G01 X-3.1001 Y0.9595 +G01 X-2.5543 Y0.9595 +G01 X-2.5533 Y0.9605 +G01 X-2.8901 Y0.9605 +G01 X-2.8986 Y0.9605 +G01 X-2.9000 Y0.9605 +G01 X-2.9158 Y0.9605 +G01 X-2.9457 Y0.9702 +G01 X-2.9712 Y0.9888 +G01 X-2.9898 Y1.0143 +G01 X-2.9995 Y1.0442 +G01 X-2.9995 Y1.0501 +G01 X-2.9995 Y1.0911 +G01 X-3.0125 Y1.1041 +G00 Z0.1000 +G00 X-2.4657 Y0.9595 +G01 Z-0.0070 F10 +G01 X-2.3549 Y0.9595 F20 +G01 X-2.3559 Y0.9605 +G01 X-2.4667 Y0.9605 +G01 X-2.4657 Y0.9595 +G00 Z0.1000 +G00 X-2.9195 Y1.7248 +G01 Z-0.0070 F10 +G01 X-2.9259 Y1.7159 F20 +G01 X-2.9259 Y1.7159 +G01 X-2.9485 Y1.6995 +G01 X-2.9195 Y1.6995 +G01 X-2.9195 Y1.7248 +G00 Z0.1000 +G00 X-3.0204 Y1.2898 +G01 Z-0.0070 F10 +G01 X-3.0204 Y1.2896 F20 +G01 X-3.0202 Y1.2896 +G01 X-3.0201 Y1.2895 +G01 X-3.0186 Y1.2895 +G01 X-3.0101 Y1.2895 +G01 X-2.9979 Y1.2895 +G01 X-3.0125 Y1.3041 +G01 X-3.0125 Y1.3048 +G01 X-3.0141 Y1.3059 +G01 X-3.0205 Y1.3148 +G01 X-3.0205 Y1.2998 +G01 X-3.0205 Y1.2900 +G01 X-3.0204 Y1.2898 +G00 Z0.1000 +G00 X-3.0050 Y1.5974 +G01 Z-0.0070 F10 +G01 X-3.0050 Y1.5974 F20 +G01 X-2.9975 Y1.6005 +G01 X-3.0200 Y1.6005 +G01 X-3.0202 Y1.6004 +G01 X-3.0204 Y1.6004 +G01 X-3.0204 Y1.6002 +G01 X-3.0205 Y1.6001 +G01 X-3.0205 Y1.5901 +G01 X-3.0205 Y1.5819 +G01 X-3.0050 Y1.5974 +G00 Z0.1000 +G00 X-3.1100 Y1.6905 +G01 Z-0.0070 F10 +G01 X-3.1101 Y1.6905 F20 +G01 X-3.1102 Y1.6904 +G01 X-3.1104 Y1.6904 +G01 X-3.1104 Y1.6902 +G01 X-3.1105 Y1.6901 +G01 X-3.1105 Y1.6814 +G01 X-3.1105 Y1.6801 +G01 X-3.1105 Y1.6489 +G01 X-3.1087 Y1.6471 +G01 X-3.0912 Y1.6712 +G01 X-3.0657 Y1.6898 +G01 X-3.0634 Y1.6905 +G01 X-3.1100 Y1.6905 +G00 Z0.1000 +G00 X-2.8298 Y1.6095 +G01 Z-0.0070 F10 +G01 X-2.8295 Y1.6095 F20 +G01 X-2.8295 Y1.6425 +G01 X-2.8326 Y1.6350 +G01 X-2.8550 Y1.6126 +G01 X-2.8625 Y1.6095 +G01 X-2.8298 Y1.6095 +G00 Z0.1000 +G00 X-2.8198 Y1.7157 +G01 Z-0.0070 F10 +G01 X-2.8198 Y1.7157 F20 +G01 X-2.8012 Y1.7412 +G01 X-2.7757 Y1.7598 +G01 X-2.7458 Y1.7695 +G01 X-2.7398 Y1.7695 +G01 X-2.7089 Y1.7695 +G01 X-2.7084 Y1.7700 +G01 X-2.7089 Y1.7705 +G01 X-2.8101 Y1.7705 +G01 X-2.8200 Y1.7705 +G01 X-2.8202 Y1.7704 +G01 X-2.8204 Y1.7704 +G01 X-2.8204 Y1.7702 +G01 X-2.8205 Y1.7701 +G01 X-2.8205 Y1.7134 +G01 X-2.8198 Y1.7157 +G00 Z0.1000 +G00 X-2.9000 Y1.8605 +G01 Z-0.0070 F10 +G01 X-2.9001 Y1.8605 F20 +G01 X-2.9002 Y1.8604 +G01 X-2.9004 Y1.8604 +G01 X-2.9004 Y1.8602 +G01 X-2.9005 Y1.8601 +G01 X-2.9005 Y1.8528 +G01 X-2.9005 Y1.8501 +G01 X-2.9005 Y1.8285 +G01 X-2.8912 Y1.8412 +G01 X-2.8657 Y1.8598 +G01 X-2.8634 Y1.8605 +G01 X-2.9000 Y1.8605 +G00 Z0.1000 +G00 X-2.0775 Y0.2859 +G01 Z-0.0070 F10 +G01 X-2.0775 Y0.2760 F20 +G01 X-2.0681 Y0.2988 +G01 X-2.0587 Y0.3081 +G01 X-2.0498 Y0.3357 +G01 X-2.0312 Y0.3612 +G01 X-2.0057 Y0.3798 +G01 X-1.9758 Y0.3895 +G01 X-1.9600 Y0.3895 +G01 X-1.9501 Y0.3895 +G01 X-1.8695 Y0.3895 +G01 X-1.8695 Y0.4517 +G01 X-1.8957 Y0.4602 +G01 X-1.9212 Y0.4788 +G01 X-1.9398 Y0.5043 +G01 X-1.9454 Y0.5216 +G01 X-1.9663 Y0.5425 +G01 X-1.9663 Y0.5975 +G01 X-1.9533 Y0.6105 +G01 X-1.9626 Y0.6105 +G01 X-1.9712 Y0.6019 +G01 X-1.9964 Y0.5915 +G01 X-2.0236 Y0.5915 +G01 X-2.0488 Y0.6019 +G01 X-2.0574 Y0.6105 +G01 X-2.0900 Y0.6105 +G01 X-2.0902 Y0.6104 +G01 X-2.0904 Y0.6104 +G01 X-2.0904 Y0.6102 +G01 X-2.0905 Y0.6101 +G01 X-2.0905 Y0.6001 +G01 X-2.0905 Y0.2989 +G01 X-2.0775 Y0.2859 +G00 Z0.1000 +G00 X-2.1798 Y0.6557 +G01 Z-0.0070 F10 +G01 X-2.1612 Y0.6812 F20 +G01 X-2.1612 Y0.6812 +G01 X-2.1357 Y0.6998 +G01 X-2.1334 Y0.7005 +G01 X-2.1801 Y0.7005 +G01 X-2.1805 Y0.7005 +G01 X-2.1805 Y0.6534 +G01 X-2.1798 Y0.6557 +G00 Z0.1000 +G00 X-2.4437 Y0.4875 +G01 Z-0.0070 F10 +G01 X-2.4437 Y0.4325 F20 +G01 X-2.4505 Y0.4257 +G01 X-2.4505 Y0.2718 +G01 X-2.4505 Y0.1995 +G01 X-2.4496 Y0.1995 +G01 X-2.4482 Y0.1995 +G01 X-2.1679 Y0.1995 +G01 X-2.2025 Y0.2341 +G01 X-2.2025 Y0.2859 +G01 X-2.1895 Y0.2989 +G01 X-2.1895 Y0.5485 +G01 X-2.2059 Y0.5259 +G01 X-2.2289 Y0.5093 +G01 X-2.2558 Y0.5005 +G01 X-2.2601 Y0.5005 +G01 X-2.4567 Y0.5005 +G01 X-2.4437 Y0.4875 +G00 Z0.1000 +G00 X-1.6998 Y1.0595 +G01 Z-0.0070 F10 +G01 X-1.6899 Y1.0595 F20 +G01 X-1.6801 Y1.0595 +G01 X-1.3459 Y1.0595 +G01 X-1.3454 Y1.0600 +G01 X-1.3459 Y1.0605 +G01 X-1.7605 Y1.0605 +G01 X-1.7605 Y1.0252 +G01 X-1.7541 Y1.0341 +G01 X-1.7311 Y1.0507 +G01 X-1.7042 Y1.0595 +G01 X-1.6998 Y1.0595 +G00 Z0.1000 +G00 X-1.7888 Y0.8088 +G01 Z-0.0070 F10 +G01 X-1.7888 Y0.8088 F20 +G01 X-1.8015 Y0.7995 +G01 X-1.7800 Y0.7995 +G01 X-1.7798 Y0.7996 +G01 X-1.7796 Y0.7996 +G01 X-1.7796 Y0.7998 +G01 X-1.7795 Y0.7999 +G01 X-1.7795 Y0.8215 +G01 X-1.7888 Y0.8088 +G00 Z0.1000 +G00 X-1.5001 Y0.7605 +G01 Z-0.0070 F10 +G01 X-1.5002 Y0.7604 F20 +G01 X-1.5004 Y0.7604 +G01 X-1.5004 Y0.7602 +G01 X-1.5005 Y0.7601 +G01 X-1.5005 Y0.7519 +G01 X-1.5005 Y0.7501 +G01 X-1.5005 Y0.6989 +G01 X-1.4925 Y0.6909 +G01 X-1.4925 Y0.7359 +G01 X-1.4679 Y0.7605 +G01 X-1.5000 Y0.7605 +G00 Z0.1000 +G00 X-1.4925 Y1.1841 +G01 Z-0.0070 F10 +G01 X-1.4925 Y1.2359 F20 +G01 X-1.4869 Y1.2415 +G01 X-1.5136 Y1.2415 +G01 X-1.5388 Y1.2519 +G01 X-1.5474 Y1.2605 +G01 X-1.5737 Y1.2605 +G01 X-1.5737 Y1.2425 +G01 X-1.6125 Y1.2037 +G01 X-1.6675 Y1.2037 +G01 X-1.7063 Y1.2425 +G01 X-1.7063 Y1.2605 +G01 X-1.7205 Y1.2605 +G01 X-1.7205 Y1.2389 +G01 X-1.7075 Y1.2259 +G01 X-1.7075 Y1.1741 +G01 X-1.7221 Y1.1595 +G01 X-1.4679 Y1.1595 +G01 X-1.4925 Y1.1841 +G00 Z0.1000 +G00 X-1.3454 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.3600 Y1.1746 F20 +G01 X-1.3675 Y1.1928 +G01 X-1.3675 Y1.1841 +G01 X-1.3921 Y1.1595 +G01 X-1.3459 Y1.1595 +G01 X-1.3454 Y1.1600 +G00 Z0.1000 +G00 X-1.8641 Y1.0605 +G01 Z-0.0070 F10 +G01 X-1.8646 Y1.0600 F20 +G01 X-1.8595 Y1.0549 +G01 X-1.8595 Y1.0605 +G01 X-1.8641 Y1.0605 +G00 Z0.1000 +G00 X-1.8595 Y0.9651 +G01 Z-0.0070 F10 +G01 X-1.8676 Y0.9570 F20 +G01 X-1.8906 Y0.9475 +G01 X-2.0294 Y0.9475 +G01 X-2.0524 Y0.9570 +G01 X-2.0559 Y0.9605 +G01 X-2.0605 Y0.9605 +G01 X-2.0605 Y0.9501 +G01 X-2.0605 Y0.9442 +G01 X-2.0702 Y0.9143 +G01 X-2.0888 Y0.8888 +G01 X-2.1015 Y0.8795 +G01 X-1.8600 Y0.8795 +G01 X-1.8598 Y0.8796 +G01 X-1.8596 Y0.8796 +G01 X-1.8596 Y0.8798 +G01 X-1.8595 Y0.8799 +G01 X-1.8595 Y0.9651 +G00 Z0.1000 +G00 X-1.3557 Y1.7202 +G01 Z-0.0070 F10 +G01 X-1.3557 Y1.7202 F20 +G01 X-1.3812 Y1.7388 +G01 X-1.3998 Y1.7643 +G01 X-1.4095 Y1.7942 +G01 X-1.4095 Y1.8001 +G01 X-1.4095 Y1.8147 +G01 X-1.4270 Y1.8322 +G01 X-1.4270 Y1.8877 +G01 X-1.4095 Y1.9052 +G01 X-1.4095 Y1.9600 +G01 X-1.4096 Y1.9602 +G01 X-1.4096 Y1.9604 +G01 X-1.4098 Y1.9604 +G01 X-1.4099 Y1.9605 +G01 X-1.4621 Y1.9605 +G01 X-1.4375 Y1.9359 +G01 X-1.4375 Y1.8841 +G01 X-1.4505 Y1.8711 +G01 X-1.4505 Y1.7574 +G01 X-1.4419 Y1.7488 +G01 X-1.4315 Y1.7236 +G01 X-1.4315 Y1.7195 +G01 X-1.3534 Y1.7195 +G01 X-1.3557 Y1.7202 +G00 Z0.1000 +G00 X-1.5388 Y1.6519 +G01 Z-0.0070 F10 +G01 X-1.5581 Y1.6712 F20 +G01 X-1.5685 Y1.6964 +G01 X-1.5685 Y1.7236 +G01 X-1.5581 Y1.7488 +G01 X-1.5495 Y1.7574 +G01 X-1.5495 Y1.8711 +G01 X-1.5625 Y1.8841 +G01 X-1.5625 Y1.9359 +G01 X-1.5379 Y1.9605 +G01 X-1.5601 Y1.9605 +G01 X-1.5700 Y1.9605 +G01 X-1.5702 Y1.9604 +G01 X-1.5704 Y1.9604 +G01 X-1.5704 Y1.9602 +G01 X-1.5705 Y1.9601 +G01 X-1.5705 Y1.7998 +G01 X-1.5705 Y1.7701 +G01 X-1.5705 Y1.6398 +G01 X-1.5705 Y1.6300 +G01 X-1.5704 Y1.6298 +G01 X-1.5704 Y1.6296 +G01 X-1.5702 Y1.6296 +G01 X-1.5701 Y1.6295 +G01 X-1.5681 Y1.6295 +G01 X-1.5601 Y1.6295 +G01 X-1.4964 Y1.6295 +G01 X-1.5149 Y1.6401 +G01 X-1.5178 Y1.6432 +G01 X-1.5388 Y1.6519 +G00 Z0.1000 +G00 X-0.8546 Y0.9600 +G01 Z-0.0070 F10 +G01 X-0.8541 Y0.9595 F20 +G01 X-0.8398 Y0.9595 +G01 X-0.8368 Y0.9595 +G01 X-0.8201 Y0.9595 +G01 X-0.8142 Y0.9595 +G01 X-0.7843 Y0.9498 +G01 X-0.7588 Y0.9312 +G01 X-0.7402 Y0.9057 +G01 X-0.7305 Y0.8758 +G01 X-0.7305 Y0.8698 +G01 X-0.7305 Y0.5789 +G01 X-0.7175 Y0.5659 +G01 X-0.7175 Y0.5141 +G01 X-0.7421 Y0.4895 +G01 X-0.6100 Y0.4895 +G01 X-0.6098 Y0.4896 +G01 X-0.6096 Y0.4896 +G01 X-0.6096 Y0.4898 +G01 X-0.6095 Y0.4899 +G01 X-0.6095 Y0.8711 +G01 X-0.6225 Y0.8841 +G01 X-0.6225 Y0.9359 +G01 X-0.5979 Y0.9605 +G01 X-0.8541 Y0.9605 +G01 X-0.8546 Y0.9600 +G00 Z0.1000 +G00 X-0.5989 Y1.0605 +G01 Z-0.0070 F10 +G01 X-0.8541 Y1.0605 F20 +G01 X-0.8546 Y1.0600 +G01 X-0.8541 Y1.0595 +G01 X-0.5979 Y1.0595 +G01 X-0.5989 Y1.0605 +G00 Z0.1000 +G00 X-1.6098 Y0.9595 +G01 Z-0.0070 F10 +G01 X-1.6005 Y0.9595 F20 +G01 X-1.6000 Y0.9595 +G01 X-1.5901 Y0.9595 +G01 X-1.3459 Y0.9595 +G01 X-1.3454 Y0.9600 +G01 X-1.3459 Y0.9605 +G01 X-1.6801 Y0.9605 +G01 X-1.6805 Y0.9605 +G01 X-1.6805 Y0.9601 +G01 X-1.6805 Y0.9185 +G01 X-1.6712 Y0.9312 +G01 X-1.6457 Y0.9498 +G01 X-1.6158 Y0.9595 +G01 X-1.6098 Y0.9595 +G00 Z0.1000 +G00 X-1.7088 Y0.7288 +G01 Z-0.0070 F10 +G01 X-1.7088 Y0.7288 F20 +G01 X-1.7213 Y0.7197 +G01 X-1.6995 Y0.6979 +G01 X-1.6995 Y0.7415 +G01 X-1.7088 Y0.7288 +G00 Z0.1000 +G00 X-1.5995 Y0.6989 +G01 Z-0.0070 F10 +G01 X-1.5995 Y0.7501 F20 +G01 X-1.5995 Y0.7519 +G01 X-1.5995 Y0.7698 +G01 X-1.5995 Y0.7758 +G01 X-1.5898 Y0.8057 +G01 X-1.5712 Y0.8312 +G01 X-1.5457 Y0.8498 +G01 X-1.5158 Y0.8595 +G01 X-1.5098 Y0.8595 +G01 X-1.3459 Y0.8595 +G01 X-1.3454 Y0.8600 +G01 X-1.3459 Y0.8605 +G01 X-1.5901 Y0.8605 +G01 X-1.6000 Y0.8605 +G01 X-1.6002 Y0.8604 +G01 X-1.6004 Y0.8604 +G01 X-1.6004 Y0.8602 +G01 X-1.6005 Y0.8601 +G01 X-1.6005 Y0.6979 +G01 X-1.5995 Y0.6989 +G00 Z0.1000 +G00 X-1.2605 Y0.2905 +G01 Z-0.0070 F10 +G01 X-1.2605 Y0.2289 F20 +G01 X-1.2575 Y0.2259 +G01 X-1.2575 Y0.1741 +G01 X-1.2821 Y0.1495 +G01 X-1.1400 Y0.1495 +G01 X-1.1398 Y0.1496 +G01 X-1.1396 Y0.1496 +G01 X-1.1396 Y0.1498 +G01 X-1.1395 Y0.1499 +G01 X-1.1395 Y0.1901 +G01 X-1.1395 Y0.1944 +G01 X-1.1395 Y0.2098 +G01 X-1.1395 Y0.2158 +G01 X-1.1298 Y0.2457 +G01 X-1.1112 Y0.2712 +G01 X-1.0857 Y0.2898 +G01 X-1.0834 Y0.2905 +G01 X-1.2605 Y0.2905 +G00 Z0.1000 +G00 X-1.3825 Y0.1741 +G01 Z-0.0070 F10 +G01 X-1.3825 Y0.2259 F20 +G01 X-1.3595 Y0.2489 +G01 X-1.3595 Y0.2905 +G01 X-1.3726 Y0.2905 +G01 X-1.3812 Y0.2819 +G01 X-1.4064 Y0.2715 +G01 X-1.4336 Y0.2715 +G01 X-1.4588 Y0.2819 +G01 X-1.4781 Y0.3012 +G01 X-1.4885 Y0.3264 +G01 X-1.4885 Y0.3536 +G01 X-1.4781 Y0.3788 +G01 X-1.4588 Y0.3981 +G01 X-1.4336 Y0.4085 +G01 X-1.4271 Y0.4085 +G01 X-1.4412 Y0.4188 +G01 X-1.4577 Y0.4415 +G01 X-1.4588 Y0.4419 +G01 X-1.4781 Y0.4612 +G01 X-1.4885 Y0.4864 +G01 X-1.4885 Y0.5136 +G01 X-1.4795 Y0.5353 +G01 X-1.4795 Y0.6711 +G01 X-1.4875 Y0.6791 +G01 X-1.4875 Y0.6341 +G01 X-1.5241 Y0.5975 +G01 X-1.5759 Y0.5975 +G01 X-1.6005 Y0.6221 +G01 X-1.6005 Y0.1598 +G01 X-1.6005 Y0.1502 +G01 X-1.6005 Y0.1500 +G01 X-1.6004 Y0.1498 +G01 X-1.6004 Y0.1496 +G01 X-1.6002 Y0.1496 +G01 X-1.6001 Y0.1495 +G01 X-1.3579 Y0.1495 +G01 X-1.3825 Y0.1741 +G00 Z0.1000 +G00 X-0.5357 Y1.2687 +G01 Z-0.0070 F10 +G01 X-0.5357 Y1.2687 F20 +G01 X-0.5612 Y1.2872 +G01 X-0.5798 Y1.3127 +G01 X-0.5895 Y1.3427 +G01 X-0.5895 Y1.3486 +G01 X-0.5895 Y1.3501 +G01 X-0.5895 Y1.3600 +G01 X-0.5896 Y1.3602 +G01 X-0.5896 Y1.3604 +G01 X-0.5898 Y1.3604 +G01 X-0.5899 Y1.3605 +G01 X-0.6821 Y1.3605 +G01 X-0.6575 Y1.3359 +G01 X-0.6575 Y1.2841 +G01 X-0.6821 Y1.2595 +G01 X-0.5075 Y1.2595 +G01 X-0.5357 Y1.2687 +G00 Z0.1000 +G00 X-0.7589 Y1.2605 +G01 Z-0.0070 F10 +G01 X-0.8541 Y1.2605 F20 +G01 X-0.8546 Y1.2600 +G01 X-0.8541 Y1.2595 +G01 X-0.7579 Y1.2595 +G01 X-0.7589 Y1.2605 +G00 Z0.1000 +G00 X-0.8546 Y1.1600 +G01 Z-0.0070 F10 +G01 X-0.8541 Y1.1595 F20 +G01 X-0.5989 Y1.1595 +G01 X-0.5979 Y1.1605 +G01 X-0.8541 Y1.1605 +G01 X-0.8546 Y1.1600 +G00 Z0.1000 +G00 X-0.8546 Y1.3600 +G01 Z-0.0070 F10 +G01 X-0.8541 Y1.3595 F20 +G01 X-0.7589 Y1.3595 +G01 X-0.7579 Y1.3605 +G01 X-0.8541 Y1.3605 +G01 X-0.8546 Y1.3600 +G00 Z0.1000 +G00 X-0.7825 Y1.4841 +G01 Z-0.0070 F10 +G01 X-0.7825 Y1.5359 F20 +G01 X-0.7695 Y1.5489 +G01 X-0.7695 Y1.6101 +G01 X-0.7695 Y1.6200 +G01 X-0.7696 Y1.6202 +G01 X-0.7696 Y1.6204 +G01 X-0.7698 Y1.6204 +G01 X-0.7699 Y1.6205 +G01 X-1.1066 Y1.6205 +G01 X-1.1043 Y1.6198 +G01 X-1.0788 Y1.6012 +G01 X-1.0602 Y1.5757 +G01 X-1.0505 Y1.5458 +G01 X-1.0505 Y1.5300 +G01 X-1.0505 Y1.5201 +G01 X-1.0505 Y1.4549 +G01 X-1.0424 Y1.4630 +G01 X-1.0194 Y1.4725 +G01 X-0.8806 Y1.4725 +G01 X-0.8576 Y1.4630 +G01 X-0.8541 Y1.4595 +G01 X-0.7579 Y1.4595 +G01 X-0.7825 Y1.4841 +G00 Z0.1000 +G00 X-2.0595 Y1.0595 +G01 Z-0.0070 F10 +G01 X-2.0559 Y1.0595 F20 +G01 X-2.0554 Y1.0600 +G01 X-2.0605 Y1.0651 +G01 X-2.0605 Y1.0605 +G01 X-2.0595 Y1.0595 +G00 Z0.1000 +G00 X-2.1646 Y1.0600 +G01 Z-0.0070 F10 +G01 X-2.1595 Y1.0549 F20 +G01 X-2.1595 Y1.0651 +G01 X-2.1646 Y1.0600 +G00 Z0.1000 +G00 X-2.1646 Y1.1600 +G01 Z-0.0070 F10 +G01 X-2.1595 Y1.1549 F20 +G01 X-2.1595 Y1.1651 +G01 X-2.1646 Y1.1600 +G00 Z0.1000 +G00 X-2.0554 Y1.1600 +G01 Z-0.0070 F10 +G01 X-2.0605 Y1.1651 F20 +G01 X-2.0605 Y1.1549 +G01 X-2.0554 Y1.1600 +G00 Z0.1000 +G00 X-2.0554 Y1.2600 +G01 Z-0.0070 F10 +G01 X-2.0605 Y1.2651 F20 +G01 X-2.0605 Y1.2549 +G01 X-2.0554 Y1.2600 +G00 Z0.1000 +G00 X-2.1599 Y0.9595 +G01 Z-0.0070 F10 +G01 X-2.1598 Y0.9596 F20 +G01 X-2.1596 Y0.9596 +G01 X-2.1596 Y0.9598 +G01 X-2.1595 Y0.9599 +G01 X-2.1595 Y0.9651 +G01 X-2.1651 Y0.9595 +G01 X-2.1600 Y0.9595 +G00 Z0.1000 +G00 X-2.1646 Y1.2600 +G01 Z-0.0070 F10 +G01 X-2.1595 Y1.2549 F20 +G01 X-2.1595 Y1.2605 +G01 X-2.1641 Y1.2605 +G01 X-2.1646 Y1.2600 +G00 Z0.1000 +G00 X-1.0505 Y0.8599 +G01 Z-0.0070 F10 +G01 X-1.0504 Y0.8598 F20 +G01 X-1.0504 Y0.8596 +G01 X-1.0502 Y0.8596 +G01 X-1.0501 Y0.8595 +G01 X-1.0459 Y0.8595 +G01 X-1.0454 Y0.8600 +G01 X-1.0505 Y0.8651 +G01 X-1.0505 Y0.8600 +G00 Z0.1000 +G00 X-1.1546 Y0.8600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y0.8549 F20 +G01 X-1.1495 Y0.8651 +G01 X-1.1546 Y0.8600 +G00 Z0.1000 +G00 X-1.1546 Y1.3600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y1.3549 F20 +G01 X-1.1495 Y1.3651 +G01 X-1.1546 Y1.3600 +G00 Z0.1000 +G00 X-1.1546 Y1.2600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y1.2549 F20 +G01 X-1.1495 Y1.2651 +G01 X-1.1546 Y1.2600 +G00 Z0.1000 +G00 X-1.1546 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y1.1549 F20 +G01 X-1.1495 Y1.1651 +G01 X-1.1546 Y1.1600 +G00 Z0.1000 +G00 X-1.1546 Y1.0600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y1.0549 F20 +G01 X-1.1495 Y1.0651 +G01 X-1.1546 Y1.0600 +G00 Z0.1000 +G00 X-1.1546 Y0.9600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y0.9549 F20 +G01 X-1.1495 Y0.9651 +G01 X-1.1546 Y0.9600 +G00 Z0.1000 +G00 X-1.0454 Y0.9600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y0.9651 F20 +G01 X-1.0505 Y0.9549 +G01 X-1.0454 Y0.9600 +G00 Z0.1000 +G00 X-1.0454 Y1.0600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y1.0651 F20 +G01 X-1.0505 Y1.0549 +G01 X-1.0454 Y1.0600 +G00 Z0.1000 +G00 X-1.0454 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y1.1651 F20 +G01 X-1.0505 Y1.1549 +G01 X-1.0454 Y1.1600 +G00 Z0.1000 +G00 X-1.0454 Y1.2600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y1.2651 F20 +G01 X-1.0505 Y1.2549 +G01 X-1.0454 Y1.2600 +G00 Z0.1000 +G00 X-1.0454 Y1.3600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y1.3651 F20 +G01 X-1.0505 Y1.3549 +G01 X-1.0454 Y1.3600 +G00 Z0.1000 +G00 X-2.6316 Y1.7700 +G01 Z-0.0070 F10 +G01 X-2.6311 Y1.7695 F20 +G01 X-2.6300 Y1.7695 +G01 X-2.6298 Y1.7696 +G01 X-2.6296 Y1.7696 +G01 X-2.6296 Y1.7698 +G01 X-2.6295 Y1.7699 +G01 X-2.6295 Y1.7721 +G01 X-2.6316 Y1.7700 +G00 Z0.1000 +G00 X-1.6695 Y1.7405 +G01 Z-0.0070 F10 +G01 X-1.7025 Y1.7405 F20 +G01 X-1.6950 Y1.7374 +G01 X-1.6726 Y1.7150 +G01 X-1.6695 Y1.7075 +G01 X-1.6695 Y1.7405 +G00 Z0.1000 +G00 X-1.6605 Y1.5099 +G01 Z-0.0070 F10 +G01 X-1.6604 Y1.5098 F20 +G01 X-1.6604 Y1.5096 +G01 X-1.6602 Y1.5096 +G01 X-1.6601 Y1.5095 +G01 X-1.6517 Y1.5095 +G01 X-1.6501 Y1.5095 +G01 X-1.4501 Y1.5095 +G01 X-1.4442 Y1.5095 +G01 X-1.4143 Y1.4998 +G01 X-1.3888 Y1.4812 +G01 X-1.3730 Y1.4595 +G01 X-1.3600 Y1.4595 +G01 X-1.3501 Y1.4595 +G01 X-1.3459 Y1.4595 +G01 X-1.3424 Y1.4630 +G01 X-1.3194 Y1.4725 +G01 X-1.1806 Y1.4725 +G01 X-1.1576 Y1.4630 +G01 X-1.1495 Y1.4549 +G01 X-1.1495 Y1.5201 +G01 X-1.1495 Y1.5300 +G01 X-1.1496 Y1.5302 +G01 X-1.1496 Y1.5304 +G01 X-1.1498 Y1.5304 +G01 X-1.1499 Y1.5305 +G01 X-1.5601 Y1.5305 +G01 X-1.5681 Y1.5305 +G01 X-1.5798 Y1.5305 +G01 X-1.5858 Y1.5305 +G01 X-1.6157 Y1.5402 +G01 X-1.6412 Y1.5588 +G01 X-1.6598 Y1.5843 +G01 X-1.6605 Y1.5866 +G01 X-1.6605 Y1.5100 +G00 Z0.1000 +G00 X-1.9653 Y1.8563 +G01 Z-0.0070 F10 +G01 X-1.9425 Y1.8563 F20 +G01 X-1.9257 Y1.8395 +G01 X-1.6695 Y1.8395 +G01 X-1.6695 Y1.9698 +G01 X-1.6695 Y1.9758 +G01 X-1.6598 Y2.0057 +G01 X-1.6412 Y2.0312 +G01 X-1.6157 Y2.0498 +G01 X-1.5858 Y2.0595 +G01 X-1.5700 Y2.0595 +G01 X-1.5601 Y2.0595 +G01 X-1.4001 Y2.0595 +G01 X-1.3942 Y2.0595 +G01 X-1.3643 Y2.0498 +G01 X-1.3388 Y2.0312 +G01 X-1.3202 Y2.0057 +G01 X-1.3105 Y1.9758 +G01 X-1.3105 Y1.9698 +G01 X-1.3105 Y1.9052 +G01 X-1.2930 Y1.8877 +G01 X-1.2930 Y1.8322 +G01 X-1.3105 Y1.8147 +G01 X-1.3105 Y1.8100 +G01 X-1.3104 Y1.8098 +G01 X-1.3104 Y1.8096 +G01 X-1.3102 Y1.8096 +G01 X-1.3101 Y1.8095 +G01 X-1.3017 Y1.8095 +G01 X-1.3001 Y1.8095 +G01 X-0.8042 Y1.8095 +G01 X-0.8052 Y1.8105 +G01 X-1.1501 Y1.8105 +G01 X-1.1600 Y1.8105 +G01 X-1.1669 Y1.8105 +G01 X-1.1698 Y1.8105 +G01 X-1.1758 Y1.8105 +G01 X-1.2057 Y1.8202 +G01 X-1.2312 Y1.8388 +G01 X-1.2498 Y1.8643 +G01 X-1.2595 Y1.8942 +G01 X-1.2595 Y1.9001 +G01 X-1.2595 Y2.0600 +G01 X-1.2596 Y2.0602 +G01 X-1.2596 Y2.0604 +G01 X-1.2598 Y2.0604 +G01 X-1.2599 Y2.0605 +G01 X-1.2698 Y2.0605 +G01 X-1.6601 Y2.0605 +G01 X-1.6700 Y2.0605 +G01 X-1.6702 Y2.0604 +G01 X-1.6704 Y2.0604 +G01 X-1.6704 Y2.0602 +G01 X-1.6705 Y2.0601 +G01 X-1.6705 Y1.9698 +G01 X-1.6705 Y1.9666 +G01 X-1.6705 Y1.9501 +G01 X-1.6705 Y1.9442 +G01 X-1.6802 Y1.9143 +G01 X-1.6988 Y1.8888 +G01 X-1.7243 Y1.8702 +G01 X-1.7542 Y1.8605 +G01 X-1.7601 Y1.8605 +G01 X-1.9611 Y1.8605 +G01 X-1.9653 Y1.8563 +G00 Z0.1000 +G00 X-2.0405 Y1.7598 +G01 Z-0.0070 F10 +G01 X-2.0405 Y1.7500 F20 +G01 X-2.0405 Y1.7499 +G01 X-2.0404 Y1.7498 +G01 X-2.0404 Y1.7496 +G01 X-2.0402 Y1.7496 +G01 X-2.0401 Y1.7495 +G01 X-2.0301 Y1.7495 +G01 X-2.0233 Y1.7495 +G01 X-2.0363 Y1.7625 +G01 X-2.0363 Y1.8175 +G01 X-2.0063 Y1.8475 +G01 X-2.0259 Y1.8475 +G01 X-2.0389 Y1.8605 +G01 X-2.0405 Y1.8605 +G01 X-2.0405 Y1.7598 +G00 Z0.1000 +G00 X-1.3600 Y1.2454 +G01 Z-0.0070 F10 +G01 X-1.3454 Y1.2600 F20 +G01 X-1.3600 Y1.2746 +G01 X-1.3605 Y1.2759 +G01 X-1.3605 Y1.2698 +G01 X-1.3605 Y1.2441 +G01 X-1.3600 Y1.2454 +G00 Z0.1000 +G00 X-1.3600 Y1.3454 +G01 Z-0.0070 F10 +G01 X-1.3454 Y1.3600 F20 +G01 X-1.3459 Y1.3605 +G01 X-1.3501 Y1.3605 +G01 X-1.3600 Y1.3605 +G01 X-1.3602 Y1.3604 +G01 X-1.3604 Y1.3604 +G01 X-1.3604 Y1.3602 +G01 X-1.3605 Y1.3601 +G01 X-1.3605 Y1.3441 +G01 X-1.3600 Y1.3454 +G00 Z0.1000 +G00 X-2.0488 Y0.2019 +G01 Z-0.0070 F10 +G01 X-2.0681 Y0.2212 F20 +G01 X-2.0775 Y0.2440 +G01 X-2.0775 Y0.2341 +G01 X-2.1121 Y0.1995 +G01 X-2.0429 Y0.1995 +G01 X-2.0488 Y0.2019 +G00 Z0.1000 +G00 X-2.6075 Y1.8459 +G01 Z-0.0070 F10 +G01 X-2.6075 Y1.8426 F20 +G01 X-2.6012 Y1.8512 +G01 X-2.5885 Y1.8605 +G01 X-2.6221 Y1.8605 +G01 X-2.6075 Y1.8459 +G00 Z0.1000 +G00 X-0.2822 Y1.1816 +G01 Z-0.0070 F10 +G01 X-0.1178 Y1.1816 F20 +G01 X-0.0921 Y1.1709 +G01 X-0.0724 Y1.1512 +G01 X-0.0618 Y1.1255 +G01 X-0.0618 Y1.0976 +G01 X-0.0724 Y1.0719 +G01 X-0.0921 Y1.0522 +G01 X-0.1178 Y1.0416 +G01 X-0.2822 Y1.0416 +G01 X-0.3079 Y1.0522 +G01 X-0.3177 Y1.0621 +G01 X-0.3401 Y1.0621 +G01 X-0.3428 Y1.0621 +G01 X-0.3598 Y1.0621 +G01 X-0.3658 Y1.0621 +G01 X-0.3957 Y1.0718 +G01 X-0.4212 Y1.0903 +G01 X-0.4398 Y1.1158 +G01 X-0.4495 Y1.1458 +G01 X-0.4495 Y1.1517 +G01 X-0.4495 Y1.1601 +G01 X-0.4495 Y1.1605 +G01 X-0.5221 Y1.1605 +G01 X-0.4975 Y1.1359 +G01 X-0.4975 Y1.0841 +G01 X-0.5221 Y1.0595 +G01 X-0.4898 Y1.0595 +G01 X-0.4886 Y1.0595 +G01 X-0.4701 Y1.0595 +G01 X-0.4642 Y1.0595 +G01 X-0.4343 Y1.0498 +G01 X-0.4088 Y1.0312 +G01 X-0.3902 Y1.0057 +G01 X-0.3805 Y0.9758 +G01 X-0.3805 Y0.9698 +G01 X-0.3805 Y0.9598 +G01 X-0.3805 Y0.9595 +G01 X-0.3162 Y0.9595 +G01 X-0.3079 Y0.9678 +G01 X-0.2822 Y0.9784 +G01 X-0.1178 Y0.9784 +G01 X-0.0921 Y0.9678 +G01 X-0.0724 Y0.9481 +G01 X-0.0618 Y0.9223 +G01 X-0.0618 Y0.8945 +G01 X-0.0724 Y0.8688 +G01 X-0.0921 Y0.8491 +G01 X-0.1178 Y0.8384 +G01 X-0.2822 Y0.8384 +G01 X-0.3079 Y0.8491 +G01 X-0.3193 Y0.8605 +G01 X-0.3998 Y0.8605 +G01 X-0.4042 Y0.8605 +G01 X-0.4311 Y0.8693 +G01 X-0.4541 Y0.8859 +G01 X-0.4707 Y0.9089 +G01 X-0.4795 Y0.9358 +G01 X-0.4795 Y0.9500 +G01 X-0.4795 Y0.9598 +G01 X-0.4795 Y0.9600 +G01 X-0.4796 Y0.9602 +G01 X-0.4796 Y0.9604 +G01 X-0.4798 Y0.9604 +G01 X-0.4799 Y0.9605 +G01 X-0.4887 Y0.9605 +G01 X-0.4898 Y0.9605 +G01 X-0.5221 Y0.9605 +G01 X-0.4975 Y0.9359 +G01 X-0.4975 Y0.8841 +G01 X-0.5105 Y0.8711 +G01 X-0.5105 Y0.4801 +G01 X-0.5105 Y0.4742 +G01 X-0.5202 Y0.4443 +G01 X-0.5388 Y0.4188 +G01 X-0.5643 Y0.4002 +G01 X-0.5942 Y0.3905 +G01 X-0.6001 Y0.3905 +G01 X-0.7421 Y0.3905 +G01 X-0.7175 Y0.3659 +G01 X-0.7175 Y0.3141 +G01 X-0.7321 Y0.2995 +G01 X-0.5198 Y0.2995 +G01 X-0.5100 Y0.2995 +G01 X-0.5098 Y0.2996 +G01 X-0.5096 Y0.2996 +G01 X-0.5096 Y0.2998 +G01 X-0.5095 Y0.2999 +G01 X-0.5095 Y0.6501 +G01 X-0.5095 Y0.6517 +G01 X-0.5095 Y0.6698 +G01 X-0.5095 Y0.6758 +G01 X-0.4998 Y0.7057 +G01 X-0.4812 Y0.7312 +G01 X-0.4557 Y0.7498 +G01 X-0.4258 Y0.7595 +G01 X-0.4100 Y0.7595 +G01 X-0.4001 Y0.7595 +G01 X-0.3193 Y0.7595 +G01 X-0.3079 Y0.7709 +G01 X-0.2822 Y0.7816 +G01 X-0.1178 Y0.7816 +G01 X-0.0921 Y0.7709 +G01 X-0.0724 Y0.7512 +G01 X-0.0618 Y0.7255 +G01 X-0.0618 Y0.6976 +G01 X-0.0724 Y0.6719 +G01 X-0.0921 Y0.6522 +G01 X-0.1178 Y0.6416 +G01 X-0.2822 Y0.6416 +G01 X-0.3079 Y0.6522 +G01 X-0.3162 Y0.6605 +G01 X-0.4001 Y0.6605 +G01 X-0.4100 Y0.6605 +G01 X-0.4102 Y0.6604 +G01 X-0.4104 Y0.6604 +G01 X-0.4104 Y0.6602 +G01 X-0.4105 Y0.6601 +G01 X-0.4105 Y0.6516 +G01 X-0.4105 Y0.6501 +G01 X-0.4105 Y0.2901 +G01 X-0.4105 Y0.2842 +G01 X-0.4202 Y0.2543 +G01 X-0.4388 Y0.2288 +G01 X-0.4643 Y0.2102 +G01 X-0.4942 Y0.2005 +G01 X-0.5001 Y0.2005 +G01 X-0.5095 Y0.2005 +G01 X-0.5100 Y0.2005 +G01 X-0.5198 Y0.2005 +G01 X-1.0400 Y0.2005 +G01 X-1.0402 Y0.2004 +G01 X-1.0404 Y0.2004 +G01 X-1.0404 Y0.2002 +G01 X-1.0405 Y0.2001 +G01 X-1.0405 Y0.1943 +G01 X-1.0405 Y0.1901 +G01 X-1.0405 Y0.1401 +G01 X-1.0405 Y0.1342 +G01 X-1.0502 Y0.1043 +G01 X-1.0688 Y0.0788 +G01 X-1.0943 Y0.0602 +G01 X-1.1242 Y0.0505 +G01 X-1.1301 Y0.0505 +G01 X-1.6098 Y0.0505 +G01 X-1.6158 Y0.0505 +G01 X-1.6457 Y0.0602 +G01 X-1.6712 Y0.0788 +G01 X-1.6898 Y0.1043 +G01 X-1.6995 Y0.1342 +G01 X-1.6995 Y0.1401 +G01 X-1.6995 Y0.1503 +G01 X-1.6995 Y0.1598 +G01 X-1.6995 Y0.6221 +G01 X-1.7241 Y0.5975 +G01 X-1.7759 Y0.5975 +G01 X-1.7889 Y0.6105 +G01 X-1.8467 Y0.6105 +G01 X-1.8337 Y0.5975 +G01 X-1.8337 Y0.5685 +G01 X-1.8064 Y0.5685 +G01 X-1.7812 Y0.5581 +G01 X-1.7619 Y0.5388 +G01 X-1.7515 Y0.5136 +G01 X-1.7515 Y0.4864 +G01 X-1.7619 Y0.4612 +G01 X-1.7705 Y0.4526 +G01 X-1.7705 Y0.3874 +G01 X-1.7619 Y0.3788 +G01 X-1.7515 Y0.3536 +G01 X-1.7515 Y0.3264 +G01 X-1.7619 Y0.3012 +G01 X-1.7812 Y0.2819 +G01 X-1.8064 Y0.2715 +G01 X-1.8336 Y0.2715 +G01 X-1.8588 Y0.2819 +G01 X-1.8674 Y0.2905 +G01 X-1.9485 Y0.2905 +G01 X-1.9415 Y0.2736 +G01 X-1.9415 Y0.2464 +G01 X-1.9519 Y0.2212 +G01 X-1.9712 Y0.2019 +G01 X-1.9771 Y0.1995 +G01 X-1.8825 Y0.1995 +G01 X-1.8825 Y0.2259 +G01 X-1.8459 Y0.2625 +G01 X-1.7941 Y0.2625 +G01 X-1.7575 Y0.2259 +G01 X-1.7575 Y0.1741 +G01 X-1.7612 Y0.1704 +G01 X-1.7712 Y0.1397 +G01 X-1.7916 Y0.1116 +G01 X-1.8197 Y0.0912 +G01 X-1.8527 Y0.0805 +G01 X-1.8582 Y0.0805 +G01 X-2.4482 Y0.0805 +G01 X-2.4496 Y0.0805 +G01 X-2.4718 Y0.0805 +G01 X-2.4773 Y0.0805 +G01 X-2.5103 Y0.0912 +G01 X-2.5384 Y0.1116 +G01 X-2.5588 Y0.1397 +G01 X-2.5695 Y0.1727 +G01 X-2.5695 Y0.1782 +G01 X-2.5695 Y0.2105 +G01 X-2.6011 Y0.2105 +G01 X-2.6141 Y0.1975 +G01 X-2.6659 Y0.1975 +G01 X-2.7025 Y0.2341 +G01 X-2.7025 Y0.2859 +G01 X-2.6659 Y0.3225 +G01 X-2.6141 Y0.3225 +G01 X-2.6011 Y0.3095 +G01 X-2.5695 Y0.3095 +G01 X-2.5695 Y0.4257 +G01 X-2.5763 Y0.4325 +G01 X-2.5763 Y0.4875 +G01 X-2.5633 Y0.5005 +G01 X-2.8038 Y0.5005 +G01 X-2.8121 Y0.4922 +G01 X-2.8378 Y0.4816 +G01 X-3.0022 Y0.4816 +G01 X-3.0279 Y0.4922 +G01 X-3.0476 Y0.5119 +G01 X-3.0582 Y0.5376 +G01 X-3.0582 Y0.5655 +G01 X-3.0476 Y0.5912 +G01 X-3.0279 Y0.6109 +G01 X-3.0022 Y0.6216 +G01 X-2.8378 Y0.6216 +G01 X-2.8121 Y0.6109 +G01 X-2.8007 Y0.5995 +G01 X-2.2795 Y0.5995 +G01 X-2.2795 Y0.5998 +G01 X-2.2795 Y0.7198 +G01 X-2.2795 Y0.7242 +G01 X-2.2707 Y0.7511 +G01 X-2.2541 Y0.7741 +G01 X-2.2452 Y0.7805 +G01 X-2.2701 Y0.7805 +G01 X-2.2800 Y0.7805 +G01 X-2.2802 Y0.7804 +G01 X-2.2804 Y0.7804 +G01 X-2.2804 Y0.7802 +G01 X-2.2805 Y0.7801 +G01 X-2.2805 Y0.7701 +G01 X-2.2805 Y0.7698 +G01 X-2.2805 Y0.7600 +G01 X-2.2805 Y0.7569 +G01 X-2.2805 Y0.7501 +G01 X-2.2805 Y0.7462 +G01 X-2.2911 Y0.7206 +G01 X-2.3106 Y0.7011 +G01 X-2.3362 Y0.6905 +G01 X-2.3401 Y0.6905 +G01 X-2.6411 Y0.6905 +G01 X-2.6441 Y0.6875 +G01 X-2.6959 Y0.6875 +G01 X-2.7089 Y0.7005 +G01 X-2.8007 Y0.7005 +G01 X-2.8121 Y0.6891 +G01 X-2.8378 Y0.6784 +G01 X-3.0022 Y0.6784 +G01 X-3.0279 Y0.6891 +G01 X-3.0476 Y0.7088 +G01 X-3.0582 Y0.7345 +G01 X-3.0582 Y0.7623 +G01 X-3.0476 Y0.7881 +G01 X-3.0279 Y0.8078 +G01 X-3.0022 Y0.8184 +G01 X-2.8378 Y0.8184 +G01 X-2.8121 Y0.8078 +G01 X-2.8038 Y0.7995 +G01 X-2.7089 Y0.7995 +G01 X-2.6959 Y0.8125 +G01 X-2.6441 Y0.8125 +G01 X-2.6211 Y0.7895 +G01 X-2.3795 Y0.7895 +G01 X-2.3795 Y0.7958 +G01 X-2.3698 Y0.8257 +G01 X-2.3512 Y0.8512 +G01 X-2.3385 Y0.8605 +G01 X-2.4657 Y0.8605 +G01 X-2.4825 Y0.8437 +G01 X-2.5375 Y0.8437 +G01 X-2.5543 Y0.8605 +G01 X-3.1001 Y0.8605 +G01 X-3.1030 Y0.8605 +G01 X-3.1198 Y0.8605 +G01 X-3.1258 Y0.8605 +G01 X-3.1557 Y0.8702 +G01 X-3.1812 Y0.8888 +G01 X-3.1998 Y0.9143 +G01 X-3.2095 Y0.9442 +G01 X-3.2095 Y0.9501 +G01 X-3.2095 Y1.5711 +G01 X-3.2225 Y1.5841 +G01 X-3.2225 Y1.6359 +G01 X-3.2095 Y1.6489 +G01 X-3.2095 Y1.6801 +G01 X-3.2095 Y1.6814 +G01 X-3.2095 Y1.6998 +G01 X-3.2095 Y1.7058 +G01 X-3.1998 Y1.7357 +G01 X-3.1812 Y1.7612 +G01 X-3.1557 Y1.7798 +G01 X-3.1258 Y1.7895 +G01 X-3.1198 Y1.7895 +G01 X-2.9998 Y1.7895 +G01 X-2.9995 Y1.7895 +G01 X-2.9995 Y1.8501 +G01 X-2.9995 Y1.8528 +G01 X-2.9995 Y1.8698 +G01 X-2.9995 Y1.8758 +G01 X-2.9898 Y1.9057 +G01 X-2.9712 Y1.9312 +G01 X-2.9457 Y1.9498 +G01 X-2.9158 Y1.9595 +G01 X-2.9098 Y1.9595 +G01 X-2.0801 Y1.9595 +G01 X-2.0389 Y1.9595 +G01 X-2.0259 Y1.9725 +G01 X-1.9741 Y1.9725 +G01 X-1.9611 Y1.9595 +G01 X-1.7700 Y1.9595 +G01 X-1.7698 Y1.9596 +G01 X-1.7696 Y1.9596 +G01 X-1.7696 Y1.9598 +G01 X-1.7695 Y1.9599 +G01 X-1.7695 Y1.9666 +G01 X-1.7695 Y1.9698 +G01 X-1.7695 Y2.0698 +G01 X-1.7695 Y2.0758 +G01 X-1.7598 Y2.1057 +G01 X-1.7412 Y2.1312 +G01 X-1.7157 Y2.1498 +G01 X-1.6858 Y2.1595 +G01 X-1.6700 Y2.1595 +G01 X-1.6601 Y2.1595 +G01 X-1.2698 Y2.1595 +G01 X-1.2600 Y2.1595 +G01 X-1.2442 Y2.1595 +G01 X-1.2143 Y2.1498 +G01 X-1.1888 Y2.1312 +G01 X-1.1702 Y2.1057 +G01 X-1.1605 Y2.0758 +G01 X-1.1605 Y2.0698 +G01 X-1.1605 Y1.9100 +G01 X-1.1604 Y1.9098 +G01 X-1.1604 Y1.9096 +G01 X-1.1602 Y1.9096 +G01 X-1.1601 Y1.9095 +G01 X-1.1501 Y1.9095 +G01 X-0.8052 Y1.9095 +G01 X-0.7979 Y1.9168 +G01 X-0.7733 Y1.9270 +G01 X-0.7467 Y1.9270 +G01 X-0.7220 Y1.9168 +G01 X-0.7147 Y1.9095 +G01 X-0.2617 Y1.9095 +G01 X-0.2524 Y1.9095 +G01 X-0.2159 Y1.8976 +G01 X-0.1849 Y1.8751 +G01 X-0.1728 Y1.8584 +G01 X-0.1178 Y1.8584 +G01 X-0.0921 Y1.8478 +G01 X-0.0724 Y1.8281 +G01 X-0.0618 Y1.8023 +G01 X-0.0618 Y1.7745 +G01 X-0.0724 Y1.7488 +G01 X-0.0921 Y1.7291 +G01 X-0.1178 Y1.7184 +G01 X-0.2822 Y1.7184 +G01 X-0.3079 Y1.7291 +G01 X-0.3276 Y1.7488 +G01 X-0.3382 Y1.7745 +G01 X-0.3382 Y1.8023 +G01 X-0.3349 Y1.8105 +G01 X-0.7147 Y1.8105 +G01 X-0.7158 Y1.8095 +G01 X-0.6501 Y1.8095 +G01 X-0.6458 Y1.8095 +G01 X-0.6189 Y1.8007 +G01 X-0.5959 Y1.7841 +G01 X-0.5793 Y1.7611 +G01 X-0.5705 Y1.7342 +G01 X-0.5705 Y1.7298 +G01 X-0.5705 Y1.6500 +G01 X-0.5704 Y1.6498 +G01 X-0.5704 Y1.6496 +G01 X-0.5702 Y1.6496 +G01 X-0.5701 Y1.6495 +G01 X-0.5601 Y1.6495 +G01 X-0.3093 Y1.6495 +G01 X-0.3079 Y1.6509 +G01 X-0.2822 Y1.6616 +G01 X-0.1178 Y1.6616 +G01 X-0.0921 Y1.6509 +G01 X-0.0724 Y1.6312 +G01 X-0.0618 Y1.6055 +G01 X-0.0618 Y1.5776 +G01 X-0.0724 Y1.5519 +G01 X-0.0921 Y1.5322 +G01 X-0.1178 Y1.5216 +G01 X-0.2822 Y1.5216 +G01 X-0.3079 Y1.5322 +G01 X-0.3262 Y1.5505 +G01 X-0.5601 Y1.5505 +G01 X-0.5700 Y1.5505 +G01 X-0.5858 Y1.5505 +G01 X-0.6157 Y1.5602 +G01 X-0.6412 Y1.5788 +G01 X-0.6598 Y1.6043 +G01 X-0.6695 Y1.6342 +G01 X-0.6695 Y1.6401 +G01 X-0.6695 Y1.7105 +G01 X-0.7266 Y1.7105 +G01 X-0.7243 Y1.7098 +G01 X-0.6988 Y1.6912 +G01 X-0.6802 Y1.6657 +G01 X-0.6705 Y1.6358 +G01 X-0.6705 Y1.6200 +G01 X-0.6705 Y1.6101 +G01 X-0.6705 Y1.5489 +G01 X-0.6575 Y1.5359 +G01 X-0.6575 Y1.4841 +G01 X-0.6821 Y1.4595 +G01 X-0.5801 Y1.4595 +G01 X-0.5742 Y1.4595 +G01 X-0.5443 Y1.4498 +G01 X-0.5188 Y1.4312 +G01 X-0.5002 Y1.4057 +G01 X-0.4905 Y1.3758 +G01 X-0.4905 Y1.3600 +G01 X-0.4905 Y1.3584 +G01 X-0.4904 Y1.3582 +G01 X-0.4904 Y1.3581 +G01 X-0.4902 Y1.3580 +G01 X-0.4901 Y1.3579 +G01 X-0.4814 Y1.3579 +G01 X-0.4801 Y1.3579 +G01 X-0.3177 Y1.3579 +G01 X-0.3079 Y1.3678 +G01 X-0.2822 Y1.3784 +G01 X-0.1178 Y1.3784 +G01 X-0.0921 Y1.3678 +G01 X-0.0724 Y1.3481 +G01 X-0.0618 Y1.3223 +G01 X-0.0618 Y1.2945 +G01 X-0.0724 Y1.2688 +G01 X-0.0921 Y1.2491 +G01 X-0.1178 Y1.2384 +G01 X-0.2822 Y1.2384 +G01 X-0.3079 Y1.2491 +G01 X-0.3177 Y1.2589 +G01 X-0.4241 Y1.2589 +G01 X-0.3989 Y1.2507 +G01 X-0.3759 Y1.2341 +G01 X-0.3593 Y1.2111 +G01 X-0.3505 Y1.1842 +G01 X-0.3505 Y1.1798 +G01 X-0.3505 Y1.1700 +G01 X-0.3505 Y1.1616 +G01 X-0.3504 Y1.1613 +G01 X-0.3504 Y1.1612 +G01 X-0.3502 Y1.1611 +G01 X-0.3501 Y1.1611 +G01 X-0.3428 Y1.1611 +G01 X-0.3401 Y1.1611 +G01 X-0.3177 Y1.1611 +G01 X-0.3079 Y1.1709 +G01 X-0.2822 Y1.1816 +G00 Z0.1000 +G82 X-0.2200 Y0.1800 Z-0.0110 F10 R0.1000 P1.000000 +G82 X-0.2300 Y2.0300 +G82 X-3.0700 Y2.0100 +G82 X-3.0700 Y0.1900 +G82 X-2.2100 Y1.4700 +G82 X-2.2100 Y1.7400 +G82 X-1.9700 Y1.4700 +G82 X-1.9700 Y1.7900 +G82 X-1.9000 Y0.5700 +G82 X-1.6400 Y1.2700 +G82 X-2.5100 Y0.9100 +G82 X-2.5100 Y0.4600 +G82 X-2.9000 Y1.4400 +G82 X-2.3000 Y1.4400 +G82 X-0.7200 Y1.3100 +G82 X-0.7200 Y1.5100 +G82 X-0.5600 Y1.1100 +G82 X-0.5600 Y0.9100 +G82 X-0.7800 Y0.5400 +G82 X-0.7800 Y0.3400 +G82 X-1.5500 Y0.6600 +G82 X-1.7500 Y0.6600 +G82 X-2.9500 Y1.1300 +G82 X-2.9500 Y1.3300 +G82 X-0.7600 Y1.8600 +G82 X-1.3600 Y1.8600 +G82 X-1.5000 Y1.3100 +G82 X-1.5000 Y1.7100 +G82 X-1.8200 Y0.5000 +G82 X-1.4200 Y0.5000 +G82 X-1.8200 Y0.3400 +G82 X-1.4200 Y0.3400 +G82 X-2.0100 Y0.2600 +G82 X-2.0100 Y0.6600 +G82 X-2.9200 Y0.5516 +G82 X-2.9200 Y0.7484 +G82 X-1.9600 Y1.3100 +G82 X-1.9600 Y1.2100 +G82 X-1.9600 Y1.1100 +G82 X-1.9600 Y1.0100 +G82 X-2.2600 Y1.0100 +G82 X-2.2600 Y1.1100 +G82 X-2.2600 Y1.2100 +G82 X-2.2600 Y1.3100 +G82 X-0.9500 Y1.4100 +G82 X-0.9500 Y1.3100 +G82 X-0.9500 Y1.2100 +G82 X-0.9500 Y1.1100 +G82 X-0.9500 Y1.0100 +G82 X-0.9500 Y0.9100 +G82 X-0.9500 Y0.8100 +G82 X-1.2500 Y0.8100 +G82 X-1.2500 Y0.9100 +G82 X-1.2500 Y1.0100 +G82 X-1.2500 Y1.1100 +G82 X-1.2500 Y1.2100 +G82 X-1.2500 Y1.3100 +G82 X-1.2500 Y1.4100 +G82 X-2.6700 Y1.8200 +G82 X-2.6700 Y1.7200 +G82 X-0.2000 Y1.7884 +G82 X-0.2000 Y1.5916 +G82 X-2.3400 Y1.7400 +G82 X-2.3900 Y1.6650 +G82 X-2.4400 Y1.7400 +G82 X-3.1600 Y1.6100 +G82 X-2.6600 Y1.6100 +G82 X-2.6700 Y0.7500 +G82 X-2.6700 Y1.2500 +G82 X-1.7700 Y1.2000 +G82 X-1.7700 Y1.7000 +G82 X-2.0000 Y1.9100 +G82 X-1.5000 Y1.9100 +G82 X-1.4300 Y1.2100 +G82 X-1.4300 Y0.7100 +G82 X-1.8200 Y0.2000 +G82 X-1.3200 Y0.2000 +G82 X-2.6400 Y0.2600 +G82 X-2.1400 Y0.2600 +G82 X-0.2000 Y1.3084 +G82 X-0.2000 Y1.1116 +G82 X-0.2000 Y0.9084 +G82 X-0.2000 Y0.7116 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/enabtmr.bot.mill.tap b/trunk/ulp/docs/examples/enabtmr.bot.mill.tap new file mode 100644 index 00000000..b4c4d899 --- /dev/null +++ b/trunk/ulp/docs/examples/enabtmr.bot.mill.tap @@ -0,0 +1,53 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0100 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-0.9700 Y0.6300 +G01 Z-0.0100 F10.00 +G01 X-1.1100 Y0.6300 F20.00 +G01 X-1.1900 Y0.7100 +G01 X-1.2600 Y0.7100 +G01 X-1.2600 Y0.5000 +G01 X-1.1900 Y0.5000 +G01 X-1.1900 Y0.5100 +G01 X-1.1200 Y0.5800 +G01 X-0.9700 Y0.5800 +G01 X-0.9700 Y0.6300 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/enabtmr.bot.text.tap b/trunk/ulp/docs/examples/enabtmr.bot.text.tap new file mode 100644 index 00000000..0a22deae --- /dev/null +++ b/trunk/ulp/docs/examples/enabtmr.bot.text.tap @@ -0,0 +1,388 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0050 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-3.0670 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-3.0670 Y2.1357 F20.00 +G01 X-3.0350 Y2.1357 +G01 X-3.0243 Y2.1250 +G01 X-3.0243 Y2.1037 +G01 X-3.0350 Y2.0930 +G01 X-3.0670 Y2.0930 +G00 Z0.1000 +G00 X-2.9598 Y2.1357 +G01 Z-0.0050 F10.00 +G01 X-2.9919 Y2.1357 F20.00 +G01 X-3.0025 Y2.1250 +G01 X-3.0025 Y2.1037 +G01 X-2.9919 Y2.0930 +G01 X-2.9598 Y2.0930 +G00 Z0.1000 +G00 X-2.9381 Y2.1571 +G01 Z-0.0050 F10.00 +G01 X-2.9381 Y2.0930 F20.00 +G01 X-2.9061 Y2.0930 +G01 X-2.8954 Y2.1037 +G01 X-2.8954 Y2.1250 +G01 X-2.9061 Y2.1357 +G01 X-2.9381 Y2.1357 +G00 Z0.1000 +G00 X-2.8523 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-2.8416 Y2.0716 F20.00 +G01 X-2.8309 Y2.0823 +G01 X-2.8309 Y2.1357 +G01 X-2.8630 Y2.1357 +G01 X-2.8736 Y2.1250 +G01 X-2.8736 Y2.1037 +G01 X-2.8630 Y2.0930 +G01 X-2.8309 Y2.0930 +G00 Z0.1000 +G00 X-2.7665 Y2.1357 +G01 Z-0.0050 F10.00 +G01 X-2.7985 Y2.1357 F20.00 +G01 X-2.8092 Y2.1250 +G01 X-2.8092 Y2.1037 +G01 X-2.7985 Y2.0930 +G01 X-2.7665 Y2.0930 +G00 Z0.1000 +G00 X-2.7341 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-2.7127 Y2.0930 F20.00 +G01 X-2.7020 Y2.1037 +G01 X-2.7020 Y2.1250 +G01 X-2.7127 Y2.1357 +G01 X-2.7341 Y2.1357 +G01 X-2.7447 Y2.1250 +G01 X-2.7447 Y2.1037 +G01 X-2.7341 Y2.0930 +G00 Z0.1000 +G00 X-2.6376 Y2.1571 +G01 Z-0.0050 F10.00 +G01 X-2.6376 Y2.0930 F20.00 +G01 X-2.6696 Y2.0930 +G01 X-2.6803 Y2.1037 +G01 X-2.6803 Y2.1250 +G01 X-2.6696 Y2.1357 +G01 X-2.6376 Y2.1357 +G00 Z0.1000 +G00 X-2.5838 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-2.6052 Y2.0930 F20.00 +G01 X-2.6158 Y2.1037 +G01 X-2.6158 Y2.1250 +G01 X-2.6052 Y2.1357 +G01 X-2.5838 Y2.1357 +G01 X-2.5731 Y2.1250 +G01 X-2.5731 Y2.1144 +G01 X-2.6158 Y2.1144 +G00 Z0.1000 +G00 X-2.5087 Y2.1037 +G01 Z-0.0050 F10.00 +G01 X-2.5194 Y2.0930 F20.00 +G01 X-2.5407 Y2.0930 +G01 X-2.5514 Y2.1037 +G01 X-2.5514 Y2.1464 +G01 X-2.5407 Y2.1571 +G01 X-2.5194 Y2.1571 +G01 X-2.5087 Y2.1464 +G01 X-2.5087 Y2.1250 +G01 X-2.5194 Y2.1144 +G01 X-2.5407 Y2.1144 +G01 X-2.5407 Y2.1357 +G01 X-2.5194 Y2.1357 +G01 X-2.5194 Y2.1144 +G00 Z0.1000 +G00 X-2.4869 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-2.4869 Y2.1357 F20.00 +G01 X-2.4549 Y2.1357 +G01 X-2.4442 Y2.1250 +G01 X-2.4442 Y2.1037 +G01 X-2.4549 Y2.0930 +G01 X-2.4869 Y2.0930 +G00 Z0.1000 +G00 X-2.3798 Y2.1357 +G01 Z-0.0050 F10.00 +G01 X-2.4118 Y2.1357 F20.00 +G01 X-2.4225 Y2.1250 +G01 X-2.4225 Y2.1037 +G01 X-2.4118 Y2.0930 +G01 X-2.3798 Y2.0930 +G00 Z0.1000 +G00 X-2.3580 Y2.1571 +G01 Z-0.0050 F10.00 +G01 X-2.3580 Y2.0930 F20.00 +G01 X-2.3260 Y2.0930 +G01 X-2.3153 Y2.1037 +G01 X-2.3153 Y2.1250 +G01 X-2.3260 Y2.1357 +G01 X-2.3580 Y2.1357 +G00 Z0.1000 +G00 X-2.2722 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-2.2615 Y2.0716 F20.00 +G01 X-2.2509 Y2.0823 +G01 X-2.2509 Y2.1357 +G01 X-2.2829 Y2.1357 +G01 X-2.2936 Y2.1250 +G01 X-2.2936 Y2.1037 +G01 X-2.2829 Y2.0930 +G01 X-2.2509 Y2.0930 +G00 Z0.1000 +G00 X-2.1864 Y2.1357 +G01 Z-0.0050 F10.00 +G01 X-2.2184 Y2.1357 F20.00 +G01 X-2.2291 Y2.1250 +G01 X-2.2291 Y2.1037 +G01 X-2.2184 Y2.0930 +G01 X-2.1864 Y2.0930 +G00 Z0.1000 +G00 X-2.1540 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-2.1326 Y2.0930 F20.00 +G01 X-2.1220 Y2.1037 +G01 X-2.1220 Y2.1250 +G01 X-2.1326 Y2.1357 +G01 X-2.1540 Y2.1357 +G01 X-2.1647 Y2.1250 +G01 X-2.1647 Y2.1037 +G01 X-2.1540 Y2.0930 +G00 Z0.1000 +G00 X-2.0575 Y2.1571 +G01 Z-0.0050 F10.00 +G01 X-2.0575 Y2.0930 F20.00 +G01 X-2.0895 Y2.0930 +G01 X-2.1002 Y2.1037 +G01 X-2.1002 Y2.1250 +G01 X-2.0895 Y2.1357 +G01 X-2.0575 Y2.1357 +G00 Z0.1000 +G00 X-2.0037 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-2.0251 Y2.0930 F20.00 +G01 X-2.0358 Y2.1037 +G01 X-2.0358 Y2.1250 +G01 X-2.0251 Y2.1357 +G01 X-2.0037 Y2.1357 +G01 X-1.9931 Y2.1250 +G01 X-1.9931 Y2.1144 +G01 X-2.0358 Y2.1144 +G00 Z0.1000 +G00 X-1.9713 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-1.9713 Y2.1037 F20.00 +G01 X-1.9606 Y2.1037 +G01 X-1.9606 Y2.0930 +G01 X-1.9713 Y2.0930 +G00 Z0.1000 +G00 X-1.9284 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-1.9071 Y2.0930 F20.00 +G01 X-1.8964 Y2.1037 +G01 X-1.8964 Y2.1250 +G01 X-1.9071 Y2.1357 +G01 X-1.9284 Y2.1357 +G01 X-1.9391 Y2.1250 +G01 X-1.9391 Y2.1037 +G01 X-1.9284 Y2.0930 +G00 Z0.1000 +G00 X-1.8746 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-1.8746 Y2.1357 F20.00 +G00 Z0.1000 +G00 X-1.8746 Y2.1144 +G01 Z-0.0050 F10.00 +G01 X-1.8533 Y2.1357 F20.00 +G01 X-1.8426 Y2.1357 +G00 Z0.1000 +G00 X-1.7996 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-1.7889 Y2.0716 F20.00 +G01 X-1.7782 Y2.0823 +G01 X-1.7782 Y2.1357 +G01 X-1.8102 Y2.1357 +G01 X-1.8209 Y2.1250 +G01 X-1.8209 Y2.1037 +G01 X-1.8102 Y2.0930 +G01 X-1.7782 Y2.0930 +G00 Z0.1000 +G00 X-2.8443 Y2.0464 +G01 Z-0.0050 F10.00 +G01 X-2.8550 Y2.0571 F20.00 +G01 X-2.8763 Y2.0571 +G01 X-2.8870 Y2.0464 +G01 X-2.8870 Y2.0037 +G01 X-2.8763 Y1.9930 +G01 X-2.8550 Y1.9930 +G01 X-2.8443 Y2.0037 +G00 Z0.1000 +G00 X-2.8119 Y1.9930 +G01 Z-0.0050 F10.00 +G01 X-2.7905 Y1.9930 F20.00 +G01 X-2.7798 Y2.0037 +G01 X-2.7798 Y2.0250 +G01 X-2.7905 Y2.0357 +G01 X-2.8119 Y2.0357 +G01 X-2.8225 Y2.0250 +G01 X-2.8225 Y2.0037 +G01 X-2.8119 Y1.9930 +G00 Z0.1000 +G00 X-2.7581 Y1.9716 +G01 Z-0.0050 F10.00 +G01 X-2.7581 Y2.0357 F20.00 +G01 X-2.7261 Y2.0357 +G01 X-2.7154 Y2.0250 +G01 X-2.7154 Y2.0037 +G01 X-2.7261 Y1.9930 +G01 X-2.7581 Y1.9930 +G00 Z0.1000 +G00 X-2.6936 Y2.0357 +G01 Z-0.0050 F10.00 +G01 X-2.6936 Y2.0037 F20.00 +G01 X-2.6830 Y1.9930 +G01 X-2.6509 Y1.9930 +G00 Z0.1000 +G00 X-2.6509 Y2.0357 +G01 Z-0.0050 F10.00 +G01 X-2.6509 Y1.9823 F20.00 +G01 X-2.6616 Y1.9716 +G01 X-2.6723 Y1.9716 +G00 Z0.1000 +G00 X-2.6292 Y1.9930 +G01 Z-0.0050 F10.00 +G01 X-2.6292 Y2.0357 F20.00 +G00 Z0.1000 +G00 X-2.6292 Y2.0144 +G01 Z-0.0050 F10.00 +G01 X-2.6078 Y2.0357 F20.00 +G01 X-2.5972 Y2.0357 +G00 Z0.1000 +G00 X-2.5755 Y2.0357 +G01 Z-0.0050 F10.00 +G01 X-2.5648 Y2.0357 F20.00 +G01 X-2.5648 Y1.9930 +G00 Z0.1000 +G00 X-2.5755 Y1.9930 +G01 Z-0.0050 F10.00 +G01 X-2.5541 Y1.9930 F20.00 +G00 Z0.1000 +G00 X-2.5648 Y2.0677 +G01 Z-0.0050 F10.00 +G01 X-2.5648 Y2.0571 F20.00 +G00 Z0.1000 +G00 X-2.5112 Y1.9716 +G01 Z-0.0050 F10.00 +G01 X-2.5005 Y1.9716 F20.00 +G01 X-2.4898 Y1.9823 +G01 X-2.4898 Y2.0357 +G01 X-2.5218 Y2.0357 +G01 X-2.5325 Y2.0250 +G01 X-2.5325 Y2.0037 +G01 X-2.5218 Y1.9930 +G01 X-2.4898 Y1.9930 +G00 Z0.1000 +G00 X-2.4681 Y2.0571 +G01 Z-0.0050 F10.00 +G01 X-2.4681 Y1.9930 F20.00 +G00 Z0.1000 +G00 X-2.4681 Y2.0250 +G01 Z-0.0050 F10.00 +G01 X-2.4574 Y2.0357 F20.00 +G01 X-2.4360 Y2.0357 +G01 X-2.4254 Y2.0250 +G01 X-2.4254 Y1.9930 +G00 Z0.1000 +G00 X-2.3929 Y2.0464 +G01 Z-0.0050 F10.00 +G01 X-2.3929 Y2.0037 F20.00 +G01 X-2.3823 Y1.9930 +G00 Z0.1000 +G00 X-2.4036 Y2.0357 +G01 Z-0.0050 F10.00 +G01 X-2.3823 Y2.0357 F20.00 +G00 Z0.1000 +G00 X-2.2535 Y1.9930 +G01 Z-0.0050 F10.00 +G01 X-2.2962 Y1.9930 F20.00 +G01 X-2.2535 Y2.0357 +G01 X-2.2535 Y2.0464 +G01 X-2.2642 Y2.0571 +G01 X-2.2855 Y2.0571 +G01 X-2.2962 Y2.0464 +G00 Z0.1000 +G00 X-2.2317 Y2.0037 +G01 Z-0.0050 F10.00 +G01 X-2.2317 Y2.0464 F20.00 +G01 X-2.2211 Y2.0571 +G01 X-2.1997 Y2.0571 +G01 X-2.1890 Y2.0464 +G01 X-2.1890 Y2.0037 +G01 X-2.1997 Y1.9930 +G01 X-2.2211 Y1.9930 +G01 X-2.2317 Y2.0037 +G01 X-2.1890 Y2.0464 +G00 Z0.1000 +G00 X-2.1673 Y2.0037 +G01 Z-0.0050 F10.00 +G01 X-2.1673 Y2.0464 F20.00 +G01 X-2.1566 Y2.0571 +G01 X-2.1353 Y2.0571 +G01 X-2.1246 Y2.0464 +G01 X-2.1246 Y2.0037 +G01 X-2.1353 Y1.9930 +G01 X-2.1566 Y1.9930 +G01 X-2.1673 Y2.0037 +G01 X-2.1246 Y2.0464 +G00 Z0.1000 +G00 X-2.1028 Y2.0037 +G01 Z-0.0050 F10.00 +G01 X-2.0922 Y1.9930 F20.00 +G01 X-2.0708 Y1.9930 +G01 X-2.0601 Y2.0037 +G01 X-2.0601 Y2.0464 +G01 X-2.0708 Y2.0571 +G01 X-2.0922 Y2.0571 +G01 X-2.1028 Y2.0464 +G01 X-2.1028 Y2.0357 +G01 X-2.0922 Y2.0250 +G01 X-2.0601 Y2.0250 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/enabtmr.brd b/trunk/ulp/docs/examples/enabtmr.brd new file mode 100644 index 00000000..1c22253c Binary files /dev/null and b/trunk/ulp/docs/examples/enabtmr.brd differ diff --git a/trunk/ulp/docs/examples/enabtmr.drl.txt b/trunk/ulp/docs/examples/enabtmr.drl.txt new file mode 100644 index 00000000..74fbfbd2 --- /dev/null +++ b/trunk/ulp/docs/examples/enabtmr.drl.txt @@ -0,0 +1,26 @@ +# +# Sample drill rack file for the enabtmr board. +# +# Drill is the size of the drill bit. +# Min is the smallest hole the bit will be used for. +# Max is the largest hole the bit will be used for. +# +# Each value can have a "unit of measure" added to it, +# such as 0.500mm . If you do not provide the unit of measure, +# values over 0.250 are considered millimeters, and +# values under 0.250 are considered inches. For example: +# 0.400 would be considered 0.400 mm. +# 0.125 would be considered 0.125 inches. +# +# Please note that you must use a TAB character +# between each setting on a line. +# +# Tip: Set the TAB size of your editor to 12 characters. +# +tool drill_size minimum maximum length +T01 0.500mm 0.000in 0.025in 1.5in +T02 0.032in 0.025in 0.035in 1.5in +T03 0.040in 0.035in 0.045in 1.5in +T04 0.050in 0.045in 0.055in 1.5in +T05 0.062in 0.055in 0.070in 1.5in +T06 0.125in 0.100in 0.125in 1.5in diff --git a/trunk/ulp/docs/examples/enabtmr.sch b/trunk/ulp/docs/examples/enabtmr.sch new file mode 100644 index 00000000..99a7e027 Binary files /dev/null and b/trunk/ulp/docs/examples/enabtmr.sch differ diff --git a/trunk/ulp/docs/examples/enabtmr.top.drill.tap b/trunk/ulp/docs/examples/enabtmr.top.drill.tap new file mode 100644 index 00000000..3e5e1dbf --- /dev/null +++ b/trunk/ulp/docs/examples/enabtmr.top.drill.tap @@ -0,0 +1,1461 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +( Tool| Size | Min Sub | Max Sub | Count ) +( T01 0.500mm 0.0197in 0.0197in 0.0236in ) +( T02 0.813mm 0.0320in 0.0320in 0.0320in ) +( T03 1.016mm 0.0400in 0.0400in 0.0440in ) +( T04 1.270mm 0.0500in 0.0470in 0.0500in ) +( T06 3.175mm 0.1250in 0.0000in 0.0000in ) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T01 ; 0.0197 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X1.9000 Y0.5700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9000 Y0.5700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9000 Y0.5700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9000 Y0.5700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.7900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.7900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.7900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.7900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.4600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.4600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.4600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.4600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T02 ; 0.0320 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X0.5600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.5600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.5600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.5600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.5100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.5100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.5100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.5100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.5400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.5400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.5400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.5400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y0.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y0.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y0.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y0.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.7000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.7000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.7000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.7000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.1400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.1400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.1400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.1400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3900 Y1.6650 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3900 Y1.6650 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3900 Y1.6650 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3900 Y1.6650 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.4400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.4400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.4400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.4400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y0.7500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y0.7500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y0.7500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y0.7500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.2500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.2500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.2500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.2500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.7200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.7200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.7200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.7200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.8200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.8200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.8200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.8200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.1300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.1300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.1300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.1300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.3300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.3300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.3300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.3300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.1600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.1600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.1600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.1600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T03 ; 0.0400 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X1.4200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T04 ; 0.0500 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X0.2000 Y0.9084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y0.9084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y0.9084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y0.9084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.1116 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.1116 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.1116 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.1116 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.3084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.3084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.3084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.3084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.5916 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.5916 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.5916 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.5916 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.7884 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.7884 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.7884 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.7884 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.5516 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.5516 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.5516 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.5516 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.7484 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.7484 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.7484 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.7484 +G01 Z-0.032000 +G01 Z0.100000 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T06 ; 0.1250 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X0.2300 Y2.0300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2300 Y2.0300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2300 Y2.0300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2300 Y2.0300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y0.1900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y0.1900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y0.1900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y0.1900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y2.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y2.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y2.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y2.0100 +G01 Z-0.032000 +G01 Z0.100000 +T01 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/enabtmr.top.etch.tap b/trunk/ulp/docs/examples/enabtmr.top.etch.tap new file mode 100644 index 00000000..0a4154f8 --- /dev/null +++ b/trunk/ulp/docs/examples/enabtmr.top.etch.tap @@ -0,0 +1,1494 @@ +(.../pcb-gcode-3.5.2.11/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcb-gcode-3.5.2.11/docs/examples/enabtmr.brd) +(Current profile is .../pcb-gcode-3.5.2.11/profiles/emc.pp ) +(This file generated 5/16/11 11:25 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0030 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.5000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0002) +(isolate step = 0.0050) +(Generated top outlines, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X2.4305 Y1.6482 +G01 Z-0.0070 F10.00 +G01 X2.4305 Y1.6818 F20.00 +G01 X2.4068 Y1.7055 +G01 X2.3732 Y1.7055 +G01 X2.3495 Y1.6818 +G01 X2.3495 Y1.6482 +G01 X2.3732 Y1.6245 +G01 X2.4068 Y1.6245 +G01 X2.4305 Y1.6482 +G00 Z0.1000 +G00 X2.0251 Y1.3505 +G01 Z-0.0070 F10.00 +G01 X1.8949 Y1.3505 F20.00 +G01 X1.8801 Y1.3443 +G01 X1.8687 Y1.3329 +G01 X1.8625 Y1.3181 +G01 X1.8625 Y1.3019 +G01 X1.8687 Y1.2871 +G01 X1.8801 Y1.2757 +G01 X1.8949 Y1.2695 +G01 X2.0251 Y1.2695 +G01 X2.0399 Y1.2757 +G01 X2.0513 Y1.2871 +G01 X2.0575 Y1.3019 +G01 X2.0575 Y1.3181 +G01 X2.0513 Y1.3329 +G01 X2.0399 Y1.3443 +G01 X2.0251 Y1.3505 +G00 Z0.1000 +G00 X2.0251 Y1.2505 +G01 Z-0.0070 F10.00 +G01 X1.8949 Y1.2505 F20.00 +G01 X1.8801 Y1.2443 +G01 X1.8687 Y1.2329 +G01 X1.8625 Y1.2181 +G01 X1.8625 Y1.2019 +G01 X1.8687 Y1.1871 +G01 X1.8801 Y1.1757 +G01 X1.8949 Y1.1695 +G01 X2.0251 Y1.1695 +G01 X2.0399 Y1.1757 +G01 X2.0513 Y1.1871 +G01 X2.0575 Y1.2019 +G01 X2.0575 Y1.2181 +G01 X2.0513 Y1.2329 +G01 X2.0399 Y1.2443 +G01 X2.0251 Y1.2505 +G00 Z0.1000 +G00 X2.3251 Y1.2505 +G01 Z-0.0070 F10.00 +G01 X2.1949 Y1.2505 F20.00 +G01 X2.1801 Y1.2443 +G01 X2.1687 Y1.2329 +G01 X2.1625 Y1.2181 +G01 X2.1625 Y1.2019 +G01 X2.1687 Y1.1871 +G01 X2.1801 Y1.1757 +G01 X2.1949 Y1.1695 +G01 X2.3251 Y1.1695 +G01 X2.3399 Y1.1757 +G01 X2.3513 Y1.1871 +G01 X2.3575 Y1.2019 +G01 X2.3575 Y1.2181 +G01 X2.3513 Y1.2329 +G01 X2.3399 Y1.2443 +G01 X2.3251 Y1.2505 +G00 Z0.1000 +G00 X2.3251 Y1.3505 +G01 Z-0.0070 F10.00 +G01 X2.1949 Y1.3505 F20.00 +G01 X2.1801 Y1.3443 +G01 X2.1687 Y1.3329 +G01 X2.1625 Y1.3181 +G01 X2.1625 Y1.3019 +G01 X2.1687 Y1.2871 +G01 X2.1801 Y1.2757 +G01 X2.1949 Y1.2695 +G01 X2.3251 Y1.2695 +G01 X2.3399 Y1.2757 +G01 X2.3513 Y1.2871 +G01 X2.3575 Y1.3019 +G01 X2.3575 Y1.3181 +G01 X2.3513 Y1.3329 +G01 X2.3399 Y1.3443 +G01 X2.3251 Y1.3505 +G00 Z0.1000 +G00 X2.0251 Y1.1505 +G01 Z-0.0070 F10.00 +G01 X1.8949 Y1.1505 F20.00 +G01 X1.8801 Y1.1443 +G01 X1.8687 Y1.1329 +G01 X1.8625 Y1.1181 +G01 X1.8625 Y1.1019 +G01 X1.8687 Y1.0871 +G01 X1.8801 Y1.0757 +G01 X1.8949 Y1.0695 +G01 X2.0251 Y1.0695 +G01 X2.0399 Y1.0757 +G01 X2.0513 Y1.0871 +G01 X2.0575 Y1.1019 +G01 X2.0575 Y1.1181 +G01 X2.0513 Y1.1329 +G01 X2.0399 Y1.1443 +G01 X2.0251 Y1.1505 +G00 Z0.1000 +G00 X2.0251 Y1.0505 +G01 Z-0.0070 F10.00 +G01 X1.8949 Y1.0505 F20.00 +G01 X1.8801 Y1.0443 +G01 X1.8687 Y1.0329 +G01 X1.8625 Y1.0181 +G01 X1.8625 Y1.0019 +G01 X1.8687 Y0.9871 +G01 X1.8801 Y0.9757 +G01 X1.8949 Y0.9695 +G01 X2.0251 Y0.9695 +G01 X2.0399 Y0.9757 +G01 X2.0513 Y0.9871 +G01 X2.0575 Y1.0019 +G01 X2.0575 Y1.0181 +G01 X2.0513 Y1.0329 +G01 X2.0399 Y1.0443 +G01 X2.0251 Y1.0505 +G00 Z0.1000 +G00 X2.3251 Y1.1505 +G01 Z-0.0070 F10.00 +G01 X2.1949 Y1.1505 F20.00 +G01 X2.1801 Y1.1443 +G01 X2.1687 Y1.1329 +G01 X2.1625 Y1.1181 +G01 X2.1625 Y1.1019 +G01 X2.1687 Y1.0871 +G01 X2.1801 Y1.0757 +G01 X2.1949 Y1.0695 +G01 X2.3251 Y1.0695 +G01 X2.3399 Y1.0757 +G01 X2.3513 Y1.0871 +G01 X2.3575 Y1.1019 +G01 X2.3575 Y1.1181 +G01 X2.3513 Y1.1329 +G01 X2.3399 Y1.1443 +G01 X2.3251 Y1.1505 +G00 Z0.1000 +G00 X2.3251 Y1.0505 +G01 Z-0.0070 F10.00 +G01 X2.1949 Y1.0505 F20.00 +G01 X2.1801 Y1.0443 +G01 X2.1687 Y1.0329 +G01 X2.1625 Y1.0181 +G01 X2.1625 Y1.0019 +G01 X2.1687 Y0.9871 +G01 X2.1801 Y0.9757 +G01 X2.1949 Y0.9695 +G01 X2.3251 Y0.9695 +G01 X2.3399 Y0.9757 +G01 X2.3513 Y0.9871 +G01 X2.3575 Y1.0019 +G01 X2.3575 Y1.0181 +G01 X2.3513 Y1.0329 +G01 X2.3399 Y1.0443 +G01 X2.3251 Y1.0505 +G00 Z0.1000 +G00 X1.5465 Y1.3007 +G01 Z-0.0070 F10.00 +G01 X1.5465 Y1.3192 F20.00 +G01 X1.5394 Y1.3363 +G01 X1.5263 Y1.3494 +G01 X1.5092 Y1.3565 +G01 X1.4907 Y1.3565 +G01 X1.4737 Y1.3494 +G01 X1.4606 Y1.3363 +G01 X1.4535 Y1.3192 +G01 X1.4535 Y1.3007 +G01 X1.4606 Y1.2837 +G01 X1.4737 Y1.2706 +G01 X1.4907 Y1.2635 +G01 X1.5092 Y1.2635 +G01 X1.5263 Y1.2706 +G01 X1.5394 Y1.2837 +G01 X1.5465 Y1.3007 +G00 Z0.1000 +G00 X1.5465 Y1.7007 +G01 Z-0.0070 F10.00 +G01 X1.5465 Y1.7192 F20.00 +G01 X1.5394 Y1.7363 +G01 X1.5263 Y1.7494 +G01 X1.5092 Y1.7565 +G01 X1.4907 Y1.7565 +G01 X1.4737 Y1.7494 +G01 X1.4606 Y1.7363 +G01 X1.4535 Y1.7192 +G01 X1.4535 Y1.7007 +G01 X1.4606 Y1.6837 +G01 X1.4737 Y1.6706 +G01 X1.4907 Y1.6635 +G01 X1.5092 Y1.6635 +G01 X1.5263 Y1.6706 +G01 X1.5394 Y1.6837 +G01 X1.5465 Y1.7007 +G00 Z0.1000 +G00 X1.8665 Y0.4907 +G01 Z-0.0070 F10.00 +G01 X1.8665 Y0.5092 F20.00 +G01 X1.8594 Y0.5263 +G01 X1.8463 Y0.5394 +G01 X1.8292 Y0.5465 +G01 X1.8107 Y0.5465 +G01 X1.7937 Y0.5394 +G01 X1.7806 Y0.5263 +G01 X1.7735 Y0.5092 +G01 X1.7735 Y0.4907 +G01 X1.7806 Y0.4737 +G01 X1.7937 Y0.4606 +G01 X1.8107 Y0.4535 +G01 X1.8292 Y0.4535 +G01 X1.8463 Y0.4606 +G01 X1.8594 Y0.4737 +G01 X1.8665 Y0.4907 +G00 Z0.1000 +G00 X1.4665 Y0.4907 +G01 Z-0.0070 F10.00 +G01 X1.4665 Y0.5092 F20.00 +G01 X1.4594 Y0.5263 +G01 X1.4463 Y0.5394 +G01 X1.4292 Y0.5465 +G01 X1.4107 Y0.5465 +G01 X1.3937 Y0.5394 +G01 X1.3806 Y0.5263 +G01 X1.3735 Y0.5092 +G01 X1.3735 Y0.4907 +G01 X1.3806 Y0.4737 +G01 X1.3937 Y0.4606 +G01 X1.4107 Y0.4535 +G01 X1.4292 Y0.4535 +G01 X1.4463 Y0.4606 +G01 X1.4594 Y0.4737 +G01 X1.4665 Y0.4907 +G00 Z0.1000 +G00 X1.8665 Y0.3307 +G01 Z-0.0070 F10.00 +G01 X1.8665 Y0.3492 F20.00 +G01 X1.8594 Y0.3663 +G01 X1.8463 Y0.3794 +G01 X1.8292 Y0.3865 +G01 X1.8107 Y0.3865 +G01 X1.7937 Y0.3794 +G01 X1.7806 Y0.3663 +G01 X1.7735 Y0.3492 +G01 X1.7735 Y0.3307 +G01 X1.7806 Y0.3137 +G01 X1.7937 Y0.3006 +G01 X1.8107 Y0.2935 +G01 X1.8292 Y0.2935 +G01 X1.8463 Y0.3006 +G01 X1.8594 Y0.3137 +G01 X1.8665 Y0.3307 +G00 Z0.1000 +G00 X1.4665 Y0.3307 +G01 Z-0.0070 F10.00 +G01 X1.4665 Y0.3492 F20.00 +G01 X1.4594 Y0.3663 +G01 X1.4463 Y0.3794 +G01 X1.4292 Y0.3865 +G01 X1.4107 Y0.3865 +G01 X1.3937 Y0.3794 +G01 X1.3806 Y0.3663 +G01 X1.3735 Y0.3492 +G01 X1.3735 Y0.3307 +G01 X1.3806 Y0.3137 +G01 X1.3937 Y0.3006 +G01 X1.4107 Y0.2935 +G01 X1.4292 Y0.2935 +G01 X1.4463 Y0.3006 +G01 X1.4594 Y0.3137 +G01 X1.4665 Y0.3307 +G00 Z0.1000 +G00 X2.0565 Y0.2507 +G01 Z-0.0070 F10.00 +G01 X2.0565 Y0.2692 F20.00 +G01 X2.0494 Y0.2863 +G01 X2.0363 Y0.2994 +G01 X2.0192 Y0.3065 +G01 X2.0007 Y0.3065 +G01 X1.9837 Y0.2994 +G01 X1.9706 Y0.2863 +G01 X1.9635 Y0.2692 +G01 X1.9635 Y0.2507 +G01 X1.9706 Y0.2337 +G01 X1.9837 Y0.2206 +G01 X2.0007 Y0.2135 +G01 X2.0192 Y0.2135 +G01 X2.0363 Y0.2206 +G01 X2.0494 Y0.2337 +G01 X2.0565 Y0.2507 +G00 Z0.1000 +G00 X2.0565 Y0.6507 +G01 Z-0.0070 F10.00 +G01 X2.0565 Y0.6692 F20.00 +G01 X2.0494 Y0.6863 +G01 X2.0363 Y0.6994 +G01 X2.0192 Y0.7065 +G01 X2.0007 Y0.7065 +G01 X1.9837 Y0.6994 +G01 X1.9706 Y0.6863 +G01 X1.9635 Y0.6692 +G01 X1.9635 Y0.6507 +G01 X1.9706 Y0.6337 +G01 X1.9837 Y0.6206 +G01 X2.0007 Y0.6135 +G01 X2.0192 Y0.6135 +G01 X2.0363 Y0.6206 +G01 X2.0494 Y0.6337 +G01 X2.0565 Y0.6507 +G00 Z0.1000 +G00 X3.2005 Y1.5932 +G01 Z-0.0070 F10.00 +G01 X3.2005 Y1.6268 F20.00 +G01 X3.1768 Y1.6505 +G01 X3.1432 Y1.6505 +G01 X3.1195 Y1.6268 +G01 X3.1195 Y1.5932 +G01 X3.1432 Y1.5695 +G01 X3.1768 Y1.5695 +G01 X3.2005 Y1.5932 +G00 Z0.1000 +G00 X2.7005 Y1.5932 +G01 Z-0.0070 F10.00 +G01 X2.7005 Y1.6268 F20.00 +G01 X2.6768 Y1.6505 +G01 X2.6432 Y1.6505 +G01 X2.6195 Y1.6268 +G01 X2.6195 Y1.5932 +G01 X2.6432 Y1.5695 +G01 X2.6768 Y1.5695 +G01 X2.7005 Y1.5932 +G00 Z0.1000 +G00 X1.0151 Y1.4505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.4505 F20.00 +G01 X0.8701 Y1.4443 +G01 X0.8587 Y1.4329 +G01 X0.8525 Y1.4181 +G01 X0.8525 Y1.4019 +G01 X0.8587 Y1.3871 +G01 X0.8701 Y1.3757 +G01 X0.8849 Y1.3695 +G01 X1.0151 Y1.3695 +G01 X1.0299 Y1.3757 +G01 X1.0413 Y1.3871 +G01 X1.0475 Y1.4019 +G01 X1.0475 Y1.4181 +G01 X1.0413 Y1.4329 +G01 X1.0299 Y1.4443 +G01 X1.0151 Y1.4505 +G00 Z0.1000 +G00 X1.0151 Y1.3505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.3505 F20.00 +G01 X0.8701 Y1.3443 +G01 X0.8587 Y1.3329 +G01 X0.8525 Y1.3181 +G01 X0.8525 Y1.3019 +G01 X0.8587 Y1.2871 +G01 X0.8701 Y1.2757 +G01 X0.8849 Y1.2695 +G01 X1.0151 Y1.2695 +G01 X1.0299 Y1.2757 +G01 X1.0413 Y1.2871 +G01 X1.0475 Y1.3019 +G01 X1.0475 Y1.3181 +G01 X1.0413 Y1.3329 +G01 X1.0299 Y1.3443 +G01 X1.0151 Y1.3505 +G00 Z0.1000 +G00 X1.0151 Y0.8505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y0.8505 F20.00 +G01 X0.8701 Y0.8443 +G01 X0.8587 Y0.8329 +G01 X0.8525 Y0.8181 +G01 X0.8525 Y0.8019 +G01 X0.8587 Y0.7871 +G01 X0.8701 Y0.7757 +G01 X0.8849 Y0.7695 +G01 X1.0151 Y0.7695 +G01 X1.0299 Y0.7757 +G01 X1.0413 Y0.7871 +G01 X1.0475 Y0.8019 +G01 X1.0475 Y0.8181 +G01 X1.0413 Y0.8329 +G01 X1.0299 Y0.8443 +G01 X1.0151 Y0.8505 +G00 Z0.1000 +G00 X1.3151 Y0.8505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y0.8505 F20.00 +G01 X1.1701 Y0.8443 +G01 X1.1587 Y0.8329 +G01 X1.1525 Y0.8181 +G01 X1.1525 Y0.8019 +G01 X1.1587 Y0.7871 +G01 X1.1701 Y0.7757 +G01 X1.1849 Y0.7695 +G01 X1.3151 Y0.7695 +G01 X1.3299 Y0.7757 +G01 X1.3413 Y0.7871 +G01 X1.3475 Y0.8019 +G01 X1.3475 Y0.8181 +G01 X1.3413 Y0.8329 +G01 X1.3299 Y0.8443 +G01 X1.3151 Y0.8505 +G00 Z0.1000 +G00 X1.0151 Y1.2505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.2505 F20.00 +G01 X0.8701 Y1.2443 +G01 X0.8587 Y1.2329 +G01 X0.8525 Y1.2181 +G01 X0.8525 Y1.2019 +G01 X0.8587 Y1.1871 +G01 X0.8701 Y1.1757 +G01 X0.8849 Y1.1695 +G01 X1.0151 Y1.1695 +G01 X1.0299 Y1.1757 +G01 X1.0413 Y1.1871 +G01 X1.0475 Y1.2019 +G01 X1.0475 Y1.2181 +G01 X1.0413 Y1.2329 +G01 X1.0299 Y1.2443 +G01 X1.0151 Y1.2505 +G00 Z0.1000 +G00 X1.0151 Y1.1505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.1505 F20.00 +G01 X0.8701 Y1.1443 +G01 X0.8587 Y1.1329 +G01 X0.8525 Y1.1181 +G01 X0.8525 Y1.1019 +G01 X0.8587 Y1.0871 +G01 X0.8701 Y1.0757 +G01 X0.8849 Y1.0695 +G01 X1.0151 Y1.0695 +G01 X1.0299 Y1.0757 +G01 X1.0413 Y1.0871 +G01 X1.0475 Y1.1019 +G01 X1.0475 Y1.1181 +G01 X1.0413 Y1.1329 +G01 X1.0299 Y1.1443 +G01 X1.0151 Y1.1505 +G00 Z0.1000 +G00 X1.0151 Y0.9505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y0.9505 F20.00 +G01 X0.8701 Y0.9443 +G01 X0.8587 Y0.9329 +G01 X0.8525 Y0.9181 +G01 X0.8525 Y0.9019 +G01 X0.8587 Y0.8871 +G01 X0.8701 Y0.8757 +G01 X0.8849 Y0.8695 +G01 X1.0151 Y0.8695 +G01 X1.0299 Y0.8757 +G01 X1.0413 Y0.8871 +G01 X1.0475 Y0.9019 +G01 X1.0475 Y0.9181 +G01 X1.0413 Y0.9329 +G01 X1.0299 Y0.9443 +G01 X1.0151 Y0.9505 +G00 Z0.1000 +G00 X1.0151 Y1.0505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.0505 F20.00 +G01 X0.8701 Y1.0443 +G01 X0.8587 Y1.0329 +G01 X0.8525 Y1.0181 +G01 X0.8525 Y1.0019 +G01 X0.8587 Y0.9871 +G01 X0.8701 Y0.9757 +G01 X0.8849 Y0.9695 +G01 X1.0151 Y0.9695 +G01 X1.0299 Y0.9757 +G01 X1.0413 Y0.9871 +G01 X1.0475 Y1.0019 +G01 X1.0475 Y1.0181 +G01 X1.0413 Y1.0329 +G01 X1.0299 Y1.0443 +G01 X1.0151 Y1.0505 +G00 Z0.1000 +G00 X1.3151 Y0.9505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y0.9505 F20.00 +G01 X1.1701 Y0.9443 +G01 X1.1587 Y0.9329 +G01 X1.1525 Y0.9181 +G01 X1.1525 Y0.9019 +G01 X1.1587 Y0.8871 +G01 X1.1701 Y0.8757 +G01 X1.1849 Y0.8695 +G01 X1.3151 Y0.8695 +G01 X1.3299 Y0.8757 +G01 X1.3413 Y0.8871 +G01 X1.3475 Y0.9019 +G01 X1.3475 Y0.9181 +G01 X1.3413 Y0.9329 +G01 X1.3299 Y0.9443 +G01 X1.3151 Y0.9505 +G00 Z0.1000 +G00 X1.3151 Y1.0505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.0505 F20.00 +G01 X1.1701 Y1.0443 +G01 X1.1587 Y1.0329 +G01 X1.1525 Y1.0181 +G01 X1.1525 Y1.0019 +G01 X1.1587 Y0.9871 +G01 X1.1701 Y0.9757 +G01 X1.1849 Y0.9695 +G01 X1.3151 Y0.9695 +G01 X1.3299 Y0.9757 +G01 X1.3413 Y0.9871 +G01 X1.3475 Y1.0019 +G01 X1.3475 Y1.0181 +G01 X1.3413 Y1.0329 +G01 X1.3299 Y1.0443 +G01 X1.3151 Y1.0505 +G00 Z0.1000 +G00 X1.3151 Y1.1505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.1505 F20.00 +G01 X1.1701 Y1.1443 +G01 X1.1587 Y1.1329 +G01 X1.1525 Y1.1181 +G01 X1.1525 Y1.1019 +G01 X1.1587 Y1.0871 +G01 X1.1701 Y1.0757 +G01 X1.1849 Y1.0695 +G01 X1.3151 Y1.0695 +G01 X1.3299 Y1.0757 +G01 X1.3413 Y1.0871 +G01 X1.3475 Y1.1019 +G01 X1.3475 Y1.1181 +G01 X1.3413 Y1.1329 +G01 X1.3299 Y1.1443 +G01 X1.3151 Y1.1505 +G00 Z0.1000 +G00 X1.3151 Y1.2505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.2505 F20.00 +G01 X1.1701 Y1.2443 +G01 X1.1587 Y1.2329 +G01 X1.1525 Y1.2181 +G01 X1.1525 Y1.2019 +G01 X1.1587 Y1.1871 +G01 X1.1701 Y1.1757 +G01 X1.1849 Y1.1695 +G01 X1.3151 Y1.1695 +G01 X1.3299 Y1.1757 +G01 X1.3413 Y1.1871 +G01 X1.3475 Y1.2019 +G01 X1.3475 Y1.2181 +G01 X1.3413 Y1.2329 +G01 X1.3299 Y1.2443 +G01 X1.3151 Y1.2505 +G00 Z0.1000 +G00 X1.3151 Y1.3505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.3505 F20.00 +G01 X1.1701 Y1.3443 +G01 X1.1587 Y1.3329 +G01 X1.1525 Y1.3181 +G01 X1.1525 Y1.3019 +G01 X1.1587 Y1.2871 +G01 X1.1701 Y1.2757 +G01 X1.1849 Y1.2695 +G01 X1.3151 Y1.2695 +G01 X1.3299 Y1.2757 +G01 X1.3413 Y1.2871 +G01 X1.3475 Y1.3019 +G01 X1.3475 Y1.3181 +G01 X1.3413 Y1.3329 +G01 X1.3299 Y1.3443 +G01 X1.3151 Y1.3505 +G00 Z0.1000 +G00 X1.3151 Y1.4505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.4505 F20.00 +G01 X1.1701 Y1.4443 +G01 X1.1587 Y1.4329 +G01 X1.1525 Y1.4181 +G01 X1.1525 Y1.4019 +G01 X1.1587 Y1.3871 +G01 X1.1701 Y1.3757 +G01 X1.1849 Y1.3695 +G01 X1.3151 Y1.3695 +G01 X1.3299 Y1.3757 +G01 X1.3413 Y1.3871 +G01 X1.3475 Y1.4019 +G01 X1.3475 Y1.4181 +G01 X1.3413 Y1.4329 +G01 X1.3299 Y1.4443 +G01 X1.3151 Y1.4505 +G00 Z0.1000 +G00 X0.2778 Y1.3564 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y1.3564 F20.00 +G01 X0.1046 Y1.3491 +G01 X0.0911 Y1.3356 +G01 X0.0838 Y1.3180 +G01 X0.0838 Y1.2989 +G01 X0.0911 Y1.2812 +G01 X0.1046 Y1.2677 +G01 X0.1222 Y1.2604 +G01 X0.2778 Y1.2604 +G01 X0.2954 Y1.2677 +G01 X0.3089 Y1.2812 +G01 X0.3162 Y1.2989 +G01 X0.3162 Y1.3180 +G01 X0.3089 Y1.3356 +G01 X0.2954 Y1.3491 +G01 X0.2778 Y1.3564 +G00 Z0.1000 +G00 X0.2778 Y1.1596 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y1.1596 F20.00 +G01 X0.1046 Y1.1523 +G01 X0.0911 Y1.1388 +G01 X0.0838 Y1.1211 +G01 X0.0838 Y1.1020 +G01 X0.0911 Y1.0844 +G01 X0.1046 Y1.0709 +G01 X0.1222 Y1.0636 +G01 X0.2778 Y1.0636 +G01 X0.2954 Y1.0709 +G01 X0.3089 Y1.0844 +G01 X0.3162 Y1.1020 +G01 X0.3162 Y1.1211 +G01 X0.3089 Y1.1388 +G01 X0.2954 Y1.1523 +G01 X0.2778 Y1.1596 +G00 Z0.1000 +G00 X0.2778 Y0.9564 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y0.9564 F20.00 +G01 X0.1046 Y0.9491 +G01 X0.0911 Y0.9356 +G01 X0.0838 Y0.9180 +G01 X0.0838 Y0.8989 +G01 X0.0911 Y0.8812 +G01 X0.1046 Y0.8677 +G01 X0.1222 Y0.8604 +G01 X0.2778 Y0.8604 +G01 X0.2954 Y0.8677 +G01 X0.3089 Y0.8812 +G01 X0.3162 Y0.8989 +G01 X0.3162 Y0.9180 +G01 X0.3089 Y0.9356 +G01 X0.2954 Y0.9491 +G01 X0.2778 Y0.9564 +G00 Z0.1000 +G00 X0.2778 Y0.7596 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y0.7596 F20.00 +G01 X0.1046 Y0.7523 +G01 X0.0911 Y0.7388 +G01 X0.0838 Y0.7211 +G01 X0.0838 Y0.7020 +G01 X0.0911 Y0.6844 +G01 X0.1046 Y0.6709 +G01 X0.1222 Y0.6636 +G01 X0.2778 Y0.6636 +G01 X0.2954 Y0.6709 +G01 X0.3089 Y0.6844 +G01 X0.3162 Y0.7020 +G01 X0.3162 Y0.7211 +G01 X0.3089 Y0.7388 +G01 X0.2954 Y0.7523 +G01 X0.2778 Y0.7596 +G00 Z0.1000 +G00 X2.8422 Y0.5036 +G01 Z-0.0070 F10.00 +G01 X2.9978 Y0.5036 F20.00 +G01 X3.0154 Y0.5109 +G01 X3.0289 Y0.5244 +G01 X3.0362 Y0.5420 +G01 X3.0362 Y0.5611 +G01 X3.0289 Y0.5788 +G01 X3.0154 Y0.5923 +G01 X2.9978 Y0.5996 +G01 X2.8422 Y0.5996 +G01 X2.8246 Y0.5923 +G01 X2.8111 Y0.5788 +G01 X2.8038 Y0.5611 +G01 X2.8038 Y0.5420 +G01 X2.8111 Y0.5244 +G01 X2.8246 Y0.5109 +G01 X2.8422 Y0.5036 +G00 Z0.1000 +G00 X2.8422 Y0.7004 +G01 Z-0.0070 F10.00 +G01 X2.9978 Y0.7004 F20.00 +G01 X3.0154 Y0.7077 +G01 X3.0289 Y0.7212 +G01 X3.0362 Y0.7389 +G01 X3.0362 Y0.7580 +G01 X3.0289 Y0.7756 +G01 X3.0154 Y0.7891 +G01 X2.9978 Y0.7964 +G01 X2.8422 Y0.7964 +G01 X2.8246 Y0.7891 +G01 X2.8111 Y0.7756 +G01 X2.8038 Y0.7580 +G01 X2.8038 Y0.7389 +G01 X2.8111 Y0.7212 +G01 X2.8246 Y0.7077 +G01 X2.8422 Y0.7004 +G00 Z0.1000 +G00 X0.2778 Y1.8364 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y1.8364 F20.00 +G01 X0.1046 Y1.8291 +G01 X0.0911 Y1.8156 +G01 X0.0838 Y1.7980 +G01 X0.0838 Y1.7789 +G01 X0.0911 Y1.7612 +G01 X0.1046 Y1.7477 +G01 X0.1222 Y1.7404 +G01 X0.2778 Y1.7404 +G01 X0.2954 Y1.7477 +G01 X0.3089 Y1.7612 +G01 X0.3162 Y1.7789 +G01 X0.3162 Y1.7980 +G01 X0.3089 Y1.8156 +G01 X0.2954 Y1.8291 +G01 X0.2778 Y1.8364 +G00 Z0.1000 +G00 X0.2778 Y1.6396 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y1.6396 F20.00 +G01 X0.1046 Y1.6323 +G01 X0.0911 Y1.6188 +G01 X0.0838 Y1.6011 +G01 X0.0838 Y1.5820 +G01 X0.0911 Y1.5644 +G01 X0.1046 Y1.5509 +G01 X0.1222 Y1.5436 +G01 X0.2778 Y1.5436 +G01 X0.2954 Y1.5509 +G01 X0.3089 Y1.5644 +G01 X0.3162 Y1.5820 +G01 X0.3162 Y1.6011 +G01 X0.3089 Y1.6188 +G01 X0.2954 Y1.6323 +G01 X0.2778 Y1.6396 +G00 Z0.1000 +G00 X0.7605 Y1.2932 +G01 Z-0.0070 F10.00 +G01 X0.7605 Y1.3268 F20.00 +G01 X0.7368 Y1.3505 +G01 X0.7032 Y1.3505 +G01 X0.6795 Y1.3268 +G01 X0.6795 Y1.2932 +G01 X0.7032 Y1.2695 +G01 X0.7368 Y1.2695 +G01 X0.7605 Y1.2932 +G00 Z0.1000 +G00 X0.7605 Y1.4932 +G01 Z-0.0070 F10.00 +G01 X0.7605 Y1.5268 F20.00 +G01 X0.7368 Y1.5505 +G01 X0.7032 Y1.5505 +G01 X0.6795 Y1.5268 +G01 X0.6795 Y1.4932 +G01 X0.7032 Y1.4695 +G01 X0.7368 Y1.4695 +G01 X0.7605 Y1.4932 +G00 Z0.1000 +G00 X0.6005 Y1.0932 +G01 Z-0.0070 F10.00 +G01 X0.6005 Y1.1268 F20.00 +G01 X0.5768 Y1.1505 +G01 X0.5432 Y1.1505 +G01 X0.5195 Y1.1268 +G01 X0.5195 Y1.0932 +G01 X0.5432 Y1.0695 +G01 X0.5768 Y1.0695 +G01 X0.6005 Y1.0932 +G00 Z0.1000 +G00 X0.6005 Y0.8932 +G01 Z-0.0070 F10.00 +G01 X0.6005 Y0.9268 F20.00 +G01 X0.5768 Y0.9505 +G01 X0.5432 Y0.9505 +G01 X0.5195 Y0.9268 +G01 X0.5195 Y0.8932 +G01 X0.5432 Y0.8695 +G01 X0.5768 Y0.8695 +G01 X0.6005 Y0.8932 +G00 Z0.1000 +G00 X0.8205 Y0.5232 +G01 Z-0.0070 F10.00 +G01 X0.8205 Y0.5568 F20.00 +G01 X0.7968 Y0.5805 +G01 X0.7632 Y0.5805 +G01 X0.7395 Y0.5568 +G01 X0.7395 Y0.5232 +G01 X0.7632 Y0.4995 +G01 X0.7968 Y0.4995 +G01 X0.8205 Y0.5232 +G00 Z0.1000 +G00 X0.8205 Y0.3232 +G01 Z-0.0070 F10.00 +G01 X0.8205 Y0.3568 F20.00 +G01 X0.7968 Y0.3805 +G01 X0.7632 Y0.3805 +G01 X0.7395 Y0.3568 +G01 X0.7395 Y0.3232 +G01 X0.7632 Y0.2995 +G01 X0.7968 Y0.2995 +G01 X0.8205 Y0.3232 +G00 Z0.1000 +G00 X1.5905 Y0.6432 +G01 Z-0.0070 F10.00 +G01 X1.5905 Y0.6768 F20.00 +G01 X1.5668 Y0.7005 +G01 X1.5332 Y0.7005 +G01 X1.5095 Y0.6768 +G01 X1.5095 Y0.6432 +G01 X1.5332 Y0.6195 +G01 X1.5668 Y0.6195 +G01 X1.5905 Y0.6432 +G00 Z0.1000 +G00 X1.7905 Y0.6432 +G01 Z-0.0070 F10.00 +G01 X1.7905 Y0.6768 F20.00 +G01 X1.7668 Y0.7005 +G01 X1.7332 Y0.7005 +G01 X1.7095 Y0.6768 +G01 X1.7095 Y0.6432 +G01 X1.7332 Y0.6195 +G01 X1.7668 Y0.6195 +G01 X1.7905 Y0.6432 +G00 Z0.1000 +G00 X2.7105 Y0.7332 +G01 Z-0.0070 F10.00 +G01 X2.7105 Y0.7668 F20.00 +G01 X2.6868 Y0.7905 +G01 X2.6532 Y0.7905 +G01 X2.6295 Y0.7668 +G01 X2.6295 Y0.7332 +G01 X2.6532 Y0.7095 +G01 X2.6868 Y0.7095 +G01 X2.7105 Y0.7332 +G00 Z0.1000 +G00 X2.7105 Y1.2332 +G01 Z-0.0070 F10.00 +G01 X2.7105 Y1.2668 F20.00 +G01 X2.6868 Y1.2905 +G01 X2.6532 Y1.2905 +G01 X2.6295 Y1.2668 +G01 X2.6295 Y1.2332 +G01 X2.6532 Y1.2095 +G01 X2.6868 Y1.2095 +G01 X2.7105 Y1.2332 +G00 Z0.1000 +G00 X2.7105 Y1.8032 +G01 Z-0.0070 F10.00 +G01 X2.7105 Y1.8368 F20.00 +G01 X2.6868 Y1.8605 +G01 X2.6532 Y1.8605 +G01 X2.6295 Y1.8368 +G01 X2.6295 Y1.8032 +G01 X2.6532 Y1.7795 +G01 X2.6868 Y1.7795 +G01 X2.7105 Y1.8032 +G00 Z0.1000 +G00 X2.7105 Y1.7032 +G01 Z-0.0070 F10.00 +G01 X2.7105 Y1.7368 F20.00 +G01 X2.6868 Y1.7605 +G01 X2.6532 Y1.7605 +G01 X2.6295 Y1.7368 +G01 X2.6295 Y1.7032 +G01 X2.6532 Y1.6795 +G01 X2.6868 Y1.6795 +G01 X2.7105 Y1.7032 +G00 Z0.1000 +G00 X2.9905 Y1.1132 +G01 Z-0.0070 F10.00 +G01 X2.9905 Y1.1468 F20.00 +G01 X2.9668 Y1.1705 +G01 X2.9332 Y1.1705 +G01 X2.9095 Y1.1468 +G01 X2.9095 Y1.1132 +G01 X2.9332 Y1.0895 +G01 X2.9668 Y1.0895 +G01 X2.9905 Y1.1132 +G00 Z0.1000 +G00 X2.9905 Y1.3132 +G01 Z-0.0070 F10.00 +G01 X2.9905 Y1.3468 F20.00 +G01 X2.9668 Y1.3705 +G01 X2.9332 Y1.3705 +G01 X2.9095 Y1.3468 +G01 X2.9095 Y1.3132 +G01 X2.9332 Y1.2895 +G01 X2.9668 Y1.2895 +G01 X2.9905 Y1.3132 +G00 Z0.1000 +G00 X1.8105 Y1.1832 +G01 Z-0.0070 F10.00 +G01 X1.8105 Y1.2168 F20.00 +G01 X1.7868 Y1.2405 +G01 X1.7532 Y1.2405 +G01 X1.7295 Y1.2168 +G01 X1.7295 Y1.1832 +G01 X1.7532 Y1.1595 +G01 X1.7868 Y1.1595 +G01 X1.8105 Y1.1832 +G00 Z0.1000 +G00 X1.8105 Y1.6832 +G01 Z-0.0070 F10.00 +G01 X1.8105 Y1.7168 F20.00 +G01 X1.7868 Y1.7405 +G01 X1.7532 Y1.7405 +G01 X1.7295 Y1.7168 +G01 X1.7295 Y1.6832 +G01 X1.7532 Y1.6595 +G01 X1.7868 Y1.6595 +G01 X1.8105 Y1.6832 +G00 Z0.1000 +G00 X2.0405 Y1.8932 +G01 Z-0.0070 F10.00 +G01 X2.0405 Y1.9268 F20.00 +G01 X2.0168 Y1.9505 +G01 X1.9832 Y1.9505 +G01 X1.9595 Y1.9268 +G01 X1.9595 Y1.8932 +G01 X1.9832 Y1.8695 +G01 X2.0168 Y1.8695 +G01 X2.0405 Y1.8932 +G00 Z0.1000 +G00 X1.5405 Y1.8932 +G01 Z-0.0070 F10.00 +G01 X1.5405 Y1.9268 F20.00 +G01 X1.5168 Y1.9505 +G01 X1.4832 Y1.9505 +G01 X1.4595 Y1.9268 +G01 X1.4595 Y1.8932 +G01 X1.4832 Y1.8695 +G01 X1.5168 Y1.8695 +G01 X1.5405 Y1.8932 +G00 Z0.1000 +G00 X1.4705 Y1.1932 +G01 Z-0.0070 F10.00 +G01 X1.4705 Y1.2268 F20.00 +G01 X1.4468 Y1.2505 +G01 X1.4132 Y1.2505 +G01 X1.3895 Y1.2268 +G01 X1.3895 Y1.1932 +G01 X1.4132 Y1.1695 +G01 X1.4468 Y1.1695 +G01 X1.4705 Y1.1932 +G00 Z0.1000 +G00 X1.4705 Y0.6932 +G01 Z-0.0070 F10.00 +G01 X1.4705 Y0.7268 F20.00 +G01 X1.4468 Y0.7505 +G01 X1.4132 Y0.7505 +G01 X1.3895 Y0.7268 +G01 X1.3895 Y0.6932 +G01 X1.4132 Y0.6695 +G01 X1.4468 Y0.6695 +G01 X1.4705 Y0.6932 +G00 Z0.1000 +G00 X1.8605 Y0.1832 +G01 Z-0.0070 F10.00 +G01 X1.8605 Y0.2168 F20.00 +G01 X1.8368 Y0.2405 +G01 X1.8032 Y0.2405 +G01 X1.7795 Y0.2168 +G01 X1.7795 Y0.1832 +G01 X1.8032 Y0.1595 +G01 X1.8368 Y0.1595 +G01 X1.8605 Y0.1832 +G00 Z0.1000 +G00 X1.3605 Y0.1832 +G01 Z-0.0070 F10.00 +G01 X1.3605 Y0.2168 F20.00 +G01 X1.3368 Y0.2405 +G01 X1.3032 Y0.2405 +G01 X1.2795 Y0.2168 +G01 X1.2795 Y0.1832 +G01 X1.3032 Y0.1595 +G01 X1.3368 Y0.1595 +G01 X1.3605 Y0.1832 +G00 Z0.1000 +G00 X2.6805 Y0.2432 +G01 Z-0.0070 F10.00 +G01 X2.6805 Y0.2768 F20.00 +G01 X2.6568 Y0.3005 +G01 X2.6232 Y0.3005 +G01 X2.5995 Y0.2768 +G01 X2.5995 Y0.2432 +G01 X2.6232 Y0.2195 +G01 X2.6568 Y0.2195 +G01 X2.6805 Y0.2432 +G00 Z0.1000 +G00 X2.1805 Y0.2432 +G01 Z-0.0070 F10.00 +G01 X2.1805 Y0.2768 F20.00 +G01 X2.1568 Y0.3005 +G01 X2.1232 Y0.3005 +G01 X2.0995 Y0.2768 +G01 X2.0995 Y0.2432 +G01 X2.1232 Y0.2195 +G01 X2.1568 Y0.2195 +G01 X2.1805 Y0.2432 +G00 Z0.1000 +G00 X2.3805 Y1.7232 +G01 Z-0.0070 F10.00 +G01 X2.3805 Y1.7568 F20.00 +G01 X2.3568 Y1.7805 +G01 X2.3232 Y1.7805 +G01 X2.2995 Y1.7568 +G01 X2.2995 Y1.7232 +G01 X2.3232 Y1.6995 +G01 X2.3568 Y1.6995 +G01 X2.3805 Y1.7232 +G00 Z0.1000 +G00 X2.4805 Y1.7232 +G01 Z-0.0070 F10.00 +G01 X2.4805 Y1.7568 F20.00 +G01 X2.4568 Y1.7805 +G01 X2.4232 Y1.7805 +G01 X2.3995 Y1.7568 +G01 X2.3995 Y1.7232 +G01 X2.4232 Y1.6995 +G01 X2.4568 Y1.6995 +G01 X2.4805 Y1.7232 +G00 Z0.1000 +G00 X2.9450 Y1.4310 +G01 Z-0.0070 F10.00 +G01 X2.9450 Y1.4489 F20.00 +G01 X2.9381 Y1.4655 +G01 X2.9255 Y1.4781 +G01 X2.9089 Y1.4850 +G01 X2.8910 Y1.4850 +G01 X2.8745 Y1.4781 +G01 X2.8619 Y1.4655 +G01 X2.8550 Y1.4489 +G01 X2.8550 Y1.4310 +G01 X2.8619 Y1.4145 +G01 X2.8745 Y1.4019 +G01 X2.8910 Y1.3950 +G01 X2.9089 Y1.3950 +G01 X2.9255 Y1.4019 +G01 X2.9381 Y1.4145 +G01 X2.9450 Y1.4310 +G00 Z0.1000 +G00 X2.3450 Y1.4214 +G01 Z-0.0070 F10.00 +G01 X2.3450 Y1.4586 F20.00 +G01 X2.3186 Y1.4850 +G01 X2.2814 Y1.4850 +G01 X2.2550 Y1.4586 +G01 X2.2550 Y1.4214 +G01 X2.2814 Y1.3950 +G01 X2.3186 Y1.3950 +G01 X2.3450 Y1.4214 +G00 Z0.1000 +G00 X0.8050 Y1.8510 +G01 Z-0.0070 F10.00 +G01 X0.8050 Y1.8689 F20.00 +G01 X0.7981 Y1.8855 +G01 X0.7855 Y1.8981 +G01 X0.7689 Y1.9050 +G01 X0.7510 Y1.9050 +G01 X0.7345 Y1.8981 +G01 X0.7219 Y1.8855 +G01 X0.7150 Y1.8689 +G01 X0.7150 Y1.8510 +G01 X0.7219 Y1.8345 +G01 X0.7345 Y1.8219 +G01 X0.7510 Y1.8150 +G01 X0.7689 Y1.8150 +G01 X0.7855 Y1.8219 +G01 X0.7981 Y1.8345 +G01 X0.8050 Y1.8510 +G00 Z0.1000 +G00 X1.4050 Y1.8414 +G01 Z-0.0070 F10.00 +G01 X1.4050 Y1.8786 F20.00 +G01 X1.3786 Y1.9050 +G01 X1.3414 Y1.9050 +G01 X1.3150 Y1.8786 +G01 X1.3150 Y1.8414 +G01 X1.3414 Y1.8150 +G01 X1.3786 Y1.8150 +G01 X1.4050 Y1.8414 +G00 Z0.1000 +G00 X2.2543 Y1.4516 +G01 Z-0.0070 F10.00 +G01 X2.2543 Y1.4884 F20.00 +G01 X2.2375 Y1.5052 +G01 X2.2375 Y1.7048 +G01 X2.2543 Y1.7216 +G01 X2.2543 Y1.7584 +G01 X2.2284 Y1.7843 +G01 X2.1916 Y1.7843 +G01 X2.1657 Y1.7584 +G01 X2.1657 Y1.7216 +G01 X2.1825 Y1.7048 +G01 X2.1825 Y1.5052 +G01 X2.1657 Y1.4884 +G01 X2.1657 Y1.4516 +G01 X2.1916 Y1.4257 +G01 X2.2284 Y1.4257 +G01 X2.2543 Y1.4516 +G00 Z0.1000 +G00 X2.0143 Y1.4516 +G01 Z-0.0070 F10.00 +G01 X2.0143 Y1.4884 F20.00 +G01 X1.9975 Y1.5052 +G01 X1.9975 Y1.7548 +G01 X2.0143 Y1.7716 +G01 X2.0143 Y1.8084 +G01 X1.9884 Y1.8343 +G01 X1.9516 Y1.8343 +G01 X1.9257 Y1.8084 +G01 X1.9257 Y1.7716 +G01 X1.9425 Y1.7548 +G01 X1.9425 Y1.5052 +G01 X1.9257 Y1.4884 +G01 X1.9257 Y1.4516 +G01 X1.9516 Y1.4257 +G01 X1.9884 Y1.4257 +G01 X2.0143 Y1.4516 +G00 Z0.1000 +G00 X2.5543 Y0.8916 +G01 Z-0.0070 F10.00 +G01 X2.5543 Y0.9284 F20.00 +G01 X2.5284 Y0.9543 +G01 X2.4916 Y0.9543 +G01 X2.4657 Y0.9284 +G01 X2.4657 Y0.8916 +G01 X2.4825 Y0.8748 +G01 X2.4825 Y0.4952 +G01 X2.4657 Y0.4784 +G01 X2.4657 Y0.4416 +G01 X2.4916 Y0.4157 +G01 X2.5284 Y0.4157 +G01 X2.5543 Y0.4416 +G01 X2.5543 Y0.4784 +G01 X2.5375 Y0.4952 +G01 X2.5375 Y0.8748 +G01 X2.5543 Y0.8916 +G00 Z0.1000 +G00 X1.6125 Y0.9246 +G01 Z-0.0070 F10.00 +G01 X1.6125 Y0.9246 F20.00 +G01 X1.6243 Y0.8961 +G01 X1.6461 Y0.8743 +G01 X1.6746 Y0.8625 +G01 X1.6845 Y0.8625 +G01 X1.6900 Y0.8625 +G01 X1.6955 Y0.8625 +G01 X1.8500 Y0.8625 +G01 X1.8544 Y0.8621 +G01 X1.8625 Y0.8587 +G01 X1.8687 Y0.8525 +G01 X1.8721 Y0.8444 +G01 X1.8725 Y0.8400 +G01 X1.8725 Y0.8368 +G01 X1.8725 Y0.8345 +G01 X1.8725 Y0.6052 +G01 X1.8557 Y0.5884 +G01 X1.8557 Y0.5516 +G01 X1.8816 Y0.5257 +G01 X1.9184 Y0.5257 +G01 X1.9443 Y0.5516 +G01 X1.9443 Y0.5884 +G01 X1.9275 Y0.6052 +G01 X1.9275 Y0.8345 +G01 X1.9275 Y0.8369 +G01 X1.9275 Y0.8455 +G01 X1.9275 Y0.8554 +G01 X1.9157 Y0.8839 +G01 X1.8939 Y0.9057 +G01 X1.8654 Y0.9175 +G01 X1.8555 Y0.9175 +G01 X1.6955 Y0.9175 +G01 X1.6900 Y0.9175 +G01 X1.6856 Y0.9179 +G01 X1.6775 Y0.9213 +G01 X1.6713 Y0.9275 +G01 X1.6679 Y0.9356 +G01 X1.6675 Y0.9400 +G01 X1.6675 Y1.2348 +G01 X1.6843 Y1.2516 +G01 X1.6843 Y1.2884 +G01 X1.6584 Y1.3143 +G01 X1.6216 Y1.3143 +G01 X1.5957 Y1.2884 +G01 X1.5957 Y1.2516 +G01 X1.6125 Y1.2348 +G01 X1.6125 Y0.9345 +G01 X1.6125 Y0.9246 +G00 Z0.1000 +G00 X0.2200 Y0.1800 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2300 Y2.0300 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X3.0700 Y2.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X3.0700 Y0.1900 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2100 Y1.4700 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2100 Y1.7400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9700 Y1.4700 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9700 Y1.7900 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9000 Y0.5700 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.6400 Y1.2700 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.5100 Y0.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.5100 Y0.4600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9000 Y1.4400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.3000 Y1.4400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7200 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7200 Y1.5100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.5600 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.5600 Y0.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7800 Y0.5400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7800 Y0.3400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.5500 Y0.6600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.7500 Y0.6600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9500 Y1.1300 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9500 Y1.3300 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7600 Y1.8600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.3600 Y1.8600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.5000 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.5000 Y1.7100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.8200 Y0.5000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.4200 Y0.5000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.8200 Y0.3400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.4200 Y0.3400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.0100 Y0.2600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.0100 Y0.6600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9200 Y0.5516 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9200 Y0.7484 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9600 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9600 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9600 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9600 Y1.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2600 Y1.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2600 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2600 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2600 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.4100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y0.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y0.8100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y0.8100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y0.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.4100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6700 Y1.8200 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6700 Y1.7200 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y1.7884 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y1.5916 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.3400 Y1.7400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.3900 Y1.6650 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.4400 Y1.7400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X3.1600 Y1.6100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6600 Y1.6100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6700 Y0.7500 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6700 Y1.2500 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.7700 Y1.2000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.7700 Y1.7000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.0000 Y1.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.5000 Y1.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.4300 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.4300 Y0.7100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.8200 Y0.2000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.3200 Y0.2000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6400 Y0.2600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.1400 Y0.2600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y1.3084 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y1.1116 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y0.9084 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y0.7116 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/enabtmr.top.mill.tap b/trunk/ulp/docs/examples/enabtmr.top.mill.tap new file mode 100644 index 00000000..c22a0891 --- /dev/null +++ b/trunk/ulp/docs/examples/enabtmr.top.mill.tap @@ -0,0 +1,53 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X0.9700 Y0.6300 +G01 Z-0.0100 F10.00 +G01 X1.1100 Y0.6300 F20.00 +G01 X1.1900 Y0.7100 +G01 X1.2600 Y0.7100 +G01 X1.2600 Y0.5000 +G01 X1.1900 Y0.5000 +G01 X1.1900 Y0.5100 +G01 X1.1200 Y0.5800 +G01 X0.9700 Y0.5800 +G01 X0.9700 Y0.6300 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/examples/enabtmr.top.text.tap b/trunk/ulp/docs/examples/enabtmr.top.text.tap new file mode 100644 index 00000000..8bde108c --- /dev/null +++ b/trunk/ulp/docs/examples/enabtmr.top.text.tap @@ -0,0 +1,151 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0100 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X0.4457 Y2.1371 +G01 Z-0.0050 F10.00 +G01 X0.4030 Y2.1371 F20.00 +G01 X0.4030 Y2.0730 +G01 X0.4457 Y2.0730 +G00 Z0.1000 +G00 X0.4030 Y2.1050 +G01 Z-0.0050 F10.00 +G01 X0.4244 Y2.1050 F20.00 +G00 Z0.1000 +G00 X0.4675 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.4675 Y2.1157 F20.00 +G01 X0.4995 Y2.1157 +G01 X0.5102 Y2.1050 +G01 X0.5102 Y2.0730 +G00 Z0.1000 +G00 X0.5426 Y2.1157 +G01 Z-0.0050 F10.00 +G01 X0.5639 Y2.1157 F20.00 +G01 X0.5746 Y2.1050 +G01 X0.5746 Y2.0730 +G01 X0.5426 Y2.0730 +G01 X0.5319 Y2.0837 +G01 X0.5426 Y2.0944 +G01 X0.5746 Y2.0944 +G00 Z0.1000 +G00 X0.5964 Y2.1371 +G01 Z-0.0050 F10.00 +G01 X0.5964 Y2.0730 F20.00 +G01 X0.6284 Y2.0730 +G01 X0.6391 Y2.0837 +G01 X0.6391 Y2.1050 +G01 X0.6284 Y2.1157 +G01 X0.5964 Y2.1157 +G00 Z0.1000 +G00 X0.6608 Y2.1371 +G01 Z-0.0050 F10.00 +G01 X0.6715 Y2.1371 F20.00 +G01 X0.6715 Y2.0730 +G00 Z0.1000 +G00 X0.6608 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.6822 Y2.0730 F20.00 +G00 Z0.1000 +G00 X0.7358 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.7145 Y2.0730 F20.00 +G01 X0.7038 Y2.0837 +G01 X0.7038 Y2.1050 +G01 X0.7145 Y2.1157 +G01 X0.7358 Y2.1157 +G01 X0.7465 Y2.1050 +G01 X0.7465 Y2.0944 +G01 X0.7038 Y2.0944 +G00 Z0.1000 +G00 X0.8540 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.8540 Y2.1371 F20.00 +G00 Z0.1000 +G00 X0.8327 Y2.1371 +G01 Z-0.0050 F10.00 +G01 X0.8754 Y2.1371 F20.00 +G00 Z0.1000 +G00 X0.8971 Y2.1157 +G01 Z-0.0050 F10.00 +G01 X0.9078 Y2.1157 F20.00 +G01 X0.9078 Y2.0730 +G00 Z0.1000 +G00 X0.8971 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.9185 Y2.0730 F20.00 +G00 Z0.1000 +G00 X0.9078 Y2.1477 +G01 Z-0.0050 F10.00 +G01 X0.9078 Y2.1371 F20.00 +G00 Z0.1000 +G00 X0.9401 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.9401 Y2.1157 F20.00 +G01 X0.9508 Y2.1157 +G01 X0.9615 Y2.1050 +G01 X0.9615 Y2.0730 +G00 Z0.1000 +G00 X0.9615 Y2.1050 +G01 Z-0.0050 F10.00 +G01 X0.9721 Y2.1157 F20.00 +G01 X0.9828 Y2.1050 +G01 X0.9828 Y2.0730 +G00 Z0.1000 +G00 X1.0366 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X1.0152 Y2.0730 F20.00 +G01 X1.0046 Y2.0837 +G01 X1.0046 Y2.1050 +G01 X1.0152 Y2.1157 +G01 X1.0366 Y2.1157 +G01 X1.0473 Y2.1050 +G01 X1.0473 Y2.0944 +G01 X1.0046 Y2.0944 +G00 Z0.1000 +G00 X1.0690 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X1.0690 Y2.1157 F20.00 +G00 Z0.1000 +G00 X1.0690 Y2.0944 +G01 Z-0.0050 F10.00 +G01 X1.0904 Y2.1157 F20.00 +G01 X1.1010 Y2.1157 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/docs/homepage.jpg b/trunk/ulp/docs/homepage.jpg new file mode 100644 index 00000000..f69a69bc Binary files /dev/null and b/trunk/ulp/docs/homepage.jpg differ diff --git a/trunk/ulp/docs/images/isolation_settings_300.gif b/trunk/ulp/docs/images/isolation_settings_300.gif new file mode 100644 index 00000000..9b8e6507 Binary files /dev/null and b/trunk/ulp/docs/images/isolation_settings_300.gif differ diff --git a/trunk/ulp/docs/images/pcbgcode-600.gif b/trunk/ulp/docs/images/pcbgcode-600.gif new file mode 100644 index 00000000..f8d8e8cc Binary files /dev/null and b/trunk/ulp/docs/images/pcbgcode-600.gif differ diff --git a/trunk/ulp/docs/images/z_axis.gif b/trunk/ulp/docs/images/z_axis.gif new file mode 100644 index 00000000..7697e86b Binary files /dev/null and b/trunk/ulp/docs/images/z_axis.gif differ diff --git a/trunk/ulp/docs/images/z_axis.svg b/trunk/ulp/docs/images/z_axis.svg new file mode 100644 index 00000000..58e76004 --- /dev/null +++ b/trunk/ulp/docs/images/z_axis.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + Up + + + High + + Down + + Drill Depth + + + + diff --git a/trunk/ulp/docs/lstlang0.sty b/trunk/ulp/docs/lstlang0.sty new file mode 100644 index 00000000..84299746 --- /dev/null +++ b/trunk/ulp/docs/lstlang0.sty @@ -0,0 +1,42 @@ +\lst@definelanguage{eagle}[]{C}% + {morekeywords={ + usage, + EAGLE_VERSION, EAGLE_REVISION, REAL_EPSILON, REAL_MAX, REAL_MIN, + INT_MAX, INT_MIN, PI, + board, deviceset, library, output, package, schematic, sheet, + symbol, + real, string, + abs, acos, asin, atan, ceil, cos, exit, exp, + filedir, fileerror, fileext, fileglob, filename, + fileread, filesetext, filesize, filetime, + floor, frac, ingroup, isalnum, isalpha, iscntrl, + isdigit, isgraph, islower, isprint, ispunct, isspace, + isupper, isxdigit, log, log10, lookup, max, min, + palette, pow, printf, round, sin, sort, sprintf, + sqrt, status, strchr, strjoin, strlen, strlwr, strrchr, + strrstr, strsplit, strstr, strsub, strtod, strtol, + strupr, system, t2day, t2dayofweek, t2hour, t2minute, + t2month, t2second, t2string, t2year, tan, time, + tolower, toupper, trunc, u2inch, u2mic, u2mil, u2mm, + UL_LIBRARY, UL_GRID, UL_LAYER, UL_DEVICESET, UL_DEVICE, UL_GATE, + UL_PACKAGE, UL_CONTACT, UL_PAD, UL_SMD, UL_CIRCLE, UL_HOLE, + UL_RECTANGLE, UL_FRAME, UL_TEXT, UL_WIRE, UL_POLYGON, + UL_SYMBOL, UL_PIN, UL_SCHEMATIC, UL_PART, UL_INSTANCE, + UL_ATTRIBUTE, UL_BUS, UL_SEGMENT, UL_LABEL, UL_NET, + UL_JUNCTION, UL_PINREF, UL_BOARD, UL_ELEMENT, UL_SIGNAL, + UL_CONTACTREF, UL_VIA, + SET, DISPLAY, GRID, SET, WINDOW, WIRE, + CLOSE, EDIT, EXPORT, OPEN, QUIT, REMOVE, SCRIPT, + USE, WRITE, ADD, ARC, ATTRIBUTE, CIRCLE, CLASS, + COPY, CUT, DELETE, DESCRIPTION, GROUP, HOLE, LAYER, + MIRROR, MITER, MOVE, NAME, PASTE, POLYGON, RECT, ROTATE, + SMASH, SPLIT, TEXT, VALUE, WIRE, DRC, ERRORS, + LOCK, RATSNEST, REPLACE, RIPUP, ROUTE, SIGNAL, VIA, + BOARD, BUS, ERC, GATESWAP, INVOKE, JUNCTION, + LABEL, NET, PINSWAP, CONNECT, PACKAGE, PAD, PIN, + PREFIX, REMOVE, SMD, TECHNOLOGY, VALUE, + ASSIGN, CHANGE, MENU, AUTO, HELP, INFO, MARK, + OPTIMIZE, PRINT, REDO, RUN, SHOW, UNDO, UPDATE + }, + sensitive=true + } diff --git a/trunk/ulp/docs/pcbgcode.pdf b/trunk/ulp/docs/pcbgcode.pdf new file mode 100644 index 00000000..f6e20204 Binary files /dev/null and b/trunk/ulp/docs/pcbgcode.pdf differ diff --git a/trunk/ulp/docs/pcbgcode.tex b/trunk/ulp/docs/pcbgcode.tex new file mode 100644 index 00000000..66a97470 --- /dev/null +++ b/trunk/ulp/docs/pcbgcode.tex @@ -0,0 +1,1074 @@ +\documentclass[11pt]{book} + +%\usepackage{setspace} +%\usepackage{fullpage} +%\usepackage{relsize} +\usepackage{graphicx} +\usepackage{geometry} + +\usepackage[sc]{mathpazo} % Use the Palatino font +\usepackage[T1]{fontenc} % Use 8-bit encoding that has 256 glyphs +%\linespread{1.05} % Line spacing - Palatino needs more space between lines +\usepackage{microtype} % Slightly tweak font spacing for aesthetics + +%\usepackage[hmarginratio=1:1,top=32mm,columnsep=20pt]{geometry} % Document margins + +\usepackage[ + pdfauthor={John T. Johnson},% + pdftitle={The PCB-GCODE User's Manual},% + pdfsubject={pcb-gcode mechanically etching printed circuit boards},% + pdfkeywords={pcb-gcode}{g-code}{pcb}{cnc}{etching},% + colorlinks=true,% + linkcolor=gray,% + urlcolor=gray% +]{hyperref} % For hyperlinks in the PDF + +\usepackage[hang, small,labelfont=bf,up,textfont=it,up]{caption} % Custom captions under/above floats in tables or figures +\usepackage{booktabs} % Horizontal rules in tables + +\usepackage{paralist} % Used for the compactitem environment which makes bullet points with less space between them + +\usepackage{fancyhdr} % Headers and footers +%\pagestyle{fancy} % All pages have headers and footers +\fancyhead{} % Blank out the default header +\fancyfoot{} % Blank out the default footer +%\fancyhead[C]{SED1 $\bullet$ December 5, 2012 $\bullet$ Unpublished} % Custom header text +\fancyfoot[RO,LE]{\thepage} % Custom footer text + +\usepackage{varioref} + +%\usepackage{lmodern} + +\usepackage{listings} + +\usepackage{textcomp} + +\usepackage{float} + +\usepackage[section]{placeins} + +%\usepackage{draftwatermark} + +\usepackage{makeidx} +\makeindex +%\usepackage{showidx} % shows index items in margins, doesn't gen index page + +%---------------------------------------------------------------------------------------- +% TITLE SECTION +%---------------------------------------------------------------------------------------- + +\title{\vspace{-15mm}\fontsize{24pt}{10pt}\selectfont\textbf{The PCB-GCODE User's Manual}\\[1em] +\fontsize{18pt}{10pt}\textsc{Version 3.6.0.4}\\[1em] +} + +\author{ +\large +Copyright \copyright\ 2013\\[1em] +\textsc{John T. Johnson}\\[2mm] %\thanks{A thank you or further information}\\[2mm] % Your name +\normalsize \href{mailto:pcbgcode@pcbgcode.org}{\texttt{pcbgcode@pcbgcode.org}} % Your email address +\vspace{-5mm} +} +%\date{} % empty date, since it is shown in the header + +%\makeglossary + +% Adobe bug workoround +\pdfminorversion=4 + +%====================================================================== +%====================================================================== +\begin{document} +%====================================================================== +%====================================================================== + +%\newcommand{\marginnote}[1]{% +% \marginpar{\colorbox{yellow}{\parbox{\marginparwidth}{% +% %\setstretch{0.5} +% \textcolor{red}{\scriptsize{#1}}}}}} + +\newcommand{\warning}[1]{ + \marginpar{ + \vspace{0.1in} + \includegraphics{/Users/john/Dropbox/Docs/warning.pdf} + \centering + #1 + } +} + +\newcommand{\information}[1]{ + \marginpar{ + \vspace{0.1in} + \includegraphics{/Users/john/Dropbox/Docs/information.pdf} + \centering + #1 + } +} + +\newcommand{\howitworks}[1]{ + \marginpar{ + \vspace{0.1in} + \includegraphics{/Users/john/Dropbox/Docs/gears.pdf} + \centering + #1 + } +} + + + +\setlength{\marginparwidth}{1.0in} +\setlength{\marginparsep}{2em} + + +\newcommand{\code}[1]{\texttt{#1}} + +\definecolor{gray}{rgb}{0.5,0.5,0.5} + +\lstset{language=eagle, + basicstyle=\ttfamily\small, + numberstyle=\small\color{gray}, + numbers=left, + showstringspaces=false, + stepnumber=1, +% frame=shadowbox, + breaklines=true} + +\frontmatter + +\maketitle + +% +%--------------------------------------------------------------------- +% +\section*{About this book} + +This book is typeset with \href{http://en.wikipedia.org/wiki/LaTeX}{\LaTeX{}} using the Computer Modern and Palatino fonts. +\vspace{1ex} + +\noindent The \LaTeX{} distribution used is \href{http://tug.org/mactex/}{MacTeX}. The editor is \href{http://texpadapp.com}{Texpad} for \href{http://www.apple.com/osx/}{Mac OS X} and \href{http://www.apple.com/ios/}{iOS}. When doing academic writing, I use \href{http://bibdesk.sourceforge.net}{BibDesk} on Mac OS X and \href{https://itunes.apple.com/us/app/pocketbib-for-bibtex-bibdesk/id524521749?mt=8}{PocketBib} on iOS. +\vspace{1ex} + +\noindent Some words, such as MacTeX in the previous paragraph, are links to websites. In this manual, all links are colored gray. The reader will note that other words are links to figures, tables, or sections in this manual. These are also colored gray. The reader may click these links to jump to the linked item. +\vspace{1ex} + +\noindent Throughout this book there are icons in the margins that will help the reader navigate the book and find material at an appropriate skill level. These icons are shown below. +\vspace{5ex} + +\howitworks{} \noindent Sections marked with this icon provide background on the operation of pcb-gcode. This information is for curious users and can safely be skipped. +\vspace{10ex} + +%\information{} \noindent Information. +%\vspace{10ex} + +\warning{} \noindent Some parts of the manual are for intermediate or advanced users. This icon alerts the reader to this fact. + +\tableofcontents + +\listoffigures + +\listoftables + +\mainmatter + +%====================================================================== +% +\chapter{Introduction}\label{chp:Introduction} +% +%====================================================================== + +% +%--------------------------------------------------------------------- +% +\section{Purpose}\label{sec:Purpose} + +Pcb-gcode is a User Language Program (ULP) for EAGLE PCB design software produced by \href{http://cadsoftusa.com}{CadSoft}. Pcb-gcode allows one to make printed circuit boards by using a CNC router or milling machine to cut the traces out of the copper on the board. It also produces files for drilling holes. Two-sided boards are supported. By "mechanically etching" the boards, no toxic chemicals are needed -- making the process more environmentally friendly. Turn-around times and costs are much reduced from ordering a prototype from a board house. + +% +%--------------------------------------------------------------------- +% +\section{Features}\label{sec:Features} + +Though no program can be all things to all people, pcb-gcode has a lot of features to help make it useful. + +\begin{description} + \item[One or two sided boards] There are checkboxes for selecting whether to generate files for the top and/or bottom sides of the boards. + \item[Outlines] Generate gcode for cutting around the tracks of the PCB. Multiple passes are possible, which helps eliminate the small slivers that may be left behind. There is also an option to make only one outline pass. + \item[Drills] Generate gcode for drilling component and mounting holes. Tool changes are supported, as well as a drill rack file. + \item[Preview] A preview for outlines is available. + \item[Milling] Milling code can be generated for any wires drawn on the Milling (46) layer. + \item[Text] Generates gcode to engrave any vector text that is on the Milling (46) layer. + \item[Spot drill holes] Holes can be spot drilled with the outlines tool to help the drill bits to start straight when drilling holes. + \item[Tool change position] Where the machine should go so that the tool can be changed. + \item[Drill rack files] Allows using one drill bit for a range of hole sizes in the board. + \item[Profile] Starting settings for particular styles of gcode, for example, Mach3 or EMC, among others. + \item[Embedding comments] Comments documenting the settings a file was created with can be inserted into the gcode. + \item[User gcode] For users that need to generate gcode for unusual situations. + \item[File naming] Several options exist for naming files according to the conventions of the user's controller, and their local language. + \item[Plugins] Allow for future expansion. +\end{description} + +% +%--------------------------------------------------------------------- +% +\section{How it Works}\label{sec:HowItWorks} +\subsection{Overview} +After designing your board in Eagle's board editor, the ULP pcb-gcode-setup is run and options are set (See \figurename \vref{fig:SetupGenerationOptions}). Pcb-gcode will generate a set of files that will cut out the tracks, pads, pours and vias (hereinafter called tracks) for the top and/or bottom of the board. Pcb-gcode can also generate files to drill holes from the top and/or bottom of the board. Since the holes usually go all the way through, they only need to be drilled from one side, although some users have drilled slightly more than half way from both sides for a cleaner finish. The user may also choose to create milling wires on the milling layer of the board. This can be used to cut out sections of the board, or cut the perimeter of the board out. There is also an option for engraving vector text that the user places on the milling layer. + +After the files are generated, they are transferred to the control software for the CNC router or milling machine. The PCB is mounted on the machine. The origin is set to the lower left for the top side of the board and the top files are run. The board is then flipped in the \code{X} axis (i.e. around the \code{Y} axis), the origin is set at the lower right, and the bottom files are run. After minimal inspection and cleanup, the board is ready to be loaded with components. + +\subsection{Isolation} +Pcb-gcode has the ability to generate g-code that cuts out tracks with increasing amounts of isolation. This is helpful because it can help eliminate small slivers of copper left behind by the cutting process. + +The isolation begins at a minimum amount and is increased by a step size until a maximum amount is reached. The builtin previewer can be used to see how this isolation works. See \figurename \vref{fig:MultipassBoard}. From the zoomed view shown in \figurename \vref{fig:MultipassBoardZoom} you can see that the passes start out close to the track, then move out by a step size. The colors of the preview tracks follow the standard resistor color codes, so brown is the first pass, red is the second, orange the third, etc. + +\howitworks{} +For the curious reader, the isolation is calculated as shown in Equation \vref{egn:IsolationCalculation}. You do not need to know this to use pcb-gcode. Note that this formula is erroneous and that the $EtchingToolSize$ should be divided by 2 to yield the offset. Changing this now would break many user's setups, so it will be left as is. Most users arrive at the setting for the etching tool size by trial and error, so it is likely a moot point. + +\begin{equation} +isolation = EtchingToolSize+MinimumIsolation+PassNumber*StepSize +\label{egn:IsolationCalculation} +\end{equation} + + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Multipass-Board.png} + } + \caption{Preview showing color-coded multiple passes.} + \label{fig:MultipassBoard} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Multipass-Board-Zoom.png} + } + \caption{Preview showing a zoomed version of the color-coded multiple passes. Brown is the first pass, red the second, orange the third, etc.} + \label{fig:MultipassBoardZoom} +\end{figure} + +\subsection{Drilling} +Compared to the isolation passes and files, drill file creation is relatively straight forward. Each hole in the board is sorted according to size and then position. Optionally a rack file can be used. Rack files contain a list of drills the user has available and the size holes they can be used for. For more information on rack files, see Section \vref{sec:DrillRackFiles}. G-code is created to position and drill each hole. Tool changes can be included in the file so that the user or an automated tool changer can change the bit. + +%====================================================================== +% +\chapter{Setup}\label{chp:Setup} +% +%====================================================================== + +% +%--------------------------------------------------------------------- +% +\section{EAGLE compatibility}\label{sec:EAGLECompatibility}\index{eagle!compatibility} + +Pcb-gcode is compatible with EAGLE versions 5 and 6\footnote{CadSoft changed the way numbers were represented internally with their release of version 6. This effectively broke parts of pcb-gcode. Version 3.6 incorporates changes for compatibility with version 5 or 6.}. For versions of EAGLE before version 5, pcb-gcode version 3.3.3 is still available \href{http://groups.yahoo.com/group/pcb-gcode/files/\%21\%20Software/pcb-gcode-3.3.3.zip}{in the Yahoo! group}. This manual does not apply to version 3.3.3. Please see the documentation included with version 3.3.3. + +% +%--------------------------------------------------------------------- +% +\section{Installation}\label{sec:Installation}\index{installation} + +\subsection{Downloading and unarchiving} +Pcb-gcode can be downloaded from the Yahoo! group's \href{http://groups.yahoo.com/group/pcb-gcode/files/\%21\%20Software}{software folder}. \index{download site} Unzip the archive into a place where the operating system will allow files to be saved. For Windows, this should be somewhere inside your Documents folder. For Mac OS X, it could be, for instance, \code{\textasciitilde/Documents/Eagle/pcbgcode}, and for Linux, somewhere off your home folder. Be sure to preserve the directory structure in the archive. See \figurename \vref{fig:folderstructure}. + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Folder-Structure.png} + } + \caption{The proper directory structure after uncompressing the archive.} + \label{fig:folderstructure} +\end{figure} + +\subsection{Configuring EAGLE} +Now that pcb-gcode is uncompressed, Eagle must know where it is located. In Eagle's \code{Control Panel}, click \code{Options $|$ Directories}, then put the path to pcb-gcode in the \code{User Language Programs} field. See \figurename \vref{fig:EagleOptionsDirectories}. + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Eagle-Options-Directories.png} + } + \caption{Add the path to pcb-gcode to the User Language Programs option.} + \label{fig:EagleOptionsDirectories} +\end{figure} + +\subsection{Selecting g-code style}\label{sub:SelectingGCodeStyle}\index{g-code style} +To complete the setup, pcb-gcode must be told which type of g-code it should generate. Open a board in Eagle, then click \code{File $|$ Run...}. Locate the folder where pcb-gcode is and select pcb-gcode-setup.ulp. You will see the screen in \figurename \vref{fig:SelectGcodeStyle}. Select the style g-code that most closely matches your controller. + +You will receive the warning shown in \figurename \vref{fig:GcodeDefaultsWarning}. If this is the first time pcb-gcode has been run, just click Yes and skip the rest of this paragraph. If this is an existing installation of pcb-gcode and gcode-defaults.h has been modified, make note of the modifications before clicking Yes, then make those modifications as needed to the new gcode-defaults.h file. + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Select-Gcode-Style.png} + } + \caption{Select the style g-code pcb-gcode should produce.} + \label{fig:SelectGcodeStyle} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Gcode-Defaults-Warning.png} + } + \caption{Overwrite warning for gcode-defaults.h.} + \label{fig:GcodeDefaultsWarning} +\end{figure} + +After clicking Yes, \code{pcb-gcode-setup} will be run again, and you will see the screen shown in \figurename \vref{fig:SetupGenerationOptions}. + +% +%--------------------------------------------------------------------- +% +\section{Machine Setup}\label{sec:MachineSetup} + +\begin{figure} + \center{ + \includegraphics[width=14cm]{figs/Setup-Machine.png} + } + \caption{Machine options.} + \label{fig:SetupMachine} +\end{figure} + +Click the \code{Machine} tab to view the machine options as shown in \figurename \vref{fig:SetupMachine}. First select the preferred unit of measure by selecting it under \code{Units}. \index{unit of measure} + +Now set the settings for the Z axis. \code{Z High} should be high enough to clear any clamps or fixtures that hold the PCB down.\index{Z High} Set \code{Z Up} high enough to clear the board when moving from location to location.\index{Z Up} Set \code{Z Down} to the depth into the board that the tool should cut.\index{Z Down} \code{Drill Depth} should be set deep enough to drill through the PCB.\index{Drill Depth} \code{Drill Dwell} is the time, in seconds, that the drill should pause at the bottom of the hole.\index{Drill Dwell} + +The \code{Tool Change} options are the position where the tool should be moved for changing the tool.\index{Tool Change} + +The \code{Spin Up Time} in the \code{Spindle} box should be set to the length of time in seconds that it takes the spindle to come up to speed. If the spindle is manually controlled, this can be set to \code{1}.\index{Spin Up Time} + +The \code{Feed Rates} should be set for \code{X Y} moves as well as \code{Z} moves. Rates here will usually be quite low unless the machine has a very fast spindle. See a machinist's reference on how to calculate the optimal feed rate, use trial and error, or post to the Yahoo! group email list for advice. + +\code{Epsilon} is the minimum move that will be written to the g-code file. For instance, if \code{Epsilon} is set to $0.0001''$ and the g-code file will not contain movements less than $0.0001''$. This option will rarely need to be changed. + +The \code{Default Drill Rack File} option allows for the selection of a rack file to be used if one has not been setup for a particular board. In most cases this can be left blank to start with. See Section \vref{sec:DrillRackFiles} for more information about setting up rack files. + +% +%--------------------------------------------------------------------- +% +\section{Generation Options}\label{sec:GenerationOptions} + +\begin{figure} + \center{ + \includegraphics[width=14cm]{figs/Setup-Generation-Options.png} + } + \caption{Options available when generating a board.} + \label{fig:SetupGenerationOptions} +\end{figure} + +Now that reasonable values have been set for the machine, click the \code{Generation Options} tab (See \figurename \vref{fig:SetupGenerationOptions}). This is where the various files produced by pcb-gcode can be selected, and common options can be set. A description of the options follows: + +\begin{description} + \item[Top Side] Options having to do with the tracks on the top of the board, and drill holes made from the top side of the board. + \begin{description} + \item[Generate top outlines] Generate g-code to cut out the tracks, pads, pours and vias on the top side of the board. + \item[Generate top drills] Generate g-code to drill holes from the top side of the board. + \end{description} + \item[Bottom Side] Options having to do with the tracks on the bottom of the board, and drill holes made from the bottom side of the board. + \begin{description} + \item[Generate bottom outlines] Generate g-code to cut out the tracks, pads, pours and vias on the bottom side of the board. + \item[Generate bottom drills] Generate g-code to drill holes from the bottom side of the board. + \item[Mirror] X coordinates for the bottom of the board are usually negative. This makes setting the origin for a two-sided board easier. Turning this option on causes the X coordinates to be positive, however, the bottom tracks will be a mirror image of what they should be. So in general, leave this option off. + \end{description} + \item[Board] Options that apply to the board in general. + \begin{description} + \item[Show preview] Use the previewer in pcb-gcode to preview the g-code generated. + \item[Generate milling] Generate g-code for any wires the user has drawn on the \code{Milling} (46) layer. \code{Depth} sets the milling depth. + \item[Generate text] Generate g-code to engrave any vector text the user may have placed on the \code{Milling} layer. \code{Depth} sets the engraving depth. Not that text on the top or bottom layers will be outlined just as the tracks are, whereas text on the milling layer is engraved. That is, the tool along the center of the lines that make up the letter. + \item[Spot drill holes] Spot drilling helps the drill bits center themselves and helps prevent "walking." Depth sets the spot drill depth. + \item[Isolation] The cutting tool can make several passes around the tracks at an increasing distance each time. This helps eliminate slivers of copper that remain. + \begin{description} + \item[Single pass] When turned on, only a single pass will be made around the tracks on the board. + \item[Minimum] The minimum distance the cutting tool will be away from tracks. That is, the starting isolation amount. + \item[Maximum] The maximum distance the cutting tool will be away from tracks. The maximum isolation amount. + \item[Step size] The amount the isolation increases with each pass. + \end{description} + \item[Etching Tool Size] The size of the cutter used to cut around tracks on the board. + \end{description} +\end{description} + +% +%--------------------------------------------------------------------- +% +\section{GCode Options}\label{sec:GCodeOptions} + +\begin{figure} + \center{ + \includegraphics[width=14cm]{figs/Setup-GCode-Options.png} + } + \caption{Options for generating g-code files.} + \label{fig:GCodeOptions} +\end{figure} + +The options under the GCode Options tab allows the customization of some of the g-code file's content, as well as how the files are named. + +\begin{description} + \item[NC File Comments] Comments added to the g-code file. + \begin{description} + \item[NC File Comment from Board] adds a comment with the name of the board file. + \item[NC File Comment Date] adds the date the g-code file is created. + \item[NC File Comment Machine Settings] adds settings related to the machine. Tool size, Z axis settings, spindle on time, milling depth, text depth, tool change position, XY feed rate, Z feed rate. + \item[NC File Comment PCB Defaults Settings] adds comments with the isolation settings: min, max, and step size, which files were selected to be produced, and the unit of measure. + \end{description} + + \item[Other Options] Options affecting how the g-code is generated. + \begin{description} + \item[Use user gcode (from user-gcode.h)] inserts user g-code into the generated file. See Section \vref{sec:UserGCode} for more details. + \item[Debug Flag] sets the global debug flag. Used for development and troubleshooting. + \item[Do tool change with zero step] after moving to the tool change position and pausing for the operator to change the bit, the Z axis will move to Z0.000 and pause. This allows the operator to adjust the bit length to touch the surface of the PCB. Note that the tool should initially be set high into the spindle so that it won't dig into the PCB when it moves to Z0. + \item[Flip board in Y instead of X] changes the code generated so that after one side of the board is cut, the board should be flipped in the Y axis to complete cutting on the other side. The default is for the board to be flipped in the X axis. + \item[Compact gcode] eliminates some redundant commands in the g-code file, such as having G01 on every line. + \item[Use line numbers?] inserts line numbers into the g-code file. The format shown \code{\%05d} will insert 5 digit numbers with leading zeroes. + \item[Use simple drill code] uses XYZ movements to create drill holes. Usually \code{DRILL\_{}FIRST\_{}HOLE} and \code{DRILL\_{}HOLE} are used, but some controllers don't understand the command (typically \code{G82}). + \end{description} + + \item[File naming] every option one could want for naming files. + \begin{description} + \item[Macros] the following can be used in the file name to create the final file name. Note that paths do not include a \code{/} at the end. Also note that \code{/} is always the path delimiter, even on Windows. Eagle handles the conversion automatically. + \begin{description} + \item[\$PROJECT\_{}PATH{[}n{]}] Project paths as set in the Eagle Control Panel. n begins at zero for the first entry. + \item[\$ULP\_{}PATH{[}n{]}] ULP paths as set in the Control Panel. + \item[\$CAM\_{}PATH{[}n{]}] CAM paths as set in the Control Panel. + \item[\$BOARD\_{}PATH] path to the board file. + \item[\$BOARD\_{}NAME] the file name of the board file with the extension removed. + \item[\$SIDE] the side of the board being generated. Defaults are 'bot' and 'top'. + \item[\$FILE] the file being generated. Defaults are 'etch', 'drill', 'mill' and 'text'. + \item[\$EXT] the extension set in \code{Extension} on this screen. + \end{description} + \item[Test Filenames] click the button to see how the file names will look. + \item[Help] gives a list of the macros defined above and tips on creating file names. + \end{description} +\end{description} + +Using the options shown in \ref{fig:GCodeOptions}, here is how the filename for the top etching file will be created: +\begin{itemize} +\item The board path and board name will be used. (\code{Filename Base}) +\item The word for 'top' will be substituted for \code{\$SIDE}. (See \code{Etching} under \code{Top (Component) Side Files}. +\item The word for 'etch' will be substituted for \code{\$FILE}. +\item The \code{Extension} will be substituted for \code{\$EXT}. +\end{itemize} +Using examples for the board path and name, the final file name would be:\\ +\lstinline!/Users/john/Documents/pcbcode/examples/enabtmr.top.etch.tap! + +%====================================================================== +% +\chapter{Using pcb-gcode} +% +%====================================================================== + +% +%--------------------------------------------------------------------- +% +\section{Running pcb-gcode}\index{pcb-gcode!running}\label{sec:running} + +Run pcb-gcode by selecting File $|$ Run... from EAGLE's board editor. Find the file \code{pcb-gcode-setup.ulp} and click the Open button. The setup screen will be shown where options can be changed (See \figurename~\ref{fig:SetupGenerationOptions}). When the options are correct, click the \code{Accept and make my board} button. To save the options without generating files for the board, click the \code{Accept} button. + +Pcb-gcode is actually two programs. The first, pcb-gcode-setup, allows for setting options and changing the way NC files are created. The second program is pcb-gcode, which actually creates the files. Most people run pcb-gcode-setup, check their settings, then click the \code{Accept and make my board} button to generate files. If settings don't need to be changed, pcb-gcode can be run directly and all the file selections and options from the last time pcb-gcode-setup was run will be used. + +To make it easier to run pcb-gcode and pcb-gcode-setup, use EAGLE's Assign function to assign a shortcut key to \code{run pcb-gcode} and \code{run pcb-gcode-setup} (See \figurename~\vref{fig:EagleOptionsAssign}). + +\begin{figure} + \center{ + \includegraphics[width=5cm]{figs/EAGLE-Options-Assign.png} + } + \caption{EAGLE shortcut key assignments.} + \label{fig:EagleOptionsAssign} +\end{figure} + +% +%--------------------------------------------------------------------- +% +\section{Using EAGLE's DRC}\index{eagle!DRC}\label{sec:EagleDRC} + +When creating files to etch a board, it is usually the case that the tracks should be made wide to allow for easier machining and to account for tolerances in the machine such as backlash and spindle runout. EAGLE's Design Rule Check (DRC) can be used to help ensure that all tracks on the board will be cut out, and no bridges will be left. + +A bridge is formed when two parts (tracks, pads, vias) on the board are too close together for the etching tool to pass between them. An example is shown in \figurename~\vref{fig:TwoComponents}. For this example, Single Pass isolation is selected, minimum isolation is set to $0.010''$, and the etching tool size is set to $0.005''$. These setting are shown in \figurename~\vref{fig:DRCExampleSettings}. + +\begin{figure} + \center{ + \includegraphics[width=5cm]{figs/Two-Components.png} + } + \caption{Two components in the board layout editor.} + \label{fig:TwoComponents} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=5cm]{figs/DRC-Example-Settings.png} + } + \caption{Pcb-gcode settings for the DRC example.} + \label{fig:DRCExampleSettings} +\end{figure} + +If the pads for the leads for the resistors that are close together are more than $0.010'' + 0.010'' + 0.005'' = 0.025''$ inches apart, the pads will be properly isolated as shown in \figurename~\vref{fig:GoodClearance}. However, if the two pads are less than $0.025''$ apart, they cannot be isolated, and a bridge will be formed as shown in \figurename~\vref{fig:TooClose}. + +\begin{figure} + \center{ + \includegraphics[width=7cm]{figs/Good-Clearance.png} + } + \caption{The pads are far enough apart to allow them to be isolated.} + \label{fig:GoodClearance} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=7cm]{figs/Too-Close.png} + } + \caption{The two pads are too close together and cannot be isolated. A bridge is formed.} + \label{fig:TooClose} +\end{figure} + +To help ensure that this does not happen, EAGLE's DRC can be used. From the board editor in EAGLE, click the Tools menu, then click DRC. Click the Clearance tab and set all clearances to 25mil. (A mil is $0.001''$, so this equals $0.025''$.) When the Check button is clicked, any distances less than 0.025" will be marked with a red mark, and a list of errors will be shown as in \figurename~\vref{fig:DRCError}. + +\begin{figure} + \center{ + \includegraphics[width=7cm]{figs/DRC-Error.png} + } + \caption{EAGLE's DRC indicating the two pads are too close together.} + \label{fig:DRCError} +\end{figure} + +Once the DRC clearances are set up, it is a simple matter to click the DRC button or run a DRC check from the Tools menu before running pcb-gcode to generate files for the board. This provides a good way to help ensure that components on the board are far enough apart to be properly isolated. + +% +%--------------------------------------------------------------------- +% +\section{Previewer}\index{previewer}\label{sec:Previewer} + +The previewer included in pcb-gcode shows a quick preview of the tool movements that are sent to the NC file. The lines are color coded using the standard resistor color codes. The first pass of the tool is drawn in brown, the second is red, the third is orange, etc. + +The preview is enabled by turning on the \code{Show preview} option under the \code{Generation Options} tab (See \figurename \vref{fig:SetupGenerationOptions}). After pcb-gcode creates the isolation or milling for the current layer, a preview of the results will be shown in the previewer. Several keys can be used to change the view, See Table \vref{tbl:PreviewerKeys}. If you wonder about some of the unusual keys, such as why \code{e} can be used to pan right, it is because of the Dvorak keyboard layout that some use, including the author. + +\begin{table}[h]\caption{Keys available in previewer}\label{tbl:PreviewerKeys}\index{previewer!keys}\index{keys!previewer} +\centering +\begin{tabular}{ll} + \toprule + Key & Function\\ + \midrule + 1 & Set zoom to 1x (no zoom)\\ + 2 & Set zoom to 2x\\ + + = & Zoom in\\ + - \_{} & Zoom out\\ + a $\leftarrow$ & Pan left\\ + d e $\rightarrow$ & Pan right\\ + w , $\uparrow$ & Pan up\\ + s o $\downarrow$ & Pan down\\ + c & Color on / off\\ + q x & Quit preview \\ \bottomrule +\end{tabular} +\end{table} + +The previewer does not read and interpret the NC files directly, but uses an internal representation of the tool movements. This gives an accurate representation of the tool's movements and size, without the overhead of interpreting several different styles of g-code. + +\begin{figure} + \center{ + \includegraphics[width=14cm]{figs/Previewer-Screen-Shot.png} + } + \caption{The previewer showing a multi-pass file for the bottom side of an example PCB included with pcb-gcode.} + \label{fig:PreviewerScreenShot} +\end{figure} + +As can be seen in \figurename~\vref{fig:PreviewerScreenShot}, additional information is provided by the preview. In the upper-left corner is the name of the board file that was processed to produce this preview. At the upper-right, the viewer version number can be found. Just to the left of that is the etching tool size set in pcb-gcode-setup. Just below the version number is the number of passes generated. Back on the left-hand side near the top is an overview of the keys available. + +The four extents of the board are marked with red corners. At the upper right corner, the X and Y coordinates are given. The X and Y coordinates are also given at the lower-left corner. Note that in the figure, the X coordinate is negative because this is the bottom of the board. In the lower right corner, a circle and crosshairs mark the origin point for the board. + +If the milling and text options are turned on, the previewer will show any files generated for the top and bottom milling and text. Since the Milling (46) layer is not a top or bottom layer (it can be thought of as going through the board), NC files are generated to mill any lines drawn on it from either the top or bottom side. So in other words, if \code{Generate milling} is selected, both top and bottom milling files will be generated. The same for text placed on the Milling layer. If \code{Generate text} is selected, both top and bottom text engraving files will be generated. There is one caveat: if the text is mirrored, it will be output in the bottom milling file. If the text is not mirrored, it will be output in the top milling file. This is similar to the way text placed on the \code{Top} and \code{Bottom} layers looks. The following example will help clarify this. + +The example board \code{docs/examples/04151\_lcdi2c.brd} shown in \figurename~\vref{fig:014151Board} includes wires (shown in blue) drawn on the Milling layer, as well as mirrored vector text (also shown in blue) placed on the Milling layer. A prewiew of the bottom milling file is shown in \figurename~\vref{fig:BottomMilling}. A preview of the bottom text engraving file is shown in \figurename~\vref{fig:BottomText}. You can see that the text is oriented properly for engraving on the bottom side of the board. The object info for the text is shown in \figurename~\vref{fig:MirroredTextInfo}. + +The top milling file preview looks just like the bottom preview, and is not shown. The top text engraving file was empty since there is no non-mirrored text on the Milling layer, so its preview has also been omitted. + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/04151_lcdi2c.png} + } + \caption{The sample board \code{docs/examples/04151\_lcdi2c.brd} with wires and mirrored text on the Milling layer.} + \label{fig:014151Board} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Bottom-Milling.png} + } + \caption{Milling generated for milling from the bottom side of \code{docs/examples/04151\_lcdi2c.brd}.} + \label{fig:BottomMilling} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Bottom-Text.png} + } + \caption{Text engraving generated for cutting on the bottom side of \code{docs/examples/04151\_lcdi2c.brd}.} + \label{fig:BottomText} +\end{figure} + +\clearpage + +\begin{figure} + \center{ + \includegraphics[width=8cm]{figs/Mirrored-Text-Info.png} + } + \caption{The object info for the mirrored text on the Milling layer. Note that the Mirror checkbox is on. This indicates to pcb-gcode that the text should be engraved on the bottom side of the board.} + \label{fig:MirroredTextInfo} +\end{figure} + + +\howitworks{} +For the curious reader, the previewer is written using a language called \href{http://processing.org}{Processing}, which is somewhat Java-like. Three versions of the previewer are included in pcb-gcode, one for each operating system supported: Mac OS X, Linux, and Windows. When the previewer is enabled, pcb-gcode detects which operating system it is running on, and runs the appropriate viewer. + +%====================================================================== +% +\chapter{Customizing} +% +%====================================================================== + +% +%--------------------------------------------------------------------- +% +\section{G-Code}\index{g-code!customizing}\label{sec:CustomizingGCode} + +\warning{Intermediate} +When the g-code style is initially selected at installation as discussed in Section \vref{sub:SelectingGCodeStyle}, the profile (\code{.pp}) file selected is copied from the \code{profiles} folder to the \code{settings} folder and to the file \code{gcode-defaults.h}. This is the file that pcb-gcode uses when generating g-code files. + +The listing found in Appendix \vref{chp:SampleProfile} can alse be used as a reference for editing \code{gcode-defaults.h}. If there is a need to change the g-code generated by pcb-gcode, the gcode-defaults.h file can be edited. + +The definitions in the file are flexible in some aspects, and restricted in others. The main restriction is that a definition that expects a certain number of parameters must be given that number of parameters. Unused parameters can be passed as comments in the g-code. + +For example, if the controller does not understand the DWELL command, it can be changed to a comment. In the listing, DWELL is defined to be: + +\begin{lstlisting}[firstnumber=46] +string DWELL = "G04 " + PARAM + "%f" + EOL; +\end{lstlisting} + +This can be made into a comment the controller will ignore by surrounding it with COMMENT\_{}BEGIN and COMMENT\_{}END: + +\begin{lstlisting}[firstnumber=46] +string DWELL = COMMENT_BEGIN + "G04 " + PARAM + "%f" + COMMENT_END + EOL; +\end{lstlisting} + +The \lstinline!%f! that pcb-gcode needs is still there, but the command is now just a comment as far as the controller is concerned. + +\marginpar{\scriptsize This is only an example. EAGLE handles line endings automatically depending on the operating system it is running on. If line endings in generated NC files need to be changed, a conversion program should be used.} + +The definitions use previous definitions as much as possible. This helps make the files more readable, and makes future changes easier as well. For instance, \code{EOL} is defined in line 22 to be \code{"\textbackslash{}n"}. Changing the line ending of all generated code would be a simple matter of changing the single definition of \code{EOL}, rather than editing every line. + +The first option on line 11, \code{FILENAMES\_8\_CHARACTERS}, tells pcb-gcode whether it should limit filenames to 8 characters. This is used for DOS control software such as TurboCNC. + +\begin{description}\index{gcode-defaults.h!definitions of commands}\index{profiles!definitions of commands} +\item[Misc defines] Comments and line ending +\begin{description} + \item[COMMENT\_{}BEGIN, COMMENT\_{}END] If your controller doesn't understand beginning and ending characters for comments, as on lines 16-17, just make \code{COMMENT\_{}END} empty. + + \item[EOL] is the character added to the end of every line. +\end{description} + +\item[Formats] Parameter formats. +\begin{description} + \item[PARAM] different controllers use different characters to introduce a parameter. Mach3 uses \code{P}, while others use \code{\#}. + + \item[FORMAT] is the floating point format used for coordinates. The default value \code{\%-7.4f} means a leading negative sign will be output for negative coordinates (very important), the number will be 7 digits long, and 4 digits will be to the right of the decimal point. The \code{f} indicates it is a floating point (real) number. + + \item[FR\_{}FORMAT] is the format used to insert feedrate parameters into the g-code. In the example, the leading \code{F} indicates this is a feedrate parameter. The rest of the format is similar to \code{FORMAT} --- leading negative sign possible, 5 digits wide, no digits to the right of the decimal point. + + \item[IJ\_{}FORMAT] is used to output \code{I J} coordinates to the g-code file. You can see by the definition on line 26 that this format reuses the \code{FORMAT} definition defined earlier. +\end{description} + +\item[Modes] Inch, metric, etc. modes +\begin{description} + \item[INCH\_{}MODE] used to set the controller to inch mode. + + \item[INCH\_{}MODE\_{}COMMENT] a comment inserted in the g-code indicating that inch mode is being set. + + \item[METRIC\_{}MODE] used to set the controller to Metric mode. + + \item[METRIC|\_{}MODE\_{}COMMENT] a comment inserted in the g-code indicating that metric mode is being set. + + \item[MIL\_{}MODE] used to set the controller to mil mode. Currently undefined in all profiles. + + \item[MICRON\_{}MODE] used to set the controller to micron mode. Currently undefined in all profiles. + + \item[ABSOLUTE\_{}MODE] would be used to set the controller to absolute coordinates mode. Currently just a comment. +\end{description} + +\item[G Codes] Basic g-code defines for movements. +\begin{description} + \item[RAPID] for rapid moves with the cutting tool out of the material. + \item[FEED] for movements with the cutting tool in the material. + \item[ARC\_{}CW] for cutting an arc clockwise. + \item[ARC\_{}CCW] for cutting an arc counter-clockwise. + \item[DWELL] pause for a number of seconds. Number of seconds (a float) is passed. +\end{description} + +\item[M Codes] M-code definitions. +\begin{description} + \item[SPINDLE\_{}ON] turns the spindle on. Takes \code{DWELL} as a parameter. + \item[SPINDLE\_{}OFF] turns the spindle off. + \item[END\_{}PROGRAM] signals the end of the gcode program. + \item[OPERATOR\_{}PAUSE] pauses for the operator to do something, like change the tool. +\end{description} + +\item[Coordinates] Definitions for coordinate parameters. +\begin{description} + \item[MOVE\_{}X] X axis movement. Passed an \code{X} coordinate as a parameter. + \item[MOVE\_{}Y] Y axis movement. Passed a \code{Y} coordinate as a parameter. + \item[MOVE\_{}XY] XY axis movement. Passed an \code{X} and \code{Y} coordinate as parameters. + \item[MOVE\_{}Z] Z axis movement. Passed a \code{Z} coordinate as a parameter. + \item[MOVE\_{}XYZ] XYZ axis movement. Passed \code{X Y Z} coordinates as parameters. +\end{description} + +\item[Rapids] Combinations of \code{RAPID} and the above coordinates. +\begin{description} + \item[RAPID\_{}MOVE\_{}X] rapid X axis movement. Passed an \code{X} coordinate as a parameter. + \item[RAPID\_{}MOVE\_{}Y] rapid Y axis movement. Passed a \code{Y} coordinate as a parameter. + \item[RAPID\_{}MOVE\_{}XY] rapid XY axis movement. Passed \code{X Y} coordinates as parameters. + \item[RAPID\_{}MOVE\_{}XY\_{}HOME] rapid XY axis movement to \code{X0 Y0}. + \item[RAPID\_{}MOVE\_{}Z] rapid Z axis movement. Passed a \code{Z} coordinate as a parameter. + \item[RAPID\_{}MOVE\_{}XYZ] rapid XYZ axis movement. Passed \code{X Y Z} coordinates as parameters. +\end{description} + +\item[Feeds] Movements at cutting speed, uses \code{FEED} and the coordinate definitions above. +\begin{description} + \item[FEED\_{}MOVE\_{}X] feed X axis movement. Passed an \code{X} coordinate as a parameter. + \item[FEED\_{}MOVE\_{}Y] feed Y axis movement. Passed a \code{Y} coordinate as a parameter. + \item[FEED\_{}MOVE\_{}XY] feed XY axis movement. Passed \code{X Y} coordinates as parameters. + \item[FEED\_{}MOVE\_{}XY\_{}WITH\_{}RATE] feed XY axis movement. Passed \code{X Y} coordinates and the feed rate. + \item[FEED\_{}MOVE\_{}Z] feed Z axis movement. Passed a \code{Z} coordinate as a parameter. + \item[FEED\_{}MOVE\_{}Z\_{}WITH\_{}RATE] feed Z axis movement. Passed \code{Z} coordinate and a feed rate as parameters. + \item[FEED\_{}MOVE\_{}XYZ] feed XYZ axis movement. Passed an \code{X Y Z} coordinates as parameters. +\end{description} + +\item[Drilling holes] Definitions for drilling holes. +\begin{description} + \item[DRILL\_{}CODE] the gcode instruction to drill a hole. + \item[RELEASE\_{}PLANE] the Z position to move the drill to after drilling. Takes a \code{Z} coordinate as a parameter. + \item[DWELL\_{}TIME] the time to dwell in the bottom of the hole. Takes a floating point (real) argument. + \item[DRILL\_{}FIRST\_{}HOLE] generated to drill the first hole. Takes \code{X Y Z}, feed rate, release \code{Z} plane and dwell time as parameters. + \item[DRILL\_{}HOLE] generated for subsequent holes. Takes \code{X Y} as parameters. +\end{description} + +\item[Tool change] Definitions for changing tools. +\begin{description} + \item[TOOL\_{}CODE] the tool selection code. Passed the tool number (an integer) as a parameter. + \item[TOOL\_{}MM\_{}FORMAT] a tool size formatted for millimeters. Passed a tool size (float). + \item[TOOL\_{}INCH\_{}FORMAT] a tool size formatted for inches. Passed a tool size (float). + \item[TOOL\_{}CHANGE] the command issued when a tool is to be changed. Takes tool number and tool size as arguments. + \item[TOOL\_{}CHANGE\_{}TABLE\_{}HEADER] the tool table header comment inserted in the g-code. + \item[TOOL\_{}CHANGE\_{}TABLE\_{}FORMAT] generates an entry for the tool table. Note that this is a function. +\end{description} + +\item[Circles / Arcs] Arc and circle commands. +\begin{description} + \item[CIRCLE\_{}TOP] a clockwise circle on the top of the board. Takes \code{X Y I J} as parameters. + \item[CIRCLE\_{}BOTTOM] a counter-clockwise circle on the bottom of the board. Takes \code{X Y I J} as parameters. +\end{description} +\end{description} + +% +%--------------------------------------------------------------------- +% +\section{Profiles}\index{profiles}\label{sec:Profiles} + +\warning{Advanced} +Profiles, which are found in the \code{profiles} folder, control the format that pcb-gcode uses when writing g-code. The files ending in \code{.pp} are the list of files shown when pcb-gcode is initially set up (See Section \vref{sec:Installation}), and also in the list of profiles in the \code{GCode Styles} tab. When a profile is selected, it is copied to \code{settings/gcode-defaults.h}. A sample profile is shown in Appendix \vref{chp:SampleProfile}. + +To create a custom profile, such as for a controller that is not already supported, begin with a profile that most closely matches the g-code the controller supports. Select this profile in \code{GCode Styles} and \code{Accept} the change. This will copy the profile to \code{settings/gcode-defaults.h}. Generate code for a test board and open the generated files in an editor. Find commands that the controller does not support, and edit \code{gcode-defaults.h} to generate the proper code. When testing is complete, copy \code{settings/gcode-defaults.h} into the \code{profiles} folder, renaming it with a descriptive name and the extension \code{.pp}. Edit the file and change the author and description fields. And of course, save a backup somewhere outside the pcb-gcode folder heirarchy. To share this profile with other users of this controller, upload the profile file to the \href{http://groups.yahoo.com/group/pcb-gcode/files/%21%20Software/Profiles/}{Profiles folder} on the Yahoo! group. + +For information on editing \code{gcode-defaults.h}, See Section \vref{sec:CustomizingGCode}. + + +% +%--------------------------------------------------------------------- +% +\section{Drill Rack Files}\index{rack files}\index{drill files}\label{sec:DrillRackFiles} + +Rack files allow the substitution of one drill size for a range of sizes that may be found in the board. For instance, a $0.031''$ drill might be used for hole sizes $0.025''$ -- $0.032''$. This cuts down on the number of drills that must be kept on hand, and the number of tool changes needed to drill a board. An example drill rack file is shown in Listing \ref{lst:SampleRackFile}. \textbf{Please heed the warning about using a tab character} between entries on a line. Otherwise, your rack file will not work. + +As can be seen, drills with different units of measure are supported. This includes inches, millimeters, mils, or wire gage sizes. See Listing \ref{lst:SampleEntries} for examples that work. The algorithm tries to be intelligent and assumes, for example, that 0.1 is in inches, whereas 0.6 is in millimeters. To be safe, add the unit of measure after the number. + +Looking at Listing \ref{lst:SampleRackFile}, the meaning of the fields are as follows: + +\begin{description} + \item[tool] The tool number to use. This is somewhat arbitrary unless the machine has a tool changer. Just be sure to start with 1 and increment by 1. + \item[drill\_size] The size of the actual drill. These should be in ascending order from smallest to largest. + \item[minimum] The smallest hole size this drill should be used for. + \item[maximum] The largest hole this drill should be used for. + \item[length] Currently not used. Leave set to 1.5in. +\end{description} + +Taking tool \code{T01} as an example. It is a 0.500mm drill, and it will be used for all holes from \code{0.000in} up to \code{0.025in}. Meaning, if there is a $0.015''$ hole in the board, it will be drilled with this bit. If there is a $0.045''$ hole, it will not be drilled with drill \code{T01}, but another drill will be used, if a good match is available. + +Looking at the table, it can be seen that all hole sizes from 0.000in up to 0.125in have been accounted for. If, say, a $0.130''$ hole is in the board, an error message will be given saying a drill is not available for that size hole. + +Rack file are selected by the following method: first, if there is a rack file with the same name as the board, but with the extension \code{.drl}, it will be used. Next, a default rack file will be used if it has been set in \code{pcb-gcode-setup} (See \figurename \vref{fig:SetupMachine}). Finally, if neither of those is available, the rack file \code{settings/default.drl} will be used from the \code{pcb-gcode} directory. If all these attempts fail and no rack file can be found, a table of drill sizes will be written to the drill file. In most cases this works well, but sometimes it can result in, for instance, drilling ten holes with a $0.031''$, then stopping and asking for a $0.032''$ bit. Obviously, the same bit could have been used for both sets of holes. That is why rack files exist. + + +\begin{lstlisting}[caption={Sample Rack File},label={lst:SampleRackFile}] +# +# Please note that you must use a TAB character +# between each setting on a line. +# +# Tip: Set the TAB size of your editor to 12 characters. +# +tool drill_size minimum maximum length +T01 0.500mm 0.000in 0.025in 1.5in +T02 0.032in 0.025in 0.035in 1.5in +T03 0.040in 0.035in 0.045in 1.5in +T04 0.050in 0.045in 0.055in 1.5in +T05 0.062in 0.055in 0.070in 1.5in +T06 0.085in 0.070in 0.125in 1.5in +\end{lstlisting} + +\begin{lstlisting}[caption={Sample entries for rack files},label={lst:SampleEntries}] +0.032in 0.032 inches +62ml 62 mils, 0.062 inches +0.43mm 0.43 millimeters +1500mc 1500 microns, 1.500 millimeters +60# 60 wire gage drill (0.040'' or 1.016mm) +0.12 0.12 inches +0.60 0.60 millimeters +43 43 wire gage drill +\end{lstlisting} + + + +% +%--------------------------------------------------------------------- +% +\section{User GCode}\index{user gcode}\label{sec:UserGCode} + +\warning{Advanced} +The pcb−gcode ULP allows you to customize the g−code created for your boards to a great degree. If you don't see an option in the profile that suits your needs, you can add your code to the \code{user-gcode.h} file. To enable user g-code, run \code{pcb-gcode-setup}, click the \code{GCode Options} tab, then turn the \code{Use user gcode...} option on. Generate a set of NC files for a board. Let's say, for example, that after you change the tool when you're drilling from the bottom of the board, you want the tool to move to X5 Y5 Z5, turn the spindle off, then turn it back on. Since this has to do with drilling the bottom of the board, we should look at the ...bot.drill.tap (bottom drill) file. An excerpt from a file is shown in Listing \vref{lst:BottomDrillBeforeGCode}. + +\begin{lstlisting}[caption={Bottom drill file before adding user g-code.},label={lst:BottomDrillBeforeGCode}] +G90 +(Tool Change Begin) +(Bottom Tool Change Begin) +M05 +G00 X0.0000 Y0.0000 Z2.0000 +M06 T01 ; 0.0236 +(Bottom Tool changed) +(Tool changed) +G00 Z0.0200 +M03 +G04 P3.000000 +(Bottom Tool Change End) +(Tool Change End) +G82 X−1.6200 Y1.2900 Z−0.1000 F9.80 R0.0200 P0.250000 +G82 X−1.8800 Y0.5900 +G82 X−1.9500 Y1.4900 +G82 X−1.9500 Y1.8100 +\end{lstlisting} + +We want to add our commands after the tool is changed when drilling the bottom of the board. Looking at the sample above, you will find this line: +\begin{lstlisting}[firstnumber=12] +(Bottom Tool Change End) +\end{lstlisting} + +That's where we want our code to go. Now you can open user-gcode.h in your favorite editor, and use the Search or Find feature to find the line with Bottom Tool Change End. Here's an excerpt from the user−gcode.h file: + +\begin{lstlisting} +TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n"; +TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n"; +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; +TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n"; +\end{lstlisting} +The 3$^{rd}$ line is the one we're interested in: +\begin{lstlisting}[firstnumber=3] +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; +\end{lstlisting} +Change the line so that it looks like this: +\begin{lstlisting}[firstnumber=3] +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n" + "G00 X5 Y5 Z5\n" + "M05 (spindle off)\n" + "G04 P3.000000 (wait 3 seconds)\n" + "M03 (spindle on)\n"; + "G04 P3.000000 (wait 3 more seconds\n"; +\end{lstlisting} + +Notice that all the lines have a \lstinline!\n! before the last \lstinline!"! and that the last line is the only one that ends with a semi−colon \lstinline!;!. +Generate the files again. Open the bottom drill file in the editor and have a look. Here's how the sample looks now: +\begin{lstlisting} +G90 +(Tool Change Begin) +(Bottom Tool Change Begin) +M05 +G00 X0.0000 Y0.0000 Z2.0000 +M06 T01 ; 0.0236 +(Bottom Tool changed) +(Tool changed) +G00 Z0.0200 +M03 +G04 P3.000000 +(Bottom Tool Change End) +G00 X5 Y5 Z5 +M05 (spindle off) +G04 P3.000000 (wait 3 seconds) +M03 (spindle on) +G04 P3.000000 (wait 3 more seconds) +(Tool Change End) +G82 X−1.6200 Y1.2900 Z−0.1000 F9.80 R0.0200 P0.250000 +G82 X−1.8800 Y0.5900 +G82 X−1.9500 Y1.4900 +G82 X−1.9500 Y1.8100 +\end{lstlisting} +Note that the lines added to the user-gcode.h file are now in the generated g-code from lines 13-17. + +Since we put our code in the \lstinline!TOOL_CHANGE_END[BOTTOM]! definition, it will only be put in files for the bottom side of the board. So the code will be in the bot.drill file. If we only wanted our code in files for the top side, we would have put the code in \lstinline!TOOL_CHANGE_END[TOP]!. You can probably guess that if we wanted the code in both the top and bottom files, we would have put the code in \lstinline!TOOL_CHANGE_END[TOOL_CHANGE_END[ALL]!. +To conclude, the steps to follow are: +\begin{enumerate} + +\item Generate a set of files. +\item Find the file that you want the code to be put in (bot, top, etc.). +\item Find the location in the file that you want the code. +\item Find the comment near that location. +\item Find the comment in the user−gcode.h file. +\item Insert your code after the comment. +\item Generate the files again and check to be sure it is correct. +\end{enumerate} + +% +%--------------------------------------------------------------------- +% +%\section{About the Author} +% +%Users have asked about my background in the past. I am currently a full-time college student studying Cell Biology / Biotechnology. My goal is to be accepted into a PhD program where I can design a direct-to-nerve interface to provide haptic (touch) and proprioceptive (position) feedback from prosthetics worn by amputees. By providing at least touch feedback, the wearer will incorporate the prosthetic into their body image. It will become part of their \textit{self} rather than just a machine attached to their body. + +\appendix +\chapter{Sample Mach3 Profile}\label{chp:SampleProfile} + +\begin{lstlisting}[numbers=left, + breaklines=true, + numberstyle=\tiny\color{gray}, + basicstyle=\ttfamily\tiny +] +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. + +// +// author=John Johnson +// description=Mach3 - EMC for Windows +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +string FORMAT = "%-7.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.0f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; + +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; + +\end{lstlisting} + + +\backmatter + +\printindex + +\end{document} diff --git a/trunk/ulp/dose-pro.ulp b/trunk/ulp/dose-pro.ulp new file mode 100644 index 00000000..c41e534a --- /dev/null +++ b/trunk/ulp/dose-pro.ulp @@ -0,0 +1,187 @@ +#usage "Export data for SMD solder cream dispenser\n" + "

    " + "Generates data to control the solder cream dosage for the dispenser " + "unit of 'Martin' on 'Bungard' drill/milling machines." + "

    " + "The file boardname.plt contains the coordinates of the SMD pads " + "in the top layer, while boardname.plb contains the coordinates of those in the " + "bottom layer." + "

    " + "The file boardname.dod contains the information of the SMD pads " + "regarding tool number Txx." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +/* + Mit uval = 0 - 3 kann die Einheit ** der Daten eingestellt werden. + + ** 0: 1/10 mil + ** 1: 1 mil + ** 2: 0.025 mm + ** 3: 0.01 mm + + *06.12.2001 az +*/ + +int uval = 3; + +string Version = "1.0.4"; + +int smdx[], smdy[]; // size of smd +int x[], y[]; // coordinate of SMD +int tb[]; // top or bottom side +int index[]; +int c = 0; // counter + +void header(void) { + switch (uval) { + case 0 : + printf("1/10 mil\n%%\n"); + break; + + case 1 : + printf("1 mil\n%%\n"); + break; + + case 2 : + printf("0.025 mm\n%%\n"); + break; + + case 3 : + printf("0.01 mm\n%%\n"); + break; + } +} + +real value (int v) { + switch (uval) { + case 0 : + return (u2mil(v) * 10); + + case 1 : + return (u2mil(v)); + + case 2 : + return (u2mm(v) * 40); + + case 3 : + return (u2mm(v) * 100); + } +} + +void genfiles(string file) { + sort(c, index, tb, smdx, smdy, x, y); // sortiere top/bottom, groesse, coord. + + int tool = 0; + int ox =0; + int oy =0; + + for (int n = 0; n < c; n++) { + if (smdx[index[n]] == ox && smdy[index[n]] ==oy) { + ; + } + else { // *** change tool # + ox = smdx[index[n]]; + oy = smdy[index[n]]; + tool++; + + printf("T%02d\n", tool); // print tool change in file #1 + + output(filesetext(file, ".plb"), "at") { + printf("T%02d\n", tool); // print tool change in file #2 + } + + output(filesetext(file, ".dod"), "at") { // print in file #3 + printf("T%02d X%06.0f Y%06.0f\t| %06.2f\n", tool, + value(smdx[index[n]]), value(smdy[index[n]]), + u2mm(smdx[index[n]]) * u2mm(smdy[index[n]]) ); + } + } + + if (tb[index[n]]) { + printf("X%06.0fY%06.0f\n", + value(x[index[n]]), value(y[index[n]]) ); + } + else { + output(filesetext(file, ".plb"), "at") { + printf("X%06.0fY%06.0f\n", + value(x[index[n]]), value(y[index[n]]) ); + } + } + } + } + +void trailer(void) { printf("M30\n"); } + +void menue(void) { + dlgDialog("Dose pro") { + dlgLabel (usage); + int align = 1; + dlgHBoxLayout { + dlgGroup("Data resolution") { + dlgRadioButton("1/10 mil", uval); + dlgRadioButton("1 mil", uval); + dlgRadioButton("0.025 mm", uval); + dlgRadioButton("0.01 mm", uval); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+&OK") dlgAccept(); + dlgPushButton("-&Cancel") exit (0); + dlgStretch(1); + } + }; + return; + } + +// main +if (board) { + board(B) { + menue(); + output(filesetext(B.name, ".dod"), "wt") { + printf("This file is generated by %s %s, exported from:\n", filename(argv[0]), Version); + printf("%s at %s;\n", B.name, t2string(time())); + printf("%s;\n\n", EAGLE_SIGNATURE); + } + output(filesetext(B.name, ".plb"), "wt") { + header(); + } + output(filesetext(B.name, ".plt"), "wt") { + header(); + B.elements(E) { + E.package.contacts(C) { + if (C.smd) { + + // collect SMD-Pads + smdx[c] = C.smd.dx; + smdy[c] = C.smd.dy; + x[c] = C.smd.x; + y[c] = C.smd.y; + + if (E.mirror) { + tb[c] = 0; + } + else { + tb[c] = 1; + } + c++; + } + } + } + + output(filesetext(B.name, ".dod"), "at") { + printf("%d SMD-Pads\n\n", c); + header(); + printf("Tool Pad-X Pad-Y Square mm^2\n"); + } + genfiles(B.name); + trailer(); + output(filesetext(B.name, ".plb"), "at") { trailer(); } + } + } +} + +else dlgMessageBox("Start this ULP from a Board!", "OK"); diff --git a/trunk/ulp/drill-aid.ulp b/trunk/ulp/drill-aid.ulp new file mode 100644 index 00000000..5c8f8231 --- /dev/null +++ b/trunk/ulp/drill-aid.ulp @@ -0,0 +1,75 @@ +#usage "Limit drill diameter of pads, vias and holes for easier manual drilling.\n" + "

    " + "Draws small circles in layer 116 inside the drilling of pads, vias and holes, " + "which should make it easier to center the tool while drilling the " + "board manually." + "

    " + "Usage: RUN drill-aid [ diameter ]" + "

    " + "Activate layer 116 in addition to the bottom side layers in the " + "CAM processor or use the DISPLAY command to activate it for printing." + "

    " + "To delete the elements in layer 116 afterwards, display it without " + "any other layers, and use GROUP and DELETE. Then remove the whole " + "layer with the command LAYER -116." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +real drilcent = 0.3; // center drill diameter + +string cmd = "GRID mm;\nLayer 116 centerDrill;\nchange layer 116;\n"; + +void center(int x, int y, int drill) { + real width = (u2mm(drill) - drilcent) / 2 + 0.05; // overlap 0.05mm 2008-09-01 alf + real radius = width / 2 + (drilcent / 2); + if (radius < (drilcent / 2 + 0.025) ) return; + string h; + sprintf(h, "circle %.3f (%.3f %.3f) (%.3f %.3f) ;\n", + width, + u2mm(x), u2mm(y), u2mm(x) + radius, u2mm(y) ); + cmd += h; + return; +} + +if (board) board(B) { + if (argv[1]) drilcent = strtod(argv[1]); + else { + int Result = dlgDialog("Drill AID V2") { + dlgLabel(usage); + dlgLabel("&Drill center diameter mm"); + dlgHBoxLayout { + dlgRealEdit(drilcent); + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + dlgPushButton("-&Cancel") dlgReject(); + } + }; + if (!Result) exit (0); + } + + B.holes(L) { + center(L.x, L.y, L.drill); + } + B.elements(E) { + E.package.holes(H) { + center(H.x, H.y, H.drill); + } + E.package.contacts(C) { + if (C.pad) { + center(C.pad.x, C.pad.y, C.pad.drill); + } + } + } + B.signals(S) { + S.vias(V) { + center(V.x, V.y, V.drill); + } + } + exit (cmd); +} + +else dlgMessageBox("Start this ULP in a Board!", "OK"); +exit (0); diff --git a/trunk/ulp/drillcfg.ulp b/trunk/ulp/drillcfg.ulp new file mode 100644 index 00000000..11acba42 --- /dev/null +++ b/trunk/ulp/drillcfg.ulp @@ -0,0 +1,118 @@ +#usage "Export drill configuration\n" + "

    " + "Generates a drill configuration file for the current board." + "

    " + "Units: mm or inches can be chosen." + "

    " + "The generated file can be edited before saving." + "

    " + "Use this ULP also for checking the drills of a board." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +/* + * This EAGLE User Language Program generates + * a drill configuration file for the current + * board. + * + * Units can be switched between mm and inch. + */ + +string unitName[] = { "mm", "in" }; +int Unit, unitPrec[] = { 2, 3 }, RoundFactor = pow(10, unitPrec[Unit]), + Result = 0, imax = 0; +real Drilling[]; +string s, fileName, conf = ""; +enum { unitMM, unitINCH}; + + int getunit (void) { + string s; + int Unit = unitMM; // preset unit + Result = dlgDialog("Drill Configuration") { + dlgHBoxLayout { + dlgStretch(0); + dlgGroup("Select unit for output file") { + dlgStretch(0); + dlgGridLayout { + dlgCell(1, 0) dlgRadioButton("&mm", Unit); + dlgCell(2, 0) dlgRadioButton("&inch", Unit); + } + } + dlgStretch(0); + dlgVBoxLayout { + dlgHBoxLayout { + dlgSpacing(20); + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + dlgHBoxLayout { + dlgSpacing(20); + dlgStretch(0); + dlgPushButton("-Quit") dlgReject(); + dlgStretch(1); + } + } + dlgStretch(1); + } + dlgStretch(1); + }; + RoundFactor = pow(10, unitPrec[Unit]); + return Unit; +} + +void AddDrilling(int Size) +{ + real x; + + switch (Unit) { + case unitMM: x = round(u2mm(Size) * RoundFactor) / RoundFactor; + break; + case unitINCH: x = round(u2inch(Size) * RoundFactor) / RoundFactor; + break; + } + + for (int i = imax; --i >= 0; ) + if (Drilling[i] == x) + return; + Drilling[imax++] = x; +} + +Unit = getunit(); +if (Result == 0) exit(0); +board(B) { + B.holes(H) AddDrilling(H.drill); + B.signals(S) S.vias(V) AddDrilling(V.drill); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) + AddDrilling(C.pad.drill); + } + E.package.holes(H) AddDrilling(H.drill); + } + sort(imax, Drilling); + + for (int i = 0; i < imax; ++i) { + sprintf(s, "T%02d %5.*f%s\n", i + 1, unitPrec[Unit], Drilling[i], unitName[Unit]); + conf += s; + } + + dlgDialog("Edit Drill Configuration") { + dlgVBoxLayout { + dlgLabel("Edit only if you are sure what you do!"); + dlgTextEdit(conf); + dlgPushButton("+Ok") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; + + + fileName = dlgFileSave("Save Configuration File", filesetext(B.name, ".drl"), "*.drl"); + if (fileName == "") exit(0); + + output(fileName) { + printf("%s",conf); + } + } diff --git a/trunk/ulp/drillegend-stack.ulp b/trunk/ulp/drillegend-stack.ulp new file mode 100644 index 00000000..95fb8b36 --- /dev/null +++ b/trunk/ulp/drillegend-stack.ulp @@ -0,0 +1,1213 @@ +#usage "Drill Legend for Eagle Board.

    " + "This ULP adds a drill legend to a board in Layer 144 (default).
    " + "Sort both drill tools and drill diameters in the same ascending order as the drill legend.
    " + "You can also generate the drill configuration for the CamProcessor.

    " + "Author: c.bohrer@m6net.fr>
    " + "


    " + "Also place the drill symbols on the board.
    " + "Do not use the Option - Set - Drill set,
    " + "while drills are rounded in diameter in this ULP!
    " + "You can extend the symbol list below the line:
    " + "ARRAY OF EAGLE DRILL SYMBOLS
    in the source text of this ULP.
    " + "support@cadsoft.de" + +/**************************************************** + * DRILEGEND 2.01 for Eagle 4.04 (12/04/2002) * + * By Christian BOHRER (PCB Designer) * + * c.bohrer@m6net.fr * + **************************************************** + + * THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY FOR POSSIBLE DAMAGE */ + +string Version = "2.10"; // 2011-06-15 check if drillegend layer exist + // generate a layer for any stack deep +// 2.02 2005-09-14 Place also the symbols of drills on board. alf@cadsoft.de +// 2.03 2008-07-30 place correct symbol alf@cadsoft.de +// 2.04 2008-09-04 "_DL.scr" extension lower case +// 2.10 2008-12-22 Place legend, define layer for stack (Vias) and +// draw symbols in Stack-Layer +// 2.11 2011-12-20 corrected drill calculation for higher resolution in V6 alf@cadsoft.de +// + +#require 5.0001; + + /************** DEFAULT SETTINGS ***********************/ + +int Legend = 1; // ** mode for drawing drill-symbol 2005-09-14 ** +int SymbolLayer = 144; +string SymbolLayerName = "DrillLegend"; +string Legend_layer ; sprintf(Legend_layer, "LAYER %d %s;\n", SymbolLayer, SymbolLayerName) ; // ** the layer of drill symbols are drawing 2005-09-14 ** +int SymbolSize = 40; /*Symbol diameter*/ +int SymbolWidth = 4; /*Symbol wire width*/ +int Drl_cnt = 0; // drill count for array +int DrilSymbol[]; // symbol number of drill +int DrillDiam[]; +int Drl_x[], Drl_y[]; // coordinate of drill ** 2005-09-14 +numeric string Drl_stack[]; // drill stack deep 2010-12-22 +int Idrl_stack = 0; // index + + +string TextFont[] = {"Vector", "Proportional", "fixed"}; +real TextSize = 70; +int TextRatio = 5; +real TextOffset = 1.5; +int IdxFnt = 0; //Vector + +int decMM = 2; /*number of decimal for milimeters*/ +int decMIL = 0; /*number of decimal fol mils*/ +int SortHoles = 1; /* 0= alternate, 1= mixed, 2= non-plated last*/ +string TolPlated = "0.02"; +string TolNonPlated = "0.03"; +int VerticalChart = 1; /* if 0 : Horizontal chart*/ +real HighCellFactor = 1.1; /* 1.0 minimum*/ +real WideCellFactor = 1.1; /* 1.0 minimum*/ +int CellOutline = 4; +int TitleOutline = 4; +int TableOutline = 8; + +string LField[] = {"&Symbols","&Tools N","&MM","M&ils","Mi&crons","&Quantity","&Plated","Tole&rance"}; +string LTitle[] = {"Sym","N","MM","Mils","Mic","Qty","Plated","Tol"}; +int LRank[] = {1,2,4,3,0,5,6,0}; //Rank = from 1 to 8. ( 0 = unselect) +string Rank[] = {"0","1","2","3","4","5","6","7","8"}; +string PlatedStatus[] = {"NOT", "BOTH", "YES"}; +real LoffsetX = 0.0; // Legend offset in X 2010-12-22 +real LoffsetY = 150.0; // Legend offset in Y + + +int OutputDrillRack = 0; +string DrillRackFile = "DRILLRACK.DRL"; /* drill rack file name */ +enum { unitMM, unitINCH }; +int Unit = unitMM; /* set this to the desired unit! */ + +int OutputUserCfg = 1; +int InputUserCfg = 1; +string UserCfgFile = "DRILEGEND.CFG"; /* drill legend user config */ +int AbsoluteLibPath = 1; +int i, j, k, Dcnt = 0, Lcnt = 1, nlines, LayerSel; +int index[]; +int Drills[], Pcnt[], Hcnt[], Ptype[], Htype[]; +string ScrName, ProjectPath, UserSettings[], LList[], LayerName[]; +int Lpos[], Cell[], LCell[], Hcell[], Bcell[], LayerNbr[]; + +int EV = EAGLE_VERSION; +int ER = EAGLE_RELEASE; + +string BoardName; +int Bx, By; + +string str_symbols; // place the symbols on board on all drills 2005-09-14 alf@cadsoft.de + +/******* DRILL RACK FOR THE CAM PROCESSOR (DRILLCFG.ULP) *******/ +string unitName[] = { "mm", "in" }; +int unitPrec[] = { 2, 3 }; +int RoundFactor = pow(10, unitPrec[Unit]); +real Drilling[]; +int imax = 0; + + +/**************ADD OR UPDATE DRILL LEGEND***********************/ + +int replace = 0; +int rename = 0; +string lay; +int laycnt = 0; + +board(B) { + int leglaynew = 1; // 2008-07-30 alf@cadsoft.de + BoardName = B.name; + Bx = B.area.x1; + By = B.area.y1; + B.elements(E) { + if(E.name == "DRILEGEND"){ + replace = 1; + leglaynew = 0; + } + } + ScrName = filesetext(B.name, "_DL.scr"); // 2008-09-04 extension lower case + ProjectPath = filedir(B.name); + + B.layers(L) { + if(L.used == 1) { + if (L.number == SymbolLayer) { + Legend_layer = ""; + leglaynew = 0; + string e; // 2011-06-15 + sprintf(e, "!Layer %d exist and used.\nDelete first all symbols in layer %d and the legend table.\n" + + "To delete the legend table select layer tOrigin.", SymbolLayer, SymbolLayer); + dlgMessageBox(e, "OK"); + exit(-1); + } + sprintf(lay,"%d %s", L.number, L.name); + LayerName[laycnt] = lay; + LayerNbr[laycnt] = L.number; + laycnt++; + } + } + if (leglaynew) { + sprintf(lay,"%d %s", SymbolLayer, SymbolLayerName); + LayerName[laycnt] = lay; // 2005-09-14 alf@cadsoft.de + LayerNbr[laycnt] = SymbolLayer; + laycnt++; + } +} + +string LbrPath; +string UlpLbrPath; + +if(AbsoluteLibPath == 1) { + sprintf(LbrPath,"'%sdrilegend.lbr'",ProjectPath); //With '' for path in script command + //Script command dont work without '' if the path contain a space like 'program Files' + sprintf(UlpLbrPath,"%sdrilegend.lbr",ProjectPath); //Without '' for path in fileglob +} +else { + LbrPath = "./drilegend.lbr"; + UlpLbrPath = "./drilegend.lbr"; +} + +string ok[]; +rename = fileglob(ok, UlpLbrPath); //Rename package if lbr exist + +int CreateCfgFile = 0; +string CfgPath; +sprintf(CfgPath,"%s\%s",ProjectPath,UserCfgFile); +string cfg[]; +CreateCfgFile = fileglob(cfg, CfgPath); + +/*********** SAVE USER'S SETTINGS *************************/ + +void OutputUserCfgFile() { + output(CfgPath) { + printf("InputUserCfg = %d\n", InputUserCfg); + printf("SymbolLayer = %d\n", SymbolLayer); + printf("SymbolSize = %d\n", SymbolSize); + printf("SymbolWidth = %d\n", SymbolWidth); + + printf("TextSize = %.4f\n", TextSize); + printf("TextRatio = %d\n", TextRatio); + printf("IdxFnt = %d\n", IdxFnt); + + printf("decMM = %d\n", decMM); + printf("decMIL = %d\n", decMIL); + printf("SortHoles = %d\n", SortHoles); + printf("TolPlated = %s\n", TolPlated); + printf("TolNonPlated = %s\n", TolNonPlated); + printf("PlatedStatusNot = %s\n", PlatedStatus[0]); + printf("PlatedStatusBoth = %s\n", PlatedStatus[1]); + printf("PlatedStatusYes = %s\n", PlatedStatus[2]); + + printf("VerticalChart = %d\n", VerticalChart); + printf("HighCellFactor = %-.2f\n", HighCellFactor); + printf("WideCellFactor = %-.2f\n", WideCellFactor); + printf("CellOutline = %d\n", CellOutline); + printf("TitleOutline = %d\n", TitleOutline); + printf("TableOutline = %d\n", TableOutline); + + printf("SymbTitle = %s\n", LTitle[0]); + printf("ToolTitle = %s\n", LTitle[1]); + printf("MMTitle = %s\n", LTitle[2]); + printf("MilTitle = %s\n", LTitle[3]); + printf("MicTitle = %s\n", LTitle[4]); + printf("QtyTitle = %s\n", LTitle[5]); + printf("TypeTitle = %s\n", LTitle[6]); + printf("ToleTitle = %s\n", LTitle[7]); + + printf("SymbRank = %d\n", LRank[0]); + printf("ToolRank = %d\n", LRank[1]); + printf("MMRank = %d\n", LRank[2]); + printf("MilRank = %d\n", LRank[3]); + printf("MicRank = %d\n", LRank[4]); + printf("QtyRank = %d\n", LRank[5]); + printf("TypeRank = %d\n", LRank[6]); + printf("ToleRank = %d\n", LRank[7]); + + printf("OutputDrillRack = %d\n", OutputDrillRack); + printf("DrillRackFile = %s\n", DrillRackFile); + printf("Unit = %d\n", Unit); + + printf("OutputUserCfg = %d\n", OutputUserCfg); + printf("UserCfgFile = %s\n", UserCfgFile); + } + return; +} + +/********* LOAD USER'S SETTINGS *********************/ + +string LoadSettings(string var) { +string a[], b; char c = ' '; + for(i = 0; i < nlines; i++){ + b = UserSettings[i]; + if (strsplit(a, b, c) == 3) { + if(var == a[0]) { return a[2]; + } + } + } + return var; +} + +void LoadUserCfgFile() { + InputUserCfg = strtol(LoadSettings("InputUserCfg")); + if(InputUserCfg == 1) { + SymbolLayer = strtol(LoadSettings("SymbolLayer")); + SymbolSize = strtol(LoadSettings("SymbolSize")); + SymbolWidth = strtol(LoadSettings("SymbolWidth")); + + TextSize = strtod(LoadSettings("TextSize")); + TextRatio = strtol(LoadSettings("TextRatio")); + IdxFnt = strtol(LoadSettings("IdxFnt")); + + decMM = strtol(LoadSettings("decMM")); + decMIL = strtol(LoadSettings("decMIL")); + SortHoles = strtol(LoadSettings("SortHoles")); + TolPlated = LoadSettings("TolPlated"); + TolNonPlated = LoadSettings("TolNonPlated"); + PlatedStatus[0] = LoadSettings("PlatedStatusNot"); + PlatedStatus[1] = LoadSettings("PlatedStatusBoth"); + PlatedStatus[2] = LoadSettings("PlatedStatusYes"); + + VerticalChart = strtol(LoadSettings("VerticalChart")); + HighCellFactor = strtod(LoadSettings("HighCellFactor")); + WideCellFactor = strtod(LoadSettings("WideCellFactor")); + CellOutline = strtod(LoadSettings("CellOutline")); + TitleOutline = strtod(LoadSettings("TitleOutline")); + TableOutline = strtod(LoadSettings("TableOutline")); + + LTitle[0] = LoadSettings("SymbTitle"); + LTitle[1] = LoadSettings("ToolTitle"); + LTitle[2] = LoadSettings("MMTitle"); + LTitle[3] = LoadSettings("MilTitle"); + LTitle[4] = LoadSettings("MicTitle"); + LTitle[5] = LoadSettings("QtyTitle"); + LTitle[6] = LoadSettings("TypeTitle"); + LTitle[7] = LoadSettings("ToleTitle"); + + LRank[0] = strtol(LoadSettings("SymbRank")); + LRank[1] = strtol(LoadSettings("ToolRank")); + LRank[2] = strtol(LoadSettings("MMRank")); + LRank[3] = strtol(LoadSettings("MilRank")); + LRank[4] = strtol(LoadSettings("MicRank")); + LRank[5] = strtol(LoadSettings("QtyRank")); + LRank[6] = strtol(LoadSettings("TypeRank")); + LRank[7] = strtol(LoadSettings("ToleRank")); + + OutputDrillRack = strtol(LoadSettings("OutputDrillRack")); + DrillRackFile = LoadSettings("DrillRackFile"); + Unit = strtol(LoadSettings("Unit")); + + OutputUserCfg = strtol(LoadSettings("OutputUserCfg")); + UserCfgFile = LoadSettings("UserCfgFile"); + } + return; +} + + +if(CreateCfgFile == 0) { OutputUserCfgFile(); } +if(CreateCfgFile == 1) { + nlines = fileread(UserSettings, CfgPath); + LoadUserCfgFile(); +} + + +/****************** HELP *************************/ + + string HelpLegend = "

    Legend


    Drill legend Settings" + + "

    " + + "" + + ""+ + "" + + "
    Title
    Enter here the name of your choice for the title field.
    Rank
    Choose here a number (from 1 to 8) for the position of each field in the drill legend. 0 = unselected.

    " + + "

    Drill legend Orientation

    "+ + "" + + ""+ + "" + + "
    Horizontal
    Choose this option for horizontal drill legend.
    Vertical
    Choose this option for vertical drill legend.
    "; + + string HelpSymbols = "

    Symbols


    Symbols Settings

    " + + "" + + "" + + "" + + "" + + "" + + "
    Symbol Layer
    Choose in this field the layer in which you want draw this drill legend.
    Symbol Size
    Enter in this field the symbol diameter (in mils).
    Symbol Width
    Enter in this field the symbol line width (in mils).

    " + + "Nota: " + + "Drilegend.ulp drills symbols and Eagle drills symbols are associated with the same drill tool number " + + "in the same ascending order, so each drill tool number always is associated with the same drill symbol. " + + "But, they are not associated in the same manner with the holes diameters.

    " + + "Drilegend.ulp sort the holes diameters (like drillcfg.ulp) in ascending order before to associate each with " + + "a drill tool number, so drill tools numbers and holes diameters are sorted together in a same increasing order. " + + "Eagle extract the holes diameters as is from the board, and give them a increasing tool number without sort before.

    " + + "The result of each method is evidently different and that's why it's very important after each run of this ulp " + + "to open the \"Options>Settings>Drill\" and verify if it's necessary to update and sort holes diameters and tools numbers " + + "in the same ascending order like the drill legend."; + + string HelpTexts = "

    Texts


    Texts Settings

    " + + "" + + "" + + "" + + "" + + "
    Text Font
    Choose a text font in the list.
    Text Size
    Enter in this field the font size (in mils).
    Text Ratio
    Enter in this field the font ratio (in %).

    " + + "Nota: For printer output choose the font what you want but " + + "for gerber output keep VECTOR."; + + string HelpTable = "

    Table


    Cell Margin Factor

    " + + "Enter in theses fields a value (from 1.0 to 9.9) for increase or decrease the space between texts and border cells.

    " + + "" + + "" + + "" + + "
    Horizontal
    Horizontal space between texts and border cells.
    Vertical
    Vertical space between texts and border cells.

    " + + "Outline Width

    " + + "" + + "" + + "" + + "" + + "
    Cell
    Enter in this field the outline width of a cell (in mils).
    Title
    Enter in this field the outline width of the title (in mils).
    Table
    Enter in this field the outline width of the table (in mils).
    "; + + string HelpHoles = "

    Holes


    Non-Plated

    " + + "All holes diameters (plated or not plated) are sorted in ascending mode.

    " + + "" + + "" + + "" + + "" + + "" + + "
    Alternate
    For each diameter, non-plated holes are treated after plated holes but before the following diameter.
    Mixed
    Only one diameter per column. Plated and non-plated holes with same diameter are added in the same column. " + + "In this case, plated status show: \"BOTH\".
    Last
    All plated holes diameter are treated first, then all non-plated are treated last.

    " + + "Plated Status

    " + + "" + + "" + + "" + + "" + + "" + + "
    Not Plated
    Enter in this field a string meaning: not plated hole. Default: \"NOT\".
    Mixed
    Enter in this field a string meaning: plated and not plated use the same drill tool. Default: \"BOTH\".
    Plated
    Enter in this field a string meaning: plated hole. Default: \"YES\".

    " + + "Nota: Avoid to use the same diameter for plated an non-plated holes.

    " + + "Unit Precision

    " + + "Choose here the number of unit after the decimal point." + + "" + + "" + + "
    Mils
    Unit of precision for mils.
    MM
    Unit of precision for millimeters.

    Holes Tolerance

    " + + "" + + "" + + "" + + "
    Plated Holes
    Enter in this field your value for plated holes tolerance.
    Non-Plated Holes
    Enter in this field your value for non-plated holes tolerance.

    " + + "Nota: Tolerance field is String type, so you can enter anything like: 0,02 or +/- 0.03"; + + string HelpOutputs = "

    Outputs


    Drill Rack File for CAM Processor

    " + + "" + + "
    Create file
    Click on this check button for create the drill rack file used in the cam processor. " + + "Choose the output unit: milimeters or inches.
    "; + + +/******** ARRAY OF EAGLE DRILL SYMBOLS ********/ +// Y +// 4 + + + + + +// 3 + + + + + +// 2 + + + + + +// 1 + + + + + +// 0 + + + + + +// 0 1 2 3 4 X + +string Symbol[] = { + "W 24 20,W 02 42", // 1 + "W 04 40,W 44 00", // 2 + "W 22 24 44 40 00 04 24", // 3 + "W 22 24 42 20 02 24", // 4 + "W 04 44 00 40 04", // 5 + "W 04 40 44 00 04", // 6 + "W 02 42 24 20 02", // 7 + "W 24 20 42 02 24", // 8 + "W 04 40,W 44 00,W 24 20", // 9 + "W 04 40,W 44 00,W 02 42", // 10 + "W 04 44 22 04,W 22 20", // 11 + "W 24 22 40 00 22", // 12 + "W 02 22 44 40 22", // 13 + "W 42 22 04 00 22", // 14 + "W 24 20,W 02 42,C 22 42", // 15 + "C 22 42,C 22 32,W 24 20,W 02 42", // 16 + "W 04 24 44 42 40 20 00 02 04,W 24 20,W 02 42", // 17 + "W 04 02 00 20 40 42 44 24 04,W 13 11 31 33 13,W 24 20,W 02 42", // 18 + + "W 02 24,W 24 42,W 42 02,W 22 20", // 19 new 2005-09-14 + "W 00 22,W 22 40,W 02 24,W 24 42", // 20 + "C 33 34,C 11 12", // 21 + "C 33 34,W 00 20,W 20 22,W 22 02,W 02 00", // 22 + "C 22 24,W 00 40,W 40 44,W 44 04,W 04 00", // 23 + "C 22 24,W 02 24,W 24 42", // 24 + "C 22 24,W 24 42,W 42 20", // 25 + "C 22 24,W 42 20,W 20 02", // 26 + "C 22 24,W 20 02,W 02 24", // 27 + "C 22 24,C 13 23", // 28 + "C 22 24,C 23 33", // 29 + "C 22 24,C 33 43", // 30 + "C 22 24,C 32 42", // 31 + "C 22 24,C 31 41", // 32 + "C 22 24,C 21 31", // 33 + "C 22 24,C 11 21", // 34 + "C 22 24,C 12 22", // 35 + "C 12 22,W 44 22,W22 40", // 36 + "C 23 33,W 40 22,W22 00", // 37 + "C 32 42,W 00 22,W22 04", // 38 + "C 21 32,W 44 22,W22 44", // 39 + + "C 22 42,W 00 44", // default ** + "" + }; + + +string DrawSymbol(int No, int Xs, int Ys, int Mode) { + Xs = Xs - (SymbolSize/2); + Ys = Ys - (SymbolSize/2); + string a[], c[], tmps, cmd, hs; + int b = 0, d = 0, U = SymbolSize/4, sx, sy, m, p; + //sprintf(tmps, "# place Symbol Nb: %d;\n", No); + if (Symbol[No]) { // check if Symbol string defined + b = strsplit(a, Symbol[No], ','); + for(m=0; m SymbolSize*0.7) { haut = TextSize * TextOffset * HighCellFactor;} + else { haut = SymbolSize * HighCellFactor;} + int org = (haut - TextSize)/2, WideMax = 0; + + for(int i = 0; i < Lcnt; ++i) { + + for(k = 0; k < 8; k++){ + if(LRank[k] > 0) { + if((k == 0) && (i > 0)) { + printf(DrawSymbol(strtol(LList[i]), Lpos[LRank[k]]+(LCell[k]/2), bas +(haut/2), Legend)); + } + else { + printf("Text '%s' R0 (%d %d);\n", LList[(k*100)+i], + CenterText(LList[(k*100)+i], LCell[k], Lpos[LRank[k]]), bas + org); + } + printCell(Lpos[LRank[k]], Lpos[LRank[k]] + LCell[k], haut, bas, CellOutline); + if(i == 0) { WideMax = WideMax + LCell[k];} + } + } + + bas -= haut; + } + printCell(0, WideMax, haut, 0, TitleOutline); + printCell(WideMax, 0, 0, haut, TitleOutline); + printCell(0, WideMax, haut, bas + haut, TableOutline); + printCell(WideMax, 0, bas + haut, haut, TableOutline); + return; +} + + +void DrillChartHorizontal(int gauche) { + int bas, org, WideMax = 0; + + for(int i = 0; i < Lcnt; ++i) { + + for(k = 0; k < 8; k++){ //k = 8 Fields + if(LRank[k] > 0) { + + bas = Bcell[LRank[k]]; + if(Cell[i] < Hcell[0]) { Cell[i] = SymbolSize * 1.3 * WideCellFactor;} + org = (Hcell[k] - TextSize)/2; + if(bas < WideMax) { WideMax = bas;} + if((k == 0) && (i > 0)) { // if symbol field but not title field + printf(DrawSymbol(strtol(LList[i]),gauche+(Cell[i]/2), bas +(Hcell[k]/2), Legend)); + printCell(gauche, gauche + Cell[i], bas + Hcell[k], bas, CellOutline); + } + + else { + printf("Text '%s' R0 (%d %d);\n", LList[(k*100)+i], + CenterText(LList[(k*100)+i], Cell[i], gauche), bas + org); + printCell(gauche, gauche + Cell[i], bas + Hcell[k], bas, CellOutline); + } + } + } + + gauche = gauche + Cell[i]; + + printCell(0, Cell[0], 0, WideMax, TitleOutline); + printCell( Cell[0], 0, WideMax, 0, TitleOutline); + + } + printCell(0, gauche, 0, WideMax, TableOutline); + printCell(gauche, 0, WideMax, 0, TableOutline); +} + + +void defHigh() { // for horizontal table + if(TextSize > SymbolSize) { Hcell[0] = TextSize * TextOffset * HighCellFactor;} + else { Hcell[0] = SymbolSize * TextOffset * HighCellFactor;} + for(i = 1; i < 8; i++) { + Hcell[i] = TextSize * TextOffset * HighCellFactor; + } + + int tmp[]; + for(i = 0; i < 8; i++) { + tmp[LRank[i]] = Hcell[i]; + } + + for(i = 1; i < 9; i++) { + Bcell[i] = Bcell[i-1] - tmp[i]; + } +} + + +void defPos() { //for vertical table + if(LCell[0] < SymbolSize*1.2) { LCell[0] = SymbolSize * 1.2 * WideCellFactor;} + int tmp[]; + for(i = 0; i < 8; i++) { + tmp[LRank[i]] = LCell[i]; + } + + for(i = 1; i < 8; i++) { + Lpos[i+1] = Lpos[i] + tmp[i]; + } +} + + +int CellLarge(string txt, int old) { + int new = (round((TextSize * 0.1 * WideCellFactor)*strlen(txt)))*10; + if( new > old) {return new;} + else { return old;} +} + +void TitleList() { + for(i=0;i<8;i++){ + LList[i*100] = LTitle[i]; + LCell[i] = CellLarge(LList[i*100], LCell[i]); + Cell[0] = CellLarge(LList[i*100], Cell[0]); + } +} + + +void List(int No, int Diam, int Qty, int Type, int cnt, string Tol) { + sprintf(LList[cnt], "%d",No); + sprintf(LList[100+cnt], "%d",No + 1); + if(decMM == 0) {sprintf( LList[200+cnt], "%-.0f", round(u2mm(Diam)));} // 2011-12-20 + if(decMM == 1) {sprintf( LList[200+cnt], "%-.1f", round(u2mm(Diam)*10)/10);} + if(decMM == 2) {sprintf( LList[200+cnt], "%-.2f", round(u2mm(Diam)*100)/100);} + if(decMM == 3) {sprintf( LList[200+cnt], "%-.3f", round(u2mm(Diam)*1000)/1000);} + if(decMIL == 0) {sprintf(LList[300+cnt], "%-.0f", round(u2mil(Diam)));} + if(decMIL == 1) {sprintf(LList[300+cnt], "%-.1f", round(u2mil(Diam)*10)/10);} + if(decMIL == 2) {sprintf(LList[300+cnt], "%-.2f", round(u2mil(Diam)*100)/100);} + if(decMIL == 3) {sprintf(LList[300+cnt], "%-.3f", round(u2mil(Diam)*1000)/1000);} + sprintf( LList[400+cnt], "%-.0f", round(Diam/10) ); + sprintf( LList[500+cnt], "%d", Qty); + sprintf( LList[600+cnt], "%s", PlatedStatus[Type]); + sprintf( LList[700+cnt], "%s", Tol); + + for(k=1;k<8;k++){ + LCell[k] = CellLarge(LList[(k*100)+cnt], LCell[k]); //Vertical table + if(LRank[k] > 0) {Cell[cnt] = CellLarge(LList[(k*100)+cnt], Cell[cnt]); } //Horizontal table + } + return; +} + + +int DrillsCapture(int Size, int Plated) { + for(i = 0; i < Dcnt; i++) { + if(Drills[i] == Size) { + if(Plated == 1) { + Ptype[i] = 1; + Pcnt[i]++; + return i; + } + if(Plated == 0) { + Htype[i] = 0; + Hcnt[i]++; + return i; + } + } + } + + Drills[Dcnt] = Size; + Htype[Dcnt] = 1; + + if(Plated == 1) { + Ptype[Dcnt] = 1; + Pcnt[Dcnt]++; + } + if(Plated == 0) { + Htype[Dcnt] = 0; + Hcnt[Dcnt]++; + } + Dcnt++; + return i; // 2008-07-30 +} + + + +void SortHolesMode(int Mode) { + if(Mode == 0) { //ALTERNATE + for( i = 0; i < Dcnt; i++) { + if(Ptype[index[i]] == 1) { + List(i, Drills[index[i]], Pcnt[index[i]], Ptype[index[i]] + 1, Lcnt, TolPlated); + Lcnt++; + } + if(Htype[index[i]] == 0) { + List(i, Drills[index[i]], Hcnt[index[i]], Htype[index[i]] + 0, Lcnt, TolNonPlated); + Lcnt++; + } + } + } + + if(Mode == 1) { //MIXED + string tol; + for( i = 0; i < Dcnt; i++) { + if(Ptype[index[i]] + Htype[index[i]] == 0) {tol = TolNonPlated;} + else {tol = TolPlated;} + List(i, Drills[index[i]], Pcnt[index[i]] + Hcnt[index[i]], Ptype[index[i]] + Htype[index[i]], Lcnt, tol); + Lcnt++; + } + } + if(Mode == 2) { //AT END + for( i = 0; i < Dcnt; i++) { + if(Ptype[index[i]] == 1) { + List(i, Drills[index[i]], Pcnt[index[i]], Ptype[index[i]] + 1, Lcnt, TolPlated); + Lcnt++; + } + } + for( i = 0; i < Dcnt; i++) { + if(Htype[index[i]] == 0) { + List(i, Drills[index[i]], Hcnt[index[i]], Htype[index[i]] + 0, Lcnt, TolNonPlated); + Lcnt++; + } + } + } +} + + +void AddDrilling(int Size) { + real x; + switch (Unit) { + case unitMM: x = round(u2mm(Size) * RoundFactor) / RoundFactor; + break; + case unitINCH: x = round(u2inch(Size) * RoundFactor) / RoundFactor; + break; + } + for (int i = imax; --i >= 0; ) + if (Drilling[i] == x) + return; + Drilling[imax++] = x; +} + + +void OutDrillRack() { + board(B) { + B.holes(H) AddDrilling(H.drill); + B.signals(S) S.vias(V) AddDrilling(V.drill); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) + AddDrilling(C.pad.drill); + } + E.package.holes(H) AddDrilling(H.drill); + } + sort(imax, Drilling); + output(DrillRackFile) { + for (int i = 0; i < imax; ++i) + printf("T%02d %5.*f%s\n", i + 1, unitPrec[Unit], Drilling[i], unitName[Unit]); + } + } +} + + +void OutDriLegend() { + output(ScrName) { + printf("OPEN %s;\n",LbrPath); + int ttime = time(); + string ftime; + sprintf(ftime,"%d",ttime); + string tfile = strsub(ftime, 2, 9); + + if(rename == 1) { + printf("Rename drilegend.pac dl%s.pac\n",tfile); + } + printf("Edit drilegend.pac\n"); + if (Legend_layer) printf("%s", Legend_layer); // is legend-layer defined? 2005-09-14 alf@cadsoft.de + printf("Display none;\n"); + printf("Display %d;\n", SymbolLayer); + printf("Set Wire_Bend 2;\n"); + printf("Grid mil 25 1 mil;\n"); + + for(j = 0; j < laycnt; j++) { + printf("Layer %s;\n",LayerName[j]); + } + printf("Change layer %d;\n", SymbolLayer); + printf("Change Size %.4f;\n", TextSize); + printf("Change Ratio %d;\n", TextRatio); + printf("Change Font %s;\n", TextFont[IdxFnt]); + printf("MARK;\n"); // *** clear MARK 2005-09-14 alf@cadsoft.de *** + + if(VerticalChart == 1) { + defPos(); + DrillChartVertical(0); + } + if(VerticalChart == 0) { + defHigh(); + DrillChartHorizontal(0); + } + + printf("WRITE %s;\n",LbrPath); + printf("CLOSE;\n"); +// printf("EDIT '%s';\n", BoardName); // use always ' ' for 'path/name' 2005-09-14 alf@cadsoft.de + printf("EDIT .brd;\n"); // 2010-12-21 alf@cadsoft.de + + if (Legend_layer) printf("%s", Legend_layer); // is legend-layer defined? 2005-09-14 alf@cadsoft.de + printf("DISPLAY 23 44 45 %d;\n",SymbolLayer); + printf("GRID MIL 25 1 ;\n"); + printf("SET WIRE_BEND 2;\n"); + printf("USE %s\n",LbrPath); + + if (replace == 0) { + printf("ADD 'DRILEGEND' DRILEGEND R0 (%.3f %.3f);\n", u2mil(Bx)-LoffsetX, u2mil(By)-LoffsetY ); + printf("%s", str_symbols); + } + if (replace == 1) { + printf("UPDATE %s;\n",LbrPath); + } + printf("DISPLAY -23 -44 -45;\n"); // 2008-07-30 + printf("WIN FIT;\n"); + printf("GRID LAST;\n"); + } +} + + +void infoHelp( string info, string help, int b, int h) { + int Result = dlgDialog(info) { + dlgHBoxLayout dlgSpacing(b); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(h); + dlgTextView(help); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+Ok") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + + +/********************DIALOG***************************/ +void menu(void) { + int Result = dlgDialog("DRILL LEGEND") { + dlgHBoxLayout { + dlgTabWidget { + dlgTabPage("&Legend") { + dlgSpacing(20); + dlgGridLayout { + dlgCell(0, 0) dlgSpacing(20); + dlgCell(0, 1, 0, 5) dlgGroup("Drill Legend Settings") { + dlgGridLayout { + + dlgCell(0, 0) dlgLabel("Field"); + dlgCell(0, 1) dlgStretch(0); + dlgCell(0, 2) dlgLabel("Title"); + dlgCell(0, 3) dlgStretch(0); + dlgCell(0, 4) dlgLabel("Rank"); + + + dlgCell(1, 0) dlgLabel(LField[0]); + dlgCell(1, 2) dlgStringEdit(LTitle[0]); + int SymbSel = LRank[0]; + dlgCell(1, 4) dlgComboBox(Rank, SymbSel) LRank[0] = strtol(Rank[SymbSel]); + + dlgCell(2, 0) dlgLabel(LField[1]); + dlgCell(2, 2) dlgStringEdit(LTitle[1]); + int ToolSel = LRank[1]; + dlgCell(2, 4) dlgComboBox(Rank, ToolSel) LRank[1] = strtol(Rank[ToolSel]); + + dlgCell(3, 0) dlgLabel(LField[2]); + dlgCell(3, 2) dlgStringEdit(LTitle[2]); + int MMSel = LRank[2]; + dlgCell(3, 4) dlgComboBox(Rank, MMSel) LRank[2] = strtol(Rank[MMSel]); + + dlgCell(4, 0) dlgLabel(LField[3]); + dlgCell(4, 2) dlgStringEdit(LTitle[3]); + int MilSel = LRank[3]; + dlgCell(4, 4) dlgComboBox(Rank, MilSel) LRank[3] = strtol(Rank[MilSel]); + + dlgCell(5, 0) dlgLabel(LField[4]); + dlgCell(5, 2) dlgStringEdit(LTitle[4]); + int MicSel = LRank[4]; + dlgCell(5, 4) dlgComboBox(Rank, MicSel) LRank[4] = strtol(Rank[MicSel]); + + dlgCell(6, 0) dlgLabel(LField[5]); + dlgCell(6, 2) dlgStringEdit(LTitle[5]); + int QtySel = LRank[5]; + dlgCell(6, 4) dlgComboBox(Rank, QtySel) LRank[5] = strtol(Rank[QtySel]); + + dlgCell(7, 0) dlgLabel(LField[6]); + dlgCell(7, 2) dlgStringEdit(LTitle[6]); + int TypeSel = LRank[6]; + dlgCell(7, 4) dlgComboBox(Rank, TypeSel) LRank[6] = strtol(Rank[TypeSel]); + + dlgCell(8, 0) dlgLabel(LField[7]); + dlgCell(8, 2) dlgStringEdit(LTitle[7]); + int ToleSel = LRank[7]; + dlgCell(8, 4) dlgComboBox(Rank, ToleSel) LRank[7] = strtol(Rank[ToleSel]); + + } + } + dlgCell(0, 6) dlgSpacing(20); + dlgCell(1, 0) dlgLabel(""); + dlgCell(2, 1, 2, 3) dlgGroup("Drill Legend Orientation") { + dlgGridLayout { + dlgCell(0, 0) dlgRadioButton("Hori&zontal", VerticalChart); + dlgCell(0, 1) dlgLabel(" "); + dlgCell(0, 2) dlgRadioButton("&Vertical", VerticalChart); + } + } + dlgCell(2, 5) dlgPushButton("Help") infoHelp("Drill Legend Help", HelpLegend, 400, 400); + } + dlgSpacing(20); + } + + dlgTabPage("&Holes") { + string dec[] = {"0","1","2","3"}; + dlgSpacing(20); + dlgGridLayout { + dlgCell(0, 0) dlgSpacing(20); + dlgCell(0, 1) dlgGroup("Non-Plated") { + dlgRadioButton("Alte&rnate ", SortHoles); + dlgRadioButton("Mix&ed", SortHoles); + dlgRadioButton("La&st", SortHoles); + } + dlgCell(0, 2) dlgSpacing(10); + + dlgCell(0, 3, 0, 6) dlgGroup("Plated Status") { + dlgGridLayout { + dlgCell(0, 0) dlgLabel("&Not Plated "); + dlgCell(0, 1) dlgStringEdit(PlatedStatus[0]); + dlgCell(1, 0) dlgLabel("Mixe&d"); + dlgCell(1, 1) dlgStringEdit(PlatedStatus[1]); + dlgCell(2, 0) dlgLabel("&Plated"); + dlgCell(2, 1) dlgStringEdit(PlatedStatus[2]); + } + } + dlgCell(0, 7) dlgSpacing(20); + dlgCell(1, 1) dlgLabel(""); + + dlgCell(2, 1) dlgGroup("Unit Precision") { + dlgGridLayout { + dlgCell(0, 0) dlgLabel("M&ils "); + dlgCell(0, 1) dlgComboBox(dec, decMIL); + dlgCell(1, 0) dlgLabel("&MM"); + dlgCell(1, 1) dlgComboBox(dec, decMM); + } + } + + dlgCell(2, 3, 2, 6) dlgGroup("Holes Tolerance") { + dlgGridLayout { + dlgCell(0, 0) dlgLabel("Pl&ated "); + dlgCell(0, 1) dlgStringEdit(TolPlated); + dlgCell(1, 0) dlgLabel("Non-Pla&ted "); + dlgCell(1, 1) dlgStringEdit(TolNonPlated); + } + } + dlgCell(3, 1) dlgStretch(0); + + dlgCell(4, 6) dlgPushButton("Help") infoHelp("Drill Legend Help", HelpHoles, 800, 600); + } + dlgSpacing(20); + } + + + dlgTabPage("S&ymbols") { + dlgSpacing(20); + dlgGridLayout { + dlgCell(0, 0) dlgSpacing(20); + dlgCell(0, 1, 0, 4) dlgGroup("Symbol Settings") { + dlgLabel(""); + dlgGridLayout { + dlgCell(0, 0) dlgLabel("L&ayer "); + dlgCell(0, 1, 0, 2) dlgComboBox(LayerName, LayerSel) SymbolLayer = LayerNbr[LayerSel]; + + dlgCell(0, 3) dlgStretch(0); + dlgCell(1, 0) dlgLabel(""); + dlgCell(2, 0) dlgLabel("&Size "); + dlgCell(2, 1) dlgSpinBox(SymbolSize, 1, 500); + dlgCell(2, 2) dlgLabel(" mils"); + dlgCell(2, 3) dlgStretch(0); + dlgCell(3, 0) dlgLabel(""); + dlgCell(4, 0) dlgLabel("&Width "); + dlgCell(4, 1) dlgSpinBox(SymbolWidth, 0, 20); + dlgCell(4, 2) dlgLabel(" mils"); + dlgCell(4, 3) dlgSpacing(100); + } + dlgLabel(""); + } + dlgCell(0, 5) dlgSpacing(20); + dlgCell(1, 1) dlgStretch(0); + dlgCell(2, 4) dlgPushButton("Help") infoHelp("Drill Legend Help", HelpSymbols, 720, 400); + } + dlgSpacing(20); + } + + dlgTabPage("Te&xts") { + dlgSpacing(20); + dlgGridLayout { + dlgCell(0, 0) dlgSpacing(20); + dlgCell(0, 1, 0, 4) dlgGroup("Texts Settings") { + dlgLabel(""); + dlgGridLayout { + int TfontSel = IdxFnt; + dlgCell(0, 0) dlgLabel("&Font "); + dlgCell(0, 1, 0, 3) dlgComboBox(TextFont, TfontSel) IdxFnt = TfontSel; + dlgCell(0, 4) dlgLabel("\t\t "); + dlgCell(1, 0) dlgLabel(""); + dlgCell(2, 0) dlgLabel("&Size "); + dlgCell(2, 1) dlgRealEdit(TextSize, 1.0, 500.0); + dlgCell(2, 2) dlgLabel(" mils\t "); + dlgCell(3, 0) dlgLabel(""); + dlgCell(4, 0) dlgLabel("&Ratio "); + dlgCell(4, 1) dlgSpinBox(TextRatio, 0, 20); + dlgCell(4, 2) dlgLabel(" %"); + } + dlgLabel(""); + } + dlgCell(0, 5) dlgSpacing(20); + dlgCell(1, 1) dlgStretch(0); + dlgCell(2, 4) dlgPushButton("Help") infoHelp("Drill Legend Help", HelpTexts, 500, 300); + } + dlgSpacing(20); + } + + dlgTabPage("Ta&ble") { + dlgSpacing(20); + dlgGridLayout { + dlgCell(0, 0) dlgSpacing(20); + dlgCell(0, 1, 0, 4) dlgGroup("Cell Margin Factor") { + dlgGridLayout { + dlgCell(0, 0) dlgLabel("Hori&zontal "); + dlgCell(0, 1) dlgRealEdit(WideCellFactor, 1.0, 5.0); + dlgCell(0, 2) dlgLabel("\t\t "); + dlgCell(0, 3) dlgStretch(0); + dlgCell(2, 0) dlgLabel("&Vertical "); + dlgCell(2, 1) dlgRealEdit(HighCellFactor, 1.0, 5.0); + } + } + dlgCell(0, 5) dlgSpacing(20); + dlgCell(1, 1) dlgLabel(" "); + dlgCell(2, 1, 2, 4) dlgGroup("Outline Width") { + dlgGridLayout { + dlgCell(0, 0) dlgLabel("&Cell "); + dlgCell(0, 1) dlgSpinBox(CellOutline, 1, 50); + dlgCell(0, 2) dlgLabel(" mils\t\t"); + dlgCell(0, 3) dlgStretch(0); + dlgCell(1, 0) dlgLabel("T&itle "); + dlgCell(1, 1) dlgSpinBox(TitleOutline, 1, 50); + dlgCell(1, 2) dlgLabel(" mils"); + dlgCell(2, 0) dlgLabel("T&able "); + dlgCell(2, 1) dlgSpinBox(TableOutline, 1, 50); + dlgCell(2, 2) dlgLabel(" mils"); + } + } + + dlgCell(3, 1) dlgStretch(0); + dlgCell(4, 4) dlgPushButton("Help") infoHelp("Drill Legend Help", HelpTable, 600, 450); + } + dlgSpacing(20); + } + + + dlgTabPage("&Files") { + dlgSpacing(20); + dlgGridLayout { + dlgCell(0, 0) dlgSpacing(20); + dlgCell(0, 1, 0, 4) dlgGroup("Drill Rack File for CAM Processor") { + dlgGridLayout { + dlgCell(0, 0) dlgCheckBox("&Generating ", OutputDrillRack); + dlgCell(0, 1) dlgLabel("&Rack file "); + dlgCell(0, 2) dlgStringEdit(DrillRackFile); + int unit = Unit; + dlgCell(1, 0) dlgRadioButton("Unit &MM", unit) Unit = unitMM; + dlgCell(2, 0) dlgRadioButton("Unit &Inch", unit) Unit = unitINCH; + } + } + dlgCell(0, 5) dlgSpacing(20); + + + + dlgCell(2, 1, 2, 4) dlgGroup("Drill Legend User Settings") { + dlgGridLayout { + dlgCell(0, 0) dlgCheckBox("&Save File ", OutputUserCfg); + dlgCell(1, 0) dlgCheckBox("Lo&ad File ", InputUserCfg); + dlgCell(0, 1) dlgSpacing(30); + dlgCell(0, 2) dlgLabel(UserCfgFile); + } + } + dlgCell(2, 5) dlgSpacing(20); + dlgCell(3, 1) dlgStretch(0); + dlgCell(4, 4) dlgPushButton("Help") infoHelp("Drill Legend Help", HelpOutputs, 400, 200); + } + dlgSpacing(20); + } + } + dlgSpacing(8); + dlgVBoxLayout { + dlgLabel(usage); + dlgStretch(1); + } + } + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") { + dlgAccept(); + if(OutputUserCfg == 1) { OutputUserCfgFile(); } + if(OutputDrillRack == 1) {OutDrillRack(); } + TitleList(); + SortHolesMode(SortHoles); + OutDriLegend(); + exit("; SCR '" + ScrName + "';\n"); + } + + dlgStretch(0); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgLabel("Version "+Version); + } + }; +} + + + + +/*** ************* Main ************* ***/ +board(B) { + Drl_cnt = 0; + B.holes(H) { + DrilSymbol[Drl_cnt] = DrillsCapture(H.drill, 0); + DrillDiam[Drl_cnt] = H.drill; + Drl_x[Drl_cnt] = H.x; Drl_y[Drl_cnt] = H.y; + Drl_stack[Drl_cnt] = "01-20"; + Drl_cnt++; + } + B.signals(S) { + S.vias(V) { + DrilSymbol[Drl_cnt] = DrillsCapture(V.drill, 1); + DrillDiam[Drl_cnt] = V.drill; + Drl_x[Drl_cnt] = V.x; Drl_y[Drl_cnt] = V.y; + sprintf(Drl_stack[Drl_cnt], "%02d-%02d", V.start, V.end); + Drl_cnt++; + } + } + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + DrilSymbol[Drl_cnt] = DrillsCapture(C.pad.drill, 1); + DrillDiam[Drl_cnt] = C.pad.drill; + Drl_x[Drl_cnt] = C.pad.x; Drl_y[Drl_cnt] = C.pad.y; + Drl_stack[Drl_cnt] = "01-16"; + Drl_cnt++; + } + } + E.package.holes(H) { + DrilSymbol[Drl_cnt] = DrillsCapture(H.drill, 0); + DrillDiam[Drl_cnt] = H.drill; + Drl_x[Drl_cnt] = H.x; Drl_y[Drl_cnt] = H.y; + Drl_stack[Drl_cnt] = "01-20"; + Drl_cnt++; + } + } +} + +sort(Dcnt, index, Drills); // sortiere die Drill-Liste (Anzahl unterschiedliche Bohrungen/Rack) + +int Dindex[]; // 2010-12-22 alf +sort(Drl_cnt, Dindex, Drl_stack, DrillDiam); // sortiere die Drilldiameter nach Stacktiefe und Diameter +string s; +string stack = ""; +str_symbols = Legend_layer; +real TextLength = TextSize * 5.0; + +sprintf(s, "TEXT 'LAYER-STACK' (%.4f %.4f);\n", // Layerbeschriftung/Kopfzeile 2010-12-22 + u2mil(Bx)-LoffsetX-TextLength*2.1, + u2mil(By)-LoffsetY-(Idrl_stack * TextSize * TextOffset * HighCellFactor) + ); +str_symbols += s; + +for (int n = 0; n < Drl_cnt; n++) { + if (stack != Drl_stack[Dindex[n]]) { + stack = Drl_stack[Dindex[n]]; + Idrl_stack++; + sprintf(s, "LAYER %d %s_%s;\n", SymbolLayer+Idrl_stack, SymbolLayerName, stack); // neuer Layer zum zeichnen der Symbole je Stack 2010-12-22 + str_symbols += s; + sprintf(s, "SET FILL_LAYER %d %d;\n", SymbolLayer+Idrl_stack, 9); + str_symbols += s; + sprintf(s, "SET COLOR_LAYER %d %d;\n", SymbolLayer+Idrl_stack, Idrl_stack+1); + str_symbols += s; + if (Idrl_stack+1 > 16) { + string h; + sprintf(h, "Define color %d - Options - Set - Color - Palette ..", Idrl_stack+1); + dlgMessageBox(h, "OK"); + } + sprintf(s, "CHANGE SIZE %.4f;\n", TextSize); // Layerbeschriftung Textgroesse + str_symbols += s; + sprintf(s, "TEXT '%s' (%.4f %.4f);\n", // Layerbeschriftung/Stacktiefe + stack, + u2mil(Bx)-LoffsetX-TextLength, + u2mil(By)-LoffsetY-(Idrl_stack * TextSize * TextOffset * HighCellFactor) + ); + str_symbols += s; + } + sprintf(s, "MARK (%.4f %.4f);\n", u2mil(Drl_x[Dindex[n]]), u2mil(Drl_y[Dindex[n]]) ); + str_symbols += s; + str_symbols += DrawSymbol(getDrill(DrillDiam[Dindex[n]]), 0, 0, 0); // 2008-07-30 alf +} + +/*******OUTPUT DRILL LEGEND FILE****************/ + +for(j = 0; j < laycnt; j++) { + if(LayerNbr[j] == SymbolLayer) LayerSel = j; +} + +menu(); diff --git a/trunk/ulp/dxf.ulp b/trunk/ulp/dxf.ulp new file mode 100644 index 00000000..70ee89a7 --- /dev/null +++ b/trunk/ulp/dxf.ulp @@ -0,0 +1,1569 @@ +#require 6.0300 + +#usage "en: Export DXF data\n" + "

    " + "Converts a board or schematic into a DXF file." + "

    " + "Usage: RUN dxf [ -s suffix ] [ -u mm|inch ] [ -a ] [ -w ] [ -f ]" + "

    " + "Options:
    " + "" + "" + "" + "" + "" + "" + "
    -s suffixdefine a suffix that will be appended to the file name
    -u mm|inch select the unit for coordinates and dimensions
    -a set the 'Always vector font' option
    -w set the 'Use wire width' option
    -f set the 'Fill areas' option
    " + "Example:" + "

    " + "RUN dxf -s _s1 -u mm -w" + "

    " + "This will create a DXF file named filename_s1.dxf, with units in millimeters and " + "wires drawn with their real widths." + "

    " + "DXF syntax generated according to the specifications given in the book
    " + "
    " + "Der DXF-Standard
    " + "By Dietmar Rudolph
    " + "Publisher: Dr. L. Rossipaul Verlagsgesellschaft m.b.H.
    " + "München, 1993
    " + "ISBN 3-87686-246-9" + "
    " + "Author: support@cadsoft.de", + "de: DXF Daten exportieren\n" + "

    " + "Konvertiert ein Board oder einen Schaltplan in eine DXF-Datei." + "

    " + "Aufruf: RUN dxf [ -s suffix ] [ -u mm|inch ] [ -a ] [ -w ] [ -f ]" + "

    " + "Optionen:
    " + "" + "" + "" + "" + "" + "" + "
    -s suffixdefiniert einen Suffix, der an den Dateinamen angehängt wird
    -u mm|inch bestimmt die Einheit für Koordinaten und Abmessungen
    -a schaltet die Option 'Immer Vektor-Font' ein
    -w schaltet die Option 'Linienbreite benutzen' ein
    -f schaltet die Option 'Flächen füllen' ein
    " + "Beispiel:" + "

    " + "RUN dxf -s _s1 -u mm -w" + "

    " + "Erzeugt eine DXF-Datei namens dateiname_s1.dxf, mit der Einheit Millimeter und " + "Linien die in ihrer wirklichen Breite dargestellt werden." + "

    " + "Die generierte DXF-Syntax folgt der Spezification im Buch
    " + "
    " + "Der DXF-Standard
    " + "Von Dietmar Rudolph
    " + "Herausgeber: Dr. L. Rossipaul Verlagsgesellschaft m.b.H.
    " + "München, 1993
    " + "ISBN 3-87686-246-9" + "
    " + "Autor: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string I18N[] = { + "en\v" + "de\v" + , + "Can't fill polygon with Width = 0\v" + "Polygon mit Width = 0 kann nicht gefüllt werden\v" + , + "+OK\v" + "+OK\v" + , + "-Cancel\v" + "-Abbrechen\v" + , + "


    ERROR: unknown unit: \v" + "
    FEHLER: unbekannte Einheit: \v" + , + "
    ERROR: missing unit\v" + "
    FEHLER: fehlende Einheit\v" + , + "
    ERROR: unknown option: \v" + "
    FEHLER: unbekannte Option: \v" + , + "
    ERROR: No board or schematic!

    \nThis program can only work in the board or schematic editor.\v" + "


    FEHLER: Kein Board oder Schaltplan!

    \nDieses Programm kann nur im Board- oder Schaltplan-Editor verwendet werden.\v" + , + "DXF Converter\v" + "DXF-Konverter\v" + , + "&Output file\v" + "&Ausgabedatei\v" + , + "&Browse\v" + "&Durchsuchen\v" + , + "Save DXF file\v" + "DXF-Datei speichern\v" + , + "DXF files (*.dxf)\v" + "DXF-Dateien (*.dxf)\v" + , + "&Always vector font\v" + "Immer &Vektor-Font\v" + , + "If checked, texts will always be drawn with the builtin vector font.\v" + "Falls ausgewählt, werden Texte immer mit dem eingebauten Vektor-Font dargestellt.\v" + , + "&Use wire widths\v" + "&Linienbreite verwenden\v" + , + "If checked, wires, arcs and circles will be generated as polygons showing their real widths. This, however, can cause the DXF file to become very large! Uncheck this if you do not need the real widths.\v" + "Falls ausgewählt, werden Linien, Kreisbögen und Kreise als Polygone mit ihrer tatsächlichen Breite dargestellt. Dies kann jedoch dazu führen, daß die DXF-Datei sehr groß wird! Deselektieren Sie diese Option wenn Sie die wahren Breiten nicht benötigen.\v" + , + "&Fill areas\v" + "&Flächen füllen\v" + , + "If checked, wires, arcs etc. will be filled (implies 'Use wire widths'!).\v" + "Falls ausgewählt, werden Linien, Kreisbögen usw. gefüllt (impliziert 'Linienbreite verwenden'!).\v" + , + "Thermal Emulation\v" + "Thermal Emulation\v" + , + "Relative inner diameter\v" + "Relativer Innendurchmesser\v" + , + "Relative gap size\v" + "Relative Spaltgröße\v" + , + "Only the outer diameter of Thermals is available. The inner diameter and gap size are calculated based on the outer diameters according to these factors.\v" + "Für Thermals steht nur der Außendurchmesser zur Verfügung. Der Innendurchmesser und die Spaltgröße werden mittels dieser Faktoren aus dem Außendurchmesser errechnet.\v" + , + "Unit\v" + "Einheit\v" + , + "Defines the unit used for coordinates and values in the DXF file\v" + "Legt die Einheit fest mit der Koordinaten und Werte in der DXF-Datei angegeben werden\v" + , + "File exists: \v" + "Datei existiert: \v" + , + "\n\nOverwrite?\v" + "\n\nÜberschreiben?\v" + , + "+&Yes\v" + "+&Ja\v" + , + "-&No\v" + "-&Nein\v" + , + "About\v" + "Info\v" + , + "Multiline texts can be exported only in vector font:\n\n\v" + "Mehrzeilige Texte können nur mit Vektor-Font ausgegeben werden:\n\n\v" + }; + +int Language = strstr(I18N[0], language()) / 3; + +string tr(string s) +{ + string t = lookup(I18N, s, Language, '\v'); + return t ? t : s; +} + +// +// The following switches allow us to customize the generated DXF file: +// + +enum { NO, YES }; + +int AlwaysVectorFont= YES; // YES always draws texts in vector font, no + // matter what the actual font settings are +int UseWireWidths = YES; // YES will generate wires, arcs and circles + // as polygons showing their real widths. + // This, however, can cause the DXF file to + // become very large! + // Set this to NO if you do not need the real + // widths. +int FillAreas = YES; // YES will fill wires, arcs etc. You must also + // set UseWireWidths to YES for this to work + +real AnnulusRelInnerDiameter = 0.8; +real AnnulusRelGap = 0.2; +int VisibleSupplyLayer = NO; +int IsSupplyLayer[]; + +enum { MM, INCH }; + +int Unit = MM; + +int SafetyOverlap = 1.0 / u2mil(1); // 1.0 mil overlap + +int PadColor = 0, ViaColor = 0; + +// +// Some tools we need later: +// + +real DxfUnit(int n) +{ + return (Unit == MM) ? u2mm(n) : u2inch(n); +} + +real DxfAngle(real a) +{ + return a >= 360 ? a - 360 : a; // 0 <= DXF-Angle < 360 +} + +int LayerActive[] = {1}; + +int DxfColors[] = { // AutoCAD Color Index (ACI) + 0x00000000, // 0 0.00000 0.00000 0.00000 + 0x00FF0000, // 1 1.00000 0.00000 0.00000 + 0x00FFFF00, // 2 1.00000 1.00000 0.00000 + 0x0000FF00, // 3 0.00000 1.00000 0.00000 + 0x0000FFFF, // 4 0.00000 1.00000 1.00000 + 0x000000FF, // 5 0.00000 0.00000 1.00000 + 0x00FF00FF, // 6 1.00000 0.00000 1.00000 + 0x00FFFFFF, // 7 1.00000 1.00000 1.00000 + 0x00FFFFFF, // 8 1.00000 1.00000 1.00000 + 0x00FFFFFF, // 9 1.00000 1.00000 1.00000 + 0x00FF0000, // 10 1.00000 0.00000 0.00000 + 0x00FF7F7F, // 11 1.00000 0.50000 0.50000 + 0x00A50000, // 12 0.65000 0.00000 0.00000 + 0x00A55252, // 13 0.65000 0.32500 0.32500 + 0x007F0000, // 14 0.50000 0.00000 0.00000 + 0x007F3F3F, // 15 0.50000 0.25000 0.25000 + 0x004C0000, // 16 0.30000 0.00000 0.00000 + 0x004C2626, // 17 0.30000 0.15000 0.15000 + 0x00260000, // 18 0.15000 0.00000 0.00000 + 0x00261313, // 19 0.15000 0.07500 0.07500 + 0x00FF3F00, // 20 1.00000 0.25000 0.00000 + 0x00FF9F7F, // 21 1.00000 0.62500 0.50000 + 0x00A52900, // 22 0.65000 0.16250 0.00000 + 0x00A56752, // 23 0.65000 0.40625 0.32500 + 0x007F1F00, // 24 0.50000 0.12500 0.00000 + 0x007F4F3F, // 25 0.50000 0.31250 0.25000 + 0x004C1300, // 26 0.30000 0.07500 0.00000 + 0x004C2F26, // 27 0.30000 0.18750 0.15000 + 0x00260900, // 28 0.15000 0.03750 0.00000 + 0x00261713, // 29 0.15000 0.09375 0.07500 + 0x00FF7F00, // 30 1.00000 0.50000 0.00000 + 0x00FFBF7F, // 31 1.00000 0.75000 0.50000 + 0x00A55200, // 32 0.65000 0.32500 0.00000 + 0x00A57C52, // 33 0.65000 0.48750 0.32500 + 0x007F3F00, // 34 0.50000 0.25000 0.00000 + 0x007F5F3F, // 35 0.50000 0.37500 0.25000 + 0x004C2600, // 36 0.30000 0.15000 0.00000 + 0x004C3926, // 37 0.30000 0.22500 0.15000 + 0x00261300, // 38 0.15000 0.07500 0.00000 + 0x00261C13, // 39 0.15000 0.11250 0.07500 + 0x00FFBF00, // 40 1.00000 0.75000 0.00000 + 0x00FFDF7F, // 41 1.00000 0.87500 0.50000 + 0x00A57C00, // 42 0.65000 0.48750 0.00000 + 0x00A59152, // 43 0.65000 0.56875 0.32500 + 0x007F5F00, // 44 0.50000 0.37500 0.00000 + 0x007F6F3F, // 45 0.50000 0.43750 0.25000 + 0x004C3900, // 46 0.30000 0.22500 0.00000 + 0x004C4226, // 47 0.30000 0.26250 0.15000 + 0x00261C00, // 48 0.15000 0.11250 0.00000 + 0x00262113, // 49 0.15000 0.13125 0.07500 + 0x00FFFF00, // 50 1.00000 1.00000 0.00000 + 0x00FFFF7F, // 51 1.00000 1.00000 0.50000 + 0x00A5A500, // 52 0.65000 0.65000 0.00000 + 0x00A5A552, // 53 0.65000 0.65000 0.32500 + 0x007F7F00, // 54 0.50000 0.50000 0.00000 + 0x007F7F3F, // 55 0.50000 0.50000 0.25000 + 0x004C4C00, // 56 0.30000 0.30000 0.00000 + 0x004C4C26, // 57 0.30000 0.30000 0.15000 + 0x00262600, // 58 0.15000 0.15000 0.00000 + 0x00262613, // 59 0.15000 0.15000 0.07500 + 0x00BFFF00, // 60 0.75000 1.00000 0.00000 + 0x00DFFF7F, // 61 0.87500 1.00000 0.50000 + 0x007CA500, // 62 0.48750 0.65000 0.00000 + 0x0091A552, // 63 0.56875 0.65000 0.32500 + 0x005F7F00, // 64 0.37500 0.50000 0.00000 + 0x006F7F3F, // 65 0.43750 0.50000 0.25000 + 0x00394C00, // 66 0.22500 0.30000 0.00000 + 0x00424C26, // 67 0.26250 0.30000 0.15000 + 0x001C2600, // 68 0.11250 0.15000 0.00000 + 0x00212613, // 69 0.13125 0.15000 0.07500 + 0x007FFF00, // 70 0.50000 1.00000 0.00000 + 0x00BFFF7F, // 71 0.75000 1.00000 0.50000 + 0x0052A500, // 72 0.32500 0.65000 0.00000 + 0x007CA552, // 73 0.48750 0.65000 0.32500 + 0x003F7F00, // 74 0.25000 0.50000 0.00000 + 0x005F7F3F, // 75 0.37500 0.50000 0.25000 + 0x00264C00, // 76 0.15000 0.30000 0.00000 + 0x00394C26, // 77 0.22500 0.30000 0.15000 + 0x00132600, // 78 0.07500 0.15000 0.00000 + 0x001C2613, // 79 0.11250 0.15000 0.07500 + 0x003FFF00, // 80 0.25000 1.00000 0.00000 + 0x009FFF7F, // 81 0.62500 1.00000 0.50000 + 0x0029A500, // 82 0.16250 0.65000 0.00000 + 0x0067A552, // 83 0.40625 0.65000 0.32500 + 0x001F7F00, // 84 0.12500 0.50000 0.00000 + 0x004F7F3F, // 85 0.31250 0.50000 0.25000 + 0x00134C00, // 86 0.07500 0.30000 0.00000 + 0x002F4C26, // 87 0.18750 0.30000 0.15000 + 0x00092600, // 88 0.03750 0.15000 0.00000 + 0x00172613, // 89 0.09375 0.15000 0.07500 + 0x0000FF00, // 90 0.00000 1.00000 0.00000 + 0x007FFF7F, // 91 0.50000 1.00000 0.50000 + 0x0000A500, // 92 0.00000 0.65000 0.00000 + 0x0052A552, // 93 0.32500 0.65000 0.32500 + 0x00007F00, // 94 0.00000 0.50000 0.00000 + 0x003F7F3F, // 95 0.25000 0.50000 0.25000 + 0x00004C00, // 96 0.00000 0.30000 0.00000 + 0x00264C26, // 97 0.15000 0.30000 0.15000 + 0x00002600, // 98 0.00000 0.15000 0.00000 + 0x00132613, // 99 0.07500 0.15000 0.07500 + 0x0000FF3F, // 100 0.00000 1.00000 0.25000 + 0x007FFF9F, // 101 0.50000 1.00000 0.62500 + 0x0000A529, // 102 0.00000 0.65000 0.16250 + 0x0052A567, // 103 0.32500 0.65000 0.40625 + 0x00007F1F, // 104 0.00000 0.50000 0.12500 + 0x003F7F4F, // 105 0.25000 0.50000 0.31250 + 0x00004C13, // 106 0.00000 0.30000 0.07500 + 0x00264C2F, // 107 0.15000 0.30000 0.18750 + 0x00002609, // 108 0.00000 0.15000 0.03750 + 0x00132617, // 109 0.07500 0.15000 0.09375 + 0x0000FF7F, // 110 0.00000 1.00000 0.50000 + 0x007FFFBF, // 111 0.50000 1.00000 0.75000 + 0x0000A552, // 112 0.00000 0.65000 0.32500 + 0x0052A57C, // 113 0.32500 0.65000 0.48750 + 0x00007F3F, // 114 0.00000 0.50000 0.25000 + 0x003F7F5F, // 115 0.25000 0.50000 0.37500 + 0x00004C26, // 116 0.00000 0.30000 0.15000 + 0x00264C39, // 117 0.15000 0.30000 0.22500 + 0x00002613, // 118 0.00000 0.15000 0.07500 + 0x0013261C, // 119 0.07500 0.15000 0.11250 + 0x0000FFBF, // 120 0.00000 1.00000 0.75000 + 0x007FFFDF, // 121 0.50000 1.00000 0.87500 + 0x0000A57C, // 122 0.00000 0.65000 0.48750 + 0x0052A591, // 123 0.32500 0.65000 0.56875 + 0x00007F5F, // 124 0.00000 0.50000 0.37500 + 0x003F7F6F, // 125 0.25000 0.50000 0.43750 + 0x00004C39, // 126 0.00000 0.30000 0.22500 + 0x00264C42, // 127 0.15000 0.30000 0.26250 + 0x0000261C, // 128 0.00000 0.15000 0.11250 + 0x00132621, // 129 0.07500 0.15000 0.13125 + 0x0000FFFF, // 130 0.00000 1.00000 1.00000 + 0x007FFFFF, // 131 0.50000 1.00000 1.00000 + 0x0000A5A5, // 132 0.00000 0.65000 0.65000 + 0x0052A5A5, // 133 0.32500 0.65000 0.65000 + 0x00007F7F, // 134 0.00000 0.50000 0.50000 + 0x003F7F7F, // 135 0.25000 0.50000 0.50000 + 0x00004C4C, // 136 0.00000 0.30000 0.30000 + 0x00264C4C, // 137 0.15000 0.30000 0.30000 + 0x00002626, // 138 0.00000 0.15000 0.15000 + 0x00132626, // 139 0.07500 0.15000 0.15000 + 0x0000BFFF, // 140 0.00000 0.75000 1.00000 + 0x007FDFFF, // 141 0.50000 0.87500 1.00000 + 0x00007CA5, // 142 0.00000 0.48750 0.65000 + 0x005291A5, // 143 0.32500 0.56875 0.65000 + 0x00005F7F, // 144 0.00000 0.37500 0.50000 + 0x003F6F7F, // 145 0.25000 0.43750 0.50000 + 0x0000394C, // 146 0.00000 0.22500 0.30000 + 0x0026424C, // 147 0.15000 0.26250 0.30000 + 0x00001C26, // 148 0.00000 0.11250 0.15000 + 0x00132126, // 149 0.07500 0.13125 0.15000 + 0x00007FFF, // 150 0.00000 0.50000 1.00000 + 0x007FBFFF, // 151 0.50000 0.75000 1.00000 + 0x000052A5, // 152 0.00000 0.32500 0.65000 + 0x00527CA5, // 153 0.32500 0.48750 0.65000 + 0x00003F7F, // 154 0.00000 0.25000 0.50000 + 0x003F5F7F, // 155 0.25000 0.37500 0.50000 + 0x0000264C, // 156 0.00000 0.15000 0.30000 + 0x0026394C, // 157 0.15000 0.22500 0.30000 + 0x00001326, // 158 0.00000 0.07500 0.15000 + 0x00131C26, // 159 0.07500 0.11250 0.15000 + 0x00003FFF, // 160 0.00000 0.25000 1.00000 + 0x007F9FFF, // 161 0.50000 0.62500 1.00000 + 0x000029A5, // 162 0.00000 0.16250 0.65000 + 0x005267A5, // 163 0.32500 0.40625 0.65000 + 0x00001F7F, // 164 0.00000 0.12500 0.50000 + 0x003F4F7F, // 165 0.25000 0.31250 0.50000 + 0x0000134C, // 166 0.00000 0.07500 0.30000 + 0x00262F4C, // 167 0.15000 0.18750 0.30000 + 0x00000926, // 168 0.00000 0.03750 0.15000 + 0x00131726, // 169 0.07500 0.09375 0.15000 + 0x000000FF, // 170 0.00000 0.00000 1.00000 + 0x007F7FFF, // 171 0.50000 0.50000 1.00000 + 0x000000A5, // 172 0.00000 0.00000 0.65000 + 0x005252A5, // 173 0.32500 0.32500 0.65000 + 0x0000007F, // 174 0.00000 0.00000 0.50000 + 0x003F3F7F, // 175 0.25000 0.25000 0.50000 + 0x0000004C, // 176 0.00000 0.00000 0.30000 + 0x0026264C, // 177 0.15000 0.15000 0.30000 + 0x00000026, // 178 0.00000 0.00000 0.15000 + 0x00131326, // 179 0.07500 0.07500 0.15000 + 0x003F00FF, // 180 0.25000 0.00000 1.00000 + 0x009F7FFF, // 181 0.62500 0.50000 1.00000 + 0x002900A5, // 182 0.16250 0.00000 0.65000 + 0x006752A5, // 183 0.40625 0.32500 0.65000 + 0x001F007F, // 184 0.12500 0.00000 0.50000 + 0x004F3F7F, // 185 0.31250 0.25000 0.50000 + 0x0013004C, // 186 0.07500 0.00000 0.30000 + 0x002F264C, // 187 0.18750 0.15000 0.30000 + 0x00090026, // 188 0.03750 0.00000 0.15000 + 0x00171326, // 189 0.09375 0.07500 0.15000 + 0x007F00FF, // 190 0.50000 0.00000 1.00000 + 0x00BF7FFF, // 191 0.75000 0.50000 1.00000 + 0x005200A5, // 192 0.32500 0.00000 0.65000 + 0x007C52A5, // 193 0.48750 0.32500 0.65000 + 0x003F007F, // 194 0.25000 0.00000 0.50000 + 0x005F3F7F, // 195 0.37500 0.25000 0.50000 + 0x0026004C, // 196 0.15000 0.00000 0.30000 + 0x0039264C, // 197 0.22500 0.15000 0.30000 + 0x00130026, // 198 0.07500 0.00000 0.15000 + 0x001C1326, // 199 0.11250 0.07500 0.15000 + 0x00BF00FF, // 200 0.75000 0.00000 1.00000 + 0x00DF7FFF, // 201 0.87500 0.50000 1.00000 + 0x007C00A5, // 202 0.48750 0.00000 0.65000 + 0x009152A5, // 203 0.56875 0.32500 0.65000 + 0x005F007F, // 204 0.37500 0.00000 0.50000 + 0x006F3F7F, // 205 0.43750 0.25000 0.50000 + 0x0039004C, // 206 0.22500 0.00000 0.30000 + 0x0042264C, // 207 0.26250 0.15000 0.30000 + 0x001C0026, // 208 0.11250 0.00000 0.15000 + 0x00211326, // 209 0.13125 0.07500 0.15000 + 0x00FF00FF, // 210 1.00000 0.00000 1.00000 + 0x00FF7FFF, // 211 1.00000 0.50000 1.00000 + 0x00A500A5, // 212 0.65000 0.00000 0.65000 + 0x00A552A5, // 213 0.65000 0.32500 0.65000 + 0x007F007F, // 214 0.50000 0.00000 0.50000 + 0x007F3F7F, // 215 0.50000 0.25000 0.50000 + 0x004C004C, // 216 0.30000 0.00000 0.30000 + 0x004C264C, // 217 0.30000 0.15000 0.30000 + 0x00260026, // 218 0.15000 0.00000 0.15000 + 0x00261326, // 219 0.15000 0.07500 0.15000 + 0x00FF00BF, // 220 1.00000 0.00000 0.75000 + 0x00FF7FDF, // 221 1.00000 0.50000 0.87500 + 0x00A5007C, // 222 0.65000 0.00000 0.48750 + 0x00A55291, // 223 0.65000 0.32500 0.56875 + 0x007F005F, // 224 0.50000 0.00000 0.37500 + 0x007F3F6F, // 225 0.50000 0.25000 0.43750 + 0x004C0039, // 226 0.30000 0.00000 0.22500 + 0x004C2642, // 227 0.30000 0.15000 0.26250 + 0x0026001C, // 228 0.15000 0.00000 0.11250 + 0x00261321, // 229 0.15000 0.07500 0.13125 + 0x00FF007F, // 230 1.00000 0.00000 0.50000 + 0x00FF7FBF, // 231 1.00000 0.50000 0.75000 + 0x00A50052, // 232 0.65000 0.00000 0.32500 + 0x00A5527C, // 233 0.65000 0.32500 0.48750 + 0x007F003F, // 234 0.50000 0.00000 0.25000 + 0x007F3F5F, // 235 0.50000 0.25000 0.37500 + 0x004C0026, // 236 0.30000 0.00000 0.15000 + 0x004C2639, // 237 0.30000 0.15000 0.22500 + 0x00260013, // 238 0.15000 0.00000 0.07500 + 0x0026131C, // 239 0.15000 0.07500 0.11250 + 0x00FF003F, // 240 1.00000 0.00000 0.25000 + 0x00FF7F9F, // 241 1.00000 0.50000 0.62500 + 0x00A50029, // 242 0.65000 0.00000 0.16250 + 0x00A55267, // 243 0.65000 0.32500 0.40625 + 0x007F001F, // 244 0.50000 0.00000 0.12500 + 0x007F3F4F, // 245 0.50000 0.25000 0.31250 + 0x004C0013, // 246 0.30000 0.00000 0.07500 + 0x004C262F, // 247 0.30000 0.15000 0.18750 + 0x00260009, // 248 0.15000 0.00000 0.03750 + 0x00261317, // 249 0.15000 0.07500 0.09375 + 0x00545454, // 250 0.33000 0.33000 0.33000 + 0x00767676, // 251 0.46400 0.46400 0.46400 + 0x00989898, // 252 0.59800 0.59800 0.59800 + 0x00BABABA, // 253 0.73200 0.73200 0.73200 + 0x00DCDCDC, // 254 0.86600 0.86600 0.86600 + 0x00FFFFFF // 255 1.00000 1.00000 1.00000 + }; + +int DxfColor(int Rgb) +{ + int r = (Rgb & 0x00FF0000) >> 16; + int g = (Rgb & 0x0000FF00) >> 8; + int b = (Rgb & 0x000000FF); + int n = 1; // = 0; if the DXF tool is able to handle color 0 + int Min = INT_MAX; + for (int i = n; i < 256; i++) { + int c = DxfColors[i]; + int dr = r - ((c & 0x00FF0000) >> 16); + int dg = g - ((c & 0x0000FF00) >> 8); + int db = b - (c & 0x000000FF); + int d = dr * dr * 77 + dg * dg * 150 + db * db * 29; + if (d < Min) { + n = i; + Min = d; + } + } + return n; +} + +// +// Level 0: DXF code generating functions: +// + +void DxfString(int code, string value) +{ + printf("%3d\n%s\n", code, value); +} + +void DxfInt(int code, int value) +{ + printf("%3d\n%d\n", code, value); +} + +void DxfReal(int code, real value) +{ + printf("%3d\n%1.*f\n", code, (Unit == MM) ? 4 : 6, value); +} + +// +// Level 1: DXF group functions: +// + +void DxfCoordinate(int n, real x, real y) +{ + DxfReal(10 + n, x); + DxfReal(20 + n, y); + DxfReal(30 + n, 0.0); +} + +void DxfSection(string name) +{ + DxfString(0, "SECTION"); + DxfString(2, name); +} + +void DxfEndSection(void) +{ + DxfString(0, "ENDSEC"); +} + +void DxfTable(string name, int number) +{ + DxfString(0, "TABLE"); + DxfString(2, name); + DxfInt(70, number); +} + +void DxfEndTable(void) +{ + DxfString(0, "ENDTAB"); +} + +void DxfBlock(string name) +{ + DxfString(0, "BLOCK"); + DxfInt(8, 0); + DxfString(2, name); + DxfInt(70, 64); + DxfCoordinate(0, 0.0, 0.0); + DxfString(3, name); +} + +void DxfEndBlock(void) +{ + DxfString(0, "ENDBLK"); + DxfInt(8, 0); +} + +void DxfVariable(string name) +{ + DxfString(9, "$" + name); +} + +void DxfTrailer(void) +{ + DxfString(0, "EOF"); +} + +void DxfPolyline(int layer, real width) +{ + int Mode = width > 0 ? 0 // polyline is NOT closed + : 1; // polyline is closed + if (width < 0) + width = -width; + DxfString(0, "POLYLINE"); + DxfInt(8, layer); + DxfInt(66, 1); + DxfCoordinate(0, 0.0, 0.0); + DxfReal(40, width); + DxfReal(41, width); + DxfInt(70, Mode); +} + +void DxfVertex(int layer, real x, real y) +{ + DxfString(0, "VERTEX"); + DxfInt(8, layer); + DxfCoordinate(0, x, y); +} + +void DxfVertexRound(int layer, real x, real y, real r) +{ + DxfString(0, "VERTEX"); + DxfInt(8, layer); + DxfCoordinate(0, x, y); + DxfReal(42, r); +} + +void DxfSeqEnd(void) +{ + DxfString(0, "SEQEND"); + DxfInt(8, 0); +} + +void DxfInsert(int layer, string name, real x, real y, real dx, real dy, real a) +{ + if (LayerActive[layer]) { + DxfString(0, "INSERT"); + DxfInt(8, layer); + DxfString(2, name); + DxfCoordinate(0, x, y); + DxfReal(41, dx); + DxfReal(42, dy); + DxfReal(43, 1.0); + DxfReal(50, a); + } +} + +void DxfPoint(int layer, real x, real y) +{ + if (LayerActive[layer]) { + DxfString(0, "POINT"); + DxfInt(8, layer); + DxfCoordinate(0, x, y); + } +} + +void DxfLine(int layer, real x1, real y1, real x2, real y2) +{ + if (LayerActive[layer]) { + DxfString(0, "LINE"); + DxfInt(8, layer); + DxfCoordinate(0, x1, y1); + DxfCoordinate(1, x2, y2); + } +} + +void DxfCircle(int layer, real x, real y, real r) +{ + if (layer == 0 || LayerActive[layer]) { + DxfString(0, "CIRCLE"); + DxfInt(8, layer); + DxfCoordinate(0, x, y); + DxfReal(40, r); + } +} + +void DxfArc(int layer, real x, real y, real r, real a1, real a2) +{ + if (LayerActive[layer]) { + DxfString(0, "ARC"); + DxfInt(8, layer); + DxfCoordinate(0, x, y); + DxfReal(40, r); + DxfReal(50, a1); + DxfReal(51, a2); + } +} + +void DxfSolid(int layer, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4) +{ + if (layer == 0 || LayerActive[layer]) { + DxfString(0, "SOLID"); + DxfInt(8, layer); + DxfCoordinate(0, x1, y1); + DxfCoordinate(1, x2, y2); + DxfCoordinate(2, x3, y3); + DxfCoordinate(3, x4, y4); + } +} + +void DxfText(int layer, int font, real x, real y, real size, string value, real angle, int mirror, int spin) +{ + if (LayerActive[layer]) { + int Adjust = !spin; + int Reference = 0; // 3 2 + // Text + // 0 1 + if (!board) + Adjust = 1; + if (!board && mirror) { + mirror = 0; + Adjust = 0; + if (angle == 0) { Reference = 1; } + else if (angle == 90) { Reference = 3; } + else if (angle == 180) { Reference = 3; angle = 0; } + else if (angle == 270) { Reference = 1; angle = 90; } + } + DxfString(0, "TEXT"); + DxfString(7, font == FONT_PROPORTIONAL ? "ISOCP" : "ISOCT"); + DxfInt(8, layer); + DxfCoordinate(0, x, y); + Adjust = Adjust && 90 < angle && angle <= 270; + if (mirror) { + angle = -angle; + if (angle < 0) + angle += 360; + } + if (Adjust) { + angle -= 180; + if (angle < 0) + angle += 360; + Reference = 2; + } + DxfReal(40, size); + DxfString(1, value); + if (angle) + DxfReal(50, angle); + if (mirror) + DxfInt(71, 2); + if (Reference) { + DxfInt(72, Reference == 1 || Reference == 2 ? 2 : 0); + DxfInt(73, Reference >= 2 ? 3 : 0); + DxfCoordinate(1, x, y); + } + } +} + +void DxfLayer(int number, int color) +{ + DxfString(0, "LAYER"); + DxfInt(2, number); + DxfInt(70, 64); + DxfInt(62, DxfColor(palette(color))); + DxfString(6, "CONTINUOUS"); +} + +void DxfLineTypes(void) +{ + DxfString(0, "LTYPE"); + DxfString(2, "CONTINUOUS"); + DxfInt(70, 64); + DxfString(3, "Solid line"); + DxfInt(72, 65); + DxfInt(73, 0); + DxfInt(40, 0); +} + +void DxfVersion(void) +{ + DxfVariable("ACADVER"); + DxfString(1, "AC1009"); + DxfVariable("FILLMODE"); + DxfInt(70, FillAreas ? 1 : 0); +} + +void DxfWireRaw(int layer, real x1, real y1, real x2, real y2, real width) +{ + real dx = x2 - x1; + real dy = y2 - y1; + real l = sqrt(dx * dx + dy * dy); + + if (l > 0) { + if (FillAreas) + l *= 2; + + real w2 = width / 2; + real dxl = dx / l * w2; + real dyl = dy / l * w2; + + if (FillAreas) { + DxfPolyline(layer, width); + DxfVertex(layer, x1, y1); + DxfVertex(layer, x2, y2); + DxfSeqEnd(); + DxfPolyline(layer, w2); + DxfVertexRound(layer, x2 + dyl, y2 - dxl, 1); + DxfVertex (layer, x2 - dyl, y2 + dxl); + DxfSeqEnd(); + DxfPolyline(layer, w2); + DxfVertexRound(layer, x1 - dyl, y1 + dxl, 1); + DxfVertex (layer, x1 + dyl, y1 - dxl); + DxfSeqEnd(); + } + else { + DxfPolyline(layer, 0); + DxfVertex(layer, x1 + dyl, y1 - dxl); + DxfVertexRound(layer, x2 + dyl, y2 - dxl, 1); + DxfVertex (layer, x2 - dyl, y2 + dxl); + DxfVertexRound(layer, x1 - dyl, y1 + dxl, 1); + DxfSeqEnd(); + } + } +} + +void DxfWire(int layer, real x1, real y1, real x2, real y2, real width) +{ + if (UseWireWidths && width > 0) + DxfWireRaw(layer, x1, y1, x2, y2, width); + else + DxfLine(layer, x1, y1, x2, y2); +} + +void DxfPie(int layer, real x, real y, real radius) +{ + if (FillAreas) { + DxfPolyline(layer, radius); + DxfVertexRound(layer, x, y - 0.5 * radius, 1); + DxfVertexRound(layer, x, y + 0.5 * radius, 1); + DxfVertex (layer, x, y - 0.5 * radius); + DxfSeqEnd(); + } + else + DxfCircle(layer, x, y, radius); +} + +// +// Level 1: Block definitions for EAGLE primitives: +// + +void DxfOctagonBlock(string name, real e1, real e2) +{ + int layer = 0; + real r = 0.5; + real w = 0; + + if (e1 || e2) { + e1 *= r; + e2 *= r; + DxfBlock(name); + DxfWireRaw(layer, -e1, 0, e2, 0, 1); + DxfEndBlock(); + } + else { + real a_2 = r * (sqrt(2) - 1); // a = 2 * r * tan(22.5) + + if (FillAreas) { + w = 0.5; + r *= 0.5; + a_2 *= 0.5; + } + DxfBlock(name); + DxfPolyline(layer, w); + DxfVertex(layer, -r , -a_2); + DxfVertex(layer, -r , a_2); + DxfVertex(layer, -a_2, r); + DxfVertex(layer, a_2, r); + DxfVertex(layer, r , a_2); + DxfVertex(layer, r , -a_2); + DxfVertex(layer, a_2, -r); + DxfVertex(layer, -a_2, -r); + if (FillAreas) { + DxfVertex(layer, -r, -a_2); + DxfVertex(layer, -r, a_2); + } + DxfSeqEnd(); + DxfEndBlock(); + } +} + +void DxfPadAndSmdBlocks(void) // LONG/OFFSET pad and any smd shapes +{ + string CollectedPads, + CollectedSmds; + string s; + + if (board) board(B) { + B.elements(E) + E.package.contacts(C) { + if (C.pad) { + int Elongation = C.pad.elongation; + + if (Elongation) { + int sc = C.pad.shape[LAYER_PADS]; + + sprintf(s, "%sP%d", sc == PAD_SHAPE_OFFSET ? "OFFSET" : "LONG", Elongation); + if (strstr(CollectedPads, s + '#') < 0) { + CollectedPads += s + '#'; + + real e = Elongation / 100.0; + + if (sc == PAD_SHAPE_OFFSET) + DxfOctagonBlock(s, 0, 2 * e); + else + DxfOctagonBlock(s, e, e); + } + } + } + else if (C.smd) { + int Roundness = C.smd.roundness; + if (Roundness) { + for (int l = C.smd.layer; l; ) { + if (LayerActive[l]) { + int dx2 = C.smd.dx[l] / 2, + dy2 = C.smd.dy[l] / 2; + + sprintf(s, "RECT%dX%dR%d", dx2, dy2, Roundness); + if (strstr(CollectedSmds, s + '#') < 0) { + CollectedSmds += s + '#'; + + real rr = sqrt(2) - 1; + int rf = min(dx2, dy2) * Roundness / 100; + + if (FillAreas) { + rf /= 2; + dx2 -= rf; + dy2 -= rf; + } + + real r = DxfUnit(rf); + real x1 = DxfUnit(-dx2), + y1 = DxfUnit(-dy2), + x2 = DxfUnit(dx2), + y2 = DxfUnit(dy2); + + DxfBlock(s); + DxfPolyline(0, FillAreas ? -2 * r : 0); + DxfVertex (0, x2 , y1 + r); + DxfVertexRound(0, x2 , y2 - r, rr); + DxfVertex (0, x2 - r, y2 ); + DxfVertexRound(0, x1 + r, y2 , rr); + DxfVertex (0, x1 , y2 - r); + DxfVertexRound(0, x1 , y1 + r, rr); + DxfVertex (0, x1 + r, y1 ); + DxfVertexRound(0, x2 - r, y1 , rr); + DxfSeqEnd(); + + if (FillAreas) { + int o = min(SafetyOverlap, rf / 2); + dx2 -= rf - o; + dy2 -= rf - o; + x2 = DxfUnit(dx2); + y2 = DxfUnit(dy2); + DxfSolid(0, -x2, -y2, x2, -y2, -x2, y2, x2, y2); + } + DxfEndBlock(); + } + } + switch (l) { + case LAYER_TOP: l = LAYER_TSTOP; break; + case LAYER_TSTOP: l = LAYER_TCREAM; break; + case LAYER_BOTTOM: l = LAYER_BSTOP; break; + case LAYER_BSTOP: l = LAYER_BCREAM; break; + default: l = 0; + } + } + } + } + } + } +} + +void DxfBlocks(void) +{ + DxfBlock("RECT"); + DxfSolid(0, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5); + DxfEndBlock(); + + DxfBlock("PIE"); + DxfPie(0, 0, 0, 0.5); + DxfEndBlock(); + + if (board) { + string pv[] = { "P", "V" }; + + for (int i = 0; i < 2; ++i) { + DxfOctagonBlock("OCTAGON" + pv[i], 0, 0); + + DxfBlock("SQUARE" + pv[i]); + DxfSolid(0, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5); + DxfEndBlock(); + + DxfBlock("ROUND" + pv[i]); + DxfPie(0, 0, 0, 0.5); + DxfEndBlock(); + + DxfBlock("ANNULUS" + pv[i]); + DxfPie(0, 0, 0, 0.5); + DxfEndBlock(); + + DxfBlock("THERMAL" + pv[i]); + real dr = (1.0 + AnnulusRelInnerDiameter) / 4, + dw = (1.0 - AnnulusRelInnerDiameter) / 2, + ds = dr - (AnnulusRelGap + dw) / sqrt(2.0); + + if (ds < 0.01) + ds = 0.01; + DxfWire(0, -ds, +dr, +ds, +dr, dw); + DxfWire(0, +dr, +ds, +dr, -ds, dw); + DxfWire(0, +ds, -dr, -ds, -dr, dw); + DxfWire(0, -dr, -ds, -dr, +ds, dw); + DxfEndBlock(); + } + DxfPadAndSmdBlocks(); + } +} + +// +// Level 2: Low level EAGLE to DXF conversion functions: +// + +void Layer(UL_LAYER L) +{ + if (L.visible) + DxfLayer(L.number, L.color); + LayerActive[L.number] = L.visible; + switch (L.number) { + case LAYER_PADS: PadColor = L.color; break; + case LAYER_VIAS: ViaColor = L.color; break; + } +} + +void Area(UL_AREA A) +{ + DxfVariable("EXTMIN"); + DxfCoordinate(0, DxfUnit(A.x1), DxfUnit(A.y1)); + DxfVariable("EXTMAX"); + DxfCoordinate(0, DxfUnit(A.x2), DxfUnit(A.y2)); +} + +void Arc(UL_ARC A) +{ + if (LayerActive[A.layer]) { + if (UseWireWidths && A.width > 0) { + + real a1 = A.angle1 / 180 * PI; + real a2 = A.angle2 / 180 * PI; + real vr = tan((a2 - a1) / 4); // vertex roundness: vr = tan(delta_phi/4) = 2*H/R (H: segment height, R: segment radius) + + real x1 = DxfUnit(A.x1), y1 = DxfUnit(A.y1), + x2 = DxfUnit(A.x2), y2 = DxfUnit(A.y2); + real w2 = DxfUnit(A.width / 2); + real x1r = w2 * cos(a1), y1r = w2 * sin(a1), // a vector with angle1 and a length of width/2 + x2r = w2 * cos(a2), y2r = w2 * sin(a2); + + if (FillAreas) { + DxfPolyline(A.layer, DxfUnit(A.width)); + DxfVertexRound(A.layer, x1, y1, vr); + DxfVertex(A.layer, x2, y2); + DxfSeqEnd(); + if (A.cap == CAP_ROUND) { + DxfPolyline(A.layer, w2); + DxfVertexRound(A.layer, x1 - x1r/2, y1 - y1r/2, 1); + DxfVertex (A.layer, x1 + x1r/2, y1 + y1r/2); + DxfSeqEnd(); + DxfPolyline(A.layer, w2); + DxfVertexRound(A.layer, x2 + x2r/2, y2 + y2r/2, 1); + DxfVertex (A.layer, x2 - x2r/2, y2 - y2r/2); + DxfSeqEnd(); + } + } + else { + DxfPolyline(A.layer, 0); + if (A.cap == CAP_ROUND) + DxfVertexRound(A.layer, x1 - x1r, y1 - y1r, 1); + else + DxfVertex (A.layer, x1 - x1r, y1 - y1r); + DxfVertexRound (A.layer, x1 + x1r, y1 + y1r, vr); + if (A.cap == CAP_ROUND) + DxfVertexRound(A.layer, x2 + x2r, y2 + y2r, 1); + else + DxfVertex (A.layer, x2 + x2r, y2 + y2r); + DxfVertexRound (A.layer, x2 - x2r, y2 - y2r, -vr); + DxfSeqEnd(); + } + } + else + DxfArc(A.layer, + DxfUnit(A.xc), DxfUnit(A.yc), + DxfUnit(A.radius), + DxfAngle(A.angle1), DxfAngle(A.angle2)); + } +} + +void WireSegment(UL_WIRE W) +{ + if (W.arc) + Arc(W.arc); + else + DxfWire(W.layer, DxfUnit(W.x1), DxfUnit(W.y1), DxfUnit(W.x2), DxfUnit(W.y2), DxfUnit(W.width)); +} + +void Wire(UL_WIRE W) +{ + if (LayerActive[W.layer]) { + if (W.style != WIRE_STYLE_CONTINUOUS) + W.pieces(P) WireSegment(P); + else + WireSegment(W); + } +} + +void Circle(UL_CIRCLE C) +{ + if (LayerActive[C.layer]) { + if (UseWireWidths) { + if (C.width > 0) { + if (FillAreas) { + DxfPolyline(C.layer, DxfUnit(C.width)); + DxfVertexRound(C.layer, DxfUnit(C.x), DxfUnit(C.y - C.radius), 1); + DxfVertexRound(C.layer, DxfUnit(C.x), DxfUnit(C.y + C.radius), 1); + DxfVertex(C.layer, DxfUnit(C.x), DxfUnit(C.y - C.radius)); + DxfSeqEnd(); + } + else { + int r1 = C.radius - C.width / 2, + r2 = C.radius + C.width / 2; + + if (r1 > 0) + DxfCircle(C.layer, DxfUnit(C.x), DxfUnit(C.y), DxfUnit(r1)); + DxfCircle(C.layer, DxfUnit(C.x), DxfUnit(C.y), DxfUnit(r2)); + } + return; + } + else if (FillAreas) { + DxfPolyline(C.layer, DxfUnit(C.radius)); + DxfVertexRound(C.layer, DxfUnit(C.x), DxfUnit(C.y - C.radius / 2), 1); + DxfVertexRound(C.layer, DxfUnit(C.x), DxfUnit(C.y + C.radius / 2), 1); + DxfVertex(C.layer, DxfUnit(C.x), DxfUnit(C.y - C.radius / 2)); + DxfSeqEnd(); + return; + } + } + DxfCircle(C.layer, DxfUnit(C.x), DxfUnit(C.y), DxfUnit(C.radius)); + } +} + +void Rectangle(UL_RECTANGLE R) +{ + DxfInsert(R.layer, "RECT", DxfUnit((R.x1 + R.x2) / 2), DxfUnit((R.y1 + R.y2) / 2), DxfUnit(R.x2 - R.x1), DxfUnit(R.y2 - R.y1), R.angle); +} + +void Hole(UL_HOLE H) +{ + DxfCircle(LAYER_DIMENSION, DxfUnit(H.x), DxfUnit(H.y), DxfUnit(H.drill / 2)); + if (LayerActive[LAYER_TSTOP]) DxfPie(LAYER_TSTOP, DxfUnit(H.x), DxfUnit(H.y), DxfUnit(H.diameter[LAYER_TSTOP] / 2)); + if (LayerActive[LAYER_BSTOP]) DxfPie(LAYER_BSTOP, DxfUnit(H.x), DxfUnit(H.y), DxfUnit(H.diameter[LAYER_BSTOP] / 2)); +} + +void Via(UL_VIA V) +{ + string Shape[] = { "SQUAREV", "ROUNDV", "OCTAGONV", "XLONGOCT", "YLONGOCT", "ANNULUSV", "THERMALV" }; + int Count = 0; + int Extended = 0; + + for (int l = LAYER_TOP; l; ) { + real d = DxfUnit(V.diameter[l]); + if (d && (LayerActive[l] || l == Extended)) { + Count++; + DxfInsert(ViaColor && !IsSupplyLayer[l] && l <= LAYER_BOTTOM ? LAYER_VIAS : l, Shape[V.shape[l]], DxfUnit(V.x), DxfUnit(V.y), d, d, 0); + } + if (l < LAYER_BOTTOM) { + if (Extended) + l = Extended = LAYER_BOTTOM; + else + ++l; + } + else + switch (l) { + case LAYER_BOTTOM: if (!Extended && !Count && ViaColor && LayerActive[LAYER_VIAS]) + l = Extended = LAYER_BOTTOM; + else + l = LAYER_TSTOP; + break; + case LAYER_TSTOP: l = LAYER_BSTOP; break; + default: l = 0; + } + } + if (Count) + DxfCircle(LAYER_DRILLS, DxfUnit(V.x), DxfUnit(V.y), DxfUnit(V.drill / 2)); +} + +void Pad(UL_PAD P) +{ + string Shape[] = { "SQUAREP", "ROUNDP", "OCTAGONP", "LONGP", "OFFSETP", "ANNULUSP", "THERMALP" }; + int Count = 0; + int Extended = 0; + + for (int l = LAYER_TOP; l; ) { + real d = DxfUnit(P.diameter[l]); + if (d && (LayerActive[l] || l == Extended)) { + int sc = P.shape[l]; + string s; + + switch (sc) { + case PAD_SHAPE_LONG: + case PAD_SHAPE_OFFSET: { + int e = P.elongation; + if (e) + sprintf(s, "%d", e); + else + sc = PAD_SHAPE_OCTAGON; + } + } + Count++; + DxfInsert(PadColor && !IsSupplyLayer[l] && l <= LAYER_BOTTOM ? LAYER_PADS : l, Shape[sc] + s, DxfUnit(P.x), DxfUnit(P.y), d, d, P.angle); + } + if (l < LAYER_BOTTOM) { + if (Extended) + l = Extended = LAYER_BOTTOM; + else + ++l; + } + else + switch (l) { + case LAYER_BOTTOM: if (!Extended && !Count && PadColor && LayerActive[LAYER_PADS]) + l = Extended = LAYER_TOP; + else + l = LAYER_TSTOP; + break; + case LAYER_TSTOP: l = LAYER_BSTOP; break; + default: l = 0; + } + } + if (Count) + DxfCircle(LAYER_DRILLS, DxfUnit(P.x), DxfUnit(P.y), DxfUnit(P.drill / 2)); +} + +void Smd(UL_SMD S) +{ + for (int l = S.layer; ; ) { + if (LayerActive[l]) { + int dx2 = S.dx[l] / 2, dy2 = S.dy[l] / 2; + + if (dx2 == 0 || dy2 == 0) + ; // nothing to do + else if (S.roundness == 100 && dx2 == dy2) + DxfInsert(l, "PIE", DxfUnit(S.x), DxfUnit(S.y), DxfUnit(2 * dx2), DxfUnit(2 * dy2), 0); + else if (S.roundness) { + string Name; + + sprintf(Name, "RECT%dX%dR%d", dx2, dy2, S.roundness); + DxfInsert(l, Name, DxfUnit(S.x), DxfUnit(S.y), 1.0, 1.0, S.angle); + } + else + DxfInsert(l, "RECT", DxfUnit(S.x), DxfUnit(S.y), DxfUnit(2 * dx2), DxfUnit(2 * dy2), S.angle); + } + switch (l) { + case LAYER_TOP: l = LAYER_TSTOP; break; + case LAYER_TSTOP: l = LAYER_TCREAM; break; + case LAYER_BOTTOM: l = LAYER_BSTOP; break; + case LAYER_BSTOP: l = LAYER_BCREAM; break; + default: return; + } + } +} + +void Junction(UL_JUNCTION J) +{ + DxfPie(LAYER_NETS, DxfUnit(J.x), DxfUnit(J.y), DxfUnit(J.diameter / 2)); +} + +void Polygon(UL_POLYGON P) +{ + P.contours(W) Wire(W); + if (P.width > 0) + P.fillings(W) Wire(W); + else if (dlgMessageBox(tr("Can't fill polygon with Width = 0"), tr("+OK"), tr("-Cancel")) != 0) + exit(1); +} + +int CheckMultiline(string t) +{ + return (strchr(t, '\n') >= 0); +} + +void Text(UL_TEXT T) +{ + if (LayerActive[T.layer]) { + if (T.font == FONT_VECTOR || AlwaysVectorFont) { + T.wires(W) WireSegment(W); + } + else { + if (CheckMultiline(T.value)) { + dlgMessageBox(tr("Multiline texts can be exported only in vector font:\n\n") + T.value, tr("-Cancel")); + string er; + sprintf(er, "WIN (%.3fmil %.3fmil);\nSHOW (%.3fmil %.3fmil)", + u2mil(T.x), u2mil(T.y), u2mil(T.x), u2mil(T.y)); + exit(er); + } + DxfText(T.layer, T.font, + DxfUnit(T.x), DxfUnit(T.y), DxfUnit(T.size), + T.value, T.angle, T.mirror, T.spin); + } + } +} + +void Label(UL_LABEL L) +{ + if (LayerActive[L.layer]) { + L.wires(W) Wire(W); + Text(L.text); + } +} + +void Dimension(UL_DIMENSION D) +{ + D.wires(W) Wire(W); + D.texts(T) Text(T); +} + +void Frame(UL_FRAME F) +{ + F.wires(W) Wire(W); + F.texts(T) Text(T); +} + +// +// Level 3: High level EAGLE decomposing functions: +// + +void Package(UL_PACKAGE P) +{ + P.polygons(P) Polygon(P); + P.wires(W) Wire(W); + P.texts(T) Text(T); + P.dimensions(D) Dimension(D); + P.circles(C) Circle(C); + P.rectangles(R) Rectangle(R); + P.frames(F) Frame(F); + P.holes(H) Hole(H); + P.contacts(C) { + if (C.pad) Pad(C.pad); + else Smd(C.smd); + // arbitrary pad shapes + C.wires(W) Wire(W); + C.polygons(P) Polygon(P); + } +} + +void Element(UL_ELEMENT E) +{ + int layer; + + switch (E.mirror) { + case 0: layer = LAYER_TORIGINS; break; // not mirrored + case 1: layer = LAYER_BORIGINS; break; // mirrored + } + DxfPoint(layer, DxfUnit(E.x), DxfUnit(E.y)); + Package(E.package); + E.texts(T) Text(T); +} + +void Signal(UL_SIGNAL S) +{ + S.polygons(P) Polygon(P); + S.wires(W) Wire(W); + S.vias(V) Via(V); +} + +void Board(UL_BOARD B) +{ + B.polygons(P) Polygon(P); + B.wires(W) Wire(W); + B.texts(T) Text(T); + B.dimensions(D) Dimension(D); + B.circles(C) Circle(C); + B.rectangles(R) Rectangle(R); + B.frames(F) Frame(F); + B.holes(H) Hole(H); + B.elements(E) Element(E); + B.signals(S) Signal(S); +} + +void Pin(UL_PIN P) +{ + P.wires(W) Wire(W); + P.circles(C) Circle(C); + P.texts(T) Text(T); +} + +void Symbol(UL_SYMBOL S) +{ + S.polygons(P) Polygon(P); + S.wires(W) Wire(W); + S.texts(T) Text(T); + S.dimensions(D) Dimension(D); + S.pins(P) Pin(P); + S.circles(C) Circle(C); + S.rectangles(R) Rectangle(R); + S.frames(F) Frame(F); +} + +void Instance(UL_INSTANCE I) +{ + Symbol(I.gate.symbol); + I.texts(T) Text(T); + I.xrefs(X) Symbol(X.symbol); +} + +void Port(UL_PORT P) +{ + P.wires(W) Wire(W); + P.texts(T) Text(T); +} + +void ModuleInstance(UL_MODULEINST MI) +{ + MI.texts(T) Text(T); + MI.wires(W) Wire(W); + MI.module.ports(P) Port(P); +} + +void Part(UL_PART P) +{ + P.instances(I) Instance(I); +} + +void Segment(UL_SEGMENT S) +{ + S.wires(W) Wire(W); + S.junctions(J) Junction(J); + S.labels(L) Label(L); +} + +void Bus(UL_BUS B) +{ + B.segments(S) Segment(S); +} + +void Net(UL_NET N) +{ + N.segments(S) Segment(S); +} + +void Sheet(UL_SHEET S) +{ + S.polygons(P) Polygon(P); + S.wires(W) Wire(W); + S.texts(T) Text(T); + S.dimensions(D) Dimension(D); + S.circles(C) Circle(C); + S.rectangles(R) Rectangle(R); + S.frames(F) Frame(F); + S.parts(P) Part(P); + S.busses(B) Bus(B); + S.nets(N) Net(N); + S.moduleinsts(MI) ModuleInstance(MI); +} + +// +// Main program: +// + +string OutputFileName; +int DoDialog = argc == 1; +string FileNameSuffix; + +for (int i = 1; i < argc; i++) { + if (argv[i] == "-s") FileNameSuffix = argv[++i]; + else if (argv[i] == "-u") { + string u = strupr(argv[++i]); + if (u) { + if (u == "MM") + Unit = MM; + else if (u == "INCH") + Unit = INCH; + else { + dlgMessageBox(usage + tr("


    ERROR: unknown unit: ") + argv[i] + ""); + exit(1); + } + } + else { + dlgMessageBox(usage + tr("
    ERROR: missing unit")); + exit(1); + } + } + else if (argv[i] == "-a") AlwaysVectorFont = YES; + else if (argv[i] == "-w") UseWireWidths = YES; + else if (argv[i] == "-f") FillAreas = YES; + else { + dlgMessageBox(usage + tr("
    ERROR: unknown option: ") + argv[i] + ""); + exit(1); + } + } + +if (board) + board(B) { + OutputFileName = B.name; + B.layers(L) { + string s = L.name; + if (L.visible && s[0] == '$') { + VisibleSupplyLayer = YES; + IsSupplyLayer[L.number] = YES; + } + } + } +else if (schematic) + schematic(SCH) OutputFileName = SCH.name; +else { + dlgMessageBox(usage + tr("
    ERROR: No board or schematic!

    \nThis program can only work in the board or schematic editor.")); + exit(1); + } + +OutputFileName = filesetext(OutputFileName, FileNameSuffix + ".dxf"); + +if (DoDialog) { + dlgDialog(tr("DXF Converter")) { + dlgHBoxLayout dlgSpacing(400); // let's have some space for the file name + dlgHBoxLayout { + dlgLabel(tr("&Output file")); + dlgStringEdit(OutputFileName); + dlgPushButton(tr("&Browse")) { + string FileName = dlgFileSave(tr("Save DXF file"), OutputFileName, tr("DXF files (*.dxf)")); + if (FileName) + OutputFileName = FileName; + } + } + dlgCheckBox(tr("&Always vector font"), AlwaysVectorFont); + dlgLabel(tr("If checked, texts will always be drawn with the builtin vector font.")); + dlgCheckBox(tr("&Use wire widths"), UseWireWidths) { UseWireWidths |= FillAreas; }; + dlgLabel(tr("If checked, wires, arcs and circles will be generated as polygons showing their real widths. This, however, can cause the DXF file to become very large! Uncheck this if you do not need the real widths.")); + dlgCheckBox(tr("&Fill areas"), FillAreas) { UseWireWidths |= FillAreas; } + dlgLabel(tr("If checked, wires, arcs etc. will be filled (implies 'Use wire widths'!).")); + if (VisibleSupplyLayer) { + dlgGroup(tr("Thermal Emulation")) { + dlgHBoxLayout { + dlgLabel(tr("Relative inner diameter")); + dlgRealEdit(AnnulusRelInnerDiameter, 0.5, 0.99); + } + dlgHBoxLayout { + dlgLabel(tr("Relative gap size")); + dlgRealEdit(AnnulusRelGap, 0.1, 0.5); + } + dlgLabel(tr("Only the outer diameter of Thermals is available. The inner diameter and gap size are calculated based on the outer diameters according to these factors.")); + } + } + dlgGroup(tr("Unit")) { + dlgHBoxLayout { + dlgVBoxLayout { + dlgRadioButton("&mm", Unit); + dlgRadioButton("&inch", Unit); + } + dlgLabel(tr("Defines the unit used for coordinates and values in the DXF file")); + } + } + dlgStretch(1); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton(tr("+OK")) { + string a[]; + if (!fileglob(a, OutputFileName) || dlgMessageBox(tr("File exists: ") + OutputFileName + tr("\n\nOverwrite?"), tr("+&Yes"), tr("-&No")) == 0) + dlgAccept(); + } + dlgPushButton(tr("-Cancel")) { dlgReject(); exit(1); } + dlgPushButton(tr("About")) dlgMessageBox(usage); + } + }; + } + +output(OutputFileName) { + DxfSection("HEADER"); + DxfVersion(); + if (board) board(B) Area(B.area); + else sheet(S) Area(S.area); + DxfEndSection(); + DxfSection("TABLES"); + DxfTable("LTYPE", 1); + DxfLineTypes(); + DxfEndTable(); + DxfTable("LAYER", 255); + if (board) board(B) B.layers(L) Layer(L); + else schematic(SCH) SCH.layers(L) Layer(L); + DxfEndTable(); + DxfEndSection(); + DxfSection("BLOCKS"); + DxfBlocks(); + DxfEndSection(); + DxfSection("ENTITIES"); + if (board) board(B) Board(B); + else sheet(S) Sheet(S); + DxfEndSection(); + DxfTrailer(); + } diff --git a/trunk/ulp/e-attributverwaltung.ulp b/trunk/ulp/e-attributverwaltung.ulp new file mode 100644 index 00000000..ae6c5568 --- /dev/null +++ b/trunk/ulp/e-attributverwaltung.ulp @@ -0,0 +1,1486 @@ +#usage "de:Attributverwaltung

    " + "Mit diesem ULP können Sie Attribute anlegen und verwalten. Für einige " + "Bauteile (speziell für Zeichnungsrahmen aus der Bibliothek " + "e-elektro-zeichnungsrahmen) sind schon bei der Bibliotheksdefinition " + "Attribute und die entsprechenden Textplatzhalter angelegt worden.

    " + "Es wird unterschieden zwischen lokalen und globalen Attributen:
    " + "Bei einem lokalen Attribut wurde in der Bibliothek im Symbol " + "ein Platzhaltertext (>ATTRIBUTNAME) angelegt und in der Devicedefinition " + "das entsprechende Attribut definiert. Der Attributwert ist üblicherweise " + "noch nicht festgelegt.
    " + "Ein Attribut gilt ebenfalls als lokal, wenn es erst im Schaltplan " + "für ein spezielles Bauteil angelegt wurde. Der Platzhaltertext muss " + "aber bereits bei der Bauteildefinition im Symbol angelegt worden sein, " + "ansonsten kann mit CHANGE DISPLAY OFF | VALUE | NAME | BOTH im SCH/BRD " + "die Anzeige des Attribute entsprechend eingestellt werden.

    " + "Ein globales Attribut wird direkt im Schaltplan oder Board angelegt. " + "Es ist für alle Bauteile gültig, die bereits einen entsprechenden " + "Platzhaltertext haben. Dieser muss bereits bei der Bauteildefinition " + "im Symbol angelegt worden sein. Globale Attribute werden üblicherweise " + "für Zeichnugsrahmen verwendet.

    " + "Das ULP hilft Ihnen beim Bearbeiten und Erstellen von Attributen. " + "Nach dem Start entscheiden Sie zuerst was Sie tun möchten. " + "Es gibt die Möglichkeiten LOKALE oder GLOBALE Attribute zu " + "bearbeiten oder anzulegen.
    " + "Wollen Sie zum Beispiel für einen Zeichnungsrahmen ein globales Attribut anlegen, " + "wählen Sie unter GLOBALE die Option anlegen. " + "Doppelklicken Sie dann auf den Rahmen in der Liste der Bauteile. " + "Es öffnet sich ein neues Fenster mit den vorhandenen Attributen. " + "Durch Doppelklick auf einen Eintrag in der Liste wählen Sie das Attribut, " + "das angelegt werden soll. Es öffnet sich ein weiteres Fenster, in dem Sie " + "den Wert für das Attribut definieren können.
    " + "Aktivieren Sie unter Attribut bearbeiten die Option ja, " + "wenn Sie die Änderung übernehmen wollen, nicht ändern, wenn Sie " + "keine Änderung machen wollen, oder löschen wenn sie das Attribut " + "löschen wollen.
    " + "Mit OK übernehmen Sie die Einstellungen.
    " + "Dieselbe Vorgehensweise gilt auch für das Bearbeiten und Anlegen " + "von lokalen Attributen.

    " + "Das ULP kann auch in einer Bibliothek im Device-Editor zum einfachen " + "erstellen und bearbeiten von lokalen Attributen verwendet werden.

    " + "Benutzung des ULP:
    " + "RUN e-attributverwaltung [+L | -L] | [+A | -A] | 1DESCRIPTION
    " + "" + "Option +L setzt die Attribute aus einer definierbaren Liste im Deviceset (direkt ohne Nachfragen).
    " + "Option -L löscht die Attribute aus einer definierbaren Liste im Deviceset (direkt ohne Nachfragen).
    " + "Option +A setzt die Attribute aus einer definierbaren Liste in allen Devicesets in der LBR (direkt ohne Nachfragen).
    " + "Option -A löscht die Attribute aus einer definierbaren Liste in allen Devicesets in der LBR (direkt ohne Nachfragen).
    " + "
    " + "Option 1DESCRIPTION erzeugt ein ATTRIBUTE 'A_DESCRIPTION' für jedes Bauteil (Part) und kopiert den Inhalt " + "der Kopfzeile der Description als Wert in das Attribut, um die Description am Symbol des Part anzeigen zu können.
    " + "Diese Option gibt es nur im Schaltplan.

    " + "Author alf@cadsoft.de" + , + "en:" + "Author alf@cadsoft.de" + +// 2.0.0 | 2008-11-07 - Globale Attribute von SCH -> BRD oder BRD -> SCH übertragen +// bzw. zwischen SCH und BRD angleichen. +// Technologien und Package-Varianten werden berücksichtigt +// 2.0.1 | 2009-11-27 - Menü-Button mit ALT-Option +// +// 2.1.0 | 2009-12-17 - Es kann eine Liste von Attribute-Namen verwaltet werden, +// um in Devices in der Bibliothek diese Attribute zu definieren. +// Option +L setzt die Attribute aus der Liste ohne nachfragen +// Option -L löscht die Attribute aus der Liste ohne nachfragen +// +// 2.1.1 | 2010-01-14 - Globale Attribute mit INDEX_Sxxx werden nicht berücksichtigt, +// wegen e-seiten-index.ulp. +// +// 2.1.2 | 2010-02-10 - Liste erst in Funktion aus_liste_anlegen() laden. +// 2.1.3 | 2010-08-17 - Option +A -A alf@cadsoft.de +// +// 2.1.4 | 2010-12-14 - Option 1DESCRIPTION erzeugt ein ATTRIBUTE A_DESCRIPT mit dem +// Inhalt der Kopfzeile der Description des Parts (Devices). +// Diese Optiopn ist nur im Schaltplan verfügbar. +// +// 2.1.5 | 2011-03-02 - Option Auch in Board übertragen. +// +// 2.1.6 | 2011-12-07 - Variablenname variant[] für Version 6 angepasst. +// Reservierte Textplatzhalter erweitert. +// +// 2.1.7 | 2011-12-30 - Lösche selektierte Attribute in allen Devices +// +// 2.1.8 | 2013-08-21 - Bei konsistenten SCH/BRD bei TABs anzeigen. +// +// 2.1.9 | 2013-11-28 - Attribute Option constant variable +// Die Option "Change Option" ist per Default auf ON gesetzt, +// damit man constant bzw. variable einfacher editieren kann. +// +string Version = "Version 2.1.9"; // 1.0.0 - 2008-04-17 alf@cadsoft.de + +string cmd, s; +string Pname[], Psheet[]; +int cntP = 0; +int cntA = 0; +string AttribPart[]; +string AttribWert[]; +numeric string ListAttrib[]; +string Platzhalter[]; +string LPlatzhalter[]; +string PacVariant[]; +string Techno[]; +string ReservedAttname = "INDEX_S"; // 2010-01-14 +string Description1[]; // 2010-12-14 +string DelAttrib[]; // 2011-12-30 + + +string setze[] = { "nicht ändern", "ja", "löschen" }; +enum { nein, ja, loeschen }; +string Edit[] = { "Device", "Part", "Element" }; +enum { Device, Part, Element }; +string aType[] = { "Lokale", "Globale" }; +enum { Lokal, Global }; +enum { neu, bearbeiten }; +string AttOption[] = { "variable", "constant" }; // 2013-09-02 +enum { ATTvariable, ATTconstant }; + +// 2008-09-02 +enum { DEVeditor, SCHeditor, BRDeditor }; +int isBoard = 0; +int isSchematic = 0; +string Ename[]; +int cntE = 0; +int cntEA = 0; +string AttribElement[]; +string EAttribWert[]; +string EListAttrib[]; +string EPlatzhalter[]; + +string sch_attributte[], brd_attributte[]; +string sch_attributteValue[], brd_attributteValue[]; +int cnt_schattr, cnt_brdattr; +int in_brd_sch = 0; + +string attdiff_sch[], attdiff_brd[], attdiff_val[]; +int cntdiffs = 0; +int cntdiffb = 0; +int cntdiffval = 0; + +// 2009-12-15 +string attribute_list_datei = filesetext(argv[0], ".lst"); +string attribute_liste[]; +int cntattributelist = 0; // nicht verändern + + +// ############## Funktionen ################ +string AttribT(string s) { + if (s[0] == '>') { // folgende Textplatzhalter sind keine Attribute + if (s == ">NAME" || + s == ">VALUE" || + s == ">PART" || + s == ">GATE" || + s == ">XREF" || + s == ">CONTACT_XREF" || + s == ">ASSEMBLY_VARIANT" || + s == ">DRAWING_NAME" || + s == ">LAST_DATE_TIME" || + s == ">PLOT_DATE_TIME " || + s == ">SHEETNR" || + s == ">SHEETS" || + s == ">SHEET" + ) s = ""; + else s = strsub(s, 1); + } + else s = ""; // kein Attribut-Platzhalter, nur Text. + return s; +} + +string changeAttribOption(string att) { // 2013-09-02 + string s[]; + int cnt = strsplit(s, att, '\t'); + if (s[5] == AttOption[ATTvariable]) s[5] = AttOption[ATTconstant]; + else if (s[5] == AttOption[ATTconstant]) s[5] = AttOption[ATTvariable]; + return strjoin(s, '\t'); +} + +// ========== Unter-Menu Ändern ========== // +string changeAttrib(string att, int Objekt, int newchange) { + string s[]; + int setAttrib = -1; + int cnt = strsplit(s, att, '\t'); + if (s[1] == setze[1]) setAttrib = ja; + int Result = dlgDialog("Attribut") { + dlgLabel(s[0]); + dlgHBoxLayout { + dlgLabel("&Wert "); + dlgStringEdit(s[2]); + } + if (newchange == bearbeiten) { + dlgGroup("Attribut bearbeiten") { + dlgRadioButton("&nicht ändern", setAttrib); + dlgRadioButton("&ja", setAttrib); + dlgRadioButton("&löschen", setAttrib); + } + } + else { + dlgGroup("Attribut anlegen") { + dlgRadioButton("&nein", setAttrib); + dlgRadioButton("&ja", setAttrib); + } + } + dlgHBoxLayout { + dlgPushButton("+OK") { + if (setAttrib < 0) { + if (newchange == bearbeiten) dlgMessageBox("Wählen Sie eine Option,\nnein, ja, löschen", "OK"); + else dlgMessageBox("Wählen Sie eine Option,\nnein, ja", "OK"); + } + else { + att = s[0] + "\t" + setze[setAttrib] + "\t" + s[2]; + for (int n = 3; n < cnt; n++) att += "\t" + s[n]; + dlgAccept(); + } + } + dlgPushButton("-Abbruch") dlgReject(); + dlgStretch(1); + } + }; + return att; +} + + +void setzealle(int nein_ja) { + string s[]; + for (int a = 0; a < cntP; a++) { + int cnt = strsplit(s, ListAttrib[a], '\t'); + ListAttrib[a] = s[0] + "\t" + setze[nein_ja] + "\t" + s[2]; + for (int n = 3; n < cnt; n++) ListAttrib[a] += "\t" + s[n]; + } + return; +} + + +void setze_attribut(int nein_ja, int sel) { +//stop + string s[]; + for (int n = 0; n < cntP; n++) { + if (AttribPart[n] == AttribPart[sel]) { + strsplit(s, ListAttrib[n], '\t'); + ListAttrib[n] = s[0] + "\t" + setze[nein_ja] + "\t" + s[2] + "\t" + s[3] + "\t" + s[4]; + } + } + return; +} + + + +void setze_variant(int nein_ja, int sel) { + string s[]; + for (int n = 0; n < cntP; n++) { + if (PacVariant[n] == PacVariant[sel]) { + strsplit(s, ListAttrib[n], '\t'); + ListAttrib[n] = s[0] + "\t" + setze[nein_ja] + "\t" + s[2] + "\t" + s[3] + "\t" + s[4]; + } + } + return; +} + + +void setze_techno(int nein_ja, int sel) { + string s[]; + for (int n = 0; n < cntP; n++) { + if (Techno[n] == Techno[sel]) { + strsplit(s, ListAttrib[n], '\t'); + ListAttrib[n] = s[0] + "\t" + setze[nein_ja] + "\t" + s[2] + "\t" + s[3] + "\t" + s[4]; + } + } + return; +} + + +void copyPlatzhalterList(int L) { + for (int n = 0; n < L; n++) { + ListAttrib[n] = LPlatzhalter[n] + "\t" + setze[ja] + "\t"; + } + ListAttrib[L] = ""; // letzter Eintrag löschen + cntP = L; + return; +} + + +void generateAttribScript(int Objekt, int Editor, string PartName, string Sheet) { + string a[]; + int cnt; + cmd = ""; + + for (int n = 0; n < cntP; n++) { + cnt = strsplit(a, ListAttrib[n], '\t'); + if (a[1] == setze[ja]) { + if (deviceset) { + if(a[3][0] == '\'') sprintf(s, "PACKAGE %s;\n", a[3]); + else sprintf(s, "PACKAGE '%s';\n", a[3]); // 2013-09-02 Packagevariante kann mit "-" beginnen! + cmd += s; + sprintf(s, "TECHNOLOGY %s;\n", a[4]); + cmd += s; + sprintf(s, "ATTRIBUTE %s '%s' %s;\n", a[0], a[2], a[5]); // 2013-09-02 Option conctant/variable + } + else if (Objekt == Global) { + sprintf(s, "ATTRIBUTE * %s '%s';\n", a[0], a[2]); + } + else if (Objekt == Lokal) { + cmd += "CHANGE DISPLAY OFF;\n"; // | VALUE | NAME | BOTH + sprintf(s, "ATTRIBUTE %s %s '%s' %s;\n", PartName, a[0], a[2], a[5]); + } + else { + cmd += "CHANGE DISPLAY OFF;\n"; + sprintf(s, "ATTRIBUTE %s %s '%s' %s;\n", PartName, a[0], a[2], a[5]); + } + cmd+=s; + } + else if (a[1] == setze[loeschen]) { + if (deviceset) { + sprintf(s, "PACKAGE %s;\n", a[3]); + cmd += s; + sprintf(s, "TECHNOLOGY %s;\n", a[4]); + cmd += s; + sprintf(s, "ATTRIBUTE %s DELETE;\n", a[0]); + } + else if (Objekt == Global) { + sprintf(s, "ATTRIBUTE * %s DELETE;\n", a[0]); + } + else { + sprintf(s, "ATTRIBUTE %s '%s' DELETE;\n", PartName, a[0]); + } + cmd+=s; + } + } + string ecmd; + if (Editor == SCHeditor && in_brd_sch) ecmd = "EDIT .SCH;\n" + cmd + "EDIT .BRD;\n" + cmd; // 2011-03-02 auch in Board übertragen + else if (Editor == BRDeditor && in_brd_sch) ecmd = "EDIT .BRD;\n" + cmd + "EDIT .SCH;\n" + cmd; // 2011-03-02 auch in Schaltplan übertragen + else if (Editor == BRDeditor || Editor == SCHeditor) ecmd = cmd; + else ecmd = cmd; + exit(ecmd); +} + + +void getTextPlatzhalterDS(UL_DEVICESET DS) { + cntP = 0; + DS.devices(D) { + string t[]; + int n = strsplit(t, D.technologies, ' '); + n = 1; /************** nur eine Technologie behandeln, ******** + ************** alle Technologien haben die gleichen Attribute ********/ + for (int na = 0; na < n; na++) { + string la[]; // lokales attribute + int cntla = 0; + D.attributes(A, t[na]) { + la[cntla] = A.name; + cntla++; + } + D.gates(G) { + G.symbol.texts(T) { + string s = AttribT(strupr(T.value)); // keine reservierten Textplatzhalter >NAME >VALUE >PART >GATE ... + for (int n = 0; n < cntla; n++) { + if (s == la[n]) { + s = ""; // Textplatzhalter schon benutzt + break; + } + } + if (s) { // sammle Platzhalter + AttribPart[cntP] = s; // zum selektieren eines Attribut + Platzhalter[cntP] = s; + ListAttrib[cntP] = s + "\t" + setze[ja] + "\t" + "" + "\t" + D.name + "\t" + t[na] ; + Techno[cntP] = t[na]; + PacVariant[cntP] = D.name; + cntP++; + } + } + } + } + } + ListAttrib[cntP] = ""; + return; +} + + +void getAttributeDS(UL_DEVICESET DS) { + cntP = 0; + cntA = 0; + DS.devices(D) { + /* + string dname = D.name; + if (dname[0] == '-') { // 2013-09-02 + if (dlgMessageBox("!Verbotenes Zeichen im Namen.

    Package-Variante "+ D.name + " hat Minus-Zeichen an erster Position.", "OK", "CANCEL") != 0) exit(-379); + } + */ + string t[]; + int n = strsplit(t, D.technologies, ' '); + for (int na = 0; na < n; na++) { + D.attributes(A, t[na]) { + AttribPart[cntA] = A.name; + AttribWert[cntA] = A.value; + sprintf(ListAttrib[cntA], "%s\t%s\t%s\t%s\t%s\t%s", A.name, setze[ja], A.value, D.name, t[na], AttOption[A.constant]); // 2013-09-02 + Techno[cntA] = t[na]; + PacVariant[cntA] = D.name; + cntA++; + AttribPart[cntA] = ""; + ListAttrib[cntA] = ""; + } + } + cntP = cntA; + } + return; +} + + +void clear_list(void) { // zurück aus Untermenu löscht die Einträge aller Listen + cntP = 0; + cntA = 0; + cntE = 0; + ListAttrib[0] = ""; + AttribPart[0] = ""; + AttribWert[0] = ""; + Platzhalter[0] = ""; + EListAttrib[0] = ""; + AttribElement[0] = ""; + EAttribWert[0] = ""; + EPlatzhalter[0] = ""; + return; +} + + +int diff_attr_sch_brd(int menu_on) { + int notfound, n; + for (n = 0; n < cnt_schattr; n++) { + notfound = 1; + for (int x = 0; x < cnt_brdattr; x++) { + if (sch_attributte[n] == brd_attributte[x]) { + notfound = 0; + if (sch_attributteValue[n] != brd_attributteValue[x]) { + sprintf(attdiff_val[cntdiffval], "%s\t%s\t%s", sch_attributte[n], sch_attributteValue[n], brd_attributteValue[x]); + cntdiffval++; + } + break; + } + } + if (notfound) { + sprintf(attdiff_sch[cntdiffs], "%s\t'%s'", sch_attributte[n], sch_attributteValue[n]); + cntdiffs++; + attdiff_sch[cntdiffs] = ""; // letzen markieren + } + } + for (n = 0; n < cnt_brdattr; n++) { + notfound = 1; + for (int x = 0; x < cnt_schattr; x++) { + if (brd_attributte[n] == sch_attributte[x]) { + notfound = 0; + break; + } + } + if (notfound) { + sprintf(attdiff_brd[cntdiffb], "%s\t'%s'", brd_attributte[n], brd_attributteValue[n]); + cntdiffb++; + attdiff_brd[cntdiffb] = ""; // letzen markieren + } + } + if (!menu_on) return cntdiffs + cntdiffb; + return 0; +} + + +void hilfe(void) { + dlgDialog("Hilfe "+filename(argv[0])) { + dlgLabel(usage); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + + +// ======== Unter-Menu ======== // +// ### Attribute Menu zum Anlgen bzw. Ändern ### +int menu(int Objekt, int Editor, string PartName, string Sheet, int newchange) { + int sel = -1; + int selp = -1; + int alle_setzen = -1; + int changeoption = 1; // 2013-09-02 + string cnt_selAttrib = ""; + string InfoCnt = " "; + string attmsg = " "; + + switch(Editor) { + case Device : if (newchange == neu) sprintf(InfoCnt, "%d Textplatzhalter in %s %s verfügbar", cntP, Edit[Editor], PartName); + else sprintf(InfoCnt, "%d Attribute in %s %s", cntP, Edit[Editor], PartName); + break; + case Part : if (newchange == neu) sprintf(InfoCnt, "%d Textplatzhalter in %s %s sheet %s verfügbar", cntP, Edit[Editor], PartName, Sheet); + else sprintf(InfoCnt, "%d Attribute in %s %s sheet %s", cntP, Edit[Editor], PartName, Sheet); + attmsg = "Attribute auch in Board übertragen."; + break; + case Element : if (newchange == neu) sprintf(InfoCnt, "%d Textplatzhalter in %s %s verfügbar", cntE, Edit[Editor], PartName); + else sprintf(InfoCnt, "%d Attribute in %s %s", cntE, Edit[Editor], PartName); + attmsg = "Attribute auch in Schaltplan übertragen."; + break; + } + int srt = 1; + int RESULT = dlgDialog(aType[Objekt]+" Attribute") { + dlgHBoxLayout dlgSpacing(300); + dlgLabel(InfoCnt, 1); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + switch(Editor) { + case Device : dlgListView("Attribute\tDefiniert\tWert\tVariant\tTechnologie\tOption", ListAttrib, sel, srt) { // 2013-09-02 + if (changeoption) ListAttrib[sel] = changeAttribOption(ListAttrib[sel]); // 2013-09-02 + else ListAttrib[sel] = changeAttrib(ListAttrib[sel], Objekt, newchange); + } + sprintf(InfoCnt, "DEVICE %d Attribute", cntP); + break; + case Part : dlgListView("Attribute\tDefiniert\tWert", ListAttrib, sel, srt) { + ListAttrib[sel] = changeAttrib(ListAttrib[sel], Objekt, newchange); + } + break; + case Element : dlgListView("Attribute\tDefiniert\tWert", ListAttrib, sel, srt) { + ListAttrib[sel] = changeAttrib(ListAttrib[sel], Objekt, newchange); + } + break; + } + } + + dlgHBoxLayout { + if (newchange == bearbeiten) { + dlgGroup("Alle Attribute ändern") { + if (deviceset) { + dlgHBoxLayout { + dlgRadioButton("&nein", alle_setzen); + dlgRadioButton("&ja", alle_setzen); + dlgRadioButton("&löschen", alle_setzen); + dlgStretch(1); + } + dlgLabel("


    "); + dlgHBoxLayout { + dlgPushButton("&Alle") { + if (alle_setzen < 0) dlgMessageBox("Wählen sie, nein, ja, löschen.", "OK"); + else setzealle(alle_setzen); + } + dlgPushButton("nur &Atrribute") { + if (alle_setzen < 0) dlgMessageBox("Wählen sie, nein, ja, löschen.", "OK"); + else if(sel < 0) dlgMessageBox("Wählen sie ein Atrribut (stellvertretend in einer Zeile).", "OK"); + else setze_attribut(alle_setzen, sel); + } + dlgPushButton("nur &Variant") { + if (alle_setzen < 0) dlgMessageBox("Wählen sie, nein, ja, löschen.", "OK"); + else if (sel < 0) dlgMessageBox("Wählen sie eine Variante (stellvertretend in einer Zeile).", "OK"); + else setze_variant(alle_setzen, sel); + } + dlgPushButton("nur &Technologie") { + if (alle_setzen < 0) dlgMessageBox("Wählen sie, nein, ja, löschen.", "OK"); + else if (sel < 0) dlgMessageBox("Wählen sie eine Technologie (stellvertretend in einer Zeile).", "OK"); + else setze_techno(alle_setzen, sel); + } + dlgStretch(1); + } + } + else { + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("&nein") { alle_setzen = nein; setzealle(alle_setzen); } + dlgPushButton("&ja") { alle_setzen = ja; setzealle(alle_setzen); } + dlgPushButton("&löschen") { alle_setzen = loeschen; setzealle(alle_setzen); } + dlgStretch(1); + } + } + } + dlgVBoxLayout { + dlgStretch(1); + dlgCheckBox("Change Option", changeoption); // 2013-09-02 + dlgLabel("Ändert die Option:\nconstant/variable\n(Toggle funktion)"); + } + dlgStretch(1); + } + else { + dlgGroup("Alle Attribute anlegen") { + if (deviceset) { + dlgHBoxLayout { + dlgRadioButton("&nein", alle_setzen); + dlgRadioButton("&ja", alle_setzen); + dlgRadioButton("&löschen", alle_setzen); + dlgStretch(1); + } + dlgLabel("
    "); + dlgHBoxLayout { + dlgPushButton("&Alle") { + if (alle_setzen < 0) dlgMessageBox("Wählen sie, nein, ja, löschen.", "OK"); + else setzealle(alle_setzen); + } + dlgPushButton("nur &Atrribute") { + if (alle_setzen < 0) dlgMessageBox("Wählen sie, nein, ja, löschen.", "OK"); + else if(sel < 0) dlgMessageBox("Wählen sie ein Atrribut (stellvertretend in einer Zeile).", "OK"); + else setze_attribut(alle_setzen, sel); + } + dlgPushButton("nur &Variant") { + if (alle_setzen < 0) dlgMessageBox("Wählen sie, nein, ja, löschen.", "OK"); + else if(sel < 0) dlgMessageBox("Wählen sie eine Variante (stellvertretend in einer Zeile).", "OK"); + else setze_variant(alle_setzen, sel); + } + dlgPushButton("nur &Technologie") { + if (alle_setzen < 0) dlgMessageBox("Wählen sie, nein, ja, löschen.", "OK"); + else if (sel < 0) dlgMessageBox("Wählen sie eine Technologie (stellvertretend in einer Zeile).", "OK"); + else setze_techno(alle_setzen, sel); + } + dlgStretch(1); + } + } + else { + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("&nein") { alle_setzen = nein; setzealle(alle_setzen); } + dlgPushButton("&ja") { alle_setzen = ja, setzealle(alle_setzen); } + dlgStretch(1); + } + } + } + dlgStretch(1); + } + } + dlgLabel("oder selektieren Sie ein Attribut durch Doppelklick in die Zeile."); + if (isBoard && isSchematic && Objekt != Lokal) { + dlgCheckBox(attmsg, in_brd_sch); + } + + if (Objekt == Lokal && schematic) dlgLabel("Anmerkung: Lokale Attribute die im Device definiert sind, können nicht gelöscht werden."); + dlgHBoxLayout { + dlgStretch(1); + dlgLabel(Version); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-&Zurück") { dlgReject(); clear_list(); } + dlgStretch(1); + dlgPushButton("Hilfe") hilfe(); + } + }; + return RESULT; +} + + +/************** SCHEMATIC ***************/ +void SCH_attribut_anlegen(int Type, string PartName, string PartSheet) { + cntP = 0; + cntA = 0; + int cntL = 0; + if (project.schematic) project.schematic(SCH) { + if (Type == Global) { + SCH.attributes(A) { // sammle globale Attribute + if (strstr(A.name, ReservedAttname) < 0) { // 2010-01-14 + AttribPart[cntA] = A.name; + AttribWert[cntA] = A.value; + cntA++; + } + } + SCH.parts(P) { + if (P.name == PartName) { + P.instances(I) { + I.gate.symbol.texts(T) { // sammle Platzhalter + string s = AttribT(strupr(T.value)); + if (s) { + Platzhalter[cntP] = s; + cntP++; + LPlatzhalter[cntL] = s; + cntL++; + } + } + } + Platzhalter[cntP] = ""; + } + } + } + else { + SCH.parts(P) { + if (P.name == PartName) { + cntA = 0; + P.attributes(A) { // sammle lokale Attribute + AttribPart[cntA] = A.name; + cntA++; + } + AttribPart[cntA] == ""; + P.instances(I) { + I.gate.symbol.texts(T) { // sammle Platzhalter + string s = AttribT(strupr(T.value)); + if (s) { + Platzhalter[cntP] = s; + cntP++; + LPlatzhalter[cntL] = s; + cntL++; + } + } + } + Platzhalter[cntP] = ""; + } + } + } + } + if (!cntP) { + dlgMessageBox("In "+PartName+" sind keine freien Textplatzhalter verfügbar!", "OK"); + return; + } + if (cntP) { + copyPlatzhalterList(cntL); + if (menu(Type, SCHeditor, PartName, PartSheet, neu)) generateAttribScript(Type, SCHeditor, PartName, PartSheet); + } + return; +} + + +void SCH_attribut_bearbeiten(int Type, string PartName, string Sheet) { + cntP = 0; + cntA = 0; + if (project.schematic) project.schematic(SCH) { + if (Type == Global) { + SCH.attributes(A) { // sammle globale Attribute + if (strstr(A.name, ReservedAttname) < 0) { // 2010-01-14 + ListAttrib[cntA] = A.name + "\t" + setze[ja] + "\t" + A.value; + AttribPart[cntA] = A.name; + AttribWert[cntA] = A.value; + cntA++; + } + } + Platzhalter[cntA] = ""; // letzten Platzhalter markieren + ListAttrib[cntA] = ""; + cntP = cntA; + if (cntP) { + if (menu(Type, SCHeditor, PartName, Sheet, bearbeiten)) { + generateAttribScript(Type, SCHeditor, PartName, Sheet); + } + } + else dlgMessageBox("!Keine globalen Attribute definiert!", "OK"); + } + else if (Type == Lokal) { + SCH.parts(P) { + if (P.name == PartName) { + P.attributes(A) { // sammle lokale Attribute + ListAttrib[cntA] = A.name + "\t" + setze[ja] + "\t" + A.value; + Platzhalter[cntA] = A.name; + AttribWert[cntA] = A.value; + cntA++; + } + } + } + Platzhalter[cntA] = ""; // letzten Platzhalter markieren + ListAttrib[cntA] = ""; + cntP = cntA; + if (cntP) { + if (menu(Type, SCHeditor, PartName, Sheet, bearbeiten)) generateAttribScript(Type, SCHeditor, PartName, Sheet); + } + else dlgMessageBox("In "+PartName+" sheet " + Sheet + " sind keine lokalen Attribute definiert!", "OK"); + } + } + return; +} + + +/************** BOARD ***************/ +void BRD_attribut_anlegen(int Type, string ElementName) { + cntP = 0; + cntA = 0; + cntE = 0; + if (project.board) project.board(BRD) { + BRD.attributes(A) { // sammle globale Attribute + AttribPart[cntA] = A.name; + AttribWert[cntA] = A.value; + cntA++; + } + BRD.elements(E) { + if (E.name == ElementName) { + cntA = 0; + E.attributes(A) { + AttribPart[cntA] = A.name; + cntA++; + } + AttribPart[cntA] == ""; + + E.package.texts(T) { // sammle Platzhalter + // in Packages kann es sinnvoll sein, Platzhalter mehrfach zu platzieren, + // Beispiel: Zeichnungsrahmen für Top und Bottom, wegen gespiegeltem Ausdruck. + // Hier muß überprüft werden ob eine POlattzhalter dopplet definiert ist, + // da es sonst zu doppelter Definition kommt, und die letzte Defionition + // die entscheidende ist. + string s = AttribT(strupr(T.value)); // überprüfe auf reservierte Textplatzhalter wie >NAME >VALUE >GATE ... + if (s) { + int found = 0; + for(int n = 0; n < cntP; n++) { + if (Platzhalter[n] == s) { + found = 1; + break; + } + } + if (!found) { + Platzhalter[cntP] = s; + cntP++; + LPlatzhalter[cntE] = s; + cntE++; + } + } + } + Platzhalter[cntP] = ""; + } + } + } + if (!cntP) { + dlgMessageBox("In "+ElementName+" sind keine freien Textplatzhalter verfügbar!", "OK"); + return; + } + if (cntP) { + copyPlatzhalterList(cntP); + if (menu(Type, BRDeditor, ElementName, "BRD", neu)) generateAttribScript(Type, BRDeditor, ElementName, ".BRD"); + } + return; +} + + +void BRD_attribut_bearbeiten(int Type, string ElementName) { + if (project.board) project.board(BRD) { + if (Type == Global) { + cntE = 0; + BRD.attributes(A) { // sammle globale Attribute + ListAttrib[cntE] = A.name + "\t" + setze[ja] + "\t" + A.value; + AttribPart[cntE] = A.name; + AttribWert[cntE] = A.value; + cntE++; + } + cntP = cntE; + if (!cntP) dlgMessageBox("Keine globalen Attribute definiert!", "OK"); + else { + if (menu(Type, BRDeditor, ElementName, "BRD", bearbeiten)) generateAttribScript(Type, BRDeditor, ElementName, ".BRD"); + } + } + else if (Type == Lokal) { + cntE = 0; + BRD.elements(E) { + if (ElementName == E.name) { + E.attributes(A) { // sammle lokale Attribute + ListAttrib[cntE] = A.name + "\t" + setze[ja] + "\t" + A.value; + Platzhalter[cntE] = A.name; + AttribWert[cntE] = A.value; + cntE++; + } + } + } + cntP = cntE++; + Platzhalter[cntP] = ""; // letzten Platzhalter markieren + ListAttrib[cntP] = ""; + if (cntP) { + if (menu(Type, BRDeditor, ElementName, "BRD", bearbeiten)) generateAttribScript(Type, BRDeditor, ElementName, ".BRD"); + } + else dlgMessageBox("In "+ElementName+" sind keine lokalen Attribute definiert!", "OK"); + } + } + return; +} + + +/************** DEVICE ***************/ +void DEV_attribut_bearbeiten(int Type, string PartName) { + deviceset(DS) { + getAttributeDS(DS); + if (cntA) { + if (menu(Type, DEVeditor, PartName, "DEV", bearbeiten)) generateAttribScript(Type, DEVeditor, PartName, ""); + } + else dlgMessageBox("In " + PartName + " sind keine Attribute in definiert!", "OK"); + } + return; +} + + +void DEV_attribut_anlegen(void) { + deviceset(DS) { + getTextPlatzhalterDS(DS); + if (!cntP) { + dlgMessageBox("In " + DS.name + " sind keine Textplatzhaltzer definiert,
    oder keine freien Textplatzhalter verfügbar.", "OK"); + } + else { + if (menu(Device, DEVeditor, DS.name, "DEV", neu)) generateAttribScript(Device, DEVeditor, DS.name, ""); + } + } + return; +} + + + +void generateAttribListe(string devname, string option) { + // kopiere Liste in Arbeitsliste + for (int n = 0; n < cntattributelist; n++) { + sprintf( ListAttrib[n], "%s\t%s\t", attribute_liste[n], option); + } + cntP = n; + + generateAttribScript(Lokal, DEVeditor, devname, ""); +} + + +void attributliste_sichern(void) { + output(attribute_list_datei, "wt") { + for (int n = 0; n < cntattributelist; n++) { + printf("%s\n", strupr(attribute_liste[n])); + } + } + return; +} + + +void attributliste_erweitern(void) { + string s; + dlgDialog("Attributliste bearbeiten") { + dlgHBoxLayout { + dlgLabel("Hinzufügen "); + dlgStringEdit(s); + } + dlgHBoxLayout { + dlgPushButton("+OK") { attribute_liste[cntattributelist] = strupr(s); cntattributelist++; dlgAccept(); } + dlgPushButton("-Abbruch") dlgReject(); + } + }; + return; +} + + +void attributliste_delete(int sel) { + if (sel < 0) { + dlgMessageBox("wählen Sie einen Eintrag in der Liste", "OK"); + return; + } + for (int n = sel; n < cntattributelist-1; n++) { + attribute_liste[n] = attribute_liste[n+1]; + } + cntattributelist--; + attribute_liste[cntattributelist] = ""; + return; +} + + +string attributliste_bearbeiten(string alt) { + string s = alt; + dlgDialog("Attributliste bearbeiten") { + dlgHBoxLayout { + dlgLabel("ändern "); + dlgStringEdit(s); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Abbruch") { s = alt; dlgReject(); } + } + }; + return s; +} + + +void load_list(void) { + string fg[]; + int fcnt = fileglob(fg, attribute_list_datei); + if (!fcnt) dlgMessageBox("Attributliste " + attribute_list_datei + " nicht gefunden!", "OK"); // != 0) aus_liste_anlegen(""); + else cntattributelist = fileread(attribute_liste, attribute_list_datei); + return; +} + + +void aus_liste_anlegen(string devname) { + int sel = -1; + dlgDialog("Attributliste verwalten") { + dlgLabel(attribute_list_datei); + dlgListView("Attr. Name", attribute_liste, sel) attribute_liste[sel] = strupr(attributliste_bearbeiten(attribute_liste[sel])); + // cntattributelist + dlgLabel("Listeneintrag"); + dlgHBoxLayout { + dlgPushButton("Erweitern") attributliste_erweitern(); + dlgPushButton("Löschen") attributliste_delete(sel); + dlgPushButton("Sichern") attributliste_sichern(); + dlgStretch(1); + } + dlgLabel("Attribute "); + dlgHBoxLayout { + if (devname) dlgPushButton("Anlegen") { dlgAccept(); generateAttribListe(devname, setze[ja]); } + else dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + dlgPushButton("-Abbruch") { dlgReject(); return; } + } + }; + return; +} + + +void gen_attr_sch_brd(void) { // 2008-09-10 + if (board); + else sprintf(cmd, "EDIT .brd;\n"); + for (int n = 0; n < cnt_schattr; n++) { + sprintf(s, "ATTRIBUTE * %s '%s';\n", sch_attributte[n], sch_attributteValue[n]); + cmd += s; + } + return; +} + + +void gen_attr_brd_sch(void) { + if (schematic); + else sprintf(cmd, "EDIT .sch;\n"); + for (int n = 0; n < cnt_brdattr; n++) { + sprintf(s, "ATTRIBUTE * %s '%s';\n", brd_attributte[n], brd_attributteValue[n]); + cmd += s; + } + return; +} + + +void get_diff_attr_sch(void) { + int n = 0; + if (board); + else cmd = "EDIT .brd;\n"; + do { + if (attdiff_sch[n]) { + string l[]; + int ln = strsplit(l, attdiff_sch[n], '\t'); + sprintf(s, "ATTRIBUTE * %s %s;\n", l[0], l[1]); + cmd += s; + } + n++; + } while (attdiff_sch[n]); + exit(cmd); +} + + +void get_diff_attr_brd(void) { + int n = 0; + if (schematic); + else cmd = "EDIT .sch;\n"; + do { + if (attdiff_brd[n]) { + string l[]; + int ln = strsplit(l, attdiff_brd[n], '\t'); + sprintf(s, "ATTRIBUTE * %s %s;\n", l[0], l[1]); + cmd += s; + } + n++; + } while (attdiff_brd[n]); + exit(cmd); +} + + +void get_diff_val_sch(void) { // Werte der Attribute angleichen + int n = 0; + if (schematic); + else cmd = "EDIT .sch;\n"; + do { + if (attdiff_val[n]) { + string l[]; + int ln = strsplit(l, attdiff_val[n], '\t'); + sprintf(s, "ATTRIBUTE * %s '%s';\n", l[0], l[2]); + cmd += s; + } + n++; + } while (attdiff_val[n]); + exit(cmd); +} + + +void get_diff_val_brd(void) { // Werte der Attribute angleichen + int n = 0; + if (board); + else cmd = "EDIT .brd;\n"; + do { + if (attdiff_val[n]) { + string l[]; + int ln = strsplit(l, attdiff_val[n], '\t'); + sprintf(s, "ATTRIBUTE * %s '%s';\n", l[0], l[1]); + cmd += s; + } + n++; + } while (attdiff_val[n]); + exit(cmd); +} + + +void alldevices(string setclear) { // generateAttribListe(Pname[0], setze[ja]); } + library(L) { + L.devicesets(DS) { + cmd += "EDIT "+DS.name+".DEV;\n"; + DS.devices(D) { + cmd += "PACKAGE "+D.name+";\n"; + string t[]; + int n = strsplit(t, D.technologies, ' '); + for (int tn = 0; tn < n; tn++) { + cmd += "TECHNOLOGY "+t[tn]+";\n"; + for (int a = 0; a < cntattributelist; a++) { + cmd += "ATTRIBUTE "+attribute_liste[a]+" "+setclear+";\n"; // set or delete attribute + } + } + } + } + } + exit(cmd); +} + + +string del_html_tag(string html) { // 2010-12-14 + string s[]; + string news = ""; + int cnt = strsplit(s, html, '>'); + for (int n = 0; n < cnt; n++) { + string s1[]; + strsplit(s1, s[n], '<'); + news += s1[0]; + } + return news; +} + + +string get_description(string descript) { // Kopfzeile der Description 2010-12-14 + string s[]; + strsplit(s, descript, '\n'); + return del_html_tag(s[0]); +} + + +void collect(string name) { // 2011-12-30 + int n = 0; + do { + if (DelAttrib[n] == name) return; + } while(DelAttrib[n++]); + DelAttrib[n-1] = name; + return; +} + + +string setdelatt(string att) { // 2011-12-30 + string s[]; + int cnt = strsplit(s, att, '\t'); + if (dlgMessageBox("Delete Attribute: "+ s[1], "+Yes", "-No") != 0) return s[0] + "\t"; + return s[0]+"\tDELETE"; +} + + +void DEV_attribut_delete(void) { // 2011-12-30 + int n = 0; + while(DelAttrib[n]) { // reset liste + DelAttrib[n] = ""; + n++; + }; + string fs; + library(L) { + fs = filesetext(L.name, "~del-attribute~.scr"); + // collect attributes + L.devicesets(DS) { + DS.devices(D) { + string t[]; + int n = strsplit(t, D.technologies, ' '); + for (int i = 0; i < n; i++) { + D.attributes(A, t[i]) { + collect(A.name); + } + } + } + } + + int sel; + dlgDialog("Delete Attributes") { + dlgListView("Attribute-Name\tDelete", DelAttrib, sel) { + DelAttrib[sel] = setdelatt(DelAttrib[sel]); + } + dlgHBoxLayout { + dlgPushButton("ok") dlgAccept(); + dlgPushButton("-esc") { dlgReject(); exit(-3); } + } + }; + cmd = ""; + L.devicesets(DS) { + cmd += "EDIT "+DS.name+".DEV;\n"; + DS.devices(D) { + cmd += "PACKAGE "+D.name+";\n"; + string t[]; + int n = strsplit(t, D.technologies, ' '); + cmd += "TECHNOLOGY " + t[0] + ";\n"; + D.attributes(A, t[0]) { /******* nur eine Technologie behandeln, ******** + ******* alle Technologien haben die gleichen Attribute ********/ + string actattribute = A.name; + sel = 0; + do { + string s[]; + strsplit(s, DelAttrib[sel], '\t'); + if (s[0] == actattribute && s[1] == "DELETE") { + cmd += "ATTRIBUTE " + s[0] + " " + s[1] + ";\n"; + } + } while(DelAttrib[sel++]); + } + } + } + } + /* + dlgDialog("test") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+ok") dlgAccept(); + dlgPushButton("-esc") {dlgReject(); exit(-1160); } + } + }; + */ + output(fs, "wtD") printf("%s", cmd); + exit("SCRIPT '"+fs+"'"); +} + + +// ======== main ======== // +if (schematic || deviceset || board) { + int npart = 0; + int nelement = 0; + + if (project.schematic) { + isSchematic = 1; + project.schematic(SCH) { + int actualsheet = 0; + SCH.parts(P) { + Pname[npart] = P.name; + P.instances(I) { + sprintf(Psheet[npart], ".s%d", I.sheet); + if (argv[1] == "1DESCRIPTION") { // 2010-12-14 + if (P.device.package) { + sprintf(Description1[npart], "%s", get_description(P.device.description) ); + if (actualsheet != I.sheet) { + actualsheet = I.sheet; + sprintf(s, "EDIT .S%d;\n", I.sheet); + cmd += s; + } + sprintf(s, "CHANGE DISPLAY OFF; ATTRIBUTE %s A_DESCRIPTION '%s';\n", P.name, Description1[npart]); + if (dlgMessageBox(s, "ok", "esc") != 0) exit(-1101); + cmd += s; + } + } + break; + } + npart++; + } + SCH.attributes(A) { + sch_attributte[cnt_schattr] = A.name; + sch_attributteValue[cnt_schattr] = A.value; + cnt_schattr++; + } + if (argv[1] == "1DESCRIPTION") exit(cmd); // 2010-12-14 + } + } + if (project.board) { + isBoard = 1; + project.board(BRD) { + BRD.elements(E) { + Ename[nelement] = E.name; + nelement++; + } + BRD.attributes(A) { + brd_attributte[cnt_brdattr] = A.name; + brd_attributteValue[cnt_brdattr] = A.value; + cnt_brdattr++; + } + } + } + if (deviceset) { + deviceset(DS) { + Pname[0] = DS.name; + npart = 1; + } + if (argv[1] == "+L") { load_list(); if (!cntattributelist) aus_liste_anlegen(""); generateAttribListe(Pname[0], setze[ja]); } + if (argv[1] == "-L") { load_list(); if (!cntattributelist) aus_liste_anlegen(""); generateAttribListe(Pname[0], setze[loeschen]); } + if (argv[1] == "+A") { load_list(); if (!cntattributelist) aus_liste_anlegen(""); alldevices(""); } // 2010-08-17 alf@cadsoft.de + if (argv[1] == "-A") { load_list(); if (!cntattributelist) aus_liste_anlegen(""); alldevices("DELETE"); } + } + int psel = -1; + int esel = -1; + if (deviceset) psel = 0; + int Result; + string statsch, statbrd, statusdif; + sprintf(statsch, "%d Part(s) in SCH gefunden", npart); + sprintf(statbrd, "%d Element(s) in BRD gefunden", nelement); + + if (isBoard && isSchematic) { + if (diff_attr_sch_brd(0)) sprintf(statusdif, "In Schematic und Board sind unterschiedliche globale Attribute definiert."); + } + + // ======== Haupt-Menu ======== // + Result = dlgDialog("Attributverwaltung") { + int atttype = -1; + dlgHBoxLayout { // --------------------- + if (deviceset) { + dlgVBoxLayout { + dlgGroup("Attribute") { + dlgLabel("LOKALE"); + dlgHBoxLayout { + dlgPushButton("&Anlegen") DEV_attribut_anlegen(); + dlgLabel(" aus Textplatzhalter in Symbolen."); + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("An&legen") { load_list(); aus_liste_anlegen(Pname[0]); } + dlgLabel(" aus definierter Liste."); + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("&Bearbeiten") DEV_attribut_bearbeiten(Lokal, Pname[psel]); + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("&Löschen") DEV_attribut_delete(); + dlgStretch(1); + } + } + dlgStretch(1); + } + } + else { + dlgTabWidget { + if (isSchematic) { + dlgTabPage("Schematic") { // ######## Schaltplan ################# + dlgVBoxLayout { + dlgGroup("Attribute") { + dlgLabel("LOKALE"); + dlgHBoxLayout { + dlgPushButton("an&legen") { + if (psel < 0) dlgMessageBox("Wählen sie ein Part aus der Liste!", "OK"); + else if (psel >= 0) SCH_attribut_anlegen(Lokal, Pname[psel], Psheet[psel]); + } + dlgStretch(1); + dlgLabel(" nur def. Textplatzhalter"); + } + dlgHBoxLayout { + dlgPushButton("b&earbeiten") { + if (psel < 0) dlgMessageBox("Wählen sie ein Part aus der Liste!", "OK"); + else if (psel >= 0) SCH_attribut_bearbeiten(Lokal, Pname[psel], Psheet[psel]); + } + dlgStretch(1); + } + dlgLabel("
    "); + dlgLabel("GLOBALE"); + dlgHBoxLayout { + dlgPushButton("&anlegen") { + if (psel < 0) dlgMessageBox("Wählen sie ein Part aus der Liste!", "OK"); + else if(psel >= 0) SCH_attribut_anlegen(Global, Pname[psel], ".SCH"); + } + dlgStretch(1); + dlgLabel(" nur def. Textplatzhalter"); + } + dlgHBoxLayout { + dlgPushButton("&bearbeiten") { + SCH_attribut_bearbeiten(Global, "*", ".SCH"); + } + dlgStretch(1); + } + } + } + dlgListView("Part", Pname, psel); + dlgLabel(statsch); + } + } + if (isBoard) { + dlgTabPage("Board") { // ######## Layout ################# + dlgVBoxLayout { + dlgGroup("Attribute") { + dlgLabel("LOKALE"); + dlgHBoxLayout { + dlgPushButton("anlegen") { + if (esel < 0) dlgMessageBox("Wählen sie ein Element aus der Liste!", "OK"); + else BRD_attribut_anlegen(Lokal, Ename[esel]); + } + dlgStretch(1); + dlgLabel(" nur def. Textplatzhalter"); + } + dlgHBoxLayout { + dlgPushButton("bearbeiten") { + if (esel < 0) dlgMessageBox("Wählen sie ein Element aus der Liste!", "OK"); + else BRD_attribut_bearbeiten(Lokal, Ename[esel]); + } + dlgStretch(1); + } + dlgLabel("
    "); + dlgLabel("GLOBALE"); + dlgHBoxLayout { + dlgPushButton("anlegen") { + if (esel < 0) dlgMessageBox("Wählen sie ein Element aus der Liste!", "OK"); + else BRD_attribut_anlegen(Global, Ename[esel]); + } + dlgStretch(1); + dlgLabel(" nur def. Textplatzhalter"); + } + dlgHBoxLayout { + dlgPushButton("bearbeiten") BRD_attribut_bearbeiten(Global, "*"); + dlgStretch(1); + } + } + } + dlgVBoxLayout { + dlgListView("Element", Ename, esel); + dlgLabel(statbrd); + } + } + } + } + } + if (statusdif) { + dlgVBoxLayout { + dlgLabel(statusdif); + dlgHBoxLayout { + int globatt = -1; // 2008-09-10 + int assel, absel; + if (isSchematic && isBoard) { + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel("Schematic"); + dlgListView("Attributte", sch_attributte, assel); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("SCH >>") gen_attr_sch_brd(); + } + } + dlgVBoxLayout { + dlgLabel("Board"); + dlgListView("Attributte", brd_attributte, absel); + dlgHBoxLayout { + dlgPushButton("<< BRD") gen_attr_brd_sch(); + dlgStretch(1); + } + } + } + } + } + } + } + // Unterschiede ------------------------------------------------ + if (cntdiffval || statusdif) { + int ssel, bsel, dsel; + dlgVBoxLayout { + dlgLabel(" "); + dlgGroup("Unterschiede") { + if (statusdif) { + dlgHBoxLayout { + dlgVBoxLayout { + dlgListView("nicht im BRD\tValue", attdiff_sch, ssel); + dlgHBoxLayout { + dlgPushButton("in BRD übertragen") { + get_diff_attr_sch(); + exit(cmd); + } + dlgStretch(1); + } + } + dlgVBoxLayout { + dlgListView("nicht im SCH\tValue", attdiff_brd, bsel); + dlgHBoxLayout { + dlgPushButton("in SCH übertragen") { + get_diff_attr_brd(); + exit(cmd); + } + dlgStretch(1); + } + } + } + } + if (cntdiffval) { + dlgLabel("Values"); + dlgListView("Attributt\tSCH\tBRD", attdiff_val, dsel); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("SCH >>> BRD") { + get_diff_val_brd(); + exit(cmd); + } + dlgPushButton("SCH <<< BRD") { + get_diff_val_sch(); + exit(cmd); + } + dlgStretch(1); + } + } + } + } + } + } + dlgHBoxLayout { + dlgStretch(1); + dlgLabel(Version); + } + dlgSpacing(8); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Abbruch") dlgReject(); + dlgStretch(1); + dlgPushButton("Hilfe") dlgMessageBox(usage, "OK"); + } + }; +} + +else dlgMessageBox("Starten Sie das ULP in einem Schaltplan, Board oder Device (Bibliothek).", "OK"); diff --git a/trunk/ulp/e-bauteil-erstellen.ulp b/trunk/ulp/e-bauteil-erstellen.ulp new file mode 100644 index 00000000..9950c857 --- /dev/null +++ b/trunk/ulp/e-bauteil-erstellen.ulp @@ -0,0 +1,453 @@ +#require 5.0000 +#usage "Bequemes Definieren von Bauteilen, insbesondere von Schützen\n" + "

    " + "Starten Sie das Programm vom Bibliothekseditor aus." + "

    " + "Sie können damit aus vorhandenen Symbolen ein fertiges Device mit " + "Dummy-Package erzeugen. Die Pad-Namen des Package lassen sich editieren. " + "Das ist deshalb wichtig, weil in den Devices der Elektro-Bibliotheken nicht die " + "Symbol-Pin-Namen, sondern die Package-Pad-Namen angezeigt werden." + "

    " + "Das Programm erzeugt eine temporäre Script-Datei im ersten SCR-Pfad, die " + "nach Drücken des OK-Buttons sofort ausgeführt wird. Die Datei wird gelöscht, " + "sobald EAGLE beendet wird.

    " + "Author: support@cadsoft.de" + +string Version = "1.0.1"; // 2010-06-08 alf@cadsoft.de + +numeric string PinCount[], PinNames[], SymName[]; +numeric string Lines[], DevLines[]; +numeric string DevRang[], DevPinCount[], DevPinNames[], DevSymName[]; +numeric string s; +int NumAllPins = 0, NumSyms = 0; +int Selected, SelectedDev = -1; +int OutputFormat = 1; +int SymDisplay = 1; +int RangDev = 0; +string NewDeviceName = ""; +string DeviceDescription = ""; +string MakePackCmd, MakeDevCmd; +string DevicePrefix = ""; +string DevPinNamesAll = ""; +string f; +// Benutzerspezifische Einstellungen +int PadOffset = 100; +int SpulenOffset = -400; +int XrefOffset = 200; +int ZeicheSymbolOffset = -500; + +// + +string HelpAllgemein = +"Bauteil (Device) für Elektro-Pläne erstellen

    " +"Wählen Sie im Bereich Symbolauswahl-Filter, welche Symbolart in der oberen Liste dargestellt " +"werden soll. Ein Doppelklick auf einen Listeneintrag fügt dieses Symbol in die Device-Liste " +"ein.

    " +"Wenn Sie ein Schütz entwerfen, wählen Sie zuerst eine Spule, dann die Kontakte und danach " +"eventuell Zusatzsymbole ohne Kontakte. Das ganze Bauteil wird in dieser Reihenfolge im Schaltplan " +"dargestellt. Die Reihenfolge ist wichtig, damit der Kontaktspiegel richtig dargestellt wird.
    " +"Das erste GATE erhält den Addlevel Must, und nur unter diesem Must-Gate wird der Kontaktspiegerl erzeugt.

    " +"Die Zusatzsymbole werden nur auf Anforderung (mit INVOKE) in den Schaltplan geholt.

    " +"Danach können Sie nach Anklicken des entsprechenden Buttons die Kontaktnamen editieren.

    " +"Nach OK entsteht das Bauteil in der geladenen Bibliothek. Vergessen Sie nicht, sie danach abzuspeichern.

    " +"Wenn Sie Bauteile ohne Kontaktspiegel entwerfen wollen, selektieren Sie Alle Symbole und " +"übertragen Sie die Symbole in die Device-Liste, die nicht mit _KS (Kontaktspiegel) enden.
    " +; + +void ShowHelp(void) { + dlgDialog("Hilfe") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(300); + dlgVBoxLayout { + dlgLabel("&Hilfe"); + dlgTextView(HelpAllgemein); + } + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; +} + +string HelpTextKontaktnamen = +"Tragen Sie die gewünschten Kontaktnamen durch Leerzeichen getrennt ein und kontrollieren Sie \ +die Namen in der Listenansicht.\n\ +Reihenfolge: links oben, links unten (Spule), erster Kontakt oben, erster Kontakt unten etc."; + +string ErrorCorrectNames = +"Kontaktamen nicht korrekt oder kein Device-Listen-Eintrag!\n" +"Jeder Kontaktname darf nur einmal vorkommen, und die Anzahl \n" +"der Namen muss der Anzahl der Pins entsprechen.\n"; + + +// Debug-Routinen +string DebugString = ""; + +void DebugInt(string name, int n) { + string s; + sprintf(s, name + " %d\n", n); + DebugString += s; + return; +} + +void DebugStr(string name, string v) { + DebugString += name + " " + v +"\n"; + return; +} + +void ShowInteger(string v, int n) { + string s; + sprintf(s, "%d", n); + dlgMessageBox(v + ": " + s); + return; +} + +void ShowString(string label, string v) { + dlgMessageBox(label + ": " + v); + return; +} + +// ----------------------------------------------------------------------------- +string StripWhiteSpace(string s) { // mit Zusatz: Doppel-Blanks im Inneren werden 1 Blank + int i, n; + string t; + + while (s && isspace(s[0])) + s = strsub(s, 1); + while (s && isspace(s[strlen(s) - 1])) + s = strsub(s, 0, strlen(s) - 1); + // Doppel-Blanks + for (i = 0; i < strlen(s); i++) { + if (!isspace(s[i])) t[n++] = s[i]; + else { + if ((strlen(s) > i+1) && isspace(s[i+1])); + else t[n++] = s[i]; + }; + } + s = t; + return s; +} + +// Erzeuge Symbolauswahlliste +void MakeSymSelectList(void) { + int NumLines = 0; + int NrOfPins = 0; + int Xref = 0; + string PNam; + NrOfPins = 0; + + library(L) { + f = filename(L.name); + f = filesetext(f, "$$$.scr"); + f = path_scr[0] + '/' + f; // verwende Script-Pfad + L.symbols(S) { + NrOfPins = 0; + Xref = 0; + PinCount[NumLines] = ""; + PinNames[NumLines] = ""; + SymName[NumLines] = S.name; + S.texts(T) { + if (T.value == ">XREF") Xref++; + } + S.pins(P) { + NrOfPins++; + PinNames[NumLines] += StripWhiteSpace(P.name) + " "; + sprintf(PinCount[NumLines], "%d", NrOfPins); + PNam = P.name; + } + if ((strstr(S.name, "SPULE") >= 0) && SymDisplay == 0) { + Lines[NumLines++] = PinCount[NumLines] + // Spulen + "\t" + PinNames[NumLines] + + "\t" + SymName[NumLines]; + } + if (strstr(S.name, "_KS", strlen(S.name) - 3) >= 0) { // nur wenn Symbolname auf xxxx_KS endet + if (NrOfPins && SymDisplay == 1 && strstr(S.name, "SPULE") == -1 && strstr(PNam, "_") == -1) { + Lines[NumLines++] = PinCount[NumLines] + // Hauptkontakte + "\t" + PinNames[NumLines] + + "\t" + SymName[NumLines]; + } + if (NrOfPins && SymDisplay == 2 && strstr(S.name, "SPULE") == -1 && strstr(PNam, "_") == 0) { + Lines[NumLines++] = PinCount[NumLines] + // Hilfskontakte + "\t" + PinNames[NumLines] + + "\t" + SymName[NumLines]; + } + } + if (!NrOfPins && !Xref && SymDisplay == 3) { // Symbole ohne Kontakte + Lines[NumLines++] = PinCount[NumLines] + + "\t" + PinNames[NumLines] + + "\t" + SymName[NumLines]; + } + if (SymDisplay == 4) { // Symbole ohne Kontakte + Lines[NumLines++] = PinCount[NumLines] + + "\t" + PinNames[NumLines] + + "\t" + SymName[NumLines]; + } + Lines[NumLines] = ""; + } + } + return; +} + + +// Übertrage gewähltes Symbol in Symbolliste +void SymEntry(void) { // Selected liefert aus ListView gewählten Symbol-Index + numeric string Rang; + + RangDev++; + sprintf(Rang, "%d", RangDev); + + DevRang[NumSyms] = Rang; + DevPinCount[NumSyms] = PinCount[Selected]; + DevPinNames[NumSyms] = PinNames[Selected]; + DevSymName[NumSyms] = SymName[Selected]; + + DevLines[NumSyms++] = Rang + + "\t" + PinCount[Selected] + + "\t" + PinNames[Selected] + + "\t" + SymName[Selected]; + + NumAllPins += strtol(PinCount[Selected]); + + DevPinNamesAll += " " + PinNames[Selected]; + DevPinNamesAll = StripWhiteSpace(DevPinNamesAll); + return; +} + +void ClearDevList(void) { + int i; + for (i = 0; i <= NumSyms; i++) { + DevLines[i] = ""; + } + NumSyms = 0; + RangDev = 0; + NumAllPins = 0; + MakeDevCmd = ""; + DevPinNamesAll = ""; + return; +} + +// int ValidSymName(string symname) { +// if (symname == "") return 0; +// library(L) { // Symbol-Name schon vorhanden? +// L.symbols(S) { +// if (strupr(symname) == S.name) return 0; +// } +// } +// return 1; +// } + +string GetPinName(int PinIndex) { // Pin-Namen aus Listeneintrag extr., PinIndex 0... + string Pnames[]; + strsplit(Pnames, DevPinNamesAll, ' '); + return Pnames[PinIndex]; +} + +int CorrectContactNames(void) { // Anzeige der Kontaktnamen aktualisieren + int i, j, n; + string pn = ""; // temp. Pin-Namen-String für 1 Symbol + string a[]; + + DevPinNamesAll = StripWhiteSpace(DevPinNamesAll); + + // Prüfe Zahl der Pins + if (strsplit(a, DevPinNamesAll, ' ') != NumAllPins) return 0; + + // Prüfe Doppelnamen + if (NumAllPins > 1) { + while (i < NumAllPins) { + j = i + 1; + while (j < NumAllPins) { + if (a[i] == a[j++]) return 0; + } + i++; + } + } + for (j = 0; j < NumSyms; j++) { + pn = ""; + for (i = 0; i < strtol(DevPinCount[j]); i++) { + pn += " " + GetPinName(n++); + } + pn = StripWhiteSpace(pn); + DevPinNames[j] = pn; + DevLines[j] = DevRang[j] + + "\t" + DevPinCount[j] + + "\t" + pn + + "\t" + DevSymName[j]; + } + return 1; +} + +int OkToClose(void) { + if (!CorrectContactNames()) { + dlgMessageBox(ErrorCorrectNames); + return 0; + } + library(L) { // Device-Name schon vorhanden? + L.devicesets(D) { + if (strupr(NewDeviceName) == D.name) { + dlgMessageBox("Bitte wählen Sie einen anderen Namen\n (Device schon vorhanden)!\n"); + return 0; + } + } + L.packages(P) { + if (strupr(NewDeviceName) == P.name) { + dlgMessageBox("Bitte wählen Sie einen anderen Namen\n (Package schon vorhanden)!\n"); + return 0; + } + } + } + if (NewDeviceName == "" || !NumSyms) { + dlgMessageBox("Das Bauteil kann nur erzeugt werden, wenn Sie einen Namen eingeben\n und mindestens ein Symbol in der Device-Liste steht!"); + return 0; + } + else return 1; +} + +string GetPinNameFromLbr(string Sname, int i) { // Pinname, i-ter Pin + string pn = ""; + int n; + library(L) { + L.symbols(S) { + if (S.name == Sname) { + n = 0; + S.pins(P) { + if (i == n++) { + pn = P.name; + return pn; + } + } + } + } + } + return ""; +} + +void GenerateDevice(void) { + string s; + int i, j, k; + int XOffset = 0; // virtuelle Y-Nulllinie: rechts daneben wird nächster Kontakt platziert + int SymOffset; + int CoordY; + // Erzeuge Device-Befehle + MakeDevCmd += "edit " + NewDeviceName + ".dev;\n"; + MakeDevCmd += "value on;\n"; + MakeDevCmd += "grid mil 100 on;\n"; + MakeDevCmd += "prefix '" + DevicePrefix + "';\n"; + MakeDevCmd += "description '" + DeviceDescription + "';\n"; + MakeDevCmd += "package '" + NewDeviceName + "';\n"; + sprintf(s, "add '%s' R0 must 0 (%d %d);\n", DevSymName[0], SpulenOffset, XrefOffset); + MakeDevCmd += s; + for (i = 1; i < NumSyms; i++) { + if (strtol(DevPinCount[i]) >= 9) SymOffset = 600; + if (strtol(DevPinCount[i]) < 9) SymOffset = 400; + if (strtol(DevPinCount[i]) < 7) SymOffset = 300; + if (strtol(DevPinCount[i]) < 5) SymOffset = 200; + if (strtol(DevPinCount[i]) < 3) SymOffset = 100; // Abstand zwischen Einzelkontaktsymbolen, mil + + if (strtol(DevPinCount[i])) { // Symbol mit Pins, rechts der Reihe nach platzieren + sprintf(s, "add '%s' R0 next 0 (%d %d);\n", DevSymName[i], XOffset + SymOffset, XrefOffset); + } + else { // Symbol ohne Pins, unter Spule aufeinander platzieren + sprintf(s, "add '%s' R0 can 0 (%d %d);\n", DevSymName[i], SpulenOffset, ZeicheSymbolOffset + SymOffset); + } + + MakeDevCmd += s; + XOffset += 2 * SymOffset; + } + + // Erzeuge Connect-Befehle + i = 0; + while (DevSymName[i]) { + j = 0; + while (GetPinNameFromLbr(DevSymName[i], j) != "") { + if (GetPinName(k)) { + sprintf(s, "connect 'G$%d.%s' '%s';\n", i+1 , GetPinNameFromLbr(DevSymName[i], j++), GetPinName(k++)); + MakeDevCmd += s; + } + } + i++; + } + +//MakeDevCmd += "value on;\n"; + MakeDevCmd += "grid last;\n"; + + // Erzeuge Package-Befehle + MakePackCmd = "edit " + NewDeviceName + ".pac;\n"; + MakePackCmd += "grid mil 100 on;\n"; + for (i = 0; i < NumAllPins; i++) { + CoordY = i * PadOffset; + sprintf(s, "pad '%s' (%d 0);\n", GetPinName(i), CoordY); + MakePackCmd += s; + } + + MakePackCmd += "grid last;\n"; + +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + // Ausgabe zuerst in Script-Datei, dann SCRIPT-Befehl ausführen + s = MakePackCmd + MakeDevCmd; + output(f, "wtD") printf("%s", s); // temporäre Script-Datei erzeugen + exit("SCRIPT '"+ f +"';"); +//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + } + +void EditSymParams(void) { + string a[]; + + dlgDialog("Kontaktnamen editieren") { + dlgHBoxLayout { + dlgLabel("Kontaktnamen"); + dlgStringEdit(DevPinNamesAll); + } + dlgHBoxLayout { + dlgPushButton("&Hilfe") dlgMessageBox(HelpTextKontaktnamen); + dlgPushButton("-Abbrechen") dlgReject(); + dlgPushButton("+OK") if (CorrectContactNames()) dlgAccept(); + else dlgMessageBox(ErrorCorrectNames); + } + }; +} + +//*************************************************************** +SymDisplay = 0; +MakeSymSelectList(); + +dlgDialog("Erzeuge Device") { + dlgLabel("Symbolauswahlliste"); + dlgListView("Pins\tPin-Namen\tSymbol-Name", Lines, Selected) SymEntry(); + dlgLabel("Device-Liste"); + dlgListView("Rang\tPins\tKontakt-Namen\tSymbol-Name", DevLines, SelectedDev); + dlgHBoxLayout { + dlgGroup("Symbolauswahl-Filter") { + dlgRadioButton("Spulen", SymDisplay) MakeSymSelectList(); + dlgRadioButton("Hauptkontakte mit Kontaktspiegel", SymDisplay) MakeSymSelectList(); + dlgRadioButton("Hilfskontakte mit Kontaktspiegel", SymDisplay) MakeSymSelectList(); + dlgRadioButton("Symbole ohne Kontakte", SymDisplay) MakeSymSelectList(); + dlgRadioButton("Alle Symbole", SymDisplay) MakeSymSelectList(); + } + dlgGroup("Device-Parameter") { + dlgHBoxLayout { + dlgLabel("&Device-Name"); + dlgStringEdit(NewDeviceName); + } + dlgHBoxLayout { + dlgLabel("&Bauteil-Prefix "); + dlgStringEdit(DevicePrefix); + } + dlgHBoxLayout { + dlgLabel("&Beschreibung"); + dlgStringEdit(DeviceDescription); + } + } + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("&Hilfe") ShowHelp(); + dlgPushButton("&Device-Liste löschen") ClearDevList(); + dlgPushButton("&Kontaktnamen ändern") EditSymParams(); + dlgPushButton("-Abbrechen") dlgReject(); + dlgPushButton("+OK") if (OkToClose()) GenerateDevice(); + } + }; diff --git a/trunk/ulp/e-brueckenverwaltung.ulp b/trunk/ulp/e-brueckenverwaltung.ulp new file mode 100644 index 00000000..d15198ad --- /dev/null +++ b/trunk/ulp/e-brueckenverwaltung.ulp @@ -0,0 +1,934 @@ +#usage "Brückenklemmen-Verwaltung: Brücken eintragen und ändern\n

    " +"Brückenklemmen sind Bauteile mit Einzelklemmen, die jeweils zwei Kontakte " +"mit Anschlussmöglichkeit für Drähte haben. Zusätzlich können die Klemmen " +"untereinander mit gesteckten Brückenkämmen o.ä. verbunden werden. Mit diesem " +"User-Language-Programm (ULP) definieren Sie auf bequeme Weise, welche Klemmen " +"innerhalb eines Klemmenblocks gebrückt werden sollen. Die Brückendefinitionen " +"werden als Liste in einer Datei (schaltungsname.brk) ausgegeben. Außerdem " +"wird eine Log-Datei (schaltungsname.log) angelegt, aus der mögliche Probleme " +"hervorgehen. Die Log-Datei wird gelöscht, nachem die EAGLE-Sitzung beendet ist.

    " +"Die erzeugte Liste (schaltungsname.brk) kann in einem Tabellenkalkulationsprogramm " +"weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die " +"Schaltungszeichnung importiert werden.

    " +"Author: support@cadsoft.de" + +// Verwaltung von Brückenklemmen (nur für Devices KLEMME*BRUECKE in Bibliothek e-klemmen.lbr) +// rudi hofer +// Gate-Namen der Brücken-Devices müssen alphabetisch so geordnet sein, dass ihre Pins +// der Reihe nach 1.x, 2.x etc. sind + +// todo +// Anzeigen, welcher Klemmenblock gerade bearbeitet wird + +string Version = "Version 1.02"; + +// History +// 1.01 -- 2009-10-01 nicht benötigte "\t\t" in Kopfzeilen von dlgDialog() entfernt +// 1.02 -- 2013-10-02 sheet aus der Instance, nicht über SCH.sheets() +// die Sheet-Nummer entspr. jetzt der Klemme mit Space getrennt, +// und mit TAB von den Klemmen selbst. + +#require 6.0500 + + +///////////////////////////////////////////////////////////////////////////////// +// Vom Benutzer zu ändern: +// Wenn verdrahteten Verbindungen keine Verweise bekommen sollen, setzen Sie den +// Wert für ExcludeDrahtverbindungen in der folgenden Zeile auf 1; +int ExcludeDrahtverbindungen = 0; +///////////////////////////////////////////////////////////////////////////////// + +string s, cmd, f, LogCmd, DoCmd, ListCmd; +string PartDatabase[], CurrentPart; +numeric string ChangeString, SheetsUsedInEdit[]; +int maxklemmen, LogOn, ErrOn, CurrentPartIndex; + +string scrfile, listfile, errorfile, pinfile, vbdfile, klpfile, kapfile, brpfile, pfad; +numeric string sh, PartPin, SigName, col, row, PartName, PinName; +numeric string pindatabase[], b[]; +string PartPinSep = " "; +int YRef[]; +int distY, netnr, n, i; +// Debug +string DebugString; +// Variablen für main +int SelAll = -1, SelConnected = -1, Sort = 0, SortAll = 0, NrLinesListAll; +numeric string ListAll[], ListAllSheet[], ListSel[], ListUndo[]; //, ListUndoOben[]; +string h[]; +// Header-Variablen ------------------------------------------------------------------------------------------- +string head [], SelParam[], ChangeParam[]; +int NrHeader; // Zahl der Rubriken +// head [] enthält ListHeader-Einträge: +// head[Draehte].. v +enum {Draehte, Bruecken}; +numeric string ListHeader = "Drähte \tBrücken"; + +enum {Name, Anz, Verwendet, Verdrahtet}; +numeric string ListHeaderMain = "Name\tAnz.\tVerwendet\tVerdrahtet"; +// Ende Header-Variablen -------------------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////////////////////////// +string HelpText = + + +"Brückenklemmen-Verwaltung: Brücken eintragen und ändern

    " + +"Brückenklemmen sind Bauteile mit Einzelklemmen, die jeweils zwei Kontakte " +"mit Anschlussmöglichkeit für Drähte haben. Zusätzlich können die Klemmen " +"untereinander mit gesteckten Brückenkämmen o.ä. verbunden werden. Mit diesem " +"User-Language-Programm (ULP) definieren Sie auf bequeme Weise, welche Klemmen " +"innerhalb eines Klemmenblocks gebrückt werden sollen. Die Brückendefinitionen " +"werden als Liste in einer Datei (schaltungsname.brk) ausgegeben. Außerdem " +"wird eine Log-Datei (schaltungsname.log) angelegt, aus der mögliche Probleme " +"hervorgehen. Die Log-Datei wird gelöscht, nachem die EAGLE-Sitzung beendet ist.
    " +"Die erzeugte Liste (schaltungsname.brk) kann in einem Tabellenkalkulationsprogramm " +"weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die " +"Schaltungszeichnung importiert werden.

    " + +"Klemmenbibliothek

    " + +"Dieses Programm berücksichtigt nur Brückenklemmen, wie sie in der " +"Bibliothek e-klemmen.lbr unter den Device-Namen KLEMME*BRUECKE definiert sind. " +"In der Schaltung muss der Bauteilname mit X beginnen, und in der Bibliothek " +"muss der Namensbestandteil BRUECKE vorhanden sein. " +"In der Bibliothek e-klemmen.lbr befinden sich vordefinierte Brückenklemmen. " +"Bitte lesen Sie die Bibliotheksbeschreibung (z.B. im Control-Panel), wenn Sie " +"eigene Brückenklemmen definieren wollen.

    " + +"Prinzip

    " + +"Klemmen werden behandelt, wie jedes andere Bauteil auch: Kontakte, die mit " +"anderen verbunden sind, erscheinen im Klemmenplan. Eine Verbindung entsteht, " +"wenn die Kontakte über eine Netzlinie verbunden sind oder wenn an den Kontakten " +"jeweils ein Netz mit gleichem Namen hängt. Letzteres ist insbesondere dann " +"der Fall, wenn Kontakte auf unterschiedlichen Schaltplanseiten verbunden sind.

    " + +"Brückenklemmen bieten darüber hinaus eine weitere Möglichkeit, Verbindungen " +"innerhalb desselben Klemmenblocks zu definieren. Man bringt einen " +"Verweis (Referenz) im Brückenklemmen-Symbol an, der auf die vorherige bzw. nächste " +"Klemme zeigt, mit der die Klemme verbunden werden soll. Damit vermeidet man ein " +"Wirrwarr von gezeichneten Brücken bei größeren Plänen. Die Verweise verwenden " +"Attribute, die in der Bibliothek festgelegt sind. Der Benutzer hat damit aber " +"nichts zu tun, solange er für die Definition der Brücken dieses ULP verwendet.

    " + +"Was steht im Klemmenplan und im Brückenplan?

    " + +"Der Klemmenplan stellt alle Draht- und Kabelverbindungen in einer Liste dar. " +"Der Brückenplan enthält die (üblicherweise mit Brückenkämmen ausgeführten) " +"Verbindungen innerhalb eines Klemmenblocks, die mit Hilfe dieses Programms " +"erstellt wurden.

    " + +"Werden Kontakte eines Brückenklemmenblocks über ein Netz verbunden, erscheint diese " +"Verbindung im Klemmenplan als Drahtverbindung. Sie sollten das dann tun, wenn " +"Sie darauf hinweisen wollen, dass hier tatsächlich ein Draht von einer Klemme " +"zur anderen verlegt werden soll.

    " + +"Werden Kontakte eines Brückenklemmenblocks über Klemmen-Referenzen (mit diesem " +"Programm) verbunden, erscheint diese Verbindung im Brückenplan (ebenso wie " +"Verbindungen zwischen unterschiedlichen Klemmenblöcken, etwa eine Klemme " +"von X1 mit einer von X2).

    " + +"Falls Kontakte auf beide Arten verbunden sind (was keinen Sinn macht), " +"erscheinen sie im Klemmenplan und im Brückenplan.

    " + +"Wie werden Brücken im Stromlaufplan dargestellt?

    " + +"Im Brückenklemmen-Symbol weisen (maximal) zwei Zahlen auf die nächsten Klemmen hin, " +"mit denen es verbunden ist. Da Referenzverbindungen nicht über die Draht-Anschlüsse " +"realisiert werden, erscheint als Referenz nicht der jeweilige Kontaktname " +"(1.1, 1.2 etc.), sondern die Klemmennummer (1, 2, 3 etc.). Klemme 5 etwa " +"ist die Klemme mit den Kontakten 5.1 und 5.2.

    " + +"Beispiel: In einem Block mit sechs Einzelklemmen, sollen die Klemmen 1, 3 und 5 " +"miteinander verbunden sein: Klemme 1 verweist auf 3, Klemme 3 verweist auf 1 und 5, " +"und Klemme 5 verweist auf Klemme 3.

    " + +"Bedienung

    " + +"In jeder Programmsitzung können Sie nur die Brücken eines Klemmenblocks (also etwa X1) " +"bearbeiten.

    " + +"Typischer Ablauf einer Programmsitzung:

    " + +"Log-Datei: Dieser Button öffnet ein Textfenster, in dem Sie die vorhandenen " +"Draht- und Referenz-Brücken sowie Warnungen zu eventuellen Fehlern finden.

    " + +"Doppelklick auf obere Liste: Wählen Sie den zu bearbeitenden Klemmenblock. " +"Dargestellt sind die Anzahl und die Nummern der in der Schaltung platzierten " +"Klemmen sowie die Klemmen, die mit Drähten (Netzen) verbunden sind. " +"Mit dem Doppelklick wird dieser Klemmenblock in die untere Liste zur Bearbeitung " +"übertragen.

    " + +"Untere Liste: Links sind Drahtverbindungen dargestellt, sie können nicht " +"verändert werden (nur in der Schaltung). Rechts sind die Einzelbrücken " +"in jeweils einer Zeile dargestellt.

    " + +"Doppelklick auf untere Liste: Die verbundenen Klemmen einer Einzelbrücke " +"wandern in das Editier-Fenster (Verbinden). Dort können Sie eintragen, " +"welche Klemmen verbunden werden sollen (durch Leerzeichen getrennt). " +"Die Eingabetaste oder ein Klick auf Anwenden ändert die selektierte " +"Zeile entsprechend. Falls Sie Klemmen gewählt haben, die nicht in der " +"Schaltung platziert sind, erscheint eine Fehlermeldung.

    " + +"Speichern: Dieser Button beendet das Programm und führt die Änderungen " +"an der zuletzt bearbeiteten Klemme durch. Der aktuelle Brückenplan " +"wird als schaltungsname.brk abgespeichert, zusätzlich die Log-Datei " +"(*.log) und eine Script-Datei (*.scr), aus der die EAGLE-Befehle zur Änderung " +"der Referenzen hervorgehen. Um den endgültigen Brückenplan für ihre " +"Projektunterlagen zu erstellen, sollten Sie das Programm starten und " +"ohne eine Änderung durchzuführen den Button Speichern betätigen, dann " +"ist die Liste richtig sortiert.

    " + +"Undo: Dieser Button bringt nach einer Änderung den letzten Zustand in die " +"untere Liste (nur eine Undo-Stufe).

    " + +"Unbenutzte: Dieser Button bringt alle Klemmen in das Editier-Feld, die " +"als Eingabe möglich sind, da sie gegenwärtig keiner anderen Brücke angehören. " +"Am besten, sie betätigen diesen Button und löschen dann die Klemmen heraus, " +"die nicht mit der zu erstellenden Brücke verbunden werden sollen.

    " + +"Löschen: Löscht eine komplette Brückenzeile.

    " + +"Neu: Erzeugt eine neue Brückenzeile, in die Sie den Inhalt des Editier-Fensters " +"übertragen können.

    " + +"Abbrechen: Programm ohne Änderungen verlassen." +; +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void SetFileNames(void) { // in Schematic-Kontext aufrufen + + if (!schematic) { + // dlgMessageBox("Dieses Programm muss vom Schaltplan-Editor aus aufgerufen werden"); + exit(1); + } + schematic(SCH) { + scrfile = filesetext(SCH.name, ".scr"); + errorfile = filesetext(SCH.name, ".log"); + listfile = filesetext(SCH.name, ".brk"); + } +} + +string StripWhiteSpace(string s) { // mit Zusatz: Doppel-Whitespaces im Inneren werden 1 Whitespace + int i, n; + string t; + + while (s && isspace(s[0])) + s = strsub(s, 1); + while (s && isspace(s[strlen(s) - 1])) + s = strsub(s, 0, strlen(s) - 1); +// Doppel-Blanks + for (i = 0; i < strlen(s); i++) { + if (!isspace(s[i])) t[n++] = s[i]; + else { + if ((strlen(s) > i+1) && isspace(s[i+1])); + else t[n++] = s[i]; + }; + } + s = t; + return s; +} + +string SortBlankSeparatedString(string s) { + int nb; + numeric string b[]; + s = StripWhiteSpace(s); + nb = strsplit(b, s, ' '); + sort(nb, b); + s = strjoin(b, ' '); + return s; +} + +// Lösche Mehrfacheinträge aus blanksepariertem String und sortiere +string DelMultiples(string st) { + string s, h[], ht[]; + int i, n, np; + st = SortBlankSeparatedString(st); + np = strsplit(h, st, ' '); + for (i = 0; i < np; i++) { + ht[n] = h[i]; + if (ht[n] == h[i+1]) { + i++; + } + n++; + } + s = strjoin(ht, ' '); + return StripWhiteSpace(s); +} + +// Liefert einen kommaseparierten String mit allen verdrahteten Brücken eines Klemmenblocks +// Für Log werden die Brücken nach Netzen getrennt ausgegeben +string GetConnectedOnePart(string pname) { + int klnr, nrnetpins; + string s, t, connects, allconnects; + schematic(SCH) { + SCH.nets(N) { + nrnetpins = 0; + N.pinrefs(P) { + if (P.part.name == pname && P.pin.contact) { + nrnetpins++; + if (nrnetpins == 2) { + sprintf(s, "%s\tNetz: %s\tKlemmen: ", P.part.name, N.name); LogCmd += s; + break; + } + } + } + t = ""; connects = ""; nrnetpins = 0; + N.pinrefs(P) { + s = ""; + if (P.part.name == pname && P.pin.contact) { + if(strtol(P.pin.contact.pad.name)) klnr = strtol(P.pin.contact.pad.name); + else sprintf(s, "\n%s: Fehler in Bibliothek! Pad-Name muss mit Ziffer beginnen!\n", P.pin.contact.pad.name); LogCmd += s; + sprintf(s, "%d ", klnr); connects += s; t += s; // nur wegen \n + nrnetpins++; + } + } + if (nrnetpins == 1) connects = ""; // nur ein Pin an Netz + LogCmd += SortBlankSeparatedString(connects); + if (t && nrnetpins > 1) LogCmd += "\n"; + allconnects += " " + connects; + } + } + return SortBlankSeparatedString(allconnects); +} + +void PackListsel (int ix, int pos, string s) { + int np; + if (ix < 0 || pos < 0) return; + numeric string h[]; + strsplit(h, ListSel[ix], '\t'); + h[pos] = s; + ListSel[ix] = strjoin(h, '\t'); +} + +string UnpackListsel (int ix, int pos) { + if (ix < 0) return ""; + numeric string h[]; + strsplit(h, ListSel[ix], '\t'); + return h[pos]; +} + +void PackListall (int ix, int pos, string s) { + int np; + if (ix < 0 || pos < 0) return; + numeric string h[]; + strsplit(h, ListAll[ix], '\t'); + h[pos] = s; + ListAll[ix] = strjoin(h, '\t'); +} + +string UnpackListall (int ix, int pos) { + if (ix < 0) return ""; + numeric string h[]; + strsplit(h, ListAll[ix], '\t'); + return h[pos]; +} + +int IsInBlankStr (string item, string st) { // ist item in blanksep. String st vorhanden? + int i, np; + numeric string h[]; + st = StripWhiteSpace(st); + np = strsplit(h, st, ' '); + for (i = 0; i < np; i++) { + if (item == h[i]) return 1; + } + return 0; +} + +// Löscht Edit-Liste +void DelListsel(void) { + for (i = 0; i < maxklemmen; i++) { + ListSel[i] = ""; + } +} + +// Ref-Verbindungen für Editierliste erstellen: blank/tab separated string (ordered) +// 1 2 5 \n 4 6 Zeilen mit \t getrennt +string GetConnectedRefwise(string pname){ + numeric string s, klemmenused[], ku, c1, c2, bridges[], h[], lastline[], prevline[]; + int i, j, k, u, v, w, np, np1, np2, bx, found; + schematic(SCH) { + SCH.sheets(SH) { + SH.parts(P) { + if (P.name == pname) { + if (LogOn) LogCmd += P.name + " "; + np = strsplit(klemmenused, StripWhiteSpace(lookup(PartDatabase, P.name, "Verwendet", '\t')) ,' '); + i = 0; bx = 0; found = 0;// Brückenindex, trennt Einzelpotentiale + for (i = 0; i < np; i++) { + ku = klemmenused[i]; + c1 = P.attribute[klemmenused[i]+"1"]; + c2 = P.attribute[klemmenused[i]+"2"]; + if (P.attribute[klemmenused[i]+"1"] || P.attribute[klemmenused[i]+"2"]) { + sprintf(s, "%d: %s %s %s\n", bx, ku, c1, c2); + sprintf(s, "%s %s %s", ku, c1, c2); + if (StripWhiteSpace(s)) bridges[bx++] = StripWhiteSpace(s); + } + } + // bx Zahl der Klemmen mit Ref (höchster Index ist bx-1); max drei Klemmen pro Eintrag + for (j = bx-1; j > 0; j--) { // Fasse Potentiale in bridges[] zusammen + np1 = strsplit(lastline, bridges[j], ' '); // bis zu drei Klemmen in lastline + v = j - 1; + while (v >= 0) { // vorherige Zeilen + strsplit(prevline, bridges[v], ' '); + w = 0; + while(prevline[w]) { + u = 0; + while (lastline[u]) { + if (lastline[u] == prevline[w]) { + bridges[v] += " " + StripWhiteSpace(bridges[j]); + bridges[j] = ""; + found = 1; + break; + } + u++; + } + if (found) break; + w++; + } + v--; + } + } // Ende Zusammenfassen der Potentiale (Mehrfacheinträge hier noch möglich) + i = 0; n = 0; + while (h[i]) h[i++] = ""; + for (i = 0; i < maxklemmen; i++) { + if (StripWhiteSpace(bridges[i])){ + h[n] = DelMultiples(bridges[i]); + n++; + } + } + sort(n, h); + i = 0; s = ""; + while (StripWhiteSpace(h[i])) { + h[i] = DelMultiples(h[i]); + s += h[i] + "\n"; + if (LogOn) LogCmd += " : " + h[i]; + i++; + } + if (LogOn) LogCmd += "\n"; + } + } + } + } + return s; +} + +// Editier-Liste (Drähte) für einen Klemmenblock erstellen: blank/tab separated string (ordered) +// 1 2 5 \n 4 6 Zeilen mit \t getrennt +string GetConnectedNetwise(string pname){ + int klnr, nrnetpins; + string s, t, connects, allconnects; + schematic(SCH) { + SCH.nets(N) { + t = ""; connects = ""; nrnetpins = 0; + N.pinrefs(P) { + s = ""; + if (P.part.name == pname && P.pin.contact) { + klnr = strtol(P.pin.contact.pad.name); // trennt .x ab von x.x + sprintf(s, "%d ", klnr); connects += s; t += s; // t nur wegen \n erforderlich + nrnetpins++; + } + } + connects = SortBlankSeparatedString(connects); + if (nrnetpins == 1) connects = ""; // nur ein Pin an Netz + if (t && nrnetpins > 1) { + allconnects += connects + "\n"; + } + } + } + return allconnects; +} + +// Ermittelt Wired-Brücken an und schreibt Log nach Startvorgang +// Part \t Klemmen +// wobei Klemmen blanksepariert sind (alle fest verdrahteten Klemmen) +// z. B.: X1 1 3 4 5 9 +void GetConnectedAllParts(void) { + int i, np; + string h[]; + LogCmd += "---------------------------------------------------------------------------------------------\n"; + LogCmd += "Mit Netzen realisierte Brücken: nicht mit diesem ULP zu verändern!\n"; + LogCmd += "---------------------------------------------------------------------------------------------\n"; + while (ListAll[i]) { + np = strsplit(h, ListAll[i], '\t'); +// Wired Connections + h[Verdrahtet] = DelMultiples((GetConnectedOnePart(h[Name]))); + ListAll[i] = strjoin(h, '\t'); + i++; + } + LogCmd += "---------------------------------------------------------------------------------------------\n"; + LogCmd += "Mit Referenzen realisierte Brücken: mit diesem ULP zu verändern!\n"; + LogCmd += "---------------------------------------------------------------------------------------------\n"; +// Ref Connections + i = 0; + while (ListAll[i]) { + np = strsplit(h, ListAll[i], '\t'); + LogOn = 1; + GetConnectedRefwise(h[Name]); + LogOn = 0; + i++; + } + LogCmd += "---------------------------------------------------------------------------------------------\n"; +} + + +int CheckOKBridgeLine(string st) { // lässt nur in schematic vorhandene Klemmen zu + int i, np; + string s, h[]; + s = StripWhiteSpace(st); + if (st == "") return 1; + char c; + for (i = 0; i < strlen(s); i++) { + c = s[i]; + if (isdigit(c) || c == ' ') { + } + else return 0; + } + np = strsplit(h, st, ' '); + if (np == 1) return 0; + for (i = 0; i < np; i++) { + if (!IsInBlankStr(h[i], UnpackListall(CurrentPartIndex, Verwendet))) { + return 0; + } + } + return 1; +} + +void MakeEditListOnePart(int Sel) { + int i, ErrPrinted; + string wirelines[], reflines[], h[], x[]; + if (Sel < 0) return; + strsplit(h, ListAll[Sel], '\t'); + CurrentPartIndex = Sel; + CurrentPart = h[Name]; + DelListsel(); + strsplit(wirelines, GetConnectedNetwise(h[Name]), '\n'); // alle Br. als Einzelzeilen + strsplit(reflines, GetConnectedRefwise(h[Name]), '\n'); // alle Br. als Einzelzeilen + while(wirelines[i] || reflines[i]) { + ListSel[i] = DelMultiples(wirelines[i]) + "\t" + DelMultiples(reflines[i]); + if (!CheckOKBridgeLine(reflines[i])) { + if (ErrOn && !ErrPrinted) { + dlgMessageBox( "Unzulässige Brückenbezeichnung, siehe Log-Liste!

    " + "Bitte tragen Sie in die Brückenzeilen nur erlaubte Bezeichnungen ein " + "und speichern Sie das Ergebnis ab!" + ); + ErrPrinted = 1; + } + if (!ErrOn) + if (strsplit(x, reflines[i], ' ') == 1) + LogCmd += UnpackListall(Sel, Name) + ": " + reflines[i] + + "\tNur ein Klemmenverweis (min. 2 erforderlich)!\n"; + else + LogCmd += UnpackListall(Sel, Name) + ": " + reflines[i] + + "\tNicht alle Klemmen in Schaltung vorhanden!\n"; + } + i++; + } + return; +} + +// void MakeEditListPerName(string pname) { +// int i; +// pname = StripWhiteSpace(pname); +// while (UnpackListall(i, Name)) { +// if (pname == UnpackListall(i, Name)) { +// MakeEditListOnePart(i); +// SelAll = i; +// return; +// } +// i++; +// } +// dlgMessageBox("Kein Klemmenblock mit diesem Namen vorhanden!

    "); +// return; +// } + +// Sammle Brückenklemmen (Part-Name: X...; Device-Name: ..BRUECKE..) +// Fülle obere Liste und lege identische Datenbank mit Header an (PartDatabase[]) +void CollectX(void) { + numeric string s, sheetgate; + int cntpart; + PartDatabase[0] = ListHeaderMain + "\tSeite(n)"; // 2013 die Seiten sind pro gate eingetragen + schematic(SCH) { + SCH.parts(P) { // 2013-10-02 nicht durch die sheets + if (strchr(P.name, 'X') == 0) { + if (strstr(P.device.name, "BRUECKE") >= 0) { + int cntmaxklem = 0; + string listallsheet = ""; + P.instances(I) if (I.sheet) cntmaxklem++; + maxklemmen = max(maxklemmen, cntmaxklem); + sprintf(ListAll[cntpart], "%s\t%d\t", P.name, cntmaxklem); + + P.instances(I) { + if (I.sheet) { + ListAll[cntpart] += I.gate.name + " ";; + sprintf(sheetgate, "%d ", I.sheet); // 2013-10-02 sheet aus der Instance + listallsheet += sheetgate; + } + } + ListAllSheet[cntpart] = listallsheet; + PartDatabase[cntpart+1] = ListAll[cntpart];// + "\t" + listallsheet; // die sheets zu den Gates + LogCmd += PartDatabase[cntpart+1] + "\n"; + cntpart++; + } + } + } + } +} + +void PushUndo(void) { + int i; + while (ListUndo[i]) { + ListUndo[i] = ""; + i++; + } + i = 0; + while (ListSel[i]) { + ListUndo[i] = ListSel[i]; + i++; + } +} + +void PullUndo(void) { + int i; + while (ListSel[i]) { + ListSel[i] = ""; + i++; + } + i = 0; + while (ListUndo[i]) { + ListSel[i] = ListUndo[i]; + i++; + } +} + +void ShowLog(void) { + dlgDialog("Brückendaten aus der Schaltung") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout{ + dlgTextEdit(LogCmd); + } + dlgHBoxLayout { + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("&Hilfe") dlgMessageBox( "Die Liste gibt Hinweise auf mögliche Probleme beim Einlesen\n" + "der Brückenverbindungen." + ); + dlgPushButton("+OK") dlgAccept(); + } + }; +} + +// liefert alle a, die nicht in b sind; a,b und return-Wert sind blanksep. Strings +string AllAnotinB(string a, string b) { + int i, na; + numeric string ha[]; + a = StripWhiteSpace(a); + b = StripWhiteSpace(b); + na = strsplit(ha, a, ' '); + a = ""; + for (i = 0; i < na; i++) { + if (!IsInBlankStr(ha[i], b)) { + a += ha[i] + " "; + } + } + return StripWhiteSpace(a); +} + +string GetUnused(int Sel) { // liefert unbenutzte Klemmen als blanksep. String + int i, n; + string h[], s, usedB, usedD, t; // von Brücken benutzt; von Drähten benutzt + if (Sel < 0 || CurrentPartIndex < 0) return ""; + PushUndo(); + s = UnpackListall(CurrentPartIndex, Verwendet); + while (ListSel[i]) { + if (Sel != i) usedB += UnpackListsel(i, Bruecken) + " "; + usedD += UnpackListsel(i, Draehte) + " "; + i++; + } + s = AllAnotinB(s, usedB); + if (ExcludeDrahtverbindungen) s += " " + AllAnotinB(s, usedD); + return StripWhiteSpace(s); +} + +int CheckOKChangeString(string st) { // lässt nur solche zu, die noch nicht in anderer Br. verwendet + int i, np; + string s, h[]; + s = StripWhiteSpace(st); + char c; + for (i = 0; i < strlen(s); i++) { + c = s[i]; + if (isdigit(c) || c == ' ') { + } + else return 0; + } + np = strsplit(h, st, ' '); + if (np == 1) return 0; + for (i = 0; i < np; i++) { + if (!IsInBlankStr(h[i], GetUnused(SelConnected))) { + return 0; + } + } + return 1; +} + +void ClearGarbageListsel() { // löscht leere Einträge am Ende von ListSel + int i; + while (ListSel[i]) { + if (UnpackListsel(i, Draehte) == "" && UnpackListsel(i, Bruecken) == "") ListSel[i] = ""; + i++; + } +} + +// Lösche eine Verbindung aus Auswahlliste +void DelOneEntry(int Sel) { + int i, n, imax; + string x[]; + PushUndo(); + if (Sel < 0) return; + SelConnected = -1; + while(UnpackListsel(i, Bruecken)) i++; // # Einträge feststellen + imax = i; + for (i = 0; i < imax; i++) { + if (i <= Sel) { + x[i] = UnpackListsel(i, Bruecken); + } + else { + x[i-1] = UnpackListsel(i, Bruecken); + } + } + if (imax != 0) PackListsel(imax-1, Bruecken, ""); + + if (Sel == 0 && imax == 0) { + PackListsel(0, Bruecken, ""); + } + else { + imax = imax -1; + for (i = 0; i < imax; i++) { + PackListsel(i, Bruecken, x[i]); + } + } + if (Sel > 0) SelConnected = Sel-1; + else SelConnected = 0; + ClearGarbageListsel(); // entferne leere Zeilen aus ListSel +} + +void CreateBridge(void) { + int i; + while(UnpackListsel(i, Bruecken)) i++; // # Einträge feststellen + PackListsel(i, Bruecken, ""); + ChangeString = ""; + SelConnected = i; +} + +void EditOneEntry(int Sel) { + string h[]; + if (Sel < 0) return; + strsplit(h, ListSel[Sel], '\t'); + ChangeString = SortBlankSeparatedString(h[Bruecken]); +} + +void TransferEditLine (int Sel) { + string h[]; + if (Sel < 0) return; + PushUndo(); + if (StripWhiteSpace(ChangeString) == "") { + DelOneEntry(Sel); + return; + } + ChangeString = SortBlankSeparatedString(ChangeString); + if (CheckOKChangeString(ChangeString)) { + PackListsel(Sel, Bruecken, ChangeString); + } + else dlgMessageBox("Ungültige Klemmennummern im Editier-Feld!

    " + "Erlaubt sind Klemmennummern, die in der selektierten Brücke verwendet wurden, " + "aber in keiner anderen (nur Leerzeichen und 0-9).

    " + "Es müssen mindestens zwei Klemmen eingetragen sein."); +} + +void WriteAttributeLog(void) { + int i; + string s; + ErrOn = 0; + LogCmd += "Warnungen! - Falsche Verweise\n"; + LogCmd += "---------------------------------------------------------------------------------------------\n"; + while (ListAll[i]) { + SelAll = i; + CurrentPartIndex = i; + MakeEditListOnePart(i); + i++; + } + SelAll = 0; + CurrentPartIndex = 0; + MakeEditListOnePart(0); + ErrOn = 1; +} + +string MakeList (void) { // aktuelle Brückenliste erstellen + int i, j, k; + string h[], b[], BrkCmd, s; + BrkCmd += "Name\tBrücken\n"; + while (ListAll[i]) { + strsplit(h, ListAll[i], '\t'); // hole Bauteilnamen + LogOn = 0; + BrkCmd += h[Name] + "\t"; + strsplit (b, GetConnectedRefwise(h[Name]), '\n'); // h: 1 2 3 \t 2 4 + + if (CurrentPartIndex == i) { + k = 0; + while (UnpackListsel(k, Bruecken)) { + b[k] = UnpackListsel(k, Bruecken); + k++; + } + b[k] = ""; + } + + j = 0; s = ""; + while (b[j]) { // Einzelbrücken + // hier ev. aus 1 2 3 4 5 -> 1-5 + if (!s) s += b[j] + " "; + else s += " : " + b[j]; + j++; + } + // s = strjoin(b, ':'); + BrkCmd += s + "\n"; + i++; + } + return BrkCmd; +} + +int CancelOk(void) { + int CancelOk; + dlgDialog("Programm verlassen") { + dlgHBoxLayout dlgSpacing(400); + dlgHBoxLayout { + dlgTextView ( "Wenn Sie das Programm abbrechen, verlieren Sie alle Änderungen!\n\n" + "Abbrechen?" + ); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+Nein") dlgReject(); + dlgPushButton("-Ja") {CancelOk = 1; dlgAccept();} + } + }; + if (CancelOk) return 1; + else return 0; +} + +void SaveList(void) { + int i, k, np, ns; + string line, klemme[], klemmsheet[], h[], sht; + DoCmd = ""; +// if (SelConnected < 0) { +// dlgMessageBox( "Sie müssen erst eine Zeile im unteren Fenster selektieren!

    "); +// return; +// } + strsplit(h, ListAll[CurrentPartIndex], '\t'); + string pname = h[Name]; + //sht = lookup(PartDatabase, pname, "Seite", '\t'); + LogCmd += "---------------------------------------------------------------------------------------------\n"; + LogCmd += "Befehle zum Eintragen der neuen Verweise\n"; + LogCmd += "---------------------------------------------------------------------------------------------\n"; + DoCmd += "change display off;\n"; + line = StripWhiteSpace(UnpackListall(CurrentPartIndex, Verwendet)); + np = strsplit(klemme, line, ' '); + ns = strsplit(klemmsheet, ListAllSheet[CurrentPartIndex], ' '); + for (k = 0; k < np; k++) { // alle Attr. der verwendeten Klemmen löschen + DoCmd += "edit .s" + klemmsheet[k] + ";\n"; + DoCmd += "change display off;\n"; + DoCmd += "attribute " + pname + " " + klemme[k] + "1 " + "'';\n"; + DoCmd += "change display off;\n"; + DoCmd += "attribute " + pname + " " + klemme[k] + "2 " + "'';\n"; + } + i = 0; k = 0; + while (StripWhiteSpace(UnpackListsel(i, Bruecken))) { // alle Brückenzeilen in Att. eintragen + line = StripWhiteSpace(UnpackListsel(i, Bruecken)); + np = strsplit(klemme, line, ' '); + for (k = 1; k < np; k++) { // alle Klemmen pro Brücke + DoCmd += "change display off;\n"; + DoCmd += "attribute " + pname + " " + klemme[k-1] + "2 " + "'" + klemme[k] + "';\n"; + } + for (k = np - 2; k >= 0; k--) { // alle Klemmen pro Brücke + DoCmd += "change display off;\n"; + DoCmd += "attribute " + pname + " " + klemme[k+1] + "1 " + "'" + klemme[k] + "';\n"; + } + i++; + } + LogCmd += DoCmd; + LogCmd += "---------------------------------------------------------------------------------------------\n"; + + output(errorfile, "wtD") printf("%s", LogCmd); + output(scrfile, "wtD") printf("%s", DoCmd); + ListCmd = MakeList(); + output(listfile, "wt") printf("%s", ListCmd); + + exit(DoCmd); +} + +void ShowHelp(void) { + dlgDialog("Hilfe") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout{ + dlgVBoxLayout dlgSpacing(600); + dlgTextView(HelpText); + } + dlgHBoxLayout { + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + } + }; +} + +//***************************************************** +void ShowUserInterface(void) { + dlgDialog("Brückenklemmen verwalten - (" + filename(argv[0]) + ") " + Version) { + dlgHBoxLayout dlgSpacing(300); + dlgGroup("") { + dlgLabel("Vorhandene Klemmenblöcke"); + dlgListView(ListHeaderMain, ListAll, SelAll, SortAll) MakeEditListOnePart(SelAll); + dlgSpacing(10); + } + dlgGroup("") { + dlgHBoxLayout { + dlgLabel(CurrentPart, 1) ; + dlgLabel(": Brücken dieses Klemmenblocks editieren"); + dlgStretch(1); + } + dlgListView(ListHeader, ListSel, SelConnected, Sort) EditOneEntry(SelConnected); + dlgHBoxLayout { + dlgLabel("Verbinden"); + dlgStringEdit(ChangeString); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("Undo") PullUndo(); + dlgStretch(1); + dlgPushButton("Unbenutzte") ChangeString = GetUnused(SelConnected); + dlgPushButton("Löschen") DelOneEntry(SelConnected); + dlgPushButton("Neu") CreateBridge(); + dlgPushButton("+Anwenden") TransferEditLine(SelConnected); + } + } + dlgSpacing(10); + dlgHBoxLayout { + } + dlgHBoxLayout { + dlgPushButton("&Hilfe") ShowHelp(); + dlgStretch(1); + dlgPushButton("Log-Datei") ShowLog(); + dlgPushButton("-Abbrechen") dlgReject(); // if (CancelOk()) dlgReject(); + dlgPushButton("Speichern") SaveList(); + } + }; +} +//***************** Main ****************************** +SetFileNames(); +NrHeader = strsplit(head, ListHeader, '\t'); +CollectX(); +GetConnectedAllParts(); +WriteAttributeLog(); +output(errorfile, "wtD") printf("%s", LogCmd); +ShowUserInterface(); + diff --git a/trunk/ulp/e-klemmenplan.ulp b/trunk/ulp/e-klemmenplan.ulp new file mode 100644 index 00000000..2e95b771 --- /dev/null +++ b/trunk/ulp/e-klemmenplan.ulp @@ -0,0 +1,1113 @@ +// Klemmenplan/Kabelplan/Brückenplan für Elektro-Projekte + +// todo +// Prüfen ob Netz auf Pin und nicht angeschlossen (pindatabase) +// x-Verbindungen nach Namen sortieren + +string Version = "Version 1.03"; + +// History +// 1.03 -- 2009-10-01 +// nicht benötigte "\t\t" im Titel von dlgDialog() entfernt +// +// 1.02 +// Verbindungen von Netzen mit mehr als zwei Kontakten werden jetzt in anderer Reihenfolge +// erstellt (siehe Help) +// +// Ist auf einer Seite keine Klemme (Prefix X) vorhanden, werden alle Verbindungen als d +// (Drahtverbindung) gekennzeichnet +// +// 1.01 Keine Fehlermeldung mehr, wenn Packages Smds enthalten + +#require 4.9206 + +#usage "Erstellen eines Klemmenplans\n

    " + +"Mit diesem ULP erstellen Sie einen Klemmenplan, der alle Zweipunktverbindungen " +"der geladenen Schaltung enthält, also Verbindungen im Schaltschrank, die " +"üblicherweise mit Drähten realisert werden, und externe, die mit Kabeln " +"realisiert werden. Interne, externe und Brücken-Verbindungen erscheinen nacheinander in der Liste.

    " +"Das Programm sollte erst dann verwendet werden, wenn die " +"Schaltung nicht mehr oder nur noch geringfügig verändert wird.

    " +"Die erzeugte Liste (schaltungsname.vbd) kann in einem Tabellenkalkulationsprogramm " +"weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die " +"Schaltungszeichnung importiert werden.

    " +"Author: support@cadsoft.de" + +string s, cmd, f, ErrCmd; +string tmpfile, listfile, errorfile, pinfile, vbdfile, klpfile, kapfile, brpfile, pfad; +numeric string sh, PartPin, SigName, col, row, PartName, PinName; +numeric string pindatabase[], b[]; +string PartPinSep = " "; +int YRef[]; +int distY, netnr, n, i; +// Debug +string DebugString; +// Variablen für main +int SelAll = -1, SelConnection = -1, Sort = 0, SortAll = 0, NrLinesListAll; +numeric string listall[], listsel[], listundo[], listundoOben[]; +string h[]; +// Header-Variablen ------------------------------------------------------------------------------------------- +string head [], SelParam[], ChangeParam[]; +int NrHeader; // Zahl der Rubriken +enum {Nummer, Von, Quelle, Ziel, Nach, Art}; +// head [] enthält ListHeader-Einträge: head[Farbe].. +// head[Nummer].. v +numeric string ListHeader = "Nummer\tVon\tQuelle\tZiel\tNach\tArt\tBrücke\tFarbe\tQuerschnitt\tKabeltyp\tFunktion"; +// Ende Header-Variablen -------------------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////////////////////////// +string HelpText = + +"Erstellen des Klemmenplans mit diesem User-Language-Programm (ULP)

    " + +"Mit diesem ULP erstellen Sie einen Klemmenplan, der alle Zweipunktverbindungen " +"der geladenen Schaltung enthält, also Verbindungen im Schaltschrank, die " +"üblicherweise mit Drähten realisert werden, und externe, die mit Kabeln " +"realisiert werden. Das Programm sollte erst dann verwendet werden, wenn die " +"Schaltung nicht mehr oder nur noch geringfügig verändert wird.

    " + +"Die obere Liste (Verbindungsliste) enthält immer alle Verbindungen mit diversen " +"Parametern. Sie wird abgespeichert, wenn Sie den Button Speichern " +"anklicken. Der Benutzer hat die Aufgabe, jeder Verbindung die passenden " +"Parameter (Farbe, Kabeltyp etc.) zuzuordnen. Dabei unterstützt ihn dieses " +"ULP.

    " +"Die erzeugte Liste (schaltungsname.vbd) kann in einem Tabellenkalkulationsprogramm " +"weiter verarbeitet oder mit Hilfe von e-makelist.ulp direkt in die " +"Schaltungszeichnung importiert werden.

    " + +"Regeln für das Zeichnen von Mehrfachverbindungen

    " + +"Sind mehr als zwei Klemmen im Schaltplan miteinander verbunden, dann gelten folgende Regeln:

    " +"Die Klemmen werden der Reihe nach von oben nach unten und von links nach rechts verbunden. " +"Das heißt, wenn sich auf diese Weise eine Reihenfolge der Klemmen von A, B, C, D ergibt, " +"dann entstehen die Drahtverbindungen A-B, B-C, C-D. Die Art, wie die Netzlinien gezeichnet sind, " +"spielt dabei keine Rolle. Sollen die Einzelverbindungen auf andere Art realisiert werden, " +"etwa A-C, C-B, B-D, dann müssen die Klemmen im Schaltplan entsprechend platziert werden. " +"Erstreckt sich ein Netz über mehrere Seiten, dann wird die Klemme rechts unten mit der " +"Klemme rechts oben auf der Folgeseite verbunden.

    " + +"Bedeutung der Spalten

    " + +"Die Spalten der beiden dargestellen Listen haben folgende Bedeutung:

    " + +"Nummer: Laufende Nummer, die vom Programm automatisch erzeugt wird.

    " +"Von/Nach: 1.A1 bedeutet, die Verbindung startet/endet auf Seite 1, " +"Rahmenkoordinaten A1.

    " +"Quelle/Ziel: F1 1 bedeutet, die Verbindung beginnt/endet an Bauteil F1, Kontakt 1.

    " +"Art:
    " +"\td = Drahtverbindung (intern, im Schaltschrank)
    " +"\tk = Kabelverbindung (extern, außerhalb des Schaltschranks)
    " +"\tx = Brücke (Klemme zu Klemme im gleichen Klemmenblock)

    " + +"Das Programm kennzeichnet alle Verbindungen als extern, die auf einer Seite " +"unterhalb der untersten Klemme (Präfix X..) beginnen.

    " + +"Die Spalteneinträge bis Art werden vom Programm automatisch erzeugt. Die " +"Spalten rechts davon trägt der Benutzer ein. Art kann ebenfalls verändert werden, " +"dieser Parameter ist dafür verantwortlich, wo die Verbindung in der Ausgabeliste " +"erscheint (wenn das Feld leer ist, wird die Zeile nicht ausgegeben).

    " + +"Bedienung des Programms

    " + +"In die untere Liste (Auswahlliste) holen Sie eine Gruppe von Verbindungen, die " +"gemeinsame Parameter erhalten sollen, abhängig davon, welche Auswahl-Parameter " +"eingetragen sind (Button Holen). Danach setzen sie für die ganze Gruppe " +"die Werte, die Sie unter Parameter ändern eingetragen haben (Button " +"Alle eintragen oder Alle außer leere). Dann übertragen Sie die " +"Parameter in die obere Liste mit dem Button Anwenden. " +"Sie können die Parameter der selektierten Auswahllisten-Zeile auch in einem " +"separaten Fenster editieren, das sich nach einem Doppelklick auf diese Zeile öffnet.

    " + +"Beispiel: Es sollen alle Bauteile als Farbe rot erhalten, die mit F " +"beginnen.

    " +"Löschen Sie zunächst die Auswahlliste mit dem Button Alle löschen.

    " +"Klicken Sie dann Alle * an, damit das Wildcard-Zeichen * in alle " +"Suchfelder eingetragen wird. In die Felder kann ein sogenannter Wildcard-Text " +"eingegeben werden, bei dem das Zeichen * beliebige Zeichen ersetzt. Ein Stern " +"bedeuted, es spielt keine Rolle, wie der Eintrag lautet.

    " +"Jetzt tippen Sie in das Feld Quelle/Ziel der Gruppe Auswahl-Parameter F* ein und " +"klicken dann auf Holen. Alle F..-Bauteile erscheinen jetzt in der " +"unteren Liste.

    " +"Tragen Sie jetzt rot im Feld Farbe des Blocks Parameter " +"ändern ein, und klicken Sie auf den Button Anwenden. Die Parameter " +"werden dann in die obere Liste übertragen.

    " + +"Bedeutung der Buttons

    " + +"Undo oben: Die letzte Veränderung der Verbindungsliste wird " +"rückgängig gemacht (nur ein Schritt möglich).

    " + +"Nach oben/Nach unten: Die in der Verbindungsliste selektierte Zeile wird nach " +"oben oder unten verschoben. Damit ändert sich die laufende Nummer der Zeile. Auf " +"diese Weise lässt sich die Ausgabereihenfolge verändern.

    " + +"Quelle - Ziel: Quelle und Ziel des selektierten Eintrags in der " +"Verbindungsliste werden vertauscht.

    " + +"Undo unten: Die letzte Veränderung der Auswahlliste wird " +"rückgängig gemacht (nur ein Schritt möglich).

    " + +"Eintrag löschen: Die in der Auswahlliste selektierte Zeile wird gelöscht.

    " + +"Alle löschen: Alle Zeilen der Auswahlliste werden gelöscht.

    " + +"Anwenden: Die Parameter der Auswahlliste werden in die entsprechenden " +"Verbindungen der Verbindungsliste eingetragen: Dabei werden die bisherigen " +"Parameter (einschließlich leere Felder) überschrieben.

    " + +"Löschen: Alle Felder der Blöcke Auswahl-Parameter und Parameter " +"ändern werden gelöscht.

    " + +"Alle *: Setze alle Suchfelder auf das Wildcard-Zeichen *. Es sind auch Muster " +"wie *F* oder *F*1* erlaubt.

    " + +"Holen: Hole alle Verbindungen, bei denen die eingetragenen Suchparameter " +"zutreffen. Die Felder untereinander sind UND-Verknüpft, das heißt nur wenn bei " +"allen Feldern ein entsprechender Eintrag in der Verbindungsliste gefunden wird, " +"wird die Verbindung in die Auswahlliste geholt. Wenn Sie etwa alle Verbindungen " +"auf Seite 1 mit der Farbe rot holen wollen, dann tragen Sie in Von/Nach " +"1.* ein und in das Feld Farbe rot. Alle anderen Felder enthalten *.
    " +"Ein Doppelklick auf einen Eintrag in der Verbindungsliste bringt diese " +"eine Verbindung in die Auswahlliste.

    " + +"Alle eintragen: Die in den Feldern eingetragenen Parameter werden in alle " +"Verbindungen der Auswahlliste eingetragen (auch leere Felder).

    " + +"Alle außer leere: Die in den Feldern eingetragenen Parameter werden in alle " +"Verbindungen der Auswahlliste eingetragen. Ist ein Feld im Block Parameter " +"ändern leer, dann wird das entsprechende Feld in der Auswahlliste nicht " +"verändert.

    " + +"Fehlerliste: Zeigt eine Liste mit möglichen Fehlern in der Schaltung.

    " + +"Lade ext. Liste: Falls Sie bereits einen Klemmenplan erstellt haben und " +"anschließend nur noch geringfügige Änderungen durchgeführt wurden (Namen der " +"Bauteile im Wesentlichen gleich), dann starten Sie das ULP und klicken als " +"erstes auf diesen Button, damit die bisherigen Parameter in die Verbindungsliste " +"übernommen werden. Verbindungen, die aufgrund von Schaltungsänderungen nicht " +"zugeordnet werden können, erscheinen in der Auswahlliste.

    " + +"Abbrechen: Programm ohne Abspeichern des Klemmenplans verlassen. Achtung, Sie " +"verlieren alle Änderungen am Klemmenplan.

    " + +"Speichern: Abspeichern des Klemmenplans.

    " + +"Ausgabe

    " + +"In der vorliegenden Version wird eine tabulatorseparierte Liste ausgegeben, " +"die Sie entweder in einem Texteditor (mit passend gesetzten Tabulatorwerten) " +"oder z. B. mit Excel oder OpenOffice weiterverarbeiten können.

    " + +"Verändern der Spaltenüberschriften

    " + +"Wenn Sie die Spaltenüberschriften an eigene Bedürfnisse anpassen wollen, " +"verändern Sie im Programm die Zeile:

    " + +"\"Nummer\\tVon\\tQuelle\\tZiel\\tNach\\tArt\\tBrücke\\tFarbe\\tQuerschnitt\\tKabeltyp\\tFunktion\";

    " + +"Sie können zwischen den Tabulatorzeichen (\\t) die Texte verändern oder neue " +"Texte hizufügen, z.B.:

    " + +"\"...\\tFunktion\\tBeschreibung\";

    " + +"Achtung: Die Bedeutung der Spalten von Nummer bis Art bleibt " +"unverändert!

    " +; +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void SetFileNames(void) { // in Schematic-Kontext aufrufen + + if (!schematic) { + // dlgMessageBox("Dieses Programm muss vom Schaltplan-Editor aus aufgerufen werden"); + exit(1); + } + schematic(SCH) { + tmpfile = filesetext(SCH.name, ".$$$"); + listfile = filesetext(SCH.name, ".kp$"); + errorfile = filesetext(SCH.name, ".log"); + pinfile = filesetext(SCH.name, ".pi$"); + vbdfile = filesetext(SCH.name, ".vbd"); + klpfile = filesetext(SCH.name, ".klp"); + kapfile = filesetext(SCH.name, ".kap"); + brpfile = filesetext(SCH.name, ".brp"); + } +} + +string StripWhiteSpace(string s) { // mit Zusatz: Doppel-Whitespaces im Inneren werden 1 Whitespace + int i, n; + string t; + + while (s && isspace(s[0])) + s = strsub(s, 1); + while (s && isspace(s[strlen(s) - 1])) + s = strsub(s, 0, strlen(s) - 1); +// Doppel-Blanks + for (i = 0; i < strlen(s); i++) { + if (!isspace(s[i])) t[n++] = s[i]; + else { + if ((strlen(s) > i+1) && isspace(s[i+1])); + else t[n++] = s[i]; + }; + } + s = t; + + return s; +} + +void ErrorMessage(string PartPin, string msg) { + string s, sh, col, row; + sh = lookup(pindatabase, PartPin, "Sheet", '\t'); + col = lookup(pindatabase, PartPin, "Column", '\t'); + row = lookup(pindatabase, PartPin, "Row", '\t'); + sprintf(s, "S. %s/%s-%s \tKontakt %s: \t%s", sh, row, col, PartPin, msg); + ErrCmd += s + "\n"; +} + +///////////////////////////////////////// +// pindatabase anlegen +// +// ermittle Zahl der Wires, die von Pin bzw. x,y aus starten +int NrOfWiresFromPin(string net, int shnr, int x, int y) { + string s; + int n; + schematic(SCH) { + SCH.sheets(SH) { + if (SH.number == shnr) { + SH.nets(N) { + if (N.name == net) { + N.segments(SEG) { + SEG.wires(W) { + if (x == W.x1 && y == W.y1 || x == W.x2 && y == W.y2) { // Wire beginnt an x, y + n++; + } + } + } + } + } + } + } + } + if (net && !n) n = 1; // wenn Pin auf Pin, net vorhanden, deshalb n auf 1 + return n; +} + +// ermittle Zahl der Wires, die nach dem ersten Wire-Segment vom Pin aus starten +// Wire vom Pin weg wird mitgezählt +int NrOfWiresAfterPin(string net, int shnr, int x, int y) { + string s; + int n, n1, u; + schematic(SCH) { + SCH.sheets(SH) { + if (SH.number == shnr) { + SH.nets(N) { + if (N.name == net) { + N.segments(SEG) { + n1 = 0; + SEG.wires(W) { + if (x == W.x1 && y == W.y1 || x == W.x2 && y == W.y2) { // suche ersten Wire + if (x == W.x1 && y == W.y1) { // stelle Endkoordinaten des Wires fest + x = W.x2; y = W.y2; + } + else { + x = W.x1; y = W.y1; + } + if (y == W.y1 || y == W.y2) { // Wire-Anfang zweigt nach erstem Wire-Segment über/unter Pin ab + n1 = NrOfWiresFromPin(net, shnr, x, y); // x, y nach erstem Wire-Stück + distY = y; // global, Distanz des Abzweigs in vertikaler Richtung + if (n1) break; + } + } + + } + } + } + } + } + } + } + + return n1; +} + +void SetupPinDatabase(void) { + string s, cmd, pname; + int np, nw; + schematic(SCH) { + cmd = "PartContact\tNet\tSheet\tRow\tColumn\tx\ty\tNP\tNW\tdistY\n"; + SCH.sheets(SH) { // # Wires ab Pin + SH.parts(PRT) { // # Wires nach erstem Wire + PRT.instances (I) { // Abstand des Abzweigs vertikal + I.gate.symbol.pins(P) { + if (P.contact) { + pname = P.contact.name; + } + else { + pname = P.name; + } + np = NrOfWiresFromPin(P.net, SH.number, P.x, P.y); nw = NrOfWiresAfterPin(P.net, SH.number, P.x, P.y); + sprintf(s, "%s%s%s\t%s\t%d\t%s\t%s\t%d\t%d\t", PRT.name, PartPinSep, pname, P.net, SH.number, I.row, I.column, P.x, P.y); cmd += s; + sprintf(s, "\t%d\t%d\t%d\n", np, nw, distY); cmd += s; + // Hier lassen sich alle Pin-Parameter prüfen + if (nw > 3 || np > 2) { + sprintf(s, "S. %d/%s-%s \tKontakt %s %s: \tMehr als zwei Abzweigungen vom Kontakt!", SH.number, I.row, I.column, PRT.name, pname); + ErrCmd += s + "\n"; + } + // todo: Prüfen, ob ein nicht angeschlossenes Netz auf dem Pin liegt + } + } + } + } + } + strsplit(pindatabase, cmd, '\n'); + output(pinfile, "wtD") { + printf(cmd); + } +} +//ende pindatabase ///////////////////////////////// + +void ReadConnects(void) { + int i, n, x[], y[], index[], loopcnt; + numeric string Part_Pin[]; + schematic(SCH) { + SCH.nets(NET) { + loopcnt = 0; + SCH.sheets(SH) { + SH.nets(N) { + if (NET.name == N.name) { + loopcnt++; + if (loopcnt == 1) { + cmd += "\n"; + } + n = 0; + N.segments(SEG) { + SEG.pinrefs(P) { + if (P.pin.contact) { + Part_Pin[n] = P.part.name + "\t" + P.pin.contact.name; + } + else { + Part_Pin[n] = P.part.name + "\t" + P.pin.name; + } + x[n] = P.pin.x; y[n] = INT_MAX - P.pin.y; // scanne Klemmen von oben nach unten + ++n; + } + } + sort(n, index, x, y, Part_Pin); // sortiere PartPin innerhalb eines Segments nach Position + // scanne Klemmen: erst alle y auf x = 0 etc. + for (int i = 0; i < n; ++i) { + sprintf(s, "%s\t", Part_Pin[index[i]]); cmd += s; + } + } + } + } + } + } + output(tmpfile, "wtD") { + printf(cmd); + } +} + +// Ermittle y-Wert für Trennung zwischen interner und externer Verdrahtung +// Hier: Klemme mit niedrigstem y pro Sheet +void GetYReference(void) { // YRef[] liefert: #sheets, yref-sh1, yref-sh2 .. + int sn, ymin, klemme_exists; + schematic(S) { + S.sheets(SH) { + sn++; + ymin = INT_MAX; + klemme_exists = 0; + SH.parts(P) { + P.instances(I) { + if (strchr(I.name, 'X') == 0) { // Alle, die mit X beginnen + ymin = min(ymin, I.y); // sprintf(s, "%s: %d\n", I.name, ymin); ErrCmd += s; + klemme_exists = 1; + } + } + } + YRef[SH.number] = ymin; // sprintf(s, " %d: %d\n", SH.number, YRef[SH.number]); ErrCmd += s; + if (klemme_exists == 0) { + YRef[SH.number] = 0; + } + } + YRef[0] = sn; + } +} + +string AssembleNetLine(string line){ + int i, j, n, npar, snr; + string s, st, lxy, rxy; + string ps[]; // Einzelparameter, Source + string pair[]; // Name-Pin-Paar mit Blank + string x[]; + string y[]; + string distY[];// Distanz der Abzweigung vom Pin + string np[]; // # Wires ab Pin + string nw[]; // # Wires ab erstem Wire-Segment nach Pin + string Sep = "\t"; + string net[]; + string sht[]; + string row[]; + string col[]; + + npar = strsplit(ps, line, '\t'); + for (j = 0; j < npar/2;) { // Zusammenfassen von Part und Pin mit Blank + pair[j++] = ps[n++] + " " + ps[n++]; + } + n = 0; + while (pair[n]) { // Sammeln der Pin-Informationen +// np[n] = lookup(pindatabase, PartPin, "NP", '\t'); + x[n] = lookup(pindatabase, pair[n], "x", '\t'); + y[n] = lookup(pindatabase, pair[n], "y", '\t'); + net[n] = lookup(pindatabase, pair[n], "Net", '\t'); + sht[n] = lookup(pindatabase, pair[n], "Sheet", '\t'); + row[n] = lookup(pindatabase, pair[n], "Row", '\t'); + col[n] = lookup(pindatabase, pair[n], "Column", '\t'); + if (!sht[n]) { + sht[n] = "?"; + col[n] = "?"; + row[n] = "?"; + } + n++; + } + if (npar <= 2) { + ErrorMessage(pair[0], "Netz nicht abgeschlossen!"); + return ""; + } + + netnr++; + sprintf (lxy, "%08d %08d", strtol(x[0]), strtol(y[0])); + sprintf (rxy, "%08d %08d", strtol(x[1]), strtol(y[1])); + + // Art voranstellen + snr = min (strtol(sht[0]), strtol(sht[1])); // Sheetnr + if (strtol(y[0]) <= YRef[snr] && strtol(y[1]) > YRef[snr]) ErrorMessage(pair[0], "Verbindung nicht eindeutig (intern oder extern?)"); + if (strtol(y[0]) > YRef[snr]) s = "d\t"; + if (strtol(y[0]) <= YRef[snr]) s = "k\t"; + if (strsub(pair[0], 0, 1) == "X" && ps[0] == ps[2]) s = "x\t"; + st += s; + + if ((lxy > rxy && strtol(sht[0]) == strtol(sht[1])) || (strtol(sht[0]) > strtol(sht[1]))) { // Reihenfolge Quelle-Ziel etc. tauschen + sprintf(s, "%03d%s", strtol(sht[1]), Sep); st+= s; + sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[1]), strtol(y[1]), Sep, strtol(x[0]), strtol(y[0]), Sep); st += s; + sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[1], Sep, sht[1], row[1], col[1], Sep); st += s + pair[1] + Sep + pair[0]; + sprintf(s, "%s%s.%s%s", Sep, sht[0], row[0], col[0]); st += s; + } + else { + sprintf(s, "%03d%s", strtol(sht[0]), Sep); st+= s; + sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[0]), strtol(y[0]), Sep, strtol(x[1]), strtol(y[1]), Sep); st += s; + sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[0], Sep, sht[0], row[0], col[0], Sep); st += s + pair[0] + Sep + pair[1]; + sprintf(s, "%s%s.%s%s", Sep, sht[1], row[1], col[1]); st += s; + } + + st += "\n"; + if (npar <= 4) return st; // nur Zweipunktverbindung + if (npar > 4) { // jeden mit dem Nachbarn verbinden (gleiches y hat Vorrang) + n = 2; + while (pair[n]) { + netnr++; + sprintf (lxy, "%08d %08d", strtol(x[n-1]), strtol(y[n-1])); + sprintf (rxy, "%08d %08d", strtol(x[n]), strtol(y[n])); + + // Art voranstellen + snr = min (strtol(sht[n-1]), strtol(sht[n])); // Sheetnr + if (strtol(y[n-1]) <= YRef[snr] && strtol(y[n]) > YRef[snr]) ErrorMessage(pair[n-1], "Verbindung nicht eindeutig (intern oder extern?)"); + if (strtol(y[n-1]) > YRef[snr]) s = "d\t"; + if (strtol(y[n-1]) <= YRef[snr]) s = "k\t"; + if (strsub(pair[n-1], 0, 1) == "X" && ps[(n-1)*2] == ps[n*2]) s = "x\t"; + st += s; + + if ((lxy > rxy && strtol(sht[n-1]) == strtol(sht[n])) || (strtol(sht[n-1]) > strtol(sht[n]))) { + sprintf(s, "%03d%s", strtol(sht[n]), Sep); st+= s; + sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[n]), strtol(y[n]), Sep, strtol(x[n-1]), strtol(y[n-1]), Sep); st += s; + sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[n], Sep, sht[n], row[n], col[n], Sep); st += s + pair[n] + Sep + pair[n-1]; + sprintf(s, "%s%s.%s%s", Sep, sht[n-1], row[n-1], col[n-1]); st += s; + } + else { + sprintf(s, "%03d%s", strtol(sht[n-1]), Sep); st+= s; + sprintf(s, "%08d %08d%s%08d %08d%s", strtol(x[n-1]), strtol(y[n-1]), Sep, strtol(x[n]), strtol(y[n]), Sep); st += s; + sprintf(s, "%d%s%s%s%s.%s%s%s", netnr, Sep, net[n-1], Sep, sht[n-1], row[n-1], col[n-1], Sep); st += s + pair[n-1] + Sep + pair[n]; + sprintf(s, "%s%s.%s%s", Sep, sht[n], row[n], col[n]); st += s; + } + st += "\n"; + n++; + } + } + return st; +} + +// Verbindungsliste aufbereiten +void ChangeList(void) { + int i, j, nl, np; + numeric string a[], c[], s, sh; + GetYReference(); // YRef[sheet] enthält y von unterstem Klemmenkontakt + + nl = fileread(a, tmpfile); + // sort(n, a); + output(tmpfile, "wtD") { // leere Zeilen entfernen + for (i = 0; i < nl; i++) { + if (a[i]) printf("%s\n",a[i]); + } + } + nl = fileread(a, tmpfile); + if (nl > 0) { + output(listfile, "wtD") { // sheetnr \t x y \t x y \t Nummer \t Netz \t Von .. + for (i = 0; i < nl; i++) { + a[i] = StripWhiteSpace(a[i]); // a[] enthält urspr. Connect-Zeilen + b[i] = a[i]; // b[] enthält Zeilen eines Signals und wird verändert (global) + b[i] = AssembleNetLine(b[i]); + if (b[i]) printf("%s", b[i]); // b[0..nl] -> alle Zeilen eines Signals geordnet nach Pos. + } + } + } + nl = fileread(a, listfile); // sortieren nach sheetnr und erstem x y \t xy + sort(nl, a); + output(listfile, "wtD") { + for (i = 0; i < nl; i++) { + strsplit(c, a[i], '\t'); + printf("%d\t%s\t%s\t%s\t%s\t%s\n", i + 1, c[6], c[7], c[8], c[9], c[0]); +// printf("%s\n", a[i]); + } + } +} + +//************** von Main benutzt ********************** + +void PushUndo(void) { + int i; + while (listundo[i]) { + listundo[i] = ""; + i++; + } + i = 0; + while (listsel[i]) { + listundo[i] = listsel[i]; + i++; + } +} + +void PullUndo(void) { + int i; + while (listsel[i]) { + listsel[i] = ""; + i++; + } + i = 0; + while (listundo[i]) { + listsel[i] = listundo[i]; + i++; + } +} + +void PushUndoOben(void) { + int i; + while (listundoOben[i]) { + listundoOben[i] = ""; + i++; + } + i = 0; + while (listall[i]) { + listundoOben[i] = listall[i]; + i++; + } +} + +void PullUndoOben(void) { + int i; + while (listundoOben[i]) { + i++; + } + if (i == 0) return; // wenn alte Liste leer (nach dem Start) + i = 0; + while (listall[i]) { + listall[i] = ""; + i++; + } + i = 0; + while (listundoOben[i]) { + listall[i] = listundoOben[i]; + i++; + } +} + +// Lies rohe Verbindungsliste +void ReadList(void) { + int i, j, np; + numeric string h[]; + NrLinesListAll = fileread(listall, listfile) -1; + for (i = 0; i < NrLinesListAll; i++) { + while (strsplit(h, listall[i], '\t') < NrHeader) listall[i] += "\t"; + listsel[i] = listall[i]; // erst, Auswahliste füllen, damit Listen gleich formatiert werden + } +} + +void ShowErrorList(void) { + dlgDialog("Fehlerliste") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout{ + dlgTextEdit(ErrCmd); + } + dlgHBoxLayout { + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("&Hilfe") dlgMessageBox( "Überprüfen Sie die in der Liste aufgeführten Kontakte!\n" + "Sie können die Fehlerliste auch editieren und mit Cut&Paste \n" + "zu einem Texteditor übertragen." + ); + dlgPushButton("+OK") dlgAccept(); + } + }; +} + +// Übertrage eine Verbindung in Auswahlliste, wenn noch nicht vorhanden +void TransferOneEntry(int Sel) { + int i, n; + string h1[], h2[]; + PushUndo(); + strsplit(h1, listall[Sel], '\t'); + while(listsel[i]) { + strsplit(h2, listsel[i], '\t'); + if (h1[Nummer] == h2[Nummer] && + h1[Von] == h2[Von] && + h1[Quelle] == h2[Quelle] && + h1[Ziel] == h2[Ziel] && + h1[Nach] == h2[Nach] + ) + return; // Zeilen identisch -> kein neuer Eintrag (nur feste Felder bis Nach geprüft) + i++; + } + i = 0; + while(listsel[i++]) { // finde letzte Zeile + } + listsel[i-1] = listall[Sel]; +} + +// Lösche eine Verbindung aus Auswahlliste +void DelOneEntry(int Sel) { + int i, n, imax; + string x[]; + PushUndo(); + if (Sel < 0) return; + //SelConnection = -1; + while(listsel[i++]) { + } + imax = i; + for (i = 0; i < imax; i++) { + if (i <= Sel) { + x[i] = listsel[i]; + } + else { + x[i-1] = listsel[i]; + } + } + listsel[imax-1] = ""; listsel[imax] = ""; + imax = imax -1; + for (i = 0; i < imax; i++) { + listsel[i] = x[i]; + } +} + +void SetSelParams(string c) { + int i; + for (i = 1; i < NrHeader; i++) { + SelParam[i] = c; // einige nicht relevant + } +} + +void SetChangeParams(string c) { + int i; + for (i = 1; i < NrHeader; i++) { + ChangeParam[i] = c; // einige nicht relevant + } +} + +// Suche mit Wildcard * +int WildMatch(string wild, string st) { // wild = Suchmuster, st = zu durchsuchender Sting + int wx, sx, pos; + string sw, ss; + wild = StripWhiteSpace(wild); + st = StripWhiteSpace(st); + if (wild == st || wild == "*") return 1; + if (!wild && st) return 0; + if (strchr(wild, '*') < 0 && strlen(wild) > 0 && st == "") return 0; // wild exist., aber kein * + if (strlen(wild) > 0 && st == "") { // wild exist. mit Nicht-*-Zeichen, st = "" + pos = 0; + sw = wild; + while (sw[pos]) { // Zeichen außer * in wild vorhanden -> return 0 + if (sw[pos] != '*') return 0; + pos++; + } + return 1; // wild ist **... + } + while (wild[wx] && st[sx]) { + while (wild[wx] != '*') { // vgl. bis zum nächsten * + if (wild[wx++] != st[sx++]) return 0; + if (sx == strlen(st) && !(wx == strlen(wild))) { // Ende von st erreicht aber nicht Ende von wild + if (wild[wx] == '*' && !wild[wx+1]) return 1; // nächstes Zeichen von wild ist *, dann Stringende + else return 0; + } + if (wx == strlen(wild) && !(sx == strlen(st))) return 0; // Ende von wild erreicht aber nicht Ende von st + if (wx == strlen(wild) && (sx == strlen(st))) return 1; // Ende von wild erreicht aber nicht Ende von st + } + // jetzt kommt zwingend ein *, wx steht auf Index von * + if (wx == strlen(wild) - 1) return 1; // Ende von wild erreicht und * + wx++; + while (st[sx] != wild[wx] && wild[wx] != '*') { // bis zum Match nach Stern + if (sx == strlen(st) -1) return 0; // Ende von st erreicht ohne Match + sx++; + } + } + return 1; +} + +// Von Verbindungs- in Auswahlliste +void TransferMatchingEntries(void) { + int iall, i, match1, match2, np; + string h[]; // Einzelparameter + PushUndo(); + SelParam[Quelle] = strupr(SelParam[Quelle]); + SelParam[Von] = strupr(SelParam[Von]); + while (listall[iall]) { + match1 = 0; + np = strsplit(h, listall[iall], '\t'); // bisherige Einzelpar. in h[] + if ((WildMatch(SelParam[Quelle], h[Quelle]) || WildMatch(SelParam[Quelle], h[Ziel])) && + (WildMatch(SelParam[Von], h[Von]) || WildMatch(SelParam[Von], h[Nach])) + ) match1 = 1; + match2 = 0; + for (i = Nach + 1; i < NrHeader; i++) { + if (WildMatch(SelParam[i], h[i]) ) { + match2 = 1; + } + else { + match2 = 0; + break; + } + } + if (match1 && match2) { // nach break + TransferOneEntry(iall); + } + iall++; + } + SelAll = -1; +} + +// Lösche alle Verbindungen aus Auswahlliste +void DelAllEntries(void) { + int i; + PushUndo(); + while(listsel[i]) { + listsel[i] = ""; + i++; + } +} + +void ChangeOneEntry(int Sel) { + int i; + PushUndo(); + for (i = Nach + 1; i < NrHeader; i++) { + h[i] = ChangeParam[i]; + } + listsel[Sel] = strjoin(h, '\t'); +} + +void EditOneEntry(int Sel) { + int i, np; + np = strsplit(h, listsel[Sel], '\t'); + for (i = np; i < NrHeader; i++) h[i] = ""; + dlgDialog("Editiere Verbindungs-Parameter") { + for (i = Nach + 1; i < NrHeader; i++) { + ChangeParam[i] = h[i]; + } + for (i = Nach + 1; i < NrHeader; i++) { + dlgHBoxLayout { + dlgLabel(head[i] + "\t"); + dlgStringEdit(ChangeParam[i]); + } + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("-Abbrechen") dlgReject(); + dlgPushButton("+OK") {dlgAccept(); ChangeOneEntry(Sel);} + } + }; +} + +void CopyChangeParams(int all) { + int i, j; + string h[]; + PushUndo(); + while (listsel[j]) { + strsplit(h, listsel[j], '\t'); + for (i = Nach + 1; i < NrHeader; i++) { + if (ChangeParam[i] != "" || all) + h[i] = ChangeParam[i]; + } + listsel[j] = strjoin(h, '\t'); + j++; + } +} + +void ApplyChanges(void) { + int j, k; + string ls[], la[]; + PushUndoOben(); + while (listall[j]) { + strsplit(la, listall[j], '\t'); // bisherige Zeile in la[] + k = 0; + while (listsel[k]) { + strsplit(ls, listsel[k], '\t'); // neue Zeile in ls[] + if ((la[Quelle] == ls[Quelle] && la[Ziel] == ls[Ziel]) || + (la[Quelle] == ls[Ziel] && la[Ziel] == ls[Quelle]) + ) { // Match-Zeile gefunden + ls[0] = la[0]; // alte Nummer verwenden + listall[j] = strjoin(ls, '\t'); + } + k++; + } + j++; + } +} + +// Übertrage Parameter der externen Liste nach listall und lösche die verwendeten aus listsel +void ApplyChangesOldList(void) { + int j, k; + string ls[], la[]; + while (listall[j]) { + strsplit(la, listall[j], '\t'); // bisherige Zeile in la[] + k = 0; + while (listsel[k]) { + strsplit(ls, listsel[k], '\t'); // neue Zeile in ls[] + if ((la[Quelle] == ls[Quelle] && la[Ziel] == ls[Ziel]) || + (la[Quelle] == ls[Ziel] && la[Ziel] == ls[Quelle]) + ) { // Match-Zeile gefunden + ls[0] = la[0]; // alte Nummer verwenden + listall[j] = strjoin(ls, '\t'); + DelOneEntry(k); + break; + } + k++; + } + j++; + } +} + +int LoadOldListOk(void) { + int LoadOk; + dlgDialog("Verbindungsliste laden") { + dlgHBoxLayout dlgSpacing(400); + dlgHBoxLayout { + dlgTextView ( "Achtung, wenn Sie eine vorhandene Verbindungsliste laden, " + "werden alle bisher definierten Parameter der Verbindungen " + "überschrieben, die in der aktuellen und der gespeicherten " + "Liste vorhanden sind!\n\n" + "Nicht gefundene Verbindungen sind im Auswahlfenster aufgelistet.\n\n" + ); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+Abbrechen") dlgReject(); + dlgPushButton("-Weiter") {LoadOk = 1; dlgAccept();} + } + }; + if (LoadOk) return 1; + else return 0; +} + +int CancelOk(void) { + int CancelOk; + dlgDialog("Programm verlassen") { + dlgHBoxLayout dlgSpacing(400); + dlgHBoxLayout { + dlgTextView ( "Wenn Sie das Programm abbrechen, verlieren Sie alle veränderten Parametereinträge!\n\n" + "Abbrechen?" + ); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+Nein") dlgReject(); + dlgPushButton("-Ja") {CancelOk = 1; dlgAccept();} + } + }; + if (CancelOk) return 1; + else return 0; +} + + +void ApplyOldList(void) { + int NrLines; + string FileName = dlgFileOpen("Verbindungsliste/Klemmenplan/Kabelplan/Brückenplan wählen", vbdfile, "Klemmenplan-Dateien (*.vbd);;Alle Dateien (*)"); + if (FileName) { + PushUndo(); + PushUndoOben(); + DelAllEntries(); + NrLines = fileread(listsel, FileName); + DelOneEntry(0); // Header löschen + ApplyChangesOldList(); + } +} + +void SaveList(void) { + int i; + schematic(SCH) vbdfile = filesetext(SCH.name, ".vbd"); + string FileName = dlgFileSave("Speichere Verbindungsliste", vbdfile); + if (FileName) { + string a[]; + output(FileName, "wt") { + printf ("%s\n", ListHeader); + while (listall[i]) { + printf("%s\n", listall[i]); // "%s" um Probleme zu vermeiden, wenn listall '%' enthält + i++; + } + } + } +} + +void MoveDown(int Sel) { + int i; + string hi[], lo[], tmp; + if (listall[Sel + 1]) { + PushUndoOben(); + while (listsel[i]) listsel[i++] = ""; + strsplit(hi, listall[Sel + 1], '\t'); + strsplit(lo, listall[Sel], '\t'); + tmp = hi[Nummer]; hi[Nummer] = lo[Nummer]; lo[Nummer] = tmp; // vertausche Rang + listall[Sel] = strjoin(hi, '\t'); + listall[Sel + 1] = strjoin(lo, '\t'); + SelAll = Sel + 1; + } +} + +void MoveUp(int Sel) { + int i; + string hi[], lo[], tmp; + if (Sel > 0) { + PushUndoOben(); + while (listsel[i]) listsel[i++] = ""; + strsplit(hi, listall[Sel], '\t'); + strsplit(lo, listall[Sel - 1], '\t'); + tmp = hi[Nummer]; hi[Nummer] = lo[Nummer]; lo[Nummer] = tmp; // vertausche Rang + listall[Sel] = strjoin(lo, '\t'); + listall[Sel - 1] = strjoin(hi, '\t'); + SelAll = Sel - 1; + } +} + +void ChangeSourceDest (int Sel) { + string h[], s; + if (Sel < 0) return; + PushUndoOben(); + strsplit(h, listall[Sel], '\t'); + s = h[Quelle]; h[Quelle] = h[Ziel]; h[Ziel] = s; + listall[Sel] = strjoin(h, '\t'); +} + +void ShowHelp(void) { + dlgDialog("Hilfe") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout{ + dlgVBoxLayout dlgSpacing(600); + dlgTextView(HelpText); + } + dlgHBoxLayout { + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + } + }; +} + +//***************************************************** +void ShowUserInterface(void) { +dlgDialog("Klemmenplan/Kabelplan erstellen - " + Version) { + dlgHBoxLayout dlgSpacing(800); + dlgGroup("") { + dlgLabel("Verbindungsliste"); + dlgListView(ListHeader, listall, SelAll, SortAll) TransferOneEntry(SelAll); + dlgSpacing(10); + } + dlgGroup("") { + dlgLabel("Auswahlliste"); + dlgListView(ListHeader, listsel, SelConnection, Sort) EditOneEntry(SelConnection); + dlgHBoxLayout { + dlgPushButton("Undo oben") PullUndoOben(); + dlgPushButton("Nach oben") MoveUp(SelAll); + dlgPushButton("Nach unten") MoveDown(SelAll); + dlgPushButton("Quelle <-> Ziel") ChangeSourceDest(SelAll); + dlgStretch(1); + dlgPushButton("Undo unten") PullUndo(); + dlgPushButton("Eintrag löschen") DelOneEntry(SelConnection); + dlgPushButton("Alle löschen") DelAllEntries(); + dlgPushButton("Anwenden") ApplyChanges(); + } + } + + dlgSpacing(10); + dlgHBoxLayout { + dlgGroup("Auswahl-Parameter") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgHBoxLayout { + dlgLabel(head[Quelle] + "/" + head[Ziel] + "\t"); + dlgStringEdit(SelParam[Quelle]); + } + dlgHBoxLayout { + dlgLabel(head[Von] + "/" + head[Nach] + "\t"); + dlgStringEdit(SelParam[Von]); + } + dlgGroup("") { + } + } + dlgVBoxLayout { + for (i = Nach + 1; i < NrHeader; i++) { + dlgHBoxLayout { + dlgLabel(head[i] + "\t"); + dlgStringEdit(SelParam[i]); + } + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("Löschen") SetSelParams(""); + dlgPushButton("Alle *") SetSelParams("*"); + dlgPushButton("Holen") TransferMatchingEntries(); + } + } + } + } + dlgGroup("Parameter ändern") { + for (i = Nach + 1; i < NrHeader; i++) { + dlgHBoxLayout { + dlgLabel(head[i] + "\t"); + dlgStringEdit(ChangeParam[i]); + } + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("Löschen") SetChangeParams(""); + dlgPushButton("Alle eintragen") CopyChangeParams(1); + dlgPushButton("Alle außer leere") CopyChangeParams(0); + } + } + } + + dlgHBoxLayout { + dlgPushButton("&Hilfe") ShowHelp(); + dlgStretch(1); + dlgPushButton("Fehlerliste") ShowErrorList(); + dlgPushButton("Lade ext. Liste") if (LoadOldListOk()) ApplyOldList(); + dlgPushButton("-Abbrechen") if (CancelOk()) dlgReject(); + dlgPushButton("+Speichern") SaveList(); + } + }; +} +//***************** Main ****************************** +NrHeader = strsplit(head, ListHeader, '\t'); +SetFileNames(); +SetupPinDatabase(); +ReadConnects(); +ChangeList(); +output(errorfile, "wt") printf(ErrCmd + "\n"); // hier sind alle Listen fertig (*.kp$ ohne Parameter-Einträge +// Oberfläche +ReadList(); +ShowUserInterface(); + diff --git a/trunk/ulp/e-makelist.ulp b/trunk/ulp/e-makelist.ulp new file mode 100644 index 00000000..6ada49aa --- /dev/null +++ b/trunk/ulp/e-makelist.ulp @@ -0,0 +1,285 @@ +// Generiere Liste als EAGLE-Script + +string Version = "Listenausgabe Version 1.0"; + +#require 4.9206 + +#usage "Erstellen von Listen auf EAGLE-Schaltplanseiten (nicht mit EAGLE Light)\n

    " + +"Mit diesem ULP erstellen Sie aus den Dateien, die von den Programmen " +"e-klemmenplan und e-brueckenverwaltung erzeugt wurden, " +"Listen, die Bestandteil eines Schaltplans sind.

    " + +"Außerdem können Sie mit diesem Programm Schaltplanseiten ab einer " +"bestimmten Seite bequem löschen.

    " + +"Author: support@cadsoft.de" + +int NrLines, i, j, np, maxlen[], PrintOff[], xstart, ystart, xtextpos, ypos, size; +int shnr, linedist, layer, lowmargin, linelength, fieldmarginchar, width, width_head; +int x_margin, y_margin, xright, MaxSize, linemil, delpage; +numeric string lines[], head[], item[]; +string FileName, FileTmp, Cmd, s, t, headline, fext, MaxSizeStr, CmdDel; + +/////////////////////////////////////////////////////////////////////////////////////// +// Folgende Parameter können vom Benutzer angepasst werden +// Alle Maße in mil = 1/1000 Zoll; 40 mil ist ca. 1 mm +fext = ".vbd"; +xstart = 150; // Trennlinien-Abstand vom linken Rand +xright = 11200; // x-Koordinate für Trennlinie rechts +ystart = 7750; // y-Koordinate für erste (obere) Trennlinie +lowmargin = 435; // y-Koordinate für letztmögliche (unterste) Trennlinie +linedist = 200; // Zeilenabstand +fieldmarginchar = 2; // zusätzliche Zeichen pro Feld (Abstand) +size = 140; // Texthöhe (wird intern optimiert) +width = 7; // Strichstärke für Trennlinien +width_head = 10; // Strichstärke für Trennlinien der Kopfzeile +layer = 94; // wenn ein anderer Layer angegeben wird, muss er definiert sein +/////////////////////////////////////////////////////////////////////////////////////// + +xtextpos = xstart + size; +ypos = ystart; +x_margin = size * fieldmarginchar/2; // Abstand zu Linien in mil +y_margin = (linedist - size)/2; // Versatz der Linien gegen Text vertikal +// shnr wird in SetFileNames auf höchste Seitennummer + 1 gesetzt + +string HelpText = + +"Erstellen von Listen auf EAGLE-Schaltplanseiten (nicht mit EAGLE Light)

    " + +"Mit diesem ULP erstellen Sie aus den Dateien, die von den Programmen " +"e-klemmenplan und e-brueckenverwaltung erzeugt wurden, " +"Listen, die Bestandteil eines Schaltplans sind.

    " + +"Nach dem Start des Programms wählen Sie, ob Sie eine Liste erstellen " +"oder eine vorher erstellte Liste ab einer bestimmten Seite löschen wollen.

    " + +"Liste erstellen

    " + +"Wählen Sie eine Datei, die Sie vorher mit den oben genannten Programmen erzeugt haben " +"(*.brk oder *.vbd).

    " + +"Im Menü links können Sie selektieren, welche Spalten der Datei nicht ausgegeben werden sollen. " +"Das Programm errechnet den Maximalwert der Textgröße (in mil), damit die Tabelle auf eine " +"Schaltplanseite passt. " +"Sie können den Wert innerhalb bestimmter Grenzen im Menü rechts verändern. " +"Ein Klick auf Liste erzeugen hängt die Liste an den bisherigen Schaltplan an. " +"Dabei wird auf den neuen Seiten jeweils der Rahmen von Seite 1 des Schaltplans verwendet. " +"Voraussetzung: er muss am Koordinatennullpunkt platziert sein.

    " + +"Anpassungen an andere Rahmen können Sie direkt im Programm vornehmen (siehe Kommentare).

    " + +"Achtung! Alle Maße in mil (40 mil ist ca. 1 mm)

    " + +"Seiten löschen

    " + +"Tragen Sie in das Textfeld die Seitennummer ein, ab der (inklusive) die restlichen Seiten " +"des Schaltplans gelöscht werden sollen, und klicken Sie auf Seiten löschen. " +"Bestätigen Sie dann die Fragen des Programms alle mit Ja, bis alle Seiten gelöscht sind.

    " + +"Die Seitennummer muss 2 oder größer sein.

    " +; + +void ShowHelp(void) { + dlgDialog("Hilfe\t\t\t\t\t") { + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout{ + dlgVBoxLayout dlgSpacing(600); + dlgTextView(HelpText); + } + dlgHBoxLayout { + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + } + }; +} + +void SetFileNames(void) { // in Schematic-Kontext aufrufen + if (!schematic) { + exit(1); + } + schematic(SCH) { + FileName = filesetext(SCH.name, fext); + FileTmp = filesetext(SCH.name, ".scr"); + i = 0; + SCH.sheets(SH) { + i++; + } + shnr = i + 1; + } +} + +void ReadFile(void) { + if (FileName != "") + NrLines = fileread(lines, FileName); +} + +int GetMaxSize(void) { + if (FileName == "") return MaxSize; + np = strsplit(head, lines[0], '\t'); + // Breite der Felder feststellen + for (i = 0; i < NrLines; i++) { + strsplit(item, lines[i], '\t'); + linelength = 0; // max # Zeichen + for (j = 0; j < np; j++) { + maxlen[j] = max(maxlen[j], strlen(item[j])); + if (!PrintOff[j]) { + linelength += maxlen[j] + fieldmarginchar; // linelength in Zeichen + } + } + } + // Höhe zu Breite = 100/85 + MaxSize = min (180, 11000 * 100 / (linelength * 85)); // max. 180 Mil + sprintf(MaxSizeStr, "Zeichengröße/mil (max. %d)\t", MaxSize); + return MaxSize; +} + +int GenerateScr(void) { + // Header + Cmd = ""; ypos = ystart; + GetMaxSize(); + if (size > MaxSize) return 0; // Zeilen zu lang (11050 ist max., aber 50 mil Sicherheit) + //Kommandostring erzeugen + sprintf(s, "grid mil 100 1;\n"); Cmd += s; + sprintf(s, "group (-1 -1) (-1 1) (1 1) (1 -1) (> -1 -1);\ncut (0 0);\n"); Cmd += s; + sprintf(s, "display -98;\n"); Cmd += s; + sprintf(s, "edit .S%d;\n", shnr); Cmd += s; + sprintf(s, "paste (0 0);\nwindow fit;\n"); Cmd += s; + sprintf(s, "change layer %d;\n", layer); Cmd += s; + sprintf(s, "change font fixed;\n"); Cmd += s; + sprintf(s, "change size %d;\n", size); Cmd += s; + sprintf(s, "change width %d;\n", width_head); Cmd += s; + sprintf(s, "wire (%d %d) (%d %d);\n", xstart, ypos, xright, ypos); Cmd += s; + for (i = 0; i < NrLines; i++) { + if (ypos > lowmargin + linedist) { + ypos -= linedist; + } + else { // neue Seite + ypos = ystart; + shnr++; + sprintf(s, "edit .S%d;\n", shnr); Cmd += s; + sprintf(s, "paste (0 0);\nwindow fit;\n"); Cmd += s; + sprintf(s, "change width %d;\n", width_head); Cmd += s; + sprintf(s, "wire (%d %d) (%d %d);\n", xstart, ypos, xright, ypos); Cmd += s; + ypos -= linedist; + sprintf (s, "text '%s' R0 (%d %d);\n", headline, xtextpos, ypos + y_margin); Cmd += s; + sprintf(s, "wire (%d %d) (%d %d);\n", xstart, ypos, xright, ypos); Cmd += s; + ypos -= linedist; + sprintf(s, "change width %d;\n", width); Cmd += s; + } + strsplit(item, lines[i], '\t'); + t = ""; + for (j = 0; j < np; j++) { + maxlen[j] = max(maxlen[j], strlen(item[j])); + if (!PrintOff[j]) { + sprintf (s, "%-*s", maxlen[j]+fieldmarginchar, item[j]); t += s; // t ist Textzeile + } + } + sprintf (s, "text '%s' R0 (%d %d);\n", t, xtextpos, ypos + y_margin); Cmd += s; + sprintf(s, "wire (%d %d) (%d %d);\n", xstart, ypos, xright, ypos); Cmd += s; + if (i == 0) { + headline = t; + sprintf(s, "change width %d;\n", width); Cmd += s; + } + } + Cmd += "grid last;\n"; + return 1; +} + +void OutputScr(string Cmd) { + output(FileTmp, "wtD") { + printf ("%s", Cmd); + } + exit("script '" + FileTmp + "';\n"); +} + +void DelSheets(int page) { + CmdDel = ""; + if (page == 0) return; + schematic(SCH) { + SCH.sheets(SH) { + if (SH.number >= page) { + sprintf(s, "remove .S%d;\n", page); + CmdDel += s; + } + } + } +} +//-------------------------------------------------------------------------------------- +void GetFileName(void) { + dlgDialog("Ausgangsdatei wählen") { + dlgHBoxLayout dlgSpacing(+450); + dlgTextView("Wählen Sie die Ausgangsdatei für die Listenausgabe, " + "normalerweise *.vbd oder *.brk, wie von den Programmen " + "e-klemmenplan oder e-brueckenverwaltung erzeugt.

    " + "Oder wählen Sie Seiten löschen, wenn Sie " + "Seiten Ihres Schaltplans löschen wollen." + ); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("&Seiten löschen") {FileName = ""; dlgAccept();} + dlgPushButton("+&Liste erzeugen") { + FileName = dlgFileOpen("Datei wählen", FileName, + "Klemmenplan (*.vbd);;Brückenplan (*.brk);;Alle Dateien (*)"); + if (FileName != "") dlgAccept(); + } + dlgPushButton("-&Beenden") exit(0); + } + }; +} + +void ShowUserInterface(void) { +dlgDialog(Version) { + dlgHBoxLayout dlgSpacing(100); + dlgHBoxLayout { + if (FileName != "") { + dlgGroup("Nicht drucken") { + for (i = 0; i < np; i++) { + dlgHBoxLayout { + dlgCheckBox(head[i], PrintOff[i]) if (GetMaxSize() < size) size = MaxSize; + } + } + dlgSpacing(10); + } + } + + dlgGroup("") { + if (FileName != "") + dlgHBoxLayout { + dlgLabel(MaxSizeStr, 1); + dlgIntEdit(size, 40, 180); + } + else + dlgHBoxLayout { + dlgLabel("Löschen ab Seite\t"); + dlgIntEdit(delpage, 0, 999); + } + } + + } + dlgSpacing(10); + dlgHBoxLayout { + } + dlgHBoxLayout { + dlgPushButton("&Hilfe") ShowHelp(); + dlgStretch(1); + if (FileName == "") + dlgPushButton("&Seiten Löschen") if (delpage > 1){DelSheets(delpage); OutputScr(CmdDel);} + else dlgMessageBox("Löschen erst ab Seite 2 möglich!", "OK"); + else + dlgPushButton("&Liste erzeugen") if (GenerateScr()) OutputScr(Cmd); + else dlgMessageBox("Wert für Textgröße zu hoch!", "OK"); + dlgPushButton("&Beenden") dlgReject(); + } + }; +} + +//-------------------------------------------------------------------------------------- + +SetFileNames(); +GetFileName(); +ReadFile(); +if (!GenerateScr()) size = MaxSize; +ShowUserInterface(); diff --git a/trunk/ulp/e-packages-aus-devices-pin-ist-padname.ulp b/trunk/ulp/e-packages-aus-devices-pin-ist-padname.ulp new file mode 100644 index 00000000..18e2a96b --- /dev/null +++ b/trunk/ulp/e-packages-aus-devices-pin-ist-padname.ulp @@ -0,0 +1,114 @@ +#usage "Generiert Dummy-Package für aktuelles Device im Bibliothekseditor\n" + "

    " + "Für Elektro-Bauteile empfiehlt es sich, dass Symbol-Pins und Package-Pads gleiche " + "Namen haben. Dieses Programm erzeugt ein Package mit identischen Pad-/Pin-Namen, " + "falls kein Pin-Name doppelt vorkommt.

    " + "Starten Sie das Programm im Bibliothekseditor, sobald Sie ein Device angelegt " + "und die Symbole mit dem Add-Befehl geholt haben. Es wird ein Package angelegt, " + "dessen Name dem des Device entspricht (falls noch nicht vorhanden) und dessen " + "Pads entsprechend den Pins benannt sind. Pins und Pads sind mit dem Connect-Befehl " + "verbunden.

    " + "Author: support@cadsoft.de" + +string Version = "1.0.2"; // 2012-03-23 Behandlung der Apostrophen in Pin/Pad-Namen berichtig. + // 2013-01-25 Bei nur einem Gate den Gate-Namen nicht benutzen um die Pad-Namen zu erzeugen +string cmd, concmd, s; +string f; +string PadName; +string CurrentDevice; +int PackagePresent = 0; +int PADname; + +int test = 0; + +// Da der ganze String in ' eingeschlossen wird, +// müssen die Apostrophen verdoppelt werden. +string addApostroph(string name) { // 2012-03-23 + string t[]; + int cnt = strsplit(t, name, '\''); // check Apostroph + if (cnt > 1) { + name = ""; + for (int i = 0; i < cnt; i++) { + if (i == 0) { + if (t[i]) name += t[i]; + } + else if (i) name += "''" + t[i]; + } + } + return name; +} + +if (library) { + library(L) { + f = filename(L.name); + f = filesetext(f, "$$$.scr"); + f = path_scr[0] + '/' + f; // verwende Script-Pfad + if (deviceset) { + deviceset(DS) { + CurrentDevice = DS.name; + DS.devices(D) { + if (!D.package && CurrentDevice == DS.name) { + sprintf(s, "EDIT %s.PAC;\n", DS.name); + cmd += s; + sprintf(s, "DESCRIPTION 'Dummy';\n"); + cmd += s; + sprintf(s, "GRID MM; CHANGE DRILL 0.5; CHANGE DIAMETER 1.0;\n"); + cmd += s; + sprintf(s, "EDIT %s.DEV;\n", DS.name); + concmd += s; + sprintf(s, "PAC '%s' '';\n", DS.name); + concmd += s; + int cntg = 0; + DS.gates(G) { + cntg++; + } + DS.gates(G) { + string gname = addApostroph(G.name); + if (cntg == 1) gname = ""; // 2013-01-25 bei nur einem Gate, nur den Pin-Namen beutzen. + G.symbol.pins(P) { + PadName = (P.name); + sprintf(s, "PAD '%s%s' (%.4f %.4f);\n", + gname, addApostroph(PadName), + u2mm(P.x), + u2mm(P.y)-7.62 + ); // Pin-Offset im Device in Y-Richtung + cmd += s; + sprintf(s, "CONNECT '%s.%s' '%s%s';\n", + addApostroph(G.name), + addApostroph(P.name), + gname, + addApostroph(PadName) + ); + concmd += s; + } + } + } + } + } + } + L.packages(P) { + if (CurrentDevice == P.name) PackagePresent = 1; + } + } + cmd += concmd; + if (cmd && !PackagePresent) { + if (test) { + dlgDialog("Check") { + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgTextEdit(cmd); + } + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("Abbrechen") { dlgReject(); exit(-1); } + } + }; + } + output(f, "wtD") printf("%s", cmd); // temporäre Script-Datei erzeugen + exit("SCRIPT '"+ f +"'"); + } + else dlgMessageBox("Device hat schon ein Package oder Package mit dem Namen des Device schon vorhanden.", "OK"); +} + +else dlgMessageBox("Das ULP kann nur vom Bibliothekseditor aus geladen werden!", "OK"); \ No newline at end of file diff --git a/trunk/ulp/eagle.bmp b/trunk/ulp/eagle.bmp new file mode 100644 index 00000000..a016d3a7 Binary files /dev/null and b/trunk/ulp/eagle.bmp differ diff --git a/trunk/ulp/eagleidfexporter.ulp b/trunk/ulp/eagleidfexporter.ulp new file mode 100644 index 00000000..864a7c58 --- /dev/null +++ b/trunk/ulp/eagleidfexporter.ulp @@ -0,0 +1,2872 @@ +#usage "Generate IDF files from CADSoft Eagle

    \n" +"Run ULP on board file to generate IDF board and library files for import to CAD tools.
    " +"Version: 0.1 - Development Started - 12-8-13
    " +"Version: 0.2 - Bug fix and cleanup - 12-21-13
    " +"Version: 0.3 - Added in logic to lookup height if set - 1-29-14
    " +"Version: 0.4 - Added validations on height values to ensure only number values are passed - 2-7-14
    " +"Version: 0.5 - Baseline commit before code style changes - 3-20-14
    " +"Version: 0.6 - Code style Issues addressed - 3-20-14
    " +"Version: 0.7 - Updated component outline bounding box logic - 4-13-14
    " +"Version: 0.8 - Cleanup of unused functions - 5-3-14
    " +"Version: 0.9 - Fixed minor GUI issues related to reset of html table values - 5-6-14
    " +"Version: 0.10 - Added logic for varied heights in packages on board - 5-6-14
    " +"Version: 0.11 - Fixed bug in logic to handle HEIGHT attributes set with numbertext value.- 5-13-14
    " +"Version: 1.0 - Initial production release.- 5-21-14
    " +"Version: 1.1 - Change to consider circles on layer 20 regardless of other lines. Improved arc/circle processing logic. - 9-6-14
    " +"Version: 2.0 - Updated to integrate with SSI IDF site - 3-25-15
    " +"Version: 2.1 - Updates to include banner and links - 3-29-15
    " +"Version: 2.2 - Updates to logic to open links in browser - 4-7-15
    " +"

    " +"Author: marc.battistello@gmail.com" + +#require 5.1000 +string version = "2.2"; //ulp version + +//vars used for the text dialog +string TextMessageDialog; //used to store text shown to user + +string HeightHtmlTable = ""; + +string BoardThickness = "1.6"; //mm +string WireLayer = "20"; +//string DummyHistory[]; + +string LibraryLookup = "RCL:RESISTOR:TRANSISTOR:PINHEAD:RESISTOR-DIL:SMARTPRJ:C5B2,5A:CAP-WI:POLCAP:ELKO:CON-PTR500:SPECIAL:LED:CAPACITOR-WIMA:CON-WAGO-500:CON-HARTING-ML:ST-ML:CON-ML:CON-LSTB:CON-BERG:CON-SUBD:POLCAP"; +string Libraries[]; //used to hold Libraries +string PackageOutlines[]; //used to hold outlines of packages +int PackageCounter = 0; //keeps track of how many entries in packages outline array + +string NULL_HEIGHT = "0.000000"; //used for null heights + +//web request urls +string Host = "http://www.simplifiedsolutionsinc.com"; +string Service_port = "8080"; +//string service_port = "80"; +string Static_port = "80"; +string Service_name = "EMN-EMPAdvancedApp/EagleTo3DSSIServlet"; +string Login_name = "EMN-EMPAdvancedApp/LinkLoginServlet"; +string Static_name = "EagleTo3D/"; +string Service_url = Host + ":" + Service_port + "/" + Service_name; +string Login_url = Host + ":" + Service_port + "/" + Login_name; +string Static_url = Host + "/" + Static_name; + +int useSecondaryMappings = 1; +int useSuggestionMappings = 1; + +//debug flags +int Debug = 1; //general Debug flag + + +//----------------------------------------------------------------------------- +// subroutines +//----------------------------------------------------------------------------- + +string itos(int num) { + string temp; + + sprintf(temp, "%d", num); + + return temp; +} + +string rtos(real num) { + string temp; + + sprintf(temp, "%f", num); + + return temp; +} + +int IsInt(string str) { + //returns 1 if int. 0 if not string + + //first check to make sure its not "0" which Is the fail mode for the cast + if (str == "0") { + return 1; + } else if (strtol(str) != 0) { + return 1; + } else { + return 0; + } + +} //end IsInt + +int IsReal(string str) { + //returns 1 if int. 0 if not string + + //first check to make sure its not "0.0" which Is the fail mode for the cast + if (str == "0.0") { + return 1; + } else if (strtod(str) != 0.0) { + return 1; + } else { + return 0; + } + +} //end IsInt + +int CompareReals(real n1, real n2) { + string n1s; + string n2s; + + sprintf(n1s, "%1.2f", n1); + sprintf(n2s, "%1.2f", n2); + + if (n1s == n2s) { + return 1; + } else { + return 0; + } +} + +string GetBoardThickness() { + //make sure there Is value for board thickness + if (BoardThickness == "") { + BoardThickness = "1.6"; + } + + //check if first char Is decimal and if it Is then add 0 + char dec = '.'; + int pos = strchr(BoardThickness, dec); + + if (pos == 0) { + BoardThickness = "0" + BoardThickness; + } + + //return form value + return BoardThickness; +} //end func + +string GetBoardUnits() { + + /* + GRID_UNIT_MIC microns + GRID_UNIT_MM millimeter + GRID_UNIT_MIL mil + GRID_UNIT_INCH inch + */ + + /* force to mm + string unitsMap[] = { "MIC", "MM", "MIL", "IN" }; + + board(B) { + return unitsMap[ B.grid.unit ]; + } + */ + + return "MM"; +} + +real BackConvertDimensions(real mmDim) { + real boardDim; + int unitsInt; + + //get board dimensions + board(B) + { + unitsInt = B.grid.unit; + } + + /* + GRID_UNIT_MIC microns + GRID_UNIT_MM millimeter + GRID_UNIT_MIL mil + GRID_UNIT_INCH inch + */ + + switch (unitsInt) { + case 0: + //micron + boardDim = mmDim * 1000; + break; + case 1: + //mm + boardDim = mmDim; + break; + case 2: + //mil + boardDim = mmDim * 39.3700787; + break; + case 3: + //inch + boardDim = mmDim * 0.0393701; + break; + + } //end switch + + //string unitsMap[] = { "MIC", "MM", "MIL", "IN" }; + + //dlgMessageBox( "MM:" + rtos( mmDim ) + ", " + unitsMap[ unitsInt ] + ": " + rtos( boardDim ) ); + + return boardDim; + +} //end func + +real GetDimInBoardUnits(int dim) { + int unitsInt; + real convDim; + + /* removed for force to mm + board(B) { + unitsInt = B.grid.unit; + } + + switch( unitsInt ){ + case 0: + convDim = u2mic( dim ); + break; + case 1: + convDim = u2mm( dim ); + break; + case 2: + convDim = u2mil( dim ); + break; + case 3: + convDim = u2inch( dim ); + break; + + } //end switch + */ + + convDim = u2mm(dim); + + return convDim; +} //end func + +real GetTolerance() { + int unitsInt; + real Tolerance; + + /* removed to force to mm + board(B) { + unitsInt = B.grid.unit; + } + + switch( unitsInt ){ + case 0: + Tolerance = 100; + break; + case 1: + Tolerance = 0.05; + break; + case 2: + Tolerance = 3.9; + break; + case 3: + Tolerance = 0.004; + break; + + } //end switch + */ + + Tolerance = 0.05; + + return Tolerance; +} //end func + +string GetBoardFilename() { + board(BRD) + { + return filename(BRD.name); + } //end board +} + +string GetBoardDir() { + + board(BRD) + { + return filedir(BRD.name); + } //end board +} + +string GetBoardPath() { + + return GetBoardDir() + GetBoardFilename(); + +} + +string PadBRs( int count ){ + + string padding = ""; + + for( int i; i < count; i++ ){ + + + padding += "
    "; + } + + return padding; +} + +int IsWindows() { + //Returns 1, if EAGLE Is running under Windows (0 for Linux/Mac) + if ((strsub(argv[0], 0, 1) == "/") && (strsub(argv[0], 0, 2) != "//")) + return 0; + + return 1; +} //end sub + + +int IsMac(){ + if( (strsub( OS_SIGNATURE, 0, 3 ) == "Mac") || (strsub( OS_SIGNATURE, 0, 3 ) == "MAC") ) + return 1; + + return 0; + +} + +void LaunchBrowser( string url ){ + + string launchCmd = ""; + + if( IsWindows() ){ + launchCmd = "explorer \"" + url + "\""; + } + else if( IsMac() ){ + launchCmd = "open " + url; + } + else{ + //assume all others linux + //if you are on linux then change this line if the buttons dont work + launchCmd = "xdg-open " + url; + } + + + //run system command + system( launchCmd ); + } //end launch browser + +string GetFileSeperator() { + + if (IsWindows()) { + return "\\"; + } else { + return "/"; + } + +} + +// Removes carriage returns from a string and replaces with
    +string RemoveCarriageReturns(string dirtyString) { + + string cleanedString; + + for (int i = 0; dirtyString[i]; ++i) { + if (dirtyString[i] == '\n') { + cleanedString += "
    "; + } else { + cleanedString += dirtyString[i]; + } //end if-else + } //end for + + return cleanedString; +} //end sub + +// Removes spaces in string and replaces with +string RemoveSpaces(string dirtyString) { + + string cleanedString; + + for (int i = 0; dirtyString[i]; ++i) { + if (dirtyString[i] == ' ') { + cleanedString += ""; + } else { + cleanedString += dirtyString[i]; + } //end if-else + } //end for + + return cleanedString; +} //end sub + +string CleanString(string dirtyString) { + + dirtyString = strupr(dirtyString); + + string cleanedString; + + for (int i = 0; dirtyString[i]; ++i) { + if (dirtyString[i] == '0' || dirtyString[i] == '1' + || dirtyString[i] == '2' || dirtyString[i] == '3' + || dirtyString[i] == '4' || dirtyString[i] == '5' + || dirtyString[i] == '6' || dirtyString[i] == '7' + || dirtyString[i] == '8' || dirtyString[i] == '9' + || dirtyString[i] == 'A' || dirtyString[i] == 'B' + || dirtyString[i] == 'C' || dirtyString[i] == 'D' + || dirtyString[i] == 'E' || dirtyString[i] == 'F' + || dirtyString[i] == 'G' || dirtyString[i] == 'H' + || dirtyString[i] == 'I' || dirtyString[i] == 'J' + || dirtyString[i] == 'K' || dirtyString[i] == 'L' + || dirtyString[i] == 'M' || dirtyString[i] == 'N' + || dirtyString[i] == 'O' || dirtyString[i] == 'P' + || dirtyString[i] == 'Q' || dirtyString[i] == 'R' + || dirtyString[i] == 'S' || dirtyString[i] == 'T' + || dirtyString[i] == 'U' || dirtyString[i] == 'V' + || dirtyString[i] == 'W' || dirtyString[i] == 'X' + || dirtyString[i] == 'Y' || dirtyString[i] == 'Z' + || dirtyString[i] == '_' || dirtyString[i] == '-' + || dirtyString[i] == ' ') { + + cleanedString += dirtyString[i]; + } else { + cleanedString += "_"; + } //end if-else + } //end for + + return cleanedString; +} //end sub + +// Removes spaces in string and replaces with +string ReplaceSpaceWithUnderscore(string dirtyString) { + + string cleanedString; + + for (int i = 0; dirtyString[i]; ++i) { + if (dirtyString[i] == ' ') { + cleanedString += "_"; + } else { + cleanedString += dirtyString[i]; + } //end if-else + } //end for + + return cleanedString; +} //end sub + +// 0-9, letters, dashes, and underscores are always safe. + +// Reads in file and converts it to be used in a html form submit +string ParseFileToHtmlForm(string filePath) { + + string fileContents; + + int in = fileread(fileContents, filePath); + + fileContents = RemoveCarriageReturns(fileContents); + + fileContents = RemoveSpaces(fileContents); + + //dlgMessageBox( "File input value:" + in ); + + return fileContents; +} //end sub + +string ParseStringToHtmlForm(string input) { + + return RemoveSpaces(RemoveCarriageReturns(input)); + +} //end sub + +//this function Is used to Get the html to show in the UI. +//it uses a fixed header and footer and the call sets the body. +string GetHtmlText(string body) { + + string os; + + //build header html + string htmlHeader = + " \ + \ + \ + \ + \ + \ + \ + \ + \ + "; + + string htmlFooter = ""; //footer will be built later including OS padding + + //detect if windows or other + if (IsWindows()) { + os = "Windows"; + } else { + os = "Mac/Linux"; + } + + //build footer and include OS specific padding for formatting. + if (IsWindows()) { + htmlFooter += "






    "; + } else { + htmlFooter += ""; + } //end if-else + + //build version string + string versionString = "ULP Version: " + version + ", OS: " + os; + + //build footer text + htmlFooter += + " \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +

    EAGLE IDF Exporter


    CADSoft | Help( ULP Version: " + + version + "\t, OS: " + os + + " )

    "; + + return htmlHeader + "" + body + "" + + htmlFooter; +} //end sub + +real GetDistBetweenPts(real x1, real y1, real x2, real y2) { + //dist = sqrt( ( x2 - x1 )^2 + ( y2 - y1 )^2 ) + + return sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2)); + +} //end sub + +void WriteToFile(string filePath, string fileContents) { + + output(filePath, "wt") + { + printf(fileContents); + } +} //end sub + + +string GetElementHeightAttr( UL_ELEMENT E ){ + /* checks for attribute named HEIGHT. + * casts height string to real to handle any invalid values. sets to 0 if not value. + * returns height + */ + + string height = NULL_HEIGHT; + + //check for element height + E.attributes(A) + { + if (strupr(A.name) == "HEIGHT") { + if ( strtod(A.value) <= 0.0) { + height = NULL_HEIGHT; + } else { + height = rtos( strtod( A.value ) ); + } //end if-else + } //end if + } //end loop thru attributes + + return height; +} //end sub + +//----------------------------------------------------------------------------- +// emp subroutines +//----------------------------------------------------------------------------- + + + + + +string GetDateTime() { + + //time for date.time in header + int now = time(); + string dateStr; + + sprintf(dateStr, "%d/%02d/%02d.%02d:%02d:%02d", t2year(now), t2month(now), + t2day(now), t2hour(now), t2minute(now), t2second(now)); + + return dateStr; + +} //end sub + +//looks up package outline and generates text for .electical section entry +string GetComponentOutline(string footprint, string altname, string packageName, + string units, string height) { + + //package array = [ { packname1, maxX, maxY, minX, minY }, + // { packname2, maxX, maxY, minX, minY } + // ] + + //board->Library->Package->Wires + + int foundPackage = 0; + + //lookup package name in array + string packageNameLookup = lookup(PackageOutlines, packageName, 0); + + //check if found in lookup. if not then generate and put in array + if (packageNameLookup == "") { + //if package not in lookup then generate it + + //init max/min values + real maxX = 0, maxY = 0, minX = 0, minY = 0; + + //loop thru all Libraries to find packagename + board(B) + { + + //go into library + B.libraries(LBR) + { + + //loop thru packages in library + LBR.packages(P) + { + //if package name matches the one we are looking for then process it + if (P.name == packageName) { + //check min/ax for each of + //circles() UL_CIRCLE - C.x, C.y, C.radius, C.width) + //holes() UL_HOLE + //polygons() UL_POLYGON -> wires() + //rectangles() UL_RECTANGLE - R.x1, R.y1, R.x2, R.y2); + //wires() UL_WIRE + + //set found package flag + foundPackage = 1; + + //used to capture first loop of data + int loopCounter = 0; + real w2; //holds 1/2 of width + + //loop thru wires and Get max/min x/y + //do wires first to take care of loopCounter == 0 case + P.wires(W) + { + //get first data point + if (loopCounter == 0) { + w2 = W.width / 2; + minX = GetDimInBoardUnits( + min(W.x1 - w2, W.x2 - w2)); + minY = GetDimInBoardUnits( + min(W.y1 - w2, W.y2 - w2)); + maxX = GetDimInBoardUnits( + max(W.x1 + w2, W.x2 + w2)); + maxY = GetDimInBoardUnits( + max(W.y1 + w2, W.y2 + w2)); + } + + if (W.arc) { + w2 = W.width / 2; + if (W.arc.angle2 > 360) + maxX = max(maxX, + GetDimInBoardUnits( + W.arc.xc + W.arc.radius)); + else if (((W.arc.angle1 < 90) + && (W.arc.angle2 > 90)) + || (W.arc.angle2 > 450)) + maxY = max(maxY, + GetDimInBoardUnits( + W.arc.yc + W.arc.radius + + w2)); + else if (((W.arc.angle1 < 180) + && (W.arc.angle2 > 180)) + || (W.arc.angle2 > 540)) + minX = min(minX, + GetDimInBoardUnits( + W.arc.xc - W.arc.radius + - w2)); + else if (((W.arc.angle1 < 270) + && (W.arc.angle2 > 270)) + || (W.arc.angle2 > 630)) + minY = min(minY, + GetDimInBoardUnits( + W.arc.yc - W.arc.radius + - w2)); + } + else { + //handle non arc wires + minX = min(minX, GetDimInBoardUnits(W.x1)); + minY = min(minY, GetDimInBoardUnits(W.y1)); + maxX = max(maxX, GetDimInBoardUnits(W.x1)); + maxY = max(maxY, GetDimInBoardUnits(W.y1)); + } //end if-else + + loopCounter++; + } //end wires + + //UpdateBBoxBox(C.x - C.radius - w2, C.y - C.radius - w2, C.x + C.radius + w2, C.y + C.radius + w2); + // xmin, ymin, xmax, ymax + P.circles(C) + { + w2 = C.width / 2; + minX = min(minX, + GetDimInBoardUnits(C.x - C.radius - w2)); + minY = min(minY, + GetDimInBoardUnits(C.y - C.radius - w2)); + maxX = max(maxX, + GetDimInBoardUnits(C.x + C.radius + w2)); + maxY = max(maxY, + GetDimInBoardUnits(C.y + C.radius + w2)); + + loopCounter++; + } //end circles + + //P.holes(){} - Not required. These are solder masks + + P.polygons(POLY) + { + POLY.wires(PW) + { + minX = min(minX, GetDimInBoardUnits(PW.x1)); + minY = min(minY, GetDimInBoardUnits(PW.y1)); + maxX = max(maxX, GetDimInBoardUnits(PW.x1)); + maxY = max(maxY, GetDimInBoardUnits(PW.y1)); + loopCounter++; + } //end wires in polygon + } //end polgons + + P.rectangles(R) + { + minX = min(minX, + min(GetDimInBoardUnits(R.x1), + GetDimInBoardUnits(R.x2))); + minY = min(minY, + min(GetDimInBoardUnits(R.y1), + GetDimInBoardUnits(R.y2))); + maxX = max(maxX, + max(GetDimInBoardUnits(R.x1), + GetDimInBoardUnits(R.x2))); + maxY = max(maxY, + max(GetDimInBoardUnits(R.y1), + GetDimInBoardUnits(R.y2))); + + loopCounter++; + } //end rectangles + + //break out of loop since match found + break; + + } //end if for package name match + } //end packages loop + } //end Libraries loop + } //end board loop + + //make sure found match. if not then put in default values + string temp; + + if (foundPackage) { + //load to array + sprintf(temp, "%s\t%f\t%f\t%f\t%f", packageName, maxX, maxY, minX, + minY); + + } else { + sprintf(temp, "%s\t%f\t%f\t%f\t%f", packageName, maxX, maxY, minX, + minY); + } //end if-else for found package check + + //add data to package outline so it can be reused in future + PackageOutlines[PackageCounter] = temp; + + PackageCounter++; + } //end if for lookup check + + //generate outline data. first line is footpring, name, and units + string outline = footprint + " " + altname + " " + units; + + //set default height based on units + if (units == "MM") { + outline += " " + height + "\n"; + + //check if height set. if not set to 1.0 + /*if (height == "1.0") { + outline += " 1.00\n"; + } + else { + outline += " " + height + "\n"; + }*/ + } + /*else if (units == "THOU") { + //check if + if (height == "0.0") { + outline += " 39.37\n"; + } + else { + outline += " " + height + "\n"; + } + } + */ + else { + //treat as MM + //check if + if (height == "1.0") { + outline += " 1.00\n"; + } else { + outline += " " + height + "\n"; + } + } //end if-else + + //map in max/min data + string maxX = lookup(PackageOutlines, packageName, 1); + string maxY = lookup(PackageOutlines, packageName, 2); + + string minX = lookup(PackageOutlines, packageName, 3); + string minY = lookup(PackageOutlines, packageName, 4); + + /*rectangle based on max/min values. start in upper left and move clockwise + 0 minX maxY + 0 maxX maxY + 0 maxX minY + 0 minX minY + 0 minX maxY + */ + + //if max/min are all zeros then put in 1x1 block + if (maxX == "0.000000" && maxY == "0.000000" && minX == "0.000000" + && minX == "0.000000") { + outline += "0 1.00 -1.00 0.0\n" + "0 -1.00 -1.00 0.0\n" + + "0 -1.00 1.00 0.0\n" + "0 1.00 1.00 0.0\n" + + "0 1.00 -1.00 0.0\n"; + } + //if they are all the same they also set in 1x1 block so that something is shown + else if (maxX == minX || maxY == minY) { + outline += "0 1.00 -1.00 0.0\n" + "0 -1.00 -1.00 0.0\n" + + "0 -1.00 1.00 0.0\n" + "0 1.00 1.00 0.0\n" + + "0 1.00 -1.00 0.0\n"; + } + //otherwise actual coords provided. use those in output + else { + outline += "0 " + minX + " " + maxY + " 0.0\n" + "0 " + maxX + + " " + maxY + " 0.0\n" + "0 " + maxX + " " + minY + + " 0.0\n" + "0 " + minX + " " + minY + " 0.0\n" + + "0 " + minX + " " + maxY + " 0.0\n"; + } //end if-else + + return outline; +} //end sub + +string GetEmpHeader() { + /* + .HEADER + LIBRARY_FILE 3.0 "Commend International >generate_3d_data_v10-5_MJB.ulp V0.9<" 2012/03/21.12:23:09 1 + .END_HEADER + */ + + return ".HEADER\n" + "LIBRARY_FILE 3.0 \"Eagle IDF Exporter " + version + + "\" " + GetDateTime() + "\n" + ".END_HEADER\n"; + +} //end sub + +string GetEmpElectrical() { + /* + .ELECTRICAL + TSSOP16 NOREFDES MM 4876.80 + 0 -2.51 -2.28 0 + 0 2.51 -2.28 0 + 0 2.51 2.28 0 + 0 -2.51 2.28 0 + 0 -2.51 -2.28 0 + .END_ELECTRICAL + */ + + string electricalSection; + + string footprint; + string altname; + string height = NULL_HEIGHT; + + string LibraryLookup; + + string components[]; + + string component; + + //loop thru elements on board + board(BRD) + { + + int i = 0; + + BRD.elements(E) + { + + height = NULL_HEIGHT; + + //check if library in lookup + LibraryLookup = lookup(Libraries, strupr(E.package.library), 0); + + //set footprint and altname based on logic + if (LibraryLookup != "") { + footprint = E.package.name; + altname = E.package.name; + + //add comment to emn for debuggin + //placementSection += "#Resistor or rcl library found\n"; + } else if (E.value != "") { + altname = E.value; + footprint = E.package.name; + + //add comment to emn for debuggin + //placementSection += "#E.value present\n"; + } else { + //if library Is not in list and the E.value Is blank then concat refid and package name + altname = E.name + "_" + E.package.name; + footprint = E.package.name; + + //add comment to emn for debuggin + //placementSection += "#Fallback logic applied. Not res/rcl and E.value not found.\n"; + } + + altname = CleanString(altname); + footprint = CleanString(footprint); + + //check for element height + /* + E.attributes(A) + { + if (strupr(A.name) == "HEIGHT") { + + if (strtod(A.value) < 0) { + height = "0.000000"; + } else { + height = rtos(strtod(A.value)); + } //end if-else + + } //end if + } //end loop thru attributes + */ + + //check if height set for element. if not set then set to NULL_HEIGHT + height = GetElementHeightAttr( E ); + + //add component to height lookup table + HeightHtmlTable = HeightHtmlTable + "" + E.name + + "" + altname + "" + E.package.name + + ""; + + //if height is not set then set to default + if (height == NULL_HEIGHT) { + height = "1.0"; //set to value of 1.0 + HeightHtmlTable = HeightHtmlTable + "" + height + ""; + } else { + HeightHtmlTable = HeightHtmlTable + "" + height + ""; + } //if-else for height value + + + //if height is default value then do not append it to altname. this will prevent the height from poluting the naming convention + //if height is not default then append it to altname so that its unique + if( height == "1.0" ){ + //component = lookup(components, footprint + "~" + altname, 0); - Fix for multi comp and heights + component = lookup(components, footprint + "~" + altname, 0); + + //if component Is empty then it has not been written out yet. + if (component == "") { + + //build section by call to GetComponentOutlineDummy( string footprint, string altname, string units ) + electricalSection += ".ELECTRICAL\n" + + GetComponentOutline(footprint, altname, E.package.name, GetBoardUnits(), height) + + ".END_ELECTRICAL\n"; + + //add component to components list. + //components[i] = footprint + "~" + altname; - Fix for multi comp and heights + components[i] = footprint + "~" + altname; + + i++; + } //end if + + } + else{ + component = lookup(components, footprint + "_" + height + "~" + altname + "_" + height, 0); + + //if component Is empty then it has not been written out yet. + if (component == "") { + + //build section by call to GetComponentOutlineDummy( string footprint, string altname, string units ) + electricalSection += ".ELECTRICAL\n" + + GetComponentOutline(footprint + "_" + height, altname + "_" + height, E.package.name, GetBoardUnits(), height) + + ".END_ELECTRICAL\n"; + + //add component to components list. + //components[i] = footprint + "~" + altname; - Fix for multi comp and heights + components[i] = footprint + "_" + height + "~" + altname + "_" + height; + + i++; + } //end if + + } //end if-else + + + + } //end loop thru elements + } //end loop thru board + + return electricalSection; + +} //end sub + +string GetEmpMechanical() { + + return ""; +} //end sub + +//----------------------------------------------------------------------------- +// emn subroutines +//----------------------------------------------------------------------------- +string GetEmnHeader() { + /* + .HEADER + BOARD_FILE 3.0 "Commend International >generate_3d_data_v10-5_MJB.ulp V0.9<" 2012/03/21.12:23:10 1 + "untitled.brd" MM + .END_HEADER + */ + + string boardName; + + //get board name + board(BRD) + { + boardName = filename(BRD.name); + } + + return ".HEADER\n" + "BOARD_FILE 3.0 \"Eagle IDF Exporter Version " + + version + "\" " + GetDateTime() + "\n" + "\"" + boardName + "\" " + + GetBoardUnits() + "\n" + ".END_HEADER\n"; + +} //end sub + +string SetUsedFlag(string pt) { + string fields[]; + int fieldCount = strsplit(fields, pt, '\t'); + + return fields[0] + "\t" + fields[1] + "\t" + fields[2] + "\t" + fields[3] + + "\ty\n"; +} + +int IsUsedPoint(string pt) { + string fields[]; + int fieldCount = strsplit(fields, pt, '\t'); + + if (fields[4] == "n\n") + return 0; + else + return 1; +} + +string IsUsedPointDebug(string pt) { + string fields[]; + int fieldCount = strsplit(fields, pt, '\t'); + + return fields[4]; + +} + +string FlipPoints(string line) { + string fields[]; + + int fieldCount = strsplit(fields, line, '\t'); + + return fields[2] + "\t" + fields[3] + "\t" + fields[0] + "\t" + fields[1] + + "\t" + fields[4]; +} + +string GetFieldFromPtString(string ptString, int index) { + string fields[]; + + // "pt 1\ttype\tx1\ty1\tx2\ty2\tsorted_flag" + int fieldCount = strsplit(fields, ptString, '\t'); + + if (fieldCount >= index) { + return fields[index]; + } else { + return ""; + } //end if-else + +} //end sub + +real GetX1FromPtString(string ptString) { + return strtod(GetFieldFromPtString(ptString, 0)); +} //end sub + +real GetY1FromPtString(string ptString) { + return strtod(GetFieldFromPtString(ptString, 1)); +} //end sub + +real GetX2FromPtString(string ptString) { + return strtod(GetFieldFromPtString(ptString, 2)); +} //end sub + +real GetY2FromPtString(string ptString) { + return strtod(GetFieldFromPtString(ptString, 3)); +} //end sub + +int LayerNumInUse(int layerNum) { + //returns true=1 if layer Is being used. returns 0 if layer Is not used. + int layerUsed = 0; + + board(B) + { + B.layers(L) + { + if (L.number == layerNum) { + layerUsed = 1; + } //end if + } //layers loop + } //board loop + + return layerUsed; +} + +int LayerIsIDFDebug(int layerNum) { + board(B) + { + B.layers(L) + { + if (L.number == layerNum && L.name == "IDFDebug") { + return 1; + } //end if + } //layers loop + } //board loop + + return 0; +} + +string GetIDFDebugLayerAvailNum() { + + //loop thru layers and check for name IDFDebug + int startSearchNumber = 100; + int layerAvail = -1; + + for (int i = startSearchNumber; i < 256; ++i) { + + //if layer Is not in use then use it. also have to check if layer Is in use but Is already idf debug + if (!LayerNumInUse(i)) { + layerAvail = i; + break; + } else { + //check to make sure layer Is not already idf debug + if (LayerIsIDFDebug(i)) { + layerAvail = i; + break; + } //end if + } //end if-else + } //end for + + string temp; + + sprintf(temp, "%d", layerAvail); + + return temp; + +} //end func + +string GetIDFDebugLayerNum() { + + //loop thru layers and check for name IDFDebug + int IDFDebugLayerNum = -1; + + board(B) + { + B.layers(L) + { + if (L.name == "IDFDebug") { + IDFDebugLayerNum = L.number; + } //end if + } //layers loop + } //board loop + + string temp; + + sprintf(temp, "%d", IDFDebugLayerNum); + + return temp; + +} //end func + +string RemoveIDFDebugLayerCommands() { + + //check if present + string debugLayerNum = GetIDFDebugLayerNum(); + + //if debugLayerNum Is -1 then it doesnt exist so no delete needed. + if (debugLayerNum == "-1") { + return ""; + } else { + string commands; + + //commands + //show only IDFDebugLayer + commands += "DISPLAY -20 " + debugLayerNum + ";"; + + //run group all command to select all circles + //commands += "GROUP ALL;"; + + //delete circles + //DELETE (x y) where x y are points on circle outline + board(B) + { + B.circles(C) + { + if (C.layer == strtol(debugLayerNum)) { + + commands += "DELETE ( " + rtos(GetDimInBoardUnits(C.x)) + + " " + rtos(GetDimInBoardUnits(C.y)) + " );"; + + } //end if + } //end wire loop + + B.wires(W) + { + if (W.layer == strtol(debugLayerNum)) { + + commands += "DELETE ( " + rtos(GetDimInBoardUnits(W.x1)) + + " " + rtos(GetDimInBoardUnits(W.y1)) + " );"; + + } //end if + } //end wire loop + + } //board loop + + //delete layer now + commands += "LAYER ?? -" + debugLayerNum + ";"; + + return commands; + } //end if/else +} //end fund + +int CountWireHoles() { + int holeCount = 0; + + board(BRD) + { + /* + BRD.holes(H){ + + holeCount++; + } //end holes + */ + + BRD.circles(C) + { + if (C.layer == strtol(WireLayer)) { + holeCount++; + } + } + } //end board loop + + return holeCount; + +} //end func + +real Tolerance = GetTolerance(); + +/* +string getComponentOutlinePoints(){ + + //init vars + int Debug = 1; //used for debugging and generation of log in board outline processing + string logFilePath = filesetext(GetBoardPath(), ".log"); + string BoardThickness = GetBoardThickness(); + string boardOutlineSection = ".BOARD_OUTLINE UNOWNED\n" + BoardThickness + "\n"; + int wireCount = 0; + + string outlinePoints[]; //holds points extracted from board + string outlinePointsSorted[]; //holds points after they are sorted + + real deg2rad = 0.0174532925; //used to convert degress to radians for arc parsing + + real bx1 = 0.0, by1 = 0.0, bx2 = 0.0, by2 = 0.0; //line start and end points + real startX = 0.0, startY = 0.0; + int outlineNum = 0; + + //used for drawing arc lines + real incx = 0.0, incy = 0.0; //store incremental x/y values for arc + real currentAngle = 0.0, incrementAngle = 15.0; + + string temp; //temp string used with sprintf + + int newOutline = 1; + string pad = " "; + + real minDist = -1.0; //used to keep track of min distance found + real dist = 0.0; //used to store distance between two points + + string fromPoints, toPoints; + string boardOutlineSectionDebug; + + int matchFound = 0; + + //get list of component names in board + board(B){ + + //go into library + B.libraries(LBR){ + + //loop thru packages in library + LBR.packages(P){ + + + + dlgMessageBox( P.name ); + + } //end package loop + + } //end library loop + + } //end board loop + + exit(0); + + // Step 1 & 2 + //loop thru layer 20 and wires on layer + board(BRD) + { + //loop thru wires + BRD.wires(W) + { + + //only pull layer 20 wires + if (W.layer == strtol(WireLayer)) { + //get wire start and end points + + //get x/y for start and end. + bx1 = GetDimInBoardUnits(W.x1), by1 = GetDimInBoardUnits(W.y1), bx2 = + GetDimInBoardUnits(W.x2), by2 = GetDimInBoardUnits(W.y2); + + //handle arcs and lines differently + if (W.arc) { + + //for arc Get data to generate points + real angle1 = W.arc.angle1, angle2 = W.arc.angle2, centerx = + GetDimInBoardUnits(W.arc.xc), centery = + GetDimInBoardUnits(W.arc.yc); + + real endx = bx2, endy = by2; //store arc end points to close arc. + + //reset current angle value + currentAngle = incrementAngle; + + //determine which direction to draw arc by Getting x/y points based on angle1 + incx = (cos(deg2rad * (angle1)) + * GetDimInBoardUnits(W.arc.radius)) + centerx; + incy = (sin(deg2rad * (angle1)) + * GetDimInBoardUnits(W.arc.radius)) + centery; + + //check if arc start points match calculated start points using angle1. if they do then its a counter clockwise drawn arc + if (CompareReals(incx, bx1) && CompareReals(incy, by1)) { + + ///loop thru 5 deg increments + //arc defined counter clockwise so you need to subtract the increment + while ((angle1 + currentAngle) < angle2) { + + incx = (cos(deg2rad * (angle1 + currentAngle)) + * GetDimInBoardUnits(W.arc.radius)) + + centerx; + incy = (sin(deg2rad * (angle1 + currentAngle)) + * GetDimInBoardUnits(W.arc.radius)) + + centery; + + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx, incy); + + outlinePoints[wireCount] = temp; + + currentAngle += incrementAngle; + + wireCount++; + + //update beginning x/y values + bx1 = incx; + by1 = incy; + } //end while + + } else { + ///loop thru 5 deg increments + //arc defined counter clockwise so you need to subtract the increment + while ((angle2 - currentAngle) > angle1) { + + incx = (cos(deg2rad * (angle2 - currentAngle)) + * GetDimInBoardUnits(W.arc.radius)) + + centerx; + incy = (sin(deg2rad * (angle2 - currentAngle)) + * GetDimInBoardUnits(W.arc.radius)) + + centery; + + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx, + incy); + + outlinePoints[wireCount] = temp; + + currentAngle += incrementAngle; + + wireCount++; + + //update beginning x/y values + bx1 = incx; + by1 = incy; + } //end while + } //end if/else for check on direction of arc + + //close arc + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, endx, endy); + + outlinePoints[wireCount] = temp; + + wireCount++; + } else { + //process lines + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, bx2, by2); + + outlinePoints[wireCount] = temp; + + wireCount++; + + } //end if for arc + } //end if check for layer=20 + } //end loop thru wires + } //end loop thru board + + //if there are wireholes then consider those as part of the outline + if ( CountWireHoles() > 0) { + + board(B){ + B.circles(C){ + + if (C.layer == strtol(WireLayer)) { + + real angle1 = 0; + real angle2 = 360; + + real currentAngle = 0; + + real radius = GetDimInBoardUnits(C.radius); + real centerx = GetDimInBoardUnits(C.x); + real centery = GetDimInBoardUnits(C.y); + real bx1 = centerx + radius; + real by1 = centery; + + while ((angle1 + currentAngle) <= angle2) { + + //handle first point where angle = 0 + if( currentAngle == 0 ){ + incx = (cos(deg2rad * (angle1 + (incrementAngle/2))) * radius) + centerx; + incy = (sin(deg2rad * (angle1 + (incrementAngle/2))) * radius) + centery; + } + else{ + incx = (cos(deg2rad * (angle1 + currentAngle)) * radius) + centerx; + incy = (sin(deg2rad * (angle1 + currentAngle)) * radius) + centery; + } //end if-else for current angle = 0 + + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx,incy); + + outlinePoints[wireCount] = temp; + + currentAngle += incrementAngle; + + wireCount++; + + //update beginning x/y values + bx1 = incx; + by1 = incy; + } //end while + + } //end if for layer check + + } //end circle loop + + } //end board loop + + } //wire holes if + + return outlinePoints; + + + } //end func + + */ + +string GetEmnBoardOutline() { + + /* + Board outline logic + -------------------- + 1. Loop thru wires on layer 20 and parse out points based on type of wire. + Wire can be either arc or line. If it Is an arc then the .arc property Is set to 1. + + 2. For lines extract the start and end points. For arcs you need to convert them in + to a set of lines that simulates an arc by drawing a line at angle increments. + + 3. After looping thru the wires on layer 20 verify that wires were actually found. + If none were found then exit the ulp and notify the user no lines were found on layer 20. + + 4. Once the points are loaded to the array they need to reordered so that they are written in the correct order in the outline. This Is + due to fact that the loop thru .wires provides the wires in the order they were drawn and not necessarily in the correct order. + To accomplish this you need to first fine the start point. I do this by finding the point closest to 0,0. + + 5. Once the line with a start point closest to 0,0 Is found I then look thru the points to find a match for the end point of the first line. + The lines may not be written in end point to start point so you need to check for closet match on both the start and end. + + 6. After sorting the lines you can now write out the points to the board_outline section. I check for matches from end to start points. + If a match Isnt found then I assume a new outline Is found and increment the counter. I also need to make sure that when a new outline Is found that the prev + outline Is closed. + */ + + //init vars + int Debug = 1; //used for debugging and generation of log in board outline processing + string logFilePath = filesetext(GetBoardPath(), ".log"); + string BoardThickness = GetBoardThickness(); + string boardOutlineSection = ".BOARD_OUTLINE UNOWNED\n" + BoardThickness + "\n"; + int wireCount = 0; + + string outlinePoints[]; //holds points extracted from board + string outlinePointsSorted[]; //holds points after they are sorted + + real deg2rad = 0.0174532925; //used to convert degress to radians for arc parsing + + real bx1 = 0.0, by1 = 0.0, bx2 = 0.0, by2 = 0.0; //line start and end points + real startX = 0.0, startY = 0.0; + int outlineNum = 0; + + //used for drawing arc lines + real incx = 0.0, incy = 0.0; //store incremental x/y values for arc + real currentAngle = 0.0, incrementAngle = 15.0; + + string temp; //temp string used with sprintf + + int newOutline = 1; + string pad = " "; + + real minDist = -1.0; //used to keep track of min distance found + real dist = 0.0; //used to store distance between two points + + string fromPoints, toPoints; + string boardOutlineSectionDebug; + + int matchFound = 0; + + /* Step 1 & 2 */ + //loop thru layer 20 and wires on layer + board(BRD) + { + //loop thru wires + BRD.wires(W) + { + + //only pull layer 20 wires + if (W.layer == strtol(WireLayer)) { + //get wire start and end points + + //get x/y for start and end. + bx1 = GetDimInBoardUnits(W.x1), by1 = GetDimInBoardUnits(W.y1), bx2 = + GetDimInBoardUnits(W.x2), by2 = GetDimInBoardUnits(W.y2); + + //handle arcs and lines differently + if (W.arc) { + + //for arc Get data to generate points + real angle1 = W.arc.angle1, angle2 = W.arc.angle2, centerx = + GetDimInBoardUnits(W.arc.xc), centery = + GetDimInBoardUnits(W.arc.yc); + + real endx = bx2, endy = by2; //store arc end points to close arc. + + //reset current angle value + currentAngle = incrementAngle; + + //determine which direction to draw arc by Getting x/y points based on angle1 + incx = (cos(deg2rad * (angle1)) + * GetDimInBoardUnits(W.arc.radius)) + centerx; + incy = (sin(deg2rad * (angle1)) + * GetDimInBoardUnits(W.arc.radius)) + centery; + + //check if arc start points match calculated start points using angle1. if they do then its a counter clockwise drawn arc + if (CompareReals(incx, bx1) && CompareReals(incy, by1)) { + + ///loop thru 5 deg increments + //arc defined counter clockwise so you need to subtract the increment + while ((angle1 + currentAngle) < angle2) { + + incx = (cos(deg2rad * (angle1 + currentAngle)) + * GetDimInBoardUnits(W.arc.radius)) + + centerx; + incy = (sin(deg2rad * (angle1 + currentAngle)) + * GetDimInBoardUnits(W.arc.radius)) + + centery; + + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx, incy); + + outlinePoints[wireCount] = temp; + + currentAngle += incrementAngle; + + wireCount++; + + //update beginning x/y values + bx1 = incx; + by1 = incy; + } //end while + + } else { + ///loop thru 5 deg increments + //arc defined counter clockwise so you need to subtract the increment + while ((angle2 - currentAngle) > angle1) { + + incx = (cos(deg2rad * (angle2 - currentAngle)) + * GetDimInBoardUnits(W.arc.radius)) + + centerx; + incy = (sin(deg2rad * (angle2 - currentAngle)) + * GetDimInBoardUnits(W.arc.radius)) + + centery; + + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx, + incy); + + outlinePoints[wireCount] = temp; + + currentAngle += incrementAngle; + + wireCount++; + + //update beginning x/y values + bx1 = incx; + by1 = incy; + } //end while + } //end if/else for check on direction of arc + + //close arc + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, endx, endy); + + outlinePoints[wireCount] = temp; + + wireCount++; + } else { + //process lines + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, bx2, by2); + + outlinePoints[wireCount] = temp; + + wireCount++; + + } //end if for arc + } //end if check for layer=20 + } //end loop thru wires + } //end loop thru board + + //if there are wireholes then consider those as part of the outline + if ( CountWireHoles() > 0) { + + board(B){ + B.circles(C){ + + if (C.layer == strtol(WireLayer)) { + + real angle1 = 0; + real angle2 = 360; + + real currentAngle = 0; + + real radius = GetDimInBoardUnits(C.radius); + real centerx = GetDimInBoardUnits(C.x); + real centery = GetDimInBoardUnits(C.y); + real bx1 = centerx + radius; + real by1 = centery; + + while ((angle1 + currentAngle) <= angle2) { + + //handle first point where angle = 0 + if( currentAngle == 0 ){ + incx = (cos(deg2rad * (angle1 + (incrementAngle/2))) * radius) + centerx; + incy = (sin(deg2rad * (angle1 + (incrementAngle/2))) * radius) + centery; + } + else{ + incx = (cos(deg2rad * (angle1 + currentAngle)) * radius) + centerx; + incy = (sin(deg2rad * (angle1 + currentAngle)) * radius) + centery; + } //end if-else for current angle = 0 + + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx1, by1, incx,incy); + + outlinePoints[wireCount] = temp; + + currentAngle += incrementAngle; + + wireCount++; + + //update beginning x/y values + bx1 = incx; + by1 = incy; + } //end while + + } //end if for layer check + + } //end circle loop + + } //end board loop + + } //wire holes if + + /* Step 3 - Verify wires found */ + if (wireCount == 0) { + dlgMessageBox("No wires were found on layer 20.\nUnable to detect board outline. Exiting."); + + + //add in check if user wants to use a component as the board outline + if ( dlgMessageBox("No outlines were found on layer 20.\n\nWould you like to select a component to use as outline?\n\nIf you select No then the program will exit.", "&Yes", "&No") == 0) { + //call function to get from component and then assign to ouline array + //outlinePoints = getComponentOutlinePoints(); + } + else{ + exit(0); + } + + } //end if for wirecount = 0 check + + + if (Debug) { + boardOutlineSectionDebug += + "########### array before sorts ###########\n"; + + for (int j = 0; j < wireCount; j++) { + sprintf(temp, "%d\t%s", j, outlinePoints[j]); + + boardOutlineSectionDebug += temp; + } //end for + } //end if for debug + + /* + //calculate Tolerance based on 1/2 of smallest wire length + for( int i = 0; i < wireCount; i++ ){ + bx1 = GetX1FromPtString( outlinePoints[ i ] ); + by1 = GetY1FromPtString( outlinePoints[ i ] ); + bx2 = GetX2FromPtString( outlinePoints[ i ] ); + by2 = GetY2FromPtString( outlinePoints[ i ] ); + + dist = GetDistBetweenPts( bx1, by1, bx2, by2 ); + + if( minDist == -1.0 ){ + minDist = dist; + } + else if( dist < minDist ){ + minDist = dist; + } + else{ + //do nothing if dist Is not smaller then minDist + } + } //end for loop + + Tolerance = minDist / 2; + */ + + /* Step 4 & 5 - Verify wires found */ + //loop thru points and sort so they are in order + //outer loop thru points + boardOutlineSectionDebug += "Tolerance=" + rtos(Tolerance) + ".\n"; + + for (int i = 0; i < wireCount; i++) { + + //boardOutlineSection += itos( outlineNum ) + pad + + // rtos( GetX1FromPtString( outlinePoints[ i ] ) ) + pad + + // rtos( GetY1FromPtString( outlinePoints[ i ] ) ) + pad + "0\n"; + + outlinePoints[i] = SetUsedFlag(outlinePoints[i]); + + //get line end points + bx2 = GetX2FromPtString(outlinePoints[i]); + by2 = GetY2FromPtString(outlinePoints[i]); + + //handle initializations, new outlines, and closed outline checks. + if (i == 0) { + startX = GetX1FromPtString(outlinePoints[i]); + startY = GetY1FromPtString(outlinePoints[i]); + + boardOutlineSection += itos(outlineNum) + pad + + rtos(GetX1FromPtString(outlinePoints[i])) + pad + + rtos(GetY1FromPtString(outlinePoints[i])) + pad + "0\n"; + + newOutline = 0; + } + else if (newOutline) { + startX = GetX1FromPtString(outlinePoints[i]); + startY = GetY1FromPtString(outlinePoints[i]); + + boardOutlineSection += itos(outlineNum) + pad + + rtos(GetX1FromPtString(outlinePoints[i])) + pad + + rtos(GetY1FromPtString(outlinePoints[i])) + pad + "0\n"; + + newOutline = 0; + } + //check if point closes outline + else if (GetDistBetweenPts(startX, startY, + GetX2FromPtString(outlinePoints[i]), + GetY2FromPtString(outlinePoints[i])) == 0) { + boardOutlineSection += itos(outlineNum) + pad + + rtos(GetX2FromPtString(outlinePoints[i])) + pad + + rtos(GetY2FromPtString(outlinePoints[i])) + pad + "0\n"; + + outlineNum++; + + newOutline = 1; + + continue; + } //end if + else if (GetDistBetweenPts(startX, startY, + GetX2FromPtString(outlinePoints[i]), + GetY2FromPtString(outlinePoints[i])) <= Tolerance) { + boardOutlineSection += itos(outlineNum) + pad + rtos(startX) + pad + + rtos(startY) + pad + "0\n"; + + outlineNum++; + + newOutline = 1; + + continue; + } //end if + + matchFound = 0; + + //inner loop thru points to find matching line + for (int j = 0; j < wireCount; j++) { + + //boardOutlineSectionDebug += "Checking points for i=" + itos( i ) + " and j=" + itos( j ) + ".\n"; + + //check if line Is already used. if it Is then skip it + if (!IsUsedPoint(outlinePoints[j])) { + + //check for exact match on line start + if (GetDistBetweenPts(bx2, by2, + GetX1FromPtString(outlinePoints[j]), + GetY1FromPtString(outlinePoints[j])) == 0) { + + boardOutlineSectionDebug += "*Exact match for i=" + itos(i) + + " and j=" + itos(j) + ".\n"; + boardOutlineSectionDebug += "*i point " + outlinePoints[i]; + + boardOutlineSection += itos(outlineNum) + pad + + rtos(GetX1FromPtString(outlinePoints[j])) + pad + + rtos(GetY1FromPtString(outlinePoints[j])) + pad + + "0\n"; + + //flag points as used + outlinePoints[j] = SetUsedFlag(outlinePoints[j]); + + //swap matched point with current point + //outlinePoints = swapPoints( outlinePoints, (i+1), j ); + + toPoints = outlinePoints[j]; + fromPoints = outlinePoints[(i + 1)]; + + //move toIndex to from position + outlinePoints[(i + 1)] = toPoints; + outlinePoints[j] = fromPoints; + + matchFound = 1; + + break; + } + //check for exact match on line end + else if (GetDistBetweenPts(bx2, by2, + GetX2FromPtString(outlinePoints[j]), + GetY2FromPtString(outlinePoints[j])) == 0) { + boardOutlineSectionDebug += "*Exact match for i=" + itos(i) + + " and j=" + itos(j) + ".\n"; + boardOutlineSectionDebug += "*i point " + outlinePoints[i]; + + boardOutlineSection += itos(outlineNum) + pad + + rtos(GetX2FromPtString(outlinePoints[j])) + pad + + rtos(GetY2FromPtString(outlinePoints[j])) + pad + + "0\n"; + + //flag point as used + outlinePoints[j] = SetUsedFlag(outlinePoints[j]); + + boardOutlineSectionDebug += "\t*Before flip \t" + + outlinePoints[j]; + + //flip point + outlinePoints[j] = FlipPoints(outlinePoints[j]); + + boardOutlineSectionDebug += "\t*After flip \t" + + outlinePoints[j]; + + //swap matched point with current point + //outlinePoints = swapPoints( outlinePoints, (i+1), j ); + + toPoints = outlinePoints[j]; + fromPoints = outlinePoints[(i + 1)]; + + //move toIndex to from position + outlinePoints[(i + 1)] = toPoints; + outlinePoints[j] = fromPoints; + + matchFound = 1; + + break; + } + //check for Tolerance match on line start + else if (GetDistBetweenPts(bx2, by2, + GetX1FromPtString(outlinePoints[j]), + GetY1FromPtString(outlinePoints[j])) <= Tolerance) { + + boardOutlineSectionDebug += "*Tolerance match for i=" + + itos(i) + " and j=" + itos(j) + ". Dist=" + + rtos( + GetDistBetweenPts(bx2, by2, + GetX1FromPtString(outlinePoints[j]), + GetY1FromPtString( + outlinePoints[j]))) + "\n"; + boardOutlineSectionDebug += "*i point " + outlinePoints[i]; + + boardOutlineSection += itos(outlineNum) + pad + rtos(bx2) + + pad + rtos(by2) + pad + "0\n"; + + boardOutlineSectionDebug += "\t*Before fix for Tolerance \t" + + outlinePoints[j]; + + //update matched point start points to prev line end points to fix the gap + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", bx2, by2, + GetX2FromPtString(outlinePoints[j]), + GetY2FromPtString(outlinePoints[j])); + + outlinePoints[j] = temp; + + boardOutlineSectionDebug += "\t*After fix for Tolerance \t" + + outlinePoints[j]; + + //flag points as used + outlinePoints[j] = SetUsedFlag(outlinePoints[j]); + + //swap matched point with current point + //outlinePoints = swapPoints( outlinePoints, (i+1), j ); + + toPoints = outlinePoints[j]; + fromPoints = outlinePoints[(i + 1)]; + + //move toIndex to from position + outlinePoints[(i + 1)] = toPoints; + outlinePoints[j] = fromPoints; + + matchFound = 1; + + break; + } + //check for Tolerance match on line end + else if (GetDistBetweenPts(bx2, by2, + GetX2FromPtString(outlinePoints[j]), + GetY2FromPtString(outlinePoints[j])) <= Tolerance) { + + boardOutlineSectionDebug += "*Tolerance match for i=" + + itos(i) + " and j=" + itos(j) + ". Dist=" + + rtos( + GetDistBetweenPts(bx2, by2, + GetX2FromPtString(outlinePoints[j]), + GetY2FromPtString( + outlinePoints[j]))) + "\n"; + boardOutlineSectionDebug += "*i point " + outlinePoints[i]; + + boardOutlineSection += itos(outlineNum) + pad + rtos(bx2) + + pad + rtos(by2) + pad + "0\n"; + + boardOutlineSectionDebug += "\t*Before fix for Tolerance \t" + + outlinePoints[j]; + + //update matched point start points to prev line end points to fix the gap + sprintf(temp, "%f\t%f\t%f\t%f\tn\n", + GetX1FromPtString(outlinePoints[j]), + GetY1FromPtString(outlinePoints[j]), bx2, by2); + + outlinePoints[j] = temp; + + boardOutlineSectionDebug += "\t*After fix for Tolerance \t" + + outlinePoints[j]; + + //flag points as used + outlinePoints[j] = SetUsedFlag(outlinePoints[j]); + + boardOutlineSectionDebug += "\t*Before flip \t" + + outlinePoints[j]; + + //flip point + outlinePoints[j] = FlipPoints(outlinePoints[j]); + + boardOutlineSectionDebug += "\t*After flip \t" + + outlinePoints[j]; + + //swap matched point with current point + //outlinePoints = swapPoints( outlinePoints, (i+1), j ); + + toPoints = outlinePoints[j]; + fromPoints = outlinePoints[(i + 1)]; + + //move toIndex to from position + outlinePoints[(i + 1)] = toPoints; + outlinePoints[j] = fromPoints; + + matchFound = 1; + + break; + } + //else line has not matching point. + else { + //boardOutlineSectionDebug += "No match for i=" + itos( i ) + " and j=" + itos( j ) + ".\n"; + + } //end if-else + + } else { + //do nothing for skipped line + //boardOutlineSectionDebug += "Points skipped for i=" + itos( i ) + " and j=" + itos( j ) + ".\n"; + } //end if/else + + } //end j loop + + //check to make sure a matching point was found. if not notify user and mark on board. + if (!matchFound) { + boardOutlineSectionDebug += "No match for i=" + itos(i) + ".\n"; + + //if no match found then generate circle command and exit. + string circleDefectCommands; + string runCommands; + + sprintf(circleDefectCommands, "CIRCLE (%f %f) (%f %f);", + BackConvertDimensions(bx2), BackConvertDimensions(by2), + BackConvertDimensions(bx2 + 2.0), + BackConvertDimensions(by2)); + + //delete existing Debug layer if it exists + runCommands += RemoveIDFDebugLayerCommands(); + + //get Debug layer number + string debugLayerNum = GetIDFDebugLayerAvailNum(); + + //dlgMessageBox( "A fatal defect was found in your board outline in the form\n" + + // "of a gap in the board outline. We cannot repair this defect.\n\n" + + // "Defects will be shown on layer " + debugLayerNum + " with red circles." ); + + dlgMessageBox( + "An error was found in your board outline that cannot be automatically repaired. Outlines must be enclosed loops.\n" + + "Defects will be shown on layer " + debugLayerNum + + " with red circles."); + + string wireCommands = "change width 0.01;\nSET Wire_Bend 2;\n"; + + if (Debug) { + boardOutlineSectionDebug += + "########### array after sorts ###########\n"; + + //build wire commands that will draw the outlines that have been matched. the last wire will be drawn but it has no match + for (int j = 0; j < wireCount; j++) { + sprintf(temp, "%d\t%s", j, outlinePoints[j]); + boardOutlineSectionDebug += temp; + + if (IsUsedPoint(outlinePoints[j])) { + wireCommands += "WIRE ( " + + rtos( + BackConvertDimensions( + GetX1FromPtString( + outlinePoints[j]))) + + " " + + rtos( + BackConvertDimensions( + GetY1FromPtString( + outlinePoints[j]))) + + ") (" + + rtos( + BackConvertDimensions( + GetX2FromPtString( + outlinePoints[j]))) + + " " + + rtos( + BackConvertDimensions( + GetY2FromPtString( + outlinePoints[j]))) + + ");"; + } + } //end for + } //end if + + //circleDefectCommands = "LAYER 100 IDFDebug;SET COLOR_LAYER 100 red;CHANGE WIDTH 0.01;" + + //removed change width comand + runCommands += "LAYER " + debugLayerNum + " IDFDebug;" + + "SET COLOR_LAYER " + debugLayerNum + " red;" + + circleDefectCommands + wireCommands + "DISPLAY NONE;" + + "DISPLAY 20 " + debugLayerNum + ";" + "WINDOW FIT;"; + + if (Debug) { + WriteToFile(logFilePath, + boardOutlineSectionDebug + "***************\n" + + runCommands + "***************\n" + + boardOutlineSection); + } + + exit(runCommands); + } //end if for matchfound + + } //end i loop + + if (Debug) { + boardOutlineSectionDebug += + "########### array after sorts ###########\n"; + + for (int j = 0; j < wireCount; j++) { + sprintf(temp, "%d\t%s", j, outlinePoints[j]); + + boardOutlineSectionDebug += temp; + } //end for + } //end if + + if (Debug) { + WriteToFile(logFilePath, + boardOutlineSectionDebug + "***************\n" + + boardOutlineSection); + } + + boardOutlineSection += ".END_BOARD_OUTLINE\n"; + + return boardOutlineSection; +} //end GetEmnBoardOutline + +string GetEmnDrilledHoles() { + /* + .DRILLED_HOLES + 40.0 1773.0 1207.5 PTH S1 PIN ECAD + 40.0 1773.0 1384.5 PTH S1 PIN ECAD + 40.0 2029.0 1207.5 PTH S1 PIN ECAD + ... + .END_DRILLED_HOLES + */ + + string drilledHolesSection = ".DRILLED_HOLES\n"; + string temp; + + int holeCount = 0; + + board(BRD) + { + //loop thru holes + BRD.holes(H) + { + sprintf(temp, "%10.4f%10.4f%10.4f NPTH BOARD OTHER UNOWNED\n", + (GetDimInBoardUnits(H.drill)), (GetDimInBoardUnits(H.x)), + (GetDimInBoardUnits(H.y))); + + drilledHolesSection += temp; + + holeCount++; + } //end holes + + //get any holes from packages on elements + BRD.elements(E) + { + E.package.holes(C) + { + sprintf(temp, "%10.4f%10.4f%10.4f NPTH %-4s PIN UNOWNED\n", + (GetDimInBoardUnits(C.drill)), + (GetDimInBoardUnits(C.x)), (GetDimInBoardUnits(C.y)), + E.name); + + drilledHolesSection += temp; + + holeCount++; + } //end package.holes + + E.package.contacts(P) + { + if (P.pad) { + sprintf(temp, "%.2f %.2f %.2f PTH BOARD VIA UNOWNED\n", + GetDimInBoardUnits(P.pad.drill), + GetDimInBoardUnits(P.x), GetDimInBoardUnits(P.y)); + + drilledHolesSection += temp; + + holeCount++; + } //end if + } //end loop thru contacts + + } //end elements + + //get any holes on vias + BRD.signals(S) + { + S.vias(V) + { + sprintf(temp, "%10.4f%10.4f%10.4f NPTH BOARD OTHER UNOWNED\n", + (GetDimInBoardUnits(V.drill)), + (GetDimInBoardUnits(V.x)), (GetDimInBoardUnits(V.y))); + + drilledHolesSection += temp; + + holeCount++; + } + } + } //end board loop + + //close drilled holes section + drilledHolesSection += ".END_DRILLED_HOLES\n"; + + //check if drilled holes Is empty and if so clear it + if (holeCount == 0) { + drilledHolesSection = ""; + } + + return drilledHolesSection; +} //end sub + +string GetEmnPlacements() { + /* + .PLACEMENT + 0805 RES R4 + 2300.0 1275.0 0.0 180.0 TOP PLACED + 0805 CAP C13 + 2565.0 1380.0 0.0 0.0 TOP PLACED + + + + + ... + .END_PLACEMENT + */ + + string sideMap[] = { "TOP", "BOTTOM" }; + + string placementSection; + + string footprint; + string altname; + string ref_id; + + string components[]; + string component; + string temp; + string side; + string height; + + placementSection = ".PLACEMENT\n"; + + //loop thru elements on board + board(BRD) + { + + int i = 0; + + BRD.elements(E) + { + + LibraryLookup = lookup(Libraries, strupr(E.package.library), 0); + + //logic to setup footprint an altname values + if (LibraryLookup != "") { + //if found in LibraryLookup then assign package name to both footprint and altname + altname = E.package.name; + footprint = E.package.name; + } else if (E.value != "") { + //if e.value Is not empty then put it in the footprint + altname = E.value; + footprint = E.package.name; + } else { + //if library Is not in list and the E.value Is blank then concat refid and package name + altname = E.name + "_" + E.package.name; + footprint = E.package.name; + } //end if-else + + footprint = CleanString(footprint); + altname = CleanString(altname); + + ref_id = E.name; + ref_id = CleanString(ref_id); + + //get side value based on mirror value + side = sideMap[E.mirror]; + + //check if height set for element. if not set then set to NULL_HEIGHT + height = GetElementHeightAttr( E ); + + //if height is not set then set to default + if (height == NULL_HEIGHT) { + height = "1.0"; //set to value of 1.0 + } + + //if default height then dont append to altname. otherwise put unique height on altname + if( height == "1.0" ){ + sprintf(temp, "%s %s %s\n%f %f 0 %f %s PLACED\n", footprint, + altname, ref_id, GetDimInBoardUnits(E.x), + GetDimInBoardUnits(E.y), E.angle, side); + + //add component to components list + components[i] = footprint + "~" + altname; + } + else{ + sprintf(temp, "%s %s %s\n%f %f 0 %f %s PLACED\n", footprint + "_" + height, + altname + "_" + height, ref_id, GetDimInBoardUnits(E.x), + GetDimInBoardUnits(E.y), E.angle, side); + + //add component to components list + components[i] = footprint + "_" + height + "~" + altname + "_" + height; + + } //end if-else + + placementSection += temp; + + i++; + } //end loop thru elements + } //end loop thru board + + placementSection += ".END_PLACEMENT\n"; + + return placementSection; +} //end sub + +string GenerateEmn() { + + //build emn file + string emn = GetEmnHeader() + GetEmnBoardOutline() + GetEmnDrilledHoles() + + GetEmnPlacements(); + + return emn; +} //end sub + +string GenerateEmp() { + + //build emp file + string emp = GetEmpHeader() + GetEmpElectrical() + GetEmpMechanical(); + + return emp; +} //end sub + +//Submits emn and emp data to IDF site. IDF returns full html page. +void SubmitFormData(){ + + //update user now as the post will take some time to start + TextMessageDialog = GetHtmlText( "
    3D build request submitted. Please wait for update...

















    " ); + + dlgRedisplay(); + + if( 0 ){ + dlgMessageBox( path_ulp[0] ); + } + + + //get board name + string boardName; + string boardDir; + + board( BRD ){ + boardName = filename( BRD.name ); + + boardDir = filedir( BRD.name ); + } //end board + + //get emn and emp strings + string emnData = GenerateEmn() + "\n"; + string empData = GenerateEmp() + "\n"; + + + //convert to html format + emnData = ParseStringToHtmlForm( emnData ); + empData = ParseStringToHtmlForm( empData ); + + + //data for url post + string postResponse; + string postData; + int requestSubmitted = 0; + + string urlParams; + + //strings used to build some html elements + string tempStr; + string thumbnailImg; + string pdf3dLink; + string thumbnailLink; + + string purchaseStlLink; + string purchaseDownloadLink; + string complete3DDesignLink; + + //response data + string jobId; + string jobStatus; + string percentComplete; + string sessionKey; + string sessionLink; + + string downloadPurchaseUrl; + string stlPurchaseUrl; + string complete3DDesignUrl; + + int jobCompleted = 0; + + + + //submit post and get response + sprintf( postData,"emn=%s\nemp=%s\nboardname=%s\nversion=%s", emnData, empData, boardName, version ); + + if( netpost( postResponse, Service_url, postData ) >= 0 ) { + + //dlgMessageBox( postResponse ); + + //get session key response + sessionKey = xmltext( postResponse, "response/session_key" ); + //sessionLink = xmltext( postResponse, "response/session_link" ); + + //sprintf( complete3DDesignLink, "
    Click here to open your board.", sessionLink ); + + + TextMessageDialog = + GetHtmlText( "
    Your board has been uploaded and is ready.
    \ + Your browser will open in the background.

























    " ); + + //update display + dlgRedisplay(); + + string login = Login_url + "?sid=" + sessionKey; + + LaunchBrowser( login ); + + } + else{ + //handle error in netpost + TextMessageDialog = GetHtmlText( "We were unable to complete your request at this time. Please try submit again. \ + If error persists contact support. \ + Contact Support
    \ + Error Code:" + neterror() + "
    Post Response:" + postResponse ); + + dlgRedisplay(); + + + } //end if-else for posting + + + //********** old code below **********/ + /* + //loop thru form post + for( int i = 0; i < 50000; i++ ){ + + //only check every 10th loop + if( i % 10 == 0 ){ + + //check if request has already been submitted + if( !requestSubmitted ){ + //load data to post parameters including secondary flag + sprintf( postData,"emn=%s\nemp=%s\nboardname=%s\nsecondary=y\nversion=%s", emnData, empData, boardName, version ); + } + else{ + //load data to post parameters + sprintf( postData,"id=%s\nsecondary=y", jobId ); + } //end if-else + + //post data and get response + if( netpost( postResponse, Service_url, postData ) >= 0 ) { + + //after first request set to 1/true + requestSubmitted = 1; + + //parse xml response data + jobStatus = xmltext( postResponse, "response/status" ); + jobId = xmltext( postResponse, "response/id" ); + percentComplete = xmltext( postResponse, "response/percent_complete" ); + sessionKey = xmltext( postResponse, "response/session_key" ); + + //get response and parse. first check status + if( jobStatus == "ERROR" ){ + //post error to user + TextMessageDialog = GetHtmlText( "Error in netpost. Please try submit again. If error persists contact support. Contact Support" ); + + dlgRedisplay(); + + break; + } + else if( jobStatus == "ACTIVE" || jobStatus == "NOT STARTED" || jobStatus == "not started" ){ + + //sprintf( tempStr, "%s

    Request is active. Percent Complete: %s

    ", tagImgActive, percentComplete); + sprintf( tempStr, "


    Request is active.


    Percent Complete: %s%%













    ", percentComplete ); + + TextMessageDialog = GetHtmlText( tempStr ); + + } + else if( jobStatus == "COMPLETE" ){ + //set job complete flag + jobCompleted = 1; + + //dlgMessageBox( postResponse ); + + //get link from xml response + //downloadPurchaseUrl = xmltext( postResponse, "response/betaDownloadKey" ); + //stlPurchaseUrl = xmltext( postResponse, "response/betaStlKey" ); + //complete3DDesignUrl = xmltext( postResponse, "response/betaComplete3DDesignKey" ); + complete3DDesignUrl = xmltext( postResponse, "response/complete3DDesignKey" ); + + //build image link + sprintf( thumbnailImg, "\"If", sessionKey); + + sprintf( thumbnailLink, "Open Larger Thumbnail - Free", sessionKey); + + sprintf( pdf3dLink, "Click here", sessionKey); + + //links for purchase + //sprintf( purchaseDownloadLink, "Click here", downloadPurchaseUrl ); + + //sprintf( purchaseStlLink, "Click here", stlPurchaseUrl ); + + sprintf( complete3DDesignLink, "Click here", complete3DDesignUrl ); + + + TextMessageDialog = + GetHtmlText( "

    Generating data complete: A session to map your components with our 3D database is ready.

    \ + The picture shows your board and components that could be mapped automatically. \ + \ + \ + \ + \ + \ +
    " + thumbnailImg + "
    Important: Automatic component mapping works only with the original EAGLE Library. Components shown in red can be mapped manually.

    \ +     " + complete3DDesignLink + " to complete the component mapping manually \ +
      \ +
    • Use of our IDF-to-3D tool is free
    • \ +
    • Generate a 3D PDF of your 3D Board Assembly at no cost
    • \ +
    • Incorporate additional 3D Models to your design by using our IDF-to-3D model library and 3D STEP Model integration tool
    • \ +
    \ +     If satisfied with your 3D image:

    \ +     " + pdf3dLink + " to open a 3D PDF (Free)

    \ +
    " ); + + //update display + dlgRedisplay(); + + break; + } + else{ + TextMessageDialog = GetHtmlText( "There was an error in your request. Please try submit again. \ + If error persists contact support. \ + Contact Support
    \ + Error Code:" + neterror() + " - Unable to parse xml response

    \ + XML Response:" + postResponse ); + dlgRedisplay(); + + //dlgMessageBox( postResponse ); + + break; + } + + //this is needed to update the text display + dlgRedisplay(); + + } + else{ + //handle error in netpost + TextMessageDialog = GetHtmlText( "We were unable to complete your request at this time. Please try submit again. \ + If error persists contact support. \ + Contact Support
    \ + Error Code:" + neterror() + "
    Post Response:" + postResponse ); + + dlgRedisplay(); + + break; + } //end if-else + } + + } //end for + + + //alert user to job success + if( jobCompleted ){ + dlgMessageBox( "Your job is complete" ); + } + else{ + dlgMessageBox( "Your job ended in error\n Job Status: " + jobStatus ); + + TextMessageDialog = GetHtmlText( "There was an error in your request. Please try submit again. \ + If error persists contact support. \ + Contact Support
    \ + Error Code:" + neterror() + "
    " ); + //force text view to update + dlgRedisplay(); + } //end if-else + + */ + + } //end sub + +//main function to generate IDF fils +void GenerateEmnEmpFiles() { + + //update user now as the post will take some time to start + TextMessageDialog = GetHtmlText( + "IDF File generation in process."); + + HeightHtmlTable = ""; //reset + + //refresh display to show message + dlgRedisplay(); + + //get board name + string boardName; + string boardDir; + + board(BRD) + { + boardName = filename(BRD.name); + + boardDir = filedir(BRD.name); + } //end board + + //get emn and emp strings + string emnData = GenerateEmn(); + string empData = GenerateEmp(); + + //write strings to files + string dirName; + dirName = dlgDirectory("Select a directory to write IDF files to:", + boardDir); + + //show path to user + dlgMessageBox( + "Writing IDF Files: " + dirName + GetFileSeperator() + + filesetext(boardName, ".emn")); + + output(dirName + GetFileSeperator() + filesetext(boardName, ".emn"), "wt") + { + printf(emnData); + } + + output(dirName + GetFileSeperator() + filesetext(boardName, ".emp"), "wt") + { + printf(empData); + } + + //complete height table + HeightHtmlTable = + "The table below shows the components placed in the emn/emp files. \ + The height field in the table indicates an extrusion height used in generating the components on the 3D model. \ + A default value is set if a value is not set and is indicated in yellow. The values are defined as HEIGHT attribute values and can be updated in the board file. \ + Heights are set at the element level and can vary by placement. This may cause unexpected behavior if you only update a single component in the file.
    \ + " + + HeightHtmlTable + "
    Ref. IDAlt. NamePackage NameHeight
    "; + //" + HeightHtmlTable + "
    Ref. IDAlt. NamePackage NameHeight
    "; + + TextMessageDialog = GetHtmlText( + "IDF Files written successfully to " + + dirName + "

    " + HeightHtmlTable); +} //end sub + +void LoadLibraries() { + + int libraryCount = 0; + + //load library string in to Libraries array + libraryCount = strsplit(Libraries, LibraryLookup, ':'); + +} //end sub + +string GetHomepageBanner(){ + string temp; + //get banner along with version and OS data to help with support and detect unsupportedconfigs for future releases + string url = "https://www.simplifiedsolutionsinc.com/EagleTo3D/eagle_to_3d_ssi_banner.php?os=" + OS_SIGNATURE + "&v=" + version; + + if( netget( temp, url) >= 0 ){ + //pass + return temp; + } + else{ + //fail + return ""; + } //end if-else + + } + +string GetHomepageLinks(){ + string temp; + string url = "https://www.simplifiedsolutionsinc.com/EagleTo3D/eagle_to_3d_ssi_bullets.php"; + + if( netget( temp, url) >= 0 ){ + //pass + return temp; + } + else{ + //fail + return ""; + } //end if-else + + } + + +string RunNetworkTests(){ + /* + 1. Check internet + 2. Check SSI site + 3. Check SSI site with port + */ + + string temp = ""; + string internetSite = "http://www.google.com/"; + int internetSiteResult = 0; + string internetSiteError = ""; + string internetSiteTroubleshootMsg = ""; + + string ssiSite = "https://www.simplifiedsolutionsinc.com/"; + int ssiSiteResult = 0; + string ssiSiteError = ""; + string ssiSiteTroubleshootMsg = ""; + + string ssiWithPortSite = "http://www.simplifiedsolutionsinc.com:8080/"; + int ssiWithPortSiteResult = 0; + string ssiWithPortSiteError = ""; + string ssiWithPortSiteTroubleshootMsg = ""; + + + if( netget( temp, internetSite ) >= 0 ){ + //pass + internetSiteResult = 1; + } + else{ + //fail + internetSiteResult = 0; + internetSiteError = neterror(); + internetSiteTroubleshootMsg = "We are unable to reach the internet. Please verify your internet connectivity. If you have an internet proxy please configure it under Help->Check for Update->Configure in the Eagle Control Panel window before running the ULP"; + } //end if-else + + + if( netget( temp, ssiSite ) >= 0 ){ + //pass + ssiSiteResult = 1; + } + else{ + //fail + ssiSiteResult = 0; + ssiSiteError = neterror(); + ssiSiteTroubleshootMsg = "We are unable to reach the internet. Please verify your internet connectivity. If you have an internet proxy please configure it under Help->Check for Update->Configure in the Eagle Control Panel window before running the ULP"; + } //end if-else + + if( netget( temp, ssiWithPortSite ) >= 0 ){ + //pass + ssiWithPortSiteResult = 1; + } + else{ + //fail + ssiWithPortSiteResult = 0; + ssiWithPortSiteError = neterror(); + ssiWithPortSiteTroubleshootMsg = "We are unable to reach the Simplified Solutions site at port 8080. Please verify your internet connectivity. You may need to request your firewall rules be opened for port 8080."; + } //end if-else + + + //check results of tests + if( internetSiteResult && ssiSiteResult && ssiWithPortSiteResult ){ + return "PASS"; + } + else{ + return internetSiteError + ":" + internetSiteTroubleshootMsg + ";"; + } + + } + + +//----------------------------------------------------------------------------- +// main section +//----------------------------------------------------------------------------- + +void main() { + + //check to make sure board Is loaded + if (!board) { + dlgMessageBox( + usage + + "
    ERROR: No board!

    \nThis program can only work in the layout editor.

    "); + exit(-1); + } + + //load Libraries array for lookups + LoadLibraries(); + + + //run network test + string networkTestResults = RunNetworkTests(); + string networkTestMessage = ""; + + //dlgMessageBox( strsub( OS_SIGNATURE, 0, 3 ) ); + + //if network test fails then add in note to homepage + if( networkTestResults == "PASS" ){ + networkTestMessage = ""; + } + else{ + networkTestMessage ="We have detect potential network/web connection issues that may impact the execution of this ULP.
    Troubleshooting:" + networkTestResults + "

    "; + } + + + + //get banner + string homepageBanner = GetHomepageBanner(); + + //get links + string homepageLinks= GetHomepageLinks(); + + + string startHTML = networkTestMessage + homepageBanner + " \ +

    IDF Options:

    \ +
    \ + \ + \ + \ +
    \ +
      \ +
    1. Click the \"Generate IDF Files\" button to save IDF files to your computer. Import the IDF files into a Mechanical CAD to view components in \"block\" form

    2. \ +
    3. Click the \"Build 3D PCB\" button to utilize IDF-to-3D to build a 3D PCB of your active .brd file. The 3D PCB will contain accurate 3D component geometry. STEP files of the 3D PCBs can be downloaded after purchasing a subscription to IDF-to-3D

    4. \ +
    5. Click the \"Login to IDF-to-3D\" button to continue working on an existing IDF-to-3D session.
    6. \ + <\ol> \ +
      \ +
      " + homepageLinks + + "
    \ + \ +
    "; + + //set initial text view content + TextMessageDialog = GetHtmlText(startHTML); + + //show dialog to user +int mainDlgResult = dlgDialog( "Eagle IDF Exporter" ) { + //main layout + dlgVBoxLayout { + + //set width by creating a spacing hbox to drive width + if( IsWindows() ) { + //windows + dlgHBoxLayout dlgSpacing( 800 );//sets width + } + else { + //mac/linux + dlgHBoxLayout dlgSpacing( 825 );//sets width + } //end if-else + + //set height and text view + dlgHBoxLayout { + dlgTextView( TextMessageDialog ); //text view. holds html + + if( IsWindows() ) { + //windows + dlgVBoxLayout dlgSpacing( 475 );//sets height + } + else { + //mac/linux + dlgVBoxLayout dlgSpacing( 500 );//sets height + } //end if-else + } //end box layout + + //add options for IDF export + dlgHBoxLayout { + + dlgLabel("Layer for wires (Default=20): "); + + dlgStringEdit( WireLayer ); + + dlgLabel("Board Thickness (MM): "); + + dlgStringEdit( BoardThickness ); + + } //end box layout + + //buttons to submit and exit + dlgHBoxLayout { + dlgPushButton( "Generate IDF Files" ) { + + //submit data to idf site + GenerateEmnEmpFiles(); + } //end button + + dlgPushButton( "Build 3D PCB" ) { + + //submit data to idf site + SubmitFormData(); + } //end button + + dlgPushButton( "Login to IDF-to-3D" ) { + + LaunchBrowser( Login_url ); + } //end button + + dlgPushButton( "Exit" ) dlgReject(); + } //end box layout + } //end v box layout +}; //end mainDlgResult + +} //end main diff --git a/trunk/ulp/edit-used-dev-pac-sym.ulp b/trunk/ulp/edit-used-dev-pac-sym.ulp new file mode 100644 index 00000000..0a78c96f --- /dev/null +++ b/trunk/ulp/edit-used-dev-pac-sym.ulp @@ -0,0 +1,247 @@ +#usage "Offers a selection to open (one of) the respective Library Editor window(s) of the currently edited DEVice/PACkage/SYMbol.

    " + "It is also possible to edit a DEVice, PACkage, or SYMbol from Schematic or Board directly.

    " + "Example:
    " + "RUN edit-used-dev-pac-sym
    " + "RUN edit-used-dev-pac-sym partname gatename
    " + "RUN edit-used-dev-pac-sym partname @
    " + "If the Device consits of one Gate only, use the option '@' for the gatename.
    " + "In case of using @ for a device with more than one Gate, the first Gate used by the Device will be opened.

    " + "Attention: If the used Library is not available in the given path, see - Options - Directory - Library - in the Control Panel,
    " + "a new Schematic/Bord with the Device/Symbole/Package name will be opened!
    " + "Author: support@cadsoft.de
    " + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + + +string Help = "Öffnet in der Bibliothek das Editorfenster das mit dem gerade editierten DEVice/SYMbol/PACkage verknüpft ist.

    " + + "Vom Schaltplan bzw. Board muss es mit den Optionen Bauteilname Gatename aufgerufen werden.

    " + + "Beispiel:
    " + + "RUN edit-used-dev-pac-sym
    " + + "RUN edit-used-dev-pac-sym Bauteilname Gatename
    " + + "RUN edit-used-dev-pac-sym Bauteilname @
    " + + "Besitzt das Bauteil nur ein Symbol (Gate) kann mit @ das Symbol aufgerufen werden.
    " + + "Wird @ bei einem Bauteil mit mehreren Symbolen (Gates) angewendet, so wird das erste benutzte Symbol aufgerufen
    " + + "Achtung: Ist die benutzte Bibliothek nicht im Pfad im Menü - Optionen -- Verzeichnisse - Bibliotheken
    " + + "enthalten, so wird ein Schaltplan bzw. Board mit dem Bauteil/Symbol/Package-Namen angelegt.
    " + + "Author: support@cadsoft.de
    "; + +// Version 1.0 -- 19.05.2005 support@cadsoft.de +// 1.1 -- 29.06.2006 support@cadsoft.de +// 1.2 -- 05.12.2012 alf@cadsoft.de checkapostroph() in Symbol- und Device-Name + +if (language() != "de") Help = usage; + +string devList[]; +string pacList[]; +string symList[]; +string pac_name; +string sym_name; +int cntDev, cntPac, cntSym; + +string use_in; + +string Object = strupr(argv[1]); // use in schematic (Device) or board (Element) +string Gate = strupr(argv[2]); // only in schematic can use + +string checkapostroph(string s) { // da der ganze String in ' eingeschlossen wird, + // müssen die Apostrophen verdoppelt werden. + string t[]; + int cnt; + cnt = strsplit(t, s, '\''); // check Apostroph + if (cnt > 1) { + s = ""; + for (int i = 0; i < cnt; i++) { + if (i == 0) { + if (t[i]) s += t[i]; + } + else if (i) s += "''" + t[i]; + } + } + return s; +} + +int newDevice(string DS_name) { + int new = 1; + for (int n = 0; n < cntDev; n++) { + if (devList[n] == DS_name) { + new = 0; + break; + } + } + return new; +} + + +int newSymbol(string S_name) { + int new = 1; + for (int n = 0; n < cntSym; n++) { + if (symList[n] == S_name) { + new = 0; + break; + } + } + return new; +} + + +if (schematic) { + schematic(SCH) { + SCH.sheets(S) { + S.parts(PA) { + if (PA.name == Object) { + if (Gate) { + int foundgates = 0; + PA.instances(I) { + foundgates++; + if (Gate == "@") { + exit("OPEN " + PA.deviceset.library + ";\nEDIT '" + checkapostroph(I.gate.symbol.name) + ".SYM'"); + } + if (I.name == Object+Gate) { + exit("OPEN " + PA.deviceset.library + ";\nEDIT '" + checkapostroph(I.gate.symbol.name) + ".SYM'"); + } + } + if (foundgates) + if (dlgMessageBox("! Gate '" + Gate + "' from Device '" + Object + "' not found.\n" + + "Use INVOKE to see available Gates.", "Yes", "No") != 0) exit(0); + exit("INVOKE " + Object); + } + else { + exit("OPEN '" + PA.deviceset.library + "';\nEDIT '" + PA.deviceset.name + ".DEV'"); + } + } + } + } + } + dlgMessageBox(Help, "OK"); +} + +else if (board) board(B) { + B.elements(E) { + if (E.name == Object) { + exit("OPEN " + E.package.library + "; EDIT '" + E.package.name + ".PAC'"); + } + } + dlgMessageBox(Help, "OK"); +} + +else if (library) { + + if (deviceset) { + deviceset(DS) { + DS.devices(D) { + if (D.package) { + pacList[cntPac] = D.package.name; + cntPac++; + } + } + DS.gates(G) { + if (newSymbol(G.symbol.name)) { + symList[cntSym] = G.symbol.name; + cntSym++; + } + } + } + dlgDialog("EDIT selected Package or Symbol") { + int selectPac = cntPac+1, selectSym = cntSym+1; + dlgHBoxLayout dlgSpacing(400); + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel("Used p&ackages"); + dlgListView("Packages", pacList, selectPac) { + dlgAccept(); + exit("EDIT '" + pacList[selectPac] + ".PAC'"); + } + dlgHBoxLayout { + dlgPushButton("Edit &Package") { + dlgAccept(); + exit("EDIT '" + pacList[selectPac] + ".PAC'"); + } + dlgStretch(1); + } + } + dlgVBoxLayout { + dlgLabel("Used s&ymbols"); + dlgListView("Symbols", symList, selectSym) { + dlgAccept(); + exit("EDIT '" + checkapostroph(symList[selectSym]) + ".SYM'"); + } + dlgHBoxLayout { + dlgPushButton("Edit &Symbol") { + dlgAccept(); + exit("EDIT '" + checkapostroph(symList[selectSym]) + ".SYM'"); + } + dlgStretch(1); + } + } + dlgVBoxLayout dlgSpacing(200); + } + dlgLabel("Double click on listed Package or Symbol to edit."); + dlgHBoxLayout { + dlgPushButton("-Cancel") { dlgReject(); exit(0); } + dlgStretch(1); + } + }; + exit(0); + } + + if (package || symbol) { + if (package) { + package(P) pac_name = P.name; + devList[0] = "!No Devices use this package"; + use_in = "Package used in"; + library(L) { + L.devicesets(DS) { + DS.devices(D) { + if (D.package) { + if (D.package.name == pac_name) { + devList[cntDev] = DS.name; + cntDev++; + } + } + } + } + } + } + + if (symbol) { + symbol(S) sym_name = S.name; + devList[0] = "!No Devices use this symbol"; + use_in = "Symbol used in"; + library(L) { + L.devicesets(DS) { + DS.gates(G) { + if (G.symbol.name == sym_name) { + if (newDevice(DS.name)) { + devList[cntDev] = DS.name; + cntDev++; + } + } + } + } + } + } + } + if (cntDev) { + if (cntDev > 1) { // 2006.06.29 + dlgDialog("EDIT selected Device") { + int select; + dlgLabel(use_in); + dlgHBoxLayout { + dlgListView("Devices", devList, select) { + dlgAccept(); + exit("EDIT '" + checkapostroph(devList[select]) + ".DEV';"); + } + dlgVBoxLayout dlgSpacing(200); + } + dlgLabel("Double click on listed device to edit."); + dlgHBoxLayout { + dlgPushButton("+OK") { dlgAccept(); exit("EDIT '" + checkapostroph(devList[select]) + ".DEV';"); } + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + }; + } + else exit("EDIT '" + checkapostroph(devList[0]) + ".DEV';"); + } + else dlgMessageBox(devList[0], "Ok"); +} \ No newline at end of file diff --git a/trunk/ulp/editnext-dev-sym-pac.ulp b/trunk/ulp/editnext-dev-sym-pac.ulp new file mode 100644 index 00000000..2b540305 --- /dev/null +++ b/trunk/ulp/editnext-dev-sym-pac.ulp @@ -0,0 +1,71 @@ +#usage "Edit next device, symbol, or package in library\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string dev[]; +string sym[]; +string pac[]; +string edit = ""; +int scount = 0; +int dcount = 0; +int pcount = 0; +int n = 0; + +if (library) library(L) { + L.devicesets(D) { + dcount++; + dev[dcount] = D.name; + } + L.symbols(S) { + scount++; + sym[scount] = S.name; + } + L.packages(P) { + pcount++; + pac[pcount] = P.name; + } + + if (deviceset) deviceset(D) { + edit = D.name; + for (n = 1; n < dcount; n++) { + if (edit == dev[n]) { + break; + } + } + + if (n < dcount) { + cmd += "EDIT " + dev[n + 1] + ".dev;\n" ; + } + else exit (0); + } + if (symbol) symbol(S) { + edit = S.name; + for (n = 1; n < scount; n++) { + if (edit == sym[n]) { + break; + } + } + + if (n < scount) { + cmd += "EDIT " + sym[n + 1] + ".sym;\n" ; + } + else exit (0); + } + if (package) package(P) { + edit = P.name; + for (n = 1; n < pcount; n++) { + if (edit == pac[n]) { + break; + } + } + + if (n < pcount) { + cmd += "EDIT " + pac[n + 1] + ".pac;\n" ; + } + else exit (0); + } + exit(cmd); + } diff --git a/trunk/ulp/editnext-lbr.ulp b/trunk/ulp/editnext-lbr.ulp new file mode 100644 index 00000000..bbd72600 --- /dev/null +++ b/trunk/ulp/editnext-lbr.ulp @@ -0,0 +1,29 @@ +#usage "Edit next library in current directory\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +if (library) { + library(L) { + string a[], cmd; + string Lname = L.name; + string lbr_path = filedir(L.name); + int n = fileglob(a, lbr_path + "*.lbr"); + if (n) { + for (int xl = 0; xl < n; xl++) { + if (Lname == a[xl]) { + if (xl < n-1) { + string h; + sprintf(h, "OPEN '" + a[xl + 1] + "';"); + cmd += h; + exit (cmd); + } + } + } + } + } + exit (0); + } + +else dlgMessageBox("Start this ULP from a Library", "OK"); diff --git a/trunk/ulp/editnext-sheet.ulp b/trunk/ulp/editnext-sheet.ulp new file mode 100644 index 00000000..d7c31ad6 --- /dev/null +++ b/trunk/ulp/editnext-sheet.ulp @@ -0,0 +1,23 @@ +#usage "Edit next sheet\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; + +if (schematic) { + int scnt = 0; + int s; + schematic(SH) { + sheet(SH) s = SH.number; + SH.sheets(S) { + scnt = S.number; + } + if (s < scnt) { + s++; + sprintf(cmd, "EDIT .s%d;\n", s); + } + } + exit(cmd); + } diff --git a/trunk/ulp/editprev-dev-sym-pac.ulp b/trunk/ulp/editprev-dev-sym-pac.ulp new file mode 100644 index 00000000..2a2e0413 --- /dev/null +++ b/trunk/ulp/editprev-dev-sym-pac.ulp @@ -0,0 +1,71 @@ +#usage "Edit previous device, symbol, or package in library\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string dev[]; +string sym[]; +string pac[]; +string edit = ""; +int scount = 0; +int dcount = 0; +int pcount = 0; +int n = 0; + +if (library) library(L) { + L.devicesets(D) { + dcount++; + dev[dcount] = D.name; + } + L.symbols(S) { + scount++; + sym[scount] = S.name; + } + L.packages(P) { + pcount++; + pac[pcount] = P.name; + } + + if (deviceset) deviceset(D) { + edit = D.name; + for (n = 1; n < dcount; n++) { + if (edit == dev[n]) { + break; + } + } + if (n > 0) { + cmd += "EDIT " + dev[n - 1] + ".dev;\n" ; + } + else exit (0); + } + + if (symbol) symbol(S) { + edit = S.name; + for (n = 1; n < scount; n++) { + if (edit == sym[n]) { + break; + } + } + if (n > 0) { + cmd += "EDIT " + sym[n - 1] + ".sym;\n" ; + } + else exit (0); + } + + if (package) package(P) { + for (n = 1; n < pcount; n++) { + edit = P.name; + if (edit == pac[n]) { + break; + } + } + + if (n > 0) { + cmd += "EDIT " + pac[n - 1] + ".pac;\n" ; + } + else exit (0); + } + exit(cmd); + } diff --git a/trunk/ulp/editprev-lbr.ulp b/trunk/ulp/editprev-lbr.ulp new file mode 100644 index 00000000..a8def577 --- /dev/null +++ b/trunk/ulp/editprev-lbr.ulp @@ -0,0 +1,29 @@ +#usage "Edit previous library in current directory\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +if (library) { + library(L) { + string a[], cmd; + string Lname = L.name; + string lbr_path = filedir(L.name); + int n = fileglob(a, lbr_path + "*.lbr"); + if (n) { + for (int xl = 0; xl <= n; xl++) { + if (Lname == a[xl]) { + if (xl > 0) { + string h; + sprintf(h, "OPEN '" + lbr_path + filename(a[xl - 1]) + "';"); + cmd += h; + exit (cmd); + } + } + } + } + } + exit (0); + } + +else dlgMessageBox("Start this ULP from a Library", "OK"); diff --git a/trunk/ulp/editprev-sheet.ulp b/trunk/ulp/editprev-sheet.ulp new file mode 100644 index 00000000..d6dc3f16 --- /dev/null +++ b/trunk/ulp/editprev-sheet.ulp @@ -0,0 +1,19 @@ +#usage "Edit previous sheet\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; + +if (schematic) { + int s; + schematic(SH) { + sheet(SH) s = SH.number; + if (s > 1) { + s--; + sprintf(cmd, "EDIT .s%d;\n", s); + } + } + exit(cmd); + } diff --git a/trunk/ulp/ex-argv-path.ulp b/trunk/ulp/ex-argv-path.ulp new file mode 100644 index 00000000..b1f94c4a --- /dev/null +++ b/trunk/ulp/ex-argv-path.ulp @@ -0,0 +1,17 @@ +#usage "Example: Usage of argv\n" + "

    " + "Returns the path of the ULP." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +void main(void) { + string ulp_path = ""; + char c = '/'; + int pos = strrchr(argv[0], c); + if (pos >= 0) { + ulp_path = strsub(argv[0], 0, pos + 1); + } + dlgMessageBox(ulp_path , "+OK"); +} diff --git a/trunk/ulp/ex-dialogs.ulp b/trunk/ulp/ex-dialogs.ulp new file mode 100644 index 00000000..fc262343 --- /dev/null +++ b/trunk/ulp/ex-dialogs.ulp @@ -0,0 +1,653 @@ +#usage "Example: Dialogs\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +// Revision 1 : Path for bitmap corrected 2005.12.21 support@cadsoft.de + +string cmd = ""; +int Value = 42; +int Wert = 7; +int Val = 0; +string st = ""; +int Result = 0; +string msg = ""; + +string Colors[] = { "red" + , "green", "blue", "pink" + , "yellow", "cyan", "magenta" + , "brown", "white", "black" + , "gray", "orange" + }; + +int Selected = 2; // initially selects "blue" + +string Text = "example text"; + +int Lines = 0; + +// Checkboxes in Dialog +int mirror = 0; +int rotate = 1; +int flip = 0; +int black = 1; +int swap = 1; +int solid = 0; +int scaled = 0; +int align = 0; + +//use dlgRadioButton only in dlgGroup! + +Result = dlgDialog("EAGLE Version 4 / ULP Demonstration") { + dlgHBoxLayout { + dlgStretch(0); + dlgGroup("Use RadioButton only in dlgGroup!") { + dlgStretch(0); + dlgGridLayout { + dlgCell(1, 1) dlgRadioButton("&Top", align); + dlgCell(2, 0) dlgRadioButton("&Left ", align); + dlgCell(2, 1) dlgRadioButton("&Center", align); + dlgCell(2, 2) dlgRadioButton("&Right ", align); + dlgCell(3, 1) dlgRadioButton("&Bottom", align); + // 30 pixels fixed distance + dlgCell(1, 6) { dlgSpacing(30); dlgCheckBox("R&otate", rotate); }; + dlgCell(2, 6) { dlgSpacing(30); dlgCheckBox("&Mirror", mirror); }; + dlgCell(3, 6) { dlgSpacing(30); dlgCheckBox("&Flip", flip); }; + } + } + dlgStretch(0); + dlgVBoxLayout { + dlgHBoxLayout { + dlgSpacing(20); + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + dlgHBoxLayout { + dlgSpacing(20); + dlgStretch(0); + dlgPushButton("-ESC") dlgReject(); + dlgStretch(1); + } + } + dlgStretch(1); + } + dlgStretch(1); + }; +if (Result == 0) exit (0); + +// a complex menu +// default is VBoxLayout + +Text += "\nextend example text with Text+=..."; +align = 0; +Result = dlgDialog("Version 4 - ULP test"){ + + string fbmp; + sprintf(fbmp, "", filedir(argv[0]) ); // make absolute path for bitmap file 2005.12.21 alf@cadsoft.de + dlgStretch(0); // no dynamic distance on top + dlgHBoxLayout { + dlgStretch(0); // no dynamic distance on left border + dlgLabel(fbmp); // display a BMP file + dlgStretch(0); // no dynamic distance to next object + dlgGroup("ULP-Test Edit") { // start a group + dlgHBoxLayout dlgSpacing(600); // make 600 pixel spacing + dlgHBoxLayout { // horizontal direction in horizontal direction + dlgVBoxLayout dlgSpacing(300); // a vertical Box 300 pixels high + dlgTextEdit(Text); // editor window 600 x 300 pixels + } + } + dlgStretch(1); // dynamic distance to the right border + } + dlgHBoxLayout { + dlgStretch(0); // no dynamic distance allowed + dlgGroup("ULP-Test Radio") { // start a frame for a group + dlgHBoxLayout dlgSpacing(100); // a horizontle box min. 100 pixels wide + // Minimum is 80 pixels (by Windows/Microsoft) + // is the displayed Text in Combobox larger than 80 pixels + // then the Box width is automatically extended + + dlgLabel("&Color"); // the & character marks the ALT-Key + dlgComboBox(Colors, Selected); + dlgRadioButton("&Center", align); + dlgRadioButton("&Bottom", align); + } + dlgSpacing(20); + dlgStretch(0); + dlgVBoxLayout { + dlgStretch(1); + dlgCheckBox("&Mirror", mirror); + dlgStretch(0); + dlgCheckBox("&Rotate", rotate); + dlgStretch(1); + } + dlgSpacing(10); + dlgStretch(0); + dlgLabel("Enter a &Number between 0 and 99"); + dlgSpacing(5); + dlgStretch(0); + dlgHBoxLayout { + dlgIntEdit(Value, 0, 99); + } + dlgSpacing(10); + dlgStretch(0); + dlgGroup("Reset") { + dlgStretch(0); + dlgLabel("change values, press reset and look"); + dlgStretch(1); + dlgPushButton("Reset") dlgReset(); + dlgStretch(1); + } + dlgStretch(1); + } + dlgStretch(0); + dlgSpacing(10); + dlgHBoxLayout { + dlgStretch(0); + dlgSpacing(550); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + dlgSpacing(25); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + dlgStretch(1); + }; +if (Result == 0) exit (0); + +// Dialog window with Button + +align = 0; +Text = "\n\nCELL example\ndefine cells\n"; + +Result = dlgDialog(" EAGLE Version 4 / GRID/CELL Demonstration"){ + dlgGridLayout { // Grid & Cell + dlgCell(0, 0) dlgLabel("Cell 0,0"); + dlgCell(0, 1) dlgLabel("Cell 0,1"); + dlgCell(0, 2) dlgLabel("Cell 0,2"); + dlgCell(0, 3) dlgLabel("Cell 0,3"); + dlgCell(0, 4) dlgLabel("Cell 0,4"); + dlgCell(0, 5) dlgLabel("Cell 0,5"); + dlgCell(0, 6) dlgLabel("Cell 0,6"); + dlgCell(0, 7) dlgLabel("Cell 0,7"); + dlgCell(0, 8) dlgLabel("Cell 0,8"); + dlgCell(0, 9) dlgLabel("Cell 0,9"); + dlgCell(0, 10) dlgLabel("Cell 0,10"); + dlgCell(0, 11) dlgLabel("Cell 0,11"); + + dlgCell(1, 0) dlgLabel("Cell 1,0"); + dlgCell(2, 0) dlgLabel("Cell 2,0"); + dlgCell(3, 0) dlgLabel("Cell 3,0"); + dlgCell(4, 0) dlgLabel("Cell 4,0"); + dlgCell(5, 0) dlgLabel("Cell 5,0"); + dlgCell(6, 0) dlgLabel("Cell 6,0"); + dlgCell(7, 0) dlgLabel("Cell 7,0"); + dlgCell(8, 0) dlgLabel("Cell 8,0"); + dlgCell(9, 0) dlgLabel("Cell 9,0"); + dlgCell(10, 0) dlgLabel("Cell 10,0"); + dlgCell(11, 0) dlgLabel("Cell 11,0"); + + dlgCell(1, 2, 4, 6) dlgTextEdit(Text); + dlgCell(1, 8) dlgComboBox(Colors, Selected); + dlgCell(2, 8) dlgCheckBox("&Mirror", mirror); + dlgCell(3, 8) dlgCheckBox("&Rotate", rotate); + + dlgCell(4, 8, 4, 8) dlgGroup("Gruop") { + dlgGridLayout { + dlgCell(6, 8) dlgRadioButton("&Top", align); + dlgCell(7, 8) dlgRadioButton("&Center", align); + dlgCell(8, 8) dlgRadioButton("&Bottom", align); + } + } + + dlgCell(6, 4) dlgPushButton("+OK") dlgAccept(); + dlgCell(7, 4) dlgPushButton("-CANCEL\n\nStop ULP\nand\nExit") dlgReject(); + dlgCell(7, 2) dlgPushButton("Reset") dlgReset(); + dlgCell(1, 1) dlgLabel(""); // this is a absolute path 2005.12.21 alf@cadsoft.de + dlgCell(1, 8) dlgLabel(""); // this is a relativ path 2005.12.21 alf@cadfsoft.de + dlgCell(9, 1) dlgLabel(""); + dlgCell(9, 8) dlgLabel(""); + + } + dlgLabel("a small example for Grid & Cell"); + }; +if (Result == 0) exit (0); + +Result = dlgDialog("Checkbox Demonstration"){ + dlgGroup("Orientation and Print") { + dlgCheckBox("&Mirror", mirror); + dlgCheckBox("&Rotate", rotate); + dlgCheckBox("&Flip", flip); + dlgCheckBox("&Black", black); + dlgCheckBox("&Solid", solid); + dlgCheckBox("S&caled", scaled); + } + dlgVBoxLayout { + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + } + } + }; +if (Result == 0) exit (0); + + +// Comboboxes +Result = dlgDialog("Combobox"){ + dlgComboBox(Colors, Selected); + dlgVBoxLayout { + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + } + } + }; +if (Result == 0) exit (0); + +// GridLayout - define cell by cell content + +Result = dlgDialog("Grid Layout"){ + dlgGridLayout { + dlgCell(0, 0) dlgLabel("Row 0/Col 0"); + dlgCell(1, 0) dlgLabel("Row 1/Col 0"); + dlgCell(0, 4) dlgLabel("Row 0/Col 4"); + dlgCell(5, 5) dlgLabel("Row 5/Col 5"); + dlgCell(10, 20) dlgPushButton("+OK") dlgAccept(); + dlgCell(10, 24) dlgPushButton("-Cancel") dlgReject(); + } + }; +if (Result == 0) exit (0); + +// input a Integer-Value +Result = dlgDialog("IntEdit"){ + dlgHBoxLayout { + dlgLabel("Enter a &Number between 0 and 99"); + dlgIntEdit(Value, 0, 99); + } + dlgVBoxLayout { + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + } + } + }; +if (Result == 0) exit (0); + +// List box selection field +Result = dlgDialog("List Box") { + dlgListBox(Colors, Selected) + dlgAccept(); + }; +dlgMessageBox("selected Color " + Colors[Selected]); +if (Result == 0) exit (0); + + +//Multi column list view selection field +string Colours[] = { "red\tThe color RED", "green\tThe color GREEN", "blue\tThe color BLUE" }; + +Selected = 1; +Result = dlgDialog("ListView") { + dlgListView("Name\tDescription", Colours, Selected) dlgAccept(); + dlgPushButton("+OK") dlgAccept(); + }; +dlgMessageBox("last selected\n" + Colours[Selected]); +if (Result == 0) exit (0); + + +// Predefined Button OK +Result = dlgDialog("Hello") { + dlgLabel("Hello world"); + dlgPushButton("+OK") dlgAccept(); + // look at the '+' character + }; + +// Radio Button +// can be used only in a dglGroup +align = 0; + +Result = dlgDialog("RadioButton") { + dlgGroup("Alignment") { + dlgRadioButton("&Top", align); + dlgRadioButton("&Center", align); + dlgRadioButton("&Bottom", align); + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; +if (Result == 0) exit (0); + +// Input a real value + +real rValue = 33.333; +Result = dlgDialog("RealEdit"){ + dlgHBoxLayout { + dlgLabel("Enter a &Number between 0.0 and 99.0"); + dlgRealEdit(rValue, 0.0, 99.0); + dlgVBoxLayout { + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + } + } + } + }; +if (Result == 0) exit (0); + +sprintf(st, "%f", rValue); +dlgMessageBox("last real value = " + st); + +// Define additional space in a box layout context +// space is given in pixels +Result = dlgDialog("Spacing V-Box"){ + dlgVBoxLayout { + dlgLabel("Label V1"); + dlgSpacing(70); + dlgLabel("Label V2"); + } + }; +if (Result == 0) exit (0); + +Result = dlgDialog("Spacing HBox"){ + dlgHBoxLayout { + dlgLabel("Label H1"); + dlgSpacing(100); + dlgLabel("Label H2"); + } + }; +if (Result == 0) exit (0); + +// Select two values +Result = dlgDialog("Spinbox - select value for X and Y") { + dlgVBoxLayout { + dlgLabel("select &X"); // character & mark selected by ALT+Key + dlgSpinBox(Value, 0, 99); + dlgLabel("select &Y"); + dlgSpinBox(Wert, -99, 99); + dlgPushButton("+OK") dlgAccept(); + // + is the Default-Button [ENTER] + dlgPushButton("-throw away") dlgReject(); + // - is the Cancel-Button [ESC] + }; + }; +if (Result == 0) exit (0); + +dlgMessageBox("ATTENTION:\ndrag the next menu border line!", "OK"); + +// Define an empty stretchable space in a box layout context +Result = dlgDialog("Stretch horizontal") { + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(5); + dlgPushButton("Key B"); + dlgStretch(15); + dlgPushButton("Key C"); + dlgStretch(40); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(5); + } + }; + +if (Result == 0) exit (0); + +dlgMessageBox(" ATTENTION:\ndrag the next menu border line!", "OK"); + +Result = dlgDialog("Stretch vertical") { + dlgVBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(5); + dlgPushButton("Key 2"); + dlgStretch(15); + dlgPushButton("Key 3"); + dlgStretch(40); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + } + }; +if (Result == 0) exit (0); + +// Defines a string entry field +// define fixed length by dlgSpacing + +string Name = "Linus Torvalds"; +Result = dlgDialog("dlgStringEdit") { + dlgHBoxLayout dlgSpacing(400); + dlgStretch(0); + dlgLabel("Enter &Name"); + dlgStretch(0); + dlgStringEdit(Name); + dlgVBoxLayout { + dlgStretch(0); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + } + dlgStretch(10); + }; + dlgStretch(1); + }; +if (Result == 0) exit (0); +dlgMessageBox("the last selected \n" + Name); + +// Define a tab page +align = 0; +int p_align = 0; + +Result = dlgDialog("Container for tab pages") { + //Define a container for tab pages + dlgTabWidget { + dlgTabPage("&Video") { + dlgHBoxLayout { + dlgLabel(""); + } + dlgHBoxLayout { + dlgLabel("Video mode"); + dlgGroup("Gruppe") { + dlgRadioButton("&Black and White", align); + dlgRadioButton("&White and Black", align); + } + } + } + dlgTabPage("&Printer") { + dlgLabel("Printer setup"); + dlgGroup("Gruppe") { + dlgRadioButton("&Top", p_align); + dlgRadioButton("&Center", p_align); + dlgRadioButton("&Bottom", p_align); + } + } + dlgTabPage("&Memory") { + dlgLabel("Memory setup"); + dlgCheckBox("R&otate", rotate); + dlgCheckBox("Mi&rror", mirror); + dlgCheckBox("&Flip", flip); + dlgCheckBox("&Swap", swap); + } + dlgTabPage("&Export") { + dlgLabel("select a file name for WRITE"); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("&File") { + string fileName; + fileName = dlgFileOpen("select a File", "*.*", "*.BRD\n*.SCH\n*.SCH\n*.ULP"); + }; + dlgStretch(1); + } + } + dlgTabPage("&Input") { + dlgLabel("select a file for read"); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("&File") { + string fileName; + fileName = dlgFileOpen("select a File", "*.*", ""); + }; + dlgStretch(1); + } + } + dlgTabPage("&Help") { + dlgLabel(""); + dlgLabel("Copyright (c) 1988-2000 CadSoft Computer GmbH"); + } + } + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + dlgLabel(" <--------> "); + dlgStretch(0); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + }; +if (Result == 0) exit (0); + +string sresult; +sprintf(sresult, "%d", Value); +cmd = "selected X = " + sresult + ".\n"; +sprintf(sresult, "%d", Wert); +cmd += "selected Y = " + sresult + ".\n"; + +Result = dlgDialog("Editor Window") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; +if (Result == 0) exit (0); + +dlgMessageBox(cmd); + +//Define a multiline text viewer field +Text = "This is some text.\nLine 2\nLine 3"; +string Text2 = "This is the 2nd text.\nLine 2\nLine 3"; +Text2 += "\n...\n...\n...\n...\nScroll-\nbars\non?\n"; +Text2 += "OK\nEnd."; + +Result = dlgDialog("List Window") { + dlgVBoxLayout { + dlgLabel("&View the text"); + dlgTextView(Text); + + dlgLabel("Vie&w the text"); + dlgTextView(Text2); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + } + }; +if (Result == 0) exit (0); + +// Button +int haveButton = 1; +Result = dlgDialog("Test") { + dlgLabel("Start"); + if (haveButton) + dlgPushButton("Here") dlgAccept(); + }; +if (Result == 0) exit (0); + +Result = dlgDialog("'3 Boxes close by ESC") { + dlgHBoxLayout { + dlgLabel("Box 1"); + dlgLabel("Box 2"); + dlgLabel("Box 3"); + dlgPushButton("+OK") dlgAccept(); + } + }; +if (Result == 0) exit (0); + +Result = dlgDialog("selected Color") { + dlgVBoxLayout { + dlgLabel("selected Color"); + dlgLabel(Colors[Selected]); + } + }; +if (Result == 0) exit (0); + +// Redisplays the dialog after changing values +string Status[] = { "Idle", "1st run", "2nd run", "3rd run", "Finished" } ; +int stat = 0; +string labstr = Status[0]; + +Result = dlgDialog("Test") { + dlgLabel(labstr); + dlgPushButton("+OK") dlgAccept(42); + dlgPushButton("Cancel") dlgReject(-3); + dlgPushButton("Run") { + if (stat < 4) stat++; + labstr = Status[stat]; + dlgRedisplay(); + // some program action here... + } + dlgPushButton("Reset") { + dlgReset(); + stat = 0; + labstr = Status[stat]; + dlgRedisplay(); + } + }; +if (Result == 0) exit (0); + +sprintf(cmd, "%d", Result); +dlgMessageBox(cmd); + +int Number = 99; +string dlgStr = "Empty"; +real rVal = 9.99; + +Result = dlgDialog("Reset Int & Real to 0") { + dlgIntEdit(Number); + dlgRealEdit(rVal); + dlgStringEdit(dlgStr); + dlgPushButton("+OK") dlgAccept(42); + dlgPushButton("Cancel") dlgReject(); + dlgPushButton("Reset") dlgReset(); + }; +if (Result == 0) exit (0); + +// File handling +int n = 0; +char b[]; + +string fileName = dlgFileOpen("select File", "*.*", "*.BRD\n*.SCH\n*.SCH\n*.ULP"); + + int nBytes = fileread(b, fileName); + for (int x = 0; x < nBytes; x++) { + cmd += b[x]; + } +dlgMessageBox(fileName +"\nread", "OK"); diff --git a/trunk/ulp/ex-dlglist.ulp b/trunk/ulp/ex-dlglist.ulp new file mode 100644 index 00000000..a7e97981 --- /dev/null +++ b/trunk/ulp/ex-dlglist.ulp @@ -0,0 +1,25 @@ +#usage "Example: Two multiline text viewer fields\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string Text = "This is some text.\nLine 2\nLine 3"; +string Text2 = "This is text number 2\nLine 2\nLine 3"; +Text2 += "\n...\n...\n...\n...\n...\n...\n...\n...\n"; +Text2 += "end of text2."; + +int Result = dlgDialog("List-Fenster") { + dlgVBoxLayout { + dlgLabel("&View text 1"); + dlgTextView(Text); + + dlgLabel("Vie&w text 2"); + dlgTextView(Text2); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + } + }; +if (Result == 0) exit (0); diff --git a/trunk/ulp/ex-file-copy.ulp b/trunk/ulp/ex-file-copy.ulp new file mode 100644 index 00000000..200cc239 --- /dev/null +++ b/trunk/ulp/ex-file-copy.ulp @@ -0,0 +1,30 @@ +#usage "Example: Copy a file\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string fileName; +string test = ""; +int Result = 0; +int nBytes = 0; +int start = 0; +char c[]; + +fileName = dlgFileOpen("Select a file", "*.*"); + +nBytes = fileread(c, fileName); + +sprintf(test, "%d = &%x", nBytes, nBytes); +dlgMessageBox("Length of File = " + test); + +dlgMessageBox("Write " + fileName + "?"); +fileName += ".copy"; +output(fileName, "wb") { + for (int z = 0; z < nBytes; z++) { + printf("%c", c[z]); + Result = z+1; + } + } +sprintf(test, "%d = $%x", Result, Result); +dlgMessageBox("Length of File = " + test, "OK"); diff --git a/trunk/ulp/ex-include.ulp b/trunk/ulp/ex-include.ulp new file mode 100644 index 00000000..01adaffb --- /dev/null +++ b/trunk/ulp/ex-include.ulp @@ -0,0 +1,22 @@ +#usage "Example: Usage of include file\n" + "

    " + "Demonstrates how to use the include file 'useful-routines.ulp'." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#include "useful-routines.ulp" + +int Result; +string s1, s2, h; + +s1 = "DISPLAY ALL;\n"; +s2 = get_ulp_name(); +Result = edit_save_execute(s1, s2); +sprintf(h, "Result: %d", Result); +dlgMessageBox(h, "OK"); + +dlgMessageBox("ULP path: "+get_ulp_path(),"OK"); + +dlgMessageBox("Project path: "+get_project_path(),"OK"); diff --git a/trunk/ulp/ex-input-file.ulp b/trunk/ulp/ex-input-file.ulp new file mode 100644 index 00000000..9b444b8e --- /dev/null +++ b/trunk/ulp/ex-input-file.ulp @@ -0,0 +1,75 @@ +#usage "Example: Input file dialog\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +int n = 0; // global counter +char b[]; +string fileName = ""; + +fileName = dlgFileOpen("Select a File", ""); +int nBytes = fileread(b, fileName); + + for (n; n < nBytes; n++) { + switch (b[n]) { + case 0: break; + + case 1: cmd += "Device\n"; + break; + + case 2: cmd += "\nEND - HEADER\n"; + break; + + case 3: cmd += "\nEND - 3\n"; + break; + + case 4: cmd += "4"; + break; + + case 5: break; + + case 6: break; + + case 7: break; + + case 8: break; + + case 9: cmd += "\t"; + break; + + + case 10: cmd += "Line Feed\n"; + break; + + case 12: cmd += "\nNew Page\n"; + break; + + case 13: cmd += "Carriage Return\n"; + break; + + case 27: cmd += "\nEscape\n"; + break; + + case 32: cmd += ".space." + b[n]; + break; + + default: cmd += b[n]; + break; + } + } + // Demo Text Editor Box + dlgDialog("Text Editor Box") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+Ok") { + dlgAccept(); + output("test.txt", "wt") { + printf(cmd); + } + }; + dlgPushButton("-Cancel") dlgReject(); + } + }; + exit(0); diff --git a/trunk/ulp/ex-loop-lbrs.ulp b/trunk/ulp/ex-loop-lbrs.ulp new file mode 100644 index 00000000..c1a03c7d --- /dev/null +++ b/trunk/ulp/ex-loop-lbrs.ulp @@ -0,0 +1,67 @@ +#usage "Example: Check all libraries in a directory\n" + "

    " + "This is an example how to loop through all libraries in a directory " + "and perform a device check." + "

    " + "In this case, the device descriptions are checked for double bold tags. " + "An error report error.txt is generated in the library directory." + "

    " + "Load any library from the library directory and execute the ULP." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string a[], par, lbr_path, dest, cmd = "", s, progname; +int lbrpnt, x; + +//-------------------------------------------------- +string checklbr (UL_LIBRARY L) { + int errflag = 0; + string h; + L.devices(D) { + h = ""; + sprintf(h,"%s",D.description); + h = strlwr(h); + if (strstr(h, "") >= 0 && !errflag) { + cmd += L.name+"\n"; + errflag = 1; + } + } + if (errflag) return "***"; + else return ""; + } + + +//-------- main program -------------------------------------------------- +progname = filesetext(filename(argv[0]), ""); +library(L) { + lbr_path = filedir(L.name); + } +dest = lbr_path+"error.txt"; + +lbrpnt = strtod(argv[1]); +int n = fileglob(a, lbr_path+"*.lbr"); + +if (n) { + if (lbrpnt < 1) { // first run +// initial actions, e.g. headline +//------------------------------------------------------------------------ + output(dest, "wt") printf("Faulty Libraries marked with ***\n\n"); +//------------------------------------------------------------------------ + exit("OPEN '"+lbr_path+filename(a[0])+"';\nRUN '"+progname+"' 1"); + } + else { // next runs + library(L) { +// insert here whatever you want to do with the current library +//------------------------------------------------------------------------ + s = checklbr(L); + output(dest, "at") printf("%s%s\n",L.name, s); +//------------------------------------------------------------------------ + lbrpnt++; + sprintf(par, "%d", lbrpnt); + if (lbrpnt == n) exit(0); + exit("OPEN '"+lbr_path+filename(a[lbrpnt])+"';\nRUN '"+progname+"' "+par+"\n"); + } + } + } diff --git a/trunk/ulp/ex-run-script.ulp b/trunk/ulp/ex-run-script.ulp new file mode 100644 index 00000000..ea675966 --- /dev/null +++ b/trunk/ulp/ex-run-script.ulp @@ -0,0 +1,32 @@ +#usage "Example: Export a script and execute it\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string dev = ""; + +cmd += "OPEN TEST.LBR;\n"; +cmd += "Edit testxx.pac;\n"; +cmd += "change Layer tPlace;\n"; +cmd += "Grid MIL ON;\n"; +cmd += "; WIRE 1 (-100 -100) (230 360);\n"; +cmd += "; WIRE 20 (-10 -50) (130 60);\n"; +cmd += "WIN FIT;\n;"; + +string ulp_path; + +// ** always use '/' as path delimiter to keep ULPs platform independent ** + +char bkslash = '/'; +int pos = strrchr(argv[0], bkslash); +if (pos >= 0) { // split path from filename + ulp_path = strsub(argv[0], 0, pos + 1); + } + +output(ulp_path + "v4test.scr", "wt") { + printf(cmd); +} + +exit("; SCR '" + ulp_path + "v4test.scr';\n"); diff --git a/trunk/ulp/exp-descr-html.ulp b/trunk/ulp/exp-descr-html.ulp new file mode 100644 index 00000000..1df71dd5 --- /dev/null +++ b/trunk/ulp/exp-descr-html.ulp @@ -0,0 +1,90 @@ +#usage "Export descriptions of devices and packages to HTML\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string dev[]; +string descript[]; +int count = 0; +int n = 0; + +// find some path names --------- +string ulp_path = ""; +string eagle_path = ""; // certain only for EAGLE standard installation +string doc_path = ""; // certain only for EAGLE standard installation +string direntry[]; +char c = '/'; +int dirnr, j; + int pos = strrchr(argv[0], c); + if (pos >= 0) { + ulp_path = strsub(argv[0], 0, pos + 1); + eagle_path = ulp_path; + eagle_path = strsub(eagle_path, 0, pos); + int pos = strrchr(eagle_path, c); + if (pos >= 0) { + eagle_path = strsub(eagle_path, 0, pos + 1); + dirnr = fileglob(direntry, eagle_path+"*"); + doc_path = eagle_path; + for (j; j<= dirnr; j++) { + if (strrstr(direntry[j], "doc/") > 0) { + doc_path = direntry[j]; + } + } + } + } + +// find string s2 in s1, and replace with s3 +string replace_string(string s1, string s2, string s3) { +int i, pos = 1; + string a = s1; + while (pos >= 0) { + pos = strstr(a, s2); + if (pos < 0) break; + string st1 = strsub(a, 0, pos); + string st2 = strsub(a, pos + strlen(s2)); + a = st1+s3+st2; + } + return a; + } + +if (library) library(L) { + L.devicesets(D) { + count++; + dev[count] = D.name; + descript[count] = replace_string(D.description, "

    ", "
    "); + + string h = ""; + + int l = strlen(dev[count]); + string s = strsub(dev[count], 0, 2); + string t = strsub(dev[count], 3, l); + + sprintf(h, "DEVICE: %s
    %s

    \n", dev[count], descript[count]); + cmd += h; + } + + L.packages(P) { + count++; + dev[count] = P.name; + descript[count] = replace_string(P.description, "

    ", "
    "); + string h = ""; + int l = strlen(dev[count]); + string s = strsub(dev[count], 0, 2); + string t = strsub(dev[count], 3, l); + + sprintf(h, "PACKAGE: %s
    %s

    \n", dev[count], descript[count]); + cmd += h; + } + +//define destination path name +//for a fixed destination, delete next line, uncomment the one after +//the next line and edit it + string dest = dlgFileSave("Save Description File", doc_path+"descript.htm", "*.htm"); +//dest = "c:/eagle/doc/descript.htm"; + + output(dest, "wt") { + printf(cmd); + } + } diff --git a/trunk/ulp/exp-descr-script.ulp b/trunk/ulp/exp-descr-script.ulp new file mode 100644 index 00000000..98b4a72f --- /dev/null +++ b/trunk/ulp/exp-descr-script.ulp @@ -0,0 +1,105 @@ +#usage "Export descriptions of devices and packages to a script\n" + "

    " + "Use this ULP to export the device and package descriptions " + "of a library to a file." + "

    " + "You can then edit this file with a text editor and read back " + "changed descriptions with the SCRIPT command." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string dev[]; +string descript[]; +string dest; +int count = 0; +int n = 0; + +// Find some path names --------- +string ulp_path = ""; +string eagle_path = ""; // certain only for EAGLE standard installation +string scr_path = ""; // certain only for EAGLE standard installation +string direntry[]; +char c = '/'; +int dirnr, j; + int pos = strrchr(argv[0], c); + if (pos >= 0) { + ulp_path = strsub(argv[0], 0, pos + 1); + eagle_path = ulp_path; + eagle_path = strsub(eagle_path, 0, pos); + int pos = strrchr(eagle_path, c); + if (pos >= 0) { + eagle_path = strsub(eagle_path, 0, pos + 1); + dirnr = fileglob(direntry, eagle_path+"*"); + scr_path = eagle_path; + for (j; j<= dirnr; j++) { + if (strrstr(direntry[j], "scr/") > 0) { + scr_path = direntry[j]; + } + } + } + } +//-------------------------------- + +string replacenewline(string nl) { + string a[]; + int n = strsplit(a, nl, '\n'); + if (n > 0) { + nl = ""; + for (int x = 0; x < n - 1; x++) { + nl += a[x] + "\\n"; + } + nl += a[x]; + } + return nl; + } + + if (library) library(L) { + L.devicesets(D) { + count++; + dev[count] = D.name; + descript[count] = replacenewline(D.description); + string h = ""; + sprintf(h, "EDIT %s.dev ;\nDESCRIPT '%s'\n", dev[count], descript[count]); + cmd += h; + } + + L.packages(P) { + count++; + dev[count] = P.name; + descript[count] = replacenewline(P.description); + + string h = ""; + + int l = strlen(dev[count]); + string s = strsub(dev[count], 0, 2); + string t = strsub(dev[count], 3, l); + + sprintf(h, "EDIT %s.pac ;\nDESCRIPT '%s'\n", dev[count], descript[count]); + cmd += h; + } + + cmd = "SET UNDO_LOG OFF;\n" + cmd + "SET UNDO_LOG ON;\n"; + + // EditBox + dlgDialog("Descriptions") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+Ok") dlgAccept(); + dlgPushButton("-Cancel Changes") dlgReject(); + } + }; + +// define destination path name +// for a fixed destination, delete next line, uncomment the one after +// the next line and edit it + dest = dlgFileSave("Save Description File", scr_path+"descript.scr", "*.scr"); +//dest = "c:/eagle/scr/descript.scr"; + + if (dest == "") exit(0); + output(dest, "wt") { + printf(cmd); + } + } diff --git a/trunk/ulp/exp-lbrs.ulp b/trunk/ulp/exp-lbrs.ulp new file mode 100644 index 00000000..9ec905fe --- /dev/null +++ b/trunk/ulp/exp-lbrs.ulp @@ -0,0 +1,805 @@ +#usage "en:Export of libraries from a drawing.

    \n" + "This can be used to make individual changes to components in a project. " + "Just load schematic, board or both, use this ULP to generate one or several libraries " + "containing the used components. Make your changes in the library/libraries and use the " + "UPDATE command to introduce the changes to schematic and/or board.

    " + "See Help for further details.

    ", + "de:Export von Bibliotheken aus einer Zeichnungsdatei.

    \n" + "Damit können Sie individuelle Änderungen an Komponenten in einem Projekt machen. " + "Laden Sie dazu Schaltplan, Board oder beides, verwenden Sie dieses ULP, um eine oder mehrere Bibliotheken " + "mit den verwendeten Komponenten zu generieren. Machen Sie Ihre Änderungen in der/den Bibliothek(en) " + "und verwenden Sie den UPDATE-Befehl, um die Änderungen in Schaltplan und/oder Board zu bringen.

    " + "Siehe Hilfe für weitere Details.

    " + +#require 6.0301 + +string Version = "6.0"; + +// Language: +//---------- +// Please keep to alphabetic sorting for maintainability ! +string Dictionary[] = { + "en\v" + "de\v", + "Back\v" + "Zurück\v", + "Cancel\v" + "Abbrechen\v", + "Creation mode\v" + "Erzeugungsmodus\v", + "&Browse\v" + "&Durchsuchen\v", + "Export EAGLE libraries - Help\v" + "Export von EAGLE-Bibliotheken - Hilfe\v", + "Export EAGLE libraries from drawing\v" + "Export von EAGLE-Bibliotheken aus der Zeichnung\v", + "Export original libraries\v" + "Original-Bibliotheken exportieren\v", + "File \v" + "Datei \v", + "Help\v" + "Hilfe\v", + "Load\v" + "Laden\v", + "Merge to one library, \v" + "In eine Bibliothek integrieren, \v", + "original library names as prefix for symbol, package and device names\v" + "Original-Bibliotheksnamen als Präfix für Symbol-, Package- und Devicenamen verwenden\v", + "Path\v" + "Pfad\v", + "Please start from schematic or board editor!\v" + "Bitte starten Sie vom Schaltplan- oder Board-Editor!\v", + "Start\v" + "Start\v", + "unchanged symbol, package and device names\v" + "Symbol-, Package- und Devicenamen unverändert\v" +}; + +string DlgLang = language(); +if (DlgLang != "de") DlgLang = "en"; +int LangIdx = strstr(Dictionary[0], DlgLang) / 3; + +// Translate, based on dictionary +string TR(string s) { + string t = lookup(Dictionary, s, LangIdx, '\v'); + return t ? t : s; +} +//----------------------------------------------------------------------------- + +// Used in DrawText +string AlignName[]; +AlignName[ALIGN_BOTTOM_LEFT] = "BOTTOM LEFT"; +AlignName[ALIGN_BOTTOM_CENTER] = "BOTTOM CENTER"; +AlignName[ALIGN_BOTTOM_RIGHT] = "BOTTOM RIGHT"; +AlignName[ALIGN_CENTER_LEFT] = "CENTER LEFT"; +AlignName[ALIGN_CENTER] = "CENTER CENTER"; +AlignName[ALIGN_CENTER_RIGHT] = "CENTER RIGHT"; +AlignName[ALIGN_TOP_LEFT] = "TOP LEFT"; +AlignName[ALIGN_TOP_CENTER] = "TOP CENTER"; +AlignName[ALIGN_TOP_RIGHT] = "TOP RIGHT"; + +string Croute[]; +Croute[CONTACT_ROUTE_ALL] = "ALL"; +Croute[CONTACT_ROUTE_ANY] = "ANY"; // 2012-09-26 + +// Used in DrawDimension +string DimType[]; +DimType[DIMENSION_PARALLEL] = "PARALLEL"; +DimType[DIMENSION_HORIZONTAL] = "HORIZONTAL"; +DimType[DIMENSION_VERTICAL] = "VERTICAL"; +DimType[DIMENSION_RADIUS] = "RADIUS"; +DimType[DIMENSION_DIAMETER] = "DIAMETER"; +DimType[DIMENSION_ANGLE] = "ANGLE"; +DimType[DIMENSION_LEADER] = "LEADER"; + +string UnitName[]; +UnitName[GRID_UNIT_MIC] = "MIC"; +UnitName[GRID_UNIT_MM] = "MM"; +UnitName[GRID_UNIT_MIL] = "MIL"; +UnitName[GRID_UNIT_INCH] = "INCH"; + +string x[] = { " " }; +string CurrentLbrName = ""; +string EditName; +string h, cmd = ""; +string ScriptName, PureScriptName; +string WorkPath; +string Status = ""; +int n; +int NameIndex = 0; +int Merge = 0; + +char ascii127[] = { 181, 196, 214, 220, 223, 0 }; // not allowed character 2010-05-12 +// www: In 8859-1 these chars are { ,Ä ,Ö, Ü, ß } and therefore actually allowed as object names. +// Change this if requested ! What's also allowed but deprecated is { ä, ö, ü }. Should be replaced +// by { Ä, Ö, Ü }. All other chars allowed for file names are allwoed also for object names. +// Lower case is automatically converted to upper case (except the umlauts). +string Newascii127[] = { "U", "AE", "OE", "UE", "SS", "" }; // change to allowed character + +string HelpText[] = { + "The library export collects the devices or packages from a schematic or board and stores them back " + "into one or several libraries." + "

    " + "By default all contained libraries are exported with their original name into the drawing path." + "Thus you can edit symbols and/or packages in these libraries and " + "use the UPDATE command to change all respective parts in schematic or board." + "

    " + "Alternatively all objects can be merged into a single library with the name of the schematic or board." + "You can choose between using the names of the original libraries as prefix for package, symbol and device names or not." + "Not using these prefixes can lead to ambiguities and therefore is not recommended." + "

    " + "The export path can be adjusted by 'Browse' to select a directory." + "If one of the library files to be created already exists, you will be prompted if " + "the existing file may be deleted." + , + "Der Bibliotheks-Export sammelt Devices und Packages eines Schaltplans oder Boards und speichert " + "sie in eine oder mehrere Bibliotheken." + "

    " + "Standardmässig werden alle enthaltenen Bibliotheken mit ihrem Orignialnamen in den Pfad der Zeichnungsdatei(en) " + "exportiert. So können Sie Symbole und/oder Packages editieren und mit dem UPDATE-Befehl alle entsprechenden " + "Bauteile in Schaltplan und Board aktualisieren." + "

    " + "Alternativ können alle Objekte in eine einzige Bibliothek mit Schaltplan- bzw. Boardnamen integriert werden. " + "Sie können wählen, ob Sie die Namen der Original-Bibliotheken als Präfix für die Package-, Symbol- und Devicenamen verwenden " + "oder nicht. Diese Präfixe nicht zu verwenden kann zu Mehrdeutigkeit führen und wird daher nicht empfohlen." + "

    " + "Der Export-Pfad kann mit 'Durchsuchen' eingestellt werden. " + "Wenn eines der Bibliotheken bereits existiert, werden Sie gefragt, ob die bestehende Datei gelöscht werden darf." +}; + +void DisplayHelp() { + dlgDialog(TR("Export EAGLE libraries - Help")) { + dlgHBoxLayout dlgSpacing(400); + dlgTextView(HelpText[LangIdx]); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+" + TR("Back")) dlgReject(); + dlgStretch(1); + } + }; +} + +string get_project_path() { + if (board) board(B) return(filedir(B.name)); + if (schematic) schematic(B) return(filedir(B.name)); + if (library) library(B) return(filedir(B.name)); +} + +string replacenewline(string nl) { + string a[]; + int n = strsplit(a, nl, '\n'); + if (n > 0) { + nl = ""; + for (int x = 0; x < n - 1; x++) { + nl += a[x] + "\\n"; + } + nl += a[x]; + } + return nl; +} + +// Da der ganze String in ' eingeschlossen wird, +// müssen die Apostrophen verdoppelt werden. +string addApostroph(string name) { // 2012-03-23 + string t[]; + int cnt = strsplit(t, name, '\''); // check Apostroph + if (cnt > 1) { + name = ""; + for (int i = 0; i < cnt; i++) { + if (i == 0) { + if (t[i]) name += t[i]; + } + else if (i) name += "''" + t[i]; + } + } + return name; +} + +string replaceascii127(string s, int n, string newascii) { + if (n == strlen(s)) return strsub(s, 0, n) + newascii; + else return strsub(s, 0, n) + newascii + strsub(s, n+1); +} + +string check_ascii127(string s) { // 2009-02-02 + int n = 0; + int pos; + do { + pos = strchr(s, ascii127[n]); + if (pos > -1) + s = replaceascii127(s, pos, Newascii127[n]); + if (pos < 0) n++; // 2012-02-08 + } while (ascii127[n]); + return s; +} + +// Remove this as soon as the "@-problem" is solved ! +string ReplaceAt(string s) { + for (int i = 0; i < strlen(s); i++) + if (s[i]=='@') s[i]='$'; // Creates problems when name is used in ADD and other commands + return s; +} + +string ReplaceInvalidCharsForObjNames(string s) { + for (int i = 0; i < strlen(s); i++) + if (s[i]==' ') s[i]='-'; // No '_' to distinguish from prefix ending ! + return ReplaceAt(s); +} + +string LbrPrefix(string s) { + s = check_ascii127(s); + return ReplaceInvalidCharsForObjNames(s) + "_"; +} + +int exist_file(string FileName) { + string a[]; + int n = fileglob(a, FileName); + if (n == 0) return 0; + else return 1; +} + +void CreateLBRdescription(string project_name) { + // !!! Wird nicht vorherige Description überschrieben ? + sprintf(h, "DESCRIPTION 'Generated from %s

    \\n\\\nby %s';\n", filename(project_name), filename(argv[0])); + cmd += h; + return; +} + +// Needed for delayed scripting of the layer info: +// Avoid unconditional creation of (routing) layers although they are actually not used, +// because for licenses with layer restriction the script might stop. +int RouteLayerUsed[]; // For layer with index 1..16, wether it's used by some object +string RouteLayerNames[]; + +void CreateHeader(UL_LIBRARY LBR) { + for (int i = 0; i < 16; ++i) // Reset + RouteLayerUsed[i] = 0; + LBR.layers(L) + if (L.number > 16) { + sprintf(h, "Layer %d %s;\n", L.number, L.name); cmd += h; + } + else + RouteLayerNames[L.number - 1] = L.name; // Keep names later use. + sprintf(h, "Set Wire_bend 2;\nSet Select_factor 0;\nSet Undo_log off;\n"); cmd += h; + sprintf(h, "Grid mic 1;\n"); cmd += h; + sprintf(h, "Display All;\n"); cmd += h; + cmd += "DESCRIPTION '" + addApostroph(replacenewline(LBR.description)) + "';\n"; +} + +void CreateTrailer(void) { + sprintf(h, "Set Undo_log On;\nSet Select_factor 0.02;\nGrid last;\n"); cmd += h; +} + +void PrintValidLayer(int LNr) { + if (LNr <= 16 && !RouteLayerUsed[LNr - 1]) { + // Layer used first time. Assign it's name, flag as used. + sprintf(h, "Layer %d %s;\n", LNr, RouteLayerNames[LNr -1]); cmd += h; + RouteLayerUsed[LNr - 1] = 1; + } + sprintf(h, "Layer %d;\n", LNr); cmd += h; +} + +void DrawDimension(UL_DIMENSION D) { // 2011-12-06 + sprintf(h, "CHANGE LAYER %d;\n", D.layer); cmd += h; + sprintf(h, "CHANGE SIZE %f;\n", u2mic(D.size)); cmd += h; + sprintf(h, "CHANGE RATIO %d;\n", D.ratio); cmd += h; + sprintf(h, "CHANGE DUNIT %s %s %d;\n", UnitName[D.unit], (D.visible==0) ? "off" : "on", D.precision); cmd += h; + sprintf(h, "CHANGE DLINE %f %f %f %f;\n", u2mic(D.width), u2mic(D.extwidth), u2mic(D.extlength), u2mic(D.extoffset)); cmd += h; + sprintf(h, "DIMENSION %s (C%f %f) (%f %f) (%f %f);\n", // Warum das C ? + DimType[D.dtype], + u2mic(D.x1), u2mic(D.y1), + u2mic(D.x2), u2mic(D.y2), + u2mic(D.x3), u2mic(D.y3) ); + cmd += h; + return; +} + +void DrawFrame(UL_FRAME F) { + PrintValidLayer(F.layer); + + string FBorder = ""; + if (F.border & 1) FBorder += " BOTTOM"; + if (F.border & 2) FBorder += " RIGHT"; + if (F.border & 4) FBorder += " TOP"; + if (F.border & 8) FBorder += " LEFT"; + + sprintf(h, "FRAME %d %d %s (%f %f) (%f %f);\n", + F.columns, F.rows, + FBorder, + u2mic(F.x1), u2mic(F.y1), + u2mic(F.x2), u2mic(F.y2) ); + cmd += h; + return; +} + +void DrawCircle(UL_CIRCLE C) { + PrintValidLayer(C.layer); + sprintf(h, "Circle %f (%f %f) (%f %f);\n", + u2mic(C.width), + u2mic(C.x), u2mic(C.y), + u2mic(C.x + C.radius), u2mic(C.y)); + cmd += h; + return; +} + +void DrawWire(UL_WIRE W) { + PrintValidLayer(W.layer); + if (W.arc) { // 2008-09-11 + sprintf(h, "WIRE %f %s (%f %f) %+f (%.f %.f);\n", + u2mic(W.width), + W.cap == CAP_ROUND ? "ROUND" : "FLAT", // 2011-09-07 + u2mic(W.x1), u2mic(W.y1), + W.curve, + u2mic(W.x2), u2mic(W.y2)); + cmd += h; + } + else { + sprintf(h, "Wire %f (%f %f) (%f %f);\n", + u2mic(W.width), u2mic(W.x1), u2mic(W.y1), u2mic(W.x2), u2mic(W.y2)); + cmd += h; + } +} + +void DrawRectangle(UL_RECTANGLE R) { + PrintValidLayer(R.layer); + sprintf(h, "Rect R%.1f (%f %f) (%f %f);\n", + R.angle, + u2mic(R.x1), u2mic(R.y1), + u2mic(R.x2), u2mic(R.y2)); + cmd += h; +} + +void DrawContact(UL_CONTACT C) { + string ShapeString; + string ShapeFlag; + if (C.pad) { + switch(C.pad.shape[17]) { //!!! + case PAD_SHAPE_SQUARE : ShapeString = "Square"; break; + case PAD_SHAPE_ROUND : ShapeString = "Round"; break; + case PAD_SHAPE_OCTAGON : ShapeString = "Octagon"; break; + case PAD_SHAPE_LONG : ShapeString = "Long"; break; + case PAD_SHAPE_OFFSET : ShapeString = "Offset"; break; + } + if (!(C.pad.flags & PAD_FLAG_STOP) ) ShapeFlag = "NOSTOP "; + if (!(C.pad.flags & PAD_FLAG_THERMALS) ) ShapeFlag += "NOTHERMALS "; + if ((C.pad.flags & PAD_FLAG_FIRST) ) ShapeFlag += "FIRST "; // 22.11.2004 support@cadsoft + // + // PAD [diameter] [shape] [orientation] [flags] ['name'] *.. + // + sprintf(h, "Change Drill %f;\n", u2mic(C.pad.drill)); cmd += h; + sprintf(h, "Pad %f %s R%.1f %s '%s' (%f %f);\n", + u2mic(C.pad.diameter[17]), + ShapeString, + C.pad.angle, + ShapeFlag, + addApostroph(C.pad.name), // 2012-03-29 + u2mic(C.pad.x), u2mic(C.pad.y)); + cmd += h; + } + else if (C.smd) { + if (!(C.smd.flags & PAD_FLAG_STOP) ) ShapeFlag = "NOSTOP "; + if (!(C.smd.flags & SMD_FLAG_THERMALS) ) ShapeFlag += "NOTHERMALS "; + if (!(C.smd.flags & SMD_FLAG_CREAM) ) ShapeFlag += "NOCREAM "; + + PrintValidLayer(C.smd.layer); + sprintf(h, "CHANGE Roundness %d;\n", C.smd.roundness); cmd += h; + // + // SMD [x_width y_width] [-roundness] [orientation] [flags] ['name'] *.. + // + sprintf(h, "SMD %f %f -%d R%.1f %s '%s' (%f %f);\n", + u2mic(C.smd.dx), u2mic(C.smd.dy), + C.smd.roundness, + C.smd.angle, + ShapeFlag, + addApostroph(C.smd.name), // 2012-03-29 + u2mic(C.smd.x), u2mic(C.smd.y)); + cmd += h; + } +} + +void DrawText(UL_TEXT T) { + PrintValidLayer(T.layer); + switch(T.font) { + case FONT_VECTOR : sprintf(h, "CHANGE FONT VECTOR;\n"); + cmd += h; + break; + case FONT_PROPORTIONAL : sprintf(h, "CHANGE FONT PROPORTIONAL;\n"); + cmd += h; + break; + case FONT_FIXED : sprintf(h, "CHANGE FONT FIXED;\n"); + cmd += h; + break; + } + + string Spin = ""; + string Mirror = ""; + if (T.spin) Spin = "S"; + if (T.mirror) Mirror = "M"; + + sprintf(h, "Change Size %f;\n", u2mic(T.size)); + cmd += h; + sprintf(h, "Change Ratio %d;\n", T.ratio); + cmd += h; + sprintf(h, "Change Align %s;\n", AlignName[T.align]); + cmd += h; + sprintf(h, "Change Linedistance %d;\n", T.linedistance); + cmd += h; + + sprintf(h, "Text %s%sR%.1f '%s' (%f %f);\n", + Spin, Mirror, T.angle, addApostroph(replacenewline(T.value)), u2mic(T.x), u2mic(T.y) // AddApostroph ? + ); + cmd += h; +} + +void DrawHole(UL_HOLE H) { + sprintf(h, "Change Drill %f;\n", u2mic(H.drill)); cmd += h; + sprintf(h, "Hole (%f %f);\n", u2mic(H.x), u2mic(H.y)); cmd += h; +} + +void DrawPolygon(UL_POLYGON PL) { + PrintValidLayer(PL.layer); + //sprintf(h, "Change Isolate %f;\n", u2mic(PL.isolate)); cmd += h; exist only in board + sprintf(h, "Change Spacing %f;\n", u2mic(PL.spacing)); cmd += h; + if (PL.pour == POLYGON_POUR_SOLID) { + sprintf(h, "Change Pour Solid;\n"); cmd += h; + } + else { + sprintf(h, "Change Pour Hatch;\n"); cmd += h; + } + sprintf(h, "Polygon %f ", u2mic(PL.width)); cmd += h; + PL.wires(W) { + sprintf(h, "(%f %f) ", u2mic(W.x1), u2mic(W.y1)); cmd += h; /*start coord.*/ + break; + } + PL.wires(W) { + sprintf(h, " %+f (%f %f) ", W.curve, u2mic(W.x2), u2mic(W.y2)); cmd += h; + } + sprintf(h, ";\n"); cmd += h; +} + +void DrawPin(UL_PIN P) { + string DIR = "", FUNC = "", LEN = "", VIS = "", ANGLE = "R0"; + if (P.angle == 90) (ANGLE = "R90"); + if (P.angle == 180) (ANGLE = "R180"); + if (P.angle == 270) (ANGLE = "R270"); + + if (P.function == PIN_FUNCTION_FLAG_NONE) (FUNC = "None"); + if (P.function == PIN_FUNCTION_FLAG_DOT) (FUNC = "Dot"); + if (P.function == PIN_FUNCTION_FLAG_CLK) (FUNC = "Clk"); + if (P.function == (PIN_FUNCTION_FLAG_DOT | PIN_FUNCTION_FLAG_CLK)) + (FUNC = "DotClk"); + + if (P.visible == PIN_VISIBLE_FLAG_OFF) (VIS = "Off"); + if (P.visible == PIN_VISIBLE_FLAG_PIN) (VIS = "Pin"); + if (P.visible == PIN_VISIBLE_FLAG_PAD) (VIS = "Pad"); + if (P.visible == (PIN_VISIBLE_FLAG_PIN | PIN_VISIBLE_FLAG_PAD)) + (VIS = "Both"); + + switch(P.direction) { + case PIN_DIRECTION_NC : DIR = "NC"; break; + case PIN_DIRECTION_IN : DIR = "In"; break; + case PIN_DIRECTION_OUT : DIR = "Out"; break; + case PIN_DIRECTION_IO : DIR = "IO"; break; // 2011-10-10 + case PIN_DIRECTION_OC : DIR = "OC"; break; + case PIN_DIRECTION_PWR : DIR = "Pwr"; break; + case PIN_DIRECTION_PAS : DIR = "Pas"; break; + case PIN_DIRECTION_HIZ : DIR = "Hiz"; break; + case PIN_DIRECTION_SUP : DIR = "Sup"; + } + + switch(P.length) { + case PIN_LENGTH_POINT : LEN = "Point"; break; + case PIN_LENGTH_SHORT : LEN = "Short"; break; + case PIN_LENGTH_MIDDLE : LEN = "Middle"; break; + case PIN_LENGTH_LONG : LEN = "Long"; + } + + sprintf(h, "Pin '%s' %s %s %s %s %s %d (%f %f);\n", + addApostroph(P.name), // 2012-02-08 + DIR, FUNC, LEN, ANGLE, VIS, P.swaplevel, u2mic(P.x), u2mic(P.y)); + cmd += h; +} + +void DrawSymbol(UL_SYMBOL S) { + S.circles(C) DrawCircle(C); + S.rectangles(R) DrawRectangle(R); + S.wires(W) DrawWire(W); + S.pins(P) DrawPin(P); + S.texts(T) DrawText(T); + S.polygons(PL) DrawPolygon(PL); + S.frames(F) DrawFrame(F); + S.dimensions(D) DrawDimension(D); + cmd += "DESCRIPTION '" + addApostroph(replacenewline(S.description)) + "';\n"; +} + +void DrawPackage(UL_PACKAGE P) { + sprintf(h, "GRID mic;\n"); cmd+=h; // 2011-04-11 + P.circles(C) DrawCircle(C); + P.wires(W) DrawWire(W); + P.rectangles(R) DrawRectangle(R); + P.contacts(C) DrawContact(C); + P.texts(T) DrawText(T); + P.holes(H) DrawHole(H); + P.polygons(PL) DrawPolygon(PL); + P.frames(F) DrawFrame(F); + P.dimensions(D) DrawDimension(D); + cmd += "DESCRIPTION '" + addApostroph(replacenewline(P.description)) + "';\n"; +} + +// ************************************************ +// see also *** export-schematic_mil-board_mm-script.ulp *** +// ************************************************ + +void DrawDevice(UL_DEVICESET D, UL_LIBRARY LBR) { + cmd += "DESCRIPTION '" + addApostroph(replacenewline(D.description)) + "';\n"; + cmd += "PREFIX '" + D.prefix + "';\n"; + cmd += "VALUE " + D.value + ";\n"; + D.gates(G) { + string GateAddlevel; + switch (G.addlevel) { + case GATE_ADDLEVEL_NEXT : GateAddlevel = "Next"; break; + case GATE_ADDLEVEL_MUST : GateAddlevel = "Must"; break; + case GATE_ADDLEVEL_CAN : GateAddlevel = "Can"; break; + case GATE_ADDLEVEL_REQUEST : GateAddlevel = "Request"; break; + case GATE_ADDLEVEL_ALWAYS : GateAddlevel = "Always"; + }; + sprintf(h, "CHANGE Addlevel %s;\n", GateAddlevel); cmd += h; + sprintf(h, "CHANGE Swaplevel %d;\n", G.swaplevel); cmd += h; + string symname = G.symbol.name; // No problem with @... + if (Merge == 1) + symname = LbrPrefix(LBR.name) + symname; + sprintf(h, "ADD '%s' '%s' (%f %f);\n", addApostroph(symname), addApostroph(G.name), u2mic(G.x), u2mic(G.y)); // 2012-02-07 + cmd += h; + } + D.devices(DV) { + if (DV.package) { + string pacname = ReplaceAt(DV.package.name); // !!! + if (Merge == 1) + pacname = LbrPrefix(LBR.name) + pacname; + cmd += "PACKAGE '" + addApostroph(pacname) + "' " + DV.name + ";\n"; // addApostroph here problematic ! + } + DV.gates(G) { + if (DV.package) { + G.symbol.pins(P) { + string cont = ""; + P.contacts(C) { // 2011-12-06 + if (!cont) sprintf(h, "%s", addApostroph(C.name)); // 2012-03-29 + else sprintf(h, " %s", addApostroph(C.name)); // 2012-003-29 + cont += h; + } + if (cont) { + sprintf(h, "CONNECT %s '%s.%s' '%s';\n", // //2012-03-23 problem with # in pin name + Croute[P.route], + addApostroph(G.name), // 2012-03-29 + addApostroph(P.name), // 2012-03-29 + cont + ); + cmd += h; + } + } + } + } + string t[]; + int n = strsplit(t, DV.technologies, ' '); + for (int i = 0; i < n; i++) { + sprintf(h,"TECHNOLOGY '%s';\n", addApostroph(t[i])); // 2012-03-23 + cmd += h; + DV.attributes(A, t[i]) { + string const = ""; + if (A.constant) const = " CONSTANT"; + sprintf(h,"ATTRIBUTE '%s' '%s' %s\n", A.name, addApostroph(A.value), const); // 2010-10-14 + cmd += h; + } + } + } + return; +} + +//---------------- +int is_new(void) { // n = nr of entries + int i; + if (n == 0) return 1; + for (i = 0; i < n; i++) { + if (x[n] == x[i]) { + return(0); + } + } + return 1; +} + +// --------- +void CreateOneLibHeader(UL_LIBRARY LBR, string project_name) { + if (exist_file(WorkPath+CurrentLbrName+".lbr")) { + sprintf(h, "REMOVE '%s';\n", WorkPath+CurrentLbrName+".lbr"); cmd += h; // delete existing lbr + } + sprintf(h, "OPEN '~dummy~.lbr';\nCLOSE;\nOPEN '%s.lbr';\n", WorkPath+CurrentLbrName); // 2012-02-07 to close an opened library first + cmd += h; + CreateHeader(LBR); + CreateLBRdescription(project_name); +} + +// --------- +void OutputPackages(UL_LIBRARY LBR) { + LBR.packages(P) { + string pacname = ReplaceAt(P.name); + if (Merge == 1) + pacname = LbrPrefix(LBR.name) + pacname; + n++; + x[n] = pacname; + if (is_new()) { + Status = " PAC: " + P.name; dlgRedisplay(); + sprintf(h, "\nEdit '%s.PAC';\n", addApostroph(pacname)); cmd += h; + DrawPackage(P); + } + } +} + +void OutputSymbols(UL_LIBRARY LBR) { + LBR.symbols(S) { + string symname = S.name; + if (Merge == 1) + symname = LbrPrefix(LBR.name) + symname; + n++; + x[n] = symname; + if (is_new()) { + Status = " SYM: " + S.name; dlgRedisplay(); + sprintf(h, "\nEdit '%s.SYM';\n", addApostroph(symname)); cmd += h; + DrawSymbol(S); + } + } +} + +void OutputDevices(UL_LIBRARY LBR) { + LBR.devicesets(D) { + string dname = D.name; + if (Merge == 1) + dname = LbrPrefix(LBR.name) + dname; + n++; + x[n] = dname; + if (is_new()) { + Status = " DEV: " + D.name; dlgRedisplay(); + NameIndex = 0; + sprintf(h, "\nEdit '%s.DEV';\n", addApostroph(dname)); cmd += h; + DrawDevice(D, LBR); + } + } +} + +void CreateLbr(UL_LIBRARY LBR) { + if (exist_file(WorkPath+CurrentLbrName+".lbr")) { + sprintf(h, "REMOVE '%s.lbr';\n", WorkPath+CurrentLbrName); + cmd += h; // delete existing lbr + } + sprintf(h, "OPEN '~dummy~.lbr';\nCLOSE;\nOPEN '%s.lbr';\n", WorkPath+CurrentLbrName); // 2012-02-07 to close a opened library first + cmd += h; + CreateHeader(LBR); +} + +void make_lbr(void) { + if (board) board(B) { + B.libraries(LBR) { + CurrentLbrName = LBR.name; + CreateLbr(LBR); + LBR.packages(PAC) { + OutputPackages(LBR); + cmd += "WRITE;\n"; + break; + }; + } + } + if (schematic) schematic(SCH) { + SCH.libraries(LBR) { + CurrentLbrName = LBR.name; + CreateLbr(LBR); + LBR.devices(DEV) { + OutputPackages(LBR); + n=0; + OutputSymbols(LBR); + n=0; + OutputDevices(LBR); + cmd += "WRITE;\n"; + break; + }; + } + } + CreateTrailer(); +} + +//------------------- +void make_one_lbr(void) { + int noLbrs = 1; + if (board) board(B) { + B.libraries(LBR) { + CurrentLbrName = filesetext(EditName, ""); + CreateOneLibHeader(LBR, B.name); + noLbrs = 0; + break; + } + n = 0; + B.libraries(LBR) { + OutputPackages(LBR); + } + } + if (schematic) schematic(SCH) { + SCH.libraries(LBR) { + CurrentLbrName = filesetext(EditName, ""); + CreateOneLibHeader(LBR, SCH.name); + noLbrs = 0; + break; + } + n = 0; + SCH.libraries(LBR) { + OutputPackages(LBR); + } + n = 0; + SCH.libraries(LBR) { + LBR.devices(DEV) { + OutputSymbols(LBR); + } + } + n = 0; + SCH.libraries(LBR) { + LBR.devices(DEV) { + OutputDevices(LBR); + } + } + } + if (!noLbrs) { + cmd += "WRITE;\n"; + CreateTrailer(); + } + return; +} + +// ----------- +void show_save_script_file(string cm) { + ScriptName = WorkPath+PureScriptName; + output(ScriptName, "wtD") printf("%s", cm); + return; +} + +//------------ main ---------------------------------------- +if (library) { + dlgMessageBox(TR("Please start from schematic or board editor!")); + exit(1); +} +else { + if (board) board(B) EditName = filename(B.name); // name of loaded board/schematic w/o path + if (schematic) schematic(S) EditName = filename(S.name); +} + +PureScriptName = filesetext(EditName, ".scr"); // name of generated script w/o path +WorkPath = get_project_path(); + +int Result = dlgDialog(TR("Export EAGLE libraries from drawing")) { + dlgHBoxLayout { + dlgLabel("&" + TR("Path") + ":"); + dlgStringEdit(WorkPath); + dlgPushButton(TR("&Browse") + "...") { + if (cmd) cmd = ""; + h = WorkPath; + WorkPath = dlgDirectory("", WorkPath); + if (WorkPath == "") WorkPath = h; + else WorkPath += "/"; // 29.03.2005 support@cadsoft.de + } + } + dlgGroup(TR("Creation mode")) { + dlgRadioButton("&" + TR("Export original libraries"), Merge); //name like drawing + dlgRadioButton("&" + TR("Merge to one library, ") + TR("original library names as prefix for symbol, package and device names"), Merge); + dlgRadioButton( TR("Merge to one library, ") + "&" + TR("unchanged symbol, package and device names"), Merge); + } + dlgLabel(Status, 1); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("&" + TR("Help") + "...") DisplayHelp(); + dlgPushButton("+&" + TR("OK")) { + cmd = ""; + if (Merge > 0) + make_one_lbr(); + else + make_lbr(); + show_save_script_file(cmd); + exit("SCRIPT '"+ScriptName+"';\n"); + } + dlgPushButton("-&" + TR("Cancel")) dlgReject(); + } +}; diff --git a/trunk/ulp/exp2image.ulp b/trunk/ulp/exp2image.ulp new file mode 100644 index 00000000..b7a0a220 --- /dev/null +++ b/trunk/ulp/exp2image.ulp @@ -0,0 +1,414 @@ +#usage "Export a SCH/BRD to IMAGE

    " + "Usage: RUN exp2image monochrome resolution image type layer [layer layer]" + "

    " + "Tip: Assign a funktion key with
    " + "ASSIGN Shift+Ctrl+Alt+I 'run exp2image monochrome 150 .tif 1 17 18 20;';
    " + "or
    " + "ASSIGN Shift+Ctrl+Alt+I 'run exp2image color 150 .bmp 91 92 94 95 96;';" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +// 2005-02-17 alf@cadsoft.de empty layers are not selectable +// 2008-06-23 alf@cadsoft.de do it also in deviceset, symbol and package + + +string file_name; + +string brd_suffix; +int ratsnest = 0; // start Ratsnest befor export image + +int sheetprint_from; +int sheetprint_to; +int lastsheet = 0; +string actualsheet; +int sheetprint = 0; // 0 = All, 1 = From To, 2 = Actual + +string exp_Layers; +string sec_usedlayer[]; +int absolutUsedLayer = 0; + +int lVisible[]; +int useLayer[]; +string lNames[] = { " " }; + +int Resolution = 150; // DPI +string monochrome = ""; +int sel_monochrome = 0; + +string filetype[] = { ".bmp", // Windows-Bitmap-Datei + ".png", // Portable-Network-Graphics-Datei + ".pbm", // Portable-Bitmap-Datei + ".pgm", // Portable-Grayscale-Bitmap-Datei + ".ppm", // Portable-Pixelmap-Datei + ".xbm", // X-Bitmap-Datei + ".xpm", // X-Pixmap-Datei + ".tif" // Tiff-Datei + }; + +int select_type = 0; + +string cmd = ""; +int Result = 0; +string s; + +string help = usage; + + +// *** functions *** +void commandPrint(string name_suffix) { + string h; + sprintf(h, "EXPORT IMAGE '%s%s%s' %s %d;\n", file_name, name_suffix, filetype[select_type], monochrome, Resolution); + cmd += h; + return; +} + + +// main +int nt = 0; +do { + if(strlwr(argv[3]) == filetype[nt]) { + select_type = nt; + break; + } + nt++; +} while(filetype[nt]); + +if (argv[2]) Resolution = strtol(argv[2]); + +if (argv[1]) { + string mono = strupr(argv[1]); + if (mono == "MONOCHROME") sel_monochrome = 1; + else if (mono == "COLOR") sel_monochrome = 0; + else { + dlgMessageBox("Use MONOCHROME or COLOR", "Ok"); + exit(0); + } +} + +int an = 0; +do { + if (argv[4+an]) { + exp_Layers += " " + argv[4+an]; + an++; + } + else break; +} while (an); + +if (schematic) { + schematic(S) { + file_name = filesetext(S.name, ""); + if (sheet) sheet(SH) sprintf(actualsheet, "%d", SH.number); + S.sheets(SH) { + lastsheet = SH.number; + } + S.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + } + } + sheetprint_to = lastsheet; +} + +else if (board) { + board(B) { + file_name = filesetext(B.name, ""); + B.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + } + } +} + +else if (package || symbol || deviceset) { + library(LBR) { + if (package) package(P) file_name = P.name; + else if(symbol) symbol(SYM) file_name = SYM.name; + else if (deviceset) deviceset(DEV) file_name = DEV.name; + LBR.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + } + } +} + +else { + dlgMessageBox("Start this ULP in a SCH, BRD, DEV, PAC or SYM:", "OK"); + exit(-1); +} + +// *** tabs menue *** +Result = dlgDialog("Export Image") { + // Define a container for tab pages + dlgLabel(file_name); + + dlgTabWidget { + dlgTabPage("&Export to Image") { + dlgHBoxLayout { + dlgStretch(0); + + if (board) { + + string Example = "Example: _top --> " + filename(file_name) + "_top" + filetype[select_type] + ""; + dlgVBoxLayout { + dlgSpacing(4); + dlgHBoxLayout { + dlgSpacing(8); + dlgCheckBox("Start &RATSNEST befor export ", ratsnest); + dlgStretch(1); + } + dlgStretch(1); + dlgHBoxLayout { + dlgSpacing(8); + dlgLabel("&File suffix "); + dlgStringEdit(brd_suffix); + dlgStretch(1); + } + dlgHBoxLayout { + dlgSpacing(8); + dlgLabel(Example); + dlgStretch(1); + } + } + } // end if board + + if (package) { + } // end if package + + if (schematic) { + dlgSpacing(8); + dlgGroup("Sheet") { + dlgVBoxLayout { + dlgHBoxLayout { + dlgRadioButton("&All sheets", sheetprint); + dlgLabel(" "); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("&Select ", sheetprint); + dlgLabel(" &from "); + dlgIntEdit(sheetprint_from, 1, lastsheet); + dlgLabel(" &to "); + dlgIntEdit(sheetprint_to, sheetprint_from, lastsheet); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("A&ctual sheet #", sheetprint); + dlgLabel(actualsheet); + dlgStretch(1); + } + } + dlgStretch(1); + } + } // end if schematic + + if (deviceset || symbol) { + } // end if deviceset/symbol + + // *** Layer list to print *** + int Seleclayer; + string layer[] ; + int n = 0; + int ln = strsplit(layer, exp_Layers, ' '); + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (useLayer[num]) { + if(schematic || deviceset || symbol) { // 2008-06-23 + if (num >= 90) { + sprintf(sec_usedlayer[n], "%3s %s", layer[x], lNames[num]); + n++; + } + } + if(board || package) { // 2008-06-23 + if (num < 90 || num > 100) { + sprintf(sec_usedlayer[n], "%3s %s", layer[x], lNames[num]); + n++; + } + } + } + } + sec_usedlayer[n] = ""; // clear last+1 + absolutUsedLayer = n; + dlgSpacing(10); + dlgVBoxLayout { + if (absolutUsedLayer) { + dlgHBoxLayout { + dlgSpacing(100); + } + dlgLabel("Printed layers"); + dlgListBox(sec_usedlayer, Seleclayer); + } + else { + dlgLabel(""); + dlgLabel("No Layers selected."); + } + dlgStretch(0); + } + dlgStretch(1); + } + dlgStretch(1); + } // ************ End of TAB | SHEET *********** + + dlgTabPage("&Help") { + dlgHBoxLayout { + dlgSpacing(10); + dlgVBoxLayout { + dlgLabel(help); + dlgStretch(1); + } + } + } + } // ************ End of all TABs *********** + + dlgHBoxLayout { + dlgLabel("&Image type"); + dlgComboBox(filetype, select_type); + dlgSpacing(15); + dlgCheckBox("&Monochrome", sel_monochrome); + dlgSpacing(15); + dlgLabel("Resolution &DPI"); + dlgIntEdit(Resolution, 50, 600); + dlgStretch(1); + } + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } +}; + +if (Result == 0) exit (0); +if (!absolutUsedLayer) exit(0); + +if (sel_monochrome) monochrome = "MONOCHROME"; +else monochrome = ""; + + +string layer[] ; +int n = 0; +int ln = strsplit(layer, exp_Layers, ' '); +if(board || package) { // 2008-06-23 + cmd += "SET DISPLAY_MODE REAL;\n"; + if (ratsnest) cmd += "RATSNEST;\n"; + cmd += "DISPLAY NONE "; + + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (num < 90 || num > 100) { + if (useLayer[num]) { + sprintf(s, " %3s", layer[x]); + cmd += s; + if(num == 21) cmd += " -23 -25 -27 -51"; + if(num == 22) cmd += " -24 -26 -28 -52"; + n++; + } + } + } + cmd += ";\n"; + if (board) commandPrint(brd_suffix); + else if (package) commandPrint("-PAC"); +} + +if(schematic || deviceset || symbol) { + cmd += "DISPLAY NONE "; + for (int x = 0; x < ln; x++) { + int num = strtod(layer[x]); + if (useLayer[num]) { + if (num >= 90) { + sprintf(s, " %3s", layer[x]); + cmd += s; + n++; + } + } + } + cmd += ";\n"; + string sh; + string shn; + if (schematic) { // 2008-06-23 + switch (sheetprint) { + case 0 : schematic(S) { + S.sheets(SH) { + sprintf(sh, "EDIT '.s%d';\n", SH.number); + cmd += sh; + sprintf(shn, "_s%d", SH.number); + commandPrint(shn); + } + } + break; + + case 1 : for (int prn = sheetprint_from; prn <= sheetprint_to; prn++) { + sprintf(sh, "EDIT '.s%d';\n", prn); + cmd += sh; + sprintf(shn, "_s%d", prn); + commandPrint(shn); + } + break; + + case 2 : sprintf(sh, "EDIT '.s%s';\n", actualsheet); + cmd += sh; + sprintf(shn, "_s%s", actualsheet); + commandPrint(shn); + break; + } + } + else if (deviceset) commandPrint("-DEV"); + else if (symbol) commandPrint("-SYM"); + +} + +cmd += "DISPLAY "; +if(board || package) { + for(int l = 1; l < 90; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + for(l = 100; l < 256; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + cmd += ";\n"; +} + +if(schematic || deviceset || symbol) { // 2008-06-23 + for(int l = 91; l < 256; l++) { + if (useLayer[l]) { + if (lVisible[l]) { + sprintf(s, " %d", l); + cmd += s; + } + else { + sprintf(s, " -%d", l); + cmd += s; + } + } + } + cmd += ";\n"; + if(schematic) { // 2008-06-23 alf@cadsoft.de + sprintf(s, "EDIT '.s%s';\n", actualsheet); + cmd += s; + } +} + +exit (cmd); diff --git a/trunk/ulp/export-class.ulp b/trunk/ulp/export-class.ulp new file mode 100644 index 00000000..0bf0fff5 --- /dev/null +++ b/trunk/ulp/export-class.ulp @@ -0,0 +1,89 @@ +#usage "Export Net-Classes\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#require 5.0200; + +string Version = "1.3"; // 2008-10-24 export Matrix - alf@cadsoft.de + // 2009-01-20 corrected drill options - alf@cadsoft.de + // 2011-09-29 undeline and printable character allowed + + +string grid[] = { "MIC", "MM", "MIL", "INCH" }; +int Gridval = 1; // 0=mic 1=mm 2=mil 3=inch *** + // choose the value for the units you're working with + +string cmd, s; +string projectm; + +real u2u(int val) { + switch(Gridval) { + case 0 : return u2mic(val); + case 1 : return u2mm(val); + case 2 : return u2mil(val); + case 3 : return u2inch(val); + } +} + +void savescr(string projectname) { + string file = dlgFileSave("save CLASS script", filesetext(projectname, "-class.scr"), "*.scr"); + if (file) { + output(file, "wt" ) printf("%s", cmd); + exit(0); + } + else return; +} + +void menue(string projectname) { + int Result = dlgDialog("Export Net CLASSes") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgTextEdit(cmd); + } + dlgHBoxLayout { + dlgPushButton("+&Cancel") dlgAccept(); + dlgPushButton("&Save script") savescr(projectname); + dlgStretch(1); + } + }; + if (Result == 0) exit (0); + return; + } + +void check(string cname) { + if (!isdigit(cname[0]) && !isspace(cname[0])) return; // 2011-09-29 + dlgMessageBox("Do not use a digit for first character of CLASS name!\n" + cname, "OK"); + exit("CLASS"); +} + +void class(UL_CLASS C) { + int classn = C.number; + for (int n = 0; n <= C.number; n++) { + if (C.name) { + check(C.name); + sprintf(s, "CLASS %d '%s' %.4f %.4f %.4f %d:%.4f;\n", C.number, C.name, u2u(C.width), u2u(C.clearance), u2u(C.drill), n, u2u(C.clearance[n]) ); + cmd += s; + } + } +} + +// main +if (board) board(B) { + projectm = B.name; + sprintf(cmd, "# export from %s\n# at %s with %s Version %s\nGRID %s;\n", B.name, t2string(time()), EAGLE_SIGNATURE, Version, grid[Gridval]); + B.classes(C) class(C); +} + +else if (schematic) schematic(S) { + projectm = S.name; + sprintf(cmd, "# export from %s\n# at %s with %s Version %s\nGRID %s;\n", S.name, t2string(time()), EAGLE_SIGNATURE, Version, grid[Gridval]); + S.classes(C) class(C); +} + +else if (library) dlgMessageBox("start this ULP in Board or Schematic", "OK"); + +cmd += "GRID LAST;\nCLASS"; +menue(projectm); diff --git a/trunk/ulp/export-error.ulp b/trunk/ulp/export-error.ulp new file mode 100644 index 00000000..afaf3d49 --- /dev/null +++ b/trunk/ulp/export-error.ulp @@ -0,0 +1,484 @@ +#usage "de:Exportiert/speichert DRC & ERC Errors

    " + "RUN export-errors [Save] [Filename]
    " + "author alf@cadsoft.de" + , + "en:Export/save DRC & ERC errors

    " + "RUN export-errors [Save] [Filename]
    " + "author alf@cadsoft.de" + +#require 7.01.03; +string Version = "1.0.0"; // 2014-11-11 alf@cadsoft.de + +string HeaderErcErrors; +string HeaderDrcErrors; + +string SaveErrorFileName = ""; +string Option1 = strupr(argv[1]); +int CntErrorInconsistenc = 0; + +int Consistence = 0; +string ExistSCHfile = ""; +string ExistBRDfile = ""; +string ErrorList[]; +int CntError = 0; + +int Debug = 0; + +/* +Die Member layer und contours() sind nur im UL_BOARD Kontext und +die Member area2, modulename, s1..s6 und sheet sind nur im UL_SCHEMATIC Kontext verfügbar. +*/ +int ErrBx1[], ErrBy1[], ErrBx2[], ErrBy2[]; // area UL_AREA nur im Board +int ErrSx1[], ErrSy1[], ErrSx2[], ErrSy2[]; // area2 UL_AREA nur im Schaltplan +int ErrCode[]; // Identifikations-Nummer +string ErrDescription[]; +int ErrLayer[]; +string ErrModulename[]; +string ErrS1[], ErrS2[], ErrS3[], ErrS4[], ErrS5[], ErrS6[]; +int ErrSheet[]; // int Seitennummer +string ErrSignature[]; // string (Signatur-String) state +int ErrState[]; // int (ERROR_STATE_...) +int ErrType[]; // int (ERROR_TYPE_...) +int ErrX[], ErrY[]; // int (Mittelpunkt) + +string ErrorState[], ErrorType[]; + ErrorState[ERROR_STATE_ACTIVE] = "error has not yet been approved or processed"; + ErrorState[ERROR_STATE_APPROVED] = "error has been approved"; + ErrorState[ERROR_STATE_PROCESSED] = " error has been processed"; + ErrorType[ERROR_TYPE_NONE] = "no error"; + ErrorType[ERROR_TYPE_WARNING] = "warning"; + ErrorType[ERROR_TYPE_ERROR] = "error"; + ErrorType[ERROR_TYPE_CONSISTENCY] = "consistency error"; + + HeaderErcErrors = "Consistency not checked (no board loaded)"; + +if (language() == "de") { + ErrorState[ERROR_STATE_ACTIVE] = "Fehler wurde weder bearbeitet, noch gebilligt"; + ErrorState[ERROR_STATE_APPROVED] = "Fehler wurde gebilligt"; + ErrorState[ERROR_STATE_PROCESSED] = "Fehler wurde bearbeitet"; + ErrorType[ERROR_TYPE_NONE] = "kein Fehler"; + ErrorType[ERROR_TYPE_WARNING] = "Warnung"; + ErrorType[ERROR_TYPE_ERROR] = "Fehler"; + ErrorType[ERROR_TYPE_CONSISTENCY] = "Konsistenz-Fehler"; + + HeaderErcErrors = "Konsistenz nicht geprüft (kein Board geladen)"; +} + + +string s; + +/* ### ERROR functions ### */ +void error_3(int sel) { + sprintf(s, "RUN ulpmessage 'Signatur:%s
    Description:%s
    Layer:%d
    '", + ErrSignature[sel], ErrDescription[sel], ErrLayer[sel] + ); + exit(s); +} + +void error_5(int sel) { + real x = u2mm(ErrSx2[sel]) - u2mm(ErrSx1[sel]); + real y = u2mm(ErrSy2[sel]) - u2mm(ErrSy1[sel]); + if (x < y) { + sprintf(s, "Win (%.8fmm %.8fmm);\nRUN ulpmessage 'der Abstand in x ist um %.8fmm zu klein.'", + u2mm(ErrX[sel]), u2mm(ErrY[sel]), x + ); + } + else if (y < x) { + sprintf(s, "Win (%.8fmm %.8fmm);\nRUN ulpmessage 'der Abstand in y ist um %.8fmm zu klein.'", + u2mm(ErrX[sel]), u2mm(ErrY[sel]), y + ); + } + else { + sprintf(s, "Win (%.8fmm %.8fmm);\nRUN ulpmessage 'der Abstand in x & y ist jeweils um %.8fmm zu klein.'", + u2mm(ErrX[sel]), u2mm(ErrY[sel]), y + ); + } + exit(s); +} + +void error_11(int sel) { + sprintf(s, "DISPLAY NONE %d;\nWINDOW (%.8fmm %.8fmm);\nCHANGE FONT Vector (%.8fmm %.8fmm);\nDISPLAY LAST;", + ErrLayer[sel], + u2mm(ErrX[sel]), u2mm(ErrY[sel]), + u2mm(ErrX[sel]), u2mm(ErrY[sel]) + ); + exit(s); +} + +void checkerror(int sel) { + int ecod = ErrCode[sel]; + switch(ecod) { + case 1 : // Drill Size + break; + case 2 : // Drill Distance + break; + case 3 : // Width + break; + case 4 : // Dimension + break; + case 5 : // Clearance + break; + case 6 : // Restrict + break; + case 7 : // Keepout + break; + case 8 : // Angle + break; + case 9 : // Off Grid + break; + case 11 : // No Vector Font + break; + case 19 : // Overlap + break; + case 101 : // Nicht angeschlossener Pin + break; + case 102 : // SUPPLY-Pin überschrieben mit xxx + break; + case 103 : // NC-Pin IC3 xxxx verbunden mit xx + break; + case 104 : // POWER-Pin verbunden mit xxx + break; + case 105 : // Keine Pins an Netz xxx + break; + case 106 : // Nur ein Pin an Netz xxx + break; + case 107 : // Junction verbindet Netze xx und xx scheinbar + break; + case 108 : // Fehlende Junction in Netz xxx + break; + case 109 : // Nahe beieinander liegende, aber unverbundene Linien in Netz xx + break; + case 110 : // Nahe beeinander liegende, aber unverbundene Linien in Netzen xxx und xxx + break; + case 111 : // Netz xxx überlappt Pin + break; + case 112 : // Pins überlappen + break; + case 113 : // Part has no value + break; + case 115 : // Segment des Netzes XXX hat keine erkennbare Verbindung (z.B. Label, Bus oder Supply-Pin) zu anderen Segmenten des selben Netzes + break; + case 116 : // Pin an XXXX angeschlossen ohne Netz-Wire, Junction oder anderen Pin + break; + case 118 : // Netz benutzt durch Port xxx hat kein Label + break; + case 119 : // Es existiert kein Modul Netz für Port xxxx + break; + case 120 : // Bus A[0..15] überlappt Port + break; + case 121 : // Netz L1 überlappt Port + break; + case 201 : // SUPPLY-Pin überschrieben mit mehr als einem Signal + break; + case 202 : // not connected input pin + break; + case 205 : // no Supply-Pin for implizit Power pin + break; + case 206 : // Mehr als ein OUTPUT-Pin an Netz xx + break; + case 209 : // Nur INPUT-Pins an Netz xxx + break; + case 211 : // Netzname XXX ist im Bus xxxxxx nicht enthalten + break; + case 213 : // Direction 'io' von Port KB0 ist nicht kompatibel mit den Pins am Netz im Modul + break; + case 304 : // element not found on board + break; + case 305 : // part not found on schematic + break; + default : sprintf(s, "Error-Code %d: unknown!", ecod); + dlgDialog("Error") { + dlgHBoxLayout dlgSpacing(600); + dlgStringEdit(ErrDescription[sel]); + dlgLabel(s); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); exit(-1); } + dlgStretch(1); + } + }; + } +} + +/* *** normal functions *** */ +string checkexistfile(string existfile) { + string a[]; + int cnt = fileglob(a, existfile); + if (cnt) return a[0]; + return ""; +} + +void savefile(string sourcefilename, string editname) { + output(SaveErrorFileName, "wt") { + printf("#Exported from: \"%s\"\n#with %s Version %s\n", sourcefilename, filename(argv[0]), Version); + printf("#%s\n", EAGLE_SIGNATURE); + printf("#at:%s\n", t2string(time()) ); + if (CntErrorInconsistenc) { + //if (ExistSCHfile) printf("%s\n",ExistSCHfile); + //if (ExistBRDfile) printf("%s\n",ExistBRDfile); + printf("%s\n", HeaderErcErrors); + } + else { + printf("%s\n", HeaderErcErrors); + } + for (int n = 0; n < CntError; n++) { + printf("%s\n", ErrorList[n]); + } + } +} + +void saveerrors(string header, string sourcefilename, string errorfilename) { + string a[]; + int fexist = fileglob(a, errorfilename); + int xl = 30 + strlen(errorfilename) * 5; + + dlgDialog(header) { + dlgHBoxLayout dlgSpacing(xl); + dlgStringEdit(errorfilename); + dlgHBoxLayout { + if (fexist) { + if (language() == "de") { + dlgLabel("Datei existiert bereits... "); + dlgPushButton("Überschreiben") { dlgAccept(); savefile(sourcefilename, errorfilename); exit(0); } + } + else { + dlgLabel("File exist... "); + dlgPushButton("Overwrite") { dlgAccept(); savefile(sourcefilename, errorfilename); exit(0); } + } + } + else { + dlgPushButton("+OK") { dlgAccept(); savefile(sourcefilename, errorfilename); exit(0); } + } + dlgPushButton("+CANCEL") { dlgReject(); exit(-2); } + dlgStretch(1); + } + }; +} + +void saveerrdialog(string dialogheader, string listheader, string sourcefilename) { + string consistenceleader; + string consistencetrailer; + if (schematic) { + if (CntErrorInconsistenc) { + //if (ExistSCHfile) printf("%s\n",ExistSCHfile); + //if (ExistBRDfile) printf("%s\n",ExistBRDfile); + } + else { + consistenceleader = ""; + consistencetrailer = ""; + } + if (Consistence) { + ExistSCHfile = ""; + ExistBRDfile = ""; + consistenceleader = ""; + consistencetrailer = ""; + } + } + if (board) { + ExistSCHfile = ""; + ExistBRDfile = ""; + consistenceleader = ""; + consistencetrailer = ""; + } + dlgDialog(dialogheader) { + int sel = -1; + int srt = 0; + dlgHBoxLayout dlgSpacing(800); + if (ExistSCHfile) dlgLabel(ExistSCHfile); + if (ExistBRDfile) dlgLabel(ExistBRDfile); + + dlgLabel(consistenceleader + HeaderErcErrors + consistencetrailer); + + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgListView(listheader, ErrorList, sel, srt) checkerror(sel); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("&Save") saveerrors("Save ERC-ERRORS", sourcefilename, SaveErrorFileName); + dlgStretch(1); + } + }; +} + +if (schematic) { + schematic(SCH) { + if (!SCH.checked) { + string msg = "Schematic is changed, first start Electrical Rule Check (ERC)!"; + if (language() == "de") msg = "Der Schaltplan wurde verändert, starten sie zuerst den Electrical Rule Check!"; + if (dlgMessageBox(msg, "OK", "CANCEL") != 0) exit(-3); + string cmd; + sprintf(cmd, "ERC; RUN '%s'", argv[0]); + exit (cmd); + } + ExistSCHfile = "SCH File loaded: \"" + SCH.name + "\""; + ExistBRDfile = "BRD File exist : \"" + checkexistfile(filesetext(SCH.name, ".brd")) + "\""; + if(project.board) { + Consistence = 1; + HeaderErcErrors = "Baord and schematic are consistent"; + if (language() == "de") HeaderErcErrors = "Board und Schaltplan sind konsistent"; + } + else Consistence = 0; + + SCH.errors(E) { + if (E.type == ERROR_TYPE_CONSISTENCY) CntErrorInconsistenc++; + ErrSignature[CntError] = E.signature; + ErrSx1[CntError] = E.area.x1; + ErrSy1[CntError] = E.area.y1; + ErrSx2[CntError] = E.area.x2; + ErrSy2[CntError] = E.area.y2; + ErrBx1[CntError] = E.area2.x1;// Das Member area2 ist eine zweite UL_AREA, die nur im Schaltplan bei einzelnen ERC-Fehlern die entsprechende Region im Board angibt. + ErrBy1[CntError] = E.area2.y1; + ErrBx2[CntError] = E.area2.x2; + ErrBy2[CntError] = E.area2.y2; + + ErrCode[CntError] = E.code; + ErrDescription[CntError] = E.description; + ErrLayer[CntError] = E.layer; + ErrModulename[CntError] = E.modulename; + ErrS1[CntError] = E.s1; + ErrS2[CntError] = E.s2; + ErrS3[CntError] = E.s3; + ErrS4[CntError] = E.s4; + ErrS5[CntError] = E.s5; + ErrS6[CntError] = E.s6; + + ErrX[CntError] = E.x; + ErrY[CntError] = E.y; + ErrSheet[CntError] = E.sheet; + ErrState[CntError] = E.state; + ErrType[CntError] = E.type; + if (Debug) checkerror(CntError); + sprintf(ErrorList[CntError], "%s\t%s\t%d\t%s\t%s\t%s\t%d\t%d\t%d\t%d", + ErrorType[E.type], + E.description, + E.sheet, + E.modulename, + E.signature, + ErrorState[E.state], + ErrSx1[CntError], + ErrSy1[CntError], + ErrSx2[CntError], + ErrSy2[CntError] + ); + CntError++; + } + if (CntErrorInconsistenc) { + sprintf(HeaderErcErrors, "Consistence Error(%d).", CntErrorInconsistenc); + if (language() == "de") sprintf(HeaderErcErrors, "Konsistenzfehler (%d)", CntErrorInconsistenc); + } + else { + if (Consistence) { + HeaderErcErrors = "Board and Schematic are consistent."; + if (language() == "de") HeaderErcErrors = "Board und Schematic sind konsistent"; + } + } + + if (Option1 == "SAVE") { + if (!argv[2]) { + SaveErrorFileName = filesetext(SCH.name, ".erc.err"); + saveerrors("Save ERC-ERRORS", SCH.name, SaveErrorFileName); + } + else { + SaveErrorFileName = argv[2]; + } + savefile(SaveErrorFileName, SCH.name); + } + else { + SaveErrorFileName = filesetext(SCH.name, ".erc.err"); + string listheader = "Type\tDesciption\tSheet\tModul\tSignatur\tState\tAreaX1\tAreaY1\tAreaX2\tAreaY2"; + if (language() == "de") listheader = "Type\tBeschreibung\tSeite\tModul\tSignatur\tStatus\tAreaX1\tAreaY1\tAreaX2\tAreaY2"; + saveerrdialog("ERRORS ERC)", listheader, SCH.name); + } + } +} + +else if (board) { + board(BRD) { + if (!BRD.checked) { + string msg = "Board is changed, first start Design Rile Check (DRC)!"; + if (language() == "de") msg = "Board wurde verändert, starten sie zuerst den Design Rule Check! (DRC)"; + if (dlgMessageBox(msg, "OK", "CANCEL") != 0) exit(-4); + + string cmd; + sprintf(cmd, "DRC; RUN '%s'", argv[0]); + exit (cmd); + } + ExistBRDfile = "BRD File loaded: " + BRD.name; + ExistSCHfile = "SCH File exist : " + checkexistfile(filesetext(BRD.name, ".sch")); + + if(project.schematic) { + Consistence = 1; + } + else Consistence = 0; + BRD.errors(E) { + ErrSignature[CntError] = E.signature; + ErrSx1[CntError] = E.area.x1; + ErrSy1[CntError] = E.area.y1; + ErrSx2[CntError] = E.area.x2; + ErrSy2[CntError] = E.area.y2; + ErrBx1[CntError] = E.area2.x1;// Das Member area2 ist eine zweite UL_AREA, die nur im Schaltplan bei einzelnen ERC-Fehlern die entsprechende Region im Board angibt. + ErrBy1[CntError] = E.area2.y1; + ErrBx2[CntError] = E.area2.x2; + ErrBy2[CntError] = E.area2.y2; + + ErrCode[CntError] = E.code; + ErrDescription[CntError] = E.description; + ErrLayer[CntError] = E.layer; + ErrModulename[CntError] = E.modulename; + ErrS1[CntError] = E.s1; + ErrS2[CntError] = E.s2; + ErrS3[CntError] = E.s3; + ErrS4[CntError] = E.s4; + ErrS5[CntError] = E.s5; + ErrS6[CntError] = E.s6; + + ErrX[CntError] = E.x; + ErrY[CntError] = E.y; + ErrSheet[CntError] = E.sheet; + ErrState[CntError] = E.state; + ErrType[CntError] = E.type; + if (Debug) checkerror(CntError); + sprintf(ErrorList[CntError], "%s\t%s\t%d\t%s\t%s\t%d\t%d\t%d\t%d\t%s", + ErrorType[E.type], + E.description, + E.layer, + E.signature, + ErrorState[E.state], + ErrSx1[CntError], + ErrSy1[CntError], + ErrSx2[CntError], + ErrSy2[CntError], + "" + ); + CntError++; + } + sprintf(HeaderErcErrors, "Error (%d)", CntError); + if (language() == "de") sprintf(HeaderErcErrors, "Fehler (%d)", CntError); + + if (Option1 == "SAVE") { + if (!argv[2]) { + SaveErrorFileName = filesetext(BRD.name, ".drc.err"); + saveerrors("Save DRC-ERRORS", BRD.name, SaveErrorFileName); + } + else { + SaveErrorFileName = argv[2]; + } + savefile(SaveErrorFileName, BRD.name); + } + else { + SaveErrorFileName = filesetext(BRD.name, ".drc.err"); + string listheader = "Type\tDesciption\tLayer\tSigatur\tState\tAreaX1\tAreaY1\tAreaX2\tAreaY2"; + if (language() == "de") listheader = "Type\tBeschreibung\tLayer\tSigatur\tStatus\tAreaX1\tAreaY1\tAreaX2\tAreaY2"; + saveerrdialog("ERRORS DRC", listheader, BRD.name); + } + } +} + +else { + dlgMessageBox("Start this ULP in a schematic or board.", "OK"); + exit(0); +} + diff --git a/trunk/ulp/export-ict-netlist-pad-coordinates.ulp b/trunk/ulp/export-ict-netlist-pad-coordinates.ulp new file mode 100644 index 00000000..7fa78088 --- /dev/null +++ b/trunk/ulp/export-ict-netlist-pad-coordinates.ulp @@ -0,0 +1,100 @@ +#usage "Export In-Circuit-Test net list with pad/smd coordinates" + "Exported format: Net Part.Pad Layer X Y
    " + "support@cadsoft.de" + +string Version = " Version 1.0"; // 2008-05-14 alf@cadsoft.de +int withSignal = 0; + +if (strupr(argv[1]) == "NOSIGNAL") withSignal = 1; + +string list, s; +string lTop = "t"; +string lBottom = "b"; + +void sortnet(void) { + string s[]; + int n; + int index[], i; + n = strsplit(s, list, '\n'); + sort(n, index, s); + list = ""; + for (i = 0; i < n; i++) { + list += s[index[i]] + "\n"; + } + return; +} + + +if (board) { + board(B) { + B.elements(E) { + E.package.contacts(C) { + if (C.signal || withSignal) { + string cLayer; + if (C.smd) { + if (C.smd.layer == 1) cLayer = lTop; + else cLayer = lBottom; + sprintf(s, "%s\t%s.%s\t%s\t%.4f\t%.4f\n", + C.signal, + E.name, + C.name, + cLayer, + u2mm(C.x), + u2mm(C.y) + ); + list += s; + } + else { + sprintf(s, "%s\t%s.%s\t%s\t%.4f\t%.4f\n", + C.signal, + E.name, + C.name, + lTop, + u2mm(C.x), + u2mm(C.y) + ); + list += s; + sprintf(s, "%s\t%s.%s\t%s\t%.4f\t%.4f\n", + C.signal, + E.name, + C.name, + lBottom, + u2mm(C.x), + u2mm(C.y) + ); + list += s; + } + } + } + } + sortnet(); + list = "# Data export with " + filename(argv[0]) + Version + "\n# at: "+ t2string(time()) + " from: "+filename(B.name) + "\n# " + EAGLE_SIGNATURE + "\n# Testpoint for In-Circuit-Test (Coordinates in mm)\nNet\tPart.Pad\tLayer\tX\tY\n" + list; + string f = filesetext(B.name, ".ict"); + dlgDialog("ICT Netlist") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(600); + dlgVBoxLayout { + dlgTextEdit(list); + } + } + dlgLabel("If you want this list with unconnected pads start with:
    RUN export-ict-netlist-pad-coordinates.ulp NOSIGNAL"); + dlgLabel("Save as: "+f); + dlgHBoxLayout { + dlgPushButton("OK") { + dlgAccept(); + { + output(f, "wt") printf("%s", list); + } + } + dlgPushButton("-CANCEL") { + dlgReject(); + exit(-1); + } + dlgStretch(1); + } + }; + } +} + +else dlgMessageBox("Start this ULP from a Board", "OK"); diff --git a/trunk/ulp/export-protelnet.ulp b/trunk/ulp/export-protelnet.ulp new file mode 100644 index 00000000..e4d236e4 --- /dev/null +++ b/trunk/ulp/export-protelnet.ulp @@ -0,0 +1,91 @@ +/* + * This EAGLE User Language Program prints the netlist of a board + * in standard Protel format (1.0) (very similar to Tango netlist format) + * to import it to Protel PCB software. + * + * It is also possible to print the netlist of a schematic, + * but this will not adhere to the correct Protel format: + * package names are missing, pin names instead of pad names. + * + * If you have only the schematic, just generate the board and run this + * ULP in the EAGLE board editor. + * + * 19.09.2001 Hans Lederer, Ingenieurbüro Lederer, Emmendingen + * Hans.Lederer@ib-lederer.de + */ + +if (board) board(B) { + output(filesetext(B.name, ".NET")) { + + B.elements(E) { + printf("%s\n","["); + printf("%s\n",E.name); + printf("%s\n",E.package.name); + printf("%s\n",E.value); + printf("\n\n\n%s\n","]"); + } + + B.signals(S) { + numeric string Part[], Pad[]; + int cnt = 0, index[]; + + S.contactrefs(C) { + Part[cnt] = C.element.name; + Pad[cnt] = C.contact.name; + cnt++; + } + if (cnt) { + sort(cnt, index, Part, Pad); + printf("%s\n","("); + printf("%s\n",S.name); + for (int i = 0; i < cnt; i++) + printf("%s%s%s\n",Part[index[i]],"-",Pad[index[i]]); + printf("%s\n",")"); + } + } + } + } + +if (schematic) schematic(SCH) { + output(filesetext(SCH.name, ".net")) { + + SCH.parts(P) { + int pos_g = strrstr(P.device.name,"GND"); + int pos_v = strrstr(P.device.name,"VCC"); + + if ((pos_g < 0) && (pos_v < 0)) { + string pkg = P.device.package.name; + int dip_dil = strrstr(pkg,"DIL"); + if ( dip_dil >= 0) + pkg[2]='P'; + printf("%s\n","["); + printf("%s\n",P.name); + printf("%s\n",pkg); + printf("%s\n",P.device.name); + printf("\n\n\n%s\n","]"); + } + } + + SCH.nets(N) { + numeric string Part[], Pin[], trimmed, Pad[]; + int cnt = 0, index[]; + + N.pinrefs(P) { + Part[cnt] = P.part.name; + Pin[cnt] = P.pin.name; + Pad[cnt] = P.pin.contact.name; + cnt++; + } + + if (cnt) { + sort(cnt, index, Part, Pin); + printf("%s\n","("); + printf("%s\n",N.name); + for (int i = 0; i < cnt; i++) { + printf("%s%s%s\n",Part[index[i]],"-",Pad[index[i]]); + } + printf("%s\n",")"); + } + } + } + } diff --git a/trunk/ulp/export-protelpcb.ulp b/trunk/ulp/export-protelpcb.ulp new file mode 100644 index 00000000..b3fdbdfc --- /dev/null +++ b/trunk/ulp/export-protelpcb.ulp @@ -0,0 +1,432 @@ +#usage "Export PCB project to Protel .PCBDOC (ASCII)" + "

    " + "This ULP script tries to export PCB file which can be opened by Protel. " + "It is probably not bug-free as well as it seems to be impossible to export " + "with 100% accuracy so use at your own risk and check the results carefully." + "

    " + "Bugs" + "

    " + "Units are always English for now.
    " + "Polygons are not exported.
    " + "Vias are always exported round. Protel does not have other via shapes.
    " + "Board outline is lost and must be restored from Mechanical 1 (Protel DXP only).
    " + "Not all layers exported correctly.
    " + "

    " + "Important Notice\n" + "

    " + "This script is NOT designed to replace Protel. " + "As Protel file format is proprietary, " + "use of this script for purposes other than migrating from Eagle to Protel " + "may be illegal due to copyright laws. The author will not be liable for any illegal " + "use of this script." + "

    " + "Version: 0.1" + "

    " + "Author: Alex Galakhov avg6f4@umkc.edu" + + +// Global variables + +string fileName; + +string netn []; +string layer []; + +int x0, y0; + +// Units + +int usedunits; +string units [] = { "mil", "mm" }; + +// PCB record handling functions + +string record (string name) + { + return "|RECORD=" + name; + } + +string endr () + { + return "\r\n"; + } + +string r_b (string name, int val) + { + return "|" + name + "=" + (val ? "TRUE" : "FALSE"); + } + +string r_l (string name, int val, int v0) + { + real value; + value = (usedunits == 0 ? u2mil (val - v0) : u2mm (val - v0)); + string s; + sprintf (s, "|%s=%g%s", name, value, units [usedunits]); + return s; + } + +string r_i (string name, int val) + { + string s; + sprintf (s, "|%s=%d", name, val); + return s; + } + +string r_f (string name, real val) + { + string s; + sprintf (s, "|%s=%g", name, val); + return s; + } + +string r_s (string name, string val) + { + return "|" + name + "=" + val; + } + +string r_layer (string name, int lay) + { + return "|" + name + "=" + layer [lay]; + } + +string ra_net (int n) + { + if (n == -1) return ""; + return r_i ("NET", n); + } + +string ra_comp (int c) + { + if (c == -1) return ""; + return r_i ("COMPONENT", c); + } + +int fixwidth (int w) + { + return ((w == 0) ? 2540 : w); + } + + +// PCB data storage + +string arcs = ""; +string comps = ""; +string fills = ""; +string header = ""; +string nets = ""; +string pads = ""; +string texts = ""; +string tracks = ""; +string vias = ""; + +int arcs_c = 0; +int comps_c = 0; +int fills_c = 0; +int nets_c = 0; +int pads_c = 0; +int texts_c = 0; +int tracks_c = 0; +int vias_c = 0; + +int netbyname (string netname) + { + int i; + for (i = 0; (i < nets_c) && (netname != netn [i]); i++) { } + if (netn [i] != netname) i = -1; // we should never get it unless there's a bug + return i; + } + +// PCB writing functions + +void out_arc (UL_ARC a, int n, int c) + { + arcs += record ("Arc") + ra_net (n) + ra_comp (c) + + r_i ("INDEXFORSAVE", arcs_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", a.layer) + + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + + r_l ("LOCATION.X", a.xc, x0) + r_l ("LOCATION.Y", a.yc, y0) + r_l ("RADIUS", a.radius, 0) + + r_f ("STARTANGLE", a.angle1) + r_f ("ENDANGLE", a.angle2) + r_l ("WIDTH", fixwidth (a.width), 0) + + r_i ("SUBPOLYINDEX", 0) + + endr (); + arcs_c ++; + } + +void out_circle (UL_CIRCLE a, int c) + { + arcs += record ("Arc") + ra_comp (c) + + r_i ("INDEXFORSAVE", arcs_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", a.layer) + + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + + r_l ("LOCATION.X", a.x, x0) + r_l ("LOCATION.Y", a.y, y0) + r_l ("RADIUS", a.radius, 0) + + r_f ("STARTANGLE", 0) + r_f ("ENDANGLE", 360) + r_l ("WIDTH", fixwidth (a.width), 0) + + r_i ("SUBPOLYINDEX", 0) + + endr (); + arcs_c ++; + } + +void out_track (UL_WIRE w, int n, int c) + { + if (w.arc) + { + out_arc (w.arc, n, c); + return; + } + tracks += record ("Track") + ra_net (n) + ra_comp (c) + + r_i ("INDEXFORSAVE", tracks_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", w.layer) + + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + + r_l ("X1", w.x1, x0) + r_l ("Y1", w.y1, y0) + r_l ("X2", w.x2, x0) + r_l ("Y2", w.y2, y0) + + r_l ("WIDTH", fixwidth (w.width), 0) + r_i ("SUBPOLYINDEX", 0) + + endr (); + tracks_c ++; + } + +void out_via (UL_VIA v, int n, int c) + { + vias += record ("Via") + ra_net (n) + ra_comp (c) + + r_i ("INDEXFORSAVE", vias_c) + r_b ("SELECTION", 0) + r_s ("LAYER", "MULTILAYER") + + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + r_l ("X", v.x, x0) + r_l ("Y", v.y, y0) + + r_l ("DIAMETER", max (v.diameter [v.start], v.diameter [v.end]), 0) + + r_l ("HOLESIZE", v.drill, 0) + r_layer ("STARTLAYER", v.start) + r_layer ("ENDLAYER", v.end) + // + r_i ("CCSV", 1) + r_i ("CPLV", 1) + r_i ("CCWV", 1) + r_i ("CAGV", 1) + r_i ("CPEV", 0) + // + r_i ("CSEV", 0) + r_i ("CPCV", 1) + r_i ("CPRV", 1) + r_s ("CCS", "Relief") + r_s ("CPL", 0) + // + r_l ("CCW", 10mil) + r_i ("CEN", 4) + r_l ("CAG", 10mil) + r_l ("CSE", 4mil) + // + r_l ("CPC", 20mil) + r_l ("CPR", 20mil) + // I don't know what it menas so I don't use them + + endr (); + vias_c ++; + } + +void out_pad (UL_PAD p, int n, int c) + { + string psh []; + psh [PAD_SHAPE_SQUARE] = "RECTANGLE"; + psh [PAD_SHAPE_ROUND] = "ROUND"; + psh [PAD_SHAPE_OCTAGON] = "OCTAGONAL"; + psh [PAD_SHAPE_LONG] = "OCTAGONAL"; + psh [PAD_SHAPE_OFFSET] = "bug"; //! + psh [PAD_SHAPE_ANNULUS] = "bug"; //! + psh [PAD_SHAPE_THERMAL] = "bug"; //! + pads += record ("Pad") + ra_net (n) + ra_comp (c) + + r_i ("INDEXFORSAVE", pads_c) + + r_s ("LAYER", "MULTILAYER") + r_b ("LOCKED", 0) + r_b ("USERROUTED", 1) + r_s ("NAME", p.name) + + r_l ("X", p.x, x0) + r_l ("Y", p.y, y0) + + r_l ("XSIZE", p.diameter [LAYER_BOTTOM] * (1 + p.elongation / 100), 0) + r_l ("YSIZE", p.diameter [LAYER_BOTTOM], 0) + + r_s ("SHAPE", psh [p.shape [LAYER_BOTTOM]]) + r_l ("HOLESIZE", p.drill, 0) + r_f ("ROTATION", p.angle) + + r_b ("PLATED", 1) + // + r_s ("DAISYCHAIN", "Load") + // + ... ... ... + + endr (); + pads_c ++; + } + +void out_smd (UL_SMD s, int n, int c) + { + pads += record ("Pad") + ra_net (n) + ra_comp (c) + + r_i ("INDEXFORSAVE", pads_c) + + r_layer ("LAYER", s.layer) + r_b ("LOCKED", 0) + r_b ("USERROUTED", 1) + r_s ("NAME", s.name) + + r_l ("X", s.x, x0) + r_l ("Y", s.y, y0) + + r_l ("XSIZE", s.dx, 0) + r_l ("YSIZE", s.dy, 0) + + r_s ("SHAPE", "RECTANGLE") + r_l ("HOLESIZE", 0, 0) + r_f ("ROTATION", s.angle) + + r_b ("PLATED", 0) + // + r_s ("DAISYCHAIN", "Load") + // + ... ... ... + + endr (); + pads_c ++; + } + +void out_text (UL_TEXT t, int c, int isDes, int isComm) + { + texts += record ("Text") + ra_comp (c) + + r_i ("INDEXFORSAVE", texts_c) + r_b ("SELECTION", 0) + + r_layer ("LAYER", t.layer) + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + // + r_l ("X1", ???) ... ... what they mean ? + + r_l ("X", t.x, x0) + r_l ("Y", t.y, y0) + r_f ("ROTATION", t.angle) + r_l ("HEIGHT", t.size, 0) + + r_s ("TEXT", t.value) + + (isDes ? r_s ("DESIGNATOR", "True") : "") + + (isComm ? r_s ("COMMENT", "True") : "") + + endr (); + texts_c ++; + } + +void out_fill (UL_RECTANGLE r, int c) + { + fills += record ("Fill") + ra_comp (c) + + r_i ("INDEXFORSAVE", tracks_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", r.layer) + + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + + r_l ("X1", r.x1, x0) + r_l ("Y1", r.y1, y0) + r_l ("X2", r.x2, x0) + r_l ("Y2", r.y2, y0) + + r_f ("ROTATION", r.angle) + + endr (); + fills_c ++; + } + +void out_hole (UL_HOLE h, int c) + { + pads += record ("Pad") + ra_comp (c) + + r_i ("INDEXFORSAVE", pads_c) + + r_layer ("LAYER", LAYER_TOP /*incorrect*/) + r_b ("LOCKED", 0) + r_b ("USERROUTED", 0) + + r_s ("NAME", "") + r_l ("X", h.x, x0) + r_l ("Y", h.y, y0) + + r_l ("XSIZE", h.drill, 0) + r_l ("YSIZE", h.drill, 0) + + r_s ("SHAPE", "ROUND") + r_l ("HOLESIZE", h.drill, 0) + r_f ("ROTATION", 0) + + r_b ("PLATED", 0) + // + r_s ("DAISYCHAIN", "Load") + // + ... ... ... + + endr (); + pads_c ++; + } + +void out_net (UL_SIGNAL s) + { + netn [nets_c] = s.name; + nets += record ("Net") + + r_i ("ID", nets_c) + r_i ("INDEXFORSAVE", nets_c) + r_b ("SELECTION", 0) + r_layer ("LAYER", LAYER_BOTTOM /*incorrect*/) + + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + r_b ("PRIMITIVELOCK", 0) + + r_s ("NAME", s.name) + r_b ("VISIBLE", 0) + r_i ("COLOR", 770986 /*incorrect*/) + + endr (); + nets_c ++; + } + +void out_component (UL_ELEMENT e, int hasDes, int hasComm) + { + comps += record ("Component") + + r_i ("ID", comps_c) + r_i ("INDEXFORSAVE", comps_c) + r_b ("SELECTION", 0) + + r_layer ("LAYER", (e.mirror ? LAYER_BOTTOM : LAYER_TOP)) + + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + r_b ("USERROUTED", 1) + r_b ("PRIMITIVELOCK", 1) + + r_l ("X", e.x, x0) + r_l ("Y", e.y, y0) + r_s ("PATTERN", e.package.name) + r_b ("NAMEON", hasDes) + + r_b ("COMMENTON", hasComm) + r_i ("GROUPNUM", 0) + r_i ("COUNT", 0) + r_f ("ROTATION", e.angle) + + r_i ("COMMENTAUTOPOSITION", 0) + r_i ("CHANNELOFFSET", 0) + r_s ("SOURCEDESIGNATOR", e.name) + + r_s ("SOURCEUNIQUEID", e.name) + r_s ("SOURCESEARCHPATH", ".") + + endr (); + comps_c ++; + } + +// main + +board (B) + { + fileName = dlgFileSave ("Export to Protel PCB", filesetext (B.name, ".pcb"), "*.pcb"); + if (fileName == "") exit (0); + + usedunits = 0; // FIXME + + // Protel doesn't like negative values. + + x0 = B.area.x1; + y0 = B.area.y1; + + // Layers Naming + B.layers (L) layer [L.number] = L.name; + + layer [LAYER_TOP] = "TOP"; + layer [LAYER_BOTTOM] = "BOTTOM"; + layer [LAYER_PADS] = "MULTILAYER"; //? + layer [LAYER_VIAS] = "MULTILAYER"; //? + layer [LAYER_UNROUTED] = "bug"; //! + layer [LAYER_DIMENSION] = "KEEPOUT"; + layer [LAYER_TPLACE] = "TOPOVERLAY"; + layer [LAYER_BPLACE] = "BOTTOMOVERLAY"; + layer [LAYER_TORIGINS] = "TOPOVERLAY"; + layer [LAYER_BORIGINS] = "BOTTOMOVERLAY"; + layer [LAYER_TNAMES] = "TOPOVERLAY"; + layer [LAYER_BNAMES] = "BOTTOMOVERLAY"; + layer [LAYER_TVALUES] = "TOPOVERLAY"; + layer [LAYER_BVALUES] = "BOTTOMOVERLAY"; + layer [LAYER_TSTOP] = ""; + layer [LAYER_BSTOP] = ""; + layer [LAYER_TCREAM] = ""; + layer [LAYER_BCREAM] = ""; + layer [LAYER_TFINISH] = ""; + layer [LAYER_BFINISH] = ""; + layer [LAYER_TGLUE] = ""; + layer [LAYER_BGLUE] = ""; + layer [LAYER_TTEST] = "TOP"; //? + layer [LAYER_BTEST] = "BOTTOM"; //? + layer [LAYER_TKEEPOUT] = ""; + layer [LAYER_BKEEPOUT] = ""; + layer [LAYER_TRESTRICT] = ""; + layer [LAYER_BRESTRICT] = ""; + layer [LAYER_VRESTRICT] = ""; + layer [LAYER_DRILLS] = "MULTILAYER"; + layer [LAYER_HOLES] = "MULTILAYER"; + layer [LAYER_MILLING] = "MECHANICAL1"; + layer [LAYER_MEASURES] = "MECHANICAL2"; //? + layer [LAYER_DOCUMENT] = "MECHANICAL2"; //? + layer [LAYER_REFERENCE] = "MECHANICAL2"; //? + layer [LAYER_TDOCU] = "TOPOVERLAY"; + layer [LAYER_BDOCU] = "BOTTOMOVERLAY"; + + // Signals Loop + + B.signals (S) + { + // S.polygons (P) out_polygon (P, nets_c, -1); + S.wires (W) out_track (W, nets_c, -1); + S.vias (V) out_via (V, nets_c, -1); + out_net (S); + } + + // Components Loop + + B.elements (E) + { + UL_PACKAGE P = E.package; + P.contacts (C) + { + if (C.pad) out_pad (C.pad, netbyname (C.signal), comps_c); + if (C.smd) out_smd (C.smd, netbyname (C.signal), comps_c); + } + P.wires (W) out_track (W, -1, comps_c); + P.circles (C) out_circle (C, comps_c); + P.rectangles (R) out_fill (R, comps_c); + // P.polygons (PO) out_polygon (PO, -1, comps_c); + P.holes (H) out_hole (H, comps_c); + + int hasDesignator = 0; + int hasComment = 0; + E.texts (T) + { + int isDes = 0; if ((T.value == E.name) && (! hasDesignator)) hasDesignator = isDes = 1; + int isComm = 0; if ((T.value == E.value) && (! hasComment)) hasComment = isComm = 1; + out_text (T, comps_c, isDes, isComm); + } + P.texts (T) + { + int isDes = 0; if ((T.value == E.name) && (! hasDesignator)) hasDesignator = isDes = 1; + int isComm = 0; if ((T.value == E.value) && (! hasComment)) hasComment = isComm = 1; + out_text (T, comps_c, isDes, isComm); + } + out_component (E, hasDesignator, hasComment); + } + + // Free elements + + B.circles (C) out_circle (C, -1); + B.holes (H) out_hole (H, -1); + // B.polygons (P) out_polygon (P, -1, -1); + B.rectangles (R) out_fill (R, -1); + B.texts (T) out_text (T, -1, 0, 0); + B.wires (W) out_track (W, -1, -1); + + // Header + header += record ("Board") + + r_b ("SELECTION", 0) + r_s ("LAYER", "UNKNOWN") + r_b ("LOCKED", 0) + r_b ("POLYGONOUTLINE", 0) + + r_b ("USERROUTED", 1) + + r_s ("FILENAME", filename (fileName)) + r_s ("KIND", "Protel_Advanced_PCB") + r_s ("VERSION", "5.0") + // + r_s ("DATE", ...) + r_s ("TIME", ...) + + r_l ("ORIGINX", 0, 0) + r_l ("ORIGINY", 0, 0) + // + ... ... ... + + endr (); + + // Now, save to file + + output (fileName) + { + printf (header); + printf (nets); + printf (comps); + printf (arcs); + printf (pads); + printf (vias); + printf (tracks); + printf (texts); + printf (fills); + } + dlgMessageBox (fileName + "exported."); + } diff --git a/trunk/ulp/export-protelsch.ulp b/trunk/ulp/export-protelsch.ulp new file mode 100644 index 00000000..154e75cd --- /dev/null +++ b/trunk/ulp/export-protelsch.ulp @@ -0,0 +1,908 @@ +#usage "Eagle schematic exporting tool \n" + "

    " + "This ULP can convert an Eagle schematic into an ALTIUM schematic." + "

    " + "Load any schematic and execute the ULP in the eagle." + + +/* ========================================================================== + * This script is based on the eagle2kicad_sch.ULP from Juergen Messerer which + * was released under the license of the GNU Public license Version 2. + * Adaption was made by Christian Keller (retrochris (at) web.de) + * ==========================================================================*/ + +/* + * CHANGELOG================================================ + * + * 08.12.2009: Version 1.1: + * minor issue fixed preventing V5.x creating correct results + * file naming scheme corrected + * 18.11.2009: printf was causing an error if a value contains the char '%' (e.g. 10k/1%), heiko.schedletzky (at) grossfunk.de + * 05.11.2009: Initial Version 1 + * + */ + +/* ========================================================================== + * License: This file is released under the license of the GNU Public license + * Version 2. + * ==========================================================================*/ + + + + string sch_name = ""; + +//------------------------------------------------------ +//Records +//------------------------------------------------------ + +string HeaderRecord (int val) +{ + string s; + sprintf (s, "|HEADER=Protel for Windows - Schematic Capture Ascii File Version 5.0|WEIGHT=%d\n" , val); + return s; +} + +//------------------------------------------------------ +// Optimize Text for output with printf +// 18.11.2009 - heiko.schedletzky (at) grossfunk.de +//------------------------------------------------------ + +string FixText(string src) +{ + // problem : printf is causing an error if a value contains the char '%' (e.g. 10k/1%) + // solution : '%' is substituted with '_' + + string tarray[]; + strsplit(tarray,src,'%'); + return strjoin(tarray,'_'); +} + +//------------------------------------------------------ +//convert string +//------------------------------------------------------ +string ConvString(string text) +{ + int i; + int Felder; + string helper; + + helper=""; + + + for (i=0;i0) + mirrored="T"; + + + orientation=0; +// if (I.angle==90) orientation=1; +// if (I.angle==180) orientation=2; +// if (I.angle==270) orientation=3; + if (I.angle==90) + if(I.mirror==0) orientation=1; + else + orientation=3; + if (I.angle==180) orientation=2; + if (I.angle==270) + if(I.mirror==0) orientation=3; + else + orientation=1; + + x=int(u2mil(I.x)/10); + y=int(u2mil(I.y)/10); + + string s; + sprintf (s, "|RECORD=1|LIBREFERENCE=%s|PARTCOUNT=%d|DISPLAYMODECOUNT=1|ISMIRRORED=%s|INDEXINSHEET=%d|OWNERPARTID=-1|LOCATION.X=%d|LOCATION.Y=%d|ORIENTATION=%d|CURRENTPARTID=%d|LIBRARYPATH=*|SOURCELIBRARYNAME=%s|TARGETFILENAME=*|AREACOLOR=11599871|COLOR=128|PARTIDLOCKED=F|DESIGNITEMID=%s\n",P.device.name,partcount, mirrored,Record ,x,y,orientation,part,I.gate.symbol.library,P.device.name); + return s; +} + + +//------------------------------------------------------ +string PinRecord (UL_PIN P, int owner,int owner2,int ownerpartid) +{ + + int PinLength; + int x; + int y; + int PinConglomerate; + string designator; + string pinsymbol; + + + pinsymbol=""; + if (P.function==PIN_FUNCTION_FLAG_CLK) + pinsymbol="SYMBOL_INNEREDGE=3|"; + if (P.function==PIN_FUNCTION_FLAG_DOT) + pinsymbol="SYMBOL_OUTEREDGE=1|"; + + x=int(u2mil(P.x)/10); + y=int(u2mil(P.y)/10); + + if (P.length==PIN_LENGTH_POINT) PinLength=0; + if (P.length==PIN_LENGTH_SHORT) PinLength=10; + if (P.length==PIN_LENGTH_MIDDLE) PinLength=20; + if (P.length==PIN_LENGTH_LONG) PinLength=30; + + PinConglomerate=32; + + + if (P.visible==PIN_VISIBLE_FLAG_OFF) PinConglomerate+=0; + else + if (P.visible==PIN_VISIBLE_FLAG_PIN) PinConglomerate+=8; + else + if (P.visible==PIN_VISIBLE_FLAG_PAD) PinConglomerate+=16; + else + PinConglomerate+=24; + + if (P.angle==0) { + PinConglomerate+=2; + x=x+PinLength;} + if (P.angle==90) { + PinConglomerate+=3; + y=y+PinLength;} + if (P.angle==180) { + PinConglomerate+=0; + x=x-PinLength;} + if (P.angle==270) { + PinConglomerate+=1; + y=y-PinLength;} + + if (!P.contact) + designator="0"; + else + designator=P.contact.name; + + string s; + sprintf (s, "|RECORD=2|OWNERINDEX=%d|OWNERPARTID=%d|%sFORMALTYPE=1|ELECTRICAL=4|PINCONGLOMERATE=%d|PINLENGTH=%d|LOCATION.X=%d|LOCATION.Y=%d|NAME=%s|DESIGNATOR=%s|SWAPIDPART=1\n",owner,ownerpartid,pinsymbol,PinConglomerate,PinLength,x,y,P.name, designator); + + return s; +} + + + + +//------------------------------------------------------ +string LabelRecord (UL_TEXT T,int Ownerindex, int Ownerpart){ + + string s; + int x; + int y; + int orientation; + + orientation=0; + if (T.angle==90) orientation=1; + if (T.angle==180) orientation=2; + if (T.angle==270) orientation=3; + + + x=int(u2mil(T.x)/10); + y=int(u2mil(T.y)/10); + + sprintf (s, "|RECORD=4|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|ORIENTATION=%d|COLOR=8388608|FONTID=1|TEXT=%s\n",Ownerindex, Ownerpart, x,y,orientation,T.value); + + return s; +} + + +//------------------------------------------------------ + +string PolygonRecord (UL_POLYGON P,int Ownerindex, int Ownerpart) +{ + int x; + int y; + int count=1; + string helper=""; + string helper2=""; + + string s; + sprintf (s, "|RECORD=7|OWNERINDEX=%d|OWNERPARTID=%d|COLOR=16711680|AREACOLOR=12632256|ISSOLID=T",Ownerindex,Ownerpart ); + + P.contours(C){ + x=int(u2mil(C.x1)/10); + y=int(u2mil(C.y1)/10); + + sprintf (helper, helper+ "|X%d=%d|Y%d=%d",count,x,count,y ); + count+=1; + + } + + sprintf (helper2, "|LOCATIONCOUNT=%d",(count-1)); + sprintf (s, s+helper2+helper+"\n"); + + + return s; +} + + +//------------------------------------------------------ +string ArcRecord (UL_CIRCLE C, int Record, int Index, int Owner){ + + string s; + int x; + int y; + int r; + + x=int(u2mil(C.x)/10); + y=int(u2mil(C.y)/10); + r=int(u2mil(C.radius)/10); + + sprintf (s, "|RECORD=12|INDEXINSHEET=%d|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|RADIUS=%d|RADIUS_FRAC=0|LINEWIDTH=1|STARTANGLE=0|ENDANGLE=0|COLOR=16711680\n",Record, Index,Owner,x,y,r ); + return s; +} + + +//------------------------------------------------------ +string LineRecord (UL_WIRE W,int Records,int Owner, int ownerpartid) +{ + int x1; + int y1; + int x2; + int y2; + int r; + + string s; + + x1=int(u2mil(W.x1)/10); + y1=int(u2mil(W.y1)/10); + x2=int(u2mil(W.x2)/10); + y2=int(u2mil(W.y2)/10); + + if (W.curve==0) + sprintf (s, "|RECORD=13|OWNERINDEX=%d|ISNOTACCESIBLE=T|INDEXINSHEET=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|CORNER.X=%d|CORNER.Y=%d|LINEWIDTH=1|COLOR=16711680\n",Owner,Records,ownerpartid, x1,y1,x2,y2); + + else{ + x1=int(u2mil(W.arc.xc)/10); + y1=int(u2mil(W.arc.yc)/10); + r=int(u2mil(W.arc.radius)/10); + + sprintf (s, "|RECORD=12|OWNERINDEX=%d|INDEXINSHEET=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|RADIUS=%d|RADIUS_FRAC=0|LINEWIDTH=1|STARTANGLE=%f|ENDANGLE=%f|COLOR=16711680\n",Owner,Records,ownerpartid,x1,y1,r, W.arc.angle1, W.arc.angle2 ); + } + + return s; +} + + +//------------------------------------------------------ +string RectangleRecord (UL_RECTANGLE R,int Records,int Owner) +{ + + string s; + int x1; + int y1; + int x2; + int y2; + int xt1; + int yt1; + int xt2; + int yt2; + int x; + int y; + real winkel; + + x1=int(u2mil(R.x1)/10); + y1=int(u2mil(R.y1)/10); + x2=int(u2mil(R.x2)/10); + y2=int(u2mil(R.y2)/10); + + x=(x1+x2)/2; + y=(y1+y2)/2; + + + y1=y-y1+y; + y2=y-y2+y; + + winkel=PI/180*R.angle; + + xt1=(x1-x)*cos(winkel)+(y1-y)*sin(winkel+PI)+x; + yt1=(x1-x)*sin(winkel)+(y1-y)*cos(winkel)+y; + xt2=x-(xt1-x); + yt2=y-(yt1-y); + + + sprintf (s, "|RECORD=14|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|CORNER.X=%d|CORNER.Y=%d|COLOR=8388608|AREACOLOR=8388608|ISSOLID=T\n",Records, Owner, xt1,yt1,xt2,yt2); + return s; + +} + + +//------------------------------------------------------ +string PowerObjectRecord (int x,int y, int owner) +{ + + string s; + + x=int(u2mil(x)/10); + y=int(u2mil(y)/10); + + sprintf (s, "|RECORD=17|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|COLOR=128|TEXT=OffSheet|ISCROSSSHEETCONNECTOR=T",owner, x,y); + return s; + +} + + +//------------------------------------------------------ +string NetLabelRecord (string name, int x, int y) +{ + x=int(u2mil(x)/10); + y=int(u2mil(y)/10); + + string s; + sprintf (s, "|RECORD=25|OWNERPARTID=-1|LOCATION.X=%d|LOCATION.Y=%d|COLOR=128|FONTID=1|TEXT=%s\n", x,y,name); + return s; +} + + +//------------------------------------------------------ + +string BusRecord (int x1,int y1,int x2,int y2) +{ + + string s; + int cx1; + int cy1; + int cx2; + int cy2; + + cx1=int(u2mil(x1)/10); + cy1=int(u2mil(y1)/10); + cx2=int(u2mil(x2)/10); + cy2=int(u2mil(y2)/10); + + sprintf (s, "|RECORD=26|OWNERPARTID=-1|LINEWIDTH=1|COLOR=8388608|LOCATIONCOUNT=2|X1=%d|Y1=%d|X2=%d|Y2=%d\n",cx1,cy1,cx2,cy2); + + return s; + +} + + +//------------------------------------------------------ +string WireRecord (UL_WIRE W,int Records,int Owner) +{ + int x1; + int y1; + int x2; + int y2; + string s; + + x1=int(u2mil(W.x1)/10); + y1=int(u2mil(W.y1)/10); + x2=int(u2mil(W.x2)/10); + y2=int(u2mil(W.y2)/10); + + sprintf (s, "|RECORD=27|INDEXINSHEET=%d|OWNERPARTID=%d|LINEWIDTH=1|COLOR=8388608|LOCATIONCOUNT=2|X1=%d|Y1=%d|X2=%d|Y2=%d\n",Owner,Records, x1,y1,x2,y2); + + return s; +} + + +//------------------------------------------------------ +string JunctionRecord (int x, int y) +{ + + x=int(u2mil(x)/10); + y=int(u2mil(y)/10); + + string s; + sprintf (s, "|RECORD=29|OWNERPARTID=-1|LOCATION.X=%d|LOCATION.Y=%d|COLOR=128|LOCKED=T\n",x ,y); + return s; +} + + +//------------------------------------------------------ +string ImplementationListRecord (int Owner) + { + + string s; + sprintf (s, "|RECORD=44|OWNERINDEX=%d\n",Owner); + return s; + } + + +//------------------------------------------------------ +string SheetRecord (UL_SHEET SCH) +{ + + int x1; + int y1; + int x2; + int y2; + + x1=int(u2mil(SCH.area.x1)/10); + y1=int(u2mil(SCH.area.y1)/10); + x2=int(u2mil(SCH.area.x2)/10); + y2=int(u2mil(SCH.area.y2)/10); + + string s; + sprintf (s, "|RECORD=31|FONTIDCOUNT=1|SIZE1=10|FONTNAME1=Times New Roman|USEMBCS=T|ISBOC=T|HOTSPOTGRIDON=T|HOTSPOTGRIDON=T|HOTSPOTGRIDSIZE=4|SYSTEMFONT=1|SHEETNUMBERSPACESIZE=4|AREACOLOR=16317695|SNAPGRIDON=T|SNAPGRIDSIZE=10|VISIBLEGRIDON=T|VISIBLEGRIDSIZE=10|CUSTOMX=%d|CUSTOMY=%d|USECUSTOMSHEET=T|REFERENCEZONESON=T|CUSTOMXZONES=6|CUSTOMYZONES=4|CUSTOMMARGINWIDTH=20|DISPLAY_UNIT=4\n",x2-x1,y2-y1); + return s; + +} + + +//------------------------------------------------------ +string DesignatorRecord (int Owner, string T, int x, int y, int angle, int ownerpartid, string ishidden) +{ + + string s; + + x=int(u2mil(x)/10); + y=int(u2mil(y)/10); + + int orientation; + + orientation=0; + if (angle==90) orientation=1; + if (angle==180) orientation=2; + if (angle==270) orientation=3; + + + sprintf (s, "|RECORD=34|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|COLOR=8388608|FONTID=1|TEXT=%s|ORIENTATION=%d|ISHIDDEN=%s|NAME=Designator\n",Owner,ownerpartid,x,y,T,orientation,ishidden); + return s; +} + + +//------------------------------------------------------ +string ParameterRecord (int Owner,string name, string text,int x, int y, int ownerpart, string hidden) +{ + + string s; + + x=int(u2mil(x)/10); + y=int(u2mil(y)/10); + + int orientation; + + orientation=0; +// if (I.angle==90) orientation=1; +// if (I.angle==180) orientation=2; +// if (I.angle==270) orientation=3; + + sprintf (s, "|RECORD=41|OWNERINDEX=%d|OWNERPARTID=%d|LOCATION.X=%d|LOCATION.Y=%d|COLOR=8388608|FONTID=1|TEXT=%s|ISHIDDEN=%s|NAME=%s\n",Owner, ownerpart,x,y,text,hidden,name); + return s; +} + + +//------------------------------------------------------ +string ImplementationRecord (int Owner, UL_PART P){ + + string s; + + sprintf (s, "|RECORD=45|OWNERINDEX=%d|INDEXINSHEET=-1|DESCRIPTION=%s|USECOMPONENTLIBRARY=T|MODELNAME=%s|MODELTYPE=PCBLIB|DATAFILECOUNT=1|MODELDATAFILEENTITY0=%s|MODELDATAFILEKIND0=PCBLib|ISCURRENT=T|DATALINKSLOCKED=T|DATABASEDATALINKSLOCKED=T|INTEGRATEDMODEL=F|DATABASEMODEL=T\n",Owner, P.device.package.headline,P.device.package.name,P.device.package.name); + + return s; +} + +//------------------------------------------------------ + + +//------------------------------------------------------ +// Parts erzeugen +//------------------------------------------------------ + +int MakePart(UL_SYMBOL S, UL_PART P, int OwnerPart, int Records, int partcount){ + +// printf("*** Bauteil ***\n"); + + S.pins(Pi){ + printf(PinRecord(Pi,OwnerPart-2,Records,partcount)); + Records+=1; + if (Pi.direction==PIN_DIRECTION_SUP){ + printf(NetLabelRecord(Pi.net, Pi.x, Pi.y)); + Records+=1; + + } + + } + + + S.wires(W){ + printf(LineRecord(W,Records,OwnerPart-2,partcount)); + Records+=1; + } + + + + + S.texts(T){ + + if ((T.layer != LAYER_NAMES) && (T.layer != LAYER_VALUES)){ + printf(LabelRecord(T,OwnerPart-2,partcount)); + Records+=1; + } + } + + S.rectangles(R){ + printf(RectangleRecord(R,OwnerPart-2,partcount)); + Records+=1; + } + + + S.polygons(Poly){ + printf(PolygonRecord(Poly,OwnerPart-2,partcount)); + Records+=1; + } + + + +return Records; + +} + +//------------------------------------------------------ +//write index of modules +//------------------------------------------------------ +void write_sch( string fileName ){ + +string CopyHelp[]; +string FileNameNumbered; +int Records=1; +int OwnerPart; +int SchaltplanSeite=1; +int i; +int Technik; +int Footprint; +int partcount; +int part; +int CommentLayer=0; +int DesignatorLayer=0; +string name; +string konstrukt; +int designatorflag; +int commentflag; + + schematic(S){ + + S.sheets(SCH){ + + Records=1; + sprintf(FileNameNumbered,fileName+"_%d.SchDoc",SchaltplanSeite); + SchaltplanSeite+=1; + + output(FileNameNumbered, "Fwt") { + + + printf(SheetRecord(SCH)); + Records+=1; + + + +// ********************************************** Bauteile ************************************** + SCH.parts(P){ + P.instances(I){ + + + + // wieviele parts hat die komponente ? + + partcount=2; + part=1; + S.libraries(L) { + L.devicesets(D) { + if (D.name==P.deviceset.name){ + partcount=1; + part=1; + D.gates(G) { + if ((P.name+G.name)==I.name) + part=partcount; + partcount+=1; + + } + } + } + } + printf(PartRecord(I,P,part,partcount,Records)); + Records+=1; + OwnerPart=Records; + + S.libraries(L) { + if (P.deviceset.library==L.name){ + + L.devicesets(D) { + + + if (D.name==P.deviceset.name) { + + D.devices(devi){ + + + konstrukt=""; + name=D.name; + Technik=0; + Footprint=0; + + + + for (i=0;iGenerate EAGLE Output in Fabmaster Format FATF REV 11.1

    \n" + "See program text for more information

    " + "ULP Rev. 1.46
    " + "Author: support@cadsoft.de" + +string ULPversion = "V1.46"; // 2013-07-01 alf@cadsoft.de + +/////////////////////////////////////////////////////////////////////////////////////////// +// ASCII Transfer Format (FATF) FABmaster software V8.E - 11 August 2000 // +// FABMASTER FATF REV 11.1 // +// // +// Rev. 1.46: correct funktion validname () add chenge '(' to '_' // +// 2013-10-24 by alf@cadsoft.de // +// // +// Rev. 1.45: Comma ends the last line // +// 2013-07-01 by alf@cadsoft.de // +// +// Rev. 1.44: message exportet to path/file // +// 2012-12-19 by alf@cadsoft.de // +// // +// Rev. 1.43: corrected request in loop S.contactrefs(C) { => if (C.contact) { // +// 2011-03-30 by alf@cadsoft.de // +// // +// Rev. 1.42: quick find pin-name part-name // +// 2009-12-04 by support@cadsoft.de // +// // +// Rev. 1.41: Corrected LAYER_NAMES definition for BPLACE // +// March 2007 by support@cadsoft.de // +// // +// Revision 1.4: Export Layer 51/52 (Layer table expanded) // +// Febr. 2007 support@cadsoft.de // +// // +// Revision 1.3: Export Wires with Arc, rotated Pads, Pad Shape Long & Offset // +// rotated Packages in 0.1 degree // +// export rectangle and circle on layer 1, 16, 21, 22 // +// export polygon filling on klayer 1, 16 // +// export text on layer 1,16,21,22 as wire (**vector font**) // +// Mai 2004 by support@cadsoft.de // +/////////////////////////////////////////////////////////////////////////////////////////// +// Revision 1.2: Slightly changed in the output statement, so that the Fabmaster file // +// will be written in the same directory as the brd file is. // +// November 2001 by support@cadsoft.de // +/////////////////////////////////////////////////////////////////////////////////////////// +// Revision 1.1: Runs with EAGLE version >= 4; top pad shape assumed for all layers; +// fixed bug in EAGLE version output +/////////////////////////////////////////////////////////////////////////////////////////// +// Rudi Hofer, CadSoft, rudi.hofer@cadsoft.de, 9/99 +// +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, +// EXPRESSED OR IMPLIED. +// +// This ULP generates output for FABMASTER software which is able to convert the +// data for automatic mounting and test equipment. The resolution is fixed to 1 mil. +// +// To generate the output, load the board and run this ULP from the board window. +// +// Restrictions and prerequisites: +// - Board outline must be defined as wires in dimension layer (directly in +// board or in a package). +// - All coordinates must be positive!!! Please move the board accordingly!!! +// - Do not use different packages with the same name (avoid REPLACE command). +// - Padtypes octagon, xlongoct, ylongoct are realized with round shapes. +// - For polygons no output is generated. +// - Inner layer Route2..5 may contain tracks. +// - Inner layer Route6 may contain a power plain (no output generated yet!). +// - For all other inner layers no output is generated. +// - On the top and bottom layers only wires and smd pads are output. +// Exception: Circles defined in a package are output as filled circles +// but do not belong to a signal. +// +/////////////////////////////////////////////////////////////////////////////////////////// + +#require 4.1602 + + +string jobname, + layer_name[], + padshape[] = {"P_ROUND","P_ROUND","P_ROUND","P_ROUND","P_ROUND"},// if long/offset subst. by round + viashape[] = {"P_BLOCK","P_ROUND","P_ROUND","P_ROUND","P_ROUND"},// if long/offset subst. by round + padname, + shapename[], // package names + t[], // padtypes + pst[]; // padstacktypes + +real cx, cy, rx, ry, x, y, x1, x2, y1, y2, r, a1, a2;; +real delta = 5; + +int i, new, sx, + padcount, + pad_is_numeric, + // eagle to fabmaster layer conversion + // eagle 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52 ** Feb. 2007 ** + flayer[] = {0, 2, 4, 5, 6, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 0,16,16,17, 0, 0,18,19,20,21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,16,17}; + +string partnumname[]; // 2009-12-03 quick find pin-name part-name +int cntnumname = 0; + +numeric string areaEname[]; +int indexareaEname[]; +int cntindex = 1; + // create pad number index list +numeric string areaEpadname[]; +int areaPadNumber[]; // the number of pad in FATF format +int cntEpad = 1; + + +int sizes[], ratio[]; // Text fonts +int cntt = 0; +int boardroundness = 100; // global roundness (design rules) + +int xmin = 32000, xmax = 0, ymin = 32000, ymax = 0; + +int ht = time(); + +//----------------------------------------------------- +string validname (string s) { + int i; + for (i = 0; s[i]; i++) { + if (s[i] == ',') s[i] = '_'; + if (s[i] == ';') s[i] = '_'; + if (s[i] == ')') s[i] = '_'; + if (s[i] == '(') s[i] = '_'; // 2013-10-24 + // add further substitutions here + } + return s; +} +//----------------------------------------------------- +int fablayer(int l) { + return flayer[l]; +} + +//----------------------------------------------------- +int u2u(int x) { // resolution 1/1000 inch + return u2mil(x); // mil +} + +//----------------------------------------------------- +real deg2arc(int x) { // degree to arc + return x*PI/180; +} + +//----------------------------------------------------- +int u2ang(real x, int mirror) { + if (mirror) { + real m = 360 - x; + if (m > 180) m -= 180; + else m += 180; + x = round((360 - m) * 10); // clockwise in FABMASTER!!! + } + else { + x = round((360 - x) * 10); // clockwise in FABMASTER!!! + } + return x; +} + +//---------------------------------------------------- +real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } +} + +real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } +} + + +//----------------------------------------------------- +string padtype(UL_ELEMENT E, UL_CONTACT C) { + string s; + int pdi, x1, y1, x2, y2, r, d; + if (C.pad) { + pdi = u2u(C.pad.diameter[16]); + if (C.pad.shape[16] == PAD_SHAPE_ROUND || C.pad.shape[16] == PAD_SHAPE_OCTAGON || C.pad.shape[16] == PAD_SHAPE_SQUARE) { + sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi); + } + // if long subst. by round use this code + else if (C.pad.shape[16] == PAD_SHAPE_LONG) { // substitute y/xlongoct by round + pdi = pdi/2; + sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi); + } + // if offset subst. by round use this code + else if (C.pad.shape[16] == PAD_SHAPE_OFFSET) { // substitute offset by round + pdi = pdi/2; + sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi); + } + } + return s; +} + +void get_roundness(UL_ELEMENT E) { + E.package.contacts(C) { + if (C.smd) { + if (C.smd.roundness < boardroundness) boardroundness = C.smd.roundness; + } + } + return; +} + +//----------------------------------------------------- +int padindex(UL_ELEMENT E,UL_CONTACT C) { + int i = 0; + for (i = 0; t[i]; i++) { + if (t[i] == padtype(E,C)) + return i+1; + } + return i; // should not be possible +} + +//----------------------------------------------------- +string padstacktype(UL_ELEMENT E, UL_CONTACT C) { + int px, d; + string s; + px = padindex(E,C); + d = u2u(C.pad.drill); + sprintf(s, "P_%d_%d", d, px); + return s; +} + +//----------------------------------------------------- +string PAC_padtype(UL_PACKAGE P, UL_CONTACT C) { + string s; + int pdi, x1, y1, x2, y2, r, d; + if (C.pad) { + pdi = u2u(C.pad.diameter[16]); + if (C.pad.shape[16] == PAD_SHAPE_ROUND || C.pad.shape[16] == PAD_SHAPE_OCTAGON || C.pad.shape[16] == PAD_SHAPE_SQUARE) { + sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi); + } + // if long subst. by round use this code + else if (C.pad.shape[16] == PAD_SHAPE_LONG) { // substitute y/xlongoct by round + pdi = pdi/2; + sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi); + } + // if offset subst. by round use this code + else if (C.pad.shape[16] == PAD_SHAPE_OFFSET) { // substitute offset by round + pdi = pdi/2; + sprintf(s, "%s (%d);", padshape[C.pad.shape[16]], pdi); + } + } + return s; +} + +//----------------------------------------------------- +int PAC_padindex(UL_PACKAGE P,UL_CONTACT C) { + int i = 0; + for (i = 0; t[i]; i++) { + if (t[i] == PAC_padtype(P,C)) + return i+1; + } + return i; // should not be possible +} + +//----------------------------------------------------- +string PAC_padstacktype(UL_PACKAGE P, UL_CONTACT C) { + int px, d; + string s; + px = PAC_padindex(P,C); + d = u2u(C.pad.drill); + sprintf(s, "P_%d_%d", d, px); + return s; +} + +//----------------------------------------------------- +int padstackindex(UL_PACKAGE P, UL_CONTACT C) { + int i = 0; + for (i = 0; pst[i]; i++) { + if (pst[i] == PAC_padstacktype(P,C)) + return i+1; + } + return i; // should not be possible +} + +//----------------------------------------------------- +string viatype(UL_VIA V) { + string s; + int pdi, x1, y1, x2, y2; + pdi = u2u(V.diameter[16]); + if (V.shape[16] == VIA_SHAPE_ROUND || V.shape[16] == VIA_SHAPE_OCTAGON) { + sprintf(s, "%s (%d);", viashape[V.shape[16]], pdi); + } + if (V.shape[16] == VIA_SHAPE_SQUARE) { + x1 = round(-pdi/2); y1 = round(-pdi/2); + x2 = round(pdi/2); y2 = round(pdi/2); + sprintf(s, "%s (%d,%d,%d,%d);", viashape[V.shape[16]], x1,y1,x2,y2); + } + return s; +} + +//----------------------------------------------------- +int viaindex(UL_VIA V) { + int i = 0; + for (i = 0; t[i]; i++) { + if (t[i] == viatype(V)) + return i+1; + } + return i; // should not be possible +} + +//----------------------------------------------------- +string viastacktype(UL_VIA V) { + int px, d; + string s; + px = viaindex(V); + d = u2u(V.drill); + sprintf(s, "P_%d_%d", d, px); + return s; +} + +//----------------------------------------------------- +int viastackindex(UL_VIA V) { + int i = 0; + for (i = 0; pst[i]; i++) { + if (pst[i] == viastacktype(V)) + return i+1; + } + return i; // should not be possible +} + +//----------------------------------------------------- +string drawpadpoly(int dx, int dy, int xo, int yo, real angle, int roundness, real elong, int padtype) { + string s; + real a = angle; + + if(roundness) { + real r1; + int l, r; + real rad, rad1, x1, x2, y1, y2; + real x_1, y_1, x_2, y_2; + + if (dx <= dy) { + r = dx; + l = dy; + } + else { + r = dy; + l = dx; + } + r1 = r / 200 * roundness; + + if (roundness == 100) { // rounded pad + if (padtype == PAD_SHAPE_OFFSET) { + rad = PI / 180 * a; + rad1 = PI / 180 * (a + 180); + x1 = 0; + y1 = 0; + x2 = u2u(cos(rad) * (r*elong/100) ); + y2 = u2u(sin(rad) * (r*elong/100) ); + } + else if (padtype == PAD_SHAPE_LONG) { + rad = PI / 180 * a; + rad1 = PI / 180 * (a + 180); + x1 = u2u(cos(rad) * ((r*elong/100) /2) ); + y1 = u2u(sin(rad) * ((r*elong/100) /2) ); + x2 = u2u(cos(rad1) * ((r*elong/100) /2) ); + y2 = u2u(sin(rad1) * ((r*elong/100) /2) ); + } + else { // SMD + rad = PI / 180 * a; + rad1 = PI / 180 * (a + 180); + x1 = u2u(cos(rad) * ((l-r) /2) ); + y1 = u2u(sin(rad) * ((l-r) /2) ); + x2 = u2u(cos(rad1) * ((l-r) /2) ); + y2 = u2u(sin(rad1) * ((l-r) /2) ); + } + sprintf(s, "TRACK (%d(%.0f,%.0f)(%.0f,%.0f))", + u2u(r), + u2u(xo) + x1, + u2u(yo) + y1, + u2u(xo) + x2, + u2u(yo) + y2 ); + } + + else { // octagon + r1 = r * 0.56; + sprintf(s, "POLYGON ((%.0f,%.0f)(%.0f,%.0f)\n (%.0f,%.0f)(%.0f,%.0f)\n (%.0f,%.0f)(%.0f,%.0f)\n (%.0f,%.0f)(%.0f,%.0f)\n (%.0f,%.0f))", + u2u(xo) + Xneu( u2u(0+ dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a), + u2u(yo) + Yneu( u2u(0+ dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a), + u2u(xo) + Xneu( u2u(0+ (dx-r1) /2 ), u2u(0+ dy /2 ), 0, 0, a), + u2u(yo) + Yneu( u2u(0+ (dx-r1) /2 ), u2u(0+ dy /2 ), 0, 0, a), + u2u(xo) + Xneu( u2u(0- (dx-r1) /2 ), u2u(0+ dy /2 ), 0, 0, a), + u2u(yo) + Yneu( u2u(0- (dx-r1) /2 ), u2u(0+ dy /2 ), 0, 0, a), + u2u(xo) + Xneu( u2u(0- dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a), + u2u(yo) + Yneu( u2u(0- dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a), + u2u(xo) + Xneu( u2u(0- dx /2 ), u2u(0- (dy-r1) /2 ), 0, 0, a), + u2u(yo) + Yneu( u2u(0- dx /2 ), u2u(0- (dy-r1) /2 ), 0, 0, a), + u2u(xo) + Xneu( u2u(0- (dx-r1) /2 ), u2u(0- dy /2 ), 0, 0, a), + u2u(yo) + Yneu( u2u(0- (dx-r1) /2 ), u2u(0- dy /2 ), 0, 0, a), + u2u(xo) + Xneu( u2u(0+ (dx-r1) /2 ), u2u(0- dy /2 ), 0, 0, a), + u2u(yo) + Yneu( u2u(0+ (dx-r1) /2 ), u2u(0- dy /2 ), 0, 0, a), + u2u(xo) + Xneu( u2u(0+ dx /2 ), u2u(0- (dy-r1) /2 ), 0, 0, a), + u2u(yo) + Yneu( u2u(0+ dx /2 ), u2u(0- (dy-r1) /2 ), 0, 0, a), + u2u(xo) + Xneu( u2u(0+ dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a), + u2u(yo) + Yneu( u2u(0+ dx /2 ), u2u(0+ (dy-r1) /2 ), 0, 0, a) ); + + } + } + else { // rectangle + sprintf(s, "POLYGON ((%.0f,%.0f)(%.0f,%.0f)(%.0f,%.0f)(%.0f,%.0f)(%.0f,%.0f))", + u2u(xo) + Xneu( u2u(0 + dx /2), u2u(0 + dy / 2), 0, 0, a), + u2u(yo) + Yneu( u2u(0 + dx /2), u2u(0 + dy / 2), 0, 0, a), + u2u(xo) + Xneu( u2u(0 + dx /2), u2u(0 - dy / 2), 0, 0, a), + u2u(yo) + Yneu( u2u(0 + dx /2), u2u(0 - dy / 2), 0, 0, a), + u2u(xo) + Xneu( u2u(0 - dx /2), u2u(0 - dy / 2), 0, 0, a), + u2u(yo) + Yneu( u2u(0 - dx /2), u2u(0 - dy / 2), 0, 0, a), + u2u(xo) + Xneu( u2u(0 - dx /2), u2u(0 + dy / 2), 0, 0, a), + u2u(yo) + Yneu( u2u(0 - dx /2), u2u(0 + dy / 2), 0, 0, a), + u2u(xo) + Xneu( u2u(0 + dx /2), u2u(0 + dy / 2), 0, 0, a), + u2u(yo) + Yneu( u2u(0 + dx /2), u2u(0 + dy / 2), 0, 0, a) ); + } + return s; +} + +//----------------------------------------------------- +string drawpad(UL_PACKAGE P, UL_CONTACT C, int l) { + string s = "no pad!"; + int dx, dy, r, d; + if (C.pad) { + + + if (C.pad.shape[l] == PAD_SHAPE_ROUND) { + sprintf(s, "ROUND (%d,%d,%d)", u2u(C.pad.diameter[l]), u2u(C.pad.x), u2u(C.pad.y) ); + } + else if (C.pad.shape[l] == PAD_SHAPE_SQUARE) { + s = drawpadpoly(C.pad.diameter[l], C.pad.diameter[l], C.pad.x, C.pad.y, C.pad.angle, 0, 0, 0); + } + + else if (C.pad.shape[l] == PAD_SHAPE_OCTAGON) { + d = round(d); + s = drawpadpoly(C.pad.diameter[l], C.pad.diameter[l], C.pad.x, C.pad.y, C.pad.angle, 50, C.pad.elongation, PAD_SHAPE_OCTAGON); + } + + else if (C.pad.shape[l] == PAD_SHAPE_LONG) { + r = round(d/2); + s = drawpadpoly(C.pad.diameter[l]*2, C.pad.diameter[l], C.pad.x, C.pad.y, C.pad.angle, 100, C.pad.elongation, PAD_SHAPE_LONG); + } + + else if (C.pad.shape[l] == PAD_SHAPE_OFFSET) { + r = round(d); + s = drawpadpoly(C.pad.diameter[l]*2, C.pad.diameter[l], C.pad.x, C.pad.y, C.pad.angle, 100, C.pad.elongation, PAD_SHAPE_OFFSET); + } + + // PAD_SHAPE_ANNULUS + // PAD_SHAPE_THERMAL + } + else { // smd + int smd_roundnes = C.smd.roundness; + if (smd_roundnes < boardroundness) smd_roundnes = boardroundness; + s = drawpadpoly(C.smd.dx, C.smd.dy, C.smd.x, C.smd.y, C.smd.angle, smd_roundnes, 0, 0); + } + return s; +} + + +//--------------------------------------------------- +string pin_number(UL_ELEMENT E, string pinname) { + int j, pad_is_numeric = 1, padcount; + string s = ""; + E.package.contacts(CT) { + s = CT.name; + for (j = 0; s[j]; ++j) { + if (!isdigit(s[j])) { + pad_is_numeric = 0; + } + } + } + if (pad_is_numeric) { + return pinname; + } + else { + padcount = 0; + E.package.contacts(CT) { + padcount++; + if (CT.name == pinname) { + sprintf(s, "%d", padcount); + return s; + } + } + } + return s; +} + + +//------------------------------------------------------- +string PAC_pin_number(UL_PACKAGE P, string pinname) { + int j, pad_is_numeric = 1, padcount; + string s = ""; + P.contacts(CT) { + s = CT.name; + for (j = 0; s[j]; ++j) { + if (!isdigit(s[j])) { + pad_is_numeric = 0; + } + } + } + if (pad_is_numeric) { + return pinname; + } + else { + padcount = 0; + P.contacts(CT) { + padcount++; + if (CT.name == pinname) { + sprintf(s, "%d", padcount); + return s; + } + } + } + return s; +} + +//--------------------------------------------------- +int realnet(UL_SIGNAL S) { + S.contactrefs(S) return 1; + return 0; +} + +//--------------------------------------------------- +int net_on_layer(UL_SIGNAL S, int layer) { // 1 if a wire of this net is on the given layer + S.wires(W) + if (W.layer == layer) return 1; + S.polygons(P) + if(P.layer == layer) return 1; + return 0; +} + +////////////////////////////////////////////////////// +void create_header () { + printf (";EAGLE %d.%02d %s %s FATF OUTPUT FILE FABmaster(R) ", EAGLE_VERSION, EAGLE_RELEASE, filename(argv[0]), ULPversion); + printf ("%02d.%02d.%02d %02d:%02d:%02d\n\n", + t2day(ht),t2month(ht)+1,t2year(ht),t2hour(ht),t2minute(ht),t2second(ht)); + printf (":FABMASTER FATF REV11.1;\n\n"); + printf (":UNITS = 1/1000 INCH\n"); + printf (":NOAUTOROTATE\n"); + return; +} + + +////////////////////////////////////////////////////// +void board_data(UL_BOARD B) { + int t = time(); + printf ("\n:BOARD_DATA\n"); + printf ("1,JOB(\"%s\",,%02d-%02d-%02d,);\n", jobname,t2day(t),t2month(t),t2year(t)); + + B.wires(W) { // if board outline as wires in board + if (W.layer == LAYER_DIMENSION) { + xmin = min(u2u(W.x1), xmin); xmin = min(u2u(W.x2), xmin); + ymin = min(u2u(W.y1), ymin); ymin = min(u2u(W.y2), ymin); + xmax = max(u2u(W.x1), xmax); xmax = max(u2u(W.x2), xmax); + ymax = max(u2u(W.y1), ymax); ymax = max(u2u(W.y2), ymax); + + if (W.curve) { + // process arcs (done with wire segments) + x = W.arc.x1; + y = W.arc.y1; + + printf ("2,CONTOUR ("); + printf("(%d,%d,0)", u2u(x), u2u(y)); + real angle = W.arc.angle1 + delta; + + while (angle < W.arc.angle2) { + i++; + if (i==1) { + printf(","); + } + else if (i==2){ + printf(");\n2,CONTOUR ("); + i = 0; + } + x = W.arc.xc + W.arc.radius * cos(deg2arc(angle)); + y = W.arc.yc + W.arc.radius * sin(deg2arc(angle)); + printf("(%d,%d)", u2u(x), u2u(y)); + xmin = min(u2u(x), xmin); xmin = min(u2u(x), xmin); + ymin = min(u2u(y), ymin); ymin = min(u2u(y), ymin); + xmax = max(u2u(x), xmax); xmax = max(u2u(x), xmax); + ymax = max(u2u(y), ymax); ymax = max(u2u(y), ymax); + angle += delta; + } + if (!i) { + printf("(%d,%d,0));\n", u2u(W.arc.x2), u2u(W.arc.y2)); + } + else { + printf(");\n2,CONTOUR ((%d,%d,0)", u2u(x), u2u(y)); + printf(",(%d,%d,0));\n", u2u(W.arc.x2), u2u(W.arc.y2)); + } + i=0; + } + else { + printf ("2,CONTOUR ("); + printf("(%d,%d,0),(%d,%d,0)", u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + printf(");\n"); + } + } + } + B.elements(E) { + E.package.wires(W) { + if (W.layer == LAYER_DIMENSION) { + xmin = min(u2u(W.x1), xmin); xmin = min(u2u(W.x2), xmin); + ymin = min(u2u(W.y1), ymin); ymin = min(u2u(W.y2), ymin); + xmax = max(u2u(W.x1), xmax); xmax = max(u2u(W.x2), xmax); + ymax = max(u2u(W.y1), ymax); ymax = max(u2u(W.y2), ymax); + + if (W.curve) { + // process arcs (done with wire segments) + x = W.arc.x1; + y = W.arc.y1; + + printf ("2,CONTOUR ("); + printf("(%d,%d,0)", u2u(x), u2u(y)); + real angle = W.arc.angle1 + delta; + + while (angle < W.arc.angle2) { + i++; + if (i==1) { + printf(","); + } + else if (i==2){ + printf(");\n2,CONTOUR ("); + i = 0; + } + x = W.arc.xc + W.arc.radius * cos(deg2arc(angle)); + y = W.arc.yc + W.arc.radius * sin(deg2arc(angle)); + printf("(%d,%d)", u2u(x), u2u(y)); + xmin = min(u2u(x), xmin); xmin = min(u2u(x), xmin); + ymin = min(u2u(y), ymin); ymin = min(u2u(y), ymin); + xmax = max(u2u(x), xmax); xmax = max(u2u(x), xmax); + ymax = max(u2u(y), ymax); ymax = max(u2u(y), ymax); + angle += delta; + } + if (!i) { + printf("(%d,%d,0));\n", u2u(W.arc.x2), u2u(W.arc.y2)); + } + else { + printf(");\n2,CONTOUR ((%d,%d,0)", u2u(x), u2u(y)); + printf(",(%d,%d,0));\n", u2u(W.arc.x2), u2u(W.arc.y2)); + } + i=0; + } + else { + printf ("2,CONTOUR ("); + printf("(%d,%d,0),(%d,%d,0)", u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + printf(");\n"); + } + } + } + } + printf("3,WORK_SPACE (%d,%d,%d,%d);\n", xmin, xmax, ymin, ymax); + printf (":EOD\n"); + printf ("\n:NOTRACE\n"); + return; +} + +////////////////////////////////////////////////////// +void parts(UL_BOARD B) { + int i = 1; + printf ("\n:PARTS\n"); + B.elements(E) { + partnumname[i] = E.name; // 2009-12-03 + printf("%d,",i++); // PART ID + printf("%s,",E.name); // PART NAME (not as in definition!) + printf("\"%s\",",E.value); // DEVICE NAME = Value + printf("%s,",validname(E.package.name + "__" + E.package.library)); // PACKAGE NAME + printf("%d,%d,",u2u(E.x), u2u(E.y)); // X,Y + printf("%d,",u2ang(E.angle, E.mirror)); // ROTATION + if (E.mirror) // ASSEMBLY SIDE + printf("B;"); + else + printf("T;"); + printf("\n"); + } + cntnumname = i; // 2009-12-03 + printf(":EOD\n"); + return; +} + +////////////////////////////////////////////////////// +void pad_symbols(UL_BOARD B) { + int i, j = 0, new; // j+1 = pad index; t[] contains padtypes + printf ("\n:PAD_SYMBOLS\n\n"); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + new = 1; // padtype not generated yet + for (i = 0; t[i]; i++) { + if (t[i] == padtype(E,C)) + new = 0; // padtype exists + } + if (new) { + t[j] = padtype(E,C); + printf("%d,%s\n", j+1, padtype(E,C)); + j++; + } + } + } + } + B.signals(S) { + S.vias(V) { + new = 1; + for (i = 0; t[i]; i++) { + if (t[i] == viatype(V)) + new = 0; // padtype exists + } + if (new) { + t[j] = viatype(V); + printf("%d,%s\n", j+1, viatype(V)); + j++; + } + } + } + printf(":EOD\n"); + return; +} + +////////////////////////////////////////////////////// +void layer_names(UL_BOARD B) { + int i; + string layers[] = { + "\"DRILL PAD\",COMMON,0,ELECTRICAL;" // layer 1 + ,"\"TOP\",TOP,3,ELECTRICAL;" + ,"\"BOTTOM\",BOTTOM,2,ELECTRICAL;" + ,"\"ROUTE2\",TRANSPARENT,0,ELECTRICAL;" + ,"\"ROUTE3\",TRANSPARENT,0,ELECTRICAL;" + ,"\"ROUTE4\",TRANSPARENT,0,ELECTRICAL;" + ,"\"ROUTE5\",TRANSPARENT,0,ELECTRICAL;" + ,"\"POWER1\",TRANSPARENT,0,ELECTRICAL;" + ,"\"DRILLH\",TRANSPARENT,0,DOCUMENTATION;" //layer 9 + ,"\"POWER2\",TRANSPARENT,0,DOCUMENTATION;" + + ,"\"DRILL\",TRANSPARENT,0,DOCUMENTATION;" + ,"\"THERMAL_2\",TRANSPARENT,0,DOCUMENTATION;" + ,"\"FORMAT\",TRANSPARENT,0,BOARD_CUTOUT;" + ,"\"THERMAL_1\",TRANSPARENT,0,DOCUMENTATION;" + ,"\"THERMAL\",TRANSPARENT,0,DOCUMENTATION;" + + + ,"\"TPLACE\",TOP,17,ASSEMBLY;" // 16 + ,"\"BPLACE\",BOTTOM,16,ASSEMBLY;" + + ,"\"TNAMES\",TOP,19,DOCUMENTATION;" + ,"\"BNAMES\",BOTTOM,18,DOCUMENTATION;" + + ,"\"TVALUES\",TOP,21,DOCUMENTATION;" + ,"\"BVALUES\",BOTTOM,20,DOCUMENTATION;" + }; + printf("\n:LAYER_NAMES\n"); + for (i=0; layers[i]; i++) { + printf("%d,%s\n", i+1, layers[i]); + } + printf(":EOD\n"); + printf("\n:LAYER_SETS\n"); //layer sets + printf("1,\"ALL\",(1"); + for (i=1; layers[i]; i++) { + printf(",%d", i+1); + } + printf(");\n"); + printf(":EOD\n"); + return; +} + +////////////////////////////////////////////////////// +void pad_stacks(UL_BOARD B) { + int new, i, j; + printf ("\n:PAD_STACKS\n"); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + new = 1; // padstacktype not generated yet + for (i = 0; pst[i]; i++) { + if (pst[i] == padstacktype(E, C)) + new = 0; // padstacktype exists + } + if (new) { + pst[j] = padstacktype(E, C); + printf("%d,\"%s\",%d,P,((1,%d));\n", + j+1, + padstacktype(E,C), + u2u(C.pad.drill), + padindex(E,C) + ); + j++; + } + } + } + } + B.signals(S) { + S.vias(V) { + new = 1; + for (i = 0; pst[i]; i++) { + if (pst[i] == viastacktype(V)) + new = 0; // viastacktype exists + } + if (new) { + pst[j] = viastacktype(V); + printf("%d,\"%s\",%d,P,((1,%d));\n", + j+1, + viastacktype(V), + u2u(V.drill), + viaindex(V) + ); + j++; + } + } + } + printf(":EOD\n"); + return; +} + +////////////////////////////////////////////////////// +void pads(UL_BOARD B) { + int i = 0; + printf ("\n:PADS\n"); + B.signals(S) { + if (realnet(S)) { // vias belonging to real net + i++; + S.vias(V) { + printf("%d,%d,((%d,%d));\n", i, viastackindex(V), u2u(V.x), u2u(V.y)); + } + } + else { // other vias + S.vias(V) { + printf("0,%d,((%d,%d));\n", viastackindex(V), u2u(V.x), u2u(V.y)); + } + } + } + printf(":EOD\n"); + return; +} + + +int searchfont(int tsize, int tratio) { + int found = -1; + for (int n = 0; n < cntt; n++) { + if (sizes[n] == tsize && ratio[n] == tratio) { + found = n; + break; + } + } + return found; +} + +////////////////////////////////////////////////////// +void fonts(UL_BOARD B) { + int n; + printf ("\n:FONTS\n"); + printf ("1,\"STANDARD\",96,60,72,0;\n"); + B.texts(T) { + if (searchfont(T.size, T.ratio) < 0) { + sizes[cntt] = T.size; + ratio[cntt] = T.ratio; + cntt++; + } + } + B.elements(E) { + E.package.texts(T) { + if (searchfont(T.size, T.ratio) < 0) { + sizes[cntt] = T.size; + ratio[cntt] = T.ratio; + cntt++; + } + } + } + for (n = 0; n < cntt; n++) { + printf("%d,\"FONT_%d\",%d,%.0f,%.0f,%.d;\n", n+2, n+2, u2u(sizes[n]), u2u(sizes[n])*.6, u2u(sizes[n])*.72, u2u(sizes[n]*ratio[n])/100); + } + printf(":EOD\n"); + return; +} + +////////////////////////////////////////////////////// +void packages(UL_BOARD B) { + int i = 1, j, k, l, xll,yll, textlayer; + real tangle, angle; + string dp, jst; + printf ("\n:PACKAGES\n"); + B.libraries(LBR) { + LBR.packages(P) { + new = 1; // padstacktype not generated yet + for (i = 0; shapename[i]; i++) { + if (shapename[i] == validname(P.name + "__" + P.library)) + new = 0; // package name exists + } + if (new) { + shapename[sx] = validname(P.name + "__" + P.library); + sx++; + + printf("%d,",i++); // PACKAGE ID + printf("\"%s\",",validname(P.name + "__" + P.library)); // PACK.NAME + printf(",,,\n"); // xmin etc. left blank + j = 0; k = 0; + P.contacts(C) { + if (k == 0) printf(" (PINS "); // only if contacts present + k++; + printf("(%s,,%d,%d,", PAC_pin_number(P, C.name), u2u(C.x), u2u(C.y)); // Pin IDs + if (C.pad) printf("D)"); // ASSEMBLY SIDE + else printf("T)"); + j++; + if (j > 2) { // max. 3 pins in one line + printf("\n "); + j = 0; + } + } + if (k != 0) printf(")\n"); // only if contacts present close PINS section + j = 0; + printf(" ("); // corresponds to ); before next package + P.contacts(C) { + if (C.pad) { + if (j > 0) { + printf(" "); + } + printf("%s,PAD (%d ((%d,%d)))\n", // PAD + PAC_pin_number(P, C.name), padstackindex(P,C), u2u(C.x), u2u(C.y)); + j++; + } + } // close PIN-ID,PAD section + j = 0; + P.contacts(C) { + if (C.pad) { + dp = drawpad(P, C, 1); + printf(" %s,LAYER (%d (\n", PAC_pin_number(P, C.name), fablayer(1)); // top side + printf(" %s))\n", dp); + dp = drawpad(P, C, 16); + printf(" %s,LAYER (%d (\n", PAC_pin_number(P, C.name), fablayer(16)); // bottom side + printf(" %s))\n", dp); + } + else { // smd, always on top layer + if (j > 0) printf(" "); + if (C.smd.layer == 1) { + printf("%s,LAYER (%d (\n", PAC_pin_number(P, C.name), fablayer(1)); + printf(" %s))\n", drawpad(P, C, 1)); + } + else { + printf("%s,LAYER (%d (\n", PAC_pin_number(P, C.name), fablayer(16)); + printf(" %s))\n", drawpad(P, C, 16)); + } + } + j++; + } // close PIN-ID,LAYER section + + // process circles etc. on top and bottom side + P.circles(C) { + if (C.layer == 1 || C.layer == 16) { + printf("\n 0,LAYER (%d (\n", fablayer(C.layer)); + int RminRmax = C.radius - C.width; + if (!C.width || RminRmax < 0) { + RminRmax = C.width/2; + printf(" ROUND (%d,%d,%d)", u2u((C.radius + RminRmax)*2), + u2u(C.x), u2u(C.y)); + } + else { + printf(" CIRCLE (%d,%d,%d,%d)", u2u(C.radius) + u2u(C.width)/2, + u2u(C.radius) - u2u(C.width)/2, + u2u(C.x), u2u(C.y)); + } + printf("))\n"); + } + } + P.rectangles(W) { + if (W.layer == 1 || W.layer == 16) { + printf("\n 0,LAYER (%d (\n", fablayer(W.layer)); + xll = W.x1; yll = W.y1; + int rectcenterx = (W.x1 + W.x2) /2; + int rectcentery = (W.y1 + W.y2) /2; + int rectx = W.x2 - W.x1; + int recty = W.y2 - W.y1; + printf(" %s", drawpadpoly(rectx, recty, rectcenterx, rectcentery, W.angle, 0, 0, 0)); + printf("))\n"); + } + } + P.texts(T) { + if (T.layer == 1 || T.layer == 16) { + printf(" 0,LAYER (%d (\n", fablayer(T.layer)); + T.wires(W) { + printf(" TRACK (%d,(%d,%d),(%d,%d))\n", u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + /* + printf(" TEXT (%d,%d,%d,%s,%.1f,%s,%s)))\n", + searchfont(T.size, T.ratio)+2, + u2u(T.x), u2u(T.y), jst, T.angle, Mirror, T.value); + */ + printf("))\n"); + } + } + + // end circles etc. on top and bottom + P.wires(W) { + if (W.layer == 1 || W.layer == 16 || W.layer == 21 || W.layer == 22 || W.layer == 51 || W.layer == 52) { + printf(" 0,LAYER (%d (\n", fablayer(W.layer)); // tplace layer + if (W.curve) { + // process arcs (done with wire segments) + printf(" TRACK (%d,(%d,%d),", u2u(W.width), u2u(W.arc.x1), u2u(W.arc.y1)); + angle = W.arc.angle1 + delta; + while (angle < W.arc.angle2) { + printf("\n (%d,%d),", + u2u(W.arc.xc + W.arc.radius * cos(deg2arc(angle))), + u2u(W.arc.yc + W.arc.radius * sin(deg2arc(angle))) ); + angle += delta; + } + printf("(%d,%d))", u2u(W.arc.x2), u2u(W.arc.y2) ); + } + else { + printf(" TRACK (%d,(%d,%d),", u2u(W.width), u2u(W.x1), u2u(W.y1)); + printf("(%d,%d))", u2u(W.x2), u2u(W.y2)); + } + printf("))\n"); + } + } + + P.rectangles(W) { + if (W.layer == 21 || W.layer == 22 || W.layer == 51 || W.layer == 52) { + printf(" 0,LAYER (%d (\n", fablayer(W.layer)); // tplace layer + xll = W.x1; yll = W.y1; + int rectcenterx = (W.x1 + W.x2) /2; + int rectcentery = (W.y1 + W.y2) /2; + int rectx = W.x2 - W.x1; + int recty = W.y2 - W.y1; + printf("%s", drawpadpoly(rectx, recty, rectcenterx, rectcentery, W.angle, 0, 0, 0)); + printf("))\n"); + } + } + + P.circles(C) { + if (C.layer == 21 || C.layer == 22 || C.layer == 51 || C.layer == 52) { + printf(" 0,LAYER (%d (\n", fablayer(C.layer)); // tplace layer + int RminRmax = C.radius - C.width; + if (!C.width || RminRmax < 0) { + RminRmax = C.width/2; + printf(" ROUND (%d,%d,%d)\n", u2u((C.radius + RminRmax)*2), + u2u(C.x), u2u(C.y)); + } + else { + printf(" CIRCLE (%d,%d,%d,%d)\n", u2u(C.radius) + u2u(C.width)/2, + u2u(C.radius) - u2u(C.width)/2, + u2u(C.x), u2u(C.y)); + } + printf("))\n"); + } + } + + P.texts(T) { + if (T.layer == 1 || T.layer == 16 || T.layer == 21 || T.layer == 22 || T.layer == 51 || T.layer == 52) { + printf(" 0,LAYER (%d (\n", fablayer(T.layer)); + T.wires(W) { + printf(" TRACK (%d,(%d,%d),(%d,%d))\n", u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + printf("))\n"); + } + /* + if (T.layer == 51 || T.layer == 52) { + printf(" 0,LAYER (%d (\n", fablayer(T.layer - 30)); // tplace layer + if (!T.mirror) { + jst = "BOTTOM_LEFT"; + } + else { + jst = "TOP_RIGHT"; + } + printf(" TEXT (1,%d,%d,%s,%3.0f, ,%s)\n", + u2u(x), u2u(y), jst, T.angle, T.value); + } + */ + } + printf(");\n"); + } + } + } + printf(":EOD\n"); + return; +} + +////////////////////////////////////////////////////// +void layer(UL_BOARD B) { + int textlayer; + string jst, mir; + real tangle, angle; + printf ("\n:LAYERS\n"); + int i = 0, lay; + B.signals(S) { + if (realnet(S)) { + ++i; + for (lay = 1; lay <= 16; lay++) { + if (net_on_layer(S, lay) && fablayer(lay) > 0) { + printf("%d,LAYER (%d, (\n", i, fablayer(lay)); + S.wires(W) { + if (lay == W.layer) { + + if (W.curve) { + // process arcs (done with wire segments) + x = W.arc.x1; + y = W.arc.y1; + printf(" TRACK (%d,(%d,%d)", u2u(W.width), u2u(x), u2u(y)); + angle = W.arc.angle1 + delta; + while (angle < W.arc.angle2) { + x = W.arc.xc + W.arc.radius * cos(deg2arc(angle)); + y = W.arc.yc + W.arc.radius * sin(deg2arc(angle)); + printf(",\n (%d,%d)", u2u(x), u2u(y)); + angle += delta; + } + printf(",\n (%d,%d))", u2u(W.arc.x2), u2u(W.arc.y2)); // Comma ends the last line 2013-07-01 + } + else { + printf(" TRACK (%d,(%d,%d),(%d,%d))\n", + u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + } + } + + S.polygons(P) { // 13.05.2004 polygon + if (lay == P.layer) { + P.contours(W) { + printf(" TRACK (%d,(%d,%d),(%d,%d))\n", + u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + P.fillings(W) { + printf(" TRACK (%d,(%d,%d),(%d,%d))\n", + u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + } + } + printf(" ));\n"); + } + } + } + } + + // process name texts + B.elements(E) { + if (E.package) { + tangle = 0; + if (!E.mirror) { + textlayer = 25; + mir = ""; + } + else { + textlayer = 26; + mir = "M"; + } + jst = "CENTER"; + x = E.x; y = E.y; + printf("0,LAYER (%d (\n", fablayer(textlayer)); // tnames layer + printf(" TEXT (1,%d,%d,%s,0,%s,%s)));\n", u2u(x), u2u(y), jst, mir, E.name); + } + } + B.texts(T) { + if (T.layer == 1 || T.layer == 16 || T.layer == 21) { + printf(" 0,LAYER (%d (\n", fablayer(T.layer)); + T.wires(W) { + printf(" TRACK (%d,(%d,%d),(%d,%d))\n", u2u(W.width), u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + printf("))\n"); + } + } + printf(":EOD\n"); +} + + +// //////////// 2009-12-03 ///////////////// +void creat_pad_number_index(UL_BOARD B) { + B.elements(E) { + int iscontact = 0; + E.package.contacts(C) { + iscontact = 1; + break; + } + if (!iscontact) { + sprintf(areaEname[cntindex], "%s", E.name); // index of element without contacts + indexareaEname[cntindex] = 0; + cntindex++; + } + else { + int j = 0; + E.package.contacts(C) { + if (!j) { + j++; + sprintf(areaEname[cntindex], "%s", E.name); // index to start of pad names in package-pad-list + indexareaEname[cntindex] = cntEpad; + cntindex++; + } + // create pad number index list 2009-12-03 + sprintf(areaEpadname[cntEpad], "%s~%s", E.name, C.name); + areaPadNumber[cntEpad] = strtol(pin_number(E, C.name)); // *** the number of pad in FATF format + cntEpad++; + j++; + } + } + } + return; +} + +//------------------------------------- +int getpadnbr(int i, string epname) { + for (int n = i; n < cntEpad; n++) { + if (areaEpadname[n] == epname) return areaPadNumber[n]; + } + return 0; +} + +int getpinr(string ename, string pname) { + string ep = ename + "~" + pname; + for (int i = 1; i < cntindex; i++) { + if (areaEname[i] == ename) return getpadnbr(indexareaEname[i], ep); + } + return 0; +} + +int getelnr(string ename) { + for (int i = 1; i < cntindex; i++) { + if (areaEname[i] == ename) return i; + } + return 0; +} + + +////////////////////////////////////////////////////// +void nets(UL_BOARD B) { + int i = 0, itemcnt, elnr, j; + string pin; + printf("\n:NETS\n"); + B.signals(S) { + if (realnet(S)) { + printf("%d,\"%s\",S,\n (", ++i, S.name); // NET NR, NET NAME, STYPE + itemcnt = 0; + S.contactrefs(C) { + if (C.contact) { // 2011-02-30 first request if a connect. + elnr = getelnr(C.element.name); // Part ID 2009-12-03 + sprintf(pin, "%d", getpinr(C.element.name, C.contact.name)); // Pin ID 2009-12-03 + if (itemcnt) { + printf(","); + } + if (itemcnt > 5) { + printf("\n "); + itemcnt = 0; + } + itemcnt++; + printf("(%d,%s)", elnr, pin); // PART ID, PIN ID + } + else { + dlgMessageBox("Found signal '"+S.name+ "' without contactref!\nCheck consistence and corrupted signals.", "OK"); + exit(-1); + } + } + printf(");\n"); + } + } + printf(":EOD\n"); + return; +} + +////////////////////////////////////////////////////// +void create_pcboard_section(UL_BOARD B) { + B.elements(E) get_roundness(E); + board_data(B); + parts(B); + nets(B); + pad_symbols(B); + layer_names(B); + pad_stacks(B); + pads(B); + fonts(B); + packages(B); + layer(B); + return; +} + +////////////////////////////////////////////////////// +if (board) board(B) { + jobname = filename(B.name); + jobname = strsub(jobname, 0, strlen(jobname) - 4); + output(filesetext(B.name, ".fab")) { + create_header(); + creat_pad_number_index(B); + create_pcboard_section(B); + /* option to count run time + printf (";start %02d.%02d.%02d %02d:%02d:%02d : ", + t2day(ht),t2month(ht)+1,t2year(ht),t2hour(ht),t2minute(ht),t2second(ht)); + int t = time(); + printf (";end %02d.%02d.%02d %02d:%02d:%02d\n", + t2day(t),t2month(t)+1,t2year(t),t2hour(t),t2minute(t),t2second(t)); + */ + } + string ex; + sprintf(ex, "Data exported to:\n\n%s", filesetext( B.name, ".fab" )); + dlgMessageBox(ex, "OK"); +} diff --git a/trunk/ulp/fill-via4vacuum.ulp b/trunk/ulp/fill-via4vacuum.ulp new file mode 100644 index 00000000..23063249 --- /dev/null +++ b/trunk/ulp/fill-via4vacuum.ulp @@ -0,0 +1,84 @@ +#usage "Generate a mask to fill vias for vacuum adapter.\n" + "

    " + "To delete the elements in user layer afterwards, display it without " + "any other layers, and use GROUP and DELETE. Then remove the user " + "layer with the command LAYER -number." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + + +int userlayer = 101; +if (argv[1]) userlayer = strtol(argv[1]); +if (!userlayer) { + int Result = dlgDialog("Fill mask for vacuum") { + dlgLabel(usage); + dlgHBoxLayout { + dlgIntEdit(userlayer); + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + dlgPushButton("-Cancel") dlgReject(); + } + }; + if (!Result) exit (0); +} + +string cmd; +sprintf(cmd, "SET WIRE_BEND 2;\nGRID mm;\nLayer %d FillVia;\nchange layer %d;\n", userlayer, userlayer); + +void center(int x, int y, int diameter, int shape) { + real radius = u2mm(diameter) / 2; + string h; + switch (shape) { + case VIA_SHAPE_SQUARE : sprintf(h, "RECT (%.4f %.4f) (%.4f %.4f) ;\n", + u2mm(x) - radius, u2mm(y) - radius, u2mm(x) + radius, u2mm(y) + radius ); + break; + + case VIA_SHAPE_ROUND : sprintf(h, "CIRCLE 0 (%.4f %.4f) (%.4f %.4f) ;\n", + u2mm(x), u2mm(y), u2mm(x) + radius, u2mm(y) ); + break; + + case VIA_SHAPE_OCTAGON : real pwidth = 0.2032; + real frame = radius - pwidth/2; + sprintf(h, "CHANGE STYLE 0;\nPOLYGON %.4f (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + pwidth, + u2mm(x) - frame, + u2mm(y) - frame * 0.4139, + u2mm(x) - frame * 0.4139, + u2mm(y) - frame, + u2mm(x) + frame * 0.4139, + u2mm(y) - frame, + u2mm(x) + frame, + u2mm(y) - frame * 0.4139, + u2mm(x) + frame, + u2mm(y) + frame * 0.4139, + u2mm(x) + frame * 0.4139, + u2mm(y) + frame, + u2mm(x) - frame * 0.4139, + u2mm(y) + frame, + u2mm(x) - frame, + u2mm(y) + frame * 0.4139, + u2mm(x) - frame, + u2mm(y) - frame * 0.4139 + ); + break; + } + cmd += h; + return; +} + +if (board) board(B) { + B.signals(S) { + S.vias(V) { + if(V.start == 1 && V.end == 16) { + center(V.x, V.y, V.diameter[1], V.shape[1]); + } + } + } + exit (cmd); +} + +else dlgMessageBox("Start this ULP in a Board!", "OK"); +exit (0); diff --git a/trunk/ulp/find-single-ended-wire.ulp b/trunk/ulp/find-single-ended-wire.ulp new file mode 100644 index 00000000..b5b84f41 --- /dev/null +++ b/trunk/ulp/find-single-ended-wire.ulp @@ -0,0 +1,405 @@ +#usage "en: Find single-ended wires (wire stubs)" + "

    " + "Find single-ended wires that don't start or end at another wire, via or pad.
    " + "Starting the ulp without parameter generates a list. " + "The temporary list (file) will be deleted as soon as you quit EAGLE.
    " + "After running this ULP the MOVE command will be active. Now you should move this wire to a position where you can
    " + "select it easily with the RIPUP command." + "
    " + "RUN find-single-ended-wire [+] [-] [M] [=]" + "" + "" + "" + "" + "" + "
    + shows the next entry of the list (trace).
    - shows the previous entry of the list (trace)
    = shows this message again
    M defines a 0.1 micron group around this coordinate and activates the MOVE command
    " + "When using the parameters + and - for purposes of clarity only the layer that contains " + "the wire is displayed. Possibly plus the layer(s) Pads and/or Vias.
    " + "For recognizing the wire stubs it is necessary to set the fill style of the respective layer " + "to not filled (dotted or hatched).

    " + "NOTE: WIREs or VIAs that end in a polygon's area, are recognized as single-ended!
    " + "To avoid mistakes use RATSNEST to calculate the polygons before. Now you can start the ULP!
    " + "

    " + "Author: support@cadsoft.de" + , + "de: Find single ended wire." + "

    " + "Findet WIREs die nicht an einem Pad, Via oder einem anderen Wire beginnen bzw. enden (Stummel).
    " + "Der Start des ULP ohne Parameter erzeugt eine Liste (Datei) der Wire, die zum einzeln durchschalten benutzt werden kann.
    " + "Die Liste (Datei) wird nur temporär erzeugt und beim Beenden von Eagle gelöscht." + "
    " + "RUN find-single-ended-wire [+] [-] [M] [=]" + "" + "" + "" + "" + "" + "
    + zeigt den nächsten Eintrag in der Liste der gefundenen Elemente
    - zeigt den vorhergehenden Eintrag in der Liste der gefundenen Elmente
    = zeige den aktuellen Eintrag nochmal
    M Definiert einen Bereich von 0.1 Micron als Gruppe um die Koordinate und aktiviert den MOVE-Befehl
    " + "Nach dem Beenden des ULP ist der MOVE-Befehl aktiv. Damit kann der Wire zuerst aus dem " + "Bereich herausgezogen werden, um ihn eindeutig mit dem RIPUP-Befehl zu selektieren.
    " + "Um die Übersichtlichkeit zu erhöhen, wird bei der Weiterschaltung mit + oder - nur der " + "Layer in dem sich der Wire-Stummel befindet, plus eventuell der Pad-Layer und/oder " + "Via-Layer eingeblendet.
    " + "Um die Wire-Stummel innerhalb eines Pad oder Via zu erkennen ist es nötig das Füllmuster der " + "entsprechenden Layer auf nicht füllend (gepunktet oder schraffiert) einzustellen.

    " + "ACHTUNG: WIREs oder VIAs, die in einer Polygonfläche enden, werden ebenfalls als Single-Ended erkannt!
    " + "Um Verwechslungen auszuschliessen lassen Sie mit RATSNEST zuerst die Polygonflächen berechnen und starten Sie dann das ULP!
    " + "

    " + "Author: support@cadsoft.de" + +string Version = "1.0.2"; // 2007-04-03 alf@cadsoft.de + // 2008-04-10 changed GROUP ... (>x y); alf@cadsoft.de + // 2011-03-30 corrected request in loop S.contactrefs(C) { => if (C.contact) { + +#require 4.1600; + + +int test = 0; + +enum { typeW, typeS, typeP, typeV }; +string Typ[] = { "Wire", "Smd", "Pad", "Via" }; +int sameL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int sameS[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int padL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int viaL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +int viaStackS[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; +int viaStackE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + +int ncoord = 0; +int wx[]; // X coordinate +int wy[]; // Y coordinate +int wl[]; // Layer +int ws[]; // Start Layer for Via & Pad, Smd and Wire +int we[]; // End Layer for Via & Pad, Smd and Wire == Start Layer +int wt[]; // Type +int index[]; + +string cmd, s; + +string h; +string file, memory; +string cmdr[]; + + +// ### ---------------- functions ------------------- ### +void set_layer(int lay, int s_lay, int e_lay, int type) { + switch(type) { + case typeW : // Wire + sameL[lay]++; + break; + case typeS : // Smd + sameL[lay]++; + sameS[lay]++; + break; + + case typeP : // Pad + for (int pl = 1; pl < 18; pl++) { + padL[pl]++; + } + sameL[17]++; + break; + case typeV : // Via + for (int vl = s_lay; vl <= e_lay; vl++) { + viaL[vl]++; + } + viaStackS[viaL[18]] = s_lay; + viaStackE[viaL[18]] = e_lay; + viaL[18]++; + break; + } + return; +} + + +// ### claer counter ### +void clear_same_counter(void) { + for (int n = 0; n < 19; n++) { + viaL[n] = 0; + padL[n] = 0; + sameS[n] = 0; + sameL[n] = 0; + viaStackS[n] = 0; + viaStackE[n] = 0; + } + return; +} + + +// #*#*#* check via stack and if via routet on more as 1 layer *#*#*# +void check_via(int k, string sigName) { + int cntViaOverLap[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + string usedWireLayer = ""; + int nV = 0; + for (nV = 0; nV < viaL[18]; nV++) { // ### Via Stack + usedWireLayer = ""; + int wire_on_stack_via = 0; + for (int n = viaStackS[nV]; n <= viaStackE[nV]; n++) { + cntViaOverLap[n]++; + if (sameL[n]) { + sprintf(s, " %d", n); + usedWireLayer += s; + wire_on_stack_via++; + } + } + if (wire_on_stack_via < 2) { + if (!wire_on_stack_via) { + if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 18\tNur VIA von Layer %d - %d, Signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + viaStackS[nV], viaStackE[nV], + viaStackS[nV], viaStackE[nV], + sigName + ); + + else sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 18\tOnly VIA from layer %d - %d, signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + viaStackS[nV], viaStackE[nV], + viaStackS[nV], viaStackE[nV], + sigName + ); + } + else { + if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tZu wenig WIRE: Nur in Layer %s an VIA von Layer %d - %d geroutet, Signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + usedWireLayer, + usedWireLayer, + viaStackS[nV], viaStackE[nV], + sigName + ); + + else sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tOnly WIRE on layer %s on VIA from layer %d - %d, signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + usedWireLayer, + usedWireLayer, + viaStackS[nV], viaStackE[nV], + sigName + ); + } + cmd += s; + } + } + if (viaL[18]) { // ### check via layer overlap ### + string ViaOverlap = ""; + int cnt; + for (cnt = 1; cnt < 17; cnt++) { + if (cntViaOverLap[cnt] > 1) { + sprintf(s, " %d", cnt); + ViaOverlap += s; + } + } + if (ViaOverlap) { + if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tVIAs Stack-Überlappung in Layer %s, Signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + ViaOverlap, + ViaOverlap, + sigName + ); + + else sprintf(s, "WINDOW (%.4f %.4f);\t %s 18\tVIAs stack overlap on layer %s, signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + ViaOverlap, + ViaOverlap, + sigName + ); + cmd += s; + } + } + return; +} + + +// ### check count of elements on coordinate ### +void check_same(int k, string sigName) { + if (!sameL[17]) { // ### Pads können kein Single-Ended-Wire sein ### + if (viaL[18]) { + check_via(k, sigName); + } + else { + for (int n = 1; n <= 16; n++) { + if (sameL[n]) { + if (sameL[n] + viaL[n] + sameS[n] < 2) { + if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %d \tNur 1 WIRE im Layer %d von Signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + n, n, sigName); + + else sprintf(s, "WINDOW (%.4f %.4f);\t %d \tFew WIRE on layer %d at signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + n, n, sigName); + cmd += s; + } + } + } + } + } + + if (padL[17] && viaL[18]) { + if (language() == "de") sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 17 18\tPAD und VIA an gleicher Koordinate, Signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + ws[index[k]], we[index[k]], + sigName); + else sprintf(s, "WINDOW (%.4f %.4f);\t %d %d 17 18\tPAD and VIA on same coordinate, signal %s\n", + u2mm(wx[index[k]]), u2mm(wy[index[k]]), + ws[index[k]], we[index[k]], + sigName); + cmd += s; + } + return; +} + + + +// check multiple coordinates or one coordinate on this Signal +void checkcoord(string sigName) { + int n = 0; + h = ""; + sort(ncoord, index, wx, wy, wl, wt); // in Order - Coordinates - Layer - Type + n = 0; + clear_same_counter(); + + if (ncoord > 1) { + // ### loop ### + do { + set_layer(wl[index[n]], ws[index[n]], we[index[n]], wt[index[n]]); + if (wx[index[n+1]] == wx[index[n]] && wy[index[n+1]] == wy[index[n]] ) { + n++; + } + else { + check_same(n, sigName); + clear_same_counter(); + n++; + } + } while (n < ncoord); + check_same(n, sigName); + } + else check_same(n, sigName); + return; +} + + +// collect coordinates +void add(int x, int y, int lay, int l_start, int l_end, int type) { + wx[ncoord] = x; + wy[ncoord] = y; + wl[ncoord] = lay; + ws[ncoord] = l_start; + we[ncoord] = l_end; + wt[ncoord] = type; + ncoord++; + return; +} + + +// ### main ### +if (board) { + board(B) { + string trace_file = filesetext(B.name, "~~.sew"); // single endet wire + string memory_file = filesetext(B.name, "~~.mlc"); // memory line counter + + if (!argv[1]) { + dlgMessageBox(usage, "OK"); + B.signals(S) { + status(" check "+S.name); + ncoord = 0; + S.wires(W) { + if (W.layer < 17) { + add(W.x1, W.y1, W.layer, W.layer, W.layer, typeW); + add(W.x2, W.y2, W.layer, W.layer, W.layer, typeW); + } + } + S.contactrefs(C) { + if (C.contact) { // 2011-02-30 first request if a connect. + if (C.contact.smd) { + add(C.contact.x, C.contact.y, C.contact.smd.layer, C.contact.smd.layer, C.contact.smd.layer, typeS); + } + else { + add(C.contact.pad.x, C.contact.pad.y, 17, 1, 16, typeP); + } + + } + else { // 2011-03-30 + dlgMessageBox("Found signal '"+ S.name + "' without contactrefs!\nCheck consistence and corrupted signals!", "OK"); + exit(-1); + } + } + S.vias(V) { + add(V.x, V.y, 18, V.start, V.end, typeV); + } + checkcoord(S.name); + } + output(trace_file, "wtD") printf("%s", cmd); + output(memory_file, "wtD") printf("-1"); + exit("RUN '" + argv[0] + "' +\n"); + } + + // ### trace listed points by key "+" "-" + else { + string m_cmd[]; + int n = fileread(m_cmd, memory_file); // memory line counter + int cnt = strtol(m_cmd[0]); + string lines[]; + n = fileread(lines, trace_file); // single endet wire + + if (!n) { + dlgMessageBox("No single ended WIRE found!", "OK"); + exit(0); + } + + else if (argv[1] == "+" || argv[1] == "-" || argv[1] == "=" || strupr(argv[1]) == "M") { + if (argv[1] == "+") { + if (cnt < n-1) cnt++; + else { + if (language() == "de") dlgMessageBox("Letze Position!", "OK"); + else dlgMessageBox("The last position in list!", "OK"); + } + } + else if (argv[1] == "-") { + if(cnt) cnt--; + else { + if (language() == "de") dlgMessageBox("Erste Position!", "OK"); + else dlgMessageBox("The first position in list!", "OK"); + } + } + else if (strupr(argv[1]) == "M") { + n = strsplit(cmdr, lines[cnt], '('); + string Display = ""; + n = strsplit(m_cmd, cmdr[1], ')'); + n = strsplit(cmdr, m_cmd[0], ' '); + real x = strtod(cmdr[0]); + real y = strtod(cmdr[1]); + sprintf(Display, "GROUP (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (>%.4f %.4f);\nMOVE (>%.4f %.4f)", + x-0.0001, y-0.0001, + x+0.0001, y-0.0001, + x+0.0001, y+0.0001, + x-0.0001, y+0.0001, + x-0.0001, y-0.0001, + x, y + ); + exit(Display); + } + else if (argv[1] == "="); + } + + else { + if (language() == "de") dlgMessageBox("Unbekannter Parameter!", "OK"); + else dlgMessageBox("Unknown parameter!", "OK"); + exit(0); + } + + n = strsplit(cmdr, lines[cnt], '\t'); + string Display = ""; + if (m_cmd[1] != cmdr[1]) { + sprintf(Display, "DISPLAY NONE %s ;\n", cmdr[1]); + } + output(memory_file, "wtD") printf("%d\n%s", cnt, m_cmd[1]); // save the last pointer + exit("GRID mm;\n"+Display+cmdr[0]+"RUN ulpmessage '"+cmdr[2]+"';"+"MOVE"); // activate th move command + } + } +} + +else { + if (language() == "de") dlgMessageBox("Starten Sie das ULP in einem Board", "OK"); + else dlgMessageBox("Start this ULP in a Board", "OK"); +} \ No newline at end of file diff --git a/trunk/ulp/find.ulp b/trunk/ulp/find.ulp new file mode 100644 index 00000000..bce1219e --- /dev/null +++ b/trunk/ulp/find.ulp @@ -0,0 +1,1282 @@ +#usage "en: nobrFind elements in schematic/board and zoom in\n" + "

    " + "Centers the object and zooms into the drawing." + "

    " + "

    You can also run this ULP from the command line:

    " + "Usage: RUN find [ name [ pin | pad | [value [current_value [CH new_value]] [ count | * ]]" + "

    " + "RUN find
    " + "RUN find name
    " + "RUN find name [counter]
    " + "RUN find [DEV | GATE | PIN | PAD | POLYGON width | DRILL diameter | VIA stack | value [-S|+|-] [counter | *]] **
    " + "RUN find DRILL diameter [counter | *] **
    " + "RUN find VALUE current_value CH new_value [counter]
    " + "RUN find value -S
    " + "RUN find value + | - (step option)
    " + "" + "Search string is the name of the Device/Package/Net/Bus/Pin/Pad/Signal/Value

    " + "counter specifies the number of elements that shall be found before ending the search
    " + "* sets the counter to 1000

    " + "PIN | PAD | DEV | GATE additionally searches for PIN, PAD, GATE, DEVICE names
    " + "GATE without a given name, places the foremost found, unused gate
    " + "GATE * lists all unused gates, select one of them to place it
    " + "VIA start end searches for blind, buried, and micro vias with a certain length
    " + "VALUE value CHvalue replaces the value of an element with the given new one, if found (CH is case sensitive)
    " + "value -S displays all elements with the same value at the same time (highlighted like with SHOW), in BRD only
    " + "value - + shows step by step the previous or next found element, in BRD and SCH
    " + "


    " + "Searching order:
    " + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
    Schematic: Board:
    1. Part name 1. Element
    2. Net name 2. Signal/Wires/Vias
    3. Bus name 3. Pads
    4. Value 4. ValueSearching for values is not case sensitive.
    5. Device ** 5. Polygon width **
    6. Gate ** 6. Drill
    7. Pin ** 7. Via stack
    8. Pad **
    9. Text
    " + "** Device name, Gate name, Pin name, Pad name, Polygon width, or Drill diameter will be searched, if one of the options DEV, GATE, PIN, PAD, POLYGON or DRILL is given.

    " + "" + "In the symbol editor you can search for PIN names, in the package editor you can search for PAD/SMD names
    " + "Author: support@cadsoft.de" + , + "de: Findet Elemente in Schaltplan und Board
    " + "

    " + "Zoomt das gefundene Element in die Fenstermitte" + "

    " + "

    Sie können das ULP auch aus der Kommandozeile starten mit:

    " + "RUN find [ name [ pin | pad | value [aktueller_value [CH neuer_value]] [ count | * ]]" + "
    " + "RUN find
    " + "RUN find name
    " + "RUN find name [Zähler]
    " + "RUN find [DEV | GATE | PIN | PAD | POLYGON width | DRILL diameter | VIA stack | value [-S|+|-] [Zähler | *]] **
    " + "RUN find DRILL Durchmesser [Zähler | *] **
    " + "RUN find VALUE alter_value CH neuer_value [Zähler]
    " + "RUN find value -S
    " + "RUN find value + | - (Step-Option)
    " + "
    " + "Suchbegriff ist der name des Device/Package/Net/Bus/Pin/Pad/Signal/Value
    " + "Zähler legt die Anzahl der gefundenen Elemente fest, nach der die Suche beendet wird
    " + "* setzt den Zähler auf 1000
    " + "PIN | PAD | DEV | GATE sucht zusätzlich nach PIN-, PAD-, GATE-, DEVICE-Namen
    " + "GATE ohne Namen, platziert das zuerst gefundene, nicht benutzte Gate.
    " + "GATE * listet alle nicht benutzen Gates; das aus der Liste gewählte Gate wird plaziert.
    " + "VIA start end sucht Blind- Buried- und Micro-Via einer bestimmten Länge
    " + "VALUE value CH value ersetzt den Value des gefundenen Elements (CH beachtet die Gross-/Klein-Schreibung)
    " + "value -S zeigt alle Elemente mit gleichen Values gleichzeitig (gehighlightet wie bei SHOW), nur in BRD.
    " + "- + zeigt die gefundenen Elemente Schritt für Schritt (+ vor, - zurück), in BRD und SCH
    " + "


    " + "Such-Reihenfolge:
    " + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" // 2013-07-02 + "" + "
    Schematic: Board:
    1. Part name 1. Element
    2. Net name 2. Signal/Wires/Vias
    3. Bus name 3. Pads
    4. Value 4. ValueKeine Unterscheidung der Groß-/Kleinschreibung.
    5. Device ** 5. Polygon width **
    6. Gate ** 6. Drill
    7. Pin ** 7. Via stack
    8. Pad ** 8. Roundness
    9. Text
    " + "** nach Device-, Gate-, Pin-, Pad-Namen, Polygon-Width und Drill-Durchmesser wird gesucht, falls DEV, GATE, PIN, PAD, POLYGON oder DRILL gesetzt ist.
    " + "
    " + "Im Symbol-Editor kann nach Pin-Name, im Package-Editor kann nach Pad/Smd-Name gesucht werden.

    " + "Author: support@cadsoft.de"; + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + + +// Version 1.1 2005.06.15 - CH : search and replace Value / Suchen und ersetzen das Value alf@cadsoft.de +// Zuweisung von Vfind berichtigt, es konnten nur Values mit Großschreibung gefunden werden. +// durchsuchen von Netz-Namen in Bussen berichtigt. +// Version 1.2 2005.07.19 - Search also in Polygon - contour - wire +// +// Version 1.3 2005.11.14 - Search Part_Name +// +// Version 1.4 2006.04.25 - Show all parts with same Value in Board +// +// Version 1.5 2006.05.08 - Clip zoom coordinate for show to maximum +// +// Version 1.6 2006.09.26 - Find also (Device+)GATE-name +// +// Version 1.7 2006.11.09 - +/- Trace step by step with value +// ein neuer Suchbegriff setzt den Trace-counter auf 0 +// +// Version 1.8 2007.02.13 - Find Net without Segment-Wire, but with Pinref +// +// Version 1.9 2007.02.23 - Find Polygons with Wire-Width +// Zuweisung von Vfind als Kommadozeileneingabe berichtigt +// In Bus-Namen werden jetzt auch Netze in der Schreibweise "D[0..7],A[0..15]" gefunden +// Falls der Layer des gefundenen Element nicht Visible ist wird er eingeschaltet +// +// Version 2.0 2007.04.23 - Find Drills (Pad, Via, Hole - Diameter) +// GATE +// VIA stack, sucht Vias von Layer bis Layer +// +// Version 2.1 2007.06.27 - Erst die Anzahl der gefundenen Elemente anzeigen, dann mit SHOW markieren, +// damit man anschliessend mit WINDOW bzw. Scroll-Rad zoomen kann ohne daß die +// Markierung (highlighten) aufgehoben wird. +// Abfrage des Zähler argc für die zu suchende Anzahl berichtigt. +// +// Version 2.2 2007.07.05 - Hilfe in #usage en: de: integriert. +// +// Version 2.3 2007.10.16 - Find PIN in Symbol +// - Find PAD/SMD in Package +// +// Version 2.4 2008.06.10 - Window-Befehl für SCH angepasst, +// Zoomfenster in SCH über Area berechnet +// Zähler für Option PAD/PIN/DEV berichtigt +// require 5.0.1 +// +// Version 2.5 2010.09.03 - Suche auch in TEXTen +// +// Version 2.6 2013.07.02 - Suche nach Roundness bei SMD +// +// Version 2.7 2013.11.25 - Option Change Value berichtigt run find oldvalue CH newvalue * +// +// Version 2.8 2014.03.21 - corrected option -S +// + +#require 5.1200; +string Version = "Version 2.8"; +string Find; +string Vfind; +string NewValue; +int Change_Value = 0; +string Again; +string Fpin; +string FndPin = "Element"; +string foundelement = ""; + +enum { sNull, sPin, sPad, sDevice, sGate, sValue }; +string SCHfPinPad[] = { "", "PIN", "PAD", "DEV", "GATE", "VALUE"}; + +enum { bNull, bPad, bValue, bPolygon, bDrill, bVia, bRoundness }; +string BRDfPinPad[] = { "", "PAD", "VALUE", "POLYGON", "DRILL", "VIA", "ROUNDNESS" }; + // for "POLYGON", "DRILL", "VIA" see also function returnfind() and function show_B() + +string Invoke[] ; // invoke list of not placed gates + +int Vstart; +int Vend; + +int Fcnt = 0; +int CntStep = 0; +string StepFile = ""; +int all; +int cnt; +int StepMode = 0; // for trace vorward/backward of elements for show +int Result; +real lastZoom = 0; +int lastSheet = 0; +real PolyWidth = 0; +real DrillDiam = 0; +int Roundness = 0; + +int OptShow = 0; // Only board. Option to manually placing 2006.04.25 +int display_layer[]; + + +int test = 0; + +string fileName = argv[0]; +string scriptfile = filesetext(fileName, "$$$.scr"); + +int gridunit; +string unit[] = { "Micron", "mm", "Mil", "Inch" }; + +string repeat = ""; + +// ### Functions ### +real u2u(int val) { + switch (gridunit) { + case GRID_UNIT_MIC : return u2mic(val); + case GRID_UNIT_MM : return u2mm(val); + case GRID_UNIT_MIL : return u2mil(val); + case GRID_UNIT_INCH : return u2inch(val); + } +} + +string dpbacksl(string fs) { + int l = 0; + do { + if (fs[l] == '\\') { + string fs1 = strsub(fs, 0 , l + 1); + string fs2 = strsub(fs, l + 1 ); + fs = fs1 + "\\" + fs2; + l += 2; + } + l++; + } while (fs[l]); + return fs; +} + + +string check_layer(void) { + board(B) { + B.layers(L) { + display_layer[L.number] = L.visible; + string s; + if (L.number == 21 || L.number == 22 || L.number == 25 || L.number == 26 || L.number == 27 || L.number == 28 || L.number == 51 || L.number == 52 ) { + if (L.visible) return "DISPLAY NONE 21 -23 25 27 51 22 -24 26 28 52;\n"; // display only Top layer + } + else if (L.visible) return "DISPLAY NONE 21 -23 25 27 51 22 -24 26 28 52;\n"; // display only Top layer + } + } + return ""; +} + + +void showrepeat(string text) { + dlgDialog("FIND.ULP") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(300); + dlgTextEdit(text); + } + dlgHBoxLayout { + dlgPushButton("+&OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + + +string returnfind(void) { + string rs; + if (!Fpin) FndPin = "Element"; + + if (Fpin == "POLYGON") sprintf(rs, "run ulpmessage.ulp '%d %s found!';\n", Fcnt, FndPin); + else if (Fpin == "DRILL") sprintf(rs, "run ulpmessage.ulp '%d %s found!';\n", Fcnt, FndPin); + else if (Fpin == "VIA") sprintf(rs, "run ulpmessage.ulp '%d %s found!';\n", Fcnt, FndPin); + else if (Fpin == "ROUNDNESS") sprintf(rs, "run ulpmessage.ulp '%d %s found!';\n", Fcnt, FndPin); + else if (StepMode){ + if (StepMode == Fcnt) exit(repeat); + else repeat = ""; // no message while step mode + return ""; + } + else sprintf(rs, "run ulpmessage.ulp '%d %s(s) %s found!' '%s';\n", Fcnt, FndPin, Find, foundelement); // 2007.03.23 alf + + if (Find) { + if (CntStep) { + if (CntStep > Fcnt) { + output(StepFile, "wt") printf("%d\n%s\n%d", Fcnt, Vfind, CntStep); // write actual counter in file + } + else return ""; // for Trace step by step disply no message + } + } + return dpbacksl(rs); +} + + +void check(string repeat) { + if (OptShow) { + if (test) showrepeat(repeat); + if (Fcnt) { + exit(repeat); + } + return; + } + repeat = returnfind() + repeat; + if (test) showrepeat(repeat); + exit (repeat); // first messagebox than show 2007.06.27 alf +} + + +void helpULP(void) { + dlgDialog("find.ulp") { + dlgHBoxLayout dlgSpacing(550); + dlgLabel(usage); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + + +string getfind() { + real Dmin = 0.0, Dmax = u2u(13100); + string f; + all = 0; + int sel_m = 0; + int findpoly = 0; + Result = dlgDialog("Find Element") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgHBoxLayout { + dlgLabel("&Name "); + dlgStringEdit(f); + dlgLabel(" (Value) "); + dlgSpacing(30); + dlgStretch(1); + dlgPushButton("&Help") helpULP(); + } + dlgHBoxLayout { + dlgLabel("&Counts"); + dlgIntEdit(all, 0, 10000); + dlgSpacing(200); + dlgStretch(1); + dlgLabel(Version); + dlgSpacing(12); + } + dlgHBoxLayout { + if (schematic) { + dlgGroup("Find options") { + dlgRadioButton("&...", sel_m) Fpin = ""; + dlgRadioButton("P&IN", sel_m) { Fpin = "PIN"; } + dlgRadioButton("P&AD", sel_m) { Fpin = "PAD"; } + dlgRadioButton("&DEV", sel_m) { Fpin = "DEV"; } + dlgRadioButton("&GATE", sel_m) { Fpin = "GATE"; } + dlgHBoxLayout { + dlgRadioButton("&VALUE", sel_m) Fpin = ""; + dlgSpacing(22); + dlgCheckBox(" &change to ", Change_Value); + dlgLabel(" Val&ue "); + dlgStringEdit(NewValue); + dlgStretch(1); + } + } + } + if (board) { + dlgGroup("Find options") { + dlgRadioButton("&...", sel_m) Fpin = ""; + dlgRadioButton("P&AD", sel_m) Fpin = "PAD"; + dlgHBoxLayout { + dlgRadioButton("&VALUE", sel_m) Fpin = ""; + dlgSpacing(12); + dlgCheckBox(" &change to", Change_Value) if (Change_Value) OptShow = 0; + dlgLabel("Val&ue "); + dlgStringEdit(NewValue); + dlgSpacing(12); + dlgCheckBox("Sh&ow all ", OptShow) if (OptShow) Change_Value = 0; + dlgSpacing(132); + } + dlgHBoxLayout { + dlgRadioButton("POL&YGON", sel_m) Fpin = "PPOLYGON"; + dlgSpacing(70); + dlgLabel(" &Width "); + dlgRealEdit(PolyWidth, 0, 10000); + dlgSpacing(90); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("&DRILL", sel_m) Fpin = "DRILL"; + dlgSpacing(73); + dlgLabel(" Diamete&r "); + dlgRealEdit(DrillDiam, Dmin, Dmax); + dlgSpacing(90); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("V&IA layer stack", sel_m) Fpin = "VIA"; + dlgSpacing(45); + dlgLabel(" &Start "); + dlgIntEdit(Vstart, 0, 16); + dlgSpacing(12); + dlgLabel(" &End "); + dlgIntEdit(Vend, 0, 16); + dlgSpacing(90); + dlgStretch(1); + } + dlgHBoxLayout { + dlgRadioButton("&ROUNDNESS", sel_m) Fpin = "ROUNDNESS"; + dlgSpacing(72); + dlgLabel(" &% "); + dlgIntEdit(Roundness, 0, 100); + dlgSpacing(250); + dlgStretch(1); + } + } + dlgStretch(1); + } + } + dlgStretch(0); + dlgHBoxLayout { + dlgPushButton("+&Find") { + dlgAccept(); + all--; + } + dlgStretch(1); + dlgPushButton("-Cancel") { dlgReject(); exit(-1); } + } + dlgStretch(1); + } + } + }; + if (!f && Fpin == "GATE") f = "0"; + return f; +} + + +real clip_zoom(real v) { // clip value to max. coordinate 2006.05.08 + switch (gridunit) { + case GRID_UNIT_MIC : if (v > 838200) return 838200; + if (v < -838200) return -838200; + break; + case GRID_UNIT_MM : if (v > 838.2) return 838.2; + if (v < -838.2) return -838.2; + break; + case GRID_UNIT_MIL : if (v > 33000.0) return 33000; + if (v < -33000.0) return -33000; + break; + case GRID_UNIT_INCH : if (v > 33.0) return 33; + if (v < -33.0) return -33; + break; + } + return v; +} + + +// #### make script line for show in board #### +string show_B(real x, real y, real zoom1, real zoom2, string findb, int fist, int layer) { + Fcnt++; + string cmd = ""; + string cmd_show; + + if (findb[0] == '(') sprintf(cmd_show, "SHOW %s ", findb); // 2010.09.03 alf bei TEXTen Koordinate benutzen + else if (OptShow)sprintf(cmd_show, " '%s' ", findb); // 2014.03.21 corrected option -S + else sprintf(cmd_show, ";SHOW '%s' ", findb); // 2007.06.27 alf + + if (Fpin == "PAD") cmd_show = ""; // can not show pads + if (Fpin == "POLYGON") sprintf(cmd_show, ";SHOW (%.4f %.4f);\n", x, y); // do not show polygons + // ### can not show drills ### + if (Fpin == "DRILL") cmd_show = ""; // do not change this line + // ### can not show vias, only complete signal ### + if (Fpin == "VIA") { cmd_show = ""; layer = 0; } // do not change this line + if (Fpin == "ROUNDNESS") { cmd_show = "";} // do not change this line 2013-07-02 + + if (OptShow) { + sprintf(cmd, "%s", cmd_show); + } + else { + if (lastZoom) { + if (StepMode) { + sprintf(cmd, "\n;WINDOW (%.6f %.6f) ;\n%s", + x, y, + cmd_show + ); + } + else { + sprintf(cmd, "\n;WINDOW (%.6f %.6f) (%.6f %.6f) (%.6f %.6f);\n%s;\n", + x, y, + x, y, + x, y, + cmd_show + ); + } + } + else { + if (StepMode) { + sprintf(cmd, + ";\nWINDOW (%.6f %.6f);\n%s", + x, y, + cmd_show + ); + } + else { + sprintf(cmd, ";WINDOW FIT;\n" + ";WINDOW (%.6f %.6f) (%.6f %.6f) (%.6f %.6f);\n%s", + x, y, + clip_zoom(x + zoom1), y, + clip_zoom(x + zoom2), y, + cmd_show + ); + lastZoom = zoom2; + } + } + } + if (Change_Value) { // 2013-10-24 + string chval; + sprintf(chval, "; VALUE %s '%s';\n", findb, NewValue); + cmd += chval; + } + + if (!display_layer[layer] && layer != 0) { + sprintf(cmd_show, "DISPLAY %d;\n%s", layer, cmd); + cmd += cmd_show; + } + if (Fpin == "VIA") { + sprintf(cmd_show, "DISPLAY %d %d 18;\n", Vstart, Vend); + cmd += cmd_show; + } + if (Fpin == "ROUNDNESS") { // 2013-07-02 + sprintf(cmd_show, "DISPLAY 1 16;\n"); + cmd += cmd_show; + } + return cmd; +} + + +// #### make script line for show in schematic #### +string show_S(int s, real x1area, real y1area, real x2area, real y2area, string finds) { + Fcnt++; + string cmd_show; + if (finds[0] == '(') sprintf(cmd_show, ";SHOW %s ", finds); // 2010.09.03 alf Bei TEXTen kann nur die Koordinate benutzt werden + else sprintf(cmd_show, "\n;SHOW '%s' ", finds); // 2007.06.27 alf + + string cmd = ""; + if (s != lastSheet) { + lastSheet = s; + if (StepMode) { + sprintf(cmd, ";\nEDIT .s%d;\nWINDOW (%.6f %.6f) (%.6f %.6f);\n%s", s, + x1area, y1area, + x2area, y2area, + cmd_show + ); + } + else { + sprintf(cmd, ";\nEDIT .s%d;\nWINDOW (%.6f %.6f) (%.6f %.6f);\n%s", s, + x1area, y1area, + x2area, y2area, + cmd_show + ); + } + } + else { + if (StepMode) { + sprintf(cmd, ";\nWINDOW (%.6f %.6f) (%.6f %.6f);\n%s", s, + x1area, y1area, + x2area, y2area, + cmd_show + ); + } + else { + sprintf(cmd, ";\nEDIT .s%d;\nWINDOW (%.6f %.6f) (%.6f %.6f);\n%s", s, + x1area, y1area, + x2area, y2area, + cmd_show + ); + } + } + if (Change_Value) { // 2013-10-24 + string chval; + sprintf(chval, "; VALUE %s '%s';\n", finds, NewValue); + cmd += chval; + } + if (StepMode) { + if (CntStep != Fcnt) cmd = ""; + } + return cmd; +} + + +real zfactor(real x1, real y1, real x2, real y2) { + return sqrt( pow(x2 - x1, 2) + pow(y2 - y1, 2) ); +} + + + +// *** split bus-name from net-name *** +int findBus(string name, string sfind) { + string bn[]; + int b; + b = strsplit(bn, name, ':'); + string nn[]; + if (b == 2) { + b = strsplit(nn, bn[1], ','); + } + else { + b = strsplit(nn, name, ','); + } + for (int x = 0; x < b; x++) { + if(nn[x] == sfind) return 1; + } + // *** search for name[n..n] *** + string nm; + for (x = 0; x < b; x++) { + int pos1 = strchr(nn[x], '['); + int pos2 = strchr(nn[x], '.'); + int pos3 = strchr(nn[x], ']'); + string Pref = strsub(nn[x], 0 , pos1); + string n1 = strsub(nn[x], pos1+1, pos2-pos1-1); + string n2 = strsub(nn[x], pos2+2, pos3-pos2-2); + for (int n = strtol(n1); n <= strtol(n2); n++) { + sprintf(nm, "%s%d", Pref, n); + if (nm == sfind) return 1; + } + } + return 0; +} + + + +// *** trace elemete step by step *** +string get_step(int step) { + StepMode = 1; + CntStep = 0; + string s = ""; + string lastvalue; + StepFile = filesetext(argv[0], ".stp"); + string sf[]; + int isfile = fileglob(sf, StepFile); + if (isfile) { + string t[]; + int ct = fileread(t, StepFile); + CntStep = strtod(t[0]); + if (Vfind != t[1]) CntStep = 0; + } + CntStep += step; + if (CntStep < 1) { + CntStep = 1; + dlgMessageBox("!This is the first Element", "OK"); + } + output(StepFile, "wt") printf("%d\n%s", CntStep, Vfind); // write actual counter in file + sprintf(s, "%d", CntStep); + return s; +} + + +string get_invoke(void) { + int sel; + int Result = dlgDialog("Invoke unused gates") { + dlgListView("Gates to Invoke", Invoke, sel) { dlgAccept(); return Invoke[sel]; } + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + }; + if (Result) return Invoke[sel]; + return ""; +} + + + +// ****** Main ****** + +Vfind = argv[1]; +if (argc > 2) Again = strupr(argv[argc-1]); // 2007.06.27 alf +if (argv[2] == "+") { Again = get_step(1); StepMode = strtod(Again); } +if (argv[2] == "-") { Again = get_step(-1); StepMode = strtod(Again); } + +if (symbol) symbol(S) { // 2007.10.16 + Vfind = strupr(argv[1]); + if (!Vfind) { + dlgMessageBox(usage + "
    " + Version); + exit(0); + } + library(L) gridunit = (L.grid.unit); + S.pins(P) { + if (P.name == Vfind) { + sprintf(Vfind, "WIN (%.4f %.4f);", u2u(P.x), u2u(P.y) ); + exit(Vfind); + } + } + exit("run ulpmessage.ulp '" + Vfind + " not found!';\n"); +} + +else if (package) package(P) { // 2007.10.16 + Vfind = strupr(argv[1]); + if (!Vfind) { + dlgMessageBox(usage + "
    " + Version); + exit(0); + } + library(L) gridunit = (L.grid.unit); + P.contacts(C) { + if (C.name == Vfind) { + sprintf(Vfind, "WIN (%.4f %.4f);", u2u(C.x), u2u(C.y) ); + exit(Vfind); + } + } + exit("run ulpmessage.ulp '" + Vfind + " not found!';\n"); +} + +else if (schematic) { + if ( strupr(argv[1]) == SCHfPinPad[1]) { Fpin = SCHfPinPad[1]; Vfind = argv[2]; } // "PIN" + else if ( strupr(argv[1]) == SCHfPinPad[2]) { Fpin = SCHfPinPad[2]; Vfind = argv[2]; } // "PAD" + else if ( strupr(argv[1]) == SCHfPinPad[3]) { Fpin = SCHfPinPad[3]; Vfind = argv[2]; } // "DEV" + else if ( strupr(argv[1]) == SCHfPinPad[4]) { // "GATE" + Fpin = SCHfPinPad[4]; + Vfind = argv[2]; + if (!Vfind) { // found Gates are not placed in schematic + Vfind = "0"; + } + } + else if ( strupr(argv[1]) == SCHfPinPad[5]) { Fpin = SCHfPinPad[5]; Vfind = argv[2]; } // "VALUE" + if (argc > 2) Again = strupr(argv[argc-1]); + else Again = ""; +} + +else if (board) { + if ( strupr(argv[1]) == BRDfPinPad[bPad]) { Fpin = BRDfPinPad[bPad]; Vfind = argv[2]; } // "PAD" + else if ( strupr(argv[1]) == BRDfPinPad[bValue]) { Fpin = BRDfPinPad[bValue]; Vfind = argv[2]; } // "VALUE" + else if ( strupr(argv[1]) == BRDfPinPad[bPolygon]) { // "POLYGON" + Fpin = BRDfPinPad[bPolygon]; + Find = BRDfPinPad[bPolygon]; + PolyWidth = strtod(argv[2]); + if (argc > 3) Again = strupr(argv[argc-1]); + else Again = ""; + } + else if ( strupr(argv[1]) == BRDfPinPad[bDrill]) { // "DRILL" + Fpin = BRDfPinPad[bDrill]; + Find = BRDfPinPad[bDrill]; + DrillDiam = strtod(argv[2]); + if (argc > 3) Again = strupr(argv[argc-1]); + else Again = ""; + } + else if ( strupr(argv[1]) == BRDfPinPad[bVia]) { // "VIA" + Fpin = BRDfPinPad[bVia]; + Find = BRDfPinPad[bVia]; + Vstart = strtod(argv[2]); + Vend = strtod(argv[3]); + if (argc > 4) Again = strupr(argv[argc-1]); + else Again = ""; + } + else if ( strupr(argv[1]) == BRDfPinPad[bRoundness]) { // "ROUNDNESS" 2013-07-02 + Fpin = BRDfPinPad[bRoundness]; + Find = BRDfPinPad[bRoundness]; + Roundness = strtol(argv[2]); + if (argc > 3) Again = strupr(argv[argc-1]); + else Again = ""; + } +} + +else { + if (language() == "de") dlgMessageBox("Starten Sie dieses ULP in einem Schaltplan, Board, Symbol oder Package Editor", "OK"); + else dlgMessageBox("Start this ULP in Schematic, Board, Symbol or Package Editor", "OK"); + exit(0); +} + +if (argv[3] == "CH") { + Change_Value = 1; + NewValue = argv[4]; +} + + +if (Again == "*") all = 1000; +else all = strtol(Again) - 1; + +if (!Vfind) { + Vfind = getfind(); +} + +if (Change_Value) Find = Vfind; // 2013-11-25 +else Find = strupr(Vfind); +if (!Find && Change_Value) exit (0); +cnt = all + 1; + +if (!Fpin && !Find) { + dlgMessageBox("Missing options", "OK"); + exit(-1); +} + + +// *** Board coord. *** +if (board) { + int mx, my; // 2008.06.10 alf + if (argv[2] == "-S") OptShow = 1; // Show option 2006.04.25 + board(B) { + gridunit = (B.grid.unit); + if (OptShow) { + all = 10000; + repeat = check_layer(); + repeat += ";SHOW;\nWIN;\nSHOW "; // refresh window clear showed elements // 2007.06.27 alf + } + + mx = B.area.x2 + (B.area.x1 * -1); + my = B.area.y2 + (B.area.y1 * -1); + if (Vfind) { + B.elements(E) { + if (E.value == Vfind || E.value == Find) { + FndPin = "Value"; + if (StepMode && all > 0) { + ; // do nothing + } + else { + repeat += show_B(u2u(E.x), u2u(E.y), 2, 5, E.name, all, E.mirror); + sprintf(foundelement, "Element %s on (%.4f %.4f)", E.name ,u2u(E.x), u2u(E.y) ); + } + if (all <= 0) check(repeat); + all--; + } + } + } + if (!Fpin && Find) { + B.elements(E) { + if (E.name == Find) { + FndPin = "Element"; + repeat += show_B(u2u(E.x), u2u(E.y), 2, 5, Find, all, E.mirror); + sprintf(foundelement, "Element %s on (%.4f %.4f)", E.name, u2u(E.x), u2u(E.y) ); + check(repeat); + } + } + B.signals(S) { + if (S.name == Find) { + S.contactrefs(C) { + if (C.contact) { // 2011-02-30 first request if a connect. + FndPin = "Signal"; + repeat += show_B(u2u(C.contact.x), u2u(C.contact.y), 2, 5, Find, all, 0); // 0 = dummy for Layer + if (all <= 0) check(repeat); + all--; + } + else { + dlgMessageBox("Found signal '"+S.name+ "' without contactref!\nCheck consistence and corrupted signals.", "OK"); + exit(-1); + } + } + } + } + B.signals(S) { + if (S.name == Find ) { + S.wires(W) { + FndPin = "Wire"; + real z = zfactor(u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2) ); + repeat += show_B( u2u((W.x1 + W.x2)/2), u2u((W.y1 + W.y2)/2), z/(z/2) , z/(z/5), Find, all, W.layer); + if (all <= 0) check(repeat); + all--; + } + } + } + B.signals(S) { + if (S.name == Find ) { + S.polygons(P) { + FndPin = "Polygon"; + P.contours(W) { + real z = zfactor(u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2) ); + repeat += show_B( u2u((W.x1 + W.x2)/2), u2u((W.y1 + W.y2)/2), z/(z/2) , z/(z/5), Find, all, W.layer); + if (all <= 0) check(repeat); + all--; + break; + } + } + } + } + B.signals(S) { + if (S.name == Find ) { + S.vias(V) { + FndPin = "Via"; + repeat += show_B(u2u(V.x), u2u(V.y), 1, 5, Find, all, 18); // 18 dummy layer for via + sprintf(foundelement, "Element on (%.4f %.4f) %s
    VIA
    LayerDiameterRestring
    Top%.4f%.4f
    Inner%.4f%.4f
    Bottom%.4f%.4f
    Drill%.4f
    ", + u2u(V.x), u2u(V.y), + unit[gridunit], + u2u(V.diameter[1]), + u2u( (V.diameter[1] - V.drill) / 2), + u2u(V.diameter[2]), + u2u( (V.diameter[2] - V.drill) / 2), + u2u(V.diameter[16]), + u2u( (V.diameter[16] - V.drill) / 2), + u2u(V.drill) ); + if (all <= 0) check(repeat); + all--; + } + } + } + } + B.elements(E) { + if (Fpin == BRDfPinPad[bPad]) { // "PAD" + E.package.contacts(C) { + if (C.pad) { + if (C.pad.name == Find) { + FndPin = "Pad/Smd"; + repeat += show_B(u2u(C.pad.x), u2u(C.pad.y), 2, 5, E.name, all, E.mirror); + sprintf(foundelement, "
    PAD %s on (%.4f %.4f) %s [Element %s]
    LayerDiameterRestring
    Top%.4f%.4f
    Inner%.4f%.4f
    Bottom%.4f%.4f
    Drill%.4f
    ", + C.pad.name, + u2u(C.pad.x), u2u(C.pad.y), + unit[gridunit], + E.name, + u2u(C.pad.diameter[1]), + u2u( (C.pad.diameter[1] - C.pad.drill) / 2), + u2u(C.pad.diameter[2]), + u2u( (C.pad.diameter[2] - C.pad.drill) / 2), + u2u(C.pad.diameter[16]), + u2u( (C.pad.diameter[16] - C.pad.drill) / 2), + u2u(C.pad.drill) ); + if (all <= 0) check(repeat); + all--; + } + } + if (C.smd) { + if (C.smd.name == Find) { + FndPin = "Pad/Smd"; + repeat += show_B(u2u(C.smd.x), u2u(C.smd.y), 2, 5, E.name, all, E.mirror); + sprintf(foundelement, "
    SMD %s on (%.4f %.4f) %s [Element %s]", + C.smd.name, + u2u(C.smd.x), u2u(C.smd.y), + unit[gridunit], + E.name ); + if (all <= 0) check(repeat); + all--; + } + } + } + } + } + + if (Fpin == BRDfPinPad[bPolygon]) { // "POLYGON" + B.signals(S) S.polygons(P) { + if (PolyWidth == u2u(P.width)) { + FndPin = "Polygon"; + P.contours(W) { + sprintf(FndPin, " Polygon with WIRE-Width %.4f", PolyWidth); + repeat += show_B(u2u(W.x1), u2u(W.y1), 2, 5, S.name, all, P.layer); + sprintf(foundelement, "
    POLYGON in Layer %d on (%.4f %.4f) %s", + P.layer, + u2u(W.x1), u2u(W.y1), + unit[gridunit] ); + break; + } + if (all <= 0) check(repeat); + all--; + } + } + B.polygons(P) { + if (PolyWidth == u2u(P.width)) { + FndPin = "Polygon"; + P.contours(W) { + sprintf(FndPin, " Polygon with WIRE-Width %.4f", PolyWidth); + repeat += show_B(u2u(W.x1), u2u(W.y1), 2, 5, "POLYGON", all, P.layer); + sprintf(foundelement, "
    POLYGON in Layer %d on (%.4f %.4f) %s", + P.layer, + u2u(W.x1), u2u(W.y1), + unit[gridunit] ); + break; + } + if (all <= 0) check(repeat); + all--; + } + } + } + if (Fpin == BRDfPinPad[bDrill]) { // "DRILL" + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + if (u2u(C.pad.drill) == DrillDiam) { + sprintf(FndPin, " Drill %.4f", DrillDiam); + repeat += show_B(u2u(C.x), u2u(C.y), 1, u2u(B.area.x2 - B.area.x1)/DrillDiam/10, "DRILL", all, 17); + sprintf(foundelement, "
    Drill %.4f on (%.4f %.4f) %s", + DrillDiam, u2u(C.x), u2u(C.y), unit[gridunit]); + if (all <= 0) check(repeat); + all--; + } + } + } + E.package.holes(H) { + if (u2u(H.drill) == DrillDiam) { + sprintf(FndPin, " Drill %.4f", DrillDiam); + repeat += show_B(u2u(H.x), u2u(H.y), 1, u2u(B.area.x2 - B.area.x1)/DrillDiam/10, "DRILL", all, 45); + sprintf(foundelement, "
    Hole %.4f on (%.4f %.4f) %s", + DrillDiam, u2u(H.x), u2u(H.y), unit[gridunit]); + if (all <= 0) check(repeat); + all--; + } + } + } + B.signals(S) { + S.vias(V) { + if (u2u(V.drill) == DrillDiam) { + sprintf(FndPin, " Drill %.4f", DrillDiam); + repeat += show_B(u2u(V.x), u2u(V.y), 1, u2u(B.area.x2 - B.area.x1)/DrillDiam/10, "DRILL", all, 18); + sprintf(foundelement, "
    Dril %.4f in Via on (%.4f %.4f) %s", + DrillDiam, u2u(V.x), u2u(V.y), unit[gridunit]); + if (all <= 0) check(repeat); + all--; + } + } + } + B.holes(H) { + if (u2u(H.drill) == DrillDiam) { + sprintf(FndPin, " Drill %.4f", DrillDiam); + repeat += show_B(u2u(H.x), u2u(H.y), 1, u2u(B.area.x2 - B.area.x1)/DrillDiam/10, "DRILL", all, 45); + sprintf(foundelement, "
    Hole %.4f on (%.4f %.4f) %s", + DrillDiam, u2u(H.x), u2u(H.y), unit[gridunit]); + if (all <= 0) check(repeat); + all--; + } + } + } + if (Fpin == BRDfPinPad[bVia]) { // "VIA" + B.signals(S) { + sprintf(FndPin, "VIA stack %d-%d", Vstart, Vend); + S.vias(V) { + if (V.start == Vstart && V.end == Vend) { + repeat += show_B(u2u(V.x), u2u(V.y), 2, 5, Find, all, 0); + if (all <= 0) check(repeat); + all--; + } + } + } + } + if (Fpin == BRDfPinPad[bRoundness]) { // "ROUNDNESS" + B.elements(E) { + E.package.contacts(C) { + if (C.smd) { + if (C.smd.roundness == Roundness) { + sprintf(FndPin, " Roundness %d", C.smd.roundness); + repeat += show_B(u2u(C.x), u2u(C.y), 1, u2u(B.area.x2 - B.area.x1)/5, "ROUNDNESS", all, 17); + sprintf(foundelement, "
    Roundness %d on (%.4f %.4f) %s", + Roundness, u2u(C.x), u2u(C.y), unit[gridunit]); + if (all <= 0) check(repeat); + all--; + } + } + } + } + } + + B.texts(T) { // 2010.09.03 nach Texten suchen + status("Texte:" + T.value); + if (T.value == Vfind) { + FndPin = "Text"; + sprintf(foundelement, "TEXT %s : on (%.4f %.4f)", T.value, u2u(T.x), u2u(T.y) ); + // Text kann nicht anhand von T.value angezeigt werden, + // deshalb muß die Koordinate als Text übergeben werden. + string tv; + sprintf(tv, "(%.4f %.4f)", u2u(T.x), u2u(T.y)); + //show_B(real x, real y, real zoom1, real zoom2, string findb, int fist, int layer) { + repeat += show_B(u2u(T.x), u2u(T.y), 2, 15, tv, all, T.layer); // + if (all <= 0) check(repeat); + all--; + } + } + } + + if (repeat) check(repeat); + string StepFound = " not found!"; + if (Fpin == "VIA") sprintf(StepFound, " %d-%d not found!", Vstart, Vend); + if (Fpin == "ROUNDNESS") sprintf(StepFound, " %d%% not found!", Roundness); + if (StepMode) { + get_step(-1); // do not count upper while not found + StepFound = " no more found!"; + } + dlgMessageBox("" + dpbacksl(Find) + StepFound, "OK"); + exit (0); +} + + +// *** search and find in Schematic *** +if (schematic) { + lastSheet = 0; + schematic(S) { + gridunit = (S.grid.unit); + if (Fpin == "GATE" && Find == "0" || Fpin == "GATE" && Find == "*") { // 2007.04.03 Find not placed GATEs + S.parts(PA) { + PA.instances(I) { + if (!I.sheet) { + if (Find == "0") { + sprintf(repeat, "INVOKE %s %s\n", PA.name, I.gate.name); + exit(repeat); + } + else { + sprintf(Invoke[Fcnt], "INVOKE %s %s\n", PA.name, I.gate.name); + Fcnt++; + } + } + } + } + exit(get_invoke()); + } + + S.sheets(SH) { + SH.parts(PA) { + if (Fpin == "DEV") { + if (PA.device.name == Find) { // 2005.11.14 alf@cadsoft.de + PA.instances(IN) { + IN.gate.symbol.pins(P) { + FndPin = "Dev"; + sprintf(foundelement, "DEVice %s : sheet %d on (%.4f %.4f)", IN.name , IN.sheet, u2u(IN.x), u2u(IN.y) ); + repeat += show_S(IN.sheet, + u2u(IN.gate.symbol.area.x1), u2u(IN.gate.symbol.area.y1), + u2u(IN.gate.symbol.area.x2), u2u(IN.gate.symbol.area.y2), + PA.name + ); + if (all <= 0) check(repeat); + all--; + break; + } + break; + } + } + } + else if (Fpin == "GATE") { + PA.instances(IN) { + if (PA.name+IN.gate.name == Find || IN.gate.name == Find) { + FndPin = "Gate"; + sprintf(foundelement, "GATE %s : sheet %d on (%.4f %.4f)", IN.gate.name , IN.sheet, u2u(IN.x), u2u(IN.y) ); + repeat += show_S(IN.sheet, + u2u(IN.gate.symbol.area.x1), u2u(IN.gate.symbol.area.y1), + u2u(IN.gate.symbol.area.x2), u2u(IN.gate.symbol.area.y2), + PA.name + ); + if (all <= 0) check(repeat); + all--; + break; + } + } + } + else if (Fpin == "PIN") { + PA.instances(IN) { + status("Pin:"+PA.name); + IN.gate.symbol.pins(P) { // Pin + if (P.name == Find) { + FndPin = "Pin"; + sprintf(foundelement, "PIN %s : sheet %d on (%.4f %.4f)", P.name , IN.sheet, u2u(P.x), u2u(P.y) ); + repeat += show_S(IN.sheet, + u2u(P.x)-u2u(50000), u2u(P.y)-u2u(50000), + u2u(P.x)+u2u(50000), u2u(P.y)+u2u(50000), + PA.name + ); + if (all <= 0) check(repeat); + all--; + break; + } + } + } + } + else if (Fpin == "PAD") { + status("Pad:"+PA.name); + PA.instances(IN) { + IN.gate.symbol.pins(P) { + if (P.contact) { + if (P.contact.name == Find) { + FndPin = "Pad"; + sprintf(foundelement, "PAD %s (PIN %s) : sheet %d on (%.4f %.4f)", PA.name, P.name , IN.sheet, u2u(IN.x), u2u(IN.y) ); + repeat += show_S(IN.sheet, + u2u(P.x)-u2u(100000), u2u(P.y)-u2u(100000), + u2u(P.x)+u2u(100000), u2u(P.y)+u2u(100000), + PA.name + ); + if (all <= 0) check(repeat); + all--; + break; + } + } + } + } + } + } + SH.nets(N) { + status("Net:"+N.name); + if (N.name == Find) { + FndPin = "Net"; + N.segments(SEG) { + SEG.wires(W) { + real ox, oy; // 2008.06.10 alf neue Berechnung des Zoomausschnitt + if (W.x1 < W.x2) { + ox = -0.1 * (u2u(W.x1 + W.x2) / 2); + } + else { + ox = 0.1 * (u2u(W.x1 + W.x2) / 2); + } + if (W.y1 < W.y2) { + oy = -0.1 * (u2u(W.y1 + W.y2) / 2); + } + else { + oy = 0.1 * (u2u(W.y1 + W.y2) / 2); + } + repeat += show_S(SH.number, + u2u(W.x1) - ox, u2u(W.y1) - oy, + u2u(W.x2) + ox, u2u(W.y2) + oy, + Find + ); + if (all <= 0) check(repeat); + all--; + } + } + } + } + } + S.sheets(SH) { + SH.parts(PA) { + status("Part:"+PA.name); + if (PA.name == Find) { + PA.instances(IN) { // Gate + if (IN.sheet) { + FndPin = "Part"; + sprintf(foundelement, "Device %s : sheet %d on (%.4f %.4f)", PA.name , IN.sheet, u2u(IN.x), u2u(IN.y) ); + repeat += show_S(IN.sheet, + u2u(IN.gate.symbol.area.x1), u2u(IN.gate.symbol.area.y1), + u2u(IN.gate.symbol.area.x2), u2u(IN.gate.symbol.area.y2), + PA.name + ); + if (all <= 0) check(repeat); + all--; + } + } + } + } + SH.busses(B) { + status("Bus:"+B.name); + if (findBus(B.name, Find)) { + FndPin = "Bus"; + B.segments(SEG) { + SEG.wires(W) { + real ox, oy; // 2008.06.10 alf neue Berechnung des Zoomausschnitt + if (W.x1 < W.x2) { + ox = -0.1 * (u2u(W.x1 + W.x2) / 2); + } + else { + ox = 0.1 * (u2u(W.x1 + W.x2) / 2); + } + if (W.y1 < W.y2) { + oy = -0.1 * (u2u(W.y1 + W.y2) / 2); + } + else { + oy = 0.1 * (u2u(W.y1 + W.y2) / 2); + } + repeat += show_S(SH.number, + u2u(W.x1) - ox, u2u(W.y1) - oy, + u2u(W.x2) + ox, u2u(W.y2) + oy, + Find + ); + if (all <= 0) check(repeat); + all--; + } + } + } + } + SH.parts(PA) { + status("Value:" + PA.name); + PA.instances(IN) { // Gate + if (PA.value == Vfind) { + FndPin = "Value"; + sprintf(foundelement, "Value %s | %s : sheet %d on (%.4f %.4f)", PA.value, PA.name , IN.sheet, u2u(IN.x), u2u(IN.y) ); + repeat += show_S(IN.sheet, + u2u(IN.gate.symbol.area.x1), u2u(IN.gate.symbol.area.y1), + u2u(IN.gate.symbol.area.x2), u2u(IN.gate.symbol.area.y2), + PA.name + ); + if (all <= 0) check(repeat); + all--; + } + } + } + SH.texts(T) { // 2010.09.03 nach Texten suchen + status("Texte:" + T.value); + if (T.value == Vfind) { + FndPin = "Text"; + sprintf(foundelement, "TEXT %s : sheet %d on (%.4f %.4f)", T.value, SH.number, u2u(T.x), u2u(T.y) ); + // Text kann nicht anhand von T.value angezeigt werden, + // deshalb muß die Koordinate als Text übergeben werden. + string tv; + sprintf(tv, "(%.4f %.4f)", u2u(T.x), u2u(T.y)); + // je nach Rotation den Zoomausschnitt verschieben + int px1 = T.size * 2; + int py1 = T.size * 2; + int px2 = T.size * 2; + int py2 = T.size * 2; + repeat += show_S(SH.number, + u2u(T.x-px1), u2u(T.y-py1), + u2u(T.x+px2), u2u(T.y+py2), + tv + ); + if (all <= 0) check(repeat); + all--; + } + } + } + } + check(repeat); +} +else { + dlgMessageBox("Start this ULP from schematic or board!", "OK"); + exit (0); +} diff --git a/trunk/ulp/gen-3d-idf-pac.ulp b/trunk/ulp/gen-3d-idf-pac.ulp new file mode 100644 index 00000000..2630d2f8 --- /dev/null +++ b/trunk/ulp/gen-3d-idf-pac.ulp @@ -0,0 +1,292 @@ +#usage "en:Generate 3D data for export generate_3d_datav13.ulp on the current package.

    " + "

    " + "Author: alf@cadsoft.de" + , + "de:Erzeuge die Daten für die 3D-Ausgabe des generate_3d_data(v13).ulp in dem " + "geladenen Package.

    " + "RUN gen-3D-pac-idf [high-top high-bottom]

    " + "high top high bottom == mm. Die tatsächliche Höhe des Bauteil.
    " + "Beachten Sie auch die interne Auflösung von Eagle V6 (3.125 Nanometer), und daß WIRE immer eine " + "Breite von 2 Einheiten benötigen. Dadurch ergeben sich WIRE-Breiten mit einem mehrfachen von " + "6.25 Nanometer.

    " + "

    " + "Es werden nur Objekte (WIRE/RECT) im Layer 21/51 & 22/52 im Layr 57/58 nachgezeichnet.
    " + "Das generate_3d_data_v13.ulp von Herrn Naubacher benutzt die Layer 57 und 58, " + "um die Daten für die 3. Dimension (Z-Achse) im .PAC zu hinterlegen.
    " + "Das generate_3d_data(v13).ulp liest im Board diese Daten (WIRE-Breite) und multipliziert sie mit 1000. " + "Der Trick ist, die Linienbreite der Bestückungsdruck (Layer 57 für Top und Layer 58 für Bottom) " + "in micrometer abzulegen. Diese dünnen Linien stören später die grafische Ansicht nicht, wenn goße Werte " + "für die 3. Dimension (Z-Achse) angegeben werden müssen, und man mit DISPLAY 57 58 die komplette Zeichnung " + "(alle Layer) anzeigt." + "Da die Lötbeinchen typischerweise mit RECT gezeichnet werden, bietet sich an, für RECT eine eigene " + "Höhenangabe zu berücksichtigen, wobei hier das Problem besteht, das EAGLE an einem Koorinatenpaar nur " + "eine Wirebreite zulässt. Hier muß dafür gesorgt werden, daß WIRE im Layer 57/58 die die gleiche " + "ausrichtung besitzen aber unterschiedlich breit sein müssen (wegen Z) nicht an den gleichen Koordinaten " + "beginnen bzw. Enden wie die RECTs. EAGLE würde sonst die Wirekoordinaten integrieren und eine " + "resultierende Wirebreite erzeugen. Es muß also dafür gesorgt werden, das die unterschiedlichen Wirebreiten " + "mindestens mit einen Versatz von einer Eagle-Einheit (3.125nanometer) gezeichnet werden." + "Author: alf@cadsoft.de" + +string Verison = "1.0.2"; // 2013-01-14 alf@cadsoft.de + // 2013-04-23 now with menu + // 2014-03-13 draw also RECT as wire with "high" as line + +int Test = 0; + +// Benutzung : Xneu(X, Y, X-drehpunkt, Y-drehpunkt, UserWinkel) +real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; + /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } +} + +// Benutzung : Yneu(X, Y, X-drehpunkt, Y-drehpunkt, UserWinkel) +real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; + /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } +} + +if (package) { + real Ztop = strtod(argv[1]); + real Zbottom = strtod(argv[1]); + + if (argc == 1) { + int optg, optb; + dlgDialog("IDF 3D Package") { + dlgLabel(usage); + dlgLabel("


    "); + dlgHBoxLayout { + dlgGridLayout { + dlgCell( 0, 0) dlgLabel("&Z high top mm"); + dlgCell( 0, 1) dlgRealEdit(Ztop); + dlgCell( 1, 0) dlgLabel("&Z high bottom mm"); + dlgCell( 1, 1) dlgRealEdit(Zbottom); + + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+OK") { + Ztop /= 1000; + Zbottom /= 1000; + if (Ztop >= u2mm(2) || Zbottom >= u2mm(2) ) { + dlgAccept(); + } + else { + if (language() != "de") { + dlgMessageBox("First type in a real value for Z of Top and/or Bottom.", "OK"); + } + else { + dlgMessageBox("Geben Sie zuerst einen (gültigen) Wert für die Höhe Z von Top bzw. Bottom ein.", "OK"); + } + } + } + dlgPushButton("-CANCEL") { dlgReject(); exit(0); } + dlgStretch(1); + } + }; + } + + string cmd, s; + string cmdl = ""; + int layer3dt, layer3db; + + library(LIB) LIB.layers(LAY) { + if(LAY.number == 57) layer3dt = LAY.number; + if(LAY.number == 58) layer3db = LAY.number; + } + if (!layer3dt && !layer3db) { + layer3dt = 57; + layer3db = 58; + cmdl = "LAYER 57 t3D; SET COLOR_LAYER 57 6; SET FILL_LAYER 57 5; LAYER 58 b3D; SET COLOR_LAYER 58 5; SET FILL_LAYER 58 4;"; + } + + if (Ztop < u2mm(2)) { + string h, com; + + if (language() != "de") { + sprintf(h, "!The calculated value for Z-top %.9f is < %.9fmm", Ztop, u2mm(2)); + com = "CANCEL"; + } + else { + sprintf(h, "!Der umgerechnete Wert für Z-top %.9f ist < %.9fmm", Ztop, u2mm(2)); + com = "ABBRUCH"; + } + dlgMessageBox(h, com); + exit(-1); + } + if (Ztop < u2mm(2)) { + string h, com; + + if (language() != "de") { + sprintf(h, "!The calculated value for Z-bottom %.9f is < %.9fmm", Ztop, u2mm(2)); + com = "CANCEL"; + } + else { + sprintf(h, "!Der umgerechnete Wert für Z-bottom %.9f ist < %.9fmm", Ztop, u2mm(2)); + com = "ABBRUCH"; + } + dlgMessageBox(h, com); + exit(-1); + } + package(P) { + //sprintf(cmd, "Display NONE 1 16 17 18 20 23 25 27 57;\nSET WIRE_BEND 2;\n"); + cmd += cmdl; + P.rectangles(R) { + real rectcenterx = u2mm((R.x1 + R.x2) / 2); + real rectcentery = u2mm((R.y1 + R.y2) / 2); + if (R.layer == 21 || R.layer == 51) { + sprintf(s, "LAYER %d;\nWIRE %.9fmm (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm );\n", + layer3dt, + Ztop, + Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery, + + Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcentery, + + Xneu(u2mm(R.x2) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x2) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcentery, + + Xneu(u2mm(R.x2) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x2) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery, + + Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery + ); + cmd += s; + } + else if (R.layer == 22 || R.layer == 52) { + sprintf(s, "LAYER %d;\nWIRE %.9fmm (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm ) (%.9fmm %.9fmm );\n", + layer3db, + Zbottom, + Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery, + + Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcentery, + + Xneu(u2mm(R.x2) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x2) - rectcenterx, u2mm(R.y2) - rectcentery, 0, 0, R.angle) + rectcentery, + + Xneu(u2mm(R.x2) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x2) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery, + + Xneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcenterx, + Yneu(u2mm(R.x1) - rectcenterx, u2mm(R.y1) - rectcentery, 0, 0, R.angle) + rectcentery + ); + cmd += s; + } + } + P.wires(W) { + if (W.layer == 21 || W.layer == 51) { + sprintf(s, "Layer %d;\nWIRE %.9fmm (%.9fmm %.9fmm ) %+.3f (%.9fmm %.9fmm );\n", + layer3dt, + Ztop, + u2mm(W.x1), u2mm(W.y1), W.curve, u2mm(W.x2), u2mm(W.y2) + ); + cmd += s; + } + else if (W.layer == 22 || W.layer == 52) { + sprintf(s, "Layer %d;\nWIRE %.9fmm (%.9fmm %.9fmm ) %+.3f (%.9fmm %.9fmm );\n", + layer3db, + Zbottom, + u2mm(W.x1), u2mm(W.y1), W.curve, u2mm(W.x2), u2mm(W.y2) + ); + cmd += s; + } + } + } + if (Test) { + dlgDialog("3D IDF test") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(600); + dlgTextEdit(cmd); + } + dlgHBoxLayout { + dlgPushButton("ok") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-273); } + dlgStretch(1); + } + }; + } + exit(cmd); +} + +else { + if (language() == "de") dlgMessageBox("Starten Sie das ULP in einem Package (Bibliothek)", "OK"); + else dlgMessageBox("Start this ULP in a package (library)", "OK"); +} \ No newline at end of file diff --git a/trunk/ulp/generate-3d-idf-data.ulp b/trunk/ulp/generate-3d-idf-data.ulp new file mode 100644 index 00000000..438e5c2a --- /dev/null +++ b/trunk/ulp/generate-3d-idf-data.ulp @@ -0,0 +1,1018 @@ + +#usage "en:export 3d-data from board to IDF-FileFormat

    " + "More info can be found here: .../eagle.../doc/generate_3d_data_eng.pdf
    " + "Original author: Uploaded by Neubacher Andreas from Commend International GmbHh
    " + "co-Author: alf@cadsoft.de

    " + , + "de:export 3d-data from board to IDF-FileFormat

    " + "Im Layer 50 muß eine Kopie der Boardkontour des Layer 20 angelegt werden. Die Wirebreite in Micron " + "ergibt die Boarddicke in mm.
    " + "Die Bordkontour kann entweder im Board lebst oder in einem Package angelegt werden, es muß nur die " + "obenstehende Bedingung eingehalten werden.
    " + "Um in einem Board einen Durchbruch zu erzeugen, kann man entweder im Board selbst oder in einem Package " + "eine Kontur mit der Wirebreite von 0 im Layer 50 anlegen.
    " + "Original author: Uploaded by Neubacher Andreas from Commend International GmbHh
    " + "co-Author: alf@cadsoft.de

    " + +#require 6.0600 +string UlpVersion = "1.9"; + +string Docuemantpath = "Weiter Infos finden sie im Dokumentenordner unter " + path_doc[0] + "/generate_3d_data_eng.pdf
    "; + + +//############################################################################ +// Author: Andy Neubacher +// Version | Date | log +//---------+------------+----------------------------------------------------- +// v1.9 | 2014-04-08 | - Now can change the filedirectory an filename +// select Top and or Bottom side of parts to export +// v1.8 | 2014-04-01 | - Cutout und Koordinaten berichtigt (nur beim ersten Wire, Anfang und Endkoordinate ausgeben) +// dann immer nur die 2. Koordinate bis die erste Koordinate wieder erreicht ist. +// - LoopCounter für geschlossene Konturen (Durchbruch/Cutout) wieder berichtigt. +// +// v1.7 | 2014-01-20 | - draw also pad-holes +// v1.6 | 2013-12-19 | - LoopCounter für geschlossene Konturen (Durchbruch/Cutout). +// Die Bedingung für die Erkennung der einzelnen Konturen ist: +// 1. Die allererste Kontour im Layer 50 ist die Boardkontur, +// was bedeutet, diese Kontour muss als allererste Kontur gezeichnet werden. +// 2. Jede weitere Kontur wird als Cutout betrachtet, und es wird keine Überprüfung +// vorgenommen, ob diese Kontur innerhalb oder ausserhalb der Board-Dimension ist. +// 3. Jede Kontur muss durchgehend gezeichnet und geschlossen sein. +// Das bedeutet, man darf innerhalb einer Kontur nicht an beliebigen Punkten +// das (WIRE) zeichnen unterbrechen, und an einer anderen Stelle wieder beginnen, +// also dem vorher unterbrochenen *Ende* entgegen zeichnen. +// +// v1.5 | 2013-12-18 | - file renamed and now without version, for use in Text-Menu +// | | - draw board cutout +// | | - ++CutoutNumSegments change to CutoutNumSegments++ +// alf@cadsoft.de +// v1.4 | 2013-12-11 | - correct Board outline Curve +// | | - correct Pre- to Post-Increment in all Functions +// | | - fixed by Angelo.Cuccato@bogen-electronic.com +// v1.3 | 2013-03-14 | - correct using ARC coorinates +// v1.2 | 2013-01-14 | - Link in description to download page - fixes by alf@cadsoft.de +// v1.1 | 2012-12-04 | - korrect Loop Label for contours in layer Dimension - fixes by alf@cadsoft.de +// v1.0 | 2012-08-20 | - more resolution %.6f of coordinates - fixes by alf@cadsoft.de +// v0.9 | 2012-02-08 | - used function u2mm() for Z-axis value - fixes by alf@cadsoft.de +// | | +// v0.8 | 2011-05-31 | - changed characters that caused import problems +// | | - changed output file extension to .emn and .emp +// | | - fixes by morten@riftlabs.com +// | | +// v0.7 | 2006-10-24 | - outline of board can also be drawn direct in brd-file +// | | - any hole is taken from devices and board direct +// | | - close open polygons on request +// | | - drill vias on request +// | | - bugfix : error if device contains more than one poly on top and bottom +// | | - bugfix : sorting of points possible failed if polygon was open +// | | - bugfix : partheights on bottomlayer were ignored +// v0.6 | 2006-08-31 | now multiple partheights are possible +// v0.5 | 2006-08-25 | modification to 'RIR-standard' +// v0.4 | 2005-11-09 | 1st export of a real board+parts successfull +// v0.3 | 2005-11-03 | correct mirrors at top and bottom side +// v0.2 | 2005-10-21 | 1st working IDF-data +// v0.1 | 2005-09-30 | start of project +//---------+------------+----------------------------------------------------- +// +// HOWTO: +// Create your board outline on layer 50. +// In your library, draw the component outlines on layer 57 (tCad) and use the line thickness to set component height. +// 1000 mic = 1 mm (e.g. if your grid is in mm, then a line thickness of 0.001 equals a component height of 1 mm). +// More info can be found here: ftp://ftp.cadsoft.de/eagle/userfiles/ulp/generate_3d_data_eng.pdf +// +//############################################################################ + + +int Layer3dBoardDimension = 50; +int tLayer3Ddata = 57; +int bLayer3Ddata = 58; +int SelectSide[] = { 1, 1 }; // select Part output on side Top / Bottom +int maxCutoutLineWidth = 0; // -->> is linewidth 0.0 -> line is a cutout ?? +string UlpName = filename(argv[0]); // gets ulp name + + +// partoptions +int NumParts; // number of parts +string PartName[]; // name of part + +// vars for polygon calculation +int NumSegments = 0; // number of points +int PointX1[]; // start x +int PointY1[]; // start y +int PointX2[]; // end x +int PointY2[]; // end y +int SegmentType[]; // LINE, ARC, CIRCLE +real SegmentCurve[]; // used by ARCs : - if drawn CCW, + if drawn CW +int SegmentWidth[]; // linewitdh = partheight + +int CutoutNumSegments = 0; +int CutoutPointX1[]; // start x +int CutoutPointY1[]; // start y +int CutoutPointX2[]; // end x +int CutoutPointY2[]; // end y +int CutoutSegmentType[]; // LINE, ARC, CIRCLE +int CutoutSegmentCurve[]; // used by ARCs : -180 if drawn CCW, +180 if drawn CW +int CutoutSegmentWidth[]; // linewitdh = partheight + +int LoopCounter = 0; // 2015-04-02 für Boardoutline und Cutoutline + + +enum { LINE = 1, ARC = 2, CIRCLE = 3 }; +enum { CUTOUT = 0, OUTLINE = -1 }; +enum { false = 0, true = 1}; +string Type[]; + Type[0] = "0"; + Type[LINE] = "LINE"; + Type[ARC] = "ARC"; + Type[CIRCLE] = "CIRCLE"; + +// vars for library +int NumPacInLib = 0; // number of pacs in library +int PacIn_LIB_heights[]; // if 0 = only one partheight, if != 0 more than one height +real PacIn_LIB_angle[]; // rotation of part in board +string PacIn_LIB_name[]; // names of pack's in library +int PacIn_LIB_Device_mountside[]; // TOP, BOTTOM +string PacIn_LIB_SubPart_mountside[]; // mountside of subparts + + +int NumCutouts = 0; // number of holes in the pcb (drills, millings) +int OutlineInDeviceFound = false; // is outline drawn in device symbol + +int CloseOpenPoly = false; // close polygon if gap is smaller than ...mm +real MaxGapWidth = 0.1; // value of maximum gap to close + +int DrillViaHoles = true; // drill via-holes in pcb +real MinViaHoleDia = 0.254; // diameter of drill + + +//////////////////////////////////////////////////// +void CollectPartData(UL_BOARD brd) { // read out all parts + NumParts = 0; + brd.elements(E) { + PartName[NumParts] = E.name; + PacIn_LIB_angle[NumParts] = -1; // fill with invalid rotation and ... + PacIn_LIB_Device_mountside[NumParts] = -1; // fill with invalid mountside (mirror) for "void IDF_LibaryElectrical(UL_BOARD BRD)" function + PacIn_LIB_heights[NumParts] = 0; // part is only one package + NumParts++; + } +} + +//////////////////////////////////////////////////// +void IDF_Circle(int x1, int y1, int x2, int y2, int type) { // output circle to file in IDF format + int loopcount = 0; + if(type == CUTOUT) loopcount = NumCutouts; // 2013-12-19 + printf("%d %.6f %.6f 0\n", loopcount, u2mm(x1), u2mm(y1)); + printf("%d %.6f %.6f 360\n", loopcount, u2mm(x2), u2mm(y2)); + return; +} + +//////////////////////////////////////////////////// +void IDF_Arc(int x1, int y1, int x2, int y2, real angle, int type, int first) { // output arc to file in IDF format + int loopcount = 0; + if(type == CUTOUT) loopcount = NumCutouts; // 2013-12-19 + if (first) printf("%d %.6f %.6f 0\n", loopcount, u2mm(x1), u2mm(y1)); + printf("%d %.6f %.6f %.1f\n", loopcount, u2mm(x2), u2mm(y2), angle); + return; +} + +//////////////////////////////////////////////////// +void IDF_Line(int x1, int y1, int x2, int y2, int type, int first) { // output line to file in IDF format + int loopcount = 0; + if(type == CUTOUT) loopcount = NumCutouts; // 2013-12-19 + if (first) printf("%d %.6f %.6f 0\n", loopcount, u2mm(x1), u2mm(y1)); + printf("%d %.6f %.6f 0\n", loopcount, u2mm(x2), u2mm(y2)); + return; +} + +//////////////////////////////////////////////////// +void OutputLines(int originx, int originy, int type) { // write to file + int first = 1; + int i = 0; + int startx = PointX1[i]; + int starty = PointY1[i]; + for(i = 0; i < NumSegments; i++) { + NumCutouts = LoopCounter; + switch(SegmentType[i]) { + case LINE : IDF_Line(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, type, first); + first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2, + // bis zum Ende sprich schliessen der Schleife + break; + case ARC : IDF_Arc(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, SegmentCurve[i], type, first); + first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2, + // bis zum Ende sprich schliessen der Schleife + break; + case CIRCLE : IDF_Circle(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, type); + LoopCounter++; + NumCutouts = LoopCounter; + startx = PointX1[i+1]; + starty = PointY1[i+1]; + first = 1; + break; + default : string s; + sprintf(s, "Unknown type in Segment %d", i); + if (dlgMessageBox(s, "OK", "esc") != 0) exit(-182); + } + if (startx == PointX2[i] && starty == PointY2[i]) { + first = 1; // beim Anfang eine neuen Kontour wieder beie Koordinatenpaare ausgeben + startx = PointX1[i+1]; + starty = PointY1[i+1]; + LoopCounter++; // die Schleife (Kontur) ist geschlossen. Bedingung siehe in oben. + } + } + return; +} + +//////////////////////////////////////////////////// +void OutputBoardOutLines(int originx, int originy, int type) { // write to file :: type ist hier irrelevant + int first = 1; + int i = 0; + int startx = PointX1[i]; + int starty = PointY1[i]; + for(i = 0; i < NumSegments; i++) { + NumCutouts = LoopCounter; + switch(SegmentType[i]) { // 2013-12-18 + case LINE : IDF_Line(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, CUTOUT, first); + first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2, + // bis zum Ende sprich schliessen der Schleife + break; + case ARC : IDF_Arc(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, SegmentCurve[i], CUTOUT, first); + first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2, + // bis zum Ende sprich schliessen der Schleife + break; + case CIRCLE : IDF_Circle(PointX1[i]-originx, PointY1[i]-originy, PointX2[i]-originx, PointY2[i]-originy, CUTOUT); + LoopCounter++; + NumCutouts = LoopCounter; + startx = PointX1[i+1]; + starty = PointY1[i+1]; + first = 1; + break; + default : string s; + sprintf(s, "Unknown type in Segment %d", i); + } + if (startx == PointX2[i] && starty == PointY2[i]) { + first = 1; // beim Anfang eine neuen Kontour wieder beie Koordinatenpaare ausgeben + startx = PointX1[i+1]; + starty = PointY1[i+1]; + LoopCounter++; // die Schleife (Kontur) ist geschlossen. Bedingung siehe in oben. + } + } + return; +} + +void OutputBoardCutOutLines(int originx, int originy, int type) { // write to file :: type ist hier irrelevant + int first = 1; + int i = 0; + int startx = CutoutPointX1[i]; + int starty = CutoutPointY1[i]; + for(i = 0; i < CutoutNumSegments; i++) { + NumCutouts = LoopCounter; + switch(CutoutSegmentType[i]) { // 2013-12-18 + case LINE : IDF_Line(CutoutPointX1[i]-originx, CutoutPointY1[i]-originy, CutoutPointX2[i]-originx, CutoutPointY2[i]-originy, CUTOUT, first); + first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2, + // bis zum Ende sprich schliessen der Schleife + break; + case ARC : IDF_Arc(CutoutPointX1[i]-originx, CutoutPointY1[i]-originy, CutoutPointX2[i]-originx, CutoutPointY2[i]-originy, CutoutSegmentCurve[i], CUTOUT, first); + first = 0; // nur die erste Koordinate wird mit xy1 und xy2 ausgegeben, alles weiteren nur yx2, + // bis zum Ende sprich schliessen der Schleife + break; + case CIRCLE : IDF_Circle(CutoutPointX1[i]-originx, CutoutPointY1[i]-originy, CutoutPointX2[i]-originx, CutoutPointY2[i]-originy, CUTOUT); + LoopCounter++; + NumCutouts = LoopCounter; + startx = CutoutPointX1[i+1]; + starty = CutoutPointY1[i+1]; + first = 1; + break; + default : string s; + sprintf(s, "Unknown type in Segment %d", i); + } + if (startx == CutoutPointX2[i] && starty == CutoutPointY2[i]) { + first = 1; // beim Anfang eine neuen Kontour wieder beie Koordinatenpaare ausgeben + startx = CutoutPointX1[i+1]; + starty = CutoutPointY1[i+1]; + LoopCounter++; // die Schleife (Kontur) ist geschlossen. Bedingung siehe in oben. + } + } + return; +} + +//////////////////////////////////////////////////// +int IsPointEqual (int x1, int y1, int x2, int y2) { // really need a func-description ?? + if(x1 == x2 && y1 == y2) return true; + return false; +} + +//////////////////////////////////////////////////// +real getPartHeight() { // returns maximum partlevel + real ret = u2mm(SegmentWidth[0])*1000.0; // 2012-02-08 + return ret; +} + +//////////////////////////////////////////////////// +int IsPointInCircle(int target_x, int target_y, int circle_x, int circle_y, real radius) { + real dist,a,b; + a = abs(target_y-circle_y); + b = abs(target_x-circle_x); + // calculate distance + dist = sqrt(a*a + b*b); + if(dist <= radius) return true; + return false; +} + +//////////////////////////////////////////////////// +//int GetArcOptions(UL_WIRE w) { // is arc drawn CW or CCW +// if(IsPointEqual(w.x1, w.y1, w.x2, w.y2)) return (w.arc.angle1 - w.arc.angle2); +// else return (w.arc.angle2 - w.arc.angle1); +//} + +//////////////////////////////////////////////////// +int DataOnLayerPresent(UL_ELEMENT E, int layer) { + E.package.circles(CIR) { // circle found + if(CIR.layer == layer && CIR.width > maxCutoutLineWidth) return true; + } + E.package.wires(W) { + if(W.arc) { // arc found + if(W.layer == layer && W.width > maxCutoutLineWidth) return true; + } + else { // straight line found + if(W.layer == layer && W.width > maxCutoutLineWidth) return true; + } + } + return false; // no 3d-data on given layer found +} + +//////////////////////////////////////////////////// +void CollectRemainingPoints(int start, int nr) { + int i; + for(i = 0; i < nr; i++) { + PointX1[i] = PointX1[i+start]; + PointY1[i] = PointY1[i+start]; + PointX2[i] = PointX2[i+start]; + PointY2[i] = PointY2[i+start]; + SegmentType[i] = SegmentType[i+start]; + SegmentCurve[i] = SegmentCurve[i+start]; + SegmentWidth[i] = SegmentWidth[i+start]; + } + NumSegments = nr; + return; +} + +//////////////////////////////////////////////////// +int SortPointsEx (void) { // sort all points to a continous polygon + int i; + int ptfound; + int ResultPointX1[]; // start x + int ResultPointY1[]; // start y + int ResultPointX2[]; // end x + int ResultPointY2[]; // end y + int ResultSegmentType[]; // SegmentType + int ResultSegmentCurve[]; // options of segment (only used for ARCs) + int ResultSegmentWidth[]; // width of line + int PointUsed[]; + enum { NOT_FOUND = 0, FOUND = 1, ERROR = 2 }; + enum { NOT_USED = 0, USED = 1 }; + for(i = 0; i < NumSegments; i++) PointUsed[i] = NOT_USED; + + ResultPointX1[0] = PointX1[0]; // startpoint + ResultPointY1[0] = PointY1[0]; + ResultPointX2[0] = PointX2[0]; + ResultPointY2[0] = PointY2[0]; + ResultSegmentType[0] = SegmentType[0]; + ResultSegmentWidth[0] = SegmentWidth[0]; + ResultSegmentCurve[0] = SegmentCurve[0]; + PointUsed[0] = USED; + + for(int x=1; x= (NumSegments-1)) { + if(ptfound != FOUND) ptfound = ERROR; + } + } while(ptfound == NOT_FOUND); + // if point was not found -> end sorting of points + if (ptfound == ERROR) break; + } // for NumSegments + // count how many points are not used + int n; + int NumPointsUsed = 0; + for(i=0; i < NumSegments; i++) { + if(PointUsed[i] == USED) NumPointsUsed++; + } + // copy not used points to end of ResultPoint[] + for(i = NumSegments-1; i >= NumPointsUsed; i--) { + for(n = 0; n < NumSegments; n++) { + if(PointUsed[n] == NOT_USED) { // copy if point is not used + PointUsed[n] = USED; + ResultPointX1[i] = PointX1[n]; + ResultPointY1[i] = PointY1[n]; + ResultPointX2[i] = PointX2[n]; + ResultPointY2[i] = PointY2[n]; + ResultSegmentCurve[i] = SegmentCurve[n]; + ResultSegmentType[i] = SegmentType[n]; + ResultSegmentWidth[i] = SegmentWidth[n]; + break; + } + } + } + // copy back sorted list + for(i=0; i search for points within circle + if(IsPointInCircle(PointX1[i], PointY1[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) { // 2012-02-08 + PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point + PointY1[NumSegments] = PointY2[LastPoint]; + PointX2[NumSegments] = PointX1[i]; + PointY2[NumSegments] = PointY1[i]; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = SegmentWidth[LastPoint]; + SegmentCurve[NumSegments++] = 0; // 2013-12-11 + LineAdded = true; + break; // point within circle found and added -> escape from "for"-loop + } + if(IsPointInCircle(PointX2[i], PointY2[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) { // 2012-02-08 + PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point + PointY1[NumSegments] = PointY2[LastPoint]; + PointX2[NumSegments] = PointX2[i]; + PointY2[NumSegments] = PointY2[i]; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = SegmentWidth[LastPoint]; + SegmentCurve[NumSegments++] = 0; // 2013-12-11 + LineAdded = true; + break; // point within circle found and added -> escape from "for"-loop + } + } + } + } while(LineAdded); // resort points and close gaps if new line added + // finished correct -> but is polygon closed ?!? (firstpoint and lastpoint may no be the same coordinate !) + if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false) { // poly closed ? + if(IsPointInCircle(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) { // 2012-02-08 + PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point + PointY1[NumSegments] = PointY2[LastPoint]; + PointX2[NumSegments] = PointX1[0]; + PointY2[NumSegments] = PointY1[0]; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = SegmentWidth[LastPoint]; + SegmentCurve[NumSegments++] = 0; // 2013-12-11 + } + } + return; +} + +//////////////////////////////////////////////////// +int SortPoints(string ElementName) { // sort all points to a continous polygon + int LastPoint, RemainingPoints; + // close open polygon + if (CloseOpenPoly) CloseOpenPolygon(); + // do final sorting + RemainingPoints = SortPointsEx(); + // check if polygon is closed + LastPoint = NumSegments - RemainingPoints - 1; + if (LastPoint < 0) { + dlgMessageBox("!Negativ Index in function SortPoints().", "OK"); + exit(-472); + } + if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false) { + if(SegmentType[0] != CIRCLE) { + string x; + int pt_x, pt_y; + pt_x = PointX2[LastPoint]; + pt_y = PointY2[LastPoint]; + sprintf(x,"!%s contains an open polygon !\n\ncoordinate : X= %.6f[mm], Y= %.6f[mm]", ElementName, u2mm(pt_x), u2mm(pt_y)); + if (dlgMessageBox(x, "OK", "Show") != 0) { + sprintf(x, "WIN (%.6fmm %.6fmm);\n", u2mm(pt_x), u2mm(pt_y)); + exit(x); + } + } + } + return RemainingPoints; +} + +//////////////////////////////////////////////////// +void IDF_LibaryHeader(UL_BOARD BRD) { //-> create header of libary + int t = time(); + string date; + string sourceID; + sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t)); + sprintf(sourceID, "Commend International >%s %s %s<", UlpName, UlpVersion, EAGLE_SIGNATURE); // 2013-01-14 + printf(".HEADER\n"); + printf("LIBRARY_FILE 3.0 \"%s\" %s 1\n", sourceID, date); + printf(".END_HEADER\n"); + return; +} + +//////////////////////////////////////////////////// +int CollectLibOutlineSegments(UL_ELEMENT E, int layer) { // get all segments of elements on 3D-layer + NumSegments=0; + E.package.circles(CIR) { // create circles + if(CIR.layer == layer && CIR.width > maxCutoutLineWidth) { + PointX1[NumSegments] = CIR.x; + PointY1[NumSegments] = CIR.y; + PointX2[NumSegments] = CIR.x + CIR.radius; + PointY2[NumSegments] = CIR.y; + SegmentType[NumSegments] = CIRCLE; + SegmentWidth[NumSegments] = CIR.width; + SegmentCurve[NumSegments++] = 0; // 2013-12-11 + } + } + E.package.wires(W) { + if(W.curve) { // create arcs + if(W.layer == layer && W.width > maxCutoutLineWidth) { + PointX1[NumSegments] = W.x1; // 2013-03-14 use wire coordinate, not arc! + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = ARC; + SegmentWidth[NumSegments] = W.width; + SegmentCurve[NumSegments++] = W.curve; //GetArcOptions(W); + } + } + else { // create straight lines + if(W.layer == layer && W.width > maxCutoutLineWidth) { + PointX1[NumSegments] = W.x1; + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = W.width; + SegmentCurve[NumSegments++] = 0; // 2013-12-11 + } + } + } + if(NumSegments != 0) { // show warningbox if element contains no 3d-data + if(layer == bLayer3Ddata) { // is given layer the bottom layer -> mirror + for(int i=0; i create electrical parts (R, C, IC, ...) + int i,x,inlib,NrOfPolygon; + int RemainingPoints; + string MountSide[] = {"TOP", "BOTTOM"}; + int layer[] = { tLayer3Ddata, bLayer3Ddata }; + + for(i=0;i subract given offsets -> E.x, E.y + printf(".END_ELECTRICAL\n"); + CollectRemainingPoints(NumSegments, RemainingPoints); + PacIn_LIB_heights[NumPacInLib] = NrOfPolygon; // 0=package has only 1 poly; >0 package has more than one poly-outline + PacIn_LIB_name[NumPacInLib] = E.package.name; // mark that package is now in LIB-file + PacIn_LIB_Device_mountside[NumPacInLib] = E.mirror; // safe top- or bottom-side + PacIn_LIB_SubPart_mountside[NumPacInLib] = MountSide[tb]; // safe mountside of subparts + PacIn_LIB_angle[NumPacInLib++] = E.angle; // safe angle of partplacement + if(RemainingPoints != 0 || NrOfPolygon != 0) NrOfPolygon++; + } while(RemainingPoints != 0); // get multiple outline with multiple partheights + } + } + } + } + } + return; +} + +//////////////////////////////////////////////////// +void IDF_LibaryMechanical(UL_BOARD BRD) { //-> create mechanical parts (drills, holes, ...) + // not implemented yet + return; +} + +//////////////////////////////////////////////////// +int CollectBoardOutlineSegments(UL_BOARD BRD) { //++ get all segments of boardoutline + NumSegments = 0; + // first search board outline in board direct + BRD.circles(CIR) { + if(CIR.layer == Layer3dBoardDimension) { + if (CIR.width > maxCutoutLineWidth) { + PointX1[NumSegments] = CIR.x; + PointY1[NumSegments] = CIR.y; + PointX2[NumSegments] = CIR.x + CIR.radius; + PointY2[NumSegments] = CIR.y; + SegmentType[NumSegments] = CIRCLE; + SegmentWidth[NumSegments] = CIR.width; + SegmentCurve[NumSegments++] = 0; + } + else { + CutoutPointX1[CutoutNumSegments] = CIR.x; + CutoutPointY1[CutoutNumSegments] = CIR.y; + CutoutPointX2[CutoutNumSegments] = CIR.x + CIR.radius; + CutoutPointY2[CutoutNumSegments] = CIR.y; + CutoutSegmentType[CutoutNumSegments] = CIRCLE; + CutoutSegmentWidth[CutoutNumSegments] = CIR.width; + CutoutSegmentCurve[CutoutNumSegments++] = 0; + } + } + } + BRD.wires(W) { + if(W.layer == Layer3dBoardDimension) { + if (W.width > maxCutoutLineWidth) { + if(W.curve) { // create arcs board-outline board + PointX1[NumSegments] = W.x1; // 2013-03-14 use direct wire coordinate, not arc-coordinate + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = ARC; + SegmentWidth[NumSegments] = W.width; + SegmentCurve[NumSegments] = W.curve; // GetArcOptions(W); + } + else { // create straight lines board-outline board + PointX1[NumSegments] = W.x1; + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = W.width; + SegmentCurve[NumSegments] = 0; + } + NumSegments++; + } + else { + if(W.curve) { // create arcs board-outline board + CutoutPointX1[CutoutNumSegments] = W.x1; + CutoutPointY1[CutoutNumSegments] = W.y1; + CutoutPointX2[CutoutNumSegments] = W.x2; + CutoutPointY2[CutoutNumSegments] = W.y2; + CutoutSegmentType[CutoutNumSegments] = ARC; + CutoutSegmentWidth[CutoutNumSegments] = W.width; + CutoutSegmentCurve[CutoutNumSegments] = W.curve; //GetArcOptions(W); + } + else { + CutoutPointX1[CutoutNumSegments] = W.x1; + CutoutPointY1[CutoutNumSegments] = W.y1; + CutoutPointX2[CutoutNumSegments] = W.x2; + CutoutPointY2[CutoutNumSegments] = W.y2; + CutoutSegmentType[CutoutNumSegments] = LINE; + CutoutSegmentWidth[CutoutNumSegments] = W.width; + CutoutSegmentCurve[CutoutNumSegments] = 0; + } + CutoutNumSegments++; + } + } + } + // second search board outline in packages + BRD.elements(E) { + E.package.circles(CIR) { // create board-outline of package-libary + if(CIR.layer == Layer3dBoardDimension) { + PointX1[NumSegments] = CIR.x; + PointY1[NumSegments] = CIR.y; + PointX2[NumSegments] = CIR.x + CIR.radius; + PointY2[NumSegments] = CIR.y; + SegmentType[NumSegments] = CIRCLE; + SegmentWidth[NumSegments] = CIR.width; + SegmentCurve[NumSegments++] = 0; + } + } + } + BRD.elements(E) { + E.package.wires(W) { + if(W.layer == Layer3dBoardDimension) { + if (W.width > maxCutoutLineWidth) { + if(W.curve) { // create arcs board-outline of package-libary + PointX1[NumSegments] = W.x1; + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = ARC; + SegmentWidth[NumSegments] = W.width; + SegmentCurve[NumSegments] = W.curve; // GetArcOptions(W); + } + else { // create straight lines board-outline of package-libary + PointX1[NumSegments] = W.x1; + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = W.width; + SegmentCurve[NumSegments] = 0; + } + NumSegments++; + } + else { + if(W.curve) { // create arcs board-cutout of package-libary + CutoutPointX1[CutoutNumSegments] = W.x1; + CutoutPointY1[CutoutNumSegments] = W.y1; + CutoutPointX2[CutoutNumSegments] = W.x2; + CutoutPointY2[CutoutNumSegments] = W.y2; + CutoutSegmentType[CutoutNumSegments] = ARC; + CutoutSegmentWidth[CutoutNumSegments] = W.width; + CutoutSegmentCurve[CutoutNumSegments] = W.curve; //GetArcOptions(W); + } + else { // create line board-cutout of package-libary + CutoutPointX1[CutoutNumSegments] = W.x1; + CutoutPointY1[CutoutNumSegments] = W.y1; + CutoutPointX2[CutoutNumSegments] = W.x2; + CutoutPointY2[CutoutNumSegments] = W.y2; + CutoutSegmentType[CutoutNumSegments] = LINE; + CutoutSegmentWidth[CutoutNumSegments] = W.width; + CutoutSegmentCurve[CutoutNumSegments] = 0; + } + CutoutNumSegments++; + } + } + } + } + + if(NumSegments == 0) { + string error; + sprintf(error,"!No board-outline on layer %d found !", Layer3dBoardDimension); + dlgMessageBox(error); + exit(-771); + } + return NumSegments; +} + + +//////////////////////////////////////////////////// +void IDF_BoardHeader(UL_BOARD BRD) { //-## create header of boardfile + int t = time(); + string date; + string sourceID; + + sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t)); + sprintf(sourceID, "Commend International >%s %s %s<", UlpName, UlpVersion, EAGLE_SIGNATURE); + printf(".HEADER\n"); + printf("BOARD_FILE 3.0 \"%s\" %s 1\n", sourceID, date); + printf("\"%s\" MM\n", filename(BRD.name)); + printf(".END_HEADER\n"); + return; +} + +//////////////////////////////////////////////////// +void IDF_BoardOutline(UL_BOARD BRD) { //-## create outline of board + // get outline + CollectBoardOutlineSegments(BRD); + SortPoints("Board-Outline"); // boardname + // draw outline + printf(".BOARD_OUTLINE UNOWNED\n"); + printf("%.6f\n", getPartHeight()); + OutputBoardOutLines(0, 0, OUTLINE); // subract given offsets -> E.x, E.y + OutputBoardCutOutLines(0, 0, OUTLINE); + printf(".END_BOARD_OUTLINE\n"); + LoopCounter = 0; + return; +} + +//////////////////////////////////////////////////// +void IDF_BoardPlaceParts(UL_BOARD BRD) { //-## mount parts on board + int i, inlib; + string MountSide[] = {"TOP","BOTTOM"}; + printf(".PLACEMENT\n"); + BRD.elements(E) { + inlib = 0; + for(i=0; i more than one part on same x/y position + int lib_start = i; + do { + printf("%s_ANGLE%.1f_%s.%d CI_LIB %s.%d\n", E.package.name, E.angle, PacIn_LIB_SubPart_mountside[lib_start], PacIn_LIB_heights[lib_start], E.name, PacIn_LIB_heights[lib_start]); + printf("%.6f %.6f 0 0 %s PLACED\n", u2mm(E.x), u2mm(E.y), PacIn_LIB_SubPart_mountside[lib_start]); + lib_start++; + }while(PacIn_LIB_heights[lib_start] > 1); + } + } + } + printf(".END_PLACEMENT\n"); + return; +} + +//////////////////////////////////////////////////// +void IDF_BoardHoles(UL_BOARD BRD) { //-## create holes in board (cutout, partholes, ...) + printf(".DRILLED_HOLES\n"); + // drill holes from board direct + BRD.holes(H) + printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y)); + // drill holes from elements + BRD.elements(E) { + E.package.holes(H) + printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y)); + } + // drill pad(holes) from elements 2014-01-20 + BRD.elements(E) { + E.package.contacts(C) + if (C.pad) + if (u2mm(C.pad.drill) > MinViaHoleDia) + printf("%.6f %.6f %.2f PTH BOARD Other UNOWNED\n", u2mm(C.pad.drill), u2mm(C.pad.x), u2mm(C.pad.y)); + } + // drill big via's + BRD.signals(S) { + S.vias(V) { + if((DrillViaHoles == true) && (u2mm(V.drill) > MinViaHoleDia)) // drill via-hole + printf("%.6f %.6f %.6f PTH BOARD VIA UNOWNED\n", u2mm(V.drill), u2mm(V.x), u2mm(V.y)); + } + } + printf(".END_DRILLED_HOLES\n"); + return; +} + +//////////////////////////////////////////////////// +void IDF_CreateLibaryFile(UL_BOARD BRD, string fname) { // create libary for the IDF-board + output(fname, "wt") { + IDF_LibaryHeader(BRD); + IDF_LibaryElectrical(BRD); + IDF_LibaryMechanical(BRD); + } + return; +} + +//////////////////////////////////////////////////// +void IDF_CreateBoardFile(UL_BOARD BRD, string fname) { // create boardfile with parts of libary + output(fname, "wt") { + IDF_BoardHeader(BRD); + IDF_BoardOutline(BRD); + IDF_BoardHoles(BRD); + IDF_BoardPlaceParts(BRD); + } + return; +} + + +//////////////////////////////////////////////////// +void DisplayHelp(void) { // show helptext + dlgDialog("Generate 3D IDF data") { + dlgLabel("Version " + UlpVersion); + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(200); + dlgTextView(usage); + } + dlgLabel(Docuemantpath); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("-Back") dlgReject(); + } + }; + return; +} + +//////////////////////////////////////////////////// +// S T A R T of U L P +// +if (board) { + int proceed = 0; + string FileDirectoryName; + string FilenamePanel; + string FileNameIDB; // Board + string FileNameIDL; // Library + board(BRD) { + FileDirectoryName = filedir(BRD.name); + FileNameIDB = filesetext(filename(BRD.name), ".IDB"); + FileNameIDL = filesetext(filename(BRD.name), ".IDL"); + } + dlgDialog("Generate 3D data format (IDF-file)") { + dlgHBoxLayout { + dlgGroup(" settings ") { + dlgGridLayout { + dlgCell(0,0) dlgCheckBox("close polygon if gap is smaller than : ", CloseOpenPoly); + dlgCell(0,1) dlgRealEdit(MaxGapWidth); + dlgCell(0,2) dlgLabel(" mm"); + + dlgCell(1,0) dlgCheckBox("drill via-holes if via is bigger than : ", DrillViaHoles); + dlgCell(1,1) dlgRealEdit(MinViaHoleDia); + dlgCell(1,2) dlgLabel(" mm"); + + dlgCell(2,0) dlgCheckBox("Export top parts", SelectSide[0]); + dlgCell(3,0) dlgCheckBox("Export bottom parts", SelectSide[1]); + } + } + } + dlgGridLayout { + dlgCell(1,0) dlgLabel("Output Directory:"); + dlgCell(1,1) dlgLabel(FileDirectoryName, 1); + dlgCell(1,2) { + dlgPushButton("Browse") { + string fdn = dlgDirectory("Save IDF file", FileDirectoryName); + if (fdn) { + int len = strlen(fdn); + if (fdn[len] != '/') fdn+="/"; // dlgDirectory gibt den Pfad ohne abschliessenden Slash zurück! + FileDirectoryName = fdn; + } + } + } + dlgCell(2,0) dlgLabel("Filename IDB (Board)"); + dlgCell(2,1) dlgStringEdit(FileNameIDB); + dlgCell(2,2) { + dlgPushButton("Browse") { + string fdb = dlgFileSave("Save IDF file", FileDirectoryName, "IDF files (*.IDB)"); + if (fdb) { + FileNameIDB = filename(fdb); + if(strchr(FileNameIDB, '.') < 0) // add fileextension if missing + FileNameIDB += ".IDB"; + FileNameIDL = filesetext(FileNameIDB, ".IDL"); + } + } + } + dlgCell(3,0) dlgLabel("Filename IDL (Library)"); + dlgCell(3,1) dlgStringEdit(FileNameIDL); + dlgCell(3,2) { + dlgPushButton("Browse") { + string fdl = dlgFileSave("Save IDF file", FileDirectoryName, "IDF files (*.IDL)"); + if (fdl) { + FileNameIDL = filename(fdl); + if(strchr(FileNameIDL, '.') < 0) // add fileextension if missing + FileNameIDL += ".IDL"; + FileNameIDB = filesetext(FileNameIDL, ".IDB"); + } + } + } + } + dlgHBoxLayout { + dlgPushButton("OK") { proceed = 1; dlgAccept(); } + dlgPushButton("Cancel") dlgReject(); + dlgStretch(1); + dlgLabel("Version: " + UlpVersion); + dlgPushButton("Help") DisplayHelp(); + } + }; + if(proceed) { + project.board(BRD) { + CollectPartData(BRD); // read out data from BRD + IDF_CreateLibaryFile(BRD, FileNameIDL); + IDF_CreateBoardFile(BRD, FileNameIDB); + } + } +} +else { + dlgMessageBox(usage + "


    ERROR: No board!

    \nThis program can only work in the layout editor."); + exit(0); +} \ No newline at end of file diff --git a/trunk/ulp/generate-dummy-package-and-connect.ulp b/trunk/ulp/generate-dummy-package-and-connect.ulp new file mode 100644 index 00000000..5f39e90c --- /dev/null +++ b/trunk/ulp/generate-dummy-package-and-connect.ulp @@ -0,0 +1,129 @@ +#usage "en:Generates a Dummy Package for the currently displayed Device in the Library Editor \n" + "

    " + "For electro devices it has proved to be useful to use the same names for symbol pins and " + "package pads. This program generates a package that has identical pad/pin names." + "

    " + "Start the ULP in the library editor window, after having created a device and " + "used the ADD command to add the symbol(s). A package will be created which has " + "the same name as the device and the pad names are identical with the pin names. " + "Connect pins und pads with the Connect command.

    " + "Author: alf@cadsoft.de" + , + "de:Generiert ein Dummy-Package für das aktuell angezeigte Device im Bibliothekseditor\n" + "

    " + "Für Elektro-Bauteile empfiehlt es sich, dass Symbol-Pins und Package-Pads gleiche " + "Namen haben. Dieses Programm erzeugt ein Package mit identischen Pad-/Pin-Namen." + "

    " + "Starten Sie das Programm im Bibliothekseditor, sobald Sie ein Device angelegt " + "und die Symbole mit dem Add-Befehl geholt haben. Es wird ein Package angelegt, " + "dessen Name dem des Device entspricht (falls noch nicht vorhanden) und dessen " + "Pads entsprechend den Pins benannt sind. Pins und Pads sind mit dem Connect-Befehl " + "verbunden.

    " + "Author: alf@cadsoft.de" + +string Version = "1.0.2"; // 2012-03-23 Behandlung der Apostrophen in Pin/Pad-Namen berichtig. + // 2013-01-25 Bei nur einem Gate den Gate-Namen nicht benutzen um die Pad-Namen zu erzeugen +string cmd, concmd, s; +string f; +string PadName; +string CurrentDevice; +int PackagePresent = 0; +int PADname; + +int test = 0; + +// Da der ganze String in ' eingeschlossen wird, +// müssen die Apostrophen verdoppelt werden. +string addApostroph(string name) { // 2012-03-23 + string t[]; + int cnt = strsplit(t, name, '\''); // check Apostroph + if (cnt > 1) { + name = ""; + for (int i = 0; i < cnt; i++) { + if (i == 0) { + if (t[i]) name += t[i]; + } + else if (i) name += "''" + t[i]; + } + } + return name; +} + +if (deviceset) { + library(L) { + f = filename(L.name); + f = filesetext(f, "$$$.scr"); + f = path_scr[0] + '/' + f; // verwende Script-Pfad + deviceset(DS) { + CurrentDevice = DS.name; + DS.devices(D) { + if (!D.package && CurrentDevice == DS.name) { + sprintf(s, "EDIT %s.PAC;\n", DS.name); + cmd += s; + sprintf(s, "DESCRIPTION 'Dummy';\n"); + cmd += s; + sprintf(s, "GRID MM; CHANGE DRILL 0.5; CHANGE DIAMETER 1.0;\n"); + cmd += s; + sprintf(s, "EDIT %s.DEV;\n", DS.name); + concmd += s; + sprintf(s, "PAC '%s' '';\n", DS.name); + concmd += s; + int cntg = 0; + DS.gates(G) { + cntg++; + } + DS.gates(G) { + string gname = addApostroph(G.name); + if (cntg == 1) gname = ""; // 2013-01-25 bei nur einem Gate, nur den Pin-Namen beutzen. + G.symbol.pins(P) { + PadName = (P.name); + sprintf(s, "PAD '%s%s' (%.4f %.4f);\n", + gname, addApostroph(PadName), + u2mm(P.x), + u2mm(P.y)-7.62 + ); // Pin-Offset im Device in Y-Richtung + cmd += s; + sprintf(s, "CONNECT '%s.%s' '%s%s';\n", + addApostroph(G.name), + addApostroph(P.name), + gname, + addApostroph(PadName) + ); + concmd += s; + } + } + } + } + } + L.packages(P) { + if (CurrentDevice == P.name) PackagePresent = 1; + } + } + cmd += concmd; + if (cmd && !PackagePresent) { + if (test) { + dlgDialog("Check") { + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgTextEdit(cmd); + } + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("Cancel") { dlgReject(); exit(-1); } + } + }; + } + output(f, "wtD") printf("%s", cmd); // temporäre Script-Datei erzeugen + exit("SCRIPT '"+ f +"'"); + } + else { + if (language() == "de") dlgMessageBox("Das Device besitzt schon ein Package, bzw. es existiert schon ein Package mit entsprechenden Namen.", "OK"); + else dlgMessageBox("There is already a package defined for this device/package with this name already exists.", "OK"); + } +} + +else { + if (language() == "de") dlgMessageBox("Das ULP kann nur im Device-Editor (Bibliothek) benutzt werden!", "OK"); + else dlgMessageBox("This ULP can be used in the Device Editor (Library) only!", "OK"); +} diff --git a/trunk/ulp/generate_3d_data_v10.ulp b/trunk/ulp/generate_3d_data_v10.ulp new file mode 100644 index 00000000..814873cc --- /dev/null +++ b/trunk/ulp/generate_3d_data_v10.ulp @@ -0,0 +1,1206 @@ +#usage "export 3d-data from board to IDF-FileFormat V3.0\n" + "

    " + "Author: Neubacher Andy
    " + "co-Author: alf@cadsoft.de" + +#require 6.0300 + +//############################################################################ +// Author: Andy Neubacher +// Version | Date | log +//---------+------------+----------------------------------------------------- +// v1.0 | 2012-08-20 | - more resolution %.6f of coordinates +// | | alf@cadsoft.de +// v0.9 | 2012-02-08 | - used function u2mm() for Z-axis value +// | | - fixes by alf@cadsoft.de +// v0.8 | 2011-05-31 | - changed characters that caused import problems +// | | - changed output file extension to .emn and .emp +// | | - fixes by morten@riftlabs.com +// | | +// v0.7 | 2006-10-24 | - outline of board can also be drawn direct in brd-file +// | | - any hole is taken from devices and board direct +// | | - close open polygons on request +// | | - drill vias on request +// | | - bugfix : error if device contains more than one poly on top and bottom +// | | - bugfix : sorting of points possible failed if polygon was open +// | | - bugfix : partheights on bottomlayer were ignored +// v0.6 | 2006-08-31 | now multiple partheights are possible +// v0.5 | 2006-08-25 | modification to 'RIR-standard' +// v0.4 | 2005-11-09 | 1st export of a real board+parts successfull +// v0.3 | 2005-11-03 | correct mirrors at top and bottom side +// v0.2 | 2005-10-21 | 1st working IDF-data +// v0.1 | 2005-09-30 | start of project +//---------+------------+----------------------------------------------------- +// +// HOWTO: +// Create your board outline on layer 50. +// In your library, draw the component outlines on layer 57 (tCad) and use the line thickness to set component height. +// 1000 mic = 1 mm (e.g. if your grid is in mm, then a line thickness of 0.001 equals a component height of 1 mm). +// More info can be found here: ftp://ftp.cadsoft.de/eagle/userfiles/ulp/generate_3d_data_eng.pdf +// +//############################################################################ + + +int Layer3dBoardDimension = 50; +int tLayer3Ddata = 57; +int bLayer3Ddata = 58; +int maxCutoutLineWidth = 0; // -->> is linewidth 0.0 -> line is a cutout + + +string HelpText = "1)

    3D use u2mm()

    \n"; + +string UlpName; +string UlpVersion = "V0.9"; + + + + + +// partoptions +int NumParts; // number of parts +string PartName[]; // name of part + + +// vars for polygon calculation +int NumSegments = 0; // number of points +int PointX1[]; // start x +int PointY1[]; // start y +int PointX2[]; // end x +int PointY2[]; // end y +int SegmentType[]; // ARC, LINE, CIRCLE +int SegmentOptions[]; // used by ARCs : -180 if drawn CCW, +180 if drawn CW +int SegmentWidth[]; // linewitdh = partheight +enum { LINE = 0, ARC = 1, CIRCLE = 2 }; +enum { CUTOUT = 0, OUTLINE = -1 }; +enum { false = 0, true = 1}; + + +// vars for library +int NumPacInLib = 0; // number of pacs in library +int PacIn_LIB_heights[]; // if 0 = only one partheight, if != 0 more than one height +real PacIn_LIB_angle[]; // rotation of part in board +string PacIn_LIB_name[]; // names of pack's in library +int PacIn_LIB_Device_mountside[]; // TOP, BOTTOM +string PacIn_LIB_SubPart_mountside[]; // mountside of subparts + + +int NumCutouts = 0; // number of holes in the pcb (drills, millings) +int OutlineInDeviceFound = false; // is outline drawn in device symbol + +int CloseOpenPoly = false; // close polygon if gap is smaller than ...mm +real MaxGapWidth = 0.1; // value of maximum gap to close + +int DrillViaHoles = true; // drill via-holes in pcb +real MinViaHoleDia = 1; // diameter of drill + + + + + + + + +//////////////////////////////////////////////////// +void GetUlpName(void) // reads out the own ULP-name +{ + string s = strsub(argv[0], 0, strlen(argv[0])-4); + char c = '/'; + int pos = strrchr(s, c); + + if (pos >= 0) + UlpName = strsub(s, pos + 1); +} + + + +//////////////////////////////////////////////////// +void CollectPartData(UL_BOARD brd) // read out all parts +{ + NumParts = 0; + + brd.elements(E) + { + PartName[NumParts] = E.name; + PacIn_LIB_angle[NumParts] = -1; // fill with invalid rotation and ... + PacIn_LIB_Device_mountside[NumParts] = -1; // fill with invalid mountside (mirror) for "void IDF_LibaryElectrical(UL_BOARD BRD)" function + PacIn_LIB_heights[NumParts] = 0; // part is only one package + + NumParts++; + } +} + + + + + + + +//////////////////////////////////////////////////// +void IDF_Circle(int x1, int y1, int x2, int y2, int type) // output circle to file in IDF format +{ + int x=0; + + if(type == CUTOUT) + x = NumCutouts; + + printf("%d %.6f %.6f 0\n", x, u2mm(x1), u2mm(y1)); + printf("%d %.6f %.6f 360\n", x, u2mm(x2), u2mm(y2)); +} + +//////////////////////////////////////////////////// +void IDF_Arc(int x1, int y1, int x2, int y2, int angle, int type) // output arc to file in IDF format +{ + int x=0; + + if(type == CUTOUT) + x = NumCutouts; + + printf("%d %.6f %.6f 0\n", x, u2mm(x1), u2mm(y1)); + printf("%d %.6f %.6f %d\n", x, u2mm(x2), u2mm(y2), angle); +} + +//////////////////////////////////////////////////// +void IDF_Line(int x1, int y1, int x2, int y2, int type) // output line to file in IDF format +{ + int x=0; + + if(type == CUTOUT) + x = NumCutouts; + + printf("%d %.6f %.6f 0\n", x, u2mm(x1), u2mm(y1)); + printf("%d %.6f %.6f 0\n", x, u2mm(x2), u2mm(y2)); +} + +//////////////////////////////////////////////////// +void OutputLines(int originx, int originy, int type) // write to file +{ + for(int i=0; i maxCutoutLineWidth) + return true; + } + E.package.wires(W) + { + if(W.arc) // arc found + { + if(W.arc.layer == layer && W.arc.width > maxCutoutLineWidth) + return true; + } + else // straight line found + { + if(W.layer == layer && W.width > maxCutoutLineWidth) + return true; + } + } + return false; // no 3d-data on given layer found +} + +//////////////////////////////////////////////////// +void CollectRemainingPoints(int start, int nr) +{ + int i; + + for(i=0; i= (NumSegments-1)) + { + if(ptfound != FOUND) + ptfound = ERROR; + } + + } while(ptfound == NOT_FOUND); + + + // if point was not found -> end sorting of points + if (ptfound == ERROR) + break; + + } // for NumSegments + + + + // count how many points are not used + int n; + int NumPointsUsed = 0; + for(i=0; i=NumPointsUsed; i--) + { + for(n=0; n search for points within circle + { + if(IsPointInCircle(PointX1[i], PointY1[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) + { + PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point + PointY1[NumSegments] = PointY2[LastPoint]; + PointX2[NumSegments] = PointX1[i]; + PointY2[NumSegments] = PointY1[i]; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = SegmentWidth[LastPoint]; + SegmentOptions[++NumSegments] = 0; + + LineAdded = true; + break; // point within circle found and added -> escape from "for"-loop + } + if(IsPointInCircle(PointX2[i], PointY2[i], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) + { + PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point + PointY1[NumSegments] = PointY2[LastPoint]; + PointX2[NumSegments] = PointX2[i]; + PointY2[NumSegments] = PointY2[i]; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = SegmentWidth[LastPoint]; + SegmentOptions[++NumSegments] = 0; + + LineAdded = true; + break; // point within circle found and added -> escape from "for"-loop + } + } + } + } while(LineAdded); // resort points and close gaps if new line added + + + + // finished correct -> but is polygon closed ?!? (firstpoint and lastpoint may no be the same coordinate !) + if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false) // poly closed ? + { + if(IsPointInCircle(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint], mm2u(MaxGapWidth))) + { + PointX1[NumSegments] = PointX2[LastPoint]; // add new line with start at last-point + PointY1[NumSegments] = PointY2[LastPoint]; + PointX2[NumSegments] = PointX1[0]; + PointY2[NumSegments] = PointY1[0]; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = SegmentWidth[LastPoint]; + SegmentOptions[++NumSegments] = 0; + } + } +} + + +//////////////////////////////////////////////////// +int SortPoints(string ElementName) // sort all points to a continous polygon +{ + int LastPoint, RemainingPoints; + + // close open polygon + if(CloseOpenPoly) + CloseOpenPolygon(); + + // do final sorting + RemainingPoints = SortPointsEx(); + + // check if polygon is closed + LastPoint = NumSegments - RemainingPoints - 1; + if(IsPointEqual(PointX1[0], PointY1[0], PointX2[LastPoint], PointY2[LastPoint]) == false) + { + if(SegmentType[0] != CIRCLE) + { + string x; + int pt_x, pt_y; + + pt_x = PointX2[LastPoint]; + pt_y = PointY2[LastPoint]; + sprintf(x,"!%s contains an open polygon !\n\ncoordinate : X= %.6f[mm], Y= %.6f[mm]", ElementName, u2mm(pt_x), u2mm(pt_y)); + if (dlgMessageBox(x, "OK", "Show") != 0) { + sprintf(x, "WIN (%.6fmm %.6fmm);\n", u2mm(pt_x), u2mm(pt_y)); + exit(x); + } + } + } + + return RemainingPoints; +} + + + +//////////////////////////////////////////////////// +void IDF_LibaryHeader(UL_BOARD BRD) //-> create header of libary +{ + int t = time(); + string date; + string sourceID; + + sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t)); + sprintf(sourceID, "Commend International >%s.ulp %s<", UlpName, UlpVersion); + + printf(".HEADER\n"); + printf("LIBRARY_FILE 3.0 \"%s\" %s 1\n", sourceID, date); + printf(".END_HEADER\n"); + return; +} + + +//////////////////////////////////////////////////// +int CollectLibOutlineSegments (UL_ELEMENT E, int layer) // get all segments of elements on 3D-layer +{ + NumSegments=0; + + + E.package.circles(CIR) // create circles + { + if(CIR.layer == layer && CIR.width > maxCutoutLineWidth) + { + PointX1[NumSegments] = CIR.x; + PointY1[NumSegments] = CIR.y; + PointX2[NumSegments] = CIR.x + CIR.radius; + PointY2[NumSegments] = CIR.y; + SegmentType[NumSegments] = CIRCLE; + SegmentWidth[NumSegments] = CIR.width; + SegmentOptions[++NumSegments] = 0; + } + } + + E.package.wires(W) + { + if(W.arc) // create arcs + { + if(W.arc.layer == layer && W.arc.width > maxCutoutLineWidth) + { + PointX1[NumSegments] = W.arc.x1; + PointY1[NumSegments] = W.arc.y1; + PointX2[NumSegments] = W.arc.x2; + PointY2[NumSegments] = W.arc.y2; + SegmentType[NumSegments] = ARC; + SegmentWidth[NumSegments] = W.arc.width; + SegmentOptions[++NumSegments] = GetArcOptions(W); + } + } + else // create straight lines + { + if(W.layer == layer && W.width > maxCutoutLineWidth) + { + PointX1[NumSegments] = W.x1; + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = W.width; + SegmentOptions[++NumSegments] = 0; + } + } + } + + + if(NumSegments != 0) // show warningbox if element contains no 3d-data + { + if(layer == bLayer3Ddata) // is given layer the bottom layer -> mirror + { + for(int i=0; i create electrical parts (R, C, IC, ...) +{ + int i,x,inlib,NrOfPolygon; + int RemainingPoints; + string MountSide[] = {"TOP","BOTTOM"}; + int layer[] = {tLayer3Ddata, bLayer3Ddata}; + + + for(i=0;i subract given offsets -> E.x, E.y + printf(".END_ELECTRICAL\n"); + + CollectRemainingPoints(NumSegments, RemainingPoints); + + PacIn_LIB_heights[NumPacInLib] = NrOfPolygon; // 0=package has only 1 poly; >0 package has more than one poly-outline + PacIn_LIB_name[NumPacInLib] = E.package.name; // mark that package is now in LIB-file + PacIn_LIB_Device_mountside[NumPacInLib] = E.mirror; // safe top- or bottom-side + PacIn_LIB_SubPart_mountside[NumPacInLib] = MountSide[b]; // safe mountside of subparts + PacIn_LIB_angle[NumPacInLib++] = E.angle; // safe angle of partplacement + + if(RemainingPoints != 0 || NrOfPolygon != 0) + NrOfPolygon++; + + }while(RemainingPoints != 0); // get multiple outline with multiple partheights + } + } + } + } + } + return; +} + + + +//////////////////////////////////////////////////// +void IDF_LibaryMechanical(UL_BOARD BRD) //-> create mechanical parts (drills, holes, ...) +{ + // not implemented yet + return; +} + + + + + + +//////////////////////////////////////////////////// +int CollectBoardOutlineSegments(UL_BOARD BRD) //++ get all segments of boardoutline +{ + NumSegments=0; + + BRD.elements(E) + { + E.package.circles(CIR) // create board-outline of package-libary + { + if(CIR.layer == Layer3dBoardDimension && CIR.width > maxCutoutLineWidth) + { + PointX1[NumSegments] = CIR.x; + PointY1[NumSegments] = CIR.y; + PointX2[NumSegments] = CIR.x + CIR.radius; + PointY2[NumSegments] = CIR.y; + SegmentType[NumSegments] = CIRCLE; + SegmentWidth[NumSegments] = CIR.width; + SegmentOptions[++NumSegments] = 0; + } + } + } + BRD.elements(E) + { + E.package.wires(W) + { + if(W.arc) // create arcs direct from board + { + if(W.arc.layer == Layer3dBoardDimension && W.arc.width > maxCutoutLineWidth) + { + PointX1[NumSegments] = W.arc.x1; + PointY1[NumSegments] = W.arc.y1; + PointX2[NumSegments] = W.arc.x2; + PointY2[NumSegments] = W.arc.y2; + SegmentType[NumSegments] = ARC; + SegmentWidth[NumSegments] = W.arc.width; + SegmentOptions[++NumSegments] = GetArcOptions(W); + } + } + else // create straight lines direct from board + { + if(W.layer == Layer3dBoardDimension && W.width > maxCutoutLineWidth) + { + PointX1[NumSegments] = W.x1; + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = W.width; + SegmentOptions[++NumSegments] = 0; + } + } + } + } + + if(NumSegments != 0) + { + OutlineInDeviceFound = true; + return NumSegments; // outline was found in a device -> return + } + + + + // outline of board was not found in any device -> check if drawn in boardfile direct + BRD.circles(CIR) // create board-outline of package-libary + { + if(CIR.layer == Layer3dBoardDimension && CIR.width > maxCutoutLineWidth) + { + PointX1[NumSegments] = CIR.x; + PointY1[NumSegments] = CIR.y; + PointX2[NumSegments] = CIR.x + CIR.radius; + PointY2[NumSegments] = CIR.y; + SegmentType[NumSegments] = CIRCLE; + SegmentWidth[NumSegments] = CIR.width; + SegmentOptions[++NumSegments] = 0; + } + } + BRD.wires(W) + { + if(W.arc) // create arcs direct from board + { + if(W.arc.layer == Layer3dBoardDimension && W.arc.width > maxCutoutLineWidth) + { + PointX1[NumSegments] = W.arc.x1; + PointY1[NumSegments] = W.arc.y1; + PointX2[NumSegments] = W.arc.x2; + PointY2[NumSegments] = W.arc.y2; + SegmentType[NumSegments] = ARC; + SegmentWidth[NumSegments] = W.arc.width; + SegmentOptions[++NumSegments] = GetArcOptions(W); + } + } + else // create straight lines direct from board + { + if(W.layer == Layer3dBoardDimension && W.width > maxCutoutLineWidth) + { + PointX1[NumSegments] = W.x1; + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = W.width; + SegmentOptions[++NumSegments] = 0; + } + } + } + + + if(NumSegments == 0) + { + string x; + sprintf(x,"!no board-outline on layer %d found !", Layer3dBoardDimension); + dlgMessageBox(x); + } + + return NumSegments; +} + + + +//////////////////////////////////////////////////// +int CollectBoardCutoutSegments(UL_ELEMENT E, int layer, int type) +{ + NumSegments=0; + + + if(type == CIRCLE) + { + E.package.circles(CIR) // create circles direct from board + { + if(CIR.layer == layer && CIR.width < (maxCutoutLineWidth+1)) + { + PointX1[NumSegments] = CIR.x; + PointY1[NumSegments] = CIR.y; + PointX2[NumSegments] = CIR.x + CIR.radius; + PointY2[NumSegments] = CIR.y; + SegmentType[NumSegments] = CIRCLE; + SegmentWidth[NumSegments] = CIR.width; + SegmentOptions[++NumSegments] = 0; + } + } + } + else + { + E.package.wires(W) + { + if(W.arc) // create arcs direct from board + { + if(W.arc.layer == layer && W.arc.width < (maxCutoutLineWidth+1)) + { + PointX1[NumSegments] = W.arc.x1; + PointY1[NumSegments] = W.arc.y1; + PointX2[NumSegments] = W.arc.x2; + PointY2[NumSegments] = W.arc.y2; + SegmentType[NumSegments] = ARC; + SegmentWidth[NumSegments] = W.arc.width; + SegmentOptions[++NumSegments] = GetArcOptions(W); + } + } + else // create straight lines direct from board + { + if(W.layer == layer && W.width < (maxCutoutLineWidth+1)) + { + PointX1[NumSegments] = W.x1; + PointY1[NumSegments] = W.y1; + PointX2[NumSegments] = W.x2; + PointY2[NumSegments] = W.y2; + SegmentType[NumSegments] = LINE; + SegmentWidth[NumSegments] = W.width; + SegmentOptions[++NumSegments] = 0; + } + } + } + } + + return NumSegments; +} + + +//////////////////////////////////////////////////// +void DoCutoutsFromElements(UL_BOARD BRD) +{ + int ret, RemainingPoints; + + // get cutouts from elements (holes, ...) + BRD.elements(E) + { + // get cutout segments (LINEs and ARCs) + ret = CollectBoardCutoutSegments(E, Layer3dBoardDimension, LINE); + if(ret) + { + do + { + NumCutouts++; // increment board cutouts + RemainingPoints = SortPoints(E.name); // elementname + NumSegments -= RemainingPoints; // calculate nr of correct points of poly + OutputLines(0, 0, CUTOUT); // subract given offsets -> E.x, E.y + + if(RemainingPoints) + CollectRemainingPoints(NumSegments, RemainingPoints); + + }while(RemainingPoints != 0); + } + + // get cutout holes (CIRCLEs) + ret = CollectBoardCutoutSegments(E, Layer3dBoardDimension, CIRCLE); + if(ret) + { + for(int i=0;i E.x, E.y + } + + // get cutouts from 3d-bottomlayer (for each device) + if(CollectBoardCutoutSegments(E, bLayer3Ddata, LINE)) + { + NumCutouts++; // increment board cutouts + SortPoints(E.name); // elementname + OutputLines(0, 0, CUTOUT); // subract given offsets -> E.x, E.y + } + + } //BRD.elements(E) + return; +} + + + +//////////////////////////////////////////////////// +void DoCutoutsFromBoardDirect(UL_BOARD BRD) +{ + // drill circles if linewidth = 0 + BRD.circles(CIR) // create circles direct from board + { + if(CIR.layer == Layer3dBoardDimension && CIR.width < (maxCutoutLineWidth+1)) + { + NumCutouts++; + IDF_Circle(CIR.x, CIR.y, CIR.x+CIR.radius, CIR.y, CUTOUT); + } + } + return; +} + + + +//////////////////////////////////////////////////// +void IDF_BoardHeader(UL_BOARD BRD) //-## create header of boardfile +{ + int t = time(); + string date; + string sourceID; + + sprintf(date, "%d/%02d/%02d.%02d:%02d:%02d", t2year(t), t2month(t), t2day(t), t2hour(t), t2minute(t), t2second(t)); + sprintf(sourceID, "Commend International >%s.ulp %s<", UlpName, UlpVersion); + + printf(".HEADER\n"); + printf("BOARD_FILE 3.0 \"%s\" %s 1\n", sourceID, date); + printf("\"%s\" MM\n", filename(BRD.name)); + printf(".END_HEADER\n"); + return; +} + + + +//////////////////////////////////////////////////// +void IDF_BoardOutline(UL_BOARD BRD) //-## create outline of board +{ + // get outline + CollectBoardOutlineSegments(BRD); + SortPoints("Board-Outline"); // boardname + + // draw outline + printf(".BOARD_OUTLINE UNOWNED\n"); + printf("%.6f\n", getPartHeight()); + OutputLines(0, 0, OUTLINE); // subract given offsets -> E.x, E.y + + // draw cutouts + DoCutoutsFromElements(BRD); // get cutouts from devices -> board is a device + + if(OutlineInDeviceFound) // get cutouts from board direct -> outline direct drawn in board + DoCutoutsFromBoardDirect(BRD); + + printf(".END_BOARD_OUTLINE\n"); + return; +} + + +//////////////////////////////////////////////////// +void IDF_BoardPlaceParts(UL_BOARD BRD) //-## mount parts on board +{ + int i, inlib; + string MountSide[] = {"TOP","BOTTOM"}; + + + printf(".PLACEMENT\n"); + + BRD.elements(E) + { + inlib = 0; + for(i=0; i more than one part on same x/y position + { + int lib_start = i; + + do + { + printf("%s_ANGLE%.1f_%s.%d CI_LIB %s.%d\n", E.package.name, E.angle, PacIn_LIB_SubPart_mountside[lib_start], PacIn_LIB_heights[lib_start], E.name, PacIn_LIB_heights[lib_start]); + printf("%.6f %.6f 0 0 %s PLACED\n", u2mm(E.x), u2mm(E.y), PacIn_LIB_SubPart_mountside[lib_start]); + lib_start++; + }while(PacIn_LIB_heights[lib_start] > 1); + } + } + } + + printf(".END_PLACEMENT\n"); + return; +} + + +//////////////////////////////////////////////////// +void IDF_BoardHoles(UL_BOARD BRD) //-## create holes in board (cutout, partholes, ...) +{ + printf(".DRILLED_HOLES\n"); + + // drill holes from board direct + BRD.holes(H) + printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y)); + + // drill holes from elements + BRD.elements(E) + { + E.package.holes(H) + printf("%.6f %.6f %.6f NPTH BOARD Other UNOWNED\n", u2mm(H.drill), u2mm(H.x), u2mm(H.y)); + } + + // drill big via's + BRD.signals(S) + { + S.vias(V) + { + if((DrillViaHoles == true) && (u2mm(V.drill) > MinViaHoleDia)) // drill via-hole + printf("%.6f %.6f %.6f PTH BOARD VIA UNOWNED\n", u2mm(V.drill), u2mm(V.x), u2mm(V.y)); + } + } + + printf(".END_DRILLED_HOLES\n"); + return; +} + + + +//////////////////////////////////////////////////// +void IDF_CreateLibaryFile(UL_BOARD BRD, string fname) // create libary for the IDF-board +{ + output(fname, "wt") + { + IDF_LibaryHeader(BRD); + IDF_LibaryElectrical(BRD); + IDF_LibaryMechanical(BRD); + } + return; +} + + +//////////////////////////////////////////////////// +void IDF_CreateBoardFile(UL_BOARD BRD, string fname) // create boardfile with parts of libary +{ + output(fname, "wt") + { + IDF_BoardHeader(BRD); + IDF_BoardOutline(BRD); + IDF_BoardHoles(BRD); + IDF_BoardPlaceParts(BRD); + } + return; +} + +//////////////////////////////////////////////////// +void IDF_CreatePanelFile(UL_BOARD BRD, string fname) // create panel, containing board and parts of libary +{ + // not yet implemented + return; +} + + + + +//////////////////////////////////////////////////// +void DisplayHelp(void) // show helptext +{ + dlgDialog("generation of different variants - Help") + { + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout + { + dlgVBoxLayout dlgSpacing(200); + dlgTextView(HelpText); + } + dlgHBoxLayout + { + dlgStretch(1); + dlgPushButton("-Close") dlgReject(); + } + }; + return; +} + + + +//////////////////////////////////////////////////// +// S T A R T of U L P +// +if (!board) +{ + dlgMessageBox(usage + "
    ERROR: No board!

    \nThis program can only work in the layout editor."); + exit(1); +} +else +{ + int proceed = 0; + string FilenameLibary; + string FilenameBoard; + string FilenamePanel; + + + + + project.board(BRD) + { + FilenameBoard = filesetext(BRD.name, ".emn"); + FilenameLibary = filesetext(BRD.name, ".emp"); + } + + dlgDialog("Generate 3D data format (IDF-file)") + { + dlgHBoxLayout + { + dlgGroup(" settings ") + { + dlgGridLayout + { + dlgCell(0,0) dlgCheckBox("close polygon if gap is smaller than : ", CloseOpenPoly); + dlgCell(0,1) dlgRealEdit(MaxGapWidth); + dlgCell(0,2) dlgLabel(" mm "); + + dlgCell(1,0) dlgCheckBox("drill via-holes if via is bigger than : ", DrillViaHoles); + dlgCell(1,1) dlgRealEdit(MinViaHoleDia); + dlgCell(1,2) dlgLabel(" mm "); + } + } + } + dlgHBoxLayout + { + dlgLabel("enter output-filename : "); + dlgStringEdit(FilenameBoard); + dlgPushButton("Browse") + { + string FileName = dlgFileSave("Save IDF file", FilenameBoard, "IDF files (*.emn)"); + if (FileName) + { + if(strchr(FileName, '.') < 0) // add fileextension if missing + FileName += ".emn"; + + FilenameLibary = filesetext(FileName, ".emp"); + FilenameBoard = FileName; + } + } + + } + dlgHBoxLayout + { + dlgPushButton("OK") + { + proceed = 1; + dlgAccept(); + } + + dlgPushButton("Help") + DisplayHelp(); + + dlgPushButton("Cancel") + dlgReject(); + } + }; + + + if(proceed) + { + project.board(BRD) + { + GetUlpName(); // gets ulp name + CollectPartData(BRD); // read out data from BRD + + IDF_CreateLibaryFile(BRD, FilenameLibary); + IDF_CreateBoardFile(BRD, FilenameBoard); + IDF_CreatePanelFile(BRD, FilenamePanel); + } + } +} \ No newline at end of file diff --git a/trunk/ulp/gluemark.ulp b/trunk/ulp/gluemark.ulp new file mode 100644 index 00000000..367fab70 --- /dev/null +++ b/trunk/ulp/gluemark.ulp @@ -0,0 +1,145 @@ +#usage "Export data for SMD glue dispenser equipment\n" + "

    " + "

      " + "
    • Define glue points in library as circles on tGlue layer. Use as many circles" + " per package as you like. If no circle is defined, one default point is used" + " (center of wires in tPlace layer)." + "
    • Run gluemark.ulp to generate circles on layers 111 and 112, indicating glue points" + " for smd packages on top or bottom layers." + "
    • Edit 111 + 112 if necessary (you can also add or delete circles) and then use" + " glueout4.ulp to generate data for glue dispenser. glueout.ulp has to be changed to" + " get the wanted data format." + "
    • Use gluetop.dat and gluebot.dat for your dispenser." + "
    " + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +//******* workaround due to beta version error +//all min function calls changed to minm, max changed to maxm +real minm(real a, real b) { + if (a <= b) return a; + else return b; + } +real maxm(real a, real b) { + if (a >= b) return a; + else return b; + } +//******* + +int issmd, gluedef, ontop; +real xmin , xmax, ymin, ymax, x, y; +string h, cmd; + +void setgluepoint(UL_ELEMENT E){ + gluedef = 0; + E.package.circles(CI){ + if (CI.layer == LAYER_TGLUE) { + x = u2inch(CI.x); y = u2inch(CI.y); + h = ""; + sprintf(h,"Layer tGTest;\nCircle 0.016 (%f %f) (%f %f);\n", x, y, x+0.016, y); + cmd += h; + gluedef = 1; + } + if (CI.layer == LAYER_BGLUE) { + x = u2inch(CI.x); y = u2inch(CI.y); + h = ""; + sprintf(h,"Layer bGTest;\nCircle 0.016 (%f %f) (%f %f);\n", x, y, x+0.016, y); + cmd += h; + gluedef = 1; + } + } + + xmin = u2inch(E.x); xmax = xmin; + ymin = u2inch(E.y); ymax = ymin; + if (gluedef == 0){ + E.package.wires(W){ + if (W.layer == LAYER_TPLACE) { + ontop = 1; + xmin = min(u2inch(W.x1),xmin);output("test.scr") {printf("u2iW.x%f\n",u2inch(W.x1));} + xmin = min(u2inch(W.x2),xmin); + ymin = min(u2inch(W.y1),ymin); + ymin = min(u2inch(W.y2),ymin); + xmax = max(u2inch(W.x1),xmax); + xmax = max(u2inch(W.x2),xmax); + ymax = max(u2inch(W.y1),ymax); + ymax = max(u2inch(W.y2),ymax); + } + if (W.layer == LAYER_BPLACE) { + ontop = 0; + xmin = min(u2inch(W.x1),xmin); + xmin = min(u2inch(W.x2),xmin); + ymin = min(u2inch(W.y1),ymin); + ymin = min(u2inch(W.y2),ymin); + xmax = max(u2inch(W.x1),xmax); + xmax = max(u2inch(W.x2),xmax); + ymax = max(u2inch(W.y1),ymax); + ymax = max(u2inch(W.y2),ymax); + } + } + x = (xmin+xmax)/2; y = (ymin+ymax)/2; + if (ontop == 1) { + h = ""; + sprintf(h,"LAYER tGTest;\nCircle 0.016 (%f %f) (%f %f);\n", x, y, x+0.016, y); + cmd += h; + } + if (ontop == 0) { + h = ""; + sprintf(h,"LAYER bGTest;\nCircle 0.016 (%f %f) (%f %f);\n", x, y, x+0.016, y); + cmd += h; + } + } +} + +cmd = ""; +h = ""; +sprintf(h,"Layer 111 tGTest;\n"); +cmd += h; +h = ""; +sprintf(h,"Layer 112 bGTest;\n"); +cmd += h; +h = ""; +sprintf(h,"Set Color_Layer 111 red;\n"); +cmd += h; +h = ""; +sprintf(h,"Set Color_Layer 112 blue;\n"); +cmd += h; +h = ""; +sprintf(h,"Grid inch;\n"); +cmd += h; + +if (board){ +board(B){ + B.elements(E) { + issmd = 0; + E.package.contacts(C) { + if (C.smd) { + issmd = 1; + break; + } + } + if (issmd) { + setgluepoint(E); + } + + } +} +// EditBox +int Result = dlgDialog("Edit and Execute") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+Execute") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; +if (!Result) exit(0); + +exit(cmd); + +} + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); +} diff --git a/trunk/ulp/glueout.ulp b/trunk/ulp/glueout.ulp new file mode 100644 index 00000000..f41c3c1c --- /dev/null +++ b/trunk/ulp/glueout.ulp @@ -0,0 +1,53 @@ +#usage "Export data for SMD glue dispenser equipment\n" + "

    " + "This program is used in conjunction with gluemark.ulp.
    " + "It generates top and bottom glue data from circles on layers 111 and 112." + "

    " + "Define output format in function outputdata." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string top_data_filename = "gluetop.dat"; +string bottom_data_filename = "gluebot.dat"; + +void outputdata (UL_CIRCLE C){ + +//**** change the following line to adjust the output format ****** + printf("Gluepoint coordinates: %f %f\n", u2inch(C.x),u2inch(C.y)); +} + +void header (UL_BOARD B){ + printf("#%s\n\n", EAGLE_SIGNATURE); + printf("#Gluepoints exported from %s\n#at %s\n\n", B.name, t2string(time())); +} + +if (board) { +output(top_data_filename) { + board(B){ + header(B); + B.circles(C){ + if (C.layer == 111) { + outputdata(C); + } + } + } +} + +output(bottom_data_filename) { + board(B){ + header(B); + B.circles(C){ + if (C.layer == 112) { + outputdata(C); + } + } + } +} +} + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); +} diff --git a/trunk/ulp/hyperlynx.ulp b/trunk/ulp/hyperlynx.ulp new file mode 100644 index 00000000..926b4222 --- /dev/null +++ b/trunk/ulp/hyperlynx.ulp @@ -0,0 +1,1641 @@ +#usage "nobr>Exports the board to HyperLynx Signal-Integrity Transfer Format (.HYP)

    " + "* HyprLynx.ULP Written by Frank Hoffman of LLOYD I/O INC
    " + "* Copyright (c) 1997, All Rights Reserved by LLOYD I/O INC
    " + "Author 503/222-0702 frankh@lloydio.com www.lloydio.com" + "

    " + "* 1 sided boards use layer 16
    " + "* 2 sided boards use layers 1 and 16
    " + "* 4 layer boards use layers 1,2 and 15, 16
    " + "* 6 layer boards use layers 1,2,3 and 14,15,16
    " + "* 8 layer boards use layers 1,2,3,4 and 13,14,15,16
    " + "* 10 layer boards use layers 1,2,3,4,5 and 12,13,14,15,16
    " + "* 12 layer boards use layers 1,2,3,4,5,6 and 11,12,13,14,15,16
    " + "* 14 layer boards use layers 1,2,3,4,5,6,7 and 10,11,12,13,14,15,16
    " + "* 16 layer boards use layers 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
    " + "*
    " + "* Adapted for Eagle-Version 4.1
    " + "* - Unrouted layer not exported
    " + "* - Export also Wire-Arcs
    " + "* - SMD shape Roundnes is included
    " + "* - PAD shape LONG OFFSET (Oblong) is included
    " + "* - PAD accept Top, Bottom and Inner (MDEF) layer
    " + "* - VIA generate only used layer in stack
    " + "* 02.04.2004 alf@cadsoft.de
    " + "* - W.curve correction in C.element.package.wires(W)
    " + "* 21.04.2005 alf@cadsoft.de
    " + "* - {PADSTACK=...%03d correct number while count from 1
    " + "* 17.08.2005 alf@cadsoft.de
    " + "* - First check filling of polygons and start Ratsnest
    " + "* Export calculated polygon contours and filling
    " + "* 11.03.2012 alf@cadsoft.de
    " + "* - Check if polygon placed
    " + "* 17.12.2012 alf@cadsoft.de
    " + "*
    "; + + +// Version 4.11 : W.curve correction in C.element.package.wires(W) 21.04.2005 +// Version 4.12 : Correct Padstack number while list from 0 (zerro) 03.05.2005 +// The original ULP counts the PADSTACK-List from 1 (+1), +// the used Pads counts from 0 ! *** 03.05.2005 +// Version 4.13 : Correct Padstack counter in for { loop } *** 11.08.2005 +// Check if a SMD-Pad dx=0 or dy=0 then aborted this ULP RUN. +// Version 4.14 : Correct Padstack counter in all function, count now from 1 to total_pad +// eliminate correction of 4.12 from 03.05.2005 +// Version 4.15 : First check filling of polygons and start Ratsnest +// Export calulated polygon contours and filling +// Version 4.16 : Check if a polygon placed to start first RATSNEST + +string Version = "Version 2.00 9/11/97 -- 4.16 17/12/2012"; + + +string headerline = "* Exports the board to HyperLynx Signal-Integrity Transfer Format (.HYP)"; + + + +//*********************************************** +// Definitions of yes and no! Do not modify! +char yes = 1; // yes must be different from no. +char no = 0; // no must be zero (0) +//******************************************************************************************** +//******************************************************************************************** +//******************************************************************************************** +// USER MODIFYABLE DATA + +// Generate Files Options: +char GenerateReferenceFile = yes; // Generate the Reference File ('yes'/'no') +char GenerateHyperlynxFile = yes; // Generate the Hyperlynx File ('yes'/'no') + +// Generate Component Types Options: +char UseComponentTypes = yes; // Devices Q, T, U, IC, C, D, L, R, BD, etc. ('yes'/'no') + +// Generate Component Pin Direction Options: +char GeneratePinDirection = no; // If 'yes', slows down many many times. + +// Component Value Change Options: +char TruncateComponentValues = no; // Truncate ".1uf 50v" to ".1uf" ('yes'/'no') +char ConvertCapValues = yes; // Convert Capacitor Values. i.e. change ".1" to ".1u" ('yes'/'no') +string ConvertLT1to = "uF"; // values less than 1 are labeled as this unit +string ConvertGE1to = "uF"; // convert greater than or equal to 1 are labeled as this unit + +// Board Thickness AND Stack Up Options: +char UseBoardStackUp = yes; // Use board thickness data ('yes'/'no') +real board_thickness = 0.0625; // Board Thickness, if 0: use fixed layer sizes else calc layer thicknesses + +// Copper Value Options: +real zerooz = 0.0000; // zero copper thickness +real halfoz = 0.0007; // 0.5 oz copper thickness +real oneoz = 0.0014; // 1.0 oz copper thickness +real twooz = 0.0028; // 2.0 oz copper thickness +// Copper Layer Thickness for Each Layer of Copper +real copper_thickness[] = {0.0, halfoz,halfoz,halfoz,halfoz,halfoz,halfoz, + halfoz,halfoz,halfoz,halfoz,halfoz,halfoz, + halfoz,halfoz,halfoz,halfoz}; // 1st number is not used (no layer 0) +// Copper Layer Plating Thickness for Each Layer of Copper. +// Top and Bottom are used most often. +real copper_plating[] = {0.0, halfoz,zerooz,zerooz,zerooz,zerooz,zerooz, + zerooz,zerooz,zerooz,zerooz,zerooz,zerooz, + zerooz,zerooz,zerooz,halfoz}; // 1st number is not used (no layer 0) + +// Dielectric Value Options: +real dicons = 4.8; // default dielectric constant +real dit1ly = 0.0611; // dielectric thickness for 1 sided board +real dit2ly = 0.0597; // dielectric thickness for 2 sided board +real ditmly = 0.0200; // dielectric thickness for multilayered boards +real dielectric_constant[] = { dicons,dicons,dicons,dicons,dicons,dicons,dicons,dicons,dicons}; +real dielectric_thickness[] = { dit1ly,dit2ly,ditmly,ditmly,ditmly,ditmly,ditmly,ditmly,ditmly}; + +// Special Wire Width Options: +real RectOutlineWireWidth = 0.001; // Rectangle outline wire width in inches +real HoleOutlineWireWidth = 0.001; // Holes outline wire width in inches + +// Precision of board components to accurately draw and locate. +// (After the decimal '.' point.) +int precision_of_perimeter = 4; // board perimeter dimension precision +int precision_of_layers = 5; // layer thickness precision +int precision_of_pads = 3; // pad/smd size precision +int precision_of_nets = 4; // pin/via/segment/width precision + + +//******************************************************************************************** +//******************************************************************************************** +//******************************************************************************************** +// DO NOT MODIFY ANYTHING BELOW THIS LINE // + +int index[]; // sorting index array (indirect) + +// pad info +int ISAPAD = 0; // through hole pad +int ISASMD = 1; // surface mount device pad +int ISAVIA = 18; // + +// *** HyperLynx pad shapes *** +int OVALROUND = 0; // '0' means oval or round (pad_sx=pad_sy if round) +int RECTSQUARE = 1; // '1' means rectangular or square (pad_sx=pad_sy if square) +int OBLONG = 2; // '2' means oblong (oblong shape is a rectangular with rounded corners) + +string PadShapes[]; // list of hyp's pad shapes +string HypPadShapes[]; // list of hyp's pad shapes +string EaglePadShapes[]; // list of eagle pad shapes +int Total_Pads = 0; // total pads +int pad_type[]; // pad types (ISAPAD,ISASMD) +int pad_layer[]; // 0 = Pad, 1 or 16 = SMD, 18 = Via +int pad_shape_Top_rnds[]; // hyperlynx type OVALROUND, RECTSQUARE, OBLONG +int pad_shape_Inner[]; // hyperlynx type OVALROUND, RECTSQUARE, OBLONG +int pad_shape_Bott[]; // hyperlynx type OVALROUND, RECTSQUARE, OBLONG +real pad_angle_end[]; // Pad rotation or Via End layer (Vias can not rotate!) +int pad_diameter_Top_or_dx[]; +int pad_diameter_Inner[]; +int pad_diameter_Bott[]; +int pad_dy_elong_start[]; // SMD-dy, Pad-Elongation, Via Stack-Start +int pad_drill[]; + +string padStackList = "#\ttype\tlayer\tTop_rnd\tInner\tBott\tang_end\tdx_T\tdx_I\tdx_B\tdy_el\tdril\n"; + + + + +// copper layer info +string LayerNames[]; // layer names +int copp_lookup[] = {0, 1,16, 2,15, 3,14, 4,13, 5,12, 6,11, 7,10, 8,9 }; +int copp_used_layer[]; +int Total_Layers; // total number of used layers +int layer_counter; // layer counter +real Total_Board_Thickness; // calculated total board thickness + +/* ----- Eagle HELP -------------------------------- +PAD_SHAPE_SQUARE square +PAD_SHAPE_ROUND round +PAD_SHAPE_OCTAGON octagon +PAD_SHAPE_LONG long +PAD_SHAPE_OFFSET offset +PAD_SHAPE_ANNULUS annulus (only in Supply-Layer) +PAD_SHAPE_THERMAL thermal (only in Supply-Layer) +-------------------------------------------------- */ + +// define the HyperLynx Pad Shapes +PadShapes[ PAD_SHAPE_SQUARE ] = "1"; // hyp's square and rectangle shape +HypPadShapes[ PAD_SHAPE_SQUARE ] = "Square"; // HyperLynx's square and rectangle shape +EaglePadShapes[ PAD_SHAPE_SQUARE ] = "Square"; // Eagle's square and rectangle shape +PadShapes[ PAD_SHAPE_ROUND ] = "0"; // hyp's round and oval shape +HypPadShapes[ PAD_SHAPE_ROUND ] = "Round"; // HyperLynx's round and oval shape +EaglePadShapes[ PAD_SHAPE_ROUND ] = "Round"; // Eagle's round and oval shape +PadShapes[ PAD_SHAPE_OCTAGON ] = "0"; // hyp's octagon is a round shape +HypPadShapes[ PAD_SHAPE_OCTAGON ] = "Round"; // HyperLynx's octagon is a round shape +EaglePadShapes[ PAD_SHAPE_OCTAGON ] = "Octagon"; // Eagle's octagon is a round shape +PadShapes[ PAD_SHAPE_LONG ] = "2"; // hyp's oblong, rectangle with rounded corners +HypPadShapes[ PAD_SHAPE_LONG ] = "Oblong"; // HyperLynx's oblong, rectangle with rounded corners +EaglePadShapes[ PAD_SHAPE_LONG ] = "Long"; // Eagle's oblong, rectangle with rounded corners +PadShapes[ PAD_SHAPE_OFFSET ] = "0"; // hyp's round and oval shape +HypPadShapes[ PAD_SHAPE_OFFSET ] = "Round"; // HyperLynx's oblong, rectangle with rounded corners +EaglePadShapes[ PAD_SHAPE_OFFSET ] = "Offset"; // Eagle's (Long) Offset, rectangle with rounded corners + + + +// *************************************************************************** +// layers + +// This routine counts visible layers and stores the name in an internal table +// Layer names beginning with '$' have the leading '$' striped. +// This routine is called from a loop +void CountLayers(UL_LAYER L) { + if ( ( L.number >= 1 ) && ( L.number <= 16 ) ) { + if ( strchr( L.name, '$' ) == 0 ) { + LayerNames[L.number] = strsub( L.name, 1 ); + } + else { + LayerNames[L.number] = L.name; + } + if (L.visible) { + layer_counter++; + if (L.used) copp_used_layer[L.number] = 1; + } + } +} + +// This routine writes out the layer names as signal layers or power planes +// It also writes out the dielectric layer info when needed +// This routine is called from a loop +string layernam; // layer name buffer +void PrintLayer(UL_LAYER L) { + real diele_thickness; // calculated dielectric thickness + real copp_thickness; // calculated total copper thickness + int i; // loop counter + if (L.visible) { + if ( L.number >= 1 && L.number <= 16 ) { + if ( strchr( L.name, '$' ) == 0 ) { // ** is it a Power plane? + layernam = strsub( L.name, 1 ); + printf("(PLANE T=%6.*f L=%s)\n", + precision_of_layers, copper_thickness[L.number], layernam); + } + else { + printf("(SIGNAL T=%6.*f P=%6.*f L=%s)\n", + precision_of_layers, copper_thickness[L.number], + precision_of_layers, copper_plating[L.number], + L.name); + } + layer_counter++; + if (board_thickness) { + Total_Board_Thickness = board_thickness; + copp_thickness = 0.0; + for (int i = 1; i <= Total_Layers; i++ ) { + copp_thickness += copper_thickness[copp_lookup[i]] + copper_plating[copp_lookup[i]]; + } + if (Total_Layers <= 2 ) diele_thickness = ( board_thickness - copp_thickness ); + else diele_thickness = ( board_thickness - copp_thickness ) / ( real(Total_Layers) - 1.00 ); + } + else { + diele_thickness = dielectric_thickness[Total_Layers/2]; + copp_thickness = 0.0; + for (int i = 1; i <= Total_Layers; i++ ) { + copp_thickness += copper_thickness[copp_lookup[i]] + copper_plating[copp_lookup[i]]; + } + if (Total_Layers <= 2 ) Total_Board_Thickness = copp_thickness + diele_thickness; + else Total_Board_Thickness = copp_thickness + (diele_thickness * ( real(Total_Layers) - 1.00 )); + } + if (layer_counter < Total_Layers) { + printf("(DIELECTRIC T=%6.*f C=%4.*f ", + precision_of_layers,diele_thickness, + precision_of_layers,dielectric_constant[Total_Layers/2]); + printf("L=DL%02d)\n",layer_counter); + } + if (Total_Layers == 1) { + printf("(DIELECTRIC T=%6.*f C=%4.*f ", + precision_of_layers,diele_thickness, + precision_of_layers,dielectric_constant[Total_Layers/2]); + printf("L=DL%02d)\n",layer_counter); + } + } + } +} + + + +// *************************************************************************** +// pads + +int search_A_Pad( int apad_type, int apad_layer, + int apad_shape_Top_rnds, int apad_shape_Inner, int apad_shape_Bott, + real apad_angle_end, + int apad_dx_Top, int apad_dx_Inner, int apad_dx_Bott, + int apad_dy_elong_start, + int apad_dril ) { + int found = 0; + for ( int i = 1; i <= Total_Pads; i++ ) { + if ( pad_type[i] == apad_type && + pad_layer[i] == apad_layer && + pad_shape_Top_rnds[i] == apad_shape_Top_rnds && + pad_shape_Inner[i] == apad_shape_Inner && + pad_shape_Bott[i] == apad_shape_Bott && + pad_angle_end[i] == apad_angle_end && + pad_diameter_Top_or_dx[i] == apad_dx_Top && + pad_diameter_Inner[i] == apad_dx_Inner && + pad_diameter_Bott[i] == apad_dx_Bott && + pad_dy_elong_start[i] == apad_dy_elong_start&& + pad_drill[i] == apad_dril ) + { + found = i; + break; + } + } + return( found); +} + +// This routine inserts a pad of known type and size into the pad table +// The returned value reflects the current number of pads in the table +// If the pad size already exists, the pad is not inserted + +void Insert_A_Pad( int apad_type, int apad_layer, + int apad_shape_Top_rnds, int apad_shape_Inner, int apad_shape_Bott, + real apad_angle_end, + int apad_dx_Top, int apad_dx_Inner, int apad_dx_Bott, + int apad_dy_elong_start, + int apad_dril ) { + + int fnd = search_A_Pad( apad_type, apad_layer, apad_shape_Top_rnds, apad_shape_Inner, apad_shape_Bott, apad_angle_end, apad_dx_Top, apad_dx_Inner, apad_dx_Bott, apad_dy_elong_start, apad_dril); + if (fnd == 0) { + Total_Pads++; + pad_type[Total_Pads] = apad_type; + pad_layer[Total_Pads] = apad_layer; + pad_shape_Top_rnds[Total_Pads] = apad_shape_Top_rnds; + pad_shape_Inner[Total_Pads] = apad_shape_Inner; + pad_shape_Bott[Total_Pads] = apad_shape_Bott; + pad_angle_end[Total_Pads] = apad_angle_end; + pad_diameter_Top_or_dx[Total_Pads] = apad_dx_Top; + pad_diameter_Inner[Total_Pads] = apad_dx_Inner; + pad_diameter_Bott[Total_Pads] = apad_dx_Bott; + pad_dy_elong_start[Total_Pads] = apad_dy_elong_start; + pad_drill[Total_Pads] = apad_dril; + } + return; +} + +// This routine finds a pad of a known type and size and returns the ID +// of the pad (internal number) that is used to identify the pad. + +int Find_A_Pad( int apad_type, int apad_layer, + int apad_shape_Top_rnds, int apad_shape_Inner, int apad_shape_Bott, + real apad_angle_end, + int apad_dx_Top, int apad_dx_Inner, int apad_dx_Bott, + int apad_dy_elong_start, + int apad_dril ) { + int fnd = search_A_Pad( apad_type, apad_layer, apad_shape_Top_rnds, apad_shape_Inner, apad_shape_Bott, apad_angle_end, apad_dx_Top, apad_dx_Inner, apad_dx_Bott, apad_dy_elong_start, apad_dril); + return( fnd ); +} + +// This routine finds the HyperLynx shape form of eagle shape +int SmdRoundness(int r) { + if (r == 100) return 0; // oval or round + if (r == 0) return 1; // rect or square + return 2; // oblong +} + + +// Insert a pin on in a list of associated connected contacts +int AssPinCount = 0; // Number of associated Contacts +string AssTabEname[]; // Element Name +string AssTabCname[]; // Contact Name +int AssTabLenEname[]; // Element Name Length +int AssTabLenCname[]; // Contact Name Length +int InsertAssocatedPin( string ename, string cname ) { + int lenofename,lenofcname; + lenofename = strlen(ename); + lenofcname = strlen(cname); + if ( AssPinCount > 0 ) { + for ( int i = 0; i < AssPinCount; i++ ) { + if ( lenofename == AssTabLenEname[i] ) + if ( lenofcname == AssTabLenCname[i] ) + if ( strstr( AssTabEname[i], ename ) != -1 ) + if ( strstr( AssTabCname[i], cname ) != -1 ) return( AssPinCount ); + } + } + AssTabEname[AssPinCount] = ename; + AssTabCname[AssPinCount] = cname; + AssTabLenEname[AssPinCount] = lenofename; + AssTabLenCname[AssPinCount] = lenofcname; + AssPinCount++; + return( AssPinCount ); +} + +int FindAssocatedPin( string ename, string cname ) { + int lenofename,lenofcname; + lenofename = strlen(ename); + lenofcname = strlen(cname); + if ( AssPinCount > 0 ) { + for ( int i = 0; i < AssPinCount; i++ ) { + if ( lenofename == AssTabLenEname[i] ) + if ( lenofcname == AssTabLenCname[i] ) + if ( strstr( AssTabEname[i], ename ) != -1 ) + if ( strstr( AssTabCname[i], cname ) != -1 ) return( AssPinCount ); + } + } + return( 0 ); +} + +// write a divider +void printdivider( void ) { + printf("**********************************************************************\n"); + return; +} + +// write a section header with dividers +void printheader(string hs) { + printdivider(); + printf("* %s\n*\n",hs); + return; +} + +// write translated package types from Eagle to Hyperlynx +int saypackagetype(string pn) { + if ( strstr( pn,"TSSOP" ) != -1 ) { + printf(" PKG=TSSOP"); + } + else if ( strstr( pn,"TQFP" ) != -1 ) { + printf(" PKG=TQFP"); + } + else if ( strstr( pn,"SSOP" ) != -1 ) { + printf(" PKG=SSOP"); + } + else if ( strstr( pn,"PLCC" ) != -1 ) { + printf(" PKG=PLCC"); + } + else if ( strstr( pn,"LCC" ) != -1 ) { + printf(" PKG=LCC"); + } + else if ( strstr( pn,"DIP" ) != -1 ) { + printf(" PKG=DIP"); + } + else if ( strstr( pn,"QFP" ) != -1 ) { + printf(" PKG=QFP"); + } + else if ( strstr( pn,"BGA" ) != -1 ) { + printf(" PKG=BGA"); + } + else if ( strstr( pn,"PGA" ) != -1 ) { + printf(" PKG=PGA"); + } + else if ( strstr( pn,"DIL" ) != -1 ) { + printf(" PKG=DIP"); + } + else if ( strstr( pn,"DIP" ) != -1 ) { + printf(" PKG=DIP"); + } + else if ( strstr( pn,"SO" ) != -1 ) { + printf(" PKG=SO"); + } + else return( no ); // no package type recognized + return( yes ); // yes, package recognized +} + + +// truncate trailing zeros and print value +void TruncateTrailingZeros( real value, int prec ) { + string num; + int nlen; + sprintf( num, "%1.*f", prec, value ); + nlen = strlen( num ); + if ( nlen > 0 ) { + while ( num[ nlen-1 ] == '0' ) { + // truncate with a null + num[ nlen-1 ] = 0; + // recalc string length + nlen = strlen( num ); + if ( nlen == 0 ) break; + } + } + printf("%s",num); + return; +} + +// Convert Capacitor Values. i.e. change ".1" to ".1u" +// char ConvertCapValues = yes; +// Cap value conversion rules for values without suffix multipliers +// string ConvertLT1to = "u"; // values less than 1 are "u" or "something else" +// string ConvertGE1to = "u"; // convert greater than or equal to 1 as "u" or "p" +// +void ConvertCapValue( string capvalue ) { + char cstate; // state machine + char clabel; // unit label + real cvalue; // the value of the capacitor + int lenofcapvalue; // length of the string for parsing + + if ( ConvertCapValues == yes ) { + cvalue = strtod( capvalue ); + if ( cvalue != 0.0 ) { + lenofcapvalue = strlen( capvalue ); + cstate = 1; // set state for searching digits + for ( int i=0; i 0 ) { + ICreflib = "74" + strsub( ICvalue, 2, ICccnt ) + ".PML"; + } + else { + ICreflib = "74TTL.PML"; + } + } else + if ( strstr( ICvalue, "40" ) == 0 ) { + unknownIC = no; + ICreflib = "74HC.PML"; + ICvalue = "74HC" + ICvalue; + } + if ( unknownIC == no ) { + printf("%s, %s, %s",ICname,ICreflib,ICvalue); + ICpn =E.package.name; + if ( strstr( ICpn,"TSSOP" ) != -1 ) { + printf("_TSSOP"); + } + else if ( strstr( ICpn,"TQFP" ) != -1 ) { + printf("_TQFP"); + } + else if ( strstr( ICpn,"SSOP" ) != -1 ) { + printf("_SSOP"); + } + else if ( strstr( ICpn,"PLCC" ) != -1 ) { + printf("_PLCC"); + } + else if ( strstr( ICpn,"LCC" ) != -1 ) { + printf("_LCC"); + } + else if ( strstr( ICpn,"DIP" ) != -1 ) { + printf("_DIP"); + } + else if ( strstr( ICpn,"QFP" ) != -1 ) { + printf("_QFP"); + } + else if ( strstr( ICpn,"BGA" ) != -1 ) { + printf("_BGA"); + } + else if ( strstr( ICpn,"PGA" ) != -1 ) { + printf("_PGA"); + } + else if ( strstr( ICpn,"DIL" ) != -1 ) { + printf("_DIP"); + } + else if ( strstr( ICpn,"DIP" ) != -1 ) { + printf("_DIP"); + } + else if ( strstr( ICpn,"SO" ) != -1 ) { + printf("_SSOP"); + } + printf("\n"); + } + } + } + } + } + + if ( GenerateHyperlynxFile == no ) { + exit( EXIT_SUCCESS ); + } + output( filesetext( B.name, ".HYP" ) ) { + printdivider(); + printf("%s\n", headerline); // 03.05.2005 alf@cadsoft.de + printf("* %s\n*\n", Version); + printf("* %s\n*\n", EAGLE_SIGNATURE); + printf("* HyperLynx Board exported from:\n"); + printf("* %s\n", B.name); + printf("* At %s\n*\n", t2string(time())); + + if (project.schematic) { + printf("* Schematic is loaded.\n"); + } + else { + printf("* Schematic NOT is loaded.\n"); + } + printf("*\n\n"); + printf("{VERSION=2.10} Compatible with Hyperlynx version 2.10.\n"); + printf("{UNITS=ENGLISH WEIGHT}\n\n"); + + // BOARD OVERALL AREA DIMENSIONS + // Writes the board dimensions found on layer 20 + printheader("Board Dimensions"); + printf("{BOARD\n"); + // wires on the dimension layer + B.wires(W) { + if (W.layer == 20 ) { + if (W.curve) { + // arcs in the dimension layer + printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Arcs: Board Outline Arc is CCW\n", + precision_of_nets,u2inch(W.arc.x1),precision_of_nets,u2inch(W.arc.y1), + precision_of_nets,u2inch(W.arc.x2),precision_of_nets,u2inch(W.arc.y2), + precision_of_nets,u2inch(W.arc.xc),precision_of_nets,u2inch(W.arc.yc), + precision_of_nets,u2inch(W.arc.radius) ); + } + else { + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Wires: From Board\n", + precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1), + precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2)); + } + } + } + // rectangles on the dimension layer + B.rectangles(R) { + if (R.layer == 20 ) { + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Bottom\n", + precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1), + precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1) ); + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Right\n", + precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1), + precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2) ); + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Top\n", + precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2), + precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2) ); + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Left\n", + precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2), + precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1) ); + } + } + // polygons on the dimension layer + B.polygons(P) { + if (P.layer == 20 ) { + P.wires(W) { + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Polygon Wires: From Board\n", + precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1), + precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2)); + } + } + } + // circles in the dimension layer + B.circles(C) { + if (C.layer == 20 ) { + printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Circles: Board Outline Arc is CCW\n", + precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius), + precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius), + precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y), + precision_of_nets,u2inch(C.radius) ); + } + } + // holes in the board + int halfdrilldiameter; + B.holes(H) { + halfdrilldiameter = H.drill / 2; + printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Holes: Board Outline Arc is CCW\n", + precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter), + precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter), + precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y), + precision_of_nets,u2inch(halfdrilldiameter) ); + } + // package wires on the dimension layer + B.elements(E) { + E.package.wires(W) { + if (W.layer == 20 ) { + if (W.curve) { + // package arcs in the dimension layer + printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Arcs: Board Outline Arc is CCW Package %s in %s.LBR\n", + precision_of_nets,u2inch(W.arc.x1),precision_of_nets,u2inch(W.arc.y1), + precision_of_nets,u2inch(W.arc.x2),precision_of_nets,u2inch(W.arc.y2), + precision_of_nets,u2inch(W.arc.xc),precision_of_nets,u2inch(W.arc.yc), + precision_of_nets,u2inch(W.arc.radius), + E.package.name,E.package.library ); + } + else { + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Wires: From Package %s in %s.LBR\n", + precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1), + precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2), + E.package.name,E.package.library); + } + } + } + // package rectangles on the dimension layer + E.package.rectangles(R) { + if (R.layer == 20 ) { + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Bottom\n", + precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1), + precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1), + E.package.name,E.package.library ); + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Right\n", + precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1), + precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2), + E.package.name,E.package.library ); + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Top\n", + precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2), + precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2), + E.package.name,E.package.library ); + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Left\n", + precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2), + precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1), + E.package.name,E.package.library ); + } + } + // package polygons on the dimension layer + E.package.polygons(P) { + if (P.layer == 20 ) { + P.wires(W) { + printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Polygon Wires: From Package %s in %s.LBR\n", + precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1), + precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2), + E.package.name,E.package.library); + } + } + } + // package circles in the dimension layer + E.package.circles(C) { + if (C.layer == 20 ) { + printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Circles: Board Outline Arc is CCW Package %s in %s.LBR\n", + precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius), + precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius), + precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y), + precision_of_nets,u2inch(C.radius), + E.package.name,E.package.library ); + } + } + // package holes + int halfdrilldiameter; + E.package.holes(H) { + halfdrilldiameter = H.drill / 2; + printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Holes: Board Outline Arc is CCW Package %s in %s.LBR\n", + precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter), + precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter), + precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y), + precision_of_nets,u2inch(halfdrilldiameter), + E.package.name,E.package.library ); + } + } + printf("}\n\n"); + + // LAYER INFORMATION + printheader("Thickness of Copper and Dielectric Layer Data"); + if ( UseBoardStackUp == yes ) { + printf("{STACKUP\n"); + layer_counter = 0; + B.layers(L) CountLayers(L); + Total_Layers = layer_counter; // remember active layers + layer_counter = 0; + B.layers(L) PrintLayer(L); + printf("}\n"); + // TOTAL BOARD THICKNESS + printf("* Total Board Thickness %6.4f inch\n\n",Total_Board_Thickness); + } + else { + printf("* No PCB Thickness Data Generated !!! \n*\n\n"); + } + + // PACKAGES ON THE BOARD + printheader("Components"); + printf("{DEVICES\n"); + int unknowncomponenttype, pincount, componentspace; + string componentname; + string componentvalue; + B.elements(E) { + // get the number of pins + pincount = 0; + E.package.contacts(C) { + pincount++; + } + // set component as unknown + unknowncomponenttype = yes; + // remember component reference designator + componentname = E.name; + // truncate component values at the first space + // ? ASK HYPERLYNX : what about something like .1u 50v + componentvalue = E.value; + if ( TruncateComponentValues == yes ) + if ( ( componentspace = strchr( componentvalue, ' ' ) ) != -1 ) + componentvalue = strsub( componentvalue, 0, componentspace ); + // parse reference designators ? + if ( UseComponentTypes == yes ) { + if ( strstr( componentname, "IC" ) == 0 ) { + if ( isdigit( componentname[2] ) ) { + printf("(IC REF=%s NAME=%s L=%s",componentname,componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + saypackagetype(E.package.name); + unknowncomponenttype = no; + } + } + else if ( strstr( componentname, "BD" ) == 0 ) { + if ( isdigit( componentname[2] ) ) { + printf("(BD REF=%s NAME=%s L=%s",componentname,componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + unknowncomponenttype = no; + } + } + else if ( strstr( componentname, "BEAD" ) == 0 ) { + if ( isdigit( componentname[4] ) ) { + printf("(BD REF=%s NAME=%s L=%s",componentname, componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + unknowncomponenttype = no; + } + } + else if ( isdigit( componentname[1] ) ) { + if ( strchr( componentname, 'U' ) == 0 ) { + printf("(IC REF=%s NAME=%s L=%s",componentname, componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + saypackagetype(E.package.name); + unknowncomponenttype = no; + } + else if ( strchr( componentname, 'C' ) == 0 ) { + printf("(C REF=%s VAL=",componentname); + ConvertCapValue(componentvalue); + printf(" L=%s",E.mirror ? LayerNames[16] : LayerNames[1] ); + unknowncomponenttype = no; + } + else if ( strchr( componentname, 'R' ) == 0 ) { + printf("(R REF=%s VAL=%s L=%s",componentname, componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + unknowncomponenttype = no; + } + else if ( strchr( componentname, 'L' ) == 0 ) { + printf("(L REF=%s VAL=%s L=%s",componentname, componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + unknowncomponenttype = no; + } + else if ( strchr( componentname, 'D' ) == 0 ) { + printf("(CR REF=%s NAME=%s L=%s",componentname, componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + unknowncomponenttype = no; + } + else if ( strchr( componentname, 'J' ) == 0 ) { + printf("(J REF=%s NAME=%s L=%s",componentname, componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + unknowncomponenttype = no; + } + else if ( strchr( componentname, 'Q' ) == 0 ) { + printf("(J REF=%s NAME=%s L=%s",componentname, componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + unknowncomponenttype = no; + } + else if ( strchr( componentname, 'T' ) == 0 ) { + printf("(J REF=%s NAME=%s L=%s",componentname, componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + unknowncomponenttype = no; + } + } + } + + // handle unknown component types + if ( ( unknowncomponenttype == yes ) || ( UseComponentTypes == no ) ) { + printf("(? REF=%s NAME=%s L=%s",componentname,componentvalue, + E.mirror ? LayerNames[16] : LayerNames[1] ); + saypackagetype(E.package.name); + } + + // append comment field + printf(") R%03.0f X=%5.*f Y=%5.*f : ",E.angle,precision_of_nets,u2inch(E.x), + precision_of_nets,u2inch(E.y) ); + printf(" Lib: %s : %s : ", E.package.library, E.package.name); + printf("Pins %d", pincount); + printf("\n"); + } + printf("}\n\n"); + + + // PADSTACK CREATION OF PADS, SMDS, AND VIAS + // create list of all the different pads and smds (vias are pads) + printheader("Pads, Smds, and Via Library"); + // handle all net contacts and vias + B.signals(S) { + S.vias(V) { + Insert_A_Pad( ISAPAD, ISAVIA, + V.shape[1], V.shape[2], V.shape[16], + V.end, + V.diameter[1], V.diameter[2], V.diameter[16], + V.start, + V.drill ); + } + } + // handle all package pins + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + Insert_A_Pad( ISAPAD, ISAPAD, + C.pad.shape[1], C.pad.shape[2], C.pad.shape[16], + C.pad.angle, + C.pad.diameter[1], C.pad.diameter[2], C.pad.diameter[16], + C.pad.elongation, + C.pad.drill ); + } + else if (C.smd) { + if ( !C.smd.dx || !C.smd.dy) { + string h; + sprintf(h, "!Found a SMD-Pad with dx or dy = 0 (Zerro)
    Pad %s'
    Layer %d
    Coordinate (%.4f %.4f) mil
    Package %s.PAC
    Element %s
    Library %s.lbr

    ULP aborted.", + C.name, + C.smd.layer, + u2mil(C.x), u2mil(C.y), + E.package.name, + E.name, + E.package.library + ); + dlgMessageBox( h, "OK"); + exit(0); + } + else { + Insert_A_Pad( ISASMD, C.smd.layer, + SmdRoundness(C.smd.roundness), 0, 0, + C.smd.angle, + C.smd.dx, 0, 0, + C.smd.dy, + 0 ); + } + } + } + } + + // write out sorted list of the pads and smds + if (Total_Pads) { + /* *** Hyperlynx documentation ************************************* + {PADSTACK=padstack_name, // ** maximum of 32 characters an cannot contain white space + [drill_size] + (layer_name, + pad_shape, // '0' means oval or round (pad_sx=pad_sy if round) + // '1' means rectangular or square (pad_sx=pad_sy if square) + // '2' means oblong (oblong shape is a rectangular with rounded corners) + pad_sx, + pad_sy, + pad_angle, // is the counter-clockwise rotation angle of the pad in degree; + // rotation angle can range from 0.0 to +/-359.999; + // valid angular resolution is 0.001 degree; + // 0 (without a decimal point) is th recommended way of specifying 'no rotation' + [thermal_clear_shape], + [thermal_clear_sx], + [thermal_clear_sy], + [thermal_clear_angle], + [pad_type]) + ***************************************************************** */ + + string s; + for (int i = 1; i <= Total_Pads; i++) { // *** 17.08.2005 count from 1 *** + if (pad_layer[i] == 0) s = "ISAPAD"; + if (pad_layer[i] == 1 || pad_layer[i] == 16) s = "ISASMD"; + if (pad_layer[i] == 18) s = "ISAVIA"; + if (pad_type[i] == ISASMD) { + printf("{PADSTACK=SMD%03d\n",i); // **** 17.08.2005 alf@cadsoft.de *** + // smds are square, round or oblong + + // * if you wish layer name for layer number remark * + // * this next 2 lines und mark the second 2 lines * + // printf("(%s,%d,%5.*f,%5.*f,%.1f) Shape was Smd and is now Smd\n", + // LayerNames[pad_layer[i]], // Layer name + + printf("(%d,%d,%5.*f,%5.*f,%.1f) %s Shape was Smd and is now Smd\n", + pad_layer[i], // Layer number + pad_shape_Top_rnds[i], + precision_of_pads, u2inch(pad_diameter_Top_or_dx[i]), + precision_of_pads, u2inch(pad_dy_elong_start[i]), + pad_angle_end[i], + s ); + } + else if (pad_type[i] == ISAPAD) { + + /* *** HyperLynx Signal-Integrity Transfer Format ****** + {PADSTACK=padstack_name, [drill_size] + (layer_name, pad_shape, pad_sx, pad_sy, pad_angle, + [thermal_clear_shape], + [thermal_clear_sx], + [thermal_clear_sy], + [thermal_clear_angel], + [pad_type]) [comment] + ** [pad_type]!M=metal-pad A=anti-pad ** + ******* HyperLynx Signal-Integrity Transfer Format *** */ + printf("{PADSTACK=THR%03d,%5.3f\n", i, u2inch(pad_drill[i])); // *** 17.08.2005 count from 1 *** + // pads are on all layers, and have various shapes + if (pad_layer[i] == ISAPAD) { + + // Pad layer Top + if (pad_shape_Top_rnds[i] == OBLONG) { + printf("(1,%s,%5.*f,%5.*f,%.1f) %s Shape was %s and is now %s\n", + PadShapes[pad_shape_Top_rnds[i]], + precision_of_pads,u2inch(pad_diameter_Top_or_dx[i] * pad_dy_elong_start[i]), + precision_of_pads,u2inch(pad_diameter_Top_or_dx[i]), + pad_angle_end[i], + s, + EaglePadShapes[pad_shape_Top_rnds[i]], + HypPadShapes[pad_shape_Top_rnds[i]] ); + } + else { // OVALROUND or RECTSQUARE + printf("(1,%s,%5.*f,%5.*f,%.1f) %s Shape was %s and is now %s\n", + PadShapes[pad_shape_Top_rnds[i]], + precision_of_pads,u2inch(pad_diameter_Top_or_dx[i]), + precision_of_pads,u2inch(pad_diameter_Top_or_dx[i]), + pad_angle_end[i], + s, + EaglePadShapes[pad_shape_Top_rnds[i]], + HypPadShapes[pad_shape_Top_rnds[i]] ); + } + + // Pad layer Inner + printf("(MDEF,%s,%5.*f,%5.*f,0) %s\n", + PadShapes[pad_shape_Inner[i]], + precision_of_pads,u2inch(pad_diameter_Inner[i]), + precision_of_pads,u2inch(pad_diameter_Inner[i]), + s); + + // Pad layer Bottom + if (pad_shape_Bott[i] == OBLONG) { + printf("(16,%s,%5.*f,%5.*f,%.1f) %s Shape was %s and is now %s\n", + PadShapes[pad_shape_Bott[i]], + precision_of_pads,u2inch(pad_diameter_Bott[i] * pad_dy_elong_start[i]), + precision_of_pads,u2inch(pad_diameter_Bott[i]), + pad_angle_end[i], + s, + EaglePadShapes[pad_shape_Bott[i]], + HypPadShapes[pad_shape_Bott[i]]); + } + else { // OVALROUND or RECTSQUARE + printf("(16,%s,%5.*f,%5.*f,%.1f) %s Shape was %s and is now %s\n", + PadShapes[pad_shape_Bott[i]], + precision_of_pads,u2inch(pad_diameter_Bott[i]), + precision_of_pads,u2inch(pad_diameter_Bott[i]), + pad_angle_end[i], + s, + EaglePadShapes[pad_shape_Bott[i]], + HypPadShapes[pad_shape_Bott[i]]); + } + } + + else if (pad_layer[i] == ISAVIA) { + // Top - Inner(schleife) - Bottom + for (int vlay = pad_dy_elong_start[i]; vlay <= pad_angle_end[i]; vlay++) { + // layer used and allowed? + if (copp_used_layer[vlay]) { // layer used for copper an visible + if (vlay == 1) + printf("(1,%s,%5.*f,%5.*f,0) %s Shape was %s and is now %s\n", + PadShapes[pad_shape_Top_rnds[i]], + precision_of_pads,u2inch(pad_diameter_Top_or_dx[i] * pad_dy_elong_start[i]), + precision_of_pads,u2inch(pad_diameter_Top_or_dx[i]), + s, + EaglePadShapes[pad_shape_Top_rnds[i]], + HypPadShapes[pad_shape_Top_rnds[i]] ); + + else if (vlay == 16) + printf("(16,%s,%5.*f,%5.*f,0f) %s Shape was %s and is now %s\n", + PadShapes[pad_shape_Bott[i]], + precision_of_pads,u2inch(pad_diameter_Bott[i] * pad_dy_elong_start[i]), + precision_of_pads,u2inch(pad_diameter_Bott[i]), + s, + EaglePadShapes[pad_shape_Top_rnds[i]], + HypPadShapes[pad_shape_Top_rnds[i]] ); + + else printf("(%d,0,%5.*f,%5.*f,0) %s always round in inner layer\n", + vlay, + precision_of_pads,u2inch(pad_diameter_Inner[i]), + precision_of_pads,u2inch(pad_diameter_Inner[i]), + s ); + } + } + } + } + printf("}\n\n"); + } + } + + // SIGNALS + printheader("Nets"); + int Pad_ID, Xpad, Ypad, EpadX, EpadY, TLaylimit, Blaylimit; + B.signals(S) { + printf("{NET=%s\n",S.name); + S.contactrefs(C) { + + if (C.contact.pad) { + Pad_ID = Find_A_Pad( ISAPAD, 0, + C.contact.pad.shape[1], C.contact.pad.shape[2], C.contact.pad.shape[16], + C.contact.pad.angle, + C.contact.pad.diameter[1], C.contact.pad.diameter[2], C.contact.pad.diameter[16], + C.contact.pad.elongation, + C.contact.pad.drill ); + if ( Pad_ID ) { // *** 17.08.2005 Pad count from 1 to total_pad *** + Xpad = C.contact.pad.x; + EpadX = Xpad; + Ypad = C.contact.pad.y; + EpadY = Ypad; + TLaylimit = 1; + Blaylimit = 16; + printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=THR%03d", + precision_of_nets,u2inch(Xpad), precision_of_nets,u2inch(Ypad), + C.element.name, C.contact.pad.name, Pad_ID); // ** correct number while listing count from 1 + // ** 17.08.2005 alf@cadsoft.de *** + + SayUPinFunction( C.element.name, C.contact.pad.name ); + printf(") %s, Pad Diameter: %5.*f Drill: %5.*f\n", + S.name, precision_of_nets, u2inch(C.contact.pad.diameter[16]), + precision_of_nets, u2inch(C.contact.pad.drill) ); + } + else { + printf("Unregistered Pin Size!\n"); + } + } + if (C.contact.smd) { + Pad_ID = Find_A_Pad( ISASMD, C.contact.smd.layer, + SmdRoundness(C.contact.smd.roundness), 0, 0, + C.contact.smd.angle, + C.contact.smd.dx, 0, 0, + C.contact.smd.dy, + 0 ); + if ( Pad_ID ) { // *** 17.08.2005 count from 1 *** + Xpad = C.contact.smd.x; + EpadX = Xpad; + Ypad = C.contact.smd.y; + EpadY = Ypad; + TLaylimit = C.contact.smd.layer; + Blaylimit = C.contact.smd.layer; + printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=SMD%03d", + precision_of_nets,u2inch(Xpad), precision_of_nets,u2inch(Ypad), + C.element.name, C.contact.smd.name, Pad_ID); // ** correct number while listing count from 1 + // ** 17.08.2005 alf@cadsoft.de *** SayUPinFunction( C.element.name, C.contact.smd.name ); + printf(") %s, Smd Dx: %5.*f Dy: %5.*f\n", + S.name, precision_of_nets, u2inch(C.contact.smd.dx), + precision_of_nets, u2inch(C.contact.smd.dy) ); + } + else { + printf("Unregistered Smd Size!\n"); + } + } + // if a pad/smd was located for this contact + // and a copper segment starts at this contact's x,y location, + // then the copper segment is included on this net. + if ( Pad_ID ) { // *** 17.08.2005 count from 1 *** + // Package element copper information + // circles + C.element.package.circles(A) { + if ( ( A.layer >= 1 ) && ( A.layer <= 16 ) ) { + printf("* %s has metal circles or isolation circles\n",C.element.name); + } + } + // polygons + C.element.package.polygons(P) { + if ( ( P.layer >= 1 ) && ( P.layer <= 16 ) ) { + printf("* %s has metal polygons\n",C.element.name); + } + } + // rectangles + C.element.package.rectangles(R) { + if ( ( R.layer >= 1 ) && ( R.layer <= 16 ) ) { + printf("* %s has metal rectangles\n",C.element.name); + } + } + // Find any wires that connect to this pin/pad that are internal to the package + // 1. build a table of all wires on the accepted layer + int AnyPackageWiresCount = 0; + int Wx1[], Wy1[], Wx2[], Wy2[], Wwid[], Wusedflag[], + Wcurve[], Warcx1[], Warcx2[], Warcxc[], Warcy1[], Warcy2[], Warcyc[], Warcradius[], + Wlayer ; + C.element.package.wires(W) { + // find all wires on the correct layer. + if ( ( W.layer >= TLaylimit ) && ( W.layer <= Blaylimit ) ) { + Wx1[AnyPackageWiresCount] = W.x1; + Wy1[AnyPackageWiresCount] = W.y1; + Wx2[AnyPackageWiresCount] = W.x2; + Wy2[AnyPackageWiresCount] = W.y2; + Wwid[AnyPackageWiresCount] = W.width; + Wcurve[AnyPackageWiresCount] = W.curve; + if (W.curve) { // 21.04.2005 alf@cadsoft.de + Warcx1[AnyPackageWiresCount] = W.arc.x1; + Warcx2[AnyPackageWiresCount] = W.arc.x2; + Warcxc[AnyPackageWiresCount] = W.arc.xc; + Warcy1[AnyPackageWiresCount] = W.arc.y1; + Warcy2[AnyPackageWiresCount] = W.arc.y2; + Warcyc[AnyPackageWiresCount] = W.arc.yc; + Warcradius[AnyPackageWiresCount] = W.arc.radius; + } + Wusedflag[AnyPackageWiresCount] = no; + TLaylimit = W.layer; // fix layer to first found layer on an accepted first layer + Blaylimit = W.layer; // fix layer to first found layer on an accepted first layer + Wlayer = W.layer; // fix the layer + AnyPackageWiresCount++; // count one segment + } + } + // 2. search for physically connected copper segments, even if out of order + if ( AnyPackageWiresCount != 0 ) { + for ( int woi = 0; woi < AnyPackageWiresCount; woi++ ) { + if ( Wusedflag[woi] == no ) { + // check either end of the segment + if ( ( Wx1[woi] == Xpad ) && ( Wy1[woi] == Ypad ) ) { + Xpad = Wx2[woi]; // remember the end of this segment + Ypad = Wy2[woi]; // which must be the start of the next segment + Wusedflag[woi] = yes; + woi = 0; // start searching list from the beginning again + } + else if ( ( Wx2[woi] == Xpad ) && ( Wy2[woi] == Ypad ) ) { + Xpad = Wx1[woi]; // remember the end of this segment + Ypad = Wy1[woi]; // which must be the start of the next segment + Wusedflag[woi] = yes; + woi = 0; // start searching list from the beginning again + } + } + } + } + // 3. write out all segments attached to the contact + if ( AnyPackageWiresCount != 0 ) { + for ( int woi = 0; woi < AnyPackageWiresCount; woi++ ) { + if ( Wusedflag[woi] == yes ) { + // write the segment + if ( Wlayer >= 1 && Wlayer <= 16 ) { + if (Wcurve[woi]) { + printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f W=%5.*f L=%s) Arcs: Board Outline Arc is CCW\n", + precision_of_nets,u2inch(Warcx1[woi]), precision_of_nets,u2inch(Warcy1[woi]), + precision_of_nets,u2inch(Warcx2[woi]), precision_of_nets,u2inch(Warcy2[woi]), + precision_of_nets,u2inch(Warcxc[woi]), precision_of_nets,u2inch(Warcyc[woi]), + precision_of_nets,u2inch(Warcradius[woi]), + precision_of_nets,u2inch(Wwid[woi]), + LayerNames[Wlayer] ); + } + else { + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) %s Internal Package Wire\n", + precision_of_nets,u2inch(Wx1[woi]), + precision_of_nets,u2inch(Wy1[woi]), + precision_of_nets,u2inch(Wx2[woi]), + precision_of_nets,u2inch(Wy2[woi]), + precision_of_nets,u2inch(Wwid[woi]), + LayerNames[Wlayer], + S.name); + } + } + // write any contact pins or smds + int OtherPad_ID; + C.element.package.contacts(Q) { + // don't write out contacts at the original element contact location + if ( ( Q.x != EpadX ) || ( Q.y != EpadY ) ) { + // check if this element contact is at either end of the wire segment + if ( ( ( Q.x == Wx1[woi] ) && ( Q.y == Wy1[woi] ) ) || + ( ( Q.x == Wx2[woi] ) && ( Q.y == Wy2[woi] ) ) ) { + // if a through hole pad + if (Q.pad) { + // find a pad on any layer + OtherPad_ID = Find_A_Pad( ISAPAD, 0, + Q.pad.shape[1], Q.pad.shape[2], Q.pad.shape[16], + Q.pad.angle, + Q.pad.diameter[1], Q.pad.diameter[2], Q.pad.diameter[16], + Q.pad.elongation, + Q.pad.drill ); + if ( OtherPad_ID ) { // *** 17.08.2005 count from 1 *** + printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=THR%03d", + precision_of_nets, u2inch(Q.pad.x), precision_of_nets, u2inch(Q.pad.y), + C.element.name, Q.pad.name, OtherPad_ID); + SayUPinFunction( C.element.name, Q.pad.name ); + printf(") %s, Internal Package Pad Diameter: %5.*f Drill: %5.*f\n", + S.name, precision_of_nets,u2inch(Q.pad.diameter[16]), + precision_of_nets, u2inch(Q.pad.drill) ); + InsertAssocatedPin( C.element.name, Q.pad.name ); + } + else { + printf("Unregistered Internal Package Pin Size!\n"); + } + } + // if a smd pad + if (Q.smd) { + // smd pad must be on this layer + if ( Q.smd.layer == Wlayer ) { + // find a smd that matches + OtherPad_ID = Find_A_Pad( ISASMD, Q.smd.layer, + SmdRoundness(Q.smd.roundness), 0, 0, + Q.smd.angle, + Q.smd.dx, 0, 0, + Q.smd.dy, + 0 ); + if ( OtherPad_ID ) { // *** 17.08.2005 count from 1 *** + printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=SMD%03d", + precision_of_nets,u2inch(Q.smd.x), precision_of_nets,u2inch(Q.smd.y), + C.element.name, Q.smd.name, OtherPad_ID); + SayUPinFunction( C.element.name, Q.smd.name ); + printf(") %s, Smd Dx: %5.*f Dy: %5.*f\n", + S.name,precision_of_nets,u2inch(Q.smd.dx), + precision_of_nets,u2inch(Q.smd.dy) ); + InsertAssocatedPin( C.element.name, Q.smd.name ); + } + else { + printf("Unregistered Smd Size!\n"); + } + } + } + } + } + } + } + } + } + } + } + S.vias(V) { + Pad_ID = Find_A_Pad( ISAPAD, 18, + V.shape[1], V.shape[2], V.shape[16], + V.end, + V.diameter[1], V.diameter[2], V.diameter[16], + V.start, + V.drill ); + + if ( Pad_ID ) { // 17.08.2005 count from 1 *** + printf("(VIA X=%5.*f Y=%5.*f P=THR%03d) %s\n", + precision_of_nets,u2inch(V.x), precision_of_nets, u2inch(V.y), + Pad_ID, S.name); // ** correct number while listing count from 1 + // ** 17.08.2005 alf@cadsoft.de *** + } + else { + printf("Unregistered Via Size!\n"); + } + } + S.wires(W) { + if (W.layer >= 1 && W.layer <= 16 ) { + if (W.curve) { + printf("(ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f W=%5.*f L=%s)\n", + precision_of_nets,u2inch(W.arc.x1), precision_of_nets,u2inch(W.arc.y1), + precision_of_nets,u2inch(W.arc.x2), precision_of_nets,u2inch(W.arc.y2), + precision_of_nets,u2inch(W.arc.xc), precision_of_nets,u2inch(W.arc.yc), + precision_of_nets,u2inch(W.arc.radius), + precision_of_nets,u2inch(W.width), + LayerNames[W.layer] ); + } + else { + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) %s\n", + precision_of_nets,u2inch(W.x1), precision_of_nets,u2inch(W.y1), + precision_of_nets,u2inch(W.x2), precision_of_nets,u2inch(W.y2), + precision_of_nets,u2inch(W.width), LayerNames[W.layer], S.name); + } + } + } + S.polygons(P) { + status("Polygon:"+S.name); // 2012-03-12 + printf("* POLYGONS NOT Allowed in HYP as of BoardSimm 2.2 Build 70. "); + printf("Hopefully someday they will!\n"); + printf("* I=Isolate S=Spacing W=Width O=Orphins_On/Off P=Pour_SOLID/HATCH T=Thermals_On/Off L=Layer) Polygon Format\n"); + printf("*(PLG I=%5.*f S=%5.*f W=%5.*f O=%s P=%s T=%s L=%s) Polygon %s Data\n", + precision_of_nets,u2inch(P.isolate),precision_of_nets,u2inch(P.spacing), + precision_of_nets,u2inch(P.width),P.orphans ? "On" : "Off", + P.pour == POLYGON_POUR_SOLID ? "SOLID" : "HATCH", + P.thermals ? "On" : "Off",LayerNames[P.layer],S.name); + /* // 2012-03-12 + P.wires(W) { + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Polygon %s\n", + precision_of_nets,u2inch(W.x1),precision_of_nets,u2inch(W.y1), + precision_of_nets,u2inch(W.x2),precision_of_nets,u2inch(W.y2), + precision_of_nets,u2inch(W.width),LayerNames[W.layer],S.name); + } + */ + P.contours(W) { // 2012-03-12 export polygon contours + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Polygon %s\n", + precision_of_nets,u2inch(W.x1),precision_of_nets,u2inch(W.y1), + precision_of_nets,u2inch(W.x2),precision_of_nets,u2inch(W.y2), + precision_of_nets,u2inch(W.width),LayerNames[W.layer],S.name); + } + P.fillings(W) { // 2012-03-12 export polygon fillings + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Polygon %s\n", + precision_of_nets,u2inch(W.x1),precision_of_nets,u2inch(W.y1), + precision_of_nets,u2inch(W.x2),precision_of_nets,u2inch(W.y2), + precision_of_nets,u2inch(W.width),LayerNames[W.layer],S.name); + } + } + printf("}\n\n"); + } + + // Unconnected Component Pins are on their own special net "HYP$xPy" + // where x=element name and y=pin name + + // handle all unconnected package pins + B.elements(E) { + E.package.contacts(C) { + if ( strlen(C.signal) == 0 ) { + if (C.pad) { + Pad_ID = Find_A_Pad( ISAPAD, 0, + C.pad.shape[1], C.pad.shape[2], C.pad.shape[16], + C.pad.angle, + C.pad.diameter[1], C.pad.diameter[2], C.pad.diameter[16], + C.pad.elongation, + C.pad.drill ); + if ( Pad_ID ) { // *** 17.08.2005 count from 1 *** + if ( FindAssocatedPin( E.name, C.pad.name ) == 0 ) { + Xpad = C.pad.x; + Ypad = C.pad.y; + printf("{NET=HYP$%s.%s\n",E.name,C.pad.name); + printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=THR%03d", + precision_of_nets,u2inch(Xpad), precision_of_nets,u2inch(Ypad), + E.name, C.pad.name, Pad_ID); + printf(") Pad Diameter: %5.*f Drill: %5.*f\n", + precision_of_nets, u2inch(C.pad.diameter[16]), + precision_of_nets, u2inch(C.pad.drill) ); + printf("}\n\n"); + } + else { + printf("* PIN %s.%s is part of an internal package net.\n",E.name,C.pad.name); + } + } + else { + printf("* Unregistered Pin Size!\n"); + } + } + if (C.smd) { + Pad_ID = Find_A_Pad( ISASMD, C.smd.layer, + SmdRoundness(C.smd.roundness), 0, 0, + C.smd.angle, + C.smd.dx, 0, 0, + C.smd.dy, + 0 ); + if ( Pad_ID ) { // *** 17.08.2005 count from 1 *** + if ( FindAssocatedPin( E.name, C.smd.name ) == 0 ) { + Xpad = C.smd.x; + Ypad = C.smd.y; + printf("{NET=HYP$%s.%s\n",E.name,C.smd.name); + printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=SMD%03d", + precision_of_nets,u2inch(Xpad), precision_of_nets,u2inch(Ypad), + E.name, C.smd.name, Pad_ID); + printf(") Smd Dx: %5.*f Dy: %5.*f\n", + precision_of_nets, u2inch(C.smd.dx), + precision_of_nets, u2inch(C.smd.dy) ); + printf("}\n\n"); + } + else { + printf("* PIN %s.%s is part of an internal package net.\n",E.name,C.smd.name); + } + } + else { + printf("* Unregistered Smd Size!\n"); + } + } + } + } + } + + // NETS that aren't signals but are copper are exported as a net named "N$ComNet" + // Search for any common nets + int AnyNets = no; + // B.arcs(A) if ( ( A.layer >= 1 ) && ( A.layer <= 16 ) ) AnyNets = yes; + B.circles(C) if ( ( C.layer >= 1 ) && ( C.layer <= 16 ) ) AnyNets = yes; + B.rectangles(R) if ( ( R.layer >= 1 ) && ( R.layer <= 16 ) ) AnyNets = yes; + B.wires(W) if ( ( W.layer >= 1 ) && ( W.layer <= 16 ) ) AnyNets = yes; + + if ( AnyNets == yes ) { + printf("{NET=N$ComNet\n"); + + // CIRCLES + B.circles(C) { + if ( ( C.layer >= 1 ) && ( C.layer <= 16 ) ) { + printf("(ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f W=%5.*f L=%s) Circle\n", + precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius), + precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius), + precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y), + precision_of_nets,u2inch(C.radius),precision_of_nets,u2inch(C.width), + LayerNames[C.layer]); + } + } + + // RECTANGLES + B.rectangles(R) { + if ( ( R.layer >= 1 ) && ( R.layer <= 16 ) ) { + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Rectangle Segment Bottom\n", + precision_of_nets,u2inch(R.x1),precision_of_nets,u2inch(R.y1), + precision_of_nets,u2inch(R.x2), precision_of_nets,u2inch(R.y1), + precision_of_nets,RectOutlineWireWidth,LayerNames[R.layer]); + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Rectangle Segment Right\n", + precision_of_nets,u2inch(R.x2),precision_of_nets,u2inch(R.y1), + precision_of_nets,u2inch(R.x2),precision_of_nets,u2inch(R.y2), + precision_of_nets,RectOutlineWireWidth,LayerNames[R.layer]); + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Rectangle Segment Top\n", + precision_of_nets,u2inch(R.x2),precision_of_nets,u2inch(R.y2), + precision_of_nets,u2inch(R.x1),precision_of_nets,u2inch(R.y2), + precision_of_nets,RectOutlineWireWidth,LayerNames[R.layer]); + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Rectangle Segment Left\n", + precision_of_nets,u2inch(R.x1),precision_of_nets,u2inch(R.y2), + precision_of_nets,u2inch(R.x1),precision_of_nets,u2inch(R.y1), + precision_of_nets,RectOutlineWireWidth,LayerNames[R.layer]); + } + } + + // WIRES + B.wires(W) { + if ( ( W.layer >= 1 ) && ( W.layer <= 16 ) ) { + if (W.curve) { + // ARCS + printf("(ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f W=%5.*f L=%s) Arc is CCW\n", + precision_of_nets,u2inch(W.arc.x2),precision_of_nets,u2inch(W.arc.y2), + precision_of_nets,u2inch(W.arc.x1),precision_of_nets,u2inch(W.arc.y1), + precision_of_nets,u2inch(W.arc.xc),precision_of_nets,u2inch(W.arc.yc), + precision_of_nets,u2inch(W.arc.radius),precision_of_nets,u2inch(W.width), + LayerNames[W.layer]); + } + else { + printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Wire Segment\n", + precision_of_nets,u2inch(W.x1),precision_of_nets,u2inch(W.y1), + precision_of_nets,u2inch(W.x2),precision_of_nets,u2inch(W.y2), + precision_of_nets,u2inch(W.width),LayerNames[W.layer]); + } + } + } + printf("}\n\n"); + } // end of copper as common net + + // END OF RUN + printheader("End of data"); + printf("{END}\n\n"); + printf("{KEY=028-015E-4E5D}\n\n"); + } // end of output() {} + string ex; + sprintf(ex, "Data exported to:\n\n%s\n%s", filesetext( B.name, ".REF" ), filesetext( B.name, ".HYP" )); + dlgMessageBox(ex, "OK"); +} // end of board() {} + + diff --git a/trunk/ulp/import-accel.ulp b/trunk/ulp/import-accel.ulp new file mode 100644 index 00000000..9429d96c --- /dev/null +++ b/trunk/ulp/import-accel.ulp @@ -0,0 +1,9621 @@ +#usage "en:After initial export of P-CAD / Altium and Protel boards and schematics
    " + "to ACCEL ASCII format you can import your designs herewith into EAGLE.
    " + // Remove this when it goes into EAGLE " + //"Author: apl@cadsoft.de" + , + "de:
    Durch vorherigem Export von P-CAD-/Altium- und Protel-Boards und -Schaltplänen
    " + "in ACCEL-ASCII-Format können Sie Ihre Designs hiermit in EAGLE importieren.
    " + //"Autor: apl@cadsoft.de" + , + "ru:
    Импорт из Altium / Protel и P-CAD топологии или схемы в ACCEL ASCII формат.
    " + "Сделайте экспорт в формат ACCEL ASCII и затем импортируйте этот файл в EAGLE.
    " + //"Автор: apl@cadsoft.de" + +string Version = "1.1.6"; + +// History +// +// 2013-11-12 Ver. 1.1.3 Problem with performance on schematics, skip keyword classToClassRules +// 2014-01-08 Ver. 1.1.4 Info output was corrected +// 2014-04-23 Ver. 1.1.5 Bug with mirrored and some other minor problems were fixed +// 2014-11-14 Ver. 1.1.6 Connection pin - pad was added + +#require 6.0300 + +// Please keep to alpabetic ordering for maintainability ! +string Dictionary[] = { + "en\v" + "de\v" + "ru\v", + "Cancel\v" + "Abbrechen\v" + "Отмена\v", + "ACCEL - EAGLE layer mapping\v" + "ACCEL - EAGLE - Layerzuordnung\v" + "ACCEL - EAGLE - соответствие слоёв\v", + "ACCEL\nType\tACCEL\nLayer\tACCEL\nNumber\tEAGLE\nNumber\tEAGLE\nName\v" + "ACCEL\nTyp\tACCEL\nLayer\tACCEL\nNummer\tEAGLE\nNummer\tEAGLE\nName\v" + "ACCEL\nТип\tACCEL\nСлой\tACCEL\nНомер\tEAGLE\nНомер\tEAGLE\nИмя\v", + "Adjust layer mapping\v" + "Layerzuordnung anpassen\v" + "Настройка соответствия слоёв\v", + "&Browse\v" + "&Suchen\v" + "&Обзор\v", + " doesn't exist!\v" + " existiert nicht!\v" + " не существует!\v", + "File \v" + "Datei \v" + "Файл\v", + "Help\v" + "Hilfe\v" + "Помощь\v", + "Import P-CAD/Altium/Protel (ACCEL ASCII)\v" + "Import von P-CAD/Altium/Protel (ACCEL ASCII)\v" + "Импорт из P-CAD/Altium/Protel (ACCEL ASCII)\v", + "Import file:\v" + "Import-Datei:\v" + "Импортируемый файл:\v", + "Load\v" + "Laden\v" + "Загрузить\v", + "Mapping:\v" + "Zuordnung:\v" + "Соответствие:\v", + "Please start from board or schematic editor !\v" + "Bitte starten Sie vom Board- oder Schaltplan-Editor!\v" + "Пожалуйста, начните с редактора топологии или схемы!\v", + "Process sheet \v" + "Bearbeite Sheet \v" + "Обработка листа \v", + "Save\v" + "Speichern\v" + "Сохранить\v", + "Save layer mapping file\v" + "Layerzuordnungs-Datei speichern\v" + "Сохранить соответствие слоёв\v", + "Select import file\v" + "Import-Datei auswählen\v" + "Выберите импортируемый файл\v", + "Select layer mapping file\v" + "Layerzuordnungs-Datei auswählen\v" + "Выберите файл соответствия слоёв\v", + "Start\v" + "Start\v" + "Старт\v", + "Wrong file signature: \v" + "Falsche Datei-Signatur: \v" + "Неправильная сигнатура файла: \v", + "Warnings log\v" + "Warnungen log\v" + "Предупреждения\v", + "-Back\v" + "-Zurück\v" + "-Обратно\v", + "Can't open default.dru !", + "Kann nicht geöffnet werden default.dru !", + "Ошибка при открытии файла default.dru !" +}; + +string DlgLang = language(); +if (DlgLang != "de" && DlgLang != "ru") DlgLang = "en"; +int LangIdx = strstr(Dictionary[0], DlgLang) / 3; + +// Translate, based on dictionary +string TR(string s) { + string t = lookup(Dictionary, s, LangIdx, '\v'); + return t ? t : s; +} +//----------------------------------------------------------------------------- + +// merged string contains input file without comments +string MergedString; + +// Header + +string Tokens[]; +int TokensNumber = 0; +int CurrentChar = 0; +int CurrentToken = 0; + +string MajorVersion; +string MinorVersion; + +string TimeStampYear; +string TimeStampMonth; +string TimeStampDay; +string TimeStampHour; +string TimeStampMinute; +string TimeStampSecond; + +string ProgramName; +string ProgramVersion; + +string Copyright; + +string HeaderString; + +string FileUnits; + +string GuidString; + +string FileAuthor; + +// Library + +string LibraryName; + +// This is a collection of data for Pads shapes + +int PadShapeStyleShapeType[]; +string PadShapeStyleDefsWidth[]; +string PadShapeStyleDefsHeight[]; +int PadShapeStyleDefsPolygon[]; +string PadShapeStyleDefsLayer[]; +int NrPadShapeStyle = 0; + +int PadStyleDefsArray[]; +string PadStyleDefsScript[]; +int PadShapeAddRotation[]; +// Pointer and number of Pad shapes in collection +int PadShapePoiner[]; +int NrPadShapes[]; +int PadStyleDefsSkip[]; +int IfSMD[]; +int PadStyleDefsNumber = 0; + +int ViaStyleDefsArray[]; +string ViaStyleDefsScript[]; +string ViaStyleDefsType[]; +string ViaStyleDefsDiameter[]; +int ViaStyleDefsSkip[]; +int ViaStyleDefsNumber = 0; + +int TextStyleDefsArray[]; +string TextStyleDefFontHeight[]; +string TextStyleDefFontStrokeWidth[]; +int TextStyleDefsNumber = 0; + +int PatternDefExtendedArray[]; +int PatternGraphicsDefArray[]; +int IfNameDefinedInPattern[]; +int IfValueDefinedInPattern[]; +int PatternAttributesIndex[]; +int PatternNrAttributes[]; +string PatternName[]; +string PatternOriginalName[]; +string PatternGraphicsDefName[]; +string PatternDefaultVariantName[]; +int PatternDefExtendedNumber = 0; + +int NrPadPinMap = 0; +string PadPinMapNum[]; +string PadPinMapPinRef[]; + +int CompDefsArray[]; +int CompDefsNumber = 0; +int PadPinMapRef[]; +int PadPinMapCount[]; + +int NrAttributes = 0; +string AttributesName[]; +int AttributesIndex[]; + +int SymbolDefsArray[]; +string SymbolsName[]; +string OriginalSymbolsName[]; +int IfNameDefinedInSymbol[]; +int IfValueDefinedInSymbol[]; +int SymbolAttributesIndex[]; +int SymbolNrAttributes[]; +int SymbolDefsNumber = 0; + +string DevicesName[]; +string SymbolDevicesName[]; +int NrSymbolDevices = 0; + +int NrPadsOnBoard = 0; +int PadOnBoardIndex[]; +string PadOnBoardDefs[]; + +int NrDummyDevices = 0; +string DummyDevices[]; + +// Netlist + +string NetlistName; + +// PCBDesign + +int PCBDesignToken = 0; +string PcbDesignName = ""; + +int LayerDefsArray[]; +string LayersName[]; +int LayersCode[]; +string LayersType[]; +int LayerDefsNumber = 0; + +int PCBDesignMultiLayerToken = 0; + +int PCBLayerContentsArray[]; +int NrPCBLayerContents = 0; + +// schematicDesign + +int SchematicDesignToken = 0; +string SchematicDesignName = ""; + +int SchTitleSheet = 0; + +int SheetsArray[]; +int NrSheets = 0; + +int CompInstances[]; +int NrCompInstances = 0; +string CompInstancesName[]; +string CompInstancesRef[]; +string CompValue[]; + +int NrNodes = 0; +string NodeElementName[]; +string NodePadName[]; + +int NrNets = 0; +string NetNames[]; +int NodeRef[]; +int NrNetNodes[]; + +int NrLabels = 0; +string XCoordLabels[]; +string YCoordLabels[]; +string TypeLabels[]; +string NetNameRef[]; +string IsLabelFlipped[]; +string LabelRotation[]; + +// Misc + +int DebugMessage = 1; + +int IfPinText = 0; + +string LabelTextHeight = "0.07inch"; +string NameValueTextHeight = "0.05inch"; + +int IfUpdateLayersMap = 0; + +string PCADfileName; +string SCRIPTfileName; +string WarningsLogFileName; + +string ext[] = { "*.asc", "*.asc" }; +enum { PCB, SCH }; +int FileType = PCB; +//string FileInfo = "Select a import file."; + +int Lines; +string PcadLines[]; + +string Status; // = "First select a ACCEL_ASCII file, then click on Start."; + +int SchematicWindow = 0; +int BoardWindow = 0; + +real WiresPointX[]; +real WiresPointY[]; +string WiresNet[]; +int NrWiresPoint = 0; + +int UseExternalText = 0; +string ExternalText = ""; + +int BatchMode = 0; + +string DEFAULT_WIRE_WIDTH_BOARD = "10mil"; +string DEFAULT_WIRE_WIDTH_SCHEMATIC = "6mil"; + +real ROUNDNESS = 3.0; + +string DRUFileName; + +int Vers = 1; +int SubVers = 1; + +string LogLines[]; +int NrLogLines; + +void WriteLog( string message ) +{ + if( DebugMessage ) { + printf( "%s", message ); + } + + LogLines[ NrLogLines++ ] = message; +} + +string GetFile(string fname) +{ + PCADfileName = fname; + if (fname) PCADfileName = filesetext(fname,"/"); + string f[]; + int fcnt; + + if (fname) fcnt = fileglob(f, PCADfileName); // 2008-10-21 check file name + + if( !fcnt ) { + PCADfileName = dlgFileOpen(TR("Select import file"), fname, + ext[FileType] + " *.pcb *.ASC *.PCB *.sch *.txt *.TXT;; (*.*)"); + if (!PCADfileName) return fname; + } + + Lines = fileread(PcadLines, PCADfileName); + if (Lines == -1) exit(-7113); + SCRIPTfileName = filesetext(PCADfileName, ".scr"); + return PCADfileName; +} + +string ShowRefLayer[]; + +int CntlayerDef = -1; +string RefLayerDef[]; +string RefLayerNum[]; +string RefLayerType[]; +string PcadEagleLayerRefName[]; +string PcadEagleLayerRefNum[]; + +void LoadCrossRef( string CrossfileName ) +{ + if (!CrossfileName) { + CrossfileName = dlgFileOpen(TR("Select layer mapping file"), PCADfileName + ".lmp", "*.lmp"); + if (!CrossfileName) return; + } + + CntlayerDef = fileread(ShowRefLayer, CrossfileName); + + if( CntlayerDef < 0 ) { + if( DebugMessage ) { + printf( "# info: CrossfileName %s not found\n", CrossfileName ); + } + + return; + } + + string w[]; + for (int n = 0; n < CntlayerDef; n++) { + strsplit(w, ShowRefLayer[n], '\t'); + RefLayerType[n] = w[0]; + RefLayerDef[n] = w[1]; + RefLayerNum[n] = w[2]; + PcadEagleLayerRefNum[n] = w[3]; + PcadEagleLayerRefName[n] = w[4]; + } + + if( DebugMessage ) { + //printf( "# info: CrossfileName %s loaded\n", CrossfileName ); + } +} + +void SaveCrossRef( void ) +{ + string CrossfileName = dlgFileSave(TR("Save layer mapping file"), PCADfileName + ".lmp", "*.lmp"); + + if (!CrossfileName) return; + + output(CrossfileName, "wt") { + for (int n = 0; n < CntlayerDef; n++) { + printf("%s\t%s\t%s\t%s\t%s\n", + RefLayerType[n], + RefLayerDef[n], + RefLayerNum[n], + PcadEagleLayerRefNum[n], + PcadEagleLayerRefName[n] + ); + } + } +} + +// This function updates dialog window to show progress + +void UpdateProgress( string info ) +{ + if( !BatchMode ) { + sprintf( Status, "%s", info); + dlgRedisplay(); + } +} + +// This function replaces characters which have +// special meaning in Eagle. Returns updated string + +string ReplaceNotSupportedCharacters( string InputStr ) +{ + string OutputStr; + + int length = strlen( InputStr ); + + for( int i = 0; i < length; i++ ) { + switch( InputStr[ i ] ) { + case '\\': + OutputStr[ i ] = '/'; + break; + case ' ': + OutputStr[ i ] = '_'; + break; + case '(': + OutputStr[ i ] = '_'; + break; + case ')': + OutputStr[ i ] = '_'; + break; + case '[': + OutputStr[ i ] = '_'; + break; + case ']': + OutputStr[ i ] = '_'; + break; + case '\'': + OutputStr[ i ] = '_'; + break; +// case '%': +// OutputStr[ i ] = '_'; +// break; + default: + OutputStr[ i ] = InputStr[ i ]; + } + } + + return( OutputStr ); +} + +// This function replaces characters which have +// special meaning in Eagle for text string. Returns updated string + +string ReplaceNotSupportedCharactersText( string InputStr ) +{ + string OutputStr; + + int length = strlen( InputStr ); + + int j = 0; + + for( int i = 0; i < length; i++ ) { + switch( InputStr[ i ] ) { + case '\'': + OutputStr[ j ] = '\''; + j++; + OutputStr[ j ] = '\''; + break; + case '\\': + if( ( InputStr[ i + 1 ] == 'n' ) || + ( InputStr[ i + 1 ] == '\\' ) ) { + OutputStr[ j ] = InputStr[ i ]; + i++; + j++; + OutputStr[ j ] = InputStr[ i ]; + } + else { + i++; + j--; + } + break; + default: + OutputStr[ j ] = InputStr[ i ]; + } + + j++; + } + + return( OutputStr ); +} + +// This function merges all lines and removes comments +void MergeLines( void ) +{ + for( int j = 0; j < Lines; j++ ) { + if ( strchr( PcadLines[ j ], ';' ) >= 0 ) { + string currentLine = PcadLines[ j ]; + int lineLength = strlen( currentLine ); + int flag = 0; + for( int i = 0; i < lineLength; i++ ) { + if ( currentLine[ i ] == '"' ) + flag = !flag; + if ( currentLine[ i ] == ';' && !flag) { + currentLine[ i ] = '\0'; + break; + } + } + PcadLines[ j ] = currentLine; + } + } + // Merge them all in one step ! + MergedString = strjoin(PcadLines, ' '); +} + +// This function create token for string inside double quotas + +void ProcessDoubleQuotas( int lineLength ) +{ + string tmpString; + int strLength = 0; + + tmpString[ strLength ] = MergedString[ CurrentChar ]; + strLength++; + + CurrentChar++; + + while( CurrentChar < lineLength ) { + tmpString[ strLength ] = MergedString[ CurrentChar ]; + strLength++; + + if( MergedString[ CurrentChar ] == '"' ) { + if( MergedString[ CurrentChar - 1 ] != '\\' ) { + break; + } + else { + tmpString[ strLength - 1 ] = '"'; + } + } + + CurrentChar++; + } + + tmpString[ strLength ] = 0; + + Tokens[ TokensNumber ] = tmpString; + TokensNumber++; +} + +// This function create token for keyword or variable name + +void ProcessString( int lineLength ) +{ + string tmpString; + + while( CurrentChar < lineLength ) { + switch( MergedString[ CurrentChar ] ) { + case ' ': + case '(': + case ')': + case '"': + CurrentChar--; + Tokens[ TokensNumber ] = tmpString; + TokensNumber++; + return; + default: + tmpString = tmpString + MergedString[ CurrentChar ]; + CurrentChar++; + } + } + + Tokens[ TokensNumber ] = tmpString; + TokensNumber++; +} + +// This function creates array of strings from MergedString + +void SplitToTokens( void ) +{ + UpdateProgress( TR("Parsing") ); + + int lineLength = strlen( MergedString ); + + CurrentChar = 0; + + while( CurrentChar < lineLength ) { + switch( MergedString[ CurrentChar ] ) { + case ' ': + break; + case '(': + Tokens[ TokensNumber ] = "("; + TokensNumber++; + break; + case ')': + Tokens[ TokensNumber ] = ")"; + TokensNumber++; + break; + case '"': + ProcessDoubleQuotas( lineLength ); + + //sprintf(Status, "Token %d:%s", TokensNumber, Tokens[ TokensNumber ] ); + //dlgRedisplay(); + + break; + default: + ProcessString( lineLength ); + + //sprintf(Status, "Token %d:%s", TokensNumber, Tokens[ TokensNumber ] ); + //dlgRedisplay(); + } + + CurrentChar++; + } +} + +// This function check if dbUnit equal to mil, mm or in. +// Returns 0 if dbUnit is correct +// otherwise returns 1 + +int checkDbUnits( string fileUnits ) +{ + if( fileUnits == "mil") return( 0 ); + if( fileUnits == "mm") return( 0 ); + if( fileUnits == "in") return( 0 ); + + return( 1 ); +} + +// Removes double quotas at the begining and +// the end of string if any. Return new string + +string RemoveDoubleQuotas( string inputString ) +{ + string outputString = ""; + + int startPos = 0; + int length = strlen( inputString ); + + if( length > 0 ) { + if( inputString[ length - 1 ] == '"' ) { + length--; + } + + if( inputString[ 0 ] == '"' ) { + startPos = 1; + length--; + } + } + + for( int i = 0; i < length; i++ ) { + outputString[ i ] = inputString[ startPos + i ]; + } + + return( outputString ); +} + +// Check if the first word matches the ACCEL_ASCII signature. +// Quite tolerant because many different file types are common. + +int CheckSignature(void) +{ + return strxstr(strupr(Tokens[0]), "[PCAD|ACCEL|TANGOPRO].ASCII") >= 0 ? 0 : 1; +} + +// This function process header of file. +// If header processed successfully function returns 0 +// otherwise returns 1 + +int ProcessAsciiHeader( void ) +{ + UpdateProgress( TR("ProcessAsciiHeader") ); + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "asciiVersion" ) { + CurrentToken++; + + MajorVersion = Tokens[ CurrentToken ]; + + CurrentToken++; + + MinorVersion = Tokens[ CurrentToken ]; + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in asciiVersion", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "timeStamp" ) { + CurrentToken++; + + TimeStampYear = Tokens[ CurrentToken ]; + + CurrentToken++; + + TimeStampMonth = Tokens[ CurrentToken ]; + + CurrentToken++; + + TimeStampDay = Tokens[ CurrentToken ]; + + CurrentToken++; + + TimeStampHour = Tokens[ CurrentToken ]; + + CurrentToken++; + + TimeStampMinute = Tokens[ CurrentToken ]; + + CurrentToken++; + + TimeStampSecond = Tokens[ CurrentToken ]; + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in timeStamp", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "program" ) { + CurrentToken++; + + ProgramName = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + ProgramVersion = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in program keyword", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "copyright" ) { + CurrentToken++; + + Copyright = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in copyright keyword", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "headerString" ) { + CurrentToken++; + + HeaderString = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in header string keyword", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "fileUnits" ) { + CurrentToken++; + + FileUnits = strlwr( Tokens[ CurrentToken ] ); + + if( checkDbUnits( FileUnits ) ) { + dlgMessageBox( "Unknown fileUnits " + FileUnits, "OK"); + return( 1 ); + } + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in fileUnits", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "guidString" ) { + CurrentToken++; + + GuidString = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in header guidString keyword", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "fileAuthor" ) { + CurrentToken++; + + FileAuthor = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in header fileAuthor keyword", "OK"); + return( 1 ); + } + } + else { + dlgMessageBox( "Unknown keyword in header " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + return( 0 ); + } + else { + dlgMessageBox( "Unexpected keyword in header " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process padStyleDef keyword. +// If padStyleDef processed successfully function returns 0 +// oterwise returns 1 + +int ProcessPadStyleDef( void ) +{ + int level = 1; + + CurrentToken++; + + PadStyleDefsArray[ PadStyleDefsNumber ] = CurrentToken; + + PadStyleDefsNumber++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process viaStyleDef keyword. +// If viaStyleDef processed successfully function returns 0 +// oterwise returns 1 + +int ProcessViaStyleDef( void ) +{ + int level = 1; + + CurrentToken++; + + ViaStyleDefsArray[ ViaStyleDefsNumber ] = CurrentToken; + + ViaStyleDefsNumber++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process textStyleDef keyword. +// If textStyleDef processed successfully function returns 0 +// oterwise returns 1 + +int ProcessTextStyleDef( void ) +{ + int level = 1; + + CurrentToken++; + + TextStyleDefsArray[ TextStyleDefsNumber ] = CurrentToken; + + TextStyleDefsNumber++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + + if( Tokens[ CurrentToken + 1 ] == "fontHeight" ) { + TextStyleDefFontHeight[ TextStyleDefsNumber - 1 ] = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + TextStyleDefFontHeight[ TextStyleDefsNumber - 1 ] = + TextStyleDefFontHeight[ TextStyleDefsNumber - 1 ] + Tokens[ CurrentToken + 3 ]; + } + } + else { + if( Tokens[ CurrentToken + 1 ] == "strokeWidth" ) { + TextStyleDefFontStrokeWidth[ TextStyleDefsNumber - 1 ] = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + TextStyleDefFontStrokeWidth[ TextStyleDefsNumber - 1 ] = + TextStyleDefFontStrokeWidth[ TextStyleDefsNumber - 1 ] + Tokens[ CurrentToken + 3 ]; + } + } + } + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process patternDefExtended keyword. +// If patternDefExtended processed successfully function returns 0 +// oterwise returns 1 + +int ProcessPatternDefExtended( void ) +{ + int level = 1; + + CurrentToken++; + + int patternDefExtendedToken = CurrentToken; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + + if( Tokens[ CurrentToken + 1 ] == "patternGraphicsDef" ) { + PatternDefExtendedArray[ PatternDefExtendedNumber ] = patternDefExtendedToken; + PatternGraphicsDefArray[ PatternDefExtendedNumber ] = CurrentToken + 1; + + PatternDefExtendedNumber++; + } + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process compDef keyword. +// If compDef processed successfully function returns 0 +// oterwise returns 1 + +int ProcessCompDef( void ) +{ + int level = 1; + + CurrentToken++; + + CompDefsArray[ CompDefsNumber ] = CurrentToken; + + CompDefsNumber++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process patternDef keyword. +// If patternDef processed successfully function returns 0 +// oterwise returns 1 + +int ProcessPatternDef( void ) +{ + int level = 1; + + CurrentToken++; + + //PatternDefsArray[ PatternDefsNumber ] = CurrentToken; + + //PatternDefsNumber++; + + PatternDefExtendedArray[ PatternDefExtendedNumber ] = CurrentToken; + PatternGraphicsDefArray[ PatternDefExtendedNumber ] = -1; + PatternGraphicsDefName[ PatternDefExtendedNumber ] = ""; + + PatternDefExtendedNumber++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process symbolDef keyword. +// If symbolDef processed successfully function returns 0 +// oterwise returns 1 + +int ProcessSymbolDef( void ) +{ + int level = 1; + + CurrentToken++; + + SymbolDefsArray[ SymbolDefsNumber ] = CurrentToken; + + SymbolDefsNumber++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process library keyword. +// If library processed successfully function returns 0 +// oterwise returns 1 + +int ProcessLibrary( void ) +{ + PadStyleDefsNumber = 0; + ViaStyleDefsNumber = 0; + TextStyleDefsNumber = 0; + PatternDefExtendedNumber = 0; + CompDefsNumber = 0; + //PatternDefsNumber = 0; + SymbolDefsNumber = 0; + + UpdateProgress( TR("ProcessLibrary") ); + + CurrentToken++; + + LibraryName = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + + CurrentToken++; + + if( Tokens[ CurrentToken ] == "padStyleDef" ) { + if( ProcessPadStyleDef() ) { + dlgMessageBox( "Error in padStyleDef processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "viaStyleDef" ) { + if( ProcessViaStyleDef() ) { + dlgMessageBox( "Error in viaStyleDef processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "textStyleDef" ) { + if( ProcessTextStyleDef() ) { + dlgMessageBox( "Error in textStyleDef processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "patternDefExtended" ) { + if( ProcessPatternDefExtended() ) { + dlgMessageBox( "Error in patternDefExtended processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "compDef" ) { + if( ProcessCompDef() ) { + dlgMessageBox( "Error in compDef processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "patternDef" ) { + if( ProcessPatternDef() ) { + dlgMessageBox( "Error in patternDef processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "symbolDef" ) { + if( ProcessSymbolDef() ) { + dlgMessageBox( "Error in symbolDef processing", "OK"); + return( 1 ); + } + } + else { + dlgMessageBox( "Unknown keyword in library " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + + /*string info; + + sprintf( info, "PadStyleDefsNumber = %d ViaStyleDefsNumber = %d", + PadStyleDefsNumber, ViaStyleDefsNumber ); + dlgMessageBox( info, "OK"); + + sprintf( info, "TextStyleDefsNumber = %d PatternDefExtendedNumber = %d", + TextStyleDefsNumber, PatternDefExtendedNumber ); + dlgMessageBox( info, "OK"); + + sprintf( info, "CompDefsNumber = %d PatternDefsNumber = %d SymbolDefsNumber = %d", + CompDefsNumber, PatternDefsNumber, SymbolDefsNumber ); + dlgMessageBox( info, "OK");*/ + + return( 0 ); + } + else { + dlgMessageBox( "Unexpected keyword in library " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function skip all internal data and return. + +int SkipThisItem( void ) +{ + int level = 1; + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process globalAttrs keyword. +// If globalAttrs processed successfully function returns 0 +// oterwise returns 1 + +int ProcessGlobalAttrs( void ) +{ + int level = 1; + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process compInst keyword. +// If compInst processed successfully function returns 0 +// oterwise returns 1 + +int ProcessCompInst( void ) +{ + int level = 1; + + CurrentToken++; + + CompInstances[ NrCompInstances ] = CurrentToken; + + CompInstancesName[ NrCompInstances ] = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken ] ) ); + + NrCompInstances++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + + if( Tokens[ CurrentToken + 1 ] == "compRef" ) { + CompInstancesRef[ NrCompInstances - 1 ] = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 2 ] ) ); + } + else { + if( Tokens[ CurrentToken + 1 ] == "compValue" ) { + CompValue[ NrCompInstances - 1 ] = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 2 ] ) ); + } + } + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process net keyword. +// If net processed successfully function returns 0 +// oterwise returns 1 + +int ProcessNet( void ) +{ + int nodesCount = 0; + int level = 1; + + CurrentToken++; + + NetNames[ NrNets ] = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken ] ) ); + NodeRef[ NrNets ] = NrNodes; + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + + CurrentToken++; + + if( Tokens[ CurrentToken ] == "node" ) { + CurrentToken++; + NodeElementName[ NrNodes ] = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken ] ) ); + CurrentToken++; + NodePadName[ NrNodes ] = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken ] ) ); + CurrentToken++; + NrNodes++; + nodesCount++; + } + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + if( nodesCount ) { + NrNetNodes[ NrNets ] = nodesCount; + NrNets++; + } + + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process netClass keyword. +// If netClass processed successfully function returns 0 +// oterwise returns 1 + +int ProcessNetClass( void ) +{ + int level = 1; + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process netlist keyword. +// If netlist processed successfully function returns 0 +// oterwise returns 1 + +int ProcessNetlist( void ) +{ + UpdateProgress( TR("ProcessNetlist") ); + + CurrentToken++; + + NetlistName = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + + CurrentToken++; + + if( Tokens[ CurrentToken ] == "globalAttrs" ) { + if( ProcessGlobalAttrs() ) { + dlgMessageBox( "Error in globalAttrs processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "compInst" ) { + if( ProcessCompInst() ) { + dlgMessageBox( "Error in compInst processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "net" ) { + if( ProcessNet() ) { + dlgMessageBox( "Error in net processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "netClass" ) { + if( ProcessNetClass() ) { + dlgMessageBox( "Error in net processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "classToClassRules" ) { // 2013-05-28 classToClassRules + if( SkipThisItem() ) { + dlgMessageBox( "Error in net processing", "OK"); + return( 1 ); + } + } + else { + dlgMessageBox( "Unknown keyword in netlist: " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + return( 0 ); + } + else { + dlgMessageBox( "Unexpected keyword in netlist " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process pcbDesignHeader keyword. +// If pcbDesignHeader processed successfully function returns 0 +// oterwise returns 1 + +int ProcessPcbDesignHeader( void ) +{ + int level = 1; + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process layerDef keyword. +// If layerDef processed successfully function returns 0 +// oterwise returns 1 + +int ProcessLayerDef( void ) +{ + CurrentToken++; + + LayersName[ LayerDefsNumber ] = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + + CurrentToken++; + + if( Tokens[ CurrentToken ] == "layerNum" ) { + CurrentToken++; + + LayersCode[ LayerDefsNumber ] = strtol( Tokens[ CurrentToken ] ); + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in layerNum", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "layerType" ) { + CurrentToken++; + + LayersType[ LayerDefsNumber ] = Tokens[ CurrentToken ]; + + CurrentToken++; + + if( Tokens[ CurrentToken ] != ")" ) { + dlgMessageBox( "Error in layerType", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "attr" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in LayerDef attr processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "fieldSetRef" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in LayerDef fieldSetRef processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "netNameRef" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in LayerDef netNameRef processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "layerBias" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in LayerDef layerBias processing", "OK"); + return( 1 ); + } + } + else { + dlgMessageBox( "Unknown keyword in ProcessLayerDef: " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + LayerDefsArray[ LayerDefsNumber ] = CurrentToken; + + LayerDefsNumber++; + + return( 0 ); + } + else { + dlgMessageBox( "Unexpected keyword in ProcessLayerDef " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process multiLayer keyword. +// If multiLayer processed successfully function returns 0 +// oterwise returns 1 + +int ProcessMultiLayer( void ) +{ + int level = 1; + + CurrentToken++; + + PCBDesignMultiLayerToken = CurrentToken; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pad" ) { + PadOnBoardIndex[ NrPadsOnBoard ] = CurrentToken; + NrPadsOnBoard++; + SkipThisItem(); + } + else { + if( SkipThisItem() ) { + dlgMessageBox( "Error in ProcessMultiLayer processing", "OK"); + return( 1 ); + } + level--; + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + return( 0 ); + + /*level--; + + if( level == 0 ) { + return( 0 ); + }*/ + } + else { + dlgMessageBox( "Unexpected keyword in ProcessMultiLayer " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process layerContents keyword. +// If layerContents processed successfully function returns 0 +// oterwise returns 1 + +int ProcessLayerContents( void ) +{ + int level = 1; + + PCBLayerContentsArray[ NrPCBLayerContents ] = CurrentToken; + + NrPCBLayerContents++; + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process pcbDesign keyword. +// If pcbDesign processed successfully function returns 0 +// oterwise returns 1 + +int ProcessPcbDesign( void ) +{ + UpdateProgress( TR("ProcessPcbDesign") ); + + PCBDesignToken = CurrentToken; + + CurrentToken++; + + PcbDesignName = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pcbDesignHeader" ) { + if( ProcessPcbDesignHeader() ) { + dlgMessageBox( "Error in ProcessPcbDesignHeader processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "layerDef" ) { + if( ProcessLayerDef() ) { + dlgMessageBox( "Error in ProcessLayerDef processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "multiLayer" ) { + if( ProcessMultiLayer() ) { + dlgMessageBox( "Error in ProcessMultiLayer processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "layerContents" ) { + if( ProcessLayerContents() ) { + dlgMessageBox( "Error in ProcessLayerContents processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "pcbPrintSettings" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in pcbPrintSettings processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "drillSymSettings" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in drillSymSettings processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "gerberSettings" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in gerberSettings processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "ncDrillSettings" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in ncDrillSettings processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "programState" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in programState processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "layerSets" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in layerSets processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "layerPairs" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in layerPairs processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "displayDrawOrder" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in displayDrawOrder processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "reportSettings" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in reportSettings processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "odbSettings" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in odbSettings processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "layersStackup" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in layersStackup processing", "OK"); + return( 1 ); + } + } + else { + dlgMessageBox( "Unknown keyword in ProcessPcbDesign: " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + return( 0 ); + } + else { + dlgMessageBox( "Unexpected keyword in ProcessPcbDesign " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +int ProcessSchDesignHeader( void ) +{ + int level = 1; + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +int ProcessDesignInfo( void ) +{ + int level = 1; + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +int ProcessSchTitleSheet( void ) +{ + int level = 1; + + CurrentToken++; + + if( Tokens[ CurrentToken ] == ")" ) { + return( 0 ); + } + + SchTitleSheet = CurrentToken; + + CurrentToken++; + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +int ProcessSheet( void ) +{ + int level = 1; + + CurrentToken++; + + SheetsArray[ NrSheets ] = CurrentToken; + + NrSheets++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + } + + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function process schematicDesign keyword. +// If schematicDesign processed successfully function returns 0 +// oterwise returns 1 + +int ProcessSchematicDesign( void ) +{ + UpdateProgress( TR("ProcessSchematicDesign") ); + + SchematicDesignToken = CurrentToken; + + CurrentToken++; + + SchematicDesignName = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + + CurrentToken++; + + if( Tokens[ CurrentToken ] == "schDesignHeader" ) { + if( ProcessSchDesignHeader() ) { + dlgMessageBox( "Error in ProcessSchDesignHeader processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "designInfo" ) { + if( ProcessDesignInfo() ) { + dlgMessageBox( "Error in ProcessDesignInfo processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "titleSheet" ) { + if( ProcessSchTitleSheet() ) { + dlgMessageBox( "Error in ProcessSchTitleSheet processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "sheet" ) { + if( ProcessSheet() ) { + dlgMessageBox( "Error in ProcessLayerContents processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "schematicPrintSettings" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in schematicPrintSettings processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "programState" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in programState processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "reportSettings" ) { + if( SkipThisItem() ) { + dlgMessageBox( "Error in reportSettings processing", "OK"); + return( 1 ); + } + } + else { + dlgMessageBox( "Unknown keyword in ProcessSchematicDesign: " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + return( 0 ); + } + else { + dlgMessageBox( "Unexpected keyword in ProcessSchematicDesign " + Tokens[ CurrentToken ], "OK"); + return( 1 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function parse tree starting from +// top keywords. If processed seccesfully returns 0, +// if signature is wrong returns 1 + +int ParseTree( void ) +{ + if( CheckSignature() ) { + dlgMessageBox( TR("Wrong file signature: ") + Tokens[ 0 ], "OK"); + return( 1 ); + } + + CurrentToken = 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "asciiHeader" ) { + if( ProcessAsciiHeader() ) { + dlgMessageBox( "Error in file header processing", "OK"); + } + } + else { + if( Tokens[ CurrentToken ] == "library" ) { + if( ProcessLibrary() ) { + dlgMessageBox( "Error in library processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "netlist" ) { + if( ProcessNetlist() ) { + dlgMessageBox( "Error in netlist processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "pcbDesign" ) { + if( ProcessPcbDesign() ) { + dlgMessageBox( "Error in pcbDesign processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == "schematicDesign" ) { + if( ProcessSchematicDesign() ) { + dlgMessageBox( "Error in schematicDesign processing", "OK"); + return( 1 ); + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( "Unexpected keyword: " + Tokens[ CurrentToken ], "OK"); + + if( 1 ) { + dlgMessageBox( "debug: " + Tokens[ CurrentToken - 2 ] + + Tokens[ CurrentToken - 1 ] + + Tokens[ CurrentToken ] + + Tokens[ CurrentToken + 1 ] + + Tokens[ CurrentToken + 2 ], "OK"); + } + + return( 1 ); + } + } + } + } + } + } + } + + CurrentToken++; + } + + + return( 0 ); +} + +string ConvertUnits( string textValue, string unitValue ) +{ + if( unitValue == "" ) { + if( FileUnits == "mil") { + real rValue = strtod( textValue ); + string retValue; + sprintf( retValue, "%f", round( rValue ) ); + return( retValue ); + } + return( textValue ); + } + + if( unitValue == "mil") { + if( FileUnits == "mil") { + real rValue = strtod( textValue ); + string retValue; + sprintf( retValue, "%f", round( rValue ) ); + return( retValue ); + } + + if( FileUnits == "mm") { + real rValue = strtod( textValue ); + string retValue; + sprintf( retValue, "%f", rValue * 25.4 / 1000.0 ); + return( retValue ); + } + + if( FileUnits == "in") { + real rValue = strtod( textValue ); + string retValue; + sprintf( retValue, "%f", rValue / 1000.0 ); + return( retValue ); + } + } + + if( unitValue == "mm") { + if( FileUnits == "mil") { + real rValue = strtod( textValue ); + string retValue; + sprintf( retValue, "%f", rValue * 1000.0 / 25.4 ); + return( retValue ); + } + + if( FileUnits == "mm") { + return( textValue ); + } + + if( FileUnits == "in") { + real rValue = strtod( textValue ); + string retValue; + sprintf( retValue, "%f", rValue / 25.4 ); + return( retValue ); + } + } + + if( unitValue == "in") { + if( FileUnits == "mil") { + real rValue = strtod( textValue ); + string retValue; + sprintf( retValue, "%f", rValue * 1000.0 ); + return( retValue ); + } + + if( FileUnits == "mm") { + real rValue = strtod( textValue ); + string retValue; + sprintf( retValue, "%f", rValue * 25.4 ); + return( retValue ); + } + + if( FileUnits == "in") { + return( textValue ); + } + } + + string tmp; + sprintf( tmp, "# ConvertUnits: unknown units: %s", unitValue ); + WriteLog( tmp ); + + return( textValue ); +} + +int CheckForNull( string str ) +{ + int length = strlen( str ); + + for( int i = 0; i < length; i++ ) { + switch( str[ i ] ) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return( 0 ); + default:; + } + } + + return( 1 ); +} + +string GetNumberValue( string str ) +{ + string value = ""; + + int length = strlen( str ); + + for( int i = 0; i < length; i++ ) { + switch( str[ i ] ) { + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + value = value + str[ i ]; + break; + default: + return( value ); + } + } + + return( value ); +} + +int IsNumberValue( string str ) +{ + int length = strlen( str ); + + for( int i = 0; i < length; i++ ) { + switch( str[ i ] ) { + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + break; + default: + return( 0 ); + } + } + + return( 1 ); +} + +int IsASCIIValue( string str ) +{ + if( strlen( str ) > 0 ) { + switch( str[ 0 ] ) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return( 0 ); + case '.': + case '+': + case '-': + if( strlen( str ) > 1 ) { + switch( str[ 1 ] ) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return( 0 ); + default:; + } + } + break; + default:; + } + } + + return( 1 ); +} + +string GetUnitValue( string str ) +{ + string value = ""; + + int length = strlen( str ); + + for( int i = 0; i < length; i++ ) { + switch( str[ i ] ) { + case '+': + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '.': + break; + default: + value = value + str[ i ]; + } + } + + return( value ); +} + +string MinValue( string val1, string val2 ) +{ + real rVal1 = strtod( ConvertUnits( GetNumberValue( val1 ), GetUnitValue( val1 ) ) ); + real rVal2 = strtod( ConvertUnits( GetNumberValue( val2 ), GetUnitValue( val2 ) ) ); + + string tmp; + + if( rVal1 > rVal2 ) { + sprintf( tmp, "%f", rVal2 ); + } + else { + sprintf( tmp, "%f", rVal1 ); + } + + return( tmp ); +} + +string MaxValue( string val1, string val2 ) +{ + real rVal1 = strtod( ConvertUnits( GetNumberValue( val1 ), GetUnitValue( val1 ) ) ); + real rVal2 = strtod( ConvertUnits( GetNumberValue( val2 ), GetUnitValue( val2 ) ) ); + + string tmp; + + if( rVal1 < rVal2 ) { + sprintf( tmp, "%f", rVal2 ); + } + else { + sprintf( tmp, "%f", rVal1 ); + } + + return( tmp ); +} + +real GetValue( string val ) +{ + real rVal = strtod( ConvertUnits( GetNumberValue( val ), GetUnitValue( val ) ) ); + + return( rVal ); +} + +// Find token with a name. +// Returns token number if found, +// -1 if not found +// startToken should points to "(" + +int FindToken( int startToken, string name ) +{ + int level = 1; + CurrentToken = startToken; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + CurrentToken++; + if( Tokens[ CurrentToken ] == name ) { + return( CurrentToken ); + } + else { + if( SkipThisItem() ) { + return( -1 ); + } + level--; // If an item is skipped, the level needs to be increased ! + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( -1 ); + } + } + else { + /*dlgMessageBox( "Unexpected keyword in FindToken " + Tokens[ CurrentToken ], "OK"); + return( 1 );*/ + } + } + + CurrentToken++; + } + + return( -1 ); +} + +// This function write list of PCAD layer as comments to script + +void PrintPCADLayers( void ) +{ + printf( "# PCAD layers:\n"); + + for( int i = 0; i < LayerDefsNumber; i++ ) { + printf( "#Layer = '%s' %d %s\n", LayersName[ i ], LayersCode[ i ], + LayersType[ i ] ); + } + + printf( "#\n" ); +} + +// This function returns index of found PadStyleDefinition +// in array or -1 if failed + +int FindPadStyleDef( string name ) +{ + for( int i = 0; i < PadStyleDefsNumber; i++ ) { + int startToken = PadStyleDefsArray[ i ]; + + if( Tokens[ startToken ] == name ) { + return( i ); + } + } + + return( -1 ); +} + +// This function returns index of found ViaStyleDefinition +// in array or -1 if failed + +int FindViaStyleDef( string name ) +{ + for( int i = 0; i < ViaStyleDefsNumber; i++ ) { + int startToken = ViaStyleDefsArray[ i ]; + + if( Tokens[ startToken ] == name ) { + return( i ); + } + } + + return( -1 ); +} + +// This function returns index of found TextStyleDefinition +// in array or -1 if failed + +int FindTextStyleDef( string name ) +{ + for( int i = 0; i < TextStyleDefsNumber; i++ ) { + int startToken = TextStyleDefsArray[ i ]; + + if( Tokens[ startToken ] == name ) { + return( i ); + } + } + + return( -1 ); +} + +int checkLayerType( int LayerNumPosition ) +{ + for( int i = 0; i < LayerDefsNumber; i++ ) { + if( LayersCode[ i ] == strtol( Tokens[ LayerNumPosition ] ) ) { + if( LayersType[ i ] == "Signal" ) { + return( 1 ); + } + } + } + + return( 0 ); +} + +real RotateXCoord( real x, real y, real rotationInRad ) +{ + return( x * cos( rotationInRad ) - y * sin( rotationInRad ) ); +} + +real RotateYCoord( real x, real y, real rotationInRad ) +{ + return( x * sin( rotationInRad ) + y * cos( rotationInRad ) ); +} + +void Ellipse( real a, real b, real xCoord, real yCoord, real rotationInDegree ) +{ + if( a < 0.0 ) { + dlgMessageBox( "a must be > 0", "OK"); + return; + } + + if( b < 0.0 ) { + dlgMessageBox( "b must be > 0", "OK"); + return; + } + + if( b > a ) { + dlgMessageBox( "a must be > b", "OK"); + return; + } + + real phi = atan( b / a ); + + real theta = PI / 2 - phi; + + real r1 = ( a * sin( theta ) + b * cos( theta ) - a ) / + ( sin( theta ) + cos( theta ) - 1 ); + + real r2 = ( a * sin( theta ) + b * cos( theta ) - b ) / + ( sin( theta ) + cos( theta ) - 1 ); + + real x = r2 * sin( phi ); + + real y = b - r2 * ( 1.0 - cos( phi ) ); + + real rotationInRad = rotationInDegree * PI / 180.0; + + printf( "ARC CW (%f %f) (%f %f) (%f %f);\n", + xCoord + RotateXCoord( 0.0, b, rotationInRad ), yCoord + RotateYCoord( 0.0, b, rotationInRad ), + xCoord + RotateXCoord( 0.0, b - 2.0 * r2, rotationInRad ), yCoord + RotateYCoord( 0.0, b - 2.0 * r2, rotationInRad ), + xCoord + RotateXCoord( x, y, rotationInRad ), yCoord + RotateYCoord( x, y, rotationInRad ) ); + + printf( "ARC CCW (%f %f) (%f %f) (%f %f);\n", + xCoord + RotateXCoord( 0.0, b, rotationInRad ), yCoord + RotateYCoord( 0.0, b, rotationInRad ), + xCoord + RotateXCoord( 0.0, b - 2.0 * r2, rotationInRad ), yCoord + RotateYCoord( 0.0, b - 2.0 * r2, rotationInRad ), + xCoord + RotateXCoord( -x, y, rotationInRad ), yCoord + RotateYCoord( -x, y, rotationInRad ) ); + + + printf( "ARC CW (%f %f) (%f %f) (%f %f);\n", + xCoord + RotateXCoord( 0.0, -b, rotationInRad ), yCoord + RotateYCoord( 0.0, -b, rotationInRad ), + xCoord + RotateXCoord( 0.0, 2.0 * r2 - b, rotationInRad ), yCoord + RotateYCoord( 0.0, 2.0 * r2 - b, rotationInRad ), + xCoord + RotateXCoord( -x, -y, rotationInRad ), yCoord + RotateYCoord( -x, -y, rotationInRad ) ); + + printf( "ARC CCW (%f %f) (%f %f) (%f %f);\n", + xCoord + RotateXCoord( 0.0, -b, rotationInRad ), yCoord + RotateYCoord( 0.0, -b, rotationInRad ), + xCoord + RotateXCoord( 0.0, 2.0 * r2 - b, rotationInRad ), yCoord + RotateYCoord( 0.0, 2.0 * r2 - b, rotationInRad ), + xCoord + RotateXCoord( x, -y, rotationInRad ), yCoord + RotateYCoord( x, -y, rotationInRad ) ); + + + printf( "ARC CW (%f %f) (%f %f) (%f %f);\n", + xCoord + RotateXCoord( a, 0.0, rotationInRad ), yCoord + RotateYCoord( a, 0.0, rotationInRad ), + xCoord + RotateXCoord( a - 2.0 * r1, 0.0, rotationInRad ), yCoord + RotateYCoord( a - 2.0 * r1, 0.0, rotationInRad ), + xCoord + RotateXCoord( x, -y, rotationInRad ), yCoord + RotateYCoord( x, -y, rotationInRad ) ); + + printf( "ARC CCW (%f %f) (%f %f) (%f %f);\n", + xCoord + RotateXCoord( a, 0.0, rotationInRad ), yCoord + RotateYCoord( a, 0.0, rotationInRad ), + xCoord + RotateXCoord( a - 2.0 * r1, 0.0, rotationInRad ), yCoord + RotateYCoord( a - 2.0 * r1, 0.0, rotationInRad ), + xCoord + RotateXCoord( x, y, rotationInRad ), yCoord + RotateYCoord( x, y, rotationInRad ) ); + + + printf( "ARC CW (%f %f) (%f %f) (%f %f);\n", + xCoord + RotateXCoord( -a, 0.0, rotationInRad ), yCoord + RotateYCoord( -a, 0.0, rotationInRad ), + xCoord + RotateXCoord( 2.0 * r1 - a, 0.0, rotationInRad ), yCoord + RotateYCoord( 2.0 * r1 - a, 0.0, rotationInRad ), + xCoord + RotateXCoord( -x, y, rotationInRad ), yCoord + RotateYCoord( -x, y, rotationInRad ) ); + + printf( "ARC CCW (%f %f) (%f %f) (%f %f);\n", + xCoord + RotateXCoord( -a, 0.0, rotationInRad ), yCoord + RotateYCoord( -a, 0.0, rotationInRad ), + xCoord + RotateXCoord( 2.0 * r1 - a, 0.0, rotationInRad ), yCoord + RotateYCoord( 2.0 * r1 - a, 0.0, rotationInRad ), + xCoord + RotateXCoord( -x, -y, rotationInRad ), yCoord + RotateYCoord( -x, -y, rotationInRad ) ); +} + +void FilledEllipse( real a, real b, real xCoord, real yCoord, real rotationInDegree ) +{ + if( a < 0.0 ) { + dlgMessageBox( "a must be > 0", "OK"); + return; + } + + if( b < 0.0 ) { + dlgMessageBox( "b must be > 0", "OK"); + return; + } + + if( b > a ) { + dlgMessageBox( "a must be > b", "OK"); + return; + } + + real phi = atan( b / a ); + + real theta = PI / 2 - phi; + + real r1 = ( a * sin( theta ) + b * cos( theta ) - a ) / + ( sin( theta ) + cos( theta ) - 1 ); + + real r2 = ( a * sin( theta ) + b * cos( theta ) - b ) / + ( sin( theta ) + cos( theta ) - 1 ); + + real x = r2 * sin( phi ); + + real y = b - r2 * ( 1.0 - cos( phi ) ); + + real rotationInRad = rotationInDegree * PI / 180.0; + + printf( "POLYGON 0\n"); + printf( "(%f %f) @-%f (%f %f)\n", + xCoord + RotateXCoord( 0.0, b, rotationInRad ), yCoord + RotateYCoord( 0.0, b, rotationInRad ), + r2, + xCoord + RotateXCoord( x, y, rotationInRad ), yCoord + RotateYCoord( x, y, rotationInRad ) ); + + printf( "@-%f (%f %f)\n", + r1, + xCoord + RotateXCoord( a, 0.0, rotationInRad ), yCoord + RotateYCoord( a, 0.0, rotationInRad ) ); + + printf( "@-%f (%f %f)\n", + r1, + xCoord + RotateXCoord( x, -y, rotationInRad ), yCoord + RotateYCoord( x, -y, rotationInRad ) ); + + + printf( "@-%f (%f %f)\n", + r2, + xCoord + RotateXCoord( 0.0, -b, rotationInRad ), yCoord + RotateYCoord( 0.0, -b, rotationInRad ) ); + + printf( "@-%f (%f %f)\n", + r2, + xCoord + RotateXCoord( -x, -y, rotationInRad ), yCoord + RotateYCoord( -x, -y, rotationInRad ) ); + + printf( "@-%f (%f %f)\n", + r1, + xCoord + RotateXCoord( -a, 0.0, rotationInRad ), yCoord + RotateYCoord( -a, 0.0, rotationInRad ) ); + + printf( "@-%f (%f %f)\n", + r1, + xCoord + RotateXCoord( -x, y, rotationInRad ), yCoord + RotateYCoord( -x, y, rotationInRad ) ); + + printf( "@-%f (%f %f);\n", + r2, + xCoord + RotateXCoord( 0.0, b, rotationInRad ), yCoord + RotateYCoord( 0.0, b, rotationInRad ) ); +} + +int OnePadShapeCreated; + +int ProcessOnePadShape( int Number, int startToken, string holeDiam ) +{ + int layerNumRefPosition = FindToken( startToken + 1, "layerNumRef" ); + + if( layerNumRefPosition >= 0 ) { + if( checkLayerType( layerNumRefPosition + 1 ) ) { + int padShapeTypePosition = FindToken( startToken + 1, "padShapeType" ); + + if( padShapeTypePosition >= 0 ) { + int shapeWidthPosition = FindToken( startToken + 1, "shapeWidth" ); + + if( shapeWidthPosition >= 0 ) { + string TokenText = Tokens[ shapeWidthPosition + 1 ]; + + if( Tokens[ shapeWidthPosition + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ shapeWidthPosition + 2 ] ) ) { + TokenText = TokenText + Tokens[ shapeWidthPosition + 2 ]; + } + else { + WriteLog( "#warning: wrong description.\n" ); + } + } + + string shapeWidth = ConvertUnits( GetNumberValue( TokenText ), + GetUnitValue( TokenText ) ); + + int shapeHeightPosition = FindToken( startToken + 1, "shapeHeight" ); + + if( shapeHeightPosition >= 0 ) { + + string TokenText = Tokens[ shapeHeightPosition + 1 ]; + + if( Tokens[ shapeHeightPosition + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ shapeHeightPosition + 2 ] ) ) { + TokenText = TokenText + Tokens[ shapeHeightPosition + 2 ]; + } + else { + WriteLog( "#warning: wrong description.\n" ); + } + } + + string shapeHeight = ConvertUnits( GetNumberValue( TokenText ), + GetUnitValue( TokenText ) ); + + if( ( !CheckForNull( shapeWidth ) ) || + ( !CheckForNull( shapeHeight ) ) ) { + + printf("# PadShape: layerNumRef = %s", + Tokens[ layerNumRefPosition + 1 ] ); + printf(" padShapeType = %s", + Tokens[ padShapeTypePosition + 1 ] ); + printf(" shapeWidth = %s", + shapeWidth ); + printf(" shapeHeight = %s\n", + shapeHeight ); + + if( IfSMD[ Number ] ) { // SMD + if( 1 /*OnePadShapeCreated == 0*/ ) { + if( Tokens[ padShapeTypePosition + 1 ] == "Oval" ) { // Oval + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sSMD %s %s -100", + PadStyleDefsScript[ Number ], + shapeWidth, shapeHeight ); + OnePadShapeCreated = 1; + } + } + else { + if( Tokens[ padShapeTypePosition + 1 ] == "Rect" ) { // Rectangle + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sSMD %s %s -0", + PadStyleDefsScript[ Number ], + shapeWidth, shapeHeight ); + OnePadShapeCreated = 1; + } + } + else { + if( Tokens[ padShapeTypePosition + 1 ] == "Ellipse" ) { // Ellipse + if( shapeWidth == shapeHeight ) { + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sSMD %s %s -100", + PadStyleDefsScript[ Number ], + shapeWidth, shapeHeight ); + OnePadShapeCreated = 1; + } + } + else { + //if( DebugMessage ) { + WriteLog( "# warning: Ellipse with different width and height.\n"); + //} + + // Create circle here and ellipse later over it + + //PadStyleShapeType[ Number ] = 1; + + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sSMD %s %s -100", + PadStyleDefsScript[ Number ], + shapeWidth, shapeWidth ); + OnePadShapeCreated = 1; + } + } + } + else { + if( Tokens[ padShapeTypePosition + 1 ] == "RndRect" ) { // RoundRectangle + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sSMD %s %s -25", + PadStyleDefsScript[ Number ], + shapeWidth, shapeHeight ); + OnePadShapeCreated = 1; + } + } + else { + if( Tokens[ padShapeTypePosition + 1 ] == "Target" ) { // Make round + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sSMD %s %s -100", + PadStyleDefsScript[ Number ], + shapeWidth, shapeHeight ); + OnePadShapeCreated = 1; + } + } + else { + string tmp; + sprintf( tmp, "# warning: SMDShape %s not supported yet\n", + Tokens[ padShapeTypePosition + 1 ] ); + WriteLog( tmp ); + } + } + } + } + } + } + } + else { // PAD + if( 1 /*OnePadShapeCreated == 0*/ ) { + if( Tokens[ padShapeTypePosition + 1 ] == "Oval" ) { // Oval + if( shapeWidth == shapeHeight ) { + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sPAD %s ROUND", + PadStyleDefsScript[ Number ], + shapeWidth ); + OnePadShapeCreated = 1; + } + } + else { + //PadStyleShapeType[ Number ] = 1; + + if( OnePadShapeCreated == 0 ) { + real val1 = strtod( ConvertUnits( GetNumberValue( shapeHeight ), + GetUnitValue( shapeHeight ) ) ); + real val2 = strtod( ConvertUnits( GetNumberValue( shapeWidth ), + GetUnitValue( shapeWidth ) ) ); + + real D = val1; + + if( D > val2 ) { + D = val2; + } + + sprintf( PadStyleDefsScript[ Number ], "%sPAD %f LONG", + PadStyleDefsScript[ Number ], D ); + + /*sprintf( PadStyleDefsScript[ Number ], "%sPAD %s SQUARE", + PadStyleDefsScript[ Number ], + MinValue( shapeWidth, shapeHeight ) );*/ + + OnePadShapeCreated = 1; + + if( val1 > val2 ) { + PadShapeAddRotation[ Number ] = 1; + } + } + + /*PadShapeStyleShapeType[ NrPadShapeStyle ] = 2; + PadShapeStyleDefsWidth[ NrPadShapeStyle ] = shapeWidth; + PadShapeStyleDefsHeight[ NrPadShapeStyle ] = shapeHeight; + PadShapeStyleDefsLayer[ NrPadShapeStyle ] = Tokens[ layerNumRefPosition + 1 ]; + NrPadShapeStyle++; + + NrPadShapes[ Number ]++;*/ + } + } + else { + if( Tokens[ padShapeTypePosition + 1 ] == "Rect" ) { // Rectangle + if( shapeWidth == shapeHeight ) { + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sPAD %s SQUARE", + PadStyleDefsScript[ Number ], + shapeWidth ); + OnePadShapeCreated = 1; + } + } + else { + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sPAD %s SQUARE", + PadStyleDefsScript[ Number ], + MinValue( shapeWidth, shapeHeight ) ); + OnePadShapeCreated = 1; + } + + PadShapeStyleShapeType[ NrPadShapeStyle ] = 4; + PadShapeStyleDefsWidth[ NrPadShapeStyle ] = shapeWidth; + PadShapeStyleDefsHeight[ NrPadShapeStyle ] = shapeHeight; + PadShapeStyleDefsLayer[ NrPadShapeStyle ] = Tokens[ layerNumRefPosition + 1 ]; + NrPadShapeStyle++; + + NrPadShapes[ Number ]++; + } + } + else { + if( Tokens[ padShapeTypePosition + 1 ] == "Ellipse" ) { // Ellipse + if( shapeWidth == shapeHeight ) { + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sPAD %s ROUND", + PadStyleDefsScript[ Number ], + shapeWidth ); + OnePadShapeCreated = 1; + } + } + else { + //if( DebugMessage ) { + WriteLog( "# warning: Ellipse with different width and height.\n"); + //} + + // Create circle here and ellipse later over it + + PadShapeStyleShapeType[ NrPadShapeStyle ] = 1; + PadShapeStyleDefsWidth[ NrPadShapeStyle ] = shapeWidth; + PadShapeStyleDefsHeight[ NrPadShapeStyle ] = shapeHeight; + PadShapeStyleDefsLayer[ NrPadShapeStyle ] = Tokens[ layerNumRefPosition + 1 ]; + NrPadShapeStyle++; + + NrPadShapes[ Number ]++; + + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sPAD %s ROUND", + PadStyleDefsScript[ Number ], + MinValue( shapeWidth, shapeHeight ) ); + OnePadShapeCreated = 1; + } + } + } + else { + if( Tokens[ padShapeTypePosition + 1 ] == "MtHole" ) { // MountingHole + if( shapeWidth == shapeHeight ) { + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sHOLE %s", + PadStyleDefsScript[ Number ], + holeDiam ); + + OnePadShapeCreated = 1; + } + } + else { + //if( DebugMessage ) { + WriteLog( "# warning: MtHole with different width and height.\n"); + //} + } + } + else { + if( Tokens[ padShapeTypePosition + 1 ] == "RndRect" ) { // RoundRectangle + if( OnePadShapeCreated == 0 ) { + real val1 = strtod( ConvertUnits( GetNumberValue( shapeHeight ), + GetUnitValue( shapeHeight ) ) ); + real val2 = strtod( ConvertUnits( GetNumberValue( shapeWidth ), + GetUnitValue( shapeWidth ) ) ); + + real minVal = val1; + real maxVal = val1; + + if( minVal > val2 ) { + minVal = val2; + } + + if( maxVal < val2 ) { + maxVal = val2; + } + + real d = maxVal * ( 1.0 - 0.7 / ROUNDNESS ); + + if( minVal > d ) { + minVal = d; + } + + sprintf( PadStyleDefsScript[ Number ], "%sPAD %f SQUARE", + PadStyleDefsScript[ Number ], minVal ); + OnePadShapeCreated = 1; + } + + PadShapeStyleShapeType[ NrPadShapeStyle ] = 2; + PadShapeStyleDefsWidth[ NrPadShapeStyle ] = shapeWidth; + PadShapeStyleDefsHeight[ NrPadShapeStyle ] = shapeHeight; + PadShapeStyleDefsLayer[ NrPadShapeStyle ] = Tokens[ layerNumRefPosition + 1 ]; + NrPadShapeStyle++; + + NrPadShapes[ Number ]++; + } + else { + if( Tokens[ padShapeTypePosition + 1 ] == "Target" ) { // Make it round + if( OnePadShapeCreated == 0 ) { + sprintf( PadStyleDefsScript[ Number ], "%sPAD %s ROUND", + PadStyleDefsScript[ Number ], + shapeWidth ); + OnePadShapeCreated = 1; + } + } + else { + string tmp; + sprintf( tmp, "# warning: PadShape %s not supported yet\n", + Tokens[ padShapeTypePosition + 1 ] ); + WriteLog( tmp ); + } + } + } + } + } + } + } + } + + PadStyleDefsSkip[ Number ] = 0; + } + else { + if( DebugMessage ) { + printf( "# skips because of zero coordinates.\n"); + } + } + } + } + else { // No width + if( Tokens[ padShapeTypePosition + 1 ] == "Polygon" ) { + printf( "#polygonPad\n"); + + string xLineCoord[]; + string yLineCoord[]; + int nrLines = 0; + + int shapeOutlinePosition = FindToken( startToken + 1, "shapeOutline" ); + + if( shapeOutlinePosition >= 0 ) { + int currentToken = shapeOutlinePosition + 1; + + PadShapeStyleDefsPolygon[ NrPadShapeStyle ] = currentToken; + + while( currentToken < TokensNumber ) { + if( Tokens[ currentToken ] == "(" ) { + currentToken++; + + if( Tokens[ currentToken ] == "pt" ) { + xLineCoord[ nrLines ] = Tokens[ currentToken + 1 ]; + yLineCoord[ nrLines ] = Tokens[ currentToken + 2 ]; + nrLines++; + + currentToken = currentToken + 3; + } + } + else { + if( Tokens[ currentToken ] == ")" ) { + break; + } + } + + currentToken++; + } + + string minX = xLineCoord[ 0 ]; + string minY = yLineCoord[ 0 ]; + string maxX = xLineCoord[ 0 ]; + string maxY = yLineCoord[ 0 ]; + + for( int i = 0; i < nrLines; i++ ) { + minX = MinValue( minX, xLineCoord[ i ] ); + maxX = MaxValue( maxX, xLineCoord[ i ] ); + minY = MinValue( minY, yLineCoord[ i ] ); + maxY = MaxValue( maxY, yLineCoord[ i ] ); + } + + real rMinX = strtod( minX ); + real rMaxX = strtod( maxX ); + real rMinY = strtod( minY ); + real rMaxY = strtod( maxY ); + + real rX = ( rMaxX - rMinX ) / 2.0; + real rY = ( rMaxY - rMinY ) / 2.0; + + real r = rX; + + if( r > rY ) { + r = rY; + } + + if( OnePadShapeCreated == 0 ) { + if( IfSMD[ Number ] ) { + sprintf( PadStyleDefsScript[ Number ], "%sSMD %f %f -0", + PadStyleDefsScript[ Number ], + r, + r ); + } + else { + sprintf( PadStyleDefsScript[ Number ], "%sPAD %f SQUARE", + PadStyleDefsScript[ Number ], + r ); + } + + OnePadShapeCreated = 1; + } + + PadShapeStyleShapeType[ NrPadShapeStyle ] = 3; + PadShapeStyleDefsWidth[ NrPadShapeStyle ] = maxX; + PadShapeStyleDefsHeight[ NrPadShapeStyle ] = maxY; + PadShapeStyleDefsLayer[ NrPadShapeStyle ] = Tokens[ layerNumRefPosition + 1 ]; + NrPadShapeStyle++; + + NrPadShapes[ Number ]++; + + PadStyleDefsSkip[ Number ] = 0; + } + else { + WriteLog("# warning: can't find shapeOutline\n"); + } + } + } + } + } + } + else { + if( DebugMessage ) { + printf( "#skips because of layer.\n"); + } + } + + return( 0 ); +} + +int ProcessPadShapes( int Number, int startToken, string holeDiam ) +{ + OnePadShapeCreated = 0; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "padShape" ) { + int SavePosition = CurrentToken; + + ProcessOnePadShape( Number, SavePosition, holeDiam ); + + CurrentToken = SavePosition; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( "Unexpected keyword in ProcessPadShapes " + Tokens[ + CurrentToken ], "OK"); + return( 1 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +// This function converts PCAD layers to Eagle layers + +string ConvertLayer( string PCADLayer ) +{ + for (int n = 0; n <= CntlayerDef; n++) { + if( PCADLayer == RefLayerNum[n] ) { + if( DebugMessage ) { + //printf( "# info: this layer was converted by using user file.\n"); + } + + return( PcadEagleLayerRefNum[n] ); + } + } + + if( PCADLayer == "0" ) return( "48" ); // Unknown layer + if( PCADLayer == "1" ) return( "1" ); // Top + if( PCADLayer == "2" ) return( "16" ); // Bottom + if( PCADLayer == "3" ) return( "20" ); // Dimension + if( PCADLayer == "4" ) return( "29" ); // Top Mask + if( PCADLayer == "5" ) return( "30" ); // Bot Mask + if( PCADLayer == "6" ) return( "21" ); // Top Silk + if( PCADLayer == "7" ) return( "22" ); // Bot Silk + if( PCADLayer == "8" ) return( "31" ); // Top Paste + if( PCADLayer == "9" ) return( "32" ); // Bot Paste + if( PCADLayer == "10" ) return( "21" ); // Top Assy + if( PCADLayer == "11" ) return( "22" ); // Bot Assy + if( PCADLayer == "12" ) return( "2" ); // Int1 + if( PCADLayer == "13" ) return( "3" ); // Int2 + if( PCADLayer == "14" ) return( "4" ); // Int3 + if( PCADLayer == "15" ) return( "5" ); // Int4 + if( PCADLayer == "16" ) return( "6" ); // Int5 + if( PCADLayer == "17" ) return( "7" ); // Int6 + if( PCADLayer == "18" ) return( "8" ); // Int7 + if( PCADLayer == "19" ) return( "9" ); // Int8 + if( PCADLayer == "20" ) return( "48" ); // MECH + if( PCADLayer == "21" ) return( "48" ); // MECH + if( PCADLayer == "22" ) return( "48" ); // MESH + if( PCADLayer == "23" ) return( "48" ); // MESH + if( PCADLayer == "24" ) return( "48" ); // MESH + if( PCADLayer == "25" ) return( "48" ); // TopStrMsk 48 ? + if( PCADLayer == "26" ) return( "48" ); // BotStrMsk 48 ? + if( PCADLayer == "27" ) return( "48" ); // TopCreep 48 ? + if( PCADLayer == "28" ) return( "48" ); // BotCreep 48 ? + if( PCADLayer == "29" ) return( "48" ); // Int1Creep 48 ? + if( PCADLayer == "30" ) return( "48" ); // Int2Creep 48 ? + if( PCADLayer == "31" ) return( "48" ); // Int3Creep 48 ? + if( PCADLayer == "32" ) return( "48" ); // Int4Creep 48 ? + if( PCADLayer == "33" ) return( "48" ); // Int5Creep 48 ? + if( PCADLayer == "34" ) return( "48" ); // Int6Creep 48 ? + if( PCADLayer == "35" ) return( "48" ); // Int7Creep 48 ? + if( PCADLayer == "36" ) return( "48" ); // Int8Creep 48 ? + if( PCADLayer == "37" ) return( "48" ); // Int9Creep 48 ? + if( PCADLayer == "38" ) return( "48" ); // Int10Creep 48 ? + if( PCADLayer == "39" ) return( "48" ); // Reserve ? + if( PCADLayer == "40" ) return( "48" ); // TxtCreep 48 ? + if( PCADLayer == "41" ) return( "48" ); // DrillHelp 48 ? + if( PCADLayer == "42" ) return( "44" ); // Drill + if( PCADLayer == "43" ) return( "48" ); // TopTxt 48 ? + if( PCADLayer == "44" ) return( "48" ); // BotTxt 48 ? + if( PCADLayer == "45" ) return( "48" ); // TopHelp 48 ? + if( PCADLayer == "46" ) return( "48" ); // BotHelp 48 ? + if( PCADLayer == "47" ) return( "48" ); // Int1Help 48 ? + if( PCADLayer == "48" ) return( "48" ); // Int2Help 48 ? + if( PCADLayer == "49" ) return( "48" ); // Int3Help 48 ? + if( PCADLayer == "50" ) return( "48" ); // Int4Help 48 ? + if( PCADLayer == "51" ) return( "48" ); // Int5Help 48 ? + if( PCADLayer == "52" ) return( "48" ); // Int6Help 48 ? + if( PCADLayer == "53" ) return( "48" ); // Int7Help 48 ? + if( PCADLayer == "54" ) return( "48" ); // Int8Help 48 ? + if( PCADLayer == "55" ) return( "48" ); // Int9Help 48 ? + if( PCADLayer == "56" ) return( "48" ); // Int10Help 48 ? + if( PCADLayer == "57" ) return( "48" ); // SilkscreenTop 48 ? + if( PCADLayer == "58" ) return( "48" ); // SilkscreenBot 48 ? + if( PCADLayer == "59" ) return( "48" ); // BoardHelp 48 ? + if( PCADLayer == "60" ) return( "48" ); // A4H1T0 48 ? + if( PCADLayer == "61" ) return( "48" ); // A4H1B0 48 ? + if( PCADLayer == "62" ) return( "48" ); // A4H2T0 48 ? + if( PCADLayer == "63" ) return( "48" ); // A4H2B0 48 ? + if( PCADLayer == "64" ) return( "48" ); // A4H1-5T0 48 ? + if( PCADLayer == "65" ) return( "48" ); // A4H1-5B0 48 ? + if( PCADLayer == "66" ) return( "48" ); // A4H3T0 48 ? + if( PCADLayer == "67" ) return( "48" ); // A4H3B0 48 ? + if( PCADLayer == "68" ) return( "48" ); // A3H1T0 48 ? + if( PCADLayer == "69" ) return( "48" ); // A3H1B0 48 ? + if( PCADLayer == "70" ) return( "48" ); // TitleReserveT 48 ? + if( PCADLayer == "71" ) return( "48" ); // TitleReserveB 48 ? + if( PCADLayer == "72" ) return( "48" ); // TopDesRes 48 ? + if( PCADLayer == "73" ) return( "48" ); // BotDesRes 48 ? + if( PCADLayer == "74" ) return( "48" ); // TopLCover 48 ? + if( PCADLayer == "75" ) return( "48" ); // BotLCover 48 ? + if( PCADLayer == "76" ) return( "48" ); // TopTstPnt 48 ? + if( PCADLayer == "77" ) return( "48" ); // BotTstPnt 48 ? + // No Layers 78, 79 + if( PCADLayer == "80" ) return( "48" ); // Int1Txt 48 ? + if( PCADLayer == "81" ) return( "48" ); // Int2Txt 48 ? + if( PCADLayer == "82" ) return( "48" ); // Int3Txt 48 ? + if( PCADLayer == "83" ) return( "48" ); // Int4Txt 48 ? + if( PCADLayer == "84" ) return( "48" ); // Int5Txt 48 ? + if( PCADLayer == "85" ) return( "48" ); // Int6Txt 48 ? + if( PCADLayer == "86" ) return( "48" ); // Int7Txt 48 ? + if( PCADLayer == "87" ) return( "48" ); // Int8Txt 48 ? + if( PCADLayer == "88" ) return( "48" ); // Int9Txt 48 ? + if( PCADLayer == "89" ) return( "48" ); // Int10Txt 48 ? + if( PCADLayer == "90" ) return( "48" ); // TxtTopCreep 48 ? + if( PCADLayer == "91" ) return( "48" ); // TxtBotCreep 48 ? + if( PCADLayer == "92" ) return( "48" ); // TxtInt1Creep 48 ? + if( PCADLayer == "93" ) return( "48" ); // TxtInt2Creep 48 ? + if( PCADLayer == "94" ) return( "48" ); // TxtInt3Creep 48 ? + if( PCADLayer == "95" ) return( "48" ); // TxtInt4Creep 48 ? + if( PCADLayer == "96" ) return( "48" ); // TxtInt5Creep 48 ? + if( PCADLayer == "97" ) return( "48" ); // TxtInt6Creep 48 ? + if( PCADLayer == "98" ) return( "48" ); // TxtInt7Creep 48 ? + if( PCADLayer == "99" ) return( "48" ); // TxtInt8Creep 48 ? + if( PCADLayer == "100" ) return( "48" ); // TxtInt9Creep 48 ? + if( PCADLayer == "101" ) return( "48" ); // TxtInt10Creep 48 ? + if( PCADLayer == "102" ) return( "48" ); // Reserve1 48 ? + if( PCADLayer == "103" ) return( "48" ); // TxtAssyTopCreep 48 ? + if( PCADLayer == "104" ) return( "48" ); // TxtAssyBotCreep 48 ? + if( PCADLayer == "105" ) return( "48" ); // TxtAssyTop 48 ? + if( PCADLayer == "106" ) return( "48" ); // TxtAssyBot 48 ? + if( PCADLayer == "107" ) return( "48" ); // TxtTopLCover 48 ? + if( PCADLayer == "108" ) return( "48" ); // TxtBotLCover 48 ? + if( PCADLayer == "109" ) return( "48" ); // TestPointTop 48 ? + if( PCADLayer == "110" ) return( "48" ); // TestPointBot 48 ? + if( PCADLayer == "111" ) return( "35" ); // TopGlue + if( PCADLayer == "112" ) return( "36" ); // BotGlue + if( PCADLayer == "113" ) return( "48" ); // Drill-Top-I1 48 ? + if( PCADLayer == "123" ) return( "48" ); // Drill-Top-I4 48 ? + + string tmp; + sprintf( tmp, "# warning: ConvertLayer: can't convert layer %s\n", PCADLayer ); + WriteLog( tmp ); + + return( "" ); +} + +void GenerateOnePadDefinition( int Number, int startToken ) +{ + //PadStyleDefsScript[ Number ] = "#PadStyleDef " + Tokens[ startToken ]; + printf( "#PadStyleDef %s\n", Tokens[ startToken ] ); + + /*ReplaceNotSupportedCharacters( RemoveDoubleQuotas( + Tokens[ startToken ] ) );*/ + + PadStyleDefsSkip[ Number ] = 1; + PadShapeAddRotation[ Number ] = 0; + + int holeDiamPosition = FindToken( startToken + 1, "holeDiam" ); + + if( holeDiamPosition >= 0 ) { + string TokenText = Tokens[ holeDiamPosition + 1 ]; + + if( Tokens[ holeDiamPosition + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ holeDiamPosition + 2 ] ) ) { + TokenText = TokenText + Tokens[ holeDiamPosition + 2 ]; + } + else { + WriteLog( "#warning: wrong description.\n" ); + } + } + + string holeDiam = ConvertUnits( GetNumberValue( TokenText ), + GetUnitValue( TokenText ) ); + + PadShapePoiner[ Number ] = NrPadShapeStyle; + NrPadShapes[ Number ] = 0; + + if( CheckForNull( holeDiam ) ) { + IfSMD[ Number ] = 1; + } + else { + IfSMD[ Number ] = 0; + } + + if( DebugMessage ) { + printf( "#HoleDiameter = %s\n", holeDiam ); + } + + ProcessPadShapes( Number, startToken, holeDiam ); + + if( PadStyleDefsSkip[ Number ] ) { + if( DebugMessage ) { + printf( "# this PadDefinition was skipped.\n"); + } + } + else { + if( IfSMD[ Number ] ) { + } + else { + sprintf( PadStyleDefsScript[ Number ], "CHANGE DRILL %s;\n%s", + holeDiam, PadStyleDefsScript[ Number ] ); + } + + //printf( "#%s\n", PadStyleDefsScript[ Number ] ); + } + } + else { + if( DebugMessage ) { + printf( "# skips because pad has no holeDiam.\n"); + } + } +} + +void GeneratePadDefinitions( void ) +{ + for( int i = 0; i < PadStyleDefsNumber; i++ ) { + int startToken = PadStyleDefsArray[ i ]; + + string info; + sprintf( info, "Process Pad Style definition %d (%d)", i, PadStyleDefsNumber ); + UpdateProgress( info ); + + GenerateOnePadDefinition( i, startToken ); + } +} + +// This function write library header to script + +void GenerateLibraryHeader( void ) +{ + string libraryName; + string array[]; + + libraryName = filesetext( PCADfileName, ".lbr"); + + PrintPCADLayers(); + + printf("# Library header:\n"); + + if( fileglob( array, libraryName ) ) { + printf("SET CONFIRM YES;\n"); + printf("REMOVE '%s';\n", libraryName ); + printf("SET CONFIRM OFF;\n"); + } + + printf("OPEN '%s';\n", libraryName); + printf("SET WIRE_BEND 2;\n"); + printf("SET OPTIMIZING OFF;\n"); + + printf("#\n"); +} + +// Returns originalName + +string GetOriginalDeviceName( int startToken ) +{ + string originalName = ""; + + int token = FindToken( startToken, "originalName" ); + + if( token > 0 ) { + originalName = Tokens[ token + 1 ]; + } + + return( ReplaceNotSupportedCharacters( RemoveDoubleQuotas( originalName ) ) ); +} + +// This function generates one pad in device + +void GeneratePad( int startToken, int zeroPosition ) +{ + int tokenPosition = FindToken( startToken + 1, "padStyleRef" ); + + if( tokenPosition >= 0 ) { + printf("#padStyleRef = %s\n", Tokens[ tokenPosition + 1 ] ); + + string info; + sprintf( info, "Process pad %d %s", tokenPosition, Tokens[ tokenPosition + 1 ] ); + UpdateProgress( info ); + + int PadStyleDefNum = FindPadStyleDef( Tokens[ tokenPosition + 1 ] ); + + if( PadStyleDefNum >= 0 ) { + if( PadStyleDefsSkip[ PadStyleDefNum ] == 0 ) { + printf( "%s", PadStyleDefsScript[ PadStyleDefNum ] ); + + int defaultPinDesPosition = FindToken( startToken + 1, "defaultPinDes" ); + + int padNumPosition = FindToken( startToken + 1, "padNum" ); + + if( padNumPosition >= 0 ) { + int padCoordPosition = FindToken( startToken + 1, "pt" ); + + if( padCoordPosition >= 0 ) { + string rotation = "0"; + + int rotationPosition = FindToken( startToken + 1, "rotation" ); + + if( rotationPosition >= 0 ) { + rotation = Tokens[ rotationPosition + 1 ]; + } + + if( PadShapeAddRotation[ PadStyleDefNum ] ) { + real rot = strtod( rotation ); + + rot = rot + 90.0; + + if( rot >= 360.0 ) { + rot = rot - 360.0; + } + + sprintf( rotation, "%f", rot ); + } + + string padName = ""; + + padName = Tokens[ padNumPosition + 1 ]; + + /*if( defaultPinDesPosition >= 0 ) { + padName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ defaultPinDesPosition + 1 ] ) ); + } + else { + padName = Tokens[ padNumPosition + 1 ]; + }*/ + + string xCoordPad = ""; + string yCoordPad = ""; + + xCoordPad = Tokens[ padCoordPosition + 1 ]; + + if( IsASCIIValue( Tokens[ padCoordPosition + 2 ] ) ) { + xCoordPad = xCoordPad + Tokens[ padCoordPosition + 2 ]; + + if( Tokens[ padCoordPosition + 3 ] != ")" ) { + yCoordPad = Tokens[ padCoordPosition + 3 ]; + + if( Tokens[ padCoordPosition + 4 ] != ")" ) { + yCoordPad = yCoordPad + Tokens[ padCoordPosition + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoordPad = Tokens[ padCoordPosition + 2 ]; + + if( Tokens[ padCoordPosition + 3 ] != ")" ) { + yCoordPad = yCoordPad + Tokens[ padCoordPosition + 3 ]; + } + } + + string Val1 = ConvertUnits( GetNumberValue( xCoordPad ), + GetUnitValue( xCoordPad ) ); + string Val2 = ConvertUnits( GetNumberValue( yCoordPad ), + GetUnitValue( yCoordPad ) ); + + if( zeroPosition ) { + Val1 = "0.0"; + Val2 = "0.0"; + } + + if( IfSMD[ PadStyleDefNum ] ) { + printf( " R%s '%s' (%s %s);\n", + rotation, + padName, + Val1, Val2 ); + + + } + else { + int pos = strstr( PadStyleDefsScript[ PadStyleDefNum ], "HOLE" ); + + if( padName == "0" ) { + printf( " (%s %s);\n", + Val1, Val2 ); + } + else { + if( pos >= 0 ) { + printf( " '%s' (%s %s);\n", + padName, + Val1, Val2 ); + } + else { + printf( " R%s '%s' (%s %s);\n", + rotation, + padName, + Val1, Val2 ); + } + } + } + + int PPointer = PadShapePoiner[ PadStyleDefNum ]; + int PNumber = NrPadShapes[ PadStyleDefNum ]; + + for( int i = 0; i < PNumber; i++, PPointer++ ) { + if( PadShapeStyleShapeType[ PPointer ] == 1 ) { + printf("CHANGE LAYER %s;\n", ConvertLayer( PadShapeStyleDefsLayer[ PPointer ] ) ); + + real xCoord = GetValue( Tokens[ padCoordPosition + 1 ] ); + real yCoord = GetValue( Tokens[ padCoordPosition + 2 ] ); + real halfWidth = GetValue( PadShapeStyleDefsWidth[ PPointer ] ) / 2.0; + real halfHeight = GetValue( PadShapeStyleDefsHeight[ PPointer ] ) / 2.0; + + if( halfWidth > halfHeight ) { + FilledEllipse( halfWidth, halfHeight, xCoord, yCoord, 0 ); + } + else { + FilledEllipse( halfHeight, halfWidth, xCoord, yCoord, 90.0 ); + } + } + + if( PadShapeStyleShapeType[ PPointer ] == 2 ) { + printf("CHANGE LAYER %s;\n", ConvertLayer( PadShapeStyleDefsLayer[ PPointer ] ) ); + + real xCoord = GetValue( Tokens[ padCoordPosition + 1 ] ); + real yCoord = GetValue( Tokens[ padCoordPosition + 2 ] ); + real halfWidth = GetValue( PadShapeStyleDefsWidth[ PPointer ] ) / 2.0; + real halfHeight = GetValue( PadShapeStyleDefsHeight[ PPointer ] ) / 2.0; + + real rotationInRad = strtod( rotation ) * PI / 180.0; + + real radius; + + if( halfWidth < halfHeight ) { + radius = halfWidth / ROUNDNESS; + } + else { + radius = halfHeight / ROUNDNESS; + } + + printf("# PadShapeStyleShapeType = 2 halfWidth = %f halfHeight = %f radius = %f\n", halfWidth, halfHeight, radius ); + + real x_lo = -halfWidth + radius; + real y_lo = -halfHeight + radius; + real x_hi = halfWidth - radius; + real y_hi = halfHeight - radius; + + printf("POLYGON %f (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n", 2 * radius, + xCoord + RotateXCoord( x_lo, y_lo, rotationInRad ), yCoord + RotateYCoord( x_lo, y_lo, rotationInRad ), + xCoord + RotateXCoord( x_hi, y_lo, rotationInRad ), yCoord + RotateYCoord( x_hi, y_lo, rotationInRad ), + xCoord + RotateXCoord( x_hi, y_hi, rotationInRad ), yCoord + RotateYCoord( x_hi, y_hi, rotationInRad ), + xCoord + RotateXCoord( x_lo, y_hi, rotationInRad ), yCoord + RotateYCoord( x_lo, y_hi, rotationInRad ), + xCoord + RotateXCoord( x_lo, y_hi, rotationInRad ), yCoord + RotateYCoord( x_lo, y_hi, rotationInRad ) ); + + /*printf("POLYGON 0 (%f %f) (%f %f) @-%f (%f %f) (%f %f) @-%f (%f %f) (%f %f) @-%f (%f %f) (%f %f) @-%f (%f %f) ;\n", + xCoord + RotateXCoord( halfWidth - radius, -halfHeight, rotationInRad ), yCoord + RotateYCoord( halfWidth - radius, -halfHeight, rotationInRad ), + xCoord + RotateXCoord( -halfWidth + radius, -halfHeight, rotationInRad ), yCoord + RotateYCoord( -halfWidth + radius, -halfHeight, rotationInRad ), + radius, + xCoord + RotateXCoord( -halfWidth, -halfHeight + radius, rotationInRad ), yCoord + RotateYCoord( -halfWidth, -halfHeight + radius, rotationInRad ), + xCoord + RotateXCoord( -halfWidth, halfHeight - radius, rotationInRad ), yCoord + RotateYCoord( -halfWidth, halfHeight - radius, rotationInRad ), + radius, + xCoord + RotateXCoord( -halfWidth + radius, halfHeight, rotationInRad ), yCoord + RotateYCoord( -halfWidth + radius, halfHeight, rotationInRad ), + xCoord + RotateXCoord( halfWidth - radius, halfHeight, rotationInRad ), yCoord + RotateYCoord( halfWidth - radius, halfHeight, rotationInRad ), + radius, + xCoord + RotateXCoord( halfWidth, halfHeight - radius, rotationInRad ), yCoord + RotateYCoord( halfWidth, halfHeight - radius, rotationInRad ), + xCoord + RotateXCoord( halfWidth, -halfHeight + radius, rotationInRad ), yCoord + RotateYCoord( halfWidth, -halfHeight + radius, rotationInRad ), + radius, + xCoord + RotateXCoord( halfWidth - radius, -halfHeight, rotationInRad ), yCoord + RotateYCoord( halfWidth - radius, -halfHeight, rotationInRad ) );*/ + } + + if( PadShapeStyleShapeType[ PPointer ] == 3 ) { + string xPadCoord[]; + string yPadCoord[]; + int nrLines = 0; + + printf("CHANGE LAYER %s;\n", ConvertLayer( PadShapeStyleDefsLayer[ PPointer ] ) ); + + int currentToken = PadShapeStyleDefsPolygon[ PPointer ]; + + while( currentToken < TokensNumber ) { + if( Tokens[ currentToken ] == "(" ) { + currentToken++; + + if( Tokens[ currentToken ] == "pt" ) { + xPadCoord[ nrLines ] = Tokens[ currentToken + 1 ]; + + if( IsASCIIValue( Tokens[ currentToken + 2 ] ) ) { + xPadCoord[ nrLines ] = xPadCoord[ nrLines ] + Tokens[ currentToken + 2 ]; + + if( Tokens[ currentToken + 3 ] != ")" ) { + yPadCoord[ nrLines ] = Tokens[ currentToken + 3 ]; + + if( Tokens[ currentToken + 4 ] != ")" ) { + yPadCoord[ nrLines ] = yPadCoord[ nrLines ] + Tokens[ currentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yPadCoord[ nrLines ] = Tokens[ currentToken + 2 ]; + + if( Tokens[ currentToken + 3 ] != ")" ) { + yPadCoord[ nrLines ] = yPadCoord[ nrLines ] + Tokens[ currentToken + 3 ]; + } + } + + nrLines++; + + currentToken = currentToken + 3; + } + } + else { + if( Tokens[ currentToken ] == ")" ) { + break; + } + } + + currentToken++; + } // while + + real xCoord = GetValue( Tokens[ padCoordPosition + 1 ] ); + real yCoord = GetValue( Tokens[ padCoordPosition + 2 ] ); + + //printf("GRID 0.01 mil;\n" ); + + real rotationInRad = strtod( rotation ) * PI / 180.0; + + printf("# PadShapeStyleShapeType == 3\n"); + + printf("POLYGON 0\n"); + + for( int i = 0; i < nrLines; i++ ) { + real xPolyCoord = strtod( ConvertUnits( GetNumberValue( xPadCoord[ i ] ), GetUnitValue( xPadCoord[ i ] ) ) ); + real yPolyCoord = strtod( ConvertUnits( GetNumberValue( yPadCoord[ i ] ), GetUnitValue( yPadCoord[ i ] ) ) ); + + printf(" (%f %f)\n", xCoord + RotateXCoord( xPolyCoord, yPolyCoord, rotationInRad ), yCoord + RotateYCoord( xPolyCoord, yPolyCoord, rotationInRad ) ); + } + + real xPolyCoord = strtod( ConvertUnits( GetNumberValue( xPadCoord[ 0 ] ), GetUnitValue( xPadCoord[ 0 ] ) ) ); + real yPolyCoord = strtod( ConvertUnits( GetNumberValue( yPadCoord[ 0 ] ), GetUnitValue( yPadCoord[ 0 ] ) ) ); + + printf(" (%f %f);\n", xCoord + RotateXCoord( xPolyCoord, yPolyCoord, rotationInRad ), yCoord + RotateYCoord( xPolyCoord, yPolyCoord, rotationInRad ) ); + } + + if( PadShapeStyleShapeType[ PPointer ] == 4 ) { + printf("CHANGE LAYER %s;\n", ConvertLayer( PadShapeStyleDefsLayer[ PPointer ] ) ); + + real xCoord = GetValue( Tokens[ padCoordPosition + 1 ] ); + real yCoord = GetValue( Tokens[ padCoordPosition + 2 ] ); + real halfWidth = GetValue( PadShapeStyleDefsWidth[ PPointer ] ) / 2.0; + real halfHeight = GetValue( PadShapeStyleDefsHeight[ PPointer ] ) / 2.0; + + printf("# PadShapeStyleShapeType = 4\n"); + + real rotationInRad = strtod( rotation ) * PI / 180.0; + + printf("POLYGON 0 (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n", + xCoord + RotateXCoord( -halfWidth, -halfHeight, rotationInRad ), yCoord + RotateYCoord( -halfWidth, -halfHeight, rotationInRad ), + xCoord + RotateXCoord( halfWidth, -halfHeight, rotationInRad ), yCoord + RotateYCoord( halfWidth, -halfHeight, rotationInRad ), + xCoord + RotateXCoord( halfWidth, halfHeight, rotationInRad ), yCoord + RotateYCoord( halfWidth, halfHeight, rotationInRad ), + xCoord + RotateXCoord( -halfWidth, halfHeight, rotationInRad ), yCoord + RotateYCoord( -halfWidth, halfHeight, rotationInRad ), + xCoord + RotateXCoord( -halfWidth, -halfHeight, rotationInRad ), yCoord + RotateYCoord( -halfWidth, -halfHeight, rotationInRad ) ); + } + } + } + else { + string tmp; + sprintf( tmp, "#WARNING: Can't find pt for pad %s\n", + Tokens[ startToken + 3 ] ); + WriteLog( tmp ); + } + } + else { + string tmp; + printf("#WARNING: Can't find padNum for pad %s\n", + Tokens[ startToken + 3 ] ); + WriteLog( tmp ); + } + } + else { + printf("#skip this pad\n"); + } + } + else { + string tmp; + printf("#WARNING: Can't find padStyleDef for pad %s\n", + Tokens[ startToken + 3 ] ); + WriteLog( tmp ); + } + } + else { + string tmp; + printf("#WARNING: Can't find padStyleRef for pad %s\n", + Tokens[ startToken + 3 ] ); + WriteLog( tmp ); + } +} + +void GenerateOneLine( int startToken, int ifNet, int ifBoard ) +{ + string net = ""; + string width; + string xLineCoord[]; + string yLineCoord[]; + int nrLines = 0; + + CurrentToken = FindToken( startToken + 1, "width" ); + + + if( CurrentToken > 0 ) { + string TokenText = Tokens[ CurrentToken + 1 ]; + + if( Tokens[ CurrentToken + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + TokenText = TokenText + Tokens[ CurrentToken + 2 ]; + } + else { + WriteLog( "#warning: wrong description.\n" ); + } + } + + width = TokenText; + } + else { + if( ifBoard ) { + width = DEFAULT_WIRE_WIDTH_BOARD; + } + else { + width = DEFAULT_WIRE_WIDTH_SCHEMATIC; + } + } + + if( 1 ) { + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + xLineCoord[ nrLines ] = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xLineCoord[ nrLines ] = xLineCoord[ nrLines ] + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yLineCoord[ nrLines ] = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yLineCoord[ nrLines ] = yLineCoord[ nrLines ] + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yLineCoord[ nrLines ] = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yLineCoord[ nrLines ] = yLineCoord[ nrLines ] + Tokens[ CurrentToken + 3 ]; + } + } + + nrLines++; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "width" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "netNameRef" ) { + net = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ) ); + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "dimensionRef" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "endStyle" ) { + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateOneLine ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( "Unexpected keyword in GenerateOneLine " + Tokens[ CurrentToken ], "OK"); + return; + } + } + + CurrentToken++; + } + + if( ifNet ) { + for( int i = 0; i < nrLines - 1; i++ ) { + printf("NET '%s' (%s %s) (%s %s);\n", net, xLineCoord[ i ], yLineCoord[ i ], + xLineCoord[ i + 1 ], yLineCoord[ i + 1 ] ); + } + + for( int j = 0; j < nrLines; j++ ) { + real xCoord = strtod( ConvertUnits( GetNumberValue( xLineCoord[ j ] ), GetUnitValue( xLineCoord[ j ] ) ) ); + real yCoord = strtod( ConvertUnits( GetNumberValue( yLineCoord[ j ] ), GetUnitValue( yLineCoord[ j ] ) ) ); + + WiresPointX[ NrWiresPoint ] = xCoord; + WiresPointY[ NrWiresPoint ] = yCoord; + WiresNet[ NrWiresPoint ] = net; + + NrWiresPoint++; + } + + return; + } + + // Generate line or wire + if( net == "" ) { + for( int i = 0; i < nrLines - 1; i++ ) { + string Val1 = ConvertUnits( GetNumberValue( xLineCoord[ i ] ), + GetUnitValue( xLineCoord[ i ] ) ); + string Val2 = ConvertUnits( GetNumberValue( yLineCoord[ i ] ), + GetUnitValue( yLineCoord[ i ] ) ); + + string Val3 = ConvertUnits( GetNumberValue( xLineCoord[ i + 1 ] ), + GetUnitValue( xLineCoord[ i + 1 ] ) ); + string Val4 = ConvertUnits( GetNumberValue( yLineCoord[ i + 1 ] ), + GetUnitValue( yLineCoord[ i + 1 ] ) ); + + printf("WIRE %s (%s %s) (%s %s);\n", width, Val1, Val2, Val3, Val4 ); + } + } + else { + for( int i = 0; i < nrLines - 1; i++ ) { + string Val1 = ConvertUnits( GetNumberValue( xLineCoord[ i ] ), + GetUnitValue( xLineCoord[ i ] ) ); + string Val2 = ConvertUnits( GetNumberValue( yLineCoord[ i ] ), + GetUnitValue( yLineCoord[ i ] ) ); + + string Val3 = ConvertUnits( GetNumberValue( xLineCoord[ i + 1 ] ), + GetUnitValue( xLineCoord[ i + 1 ] ) ); + string Val4 = ConvertUnits( GetNumberValue( yLineCoord[ i + 1 ] ), + GetUnitValue( yLineCoord[ i + 1 ] ) ); + + printf("WIRE '%s' %s (%s %s) (%s %s);\n", net, width, Val1, Val2, Val3, Val4 ); + } + } + } + else { + WriteLog("# warning: GenerateOneLine can't find width.\n"); + } +} + +void GenerateOnePcbPoly( int startToken, int ifBoard, string width ) +{ + string net = ""; + string xLineCoord[]; + string yLineCoord[]; + int nrLines = 0; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + xLineCoord[ nrLines ] = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xLineCoord[ nrLines ] = xLineCoord[ nrLines ] + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yLineCoord[ nrLines ] = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yLineCoord[ nrLines ] = yLineCoord[ nrLines ] + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yLineCoord[ nrLines ] = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yLineCoord[ nrLines ] = yLineCoord[ nrLines ] + Tokens[ CurrentToken + 3 ]; + } + } + + nrLines++; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "width" ) { + string TokenText = Tokens[ CurrentToken + 1 ]; + + if( Tokens[ CurrentToken + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + TokenText = TokenText + Tokens[ CurrentToken + 2 ]; + } + else { + WriteLog( "#warning: wrong description.\n" ); + } + } + + width = TokenText; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "netNameRef" ) { + net = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ) ); + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "fillets" ) { + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateOnePcbPoly ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( "Unexpected keyword in GenerateOnePcbPoly " + Tokens[ CurrentToken ], "OK"); + return; + } + } + + CurrentToken++; + } + + if( width == "" ) { + width = "0"; + + /*if( ifBoard ) { + width = DEFAULT_WIRE_WIDTH_BOARD; + } + else { + width = DEFAULT_WIRE_WIDTH_SCHEMATIC; + }*/ + } + + // Generate line + if( net == "" ) { + printf("POLYGON"); + } + else { + printf("POLYGON '%s'", net ); + } + + if( width == "" ) { + } + else { + printf(" %s", width ); + } + + printf("\n"); + + for( int i = 0; i < nrLines; i++ ) { + printf(" (%s %s)\n", xLineCoord[ i ], yLineCoord[ i ] ); + } + + printf(" (%s %s);\n", xLineCoord[ 0 ], yLineCoord[ 0 ] ); +} + +void GenerateOneText( int startToken ) +{ + string text = ""; + string textStyleDef; + string textRotation = "0"; + string xTextCoord; + string yTextCoord; + string justify = ""; + string xExtent = ""; + string yExtent = ""; + string mirrored = ""; + int pointFound = 0; + + CurrentToken = FindToken( startToken + 1, "textStyleRef" ); + + textStyleDef = Tokens[ CurrentToken + 1 ]; + + if( CurrentToken > 0 ) { + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + pointFound = 1; + + xTextCoord = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xTextCoord = xTextCoord + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yTextCoord = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yTextCoord = yTextCoord + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yTextCoord = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yTextCoord = yTextCoord + Tokens[ CurrentToken + 3 ]; + } + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "rotation" ) { + textRotation = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "textStyleRef" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "justify" ) { + justify = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "extent" ) { + //xExtent = Tokens[ CurrentToken + 1 ]; + //yExtent = Tokens[ CurrentToken + 2 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isFlipped" ) { + if( ( Tokens[ CurrentToken + 1 ] == "True" ) || ( Tokens[ CurrentToken + 1 ] == "true" ) ) { + mirrored = "M"; + } + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isVisible" ) { + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateOneText ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + if( UseExternalText ) { + text = ExternalText; + } + else { + sprintf( text, "'%s'", ReplaceNotSupportedCharactersText( RemoveDoubleQuotas( Tokens[ CurrentToken ] ) ) ); + +//printf("# IfPinText = %d text = %s\n", IfPinText, text ); + + // It should be in all cases as we discussed + //if( IfPinText ) { + if( text[ 1 ] == '~' ) { + text[ 1 ] = '!'; + } + //} + } + } + } + + CurrentToken++; + } + + if( text == "''" ) { + return; + } + + if( !pointFound ) { + return; + } + + if( justify == "" ) { //LowerLeft + printf("CHANGE ALIGN BOTTOM LEFT;\n"); + + if( xExtent != "" ) { + sprintf( xTextCoord, "%f", strtod( xTextCoord ) - strtod( xExtent ) / 2 ); + } + + if( yExtent != "" ) { + sprintf( yTextCoord, "%f", strtod( yTextCoord ) - strtod( yExtent ) / 2 ); + } + } else if( justify == "UpperLeft" ) { + printf("CHANGE ALIGN TOP LEFT;\n"); + + if( xExtent != "" ) { + sprintf( xTextCoord, "%f", strtod( xTextCoord ) - strtod( xExtent ) / 2 ); + } + + if( yExtent != "" ) { + sprintf( yTextCoord, "%f", strtod( yTextCoord ) + strtod( yExtent ) / 2 ); + } + } else if( justify == "UpperCenter" ) { + printf("CHANGE ALIGN TOP CENTER;\n"); + + if( yExtent != "" ) { + sprintf( yTextCoord, "%f", strtod( yTextCoord ) + strtod( yExtent ) / 2 ); + } + } else if( justify == "UpperRight" ) { + printf("CHANGE ALIGN TOP RIGHT;\n"); + + if( xExtent != "" ) { + sprintf( xTextCoord, "%f", strtod( xTextCoord ) + strtod( xExtent ) / 2 ); + } + + if( yExtent != "" ) { + sprintf( yTextCoord, "%f", strtod( yTextCoord ) + strtod( yExtent ) / 2 ); + } + } else if( justify == "Left" ) { + printf("CHANGE ALIGN CENTER LEFT;\n"); + + if( xExtent != "" ) { + sprintf( xTextCoord, "%f", strtod( xTextCoord ) - strtod( xExtent ) / 2 ); + } + } else if( justify == "Center" ) { + printf("CHANGE ALIGN CENTER CENTER;\n"); + } else if( justify == "Right" ) { + printf("CHANGE ALIGN CENTER RIGHT;\n"); + + if( xExtent != "" ) { + sprintf( xTextCoord, "%f", strtod( xTextCoord ) + strtod( xExtent ) / 2 ); + } + } else if( justify == "LowerLeft" ) { + printf("CHANGE ALIGN BOTTOM LEFT;\n"); + + if( xExtent != "" ) { + sprintf( xTextCoord, "%f", strtod( xTextCoord ) - strtod( xExtent ) / 2 ); + } + + if( yExtent != "" ) { + sprintf( yTextCoord, "%f", strtod( yTextCoord ) - strtod( yExtent ) / 2 ); + } + } else if( justify == "LowerCenter" ) { + printf("CHANGE ALIGN BOTTOM CENTER;\n"); + + if( yExtent != "" ) { + sprintf( yTextCoord, "%f", strtod( yTextCoord ) - strtod( yExtent ) / 2 ); + } + + } else if( justify == "LowerRight" ) { + printf("CHANGE ALIGN BOTTOM RIGHT;\n"); + + if( xExtent != "" ) { + sprintf( xTextCoord, "%f", strtod( xTextCoord ) + strtod( xExtent ) / 2 ); + } + + if( yExtent != "" ) { + sprintf( yTextCoord, "%f", strtod( yTextCoord ) - strtod( yExtent ) / 2 ); + } + } + else { + printf("# warning: unknown justify parameter value = %s\n", justify ); + printf("CHANGE ALIGN BOTTOM LEFT;\n"); + + if( xExtent != "" ) { + sprintf( xTextCoord, "%f", strtod( xTextCoord ) - strtod( xExtent ) / 2 ); + } + + if( yExtent != "" ) { + sprintf( yTextCoord, "%f", strtod( yTextCoord ) - strtod( yExtent ) / 2 ); + } + } + + // Generate text + int textStyleDefPos = FindTextStyleDef( textStyleDef ); + + if( textStyleDefPos >= 0 ) { + real fontHeight = strtod( ConvertUnits( GetNumberValue( TextStyleDefFontHeight[ textStyleDefPos ] ), GetUnitValue( TextStyleDefFontHeight[ textStyleDefPos ] ) ) ); + real fontWidth = strtod( ConvertUnits( GetNumberValue( TextStyleDefFontStrokeWidth[ textStyleDefPos ] ), GetUnitValue( TextStyleDefFontStrokeWidth[ textStyleDefPos ] ) ) ); + + printf("CHANGE SIZE %s;\n", TextStyleDefFontHeight[ textStyleDefPos ] ); + + if( fontHeight ) { + int ratio = round( 100.0 * fontWidth / fontHeight ); + + if( ratio > 31.0 ) { + ratio = 31.0; + } + + printf("CHANGE RATIO %d;\n", ratio ); + } + + printf("TEXT %s %sSR%s (%s %s);\n", text, mirrored, textRotation, xTextCoord, yTextCoord ); + } + else { + WriteLog("# warning: GenerateOneText can't find textStyleDef.\n"); + } + } + else { + WriteLog("# warning: GenerateOneText can't find textStyleRef.\n"); + } +} + +void GenerateOneBus( int startToken ) +{ + int textToken; + string dispName; + string textX; + string textY; + string xLineCoord[]; + string yLineCoord[]; + int nrLines = 0; + + CurrentToken = startToken + 1; + + string name = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + xLineCoord[ nrLines ] = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xLineCoord[ nrLines ] = xLineCoord[ nrLines ] + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yLineCoord[ nrLines ] = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yLineCoord[ nrLines ] = yLineCoord[ nrLines ] + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yLineCoord[ nrLines ] = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yLineCoord[ nrLines ] = yLineCoord[ nrLines ] + Tokens[ CurrentToken + 3 ]; + } + } + + nrLines++; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "dispName" ) { + dispName = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "text" ) { + textToken = CurrentToken; + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateOneBus ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( "Unexpected keyword in GenerateOneBus " + Tokens[ CurrentToken ], "OK"); + return; + } + } + + CurrentToken++; + } + + int pos = strchr( name, '(' ); + + if( pos >= 0 ) { + int pos1 = strchr( name, ':' ); + + if( pos1 >= 0 ) { + if( pos1 > pos + 1 ) { + int firstNumber = strtol( strsub( name, pos + 1, pos1 - pos - 1 ) ); + + int pos2 = strchr( name, ')' ); + + if( pos2 >= 0 ) { + if( pos2 > pos1 + 1 ) { + int secondNumber = strtol( strsub( name, pos1 + 1, pos2 - pos1 - 1 ) ); + + string busName = ReplaceNotSupportedCharacters( strsub( name, 0, pos ) ); + + for( int i = 0; i < nrLines - 1; i++ ) { + printf("BUS '%s[%d..%d]' (%s %s) (%s %s);\n", busName, firstNumber, secondNumber, + xLineCoord[ i ], yLineCoord[ i ], + xLineCoord[ i + 1 ], yLineCoord[ i + 1 ] ); + } + + if( dispName == "True" ) { + UseExternalText = 1; + sprintf( ExternalText, "'%s[%d..%d]'", busName, firstNumber, secondNumber ); + GenerateOneText( textToken ); + UseExternalText = 0; + } + } + } + else { + WriteLog( "#warning: GenerateOneBus cant find ')'\n"); + } + } + else { + WriteLog( "#warning: GenerateOneBus wrong first number\n"); + } + } + else { + WriteLog( "#warning: GenerateOneBus cant find ':'\n"); + } + } + else { + string busName = ReplaceNotSupportedCharacters( name ); + + for( int i = 0; i < nrLines - 1; i++ ) { + printf("BUS '%s' (%s %s) (%s %s);\n", busName, + xLineCoord[ i ], yLineCoord[ i ], + xLineCoord[ i + 1 ], yLineCoord[ i + 1 ] ); + } + + if( dispName == "True" ) { + UseExternalText = 1; + sprintf( ExternalText, "'%s'", busName ); + GenerateOneText( textToken ); + UseExternalText = 0; + } + + //printf( "# GenerateOneBus cant find '('\n"); + } +} + +void ArcDraw( string width, real X, string xArcCoordUnit, real Y, string yArcCoordUnit, + real Radius, string radiusUnit, real arcs, real arce ) +{ + string as; + real arcStart = 360 + (arcs); + if (arcStart > 360) arcStart -= 360; + real arcEnd = arcStart + (arce); + if (arcEnd > 360) arcEnd -= 360; + real xArcStart = Radius * cos(PI / 180 * arcStart); + real yArcStart = Radius * sin(PI / 180 * arcStart); + real xArcEnd = Radius * cos(PI / 180 * arcEnd); + real yArcEnd = Radius * sin(PI / 180 * arcEnd); + + printf( "ARC CCW %s (%.8f%s %.8f%s) (%.8f%s %.8f%s) (%.8f%s %.8f%s);\n", + width, + X + xArcStart, xArcCoordUnit, Y + yArcStart, yArcCoordUnit, + X - xArcStart, xArcCoordUnit, Y - yArcStart, yArcCoordUnit, + X + xArcEnd, xArcCoordUnit, Y + yArcEnd, yArcCoordUnit ); +} + +void GenerateOneArc( int startToken ) +{ + real radius; + string radiusUnit = ""; + real startAngle; + real sweepAngle; + string width; + real xArcCoord; + string xArcCoordUnit = ""; + real yArcCoord; + string yArcCoordUnit = ""; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + string xArcCoordText = ""; + string yArcCoordText = ""; + + xArcCoordText = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xArcCoordText = xArcCoordText + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yArcCoordText = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yArcCoordText = yArcCoordText + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yArcCoordText = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yArcCoordText = yArcCoordText + Tokens[ CurrentToken + 3 ]; + } + } + + xArcCoord = strtod( ConvertUnits( GetNumberValue( xArcCoordText ), GetUnitValue( xArcCoordText ) ) ); + yArcCoord = strtod( ConvertUnits( GetNumberValue( yArcCoordText ), GetUnitValue( yArcCoordText ) ) ); + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "radius" ) { + string ArcRadiusText = Tokens[ CurrentToken + 1 ]; + + if( Tokens[ CurrentToken + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + ArcRadiusText = ArcRadiusText + Tokens[ CurrentToken + 2 ]; + } + else { + WriteLog( "#warning: wront radius description.\n" ); + } + } + + radius = strtod( ConvertUnits( GetNumberValue( ArcRadiusText ), GetUnitValue( ArcRadiusText ) ) ); + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "startAngle" ) { + startAngle = strtod( Tokens[ CurrentToken + 1 ] ); + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "sweepAngle" ) { + sweepAngle = strtod( Tokens[ CurrentToken + 1 ] ); + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "width" ) { + width = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateOneArc ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + //if( ( sweepAngle - startAngle >= 360 ) || ( ( ( sweepAngle == 0 ) && ( startAngle == 0 ) ) ) ) { + if( ( sweepAngle >= 360 ) || ( ( ( sweepAngle == 0 ) && ( startAngle == 0 ) ) ) ) { + printf("CIRCLE %s (%.8f%s %.8f%s) (%.8f%s %.8f%s);\n", + width, xArcCoord, xArcCoordUnit, yArcCoord, yArcCoordUnit, + xArcCoord + radius, xArcCoordUnit, yArcCoord, yArcCoordUnit ); + } + else { + ArcDraw( width, xArcCoord, xArcCoordUnit, yArcCoord, yArcCoordUnit, radius, radiusUnit, startAngle, sweepAngle ); + } +} + +void GenerateOneTripleArc( int startToken ) +{ + string width; + real xPointCoord[]; + real yPointCoord[]; + int nrPoints = 0; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + string xArcCoordText = ""; + string yArcCoordText = ""; + + xArcCoordText = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xArcCoordText = xArcCoordText + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yArcCoordText = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yArcCoordText = yArcCoordText + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yArcCoordText = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yArcCoordText = yArcCoordText + Tokens[ CurrentToken + 3 ]; + } + } + + xPointCoord[ nrPoints ] = strtod( ConvertUnits( GetNumberValue( xArcCoordText ), GetUnitValue( xArcCoordText ) ) ); + yPointCoord[ nrPoints ] = strtod( ConvertUnits( GetNumberValue( yArcCoordText ), GetUnitValue( yArcCoordText ) ) ); + + //printf( "# coord = %f %f\n", xPointCoord[ nrPoints ], yPointCoord[ nrPoints ] ); + + nrPoints++; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "width" ) { + width = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateOneTripleArc ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + if( nrPoints == 3 ) { + if( ( xPointCoord[ 1 ] == xPointCoord[ 2 ] ) && ( yPointCoord[ 1 ] == yPointCoord[ 2 ] ) ) { + printf( "CIRCLE %s (%.8f %.8f) (%.8f %.8f); # triplePointArc\n", width, + xPointCoord[ 0 ], yPointCoord[ 0 ], + xPointCoord[ 1 ], yPointCoord[ 1 ] ); + } + else { + real pX = 2 * xPointCoord[ 0 ] - xPointCoord[ 1 ]; + real pY = 2 * yPointCoord[ 0 ] - yPointCoord[ 1 ]; + + printf( "ARC CCW %s (%.8f %.8f) (%.8f %.8f) (%.8f %.8f); # triplePointArc\n", width, + xPointCoord[ 1 ], + yPointCoord[ 1 ], + pX, + pY, + xPointCoord[ 2 ], + yPointCoord[ 2 ] ); + } + } + else { + string tmp; + sprintf( tmp, "warning: GenerateOneTripleArc wrong number of points %d\n", nrPoints ); + WriteLog( tmp ); + } +} + +void GenerateIslandCutouts( int startToken ) +{ + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "islandOutline" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "cutout" ) { + printf("CHANGE Pour cutout;\n"); + int SavePosition = CurrentToken; + CurrentToken++; + CurrentToken++; + printf( "CHANGE THERMALS OFF;\n"); + GenerateOnePcbPoly( CurrentToken, 1, "" ); + CurrentToken = SavePosition; + printf("CHANGE Pour solid;\n"); + SkipThisItem(); + } + else { + printf( "# GenerateIslandCutouts ??????? %s\n", Tokens[ CurrentToken ] ); + SkipThisItem(); + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } +} + +void GenerateOneCopperPour95( int startToken ) +{ + int thermal = 0; + int pourSolid = 1; + string width = DEFAULT_WIRE_WIDTH_BOARD; + string pourSpacing = ""; + + CurrentToken = FindToken( startToken + 1, "pourSpacing" ); + + if( CurrentToken > 0 ) { + printf( "CHANGE SPACING %s;\n", Tokens[ CurrentToken + 1 ] ); + } + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pourType" ) { + if( Tokens[ CurrentToken + 1 ] != "SolidPour" ) { + pourSolid = 0; + } + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "netNameRef" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pourSpacing" ) { + string TokenText = Tokens[ CurrentToken + 1 ]; + + if( Tokens[ CurrentToken + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + TokenText = TokenText + Tokens[ CurrentToken + 2 ]; + } + else { + WriteLog( "#warning: wrong description.\n" ); + } + } + + pourSpacing = TokenText; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pourBackoff" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pourSmoothness" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "islandRemoval" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pcbPoly" ) { + int SavePosition = CurrentToken; + + if( thermal ) { + printf( "CHANGE THERMALS ON;\n"); + } + else { + printf( "CHANGE THERMALS OFF;\n"); + } + + if( pourSolid ) { + printf( "CHANGE POUR SOLID;\n"); + } + else { + printf( "CHANGE POUR HATCH;\n"); + } + + if( pourSpacing != "" ) { + printf( "CHANGE SPACING %s;\n", pourSpacing ); + } + else { + printf( "CHANGE SPACING 50mil;\n", pourSpacing ); + } + + printf("# CopperPour95\n"); + GenerateOnePcbPoly( SavePosition, 1, width ); + + if( thermal ) { + printf( "CHANGE THERMALS OFF;\n"); + } + + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "width" ) { + string TokenText = Tokens[ CurrentToken + 1 ]; + + if( Tokens[ CurrentToken + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + TokenText = TokenText + Tokens[ CurrentToken + 2 ]; + } + else { + WriteLog( "#warning: wrong description.\n" ); + } + } + + width = TokenText; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "useDesignRules" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "thermalType" ) { + if( Tokens[ CurrentToken + 1 ] != "NoTherm" ) { + thermal = 1; + } + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "thermalWidth" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "thermalSpokes" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "viaThermalType" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "viaThermalWidth" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "viaThermalSpokes" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "island" ) { + int SavePosition = CurrentToken; + // Comment this line because Eagle doesn't use GND cutouts + //GenerateIslandCutouts( CurrentToken ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateOneCopperPour95 ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } +} + +void GenerateOneDimension( int startToken ) +{ + CurrentToken = FindToken( startToken + 1, "dimPoints" ); + + if( CurrentToken > 0 ) { + string xPointCoord[]; + string yPointCoord[]; + string xPointUnit[]; + string yPointUnit[]; + int nrPoints = 0; + + CurrentToken = CurrentToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + string xCoord = ""; + string yCoord = ""; + + xCoord = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xCoord = xCoord + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoord = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 3 ]; + } + } + + xPointCoord[ nrPoints ] = GetNumberValue( xCoord ); + yPointCoord[ nrPoints ] = GetNumberValue( yCoord ); + xPointUnit[ nrPoints ] = GetUnitValue( xCoord ); + yPointUnit[ nrPoints ] = GetUnitValue( yCoord ); + + nrPoints++; + + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateOneDimension ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + CurrentToken = FindToken( startToken + 1, "dimOrient" ); + + string dimensionDirection = "PARALLEL"; + + if( Tokens[ CurrentToken + 1 ] == "dim_vertical" ) { + xPointCoord[ 1 ] = xPointCoord[ 0 ]; + xPointUnit[ 1 ] = xPointUnit[ 0 ]; + dimensionDirection = "Horizontal"; + } + + if( Tokens[ CurrentToken + 1 ] == "dim_horizontal" ) { + yPointCoord[ 1 ] = yPointCoord[ 0 ]; + yPointUnit[ 1 ] = yPointUnit[ 0 ]; + dimensionDirection = "Vertical"; + } + + if( nrPoints == 3 ) { + printf("GRID mm 0.0001;\n" ); + printf("CHANGE LAYER 47;\n"); + printf( "DIMENSION %s (C%s%s %s%s) (C%s%s %s%s) (C%s%s %s%s);\n", + dimensionDirection, + xPointCoord[ 0 ], + xPointUnit[ 0 ], + yPointCoord[ 0 ], + yPointUnit[ 0 ], + xPointCoord[ 1 ], + xPointUnit[ 1 ], + yPointCoord[ 1 ], + yPointUnit[ 1 ], + xPointCoord[ 2 ], + xPointUnit[ 2 ], + yPointCoord[ 2 ], + yPointUnit[ 2 ] ); + } + printf("GRID %s;\n", FileUnits ); + } +} + +/*void GenerateOneAttribute( int startToken, string layer ) +{ + CurrentToken = startToken + 1; + + string type = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + if( type == "Type" ) { + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + printf("CHANGE ALIGN CENTER;\n"); + printf("CHANGE LAYER 27;\n"); + + string xCoord = Tokens[ CurrentToken + 1 ]; + string yCoord = ""; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xCoord = xCoord + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoord = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 3 ]; + } + } + + printf("TEXT '>VALUE' (%s %s);\n", + ConvertUnits( GetNumberValue( xCoord ), GetUnitValue( xCoord ) ), + ConvertUnits( GetNumberValue( yCoord ), GetUnitValue( yCoord ) ) ); + + printf("CHANGE LAYER 25;\n"); + printf("TEXT '>NAME' (0.0 0.0);\n"); + + if( layer != "" ) { + printf( "CHANGE LAYER %s;\n", layer ); + } + } + else { + SkipThisItem(); + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + } +}*/ + +/*void GenerateNameAndValue( int startToken, string layer ) +{ + CurrentToken = startToken + 1; + + int textToken = startToken + 1; + + string type = RemoveDoubleQuotas( Tokens[ CurrentToken ] ); + + string xCoord = "0.0"; + string yCoord = "0.0"; + string isVisible = "True"; + string textStyleRef = ""; + int ifPoint = 0; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + ifPoint = 1; + + xCoord = Tokens[ CurrentToken + 1 ]; + yCoord = ""; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xCoord = xCoord + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoord = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 3 ]; + } + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isVisible" ) { + if( ( Tokens[ CurrentToken + 1 ] == "False" ) || ( Tokens[ CurrentToken + 1 ] == "false" ) ) { + isVisible = "False"; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "textStyleRef" ) { + textStyleRef = RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ); + + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + if( type == "Value" ) { + if( isVisible == "True" ) { + printf("CHANGE ALIGN CENTER;\n"); + printf("CHANGE LAYER 27;\n"); + + if( ifPoint ) { + UseExternalText = 1; + ExternalText = "'>VALUE'"; + GenerateOneText( textToken ); + UseExternalText = 0; + } + else { + printf("TEXT '>VALUE' (0.0 0.0);\n"); + } + + if( layer != "" ) { + printf( "CHANGE LAYER %s;\n", layer ); + } + } + } + + if( type == "RefDes" ) { + if( isVisible == "True" ) { + printf("CHANGE ALIGN CENTER;\n"); + printf("CHANGE LAYER 25;\n"); + + if( ifPoint ) { + UseExternalText = 1; + ExternalText = "'>NAME'"; + GenerateOneText( textToken ); + UseExternalText = 0; + } + else { + printf("TEXT '>NAME' (0.0 0.0);\n"); + } + + if( layer != "" ) { + printf( "CHANGE LAYER %s;\n", layer ); + } + } + } +}*/ + +void GenerateNameAndValue( int startToken, string layer, int patternIndex ) +{ + CurrentToken = startToken + 1; + + int textToken = startToken + 1; + + string type = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken ] ) ); + + string xCoord = "0.0"; + string yCoord = "0.0"; + string isVisible = "False"; + string textStyleRef = ""; + int ifPoint = 0; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + ifPoint = 1; + + xCoord = Tokens[ CurrentToken + 1 ]; + yCoord = ""; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xCoord = xCoord + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoord = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 3 ]; + } + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isVisible" ) { + if( ( Tokens[ CurrentToken + 1 ] == "True" ) || ( Tokens[ CurrentToken + 1 ] == "true" ) ) { + isVisible = "True"; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "textStyleRef" ) { + textStyleRef = RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ); + + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + if( type == "Value" ) { + printf("CHANGE ALIGN CENTER;\n"); + printf("CHANGE LAYER 27;\n"); + + if( ifPoint ) { + UseExternalText = 1; + ExternalText = "'>VALUE'"; + GenerateOneText( textToken ); + UseExternalText = 0; + } + else { + printf("TEXT '>VALUE' (0.0 0.0);\n"); + } + + if( layer != "" ) { + printf( "CHANGE LAYER %s;\n", layer ); + } + + if( isVisible != "True" ) { + IfValueDefinedInPattern[ patternIndex ] = 1; + } + } + + if( type == "RefDes" ) { + printf("CHANGE ALIGN CENTER;\n"); + printf("CHANGE LAYER 25;\n"); + + if( ifPoint ) { + UseExternalText = 1; + ExternalText = "'>NAME'"; + GenerateOneText( textToken ); + UseExternalText = 0; + } + else { + printf("TEXT '>NAME' (0.0 0.0);\n"); + } + + if( layer != "" ) { + printf( "CHANGE LAYER %s;\n", layer ); + } + + if( isVisible != "True" ) { + IfNameDefinedInPattern[ patternIndex ] = 1; + } + } + + AttributesName[ NrAttributes ] = type; + AttributesIndex[ NrAttributes ] = startToken; + NrAttributes++; + + PatternNrAttributes[ patternIndex ]++; +} + +void GenerateNameAndValueSchematics( int startToken, int symbolIndex ) +{ + CurrentToken = startToken + 1; + + int textToken = startToken + 1; + + string type = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken ] ) ); + + string xCoord = "0.0"; + string yCoord = "0.0"; + string isVisible = "False"; + string textStyleRef = ""; + int ifPoint = 0; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + ifPoint = 1; + + xCoord = Tokens[ CurrentToken + 1 ]; + yCoord = ""; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xCoord = xCoord + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoord = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoord = yCoord + Tokens[ CurrentToken + 3 ]; + } + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isVisible" ) { + if( ( Tokens[ CurrentToken + 1 ] == "True" ) || ( Tokens[ CurrentToken + 1 ] == "true" ) ) { + isVisible = "True"; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "textStyleRef" ) { + textStyleRef = RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ); + + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + if( type == "Value" ) { + printf("CHANGE ALIGN CENTER;\n"); + printf("CHANGE LAYER 96;\n"); + + if( ifPoint ) { + UseExternalText = 1; + ExternalText = "'>VALUE'"; + GenerateOneText( textToken ); + UseExternalText = 0; + } + else { + printf("TEXT '>VALUE' (0.0 0.0);\n"); + } + + if( isVisible != "True" ) { + IfValueDefinedInSymbol[ symbolIndex ] = 1; + } + } + + if( type == "RefDes" ) { + printf("CHANGE ALIGN CENTER;\n"); + printf("CHANGE LAYER 95;\n"); + + if( ifPoint ) { + UseExternalText = 1; + ExternalText = "'>NAME'"; + GenerateOneText( textToken ); + UseExternalText = 0; + } + else { + printf("TEXT '>NAME' (0.0 0.0);\n"); + } + + if( isVisible != "True" ) { + IfNameDefinedInSymbol[ symbolIndex ] = 1; + } + } + + AttributesName[ NrAttributes ] = type; + AttributesIndex[ NrAttributes ] = startToken; + NrAttributes++; + + SymbolNrAttributes[ symbolIndex ]++; +} + +void GenerateLayerContents( int startToken, int patternIndex ) +{ + printf("# LayerContents\n"); + + CurrentToken = FindToken( startToken + 1, "layerNumRef" ); + + if( CurrentToken > 0 ) { + string layer = ConvertLayer( Tokens[ CurrentToken + 1 ] ); + + printf( "# layerNumRef = %s\n", Tokens[ CurrentToken + 1 ] ); + printf( "CHANGE LAYER %s;\n", layer ); + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "line" ) { + int SavePosition = CurrentToken; + GenerateOneLine( SavePosition, 0, 1 ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "arc" ) { + int SavePosition = CurrentToken; + GenerateOneArc( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "text" ) { + int SavePosition = CurrentToken; + GenerateOneText( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "attr" ) { + int SavePosition = CurrentToken; + + if( patternIndex >= 0 ) { + GenerateNameAndValue( SavePosition, layer, patternIndex ); + } + + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "triplePointArc" ) { + int SavePosition = CurrentToken; + GenerateOneTripleArc( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "testpoint" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "layerNumRef" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pcbPoly" ) { + int SavePosition = CurrentToken; + printf( "CHANGE THERMALS OFF;\n"); + GenerateOnePcbPoly( SavePosition, 1, DEFAULT_WIRE_WIDTH_BOARD ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "polyCutOut" ) { + printf("CHANGE Pour cutout;\n"); + int SavePosition = CurrentToken; + CurrentToken++; + CurrentToken++; + printf( "CHANGE THERMALS OFF;\n"); + GenerateOnePcbPoly( CurrentToken, 1, DEFAULT_WIRE_WIDTH_BOARD ); + CurrentToken = SavePosition; + printf("CHANGE Pour solid;\n"); + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "copperPour95" ) { + int SavePosition = CurrentToken; + GenerateOneCopperPour95( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "field" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "boardOutlineObj" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "dimension" ) { + int SavePosition = CurrentToken; + GenerateOneDimension( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "table" ) { + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateLayerContents ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( TR("Unexpected keyword in LayerContents: ") + Tokens[ CurrentToken ], "OK"); + return; + } + } + + CurrentToken++; + } + } + else { + WriteLog("# warning: GenerateLayerContents can't find layerNumRef.\n"); + } +} + +// Generate devices from patternDef and patternDefExtended + +void GeneratePackages( void ) +{ + printf("# Packages:\n"); + + for( int i = 0; i < PatternDefExtendedNumber; i++ ) { + int startToken = PatternDefExtendedArray[ i ]; + + string DeviceName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( + Tokens[ startToken ] ) + ); + + string OriginalDeviceName = GetOriginalDeviceName( startToken + 1 ); + + IfNameDefinedInPattern[ i ] = 0; + IfValueDefinedInPattern[ i ] = 0; + PatternAttributesIndex[ i ] = NrAttributes; + PatternNrAttributes[ i ] = 0; + PatternName[ i ] = DeviceName; + PatternOriginalName[ i ] = OriginalDeviceName; + + int patternGraphicsNameRefToken = FindToken( startToken + 1, "patternGraphicsNameRef" ); + + if( patternGraphicsNameRefToken >= 0 ) { + PatternDefaultVariantName[ i ] = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ patternGraphicsNameRefToken + 1 ] ) ); + } + else { + PatternDefaultVariantName[ i ] = ""; + } + + int patternGraphicsDefToken = PatternGraphicsDefArray[ i ]; + + if( patternGraphicsDefToken < 0 ) { + patternGraphicsDefToken = startToken; + PatternGraphicsDefName[ i ] = ""; + } + else { + int patternGraphicsNameDefToken = FindToken( patternGraphicsDefToken + 1, "patternGraphicsNameDef" ); + + if( patternGraphicsNameDefToken >= 0 ) { + PatternGraphicsDefName[ i ] = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ patternGraphicsNameDefToken + 1 ] ) ); + } + else { + PatternGraphicsDefName[ i ] = ""; + WriteLog( "# warning: no patternGraphicsNameDef\n"); + } + } + + printf("#\n"); + printf("# Package: %s OriginalName = %s VariantName = %s PatternDefaultVariantName = %s\n", DeviceName, OriginalDeviceName, + PatternGraphicsDefName[ i ], PatternDefaultVariantName[ i ] ); + + printf("EDIT '%s%s.PAC';\n", DeviceName, PatternGraphicsDefName[ i ] ); + printf("DESCRIPTION 'Original name %s

    ';\n", OriginalDeviceName ); + printf("GRID %s;\n", FileUnits ); + printf("CHANGE FONT VECTOR;\n"); + + if( patternGraphicsDefToken >= 0 ) { + CurrentToken = FindToken( patternGraphicsDefToken + 1, "multiLayer" ); + + if( CurrentToken > 0 ) { + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pad" ) { + int SavePosition = CurrentToken; + + GeneratePad( SavePosition, 0 ); + + CurrentToken = SavePosition; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( "Unexpected keyword in multiLayer " + Tokens[ CurrentToken ], "OK"); + return; + } + } + + CurrentToken++; + } + } + + CurrentToken = patternGraphicsDefToken; + + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "layerContents" ) { + int SavePosition = CurrentToken; + + GenerateLayerContents( SavePosition, i ); + + CurrentToken = SavePosition; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( "Unexpected keyword in layerContents " + Tokens[ CurrentToken ], "OK"); + return; + } + } + + CurrentToken++; + } + } + } +} + +int OneViaShapeCreated; + +int ProcessOneViaShape( int Number, int startToken, string holeDiam ) +{ + int layerNumRefPosition = FindToken( startToken + 1, "layerNumRef" ); + + if( layerNumRefPosition >= 0 ) { + if( checkLayerType( layerNumRefPosition + 1 ) ) { + int viaShapeTypePosition = FindToken( startToken + 1, "viaShapeType" ); + + if( viaShapeTypePosition >= 0 ) { + int shapeWidthPosition = FindToken( startToken + 1, "shapeWidth" ); + + if( shapeWidthPosition >= 0 ) { + string TokenText = Tokens[ shapeWidthPosition + 1 ]; + + if( Tokens[ shapeWidthPosition + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ shapeWidthPosition + 2 ] ) ) { + TokenText = TokenText + Tokens[ shapeWidthPosition + 2 ]; + } + else { + WriteLog( "#warning: wrong description.\n" ); + } + } + + string shapeWidth = ConvertUnits( GetNumberValue( TokenText ), + GetUnitValue( TokenText ) ); + + int shapeHeightPosition = FindToken( startToken + 1, "shapeHeight" ); + + if( shapeHeightPosition >= 0 ) { + + string TokenText = Tokens[ shapeHeightPosition + 1 ]; + + if( Tokens[ shapeHeightPosition + 2 ] != ")" ) { + if( IsASCIIValue( Tokens[ shapeHeightPosition + 2 ] ) ) { + TokenText = TokenText + Tokens[ shapeHeightPosition + 2 ]; + } + else { + WriteLog( "#warning: wrong description.\n" ); + } + } + + string shapeHeight = ConvertUnits( GetNumberValue( TokenText ), + GetUnitValue( TokenText ) ); + + if( ( !CheckForNull( shapeWidth ) ) || + ( !CheckForNull( shapeHeight ) ) ) { + + printf("# ViaShape: layerNumRef = %s", + Tokens[ layerNumRefPosition + 1 ] ); + printf(" viaShapeType = %s", + Tokens[ viaShapeTypePosition + 1 ] ); + printf(" shapeWidth = %s", shapeWidth ); + printf(" shapeHeight = %s\n", shapeHeight ); + + if( OneViaShapeCreated == 0 ) { + if( Tokens[ viaShapeTypePosition + 1 ] == "Oval" ) { // Oval + if( shapeWidth == shapeHeight ) { + ViaStyleDefsType[ Number ] = "ROUND"; + ViaStyleDefsDiameter[ Number ] = shapeWidth; + OneViaShapeCreated = 1; + ViaStyleDefsSkip[ Number ] = 0; + } + else { + ViaStyleDefsType[ Number ] = "ROUND"; + ViaStyleDefsDiameter[ Number ] = shapeWidth; + OneViaShapeCreated = 1; + ViaStyleDefsSkip[ Number ] = 0; + + //if( DebugMessage ) { + WriteLog("#warning: ViaShape: oval. Create round via\n"); + //} + } + } + else { + if( Tokens[ viaShapeTypePosition + 1 ] == "Rect" ) { // Rectangle + if( shapeWidth == shapeHeight ) { + ViaStyleDefsType[ Number ] = "SQUARE"; + ViaStyleDefsDiameter[ Number ] = shapeWidth; + OneViaShapeCreated = 1; + ViaStyleDefsSkip[ Number ] = 0; + } + else { + ViaStyleDefsType[ Number ] = "SQUARE"; + ViaStyleDefsDiameter[ Number ] = shapeWidth; + OneViaShapeCreated = 1; + ViaStyleDefsSkip[ Number ] = 0; + + //if( DebugMessage ) { + WriteLog("#warning: ViaShape: rectangle. Create square via.\n"); + //} + } + } + else { + if( Tokens[ viaShapeTypePosition + 1 ] == "Ellipse" ) { // Ellipse + if( shapeWidth == shapeHeight ) { + ViaStyleDefsType[ Number ] = "ROUND"; + ViaStyleDefsDiameter[ Number ] = shapeWidth; + OneViaShapeCreated = 1; + ViaStyleDefsSkip[ Number ] = 0; + } + else { + ViaStyleDefsType[ Number ] = "ROUND"; + ViaStyleDefsDiameter[ Number ] = shapeWidth; + OneViaShapeCreated = 1; + ViaStyleDefsSkip[ Number ] = 0; + + //if( DebugMessage ) { + WriteLog( "# warning: ViaShape: Ellips with different width and height. Create round via.\n"); + //} + } + } + else { + if( Tokens[ viaShapeTypePosition + 1 ] == "MtHole" ) { // MountingHole + //if( DebugMessage ) { + WriteLog("#warning: ViaShape:MtHole \n"); + //} + } + else { + if( Tokens[ viaShapeTypePosition + 1 ] == "RndRect" ) { // RoundRectangle + ViaStyleDefsType[ Number ] = "SQUARE"; + real width = strtod( shapeWidth ); + width = width * ( 1.0 - 0.7 / ROUNDNESS ); + + string newWidth; + + sprintf( newWidth, "%f", width ); + + ViaStyleDefsDiameter[ Number ] = newWidth; + OneViaShapeCreated = 1; + ViaStyleDefsSkip[ Number ] = 0; + + //if( DebugMessage ) { + WriteLog("#warning: ViaShape: RndRect. Create shrinked square via.\n"); + //} + } + else { + if( Tokens[ viaShapeTypePosition + 1 ] == "Target" ) { // Make it round + //if( DebugMessage ) { + WriteLog("#warning: ViaShape: Target. Do not supported.\n"); + //} + } + else { + string tmp; + sprintf( tmp, "# warning: ViaShape %s not supported yet\n", + Tokens[ viaShapeTypePosition + 1 ] ); + WriteLog( tmp ); + } + } + } + } + } + } + } + } + else { + if( DebugMessage ) { + printf( "# via's shape skips because of zero width and height.\n"); + } + } + } + } + } + } + else { + if( DebugMessage ) { + printf( "# via's shape skips because of layer.\n"); + } + } + } + + return( 0 ); +} + +int ProcessViaShapes( int Number, int startToken, string holeDiam ) +{ + OneViaShapeCreated = 0; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "viaShape" ) { + int SavePosition = CurrentToken; + + ProcessOneViaShape( Number, SavePosition, holeDiam ); + + CurrentToken = SavePosition; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( TR("Unexpected keyword in ProcessViaShapes: ") + Tokens[ + CurrentToken ], "OK"); + return( 1 ); + } + } + + CurrentToken++; + } + + return( 1 ); +} + +void GenerateOneViaDefinition( int Number, int startToken ) +{ + printf( "#ViaStyleDef %s\n", Tokens[ startToken ] ); + + ViaStyleDefsSkip[ Number ] = 1; + + int holeDiamPosition = FindToken( startToken + 1, "holeDiam" ); + + if( holeDiamPosition >= 0 ) { + string holeDiam = Tokens[ holeDiamPosition + 1 ]; + + if( CheckForNull( holeDiam ) ) { + WriteLog("# warning: zero hole in via\n"); + } + + if( DebugMessage ) { + printf( "#HoleDiameter = %s\n", holeDiam ); + } + + ProcessViaShapes( Number, startToken, holeDiam ); + + if( ViaStyleDefsSkip[ Number ] ) { + if( DebugMessage ) { + printf( "# this ViaDefinition was skipped.\n"); + } + } + else { + sprintf( ViaStyleDefsScript[ Number ], "CHANGE DRILL %s;\n%s", + holeDiam, ViaStyleDefsScript[ Number ] ); + } + } + else { + if( DebugMessage ) { + printf( "# skips because via has no holeDiam.\n"); + } + } +} + +void GenerateViaDefinitions( void ) +{ + for( int i = 0; i < ViaStyleDefsNumber; i++ ) { + int startToken = ViaStyleDefsArray[ i ]; + + string info; + sprintf( info, TR("Process Via Style definition") + " %d (%d)", i, ViaStyleDefsNumber ); + UpdateProgress( info ); + + GenerateOneViaDefinition( i, startToken ); + } +} + +string FindSymbolNameByOriginal( string originalSymbolName ) +{ + for( int i = 0; i < SymbolDefsNumber; i++ ) { + if( originalSymbolName == OriginalSymbolsName[ i ] ) { + return( SymbolsName[ i ] ); + } + } + + return( "" ); +} + +int FindSymbolIndexByName( string symbolName ) +{ + for( int i = 0; i < SymbolDefsNumber; i++ ) { + if( symbolName == SymbolsName[ i ] ) { + return( i ); + } + } + + return( -1 ); +} + +int FindPatternDefIndexByName( string patternName, string variantName ) +{ + for( int i = 0; i < PatternDefExtendedNumber; i++ ) { + if( patternName == PatternName[ i ] ) { + if( variantName == PatternGraphicsDefName[ i ] ) { + return( i ); + } + } + } + + return( -1 ); +} + +string FindPatternNameByOrigin( string originalPatternName ) +{ + for( int i = 0; i < PatternDefExtendedNumber; i++ ) { + if( originalPatternName == PatternOriginalName[ i ] ) { + return( PatternName[ i ] ); + } + } + + return( "" ); +} + +string FindPatternDefaultVariantByOrigin( string originalPatternName ) +{ + for( int i = 0; i < PatternDefExtendedNumber; i++ ) { + if( originalPatternName == PatternOriginalName[ i ] ) { + if( PatternDefaultVariantName[ i ] == PatternGraphicsDefName[ i ] ) { + return( PatternDefaultVariantName[ i ] ); + } + } + } + + return( "" ); +} + +string FindSymbolDeviceName( string compName ) +{ + for( int i = 0; i < NrCompInstances; i++ ) { + if( compName == CompInstancesName[ i ] ) { + return( CompInstancesRef[ i ] ); + } + } + + return( "" ); +} + +string FindCompValue( string compName ) +{ + for( int i = 0; i < NrCompInstances; i++ ) { + if( compName == CompInstancesName[ i ] ) { + return( CompValue[ i ] ); + } + } + + return( "" ); +} + +string FindText( int startToken ) +{ + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + + return( ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken ] ) ) ); + } + + CurrentToken++; + } + + return( "" ); +} + +string ConvertPinType( string pinType ) +{ + if( pinType == "Unknown" ) { + return( "IO" ); + } else if( pinType == "Passive" ) { + return( "Pas" ); + } else if( pinType == "Input" ) { + return( "In" ); + } else if( pinType == "Output" ) { + return( "Out" ); + } else if( pinType == "Bidirectional" ) { + return( "IO" ); + } else if( pinType == "OpenH" ) { + return( "OC" ); + } else if( pinType == "OpenL" ) { + return( "OC" ); + } else if( pinType == "PassiveH" ) { + return( "Pas" ); + } else if( pinType == "PassiveL" ) { + return( "Pas" ); + } else if( pinType == "ThreeState" ) { + return( "Hiz" ); + } else if( pinType == "Power" ) { + return( "Pwr" ); + } + + string tmp; + sprintf( tmp, "# warning: unknown pinType = %s\n", pinType ); + WriteLog( tmp ); + + return( "IO" ); +} + +int IfFitToSymbolName( int startToken, string OriginalSymbolName ) +{ + int level = 1; + CurrentToken = startToken; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + level++; + CurrentToken++; + if( Tokens[ CurrentToken ] == "attachedSymbol" ) { + int SavePosition = CurrentToken; + + CurrentToken = FindToken( SavePosition + 1, "symbolName" ); + + if( CurrentToken >= 0 ) { + string OriginalDeviceName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ) ); + + if( OriginalSymbolName == OriginalDeviceName ) { + return( 1 ); + } + } + + CurrentToken = SavePosition; + + break; + } + else { + SkipThisItem(); + + level--; + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( 0 ); + } + } + } + + CurrentToken++; + } + + return( 0 ); +} + +string FindPinDirection( string OriginalSymbolName, string pinNum ) +{ + for( int i = 0; i < CompDefsNumber; i++ ) { + int startToken = CompDefsArray[ i ]; + + if( IfFitToSymbolName( startToken, OriginalSymbolName ) ) { + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "compPin" ) { + int SavePosition = CurrentToken; + string currentPinNum = FindText( SavePosition ); + + if( currentPinNum == pinNum ) { + int tokenPosition = FindToken( SavePosition + 1, "pinType" ); + + if( tokenPosition >= 0 ) { + string pinType = Tokens[ tokenPosition + 1 ]; + + string pinTypeEagle = ConvertPinType( pinType ); + + return( pinTypeEagle ); + } + } + + CurrentToken = SavePosition; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + } + } + + CurrentToken++; + } + } + } + + return( "IO" ); +} + +string PinNamesTable[]; +int NrOfThisPinName[]; +int CurrentPinIndex[]; +int NrPinNames; + +int FindPinName( string pinName ) +{ + for( int i = 0; i < NrPinNames; i++ ) { + if( PinNamesTable[ i ] == pinName ) { + return( i ); + } + } + + return( -1 ); +} + +void FillOnePinName( int startToken ) +{ + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pinName" ) { + int pinNameToken = CurrentToken + 1; + + string pinName = FindText( pinNameToken + 1 ); + + if( pinName != "" ) { + int index = FindPinName( pinName ); + + if( index >= 0 ) { + NrOfThisPinName[ index ]++; + } + else { + PinNamesTable[ NrPinNames ] = pinName; + NrOfThisPinName[ NrPinNames ] = 1; + CurrentPinIndex[ NrPinNames ] = 1; + NrPinNames++; + } + } + + return; + } + else { + SkipThisItem(); + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } +} + +void FillPinNameTable( int startToken ) +{ + NrPinNames = 0; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pin" ) { + int SavePosition = CurrentToken; + FillOnePinName( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } +} + +void GeneratePin( int startToken, string OriginalSymbolName ) +{ + string pinNum; + string xPointCoord; + string yPointCoord; + string rotation = "0"; + string pinLength = "0"; + int isPinLength = 0; + string dispPinDes = "True"; + int pinDesToken = 0; + string pinDes = ""; + string pinVisibility = "Off"; + int pinNameToken = 0; + string defaultPinDes; + string insideStyle; + int isFlipped = 0; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + xPointCoord = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xPointCoord = xPointCoord + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yPointCoord = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yPointCoord = yPointCoord + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yPointCoord = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yPointCoord = yPointCoord + Tokens[ CurrentToken + 3 ]; + } + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pinNum" ) { + pinNum = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "rotation" ) { + rotation = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pinLength" ) { + pinLength = Tokens[ CurrentToken + 1 ]; + isPinLength = 1; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pinDisplay" ) { + if( Tokens[ CurrentToken + 2 ] == "dispPinDes" ) { + dispPinDes = Tokens[ CurrentToken + 3 ]; + } + + if( Tokens[ CurrentToken + 2 ] == "dispPinName" ) { + if( ( Tokens[ CurrentToken + 3 ] == "True" ) || ( Tokens[ CurrentToken + 3 ] == "true" ) ) { + pinVisibility = ""; + } + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pinDes" ) { + int SavePosition = CurrentToken; + pinDesToken = SavePosition + 1; + pinDes = FindText( SavePosition + 2 ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pinName" ) { + pinNameToken = CurrentToken + 1; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "defaultPinDes" ) { + defaultPinDes = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "insideStyle" ) { + insideStyle = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isFlipped" ) { + if( ( Tokens[ CurrentToken + 1 ] == "True" ) || ( Tokens[ CurrentToken + 1 ] == "true" ) ) { + isFlipped = 1; + } + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GeneratePin ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + if( pinDesToken ) { + if( dispPinDes == "True" ) { + IfPinText = 1; + GenerateOneText( pinDesToken + 1 ); + IfPinText = 0; + } + } + + /*if( pinNameToken ) { + GenerateOneText( pinNameToken + 1 ); + }*/ + + real pinLengthValue = strtod( GetNumberValue( pinLength ) ); + real rotationValue = strtod( GetNumberValue( rotation ) ); + + real pinX = strtod( ConvertUnits( GetNumberValue( xPointCoord ), GetUnitValue( xPointCoord ) ) ); + real pinY = strtod( ConvertUnits( GetNumberValue( yPointCoord ), GetUnitValue( yPointCoord ) ) ); + + if( !pinLengthValue ) { + printf( "CHANGE LENGTH POINT;\n"); + } else if( pinLengthValue == 100 ) { + printf( "CHANGE LENGTH SHORT;\n"); + } else if( pinLengthValue == 200 ) { + printf( "CHANGE LENGTH MIDDLE;\n"); + } else if ( pinLengthValue == 300) { + printf( "CHANGE LENGTH LONG;\n"); + } + + if( !isPinLength ) { + printf( "CHANGE LENGTH LONG;\n"); + pinLengthValue = 300; + } + + if( rotationValue >= 270 ) { + pinY -= pinLengthValue; + } + else if( rotationValue >= 180 ) { + pinX -= pinLengthValue; + } + else if( rotationValue >= 90 ) { + pinY += pinLengthValue; + } + else { + pinX += pinLengthValue; + } + + string mirrored = ""; + +// Mirrored (flipped) is not use here because it supported by above code + + /*if( isFlipped ) { + mirrored = "M"; + }*/ + + /*if( isFlipped ) { + if( rotationValue >= 270 ) { + pinY = pinY - 2 * pinLengthValue; + } + else if( rotationValue >= 180 ) { + pinX = pinX - 2 * pinLengthValue; + } + else if( rotationValue >= 90 ) { + pinY = pinY + 2 * pinLengthValue; + } + else { + pinX = pinX - 2 * pinLengthValue; + } + }*/ + + string pinDirection = FindPinDirection( OriginalSymbolName, pinDes ); + + string pinName = FindText( pinNameToken + 1 ); + + if( pinName != "" ) { + int index = FindPinName( pinName ); + + if( index >= 0 ) { + if( NrOfThisPinName[ index ] > 1 ) { + sprintf( pinName, "%s@%d", pinName, CurrentPinIndex[ index ] ); + CurrentPinIndex[ index ]++; + } + } + else { + string tmp; + sprintf( tmp, "# warning: can't find pin %s in table\n", pinName ); + WriteLog( tmp ); + } + + if( pinName[ 0 ] == '~' ) { + pinName[ 0 ] = '!'; + } + + printf( "PIN '%s' %s %sR%f %s (%f %f);\n", pinName, pinDirection, mirrored, rotationValue + 180.0, + pinVisibility, pinX, pinY ); + } + else { + printf( "PIN %s %sR%f %s (%f %f);\n", pinDirection, mirrored, rotationValue + 180.0, + pinVisibility, pinX, pinY ); + } +} + +void GenerateSymbols( void ) +{ + printf("# Symbols:\n"); + + for( int i = 0; i < SymbolDefsNumber; i++ ) { + int startToken = SymbolDefsArray[ i ]; + + string info; + sprintf( info, "Process symbol %d (%d)", i, SymbolDefsNumber + 1 ); + UpdateProgress( info ); + + string SymbolName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( + Tokens[ startToken ] ) + ); + + string OriginalSymbolName = GetOriginalDeviceName( startToken + 1 ); + + SymbolsName[ i ] = SymbolName; + OriginalSymbolsName[ i ] = OriginalSymbolName; + + printf("#\n"); + printf("# Symbol: %s OriginalName = %s\n", SymbolName, OriginalSymbolName ); + + printf("EDIT '%s.SYM';\n", SymbolName ); + printf("DESCRIPTION 'Original name %s

    ';\n", OriginalSymbolName ); + printf("GRID %s;\n", FileUnits ); + printf("CHANGE FONT VECTOR;\n"); + + FillPinNameTable( startToken ); + + printf( "CHANGE LAYER 94;\n" ); + + IfNameDefinedInSymbol[ i ] = 0; + IfValueDefinedInSymbol[ i ] = 0; + SymbolAttributesIndex[ i ] = NrAttributes; + SymbolNrAttributes[ i ] = 0; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "originalName" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pin" ) { + int SavePosition = CurrentToken; + + GeneratePin( SavePosition, OriginalSymbolName ); + + CurrentToken = SavePosition; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "line" ) { + int SavePosition = CurrentToken; + + GenerateOneLine( SavePosition, 0, 0 ); + + CurrentToken = SavePosition; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "attr" ) { + int SavePosition = CurrentToken; + GenerateNameAndValueSchematics( SavePosition, i ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "poly" ) { + int SavePosition = CurrentToken; + + GenerateOnePcbPoly( SavePosition, 0, DEFAULT_WIRE_WIDTH_BOARD ); + + CurrentToken = SavePosition; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "text" ) { + int SavePosition = CurrentToken; + IfPinText = 1; + GenerateOneText( SavePosition ); + IfPinText = 0; + CurrentToken = SavePosition; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "triplePointArc" ) { + int SavePosition = CurrentToken; + + GenerateOneTripleArc( SavePosition ); + + CurrentToken = SavePosition; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "arc" ) { + int SavePosition = CurrentToken; + GenerateOneArc( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateSymbols ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + } +} + +int FindAttributeByNameInSymbol( int symbolIndex, string attributeName ) +{ + for( int i = SymbolAttributesIndex[ symbolIndex ]; i < SymbolNrAttributes[ symbolIndex ]; i++ ) { + if( attributeName == AttributesName[ i ] ) { + return( AttributesIndex[ i ] ); + } + } + + return( -1 ); +} + +int FindAttributeByNameInPattern( int patternIndex, string attributeName ) +{ + for( int i = PatternAttributesIndex[ patternIndex ]; i < PatternNrAttributes[ patternIndex ]; i++ ) { + if( attributeName == AttributesName[ i ] ) { + return( AttributesIndex[ i ] ); + } + } + + return( -1 ); +} + +void AddOneAttributes( int ifSymbol, int symbolIndex, string elemName, string attributeName, string attributeValue, int startToken, string xCoord, string yCoord ) +{ + string xCoordText = "0.0"; + string yCoordText = "0.0"; + string rotation = "0"; + string isVisible = "False"; + string textStyleRef = ""; + string justify = ""; + int isFlipped = 0; + + if( symbolIndex >= 0 ) { + int attrIndex; + + if( ifSymbol ) { + attrIndex = FindAttributeByNameInSymbol( symbolIndex, attributeName ); + } + else { + attrIndex = FindAttributeByNameInPattern( symbolIndex, attributeName ); + } + +//printf("# index attr name = %s\n", attributeName ); + if( attrIndex >= 0 ) { +//printf("# attr name = %s\n", Tokens[ attrIndex + 1 ] ); + + CurrentToken = attrIndex + 3; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "rotation" ) { + rotation = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isVisible" ) { + isVisible = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "textStyleRef" ) { + textStyleRef = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isFlipped" ) { + if( ( Tokens[ CurrentToken + 1 ] == "True" ) || ( Tokens[ CurrentToken + 1 ] == "true" ) ) { + isFlipped = 1; + } + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "justify" ) { + justify = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + } + } + + CurrentToken = startToken; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + xCoordText = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xCoordText = xCoordText + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoordText = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yCoordText = yCoordText + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoordText = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoordText = yCoordText + Tokens[ CurrentToken + 3 ]; + } + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "rotation" ) { + rotation = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isVisible" ) { + isVisible = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "textStyleRef" ) { + textStyleRef = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isFlipped" ) { + if( ( Tokens[ CurrentToken + 1 ] == "True" ) || ( Tokens[ CurrentToken + 1 ] == "true" ) ) { + isFlipped = 1; + } + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "justify" ) { + justify = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + real newXCoord = strtod( ConvertUnits( GetNumberValue( xCoord ), GetUnitValue( xCoord ) ) ) + + strtod( ConvertUnits( GetNumberValue( xCoordText ), GetUnitValue( xCoordText ) ) ); + + real newYCoord = strtod( ConvertUnits( GetNumberValue( yCoord ), GetUnitValue( yCoord ) ) ) + + strtod( ConvertUnits( GetNumberValue( yCoordText ), GetUnitValue( yCoordText ) ) ); + + string mirrored = ""; + + if( isFlipped ) { + mirrored = "M"; + } + + if( attributeValue == "" ) { + attributeValue = "''"; + } + else { + attributeValue = ReplaceNotSupportedCharactersText( attributeValue ); + } + + if( isVisible != "True" ) { + if( elemName != "" ) { + printf( "CHANGE DISPLAY OFF;\n" ); + } + } + else { + if( elemName != "" ) { + printf( "CHANGE DISPLAY VALUE;\n" ); + } + } + + if( justify == "" ) { //LowerLeft + printf("CHANGE ALIGN BOTTOM LEFT;\n"); + } else if( justify == "UpperLeft" ) { + printf("CHANGE ALIGN TOP LEFT;\n"); + } else if( justify == "UpperCenter" ) { + printf("CHANGE ALIGN TOP CENTER;\n"); + } else if( justify == "UpperRight" ) { + printf("CHANGE ALIGN TOP RIGHT;\n"); + } else if( justify == "Left" ) { + printf("CHANGE ALIGN CENTER LEFT;\n"); + } else if( justify == "Center" ) { + printf("CHANGE ALIGN CENTER CENTER;\n"); + } else if( justify == "Right" ) { + printf("CHANGE ALIGN CENTER RIGHT;\n"); + } else if( justify == "LowerLeft" ) { + printf("CHANGE ALIGN BOTTOM LEFT;\n"); + } else if( justify == "LowerCenter" ) { + printf("CHANGE ALIGN BOTTOM CENTER;\n"); + } else if( justify == "LowerRight" ) { + printf("CHANGE ALIGN BOTTOM RIGHT;\n"); + } + else { + printf("# warning: unknown justify parameter value = %s\n", justify ); + printf("CHANGE ALIGN BOTTOM LEFT;\n"); + } + + int textStyleDefPos = FindTextStyleDef( textStyleRef ); + + if( textStyleDefPos >= 0 ) { + real fontHeight = strtod( ConvertUnits( GetNumberValue( TextStyleDefFontHeight[ textStyleDefPos ] ), GetUnitValue( TextStyleDefFontHeight[ textStyleDefPos ] ) ) ); + real fontWidth = strtod( ConvertUnits( GetNumberValue( TextStyleDefFontStrokeWidth[ textStyleDefPos ] ), GetUnitValue( TextStyleDefFontStrokeWidth[ textStyleDefPos ] ) ) ); + + printf("CHANGE SIZE %s;\n", TextStyleDefFontHeight[ textStyleDefPos ] ); + + if( fontHeight ) { + int ratio = round( 100.0 * fontWidth / fontHeight ); + + if( ratio > 31.0 ) { + ratio = 31.0; + } + + printf("CHANGE RATIO %d;\n", ratio ); + } + } + + if( elemName != "" ) { + printf( "ATTRIBUTE '%s' '%s' '%s' %sSR%s (%f %f);\n", elemName, attributeName, attributeValue, mirrored, rotation, newXCoord, newYCoord ); + } + else { + printf( "ATTRIBUTE '%s' '%s';\n", attributeName, attributeValue ); + } +} + +void AddAttributes( int ifSymbol, int symbolIndex, string elemName, int patternGraphicsRef, string xCoord, string yCoord ) +{ + CurrentToken = patternGraphicsRef + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "attr" ) { + string attrName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ) ); + + if( attrName == "Name" ) { + attrName = "Name_"; + } + + if( ( strlwr( attrName ) != "value" ) && ( strlwr( attrName ) != "name" ) && ( strlwr( attrName ) != "refdes" ) ) { + int SavePosition = CurrentToken; + AddOneAttributes( ifSymbol, symbolIndex, elemName, attrName, ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 2 ] ) ), + CurrentToken, xCoord, yCoord ); + CurrentToken = SavePosition; + } + + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } +} + +string FindPinNameByPinRef( int startToken, string pinRef ) +{ + int CurrentToken = startToken + 1; + int level = 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + level++; + + if( Tokens[ CurrentToken ] == "compPin" ) { + int SavePosition = CurrentToken; + string currentPinRef = FindText( SavePosition ); + + if( currentPinRef == pinRef ) { + int tokenPosition = FindToken( SavePosition + 1, "pinName" ); + + if( tokenPosition >= 0 ) { + string pinName = Tokens[ tokenPosition + 1 ]; + + return( pinName ); + } + } + + CurrentToken = SavePosition; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + level--; + + if( level == 0 ) { + return( "" ); + } + } + } + + CurrentToken++; + } + + return( "" ); +} + +string DevicePinNamesTable[]; +string DevicePadNamesTable[]; +int CurrentDevicePinCount[]; +int NrOfDevicePadNames; + +void GenerateDevices( void ) +{ + printf("# Devices:\n"); + + for( int i = 0; i < CompDefsNumber; i++ ) { + int startToken = CompDefsArray[ i ]; + + string DeviceName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( + Tokens[ startToken ] ) + ); + + string OriginalDeviceName = GetOriginalDeviceName( startToken + 1 ); + + printf("#\n"); + printf("# Device: %s OriginalName = %s\n", DeviceName, OriginalDeviceName ); + + printf("EDIT '%s.DEV';\n", DeviceName ); + printf("GRID %s;\n", FileUnits ); + + //AddAttributes( 0, -1, "", startToken, "0.0", "0.0" ); + + int packageExists = 0; + + int attachedPatternToken = FindToken( startToken + 1, "attachedPattern" ); + + if( attachedPatternToken > 0 ) { + CurrentToken = FindToken( attachedPatternToken + 1, "patternName" ); + + if( CurrentToken >= 0 ) { + string originPatternName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ) ); + + string patternName = FindPatternNameByOrigin( originPatternName ); + + if( patternName != "" ) { + string patternDefaultVariant = FindPatternDefaultVariantByOrigin( originPatternName ); + + printf( "PACKAGE '%s%s';\n", patternName, patternDefaultVariant ); + + packageExists = 1; + + CurrentToken = FindToken( attachedPatternToken + 1, "padPinMap" ); + + if( CurrentToken > 0 ) { + PadPinMapRef[ i ] = NrPadPinMap; + PadPinMapCount[ i ] = 0; + + CurrentToken++; + + while( Tokens[ CurrentToken ] != ")" ) { + PadPinMapNum[ NrPadPinMap ] = Tokens[ CurrentToken + 2 ]; + PadPinMapPinRef[ NrPadPinMap ] = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 6 ] ) ); + + //printf( "# PadMap: num = %s ref = %s\n", PadPinMapNum[ NrPadPinMap ], PadPinMapPinRef[ NrPadPinMap ] ); + + NrPadPinMap++; + PadPinMapCount[ i ]++; + + CurrentToken = CurrentToken + 8; + } + } + } + else { + string tmp; + sprintf( tmp, "# warning: no package exists for attachedPattern in device %s \n", DeviceName ); + WriteLog( tmp ); + } + } + else { + string tmp; + sprintf( tmp, "# warning: no pattern name in device %s \n", DeviceName ); + WriteLog( tmp ); + } + } + else { + string tmp; + sprintf( tmp, "# warning: no package for device %s \n", DeviceName ); + WriteLog( tmp ); + } + + if( !packageExists ) { + printf("ATTRIBUTE '_EXTERNAL_';\n"); + } + + int symbolNum = 0; + int symbolExists = 0; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "attachedSymbol" ) { + int SavePosition = CurrentToken; + + CurrentToken = FindToken( SavePosition + 1, "symbolName" ); + + if( CurrentToken > 0 ) { + string symbolName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ) ); + + string symbolNameByOriginal = FindSymbolNameByOriginal( symbolName ); + + string partNum = ""; + + int partNumPosition = FindToken( SavePosition + 1, "partNum" ); + + if( partNumPosition >= 0 ) { + partNum = Tokens[ partNumPosition + 1 ]; + } + + if( symbolNameByOriginal != "" ) { + symbolExists = 1; + + printf( "ADD '%s' 'G%s'(%.8f%s %.8f%s);\n", symbolNameByOriginal, partNum, + 0.0, FileUnits, symbolNum * -100.0, FileUnits ); + + DevicesName[ NrSymbolDevices ] = DeviceName; + SymbolDevicesName[ NrSymbolDevices ] = symbolNameByOriginal; + NrSymbolDevices++; + + symbolNum++; + } + else { + string tmp; + sprintf( tmp, "# warning: no SymbolNameByOriginal was found for symbol %s\n", symbolName ); + WriteLog( tmp ); + } + } + else { + string tmp; + sprintf( tmp, "# warning: no symbol name in device %s\n", DeviceName ); + WriteLog( tmp ); + } + + CurrentToken = SavePosition; + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( "Unexpected keyword in GenerateDevices " + Tokens[ CurrentToken ], "OK"); + return; + } + } + + CurrentToken++; + } + + // Prefix + + int compHeaderToken = FindToken( startToken + 1, "compHeader" ); + + if( compHeaderToken > 0 ) { + int prefixToken = FindToken( compHeaderToken + 1, "refDesPrefix" ); + + if( prefixToken > 0 ) { + printf("PREFIX '%s';\n", RemoveDoubleQuotas( Tokens[ prefixToken + 1 ])); + } + } + + // Make connections between pins and pads + + if( packageExists && symbolExists ) { + NrOfDevicePadNames = 0; + + for( int j = PadPinMapRef[ i ]; j < PadPinMapRef[ i ] + PadPinMapCount[ i ]; j++ ) { + string PinName = RemoveDoubleQuotas(FindPinNameByPinRef( startToken, PadPinMapPinRef[ j ])); + + if( PinName != "" ) { + DevicePinNamesTable[NrOfDevicePadNames] = PinName; + DevicePadNamesTable[NrOfDevicePadNames] = PadPinMapNum[ j ]; + CurrentDevicePinCount[NrOfDevicePadNames] = 0; + NrOfDevicePadNames++; + } + } + + for( j = 0; j < NrOfDevicePadNames; j++ ) { + if( CurrentDevicePinCount[ j ] == 0 ) { + int Count = 0; + + for( int k = j; k < NrOfDevicePadNames; k++ ) { + if( DevicePinNamesTable[ j ] == DevicePinNamesTable[ k ]) { + Count++; + } + } + + if( Count > 1) { + int m = 1; + + for( int k = j; k < NrOfDevicePadNames; k++ ) { + if( DevicePinNamesTable[ j ] == DevicePinNamesTable[ k ]) { + CurrentDevicePinCount[ k ] = m; + m++; + } + } + } + } + } + + for( j = 0; j < NrOfDevicePadNames; j++ ) { + if( CurrentDevicePinCount[ j ] == 0 ) { + printf("CONNECT '%s' '%s';\n", DevicePinNamesTable[ j ], DevicePadNamesTable[ j ]); + } + else { + printf("CONNECT '%s@%d' '%s';\n", DevicePinNamesTable[ j ], CurrentDevicePinCount[ j ], DevicePadNamesTable[ j ]); + } + } + } + } +} + +int FindDummyDeviceName( string DeviceName ) +{ + for( int i = 0; i < NrDummyDevices; i++ ) { + if( DummyDevices[ i ] == DeviceName ) { + return( 1 ); + } + } + + return( 0 ); +} + +void GenerateDummyDevices( void ) +{ + NrDummyDevices = 0; + + printf("# Dummy devices: %d\n", NrPadsOnBoard ); + + for( int i = 0; i < NrPadsOnBoard; i++ ) { + int startToken = PadOnBoardIndex[ i ]; + + int padStyleRefPosition = FindToken( startToken + 1, "padStyleRef" ); + + if( padStyleRefPosition >= 0 ) { + string DeviceName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( + Tokens[ padStyleRefPosition + 1 ] ) + ); + + PadOnBoardDefs[ i ] = DeviceName; + + if( FindDummyDeviceName( DeviceName ) == 0 ) { + DummyDevices[ NrDummyDevices ] = DeviceName; + NrDummyDevices++; + + printf("#\n"); + printf("# Dummy package: %s\n", DeviceName ); + + printf("EDIT '%s.PAC';\n", DeviceName ); + printf("GRID %s;\n", FileUnits ); + + GeneratePad( startToken, 1 ); + + printf("#\n"); + printf("# Device: %s\n", DeviceName ); + + printf("EDIT '%s.DEV';\n", DeviceName ); + printf("GRID %s;\n", FileUnits ); + printf("ATTRIBUTE '_EXTERNAL_';\n"); + } + } + else { + WriteLog("# warning: can't find padStyleRef in dummy device.\n"); + } + } +} + +// Generate library from 'library' keyword + +void GenerateLibrary( void ) +{ + GenerateLibraryHeader(); + + GeneratePadDefinitions(); + + GenerateViaDefinitions(); + + GeneratePackages(); + + GenerateSymbols(); + + GenerateDevices(); + + GenerateDummyDevices(); + + printf("WRITE;\n"); + printf("CLOSE;\n"); +} + +void GeneratePCBHeader( void ) +{ + string libraryName; + + printf("# ***** Board *****\n"); + + string eagleFileName; + string array[]; + + sprintf( eagleFileName, "%s.brd", PCADfileName); + + if( fileglob( array, eagleFileName ) ) { + printf("SET CONFIRM YES;\n"); + printf("REMOVE '%s';\n", eagleFileName ); + printf("SET CONFIRM OFF;\n"); + } + + printf("EDIT '%s';\n", eagleFileName ); + printf("DRC LOAD '%s';\n", DRUFileName ); + printf("SET WIRE_BEND 2;\n"); + + libraryName = filesetext( PCADfileName, ".lbr"); + + printf("USE -* '%s';\n", libraryName); + printf("GRID %s;\n", FileUnits ); + printf("SET OPTIMIZING ON;\n"); + printf("SET CONFIRM YES;\n"); + printf("CHANGE FONT VECTOR;\n"); +} + +// This function generates one via + +void GenerateVia( int startToken ) +{ + int tokenPosition = FindToken( startToken + 1, "viaStyleRef" ); + + if( tokenPosition >= 0 ) { + printf("#viaStyleRef = %s\n", Tokens[ tokenPosition + 1 ] ); + + string info; + sprintf( info, "Process via %d %s", tokenPosition, Tokens[ tokenPosition + 1 ] ); + UpdateProgress( info ); + + int ViaStyleDefNum = FindViaStyleDef( Tokens[ tokenPosition + 1 ] ); + + if( ViaStyleDefNum >= 0 ) { + if( ViaStyleDefsSkip[ ViaStyleDefNum ] == 0 ) { + printf( "%s", ViaStyleDefsScript[ ViaStyleDefNum ] ); + + int viaNetPosition = FindToken( startToken + 1, "netNameRef" ); + + int ifSignalName = 0; + + if( viaNetPosition >= 0 ) { + ifSignalName = 1; + } + + int viaCoordPosition = FindToken( startToken + 1, "pt" ); + + if( viaCoordPosition >= 0 ) { + string xCoordVia = ""; + string yCoordVia = ""; + + xCoordVia = Tokens[ viaCoordPosition + 1 ]; + + if( IsASCIIValue( Tokens[ viaCoordPosition + 2 ] ) ) { + xCoordVia = xCoordVia + Tokens[ viaCoordPosition + 2 ]; + + if( Tokens[ viaCoordPosition + 3 ] != ")" ) { + yCoordVia = Tokens[ viaCoordPosition + 3 ]; + + if( Tokens[ viaCoordPosition + 4 ] != ")" ) { + yCoordVia = yCoordVia + Tokens[ viaCoordPosition + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoordVia = Tokens[ viaCoordPosition + 2 ]; + + if( Tokens[ viaCoordPosition + 3 ] != ")" ) { + yCoordVia = yCoordVia + Tokens[ viaCoordPosition + 3 ]; + } + } + + string Val1 = ConvertUnits( GetNumberValue( xCoordVia ), + GetUnitValue( xCoordVia ) ); + string Val2 = ConvertUnits( GetNumberValue( yCoordVia ), + GetUnitValue( yCoordVia ) ); + + if( ifSignalName ) { + printf( "VIA '%s' %s %s (%s %s);\n", + ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ viaNetPosition + 1 ] ) ), + ViaStyleDefsDiameter[ ViaStyleDefNum ], + ViaStyleDefsType[ ViaStyleDefNum ], + Val1, Val2 ); + } + else { + printf( "VIA %s %s (%s %s);\n", + ViaStyleDefsDiameter[ ViaStyleDefNum ], + ViaStyleDefsType[ ViaStyleDefNum ], + Val1, Val2 ); + } + } + else { + string tmp; + sprintf( tmp, "#WARNING: Can't find pt for via %s\n", + Tokens[ startToken + 3 ] ); + WriteLog( tmp ); + } + } + else { + if( DebugMessage ) { + printf("#skip this via\n"); + } + } + } + else { + string tmp; + sprintf( tmp, "#WARNING: Can't find viaStyleDef for via %s\n", + Tokens[ startToken + 3 ] ); + WriteLog( tmp ); + } + } + else { + string tmp; + sprintf( tmp, "#WARNING: Can't find viaStyleRef for via %s\n", + Tokens[ startToken + 3 ] ); + WriteLog( tmp ); + } +} + +int IfNameChanged = 0; +int IfValueChanged = 0; + +void ChangeOneNameAndValue( string elemName, string attributeName, int startToken, string xCoord, string yCoord, string pureRotation ) +{ + string xCoordText = "0.0"; + string yCoordText = "0.0"; + string rotation = "0"; + string isVisible = "False"; + string textStyleRef = ""; + string justify = ""; + int isFlipped = 0; + + CurrentToken = startToken; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + xCoordText = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xCoordText = xCoordText + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoordText = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yCoordText = yCoordText + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoordText = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoordText = yCoordText + Tokens[ CurrentToken + 3 ]; + } + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "rotation" ) { + rotation = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isVisible" ) { + isVisible = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "textStyleRef" ) { + textStyleRef = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isFlipped" ) { + if( ( Tokens[ CurrentToken + 1 ] == "True" ) || ( Tokens[ CurrentToken + 1 ] == "true" ) ) { + isFlipped = 1; + } + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "justify" ) { + justify = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + + real newXCoord = strtod( ConvertUnits( GetNumberValue( xCoord ), GetUnitValue( xCoord ) ) ) + + strtod( ConvertUnits( GetNumberValue( xCoordText ), GetUnitValue( xCoordText ) ) ); + + real newYCoord = strtod( ConvertUnits( GetNumberValue( yCoord ), GetUnitValue( yCoord ) ) ) + + strtod( ConvertUnits( GetNumberValue( yCoordText ), GetUnitValue( yCoordText ) ) ); + + printf( "MOVE '%s>%s' (%f %f);\n", elemName, attributeName, newXCoord, newYCoord ); + + real finalRotation = strtod( pureRotation ); + + string mirrored = ""; + + if( isFlipped ) { + mirrored = "M"; + } + + printf( "ROTATE =S%sR%s '%s>%s';\n", mirrored, rotation, elemName, attributeName ); + + if( justify == "" ) { //LowerLeft + printf("CHANGE ALIGN BOTTOM LEFT;\n"); + } else if( justify == "UpperLeft" ) { + printf("CHANGE ALIGN TOP LEFT;\n"); + } else if( justify == "UpperCenter" ) { + printf("CHANGE ALIGN TOP CENTER;\n"); + } else if( justify == "UpperRight" ) { + printf("CHANGE ALIGN TOP RIGHT;\n"); + } else if( justify == "Left" ) { + printf("CHANGE ALIGN CENTER LEFT;\n"); + } else if( justify == "Center" ) { + printf("CHANGE ALIGN CENTER CENTER;\n"); + } else if( justify == "Right" ) { + printf("CHANGE ALIGN CENTER RIGHT;\n"); + } else if( justify == "LowerLeft" ) { + printf("CHANGE ALIGN BOTTOM LEFT;\n"); + } else if( justify == "LowerCenter" ) { + printf("CHANGE ALIGN BOTTOM CENTER;\n"); + } else if( justify == "LowerRight" ) { + printf("CHANGE ALIGN BOTTOM RIGHT;\n"); + } + else { + string tmp; + sprintf( tmp, "# warning: unknown justify parameter value = %s\n", justify ); + WriteLog( tmp ); + + printf("CHANGE ALIGN BOTTOM LEFT;\n"); + } + + int textStyleDefPos = FindTextStyleDef( textStyleRef ); + + if( textStyleDefPos >= 0 ) { + real fontHeight = strtod( ConvertUnits( GetNumberValue( TextStyleDefFontHeight[ textStyleDefPos ] ), GetUnitValue( TextStyleDefFontHeight[ textStyleDefPos ] ) ) ); + real fontWidth = strtod( ConvertUnits( GetNumberValue( TextStyleDefFontStrokeWidth[ textStyleDefPos ] ), GetUnitValue( TextStyleDefFontStrokeWidth[ textStyleDefPos ] ) ) ); + + printf("CHANGE SIZE %s (%f %f);\n", TextStyleDefFontHeight[ textStyleDefPos ], newXCoord, newYCoord ); + + if( fontHeight ) { + int ratio = round( 100.0 * fontWidth / fontHeight ); + + if( ratio > 31.0 ) { + ratio = 31.0; + } + + printf("CHANGE RATIO %d (%f %f);\n", ratio, newXCoord, newYCoord ); + } + } + + if( isVisible != "True" ) { + printf( "CHANGE DISPLAY OFF (%f %f);\n", newXCoord, newYCoord ); + } + else { + printf( "CHANGE DISPLAY VALUE (%f %f);\n", newXCoord, newYCoord ); + } +} + +void ChangeNameAndValuePosition( string elemName, int patternGraphicsRef, string xCoord, string yCoord, string pureRotation ) +{ + //printf("SMASH '%s';\n", elemName ); + + CurrentToken = patternGraphicsRef + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "attr" ) { + if( Tokens[ CurrentToken + 1 ] == "\"RefDes\"" ) { + int SavePosition = CurrentToken; + ChangeOneNameAndValue( elemName, "NAME", CurrentToken + 3, xCoord, yCoord, pureRotation ); + IfNameChanged = 1; + CurrentToken = SavePosition; + } + + if( Tokens[ CurrentToken + 1 ] == "\"Value\"" ) { + int SavePosition = CurrentToken; + ChangeOneNameAndValue( elemName, "VALUE", CurrentToken + 3, xCoord, yCoord, pureRotation ); + IfValueChanged = 1; + CurrentToken = SavePosition; + } + + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } +} + +int FindPatternGraphisRef( int startToken ) +{ + int patternGraphicsNameRefToken = FindToken( startToken + 1, "patternGraphicsNameRef" ); + + if( patternGraphicsNameRefToken >= 0 ) { + string patternGraphicsNameRef = RemoveDoubleQuotas( Tokens[ patternGraphicsNameRefToken + 1 ] ); + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "patternGraphicsRef" ) { + int SavePosition = CurrentToken; + int nameRefToken = FindToken( CurrentToken + 1, "patternGraphicsNameRef" ); + CurrentToken = SavePosition; + + if( nameRefToken >= 0 ) { + string name = RemoveDoubleQuotas( Tokens[ nameRefToken + 1 ] ); + + if( name == patternGraphicsNameRef ) { + return( SavePosition ); + } + } + + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + return( -1 ); + } + } + + CurrentToken++; + } + } + + return( FindToken( startToken + 1, "patternGraphicsRef" ) ); +} + +// This function generates one component + +void GeneratePattern( int startToken ) +{ + int patternRefPosition = FindToken( startToken + 1, "patternRef" ); + + if( patternRefPosition >= 0 ) { + printf("#patternRef = %s\n", Tokens[ patternRefPosition + 1 ] ); + + string info; + sprintf( info, "Process pattern %d %s", patternRefPosition, Tokens[ patternRefPosition + 1 ] ); + UpdateProgress( info ); + + int refDesRefPosition = FindToken( startToken + 1, "refDesRef" ); + + if( refDesRefPosition >= 0 ) { + string RotationMirrored = ""; + + int mirrored = FindToken( startToken + 1, "isFlipped" ); + + if( mirrored >= 0 ) { + if( ( Tokens[ mirrored + 1 ] == "True" ) || ( Tokens[ mirrored + 1 ] == "true" ) ) { + RotationMirrored = "M"; + } + } + + int rotationPosition = FindToken( startToken + 1, "rotation" ); + + string pureRotation = "0.0"; + + if( rotationPosition >= 0 ) { + pureRotation = Tokens[ rotationPosition + 1 ]; + RotationMirrored = RotationMirrored + "R" + Tokens[ rotationPosition + 1 ]; + } + else { + RotationMirrored = RotationMirrored + "R0"; + } + + int patternPosition = FindToken( startToken + 1, "pt" ); + + if( patternPosition >= 0 ) { + string xCoordPattern = ""; + string yCoordPattern = ""; + + xCoordPattern = Tokens[ patternPosition + 1 ]; + + if( IsASCIIValue( Tokens[ patternPosition + 2 ] ) ) { + xCoordPattern = xCoordPattern + Tokens[ patternPosition + 2 ]; + + if( Tokens[ patternPosition + 3 ] != ")" ) { + yCoordPattern = Tokens[ patternPosition + 3 ]; + + if( Tokens[ patternPosition + 4 ] != ")" ) { + yCoordPattern = yCoordPattern + Tokens[ patternPosition + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoordPattern = Tokens[ patternPosition + 2 ]; + + if( Tokens[ patternPosition + 3 ] != ")" ) { + yCoordPattern = yCoordPattern + Tokens[ patternPosition + 3 ]; + } + } + + string Val1 = ConvertUnits( GetNumberValue( xCoordPattern ), + GetUnitValue( xCoordPattern ) ); + string Val2 = ConvertUnits( GetNumberValue( yCoordPattern ), + GetUnitValue( yCoordPattern ) ); + + string patternDefName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ patternRefPosition + 1 ] ) ); + string elemName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ refDesRefPosition + 1 ] ) ); + + int patternGraphicsNameRefToken = FindToken( startToken + 1, "patternGraphicsNameRef" ); + + string variantName = ""; + + if( patternGraphicsNameRefToken >= 0 ) { + variantName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ patternGraphicsNameRefToken + 1 ] ) ); + } + + if( RotationMirrored != "" ) { + printf( "ADD '%s%s' '%s' %s (%s %s);\n", + patternDefName, + variantName, + elemName, + RotationMirrored, + Val1, Val2 ); + } + else { + printf( "ADD '%s%s' '%s' (%s %s);\n", + patternDefName, + variantName, + elemName, + Val1, Val2 ); + } + + string value = FindCompValue( elemName ); + + if( value != "" ) { + printf( "VALUE '%s' '%s';\n", elemName, value ); + } + + int patternGraphicsRef = FindPatternGraphisRef( startToken ); + + if( patternGraphicsRef >= 0 ) { + int SavePosition = CurrentToken; + + int index = FindPatternDefIndexByName( patternDefName, variantName ); + + AddAttributes( 0, index, elemName, patternGraphicsRef, Val1, Val2 ); + CurrentToken = SavePosition; + printf("SMASH '%s';\n", elemName ); + + IfNameChanged = 0; + IfValueChanged = 0; + + ChangeNameAndValuePosition( elemName, patternGraphicsRef, Val1, Val2, pureRotation ); + + if( index >= 0 ) { + if( IfNameDefinedInPattern[ index ] ) { + if( !IfNameChanged ) { + printf( "DELETE '%s>NAME';\n", elemName ); + } + } + + if( IfValueDefinedInPattern[ index ] ) { + if( !IfValueChanged ) { + printf( "DELETE '%s>VALUE';\n", elemName ); + } + } + } + else { + string tmp; + sprintf( tmp, "# warning: can't find index for pattern %s\n", patternDefName ); + WriteLog( tmp ); + } + + CurrentToken = SavePosition; + } + else { + int SavePosition = CurrentToken; + + int index = FindPatternDefIndexByName( patternDefName, "" ); + + AddAttributes( 0, index, elemName, startToken, Val1, Val2 ); + CurrentToken = SavePosition; + printf("SMASH '%s';\n", elemName ); + + ChangeNameAndValuePosition( elemName, startToken, Val1, Val2, pureRotation ); + + if( index >= 0 ) { + if( IfNameDefinedInPattern[ index ] ) { + if( !IfNameChanged ) { + printf( "DELETE '%s>NAME';\n", elemName ); + } + } + + if( IfValueDefinedInPattern[ index ] ) { + if( !IfValueChanged ) { + printf( "DELETE '%s>VALUE';\n", elemName ); + } + } + } + else { + string tmp; + sprintf( tmp, "# warning: can't find index for pattern %s\n", patternDefName ); + WriteLog( tmp ); + } + + CurrentToken = SavePosition; + } + } + else { + string tmp; + sprintf( tmp, "#warning: Can't find pattern coordinates %s\n", + Tokens[ patternRefPosition + 1 ] ); + WriteLog( tmp ); + } + } + else { + WriteLog("#warning: can't find pattern design name\n"); + } + } + else { + WriteLog("#warning: Can't find pattern reference.\n"); + } +} + +string FindNodePadName( string nodeElementName, string nodePadName ) +{ + string compDefName = FindSymbolDeviceName( nodeElementName ); + + if( compDefName != "" ) { + for( int i = 0; i < CompDefsNumber; i++ ) { + int startToken = CompDefsArray[ i ]; + + string DeviceName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( + Tokens[ startToken ] ) + ); + + if( DeviceName == compDefName ) { + int padMapIndex = PadPinMapRef[ i ]; + + for( int j = 0; j < PadPinMapCount[ i ]; j++ ) { + if( nodePadName == PadPinMapPinRef[ padMapIndex ] ) { + return( PadPinMapNum[ padMapIndex ] ); + } + + padMapIndex++; + } + } + } + } + + return( "" ); +} + +void GenerateSignals( void ) +{ + for( int i = 0; i < NrNets; i++ ) { + int node = NodeRef[ i ]; + + for( int j = 0; j < NrNetNodes[ i ]; j++ ) { + string nodePadName = FindNodePadName( NodeElementName[ node ], NodePadName[ node ] ); + + if( nodePadName != "" ) { + printf( "SIGNAL %s %s %s;\n", NetNames[ i ], NodeElementName[ node ], nodePadName ); + node++; + } + else { + string tmp; + sprintf( tmp, "# warning: NodePadName not found %s %s\n", NodeElementName[ node ], NodePadName[ node ] ); + WriteLog( tmp ); + } + } + } +} + +void GenerateOneDummyPattern( int startToken, int dummyPatternCount ) +{ + int padStyleRefPosition = FindToken( startToken + 1, "padStyleRef" ); + + if( padStyleRefPosition >= 0 ) { + string DeviceName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( + Tokens[ padStyleRefPosition + 1 ] ) + ); + + CurrentToken = FindToken( startToken + 1, "pt" ); + + if( CurrentToken >= 0 ) { + string xCoordText; + string yCoordText; + + xCoordText = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xCoordText = xCoordText + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoordText = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yCoordText = yCoordText + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoordText = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoordText = yCoordText + Tokens[ CurrentToken + 3 ]; + } + } + + printf( "ADD '%s' 'DUMMY%d' (%s %s);\n", + ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ padStyleRefPosition + 1 ] ) ), + dummyPatternCount, + xCoordText, yCoordText ); + } + else { + WriteLog("# warning: GenerateOneDummyPattern: can't find point in dummy device.\n"); + } + } + else { + WriteLog("# warning: GenerateOneDummyPattern: can't find padStyleRef in dummy device.\n"); + } + +} + +void GeneratePCBMultilayer( void ) +{ + int dummyPatternCount = 1; + + if( PCBDesignMultiLayerToken ) { + CurrentToken = PCBDesignMultiLayerToken; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pad" ) { + int SavePosition = CurrentToken; + GenerateOneDummyPattern( SavePosition, dummyPatternCount ); + CurrentToken = SavePosition; + dummyPatternCount++; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "via" ) { + int SavePosition = CurrentToken; + + GenerateVia( SavePosition ); + + CurrentToken = SavePosition; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pattern" ) { + int SavePosition = CurrentToken; + + GeneratePattern( SavePosition ); + + CurrentToken = SavePosition; + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "fromTo" ) { + SkipThisItem(); + } + else { + string tmp; + sprintf( tmp, "# warning: GeneratePCBMultilayer unknown keyword: %s\n", Tokens[ CurrentToken ] ); + WriteLog( tmp ); + SkipThisItem(); + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( "Unexpected keyword in pcbDesign multiLayer " + Tokens[ CurrentToken ], "OK"); + return; + } + } + + CurrentToken++; + } + } + else { + WriteLog( "# warning: no multilayer token in pcbDesign\n"); + } + + GenerateSignals(); +} + +void GeneratePCBLayerContents( void ) +{ + for( int i = 0; i < NrPCBLayerContents; i++ ) { + int startToken = PCBLayerContentsArray[ i ]; + + GenerateLayerContents( startToken, -1 ); + } +} + +// Generate PCB from 'pcbDesign' keyword + +void GeneratePCB( void ) +{ + GeneratePCBHeader(); + + GeneratePCBMultilayer(); + + GeneratePCBLayerContents(); + + printf("WINDOW FIT;\n"); + printf("SET CONFIRM OFF;\n"); +} + +void GenerateSchematicHeader( void ) +{ + string libraryName; + + printf("# ***** Schematic *****\n"); + + string eagleFileName; + string array[]; + + sprintf( eagleFileName, "%s.eagle.sch", PCADfileName); + + if( fileglob( array, eagleFileName ) ) { + printf("SET CONFIRM YES;\n"); + printf("REMOVE '%s';\n", eagleFileName ); + printf("SET CONFIRM OFF;\n"); + } + + printf("EDIT '%s';\n", eagleFileName ); + + libraryName = filesetext( PCADfileName, ".lbr"); + + printf("USE -* '%s';\n", libraryName); + printf("GRID %s;\n", FileUnits ); + //printf("SET OPTIMIZING ON;\n"); + printf("SET CONFIRM YES;\n"); + printf("SET AUTO_JUNCTION OFF;\n"); + printf("SET CHECK_CONNECTS OFF;\n"); + printf("SET WIRE_BEND 2;\n"); + printf("CHANGE FONT VECTOR;\n"); +} + +void GenerateOneSheetSymbol( int startToken ) +{ + int symbolRefPosition = FindToken( startToken + 1, "symbolRef" ); + + if( symbolRefPosition >= 0 ) { + //printf("#symbolRef = %s\n", Tokens[ symbolRefPosition + 1 ] ); + + string info; + sprintf( info, TR("Process symbolref ") + " %d %s", symbolRefPosition, Tokens[ symbolRefPosition + 1 ] ); + UpdateProgress( info ); + + int refDesRefPosition = FindToken( startToken + 1, "refDesRef" ); + + if( refDesRefPosition >= 0 ) { + string refDesRef = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ refDesRefPosition + 1 ] ) ); + + printf("#refDesRef = %s\n", Tokens[ refDesRefPosition + 1 ] ); + + string RotationMirrored = ""; + + int mirrored = FindToken( startToken + 1, "isFlipped" ); + + if( mirrored >= 0 ) { + if( ( Tokens[ mirrored + 1 ] == "True" ) || ( Tokens[ mirrored + 1 ] == "true" ) ) { + RotationMirrored = "M"; + } + } + + int rotationPosition = FindToken( startToken + 1, "rotation" ); + + if( rotationPosition >= 0 ) { + RotationMirrored = RotationMirrored + "R" + Tokens[ rotationPosition + 1 ]; + } + else { + RotationMirrored = RotationMirrored + "R0"; + } + + string partNum = ""; + + int partNumPosition = FindToken( startToken + 1, "partNum" ); + + if( partNumPosition >= 0 ) { + partNum = Tokens[ partNumPosition + 1 ]; + } + + int patternPosition = FindToken( startToken + 1, "pt" ); + + if( patternPosition >= 0 ) { + string DeviceName = FindSymbolDeviceName( refDesRef ); + + if( DeviceName != "" ) { + string vtText = ""; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "attr" ) { + string type = RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ); + + if( ( type == "VT" ) || ( type == "Vt" ) ) { + vtText = FindText( CurrentToken + 1 ); + + break; + } + + SkipThisItem(); + } + else { + SkipThisItem(); + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + string xCoordPattern = ""; + string yCoordPattern = ""; + + xCoordPattern = Tokens[ patternPosition + 1 ]; + + if( IsASCIIValue( Tokens[ patternPosition + 2 ] ) ) { + xCoordPattern = xCoordPattern + Tokens[ patternPosition + 2 ]; + + if( Tokens[ patternPosition + 3 ] != ")" ) { + yCoordPattern = Tokens[ patternPosition + 3 ]; + + if( Tokens[ patternPosition + 4 ] != ")" ) { + yCoordPattern = yCoordPattern + Tokens[ patternPosition + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoordPattern = Tokens[ patternPosition + 2 ]; + + if( Tokens[ patternPosition + 3 ] != ")" ) { + yCoordPattern = yCoordPattern + Tokens[ patternPosition + 3 ]; + } + } + + string Val1 = ConvertUnits( GetNumberValue( xCoordPattern ), + GetUnitValue( xCoordPattern ) ); + string Val2 = ConvertUnits( GetNumberValue( yCoordPattern ), + GetUnitValue( yCoordPattern ) ); + + if( strtol( partNum ) > 1 ) { + printf( "ADD '%s' '%sG%s' 'G%s' %s (%s %s);\n", + DeviceName, + refDesRef, + partNum, + partNum, + RotationMirrored, + Val1, Val2 ); + + string tmp; + + sprintf( tmp, "%sG%sG%s", refDesRef, partNum, partNum ); + + int SavePosition = CurrentToken; + + string symbolDefName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ symbolRefPosition + 1 ] ) ); + + int index = FindSymbolIndexByName( symbolDefName ); + + AddAttributes( 1, index, tmp, startToken, Val1, Val2 ); + CurrentToken = SavePosition; + printf("SMASH (%s %s);\n", Val1, Val2 ); + + IfNameChanged = 0; + IfValueChanged = 0; + + ChangeNameAndValuePosition( tmp, startToken, Val1, Val2, Tokens[ rotationPosition + 1 ] ); + + if( index >= 0 ) { + if( IfNameDefinedInSymbol[ index ] ) { + if( !IfNameChanged ) { + printf( "DELETE '%s>NAME';\n", tmp ); + } + } + + if( IfValueDefinedInSymbol[ index ] ) { + if( !IfValueChanged ) { + printf( "DELETE '%s>VALUE';\n", tmp ); + } + } + } + else { + string tmp; + sprintf( tmp, "# warning: can't find index for symbol %s\n", symbolDefName ); + WriteLog( tmp ); + } + + CurrentToken = SavePosition; + } + else { + printf( "ADD '%s' '%s' 'G%s' %s (%s %s);\n", + DeviceName, + refDesRef, + partNum, + RotationMirrored, + Val1, Val2 ); + + string tmp; + + sprintf( tmp, "%sG%s", refDesRef, partNum ); + + int SavePosition = CurrentToken; + + string symbolDefName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ symbolRefPosition + 1 ] ) ); + + int index = FindSymbolIndexByName( symbolDefName ); + + AddAttributes( 1, index, tmp, startToken, Val1, Val2 ); + CurrentToken = SavePosition; + printf("SMASH (%s %s);\n", Val1, Val2 ); + + IfNameChanged = 0; + IfValueChanged = 0; + + ChangeNameAndValuePosition( tmp, startToken, Val1, Val2, Tokens[ rotationPosition + 1 ] ); + + if( index >= 0 ) { + if( IfNameDefinedInSymbol[ index ] ) { + if( !IfNameChanged ) { + printf( "DELETE '%s>NAME';\n", tmp ); + } + } + + if( IfValueDefinedInSymbol[ index ] ) { + if( !IfValueChanged ) { + printf( "DELETE '%s>VALUE';\n", tmp ); + } + } + } + else { + string tmp; + sprintf( tmp, "# warning: can't find index for symbol %s\n", symbolDefName ); + WriteLog( tmp ); + } + + CurrentToken = SavePosition; + } + } + else { + WriteLog("#warning: no DeviceName found.\n" ); + } + } + else { + string tmp; + sprintf( tmp, "#warning: Can't find pattern coordinates %s\n", + Tokens[ symbolRefPosition + 1 ] ); + WriteLog( tmp ); + } + } + else { + WriteLog("#warning: can't find symbol design name\n"); + } + } + else { + WriteLog("#warning: Can't find symbol reference.\n"); + } +} + +void GenerateTitleSheet( void ) +{ + if( SchTitleSheet ) { + CurrentToken = SchTitleSheet; + + CurrentToken++; + CurrentToken++; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "isVisible" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "border" ) { + int SavePosition = CurrentToken; + //GenerateBorder( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "zones" ) { + int SavePosition = CurrentToken; + //GenerateZones( SavePosition ); FixMe + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "offset" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "line" ) { + int SavePosition = CurrentToken; + GenerateOneLine( SavePosition, 0, 0 ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "field" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "poly" ) { + int SavePosition = CurrentToken; + GenerateOnePcbPoly( SavePosition, 0, DEFAULT_WIRE_WIDTH_BOARD ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "text" ) { + int SavePosition = CurrentToken; + GenerateOneText( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "triplePointArc" ) { + int SavePosition = CurrentToken; + GenerateOneTripleArc( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# ????? GenerateTitleSheet unknown keyword: %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + else { + dlgMessageBox( TR("Unexpected keyword in GenerateTitleSheet: ") + Tokens[ CurrentToken ], "OK"); + return; + } + } + + CurrentToken++; + } + } + else { + WriteLog( "# warning: no titleSheet token in schematicDesign\n"); + } +} + +void GenerateOnePort( int startToken ) +{ + string type; + string netNameRef; + string isFlipped; + string xCoordText; + string yCoordText; + string rotation = "0"; + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "pt" ) { + xCoordText = Tokens[ CurrentToken + 1 ]; + + if( IsASCIIValue( Tokens[ CurrentToken + 2 ] ) ) { + xCoordText = xCoordText + Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoordText = Tokens[ CurrentToken + 3 ]; + + if( Tokens[ CurrentToken + 4 ] != ")" ) { + yCoordText = yCoordText + Tokens[ CurrentToken + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoordText = Tokens[ CurrentToken + 2 ]; + + if( Tokens[ CurrentToken + 3 ] != ")" ) { + yCoordText = yCoordText + Tokens[ CurrentToken + 3 ]; + } + } + + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "portType" ) { + type = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "netNameRef" ) { + netNameRef = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( Tokens[ CurrentToken + 1 ] ) ); + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isFlipped" ) { + isFlipped = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "portPinLength" ) { + isFlipped = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "rotation" ) { + rotation = Tokens[ CurrentToken + 1 ]; + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateOnePort ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + break; + } + } + + CurrentToken++; + } + + XCoordLabels[ NrLabels ] = xCoordText; + YCoordLabels[ NrLabels ] = yCoordText; + TypeLabels[ NrLabels ] = type; + NetNameRef[ NrLabels ] = netNameRef; + IsLabelFlipped[ NrLabels ] = isFlipped; + LabelRotation[ NrLabels ] = rotation; + + NrLabels++; +} + +void GenerateSheets( void ) +{ + printf("# Sheets:\n"); + + for( int i = 0; i < NrSheets; i++ ) { + int startToken = SheetsArray[ i ]; + + int junctions[]; + int NrJunctions = 0; + + NrLabels = 0; + NrWiresPoint = 0; + + int buses[]; + int NrBuses = 0; + + string info; + sprintf( info, TR("Process sheet ") + " %d (%d)", i, NrSheets ); + UpdateProgress( info ); + + string sheetName = ReplaceNotSupportedCharacters( RemoveDoubleQuotas( + Tokens[ startToken ] ) + ); + + int sheetNumberToken = FindToken( startToken + 1, "sheetNum" ); + + string sheetNumber; + + sprintf( sheetNumber, "%d", i + 1 ); + + if( sheetNumberToken >= 0 ) { + sheetNumber = Tokens[ sheetNumberToken + 1 ]; + } + else { + WriteLog( "# warning: no sheet number.\n" ); + } + + printf("#\n"); + printf("# sheet: %s %s\n", sheetName, sheetNumber ); + + printf("EDIT '.S%s'\n", sheetNumber ); + printf("GRID %s;\n", FileUnits ); + + GenerateTitleSheet(); + + printf( "CHANGE LAYER 91;\n" ); + + CurrentToken = startToken + 1; + + while( CurrentToken < TokensNumber ) { + if( Tokens[ CurrentToken ] == "(" ) { + CurrentToken++; + + if( Tokens[ CurrentToken ] == "sheetNum" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "fieldSetRef" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "junction" ) { + junctions[ NrJunctions ] = CurrentToken + 1; + NrJunctions++; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "symbol" ) { + int SavePosition = CurrentToken; + GenerateOneSheetSymbol( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "wire" ) { + int SavePosition = CurrentToken; + GenerateOneLine( SavePosition + 2, 1, 0 ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "text" ) { + int SavePosition = CurrentToken; + GenerateOneText( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "triplePointArc" ) { + int SavePosition = CurrentToken; + GenerateOneTripleArc( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "port" ) { + int SavePosition = CurrentToken; + GenerateOnePort( SavePosition ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "line" ) { + int SavePosition = CurrentToken; + GenerateOneLine( SavePosition, 0, 0 ); + CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "bus" ) { + //int SavePosition = CurrentToken; + //GenerateOneBus( SavePosition ); + buses[ NrBuses ] = CurrentToken; + NrBuses++; + //CurrentToken = SavePosition; + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "drawBorder" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "EntireDesign" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "isRotated" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "pageSize" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "scaleFactor" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "offset" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "PrintRegion" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "sheetOrderNum" ) { + SkipThisItem(); + } + else { + if( Tokens[ CurrentToken ] == "busEntry" ) { + SkipThisItem(); + } + else { + if( DebugMessage ) { + printf( "# GenerateSheets ??????? %s\n", Tokens[ CurrentToken ] ); + } + SkipThisItem(); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + else { + if( Tokens[ CurrentToken ] == ")" ) { + for( int j = 0; j < NrJunctions; j++ ) { + int CurrentToken = junctions[ j ]; + + int junctionPt = FindToken( CurrentToken, "pt" ); + + if( junctionPt >= 0 ) { + string xCoordPattern = ""; + string yCoordPattern = ""; + + xCoordPattern = Tokens[ junctionPt + 1 ]; + + if( IsASCIIValue( Tokens[ junctionPt + 2 ] ) ) { + xCoordPattern = xCoordPattern + Tokens[ junctionPt + 2 ]; + + if( Tokens[ junctionPt + 3 ] != ")" ) { + yCoordPattern = Tokens[ junctionPt + 3 ]; + + if( Tokens[ junctionPt + 4 ] != ")" ) { + yCoordPattern = yCoordPattern + Tokens[ junctionPt + 4 ]; + } + } + else { + WriteLog( "#warning: wront point description.\n" ); + } + } + else { + yCoordPattern = Tokens[ junctionPt + 2 ]; + + if( Tokens[ junctionPt + 3 ] != ")" ) { + yCoordPattern = yCoordPattern + Tokens[ junctionPt + 3 ]; + } + } + + string Val1 = ConvertUnits( GetNumberValue( xCoordPattern ), + GetUnitValue( xCoordPattern ) ); + string Val2 = ConvertUnits( GetNumberValue( yCoordPattern ), + GetUnitValue( yCoordPattern ) ); + + printf( "JUNCTION (%s %s);\n", Val1, Val2 ); + } + else { + WriteLog( "# warning: no junction position.\n" ); + } + } + + printf("CHANGE SIZE %s;\n", LabelTextHeight ); + + for( int k = 0; k < NrLabels; k++ ) { + string mirrored = ""; + + if( IsLabelFlipped[ k ] ) { + mirrored = "M"; + } + + printf("LABEL %sR%s (%s %s) (%s %s);\n", mirrored, LabelRotation[ k ], + XCoordLabels[ k ], + YCoordLabels[ k ], + XCoordLabels[ k ], + YCoordLabels[ k ] ); + + // Generate wires to fill gaps in ports + + real xLabelCoord = strtod( XCoordLabels[ k ] ); + real yLabelCoord = strtod( YCoordLabels[ k ] ); + + int toLeft = ( TypeLabels[ k ] == "LeftAngle_Sgl_Horz" ) || + ( TypeLabels[ k ] == "LeftAngle_Dbl_Horz" ) || + ( TypeLabels[ k ] == "BothAngle_Dbl_Horz" ); + int toRight = ( TypeLabels[ k ] == "RightAngle_Sgl_Horz" ) || + ( TypeLabels[ k ] == "RightAngle_Dbl_Horz" ) || + ( TypeLabels[ k ] == "BothAngle_Dbl_Horz" ); + + if( IsLabelFlipped[ k ] ) { + int tmp = toLeft; + toLeft = toRight; + toRight = tmp; + } + + if( 1 /*toRight*/ ) { + for( int l = 0; l < NrWiresPoint; l++ ) { + int right = 1000000; + int index = -1; + + if( ( yLabelCoord == WiresPointY[ l ] ) && ( WiresNet[ l ] == NetNameRef[ k ] ) ) { + if( xLabelCoord < WiresPointX[ l ] ) { + if( right > WiresPointX[ l ] ) { + right = WiresPointX[ l ]; + index = l; + } + } + } + + if( index >= 0 ) { + printf("NET '%s' (%s %s) (%f %f);\n", NetNameRef[ k ], XCoordLabels[ k ], YCoordLabels[ k ], + WiresPointX[ index ], WiresPointY[ index ] ); + } + else { + //printf( "#info: wires point %s %s to the right not found.\n", XCoordLabels[ k ], YCoordLabels[ k ] ); + } + } + } + + if( 1 /*toLeft*/ ) { + for( int l = 0; l < NrWiresPoint; l++ ) { + int left = -1000000; + int index = -1; + + if( ( yLabelCoord == WiresPointY[ l ] ) && ( WiresNet[ l ] == NetNameRef[ k ] ) ) { + if( xLabelCoord > WiresPointX[ l ] ) { + if( left < WiresPointX[ l ] ) { + left = WiresPointX[ l ]; + index = l; + } + } + } + + if( index >= 0 ) { + printf("NET '%s' (%s %s) (%f %f);\n", NetNameRef[ k ], XCoordLabels[ k ], YCoordLabels[ k ], + WiresPointX[ index ], WiresPointY[ index ] ); + } + else { + //printf( "#info: wires point %s %s to the left not found.\n", XCoordLabels[ k ], YCoordLabels[ k ] ); + } + } + } + } + + for( int l = 0; l < NrBuses; l++ ) { + int busToken = buses[ l ]; + + GenerateOneBus( busToken ); + } + + break; + } + } + + CurrentToken++; + } + } +} + +void GenerateSchematic( void ) +{ + GenerateSchematicHeader(); + + GenerateSheets(); + + printf("WINDOW FIT;\n"); + printf("SET CONFIRM OFF;\n"); +} + +// This function generate script based on parsed data. +// If processed seccesfully returns 0, +// otherwise returns 1 + +int GenerateScript( void ) +{ + output(SCRIPTfileName, "wt") { + GenerateLibrary(); + + if( PCBDesignToken ) { + GeneratePCB(); + } + + if( SchematicDesignToken ) { + GenerateSchematic(); + } + } + + return( 0 ); +} + +int Cntelayer = 0; +string EagleLayerName[]; +int EagleLayerNum[]; + +string SaveRefLayerDef[]; +string SaveRefLayerNum[]; +string SaveRefLayerType[]; +string SavePcadEagleLayerRefName[]; +string SavePcadEagleLayerRefNum[]; + +string PrevRefLayerDef[]; +string PrevRefLayerNum[]; +string PrevRefLayerType[]; +string PrevPcadEagleLayerRefName[]; +string PrevPcadEagleLayerRefNum[]; + +string PrevShowRefLayer[]; + +int UpdateRefLayers( void ) +{ + int selref = 0; + + for( int i = 0; i < LayerDefsNumber; i++ ) { + string pcadLayerStrNum; + + sprintf( pcadLayerStrNum, "%d", LayersCode[ i ] ); + + int eagleFromPcadLayerNum = strtol( ConvertLayer( pcadLayerStrNum ) ); + + int found = 0; + + for( int j = 0; j < Cntelayer; j++ ) { + if( eagleFromPcadLayerNum == EagleLayerNum[ j ] ) { + SaveRefLayerType[ i ] = LayersType[ i ]; + SaveRefLayerDef[ i ] = LayersName[ i ]; + SaveRefLayerNum[ i ] = pcadLayerStrNum; + string tmp; + sprintf( tmp, "%d", EagleLayerNum[ j ] ); + SavePcadEagleLayerRefNum[ i ] = tmp; + SavePcadEagleLayerRefName[ i ] = EagleLayerName[ j ]; + + selref++; + + found = 1; + + break; + } + } + + if( !found ) { + sprintf( ShowRefLayer[selref], "%s\t%s\t%s\t%s\t%s", + RefLayerType[ i ], + RefLayerDef[ i ], + RefLayerNum[ i ], + 0, + "unknown" ); + + selref++; + } + } + + for( i = 0; i < selref; i++ ) { + RefLayerType[ i ] = SaveRefLayerType[ i ]; + RefLayerDef[ i ] = SaveRefLayerDef[ i ]; + RefLayerNum[ i ] = SaveRefLayerNum[ i ]; + PcadEagleLayerRefNum[ i ] = SavePcadEagleLayerRefNum[ i ]; + PcadEagleLayerRefName[ i ] = SavePcadEagleLayerRefName[ i ]; + + sprintf( ShowRefLayer[ i ], "%s\t%s\t%s\t%s\t%s", + SaveRefLayerType[ i ], + SaveRefLayerDef[ i ], + SaveRefLayerNum[ i ], + SavePcadEagleLayerRefNum[ i ], + SavePcadEagleLayerRefName[ i ] ); + } + + RefLayerType[ selref ] = ""; + RefLayerDef[ selref ] = ""; + RefLayerNum[ selref ] = ""; + PcadEagleLayerRefNum[ selref ] = ""; + PcadEagleLayerRefName[ selref ] = ""; + + CntlayerDef = selref; + + return( selref ); +} + +void ProcessLayersMap( void ) +{ + if( schematic ) { + schematic(S) { + S.layers(L) { + EagleLayerName[Cntelayer] = L.name; + EagleLayerNum[Cntelayer] = L.number; + Cntelayer++; + } + } + } + else { + if( board ) { + board(B) { + B.layers(L) { + EagleLayerName[Cntelayer] = L.name; + EagleLayerNum[Cntelayer] = L.number; + Cntelayer++; + } + } + } + } + + int selPCAD = LayerDefsNumber; + int selUlay = LayerDefsNumber; + int selEAGLE = Cntelayer; + + int selref = 0; + + for( int i = 0; i < CntlayerDef; i++ ) { + PrevRefLayerType[ i ] = RefLayerType[ i ]; + PrevRefLayerDef[ i ] = RefLayerDef[ i ]; + PrevRefLayerNum[ i ] = RefLayerNum[ i ]; + PrevPcadEagleLayerRefNum[ i ] = PcadEagleLayerRefNum[ i ]; + PrevPcadEagleLayerRefName[ i ] = PcadEagleLayerRefName[ i ]; + + sprintf( PrevShowRefLayer[ i ], "%s\t%s\t%s\t%s\t%s", + RefLayerType[ i ], + RefLayerDef[ i ], + RefLayerNum[ i ], + PcadEagleLayerRefNum[ i ], + SavePcadEagleLayerRefName[ i ] ); + } + + dlgDialog(TR("ACCEL - EAGLE layer mapping")) { + + selref = UpdateRefLayers(); + + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(350); + + dlgVBoxLayout { + dlgLabel("ACCEL\nLayer\n--->>"); + dlgListBox( LayersName, selPCAD ); + } + + dlgVBoxLayout { + dlgLabel("EAGLE\nLayer\n<<---"); + dlgListBox( PcadEagleLayerRefName, selUlay ); + } + + dlgVBoxLayout { + dlgLabel("EAGLE\nLayer\n"); + dlgListBox( EagleLayerName, selEAGLE ) { + // set Reference layer name + PcadEagleLayerRefName[selPCAD] = EagleLayerName[selEAGLE]; + + // set Reference layer number + string tmp; + sprintf( tmp, "%d", EagleLayerNum[selEAGLE] ); + PcadEagleLayerRefNum[selPCAD] = tmp; + + sprintf( ShowRefLayer[ selPCAD ], "%s\t%s\t%s\t%s\t%s", + RefLayerType[ selPCAD ], + RefLayerDef[ selPCAD ], + RefLayerNum[ selPCAD ], + PcadEagleLayerRefNum[ selPCAD ], + PcadEagleLayerRefName[ selPCAD ] ); + } + } + } + + dlgSpacing(10); + + dlgVBoxLayout { + dlgLabel(TR("Mapping:")); + dlgListView(TR("ACCEL\nType\tACCEL\nLayer\tACCEL\nNumber\tEAGLE\nNumber\tEAGLE\nName"), ShowRefLayer, selref ); + } + + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("&" + TR("Load")) { LoadCrossRef(""); selref = UpdateRefLayers(); } + dlgPushButton("&" + TR("Save")) SaveCrossRef(); + dlgPushButton("+OK") + dlgAccept(); + + dlgPushButton("-" + TR("Cancel")) { + for( int i = 0; i < CntlayerDef; i++ ) { + RefLayerType[ i ] = PrevRefLayerType[ i ]; + RefLayerDef[ i ] = PrevRefLayerDef[ i ]; + RefLayerNum[ i ] = PrevRefLayerNum[ i ]; + PcadEagleLayerRefNum[ i ] = PrevPcadEagleLayerRefNum[ i ]; + PcadEagleLayerRefName[ i ] = PrevPcadEagleLayerRefName[ i ]; + ShowRefLayer[ i ] = PrevShowRefLayer[ i ]; + } + dlgReject(); + } + } + }; +} + +void OutputWarningsLogFile( void ) +{ + string fullLog = ""; + + WarningsLogFileName = PCADfileName + ".err"; + + sprintf( fullLog, "Number of messages = %d\n\n", NrLogLines ); + + for( int n = 0; n < NrLogLines; n++ ) { + fullLog = fullLog + LogLines[ n ]; + } + + output( WarningsLogFileName, "wt" ) { + printf("%s", fullLog ); + } + + if( !BatchMode ) { + if( NrLogLines ) { + dlgDialog( TR( "Warnings log" ) ) { + dlgHBoxLayout dlgSpacing (400); + + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing (300); + dlgTextView ( fullLog ); + } + + dlgHBoxLayout { + dlgStretch( 1 ); + dlgPushButton( TR("-Back")) dlgReject (); + dlgStretch(1); + } + }; + } + } +} + +void ChangeDRU( void ) +{ + string drufile = path_dru[ 0 ] + "/" + "default.dru"; + + string f[]; + int fcnt = fileglob( f, drufile ); + + if( fcnt ) { + string DRUvalues[]; + + int DRUlcnt = fileread( DRUvalues, drufile ); + + string s[]; + int n; + string outputString[]; + + for( int line = 0; line < DRUlcnt; line++ ) { + n = strsplit( s, DRUvalues[ line ], ' '); + + if( s[ 0 ] == "rvPadTop" ) { + outputString[ line ] = "rvPadTop = 0"; + } else if( s[ 0 ] == "rvPadInner" ) { + outputString[ line ] = "rvPadInner = 0"; + } else if( s[ 0 ] == "rvPadBottom" ) { + outputString[ line ] = "rvPadBottom = 0"; + } else if( s[ 0 ] == "rvViaOuter" ) { + outputString[ line ] = "rvViaOuter = 0"; + } else if( s[ 0 ] == "rvViaInner" ) { + outputString[ line ] = "rvViaInner = 0"; + } else if( s[ 0 ] == "rvMicroViaOuter" ) { + outputString[ line ] = "rvMicroViaOuter = 0"; + } else if( s[ 0 ] == "rvMicroViaInner" ) { + outputString[ line ] = "rvMicroViaInner = 0"; + } else if( s[ 0 ] == "rlMinPadTop" ) { + outputString[ line ] = "rlMinPadTop = 0mil"; + } else if( s[ 0 ] == "rlMaxPadTop" ) { + outputString[ line ] = "rlMaxPadTop = 0mil"; + } else if( s[ 0 ] == "rlMinPadInner" ) { + outputString[ line ] = "rlMinPadInner = 0mil"; + } else if( s[ 0 ] == "rlMaxPadInner" ) { + outputString[ line ] = "rlMaxPadInner = 0mil"; + } else if( s[ 0 ] == "rlMinPadBottom" ) { + outputString[ line ] = "rlMinPadBottom = 0mil"; + } else if( s[ 0 ] == "rlMaxPadBottom" ) { + outputString[ line ] = "rlMaxPadBottom = 0mil"; + } else if( s[ 0 ] == "rlMinViaOuter" ) { + outputString[ line ] = "rlMinViaOuter = 0mil"; + } else if( s[ 0 ] == "rlMaxViaOuter" ) { + outputString[ line ] = "rlMaxViaOuter = 0mil"; + } else if( s[ 0 ] == "rlMinViaInner" ) { + outputString[ line ] = "rlMinViaInner = 0mil"; + } else if( s[ 0 ] == "rlMaxViaInner" ) { + outputString[ line ] = "rlMaxViaInner = 0mil"; + } else if( s[ 0 ] == "rlMinMicroViaOuter" ) { + outputString[ line ] = "rlMinMicroViaOuter = 0mil"; + } else if( s[ 0 ] == "rlMaxMicroViaOuter" ) { + outputString[ line ] = "rlMaxMicroViaOuter = 0mil"; + } else if( s[ 0 ] == "rlMinMicroViaInner" ) { + outputString[ line ] = "rlMinMicroViaInner = 0mil"; + } else if( s[ 0 ] == "rlMaxMicroViaInner" ) { + outputString[ line ] = "rlMaxMicroViaInner = 0mil"; + } else if( s[ 0 ] == "srRoundness" ) { + outputString[ line ] = "srRoundness = 0.0"; + } else if( s[ 0 ] == "srMinRoundness" ) { + outputString[ line ] = "srMinRoundness = 0mil"; + } else { + outputString[ line ] = DRUvalues[ line ]; + } + } + + output( DRUFileName, "wt") { + for( int line = 0; line < DRUlcnt; line++ ) { + printf("%s\n", outputString[ line ] ); + } + } + } + else { + dlgMessageBox(TR("Can't open default.dru !"), "OK"); + } +} + +// This is the main parsing procedure +// This procedure do the following: +// +// 1. Merge all lines to one string and +// remove all comments (comments may be added by inserting +// a semicolon; the comment continues from the semicolon +// to the end of the line. +// 2. Split merged string to array of tokens +// 3. Parse tree +// 4. Generate script + +int Parsing( void ) +{ + string a[]; + + int fileExist = fileglob( a, PCADfileName ); + + if( !fileExist ) { + dlgMessageBox( TR("File ") + PCADfileName + TR(" doesn't exist!"), "OK" ); + return( 1 ); + } + + DebugMessage = 1; + MergedString = ""; + TokensNumber = 0; + + MergeLines(); + + SplitToTokens(); + + if( ParseTree() ) { + return( 1 ); + } + + if( PCBDesignToken ) { + DRUFileName = filesetext( PCADfileName, ".dru" ); + + ChangeDRU(); + } + + string CrossfileName = PCADfileName + ".lmp"; + string f[]; + int crossfileExist = fileglob(f, CrossfileName); + if( crossfileExist ) LoadCrossRef(CrossfileName); + + if( IfUpdateLayersMap ) { + ProcessLayersMap(); + } + + if( GenerateScript() ) { + return( 1 ); + } + + OutputWarningsLogFile(); + + return( 0 ); +} + +// *********** Show and creat Reference **************** +int Execute(string fname) { + // APL make parsing + Parsing(); + return 1; +} + +// ***** Main ***** +void main( void ) +{ + // Keep help here for it's too big to stuff into dictionary. + string help[] = { + "General
    " + "ACCEL ASCII is also known as TangoPRO ASCII or P-CAD ASCII. " + "It can be exported from P-CAD, Altium Designer and PROTEL and therefore allows conversion of " + "designs in these formats to EAGLE. From Altium Designer only boards can be exported to this format.
    " + "The conversion to EAGLE works following:
    " + "First, in the directory of the input file, an EAGLE library with same name is generated. " + "It contains the devices that are used. With this an EAGLE schematic or board with same name is generated.
    " + "For ACCEL ASCII schematic files partly end with \".sch\", EAGLE schematics get ending \".eagle.sch\". " + "The conversion of a schematic without board doesn't make much sense because the package information is " + "missing which is necessary for creation of a board.
    " + "Because of different data models and powerfulness of the foreign systems and EAGLE the conversion has limits. " + "Ideally certain cases should already be avoided in the original data. " + "Otherwise certain post processing steps may be necessary. In any case we recommend to perform a DRC after " + "import in order to find and eliminate potential weaknesses of the design. " + "

    " + "Layer assignment
    " + "Depending on the source system, signal, solder and other layer types have different names. " + "For conversion a default assignment is used which may not always be correct. " + "For this case you can change this individually with the option \"Adjust layer mapping\"." + "

    " + "Conversion details:
    " + "

    • Names:
      " + "To follow EAGLE's naming conventions for different types of entities certain characters are replaced " + "by '_', in particular '(', ')', '[', ']', ''' and space. '\\\\' is replaced by '/'. " // 4 backslashes here ? Insane. Seems to be a bug in EAGLE. + "Control characters like '\\\\r' are not processed in a special way.
    • " + "
    • Texts:
      " + "All texts are converted to vectorfont in EAGLE. This allows a system independent " + "representation for polygon calculation and CAM processing. The font can be changed to fixed or " + "proportional where needed. All other text properties are taken over from ACCEL ASCII.
    • " + "
    • Pads and SMDs:
      " + "For pad and SMD types following conversion agreement is used:
      " + "Square pad/SMD -> SQUARE pad/SMD,
      " + "Rectangle pad -> SQUARE pad with additional rectangle polygon,
      " + "Oval pad -> LONG pad in EAGLE (size and shape of original and converted pads are slightly " + "different in this case),
      " + "Ellipse pad -> ROUND pad with additional approximation polygon consisting of four arcs,
      " + "Polygon pad -> SQUARE pad with additional polygon,
      " + "Round rectangle pad -> SQUARE pad and additional polygon with rounded corners,
      " + "Target pad -> ROUND pad,
      " + "Rectangle SMD -> rectangle SMD,
      " + "Oval SMD -> SMD with 100% roundness,
      " + "Ellipse SMD -> round SMD with additional approximation polygon consisting of four arcs,
      " + "Polygon SMD -> square SMD with additional polygon,
      " + "Round rectangle -> SMD with 25% roundness,
      " + "Target SMD -> SMD with 100% roundness.
    • " + "
    • Standalone pads (Free pads):
      " + "For standalone pads an appropriate library package is created in EAGLE.
    • " + "
    • Vias:
      " + "Vias are converted the following way to EAGLE:
      " + "Oval -> ROUND, Rectangle -> SQUARE, Ellipse -> ROUND, Round rectangle -> SQUARE and Target -> ROUND.
      " + "The sizes of the EAGLE vias are adjusted to fit within the shape of the ACCEL vias to avoid clearance issues.
    • " + "
    • Contacts / Routing:
      " + "In EAGLE coordinates of traces, pads, vias etc. have to match exactly in order to be properly routed. " + "Otherwise airwires are generated. In some other systems certain deviations are allowed." + "In other systems it's possible that a longer trace crosses a pad without connecting point. " + "In EAGLE this leads to an airwire to the next connecting point. In this case the trace needs to be splitted with " + "SPLIT command in order to create an additional connecting point at the pad position.
    • " + "
    • Copper polygons general:
      " + "In EAGLE there's only one type for hatched polygons (horizontal and vertical stripes)." + "The different possible hatch types in ACCEL ASCII like diagonal style for example, are all " + "converted to this.
      " + "Thermals within polygons are also always horizontal and vertical. There's no specific thermal spoke width " + "for each polygon, but a general value in the EAGLE design rules.
      " + "The removal of orphan property is converted to EAGLE but without threshold value (only on/off).
    • " + "
    • Copper polygons in poured state:
      " + "In EAGLE polygons are saved always in unpoured state. The pour state is calculated dynamically " + "by RATSNEST and depends on the parameters currently set.
    • " + "
    • Dimensions:
      " + "As the data model for dimensions in EAGLE is much simpler than in ACCEL ASCII some details are not mapped to EAGLE.
    • " + "
    • Labels:
      " + "Input, output and bidirectional labels are all converted to Xref labels in EAGLE.
    • " + "
    • Attributes for layers:
      " + "In EAGLE layers can't have attributes. This is skipped.
    • " + "
    • 'zones' (in ACCEL schematic):
      " + "'zones' are not supported and skipped.
    • " + "
    " + , + "Allgemeines
    " + "ACCEL ASCII ist auch unter dem Namen TangoPRO ASCII, oder P-CAD ASCII bekannt. " + "Es kann von P-CAD, Altium Designer und PROTEL aus exportiert werden und ermöglicht so die " + "Konvertierung von Designs in diesen Formaten in EAGLE-Format. Von Altium Designer aus können nur
    " + "Boards in dieses Format exportiert werden. Für die Konvertierung in EAGLE ist Folgendes zu beachten:
    " + "Zunächst wird im Verzeichnis der Inputdatei eine EAGLE-Bibliothek gleichen Namens generiert, " + "die die verwendeten Bauteile enthält. Damit wird dann der gleichnamige EAGLE-Schaltplan oder das Board erstellt. " + "Da ACCEL-ASCII-Schaltpläne wie EAGLE teilweise die Endung \".sch\" haben, erhalten die EAGLE-Schaltpläne " + "die Endung \".eagle.sch\". " + "Die Konvertierung eines Schaltplans alleine macht wenig Sinn, da die Package-Information fehlt, " + "die für die Generierung eines Boards erforderlich wäre. " + "Aufgrund der verschiedenen Datenmodelle und der Mächtigkeit der Fremdsysteme und EAGLE sind der Konvertierung " + "Grenzen gesetzt. Idealerweise sollten bestimmte Fälle in den Originaldaten bereits vermieden werden. " + "Ansonsten sind gewisse Nachbearbeitungsschritte erforderlich. In jedem Fall sollten Sie nach dem Import einen " + "DRC durchführen, um eventuelle Schachstellen des Designs zu finden und zu beseitigen." + "

    " + "Zuordnung der Layer
    " + "Je nach Herkunftssystem haben die Signal- Beschriftungs- und sonstigen Layerarten verschiedene Namen. " + "Für die Konvertierung wird eine gewisse Standard-Zuordnung angenommen, die jedoch nicht immer richtig sein muss. " + "Für diesen Fall können Sie über die Option \"Manuelle Layer-Zuordnung\" dies individuell einstellen." + "

    " + "Details zur Konvertierung:
    " + "

    • Namen:
      " + "Um EAGLE's Namenskonventionen für verschiedene Objekttypen zu entsprechen, werden verschiedene Zeichen " + "durch '_' ersetzt, insbesondere '(', ')', '[', ']', ''' und Leerzeichen. '\\\\' wird ersetzt durch '/'. " + "Kontrollzeichen wie '\\\\r' werden nicht speziell behandelt.
    • " + "
    • Texte:
      " + "Alle Texte werden in Vektorfont konvertiert. Dies ermöglicht eine systemunabhängige " + "Darstellung für das Polygon-Freirechnen und die CAM-Verarbeitung. Die Schriftart kann auf Fixed oder " + "Proportional geändert werden wo nötig. Alle anderen Texteigenschaften werden aus ACCEL ASCII übernommen." + "
    • Pads und SMDs:
      " + "Für Pads und SMDs werden folgende Konvertierungsregeln verwendet:
      " + "Square Pad/SMD -> SQUARE Pad/SMD,
      " + "Rectangle Pad -> SQUARE Pad mit umgebendem rechteckigem Polygon,
      " + "Oval Pad -> LONG Pad (Größe und Form weichen leicht voneinander ab),
      " + "Ellipse Pad -> ROUND Pad mit umgebendem Approximation-Polygon aus 4 Kreisbögen,
      " + "Polygon Pad -> SQUARE Pad mit umgebendem Polygon,
      " + "Round rectangle Pad -> SQUARE Pad mit umgebendem Polygon mit Verrundungen,
      " + "Target Pad -> ROUND Pad,
      " + "Rectangle SMD -> rechteckiges SMD,
      " + "Oval SMD -> SMD mit 100% Roundness,
      " + "Ellipse SMD -> rundes SMD mit umgebendem Approximation-Polygon aus 4 Kreisbögen,
      " + "Polygon SMD -> quadratisches SMD with umgebendem Polygon,
      " + "Round rectangle -> SMD with 25% Roundness,
      " + "Target SMD -> SMD with 100% Roundness.
    • " + "
    • Standalone-Pads (Freie Pads):
      " + "Für Standalone-Pads wird ein entsprechendes Package in EAGLE erzeugt und verwendet.
    • " + "
    • Vias:
      " + "Vias werden folgendermaßen zu EAGLE konvertiert:
      " + "Oval -> ROUND, Rectangle -> SQUARE, Ellipse -> ROUND, Round rectangle -> SQUARE and Target -> ROUND.
      " + "Die Größen der EAGLE-Vias werden so gesetzt, dass sie in die Form der ACCEL-Vias hineinpassen, um Abstände einzuhalten.
    • " + "
    • Kontaktierung / Routen:
      " + "In EAGLE müssen die Koordinaten von Leiterbahnen, Pads, Vias etc. exakt aufeinander treffen, um als richtig geroutet " + "zu gelten, sonst entstehen Luftlinien. In manchen anderen Systemen sind gewisse Abweichungen zulässig. " + "Es kann in anderen Systemen vorkommen, daß eine längere Leiterbahn über einen Pad gelegt ist ohne einen Absetzpunkt. " + "Das erzeugt in EAGLE eine Luftlinie bis zum nächsten Absetzpunkt. In diesem Fall muß mit SPLIT die Leiterbahn gesplittet " + "werden, um einen zusätzlichen Absetzpunkt an der Pad-Position zu erzeugen.
    • " + "
    • Kupfer-Polygone allgemein:
      " + "In EAGLE gibt es nur einen Typ für schraffierte Polygone (horizontale und vertikale Streifen). " + "Die verschiedenen möglichen Schraffiertypen in ACCEL ASCII wie z.B. diagonale Schraffur werden alle " + "dazu konvertiert.
      " + "Thermalstege in den Polygonen verlaufen immer horizontal und vertikal. Es gibt keine spezifische " + "Thermalbreite für jedes Polygon, aber einen allgemeinen Wert in den Designregeln.
      " + "Die Orphan-Eigenschaft wird nach EAGLE konvertiert aber ohne Schwellwert (nur Orphans behalten/nicht behalten).
    • " + "
    • Kupfer-Polygone in freigerechnetem Zustand:
      " + "In EAGLE werden Polygone immer im Definitions-Zustand gespeichert (nicht freigerechnet). Das Freirechnen erfolgt " + "dynamisch durch RATSNEST und hängt von den aktuellen Parametern ab.
    • " + "
    • Bemaßungen:
      " + "Da das Datenmodell für Bemaßungen in EAGLE wesentlich einfacher ist als in ACCEL ASCII, werden einige Details " + "nicht in EAGLE abgebildet.
    • " + "
    • Labels:
      " + "Input- Output- und bidirektionale Labels werden alle in Xref-Labels in EAGLE konvertiert.
    • " + "
    • Attributes für Layer:
      " + "In EAGLE können Layer keine Attribute haben. Dies wird weggelassen.
    • " + "
    • 'zones' (in ACCEL-Schaltplänen):
      " + "'zones' werden nicht unterstützt und daher weggelassen.
    • " + "
    " + , + "Общие замечания
    " + "ACCEL ASCII также известен как TangoPRO ASCII или P-CAD ASCII. " + "Он может быть экспортирован из Altium Designer, P-CAD и PROTEL. " + "Трансляция в EAGLE работает следующим образом:
    " + "В начале, в каталоге входного файла, создаётся библиотека EAGLE с тем же именем. " + "Она содержит компоненты, которые будут использованы в дальнейшем. Затем создаётся файл EAGLE с тем же именем, содержащий схему или топологию.
    " + "Для ACCEL ASCII файла схемы \".sch\", создаётся файл EAGLE \".eagle.sch\". " + "Преобразование схемы без платы не имеет смысла, так как отсутствует информация," + "необходимая для создания платы." + "

    " + "Присвоение значений слоям
    " + "В зависимости от исходной системы, типы сигналов, припой и другие слои имеют разные названия. " + "Соответствие слоёв, заданное по умолчанию, может быть изменено. " + "Для этого воспользуйтесь опцией \"Настройка соответствия слоёв\"." + "

    " + "Различия и ограничения, возникающие при преобразовании
    " + "В связи с различными моделями данных и систем, преобразование имеет ограничения. " + "В идеале некоторые конфигурации следует избегать в исходных данных. " + "В противном случае потребуется постобработка. Это включает в себя, в частности: " + "

    • Имена:
      " + "Следуя соглашениям о именах в EAGLE следующие символы будут преобразованы " + "в '_': '(', ')', '[', ']', ''' и пробел. '\\\\' заменяется на '/'. " // 4 backslashes here ? Insane. Seems to be a bug in EAGLE. + "Управляющие символы, такие как '\\\\r' в строках не обрабатываются.
    • " + "
    • Текстовые строки:
      " + "Все текстовые строки преобразуются в векторный шрифт в EAGLE. Это даёт возможность " + "представить текст и использовать его для CAM обработки. Шрифт может быть изменен на фиксированный или " + "пропорциональный где это необходимо. Все остальные свойства шрифта сохраняются из ACCEL ASCII.
    • " + "
    • Pad и SMD:
      " + "Pad и SMD преобразуются следующим образом:
      " + "Square pad/SMD -> SQUARE pad/SMD,
      " + "Rectangle pad -> SQUARE pad с дополнительным прямоугольным полигоном,
      " + "Oval pad -> LONG pad в EAGLE (размер и форма отличаются в этом случае)," + "
      " + "Ellipse pad -> ROUND pad с дополнительным полигоном, аппроксимированным четыремя дугам,
      " + "Polygon pad -> SQUARE pad с дополнительным полигоном,
      " + "Round rectangle pad -> SQUARE pad с дополнительным полигоном с закругленными углами,
      " + "Target pad -> ROUND pad,
      " + "Rectangle SMD -> прямоугольный SMD,
      " + "Oval SMD -> SMD с 100% закругленностью,
      " + "Ellipse SMD -> ROUND SMD с дополнительным полигоном, аппроксимированным четыремя дугами,
      " + "Polygon SMD -> SQUARE SMD с дополнительным полигоном,
      " + "Round rectangle -> SMD с 25% закругленностью,
      " + "Target SMD -> SMD с 100% закругленностью.
    • " + "
    • Одиночные контактные площадки:
      " + "Для автономных контактных площадок в EAGLE создаются соответствующие библиотечные элементы.
    • " + "
    • Переходы:
      " + "Переходы преобразуются следующим образом:
      " + "Oval -> ROUND, Rectangle -> SQUARE, Ellipse -> ROUND, Round rectangle -> SQUARE and Target -> ROUND.
      " + "Размер перехода в EAGLE подбирается таким образом, чтобы исключить нарушение минимального технологического допуска.
    • " + "
    • Контакты / трассировка:
      " + "В EAGLE координаты проводов, контактных площадок, переходов и т.д. должны в точности совпадать с тем, чтобы быть правильно соединенными. " + "В противном случае создаются неподключенные соединения. В некоторых других системах допускаются отклонения.
    • " + "В других системах допускается если провод пересекает контактную площадку без подключения. " + "В EAGLE это приводит к созданию airwire к следующей точке цепи. В этом случае соединение должно быть разделено с помощью команды SPLIT " + "чтобы создать дополнительные соединительные точки. " + "
    • Преобразование заливки:
      " + "В EAGLE есть только один тип заливки (горизонтальных и вертикальных полос штриховки). " + "Различные возможные типы заливки в ACCEL ASCII, как, например, диагональный стиль, " + "преобразуется в этот.
      " + "Thermals в пределах полигона также всегда горизонтальные и вертикальные. Там нет конкретных тепловых ширин " + "для каждого полигона. Это значение задано в общих настройках EAGLE.
      " + "Удаление одиночных полигонов также преобразуется в EAGLE, но без порогового значения (только вкл / выкл). " + "
    • >Преобразование полигонов заливки:
      " + "В EAGLE полигоны заливки всегда сохраняются в незалитом состоянии. Состояние заливки всегда вычисляется динамически " + "с помощью RATSNEST и зависит от текущих установленных параметров.
    • " + "
    • Линейки:
      " + "Поскольку модель данных в EAGLE существенно проще, чем в ACCEL ASCII некоторые детали линеек не преобразуются в EAGLE.
    • " + "
    • Знаки подключения:
      " + "Входные, выходные и двунаправленные знаки подключения преобразуются в знак Xref в EAGLE.
    • " + "
    • Атрибуты слоёв:
      " + "В EAGLE атрибуты слоёв не преобразуются.
    • " + "
    • 'зоны' (в ACCEL принципиальной схеме):
      " + "'зоны' в принципиальной схеме не преобразуются
    • " + "
    " + "В любом случае мы рекомендуем выполнить DRC после импорта для того, чтобы найти и устранить потенциальные проблемы." + }; + + BatchMode = 0; + + if( argc > 1 ) { + BatchMode = 1; + + PCADfileName = argv[ 1 ]; + + Lines = fileread( PcadLines, PCADfileName ); + + if (Lines == -1) exit(-7113); + + SCRIPTfileName = filesetext(PCADfileName, ".scr"); + + if( Parsing() ) { + exit( 1 ); + } + + if( PCBDesignToken ) { + exit ("SCRIPT '" + SCRIPTfileName + "'; RATSNEST; WRITE;"); + } + + exit ("SCRIPT '" + SCRIPTfileName +"' WRITE;"); + } + + SchematicWindow = 0; + BoardWindow = 0; + + if (schematic) { + schematic(S) { + SchematicWindow = 1; + } + } + else if (board) { + board(B) { + BoardWindow = 1; + } + } + else { + dlgMessageBox(TR("Please start from board or schematic editor !"), "OK"); + exit(0); + } + + + string fname = ""; + int nowstart = 0; + dlgDialog(TR("Import P-CAD/Altium/Protel (ACCEL ASCII)")) { + dlgLabel(usage); + // www: Remove this when integrated into EAGLE + //dlgLabel("Version " + Version); + dlgLabel(Status, 1); + dlgHBoxLayout { + dlgLabel(TR("Import file:")); + dlgStringEdit(fname); + dlgPushButton(TR("&Browse") + "...") { + fname = GetFile(fname); + } + } + dlgHBoxLayout { + dlgCheckBox(TR("Adjust layer mapping"), IfUpdateLayersMap ); + dlgStretch(1); + dlgPushButton("-" + TR("Help") + "...") + dlgDialog(TR("Import P-CAD/Altium/Protel (ACCEL ASCII)") + " - " + TR("Help")) { + dlgHBoxLayout dlgSpacing(900); + + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing (500); + dlgTextView( help[LangIdx] ); + } + + //dlgLabel(help[LangIdx]); + + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+" + TR("OK")) + dlgAccept(); + dlgStretch(1); + } + }; + dlgPushButton("+" + TR("Start")) { + nowstart = Execute(fname); + if (nowstart == 1) dlgAccept(); + } + dlgPushButton("-" + TR("Cancel")) { dlgReject(); exit(-1); } + } + }; + + if( PCBDesignToken ) + exit ("SCRIPT '" + SCRIPTfileName + "'; RATSNEST"); + exit ("SCRIPT '" + SCRIPTfileName +"';"); +} + diff --git a/trunk/ulp/import-bmp-c256.bmp b/trunk/ulp/import-bmp-c256.bmp new file mode 100644 index 00000000..9088534a Binary files /dev/null and b/trunk/ulp/import-bmp-c256.bmp differ diff --git a/trunk/ulp/import-bmp-dpi.bmp b/trunk/ulp/import-bmp-dpi.bmp new file mode 100644 index 00000000..e4cf8be6 Binary files /dev/null and b/trunk/ulp/import-bmp-dpi.bmp differ diff --git a/trunk/ulp/import-bmp-ratio.bmp b/trunk/ulp/import-bmp-ratio.bmp new file mode 100644 index 00000000..106aee52 Binary files /dev/null and b/trunk/ulp/import-bmp-ratio.bmp differ diff --git a/trunk/ulp/import-bmp-scale.bmp b/trunk/ulp/import-bmp-scale.bmp new file mode 100644 index 00000000..35271ea0 Binary files /dev/null and b/trunk/ulp/import-bmp-scale.bmp differ diff --git a/trunk/ulp/import-bmp.ulp b/trunk/ulp/import-bmp.ulp new file mode 100644 index 00000000..24a202c8 --- /dev/null +++ b/trunk/ulp/import-bmp.ulp @@ -0,0 +1,1035 @@ +#usage "en:
    Import a BitMaP image into an EAGLE drawing" + "

    " + "This ULP generates a SCRIPT file that draws rectangles of successional pixels with identical color.
    " + "These rectangles serve as templates in order to draw the image with EAGLE commands like POLYGON, WIRE, CIRCLE, TEXT.
    " + "Please note: If the generated rectangles are smaller than the half of the resolution of the output device, " + "(depending on the scale factor: screen: pixel, printer: diameter of the laser beam or ink jet dropplet), it is " + "not possible to display the result. Therefore use the EAGLE commands mentioned above to reduce the number of " + "elements (rectangles). Each element has to be drawn and calculated by the display device driver. The more elements " + "the slower the display will be.
    " + "The ULP accepts BitMaP files with a maximum of 256 colors. You are allowed to select a maximum of 32 of them. " + "[Scan used colors] detects the used number of colors in the image. You have to reduce them to a maximum of 32 " + "in the following dialog.
    " + "In the final dialog you can scale the image. Either in Dots per Inch (DPI), Pixel in the units Inch, " + "Mil, Millimeter, Micron, or as Aspect Ratio (the width of the image in pixels in X) in Inch, Mil, " + "Millimeter, Micron. " + "In the case of Aspect ratio, please keep in mind that there should not be pixels in a non-selected color on " + "the left or right boarder of the image. Otherwise the resulting width of the image is not the same as the calculated one.
    " + "The start layer for the template is set to 200. Each of the maximum of 32 selected colors will use a separate layer, " + "beginning with the start layer. So it is possible to have colored logos in the Schematic or Symbol Editor.
    " + "Reduce the number of colors of an image to two (black/white), if the logo shall be displayed monochrome in one of the copper " + "layers. As soon as the image (logo) is drawn with the EAGLE commands (see above) you may delete the template with GROUP DELETE " + "and a right mouse click. The layers can be removed with LAYER -number afterwards." + "

    " + "Author: support@cadsoft.de" + , + "de:Importiert ein BitMaP-Bild als Vorlage in eine EAGLE-Zeichnung" + "

    " + "Das ULP erzeugt eine SCRIPT-Datei, in der zusammenhängende gleichfarbige Pixel als Rechteck generiert werden.
    " + "Diese Rechtecke dienen als Vorlage, um das Bild mit EAGLE-Werkzeugen wie POLYGON, WIRE, CIRLE, TEXT zu definieren.
    " + "Bedenken Sie: Wenn die erzeugten Rechtecke kleiner sind als die Hälfte der Auflösung des Ausgabegerätes" + "(je nach Skalierungsfaktor: Bildschirm-Pixel, Drucker-Laserstrahlbreite oder Düsendurchmesser), kann das Ergebnis " + "nicht dargestellt werden. Definieren Sie deshalb feine Strukturen mit den oben erwähnten Werkzeugen, um die " + "Anzahl der Elemente (Rechtecke) zu reduzieren. Jedes Element muss vom Grafikkartentreiber gezeichnet und " + "berechnet werden. Bei sehr vielen Elementen wird die Anzeige entsprechend verlangsamt.
    " + "Es werden nur BitMaP-Dateien mit maximal 256 Farben akzeptiert. Davon kann man bis zu 32 Farben auswählen.
    " + "Mit [Scan used colors] können die benutzten Farben im Bild ermittelt werden. Im folgenden Menue muss man sie " + "auf maximal 32 reduzieren.
    " + "Im abschliessenden Menue kann die Skalierung gewählt werden. Entweder Dots per Inch (DPI) oder Pixel in " + "der Maßeinheit Inch, Mil, Millimeter, Micron oder Aspect Ratio (die Breite des Bildes Pixel in X) in Inch, " + "Mil, Millimeter, Micron." + "Bei Aspect ratio sollte darauf geachtet werden, dass im Bild links und rechts keine Pixel in einer " + "nichtgewählten Farbe vorkommen. Ansonsten stimmt die Breite des Endergebnisses nicht mit der berechneten Breite überein.
    " + "Der Startlayer für die Vorlage ist der Layer 200. Für jede, der bis zu max. 32 gewählten Farben, wird ein neuer Layer, " + "beginnend mit dem Sartlayer, angelegt. So kann ein Logo im Schaltplan (Symbol) auch farbig definiert werden.
    " + "Reduzieren Sie eine BitMaP auf 2 Farben (schwarz/weiss), wenn das Ergebnis in nur einer Farbe für einen Kupferlayer " + "dargestellt werden soll. Ist das Bild (Logo) mit EAGLE-Werkzeugen (siehe oben) definiert, können mit GROUP DELETE und rechter " + "Maustaste die 'Rechtecke' wieder gelöscht werden.
    Die Layer selbst können dann mit LAYER -nummer entfernt werden." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + + +// 1.0.3 - 2006-05-11 *** corrected for 4 bit (16 colors) *** alf@cadsoft.de +// only the first 4 of 16 colors was generated +// set cselmax to maximal included colors of BitMaP +// +// 1.0.4 - 2007-03-30 --- Coral Draw sets wrong Byte Address Range, check length with address range. +// +// 1.0.5 - 2009-10-27 --- show colors by background color (table) not with Bit-MAP +// 1.0.6 - 2010-05-20 --- showbmp() use Dialog to show complete image +// Images now can 1280 pixels use +// Check selected colors. +// + +string Version = "1.0.6"; + +// 2009-10-27 color definition in 16 color BitMap (4 bit) +string colorBox16[]; + colorBox16[000] = "#000000"; // 0000 0036 + colorBox16[001] = "#800000"; // 0004 003A + colorBox16[002] = "#008000"; // 0008 003E + colorBox16[003] = "#808000"; // 000C 0042 + colorBox16[004] = "#000080"; // 0010 0046 + colorBox16[005] = "#800080"; // 0014 004A + colorBox16[006] = "#008080"; // 0018 004E + colorBox16[007] = "#C0C0C0"; // 001C 0052 + colorBox16[008] = "#808080"; // 03E0 0416 + colorBox16[009] = "#FF0000"; // 03E4 041A + colorBox16[010] = "#00FF00"; // 03E8 041E + colorBox16[011] = "#FFFF00"; // 03EC 0422 + colorBox16[012] = "#0000FF"; // 03F0 0426 + colorBox16[013] = "#FF00FF"; // 03F4 042A + colorBox16[014] = "#00FFFF"; // 03F8 042E + colorBox16[015] = "#FFFFFF"; // 03FC 0432 + + +string colorBox[]; // colors of 8 bit / 256 color bit maplist + colorBox[000] = "#000000"; // 0000 0036 + colorBox[001] = "#800000"; // 0004 003A + colorBox[002] = "#008000"; // 0008 003E + colorBox[003] = "#808000"; // 000C 0042 + colorBox[004] = "#000080"; // 0010 0046 + colorBox[005] = "#800080"; // 0014 004A + colorBox[006] = "#008080"; // 0018 004E + colorBox[007] = "#C0C0C0"; // 001C 0052 + colorBox[008] = "#C0DCC0"; // 0020 0056 + colorBox[009] = "#A6CAF0"; // 0024 005A + colorBox[010] = "#402000"; // 0028 005E + colorBox[011] = "#602000"; // 002C 0062 + colorBox[012] = "#802000"; // 0030 0066 + colorBox[013] = "#A02000"; // 0034 006A + colorBox[014] = "#C02000"; // 0038 006E + colorBox[015] = "#E02000"; // 003C 0072 + colorBox[016] = "#004000"; // 0040 0076 + colorBox[017] = "#204000"; // 0044 007A + colorBox[018] = "#404000"; // 0048 007E + colorBox[019] = "#604000"; // 004C 0082 + colorBox[020] = "#804000"; // 0050 0086 + colorBox[021] = "#A04000"; // 0054 008A + colorBox[022] = "#C04000"; // 0058 008E + colorBox[023] = "#E04000"; // 005C 0092 + colorBox[024] = "#006000"; // 0060 0096 + colorBox[025] = "#206000"; // 0064 009A + colorBox[026] = "#406000"; // 0068 009E + colorBox[027] = "#606000"; // 006C 00A2 + colorBox[028] = "#806000"; // 0070 00A6 + colorBox[029] = "#A06000"; // 0074 00AA + colorBox[030] = "#C06000"; // 0078 00AE + colorBox[031] = "#E06000"; // 007C 00B2 + colorBox[032] = "#008000"; // 0080 00B6 + colorBox[033] = "#208000"; // 0084 00BA + colorBox[034] = "#408000"; // 0088 00BE + colorBox[035] = "#608000"; // 008C 00C2 + colorBox[036] = "#808000"; // 0090 00C6 + colorBox[037] = "#A08000"; // 0094 00CA + colorBox[038] = "#C08000"; // 0098 00CE + colorBox[039] = "#E08000"; // 009C 00D2 + colorBox[040] = "#00A000"; // 00A0 00D6 + colorBox[041] = "#20A000"; // 00A4 00DA + colorBox[042] = "#40A000"; // 00A8 00DE + colorBox[043] = "#60A000"; // 00AC 00E2 + colorBox[044] = "#80A000"; // 00B0 00E6 + colorBox[045] = "#A0A000"; // 00B4 00EA + colorBox[046] = "#C0A000"; // 00B8 00EE + colorBox[047] = "#E0A000"; // 00BC 00F2 + colorBox[048] = "#00C000"; // 00C0 00F6 + colorBox[049] = "#20C000"; // 00C4 00FA + colorBox[050] = "#40C000"; // 00C8 00FE + colorBox[051] = "#60C000"; // 00CC 0102 + colorBox[052] = "#80C000"; // 00D0 0106 + colorBox[053] = "#A0C000"; // 00D4 010A + colorBox[054] = "#C0C000"; // 00D8 010E + colorBox[055] = "#E0C000"; // 00DC 0112 + colorBox[056] = "#00E000"; // 00E0 0116 + colorBox[057] = "#20E000"; // 00E4 011A + colorBox[058] = "#40E000"; // 00E8 011E + colorBox[059] = "#60E000"; // 00EC 0122 + colorBox[060] = "#80E000"; // 00F0 0126 + colorBox[061] = "#A0E000"; // 00F4 012A + colorBox[062] = "#C0E000"; // 00F8 012E + colorBox[063] = "#E0E000"; // 00FC 0132 + colorBox[064] = "#000040"; // 0100 0136 + colorBox[065] = "#200040"; // 0104 013A + colorBox[066] = "#400040"; // 0108 013E + colorBox[067] = "#600040"; // 010C 0142 + colorBox[068] = "#800040"; // 0110 0146 + colorBox[069] = "#A00040"; // 0114 014A + colorBox[070] = "#C00040"; // 0118 014E + colorBox[071] = "#E00040"; // 011C 0152 + colorBox[072] = "#002040"; // 0120 0156 + colorBox[073] = "#202040"; // 0124 015A + colorBox[074] = "#402040"; // 0128 015E + colorBox[075] = "#602040"; // 012C 0162 + colorBox[076] = "#802040"; // 0130 0166 + colorBox[077] = "#A02040"; // 0134 016A + colorBox[078] = "#C02040"; // 0138 016E + colorBox[079] = "#E02040"; // 013C 0172 + colorBox[080] = "#004040"; // 0140 0176 + colorBox[081] = "#204040"; // 0144 017A + colorBox[082] = "#404040"; // 0148 017E + colorBox[083] = "#604040"; // 014C 0182 + colorBox[084] = "#804040"; // 0150 0186 + colorBox[085] = "#A04040"; // 0154 018A + colorBox[086] = "#C04040"; // 0158 018E + colorBox[087] = "#E04040"; // 015C 0192 + colorBox[088] = "#006040"; // 0160 0196 + colorBox[089] = "#206040"; // 0164 019A + colorBox[090] = "#406040"; // 0168 019E + colorBox[091] = "#606040"; // 016C 01A2 + colorBox[092] = "#806040"; // 0170 01A6 + colorBox[093] = "#A06040"; // 0174 01AA + colorBox[094] = "#C06040"; // 0178 01AE + colorBox[095] = "#E06040"; // 017C 01B2 + colorBox[096] = "#008040"; // 0180 01B6 + colorBox[097] = "#208040"; // 0184 01BA + colorBox[098] = "#408040"; // 0188 01BE + colorBox[099] = "#608040"; // 018C 01C2 + colorBox[100] = "#808040"; // 0190 01C6 + colorBox[101] = "#A08040"; // 0194 01CA + colorBox[102] = "#C08040"; // 0198 01CE + colorBox[103] = "#E08040"; // 019C 01D2 + colorBox[104] = "#00A040"; // 01A0 01D6 + colorBox[105] = "#20A040"; // 01A4 01DA + colorBox[106] = "#40A040"; // 01A8 01DE + colorBox[107] = "#60A040"; // 01AC 01E2 + colorBox[108] = "#80A040"; // 01B0 01E6 + colorBox[109] = "#A0A040"; // 01B4 01EA + colorBox[110] = "#C0A040"; // 01B8 01EE + colorBox[111] = "#E0A040"; // 01BC 01F2 + colorBox[112] = "#00C040"; // 01C0 01F6 + colorBox[113] = "#20C040"; // 01C4 01FA + colorBox[114] = "#40C040"; // 01C8 01FE + colorBox[115] = "#60C040"; // 01CC 0202 + colorBox[116] = "#80C040"; // 01D0 0206 + colorBox[117] = "#A0C040"; // 01D4 020A + colorBox[118] = "#C0C040"; // 01D8 020E + colorBox[119] = "#E0C040"; // 01DC 0212 + colorBox[120] = "#00E040"; // 01E0 0216 + colorBox[121] = "#20E040"; // 01E4 021A + colorBox[122] = "#40E040"; // 01E8 021E + colorBox[123] = "#60E040"; // 01EC 0222 + colorBox[124] = "#80E040"; // 01F0 0226 + colorBox[125] = "#A0E040"; // 01F4 022A + colorBox[126] = "#C0E040"; // 01F8 022E + colorBox[127] = "#E0E040"; // 01FC 0232 + colorBox[128] = "#000080"; // 0200 0236 + colorBox[129] = "#200080"; // 0204 023A + colorBox[130] = "#400080"; // 0208 023E + colorBox[131] = "#600080"; // 020C 0242 + colorBox[132] = "#800080"; // 0210 0246 + colorBox[133] = "#A00080"; // 0214 024A + colorBox[134] = "#C00080"; // 0218 024E + colorBox[135] = "#E00080"; // 021C 0252 + colorBox[136] = "#002080"; // 0220 0256 + colorBox[137] = "#202080"; // 0224 025A + colorBox[138] = "#402080"; // 0228 025E + colorBox[139] = "#602080"; // 022C 0262 + colorBox[140] = "#802080"; // 0230 0266 + colorBox[141] = "#A02080"; // 0234 026A + colorBox[142] = "#C02080"; // 0238 026E + colorBox[143] = "#E02080"; // 023C 0272 + colorBox[144] = "#004080"; // 0240 0276 + colorBox[145] = "#204080"; // 0244 027A + colorBox[146] = "#404080"; // 0248 027E + colorBox[147] = "#604080"; // 024C 0282 + colorBox[148] = "#804080"; // 0250 0286 + colorBox[149] = "#A04080"; // 0254 028A + colorBox[150] = "#C04080"; // 0258 028E + colorBox[151] = "#E04080"; // 025C 0292 + colorBox[152] = "#006080"; // 0260 0296 + colorBox[153] = "#206080"; // 0264 029A + colorBox[154] = "#406080"; // 0268 029E + colorBox[155] = "#606080"; // 026C 02A2 + colorBox[156] = "#806080"; // 0270 02A6 + colorBox[157] = "#A06080"; // 0274 02AA + colorBox[158] = "#C06080"; // 0278 02AE + colorBox[159] = "#E06080"; // 027C 02B2 + colorBox[160] = "#008080"; // 0280 02B6 + colorBox[161] = "#208080"; // 0284 02BA + colorBox[162] = "#408080"; // 0288 02BE + colorBox[163] = "#608080"; // 028C 02C2 + colorBox[164] = "#808080"; // 0290 02C6 + colorBox[165] = "#A08080"; // 0294 02CA + colorBox[166] = "#C08080"; // 0298 02CE + colorBox[167] = "#E08080"; // 029C 02D2 + colorBox[168] = "#00A080"; // 02A0 02D6 + colorBox[169] = "#20A080"; // 02A4 02DA + colorBox[170] = "#40A080"; // 02A8 02DE + colorBox[171] = "#60A080"; // 02AC 02E2 + colorBox[172] = "#80A080"; // 02B0 02E6 + colorBox[173] = "#A0A080"; // 02B4 02EA + colorBox[174] = "#C0A080"; // 02B8 02EE + colorBox[175] = "#E0A080"; // 02BC 02F2 + colorBox[176] = "#00C080"; // 02C0 02F6 + colorBox[177] = "#20C080"; // 02C4 02FA + colorBox[178] = "#40C080"; // 02C8 02FE + colorBox[179] = "#60C080"; // 02CC 0302 + colorBox[180] = "#80C080"; // 02D0 0306 + colorBox[181] = "#A0C080"; // 02D4 030A + colorBox[182] = "#C0C080"; // 02D8 030E + colorBox[183] = "#E0C080"; // 02DC 0312 + colorBox[184] = "#00E080"; // 02E0 0316 + colorBox[185] = "#20E080"; // 02E4 031A + colorBox[186] = "#40E080"; // 02E8 031E + colorBox[187] = "#60E080"; // 02EC 0322 + colorBox[188] = "#80E080"; // 02F0 0326 + colorBox[189] = "#A0E080"; // 02F4 032A + colorBox[190] = "#C0E080"; // 02F8 032E + colorBox[191] = "#E0E080"; // 02FC 0332 + colorBox[192] = "#0000C0"; // 0300 0336 + colorBox[193] = "#2000C0"; // 0304 033A + colorBox[194] = "#4000C0"; // 0308 033E + colorBox[195] = "#6000C0"; // 030C 0342 + colorBox[196] = "#8000C0"; // 0310 0346 + colorBox[197] = "#A000C0"; // 0314 034A + colorBox[198] = "#C000C0"; // 0318 034E + colorBox[199] = "#E000C0"; // 031C 0352 + colorBox[200] = "#0020C0"; // 0320 0356 + colorBox[201] = "#2020C0"; // 0324 035A + colorBox[202] = "#4020C0"; // 0328 035E + colorBox[203] = "#6020C0"; // 032C 0362 + colorBox[204] = "#8020C0"; // 0330 0366 + colorBox[205] = "#A020C0"; // 0334 036A + colorBox[206] = "#C020C0"; // 0338 036E + colorBox[207] = "#E020C0"; // 033C 0372 + colorBox[208] = "#0040C0"; // 0340 0376 + colorBox[209] = "#2040C0"; // 0344 037A + colorBox[210] = "#4040C0"; // 0348 037E + colorBox[211] = "#6040C0"; // 034C 0382 + colorBox[212] = "#8040C0"; // 0350 0386 + colorBox[213] = "#A040C0"; // 0354 038A + colorBox[214] = "#C040C0"; // 0358 038E + colorBox[215] = "#E040C0"; // 035C 0392 + colorBox[216] = "#0060C0"; // 0360 0396 + colorBox[217] = "#2060C0"; // 0364 039A + colorBox[218] = "#4060C0"; // 0368 039E + colorBox[219] = "#6060C0"; // 036C 03A2 + colorBox[220] = "#8060C0"; // 0370 03A6 + colorBox[221] = "#A060C0"; // 0374 03AA + colorBox[222] = "#C060C0"; // 0378 03AE + colorBox[223] = "#E060C0"; // 037C 03B2 + colorBox[224] = "#0080C0"; // 0380 03B6 + colorBox[225] = "#2080C0"; // 0384 03BA + colorBox[226] = "#4080C0"; // 0388 03BE + colorBox[227] = "#6080C0"; // 038C 03C2 + colorBox[228] = "#8080C0"; // 0390 03C6 + colorBox[229] = "#A080C0"; // 0394 03CA + colorBox[230] = "#C080C0"; // 0398 03CE + colorBox[231] = "#E080C0"; // 039C 03D2 + colorBox[232] = "#00A0C0"; // 03A0 03D6 + colorBox[233] = "#20A0C0"; // 03A4 03DA + colorBox[234] = "#40A0C0"; // 03A8 03DE + colorBox[235] = "#60A0C0"; // 03AC 03E2 + colorBox[236] = "#80A0C0"; // 03B0 03E6 + colorBox[237] = "#A0A0C0"; // 03B4 03EA + colorBox[238] = "#C0A0C0"; // 03B8 03EE + colorBox[239] = "#E0A0C0"; // 03BC 03F2 + colorBox[240] = "#00C0C0"; // 03C0 03F6 + colorBox[241] = "#20C0C0"; // 03C4 03FA + colorBox[242] = "#40C0C0"; // 03C8 03FE + colorBox[243] = "#60C0C0"; // 03CC 0402 + colorBox[244] = "#80C0C0"; // 03D0 0406 + colorBox[245] = "#A0C0C0"; // 03D4 040A + colorBox[246] = "#FFFBF0"; // 03D8 040E + colorBox[247] = "#A0A0A4"; // 03DC 0412 + colorBox[248] = "#808080"; // 03E0 0416 + colorBox[249] = "#FF0000"; // 03E4 041A + colorBox[250] = "#00FF00"; // 03E8 041E + colorBox[251] = "#FFFF00"; // 03EC 0422 + colorBox[252] = "#0000FF"; // 03F0 0426 + colorBox[253] = "#FF00FF"; // 03F4 042A + colorBox[254] = "#00FFFF"; // 03F8 042E + colorBox[255] = "#FFFFFF"; // 03FC 0432 + + + +string script_path; +string bmpcolor[]; +string bmps[]; + +string run_info = " "; +string fileName; +int nBytes = 0; // count bytes of file (fileName) +int ColorBits = 0; // used bits for color +int AdrStart, AdrEnd = 0; // Start & End of BITMAP-Data +int length = 0; // length of bmp-Data +int Byte4Group = 0; // bmp-Data organized as 4-byte groups +int Layer = 200; // 1st used layer +real xScale = 1; // scale x +real yScale = 1; // scale y +int X = 0; // count pixels x +int Y = 0; // count pixels y +string xy = ""; +int colorscan = 0; // flag for color scanning +int cselmax = 32; // max 32 colors selectable +int Result = 0; + +real Offset = .5; // offset Wire width + +int mBit[]; // bit line for operating + +string grid[] = { "INCH", // grid units + "MIL", + "MM", + "MIC" + }; +int unit = 1; // default unit = mil +int scaled = 1; // flag for DPI Scale Ratio +real vmin[] = { 0.00001, 0.001, 0.0001, 0.1 }; +real vmax[] = { 30.0, 3000.0, 800.0, 800000.0 } ; + +string Grid = grid[unit]; // default grid + + // get parameter PDI, Scale, Aspect Ratio, mic, mm, mil INCH ... + string menuedlg[] = { + "Dots Per INCH", + "Scale factor for a pixel", + "Aspect/Ratio m" + } ; + string menuval0[] = { + "&Value between 1 and 10000 dots", + "&Value between 0.01 and 30.0 Inch", + "&Value between 0.01 and 30.0 Inch" + }; + + string menuval1[] = { + "&Value between 1 and 10000 dots", + "&Value between 0.001 and 3000.0 mil", + "&Value between 0.001 and 3000.0 mil" + }; + string menuval2[] = { + "&Value between 1 and 10000 dots", + "&Value between 0.0001 and 800.0 mm", + "&Value between 0.0001 and 800.0 mm" + }; + string menuval3[] = { + "&Value between 1 and 10000 dots", + "&Value between 0.1 and 800000.0 micron", + "&Value between 0.1 and 800000.0 micron" + }; +string menulbl = menuedlg[1]; +string menuinfo = menuval1[1]; +string ratiologo ; + + +// table of used colors in BitMaP +int colorUsed[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0 + }; + +int colorSelect[] ; +char c[]; // the file as Byte-Array + +// set / clear all colorUsed flags +void setall(int set) { + for(int n = 0; n < pow(2, ColorBits); n++) { + colorUsed[n] = set; + } + return; +} + +void ScriptLine(int Line) { + // *** corrected for 4 bit (16 colors) *** 2006.05.11 alf@cadsoft.de + for(int cs = 0; cs < cselmax; cs++) { // extract max 32 colors + sprintf(run_info, "%d Line %d Color #%d ", Y, Line, cs); + dlgRedisplay(); + if(colorSelect[cs] > -1) { // -1 color not used + int lineColor = colorSelect[cs]; // extraction color + int line = 0; + printf("change layer %d;\n", Layer + cs); + for(int z = 0; z < X; z++) { + if(mBit[z] == lineColor) { // if color used + if(line == 0) { // start of line in script (rectangle) + printf("RECT (%.4f ", (z - Offset) * xScale); + printf("%.5f)", (Line - Offset) * yScale); + line = 1; + } + } + else { + if(line == 1) { + printf( "(%.4f ", (z - Offset) * xScale); + // end of line in script (rectangle) + printf( "%.5f);\n", (Line + Offset) * yScale); + line = 0; + } + } + } + if(line == 1) { + printf( "(%.4f ", (z - Offset) * xScale); + // end of line in script(rectangle) + printf( "%.5f);\n", (Line + Offset) * yScale); + line = 0; + } + } + } + return; +} + +// Generate Script from BitMaP +void GenScript(void) { + int xByte = 4 * Byte4Group; // organised by groups of 4 bytes + int bmpBits; + + for(int yRead = 0; yRead < Y; yRead++) { // counter for lines / Y + for(int xRead = 0; xRead < xByte; xRead ++) { + bmpBits = c[AdrStart + yRead * xByte + xRead]; + + switch (ColorBits) { + case 1 : for(int bitcnt = 7; bitcnt > -1; bitcnt--) { + mBit[(xRead * 8) + (7 - bitcnt)] = bmpBits; + mBit[(xRead * 8) + (7 - bitcnt)] >>= bitcnt; + mBit[(xRead * 8) + (7 - bitcnt)] &= 0X1; + } + break; + + case 4 : mBit[xRead * 2 ] = bmpBits; + mBit[xRead * 2 + 1] = bmpBits; + mBit[xRead * 2 ] >>= 4; + mBit[xRead * 2 + 1] &= 0x0f; + break; + + case 8 : mBit[xRead] = bmpBits; + break; + } + + } + if(colorscan) { + for(int z = 0; z < X; z++) { + colorUsed[mBit[z]]++; // set flag for used color + } + } + else { + ScriptLine(yRead); // generate Eagle Script line + } + } + return; +} + +// bmp file info +string bmpDaten(void) { // diagnostics + string st = ""; + string cmd = ""; + printf( "BitMaP Start \t = %d\n", AdrStart); + cmd = st; + printf( "BitMaP End \t = %d\n", AdrEnd); + cmd += st; + printf( "BitMaP length \t = %d\n", length); + cmd += st; + printf( "high / pixel - Y \t = %d\n", Y); + cmd += st; + printf( "wide / pixel - X \t = %d\n", X); + cmd += st; + printf( "4-Byte Group(s) \t = %d\n", Byte4Group); + cmd += st; + printf( "Bits / Color \t = %d (Colors %.0f)\n", ColorBits, pow(2, ColorBits)); + cmd += st; + printf( "File length \t = %d\n", nBytes); + cmd += st; + return cmd; +} + +// Select menu for 2 color BitMaP +void Cselect2(void) { + Result = dlgDialog("Select used colors in " + fileName) { + // 2009-10-27 + dlgHBoxLayout { + dlgStretch(1); + dlgGridLayout { + dlgCell(1, 1) dlgCheckBox("", colorUsed[0]); + dlgCell(2, 1) dlgLabel("
       
    "); + dlgCell(1, 2) dlgCheckBox("", colorUsed[1]); + dlgCell(2, 2) dlgLabel("
       
    "); + } + dlgStretch(1); + } + dlgStretch(0); + dlgSpacing(20); + dlgLabel(" Select up to 2 colors "); + dlgStretch(0); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgPushButton("&Set all") setall(1); + dlgPushButton("&Clear all") setall(0); + } + dlgStretch(1); + }; + if (Result == 0) exit (0); + return; +} + +// Select menu for 16 color BitMaP +void Cselect16(void) { + Result = dlgDialog("Select used colors" + fileName) { + dlgStretch(0); + // 2009-10-27 + dlgGridLayout { + for (int colum = 0 ; colum < 16; colum++) { + dlgCell(1, colum) dlgCheckBox("", colorUsed[colum]); + string s; + sprintf(s, "
       
    ", colorBox16[colum]); + dlgCell(2, colum) dlgLabel(s); + } + } + + dlgStretch(0); + dlgSpacing(20); + dlgLabel(" Select up to 16 colors "); + dlgStretch(0); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgPushButton("&set all") { setall(1); dlgRedisplay();} + dlgPushButton("&clear all") { setall(0); dlgRedisplay();} + } + dlgStretch(1); + }; + if (Result == 0) exit (0); + return; +} + +// Select menu for 256 color BitMaP +void Cselect256(void) { + Result = dlgDialog("Select used colors " + fileName) { + // 2009-10-27 + dlgGridLayout { + for (int row = 0 ; row < 16; row++) { + for (int colum = 0 ; colum < 16; colum++) { + dlgCell(2*row, colum) dlgCheckBox("", colorUsed[row * 16 + colum]); + string s; + sprintf(s, "
       
    ", colorBox[row*16+colum]); + dlgCell(2*row + 1, colum) dlgLabel(s); + } + } + } + dlgVBoxLayout { + dlgStretch(0); + dlgSpacing(20); + string hc; + sprintf( hc, " Select up to %d colors ", cselmax); + dlgLabel(hc); + dlgStretch(0); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(0); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgPushButton("&set all") setall(1); + dlgStretch(0); + dlgPushButton("&clear all") setall(0); + dlgStretch(0); + } + dlgStretch(1); + } + dlgStretch(1); + }; + if (Result == 0) exit (0); + return; +} + +// select colors +int selectColors(void) { + switch (ColorBits) { + case 1 : cselmax = 2; // 2006.05.11 set max color for 2 colors + Cselect2(); + break; + case 4 : cselmax = 16; // 2006.05.11 set max color for 16 colors + Cselect16(); + break; + case 8 : Cselect256(); + break; + } + for(int n = 0; n < cselmax; n++) { + colorSelect[n] = -1; // reset selected colors + } + int cs; + for(int s = 0; s < 256; s++) { + if(colorUsed[s]) { + colorSelect[cs] = s; + cs++; + } + } + return cs; +} + +// select colors by scan array +void selectMenue() { + int cs; + do { + cs = selectColors(); + string hx; + if (cs > cselmax) { + sprintf( hx, "Do not use more than %d colors!", cselmax); + dlgMessageBox(hx, "OK"); + } + if (cs < 1) { + sprintf( hx, "No colors selected!"); // 2010-05-20 alf@cadsoft.de + dlgMessageBox(hx, "OK"); + } + } while (cs > cselmax || cs == 0); + return; +} + +// header from Script, define Layer +void scriptheader(void) { + printf("# generated with %s %s\n", argv[0], Version); + printf("# from %s\n", fileName); + printf("Grid %s %.6f ON;\n", Grid, xScale); + + for(int cs = 0; cs < cselmax; cs++) { // max 32 color extract + if(colorSelect[cs] > -1) { + if(Layer + cs > 99){ // user defined layer + printf( "LAYER %d %dbmp;\n", Layer + cs, Layer + cs); + printf( "SET FILL_LAYER %d 10;\n", Layer + cs); + printf( "SET COLOR_LAYER %d %d;\n", Layer + cs, cs + 1); + } + } + } + printf( "CHANGE LAYER %d;\n", Layer); + printf("SET UNDO_LOG OFF;\n"); + return; +} + +// get flag for scan colors +int scan(void) { + if (ColorBits == 1) return 0; + return (dlgDialog(filename(argv[0])) { + string st; + sprintf(st, "%s:

    is a %.0f color BitMAP : ist eine %.0f-Farben-BitMAP", + fileName, pow(2, ColorBits), pow(2, ColorBits) + ); + dlgHBoxLayout { + dlgStretch(0); + dlgVBoxLayout { + dlgGroup("Info") { + dlgLabel(st); + if (ColorBits == 4) { + dlgGridLayout { + for (int colum = 0 ; colum < 16; colum++) { + string s; + sprintf(s, "
       
    ", colorBox16[colum]); + dlgCell(1, colum) dlgLabel(s); + } + } + } + else dlgLabel(bmpcolor[ColorBits]); + } + dlgLabel(" ULP-Version " + Version); + dlgGroup("") { + dlgStretch(1); + dlgHBoxLayout { + dlgPushButton("+Scan used colors") dlgAccept(); + dlgStretch(1); + dlgPushButton("-No scan") dlgReject(); + dlgStretch(1); + dlgPushButton("Cancel") { dlgReject(); exit(0); } + } + dlgStretch(0); + } + dlgStretch(1); + } + dlgStretch(1); + } + dlgStretch(1); + } ); +} + +void colors24(void) { + string st = "bmp file contains more than 256 colors, reduce colors before use.\n\n" + + "Die benutzte Anzahl der Farben in der bmp-Datei ist groesser 256.\n" + + "Verringern Sie zuerst die Anzahl der Farben in der bmp-Datei.\n\n"; + dlgMessageBox(st, "&OK"); + return; +} + +void menuchange(void) { + menulbl = menuedlg[scaled]; + switch (scaled) { + case 0 : ratiologo = ""; + break; + case 1 : ratiologo = ""; + break; + case 2 : ratiologo = ""; + break; + } + + switch (unit) { + case 0 : menuinfo = menuval0[scaled]; + break; + case 1 : menuinfo = menuval1[scaled]; + break; + case 2 : menuinfo = menuval2[scaled]; + break; + case 3 : menuinfo = menuval3[scaled]; + break; + } + return ; +} + +//--------------------------------- +void set_scale(void) { + switch(scaled) { + case 0 : Grid = grid[0]; + yScale = 1 / xScale; // Dots Per Inch + xScale = yScale; + break; + + case 1 : Grid = Grid = grid[unit]; + yScale = xScale; + break; + + case 2 : Grid = Grid = grid[unit]; + yScale = xScale / X; // Aspect Ratio = Width / Pixel X + xScale = yScale; + break; + } + return; +} + + +void imp_bmp(void) { + colorscan = 0; // reset scanning mode + menuinfo = "Dot scale"; + scriptheader(); + GenScript(); // generate script string + + printf("SET UNDO_LOG ON;\n"); + printf("WINDOW FIT;\n"); + printf( "Change Size %.4f;\n", yScale * 2); + printf("CHANGE FONT VECTOR;\n"); + printf( "TEXT '" + fileName + "' (0 %.4f);\n", -5 * yScale ); + return; +} + + +void runscript(void) { + string script; + int s = fileread(script, script_path + "bmp.scr"); + Result = dlgDialog("Accept Script?") { + dlgHBoxLayout dlgSpacing(300); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(300); + dlgTextEdit(script); + } + dlgLabel(" ULP-Version " + Version); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+Run script") dlgAccept(); + dlgStretch(1); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + } + }; + + if (Result == 1) exit ("script '" + script_path + "bmp.scr'"); + else exit (0); +} + + +void showbmp() { + if ( X <= 1280 && Y <= 1280) { + dlgDialog("File:'" + fileName + "'") { + dlgLabel(""); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("OK") dlgAccept(); + dlgStretch(1); + } + }; + } + else dlgMessageBox("The BMP-File is to big to print complete on screen!", "OK"); + return; +} + + +if (schematic) { + schematic(S) { + script_path = filedir(S.name); + } +} +if (board) { + board(B) { + script_path = filedir(B.name); + } +} +if (library) { + library(L) { + script_path = filedir(L.name); + } +} + + +int check_max(void) { + if (X * xScale > vmax[unit] || Y * yScale > vmax[unit]) { + string e; + sprintf(e, "The Value of X (%.4f) or Y (%.4f) is grater then EAGLE maximum coordinate range %.4f %s", X * xScale, Y * yScale, vmax[unit], grid[unit]); + dlgMessageBox(e, "OK"); + return 0; + } + return 1; +} + +// ***************** main **************** +dlgMessageBox(usage, "OK"); + +void main(void) { + ratiologo = ""; + +// bmpcolor[1] = ""; +// bmpcolor[4] = ""; + bmpcolor[8] = ""; + +// bmps[0] = ""; +// bmps[1] = ""; +// bmps[2] = ""; +// bmps[3] = "", +// bmps[4] = ""; +// bmps[5] = ""; +// bmps[6] = ""; +// bmps[7] = ""; + + fileName = dlgFileOpen("Select a bmp file", "", "*.bmp"); + if (fileName == "") exit (0); + run_info = "Import File : " + filename(fileName); + nBytes = fileread(c, fileName); // read file in array + + // up to 31 bytes - not all used + if(c[0] != 'B') { + dlgMessageBox(fileName + ":\nis not a bmp file.\n\nist keine bmp-Datei.", "OK"); + exit(0); + } + if(c[1] != 'M') { + dlgMessageBox(fileName + ":\nis not a bmp file.\n\nist keine bmp-Datei.", "OK"); + exit(0); + } + if(c[21] > 0) { + dlgMessageBox(fileName + ":\nToo many pixels in x direction\n" + + "\nAnzahl der Pixel in X zu gross\n", "OK"); + exit (0); + } + if(c[25] > 0) { + dlgMessageBox(fileName + ":\nToo many pixels y direction\n" + + "\nAnzahl der Pixel in Y zu gross\n", "OK"); + exit (0); + } + // case 6 TO 9, 14 TO 17 not used + + ColorBits = c[28]; // counter of ColorBits + + if(ColorBits > 8) { + colors24(); // to many colors, break + exit(0); + } + + AdrEnd = c[2] + c[3] * 256 + c[4] * 256 * 256 + c[5] * 256 * 256 * 256; + AdrStart = c[10]+ c[11] * 256 + c[12] * 256 * 256 + c[13] * 256 * 256 * 256; + X = c[18] + c[19] * 256 + c[20] * 65536 + c[21] * 256 * 256 * 256; + Y = c[22] + c[23] * 256 + c[24] * 65536 + c[25] * 256 * 256 * 256; + sprintf(xy, " X = %5d Pixel\n Y = %5d Pixel", X, Y); + + length = AdrEnd - AdrStart; // BitMaP length + Byte4Group = length / Y / 4; + + /*** 2007.03.30 Coral-Draw sets wrong address range in Byte upper Byte 18 (22 = $14) ***/ + if (X > length || Y > length) { + dlgMessageBox("!BitMaP Format Error in Adress-Range (Byte 18+19+20 and 22+23+24) from:\n" + fileName + + "\n\nCheck this bytes or load the BMP-File in Windows Paint-Brush and save it.", + "OK"); + exit(-1); + } + + if(scan()) { // first scan used colors + colorscan = 1; + GenScript(); + } + + selectMenue(); + + //--------------------------------- + int d = 1; + while(d) { + dlgDialog("Info "+ fileName) { + dlgLabel(" ULP-Version " + Version); + dlgHBoxLayout { + dlgVBoxLayout { + dlgGroup("File data") { + dlgLabel(xy, 1); + } + dlgLabel(ratiologo, 1); + dlgStretch(1); + } + dlgVBoxLayout { + dlgGroup("Format") { + dlgRadioButton("&DPI", scaled) { unit = 0; menuchange(); } + dlgRadioButton("&Scaled", scaled) {menuchange(); } + dlgRadioButton("&Aspect/Ratio m ", scaled) { menuchange(); } + } + dlgGroup("Unit") { + dlgRadioButton("&Inch", unit) { menuchange(); dlgRedisplay();} + dlgRadioButton("Mi&l", unit) { if ( scaled == 0) scaled = 1; menuchange(); } + dlgRadioButton("&MM", unit) { if ( scaled == 0) scaled = 1; menuchange(); } + dlgRadioButton("Mi&cron", unit) { if ( scaled == 0) scaled = 1; menuchange(); } + } + dlgPushButton("S&elected colors") selectMenue(); + dlgStretch(1); + } + } + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel(menulbl, 1); + dlgLabel(menuinfo, 1); + dlgHBoxLayout { + dlgRealEdit(xScale, vmin[unit], vmax[unit]); + dlgSpacing(100); + } + dlgSpacing(10); + dlgLabel("Choose start layer for &1st selected color"); + dlgHBoxLayout { + dlgSpinBox(Layer, 1, 255); + dlgSpacing(100); + } + } + dlgStretch(1); + } + dlgStretch(1); + dlgLabel(run_info, 1); + dlgHBoxLayout { + dlgPushButton("+OK") { + set_scale(); + if (check_max()) { // check of maximum EAGLE coodinates + dlgAccept(); + output(script_path + "bmp.scr", "wtD") { + d = 0; + imp_bmp(); + } + runscript(); + } + } + dlgStretch(1); + dlgPushButton("-Cancel") exit(0); + dlgPushButton("show &BitMaP") showbmp(); + } + }; + } +} + diff --git a/trunk/ulp/import-dxf.ulp b/trunk/ulp/import-dxf.ulp new file mode 100644 index 00000000..21cab70c --- /dev/null +++ b/trunk/ulp/import-dxf.ulp @@ -0,0 +1,1037 @@ +#usage "DXFimport V1.7

    " + "This ULP can import DXF files that include polylines.
    " + "Browse to the DXF file, setup your origins, input units, scale factor and linewidth then click convert. " + "The ULP will then show you the script in case you want to change the layer the input will be written to.
    " + "Tested in version 5, 6, 7.
    " + "author Written by Jorge Garcia of Cadsoft Computer, heavily based off of Hank Wallace's DXF2SCR program.
    " + "With special thanks to Robert Starr, Alfred Zaffran, Billy Coleman and Holger Moessinger." + +string Version = "1.7"; + +string Help = "DXFimport "+Version+ "\n

    This ULP will import a DXF \ +file into EAGLE (Board, Schematic, Package or Symbol-Editor). \ +Use the browse button to find the DXF file, make sure to set \ +the units to whatever units are used by the DXF file. Set the width, Xorg, and \ +Yorg in whatever units you selected. Then set an appropriate scale factor and \ +click the OK button, the generated script will be shown for editing. Once \ +it's adjusted to your liking click Run.

    "; + +/* ******************************************************************* + REVISION HISTORY + +2012-03-03 Initial Release. + +2012-06-19 Finally incorporated Holger Moessinger's improvements to + the polygon import, added him to special thanks section. + +2012-07-10 Added support for LWPOLYLINE. + +2013-02-13 Check maximum coodinate of eagle, Alfred Zaffran. This + feature keeps track of the size of the DXF file, if it's + outside the drawing limits of EAGLE the ULP will recognize + this and suggest a corrective offset which the user can + approve. + +2013-06-12 Discovered that some files don't implement the proper + spacing so I modified the ULP to cope with that. + +2014-03-12 Implemented the ability to skip the section search state. + Some DXF files don't have an ENTITIES section which the old + ULP expected. This allows the ULP to try going through the + file again without expecting an ENTITIES section. The + downside is that some extraneous stuff may come in on the + import but usually the user will be able to tell and remove + those features. The generated script file has a comment + added to it when EAGLE uses that feature. + +2014-03-12 Assimilated Billy Coleman's scaling functionality. Added + him to the thank you list in the description. + +2014-03-13 Implemented a flag in the LWPOLYLINE state of dxf() to + make sure the state isn't exited, before processing the + object. Similar improvements where made in the VERTEX + state of DXF. + +2015-02-10 make target layer selectable alf@cadsoft.de + +********************************************************************* */ + +/* *********************************************************************** +Below I have retained Mr. Wallace's original "licensing" statement for two +reasons: + 1. As a sign of respect for the original author of the code from which this + ULP was developed and without which it would have not been possible to + develop this ULP. + 2. This is quite possibly the funniest licensing statement any one will + ever read. + +Officially though, I will license this under the MIT open software license +copied below: + +Copyright (c) 2012 Newark, Premier Farnell DBA Cadsoft Computer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to +do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Jorge Garcia +03-Mar-2012 + +---------------------------------------------------------------------- +DXF2SCR.C + +Program that crunches a DXF file with circles, arcs and lines into an +Eagle script file, useful for translating board outlines. + +Hank Wallace 20-Mar-03 +Revision 20-Mar-03 + +There are two licensing options for this program: + +1. If you are a fan of the GNU license, and you think you +understand it, and you think it is reasonable, and you believe +that 'free to download' means 'high quality' or 'low maintenance +cost', and you are a computer geek who cannot get a date who +measures the value of his/her existence by the number of +marginally useful command line options you can stuff into one +program on a lonely Friday night, and you write C source code in +such a manner that there are more #define'd constants and +conditional compilation directives than there are actual C +source statements, and you attempt to make your programs so +'portable' that they runs on no machine whatsoever without +modification, then you have no license to use this software. Get +a life. + +2. If you one of the other 6 billion people on planet Earth, +this program source code and executable is free for your use +without restriction, but NO WARRANTY OR SUPPORT IS GIVEN. + +This program compiles under Microsoft's command line compiler, version 12.00. +----------------------------------------------------------------------------- +************************************************************************** */ + +/* ************************************************************************ +* GLOBAL VARIABLES +************************************************************************** */ +// #include "/home/cadsoft/eagle/debug.ulp" + +string ConfigFileName = filesetext(argv[0], ".cfg"); + +real XMax; /* Maximum dimensions of DXF file */ +real YMax; +real XMin; +real YMin; +real Exmax = REAL_MAX; /* Maximum dimensions EAGLE can draw in um */ +real Eymax = REAL_MAX; +real Exmin = -REAL_MAX; +real Eymin = -REAL_MAX; +real S_factor; +real GUI_scale = 1.0; /* Additional scale factor that can be used to resize dxf */ +int GUI_in_unit = 0; +int GUI_scaled_Xorg = 0; /* Checkbox variables */ +int GUI_scaled_Yorg = 0; +int GUI_scaled_lwidth = 0; +string GUI_script; +string GUI_fileName; +real GUI_Xorg = 0.0; +real GUI_Yorg = 0.0; +real GUI_lwidth = 0.001; +string GUI_layers[]; + GUI_layers[0] = "select a layer"; +int GUI_layerselect = -1; +int Lcnt = 1; +int GUI_TargetLayer = 0; +int SavedTargetLayer = 0; + +/* +******************************************************************************* +* NON-GUI FUNCTIONS +******************************************************************************* +*/ + +/* +******************************************************************************* +* strcomp2() +* +* Description: The purpose of this function is to take the input scompare and +* compare it to strings s1 and s2 for an exact match. If there is +* no match to either string it will return -1, if there is a match +* to one of the strings it will return the index of the +* corresponding strstr function that succeeded. +* +* The strstr function checks to see if a substring shows up within +* a given string, if it does it gives the index where the +* substring shows up within the string. This is not enough to +* ensure an exact match. To ensure an exact match we would need +* the length of the strings to be the the same. +* +* Arguments: scompare String to be compared +* s1 First item to match +* s2 Second item to match +* +* Return: -1 If there is no match +* int If there is a match corresponding to index of strstr +* function that succeeded +* +* Caller: dxf +* +******************************************************************************* +*/ + +int strcomp2(string scompare, string s1, string s2) { + int result = strstr(scompare, s1); + + if(result != -1 && strlen(scompare) == strlen(s1)) { + return result; + } + else { + result = strstr(scompare, s2); + if (result != -1 && strlen(scompare) == strlen(s2)) { + return result; + } + else { + return -1; + } + } +} + +/* +******************************************************************************* +* mx() and my() +* +* Description: These functions below are used to find the extreme XY points of +* the DXF file we're importing. This info will later be used to +* make sure the file fits inside the drawing area of EAGLE. They +* modify the drawing Max and Min variables in order to find the +* size of the imported drawing +* +* Arguments: real Real x or y value +* +* Return: real The original x or y value that was passed +* +* Caller: dxf +* +******************************************************************************* +*/ + +real mx(real x) { + if (XMax < x) XMax = x; + if (XMin > x) XMin = x; + return x; +} + +real my(real y) { + if (YMax < y) YMax = y; + if (YMin > y) YMin = y; + return y; +} + +/* +******************************************************************************* +* dxf() +* +* Description: This function takes a DXF file path and processes it to produce +* a script full of commands to draw the contents of the DXF file +* in EAGLE. +* +* Arguments: dxffile Path to the DXF file to be processed +* units Units of the DXF file +* xorigin User defined offset in the X direction +* yorigin User defined offset in the Y direction +* liwidth User defined line width +* ent Skips the search for sections and entities, +* useful for files that don't strictly follow +* the DXF format. +* scale Optional scaling factor to increase or decrease +* the size of the DXF file +* +* Return: string A long string full of EAGLE commands +* +* Caller: checkscript +* +******************************************************************************* +*/ + +string dxf(string dxffile, int units, real xorigin, real yorigin, real liwidth, int ent, real scale) { + string s[]; // This string array will store the DXF file + string out; // Out is the script generated by this function + string temp; // Place holder + enum { state_SECTION, + state_ENTITIES, + state_SEARCH, + state_LINE, + state_ARC, + state_CIRCLE, + state_POLYLINE, + state_VERTEX, + state_LWPOLYLINE}; // Defines states for the main state machine + enum { order_FIRST, + order_SECOND, + order_THIRD, + order_FOURTH, + order_FIFTH}; // Defines states for the secondary state machines + int i; // index variable for xa and ya + int p; // dummy variable for for loop + int m; // dummy variable for main while loop + int nlines; // number of lines in the text file + int state; + int order; // Used for internal state machines + int lines; + int arcs; + int circles; + int polylines; + int linewidth=1; + int LWPOLY_FLAG=1; // See comment in LWPOLYLINE state + real x; + real y; + real x1; + real y1; + real x2; + real y2; + real x3; + real y3; + real r; + real theta1; + real theta3; + real xorg; + real yorg; + real xa[]; // xa and ya arrays hold the possible vertexes of a polyline + real ya[]; + real plclosed; + real bulgevalue[]; // plclosed and bulgevalue array helps in dealing with... + // ... closed polylines + + if (units == 1) { // Setup unit scale factor + S_factor = 1000; // Convert mm to um + XMax = u2mm(INT_MIN)*S_factor; + YMax = u2mm(INT_MIN)*S_factor; + XMin = u2mm(INT_MAX)*S_factor; + YMin = u2mm(INT_MAX)*S_factor; + } + else { + S_factor = 25400; // Convert in to um + XMax = u2inch(INT_MIN)*S_factor; + YMax = u2inch(INT_MIN)*S_factor; + XMin = u2inch(INT_MAX)*S_factor; + YMin = u2inch(INT_MAX)*S_factor; + } + + linewidth = liwidth * S_factor; + xorg = xorigin * S_factor; + yorg = yorigin * S_factor; + S_factor *= scale; // Added scale factor affects everything except xorg, ... + // ... yorg and linewidth those are handled by the GUI + + out += "# dxfimport generated script file.\n"; + out += "Grid mic 1 off;\n"; + out += "Set Wire_Bend 2;\n"; + sprintf(temp, "CHANGE LAYER %d;\n", GUI_TargetLayer); // 2015-02-10 + out += temp; + out += "Change Font Vector;\n"; + + if (ent >= 1) { // Allows the section search to be disabled + state = state_SEARCH; + out += "# Skipped Section Search\n"; + } + else { + state = state_SECTION; + } + + order = order_FIRST; + lines = arcs = circles = polylines = 0; + nlines = fileread(s, dxffile); + + for (m = 0;m < nlines;m++) { + switch (state) { + case state_SECTION: // scan for SECTIONS in the DXF file + if (strstr(s[m],"SECTION") != -1) { + if (ent >= 1) { + state = state_SEARCH; + } + else { + state = state_ENTITIES; + } + } + break; + case state_ENTITIES: // scan for ENTITIES in the DXF file + if (strstr(s[m],"ENDSEC") != -1) { + state = state_SECTION; + } + if (strstr(s[m],"ENTITIES") != -1) { + state = state_SEARCH; + } + break; + case state_SEARCH: // scanning for LINE, ARC, CIRCLE, POLYLINE, SPLINE + if (strstr(s[m],"ENDSEC") != -1) { + if (ent >= 1) { + state = state_SEARCH; + } + else { + state = state_SECTION; + } + } + if (strstr(s[m],"LINE") != -1 && strlen(s[m]) == 4) { + state = state_LINE; + lines++; + } + if (strstr(s[m],"ARC") != -1 && strlen(s[m]) == 3) { + state = state_ARC; + arcs++; + } + if (strstr(s[m],"CIRCLE") != -1 && strlen(s[m]) == 6) { + state = state_CIRCLE; + circles++; + } + if (strstr(s[m],"POLYLINE") != -1 && strlen(s[m]) == 8) { + i=0; + state = state_POLYLINE; + polylines++; + } + if (strstr(s[m],"LWPOLYLINE") != -1 && strlen(s[m]) == 10) { + i=0; // JG Support for LWPOLYLINE added 07/09/2012 + state = state_LWPOLYLINE; + polylines++; + } + break; + case state_LINE: // absorbing LINE + switch(order) { // LINE 10, 20, 30 (start point), 11, 21, 31 (end point). + case order_FIRST: + if (strcomp2(s[m], " 10", "10") != -1) { + x = S_factor*strtod(s[m+1]); + order = order_SECOND; + } + break; + case order_SECOND: + if (strcomp2(s[m], " 20", "20") != -1) { + y = S_factor*strtod(s[m+1]); + order = order_THIRD; + } + break; + case order_THIRD: + if (strcomp2(s[m], " 11", "11") != -1) { + x1 = S_factor*strtod(s[m+1]); + order = order_FOURTH; + } + break; + case order_FOURTH: + if (strcomp2(s[m], " 21", "21") != -1) { + y1 = S_factor*strtod(s[m+1]); + sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n", + linewidth, + mx(x+xorg), + my(y+yorg), + mx(x1+xorg), + my(y1+yorg) + ); + out += temp; // Write to script + state = state_SEARCH; + order = order_FIRST; + } + break; + } + break; + case state_ARC: // absorbing ARC + switch(order) { // ARC 10, 20, 30 (center), 40 (radius), 50 (start angle), 51 (end) + case order_FIRST: + if (strcomp2(s[m], " 10", "10") != -1) { + x = S_factor*strtod(s[m+1]); + order = order_SECOND; + } + break; + case order_SECOND: + if (strcomp2(s[m], " 20", "20") != -1) { + y = S_factor*strtod(s[m+1]); + order = order_THIRD; + } + break; + case order_THIRD: + if (strcomp2(s[m], " 40", "40") != -1) { + r = S_factor*strtod(s[m+1]); + order = order_FOURTH; + } + break; + case order_FOURTH: + if (strcomp2(s[m], " 50", "50") != -1) { + theta1 = strtod(s[m+1]); + theta1 *= (PI/180); + order = order_FIFTH; + } + break; + case order_FIFTH: + if (strcomp2(s[m], " 51", "51") != -1) { + theta3 = strtod(s[m+1]); + theta3 *= (PI/180); + + x1 = r*cos(theta1)+x; // compute Eagle arc parameters from DXF arc params + y1 = r*sin(theta1)+y; + x2 = x1-2*r*cos(theta1); + y2 = y1-2*r*sin(theta1); + x3 = r*cos(theta3)+x; + y3 = r*sin(theta3)+y; + + sprintf(temp, "Arc CCW %d (%0.2f %0.2f) (%0.2f %0.2f) (%0.2f %0.2f);\n", + linewidth, + mx(x1+xorg), + my(y1+yorg), + mx(x2+xorg), + my(y2+yorg), + mx(x3+xorg), + my(y3+yorg) + ); + out += temp; + state = state_SEARCH; + order = order_FIRST; + } + break; + } + break; + case state_CIRCLE: // absorbing CIRCLE + switch(order) { // CIRCLE 10, 20, 30 (center), 40 (radius). + case order_FIRST: + if (strcomp2(s[m], " 10", "10") != -1) { + x = S_factor*strtod(s[m+1]); + order = order_SECOND; + } + break; + case order_SECOND: + if (strcomp2(s[m], " 20", "20") != -1) { + y = S_factor*strtod(s[m+1]); + order = order_THIRD; + } + break; + case order_THIRD: + if (strcomp2(s[m], " 40", "40") != -1) { + y1 = S_factor*strtod(s[m+1]); + sprintf(temp, "Circle %d (%0.2f %0.2f) (%0.2f %0.2f);\n", + linewidth, + mx(x+xorg), + my(y+yorg), + mx(x+xorg), + my(y+y1+yorg) + ); + out += temp; + state = state_SEARCH; + order = order_FIRST; + } + break; + } + break; + case state_POLYLINE: // absorbing POLYLINE + if (strstr(s[m], "VERTEX") != -1) { // VERTEX + state = state_VERTEX; + } + if (strcomp2(s[m], " 70", "70") != -1) { // EDIT HM 20120425: Determine if Polyline is closed and... + plclosed = strtod(s[m+1]); // ...take care of bulge values for line segments. + } + if (strstr(s[m], "SEQEND") != -1) { + for (p=0; p < i-1;p++) { // n points give n-1 lines that's why there's an i-1 in... + if (bulgevalue[p] != 0) { // ...the conditional + sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n", + linewidth, + mx(xa[p]+xorg), + my(ya[p]+yorg), + (atan(bulgevalue[p])*180/PI*4), + mx(xa[p+1]+xorg), + my(ya[p+1]+yorg) + ); + out += temp; + } + else { + sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n", + linewidth, + mx(xa[p]+xorg), + my(ya[p]+yorg), + mx(xa[p+1]+xorg), + my(ya[p+1]+yorg) + ); + out += temp; + } + } + if(plclosed) { + if(bulgevalue[p] != 0) { + sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n", + linewidth, + mx(xa[p]+xorg), + my(ya[p]+yorg), + (atan(bulgevalue[p])*180/PI*4), + mx(xa[0]+xorg), + my(ya[0]+yorg) + ); + out += temp; + } + else { + sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n", + linewidth, + mx(xa[p]+xorg), + my(ya[p]+yorg), + mx(xa[0]+xorg), + my(ya[0]+yorg) + ); + out += temp; + } + } + state = state_SEARCH; + } + break; + case state_VERTEX: // absorbing VERTEX + switch(order) { + case order_FIRST: + if (strcomp2(s[m], " 10", "10") != -1) { // 10 (x-value) 20 (y-value) + xa[i] = S_factor*strtod(s[m+1]); + order = order_SECOND; + } + break; + case order_SECOND: + if (strcomp2(s[m], " 20", "20") != -1) { + ya[i] = S_factor*strtod(s[m+1]); // This avoids a misalignment of the bulge array should... + bulgevalue[i] = 0; // ...one or more polylines not have bulges + order = order_THIRD; + } + break; + case order_THIRD: + if (strcomp2(s[m], " 42", "42") != -1) { + bulgevalue[i] = strtod(s[m+1]); //* Store bulge value for node + } + if (strcomp2(s[m], " 0", "0") != -1) { + i++; + state = state_POLYLINE; // Look for next vertex in polyline + order = order_FIRST; + } + break; + } + break; + case state_LWPOLYLINE: // absorbing LWPOLYLINE 07/09/2012 + if (strcomp2(s[m], " 70", "70") != -1) { // Checks for closed polylines and imports them. + plclosed = strtod(s[m+1]); + } + if (strcomp2(s[m], " 42", "42") != -1) { + bulgevalue[i] = strtod(s[m+1]); // Store bulge value for node + } + if (strcomp2(s[m], " 10", "10") != -1) { + xa[i] = S_factor*strtod(s[m+1]); + } + if (strcomp2(s[m], " 20", "20") != -1) { + LWPOLY_FLAG = 0; // On poorly formated files, this state may run into an + // improperly formatted zero and exit without + // processing any points. This flag guarantees that + // the state will not be exited before points are + // processed. See the if statement below. + ya[i] = S_factor*strtod(s[m+1]); + bulgevalue[i] = 0; + i++; // This avoids a misalignment of the bulge array should + // one or more polylines not have bulges. + } + if (strcomp2(s[m], " 0", "0") != -1 & LWPOLY_FLAG == 0) { + for (p=0; p < i-1;p++) { // n points give n-1 lines that's why there's an i-1 in + if (bulgevalue[p] != 0) { // the conditional. + sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n", + linewidth, + mx(xa[p]+xorg), + my(ya[p]+yorg), + (atan(bulgevalue[p])*180/PI*4), + mx(xa[p+1]+xorg), + my(ya[p+1]+yorg) + ); + out += temp; + } + else { + sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n", + linewidth, + mx(xa[p]+xorg), + my(ya[p]+yorg), + mx(xa[p+1]+xorg), + my(ya[p+1]+yorg) + ); + out += temp; + } + } + if(plclosed) { + if(bulgevalue[p] != 0) { + sprintf(temp, "Wire %d (%0.2f %0.2f) %+0.2f (%0.2f %0.2f);\n", + linewidth, + mx(xa[p]+xorg), + my(ya[p]+yorg), + (atan(bulgevalue[p])*180/PI*4), + mx(xa[0]+xorg), + my(ya[0]+yorg) + ); + out += temp; + } + else { + sprintf(temp, "Wire %d (%0.2f %0.2f) (%0.2f %0.2f);\n", + linewidth, + mx(xa[p]+xorg), + my(ya[p]+yorg), + mx(xa[0]+xorg), + my(ya[0]+yorg) + ); + out += temp; + } + } + state = state_SEARCH; + LWPOLY_FLAG = 1; + } + break; + } + } + + sprintf(temp, "Window Fit;\n"); + out += temp; + sprintf(temp, "# lines=%d, arcs=%d, circles=%d, polylines=%d\n", + lines, + arcs, + circles, + polylines + ); + out += temp; + out += "Grid last;"; + return out; +} + +/* +******************************************************************************** +* GUI FUNCTIONS +******************************************************************************** +*/ + +/* +******************************************************************************* +* get_project_path() +* +* Description: Returns project path, if in board or schematic, otherwise +* it will return the library path +* +* Arguments: none +* +* Return: p String containing full path of project +* +* Caller: runscript +* +******************************************************************************* +*/ + +string get_project_path() { + string s = "", p = "";; + if (library) { library(L) s = L.name;} + if (board) { board(B) s = B.name;} + if (schematic){ schematic(S) s = S.name;} + char c = '/'; + int pos = strrchr(s, c); + if (pos >= 0) { + p = strsub(s, 0, pos + 1); + } + return p; +} + +/* +******************************************************************************* +* LoadConfigSettings() +* +* Description: Loads the most recent configuration settings. +* +* Arguments: none +* +* Return: none +* +* Caller: Main GUI code +* +******************************************************************************* +*/ + +void LoadConfigSettings() { + string lines[]; + string rf[]; + + int nrf = fileglob(rf, ConfigFileName); + + if (nrf) { + nrf = fileread(lines, rf[0]); + } + if (nrf == 7) { + int i = 0; + GUI_fileName = lines[i++]; + GUI_Xorg = strtod(lines[i++]); + GUI_Yorg = strtod(lines[i++]); + GUI_scale = strtod(lines[i++]); + GUI_lwidth = strtod(lines[i++]); + GUI_in_unit = strtol(lines[i++]); + SavedTargetLayer = strtol(lines[i++]); + } +} + +/* +******************************************************************************* +* SaveConfigSettings() +* +* Description: Saves the most recent configuration settings. +* +* Arguments: none +* +* Return: none +* +* Caller: runscript +* +******************************************************************************* +*/ + +void SaveConfigSettings() { + output(ConfigFileName, "wt") { + printf("%s\n", GUI_fileName); + printf("%f\n", GUI_Xorg); + printf("%f\n", GUI_Yorg); + printf("%f\n", GUI_scale); + printf("%f\n", GUI_lwidth); + printf("%d\n", GUI_in_unit); + printf("%d\n", GUI_TargetLayer); + } +} + +/* +******************************************************************************* +* runscript() +* +* Description: This function writes the commands to a script file, and then +* exits the ULP. Upon exit the command to run the script is +* issued to EAGLE. +* +* Arguments: scr List of script commands +* +* Return: none +* +* Caller: checkscript +* +******************************************************************************* +*/ + +void runscript(string scr) { + string filepath = get_project_path() + "dxfimp.scr"; + SaveConfigSettings(); + + output(filepath,"wt") { + printf(scr); + } + + exit("SCRIPT '" + filepath + "'"); +} + +/* +******************************************************************************* +* checkscript() +* +* Description: This function checks if the DXF file will fit inside EAGLE's +* drawing area and if not return helpful messages. Addtionally it +* will display the generated script to the user for modifications +* before the script is run. +* +* Arguments: none +* +* Return: none +* +* Caller: Main GUI code +* +******************************************************************************* +*/ + +void checkscript(void) { // This allows the user to inspect the script and make changes + real sc_xo = GUI_Xorg; // These allow the scale factor to be applied independently + real sc_yo = GUI_Yorg; + real sc_lw = GUI_lwidth; + string error; + if (!GUI_TargetLayer) { + dlgMessageBox("First select a layer!", "OK"); + return; + } + if (GUI_scaled_Xorg == 1) { + sc_xo *= GUI_scale; + } + if (GUI_scaled_Yorg == 1) { + sc_yo *= GUI_scale; + } + if (GUI_scaled_lwidth ==1) { + sc_lw *= GUI_scale; + } + GUI_script = + GUI_script = dxf(GUI_fileName, GUI_in_unit, sc_xo, sc_yo, sc_lw, 0, GUI_scale); + string dummy[]; // Dummy array to check of dxf function returned valid data + if (strsplit(dummy, GUI_script, '\n') == 8) { + GUI_script = dxf(GUI_fileName, + GUI_in_unit, + sc_xo, + sc_yo, + sc_lw, + 1, + GUI_scale); // Run again without searching for sections + } + real Xdim = XMax - XMin; // Max dimensions of DXF file,must be defined after dxf runs + real Ydim = YMax - YMin; + real EXdim = Exmax - Exmin; // Max dimensions of EAGLE + real EYdim = Eymax - Eymin; + + /* done = Debug(GUI_script); */ + + if ((Xdim > EXdim) || (Ydim > EYdim)) { // Checks if DXF file is larger than EAGLE's drawing area + dlgMessageBox(":DXF file is larger than EAGLE's drawing area please scale the file in your MCAD software and try again"); + exit(-1); + } + if ((Xdim < Exmax) && (Ydim < Eymax)) { // Checks if DXF file is small enough to fit in the + // first quadrant (+X +Y) + + if ((XMax > Exmax) || (YMax > Eymax) || + (XMin < Exmin) || (YMin < Eymin)) { // Check if any of the points are outside of EAGLE's drawing area + GUI_Xorg = -1.0*(XMin/S_factor); // Lower left corner of DXF file will now be at 0 0 + GUI_Yorg = -1.0*(YMin/S_factor); // Make sure we return the offset in original units + sprintf(error,":DXF file is outside of EAGLE's drawing area would you like to apply an offset in X of %.1f and %.1f in y?", + GUI_Xorg, GUI_Yorg); + if (dlgMessageBox(error, "Set offset", "CANCEL") != 0) exit(-1); + return; + } + } + else { // DXF file is too large to fit in first quadrant + if ((XMax > Exmax) || (YMax > Eymax) || + (XMin < Exmin) || (YMin < Eymin)) { // Check if any of the points are outside of EAGLE's drawing area + GUI_Xorg = -1.0*(((XMin+XMax)/2)/S_factor); // Center of DXF file will now be at 0 0 + GUI_Yorg = -1.0*(((YMin+YMax)/2)/S_factor); + sprintf(error,":DXF file is outside of EAGLE's drawing area would you like to apply an offset in X of %.1f and %.1f in y?", + GUI_Xorg, GUI_Yorg); + if (dlgMessageBox(error, "Set offset", "CANCEL") != 0) exit(-1); + return; + } + } + + int Result = dlgDialog("Run Script") { + dlgTextEdit(GUI_script); + dlgHBoxLayout { + dlgPushButton("Run") runscript(GUI_script); + dlgPushButton("Cancel") dlgReject(); + } + }; +} + +int gettargetlayer(int select) { + return strtol(GUI_layers[select]); +} + +/* +******************************************************************************** +* MAIN() * +******************************************************************************** +*/ +LoadConfigSettings(); // load the last filename and config settings +GUI_TargetLayer = 0; + +if (board) { + board(B) { + B.layers(L) { + if (L.name) { + sprintf(GUI_layers[Lcnt], "%d %s",L.number, L.name); + if (L.number == SavedTargetLayer) { + GUI_TargetLayer = L.number; + GUI_layerselect = Lcnt; + } + Lcnt++; + } + } + } +} +else if (schematic) { + schematic(SCH) { + SCH.layers(L) { + if (L.name) { + sprintf(GUI_layers[Lcnt], "%d %s",L.number, L.name); + if (L.number == SavedTargetLayer) { + GUI_TargetLayer = L.number; + GUI_layerselect = Lcnt; + } + Lcnt++; + } + } + } +} +else if (package || symbol) { + library(LIB) { + LIB.layers(L) { + if (L.name) { + sprintf(GUI_layers[Lcnt], "%d %s",L.number, L.name); + if (L.number == SavedTargetLayer) { + GUI_TargetLayer = L.number; + GUI_layerselect = Lcnt; + } + Lcnt++; + } + } + } +} +else { + dlgMessageBox("Start this ULP in a Schematic- or Board- or Package- or Symbol- Editor!", "OK"); + exit(-1); +} + +int main() { + string stateline = " "; + int Result = dlgDialog("DXFIMPORT - "+Version) { + + dlgHBoxLayout { + dlgLabel(Help); + } + dlgHBoxLayout { + dlgLabel("File &name:"); + dlgStringEdit(GUI_fileName); + dlgPushButton("Bro&wse") { + GUI_fileName = dlgFileOpen("Select a file", GUI_fileName, "*.dxf"); + } + } + + dlgHBoxLayout { + dlgLabel("Target layer "); + dlgComboBox(GUI_layers, GUI_layerselect) GUI_TargetLayer = gettargetlayer(GUI_layerselect); + dlgStretch(1); + } + + dlgHBoxLayout { + dlgGroup("Input Units") { + dlgRadioButton("Imperial(in)", GUI_in_unit); // GUI_in_unit = 0 + dlgRadioButton("Metric(mm)", GUI_in_unit); // GUI_in_unit = 1 + } + dlgGridLayout { + dlgCell(0, 0) dlgLabel("Xorg"); + dlgCell(1, 0) dlgLabel("Yorg"); + dlgCell(0, 1) dlgRealEdit(GUI_Xorg); + dlgCell(1, 1) dlgRealEdit(GUI_Yorg); + dlgCell(2, 0) dlgLabel("Width"); + dlgCell(2, 1) dlgRealEdit(GUI_lwidth); + dlgCell(3, 0) dlgLabel("Scale"); + dlgCell(3, 1) dlgRealEdit(GUI_scale); + dlgCell(0, 2, 3, 2) { + dlgGroup("Scaled") { + dlgCheckBox("Xorg", GUI_scaled_Xorg); // If checked int contains 1, if unchecked 0 + dlgCheckBox("Yorg", GUI_scaled_Yorg); + dlgCheckBox("Width", GUI_scaled_lwidth); + } + } + dlgCell(1, 3) dlgPushButton("OK") { + stateline = "converting file... please wait."; + dlgRedisplay(); + checkscript(); + stateline = " "; + dlgRedisplay(); + } + dlgCell(2, 3) dlgPushButton("-Cancel") dlgReject(); + } + } + dlgLabel(stateline, 1); + }; + return Result; +} diff --git a/trunk/ulp/import-pads-powerpcb-v5.ulp b/trunk/ulp/import-pads-powerpcb-v5.ulp new file mode 100644 index 00000000..418bf522 --- /dev/null +++ b/trunk/ulp/import-pads-powerpcb-v5.ulp @@ -0,0 +1,1369 @@ +#usage "Import PADS-POWERPCB-V5.0-BASIC! DESIGN DATABASE ASCII FILE 1.0

    " + "RUN import-pads-powerpcb-v5.ulp
    " + "

    " + "Author: alf@cadsoft.de" + +#require 6.0500 + +string Version = "1.0.4"; // 2011-10-26 + // 2012-06-25 option single-lbr to generate a library for each package + // 2012-10-08 pad count corrected, polygon corrected + // 2012-11-12 changed file handling + // 2013-09-11 no message if no .cfg file exist + +int test = 0; + +string UlpDefCfg = filesetext(argv[0], ".cfg"); +string ImpPADSSym = ""; +string EaglePADSLbrDir = ""; +string DirPADSAsc = ""; +string EaglePADSSchDir = ""; +int fn = 0; + +string LbrName; +string FilePADSSym[]; +int cntFilePADSSym = 0; + +int Import_All_Symbols = 1; +string ImportNames[]; +string ImportFNames[]; +int CntImpAll = 0; // In den Dateien kann es sein, dass der Name des Package + // nicht gleich dem Namen der Datei ist, und evtl. somit + // doppelt angelegt wird. 2011-11-08 alf + +int SingleLbr = 0; // Da es in der Definition der PADS-Dateien immer wieder den gleichen Namen + // für ein Package mit unterchiedlichen Paramtern gibt, kann man mit dieser + // Option für jedes Package eine eignen LBR anlagen, mit dem Namen der Quell-Datei. + // 2012-06-25 alf@cadsoft.de + +string SymDevName; +string CmdDev; +int CntPinname = 0; + +string PadsAscName; +string FilePADSAsc[]; +int cntFilePADSAsc = 0; + +char Delimiter = '@'; + +string ScriptFile = ""; +string ScriptExt = "~ltPADS~.scr"; + +string PADS_Headerline; +string Line[]; +int Cntl; +int nline = 0; + +string Val[]; +int CntV; + +string Cmd, h; + +string Unit; // Grid-Einheit +real Devider = 100000; + +string LineWidth; +string PacInfo = ""; +// PADS header line for a package +string PADSname; // PADS package name +string PADSunits; // Grid +int PADSx; // Package Origin x +int PADSy; // Package Origin y +int PADSpieces; // Gehäuse-Kontur +int PADStermals; // PAD-Anzahl +int PADSstacks; +string PADStext; +string PADSlabels; // Name + Value + +/* +string UNITS; // Grid +string ORIX; // Origin x +string ORIY; // Origin y +string PIECES; // Gehäuse-Kontur +string TERMINALS; +string STACKS; +string TEXT; +string LABELS; // Name + Value +*/ + +int Tcnt = 1; // Pad/Smd-Zähler +string Tname[]; +real Tx1[], Ty1[], TxName[], TyName[]; // PAD/SMD-Koordinaten, nur die ersten beiden sind relevant laut Hr. Preissner +real Tsizeidia[], Tsizelong[]; // Wird von PAD 0 vorgegeben, +real Tfinlength[]; +string Tshape[]; +real Tangle[]; +int Troundness[]; +real Tdrill[]; +string Tplatet[]; + +// Default PAD-Stack, wird durch Pad-Nummer 0 definiert +int Stacklines; // Zähler für die Anzahl der Zeilen die den Pad-Stack definieren +int Padstack0_level; +real Padstack0_size; +string Padstack0_shape; +real Padstack0_finori; +real Padstack0_idia; +real Padstack0_finlength; +real Padstack0_finoffset; +int Padstack0_corner; +real Padstack0_drill; +int Padstack0_slotori; +int Padstack0_slotlength; +string Padstack0_plated; + + +real SCALE; // SCALE 152.134 Scale of window expansion + + +/*** ######## Functions ######## ***/ +void readconfig(void) { // read configuration file of ULP + string line[]; + string f[]; + int fn = fileglob(f, UlpDefCfg); + if (!fn) { + return; + } + int lines = fileread(line, UlpDefCfg); + for (int cl = 0; cl < lines; cl++) { + string s[]; + int cnt = strsplit(s, line[cl], Delimiter); + if (s[0] == "EaglePADSLbrDir") EaglePADSLbrDir = s[1]; // "E:/EG/eg5 0/5.0_Projekte/LT-PADS/"; + else if (s[0] == "EaglePADSSchDir") EaglePADSSchDir = s[1]; // "E:/EG/eg5 0/5.0_Projekte/LT-PADS/"; + else if (s[0] == "ImpPADSSym") { + ImpPADSSym = s[1]; // "E:/Programme/LTC/LTPADSIV/lib/sym/"; + FilePADSSym[0] = ImpPADSSym; + } + else if (s[0] == "DirPADSAsc") { + DirPADSAsc = s[1]; //"E:/Programme/LTC/LTPADSIV/" + FilePADSAsc[0] = DirPADSAsc; + } + else if (s[0] == "Import_All_Symbols") Import_All_Symbols = strtol(s[1]); + else if (s[0] == "SingleLbr") SingleLbr = strtol(s[1]); // 2012-06-25 + } + return; +} + + +void saveconfig(void) { + output(UlpDefCfg, "wt") { + printf("EaglePADSLbrDir%c%s\n", Delimiter, EaglePADSLbrDir); + printf("ImpPADSSym%c%s\n", Delimiter, ImpPADSSym); + printf("EaglePADSSchDir%c%s\n", Delimiter, EaglePADSSchDir); + printf("DirPADSAsc%c%s\n", Delimiter, DirPADSAsc); + printf("Import_All_Symbols%c%d\n", Delimiter ,Import_All_Symbols); + printf("SingleLbr%c%d\n", Delimiter, SingleLbr); + } +} + + +int checkexist_pac(string name) { + if (library) { + library(L) { + L.packages(P) { + if (P.name == name) return 1; + } + } + } + return 0; +} + + +int checkexist_sym(string name) { + if (library) { + library(L) { + L.symbols(S) { + if (S.name == name) return 1; + } + } + } + return 0; +} + + +// wenn alle Dateien eines Verzeichnis eingelesen werden, +// dann überprüfe ob das Package/Symbol schon angelegt wird. +// In den Package-Dateien von LT-Spice werden einige Packages doppelt +// angelegt. Der Dateiname entspricht nicht dem Namen der in der +// Datei angegeben ist! 2011-11-07 alf@cadsoft.de +int check_double_defined(string name, string fname) { + if(SingleLbr) return 0; // 2012-06-25 + int found = 0; + for (int n = 0; n < CntImpAll; n++) { + if (ImportNames[n] == name) return 1; + } + ImportNames[CntImpAll] = name; + ImportFNames[CntImpAll] = name+ "\t" + fname; + CntImpAll++; + return 0; +} + + +string del_double_space(string l) { + string s[]; + int cnt = strsplit(s,l, ' '); + string l1 = ""; + for (int i = 0; i < cnt; i++) { + if (s[i]) l1+= s[i] + " "; + } + return l1; +} + +/*** +void getunit(string l) { + if (l == "I") { + Unit = "MIL"; + Devider = 100000; + } + else if (l == "M") { + Unit = "MM"; + Devider = 100000; + } + return; +} +***/ + +//LINEWIDTH 3810000 Width items will be created with +void linewidth(string l) { + string s[]; + int n = strsplit(s, l, ' '); + sprintf(LineWidth , "CHANGE WIDTH %.6f;\n", strtod(s[1]) / Devider); + return; +} + + +void imp_font(string l) { // do nothing + return; +} + + +// MSOP08 I 22418040 18497550 1 8 1 0 2 +// MSOP08 == name | User-defined decal name. The alphanumeric string can be +// up to 40 characters long +// I == units | Units used for this part decal. Valid values are: +// I Imperial units, given in mils +// M Metric units, given in mm +// 22418040 18497550 == x y | kann im Package-Editor ignoriert werden +// Coordinates where the symbol is placed when viewed in the Decal +// Editor. You can ignore this data when reading in ASCII files. If +// copying the data, simply preserve the values from the input field. Use +// the values 1000, 1000 if you are creating this data. +// 1 == pieces | Number of drawing outline items that make up the part decal. +// Valid values range from 0 to 32767. A definition follows each piece entry +// 8 == terminals | Number of terminals that make up the part decal. Valid values range +// from 0 to 32767. A definition follows each entry. +// 1 == stacks | Number of unique pad stack descriptions that define the terminals +// within the decal. A definition follows each entry +// 0 == text (optional) | Number of text strings associated with the decal item. Valid values +// range from 0 to 32767. +// 2 == labels (optional) | Number of attribute labels associated with the decal item. +// +// Valid values range from 0 to 32767 + +//DFN(06)2MMX2MM M 0 0 2 7 2 0 2 +//*REMARK* NAME UNITS ORIX ORIY PIECES TERMINALS STACKS TEXT LABELS +/*** +Ppcb_ASCII.pdf : PADS Layout ASCII Format Specification : Seite 31 + +name | User-defined decal name. The alphanumeric string can be up to 40 + characters long. + +units | Units used for this part decal. Valid values are: + I Imperial units, given in mils + M Metric units, given in mm + +x and y | Coordinates where the symbol is placed when viewed in the Decal + Editor. You can ignore this data when reading in ASCII files. If + copying the data, simply preserve the values from the input field. Use + the values 1000, 1000 if you are creating this data. + +pieces | Number of drawing outline items that make up the part decal. Valid + values range from 0 to 32767. A definition follows each piece entry. + +terminals | Number of terminals that make up the part decal. Valid values range + from 0 to 32767. A definition follows each entry. + +stacks | Number of unique pad stack descriptions that define the terminals + within the decal. A definition follows each entry. + +text (optional) | Number of text strings associated with the decal item. Valid values + range from 0 to 32767. + +labels(optional) | Number of attribute labels associated with the decal item. Valid values + range from 0 to 32767. + +***/ +int imp_pac_name(string l) { // start parsing + if (Tcnt > 1) { dlgMessageBox("Tcnt stimmt nicht!", "ok", "esc"); exit(-295); } + Tcnt = 1; // reset Tcnt; + string s[]; + int n = strsplit(s, l, ' '); + PADSname = s[0]; + PADSunits = s[1]; + PADSx = strtol(s[2]) / Devider; + PADSy = strtol(s[3]) / Devider; + PADSpieces = strtol(s[4]); + PADStermals = strtol(s[5]); + PADSstacks = strtol(s[6]); + PADStext = s[7]; + PADSlabels = s[8]; + + sprintf(PacInfo, "%s\nname %s\nunits %s\nx %d\ny %d\npieces %d\ntermals %d\nstacks %d\ntext %s\nlabel %s", + l, + PADSname, + PADSunits, + PADSx, + PADSy, + PADSpieces, + PADStermals, + PADSstacks, + PADStext, + PADSlabels + ); + + if (test) { + if (dlgMessageBox(PacInfo, "ok", "esc") != 0) exit(-324); + } + + if (checkexist_pac(strupr(s[0]))) { + sprintf(h, "! Package %s.PAC exist.\nDelete the package?", l); + if (dlgMessageBox(h, "YES", "NO") != 0) return 1; + sprintf(h, "SET CONFIRM YES;\nREMOVE %s.PAC;\nSET CONFIRM OFF;\n", s[0]); + Cmd += h; + } + if (check_double_defined(s[0], FilePADSSym[fn])) { + int sel; + int srt = 0; + sprintf(h, "second definition of %s in %s", s[0], filename(FilePADSSym[fn])); + dlgDialog("Import PADS library") { + dlgHBoxLayout dlgSpacing(400); + dlgStringEdit(h); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgListView("Package\tFile", ImportFNames, sel, srt); + } + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("CANCEL") { dlgReject(); exit(-346); } + dlgStretch(1); + } + }; + } + //getunit(PADSunits); // Das Grid des Package + if (s[1] == "I") { + Unit = "MIL"; // das benutzte Grid + Devider = 100000; + } + else if (s[1] = "M") { + Unit = "MM"; // das benutzte Grid + Devider = 1000000; + } + sprintf(h, "EDIT %s.PaC;\nGRID %s;\n", s[0], Unit); // der Package-Name und die Masseinheit + Cmd += h; + Cmd += "CHANGE STYLE Continuous;\n"; + Cmd += LineWidth; + sprintf(h, "DESCRIPTION 'Package generated from: %s (%s)

    \\n\\nwith :%s Version %s at %s';\n", + filename(FilePADSSym[fn]), Line[0], filename(argv[0]), Version, t2string(time()) + ); + Cmd+=h; + return 0; +} + + +/*****************************/ +string imp_arc(string l) { // 2012-10-08 + /* + *REMARK* XLOC YLOC BEGINANGLE DELTAANGLE + + COPCLS 9 299850 1 28 + -2250000 330000 1800 900 -2250000 180000 -1950000 480000 + -2100000 180000 + 2100000 180000 2700 900 1950000 180000 2250000 480000 + 2250000 330000 + 2250000 2850000 0 900 1950000 2700000 2250000 3000000 + 2100000 3000000 + -1800000 3000000 44 -900 -2776440 2473560 -1798560 3451440 + -2250000 2475000 + -2250000 330000 + + # COPCLS 9 ist ein Polygon mit 9 Teillinien bzw. Bögen + # 28 ist der 28. Pad von 0 gezählt Beispiel "QFN36(UHE).asc" + + Definition des ARC: + Die Koordinaten e/f und g/h definieren die zwei diagonalen Ecken eines umschließenden + Rechteck um einen Kreis. Die Mitte dieses Rechteck ist der Mittelpunkt des Kreises, + und somit der Mittelpunkt des ARC. + Die Koordinate a/b ergibt den Startpunkt des Kreisbogen, und sollte dem Startwinkel c, + bezogen auf den Mittelpunkt des zuvor definierten Kreises entsprechen. + d ist der Bogenwinkel, also das Ende des ARC in Grad, bezogen auf den Startwinkel. + 2011-11-14 + + Aus der PDF-Dokumentation: Ppcb_ASCII.pdf / PADS Layout ASCII Format Specification / PADS 9.0 + Arc corner format: + x1 y1 ab aa ax1 ay1 ax2 ay2 + Format Description: + x1 y1 Beginning of the arc + ab Beginning angle of the arc in tenths of a degree + aa Number of degrees in the arc in tenths of a degree + ax1, ay1 Lower left point of the rectangle around the circle of the arc + ax2, ay2 Upper right point of the rectangle around the circle of the arc + ax2 ax1 = ay2 ay1 Diameter of the circle of the arc + (ax1 + ax2)/2, (ay1 + ay2)/2 Coordinates of the center of the arc circle + */ + string s[]; + int n = strsplit(s, l, ' '); + + real startcoordx = strtod(s[0]) / Devider; + real startcoordy = strtod(s[1]) / Devider; + real startangle = strtod(s[2]) * 0.1; + real diffangle = strtod(s[3]) * 0.1; + string arc; + sprintf(arc, " (%.8f %.8f) %+.1f ", + startcoordx, startcoordy, + diffangle + ); + return arc; +} + +/**************************************/ +string get_coordinat(string l) { + string s[]; + string k, m; + int n = strsplit(s, l, ' '); + if (n > 2) { + k = imp_arc(l); + } + else { + sprintf(k, " (%.6f %.6f)", strtod(s[0]) / Devider, strtod(s[1]) / Devider); + } + k += "\\\n"; + return k; +} + + +// CLOSED 9 304800 0 +// CLOSED == type +// 9 == level +// == pinnum +// == restrictions +void imp_closed_line(string l) { + string s[]; + int cnt = strsplit(s, l, ' '); + sprintf(h, "# imp_closed_line %s \n", s[1]); + Cmd += h; + sprintf(h, "SET wIRE_BEND 2;\nCHANGE LAYER 21;\nWIRE %.4f \\\n", strtod(s[2]) / Devider); + Cmd += h; + for (int p = 1; p <= strtod(s[1]); p++) { + Cmd += get_coordinat(del_double_space(Line[++nline])); + } + Cmd += ";\n"; + return; +} + + +// OPEN 3 381000 0 +// OPEN == type +// 3 == level +// == pinnum +// == restrictions +/* +OPEN 6 304800 1 +-1500000 2250000 +-1500000 952500 +-1143000 952500 +-1143000 -952500 +-1500000 -952500 +-1500000 -2250000 +*/ +void imp_open_line(string l) { + string s[]; + int n = strsplit(s, l, ' '); + sprintf(h, "# imp_open_line() %s \n", s[1]); + Cmd += h; + Cmd += "# LAYeR "+s[3]+"\n"; + sprintf(h, "SET WiRE_BEND 2;\nCHANGE LAYER 21;\nWIRE %.4f \\\n", strtod(s[2]) / Devider); + Cmd += h; + for (int p = 1; p <= strtod(s[1]); p++) { + Cmd += get_coordinat(del_double_space(Line[++nline])); + } + Cmd += ";\n"; + return; +} + +/* +COPCLS 9 381000 1 1 +-647700 -4000500 +-647700 -1219200 +-1276350 -1219200 +-1276350 2781300 +1276350 2781300 +1276350 -1219200 +647700 -1219200 +647700 -4000500 +-647700 -4000500 +*/ +void imp_copcls(string l) { // Copper Closed? + Cmd+="# imp_copcls()\n"; + string s[]; + int cnt = strsplit(s, l, ' '); + sprintf(h, "# imp_imp_copcls %s \n", s[1]); + Cmd += h; + sprintf(h, "SET WIrE_BEND 2;\nCHANGe LAYER 1;\nChange width %.6f;\n", strtod(s[2]) / Devider); + Cmd += h; + string cmdpol; + sprintf(cmdpol, "POLYGOn "); + for (int p = 1; p <= strtod(s[1]); p++) { + cmdpol += get_coordinat(del_double_space(Line[++nline])); + } + cmdpol += ";\n"; + Cmd += cmdpol; // Kupferpolygon = PAD-Erweiterung + sprintf(h, "CHANGE LAYER 29;\nCHANGE WIDTH %.6f;\n", strtod(s[2]) / Devider * 1.2); // Stop-Maske + Cmd += h; + Cmd += cmdpol; // Kupferpolygon = PAD-Erweiterung + sprintf(h, "CHANGE LAYER 31;\nCHANGE WIDTH %.6f;\n", strtod(s[2]) / Devider / 2); // Cream-Maske + Cmd += h; + Cmd += cmdpol; // Kupferpolygon = PAD-Erweiterung + return; +} + + +/* +CIRCLE 2 266700 1 +-3429000 -1333500 +-2476500 -1333500 +*/ +void imp_circle(string l) { + string s[]; + int n = strsplit(s, l, ' '); + //int cntcircle = strtol(s[1]); + sprintf(h, ";\nCIRCLE %.6f ", strtod(s[2]) / Devider); + Cmd += h; + strsplit(s, Line[++nline], ' '); + sprintf(h, " (%.6f %.6f)", strtod(s[0]) / Devider, strtod(s[1]) / Devider); + Cmd += h; + strsplit(s, Line[++nline], ' '); + sprintf(h, " (%.6f %.6f);\n", strtod(s[0]) / Devider, strtod(s[1]) / Devider); + Cmd += h; + return; +} + + +void imp_copopn(string l) { + /* + COPOPN 2 190500 21 + -41405025 3333750 + -41405025 5333250 + */ + string s[]; + real width, x1, x2, y1, y2, dx, dy; + + int n = strsplit(s, l, ' '); + + if (s[1] == "2") { + width = strtod(s[2]) / Devider; + if (s[3] == "21") { + Cmd += "CHa LAYER 1; # "+s[3]+"\n"; + } + else if (s[3] == "28") { + Cmd += "CH LAYER 16; # "+s[3]+"\n"; + } + else { + sprintf(h, "Layer unknown %s in line %d", s[3], nline); + if (dlgMessageBox(h, "ok", "esc") != 0) exit(-578); + } + strsplit(s, Line[++nline], ' '); + x1 = strtod(s[0]) / Devider; + y1 = strtod(s[1]) / Devider; + + strsplit(s, Line[++nline], ' '); + x2 = strtod(s[0]) / Devider; + y2 = strtod(s[1]) / Devider; + sprintf(h, "# imp_copopn() 734\nSMD '%d' %.6f %.6f (%.6f %.6f);\n", Tcnt, x2-x1+width+2, y2-y1+width+2, (x1+x2) / 2, (y1+y2) / 2); + Cmd += h; + Tcnt++; // Pad counter + } + else { + sprintf(h, "unklnown parameter counter %s in Line %d", s[2], nline); + if (dlgMessageBox(h, "ok", "esc") != 0) exit(-593); + } + return; +} + +void imp_copcut(string l) { + Cmd += "# imp_copcut()\n"; + dlgMessageBox(FilePADSSym[fn]+ "\n\nCUTCUP", "?"); + exit(-601); + return; +} + +void imp_copcco(string l) { + Cmd += "# copcco\n"; + dlgMessageBox(FilePADSSym[fn]+ "\n\nCOPCCO", "?"); + exit(-608); + return; +} + +void imp_copcir(string l) { // Copper Circle? + Cmd += "# copcir\n"; + dlgMessageBox(FilePADSSym[fn]+ "\n\nCOPCIR", "?"); + exit(-615); + return; +} + +void imp_kptcls(string l) { + Cmd += "# kptcls\n"; + dlgMessageBox(FilePADSSym[fn]+ "\n\nKTPCLS", "?"); + exit(-622); + return; +} + +void imp_cptcir(string l) { + Cmd += "# cptcir\n"; + dlgMessageBox(FilePADSSym[fn]+ "\n\nKPRCIR", "?"); + exit(-629); + return; +} + +void imp_tag(string l) { + Cmd += "# Tag\n"; + dlgMessageBox(FilePADSSym[fn]+ "\n\nTAG", "?"); + exit(-636); + return; +} + + +/* +VALUE -1800000 -450000 0.000 1 1905000 190500 N LEFT DOWN +Ref.Des. +*/ +void imp_ref_des(string l) { + + real offsety; + if (Val[9] == "DOWN") offsety = 0.0; + else if (Val[9] == "UP") { + if (Unit == "MM") offsety = -1.778; + else if (Unit == "MIL") offsety = -70.0; + } + + sprintf(h, ";\nCHANGE SIZE 70mil;\nCHANGE LAYER 27;\nTEXT '>NAME' R%.1f (%.6f %.6f);\n", + strtod(Val[3]), strtod(Val[1]) / Devider, strtod(Val[2]) / Devider + offsety + ); + Cmd += h; + return; +} + + +/* +VALUE 0 0 0.000 1 1905000 190500 N LEFT UP +Part Type +VALUE -1800000 -450000 0.000 1 1905000 190500 N LEFT DOWN +Ref.Des. +*/ +void imp_value(string l) { + + //int cntv = 0; + string s[]; + int n = strsplit(s, l, ' '); + CntV = 0; + for (int i = 0; i < n; i++) { + if(s[i]) { + Val[CntV++] = s[i]; + } + } + return; +} + + +/* +VALUE 0 0 0.000 1 1905000 190500 N LEFT UP +Part Type +*/ +void imp_part_type(string l) { + + real offsety ; + if (Val[9] == "DOWN") offsety = 0.0; + else if (Val[9] == "UP") { + if (Unit == "MM") offsety = -1.778; + else if (Unit == "MIL") offsety = -70.0; + } + sprintf(h, ";\nCHANGE LAYER 25;\nCHANGE SIZE 70mil;\nTEXT '>VALUE' R%.1f (%.6f %.6f);\n", + strtod(Val[3]), strtod(Val[1]) / Devider, strtod(Val[2]) / Devider + offsety + ); + Cmd += h; + return; +} + + +/*** +T-1463040 -3257550 -1644015 -3333750 +T-487680 -3257550 -487680 -3257550 +T487680 -3257550 487680 -3257550 +T1463040 -3257550 1463040 -3257550 +T1463040 3257550 1463040 3257550 +T487680 3257550 487680 3257550 +T-487680 3257550 -487680 3257550 +T-1463040 3257550 -1463040 3257550 +PAD 0 3 +***/ + +/*** !PADS-POWERPCB-V9.3-BASIC! DESIGN DATABASE ASCII FILE 1.0 +T-2625000 -3225000 -2625000 -3225000 1 +T-1875000 -3225000 -1875000 -3225000 2 +T-1125000 -3225000 -1125000 -3225000 3 +T-375000 -3225000 -375000 -3225000 4 +***/ + +void imp_tcoord(string l) { // 2012-10-08 Tcnt ist der Zähler und Pointer selbst + l[0] = ' '; // replace T with space + string s[]; + int n = strsplit(s, l, ' '); + int padnum = strtol(s[5]); // PADS-Version 9 gibt auch Namen aus. 2012-05-25 + Tx1[Tcnt] = strtod(s[1]) / Devider; // pad coodicnate + Ty1[Tcnt] = strtod(s[2]) / Devider; // pad coordinate + TxName[Tcnt] = strtod(s[3]) / Devider; // name coodinate + TyName[Tcnt] = strtod(s[4]) / Devider; // name coodinate + Tname[Tcnt] = s[5]; + Tcnt++; + if (Tcnt-1 > PADStermals) { + string h; + sprintf(h, "%s\n%s:\n%s\n%d more then %d pads defined!", PacInfo, FilePADSSym[fn], l, Tcnt, PADStermals); + if (dlgMessageBox(h, "OK", "CANCEL") != 0) exit(-736); + } + return; +} + + +//PAD 0 3 +//-2 457200 RF 90.000 2286000 0 0 +//-1 0 R +//0 0 R + +// PAD == Keyword +// 0 == pinno | Terminal number to which the pad stack applies. A value of 0 indicates all +// pads except those explicitly listed later +// 3 == stacklines | Number of lines of information pertaining to the pin numbers. The +// minimum number of entries is 3: top layer, inner layer, and bottom layer +// +// -2 == level | Layer number being defined. Valid values are: +// -2 Top layer +// -1 Inner layer +// 0 Bottom layer +// 1 to 250 Specific layer number +// 457200 == size | Diameter of the pad for round, odd, and annular pads. Length of a side for +// square pads. Width of oval or rectangular pads +// RF == shape | Pad shape. Valid values are: +// R Round +// S Square +// A Annular +// O Odd +// OF Oval finger +// RF Rectangular finger (SMD) +// RT - Thermal pad for a round pad shape +// ST - Thermal pad for square pad shape +// 90.000 == finori | Orientation, in degrees, of oval or rectangular pads. Precision is three +// digits after the decimal point. Valid values range from 0 to 179.999. If +// the pad is not oval or rectangular, this field is omitted +// 2286000 == idia | Inner diameter of an annular pad. If the pad is not annular, this field is omitted. +// 0 == finlength | Finger length of oval or rectangular pads. Valid values range from +1 to +// 1000. If the pad is not oval or rectangular, this field is omitted. +// 0 == finoffset | Offset of the finger of oval or rectangular pads from the electrical center +// (drill). For fingers with a 0 degree orientation, a positive offset shifts the +// pad from the electrical center to the right. For fingers with a 90 degree +// orientation, a positive offset shifts the pad from the electrical center up. +// Offset values must lie within the pad, and may not be greater than 500. If +// the pad is not oval or rectangular, this field is omitted. +// +// == corner | This field stores the numerical corner radius value and is used to +// support pads with rounded and chamfered corners. It only exists for +// square and rectangular finger pad shapes. Zero value is used for 90 +// degree (non-rounded) pad corners; positive value is used for pads with +// rounded corners; negative value is used for pads with chamfered +// corners. +// == drill | Drill size. Valid values range from 0 to 1000. drill only appears on the +// side where parts are mounted. +// == plated | If this is N, the drill hole is unplated. If this is P or empty, the drill is +// plated. plated only appears on the side where parts are mounted. +// == slotori | Orientation, in degrees, of the slotted drill. Precision is three digits after +// the decimal point. Valid values range from 0 to 179.999. +// == slotlength | Length of the slotted drill. Valid values range from +1 to 1000. + +/* +PAD 7 3 +-2 915000 RF 0.000 2130000 0 0 N +-1 0 R +0 0 R + +PAD 0 4 +-2 1050000 RF 90.000 1350000 0 0 +-1 0 R +0 0 R +25 0 R + +PAD 0 4 +-2 2286000 R 1219200 +-1 2286000 R +0 2286000 R +25 3048000 R +PAD 1 4 +-2 2286000 S 0 1219200 +-1 2286000 S 0 +0 2286000 S 0 +25 3048000 R +*/ +int get_pad(string l) { + string s[]; + int n = strsplit(s, l, ' '); + int pinno = strtol(s[1]); + Stacklines = strtod(s[2]); // Anzahl der Zeilen die nach "PAD x n" noch folgen + return pinno; +} + + +void get_pad_size(string l, int pinnumber) { + string s[]; + l = del_double_space(l); + int cnt = strsplit(s, l, ' '); + + //if(dlgMessageBox(s[0] + " == 25?", "ok", "esc") != 0) exit(-825); + + + if (s[0] == "-2") { // Pad/smd dimension Top layer + int Padstack_level = strtol(s[0]); + real Padstack_size = strtod(s[1]) / Devider; + string Padstack_shape = s[2]; + real Padstack_finori = strtod(s[3]); + real Padstack_idia = strtod(s[4]) / Devider; + real Padstack_finlength = strtol(s[5]); + real Padstack_finoffset = strtol(s[6]); + int Padstack_corner = strtol(s[7]); + real Padstack_drill = strtod(s[8]) / Devider; + int Padstack_slotori = strtol(s[9]); + int Padstack_slotlength = strtol(s[10]); + string Padstack_plated; + if (s[cnt-2] == "N" || s[cnt-2] == "P") { + Padstack_plated = s[cnt-2]; + } + + if (pinnumber == 0) { // alle Pads haben diese Größe, Rotation und Form + + Padstack0_level = strtol(s[0]); + Padstack0_size = strtod(s[1]) / Devider; + Padstack0_shape = s[2]; + Padstack0_finori = strtod(s[3]); + Padstack0_idia = strtod(s[4]) / Devider; + Padstack0_finlength = strtol(s[5]); + Padstack0_finoffset = strtol(s[6]); + Padstack0_corner = strtol(s[7]); + Padstack0_drill = strtod(s[8]) / Devider; + Padstack0_slotori = strtol(s[9]); + Padstack0_slotlength = strtol(s[10]); + if (s[cnt-2] == "N" || s[cnt-2] == "P") { + Padstack0_plated = s[cnt-2]; + } + if (Padstack0_shape == "S" || Padstack0_shape == "R") { // + Padstack0_idia = Padstack0_size; + } + + for (int n = 1; n < Tcnt; n++) { // vorsetzen der PAD/SMD-Grössen + Tsizelong[n] = Padstack0_size; // size ist die Höhe + Tsizeidia[n] = Padstack0_idia; // inner diameter ist die Breite + Tangle[n] = Padstack0_finori; + Tshape[n] = Padstack0_shape; // Padform Finger = SMD / R = Rechteck | O = Oval = 100% Roundness + if (Padstack0_shape == "RF") Troundness[n] = 0; + else if (Padstack0_shape == "OF" || Padstack0_shape == "R") Troundness[n] = 100; + Tdrill[n] = Padstack0_drill; + Tplatet[n] = Padstack0_plated; + } + } + else { + Tsizelong[pinnumber] = Padstack_size; // size ist die Höhe + Tsizeidia[pinnumber] = Padstack_idia; // inner diameter ist die Breite + Tfinlength[pinnumber] = Padstack_finlength; + Tangle[pinnumber] = Padstack_finori; + Tshape[pinnumber] = Padstack_shape; + Tplatet[pinnumber] = Padstack_plated; + } + /* + string h2; + sprintf(h2, "Pinnumber =%d\nLänge %.f\nBreite %.f\nRotation %.f\nForm %s", + pinnumber, Tsizelong[pinnumber], Tsizeidia[pinnumber], Tangle[pinnumber], Tshape[pinnumber] + ); + if (dlgMessageBox(h2, "ok", "esc") != 0) exit(-902); + */ + } + else if (s[0] == "-1") ; // Eagle can not define innerlayer diameter + else if (s[0] == "0") ; // bottom layer + else if (s[0] == "25") { // drill + Padstack0_drill = strtod(s[1]) / Devider; + Padstack0_shape = s[2]; + if (pinnumber == 0) { // alle Pads haben diesen Drilldurchmesser + for (int n = 1; n < Tcnt; n++) { // vorsetzen des Drill und Form + Tdrill[n] = Padstack0_drill; + Tshape[n] = Padstack0_shape; + } + //if (dlgMessageBox("alle Drills gesetzt", "ok", "esc") != 0) exit(-902); + } + else { + Tshape[pinnumber] = Padstack0_shape; + Tdrill[pinnumber] = Padstack0_drill; + } + } + return; +} + + +void get_pad_option(string l) { + Cmd += "# get_pad_option\n"; + return; +} + + +void get_pads(string pacname) { // PAD/SMD ausgeben + Cmd += "# get_pads()\nCHANGE LAYER 1;\nSMD '1' ;\n"; // Starte Namenvergabe mit 1, PADS-V5 gibt keine Namen vor! + real lastx = -100000.0, lasty = -100000.0; + for (int n = 1; n < Tcnt; n++) { + if (Tsizelong[n]) { // nur wenn Tsizelong (bei PAD der Drill) nicht 0 ist, dann wird der Pad erzeugt, + // PADS kann SMDs mit Size 0 erzeugen, die dann aber nicht dargestellt werden! + if (Tdrill[n] && !Tsizeidia[n] && !Tsizelong[n]) { + sprintf(h, "# 951\nHOLE %.8f (%.8f %.8f);\n", + Tdrill[n], + Tx1[n], Ty1[n] + ); + Cmd += h; + } + + else { + if(lastx == Tx1[n] && lasty == Ty1[n]) { + string error; + sprintf(error, "Package '%s'\nplace more as 1 PAD/SMD '%s' on coodinate %.8f %.8f", + filename(pacname), + Tname[n], + Tx1[n], Ty1[n] + ); + dlgDialog("Error") { + dlgHBoxLayout dlgSpacing(600); + dlgTextView(error); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); exit(-945); } + dlgStretch(1); + } + }; + } + if (Tname[n]) Tname[n] = "'" + Tname[n] + "'"; // PADS V9 gibt Namen vor, wenn der Name nicht leer ist, dann in ' ' einschliessen. + + if (Tdrill[n]) { // bedrahtete Pads + string shape; + if (Tshape[n] == "S") shape = "SQUARE"; + else if (Tshape[n] == "R") shape = "ROUND"; + else if (Tshape[n] == "A") shape = "Round"; + else if (Tshape[n] == "O") shape = "OCTAGON"; + + sprintf(h, "# 977\nCHange Dril %.8f;\nPAD %.8f %s R%.3f %s (%.8f %.8f);\n", + Tsizeidia[n], + Tsizelong[n], + shape, + Tangle[n], + Tname[n], + Tx1[n], Ty1[n] + ); + Cmd += h; + } + + else { // 2012-10-08 siehe imp_tcoord() + // hier wird nachträglich der Pad-Type und die Form geändert. + //if (Tshape[n] == "RF" || Tshape[n] == "OF") { // finger ist ein SMD + if (Tshape[n] == "OF" || Tshape[n] == "R") Troundness[n] = 100; + else if (Tshape[n] == "RF" || Tshape[n] == "R") Troundness[n] = 0; + if (Tshape[n] == "S") { + if(!Tsizeidia[n] || !Tsizelong[n]) { + if (!Tsizeidia[n] && !Tsizelong[n]) { + sprintf(h, "Package %s PAD %s has no dimension %.4f %.4f", + filename(pacname), Tname[n], + Tsizeidia[n] && !Tsizelong[n] + ); + dlgMessageBox(h, "OK"); + exit(-975); + } + else if (!Tsizeidia[n]) Tsizeidia[n] = Tsizelong[n]; + else if (!Tsizelong[n]) Tsizelong[n] = Tsizeidia[n]; + } + } + sprintf(h, "# 967 %d von %d : %s\nSMD %.8f %.8f -%d R%.1f %s (%.8f %.8f);\n", + n, + Tcnt, + Tname[n], + Tsizeidia[n], Tsizelong[n], + Troundness[n], + Tangle[n], + Tname[n], + Tx1[n], Ty1[n] + ); + Cmd += h; + } + } + lastx = Tx1[n]; + lasty = Ty1[n]; + } + } + return; +} + +void checktest(void) { + numeric string check[]; + sprintf(check[0], "Num.\tTsizeidia\tTsizelong\tTfinlength\tTshape\tTroundness\tTangle\tTname\tTx1\tTy1\tTplatet"); + + ; + for (int n = 1; n < Tcnt; n++) { + sprintf(check[n], "%d\t%f\t%f\t%f\t%s\t%d\t%f\t%s\t%f\t%f\t%s", + n, + Tsizeidia[n], + Tsizelong[n], + Tfinlength[n], + Tshape[n], + Troundness[n], + Tangle[n], + Tname[n], + Tx1[n], Ty1[n], + Tplatet[n] + ); + + } + + int sel; + if (test) dlgDialog("check") { + dlgListView("", check, sel); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") { dlgReject(); exit(-1021); } + } + }; + return; +} + + +/******** main ********/ +if (library || schematic); +else { + dlgMessageBox("!Start this ULP in a schematic or library.", "OK"); + exit(-1); +} + +readconfig(); + +// ### main menu ### +//int editPADSsym = 0; +int editPADSsch = 0; +dlgDialog("PADS PowerPCB import") { + dlgHBoxLayout dlgSpacing(500); + if (library) { + //library(L) LbrName = L.name; + dlgLabel("Import a PADS symbol/library"); + dlgHBoxLayout dlgSpacing(500); + dlgLabel("Directory of imported PADS libraries:"); + dlgHBoxLayout { + dlgStringEdit(EaglePADSLbrDir); + dlgPushButton("&Browse") { + string mEaglePADSLbrDir = dlgDirectory("Directory: Translated Eagle-LBR from PADS", EaglePADSLbrDir); + if (mEaglePADSLbrDir) { + int len = strlen(mEaglePADSLbrDir); + if (mEaglePADSLbrDir[len-1] != '/') mEaglePADSLbrDir += "/"; // a directory has / on end + if (!mEaglePADSLbrDir) { + dlgMessageBox("!You must select a directory of translated libraryies.", "OK"); + } + else EaglePADSLbrDir = mEaglePADSLbrDir; + } + } + } + dlgLabel("Import PADS symbol(s):"); + dlgHBoxLayout { + dlgStringEdit(FilePADSSym[0]); + dlgPushButton("B&rowse") { + ImpPADSSym = filename(dlgFileOpen("Select a PADS symbol", EaglePADSLbrDir, "*.asc")); // 2012-11-09 + if (ImpPADSSym) { + FilePADSSym[0] = ImpPADSSym; + cntFilePADSSym = 1; + } + } + } + dlgCheckBox("Import &all symbols from directory", Import_All_Symbols); + dlgHBoxLayout { + dlgLabel("New library name "); + dlgStringEdit(LbrName); + } + dlgCheckBox("Generate a separate library for each package file", SingleLbr); + } + else if (schematic) { + dlgLabel("Import a PADS schematic"); + dlgLabel("Directory of Eagle schematic path"); + dlgHBoxLayout { + dlgStringEdit(EaglePADSSchDir); + dlgPushButton("&Browse") { + string mEaglePADSSchDir = dlgDirectory("Select a PADS schematic directory", EaglePADSSchDir); + if (mEaglePADSSchDir) EaglePADSSchDir = mEaglePADSSchDir; + } + } + dlgLabel("Directory of PADS &Schematic"); + dlgHBoxLayout { + dlgStringEdit(FilePADSAsc[0]); + dlgPushButton("&Browse") { + FilePADSAsc[0] = dlgFileOpen("Select a PADS schematic", DirPADSAsc , "*.asc"); + DirPADSAsc = filedir(FilePADSAsc[0]); + if (FilePADSAsc[0]) { + PadsAscName = filesetext(FilePADSAsc[0], ".sch"); + cntFilePADSAsc = 1; + editPADSsch = 1; + } + } + } + + dlgHBoxLayout { + dlgLabel("New schematic name "); + dlgStringEdit(PadsAscName); + } + } + dlgHBoxLayout { + dlgPushButton("+OK") { + if (fileext(FilePADSAsc[0]) == ".asc" || fileext(FilePADSSym[0]) == ".asc") { + if (schematic) { + if (!PadsAscName) PadsAscName = EaglePADSSchDir + filename(filesetext(FilePADSAsc[0], ".sch")); + ScriptFile = filesetext(PadsAscName, ScriptExt); + dlgAccept(); + } + else if (library) dlgAccept(); + } + else { + if (schematic) dlgMessageBox("First select as PADS schematic file (*.asc)!", "OK"); + else if (library) { + if (fileext(FilePADSSym[0]) != ".asc" ) dlgMessageBox("First select as PADS symbol file (*.asc)!", "OK"); + } + } + } + dlgPushButton("-CANCEL") { dlgReject(); exit(-2); } + dlgStretch(1); + dlgLabel(Version); + dlgStretch(1); + dlgPushButton("Save config") saveconfig(); + } +}; +if (!FilePADSSym[0] && !FilePADSAsc[0]) exit(-3); + + +saveconfig(); + +// # import a library # +if (cntFilePADSSym) { + + if (Import_All_Symbols) { + cntFilePADSSym = fileglob(FilePADSSym, EaglePADSLbrDir+"*.asc"); // alle .asc dateinamen einlesen + } + else { + FilePADSSym[0] = EaglePADSLbrDir+FilePADSSym[0]; // 2012-11-09 ergänze den Pfad + } + ScriptFile = EaglePADSLbrDir + ScriptExt; + if (ScriptFile && FilePADSSym[fn]) { + output(ScriptFile, "wtD") { // Datei neu anlegen + printf("# This EAGLE script is generated with '%s'\n", argv[0]); + } + for (fn = 0; fn < cntFilePADSSym; fn++) { + Cmd = ""; // Reset command string for next package + CntPinname = 0; + int len = strlen(FilePADSSym[fn]); + if (FilePADSSym[fn] && FilePADSSym[fn][len-1] != '/') { // can not use directorys + Cntl = fileread(Line, FilePADSSym[fn]); + status(FilePADSSym[fn]); + //SymDevName = strupr(filesetext(filename(FilePADSSym[fn]), "")); + + int cntp; + int pars_on = 0; // ein Flag ab wann geparsed werden soll + Tcnt = 1; // Initialiesierung der Zähler + PADSname = ""; + PADSunits = ""; + PADSpieces = 0; + PADStermals = 0; + if (SingleLbr) { + sprintf(h, "OPEN '%s%s';\n", EaglePADSLbrDir, filesetext(filename(FilePADSSym[fn]), ".lbr")); + Cmd+=h; + } + for (nline = 0; nline < Cntl; nline++) { + if (strstr(Line[nline], "!PADS-") == 0) PADS_Headerline = Line[nline]; + else if (!Line[nline]); // eine leere Zeile + else if (strstr(Line[nline], "*REMARK*") == 0); // Kommentar + else if (strstr(Line[nline], "*PARTDECAL*") == 0) { // ab hier startet das eigentliche Parsen des Package + pars_on = 1; + } + else if (pars_on == 2) { + /* ab hier wird es interessant */ + if (strstr(Line[nline], "OPEN") == 0) imp_open_line(del_double_space(Line[nline])); + else if (strstr(Line[nline], "CLOSED") == 0) imp_closed_line(del_double_space(Line[nline])); + else if (strstr(Line[nline], "CIRCLE") == 0) imp_circle(del_double_space(Line[nline])); + else if (strstr(Line[nline], "COPCLS") == 0) imp_copcls(del_double_space(Line[nline])); + else if (strstr(Line[nline], "COPOPN") == 0) imp_copopn(del_double_space(Line[nline])); + else if (strstr(Line[nline], "COPCUT") == 0) imp_copcut(del_double_space(Line[nline])); + else if (strstr(Line[nline], "COPCCO") == 0) imp_copcco(del_double_space(Line[nline])); + else if (strstr(Line[nline], "COPCIR") == 0) imp_copcir(del_double_space(Line[nline])); + else if (strstr(Line[nline], "KPTCLS") == 0) imp_kptcls(del_double_space(Line[nline])); + else if (strstr(Line[nline], "KPTCIR") == 0) imp_cptcir(del_double_space(Line[nline])); + else if (strstr(Line[nline], "TAG") == 0) imp_tag(Line[nline]); + else if (strstr(Line[nline], "PAD") == 0) { + // PAD == Keyword + // 0 == pinno | Terminal number to which the pad stack applies. A value of 0 indicates all + // pads except those explicitly listed later + // 3 == stacklines | Number of lines of information pertaining to the pin numbers. The + // minimum number of entries is 3: top layer, inner layer, and bottom layer + // + // -2 == level | Layer number being defined. Valid values are: + // -2 Top layer + // -1 Inner layer + // 0 Bottom layer + // 1 to 250 Specific layer number + // 457200 == size | Diameter of the pad for round, odd, and annular pads. Length of a side for + // square pads. Width of oval or rectangular pads + // RF == shape | Pad shape. Valid values are: + // R Round + // S Square + // A Annular + // O Odd + // OF Oval finger + // RF Rectangular finger (SMD) + // RT - Thermal pad for a round pad shape + // ST - Thermal pad for square pad shape + // 90.000 == finori | Orientation, in degrees, of oval or rectangular pads. Precision is three + // digits after the decimal point. Valid values range from 0 to 179.999. If + // the pad is not oval or rectangular, this field is omitted + // 2286000 == idia | Inner diameter of an annular pad. If the pad is not annular, this field is omitted. + // 0 == finlength + // 0 == finoffset + // + // == corner + // == drill + // == plated + // == slotori + // == slotlength + + /* + PAD 7 3 + -2 915000 RF 0.000 2130000 0 0 N + -1 0 R + 0 0 R + + PAD 0 4 + -2 1050000 RF 90.000 1350000 0 0 + -1 0 R + 0 0 R + 25 0 R + */ + int pinnumber = get_pad(del_double_space(Line[nline])); + Cmd += "# 1257 " + Line[nline]+"\n"; + get_pad_size(del_double_space(Line[nline]), pinnumber); + while(Stacklines) { // get next x lines + nline++; + get_pad_size(del_double_space(Line[nline]), pinnumber); + Stacklines--; + } + //if (dlgMessageBox(Line[nline] + "\n die nächste Padzeile!?", "ok", "esc") != 0) exit(-1245); + } + else if (strstr(Line[nline], "VALUE") == 0) imp_value(del_double_space(Line[nline])); + else if (strstr(Line[nline], "Regular") == 0) imp_font(Line[nline]); // + else if (strstr(Line[nline], "Part") == 0) imp_part_type(Line[nline]); + else if (strstr(Line[nline], "Ref.Des.") == 0) imp_ref_des(Line[nline]); + else if (Line[nline][0] == 'T') imp_tcoord(del_double_space(Line[nline])); + else if (strstr(Line[nline], "*PARTTYPE*") == 0 || strstr(Line[nline], "*END*") == 0) { // End of package definition + if (PADStermals != Tcnt-1) { + string e; + sprintf(e, "!Package %s.asc\n\nDifferent counts of PADs\nheader info = %d\nfound = %d", PADSname, PADStermals, Tcnt); + if (dlgMessageBox(e, "OK", "CANCEL") != 0) exit(-1256);; + } + checktest(); + get_pads(FilePADSSym[fn]); + Cmd += "# End of Script\nWIN FIT;\n"; + break; //n = Cntl; // raus aus der Schleife, alle benötigten Parameter geparsed. + } + } + else if (pars_on == 1) { + pars_on++; + if (imp_pac_name(del_double_space(Line[nline]))) break; // Package exist, not delete + if (test) if (dlgMessageBox(PADSname, "Start new package", "Cancel") != 0) exit(-1267); + } + } + if (SingleLbr) { // 2012-06-25 + sprintf(h, "WRITE '%s%s';\n", EaglePADSLbrDir, filesetext(filename(FilePADSSym[fn]), ".lbr")); + Cmd+=h; + //if (dlgMessageBox(h, "ok", "esc") != 0) exit(-1273); + } + + if (test) { + dlgDialog("test") { + dlgHBoxLayout dlgSpacing(700); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(700); + dlgTextEdit(Cmd); + } + dlgHBoxLayout { + dlgPushButton("ok") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-1285); } + dlgPushButton("do not show next scipt") { test = 0; dlgAccept(); } + } + }; + } + output(ScriptFile, "atD") { // Erzeugtes Script an die Datei anhängen + printf("%s", Cmd); + } + } + } + exit ("SCRIPT '"+ ScriptFile + "'"); + } +} +// # Ende Bibliothek # + + +// # import a schematic # +if (cntFilePADSAsc) { + int f = 0; + if (ScriptFile && FilePADSAsc[0]) { + for (f = 0; f < cntFilePADSAsc; f++) { + + if (FilePADSAsc[f]) { + Cntl = fileread(Line, FilePADSAsc[f]); + status(FilePADSAsc[f]); + if (!checkexist_sym(PadsAscName)) { + string cmd; + sprintf(cmd, "EDIT '%s.SCH';\nCHANGE LAYER 96;\nGRID MIL 50 2 LINES ON;\nCHANGE WIDTH 10;\n", PadsAscName); + Cmd+=cmd; + Cmd+= "CHANGE STYLE Continuous;\n"; + for (f = 0; f < Cntl; f++) { + if (strstr(Line[f], "!PADS-POWERPCB") == 0) { + sprintf(h, "# %s\n", Line[f]); + cmd+= h; + } + else { + sprintf(h, "Line %d unknown:\n%s", f+1, Line[f]); + if (dlgMessageBox(h, "OK", "ESC") != 0) exit(-1322); + } + } + Cmd += CmdDev + "WIN FIT;\n"; // make a device and use generated symbol + } + } + } + + if (test) { + dlgDialog("Das Rückgabe-SCRIPT") { + dlgHBoxLayout dlgSpacing(700); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(700); + dlgTextEdit(Cmd); + } + dlgHBoxLayout { + dlgPushButton("ok") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-1339); } + } + }; + } + output(ScriptFile, "wtD") { + printf("%s", Cmd); + } + //if (dlgMessageBox(ScriptFile, "Ausführen", "Abbrechen") != 0) exit(-9); + exit ("SCRIPT '"+ ScriptFile + "'"); + } +} + diff --git a/trunk/ulp/import-ultiboard-ddf.ulp b/trunk/ulp/import-ultiboard-ddf.ulp new file mode 100644 index 00000000..1f9b627d --- /dev/null +++ b/trunk/ulp/import-ultiboard-ddf.ulp @@ -0,0 +1,1502 @@ +#usage "Import ULTIBOARD PCB Design Data File format (DDF)\n" + "

    " + "Imports ULTIBOARD PCB Design Data File format (DDF) Version 4.80 & 5.50." + "

    " + "Based on : Ultiboard User Manual, Appendix A, FILE FORMATS." + "

    " + "ULTIBOARD is a registered trademark of Electronics Workbench." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string InfoUS = + "Confirm the message:

    \n" + + "connect Signals

    \n" + + " S$nn

    \n" + + " S$nn

    \n" + + " with OK.

    " + + "


    " + + "This message will be prompted if a net segment (track) is connected to another " + + "net segment. " + + "The reason for this is the way ULTIBOARD exports the tracks, first the " + + "horizontal ones, then the vertical ones and at least tracks that run diagonal." + + "If ULTIBOARD has not named a segment of a track, EAGLE generates a name of" + + "its own and uses the $ sign at second position in it." + + "Please notice that the text height (and length) differs in EAGLE and " + + "ULTIBOARD. The position of the text will be calculated dependent on " + + "the the height and length of each character of the EAGLE vector font.

    " + + " - ULTIBOARD uses the text center as origin point

    " + + " - EAGLE uses the left lower corner of the text as origin point.

    " + + "The DDF format does not provide information about the lenght of characters.

    "; + +string ULTIBoardinfo = + "ULTIBOARD Version 4, Revision 80

    " + + " The x_coord and y_coord are expressed in database units (1/1200th of an inch)

    " + + " The rotation is given in degrees, specified as a floating point number between 0.0 and 360.0 degrees.

    " + + " Internally, Ultiboard works with a precision of 1/64th degree

    " + + "


    " + + "ULTIBOARD Version 5, Revision 50

    " + + " The x_coord and y_coord are expressed in database units (1 nanometer)

    " + + " The rotation is given in degrees, specified as a floating point number between 0.0 and 360.0 degrees.

    " + + " Internally, Ultiboard works with a precision of 1/64th degree

    " + + "


    " + + "ULTIBOARD is a registered trademark of Electronics Workbench"; + +string InfoDE = + "Bestätigen sie die Meldung:

    \n" + + "connect Signals

    \n" + + " S$nn

    \n" + + " S$nn

    \n" + + " mit OK.

    " + + "Diese Meldung wird dadurch erzeugt, daß ein Netzsegment (Leiterzug) mit " + + "einem anderen Netzsegment verbunden wird. " + + "Die Ursache ist die Reihenfolge der Ausgabe der Leiterbahn-Segmente aus ULTIBOARD, " + + "da ULTIBOARD zuerst waagrechte dann senkrechte und am Schluß diagonale " + + "Leiterbahnsegmente ausgibt.

    " + + "Wird von ULTIBOARD diesen Leitersegmenten kein Netzname zugewiesen, " + + "so erzeugt EAGLE einen Namen mit dem Zeichen $ an zweiter Position.

    " + + "


    " + + "Beachten Sie, daß die Buchstabengrößen (Zeichenlänge) " + + "von ULTIBOARD und EAGLE nicht identisch sind. Die Position der Texte wird " + + "berechnet durch die Texthöhe und dem Wert der Zeichenlänge jedes " + + "Buchstaben des EAGLE-Vector-Font.

    \n" + + " - ULTIBOARD plaziert Texte am Mittelpunkt des Textes.

    " + + " - EAGLE plaziert Texte mit der linken unteren Ecke des 1. Buchstaben.

    " + + "Das ULP berechnet die Position anhand der Stringlänge und Texthöhe. " + + "Im DDF-Format gibt es keine Information bezüglich der Buchstabenlänge, " + + "dadurch kann es vorkommen, daß längere Texte nicht exakt an der gleichen " + + "Position wie im ULTIBOARD Layout positioniert werden.

    " + + "


    " + + "Die Warnung: No forward-/backannotation will be performed!

    " + + "wird erzeugt, falls ein Schaltplan zur Laufzeit des ULP geladen ist, und muß " + + "mit OK bestätigt werden.

    "; + +string Version = "1.1.0"; +string costomer; +string versionnumb; +string revisionnum; +string tmpchtxtfile = ".ch$"; +string tmpextfile = "$.scr"; +string changetextfile; +string scriptfile; +string ULTIversion[] = { "480", "550" }; +real ULTIscale[] = { 1.20, 25400.0 }; +real rotatemult[] = { 64 , 64 }; +int VersionCnt = 2; +real xScale; +real rotatemultiple; +string Grid = "MIL"; +real CharacterLength; +real eagle_caracter_length[] = { + 00.000, 00.000, 00.000, 00.000, + 00.000, 00.000, 00.000, 00.000, + 00.000, 00.000, 00.000, 00.000, + 00.000, 00.000, 00.000, 00.000, + 00.000, 00.000, 00.000, 00.000, + 00.000, 00.000, 00.000, 00.000, + 00.000, 00.000, 00.000, 00.000, + 00.000, 00.000, 00.000, 00.000, + 00.917, 00.303, 00.764, 00.917, + 00.917, 01.071, 00.917, 00.610, + 00.764, 00.764, 00.917, 00.917, + 00.764, 00.917, 00.764, 00.917, + 00.917, 00.764, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.764, 00.764, + 00.917, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.917, + 00.917, 00.764, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.764, + 00.917, 00.764, 00.917, 00.917, + 00.610, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.764, 00.917, + 00.917, 00.764, 00.917, 00.917, + 00.764, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.917, + 00.764, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.917, + 00.457, 00.917, 00.917, 00.917, + 01.390, 01.236, 01.390, 00.150, + -6.000, 00.000, 00.307, 00.618, + 00.618, 00.307, 00.925, 00.618, + 00.610, 00.307, 00.307, 00.917, + 00.618, 00.618, 00.618, 00.917, + 00.917, 00.917, 00.618, 00.925, + 00.925, 00.618, 00.925, 00.925, + 00.917, 00.618, 00.610, 01.071, + 00.000, 00.303, 00.917, 01.224, + 00.618, 00.610, 00.307, 00.764, + 00.457, 00.610, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.764, + 00.764, 00.917, 00.610, 00.917, + 00.917, 00.917, 00.764, 00.457, + 00.764, 00.917, 00.917, 00.917, + 01.071, 01.071, 00.917, 00.917, + 00.917, 00.610, 00.917, 00.618, + 00.917, 00.917, 01.531, 00.917, + 00.307, 00.917, 00.618, 00.618, + 00.618, 00.618, 00.925, 00.618, + 00.618, 00.917, 01.071, 01.071, + 00.764, 01.071, 00.917, 01.224, + 01.071, 00.764, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.764, + 00.917, 00.917, 00.917, 00.307, + 00.917, 00.917, 01.378, 00.917, + 00.917, 00.917, 00.917, 00.917, + 00.764, 00.610, 00.764, 00.764, + 00.618, 00.917, 00.917, 00.917, + 00.917, 00.917, 00.917, 00.764, + 00.917, 00.917, 00.917, 00.917, + 00.917, 01.224, 01.071, 00.917 + }; +real def_grid; +real refpointx; +real refpointy; +string ulp_path = ""; +int lastLayer = 0; +string filter; +string ddffile; +int Result = 0; +string st = ""; +char lf = 10; +char cr = 13; +char nl = 12; +char polysepar = ':'; +char semikolon = ';'; +string cmd = ""; +string brd = ""; +string cmdroute = ""; +string script = ""; +string polygon = ""; +string arcscript = ""; +string cmdchname = ""; +string cmdvalue = ""; +real TextRatio = 8; +char c[]; +int nBytes = 0; +int n = 0; +string fileName = ""; +string shapename = ""; +string refLayer[] = { "49", + "1", + "16", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "116", + "117", + "118", + "119", + "120", + "121", + "122", + "123", + "124", + "125", + "126", + "127", + "128", + "129", + "130", + "131" + }; +string TMrefLayer[] = { "", + "", + "M", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + }; +real boardoutline[]; +string layerDirection[]; +real tracewidth[]; +real traceclearance[]; +real drilltolerance; +real drilltolerancevalue; +int drillcode[]; +real pad0innerX1[]; +real pad0innerX2[]; +real pad0innerY[]; +real pad0innerRadius[]; +real pad0innerClear[]; +real pad0innerHorizont[]; +real pad0innerVertical[]; +real pad0innerThermH[]; +real pad0innerThermV[]; +real pad1topX1[]; +real pad1topX2[]; +real pad1topY[]; +real pad1topRadius[]; +real pad1topClear[]; +real pad1topHorizont[]; +real pad1topVertical[]; +real pad1topThermH[]; +real pad1topThermV[]; +real pad2bottomX1[]; +real pad2bottomX2[]; +real pad2bottomY[]; +real pad2bottomRadius[]; +real pad2bottomClear[]; +real pad2bottomHorizont[]; +real pad2bottomVertical[]; +real pad2bottomThermH[]; +real pad2bottomThermV[]; +int net = -1; +string netname[]; +int nettracecode[]; +real netxlo[]; +real netxhi[]; +real netylo[]; +real netyhi[]; +real netxsum[]; +real netysum[]; +int netpincount[]; +netname[65535] = ""; +int cntrefPin = 0; +string refPinNr[]; +string refPackname[]; +int pointPackPin[]; +int cntShape = 0; +string signal[]; +string brdvia; +int comp = 0; +real stringLength(string s, real hight) { + real len = 0; + for (int l = 0; l < strlen(s); l++) { + len += (eagle_caracter_length[s[l]] * hight); + } + return len; + } +void importpass2(void) { + string changetextfile = argv[2]; + string scriptfile = filesetext(changetextfile, "$" + tmpextfile); + string s[]; + int nString = fileread(s, changetextfile); + if (board) board(B) { + output(scriptfile, "wt") { + printf("DISPLAY NONE 25;\n"); + printf("GRID %s FINEST;\n", Grid); + B.elements(E) { + for (int n = 0; n < nString; n+= 7) { + if (E.name == s[n]) { + E.texts(T) { + if (T.layer == 25 && T.value == s[n]) { + real size = strtod(s[n+5]); + if (size != 0) { + printf("# %s\n", s[n]); + real r = T.angle; + int pacnametextrotate = abs(r); + real slen = strtod(s[n+1]); + int trotate = strtod(s[n+2]); + real relx = strtod(s[n+3]); + real rely = strtod(s[n+4]); + real ratio = strtod(s[n+6]); + if(ratio <= 1) ratio = 1; + printf("CHANGE SIZE %.2f (%.2f %.2f);\n", size, u2mil(T.x), u2mil(T.y) ); + printf("CHANGE RATIO %.0f (%.2f %.2f);\n", ratio, u2mil(T.x), u2mil(T.y) ); + int pacrotate = E.angle; + if (pacrotate == pacnametextrotate) { + switch (pacrotate) { + case 0 : + switch(trotate) { + case 0 : + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) + (relx) - slen, + u2mil(E.y) + (rely) - (size/2) ); + break; + case 90 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) + (relx) + (size/2), + u2mil(E.y) + (rely) - slen ); + break; + case 180 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) + (relx) + slen, + u2mil(E.y) + (rely) + (size/2)); + break; + case 270 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) + (relx) + (size/2), + u2mil(E.y) + (rely) - slen ); + break; + } + break; + case 90 : + switch(trotate) { + case 0 : + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) - (rely) + (size/2), + u2mil(E.y) + relx - slen); + break; + case 90 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) - (rely) - slen, + u2mil(E.y) + (relx) - (size/2) ); + break; + case 180 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) + (relx) + slen, + u2mil(E.y) + (rely) + (size/2)); + break; + case 270 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) - rely + slen, + u2mil(E.y) + relx + (size/2) ); + break; + } + break; + case 180 : + switch(trotate) { + case 0 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) - (relx) - slen, + u2mil(E.y) - (rely) - (size/2) ); + break; + case 90 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) - (relx) + (size/2), + u2mil(E.y) - (rely) - slen ); + break; + case 180 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) - (relx) - slen, + u2mil(E.y) - (rely) - (size/2) ); + break; + case 270 : + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) + (relx) - slen, + u2mil(E.y) + (rely) - (size/2) ); + break; + } + break; + case 270 : + switch(trotate) { + case 0 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) + (rely) + (size/2), + u2mil(E.y) - (relx) - slen ); + break; + case 90 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) + (rely) - slen, + u2mil(E.y) - relx - (size/2) ); + break; + case 180 : + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) - (relx) + (size/2), + u2mil(E.y) + (rely) - slen); + break; + case 270 : + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("ROTATE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + printf("MOVE (%.2f %.2f) (%.2f %.2f);\n", + u2mil(T.x), u2mil(T.y), + u2mil(E.x) + rely + slen, + u2mil(E.y) - relx + (size/2) ); + break; + } + break; + default : if(dlgMessageBox("Rotation only in 0, 90, 180, 270 drgree", "OK", "ESC") != 0) exit (0); + } + } + else dlgMessageBox( s[n+0] + "\nPackage und Textplatzhalter ungleiche Rotation", "OK"); + } + else printf("DELETE (%.2f %.2f);\n", u2mil(T.x), u2mil(T.y) ); + } + } + } + } + } + printf("DISPLAY 1 16 17 18 20 21 -23 49;\n"); + printf("GRID LAST;\n"); + printf("# WRITE;\n"); + } + } + exit ("SCRIPT '" + scriptfile + "';\n"); + } +void test(char cc) { + sprintf(st, "Caracter=>%c<\n", cc); + if (dlgMessageBox("Character =" + st, "&Yes", "&No") != 0) { + exit (0); + } + return ; + } +real val2mil(string val) { + return strtod(val) * xScale; + } +real v2mil(real val) { + return val * xScale; + } +string format(real rval) { + string fmt; + sprintf(fmt, "%.3f", rval); + return fmt; + } +void rwire( int netnr, int layer, real x1, real y1, real x2, real y2) { + string w; + if (netnr < 0) { + string h; + sprintf(h, "Netz#=%d\n", netnr); + dlgMessageBox(h, "OK"); + } + cmdroute += "CHANGE LAYER " + refLayer[layer] + ";\n"; + if(netname[netnr] != "") { + sprintf(w, "WIRE '%s' (%s %s) (%s %s);\n", netname[netnr], + format(v2mil(x1)), format(v2mil(y1)), + format(v2mil(x2)), format(v2mil(y2)) ); + } + else { + sprintf(w, "WIRE (%s %s) (%s %s);\n", + format(v2mil(x1)), format(v2mil(y1)), + format(v2mil(x2)), format(v2mil(y2)) ); + } + cmdroute += w; + return ; + } +void route(int layer, real coord1, real coord2, real coord3, int Netnr, int Code, int Type, int Orient) { + cmdroute += "CHANGE Layer " + refLayer[layer] + ";\n"; + cmdroute += "CHANGE WIDTH " + format(v2mil(tracewidth[Code])) + ";\n" ; + switch (Orient) { + case 1 : rwire(Netnr, layer, coord2, coord1, coord3, coord1); + break; + case 2 : rwire(Netnr, layer, coord1, coord2, coord1, coord3); + break; + case 4 : rwire(Netnr, layer, coord2 + ((coord1 - coord2) / 2 ) , + (coord1 - coord2) / -2, coord3 + ((coord1 - coord3) / 2 ) , + (coord1 - coord3) / -2); + break; + case 8 : rwire(Netnr, layer, coord2 - ((coord2 - coord1) / 2 ) , + (coord2 - coord1) / -2, coord3 - ((coord3 - coord1) / 2 ) , + (coord3 - coord1) / -2); + break; + default: { + string o; + sprintf(o, "Route error:\nLayer=%d\n%.2f\n%.2f\n%.2f\nN#%d\nC=%d\nT=%d\nO=%d\n", + layer, coord1, coord2, coord3, Netnr, Code, Type,Orient); + if (dlgMessageBox(o, "&Yes", "&No") != 0) exit (0); + } + } + return ; + } +void arcDraw( int Layer, real X, real Y, real Radius, real arcs, real arce, int Netnr, int TraceCode, string TraceType) { + string as; + sprintf (as, " Change Layer %s;\n", refLayer[Layer]); + if (arce == 360) { + sprintf (as, " Circle (%.3f %.3f) (%.3f %.3f);\n",X, Y, X + Radius, Y); + arcscript += as; + } + else { + real arcStart = 360 + (arcs); + if (arcStart > 360) arcStart -= 360; + real arcEnd = arcStart + (arce); + if (arcEnd > 360) arcEnd -= 360; + real xArcStart = Radius * cos(PI / 180 * arcStart); + real yArcStart = Radius * sin(PI / 180 * arcStart); + real xArcEnd = Radius * cos(PI / 180 * arcEnd); + real yArcEnd = Radius * sin(PI / 180 * arcEnd); + sprintf (as, " ARC CCW (%.3f %.3f) (%.3f %.3f) (%.3f %.3f);\n", + X + xArcStart, Y + yArcStart, + X - xArcStart, Y - yArcStart, + X + xArcEnd, Y + yArcEnd); + arcscript += as; + } + return; +} +string scriptheader(void) { + string scrh = "Grid " + Grid + " FINEST;\n"; + scrh += "Grid ON;\nSET UNDO_LOG OFF;\nSET WIRE_BEND 2;\n"; + scrh += "LAYER 125 Alias;\n"; + return scrh ; + } +string readTstring(void) { + string s = ""; + do { + if (c[n] == cr) { + n++; + return s; + } + else { + s += c[n]; + n++; + } + } while (c[n]); + } +string read(char srch, int rdlf) { + string s = ""; + do { + if (c[n] != ' ') { + break; + } + else n++; + } while (c[n]); + do { + if (c[n] != cr) { + break; + } + else n++; + } while (c[n]); + do { + if (c[n] != lf) { + break; + } + else { + n++; + if (rdlf) { + return s; + } + } + } while (c[n]); + do { + if (c[n] == ';' || c[n] == ':') { + if (s == "") { + string cc; + sprintf(cc, "%c", c[n]); + return cc; + } + else return s; + } + if (c[n] == srch || c[n] == cr) { + n++; + return s; + } + else { + s += c[n]; + n++; + } + } while (c[n]); + return s; + } +string readstring(char separ, char eol, char sepline) { + string sline = ""; + do { + string wx = read(separ, 0); + if (wx[0] ==eol || wx[0] == sepline) { + if ( sline == "") { + return wx; + } + else return sline; + } + string wy = read(separ, 1); + sprintf(st, "(%s %s) ", format(val2mil(wx)), format(val2mil(wy))); + sline += st; + } while (c[n]); + sprintf(st, "%d", n); + if(dlgMessageBox( "Progr. end by counter " + st , "&Yes", "&No") != 0) exit (0); + exit (0); + } +void Headerfield(void) { + n++; + costomer = read(lf, 0); + versionnumb = read(' ', 0); + revisionnum = read(' ', 0); + for (int v = 0; v < VersionCnt; v++) { + if (versionnumb + revisionnum == ULTIversion[v]) { + xScale = 1 / ULTIscale[v]; + rotatemultiple = rotatemult[v]; + break; + } + } + printf("%s", scriptheader()); + boardoutline[1] = strtol(read(',', 0)); + boardoutline[2] = strtol(read(',', 0)); + boardoutline[3] = strtol(read(',', 0)); + boardoutline[4] = strtol(read(',', 0)); + def_grid = strtol(read(',', 0)); + int grid_step = strtol(read(',', 0)); + string swaplevel = read(',', 0); + int max_layers = strtod(read(';', 0)); + n++; + string layerlaminat = read(' ', 0); + refpointx = strtol(read(',', 0)); + refpointy = strtol(read(cr, 0)); + string routeroptions[]; + int x = 0; + routeroptions[0] = read(' ', 0); + st = routeroptions[0] ; + do { + x++; + routeroptions[x] = read(' ', 1); + st += " " + routeroptions[x]; + } while (routeroptions[x] != ""); + x = 1; + layerDirection[x] = read(' ', 0); + do { + st += "\nLayer " + refLayer[x] + "=" + layerDirection[x]; + x++; + layerDirection[x] = read(' ', 1); + } while (layerDirection[x] != ""); + string powerplanes[]; + for (int p = 1; p <= 32; p++) { + powerplanes[p] = read(' ', 0); + } + return ; + } +void padset(void) { + n++; + string padsetword = read(cr, 1); + return ; + } +void TraceCode(void) { + n++; + string nb = read(',', 0); + int number = strtol(nb); + tracewidth[number] = strtol(read(',', 0)); + traceclearance[number] = strtol(read(cr, 1)); + return ; + } +void Drilltolerance(void) { + n++; + drilltolerance = strtol(read(' ', 0)); + drilltolerancevalue = strtol(read(cr, 0)); + return ; + } +void DrillCode(void) { + n++; + string nb = read(',', 0); + int number = strtol(nb); + drillcode[number] = strtod(read(cr, 1)); + return ; + } +void PadDefinitionInner(void) { + n++; + string nb = read(',', 0); + int number = strtol(nb); + pad0innerX1[number] = strtol(read(',',0)); + pad0innerX2[number] = strtol(read(',',0)); + pad0innerY[number] = strtol(read(',',0)); + pad0innerRadius[number] = strtol(read(',',0)); + pad0innerClear[number] = strtol(read(',',0)); + pad0innerHorizont[number] = strtol(read(',',0)); + pad0innerVertical[number] = strtol(read(',',0)); + pad0innerThermH[number] = strtol(read(',',0)); + pad0innerThermV[number] = strtol(read(cr, 1)); + return ; +} +void PadDefinitionTop(void) { + n++; + string nb = read(',', 0); + int number = strtol(nb); + pad1topX1[number] = strtol(read(',', 0)); + pad1topX2[number] = strtol(read(',', 0)); + pad1topY[number] = strtol(read(',', 0)); + pad1topRadius[number] = strtol(read(',', 0)); + pad1topClear[number] = strtol(read(',', 0)); + pad1topHorizont[number] = strtol(read(',', 0)); + pad1topVertical[number] = strtol(read(',', 0)); + pad1topThermH[number] = strtol(read(',', 0)); + pad1topThermV[number] = strtol(read(cr, 1)); + return ; + } +void PadDefiniBottom(void) { + n++; + string nb = read(',', 0); + int number = strtol(nb); + pad2bottomX1[number] = strtol(read(',', 0)); + pad2bottomX2[number] = strtol(read(',', 0)); + pad2bottomY[number] = strtol(read(',', 0)); + pad2bottomRadius[number] = strtol(read(',', 0)); + pad2bottomClear[number] = strtol(read(',', 0)); + pad2bottomHorizont[number] = strtol(read(',', 0)); + pad2bottomVertical[number] = strtol(read(',', 0)); + pad2bottomThermH[number] = strtol(read(',', 0)); + pad2bottomThermV[number] = strtol(read(cr, 1)); + return ; + } +void WaveSolderDir(void) { + n++; + string WaveSolder = read(' ', 0); + string WaveSolderDir = read(' ', 0); + string WaveSolderClear = read(cr, 1); + return ; + } +void testxy(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int ox, int oy) { + sprintf(st, "s(%s %s)\n2(%s %s)\n3(%s %s)\n4(%s %s)\no(%s %s)" , + format(v2mil(x1)), format(v2mil(y1)), + format(v2mil(x2)), format(v2mil(y2)), + format(v2mil(x3)), format(v2mil(y3)), + format(v2mil(x4)), format(v2mil(y4)), + format(v2mil(ox)), format(v2mil(oy)) ); + dlgDialog("Koordinaten?") { + dlgTextEdit(st); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+Yes") dlgAccept(); + dlgStretch(1); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(0); + } + }; + return ; + } +void outlinedescript(void) { + int x, y; + int wcnt = 0; + string w = ""; + string wire = ""; + string h; + int n; + sprintf(h, "CHANGE LAYER 21;\n"); + wire += h; + do { + w = read(',', 0); + if (w == ";") { + break; + } + x = strtod(w); + y = strtod(read(',', 0)); + if ( (x & 1) == 1) { + wire += ";wire\n"; + sprintf (h, "(%s %s)\n", format(v2mil(x - 1)), format(v2mil(y)) ); + } + else { + sprintf (h, "(%s %s)\n", format(v2mil(x)), format(v2mil(y)) ); + } + wire += h; + wcnt++; + } while (c[n]); + wire += ";\n"; + printf("%s", wire); + return ; + } +void pindescript(void) { + do { + string padcode = read(',', 0); + if (strrchr(padcode, ';') == 0) { + n++; + return ; + } + int pcodnumber = strtol(padcode); + real padcodeRotation = strtod(read(',', 0)) / rotatemultiple; + int padcodelayerset = strtol(read(',', 0)); + real padcoderelx = val2mil(read(',', 0)); + real padcoderely = val2mil(read(',', 0)); + string padcodepinname = read(',', 1); + refPinNr[cntrefPin] = padcodepinname; + cntrefPin++; + real px1 = v2mil(pad2bottomX1[pcodnumber]); + real px2 = v2mil(pad2bottomX2[pcodnumber]); + real py = v2mil(pad2bottomY[pcodnumber]); + real prad = v2mil(pad2bottomRadius[pcodnumber]); + real pc = v2mil(pad2bottomClear[pcodnumber]); + real ph = v2mil(pad2bottomHorizont[pcodnumber]); + real pv = v2mil(pad2bottomVertical[pcodnumber]); + real pth = v2mil(pad2bottomThermH[pcodnumber]); + real ptv = v2mil(pad2bottomThermV[pcodnumber]); + real centeroffset = (px1 - px2); + real px = px1 + px2; + int pdril = drillcode[pcodnumber]; + if(pdril != 0) { + printf("CHANGE DRIll %s;\n", format(v2mil(drillcode[pcodnumber])) ); + } + printf("CHANGE LAYER 48;\n"); + printf("CHANGE SIZE 32;\n"); + if (py == 0) { + dlgDialog("Warning") { + dlgHBoxLayout { + dlgStretch(1); + dlgLabel(""); + dlgStretch(1); + } + dlgLabel( "Package: "+ shapename + ";\nPad : " + padcodepinname + " / PadCode = " + padcode + "\n\nY-Value is zerro = 0; changed to 1 Mil\n", 1); + dlgPushButton("+&Accept") dlgAccept(); + dlgPushButton("-&Cancel") { dlgReject(); exit(-1); } + py = 1; + px = 1; + }; + } + printf("CHANGE LAYER 21;\n"); + if(pdril == 0) { + int roundness = prad / (py / 200) ; + printf("CHANGE LAYER %s;\n", refLayer[padcodelayerset]); + if (centeroffset == 0) { + if (padcodeRotation == 90 || padcodeRotation == 270) { + printf("SMD %.3f %.3f -%d '%s' (%s %s);\n", py, px, roundness, padcodepinname, format(padcoderelx), format(padcoderely) ); + } + else { + printf("SMD %.3f %.3f -%d '%s' (%s %s);\n", px, py, roundness, padcodepinname, format(padcoderelx), format(padcoderely) ); + } + } + else { + printf("SMD %.3f %.3f -%d '%s' (%s %s);\n", px, py, roundness, padcodepinname, format(padcoderelx), format(padcoderely) ); + } + } + else { + if (centeroffset == 0 && px == py) { + if (prad < px / 2) { + printf("CHANGE SHAPE SQUARE;\n"); + } + else { + printf("CHANGE SHAPE ROUND;\n"); + } + printf("CHANGE DIAMETER %s;\n", format(px) ); + } + else { + if (centeroffset == 0) { + if (padcodeRotation == 90 || padcodeRotation == 270) { + printf("CHANGE SHAPE YLongOct;\n"); + printf("CHANGE DIAMETER %s;\n", format(py) ); + } + else { + printf("CHANGE SHAPE XLongOct;\n"); + printf("CHANGE DIAMETER %s;\n", format(py) ); + } + } + else { + printf("CHANGE SHAPE OCTAGON;\n"); + if (py > px1 || py > px2) { + printf("CHANGE DIAMETER %s;\n", format(py) ); + } + else { + printf("CHANGE DIAMETER %s;\n", format(px2) ); + } + } + } + printf("PAD '%s' (%s %s);\n", padcodepinname, format(padcoderelx), format(padcoderely) ); + } + } while (c[n]); + return ; + } +void arcdescript(void) { + do { + string arcxs = read(',', 0); + if (strrchr(arcxs, ';') == 0) { + n++; + return ; + } + real arcx = val2mil(arcxs); + real arcy = val2mil(read(',', 0)); + real arcradius = val2mil(read(',', 0)); + real ang1 = strtod(read(',', 0)) / rotatemultiple ; + real ang2 = strtod(read(',', 1)) / rotatemultiple ; + printf("CHANGE LAYER 21;\n"); + if(ang1 == 0 && ang2 == 360) { + printf("CIRCLE (%s %s) (%s %s);\n", format(arcx), format(arcy), format(arcx - arcradius), format(arcy) ); + } + else { + real endangle = ang1 + ang2; + if (endangle >= 360) { + endangle -= 360; + } + real startXarc = arcradius * cos(PI / 180 * ang1); + real startYarc = arcradius * sin(PI / 180 * ang1); + real endXarc = arcradius * cos(PI / 180 * endangle); + real endYarc = arcradius * sin(PI / 180 * endangle); + printf("ARC CCW (%s %s) (%s %s) (%s %s);\n", + format(arcx + startXarc), format(arcy + startYarc), + format(arcx - startXarc), format(arcy - startYarc), + format(arcx + endXarc), format(arcy + endYarc) ); + } + } while (c[n]); + return ; + } +void ShapeDef(void) { + n++; + shapename = read(cr, 1); + printf("EDIT '" + shapename + ".PAC';\n"); + printf("CHANGE FONT VECTOR;\n"); + real ShapeNameRelx = val2mil(read(' ', 0)); + real ShapeNameRely = val2mil(read(' ', 0)); + real ShapeNameHeight = val2mil(read(' ', 0)); + real ShapeNameRotate = strtod(read(' ', 0)); + real ShapeNameWidth = val2mil(read(' ', 0)); + real ShapeNameThickness = strtod(read(' ', 1)); + real AliasNameRelx = val2mil(read(' ', 0)); + real AliasNameRely = val2mil(read(' ', 0)); + real AliasNameHeight = val2mil(read(' ', 0)); + real AliasNameRotate = strtod(read(' ', 0)); + real AliasNameWidth = val2mil(read(' ', 0)); + real AliasNameThickness = strtod(read(' ', 1)); + if (ShapeNameHeight == 0) { + ShapeNameHeight = 1; + } + real strglen2 = stringLength(shapename, ShapeNameHeight) / 2; + printf ("CHANGE SIZE %s;\n", format(ShapeNameHeight ) ); + printf ("CHANGE LAYER 25;\n"); + printf ("TEXT '>NAME' (%s %s);\n", format(ShapeNameRelx - strglen2), format(ShapeNameRely - (ShapeNameHeight / 2)) ); + if (AliasNameHeight == 0) { + AliasNameHeight = 1; + } + strglen2 = stringLength(shapename, AliasNameHeight) / 2; + printf ("CHANGE SIZE %s;\n", format(AliasNameHeight) ); + printf ("CHANGE LAYER 27;\n"); + printf ("TEXT '>VALUE' (%s %s);\n", format(AliasNameRelx), format(AliasNameRely- (AliasNameHeight / 2)) ); + n++; + string RthJuncBoard = read(cr, 1); + outlinedescript(); + n++; + cntShape++; + pointPackPin[cntShape] = cntrefPin; + refPackname[cntShape] = shapename; + pindescript(); + arcdescript(); + return ; + } +string nnameCheck(string name, int nb) { + name = strsub(name, 1); + if (name == "") { + sprintf(name, "SB$%d", nb); + } + int ch; + do { + ch = strchr( name, '\''); + if (ch == -1) break; + else name[ch] = '/'; + } while (ch != -1); + return name; + } +void NetDef(void) { + n+= 2; + net++; + netname[net] = read(' ' ,0); + if(netname[net] == "65535") { + netname[net] = ""; + dlgMessageBox("NEt 65535","OK"); + } + nettracecode[net] = strtod(read(' ' ,0)); + netxlo[net] = strtol(read(' ' ,0)); + netxhi[net] = strtol(read(' ' ,0)); + netylo[net] = strtol(read(' ' ,0)); + netyhi[net] = strtol(read(' ' ,0)); + netxsum[net] = strtol(read(' ' ,0)); + netysum[net] = strtol(read(' ' ,0)); + netpincount[net] = strtod(read(';' ,1)); + netname[net] = nnameCheck(netname[net], net); + return ; + } +string GenNet(void) { + string sign = ""; + for (int s = 0; s <= net; s++) { + string sig; + sprintf(sig, "SIGNAL '%s'\n%s\n", netname[s], signal[s] ); + sign += sig; + } + return sign; + } +void ComponentDef(void) { + n += 1; + comp++; + string componentName = read(' ', 0); + string componentAlias = read(' ', 0); + string componentShapename = read(cr, 1); + real componentX = val2mil(read(',', 0)); + real componentY = val2mil(read(',', 0)); + real componentRotate = strtod(read(',', 0)) / rotatemultiple; + real componentNameX = val2mil(read(',', 0)); + real componentNameY = val2mil(read(',', 0)); + real componentNameRotate = strtod(read(',', 0)) / rotatemultiple; + real componentNameHeight = val2mil(read(',', 0)); + real componentNameWidth = val2mil(read(',', 0)); + real componentNameThick = strtod(read(',', 0)); + real componentAliasX = val2mil(read(',', 0)); + real componentAliasY = val2mil(read(',', 0)); + real componentAliasRotate = strtod(read(',', 0)) / rotatemultiple; + real componentAliasHight = val2mil(read(',', 0)); + real componentAliasWidth = val2mil(read(',', 0)); + real componentAliasThick = val2mil(read(cr, 1)); + string ca; + sprintf(ca, "CHANGE LAYER 27;\n"); + cmdvalue += ca; + if (componentAliasHight == 0) componentAliasHight = 1; + sprintf (ca, "change size %s;\n", format(componentAliasHight) ); + cmdvalue += ca; + if (componentAliasThick <= 0) componentAliasThick = 50; + sprintf (ca, "change ratio %.0f;\n", componentAliasThick / 100 * TextRatio ); + cmdvalue += ca; + sprintf(ca, "TEXT '%s' R%.0f (%s %s);\n", componentAlias, componentAliasRotate, format(componentAliasX), format(componentAliasY) ); + cmdvalue += ca; + real stringlengh_2 = stringLength(componentName, componentNameHeight ) / 2; + sprintf(ca, "%s\n%.2f\n%.0f\n%s\n%s\n", componentName, stringlengh_2, componentNameRotate, format(componentNameX), format(componentNameY) ); + cmdchname += ca; + sprintf (ca, "%s\n", format(componentNameHeight) ); + cmdchname += ca; + sprintf (ca, "%.0f\n", componentNameThick / 100 * TextRatio ); + cmdchname += ca; + real componentXforceVect = val2mil(read(',', 0)); + real componentYforceVect = val2mil(read(',', 0)); + real componentTempcase = val2mil(read(',', 0)); + real componentTempjunc = val2mil(read(',', 0)); + real componentPower = val2mil(read(',', 0)); + real componentRTHjuncboard = val2mil(read(',', 0)); + real nul = val2mil(read(cr, 0)); + sprintf(st, "ADD %s '%s' R%.0f (%s %s);\n", componentShapename, componentName, componentRotate, format(componentX), format(componentY) ); + brd += st; + sprintf(st, "SMASH (%s %s);\n", format(componentX), format(componentY) ); + brd += st; + int pin = 0; + int z = 0; + for ( int p = 0 ; p <= cntShape ; p++ ) { + if ( componentShapename == refPackname[p]) { + z = pointPackPin[p]; + break ; + } + } + do { + string componentNetNr = read(' ', 0); + string componentPadSetting = read(' ', 1); + if (componentNetNr == ";") break; + int NetNr = strtod(componentNetNr); + if (NetNr <= net) { + string sig; + sprintf(sig, "%s %s\n", componentName, refPinNr[z + pin]); + signal[NetNr] += sig; + pin++; + } + } while (c[n]); + n--; + return ; + } +void LTrace(void) { + n++; + int Tracelayer = strtol(read(' ', 0)); + real Tracecoord1 = strtod(read(cr, 0)); + n++; + do { + string Tracec2 = read(' ', 0); + if (Tracec2 == ";") { n++; break;} + real Tracecoord2 = strtod(Tracec2); + real Tracecoord3 = strtod(read(' ', 0)); + int TraceNetnr = strtol(read(' ', 0)); + int TraceCode = strtol(read(' ', 0)); + int TraceType = strtol(read(' ', 0)); + int TraceOrient = strtol(read(' ', 0)); + route(Tracelayer, Tracecoord1, Tracecoord2, Tracecoord3, TraceNetnr, TraceCode, TraceType, TraceOrient); + } while (c[n]); + return ; + } +void LVector() { + n++; + int VectLayer = strtod(read(' ', 0)); + real VectX1 = strtol(read(' ', 0)); + real VectY1 = strtol(read(' ', 0)); + real VectX2 = strtol(read(' ', 0)); + real VectY2 = strtol(read(' ', 0)); + int VectNetnr = strtod(read(' ', 0)); + int VectTraceCode = strtod(read(' ', 0)); + string VectTraceType = read(cr, 1); + rwire(VectNetnr, VectLayer, VectX1, VectY1, VectX2, VectY2); + return ; + } +void LArc(void) { + n++; + int ArcLayer = strtod(read(' ', 0)); + real ArcX = val2mil(read(' ', 0)); + real ArcY = val2mil(read(' ', 0)); + real ArcRadius = val2mil(read(' ', 0)); + real Arc1 = strtol(read(' ', 0)) / rotatemultiple; + real Arc2 = strtol(read(' ', 0)) / rotatemultiple; + int ArcNetnr = strtod(read(' ', 0)); + int ArcTraceCode = strtod(read(' ', 0)); + string ArcTraceType = read(cr, 1); + arcDraw( ArcLayer, ArcX, ArcY, ArcRadius, Arc1, Arc2, ArcNetnr, ArcTraceCode, ArcTraceType); + return ; + } +string polygonstart(void) { + string polygx1 = read(' ', 0); + string polygy1 = read(' ', 0); + string polystart; + sprintf(polystart, "(%s %s) ", format(val2mil(polygx1)), format(val2mil(polygy1))); + return polystart; + } +void LPolygon(void) { + n++; + int PolyLayer = strtod(read(' ', 0)); + int PolyNetnr = strtod(read(' ', 0)); + string PolyPattern = read(' ', 0); + string PolyDummy = read(' ', 0); + int PolyDist = strtod(read(' ', 0)); + int PolyCode = strtod(read(' ', 0)); + int PolyClearance = strtod(read(' ', 0)); + string PolyType = read(cr, 1); + string pld; + sprintf(pld , "\n Layer %d\n Net %s\n Pattern %s\n Dist %d\n Code %d\n Clearance %d\n Type %s\n Dummy %s", + PolyLayer, + netname[PolyNetnr], + PolyPattern, + PolyDist, + PolyCode, + PolyClearance, + PolyType, + PolyDummy + ); + n++; + polygon += "CHANGE LAYER " + refLayer[PolyLayer] + ";\n"; + polygon += "CHANGE ORPHANS ON;\n"; + polygon += "CHANGE WIDTH " + format(v2mil(nettracecode[PolyNetnr])) + ";\n"; + polygon += "CHANGE ISOLATE " + format(v2mil(PolyCode)) + ";\n"; + int fillpoly = 1; + string polystart = polygonstart(); + polygon += "POLYGON " + "'" + netname[PolyNetnr] + "' " + polystart ; + string TotalPolygon = ""; + do { + string TotalPolygon = readstring(' ', semikolon, polysepar); + if(TotalPolygon[0] == semikolon) { + n++; + polygon += ";\n"; + return; + } + if(TotalPolygon[0] == polysepar) { + n+= 3; + fillpoly = 0; + polystart = polygonstart(); + if (fillpoly) { + polygon += ";\nPOLYGON " + "'" + netname[PolyNetnr] + "' " + polystart ; + } + TotalPolygon = ""; + } + else { + if (fillpoly) { + polygon += TotalPolygon; + TotalPolygon = ""; + polygon += polystart; + } + polystart = polygonstart(); + } + } while (c[n]); + } +void ViaList(void) { + n++; + string via; + int ViaX = strtod(read(cr, 1)); + do { + string VY = read(' ', 0); + if (VY == ";") break; + int ViaY = strtod(VY); + int ViaNetnr = strtod(read(' ', 0)); + int ViaPadCode = strtod(read(' ', 0)); + string ViaPadSetting = read(' ', 0); + real ViaPadRotation = strtol(read(' ', 0)) / 32; + int ViaPadShift = strtod(read(' ', 0)); + string ViaIndex = read(' ', 0); + string ViaGLueFlag = read(';', 1); + sprintf(via , "CHANGE SHAPE ROUND;\n"); + brd += via; + sprintf(via , "CHANGE DIAMETER %s;\n", format(v2mil( pad2bottomY[ViaPadCode])) ); + brd += via; + sprintf(via , "CHANGE DRILL %s;\n", format(v2mil( drillcode[ViaPadCode])) ); + brd += via; + sprintf(via , "VIA '%s' (%s %s);\n", netname[ViaNetnr], format(v2mil(ViaX)), format(v2mil(ViaY)) ); + brd += via; + } while (c[n]); + return ; + } +void Text(void) { + n++; + string text; + real TextX = strtod(read(' ', 0)); + real TextY = strtod(read(' ', 0)); + real TextHeight = strtod(read(' ', 0)); + real TextWidth = strtod(read(' ', 0)); + real TextThick = strtod(read(' ', 0)); + real TextRotation = strtod(read(' ', 0)) / rotatemultiple; + int TextLayer = strtod(read(' ', 0)); + string TextString = readTstring(); + real strgLength2 = stringLength( TextString, TextHeight) / 2; + sprintf(text, "CHANGE SIZE %s\n", format(v2mil(TextHeight)) ); + brd += text; + sprintf( text, "CHANGE LAYER %s;\n", refLayer[TextLayer]); + brd += text; + int ro = TextRotation; + if (TMrefLayer[TextLayer] == "M") { + strgLength2 = (strgLength2 * -1); + } + switch (ro) { + case 0 : sprintf(text , "TEXT '%s' %sR%.0f (%s %s);\n", + TextString, TMrefLayer[TextLayer], TextRotation, + format(v2mil(TextX - (strgLength2))), format(v2mil(TextY - (TextHeight / 2))) ); + break; + case 90 : sprintf(text , "TEXT '%s' %sR%.0f (%s %s);\n", + TextString, TMrefLayer[TextLayer], TextRotation, + format(v2mil(TextX + (TextHeight / 2))), format(v2mil(TextY - (strgLength2))) ); + break; + case 180 : sprintf(text , "TEXT '%s' %sR%.0f (%s %s);\n", + TextString, TMrefLayer[TextLayer], TextRotation, + format(v2mil(TextX + (strgLength2))), format(v2mil(TextY + (TextHeight / 2))) ); + break; + case 270 : sprintf(text , "TEXT '%s' %sR%.0f (%s %s);\n", + TextString, TMrefLayer[TextLayer], TextRotation, + format(v2mil(TextX - (TextHeight / 2))), format(v2mil(TextY + strgLength2)) ); + break; + } + brd += text; + return ; + } +void RecTechnology(void) { + n++; + switch (c[n]) { + case 'P' : padset(); + break; + case 'T' : TraceCode(); + break; + case 'C' : Drilltolerance(); + break; + case 'D' : DrillCode(); + break; + case '0' : PadDefinitionInner(); + break; + case '1' : PadDefinitionTop(); + break; + case '2' : PadDefiniBottom(); + break; + case 'S' : WaveSolderDir(); + break; + } + return ; + } +void SubRecordL(void) { + n++; + switch (c[n]) { + case 'T' : LTrace(); + break; + case 'V' : LVector(); + break; + case 'A' : LArc(); + break; + case 'P' : LPolygon(); + break; + } + return ; + } +void Record(void) { + n++; + switch (c[n]) { + case 'P' : Headerfield(); + break; + case 'T' : RecTechnology(); + break; + case 'S' : ShapeDef(); + break; + case 'N' : NetDef(); + break; + case 'C' : ComponentDef(); + break; + case 'L' : SubRecordL(); + break; + case 'V' : ViaList(); + break; + case 'X' : Text(); + break; + } + return ; +} +void BRDTrailer(void) { + printf("CHANGE LAYER 20;\n"); + printf("SET WIRE_BEND 0;\n"); + printf("WIRE 0 (%s %s) (%s %s) (%s %s) ;\n", + format(v2mil(boardoutline[1])), + format(v2mil(boardoutline[2])), + format(v2mil(boardoutline[3])), + format(v2mil(boardoutline[4])), + format(v2mil(boardoutline[1])), + format(v2mil(boardoutline[2])) + ); + printf("CHANGE SIZE 50;\n"); + real tx; + if (boardoutline[1] < boardoutline[3]) tx = boardoutline[1]; + else tx = boardoutline[3]; + real ty; + if (boardoutline[2] > boardoutline[4]) ty = boardoutline[2]; + else ty = boardoutline[4]; + int yy = 75; + printf("# 'ULTIBOARD - %s Version %s Revision %s' (%s %s);\n", costomer, versionnumb, revisionnum, format(v2mil(tx)) ,format(v2mil(ty) + yy) ); + yy += 75; + printf("# 'with import filter : %s %s' (%s %s);\n", filter, Version, format(v2mil(tx)) ,format(v2mil(ty) + yy) ); + yy += 75; + printf("# 'converted from ULTIBOARD-DDF file : %s at %s' (%s %s);\n", ddffile, t2string(time()), format(v2mil(tx)) ,format(v2mil(ty) + yy) ); + yy += 75; + printf("# '%s' (%s %s);\n", EAGLE_SIGNATURE, format(v2mil(tx)) ,format(v2mil(ty) + yy) ); + yy += 75; + } +void sign() { + printf("# %s\n", EAGLE_SIGNATURE); + printf("# Script converted from ULTIBOARD-DDF file : %s at %s\n", ddffile, t2string(time()) ); + printf("# with %s\n\n", filter ); + return; + } +void LBRdescript(void) { + printf("Description 'Library converted from ULTIBOARD-DDF file :

    \\n\\\n %s at %s

    \\n\\\n with import filter : %s';\n", ddffile, t2string(time()), filter ); + } +void ULPhelp(void) { + dlgDialog("Import ddf help") { + dlgStretch(0); + dlgHBoxLayout { + dlgSpacing(500); + } + dlgStretch(0); + dlgLabel(usage, 1); + dlgStretch(0); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+&OK") dlgAccept(); + dlgStretch(0); + dlgPushButton("-&Cancel") {dlgReject(); exit(0);} + dlgStretch(1); + dlgPushButton("&Version Info") dlgMessageBox(ULTIBoardinfo, "OK"); + dlgStretch(0); +// dlgPushButton("Hilf&e") dlgMessageBox(InfoDE, "OK"); +// dlgStretch(0); + dlgPushButton("&Help") dlgMessageBox(InfoUS, "OK"); + dlgStretch(0); + } + dlgStretch(1); + }; + } +void main(void) { + if (board) board(B) { + char bkslash = '/'; + int pos = strrchr(argv[0], bkslash); + if (argv[1] == "") ULPhelp(); + if (argv[1] == "PASS2") importpass2(); + else { + if (pos >= 0) { + ulp_path = strsub(argv[0], 0, pos + 1); + } + filter = strsub(argv[0], pos + 1); + fileName = dlgFileOpen("Select a DDF-File", "", "*.ddf"); + } + if (!fileName) exit (0); + string changetextfile = filesetext(fileName, tmpchtxtfile); + string scriptfile = filesetext(fileName, tmpextfile); + pos = strrchr(fileName, bkslash); + ddffile = strsub(fileName, pos + 1); + nBytes = fileread(c, fileName); + output(scriptfile, "wt") { + sign(); + printf("OPEN '%s';\n", filesetext(fileName, ".lbr")); + LBRdescript(); + do { + switch (c[n]) { + case 0: + break; + case '*': Record(); + break; + case ';': break; + case 10: + break; + case 12: + break; + case 13: + break; + case 27: cmd += "\nEscape\n"; + break; + default: test(c[n]); + break; + } + n++; + } while (n <= nBytes); + printf("SET UNDO_LOG ON;\n"); + printf("WRITE\n"); + printf("CLOSE;\n"); + sign(); + printf("EDIT '%s'\n", filesetext(fileName, ".brd") ); + printf("SET VECTOR_FONT ON;\n"); + printf("%s", scriptheader()); + printf("USE -*;\n"); + printf("USE '%s';\n",filesetext(fileName, ".lbr") ); + printf("\n%s\nWINDOW FIT;\n", brd); + printf("%s\n", GenNet() ); + printf("%s\n", cmdroute); + printf("%s\n", arcscript); + if (polygon) printf("%s\n", polygon); + printf("RATSNEST;\n"); + BRDTrailer(); + printf("SET UNDO_LOG ON;\n"); + printf("WINDOW FIT;\n"); + printf("WRITE;\n"); + printf("RUN '%s' 'PASS2' '%s';\n", argv[0], changetextfile); + } + output(changetextfile, "wt") { + printf("%s\n", cmdchname); + } + string ecmd = "SCRIPT '" + scriptfile + "';\n"; + string r; + sprintf(r, "REMOVE '%s';\n", scriptfile); + ecmd += r; + sprintf(r, "REMOVE '%s';\n", filesetext(changetextfile, "$" + tmpextfile) ); + ecmd += r; + sprintf(r, "REMOVE '%s';\n", changetextfile); + ecmd += r; + exit (ecmd); + } + else { + dlgMessageBox( "ERROR:\nStart this ULP from a Board", "&OK") ; + } + } diff --git a/trunk/ulp/ipc-d-356.ulp b/trunk/ulp/ipc-d-356.ulp new file mode 100644 index 00000000..c29fdd46 --- /dev/null +++ b/trunk/ulp/ipc-d-356.ulp @@ -0,0 +1,143 @@ +#usage "Export IPC-D-356 data format\n" + "

    " + "Generates a netlist in IPC-D-356 format from the current board." + "

    " + "Please take care of net names. IPC-D-356 does not allow more than 14 characters! " + "Written for EAGLE 4.1. " + "

    " + "IPC-D-356 syntax generated according to the specifications of
    " + "
    " + "IPC-D-356 Simplified
    " + "Written by Rich Nedbal
    " + "DownStream Technologies, LLC
    " + "
    " + "

    " + "Author: support@cadsoft.de" + +#require 4.1602 + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED +// +// Release 1.0 -- November 2003 +// Release 1.0.1 -- May 2006, Added source of specification (ric) +// Release 2.0.0 -- 2012-02-29, values calculated with u2inch (alf) +// Release 2.0.1 -- 2012-03-13, corrected calulation of diameter (alf) +// now generate the same data as the original ulp up to V5. +// Release 2.0.2 -- corrected line 82, multiplicator 1000 -> 10000 + +string Version = "2.0.2"; + +string fileName, RefDes, Access, Xpolarity, Ypolarity, RestOfLine, NoDiameter; +int n, TypeNumber, Diameter, Xcoord, Ycoord, RectDataX, RectDataY, Angle ; + + +void Header(UL_BOARD B) { + printf("C IPC-D-356 generated by %s\n", EAGLE_SIGNATURE); + printf("C Database %s -- Exported at %s\n", B.name, t2string(time())); + //printf("C ULP-Version %s : Values = Inch/1000\n", Version); // 2012-03-13 + printf("C \n"); + printf("P JOB EAGLE %d.%d NETLIST, DATE: %s\n", EAGLE_VERSION, EAGLE_RELEASE , t2string(time())); + printf("P UNITS CUST 0\n"); + printf("P DIM N\n"); +} + + +void TestRecord(UL_BOARD B) { + B.signals(S) { + S.vias(V) { + TypeNumber = 317 ; + RefDes = "VIA"; + Diameter = round(u2inch(V.drill)*1000); + if (V.start == 1 && V.end == 16) Access = "A00"; ///gibts auch andere? + Xcoord = round(u2inch(V.x)*10000); + Ycoord = round(u2inch(V.y)*10000); + if (Xcoord >= 0) Xpolarity = "X "; + if (Xcoord < 0) Xpolarity = "X-"; + if (Ycoord >= 0) Ypolarity = "Y "; + if (Ycoord < 0) Ypolarity = "Y-"; + RectDataX = RectDataY = round(u2inch(V.diameter[V.start])*10000); + RestOfLine = " " ; // 13 blanks to fill up 80 characters + + printf("%3d%-14s %-12sD%4dP%-3s%2s%6d%2s%6dX%4dY%4d%-13s\n", + TypeNumber, S.name, RefDes, Diameter, Access, Xpolarity, abs(Xcoord), Ypolarity, abs(Ycoord), + RectDataX, RectDataY, RestOfLine); + } + } + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + TypeNumber = 317 ; + RefDes = E.name; + Diameter = round(u2inch(C.pad.drill)*1000); + Access = "A00"; + Xcoord = round(u2inch(C.pad.x)*10000); + Ycoord = round(u2inch(C.pad.y)*10000); + if (Xcoord >= 0) Xpolarity = "X "; + if (Xcoord < 0) Xpolarity = "X-"; + if (Ycoord >= 0) Ypolarity = "Y "; + if (Ycoord < 0) Ypolarity = "Y-"; + if (C.pad.elongation == 0) + RectDataX = RectDataY = round(u2inch(C.pad.diameter[LAYER_TOP])*10000); + else { // if (C.pad.elongation != 0) + RectDataX = round(u2inch(C.pad.diameter[LAYER_TOP])*10000); + RectDataY = round((u2inch(C.pad.diameter[LAYER_TOP])*10000) * (C.pad.elongation / 100) + u2inch(C.pad.diameter[LAYER_TOP])*10000); + } + Angle = round(C.pad.angle); + RestOfLine = " "; + + printf("%3d%-14s %-6s-%-4s D%4dP%-3s%2s%6d%2s%6dX%4dY%4dR%3d%-9s\n", + TypeNumber, C.pad.signal, RefDes, C.pad.name, Diameter, Access, + Xpolarity, abs(Xcoord), Ypolarity, abs(Ycoord), RectDataX, RectDataY, Angle, RestOfLine); + } + if (C.smd) { + TypeNumber = 327 ; + RefDes = E.name; + NoDiameter = " "; // No drill ==> coloum 33-38 empty + if (C.smd.layer == 1) Access = "A01"; + if (C.smd.layer == 16) Access = "A16"; + Xcoord = round(u2inch(C.smd.x)*10000); + Ycoord = round(u2inch(C.smd.y)*10000); + if (Xcoord >= 0) Xpolarity = "X "; + if (Xcoord < 0) Xpolarity = "X-"; + if (Ycoord >= 0) Ypolarity = "Y "; + if (Ycoord < 0) Ypolarity = "Y-"; + RectDataX = round(u2inch(C.smd.dx) * 10000) ; + RectDataY = round(u2inch(C.smd.dy) * 10000) ; + Angle = round(C.smd.angle); + RestOfLine = " "; + + printf("%3d%-14s %-6s-%-4s %-6s%-3s%2s%6d%2s%6dX%4dY%4dR%3d%-9s\n", + TypeNumber, C.smd.signal, RefDes, C.smd.name, NoDiameter, Access, + Xpolarity, abs(Xcoord), Ypolarity, abs(Ycoord), RectDataX, RectDataY, Angle, RestOfLine); + } + } + // B.holes(H) TypeNumber = 347 ; printf("%d", TypeNumber); + // E.package.holes(H) TypeNumber = 347 ; printf("%d", TypeNumber); + } +} + + +void EndOfFile(void) { + printf("999\n"); +} + +//==========main=========== + + +if (board) { + board(B) { + fileName = dlgFileSave("Save IPC-D-356 File", filesetext(B.name, ".ipc"), "*.ipc"); + if (fileName == "") exit(0); + + output(fileName) { + Header(B); + TestRecord(B); + EndOfFile(); + } + } +} + +else { + dlgMessageBox("!Start this ULP in a Board."); + exit (0); +} diff --git a/trunk/ulp/layer-sequence-arrowdown.png b/trunk/ulp/layer-sequence-arrowdown.png new file mode 100644 index 00000000..4f8f3167 Binary files /dev/null and b/trunk/ulp/layer-sequence-arrowdown.png differ diff --git a/trunk/ulp/layer-sequence-arrowup.png b/trunk/ulp/layer-sequence-arrowup.png new file mode 100644 index 00000000..8b735cda Binary files /dev/null and b/trunk/ulp/layer-sequence-arrowup.png differ diff --git a/trunk/ulp/layer-sequence.ulp b/trunk/ulp/layer-sequence.ulp new file mode 100644 index 00000000..0ba7f8fa --- /dev/null +++ b/trunk/ulp/layer-sequence.ulp @@ -0,0 +1,359 @@ +#usage "en:Set Layer Sequence for PRINT command.

    " + "For printing your drawing it might be important to determine the sequence of printed layers. " + "This ULP manages the 'Option.LayerSequence' setting in the file eaglerc.usr.

    " + "From HELP SET:
    " + "Option.LayerSequence
    " + "The internal layers are rendered in a sequence that mimics the actual layer stack, " + "so that the result looks useful even on printers and PDF or Postscript files, where " + "layers are not transparent. Sometimes user defined layers may need to be rendered before " + "internal layers instead of after them. This parameter can be used to define the " + "sequence in which layers are rendered. It consists of a string of layer numbers or " + "layer ranges, followed by an optional 't' or 'b'.
    " + "123 renders layer 123
    " + "123t renders layer 123 if the output is \"viewed from top\" (not mirrored)
    " + "123b renders layer 123 if the output is \"viewed from bottom\" (mirrored)
    " + "123-140 renders layers 123 through 140 in the given sequence
    " + "140-123 renders layers 140 through 123 in the given sequence
    " + "* inserts the default sequence of the internal layers
    " + "123b * 123t makes layer 123 always be rendered first
    " + "Note that each layer is rendered only once, even if it is listed several times. " + "The default sequence of the internal layers is:
    " + "48t 49t 19t 47t 20t 46t 23 27 25 59 57 55 53 50 51 21 44t 45t 37 35 31 29 33 39 41 43t 18t 17t 1-16 17b 18b 43b 42 40 34 30 32 36 38 45b 44b 22 52 54 56 58 60 26 28 24 46b 20b 47b 19b 49b 48b 61-99.
    " + "When viewed from top, the layer sequence is rendered from right to left, while " + "when viewed from bottom (mirrored) it is rendered from left to right. For instance, " + "layer 48 (Document) is entered as 48t and 48b to always have it rendered as the last one.
    " + "Layers 21 (tPlace) and 22 (bPlace), on the other hand, are listed only once, to have " + "them rendered at the proper place, depending on whether the output is mirrored or not.
    " + "Any layers that are not explicitly mentioned in the layer sequence are rendered after " + "the given sequence in ascending order.
    " + "

    " + "Author: alf@cadsoft.de" + , + "de:Layerreihenfolge für den Ausdruck festlegen.

    " + "Für den Ausdruck kann die Reihenfolge der Layer wichtig sein. Dieses ULP nutzt die Möglichkeit mit " + "'Option.LayerSequence' in der eaglerc.usr diese Reihenfolge fest zu legen.

    " + "Auszug aus HELP SET:
    " + "Option.LayerSequence
    " + "Die internen Layer werden in der Reihenfolge dargestellt, die dem tatsächlichen Lagenaufbau entspricht, " + "so dass das Ergebnis auch auf Druckern und PDF- bzw. Postscript-Dateien brauchbar aussieht, wo die Layer " + "nicht transparent sind. Manchmal kann es erforderlich sein, dass benutzerdefinierte Layer vor den internen " + "Layern dargestellt werden müssen, anstatt nach diesen. Mit diesem Parameter kann die Reihenfolge, in der " + "die Layer dargestellt werden, festgelegt werden. Er besteht aus einer Folge von Layer-Nummern bzw. " + "Layer-Bereichen, optional gefolgt von 't' oder 'b'.
    " + "123 stellt Layer 123 dar
    " + "123t stellt Layer 123 dar, wenn die Ausgabe \"von oben gesehen\" erfolgt (nicht gespiegelt)
    " + "123b stellt Layer 123 dar, wenn die Ausgabe \"von unten gesehen\" erfolgt (gespiegelt)
    " + "123-140 stellt die Layer 123 bis 140 in der angegeben Reihenfolge dar
    " + "140-123 stellt die Layer 140 bis 123 in der angegeben Reihenfolge dar
    " + "* fügt die Standard-Sequenz der internen Layer ein
    " + "123b * 123t sorgt dafür, dass Layer 123 immer als erster dargestellt wird
    " + "Beachten Sie, dass jeder Layer nur einmal dargestellt wird, auch wenn er mehrmals aufgeführt ist. " + "Die Standard-Sequenz der internen Layer ist:
    " + "48t 49t 19t 47t 20t 46t 23 27 25 59 57 55 53 50 51 21 44t 45t 37 35 31 29 33 39 41 43t 18t 17t 1-16 17b 18b 43b 42 40 34 30 32 36 38 45b 44b 22 52 54 56 58 60 26 28 24 46b 20b 47b 19b 49b 48b 61-99.
    " + "Bei Ansicht von oben, wird die Layer-Sequenz von rechts nach links abgearbeitet, während sie bei Ansicht " + "von unten (gespiegelt) von links nach rechts abgearbeitet wird. Zum Beispiel ist Layer 48 (Document) als " + "48t und 48b enthalten, damit dieser immer als letzter dargestellt wird.
    " + "Die Layer 21 (tPlace) und 22 (bPlace) hingegen sind nur jeweils einmal aufgelistet, damit Sie an der " + "richtigen Stelle erscheinen, je nachdem, ob die Ausgabe gespiegelt erfolgt oder nicht.
    " + "Alle nicht explizit in der Layer-Sequenz aufgeführten Layer werden nach der gegebenen Sequenz, in " + "aufsteigender Reihenfolge, dargestellt.
    " + "

    " + "Author: alf@cadsoft.de" + +string Version = "1.0.0"; // 2013-03-21 alf@cadsoft.de + +string Default_Sequence = "48t 49t 19t 47t 20t 46t 23 27 25 59 57 55 53 50 51 21 44t 45t 37 35 31 29 33 39 41 43t 18t 17t 1-16 17b 18b 43b 42 40 34 30 32 36 38 45b 44b 22 52 54 56 58 60 26 28 24 46b 20b 47b 19b 49b 48b"; +numeric string Lay[]; +int CntLS; + +string LayerSequence = cfgget("EAGLE:Option.LayerSequence", "48t 49t 19t 47t 20t 46t 23 27 25 59 57 55 53 50 51 21 44t 45t 37 35 31 29 33 39 41 43t 18t 17t 1-16 17b 18b 43b 42 40 34 30 32 36 38 45b 44b 22 52 54 56 58 60 26 28 24 46b 20b 47b 19b 49b 48b 61-99"); +string LayerSequenceUndo = LayerSequence; + +string LayerNam[]; +int LayerNum[]; +int Sel = 0; +int Srt = 0; + + + +/*** Functions ***/ +void help(void) { + dlgDialog("HELP LayerSequence") { + dlgLabel(usage); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; +} + +void selerror(void) { + if (language() == "de") dlgMessageBox("!Selektieren Sie erst eine Zeile in der Liste.", "ok"); + else dlgMessageBox("!First select a list entry.", "ok"); + return; +} + +string getnewlayer(void) { + int selnew = -1; + int srt = 0; + string newlayer = ""; + dlgDialog("Insert Layer Sequence") { + dlgHBoxLayout dlgSpacing(280); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgVBoxLayout { + dlgStretch(1); + dlgLabel("Layer num."); + dlgStringEdit(newlayer); + dlgStretch(1); + } + dlgListView("Layer", LayerNam, selnew, srt) { + if (selnew < 0) selerror(); + else { + if (strstr(LayerNam[selnew], "do not use") > 0) { + } + else sprintf(newlayer, "%d", selnew); + } + } + } + dlgHBoxLayout { + dlgPushButton("+OK") { + if (newlayer) { dlgAccept(); return newlayer+"\t"+LayerNam[selnew]; } + else dlgMessageBox("First select a layer", "OK"); + } + dlgPushButton("-CANCEL") dlgReject(); + dlgStretch(1); + } + }; + return ""; +} + +void MoveDown(int sel) { + if (sel < 0) { + selerror(); + return; + } + if (sel < CntLS-1) { + string t[]; + int cnt = strsplit(t, Lay[sel], '\t'); + string t1[]; + int cnt1 = strsplit(t1, Lay[sel+1], '\t'); + Lay[sel] = t[0]+"\t"+t1[1]+"\t"+ t1[2]; + Lay[sel+1] = t1[0]+"\t"+t[1]+"\t"+t[2]; + Sel++; + } + return; +} + +void MoveUp(int sel) { + if (sel < 0) { + selerror(); + return; + } + if (sel > 0) { + string t[]; + int cnt = strsplit(t, Lay[sel], '\t'); + string t1[]; + int cnt1 = strsplit(t1, Lay[sel-1], '\t'); + Lay[sel] = t[0]+"\t"+t1[1]+"\t"+ t1[2]; + Lay[sel-1] = t1[0]+"\t"+t[1]+"\t"+t[2]; + Sel--; + } + return; +} + +void Delete(int sel) { + if (sel < 0) { + selerror(); + return; + } + for (int n = sel; n < CntLS-1; n++) { + MoveDown(n); + } + CntLS--; + Sel = -1; + Lay[CntLS] = ""; + return; +} + +void Insert(int sel) { + if (sel < 0) sel = CntLS; // hänge es hinten dran + + string newlayer = getnewlayer(); + if (newlayer) { + sprintf(Lay[CntLS], "%d\t\%s\t%s", CntLS+1, newlayer, "layernew"); + CntLS++; + for (int n = CntLS-1; n > sel; n--) { + MoveUp(n); + } + Sel = sel; + } + return; +} + +void Optiont(int sel) { + if (sel < 0) { + selerror(); + return; + } + string l[]; + strsplit(l, Lay[sel], '\t'); + int len = strlen(l[1])-1; + if (l[1][len] == 't') return; + else if (l[1][len] == 'b') { + l[1][len] = 't'; + } + else { + l[1]+= "t"; + } + Lay[sel] = l[0]+"\t"+l[1]+"\t"+l[2]; + return; +} + +void Optionb(int sel) { + if (sel < 0) { + selerror(); + return; + } + string l[]; + strsplit(l, Lay[sel], '\t'); + int len = strlen(l[1])-1; + if (l[1][len] == 'b') return; + else if (l[1][len] == 't') { + l[1][len] = 'b'; + } + else { + l[1]+= "b"; + } + Lay[sel] = l[0]+"\t"+l[1]+"\t"+l[2]; + return; +} + +void DelOpt(int sel) { + if (sel < 0) { + selerror(); + return; + } + string l[]; + strsplit(l, Lay[sel], '\t'); + int len = strlen(l[1])-1; + if (l[1][len] == 'b' || l[1][len] == 't') l[1][len] = 0; + Lay[sel] = l[0]+"\t"+l[1]+"\t"+l[2]; + return; +} + +string gensequence(void) { + string l[]; + int n = 0; + strsplit(l, Lay[n], '\t'); + string setseq = l[1]; + for (n = 1; n < CntLS; n++) { + strsplit(l, Lay[n], '\t'); + setseq += " "+ l[1]; + } + return setseq; +} + +void setsequence(void) { + string setseq = gensequence(); + if (dlgMessageBox("Set sequence:\n"+setseq, "OK", "CANCEL") != 0) return; + cfgset("EAGLE:Option.LayerSequence", setseq); + return; +} + +void get_layer_name(string ls) { + if (project.schematic) project.schematic(SCH) SCH.layers(L) { + LayerNam[L.number] = L.name; + } + if (project.board) project.board(B) B.layers(L) { + LayerNam[L.number] = L.name; + } + for (int xl = 0; xl < 256; xl++) { + if (!LayerNam[xl]) sprintf(LayerNam[xl], "%d ~do not use~", xl); + } + string h; + CntLS = strsplit(Lay, ls, ' '); + int n = 0; + sprintf(Lay[n], "%d\t%s\t%s",n+1, Lay[n], LayerNam[strtol(Lay[n])]); + while (Lay[++n]) { + if(strchr(Lay[n], '-') < 1) sprintf(Lay[n], "%d\t%s\t%s",n+1, Lay[n], LayerNam[strtol(Lay[n])]); + else sprintf(Lay[n], "%d\t%s\t%s",n+1, Lay[n], "#"); + } + CntLS = n; + return; +} + + +void set_default(void) { + LayerSequence = Default_Sequence; + get_layer_name(LayerSequence); + return; +} + +void set_undo(void) { + LayerSequence = LayerSequenceUndo; + get_layer_name(LayerSequence); + return; +} + +void getEditLine(void) { + string layseq = gensequence(); + dlgDialog("Edit Layer Sequence") { + dlgHBoxLayout dlgSpacing(900); + dlgStringEdit(layseq); + dlgHBoxLayout { + dlgPushButton("OK") { dlgAccept(); get_layer_name(layseq); return; } + dlgPushButton("CANCEL") { dlgReject(); return; } + dlgStretch(1); + } + }; + return; +} + +get_layer_name(LayerSequence); +Sel = -1; +dlgDialog("Layer Sequence") { + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(700); + dlgVBoxLayout { + dlgPushButton("&Default") set_default(); + dlgPushButton("Edit") getEditLine(); + dlgStretch(1); + if (language() == "de") dlgPushButton("Verschieben &^") MoveUp(Sel); + else dlgPushButton("Move &^") MoveUp(Sel); + if (language() == "de") dlgPushButton("E&infügen") Insert(Sel); + else dlgPushButton("&Insert") Insert(Sel); + if (language() == "de") dlgPushButton("&Löschen") Delete(Sel); + else dlgPushButton("D&elete") Delete(Sel); + dlgPushButton("Option &t") Optiont(Sel); + dlgPushButton("Option &b") Optionb(Sel); + if (language() == "de") dlgPushButton("Lösche &Opt.") DelOpt(Sel); + else dlgPushButton("Del. &Opt.") DelOpt(Sel); + if (language() == "de") dlgPushButton("Verschieben &v") MoveDown(Sel); + else dlgPushButton("Move &v") MoveDown(Sel); + dlgStretch(1); + } + dlgListView("Num.\tLay.\tName", Lay, Sel, Srt); + dlgVBoxLayout { + dlgSpacing(22); + dlgLabel(""); // relativer Pfad + if (language() == "de") dlgLabel("Reihenfolge
    der Layer
    beim Ausdruck
    von unten
    (gespiegelt)"); + else dlgLabel("Layer sequence
    to print
    bottom view
    (mirrored)"); + dlgStretch(1); + dlgPushButton("&HELP") help(); + dlgStretch(1); + if (language() == "de") dlgLabel("Reihenfolge
    der Layer
    beim Ausdruck
    von oben
    (nicht gespiegelt)"); + else dlgLabel("Layer sequence
    to print
    top view
    (not mirrored)"); + dlgLabel(""); // relativer Pfad + } + } + dlgHBoxLayout { + dlgPushButton("E&XIT") dlgAccept(); + dlgStretch(1); + dlgPushButton("&SET") setsequence(); + dlgStretch(1); + dlgPushButton("&UNDO") set_undo(); + } +}; + diff --git a/trunk/ulp/length-freq-ri.ulp b/trunk/ulp/length-freq-ri.ulp new file mode 100644 index 00000000..29996f06 --- /dev/null +++ b/trunk/ulp/length-freq-ri.ulp @@ -0,0 +1,187 @@ +#usage "Create a list of all signals with various data\n" + "

    " + "Creates a list of all signals of a board, together " + "with their maximum frequency, length, area, resistance, " + "minimum and maximum width and maximum current." + "

    " + "This is a very simplified calculation for a first evaluation " + "of the layout." + "

    " + "Parallel tracks and polygons are not taken into consideration." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +/* German description: + "Dieses ULP berechnet alle Signallaengen eines Layouts

    " + "(nur Layer 1 bis 16) und die zugehoerige Frequenz (f=c/l) " + "und erzeugt eine Textdatei length-ri.txt, die alle Signale nach " + "Frequenz bzw Laenge sortiert enthaelt.

    " + "Bei der Frequenzberechnung handelt es sich um eine ganz einfache " + "Umrechnung, die eine erste Abschaetzung bzgl. Stoerstrahlung erlaubt.

    " + "Zusaetzlich wird die minimale und maximale Leiterbahnbreite ermittelt " + "und die daraus resultierende Strombelastung.

    " + "Bei der Widerstands- und Strombelastbarkeits-Berechnung wird die " + "minimale Leiterbahnbreite herangezogen.

    " + "Es wird auch keine eine Parallelführung bzw. Fläche (Polygon) " + "berücksichtigt.

    " + "A. Zaffran 05.04.2000 alf@cadsoft.de

    " +*/ + +real f, WLtotal; +int index[]; + + // ** aus "Mechanik der Elektronik" + // mm <1 1 2 3 4 5 6 7 8 9 10 11 12 13 mm Leiterbreite bei 35 um Cu + +real k[] = { 9, 8.8, 6, 4, 3.2, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9, 2.9 }; + + // _______________________ + // Imax ~ 5.25 V [d x b x (d + b)] x k || (tL ~60) + // + // d = um Cu-Kaschierung + // b = Breite mm + // k = Korrekturwert aus Tabelle 02.02.2000 alf + // ** aus "Mechanik der Elektronik" + +real Cu = 0.035; // 35 um Cu Kaschierung + +real Length[], Freq[], Widthmin[], Widthmax[]; +string Signal[]; + +real c = 299800; // Lichtgechwindigkeit Vakuum in [km/s] + +int n = 0; +int t; +string data[]; +string h; +string header; +int note = 0; + +void dialog(void) +{ + int select = 0; + int Result = dlgDialog("Wire length of Layout") { + dlgLabel(header); + string lab; + sprintf(lab, " Cu thickness = %.3f mm", Cu); + dlgLabel(lab); + dlgListView("", data, select); + dlgStretch(0); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+&Save") { + board(B) { + string FileName = dlgFileSave("Save list", filesetext(B.name, ".txt")); + if (FileName) { + output (FileName, "wt") { + printf("%s", header); + for (int x = 0; x < t; x++) + printf("%s\n", data[x]); + if (note) { + sprintf( h, "\n *** note wire width.\n"); + data[t] += h; + t++; + } + } + } + } + } + dlgPushButton("-Close") dlgReject(); + } + }; + if (!Result) + exit(0); +} + +real WireLength(real x1, real x2, real y1, real y2) +{ + return sqrt(pow(x2 - x1, 2) + pow(y2 - y1, 2)); +} + +real ArcLength(real ang1, real ang2, real radius) +{ + return radius * 2 * PI / 360 * (ang2 - ang1); +} + +real Frequency(real c, real l) +{ + return c / l; +} + +void WireWidth(string sig, real w) +{ + // ermitteln der min-max Leiterbahnbreite + if (w < Widthmin[n]) Widthmin[n] = w; + if (w > Widthmax[n]) Widthmax[n] = w; +} + +real imax(real breite) +{ + return (breite == 0) ? 0 : 5.25 * sqrt((Cu * breite * (Cu + breite)) * k[int(trunc(breite))]); +} + +if (board) board(B) { + sprintf(h, "%s\n", EAGLE_SIGNATURE); + header += h; + sprintf(h, "List of signals with length and its max. frequency / current\n"); + header += h; + sprintf(h, "exported from %s\nat %s\n", B.name, t2string(time())); + header += h; + + B.signals(S) { + WLtotal = 0; + Widthmin[n] = 32000; + Widthmax[n] = 0; + S.wires(W) { + if (W.layer < 17) { // nur Kupfer-Layer + if (W.arc) { + WLtotal += ArcLength(W.arc.angle1, W.arc.angle2, u2mm(W.arc.radius)); + } + else { + WLtotal += WireLength(u2mm(W.x2), u2mm(W.x1), u2mm(W.y2), u2mm(W.y1)); + } + WireWidth(S.name, u2mm(W.width)); + } + } + if (WLtotal != 0) { + Signal[n] = S.name; + Length[n] = WLtotal; + Freq[n] = Frequency(c, WLtotal); + ++n; + } + } + sort(n, index, Freq); + + sprintf(h, "Signal\tf max. [MHz]\tl [mm]\tA [mm2]\tR [mOhm]\tw min [mm]\tw max [mm]\tImax [A]"); + data[0] = h; + t = 1; + + for (int i = 0; i < n; ++i) { + real mm2 = Widthmin[index[i]] * Cu; + real mOhm = 0; + string R; + if (Widthmin[index[i]]) { + mOhm = (174 * Length[index[i]] / 10) / ( Cu * 1000 * Widthmin[index[i]]); + sprintf(R, "%7.2f", mOhm); + } + + sprintf(h, "%s\t%10.2f\t%7.3f\t%4.3f\t%s\t%6.3f\t%6.3f\t%6.2f", Signal[index[i]], Freq[index[i]], Length[index[i]], mm2, R, Widthmin[index[i]], Widthmax[index[i]], imax(Widthmin[index[i]])); + data[t] = h; + + if (!Widthmin[index[i]]) { + note = 1; + sprintf( h, " ***"); + data[t] += h; + } + t++; + } + + dialog(); + } + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); +} diff --git a/trunk/ulp/length.ulp b/trunk/ulp/length.ulp new file mode 100644 index 00000000..b7480859 --- /dev/null +++ b/trunk/ulp/length.ulp @@ -0,0 +1,271 @@ +#usage "This ULP calculates the signal length of routed tracks in the layout

    \n" + "run length [name | name* | *name | *name*]
    " + "run length name [name name ...]

    " + "EXAMPLE:
    " + "run length +D -D
    " + "run length d0 d2 d7 A*
    " + "run length d*
    " + "run length *

    " + "Wires in layers 1 to 16 will be added, airwires will be shown separately.
    " + "If net names are specified, the differences in length will be calculated in procentual values.
    " + "The procentual difference is based on the shortest of the specified tracks which is taken as 100%.
    " + "Parallel tracks and polygons are not taken into consideration.
    " + "Only for all signals it is possible to change the sorting of the displayed signals in the list." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#require 4.1602 + +// ** German description: ** +string hilfe = "Dieses ULP berechnet die Signallängen von Leiterbahnen eines Layouts.

    " + + "run length [name | name* | *name | *name*]
    " + + "run length name [name name ...]

    " + + "Beispiel:
    " + + "run length +D -D
    " + + "run length d0 d2 d7 d6 A*
    " + + "run length d*
    " + + "run length *

    " + + "Die Wire in den Layern 1 bis 16 werden addiert, die Airwire werden gesondert angegeben.
    " + + "Prozentuale Längendifferenzen werden nur berechnet wenn Netznamen angegeben wurden.
    " + + "Für den prozentualen Längenunterschied wird die kürzeste Leiterbahn als 100% angesehen.
    " + + "Es wird keine Parallelführung bzw. Fläche (Polygon) berücksichtigt.
    " + + "Nur bei Anzeige aller Signale kann die Sortierung des Listfeldes beeinflußt werden.

    " + + "Ein Doppelklick auf einen Listeneintrag, beendet das ULP und zeigt des Singal im Board.

    " + + "Author: support@cadsoft.de" + ""; + +// 2008-09-11 Ohne Parameter wird erst die Hilfe aufgerufen. alf@cadsoft.de +// Wird keines der gesuchten Signale gefunden, +// wird eine entsprechnede Nachricht angezeigt. +// 2005-02-10 alf@cadsoft.de +// 2012-04-05 Doppleklick in Liste beendet das ULP mit SHOW auf den Netznamen +// 2013-01-09 Jetzt auch mit * ohne das Hilfsmenu un mit 9 Nachkommastellen + + +string Help = usage; +string HButton = "&Help"; +string SButton = "&Save"; + +real f, WLtotal; +int index[]; + + +real Length[]; +string signal_list[]; +int sig_n = 0; + +real route_length[]; +real Unroute_length[]; +int Unroute_cnt[]; + +int t; +numeric string data[]; + +string h; +string header; + +data[1] = "No signals found."; + +if (language() == "de") { + data[1] = "Keines der Signale gefunden."; // 2008-09-11 + Help = hilfe; + HButton = "&Hilfe"; + SButton = "&Sichern"; +} + + +void help(void) { + dlgMessageBox(Help, "Ok"); + return; +} + + +void show(string line) { // 2012-04-05 + string s[]; + int n = strsplit(s, line, '\t'); + sprintf(line, "SHOW '%s'", s[0]); + exit(line); +} + +void dialog(void) { + int select = 0; + int ssort = 0; + if (argc < 2) ssort = 1; + + int Result = dlgDialog("Wire length of Layout") { + dlgListView("", data, select, ssort) show(data[select]); + dlgHBoxLayout { + dlgPushButton("+Ok") dlgReject(); + dlgPushButton(SButton) { + board(B) { + string FileName = dlgFileSave("Save list", filesetext(B.name, ".txt")); + if (FileName) { + output (FileName, "wt") { + printf("%s", header); + for (int x = 0; x < t; x++) printf("%s\n", data[x]); + } + } + } + } + dlgStretch(1); + dlgPushButton(HButton) help(); + } + }; + if (!Result) + exit(0); +} + + +real WireLength(real x1, real x2, real y1, real y2) { + return sqrt((pow(x2 - x1, 2) + pow(y2 - y1, 2)) ); +} + + +real ArcLength(real ang1, real ang2, real radius) { + return radius * 2 * PI / 360 * (ang2 - ang1); +} + + +int found(string signame) { + if (argc < 2) { + return 1; + } + else if (argc == 2 && argv[1] == "*") return 1; + int f = 0; + int sig = 0; + for (int n = 0; n <= sig_n; n++) { + + if (strchr(signal_list[n], '*') >= 0) { // wildcard * in name + int l = strlen(signal_list[n]); + string s; + + if (signal_list[n][0] == '*' && signal_list[n][l-1] == '*') { // *name* + s = strsub(signal_list[n], 1, l-2 ); + if(strstr(signame, s) > 0) { + f = 1; + break; + } + } + + else if (signal_list[n][l-1] == '*') { // name* + s = strsub(signal_list[n], 0, l-1); + if(strstr(signame, s) == 0) { + f = 1; + break; + } + } + + else if (signal_list[n][0] == '*') { // *name + s = strsub(signal_list[n], 1); + if(strstr(signame, s) > 0) { + f = 1; + break; + } + } + } + else if (signame == signal_list[n]) { + f = 1; + break; + } + } + return f; +} + +// *** different length to shortesd signals in percent *** +string percent( real length, real length100) { + string s; + if (length100) sprintf(s, "%.3f", (length - length100) / (length100 / 100)); + else s = "--"; + return s; +} + +// *** Unroutet length *** +string unroute(real l, int cnt) { + string s; + if (cnt) sprintf(s, "%.f", l); + else s = "--"; + return s; +} + + + +// *** main *** +if (board) board(B) { + if (argc < 2) { // 2008-09-11 alf@cadsoft.de + help(); + } + else if (argc == 2 && argv[1] == "*") ; + else { + string h; + int n; + string list; + + // *** check only by signal name *** + sig_n = argc -2; + for (n = 1; n < argc; n++) { + signal_list[sig_n] = strupr(argv[n]); + list += signal_list[sig_n] + "\n"; + sig_n++; + } + } + + sprintf(h, "%s\n", EAGLE_SIGNATURE); + header += h; + sprintf(h, "List of signals with length"); + header += h; + + string Signal[]; + int n = 0; + B.signals(S) { + if (found(S.name)) { + WLtotal = 0; + int cntUnroute = 0; + real unroute = 0; + S.wires(W) { + if (W.layer < 17) { // nur Kupfer-Layer + if (W.arc) { + WLtotal += ArcLength(W.arc.angle1, W.arc.angle2, u2mm(W.arc.radius)); + } + else { + WLtotal += WireLength(u2mm(W.x2), u2mm(W.x1), u2mm(W.y2), u2mm(W.y1)); + } + } + if (W.layer == 19) { // unrouted Layer + unroute += WireLength(u2mm(W.x2), u2mm(W.x1), u2mm(W.y2), u2mm(W.y1)); + cntUnroute++; + } + } + Signal[n] = S.name; + Length[n] = WLtotal; + Unroute_length[n] = unroute; + Unroute_cnt[n] = cntUnroute; + ++n; + } + } + + sort(n, index, Length); + sprintf(h, "Signal\tl [mm]\tdiff. [mm]\tdiff. [%%]\tunrouted [mm]"); + data[0] = h; + t = 1; + real null_length = Length[index[0]]; + + for (int i = 0; i < n; ++i) { + sprintf(h, "%s\t%.9f\t%.9f\t%s\t%s", + Signal[index[i]], + Length[index[i]], + Length[index[i]] - null_length, + percent(Length[index[i]], null_length), + unroute(Unroute_length[index[i]], Unroute_cnt[index[i]]) + ); + data[t] = h; + t++; + } + dialog(); +} + +else { + dlgMessageBox("Start this ULP in a Board"); + exit (0); +} diff --git a/trunk/ulp/lpp.ulp b/trunk/ulp/lpp.ulp new file mode 100644 index 00000000..7f25ab90 --- /dev/null +++ b/trunk/ulp/lpp.ulp @@ -0,0 +1,1023 @@ +#usage "en: Calculate the wire length from pad to pad" + "

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

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

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

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

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

    " + "

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

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

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

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

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

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

    " + "

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

    " + "RUN ltspice /E [/S][/G]
    " + "RUN ltspice /I [/S][/G]
    " + "RUN ltspice /?
    " + " /E == Export
    " + " /I == Import
    " + " /? == System info
    " + "Option /S opens the SETUP menu for default settings.
    " + "Option /G exports a group previously created in the schematic with the GROUP command.
    " + "RUN ltspice /I 'importfilename' [RELOAD]

    " + "Start this ULP with the option /E from a Deviceset (Library), in order to export the current Deviceset. " + "Use the ULP without an option in order to export the whole library.
    " + "For the import you can choose the option Import all symbols from directory in the dialog. Select a symbol file then, " + "and all symbols from the current directory will be imported into an EAGLE library." + "

    " + "The option RELOAD is planned to check a schematic for modifications. " + "This option is not implemented yet! 2012-09
    " + "


    " + "SpiceOrder
    " + "The so-called SpiceOrder will be defined in layer 99 'SpiceOrder' as a text. " + "It has to be placed exactly at the connection point (coordinate) of the pin. " + "While exporting an EAGLE schematic the ULP checks for SpiceOrder and SpiceModel. " + "If SpiceOrder is not defined, EAGLE loads the Deviceset and starts spiceorder.ulp.
    " + "This ULP helps to assign pins of the symbol and its Spiceorder. This assignment will be written " + "as a text at the pin connection point in layer 99 automatically." + "

    " + "SpiceModel
    " + "SpiceModel is the simulation model. It will be attached with the help of the attribute " + "SPICEMODEL in the device. Therefore the LTC icon in the device editor contains the entry SpiceModel." + "

    " + "Value2
    " + "For some components you have to assign the additional Value2. It has to be created with an attribute, " + "as well. There is a further entry in the LTC icon's menu for this." + "

    " + "For an error-free schematic import we need correctly and clearly defined libraries. " + "The library lt-spice-simulation.lbr has a special status:
    " + "It should not appear in the list of USEd libraries. Otherwise the ADD dialog will open " + "for placing resistors while the import script is running.
    " + "The simulation resistors \"Rload\" are treated like normal resistors in LTSpice. " + "Just the device name gets the extension \"_RLOAD\". " + "

    " + "lt-spice-simulation.lbr contains only devices that are used for the simulation, like " + "power supply, voltage generator, loads, measurement equipment and so on.). " + "All those devices have an attribute with the name \"_EXTERNAL_\". So you don't have to " + "assign a package; such components are not transferred into the board and do not " + "appear in the bill of materials.
    " + "

    " + "A FLAG comming from LTspice results in EAGLE in a simple LABEL that is placed on the net line (FLAG 1248 176 BI_Port).
    " + "There is no rotation given for FLAGs. The rotation has to be determined with the help of the orientation of the referring line! " + "It can happen that a FLAG is placed onto a pin directly. It's not possible to determine the rotation then. " + "In such a case you have to take care on this matter manually!
    " + "

    " + "An IOPIN is reflected as a cross-reference label in EAGLE. (IOPIN 1248 176 BiDir)
    " + "There is no equivalent for IOPIN in EAGLE, so we use a cross-reference (XREF) label for BI_Port, In and Out." + "

    " + "Supply symbols (FLAGs) like 0 or COM, are taken from lt-supply.lbr directly.
    " + "If you have to use other supply symbols (not 0 and COM), you have to create them in LTspice as *.asy files " + "containing the spice symbols.
    " + "Example:
    " + "Version 4
    " + "SymbolType CELL
    " + "LINE Normal 0 11 0 16
    " + "LINE Normal -11 14 0 0
    " + "LINE Normal 0 0 11 14
    " + "LINE Normal 0 11 -11 14
    " + "LINE Normal 11 14 0 11
    " + "TEXT 0 -4 Bottom 2 +3.3V
    " + "SYMATTR Prefix X
    " + "SYMATTR SpiceModel node.sub
    " + "SYMATTR Value node
    " + "SYMATTR Value2 node
    " + "PIN 0 16 NONE 36
    " + "PINATTR PinName +3.3V
    " + "PINATTR SpiceOrder 1
    " + "

    " + "And the simulation model:
    " + "* Copyright (C) Linear Technology Corp. 1998, 1999, 2000. All rights reserved.
    " + "*
    " + ".subckt node 1
    " + "R1 1 1 0
    " + ".ends node
    " + "

    " + "In order to define a supply device in an EAGLE library, place a supply pin in a symbol and " + "define a device with ATTRIBUTE 'SPICEMODEL' 'node.sub'; and ATTRIBUTE 'VALUE2' 'node'; . " + "These two attributes make the device 'spice-usable'.
    " + "In the transferred schematic you have to place a FLAG with all the neccessary information at the pin's position." + "

    " + "When you start this ULP, EAGLE searches for the path of the LTspice executable in the file eaglerc.usr. If it " + "is not yet stored there, it searches in the default program folder and stores it in eaglerc.usr then." + "
    " + "For the export of a schematic, EAGLE checks the availability of all necessary LTspice symbols .asy. " + "If there is one is missing, EAGLE opens the referring deviceset in the EAGLE library.
    " + "

    " + "There is a check for the SpiceOrder texts in layer 99 SpiceOrder. " + "In devices EAGLE searches for the attribute 'SPICEMODEL'. If one of these items is missing, " + "EAGLE opens the library editor. Please add the missing definitions. " + "For the SpiceOrder there will be called an ULP automatically." + "

    " + "The names of the symbols in EAGLE must be different compared to the names of the LTspice symbols.
    " + "Example: If you export a symbol/device with name 'DIODE' from EAGLE, LTspice takes its own " + "symbol with name 'diode'. To insure that the EAGLE symbol is taken it has to have a unique name. " + "You can also combine device name and library name. The library name then reflects a subfolder in the " + "LTspice folder /sym . 2012-10-09" + "

    " + "The SPICEMODEL attribute can be created through an entry in the LTC icon menu." + "
    " + "This icon is created through the file eagle.scr. It will be executed automatically when you are " + "creating a new device or symbol. The icon images (PNG files) should be in " + "the subfolder bin of the EAGLE folder." + "

    " + "Export/import Libraries:
    " + "Libraries imported from LTspice have to be created in the subfolder ./lbr/ltspice/... " + "So the export function recognizes that the libary file comes from LTspice.
    " + "When you start the ULP for the first time it copies some files to LTspice.
    " + "They have to be copied into the following folder structure:
    " + "./eagle-x.x.x/
    " + " - /misc/
    " + " - - /ltspice/
    " + " - - - /lib/
    " + " - - - - /sub/ note.sub and other .sub files
    " + " - - - - /sym/
    " + " - - - - - /eagle/
    " + " - - - - - - /lbrname/ exported symbols from the EAGLE libraries
    " + " - - - /scr/ Connect scripts (provided by LT)
    " + "
    " + "EAGLE libraries will be created/copied in(to) the following folders:
    " + "./LTC/LTspiceIV/lib/sym/eagle/
    " + "Each library exported results in a subfolder with the library name.
    " + "

    " + "Author: alf@cadsoft.de" + , + + "de:Schnittstelle zur Simulationssoftware LTspiceIV
    " + "Export von EAGLE-Schaltplänen und Bibliothekssymbolen nach LTspiceIV und Import von Schaltplänen und Symbolen aus LTspiceIV

    " + "RUN ltspice /E [/S][/G]
    " + "RUN ltspice /I [/S][/G]
    " + "RUN ltspice /?
    " + " /E == Export
    " + " /I == Import
    " + " /? == Systeminfo
    " + "Option /S öffnet das SETUP-Menü für Grundeinstellungen.
    " + "Option /G exportiert eine Gruppe, die vorher im Schaltplan mit GROUP definiert wurde.
    " + "RUN ltspice /I 'importfilename' [RELOAD]

    " + "Startet man das ULP mit der Option /E aus einem Deviceset (Bibliothek), wird dieses eine Deviceset exportiert. " + "Gibt man keine Option an, wird die gesamte Bibliothek exportiert.
    " + "Beim Import kann man im Dialog die Option Import all symbols from directory aktivieren. Wählen Sie dann eine Symboldatei aus, " + "werden alle Symbole aus dem Verzeichnis in die EAGLE-Bibliothek importiert." + "

    " + "Die Option RELOAD soll in Zukunft den Schaltplan auf Änderungen prüfen. " + "Diese Option ist noch nicht implementiert! 2012-09
    " + "


    " + "SpiceOrder
    " + "Die sogenannte SpiceOrder wird im Layer 99 'SpiceOrder' als Text abgelegt. Dieser muss exakt auf dem Kontaktpunkt (Koordinate) des Pins liegen. " + "Beim Export eines EAGLE-Schaltplans wird geprüft, ob SpiceOrder und SpiceModel definiert sind. " + "Fehlt die SpiceOrder, lädt EAGLE das entsprechende Deviceset und startet spiceorder.ulp.
    " + "Mit Hilfe dieses ULPs ordnet man den Symbolpins die SpiceOrder zu. Diese Zuordnung wird automatisch an " + "den Pins als Text im Layer 99 platziert." + "

    " + "SpiceModel
    " + "Das SpiceModel ist das Simulationsmodell. Es wird in EAGLE im Device " + "als Attribut SPICEMODEL hinterlegt. Das LTC-Icon im Device-Editor enthält dazu den Eintrag SpiceModel." + "

    " + "Value2
    " + "Für manche Bauteile benötigt man zusätzlich Value2. Dieser kann ebenfalls als Attribut " + "angelegt werden. Auch hierzu gibt es eine Option im Menü des LTC-Icons." + "

    " + "Für einen fehlerfreien Schaltplan-Import benötigt man passende und eindeutige Bibliotheken. " + "Die Bibliothek lt-spice-simulation.lbr hat einen Sonderstatus:
    " + "Sie darf nicht in der USE-Liste enthalten sein, da ansonsten beim Ausführen des Scripts " + "und Einfügen von Widerständen das ADD-Menu geöffnet wird.
    " + "Die Simulationswiderstände \"Rload\" werden in LTSpice wie normale Widerstände behandelt, " + "nur der Devicename wird mit dem Anhang \"_RLOAD\" erweitert. " + "

    " + "lt-spice-simulation.lbr enthält nur Devices, die für die Simulation benötigt werden, wie " + "z.B. (Stromquellen, Spannungsquellen, Lasten, Messgeräte etc.). " + "In diesen Devices ist jeweils ein Attribut mit dem Namen \"_EXTERNAL_\" angelegt. Dadurch muss kein Package " + "zugeordnet werden; es handelt sich hierbei um Bauteile, die nicht in das Board übertragen " + "und auch nicht in die Stückliste aufgenommen werden.
    " + "

    " + "Ein FLAG aus LTspice wird in EAGLE als einfaches LABEL dargestellt und auf der Netzlinie platziert (FLAG 1248 176 BI_Port).
    " + "Bei FLAGs wird keine Rotation angegeben. Die Rotation muss anhand der Ausrichtung der letzten zugehörigen Linie " + "ermittelt werden! Es kann auch vorkommen dass FLAGs direkt auf Pins gesetzt werden. Dann ist es nicht möglich die " + "Rotation zu ermitteln. In diesem Fall muss man sich manuell um die korrekte Ausrichtung des Labels anhand des " + "Pins im Symbol kümmern!
    " + "

    " + "Ein IOPIN wird in EAGLE als LABEL mit Querverweis dargestellt. (IOPIN 1248 176 BiDir)
    " + "Da es in EAGLE keine Pendant für IOPIN gibt, wird für BI_Port, In und Out ein Label mit Querverweis (XREF) platziert." + "

    " + "Supply-Symbole (FLAG) wie 0 oder COM, werden direkt aus der lt-supply.lbr genommen.
    " + "Werden andere Supply-Symbole (ausser 0 und COM) benutzt, müssen diese in LTspice als *.asy-Datei " + "mit dem entsprechenden Spicemodel angelegt werden.
    " + "Beispiel:
    " + "Version 4
    " + "SymbolType CELL
    " + "LINE Normal 0 11 0 16
    " + "LINE Normal -11 14 0 0
    " + "LINE Normal 0 0 11 14
    " + "LINE Normal 0 11 -11 14
    " + "LINE Normal 11 14 0 11
    " + "TEXT 0 -4 Bottom 2 +3.3V
    " + "SYMATTR Prefix X
    " + "SYMATTR SpiceModel node.sub
    " + "SYMATTR Value node
    " + "SYMATTR Value2 node
    " + "PIN 0 16 NONE 36
    " + "PINATTR PinName +3.3V
    " + "PINATTR SpiceOrder 1
    " + "

    " + "Dazu das Simulationsmodell:
    " + "* Copyright (C) Linear Technology Corp. 1998, 1999, 2000. All rights reserved.
    " + "*
    " + ".subckt node 1
    " + "R1 1 1 0
    " + ".ends node
    " + "

    " + "Um ein Supply-Device in einer EAGLE-Bibliothek anzulegen, platziert man im Symbol einen Supply-Pin und " + "legt dann ein Device mit ATTRIBUTE 'SPICEMODEL' 'node.sub'; und ATTRIBUTE 'VALUE2' 'node'; an. " + "Diese beiden Attribute machen das Device 'spicetauglich'.
    " + "Im übertragenen Schaltplan, muß an der Position des Pins ein FLAG mit entsprechenden Informationen platziert werden." + "

    " + "Beim Sart des ULPs wird in der Datei eaglerc.usr nach dem Pfad zur Programmdatei von Ltspice gesucht. Ist dieser " + "noch nicht hinterlegt, wird im Default-Programme-Ordner gesucht und in eaglerc.usr eingetragen." + "
    " + "Das ULP überprüft beim Export des Schaltplan die Verfügbarkeit der benötigten LTspice-Symbole .asy. " + "Fehlt eines, öffnet EAGLE das Deviceset in der entsprechenden Bibliothek.
    " + "

    " + "Geprüft wird, ob in den Symbolen die SpiceOrder-Texte im Layer 99 SpiceOrder vorhanden sind. " + "In Devices wird nach dem Attribut 'SPICEMODEL' gesucht. Fehlt eines dieser Merkmale, wird " + "die Bibliothek mit dem entsprechenden Symbol bzw. Device geöffnet. Machen Sie dann die nötigen " + "Ergänzungen. Für die SpiceOrder ist ein ULP verfügbar, das automatisch aufgerufen wird." + "

    " + "Die Symbolnamen von EAGLE-Symbolen müssen sich von denen in LTspice unterscheiden.
    " + "Beispiel: Exportiert man aus EAGLE ein Symbol/Devic 'DIODE', verwendet LTspice sein eigenes " + "Symbol mit Namen 'diode'. Damit das EAGLE-Symbol verwendet wird, muss es einen eigenen Namen haben. " + "Man kann auchden Namen mit dem LBR-Namen zusammen angegeben. Der LBR-Name entspricht dann einem " + "Unterordner im LTspice-Ordner /sym . 2012-10-09" + "

    " + "Das Attribut SPICEMODEL kann über den Menü-Eintrag des LTC-Icons angelegt werden." + "
    " + "Dieses Icon wird durch die Datei eagle.scr angelegt. Diese wird beim Anlegen eines neuen " + "Devices bzw. Symbols automatisch ausgeführt. Die benötigten Icons (PNG-Dateien) müssen im " + "Unterordner bin des EAGLE-Verzeichnisses abgelegt werden." + "

    " + "Bibliotheken importieren/exportieren:
    " + "Die importierten LTspice-Bilbiotheken müssen im Unterordner ./lbr/ltspice/.. angelegt werden, " + "damit die Export-Funktion erkennen kann, dass es sich um eine LTspice-Bibliothek handelt.
    " + "Beim ersten Start des ULPs werden entsprechende Dateien nach LTspice kopiert.
    " + "Die zu kopierenden Dateien müssen in folgender Ordnerstruktur abgelegt sein:
    " + "./eagle-x.x.x/
    " + " - /misc/
    " + " - - /ltspice/
    " + " - - - /lib/
    " + " - - - - /sub/ note.sub und sonstige .sub Dateien
    " + " - - - - /sym/
    " + " - - - - - /eagle/
    " + " - - - - - - /lbrname/ die exportierten Symbole der entsprechenden EAGLE-Bibliotheken
    " + " - - - /scr/ die Connect-Scripte von LT (werden von LT geliefert)
    " + "
    " + "EAGLE-Bibliotheken werden in den folgenden Ordner kopiert/erzeugt:
    " + "./LTC/LTspiceIV/lib/sym/eagle/
    " + "Dabei wird für jede Bibliothek ein Ordner mit dem Namen der exportierten Bibliothek angelegt.
    " + "

    " + "Author: alf@cadsoft.de" + + +string LTspiceFormatInfo = "" + + "Das Koordinatensystem von LTspice ist entsprechend der BitMap einer Grafikkarte organisiert.
    " + + "Der Nullpunkt ist links oben, und die Vorzeichen der Y-Achse sind invertiert!
    " + + "Positiv nach unten, negativ nach oben.
    " + + "LTspice benutzt ein 16er Grid, das die Auflösung für Symbole etwas einschränkt.
    " + + "Das Raster in LTspice wird ohne Einheit angegeben und ist auf (100) mil umgerechnet.
    " + + "In Device-Namen darf kein Schrägstrich (Slash) oder Rückstrich (Backslash) vorkommen.
    " + + "Der Name des Symbols in LTspice definiert den Device-Namen, der gleichzeitig der Name der .asy-Datei ist.
    " + + "Unter Windows ist der 'Schrägstrich' in Dateinamen nicht erlaubt.
    " + + "Unter Linux würde das einen weiteren Unterordner bedeuten!" + + "
    " + + "

    " + + "alf@cadsoft.de"; + +if (language() != "de") LTspiceFormatInfo = "" + + "The coordinates system of LTspice is similar to the BitMap of a graphics adapter.
    " + + "The origin is located in the upper left corner. The coordinates direction of the y axis is inverted.
    " + + "Positive coodinates down, negative up.
    " + + "LTspice works with a multiple of 16 grid, which limits the resolution for symbols a bit.
    " + + "LTspice uses an inch based grid (units not visible) converted to (100) mil.
    " + + "Device names may not contain slash / or backslash \.
    " + + "The symbol name in LTspice defines the device name. This name is used for the .asy file, as well.
    " + + "Windows does not tolerate a slash in file names. Linux would create a subfolder." + + "
    " + + "

    " + + "alf@cadsoft.de"; + +#require 6.0500 +string ULP_Version = "1.0.4"; // 1.0.2 - 2013-10-01 alf erweitert mit Option /? Systeminfo für Diagnose + // 1.0.3 - 2014-01-23 R C L braucht kein SpiceModel (Attribute) + // 1.0.4 - 2014-04-03 Pfadauswertung zur importierten LTspice-Lbr berichtigt +int Test = 0; + + +/* *** export vaiable **** */ +string LTSpiceExecute = ""; // Pfad-Dateiname zum LTspice-Programm +string EagleExecute = EAGLE_PATH; // 2012-11-23 + +string LTSpiceLibDir = ""; // das Directory der LTspice-Symbole .asy +string ExpEagleSpiceSymDir = ""; // das Directory der exportierten Eagle Library-Symbole +string ImpSpiceSchematicAsc = ""; // der ausgewählte LTspice-Schaltplan zum importieren +string SpiceSymbol = ""; +string ExpSchematic2LTpice = ""; // der Eagle-Schaltplan der exportiert wird + +string SpiceSimulationLbr = ""; // die LBR für die Generatoren, Messinstrumente, Lastwiderstände etc. + // wird mit USE benutzt. +string SpiceDefaultSymLbr = ""; // die LBR für die default Symbole wie R, C, L, D, T .... + // wird ebenfalls mit USE benutzt, damit es keine Konflikte zwischen EAGLE-LBRs + // und LTspice-LBRs gibt. +string EagleSpiceLbrDir = ""; // Das Verzeichnis für die importierten Spice-Bibliotheken (*.asy -> .lbr) + +string LbrName; // current eagle lbr name +string NewLbrName; // new eagle lbr name + + +string FileSpiceSym[]; // file names of spice symbols of a directory +int CntFileSpiceSym = 0; +string Import_All_Symbols = "1"; + +string Imp_SpiceSchematicAsc = ""; +string Imp_SpiceSymbol = ""; +string Imp_SpiceSimulationLbr = ""; // die LBR für die Generatoren, Messinstrumente, Lastwiderstände etc. +string Imp_SpiceDefaultSymLbr = ""; // die LBR für die default Symbole wie R, C, L, D, T .... +string Imp_EagleSpiceSchDir = ""; +string Imp_LbrName; // current eagle lbr name + +string Imp_FileSpiceSym[]; // file names of spice symbols of a directory +int Imp_CntFileSpiceSym = 0; +string Imp_ConnectScriptDir = ""; + + +string Ex_AsyName; +string Ex_SpiceAscDir; + +int ExportAll = 1; // 0 to export only a GROUP +int Ex_cntFileSpiceAsc = 0; +int CntOutput = 0; // exported devices/technologies as *.asy + +int Ex_WaitOnHandShake = 0; // flag for response of external executable (LTspice) + +int Ex_PinDirSup = 0; // Flag to generate Supply-Symbols for LTspice as library +string Ex_SpiceOrder = "SpiceOrder"; +string Ex_AttributeSPICEMODEL = "SPICEMODEL"; +string Ex_AttributeSPICEPREFIX = "SPICEPREFIX"; + +string Ex_SpiceOrderNum[]; +int Ex_PinX[], Ex_PinY[]; +int Ex_LayerSpiceOrder = 99; // Die Zuordnung der Pins zu der SpiceOrder geschieht über den Text "SpiceOrder XX" + // und wird als Text in diesem Layer abgelegt! +int Ex_CntSymText = 0; +int ExOnceLib = 0; + +string FileNewTemp = "wtD"; // option for function output() for generate temporary file (script). +string FileAppend = "at"; // option for function output() append data to existing file. + + +/***** import variable ******/ + +int RELOAD = 0; // Flag zum vergleichen bzw. nachladen nach beenden von export ltspice.ulp + +string Imp_InfoExternalSymbol = "In EAGLE besteht jedes reguläre Bauteil aus ein oder mehreren Symbolen " + "und ein oder mehreren Package-Varianten!

    " + + "Simulationssymbole für LTspice (Stromquellen, Spannungsquellen, " + + "Generatoren, Messgeräte, Lasten etc.), dürfen nicht in das Board oder in die " + + "Stück- Netz- Pin-Listen übernommen werden.
    " + + "Um das zu bewerkstelligen, und alle Pin-Directions in Symbolen " + + "nutzen zu können, muß in den Devices für Simulations-Symbole ein " + + "Attribute \"_EXTERNAL_\" definiert werden." + + "Dieses Attribute veranlasst Eagle (ab Version 6.2), die Überprüfung " + + "des Device bezüglich der CONNECT-Liste und Vorhandensein eines " + + "Packages zu unterdrücken.
    "; + +if (language() != "de") { + Imp_InfoExternalSymbol = "In EAGLE every component definition consists of one or more symbols assigned to " + + "one or more package variants

    ." + + "Simulation symbols in LTSpice (like power supply, voltage supply, generators, " + + "measurment tools, loads and so on...) do not appear in the board nor in a " + + "bill of materials, pin list or net list.
    " + + "In order to have all pin directions available for such symbols, a device for " + + "a simulation symbol must have defined an attribute named \"_EXTERNAL_\". " + + "This attribute suppresses the connection check and the package check (from " + + "EAGLE version 6.2.0 on).
    "; +} + +string LTspicePrefix[], LTspicePrefixDescript[]; + LTspicePrefix[ 0] = "none"; LTspicePrefixDescript[0] = "Device used not spice prefix"; + LTspicePrefix[ 1] = "A"; LTspicePrefixDescript[ 1] = "Special functions"; + LTspicePrefix[ 2] = "B"; LTspicePrefixDescript[ 2] = "Arbitrary behavioral source"; + LTspicePrefix[ 3] = "C"; LTspicePrefixDescript[ 3] = "Capacitor"; + LTspicePrefix[ 4] = "D"; LTspicePrefixDescript[ 4] = "Diode"; + LTspicePrefix[ 5] = "E"; LTspicePrefixDescript[ 5] = "Voltage dependent voltage"; + LTspicePrefix[ 6] = "F"; LTspicePrefixDescript[ 6] = "Current dependent current"; + LTspicePrefix[ 7] = "G"; LTspicePrefixDescript[ 7] = "Voltage dependent current"; + LTspicePrefix[ 8] = "H"; LTspicePrefixDescript[ 8] = "Current dependent voltage"; + LTspicePrefix[ 9] = "I"; LTspicePrefixDescript[ 9] = "Independent current source"; + LTspicePrefix[10] = "J"; LTspicePrefixDescript[10] = "JFET transistor"; + LTspicePrefix[11] = "K"; LTspicePrefixDescript[11] = "Mutual inductance"; + LTspicePrefix[12] = "L"; LTspicePrefixDescript[12] = "Inductance"; + LTspicePrefix[13] = "M"; LTspicePrefixDescript[13] = "MOSFET transistor"; + LTspicePrefix[14] = "O"; LTspicePrefixDescript[14] = "Lossy transmission line"; + LTspicePrefix[15] = "Q"; LTspicePrefixDescript[15] = "Bipolar transistor"; + LTspicePrefix[16] = "R"; LTspicePrefixDescript[16] = "Resistor"; + LTspicePrefix[17] = "S"; LTspicePrefixDescript[17] = "Voltage controlled switch"; + LTspicePrefix[18] = "T"; LTspicePrefixDescript[18] = "Lossless transmission line"; + LTspicePrefix[19] = "U"; LTspicePrefixDescript[19] = "Uniform RC-line"; + LTspicePrefix[20] = "V"; LTspicePrefixDescript[20] = "Independent voltage source"; + LTspicePrefix[21] = "W"; LTspicePrefixDescript[21] = "Current controlled switch"; + LTspicePrefix[22] = "X"; LTspicePrefixDescript[22] = "Subcircuit"; + LTspicePrefix[23] = "Z"; LTspicePrefixDescript[23] = "MESFET transistor"; + +string ExternalAttributeName = "_EXTERNAL_"; // Attribute in order to define a device without package in eagle +string ExternalSymbol = ""; + +int LayerSpiceOrder = 99; // Die Zuordnung der Pins zu der SpiceOrder geschieht über den Text SpiceOrderXX + // und wird als Text in diesem Layer abgelegt! +int ColorViolett = 5; + +string SchName; +int Imp_CntFileSpiceAsc = 0; + +char Delimiter = '@'; + +int Imp_SetWireStyle = 0; // setze WireStyle auf continuous für den NET-Befehl + +string Imp_Coords[]; // LT-Spice rotiert ein FLAG (Supplypin/Label) automatisch + // anhand der Ausrichtung des Wire, an dessen Ende das FLAG sitzt. + // Dazu muss man alle Wires sammeln, um dann später die Rotation + // des FLAGs zu bestimmen. +int Imp_CntCo = 0; + +int Imp_WireX1[], Imp_WireY1[], Imp_WireX2[], Imp_WireY2[]; +int Imp_CntW = 0; +int Imp_WireSeg[]; // Da ein NET sehr verzweigt, und später mit einem BUSTAB zu einem BUS deklariert werden kann, + // werden die Wire, Segmenten zugeordnet. +int Imp_WireType[]; // Der Index des WireType entspricht der Segmentnummer. + // Der Inhalt wird zunächst auf NET gesetzt, wird später im Segment eine Koordinate eines BUSTAB + // gefunden, so wird das Segment auf BUS gesetzt. +int Imp_CntSeg = 0; // Anzahl der Segmente +int Imp_WireChecked = 0; // Flag ob zusammenhängenden Wire-Segmente schon ermittelt wurden. +enum { Null, BUS, NET } +int Imp_DrawNetBus = 0; // Flag ob NET und BUS schon gezeichnet wurde. + +string Imp_LineView[]; // nur zum Test + + // Eine Besonderheit beim Simulieren in LTspice sind Lastwiderstände. + // Lastwiderständer werden mit Rload benannt. +string Imp_RloadExtention = "_RLOAD"; // Namenserweiterung innerhalb Eagle, um Simulations-/Last-Widerstände von "Res" zu unterscheiden + +string Imp_InstanceName = ""; + +string Imp_Winattrib[]; +real Imp_InstCoordX, Imp_InstCoordY; // remember coordinate from last instance in schematic +real Imp_InstNameSmashX, Imp_InstNameSmashY; +real Imp_InstNameOffset; +real Imp_InstValueSmashX, Imp_InstValueSmashY; +real Imp_InstValueOffset; +real Imp_SpiceModelSmashX, Imp_SpiceModelSmashY; +real Imp_InstValue2SmashX, Imp_InstValue2SmashY; +real Imp_InstValue2Offset; +real Imp_SpiceLineSmashX, Imp_SpiceLineSmashY; +real Imp_SpiceLine2SmashX, Imp_SpiceLine2SmashY; + +real Imp_FlagRotate = 0.0; // used to rotate Label (Flag) on NET-Wire + +string Add; +string AddPart; +string AddPartLib; +string AddPartOrientation; +string TextAlign; // die Textausrichtung für Text allgemein +string TextAlignRotation; // die Rotation für algemeinen Text +string TextAlignName; // die Textausrichtung für >NAME +string TextAlignValue; // die Textausrichtung für >VALUE +string TextAlignValue2; // die Textausrichtung für Value2 +string TextAlignSpiceLine; // die Textasurichtung für die Spiceline +string TextAlignSpiceLine2; // die Textasurichtung für die Spiceline2 + +string ScriptFile = ""; +string CmdNameLabel = ""; +string RememberFlag = ""; // Ein Flag kann ein Label oder ein IOPIN sein, + // die Entscheidung fällt erst eine Zeile später + // mit IOPIN. Dazu muß man sich das Flag merken + // und die Koordinaten mit dem IOPIN vergleichen. + +string Lines[]; +int CntLines; +int n; // Global line counter + +string h; + +string Imp_Cmd = ""; +string Imp_CmdValueV = ""; +string Imp_CmdPartValue = ""; +string Imp_CmdValue2 = ""; // Das Teilscript für den Wert von Value2, wenn der Instance name erst später zugewiesen wird. + // LTspice kann Value2 schon zuweisen, bevor die Instance den Namen erhält. + // Im Script darf ein Attribute erst nach bestehen des Part erfolgen. +string Imp_MemSpiceline = ""; +string Imp_MemSpiceline2 = ""; + +string Imp_DefaultGateName = "G$1"; +string Imp_SymDevName; +string Imp_CmdDev; +string Imp_SymPinName; + +// für die Symbolbearbeitung +real Imp_SpiceLineSymX, Imp_SpiceLineSymY, Imp_SpiceLineSymOffset; +string Imp_SpiceLineSymAlign; +real Imp_SpiceLine2SymX, Imp_SpiceLine2SymY, Imp_SpiceLine2SymOffset; +string Imp_SpiceLine2SymAlign; +real Imp_SpiceModelSymX, Imp_SpiceModelSymY, Imp_SpiceModelSymOffset; +string Imp_SpiceModelSymAlign; + +string Imp_ScriptExt = "~ltspice~.scr"; + +string Imp_SpicePinName[]; +int Imp_CntPinname = 0; + +string Imp_UsedLbrs[]; +int Imp_CntUsedLbrs = 0; + +int LTTextSize = 112; // default zum importieren von LTspice symbolen + // in mil bei Font: Arial, Size: 28, unter LT_Spice-Control-Panel / Drafting Options + // die Texte können nicht exakt berechnet werden, da die Programme unterschiedliche Fonts, + // und innerhalb der Fonts die Zeichen wiederum unterschiedlich definert sind! +/* + +// ******************************** +Syntax Definition Symbol +// ******************************** + +// * +Coordinate System + +Anchor Point 0 0 -------> grid 16 + | + | + | + V grid 16 +// * + +// * Generics * + ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 + ::= + | + ::= [a-zA-Z0-9_] + ::= + | + ::= '.' +// * Coordinates * + ::= + ::= + ::= + ::= + ::= [A-MOQ-XZ] + +// * Line Styles + solid no + dash 1 + dott 2 + dash dot 3 + dash dot dot 4 +// * + + ::= 1 | 2 | 3 | 4 + +// /* Justification * + + ::= Left | Right | Center | Top | Bottom + ::= VLeft | VRight | VCenter | VTop | VBottom + ::= | + +// * Symbol Type * + + ::= CELL | BLOCK + + ::= SymbolType + +// * Drawings * + + ::= TEXT + + ::= LINE Normal + | LINE Normal + + ::= CIRCLE Normal + | CIRCLE Normal + + ::= ARC Normal + | ARC Normal + + ::= RECTANGLE Normal + | RECTANGLE Normal + + ::= | | | | + + ::= + | '\n' + +// * Attribute Window * + Type 1 - + SpiceModel 38 +SYMATTR + Value 3 - + Value2 123 - + SpiceLine 39 - + SpiceLine2 40 - +// * + + ::= 0 | 1 | 3 | 39 | 40 | 123 + + ::= 38 + + ::= WINDOW + | WINDOW '\n' SYMATTR + + ::= + | '\n' + +// * Symbol Attributes * + + ::= Prefix + ::= SpiceModel + ::= Value + ::= Value2 + ::= SpiceLine + ::= SpiceLine2 + ::= Description + ::= ModelFile + + ::= | | | | | | | + ::= SYMATTR + ::= + | '\n' +// * Pin Definition * + ::= NONE | + ::= PIN + ::= PinName + ::= SpiceOrder + ::= | + ::= PINATTR + ::= '\n' PINATTR '\n' PINATTR + ::= + | '\n' +// * File * +

    ::= Version +// * + ::= +// * + ::= SymbolType BLOCK '\n' + | SymbolType CELL '\n' + ::=
    +*/ + +int showtest = 1; + + +void testsyscommand(string cmdexe, string s) { + dlgDialog("DOS comand check") { + dlgHBoxLayout dlgSpacing(600); + dlgLabel(s); + dlgTextEdit(cmdexe); + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("ESC") { dlgReject(); exit(-666); } + } + }; + return; +} + + +char SearchStartDrive = 'C'; // *** erstes Windowslaufwerk *** +string StartFolder; // der Grundpfad +char SearchLastDrive = 'Z'; // 'Z' *** letztes Windowslaufwerk *** + +int SearchnRoot; +string SearchRoot[]; +//string SearchRootfound; +string SearchFiles[]; +int SearchStart, SearchEnd; +string a[]; +int SearchIs_UNC; +int CntSubDir = 4; // maximal bis in den 4. Unterordner suchen + +int OS = strstr(OS_SIGNATURE, "Windows"); +if (OS < 0) { + dlgMessageBox("This ULP runs only on Windows", "OK"); + exit(-1); +} + + +/* *************** file functions *************** */ +int check_files(string path, string file_ext) { + return fileglob(SearchFiles, path + file_ext); +} + + +// ein Windows-Laufwerk beginnt mit "Buchstabe:\" +// suche nach ":/" hinter dem Laufwerksbuchstaben +void check_windows_root(void) { + string drv; + for(int d = SearchStartDrive; d <= SearchLastDrive; d++) { + sprintf(drv, "%c:/", d); + if (check_files(drv, "/")) { + SearchRoot[SearchnRoot] = drv; + SearchnRoot++; + } + } + return; +} + + +string cut_path(string s) { + int pos = strrchr(s, '/', -1); + if (pos > 0) return strsub(s, 0, pos); + return ""; +} + +/* +void check_UNC(string s) { + int unc = strstr(s, "//", 0); // windows beginnt UNC Namen mit zweimal Slash // bzw. Backslash \\ + string last_unc = s; + if (unc == 0) { + SearchIs_UNC = 1; + do { + string akt_unc = cut_path(last_unc); + unc = check_files(akt_unc, ""); + if (unc) last_unc = akt_unc; + } while (unc); + SearchRootfound += last_unc; + SearchRoot[SearchnRoot] = last_unc; + SearchnRoot++; + } + return; +} +*/ + +/************************ die Suchschleife *******************************************************/ +// searchfile = die zu suchende Datei +// root = der Start-Pfad ab dem gesucht werden soll, inkl. Laufwerkbuchstabe unter Windows +// maxiteration = die Tiefe, Anzahl der Verzweigung (Unterordner) ab dem root Pfad. +/*************************************************************************************************/ +string file_search(string searchfile, string root, int maxiteration, string debugnum) { + if (!root) { + if (debugnum == "init") { + dlgMessageBox("RUN ltspice.ulp with option Setup: "+searchfile, "CANCEL"); + } + else { + if (dlgMessageBox(debugnum + "\nUnknown path of file : "+searchfile, "OK", "CANCEL") == 0) return ""; + } + exit(-752); + } + int len = strlen(root); + if (root[len-1] != '/') root += "/"; // root muß mit Slash enden! + if (!check_files(root, "")) { // den Pfad prüfen + return ""; + } + // *** Betriebsystem feststellen *** + // ******* Windows Laufwerke ******* + if (root) { + SearchRoot[0] = root; + SearchnRoot = 1; + } + else { + check_windows_root(); // unter Windows die Laufwerke ermitteln + //if (SearchnRoot) { + // sprintf(SearchRootfound, "Betriebssystem WINDOWS"); + // for (int d = 0; d < SearchnRoot; d++) { + // SearchRootfound += SearchRoot[d] + "\n"; + // } + //} + //int pos; + // ************* Windows UNC-Pfad ***************** + //pos = strstr(root, "//", 0); // windows hat bei UNC Namen zweimal Slash // am Anfang + //check_UNC(root); + //if (!SearchIs_UNC) if (project.board) project.board(B) check_UNC(B.name); + //if (!SearchIs_UNC) if (project.schematic) project.schematic(S) check_UNC(S.name); + //if (!SearchIs_UNC) if (library) library(L) check_UNC(L.name); + + // ************* LINUX File system **************** + //if (!SearchRootfound) { + // pos = strstr(root, "/", 0); + // if (pos == 0) { + // sprintf(SearchRootfound, "Betriebsystem LINUX"); + // if (check_files("/", "/")) { + // SearchRoot[SearchnRoot] = "/"; + // SearchnRoot = 1; + // } + // } + //} + } + + int n, r; + SearchStart = 0; + SearchEnd = SearchnRoot; + int iteration = 1; + int finish = 0; + int cntf; + string searchfoundfile[]; + + do { + // 1. die Root-Ordner nach der Datei durchsuchen + for (r = SearchStart; r < SearchEnd; r++) { + status(SearchRoot[r]); // Anzeige des aktuellen Verzeichnisnamen + n = check_files(SearchRoot[r], searchfile); // suche im Verzeichnis nach Datei + if (n) { + for (int f=0; f= 0) s[pos] = '\\'; + } while(pos >= 0); + return s; +} + + +// change backslash in windows path names to Eagle slash +string backslash2lash(string s) { + int pos; + do { + pos = strchr(s, '\\'); + if (pos >= 0) s[pos] = '/'; + } while(pos >= 0); + return s; +} + +string checkapostroph(string s) { // da der ganze String in ' eingeschlossen wird, + // müssen die Apostrophen verdoppelt werden. + string t[]; + int cnt; + cnt = strsplit(t, s, '\''); // check Apostroph + if (cnt > 1) { + s = ""; + for (int i = 0; i < cnt; i++) { + if (i == 0) { + if (t[i]) s += t[i]; + } + else if (i) s += "''" + t[i]; + } + } + return s; +} + +/********* export functions ***********/ +void looptest(string fname) { + string text; + int cnttext = fileread(text, fname); + if (showtest) { + dlgDialog("Export to LTspice : "+ fname) { + dlgLabel("Die Datei, siehe Kopfzeile, wurde aktuell gelesen."); + dlgLabel(fname); + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgTextEdit(text); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("Cancel") { dlgReject(); exit(-9); } + dlgPushButton("Dieses Menu nicht mehr anzeigen") { showtest = 0; dlgAccept(); } + dlgStretch(1); + } + }; + } + return; +} + + +string ex_checkbackslash(string s) { // für die Anzeige des Windows-Pfad mit Slash statt Backslash + int pos; + do { + pos = strchr(s, '\\'); + if (pos >= 0) s[pos] = '/'; + } while(pos >= 0); + return s; +} + + +string ex_check_text(string text) { // Eagle gibt Backslash doppelt aus, also halbieren! + string t[]; + int cnt = strsplit(t, text, '\n'); + if (cnt == 1) return text; + string t2 = ""; + for (int n = 0; n < cnt-1; n++) { + t2 += t[n] + "\\n"; + } + t2 += t[n]; + return t2; +} + + +string ex_checktextangle(int talign, int tangle, string name, int iangle) { + /* Wenn das Symbol gedreht ist, und der Text nicht, dann muß der Text vertikal ausgegeben werden. + Wenn der Text gedreht ist und das Symbo nicht, dann muß der Text auch vertikal ausgegeben werden, + in allen anderen Fällen horizontal. + */ + string v = ""; + + if (iangle == 0 || iangle == 180) { + if ((tangle == 90 || tangle == 270 || iangle == 90 || iangle == 270)) v = "V"; + } + else if (iangle == 90 || iangle == 270) { + if ((tangle == 0 || tangle == 180 || iangle == 0 || iangle == 180)) v = "V"; + } + switch(talign) { + case ALIGN_BOTTOM_LEFT : return v+"Left"; + break; + case ALIGN_BOTTOM_CENTER : return v+"Bottom"; + break; + case ALIGN_BOTTOM_RIGHT : return v+"Right"; + break; + case ALIGN_CENTER_LEFT : return v+"Left"; + break; + case ALIGN_CENTER : return v+"Center"; + break; + case ALIGN_CENTER_RIGHT : return v+"Right"; + break; + case ALIGN_TOP_LEFT : return v+"Left"; + break; + case ALIGN_TOP_CENTER : return v+"Top"; + break; + case ALIGN_TOP_RIGHT : return v+"Right"; + break; + default : return "Left"; + } +} + + +real ex_spicegrid(real v) { + return v / 100 * 16; +} + + +string ex_spicetextcoord(UL_TEXT T, UL_INSTANCE I) { + string s; + int ang = I.angle; + real x; + real y; + switch(ang) { + case 0 : x = ex_spicegrid(u2mil(T.x - I.x)); + y = ex_spicegrid(u2mil(T.y - I.y)*-1.0); // checked ok + break; + case 90 : if (I.mirror) { + y = ex_spicegrid(u2mil(T.x - I.x)*-1.0); + x = ex_spicegrid(u2mil(T.y - I.y)); // checked ok + } + else { + y = ex_spicegrid(u2mil(T.x - I.x)); + x = ex_spicegrid(u2mil(T.y - I.y)); // checked ok + } + break; + case 180 : if (I.mirror) { + x = ex_spicegrid(u2mil(T.x - I.x)); + y = ex_spicegrid(u2mil(T.y - I.y)); // checked ok + } + else { + x = ex_spicegrid(u2mil(I.x - T.x)); + y = ex_spicegrid(u2mil(I.y - T.y)*-1.0); // checked ok + } + break; + case 270 : if (I.mirror) { + y = ex_spicegrid(u2mil(T.x - I.x)); + x = ex_spicegrid(u2mil(T.y - I.y)*-1.0); // checked ok + } + else { + y = ex_spicegrid(u2mil(I.x - T.x)); + x = ex_spicegrid(u2mil(I.y - T.y)); // checked ok + } + break; + } + sprintf(s, "%.0f %.0f", x, y); + return s; +} + + +void ex_draw_wire(UL_WIRE W) { + if (W.curve) { + /* ARC Normal 32 -32 0 0 27 -27 5 -27 + die ersten vier Zahlen sind die umschließende Box, + die nächsten 2 die Start-Koordinate, + und die letzten beiden die End-Koordinate des ARC + */ + printf("ARC Normal %.0f %.0f %.0f %.0f %.0f %.0f %.0f %.0f\n", + ex_spicegrid(u2mil(W.arc.xc - W.arc.radius)), ex_spicegrid(u2mil(W.arc.yc + W.arc.radius)*-1.0), + ex_spicegrid(u2mil(W.arc.xc + W.arc.radius)), ex_spicegrid(u2mil(W.arc.yc - W.arc.radius)*-1.0), + ex_spicegrid(u2mil(W.arc.x1)), ex_spicegrid(u2mil(W.arc.y1)*-1.0), + ex_spicegrid(u2mil(W.arc.x2)), ex_spicegrid(u2mil(W.arc.y2)*-1.0) + ); + } + else { + printf("LINE Normal %.0f %.0f %.0f %.0f\n", + ex_spicegrid(u2mil(W.x1)), ex_spicegrid(u2mil(W.y1)*-1.0), + ex_spicegrid(u2mil(W.x2)), ex_spicegrid(u2mil(W.y2)*-1.0) + ); + } + return; +} + + +void ex_draw_rect(UL_RECTANGLE R) { + printf("LINE Normal %.0f %.0f %.0f %.0f\nLINE Normal %.0f %.0f %.0f %.0f\nLINE Normal %.0f %.0f %.0f %.0f\nLINE Normal %.0f %.0f %.0f %.0f\n", + ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y1)*-1.0), + ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y1)*-1.0), + ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y1)*-1.0), + ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y2)*-1.0), + ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y2)*-1.0), + ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y2)*-1.0), + ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y2)*-1.0), + ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y1)*-1.0) + ); + return ; +} + + +void ex_draw_poly(UL_POLYGON P) { + P.contours(W) ex_draw_wire(W); + return; +} + + +void ex_draw_net_wire(UL_WIRE W) { + printf("WIRE %.0f %.0f %.0f %.0f\n", + ex_spicegrid(u2mil(W.x1)), ex_spicegrid(u2mil(W.y1)*-1.0), + ex_spicegrid(u2mil(W.x2)), ex_spicegrid(u2mil(W.y2)*-1.0) + ); + return; +} + + +/* CIRCLE Normal 64 0 48 -16 */ +void ex_draw_circle(UL_CIRCLE C) { + printf("CIRCLE Normal %.0f %.0f %.0f %.0f\n", // 64 0 48 -16 + ex_spicegrid(u2mil(C.x - C.radius)), ex_spicegrid(u2mil(C.y + C.radius)*-1.0), + ex_spicegrid(u2mil(C.x + C.radius)), ex_spicegrid(u2mil(C.y - C.radius)*-1.0) + ); + return; +} + + +/* LTspice directiven beginnen mit ! */ +void ex_draw_text(UL_TEXT T, string option, string supply) { + string t = strupr(T.value); + real tx = ex_spicegrid(u2mil(T.x)); + real ty = ex_spicegrid(u2mil(T.y)*-1.0); + switch(T.align) { + case ALIGN_BOTTOM_LEFT : if (T.angle == 0) { + ty -= ex_spicegrid(u2mil(T.size/2)); + } + else if (T.angle == 90) { + tx += ex_spicegrid(u2mil(T.size/2)); + } + break; + case ALIGN_BOTTOM_CENTER : ; + break; + case ALIGN_BOTTOM_RIGHT : ty -= ex_spicegrid(u2mil(T.size/2)); + break; + case ALIGN_CENTER_LEFT : ty -= ex_spicegrid(u2mil(T.size/2)); + break; + case ALIGN_CENTER : ty -= ex_spicegrid(u2mil(T.size/2)); + break; + case ALIGN_CENTER_RIGHT : ty -= ex_spicegrid(u2mil(T.size/2)); + break; + case ALIGN_TOP_LEFT : ; + break; + case ALIGN_TOP_CENTER : ; + break; + case ALIGN_TOP_RIGHT : ; + break; + } + + + // TEXT 0 0 Bottom 2 +3.3V : example of supply pin name + if (Ex_PinDirSup && supply) { + if (T.layer != Ex_LayerSpiceOrder) { + printf("TEXT %.0f %.0f %s 0 %s\n", + tx, ty, + ex_checktextangle(T.align, T.angle, "", 0), + ex_check_text(supply) + ); + } + return; + } + if (t == ">NAME" || option == ">NAME") { + // WINDOW 0 36 40 Left 0 // Textplatzhalter für >NAME + if(option == ">NAME") printf("WINDOW 0 %.0f %.0f %s 0\n", tx, ty, ex_checktextangle(T.align, T.angle, "", 0)); + return; + } + if (t == ">VALUE" || option == ">VALUE") { + // WINDOW 3 36 76 Left 0 // platzhalter für >VALUE + if (option == ">VALUE") printf("WINDOW 3 %.0f %.0f %s 0\n", tx, ty, ex_checktextangle(T.align, T.angle, "", 0)); + return; + } +// if (strstr(T.value, "SpiceOrder") == 0) return; // nur vorübergehender Text im Symbol zum überprüfen + if (option == "*") { + // TEXT 0 0 Center 0 LT + printf("TEXT %.0f %.0f %s 0 %s\n", tx, ty, ex_checktextangle(T.align, T.angle, "", 0), ex_check_text(T.value)); + return; + } + t = T.value; + if (t[0] == '\\' && t[1] == '!') { // damit Eagle den Text nicht Überstreicht, muß ein Backslash vorangestellt werden. + t = strsub(t, 1); // schneide das Backslash (Escapezeichen) vor dem ! wieder ab. + } + + printf("TEXT %.0f %.0f %s 0 %s\n", + tx, ty, + ex_checktextangle(T.align, T.angle, "", 0), + ex_check_text(t) + ); + + return; +} + + +void ex_collectordertext(UL_SYMBOL S) { + Ex_CntSymText = 0; // reinitialization + S.texts(T) { + if (T.layer == Ex_LayerSpiceOrder) { + string s[]; + strsplit(s, T.value, ' '); + if (s[0] == Ex_SpiceOrder) { + Ex_PinX[Ex_CntSymText] = T.x; + Ex_PinY[Ex_CntSymText] = T.y; + Ex_SpiceOrderNum[Ex_CntSymText] = s[1]; + Ex_CntSymText++; + } + } + } +} + + +string ex_getspiceorder(int x, int y) { + for (int n = 0; n < Ex_CntSymText; n++ ) { + if (x == Ex_PinX[n] && y == Ex_PinY[n]) return Ex_SpiceOrderNum[n]; + } + return ""; +} + + +string ex_checkinverted(string pinname) { // LTspice benutzt Underline als Einleitungszeichen für den Negierungsüberstrich, + if (pinname[0] == '!') pinname[0] = '_'; // Eagle beginnt mit Ausrufezeichen. + return pinname; +} + + +void ex_draw_pin(UL_PIN P, int pcnt) { + int pinlength; + int x2, y2; + if (P.direction == PIN_DIRECTION_SUP) Ex_PinDirSup = 1; + if (pcnt) { // draw line and pin it self + switch(P.length) { // Grid unit = mil + case (PIN_LENGTH_POINT) : pinlength = 0; // kein Wire + break; + case (PIN_LENGTH_SHORT) : pinlength = 100; // 0.1-Inch-Wire + break; + case (PIN_LENGTH_MIDDLE) : pinlength = 200; // 0.2-Inch-Wire + break; + case (PIN_LENGTH_LONG) : pinlength = 300; // 0.3-Inch-Wire + break; + } + int ang = P.angle; + switch(ang) { + case (0) : x2 = pinlength; + y2 = 0; + break; + case (90) : x2 = 0; + y2 = pinlength; + break; + case (180) : x2 = pinlength * -1; + y2 = 0; + break; + case (270) : x2 = 0; + y2 = pinlength * -1; + break; + } + if (pinlength) { + printf("LINE Normal %.0f %.0f %.0f %.0f\n", // Linie des PIN + ex_spicegrid(u2mil(P.x)), ex_spicegrid(u2mil(P.y)*-1.0), // Das Vorzeichen der Y-Achse ist bei LT-Spice vertauscht + ex_spicegrid(u2mil(P.x)+x2), ex_spicegrid((u2mil(P.y)+y2)*-1.0) + ); + } + + + //if (!Ex_PinDirSup) { + printf("PIN %.0f %.0f NONE 0\n", ex_spicegrid(u2mil(P.x)), ex_spicegrid(u2mil(P.y)*-1.0 )); + printf("PINATTR PinName %s\n", ex_checkinverted(P.name)); + printf("PINATTR SpiceOrder %s\n", ex_getspiceorder(P.x, P.y)); + //} + //else { + /* **************************************************************** + if (Ex_PinDirSup) { // a supply symbol is generated + sprintf(acmd, "EDIT %s.DEV; ATTRIBUTE %s 'node.sub'; ATTRIBUT 'VALUE2' 'node';", + DEV.name, Ex_AttributeSPICEMODEL + ); + exit(acmd); + } + * ****************************************************************/ + //} + } + return; +} + + +void readconfig(void) { // read configuration file of ULP + SpiceDefaultSymLbr = cfgget("ULP:ltspice.SpiceDefaultSymLbr"); + SpiceSimulationLbr = cfgget("ULP:ltspice.SpiceSimulationLbr"); + EagleSpiceLbrDir = cfgget("ULP:ltspice.EagleSpiceLbrDir"); + LTSpiceLibDir = cfgget("ULP:ltspice.LTSpiceLibDir"); + ImpSpiceSchematicAsc = cfgget("ULP:ltspice.ImpSpiceSchematicAsc"); + LTSpiceExecute = cfgget("ULP:ltspice.LTSpiceExecute"); + SpiceSymbol = cfgget("ULP:ltspice.SpiceSymbol"); + ExpSchematic2LTpice = cfgget("ULP:ltspice.ExpSchematic2LTpice"); + SchName = cfgget("ULP:ltspice.SchName"); + Import_All_Symbols = cfgget("ULP:ltspice.Import_All_Symbols"); + ExternalSymbol = cfgget("ULP:ltspice.ExternalSymbol"); + Imp_ConnectScriptDir = cfgget("ULP:ltspice.Imp_ConnectScriptDir"); + ExpEagleSpiceSymDir = cfgget("ULP:ltspice.ExpEagleSpiceSymDir"); + Ex_SpiceAscDir = cfgget("ULP:ltspice.SpiceAscDir"); + return; +} + + +void saveconfig(void) { + cfgset("ULP:ltspice.SpiceDefaultSymLbr", SpiceDefaultSymLbr); + cfgset("ULP:ltspice.SpiceSimulationLbr", SpiceSimulationLbr); + cfgset("ULP:ltspice.EagleSpiceLbrDir", EagleSpiceLbrDir); + cfgset("ULP:ltspice.LTSpiceLibDir", LTSpiceLibDir); + cfgset("ULP:ltspice.ImpSpiceSchematicAsc", ImpSpiceSchematicAsc); + cfgset("ULP:ltspice.LTSpiceExecute", LTSpiceExecute); + cfgset("ULP:ltspice.SpiceSymbol", SpiceSymbol); + cfgset("ULP:ltspice.ExpSchematic2LTpice", ExpSchematic2LTpice); + cfgset("ULP:ltspice.SchName", SchName); + cfgset("ULP:ltspice.Import_All_Symbols", Import_All_Symbols); + cfgset("ULP:ltspice.ExternalSymbol", ExternalSymbol); + cfgset("ULP:ltspice.Imp_ConnectScriptDir", Imp_ConnectScriptDir); + cfgset("ULP:ltspice.ExpEagleSpiceSymDir", ExpEagleSpiceSymDir); + cfgset("ULP:ltspice.SpiceAscDir", Ex_SpiceAscDir); + return; +} + + +int ex_check_slash(string name) { + string s[]; + return strsplit(s, name, '/') -1; +} + + +string ex_check_dev_name(string dev) { // wenn Package-Variante "leer" dann gib auch leeren string zurück + if (dev == "''") return ""; + int pos; + do { + pos = strchr(dev, '/'); // Slash ist in Device-Namen (Packagevariant) verboten, da unter Linux sonst ein Unterordner angesprichen wird. + if (pos >= 0) dev[pos] = '_'; + } while(pos >= 0); + return dev; +} + + +string ex_check_devset_name(string devset, string pac, string tech) { // * ist in Dateinamen Deviceset verboten, + if (pac == "''") pac = ""; // da es sich hier um ein Wildcard-Zeichen handelt + if (tech == "''") tech = ""; // wie auch das ? muß es durch Pacvariante und Technology ersetzt werden. + string s[]; + int np = strsplit(s, devset, '*'); // Technologie + if (np > 1) { + if (tech == "''") tech = ""; // ein leeres Device wird intern mit '' angegeben, und muß "" (leer) werden! + devset = s[0]+tech+s[1]; + } + else { + devset = s[0]+tech; + } + int nt = strsplit(s, devset, '?'); // Packagevariante + if (nt > 1) { + if (pac == "''") pac = ""; // ein leeres Device wird intern mit '' angegeben, und muß "" (leer) werden! + devset = s[0]+pac+s[1]; + } + else { + devset = s[0]+pac; + } +//if (dlgMessageBox(">"+devset+"<", "okpactech1189", "escpactech1189") != 0) exit(-1321); + return devset; +} + + +string check_dev_description(string descript) { + if(descript[0] == '<') return ""; // Description beginnt mit HTML-Tag, dann nur leeren String zurückgeben. + string s[]; + int cnt = strsplit(s, descript, '\n'); // nur die Kopfzeile zurückgeben, da LTspice bei der Description + descript = s[0]; // keine mehrzeiligen Texte benutzen kann. + return descript; +} + + +string check_exist_asy(string symname, string sympath, string debugnum) { // müssen bestimmte symbole in bestimmten Pfaden abgelegt sein? + return file_search( symname, sympath, CntSubDir, debugnum); +} + + +int makedir(string root1, string subdir) { /*** generate DOS command MKDIR ***/ + string DOScommand; + sprintf(DOScommand, "CMD.EXE /C MKDIR \"%s%s\"", lash2backslash(root1), lash2backslash(subdir)); + system(DOScommand); + string f[]; + int n = fileglob(f, root1 + subdir); // prüfe ob das Verzeichnis angelegt werden konnte. + return n; +} + + +void check_exist_directory(string fname) { // überprüfe die Existenz des Verzeichneis, und wenn nicht vorhanden, anlegen! + string fdir = filedir(fname); + string fd[]; + int n = fileglob(fd, fdir); + int len =strlen(fdir); + if (fdir[len-1] == '/') fdir[len-1] = 0; // für MKDIR darf kein Backslash (Slash) am Ende sein. + if (!n) { + if (!makedir("", fdir)) { // Returnwert 0 wenn das Verzeichnis nicht angelegt werden konnte + dlgMessageBox("!Can't build:\n" + fdir, "ok", "esc"); + exit(-1359); + } + } + return; +} + + +void ex_draw_device(UL_DEVICE D, UL_DEVICESET DEV) { + string error; + int cntgate = 0; + D.gates(G) { + cntgate++; + } + if (ex_check_slash(DEV.name)) { + dlgMessageBox("!Do not use character / in device name!\n"+ DEV.name + ".DEV\nPlease change to '_' !", "OK"); + sprintf(error, "EDIT %s.DEV;", DEV.name); + exit(error); + } + // check attribute SPICEMODEL + string acmd = ""; + int cntnoattspicemodel = 0; + int cntnoattspiceprefix = 0; + string devnoattmodel[]; + string technoattmodel[]; + string devnoattprefix[]; + string technoattprefix[]; + int cntde = 0; + DEV.devices(DE) { + cntde++; + string t[]; + int nt = strsplit(t, DE.technologies, ' '); + int spicemodelexist = 0; + int spiceprefixexist = 0; +//if (dlgMessageBox(DEV.name + DE.name, "ok", "esc") !=0) exit(-1392); + // prüfe erst die Existenz der Spicemodelle + for (int i = 0; i < nt; i++) { + spicemodelexist = 0; + spiceprefixexist = 0; + DE.attributes(A, t[i]) { + if (A.name == "SPICEMODEL") { spicemodelexist++; // 1 = Attribute existiert + if (A.value) spicemodelexist++; // 2 = Wert gesetzt + } + if (A.name == "SPICEPREFIX") { spiceprefixexist++; // 1 = Attribute existiert + if (A.value) spiceprefixexist++; // 2 = Wert gesetzt + } + } + if (DEV.prefix == "C" || DEV.prefix == "L" || DEV.prefix == "R") { // 2014-01-23 + // C braucht kein Spicemodel + // L braucht kein Spicemodel + // R braucht kein Spicemodel + } + else { + if (spicemodelexist < 2) { + devnoattmodel[cntnoattspicemodel] = DE.name; + technoattmodel[cntnoattspicemodel] = t[i]; + cntnoattspicemodel++; + } + } + if (spiceprefixexist < 2) { // 2012-11-30 + devnoattprefix[cntnoattspiceprefix] = DE.name; + technoattprefix[cntnoattspiceprefix] = t[i]; + cntnoattspiceprefix++; + } + } + } + // check all devices of this deviceset, of attribute SPICEMODEL + string attvalspicemodel; + string attvalspiceprefix; + if (cntnoattspicemodel || cntnoattspiceprefix) { + if (cntnoattspicemodel) { // 2012-12-05 + int result = dlgDialog("Set Attributes") { + dlgHBoxLayout dlgSpacing(300); + if (cntnoattspicemodel) { + dlgLabel("" + DEV.name + ".DEV

    MISSING SpiceModel
    Type in the name of spicemodel for this device!"); + dlgStringEdit(attvalspicemodel); + } + dlgHBoxLayout { + dlgPushButton("OK") if (attvalspicemodel) dlgAccept(); + else dlgMessageBox("First type in the name of spicemodel for this device!", "OK"); + dlgPushButton("CANCEL") dlgReject(); + } + }; + if(!result) exit(-1441); + } + + if (cntnoattspiceprefix) { // 2012-12-05 + string prefixlist[]; + for (int l = 0; LTspicePrefix[l]; l++) prefixlist[l] = LTspicePrefix[l] + "\t" + LTspicePrefixDescript[l]; + int prefsel = -1; + int result = dlgDialog("Set Attributes") { + dlgHBoxLayout dlgSpacing(300); + if (cntnoattspiceprefix) { + dlgLabel("" + DEV.name + ".DEV

    MISSING SpicePrefix
    Select a spiceprefix for this device!"); + dlgListBox(prefixlist, prefsel) { attvalspiceprefix = LTspicePrefix[prefsel]; dlgAccept(); } + } + dlgHBoxLayout { + dlgPushButton("OK") if (attvalspiceprefix) dlgAccept(); + else { + if (prefsel >= 0) { + attvalspiceprefix = LTspicePrefix[prefsel]; + dlgAccept(); + } + else dlgMessageBox("First select a Spice prefix for this device.", "OK"); + } + dlgPushButton("CANCEL") dlgReject(); + } + }; + if(!result) exit(-1466); + } + // if (!spicemodelexist) dlgMessageBox("Missing attribute SPICEMODEL of technology '"+ ex_check_dev_name(actualtechno) + "' of package variant " + D.name, "OK"); + // else dlgMessageBox("Attribute SPICEMODEL of technologie '"+ ex_check_dev_name(actualtechno) + "' of package variante " + D.name + " has no value!", "OK"); + string as; + int i; + for (i = 0; i < cntnoattspicemodel; i++) { + sprintf(as, "EDIT %s.DEV;\n", DEV.name); + acmd += as; + /*** in Device und Technologie darf kein Schrägstrich, oder Backslash vorkommen, + denn das gibt ein Proglem bei Pfad und Dateinamen in Linux/MAX-OS bzw. Windows! + Hier muß ein Unterstrich benutzt werden! + ***/ + string chkdevname = ex_check_dev_name(devnoattmodel[i]); + if (devnoattmodel[i] != chkdevname && chkdevname) { // Supply-Devices haben kein Package, nicht mal '' + sprintf(as, "PACKAGE -%s %s;\n", devnoattmodel[i], chkdevname); // 2012-10-04 benenne die Packagevariante um, mit "_" als "/". + acmd += as; + } + // 2012-09-17 Attribute-Befehl zweimal aufrufen! Fehler in Dialog-Menu. + // Wenn kein Wert angegeben wird, wird es nicht als geändert erkannt, und das Attribute wird nicht angelegt! + sprintf(as, "PACkage '%s'; TECHNOLOGY %s; ATTRIBUTE %s '%s';\n", + checkapostroph(ex_check_dev_name(devnoattmodel[i])), technoattmodel[i], Ex_AttributeSPICEMODEL, attvalspicemodel // 2012-12-10 + ); + acmd += as; // if(dlgMessageBox(acmd, "acmd ok", "acmd esc") != 0) exit(-1489); ; + } + // 2012-11-30 setze den Wert für das Attribute SPICEPREFIX + for (i = 0; i < cntnoattspiceprefix; i++) { + sprintf(as, "EDIT %s.DEV;\n", DEV.name); + acmd += as; + /* ** in Device und Technologie darf kein Schrägstrich, oder Backslash vorkommen, + denn das gibt ein Proglem bei Pfad und Dateinamen in Linux/MAX-OS bzw. Windows! + Hier muß ein Unterstrich benutzt werden! + ** */ + string chkdevname = ex_check_dev_name(devnoattprefix[i]); + if (devnoattprefix[i] != chkdevname && chkdevname) { // Supply-Devices haben kein Package, nicht mal '' + sprintf(as, "PACKAGE -%s %s;\n", devnoattprefix[i], chkdevname); // 2012-10-04 benenne die Packagevariante um, mit "_" als "/". + acmd += as; + } + // 2012-09-17 Attribute-Befehl zweimal aufrufen! Fehler in Dialog-Menu. + // Wenn kein Wert angegeben wird, wird es nicht als geändert erkannt, und das Attribute wird nicht angelegt! + sprintf(as, "PACkagE '%s'; TECHNOLOGY %s; ATTRIBUTE %s '%s';\n", + checkapostroph(ex_check_dev_name(devnoattprefix[i])), technoattprefix[i], Ex_AttributeSPICEPREFIX, attvalspiceprefix // 2012-12-10 + ); + acmd += as; // if(dlgMessageBox(acmd, "acmd ok", "acmd esc") != 0) exit(-1509); ; + } + + if (acmd) { +if (dlgMessageBox("ex_draw_device() : exit " + acmd , "ok", "esc") != 0) exit(-1513); + exit(acmd); + } + } +//if (dlgMessageBox("ex_draw_device() : symbole ausgeben" , "ok", "esc") != 0) exit(-1517); + + Ex_PinDirSup = 0; + DEV.gates(G) { + library(L) { + L.symbols(SYM) { + if (SYM.name == G.symbol.name) { // prüfe nur die zum Device gehörenden Symbole + if (ex_check_slash(SYM.name)) { + dlgMessageBox("!Do not use character / in symbol name!\n"+SYM.name+".SYM\nPlease change to '_' !", "OK"); + sprintf(error, "EDIT %s.SYM;", SYM.name); + exit(error); + } + // check exist SpiceOrder + int cnttext = 0; + int cntpin = 0; + string h; + SYM.texts(T) { + if (T.layer == Ex_LayerSpiceOrder) { + if (strstr(T.value, "SpiceOrder") == 0) cnttext++; + } + } + SYM.pins(P) { + if (P.direction == PIN_DIRECTION_SUP) Ex_PinDirSup = 1; // ein Supply-Pin ist beteiligt, also ist es ein Supply-symbol + cntpin++; + } + if (!cnttext) { + sprintf(h, "!Symbol %s can not be exported, missing SpiceOder for PINs!", SYM.name); + dlgMessageBox(h, "OK"); + sprintf(h, "EDIT %s.SYM;RUN spiceorder.ulp", SYM.name); + exit(h); + } + if (cnttext != cntpin) { + dlgMessageBox("!Different counts of SpiceOrder and PINs.", "OK"); + sprintf(h, "EDIT %s.SYM;RUN spiceorder.ulp", SYM.name); // run spiceordr.ulp to define the missing spiceorder in device + exit(h); + } + ex_collectordertext(SYM); + + string actgatename = G.name; + if (cntgate < 2) actgatename = ""; // wenn Deviceset nur aus 1 Gate besteht, + // dann den Gatenamen nicht benutzen! + // keine leere '' Package-Variante angeben + int ltspicelbr = strstr(L.name, "/ltspice/"); + string tech[]; + int n = strsplit(tech, D.technologies, ' '); + for (int i = 0; i < n; i++) { + if (ltspicelbr > 0) { // eine LTspice importierte LBR ist geladen + Ex_AsyName = LTSpiceLibDir + "sym/" + DEV.library + "/" + ex_check_devset_name(DEV.name, D.name, "") + actgatename + ".asy"; // keine leere '' Package-Variante angeben + } + // eine Eagle-Lbr ist geladen + else Ex_AsyName = ExpEagleSpiceSymDir + DEV.library + "/" + ex_check_devset_name(DEV.name, D.name, tech[i]) + actgatename + ".asy"; // 2012-12-10 Technologie + // für jede technologie ein symbol anlegen 2012-10-02 + check_exist_directory(Ex_AsyName); // 2012-12-10 bevor das Symbol angelegt werden kann, muß das Verzeicnis existieren! + output(Ex_AsyName, "wt") { +//if (dlgMessageBox(Ex_AsyName, "ok", "esc") != 0) exit(-1571); + CntOutput++; + printf("Version 4\n"); + printf("SymbolType CELL\n"); + int pcnt = 0; + SYM.wires(W) ex_draw_wire(W); // Symbollinien zeichnen. + SYM.polygons(POL) ex_draw_poly(POL); // Die Kontur des Polygon zeichen (werden nicht gefüllt). + SYM.rectangles(R) ex_draw_rect(R); // Rechteck als Linien zeichnen. + SYM.circles(C) ex_draw_circle(C); + SYM.texts(T) { + if (T.layer != Ex_LayerSpiceOrder && T.layer != 93) { // Spiceorder nicht als Text ausgeben! Zusätzliche Doku im Layer 93 Pins nicht ausgeben. + if (strupr(T.value) != ">NAME" && strupr(T.value) != ">VALUE") ex_draw_text(T, "*", SYM.name); // beliebiger Text + else if (strupr(T.value) == ">NAME") ex_draw_text(T, ">NAME", ""); // der Textplatzhalter >NAME + else if (strupr(T.value) == ">VALUE") ex_draw_text(T, ">VALUE", ""); // der Textplatzhalter >VALUE + } + } + /* + SYMATTR Value LT6231 + SYMATTR Prefix X + */ + printf("SYMATTR Value %s\n", DEV.name); // nicht der Device-Prefix, sondern der Device-Name + + string t[]; + int n = strsplit(t, D.technologies, ' '); + // check exist Spice Attribute for Spice Model + //int spicemodelexist = 0; + //int spiceprefixexist = 0; + string actualtechno = ""; + /* + SYMATTR Value LT3518 + SYMATTR Prefix X + SYMATTR SpiceModel LT3518.sub + SYMATTR Value2 LT3518 + */ + + string aspiceprefix; + string aspicemodel; + string avalue2; + string aspiceline; + string aspiceline2; + string aspicetype; + DEV.devices(DE) { + if (DE.name == D.name) { + for (int i = 0; i < n; i++) { + D.attributes(A, t[i]) { + actualtechno = t[i]; + if (A.name == "SPICEPREFIX") { + sprintf(aspiceprefix, "SYMATTR Prefix %s\n", A.value); // + } + else if (A.name == "SPICEMODEL") { + //spicemodelexist++; // 1 = Attribute existiert + if (A.value != "NONE") { + sprintf(aspicemodel, "SYMATTR SpiceModel %s\n", A.value); + + } + else { + //if (dlgMessageBox(A.name + " : " + A.value, "NONE ok", "NONE esc") != 0) exit(-1627); + } + } + /* Der Value im LTspice-Symbol ist der Devicesetname + else if (A.name == "VALUE") { + sprintf(avalue, "SYMATTR Value %s\n", A.value); + } + */ + else if (A.name == "VALUE2") { + sprintf(avalue2, "SYMATTR Value2 %s\n", A.value); + } + else if (A.name == "SPICELINE") { + sprintf(aspiceline, "SYMATTR Spiceline %s\n", A.value); + } + else if (A.name == "SPICELINE2") { + sprintf(aspiceline2, "SYMATTR Spiceline2 %s\n", A.value); + } + else if (A.name == "SPICETYPE") { + sprintf(aspicetype, "SYMATTR Type %s\n", A.value); + } + } + } + printf("%s", aspiceprefix); + printf("%s", aspicemodel); + if (avalue2) printf("%s", avalue2); + if (aspiceline) printf("%s", avalue2); + if (aspicetype) { + printf("%s", aspicetype); + } + } + } + printf("SYMATTR Description %s\n", check_dev_description(DEV.description)); + SYM.pins(P) ex_draw_pin(P, 1); // die Linien der Pins plus die PINs selbst zeichnen. + /* export no description + string descript = DEV.description; + if (!descript) descript = DEV.prefix; + printf("SYMATTR Description : %s Export with %s\n", descript, argv[0]); + SYM.pins(P) ex_draw_pin(P, ++pcnt); // die Pinkontakte selbst + */ + } // end output() + } + } + } + } + } + if (Test) looptest(Ex_AsyName); + return; +} + + +void ex_draw_label(UL_LABEL L) { + // ein Flag ist ein Supply-Symbol, wobei nur zwischen 0 == GND und COM == Common unterschieden wird. + return; +} + + +void ex_draw_line(UL_WIRE W) { + return; +} + + +void ex_draw_rectangle(UL_RECTANGLE R) { + // RECTANGLE Normal 352 336 288 304 + printf("RECTANGLE Normal %.0f %.0f %.0f %.0f\n", + ex_spicegrid(u2mil(R.x1)), ex_spicegrid(u2mil(R.y1)*-1.0), + ex_spicegrid(u2mil(R.x2)), ex_spicegrid(u2mil(R.y2)*-1.0) + ); + return; +} + + +string ex_check_gate_name(UL_PART P, string igatename) { + // wenn Device aus nur 1 Gate besteht, dann keine Gate-Namen verwenden + int gcnt = 0; + P.deviceset.gates(G) { + gcnt++; + } + //string h; + //sprintf(h, "%s (%s) has %d gates!", P.name, P.deviceset.name, gcnt); + if (gcnt == 1) return ""; + return igatename; +} + + +void ex_draw_instance(UL_INSTANCE I, UL_PART P) { + int cnttext = 0; + int cntpin = 0; + string h; + string currentgatename = ex_check_gate_name(P, I.gate.name); + string libpath; + + I.gate.symbol.texts(T) { + if (T.layer == Ex_LayerSpiceOrder) { + if (strstr(T.value, "SpiceOrder") == 0) cnttext++; + } + } + I.gate.symbol.pins(P) { + cntpin++; + } + if (cnttext != cntpin || !cnttext) { + if (!cnttext) { + sprintf(h, "!No SpiceOrder in symbol %s of Part %s,\nplease define the SpiceOder for PINs first!", I.gate.symbol.name, P.name); + } + if (cnttext != cntpin) { + sprintf(h, "!Different quantity of SpiceOrder and PINs in symbol %s of part %s (%s).\nPlease check symbol!", + I.gate.symbol.name, P.name, P.device.name + ); + } + dlgMessageBox(h, "OK"); + libpath = file_search(P.deviceset.library+".lbr", EAGLE_DIR, 4, "1733"); + if (strstr(libpath, P.deviceset.library) < 0) { + dlgMessageBox("Library " + P.deviceset.library + ".lbr not found in path:\n"+ EAGLE_DIR, "OK"); + if (dlgMessageBox("Export from schematic ?", "YES", "CANCEL") != 0) exit(-1739); + exit("RUN exp-project-lbr"); + } + sprintf(h, "OPEN '%s';\nEDIT %s.DEV;RUN spiceorder.ulp", libpath, P.deviceset.name); + //if (dlgMessageBox(h, "ok", "esc1740") != 0) exit(-1743); + exit(h); + } + if (P.deviceset.library == "lt-supply") { // LTspice-Versorgungssymbole bzw. LABEL müssen in der lt-supply.lbr angelegt sein! + // FLAG(s) haben keine Rotation, sie werden anhand der Richtung des angelegten WIRE ausgerichtet! + if (P.device.name == "0") { // FLAG 144 -416 0 + printf("FLAG %.0f %.0f 0\n", ex_spicegrid(u2mil(I.x)), ex_spicegrid(u2mil(I.y)*-1.0)); + return; + } + else if (P.device.name =="COM") { // FLAG -128 288 COM + printf("FLAG %.0f %.0f COM\n", ex_spicegrid(u2mil(I.x)), ex_spicegrid(u2mil(I.y)*-1.0)); + return; + } + else { + printf("FLAG %.0f %.0f %s\n", ex_spicegrid(u2mil(I.x)), ex_spicegrid(u2mil(I.y)*-1.0), P.device.name); + return; + } + } + + string devicename = P.device.name; + if (P.deviceset.library == "lt-spice-simulation") { // Spezielle Behandlung von Bauteilen aus der Simulations-LBR + if (devicename == "RES_RLOAD") devicename = "res"; // Konvertiere einen LOAD-Resistor wieder zurück zu "res" + else if (devicename == "VOLTAGE"); + else if (devicename == "CURRENT"); + else if (devicename == "BV"); + else if (devicename == "E"); + else if (devicename == "LOAD"); // ein LOAD (veränderbarer Widerstand) als Last aus der lt-spice-simulation.lbr + else { + dlgMessageBox("Unknown simulation part " +P.name+ " (Device:"+ devicename + "), please check :
    " + P.deviceset.library + ".lbr", "OK"); + exit(-1772); + } + } + // Prüfe das Vorhandensein des benötigten Symbol in der LTspice-Datenstruktur. + // Müssen bestimmte Symbole in bestimmten Verzeichissen abgelegt sein? + string asyfile; + if (P.deviceset.library == "lt-spice-simulation") { + asyfile = check_exist_asy(ex_check_dev_name(devicename+currentgatename+".asy"), LTSpiceLibDir, "init"); + } + else if (P.deviceset.library == "lt-supply") { + if (dlgMessageBox(devicename+currentgatename+".asy" + ":" + LTSpiceLibDir , "ok1779", "esc1779") != 0) exit(-1782); + } + else { + asyfile = check_exist_asy(ex_check_dev_name(devicename+currentgatename+".asy"), LTSpiceLibDir, "1782"); // evtl. einen Ordner weiter unten beginnen, ExpEagleSpiceSymDir); + } + if (!asyfile) { // 2014-01-23 + if (dlgMessageBox(LTSpiceLibDir + "\n" + devicename+currentgatename + ".asy\ndoes not exist as LTspice symbol.\nOpen library and deviceset, and export device (symbols).", "OK", "CANCEL") != 0) exit(-1788); + libpath = file_search(P.deviceset.library+".lbr", EAGLE_DIR, 4, "1786"); + sprintf(h, "OPEN '%s';\nEDIT %s.DEV;", libpath, P.deviceset.name); + exit(h); + } + + /* *** Lastwiderstände "Rload" benutzen das selbe Symbol wie R (res.asy) beim **** + **** importieren wird dem Devicenamen (Instance) der Zusatz "_RLOAD" vergeben. *** */ + if (devicename == "RES_RLOAD") devicename = "res"; // hier ohne den expliziten Hinweis auf die Herkunft (LBR) + + string rotation; + sprintf(rotation, "R%.0f", I.angle); // ok 2012-05-11 + if (rotation == "R0" && I.mirror) rotation = "M0"; + else if (rotation == "R180" && I.mirror) rotation = "M180"; + else if (rotation == "R180") rotation = "R180"; + else if (rotation == "R90" && I.mirror) rotation = "M270"; + else if (rotation == "R90") rotation = "R270"; + else if(rotation == "R270" && I.mirror) rotation = "M90"; + else if(rotation == "R270") rotation = "R90"; + + printf("SYMBOL %s %.0f %.0f %s\n", + // Device- und Gate-Namen dürfen keine Slash enthalten, siehe LTspiceFormatInfo. + ex_check_dev_name(devicename+currentgatename), // aktueller Gatename, wenn Device aus mehr als 1 Gate besteht + /*** hier fehlt evtl. noch die Technologie ***/ + ex_spicegrid(u2mil(I.x)), + ex_spicegrid(u2mil(I.y)*-1.0), + rotation + ); + string iname = I.name; + if (strstr(iname, "RLOAD") == 0) { + // iname = "Rload"; Kleinschreibung muß nicht sein! + } + printf("SYMATTR InstName %s\n", iname); + printf("SYMATTR Value %s\n", I.value); + string SPICEMODEL = "", VALUE2 = "", SPICELINE = "", SPICELINE2 = "", SPICETYPE = "", NAME = "", VALUE = ""; + + /* nur in der LBR für das Symbol ausgeben + if (P.attribute["SPICEMODEL"]) { + SPICEMODEL = P.attribute["SPICEMODEL"]; + } */ + if (P.attribute["VALUE2"]) { + VALUE2 = P.attribute["VALUE2"]; + if (VALUE2) printf("SYMATTR Value2 %s\n", VALUE2); + } + if (P.attribute["SPICELINE"]) { + SPICELINE = P.attribute["SPICELINE"]; + if(SPICELINE) printf("SYMATTR SpiceLine %s\n", SPICELINE); + } + if (P.attribute["SPICELINE2"]) { + SPICELINE2 = P.attribute["SPICELINE2"]; + if(SPICELINE2) printf("SYMATTR SpiceLine2 %s\n", SPICELINE2); + } + if (P.attribute["SPICETYPE"]) { + SPICETYPE = P.attribute["SPICETYPE"]; + if (SPICETYPE) { + printf("SYMATTR Type %s\n", SPICETYPE); + } + } + + I.gate.symbol.texts(T) { + if (strupr(T.value) == ">VALUE") VALUE = T.value; + } + + I.texts(T) { + int windowattrib = -1; + int textoffset = 0; + if (I.name == T.value) windowattrib = 0; + else if (I.value == T.value) windowattrib = 3; + else if (SPICETYPE == T.value) windowattrib = 1; + else if (SPICEMODEL == T.value) windowattrib = 38; + else if (SPICELINE == T.value) windowattrib = 39; + else if (SPICELINE2 == T.value) windowattrib = 40; + else if (VALUE2 == T.value) windowattrib = 123; + if (windowattrib >=0) { + printf("WINDOW %d %s %s %.0f\n", + windowattrib, + ex_spicetextcoord(T, I), + ex_checktextangle(T.align, T.angle, P.name, I.angle), + u2mil(textoffset) + ); + } + } + + return; +} + + +/****************** Import functions *********************/ +void imp_Testview(string head) { + int sel = 0; + int srt = 0; + for (int n = 0; n < Imp_CntW; n++) { + sprintf(Imp_LineView[n], "%d\t%d\t%d\t%d\t%d\t%d\t%d", n, Imp_WireX1[n], Imp_WireY1[n], Imp_WireX2[n], Imp_WireY2[n], Imp_WireSeg[n], Imp_WireType[Imp_WireSeg[n]]); + } + dlgDialog(head) { + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgListView("Nr.\tx1\ty1\tx2\ty2\tSegnr\t1 BUS/2 NET", Imp_LineView, sel, srt); + } + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-1890); } + dlgStretch(1); + } + }; + return; +} + + +void imp_helpSimulationSymbols(void) { + dlgDialog("HELP import-LTspice") { + dlgHBoxLayout dlgSpacing(400); + dlgLabel(Imp_InfoExternalSymbol); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + + +string imp_dirname(string name) { // ermittle den letzen Verzeichnisnamen + string s[]; + int cntd = strsplit(s, name, '/'); + if (cntd > 1) return s[cntd-2]; + return s[0]; +} + + +string imp_check_use(string lname) { // check exist lbr in library path + if (!lname) return ""; + + for (int n = 0; n < Imp_CntUsedLbrs; n++) { // check lbr in used list? + if (Imp_UsedLbrs[n] == lname) return ""; // LBR are in use + } + int nl = 0; + int exist = 0; + string lb[]; + string dir = filedir(lname); // prüfe auf kompletten Pfad-Datei-Namen + if (dir) { // mit Pfad zur Lib + if (fileglob(lb, lname)) { + Imp_Cmd += "USE '" + lname + "'; #1933\n"; + Imp_UsedLbrs[Imp_CntUsedLbrs] = lname; // set lbr on used list + Imp_CntUsedLbrs++; + return "@"+lname; + } + else { + do { + if (fileglob(lb, path_lbr[nl] + "/" + lname + "*.lbr")) { + Imp_Cmd += "USE '" + path_lbr[nl] + "/" + lname + ".lbr'; #1941\n"; + Imp_UsedLbrs[Imp_CntUsedLbrs] = lname; // set lbr on used list + Imp_CntUsedLbrs++; + return "@"+path_lbr[nl] + "/" + lname + ".lbr"; + } + nl++; + } while(path_lbr[nl]); + + dlgMessageBox("!Library does not exist:\n\n\"" + lname + "\"\n\nULP aborted.", "OK"); + //return "lbr not found"; + exit(-1951); + } + } + else { // Ohne Pfad zur Lib, suche in allen Verzeichnissen die im Control-Panel angegeben sind. + do { + if (fileglob(lb, path_lbr[nl] + "/" + lname + "*.lbr")) { + Imp_Cmd += "USE '" + path_lbr[nl] + "/" + lname + ".lbr'; #1957\n"; + Imp_UsedLbrs[Imp_CntUsedLbrs] = lname; // set lbr on used list + Imp_CntUsedLbrs++; + return "@"+path_lbr[nl] + "/" + lname + ".lbr"; + } + nl++; + } while(path_lbr[nl]); + dlgMessageBox("!Library " + lname + ".lbr can't be found in path!
    Please check: Control Panel - Options - Directories - Libraries.
    Add path of : " + lname + ".lbr.
    " + + "Are you sure, you have imported this lbr from LTspice?", "OK"); + exit(-3); + } +} + + +int check_exist_packname(string pacname) { + int len = strlen(pacname); + if (!len) { + dlgMessageBox("! No package name : Error 1674", "CANCEL"); exit(-1962); + } + if (pacname[len-1] == '\'') pacname[len-1] =0; + if (pacname[0] == '\'') pacname = strsub(pacname, 1); + + library(L) L.packages(PAC) { + if (PAC.name == pacname) return 1; + } + return 0; +} + + +string get_pac_from_script(string scriptname) { // lade existierendes script und suche nach der Packagebezeichnung + string scrlines[]; + int cntsline = fileread(scrlines, scriptname); + string s[]; + int cnt; + int pacexist = 0; + int paccnt = 0; + string pacname = ""; + for ( int n = 0; n < cntsline; n++) { + cnt = strsplit(s, scrlines[n], ' '); + if (s[0] == "Package") { + paccnt++; + if (check_exist_packname(s[1])) { + pacname = s[1]; + pacexist++; + } + else { + dlgMessageBox("!Script:" + scriptname + "\nPackage " + s[1] + " not found in lbr.", "OK"); + exit(-1992); + } + } + else if (s[1] == "Package") { // Die Zeile beginnt mit einem SPACE + paccnt++; + if (check_exist_packname(s[2])) { + pacname = s[2]; + pacexist++; + } + else { + dlgMessageBox("!Script:\n" + scriptname + "\nPackage " + s[2] + " not found in lbr.", "OK"); + exit(-2003); + } + } + } + if (paccnt == pacexist) return pacname; // das zuletzt gefundene Package wird zurückgegeben + return ""; +} + + +string imp_checkpinname(string pname) { + /* + LTspice läßt gleichen Pin-Namen mehrfach zu, + in Eagle muß der Pinname eindeutig sein, + hier wird geprüft ob der Pinname einzigartig ist. + Wenn nein, dann wird "@n" hinzugefügt, wobei im SCH + das Zeichen @ und alle dahinter vorkommenden Zeichen + nicht angezeigt werden. n wird hochgezählt. + */ + if (pname[0] == '_') pname[0] = '!'; // LTspice benutzt das Underlinezeichen als Einleitung des Negierungsüberstrich, + string name = pname; // Eagle benutzt das Ausrufezeichen, also tauschen. + int cnt = 0; + do { + int found = 0; + for(int n = 0; n < Imp_CntPinname; n++) { + if (name == Imp_SpicePinName[n]) { + found = 1; + break; + } + } + if (!found) { + Imp_SpicePinName[Imp_CntPinname] = name; + Imp_CntPinname++; + return name; + } + else { + sprintf(name, "%s@%d", pname, ++cnt); + } + } while(pname); +} + + +real imp_eagle_coordvalue(real v) { // calculate LT_SPice-16-Grid to Eagle-100-mil-Grid + return (v / 16) * 100; +} + + +void imp_add_wire(int x1, int y1, int x2, int y2) { + Imp_WireX1[Imp_CntW] = x1; // für die spätere Untersuchung wegen des BUS-Flags + Imp_WireY1[Imp_CntW] = y1; + Imp_WireX2[Imp_CntW] = x2; + Imp_WireY2[Imp_CntW] = y2; + Imp_CntW++; + + // LT-Spice rotiert ein FLAG (Supplypin/Label) automatisch + // anhand der Ausrichtung des Wire, an dessen Ende das FLAG sitzt. + // Dazu muß man alle Wire sammeln, um dann später die Rotation + // des FLAG zu bestimmen. + // Hier wird die Tabelle aufgebaut, für die Funktion lookup(). + sprintf(Imp_Coords[Imp_CntCo], "%d %d;%d %d", x1, y1, x2, y2); // erstellen der Tabelle für lookup() + Imp_CntCo++; + sprintf(Imp_Coords[Imp_CntCo], "%d %d;%d %d", x2, y2, x1, y1); + Imp_CntCo++; + return; +} + + +int imp_getflagrotate(string coord, string l) { + string xy2[]; + strsplit(xy2, lookup(Imp_Coords, coord, 1, ';'), ' '); // prüfe auf übereinstimmung der Wire-Koordinaten + if (!xy2[0]) { // Rückgabewert ist leer, wenn keine Wire-Koordinate gefunden wurde. + strsplit(xy2, coord, ' '); + sprintf(h, "Import line: %s\nCould not find wire's coordinates in order to place a supply symbol.\n(%.4fmil %.4fmil)", + l, + imp_eagle_coordvalue(strtod(xy2[0])), // als Eagle-Koordinate anzeigen + imp_eagle_coordvalue(strtod(xy2[1]))*-1.0 + ); + if (dlgMessageBox(h, "OK", "CANCEL") != 0) exit(-2079); + return 0; + } + real r; + string xy1[]; + strsplit(xy1, coord, ' ' ); + int x1 = strtol(xy1[0]); + int y1 = strtol(xy1[1]); + int x2 = strtol(xy2[0]); + int y2 = strtol(xy2[1]); + if (x1 == x2) { // vertical + if (y1 < y2) Imp_FlagRotate = 180.0; // in LT-Spice ist die Y-Achse auf den Kopf gestellt + else Imp_FlagRotate = 0.0; + } + else if (y1 == y2) { // horizontal + if (x1 < x2) Imp_FlagRotate = 270.0; // in LT-Spice ist die Y-Achse auf den Kopf gestellt + else Imp_FlagRotate = 90.0; + } + else Imp_FlagRotate = 0.0; + return 1; +} + + +void imp_get_net_segment(void) { + /* + LT-Spice zeichnet WIRE immer von rechts nach links, und von unten nach oben! + Ein BUS wird erst am Ende durch ein BUSTAP markiert. + In Eagle wird NET und BUS unterschieden, sowohl als Befehl als auch als Objekt. + Hier müssen zuerst die Segmente zugeordnet werden, und dann als NET oder BUS + gezeichnet werden. + + WireSeg[]; // Da ein NET sehr verzweigt, und später mit einem BUSTAB zu einem BUS deklariert werden kann, + // werden die Wire, Segmenten zugeordnet. + WireType[]; // Der Index des WireType entspricht der Segmentnummer. + // Der Inhalt wird zunächst auf NET gesetzt, wird im Segment eine Koordinate eines BUSTAB + // gefunden, so wird das Segment auf BUS gesetzt. + CntSeg = 0; // Anzahl der Segmente + + */ + int found = 0; + Imp_CntSeg = 0; + int fx1 = Imp_WireX1[0]; + int fy1 = Imp_WireY1[0]; + int fx2 = Imp_WireX2[0]; + int fy2 = Imp_WireY2[0]; + + for (int n = 0; n < Imp_CntW; n++) { + if (!Imp_WireSeg[n]) { + Imp_WireSeg[n] = ++Imp_CntSeg; + Imp_WireType[Imp_CntSeg] = NET; // setze Segment-Type NET als Default + } + fx1 = Imp_WireX1[n]; + fy1 = Imp_WireY1[n]; + fx2 = Imp_WireX2[n]; + fy2 = Imp_WireY2[n]; + + do { + found = 0; + for(int i = n+1; i < Imp_CntW; i++) { + if (!Imp_WireSeg[i]) { + if ( Imp_WireX1[i] == fx1 && Imp_WireY1[i] == fy1 || Imp_WireX2[i] == fx2 && Imp_WireY2[i] == fy2 || + Imp_WireX1[i] == fx2 && Imp_WireY1[i] == fy2 || Imp_WireX2[i] == fx1 && Imp_WireY2[i] == fy1 ) { + Imp_WireSeg[i] = Imp_CntSeg; + found = i; + fx1 = Imp_WireX1[i]; + fy1 = Imp_WireY1[i]; + fx2 = Imp_WireX2[i]; + fy2 = Imp_WireY2[i]; + } + } + } + } while (found > 0); + } + Imp_WireChecked = 1; // Segmente ermittelt + return; +} + + +void imp_check_bus(int x, int y) { // check Koordinate auf BUSTAB + for (int n = 0; n < Imp_CntW; n++) { + if ( Imp_WireX1[n] == x && Imp_WireY1[n] == y || Imp_WireX2[n] == x && Imp_WireY2[n] == y) { + Imp_WireType[Imp_WireSeg[n]] = BUS; + break; + } + } + return; +} + + +void imp_draw_net(void) { // zeichne alle NETze und BUSse + Imp_Cmd += "SET CONFIRM YES;\n"; + string commandtype = "NET"; + for (int n = 0; n < Imp_CntW; n++ ) { + commandtype = "NET"; + if (Imp_WireType[Imp_WireSeg[n]] == BUS) { + sprintf(commandtype, "BUS 'B_$%d' ", Imp_WireSeg[n]); + } + sprintf(h, "%s (%.4f %.4f) (%.4f %.4f);\n", + commandtype, + imp_eagle_coordvalue(Imp_WireX1[n]), + imp_eagle_coordvalue(Imp_WireY1[n])*-1.0, + imp_eagle_coordvalue(Imp_WireX2[n]), + imp_eagle_coordvalue(Imp_WireY2[n])*-1.0 + ); + Imp_Cmd+= h; + } + Imp_Cmd += "SET CONFIRM OFF;\n"; + Imp_DrawNetBus = 1; // Flag NET/BUS gezeichnet + return; +} + + +void imp_version(string l) { + // Version 4 + string s[]; + int n = strsplit(s, l, ' '); + int versionnumber = strtol(s[1]); + sprintf(h, "# Spice version %d\n", versionnumber); + Imp_Cmd += h; + return; +} + + +// calculate angle from a pair of coordinates +real imp_wire_angle(int x1, int y1, int x2, int y2) { + real xe = imp_eagle_coordvalue(x1); + real ye = imp_eagle_coordvalue(y1); + real xa = imp_eagle_coordvalue(x2); + real ya = imp_eagle_coordvalue(y2); + real RADIUS = sqrt(((xa - xe) * (xa - xe)) + ((ya - ye) * (ya - ye))); + + if ((xa > xe) && (ya >= ye)) { /* Quadrant 1 */ + return acos((xa - xe) / RADIUS) * 57.29578; + } + if ((xa < xe) && (ya >= ye)) { /* Quadrant 2 */ + return acos((xa - xe) / RADIUS) * 57.29578; + } + if ((xa < xe) && (ya < ye)) { /* Quadrant 3 */ + return 360 - acos((xa - xe) / RADIUS) * 57.29578; + } + if ((xa > xe) && (ya < ye)) { /* Quadrant 4 */ + return 360 - acos((xa - xe) / RADIUS) * 57.29578; + } + if ((xa == xe) && (ya == ye)) { /* Ursprung */ + return (xa - xe); + } + if ((xa == xe) && (ya > ye)) { /* 90 */ + return (xa - xe + 90); + } + if ((xa == xe) && (ya < ye)) { /* 270 */ + return (xa - xe + 270); + } +} + + +/****************************************************** + parse library lines +******************************************************/ +void imp_symboltype(string l){ + // SymbolType CELL + // SymbolType BLOCK + string s[]; + int n = strsplit(s, l, ' '); + string symboltype = s[1]; + + if (symboltype == "CELL") { + } + else if (symboltype == "BLOCK") { + } + else { + dlgMessageBox("Unknown symbol type:\n" + l, "CANCEL"); + exit(-2250); + } + sprintf(h, "# Symbol Type %s\n", symboltype); + Imp_Cmd += h; + sprintf(h, "CHAnge Align Left Center; # Symbol\n"); + Imp_Cmd += h; + return; +} + + +void imp_line(string l) { + string s[]; + int n = strsplit(s, l, ' '); + if (s[1] == "Normal") { + Imp_Cmd+="CHANGE WIDTH 6 ;\n"; + } + else if (s[1] == "Bold") { + Imp_Cmd+="CHANGE WIDTH 10;\n"; + } + else { + string e; + sprintf(e, "Unknown LINE " + s[1]); + dlgMessageBox(e, "OK"); + exit(-2273); + } + if (s[6]) { + if (s[6] == "0") { + Imp_Cmd += "CHANGE STYLE Continuous;\n"; + } + else if (s[6] == "1") { + Imp_Cmd += "CHANGE STYLE LongDash;\n"; + } + else if (s[6] == "2") { + Imp_Cmd += "CHANGE STYLE ShortDash;\n"; + } + else if (s[6] == "3") { + Imp_Cmd += "CHANGE STYLE DashDot;\n"; + } + else { + Imp_Cmd += "CHANGE STYLE Continuous;\n"; + } + } + sprintf(h, "SET WIRE_BEND 2;\nLAYER 94;\nWIRE (%.4f %.4f) (%.4f %.4f);\n", + imp_eagle_coordvalue(strtod(s[2])), + imp_eagle_coordvalue(strtod(s[3])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[4])), + imp_eagle_coordvalue(strtod(s[5])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt + ); + Imp_Cmd+=h; + return; +} + + +void imp_rectangle(string l) { + string s[]; + int n = strsplit(s, l, ' '); + if (s[1] == "Normal") { + Imp_Cmd+="CHANGE WIDTH 6;\n"; + } + else if (s[1] == "Bold") { + Imp_Cmd+="CHANGE WIDTH 10;\n"; + } + sprintf(h, "SET WIRE_BEND 2;\nLAYER 94;\nWIRE (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[4])), imp_eagle_coordvalue(strtod(s[3])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[4])), imp_eagle_coordvalue(strtod(s[5])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[5])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt + ); + Imp_Cmd+=h; + return; +} + + +void imp_circle(string l) { + /* + Definition eines CIRCLE: + Die ersten zwei Koordinaten definieren mit den zwei diagonalen Ecken ein umschliesendes + Rechteck um den Kreis. Innerhalb dieses Rechteck befindet sich der Kreis, also + ist Breite und Länge des Rechteck zugleich der Durchmesser. + */ + string s[]; + int n = strsplit(s, l, ' '); + if (s[1] == "Normal") { + Imp_Cmd+="CHANGE WIDTH 6 ;\n"; + } + else if (s[1] == "Bold") { + Imp_Cmd+="CHANGE WIDTH 10;\n"; + } + sprintf(h, "LAYER 94;\nCIRCLE (%.4f %.4f) (%.4f %.4f);\n", + (imp_eagle_coordvalue(strtod(s[2])) + imp_eagle_coordvalue(strtod(s[4]))) / 2, + (imp_eagle_coordvalue(strtod(s[3])*-1.0) + imp_eagle_coordvalue(strtod(s[5])*-1.0)) / 2, // in LT-Spice ist die Y-Achse auf den Kopf gestellt + (imp_eagle_coordvalue(strtod(s[2])) + imp_eagle_coordvalue(strtod(s[4]))) / 2, + imp_eagle_coordvalue(strtod(s[5])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt + ); + Imp_Cmd+=h; + return; +} + + +void imp_arc(string l) { + // ARC Normal -20 -124 4 -100 -20 -112 -8 -100 + /* + Definition des ARC: + Die ersten zwei Koordinaten definieren die zwei diagonalen Ecken eines umschließenden + Rechteck um einen Kreis. Die Mitte dieses Rechteck ist der Mittelpunkt des Kreises, + und somit der Mittelpunkt des ARC. + Die 3. und 4. Koordinate ergibt vom Mittelpunkt des zuvor definierten Kreises + den Anfangswinkel und die 7. und 8. Koordinate den Endwinkel. + Die Genauigkeit der Zeichnungen bezüglich der Enden eines ARC in LT-Spice, ist beschränkt + durch die relativ geringe Auflösung von 16 (Einheiten), siehe ARC in Optokoppler PC817D. + 2011-10-12 + */ + string s[]; + int n = strsplit(s, l, ' '); + if (s[1] == "Normal") { + Imp_Cmd+="CHANGE WIDTH 6 ;\n"; + } + else if (s[1] == "Bold") { + Imp_Cmd+="CHANGE WIDTH 10;\n"; + } + + if (n > 10) { + sprintf(h, "# %d Parameter in line:\n# %s\n", n, l); + Imp_Cmd+=h; + } + int centerx = (strtod(s[2]) + strtod(s[4])) / 2; + int centery = (strtod(s[3])*-1.0 + strtod(s[5])*-1.0) / 2; + int aax = strtod(s[6]); + int aay = strtod(s[7]) * -1; + int aex = strtod(s[8]); + int aey = strtod(s[9]) * -1; + int radius = strtod(s[4])- centerx; + if (radius < 0) radius *= -1; // Radius darf nie negativ sein. + real startangle = imp_wire_angle(centerx, centery, strtod(s[6]), strtod(s[7])*-1.0); + real endangle = imp_wire_angle(centerx, centery, strtod(s[8]), strtod(s[9])*-1.0); + + /* P Polar-Koordinaten (relativ zur Marke, x = Radius, y = Winkel in Grad, gegen den Uhrzeigersinn) */ + sprintf(h, "LAYER 94;\nMARK (%.4f %.4f);\nARC CCW (P%.4f %.4f) (P%.4f %.4f) (P%.4f %.4f);\nMARK;\n", + imp_eagle_coordvalue(centerx), imp_eagle_coordvalue(centery), // setze Marke ins Zentrum des ARC + imp_eagle_coordvalue(radius), startangle, + imp_eagle_coordvalue(radius), startangle + 180.0, + imp_eagle_coordvalue(radius), endangle + ); + Imp_Cmd+=h; + return; +} + + +void imp_print_text(real thigh, char leading, string text, real tx, real ty) { // damit Eagle Directiven-Texte nicht überstreicht, + // muss das Einleitende ! mit einem Escapezeichen markiert werden. + string t[]; + int cnt; + + cnt = strsplit(t, text, '\''); // check Apostroph + /* + Text '''' == ' + Text '''''' == '' + Text '''''''' == ''' + Text '''ein Apostroph am Anfang' + Text 'ein Apostroph am Ende''' + Text 'ein Apostroph '' in der Mitte' + Text ''' vier '' Apostrophen '' verteilt''' + Text '''\\''' + */ + if (cnt > 1) { + text = ""; + for (int i = 0; i < cnt; i++) { + // da der ganze String in ' eingeschlossen wird, + // müssen die Apostrophen verdoppelt werden. + if (i == 0) { + if (t[i]) text += t[i]; + } + else if (i) text += "''" + t[i]; + } + } + if (leading) sprintf(h, "CHANGE SIZE %.0f;\nTEXT '%c%s' %s (%.4f %.4f);\n", thigh, leading, text, TextAlignRotation, tx, ty); + else sprintf(h, "CHANGE SIZE %.0f;\nTEXT '%s' %s (%.4f %.4f);\n", thigh, text, TextAlignRotation, tx, ty); + Imp_Cmd+=h; + return; +} + + +string imp_secondstr(string line, string w) { // return the rest of string after word + int pos = strstr(line, w) + strlen(w)+1; + return strsub(line, pos); +} + + +void imp_text(string l) { + string s[]; + int cnt = strsplit(s, l, ' '); + // berechne den wirklichen Anfang des "Textes" + // TEXT -16 512 Left 2 A A A A + int textbegin = strlen(s[0]) + strlen(s[1]) + strlen(s[2]) + strlen(s[3]) + strlen(s[4]) + 5; // 5 = 5 Spaces + string text = strsub(l, textbegin); + + TextAlignRotation = "R0"; + if (s[3] == "Center") { + sprintf(TextAlign, "change align Center;\n"); + } + else if(s[3] == "Left") { + sprintf(TextAlign, "change align Center Left;\n"); + } + else if(s[3] == "Right") { + sprintf(TextAlign, "change align Center Right;\n"); + } + else if(s[3] == "Top") { + sprintf(TextAlign, "change align Center Top;\n"); + } + else if(s[3] == "Bottom") { + sprintf(TextAlign, "change align Center Bottom;\n"); + } + else if(s[3] == "VLeft") { // 90gedreht + sprintf(TextAlign, "change align Center Left;\n"); + TextAlignRotation = "R90"; + } + else if(s[3] == "VRight") { // 90gedreht + sprintf(TextAlign, "change align Center Right;\n"); + TextAlignRotation = "R90"; + } + else if (s[3] == "VCenter") { // 90gedreht + sprintf(TextAlign, "change align Center;\n"); + TextAlignRotation = "R90"; + } + else if(s[3] == "VTop") { // 90gedreht + sprintf(TextAlign, "change align Center Top;\n"); + TextAlignRotation = "R90"; + } + else if(s[3] == "VBottom") { // 90! gedreht + sprintf(TextAlign, "change align Center Bottom;\n"); + TextAlignRotation = "R90"; + } + else { + dlgMessageBox("Unknown Text justification:" + s[3] + "\n" + Imp_SymDevName + "\n" + l, "ok", "esc"); + exit(-2485); + } + Imp_Cmd+=TextAlign; + real texthigh = LTTextSize; + real textoffsety = 0; + real textoffsetx = 0; + char leadingcharacter = 0; + + if (text[0] == ';') { + Imp_Cmd += "CHanGe Layer 94;\n"; + } + else if (text[0] == '!') { // check spice directive + Imp_Cmd += "CHanGE Layer 97;\n"; + leadingcharacter = '\\'; // Einleitendes Ausrufezeichen als Sonderzeichen definieren, da Eagle sonst den Text überstreicht. + } + + imp_print_text(texthigh, leadingcharacter, text, imp_eagle_coordvalue(strtod(s[1])), imp_eagle_coordvalue(strtod(s[2])*-1.0)); // in LT-Spice ist die Y-Achse auf den Kopf gestellt + return; +} + + +void imp_window_sym(string l, int line) { + string s[]; + int n = strsplit(s, l, ' '); + int winattrib = strtod(s[1]); + + string h = ""; + switch(winattrib) { + case 0 : Imp_Winattrib[0] = "0"; // InstName // WINDOW 0 273 -48 Bottom 2 + sprintf(h, "Change Layer 95;\nChange Size 70mil;\nTexT '>NAME' (%.4f %.4f);\n", imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0)); + Imp_Cmd += h; + break; + + case 1 : Imp_Winattrib[1] = "1"; // Type + sprintf(h, "Change Layer 97;\nChange Size 10mil;\nTexT 'win1' (%.4f %.4f);\n", imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0)); + Imp_Cmd += h; + break; + + case 2 : Imp_Winattrib[2] = "2"; + sprintf(h, "Change Layer 97;\nChange Size 10mil;\nTexT 'win2' (%.4f %.4f);\n", imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0)); + Imp_Cmd += h; + break; + + case 3 : Imp_Winattrib[3] = "3"; // Value // WINDOW 3 0 151 Center 0 + sprintf(h, "Change Layer 96;\nChange Size 70mil;\nTexT '>VALUE' (%.4f %.4f);\n", imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0)); + Imp_Cmd += h; + break; + + case 38 : Imp_Winattrib[38] = "38"; // SpiceModel // WINDOW 38 0 32 Center 0 + Imp_SpiceModelSymX = imp_eagle_coordvalue(strtod(s[2])); + Imp_SpiceModelSymY = imp_eagle_coordvalue(strtod(s[3])*-1.0); + Imp_SpiceModelSymAlign = s[4]; + Imp_SpiceModelSymOffset = imp_eagle_coordvalue(strtod(s[5])); + if (Imp_SpiceModelSymAlign != "Center") if (dlgMessageBox(l + "\error 2246", "OK", "CANCEL") != 0) exit(-2538); + break; + + case 39 : Imp_Winattrib[39] = "39"; // SpiceLine // WINDOW 39 273 154 Center 2 + Imp_SpiceLineSymX = imp_eagle_coordvalue(strtod(s[2])); + Imp_SpiceLineSymY = imp_eagle_coordvalue(strtod(s[3])*-1.0); + Imp_SpiceLineSymAlign = s[4]; + Imp_SpiceLineSymOffset = imp_eagle_coordvalue(strtod(s[5])); + break; + + case 40 : Imp_Winattrib[40] = "40"; // SpiceLine2 + Imp_SpiceLine2SymX = imp_eagle_coordvalue(strtod(s[2])); + Imp_SpiceLine2SymY = imp_eagle_coordvalue(strtod(s[3])*-1.0); + Imp_SpiceLine2SymAlign = s[4]; + Imp_SpiceLine2SymOffset = imp_eagle_coordvalue(strtod(s[5])); + break; + + case 123 : Imp_Winattrib[123] = "123"; // Value2 + sprintf(h, "Change Layer 96;\nChange Size 70mil;\nTexT '>VALUE2' (%.4f %.4f);\n", // Attribute Platzhalter + imp_eagle_coordvalue(strtod(s[2])), imp_eagle_coordvalue(strtod(s[3])*-1.0) + ); + Imp_Cmd += h; + break; + + default : sprintf(h, "File:%s\nUnknown window attribute \"%s\" in line :%d\n%s", Imp_SymDevName, s[1], line+1, l); + if (dlgMessageBox(h, "OK", "CANCEL") != 0) exit(-2563); + } + return; +} + +void attribute2script(string at, string symbolfile, string mode) { + output(filesetext(symbolfile, ".scr"), mode) { + printf("%s", at); + } + return; +} + +string imp_symattr_sym(string l, int cnt, string source) { + /***3 + Zu diesem Zeitpunk existiert noch kein Package, also kann man Attribute nur für das Packagelose + Device anlegen! + Das anlegen einer Package-Variante, löscht die Attribute, die keinem Package zugeordnet sind. + Die Attribute müssen in einem separaten SCRIPT eingetragen werden, daß dann zu gegebenen Zeitpunkt + nach dem erzeugen der Package-Variante gestartet wird. + ***3 ***/ + string s[]; + int n = strsplit(s, l, ' '); + string sy; + if (s[1] == "Prefix") { + Imp_Winattrib[0] = s[2]; + sprintf(sy, "ATTRIBUTE SPICEPREFIX '%s';\n", Imp_Winattrib[0]); // 2012-10-04 + attribute2script(sy, source, FileAppend); // im Device ablegen ***3 + return ""; + } + + else if (s[1] == "Value") { // Value [3] + Imp_Winattrib[3] = s[2]; + attribute2script("VALUE OFF;\n", source, FileAppend); // im Device ablegen ***3 + return ""; // im Device ablegen + } + + else if (s[1] == "SpiceModel") { // SpiceModel [38] + Imp_Winattrib[38] = s[2]; + sprintf(sy, "ATTRIBUTE 'SPICEMODEL' '%s';\n", Imp_Winattrib[38]); + attribute2script(sy, source, FileAppend); // im Device ablegen ***3 + return ""; + } + + else if (s[1] == "SpiceLine") { // SpiceLine Imp_Winattrib[39] + if (Imp_Winattrib[39]) { + sprintf(sy, "Change Layer %d;\nChange Size 70mil;\nCHanGE Align %s;\nTexT 'Spiceline>%s' (%.4f %.4f);\n", + LayerSpiceOrder, + Imp_SpiceLineSymAlign, + imp_secondstr(l, s[1]), // Spiceline : können mehrere Wörter durch Space getrennt sein + Imp_SpiceLineSymX, Imp_SpiceLineSymY + ); + Imp_Cmd += sy; // im Symbol ablegen + return ""; + } + else { + sprintf(sy, "ATTRIButE 'Spiceline' '%s';\n", // im Device als Attribute ablegen + imp_secondstr(l, s[1]) // Spiceline : können mehrere Wörter durch Space getrennt sein + ); + attribute2script(sy, source, FileAppend); // im Device ablegen ***3 + return ""; + } + } + + else if (s[1] == "SpiceLine2") { // SpiceLine2 Winattrib[40] + if (Imp_Winattrib[40]) { + sprintf(sy, "Change Layer %d;\nChange Size 70mil;\nTexT 'Spiceline2>%s' (%.4f %.4f);\n", // im Symbol ablegen + LayerSpiceOrder, imp_secondstr(l, s[1]), // Spiceline2 : können mehrere Wörter durch Space getrennt sein + Imp_SpiceLine2SymX, Imp_SpiceLine2SymY + ); + Imp_Cmd+= sy; + return ""; + } + else { + sprintf(sy, "ATTRIButE 'Spiceline2' '%s';\n", // im Device als Attribute ablegen + imp_secondstr(l, s[1]) // Spiceline2 : können mehrere Wörter durch Space getrennt sein + ); + attribute2script(sy, source, FileAppend); // im Device ablegen ***3 + return ""; + } + } + + else if (s[1] == "Value2") { // Value2 [123] + Imp_Winattrib[123] = imp_secondstr(l, s[1]); + sprintf(sy, "ATTRIBUTE 'VALUE2' '%s'; #2658\n", Imp_Winattrib[123]); + attribute2script(sy, source, FileAppend); // im Device ablegen ***3 + return ""; + } + + else if (s[1] == "Description") { + string descript; + sprintf(descript, "DESCRIPTION '%s'\n", imp_secondstr(l, s[1])); + return descript; // im Device ablegen + } + + else if (s[1] == "ModelFile") { + Imp_Winattrib[123] = s[2]; + sprintf(sy, "ATTRIBUTE 'ModelFile' '%s'; #2671\n", Imp_Winattrib[123]); + attribute2script(sy, source, FileAppend); // im Device ablegen ***3 + return ""; + } + else if (s[1] == "DefSubstrate") { + sprintf(sy, "ATTRIBUTE 'DefSubstrate' '%s'; #2676\n", s[2]); + attribute2script(sy, source, FileAppend); // im Device ablegen ***3 + return ""; + } + + sprintf(h, "%s:\nUnknown SYMATTR in line %d:\n%s", source, cnt+1, l); + if (dlgMessageBox(h, "OK", "ESC") != 0) exit(-2670); + return ""; +} + + +string imp_pin(string l) { + string s[]; + int n = strsplit(s, l, ' '); + string coord; + + if (s[3] == "NONE") { // bedeutet der PIN hat keinen sichbaren Namen + sprintf(coord, "%.4f %.4f\t%.4f %.4f\t%s", + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[1]) + strtod(s[4])), // plus offset + imp_eagle_coordvalue(strtod(s[2])*-1.0), + s[3] + ); + } + else if (s[3] == "LEFT") { // bedeutet der PIN steht an der linken Seite und der Name des Pin verschieb sich nach rechts + sprintf(coord, " %.4f %.4f\t%.4f %.4f\t%s", + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[1]) + strtod(s[4])), // plus offset + imp_eagle_coordvalue(strtod(s[2])*-1.0), + s[3] + ); + } + else if (s[3] == "RIGHT") {// bedeutet der PIN steh an der rechten Seite und der Name des Pin verschieb sich nach links + sprintf(coord, "%.4f %.4f\t%.4f %.4f\t%s", + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[1]) - strtod(s[4])), // minus offset + imp_eagle_coordvalue(strtod(s[2])*-1.0), + s[3] + ); + } + else if (s[3] == "TOP") { // bedeutet der PIN steht an der oberen Seite und der Name des Pin verschieb sich nach unten + sprintf(coord, "%.4f %.4f\t%.4f %.4f)\t%s", + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue((strtod(s[2]) + strtod(s[4]))*-1.0), // plus offset + s[3] + ); + } + else if (s[3] == "BOTTOM") { // bedeutet der PIN steht an der unteren Seite und der Name des Pin verschieb sich nach oben + sprintf(coord, "%.4f %.4f\t%.4f %.4f\t%s", + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue((strtod(s[2]) - strtod(s[4]))*-1.0), // minus offset + s[3] + ); + } + else { + string e; + sprintf(e, "Unknown '%s' in %s\nerror 2436", s[3], l); + dlgMessageBox(e, "OK"); + } + return coord; +} + + +void imp_pinattr(string l, string coordpin, string coordname, string orientation) { + string s[]; + int cnt = strsplit(s, l, ' '); + + string k[]; + int cntk = strsplit(k, coordname, ' '); + real kx = strtod(k[0]); + real ky = strtod(k[1]); + + if (s[1] == "PinName") { + if (cnt > 3) { // Mehr als 3 Teilstrings bedeutet der Pin-Name besteht aus mehreren Teilstrings (Leerzeichen getrennt). + for (int n = 3; n < cnt; n++) { // LTspice läßt im Namen SPACE (Leerzeichen) zu, in Eagle sind SPACE verboten! + s[2] += "_" + s[n]; + } + } + Imp_SymPinName = strupr(s[2]); // Pinnamen in Eagle nur in upper case + // Pin name of pin to use with CONNECT + // PINATTR PinName _RST der Unterstrich bedeutet das Negierungszeichen, in Eagle das ! + if (Imp_SymPinName[0] == '_') Imp_SymPinName[0] = '!'; // ! das Negierungszeichen in EAGLE + + Imp_SymPinName = imp_checkpinname(Imp_SymPinName); // doppelte Pin-Namen dürfen nicht vorkommen. + if (!orientation) { + Imp_Cmd += "CHANGE VISIBLE Off;\n"; // visible Off + sprintf(h, "PIN '%s' PAS NONE POINT (%s);\n", Imp_SymPinName, coordpin); + Imp_Cmd+=h; + } + else if (orientation == "NONE") { + Imp_Cmd += "CHANGE VISIBLE Off;\n"; // visible Off + sprintf(h, "PIN '%s' PAS NONE POINT (%s);\n", Imp_SymPinName, coordpin); + Imp_Cmd+=h; + } + else if (orientation == "LEFT") { + Imp_Cmd += "CHANGE VISIBLE Pin;\n"; // Visible Pin + sprintf(h, "PIN '%s' PAS NONE POINT R0 (%s);\n", Imp_SymPinName, coordpin); + Imp_Cmd+=h; + } + else if (orientation == "RIGHT") { + Imp_Cmd += "CHANGE VISIBLE Pin;\n"; // Visible Pin + sprintf(h, "PIN '%s' PAS NONE POINT R180 (%s);\n", Imp_SymPinName, coordpin); + Imp_Cmd+=h; + } + else if (orientation == "TOP") { + Imp_Cmd += "CHANGE VISIBLE Off;\n"; // Visible Off, der Pinnmaem wir waagerecht als Text erzeugt + sprintf(h, "PIN '%s' PAS NONE POINT R270 (%s);\n", Imp_SymPinName, coordpin); + Imp_Cmd+=h; + sprintf(h, "Change Layer 95;\nChange Align Top Center;\nCHANGE SIZE 60;\nTEXT '%s' R0 (%.4f %.4f);\n", Imp_SymPinName, kx, ky); // 50 ist der Eagle-Offset zum Pinnamen + Imp_Cmd+=h; + } + else if (orientation == "BOTTOM") { + Imp_Cmd += "CHANGE VISIBLE Off;\n"; // Visible Off, der Pinnmaem wir waagerecht als Text erzeugt + sprintf(h, "PIN '%s' PAS NONE POINT R90 (%s);\n", Imp_SymPinName, coordpin); + Imp_Cmd+=h; + sprintf(h, "CHange Layer 95;\nChAnge Align Bottom Center;\nCHANGE SIZE 60;\nTEXT '%s' R0 (%.4f %.4f);\n", Imp_SymPinName, kx , ky); // 50 ist der Eagle-Offset zum Pinnamen + Imp_Cmd+=h; + } + else { + if (dlgMessageBox("Unknown orientation: " + orientation + "\nin line:" + l,"OK", "CANCEL") != 0) exit(-2790); + } + } + + else if (s[1] == "SpiceOrder") { + if (coordname) { + sprintf(h, "CHANGE Size 16;\nChange Layer %d;\n", LayerSpiceOrder); + Imp_Cmd+=h; + sprintf(h, "CHANGE Align Center; # SpiceOrder\n"); + Imp_Cmd+=h; + sprintf(h, "TEXt '%s %s' (%s);\n", s[1], s[2], coordpin); // SpiceOrder number 2012-06-11 + Imp_Cmd+=h; + } + } + return; +} + + +void imp_dataflag(string l) { // 2012-06-14 + string s[]; + int cnt = strsplit(s, l, ' '); + string datflag; + sprintf(datflag, "TEXT 'DATAFLAG:%s' (%.6f %.6f);\n", + s[3], + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt + ); + Imp_Cmd+=datflag; + return; +} + + +int imp_checkexist_sym(string name) { + if (library) { + library(L) { + L.symbols(S) { + if (S.name == name) return 1; + } + } + } + return 0; +} + +int imp_checkexist_dev(string name) { + if (library) { + library(L) { + L.devicesets(DEV) { + if (DEV.name == name) return 1; + } + } + } + return 0; +} + +int imp_checkexist_sch(string name) { + string f[]; + int cnt = fileglob(f, name); + if (cnt) { dlgMessageBox("Schematic exist:\n" + name, "CANCEL"); exit(-2847); } + return 0; +} + + +/************************************************** + parse schematic lines +***************************************************/ +void imp_sheet(string l) { + string s[]; + int cnt = strsplit(s, l, ' '); + s[2] = strupr(s[2]); + sprintf(h, "EDIT .s%s;\nSET WIRE_BEND 0;\nCHANGE STYLE Continuous;\n;", s[1]); + Imp_Cmd+=h; + if (Test) { // nur im Testfall wird der Zeichnungsrahmen übernommen. + sprintf(h, "CHangE LAYER 94;\nWIRE 10 (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n# frame\n", + 0.0, 0.0, + imp_eagle_coordvalue(strtod(s[2])), + imp_eagle_coordvalue(strtod(s[3])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + 0.0, 0.0 + ); + Imp_Cmd+=h; + } + return; +} + + +void imp_wire(string l) { + status("WIRE"); // ein Lebenszeichen + if (!Imp_SetWireStyle) { + Imp_Cmd += "CHANGE STYLE Continuous;\n"; + Imp_SetWireStyle++; + } + string s[]; + int cnt = strsplit(s, l, ' '); + imp_add_wire(strtod(s[1]), strtod(s[2]), strtod(s[3]), strtod(s[4])); + return; +} + + +void imp_flag(string l) { // NET-Name des Segment, zugleich Supply-Symbol und LABEL + // Die FLAGs 0 und COM werden besonders behandelt, + // hier zeichnet LT-Spice ein Dreieck (Supply) das nach unten zeigt. + // Bei COM (Common/Masse) zeichnet LT-spice eine Pfeilspitze nach unten. + // Alle weiteren FLAGs sind NETz-Namen / LABEL + status("FLAG"); // ein Lebenszeichen + string s[]; + int cnt = strsplit(s, l, ' '); + CmdNameLabel+=RememberFlag; + RememberFlag = ""; + + string coordidirection; + sprintf(coordidirection, "%d %d", strtol(s[1]), strtol(s[2]) ); + int flagr = imp_getflagrotate(coordidirection, l); // Supply-Symbole sind in der Nulllage vertical ausgerichtet. + if (!flagr) { // kein NET-Segment mit der gleichen Koordinate gefunden, + // dann platziere ein Supply-Symbol + if (s[3] == "+V") Imp_FlagRotate = 0; // + Symbole nach oben 90 + else if (s[3] == "-V") Imp_FlagRotate = 180; // - Symbole nach unten 270 + string ltsupplylbr = imp_check_use("lt-supply"); + sprintf(h, "Add '%s%s' R%.0f (%.4f %.4f);\n", + s[3], ltsupplylbr, + Imp_FlagRotate, + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0) + ); + Imp_Cmd+=h; + return; + } + + sprintf(h, "Ein FLAG an Netz %s\n(%.4f %.4f)\nRotation : %.1f ", + s[3], + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0), + Imp_FlagRotate); +//if (dlgMessageBox(h, "ok", "esc") != 0) exit(-2921); + + if (s[3] == "0") { + string ltsupplylbr = imp_check_use("lt-supply"); + sprintf(h, "aDd '%s%s' R%.0f (%.4f %.4f);\n", + s[3], ltsupplylbr, + Imp_FlagRotate, + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0) + ); + Imp_Cmd+=h; + } + else if (s[3] == "COM") { + string ltsupplylbr = imp_check_use("lt-supply"); + sprintf(h, "adD '%s%s' R%.0f (%.4f %.4f);\n", + s[3], ltsupplylbr, + Imp_FlagRotate, + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0) + ); + Imp_Cmd+=h; + } + // Eagle kann kein LABEL ohne NET setzen, + + else { + // Imp_FlagRotate wird in der Funktion imp_getflagrotate() behandelt! 2012-11-05 + // Da LTspice die Rotation der FLAGS anahand des letzen Wiresegement berstimmt, + // hier muss die Nullage des Symbol entsptrechend korrigiert werden. + // Typischerweise werden die Spannungen (Pfeile) bei plus nach oben und bei + // minus nach unten angelegt. Dazu muß es für jedes Symbole eine Nulagenkorrektur geben. + // OUT ist nach rechts zeigend angelegt. + if (s[3] == "+V") Imp_FlagRotate -= 180.0; + else if (s[3] == "-V") Imp_FlagRotate -= 180.0; + else if (s[3] == "OUT") Imp_FlagRotate -= 90.0; + string ltsupplylbr = imp_check_use("lt-supply"); // alle benötigten Supply-Symbole müssen in dieser LBR erstellt sein + sprintf(h, "Add '%s%s' R%.0f (%.4f %.4f);\n", + s[3], ltsupplylbr, + Imp_FlagRotate, + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0) + ); + Imp_Cmd+=h; + + /* 2012-11-05 + sprintf(h, "#2582\nSET CONFIRM YES;\nNAME '%s' (%.4f %.4f) ;\n# FLAG\nSET CONFIRM OFF;\n", + s[3], + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0) // in LT-Spice ist die Y-Achse auf den Kopf gestellt + ); + RememberFlag += h; + string xrefoption = "OFF"; + sprintf(h, "Change size 70;\nCHANGE XREF %s;\nLABEL R%.1f (%.4f %.4f) (%.4f %.4f);\n", + xrefoption, + Imp_FlagRotate - 90.0, // Label sind in der Nulllage horizontal nach rechts ausgerichtet + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0) + ); + RememberFlag += h; + */ + } + return; +} + + + +void imp_iopin(string l) { + /* + FLAG 1248 176 BI_Port + IOPIN 1248 176 BiDir + FLAG 1248 144 Input_Port + IOPIN 1248 144 In + FLAG 1248 112 Output_Port + IOPIN 1248 112 Out + */ string s[]; + int n = strsplit(s, l, ' '); + // der IOPIN kommt immer nach dem FLAG, also immer die gleiche Kordinate + sprintf(h, "CHANGE XREF ON;\nLABEL (%.4f %.4f) (%.4f %.4f);\n", + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0), // in LT-Spice ist die Y-Achse auf den Kopf gestellt + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0) + ); + CmdNameLabel += h; + RememberFlag = ""; + return; +} + + +string imp_checktextalign(string align) { + TextAlignRotation = "R0"; + string textalign = "Left"; // default + if (align == "Center") { + sprintf(textalign, " align Center"); + } + else if(align == "Left") { + sprintf(textalign, " align Center Left"); + } + else if(align == "Right") { + sprintf(textalign, " align Center Right"); + } + else if(align == "Top") { + sprintf(textalign, " align Center Top"); + } + else if(align == "Bottom") { + sprintf(textalign, " align Center Bottom"); + } + else if(align == "VLeft") { // 90gedreht + sprintf(textalign, " align Center Left"); + TextAlignRotation = "R90"; + } + else if(align == "VRight") { // 90gedreht + sprintf(textalign, " align Center Right"); + TextAlignRotation = "R90"; + } + else if (align == "VCenter") { // 90gedreht + sprintf(textalign, " align Center"); + TextAlignRotation = "R90"; + } + else if(align == "VTop") { // 90gedreht + sprintf(textalign, " align Center Top"); + TextAlignRotation = "R90"; + } + else if(align == "VBottom") { // 90! gedreht + sprintf(textalign, " align Center Bottom"); + TextAlignRotation = "R90"; + } + return textalign; +} + + +string imp_checkempty(string s) { + if (s == "\"\"") return ""; + return s; +} + + +void imp_symbol_sch(string l) { // place a symbol in schematic + /* ******* Ein Lastwiderstand zum simulieren ****** + SYMBOL res 864 128 R0 + SYMATTR InstName Rload1 *** Rload macht aus einem normalen Widerstand einen Lastwiderstand zum simulieren. + SYMATTR Value .5 + SYMBOL eagle\\PNP_LABOR\\BST62 160 176 R0 + ************************************************* */ + Imp_InstanceName = ""; // Reset Instance name + Imp_Cmd += "CHanGe Align Left Center;\n"; // default für Textanordnung von Name/Value + // es kann, aber es muss nicht ein + // WINDOW 0 .... oder WINDOW 3 ... folgen. + + Imp_CmdValueV = ""; // Reset Value + Imp_Winattrib[0] = ""; // Reset window attribute + Imp_Winattrib[1] = ""; + Imp_Winattrib[3] = ""; + Imp_Winattrib[38] = ""; + Imp_Winattrib[39] = ""; + Imp_Winattrib[40] = ""; + Imp_Winattrib[123] = ""; + string s[]; + int cnt = strsplit(s, l, ' '); + AddPart = s[1]; + status(AddPart); // ein Lebenszeichen + + Imp_InstCoordX = imp_eagle_coordvalue(strtod(s[2])); + Imp_InstCoordY = imp_eagle_coordvalue(strtod(s[3])*-1.0); // in LT-Spice ist die Y-Achse auf den Kopf gestellt + AddPartOrientation = s[4]; + string libpart[]; + cnt = strsplit(libpart, s[1], '\\'); // == "eagle\\PNP_LABOR\\BST62" + if (cnt > 1) { // Wenn ein doppelter Backslash vor kommt, dann ist der LBR-Name angegeben. + AddPart = libpart[cnt-1]; // Library-name ist mit backslash vom part-name getrennt, + AddPartLib = ""; // es können auch mehr als ein backslash vorkommen, + for (int n = 0; n < cnt-1; n++) { // dann ist der Partname der letzte Teilstring. + if (libpart[n]) AddPartLib = libpart[n]; // 2014-04-03 setze den Pfad auf den vorletzen Teilstring + } + } + else { // dann ist es vermutlich ein Simulations-Symbol + AddPart = libpart[cnt-1]; + AddPartLib = ""; + } + return; +} + + +void imp_window_sch(string l, int cnt) { + /* Attribute Window * + InstName 0 - + Type 1 - + SpiceModel 38 +SYMATTR + Value 3 - + Value2 123 - + SpiceLine 39 - + SpiceLine2 40 - + + Rotated symbols get windows for parameters relative to the + anchor point of the symbol + */ + string h = ""; + string s[]; + int n = strsplit(s, l, ' '); + int winattrib = strtod(s[1]); + + switch(winattrib) { + case 0 : Imp_Winattrib[0] = "0"; + Imp_InstNameSmashX = imp_eagle_coordvalue(strtod(s[2])); // InstName 0 - + Imp_InstNameSmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0); + TextAlignName = s[4]; + Imp_InstNameOffset = imp_eagle_coordvalue(strtod(s[5])); + break; + + case 1 : Imp_Winattrib[1] = "1"; // Type + dlgMessageBox("WINDOW 1 : Type found", "CANCEL"); + exit(-3129); + break; + + case 3 : Imp_Winattrib[3] = "3"; + Imp_InstValueSmashX = imp_eagle_coordvalue(strtod(s[2])); // Value 3 - + Imp_InstValueSmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0); + TextAlignValue = s[4]; + Imp_InstValueOffset = imp_eagle_coordvalue(strtod(s[5])); + break; + + case 38 : Imp_Winattrib[38] = "38"; + Imp_SpiceModelSmashX = imp_eagle_coordvalue(strtod(s[2])); // SpiceModel 38 +SYMATTR + Imp_SpiceModelSmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0); + break; + + case 39 : Imp_Winattrib[39] = "39"; // WINDOW 39 273 154 Center 2 + Imp_SpiceLineSmashX = imp_eagle_coordvalue(strtod(s[2])); // SpiceLine 39 - + Imp_SpiceLineSmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0); + TextAlignSpiceLine = s[4]; + Imp_SpiceLineSymOffset = imp_eagle_coordvalue(strtod(s[5])); + break; + + case 40 : Imp_Winattrib[40] = "40"; + Imp_SpiceLine2SmashX = imp_eagle_coordvalue(strtod(s[2])); // SpiceLine2 40 - + Imp_SpiceLine2SmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0); + TextAlignSpiceLine2 = s[4]; + Imp_SpiceLine2SymOffset = imp_eagle_coordvalue(strtod(s[5])); + break; + + case 123 : Imp_Winattrib[123] = "123"; // WINDOW 123 24 146 Left 0 + Imp_InstValue2SmashX = imp_eagle_coordvalue(strtod(s[2])); // Value2 123 - + Imp_InstValue2SmashY = imp_eagle_coordvalue(strtod(s[3])*-1.0); + TextAlignValue2 = s[4]; + Imp_InstValue2Offset = imp_eagle_coordvalue(strtod(s[5])); + break; + + default : dlgMessageBox("!Unknown window attribute:\n"+ l, "OK"); + } + + + // + if (s[5] != "0") { + sprintf(h, "# %s:\n\# %s in Line %d:%s\n", ImpSpiceSchematicAsc, s[5] , cnt+1, l ); + Imp_Cmd+=h; + } + return; +} + +string imp_getTextOrientation( string instancename, string textholder, string textalign, string addpartorientation, real instcoordX, real instcoordY, real insttextsmashX, real insttextsmashY ) { + string os; + + real nameposx, nameposy; + if (addpartorientation == "R0") { + nameposx = instcoordX + insttextsmashX; + nameposy = instcoordY + insttextsmashY; + } + else if (addpartorientation == "R90") { + nameposx = instcoordX + insttextsmashY; // wegen der 90Grad + nameposy = instcoordY - insttextsmashX; // muß der für den Offset X und Y getauscht werden + } + else if (addpartorientation == "R180") { + nameposx = instcoordX - insttextsmashX; + nameposy = instcoordY - insttextsmashY; + } + else if (addpartorientation == "R270") { + nameposx = instcoordX - insttextsmashY; // wegen der 270 Grad-Drehung muß der Offset X und Y getauscht werden + nameposy = instcoordY + insttextsmashX; + } + // mirrored + else if (addpartorientation == "M0") { + nameposx = instcoordX - insttextsmashX; + nameposy = instcoordY + insttextsmashY; + } + else if (addpartorientation == "M90") { + nameposx = instcoordX - insttextsmashY; // wegen der 90Grad + nameposy = instcoordY - insttextsmashX; // muß der für den Offset X und Y getauscht werden + } + else if (addpartorientation == "M180") { + nameposx = instcoordX + insttextsmashX; + nameposy = instcoordY - insttextsmashY; + } + else if (addpartorientation == "M270") { + nameposx = instcoordX + insttextsmashY; // wegen der 270 Grad + nameposy = instcoordY + insttextsmashX; // muß der für den Offset X und Y getauscht werden + } + sprintf(h, ";\nMOVe %s>%s (%.4f %.4f); #3229\n", + strupr(instancename), textholder, nameposx, nameposy + ); + os += h; + + string alignorientation; + // text align kann bisher nur mit Hilfe der Koordinaten erfolgen + if (textalign == "Center") { + sprintf(alignorientation, "Center"); + if (addpartorientation == "R0") { + sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Center\n + } + else if (addpartorientation == "R90") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Center\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Center\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Center\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Center\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Center\n + } + else if (addpartorientation == "M180") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Center\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Center\n + } + os += h; + } + + else if(textalign == "Left") { + sprintf(alignorientation, "Bottom Left"); // 2012-07-09 Center Left + if (addpartorientation == "R0") { + sprintf(h, "rOTATe =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Left\n + } + else if (addpartorientation == "R90") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Left\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Left\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Left\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Left\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =MR270 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Left\n + } + else if (addpartorientation == "M180") { + sprintf(h, "roTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Left\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Left\n + } + os += h; + } + + else if(textalign == "Right") { + sprintf(alignorientation, "Center Right"); + if (addpartorientation == "R0") { + sprintf(h, "RoTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Right\n + } + else if (addpartorientation == "R90") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Right\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Right\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Right\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Right\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =MR270 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Right\n + } + else if (addpartorientation == "M180") { + sprintf(h, "RotATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Right\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Right\n + } + os += h; + } + + else if(textalign == "Top") { + sprintf(alignorientation, "Center Top"); + if (addpartorientation == "R0") { + sprintf(h, "ROtATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Top\n + } + else if (addpartorientation == "R90") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Top\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Top\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Top\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROtaTE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Top\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Top\n + } + else if (addpartorientation == "M180") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Top\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Top\n + } + os += h; + } + + else if(textalign == "Bottom") { + sprintf(alignorientation, "Center Bottom"); + if (addpartorientation == "R0") { + sprintf(h, "ROTaTE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name Bottom\n + } + else if (addpartorientation == "R90") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name Bottom\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name Bottom\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name Bottom\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROTatE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name Bottom\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M90Name Bottom\n + } + else if (addpartorientation == "M180") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name Bottom\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name Bottom\n + } + os += h; + + } + + else if(textalign == "VLeft") { // 90gedreht + sprintf(alignorientation, "Center Left"); + if (addpartorientation == "R0") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VLeft\n + } + else if (addpartorientation == "R90") { + sprintf(h, "ROTAtE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VLeft\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VLeft\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VLeft\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VLeft\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VLeft\n + } + else if (addpartorientation == "M180") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VLeft\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTAte =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VLeft\n + } + os += h; + } + + else if(textalign == "VRight") { // 90gedreht + sprintf(alignorientation, "Center Right"); + if (addpartorientation == "R0") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VRight\n + } + else if (addpartorientation == "R90") { + sprintf(h, "rOtATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VRight\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VRight\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VRight\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROTATE =MR90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VRight\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VRight\n + } + else if (addpartorientation == "M180") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VRight\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTATE =MR180 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VRight\n + } + os += h; + } + + else if (textalign == "VCenter") { // 90gedreht + sprintf(alignorientation, "Center"); + if (addpartorientation == "R0") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VCenter\n + } + else if (addpartorientation == "R90") { + sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VCenter\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VCenter\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VCenter\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VCenter\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VCenter\n + } + else if (addpartorientation == "M180") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VCenter\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTATE =MR180 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VCenter\n + } + os += h; + } + + else if(textalign == "VTop") { // 90gedreht + sprintf(alignorientation, "Center Top"); + if (addpartorientation == "R0") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VTop\n + } + else if (addpartorientation == "R90") { + sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VTop\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VTop\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VTop\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROTATE =MR90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VTop\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VTop\n + } + else if (addpartorientation == "M180") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VTop\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTATE =MR180 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VTop\n + } + os += h; + } + else if(textalign == "VBottom") { // 90 gedreht + sprintf(alignorientation, "Center Bottom"); + if (addpartorientation == "R0") { + sprintf(h, "ROTATE =R90%s>%s ;\n", strupr(instancename), textholder) ; // # R0 Name VBottom\n + } + else if (addpartorientation == "R90") { + sprintf(h, "ROTATE =R0 %s>%s ;\n", strupr(instancename), textholder) ; // # R90Name VBottom\n + } + else if (addpartorientation == "R180") { + sprintf(h, "ROTATE =R270 %s>%s ;\n", strupr(instancename), textholder) ; // # R180 Name VBottom\n + } + else if (addpartorientation == "R270") { + sprintf(h, "ROTATE =R180 %s>%s ;\n", strupr(instancename), textholder) ; // # R270 Name VBottom\n + } + if (addpartorientation == "M0") { + sprintf(h, "ROTATE =MR90%s>%s ;\n", strupr(instancename), textholder) ; // # M0 Name VBottom\n + } + else if (addpartorientation == "M90") { + sprintf(h, "ROTATE =MR0 %s>%s ;\n", strupr(instancename), textholder) ; // # M90Name VBottom\n + } + else if (addpartorientation == "M180") { + sprintf(h, "ROTATE =MR270 %s>%s ;\n", strupr(instancename), textholder) ; // # M180 Name VBottom\n + } + else if (addpartorientation == "M270") { + sprintf(h, "ROTATE =MR180 %s>%s ;\n", strupr(instancename), textholder) ; // # M270 Name VBottom\n + } + os += h; + } + + sprintf(h, "Change Align %s (%.4f %.4f);\n", alignorientation, nameposx, nameposy) ; // # Name\n + os += h; + return os; +} + + +void imp_symattr_sch(string l, int cnt) { + /* Attribute Window * + InstName 0 - + Type 1 - + SpiceModel 38 +SYMATTR + Value 3 - + Value2 123 - + SpiceLine 39 - + SpiceLine2 40 - + + Rotated symbols get windows for parameters relative to the + anchor point of the symbol + */ + string s[]; + int sn = strsplit(s, l, ' '); + string addpartorient; + + if (s[1] == "InstName") { // Imp_Winattrib[0] + Imp_InstanceName = s[2]; + int rload = strstr(Imp_InstanceName, "Rload"); + if (!rload) { // hier nur ein Simulations-Symbol laden + AddPart += Imp_RloadExtention; // "_RLOAD"; + //AddPartLib = SpiceSimulationLbr; /**** ACHTUNG: die LBR darf nicht in der USE-Liste aufgeführt sein! ****/ + if (Test) if (dlgMessageBox("Ein Simulationswiderstand wird geladen.\n" + l + "\n" + Imp_InstanceName + ":" + SpiceSimulationLbr, "ok", "esc") != 0) exit(-3540); + } + else { + int Vsym = strstr(Imp_InstanceName, "V"); + /* Hier gibt es ein Missverständnis wegen dem Prefix V + eine BATTRY wird in LT SPice auch mit V bezeichnet! */ + // *** es wird nicht immer die LBR angegeben siehe LTC4000 *** if (!AddPartLib) AddPartLib = "sym"; // set library on USE-list + } + /* *** Im ADD-Menu muss das Flag SMD aktiv sein, sonst findet das Script die Devices nicht! *** */ + AddPartLib = imp_check_use(AddPartLib); + if(AddPartOrientation == "R0") addpartorient = "R0"; + else if(AddPartOrientation == "R90") addpartorient = "R270"; + else if(AddPartOrientation == "R180") addpartorient = "R180"; + else if(AddPartOrientation == "R270") addpartorient = "R90"; + else if(AddPartOrientation == "M0") addpartorient = "MR0"; + else if(AddPartOrientation == "M90" ) addpartorient = "MR270"; + else if(AddPartOrientation == "M180") addpartorient = "MR180"; + else if(AddPartOrientation == "M270" ) addpartorient = "MR90"; + + sprintf(h, "AdD '%s%s' '%s' %s (%.4f %.4f) ;\n", // wegen der Package-Varianten ist es evtl. besser wenn man mit Joker * sucht?! + AddPart, AddPartLib, // Leider nein, da es CAP & CAP[METER], RES & RES[2], IND & IND[2] und + strupr(Imp_InstanceName), // sontige gleichlautende Symbole gibt! + addpartorient, + Imp_InstCoordX, + Imp_InstCoordY + ); + Imp_Cmd += h; + + sprintf(h, "SMASH %s;\n", strupr(Imp_InstanceName)); // Smash kann jetzt schon mit >Name erfolgen. + Imp_Cmd += h; + if (Imp_CmdPartValue) { + sprintf(h, "VALUE '%s' '%s'; #3586\n", strupr(Imp_InstanceName), Imp_CmdPartValue); + Imp_Cmd += h; + Imp_CmdPartValue = ""; // wieder leeren, damit der Value nicht mehrfach zugewiesen wird. + } + + if (Imp_Winattrib[0]) { // WINDOW 0 == InstName + Imp_Cmd += imp_getTextOrientation( Imp_InstanceName, "NAME", TextAlignName, AddPartOrientation, Imp_InstCoordX, Imp_InstCoordY, Imp_InstNameSmashX, Imp_InstNameSmashY); + + /**** LTSpice weist den InstancNamen mal vor, mal nach dem Value zu! ****/ + if (Imp_CmdPartValue) { + sprintf(h, "VALUE '%s' '%s'; #3596\n", strupr(Imp_InstanceName), Imp_CmdPartValue); + Imp_Cmd += h; + Imp_CmdPartValue = ""; + } + if (Imp_CmdValueV) { // Dadurch ergeben sich Probleme bei der Scriptausführung was + // die Zuweisung der Attribute (wie VALUE) betrifft. + // Trenne die Kommandos bei dem Zeichen '>' und füge die entsprechenden + // Instance-namen ein. ***###*** + string vs[]; + int vn = strsplit(vs, Imp_CmdValueV, '>'); + Imp_CmdValueV = vs[0] + strupr(Imp_InstanceName) +">" + vs[1]; // Füge für das '>' den InstanceName ein! + int n = 2; + while (vs[n]) { + Imp_CmdValueV += strupr(Imp_InstanceName) + ">" + vs[n]; // Füge für das '>' den InstanceName plus '>' ein! + n++; + } + Imp_Cmd += Imp_CmdValueV; // In LTspice kann das Attribute Value vor der Zuweisung des Namen kommen, + // dann gibt es diverse Probleme bei der Zuordnung der Attribute über Koordinaten! + // Deshalb erst den Namen zuweisen, dann alle anderen Attribute! + Imp_CmdValueV = ""; // Reset Value-Attribute + } + + string v[]; + if (Imp_CmdValue2) { // [123] LTspice weist auch ein Attribute zu, bevor der Instancename bekannt ist! + strsplit(v, Imp_CmdValue2, '>'); + string displayonoff = "OFF"; + if (Imp_Winattrib[123]) displayonoff = "Value"; // 2012-12-17 + sprintf(h, "ChAngE Display %s;\nATTRIBUTE '%s' %s%s>%s%s>%s\n", displayonoff, strupr(Imp_InstanceName), v[0], strupr(Imp_InstanceName), v[1], strupr(Imp_InstanceName), v[2]); // füge den jetzt bekannten Instanc Name ein + Imp_Cmd += h; + Imp_CmdValue2 = ""; // für das nächste Symbol/Instance wieder leeren! + } + + if (Imp_MemSpiceline) { // [39] 2012-12-17 + strsplit(v, Imp_MemSpiceline, '>'); + string displayonoff = "OFF"; + if (Imp_Winattrib[38]) displayonoff = "Value"; + sprintf(h, "ChAngE Display %s;\nATTRIBUTE %s SPICELINE '%s';\nMOvE %s>SPICELINE %s;\nCHange Align %s %s;\n", // 2012-12-17 Display off + displayonoff, + strupr(Imp_InstanceName), + v[0], + strupr(Imp_InstanceName), + v[1], + v[2], + v[1] + ); // füge den jetzt bekannten Instance Namen ein + Imp_Cmd += h; + Imp_Cmd += "ChAngE Display Off; #3642\n"; // 2012-10-11 + Imp_MemSpiceline = ""; + } + if (Imp_MemSpiceline2) { + strsplit(v, Imp_MemSpiceline2, '>'); + sprintf(h, "ChaNgE Display Value;\nATTRIBUTE %s SPICELINE2 '%s';\nMOVE %s>SPICELINE2 %s;\nCHange Align %s %s;\n", + strupr(Imp_InstanceName), + v[0], + strupr(Imp_InstanceName), + v[1], + v[2], + v[1] + ); // füge den jetzt bekannten Instance Namen ein + Imp_Cmd += h; + Imp_Cmd += "ChAngE Display Off; #3656\n"; // 2012-10-11 + Imp_MemSpiceline2 = ""; + } + return; + } + } + + // SYMATTR Value 100% + else if (s[1] == "Value") { + if (Imp_InstanceName) { // LTSpice weist den Instance-Namen mal vor mal nach dem Value zu! + sprintf(h, "VALUE '%s' '%s';\n", strupr(Imp_InstanceName), imp_checkempty(imp_secondstr(l, s[1]))); + Imp_Cmd += h; + } + else { + sprintf(Imp_CmdPartValue, "%s", imp_secondstr(l, s[1])); + } + if (Imp_Winattrib[3]) { // WINDOW 3 == Value + Imp_CmdValueV += imp_getTextOrientation( Imp_InstanceName, "VALUE", TextAlignValue, AddPartOrientation, Imp_InstCoordX, Imp_InstCoordY, Imp_InstValueSmashX, Imp_InstValueSmashY); + if (Imp_InstanceName) { + Imp_Cmd += Imp_CmdValueV; + Imp_CmdValueV = ""; + } + } + return; + } + + // SYMATTR Value2 X2 + else if (s[1] == "Value2") { // [123] 2012-12-17 + string displayonoff = "OFF"; + if (Imp_Winattrib[123]) displayonoff = "Value"; + if (Imp_InstanceName) { + sprintf(h, "Change Display %s;\nATTRIBUTE '%s' 'VALUE2' '%s';\n#3557\n", displayonoff, strupr(Imp_InstanceName), imp_secondstr(l, s[1])); + Imp_Cmd += h; + } + else { + // da noch kein InstanceName definiert ist, das Attribute zwischenmerken! + sprintf(Imp_CmdValue2, " 'VALUE2' '%s';\n#3562\n", imp_secondstr(l, s[1])); + } + + Imp_CmdValue2 += imp_getTextOrientation( Imp_InstanceName, strupr(s[1]), TextAlignValue2, AddPartOrientation, Imp_InstCoordX, Imp_InstCoordY, Imp_InstValue2SmashX, Imp_InstValue2SmashY); + /********************************************/ + if (Imp_InstanceName) { + Imp_Cmd += Imp_CmdValue2; // Ist der Name noch nicht zugewiesen, dann erfolgt die Zuweisung des Value + Imp_CmdValue2 = ""; // mit dem Namen. Die Befehlssequenz wird entsprechend nachbearbeitet. ****** + } + return; + } + + else if(s[1] == "SpiceLine") { // [39] + if (Imp_Winattrib[39]) { // wenn es eine Koordinate für das Attribute gibt, dann anzeigen, sonst nur ein Attribute definieren + real spicelineposx, spicelineposy; + if (AddPartOrientation == "R0") { + spicelineposx = Imp_InstCoordX + Imp_SpiceLineSmashX; + spicelineposy = Imp_InstCoordY + Imp_SpiceLineSmashY; + } + else if (AddPartOrientation == "R90") { + spicelineposx = Imp_InstCoordX + Imp_SpiceLineSmashY; // wegen der der 90Drehung muß X und Y getauscht werden + spicelineposy = Imp_InstCoordY - Imp_SpiceLineSmashX; + } + else if (AddPartOrientation == "R180") { + spicelineposx = Imp_InstCoordX - Imp_SpiceLineSmashX; + spicelineposy = Imp_InstCoordY - Imp_SpiceLineSmashY; + } + else if (AddPartOrientation == "R270") { // Verkehrtes Vorzeichen der Y-Achse + spicelineposx = Imp_InstCoordX - Imp_SpiceLineSmashY; // wegen der 270 Grad-Drehung muß der Offset X und Y getauscht werden + spicelineposy = Imp_InstCoordY + Imp_SpiceLineSmashX; + } + else if (AddPartOrientation == "M0") { + spicelineposx = Imp_InstCoordX - Imp_SpiceLineSmashX; + spicelineposy = Imp_InstCoordY + Imp_SpiceLineSmashY; + } + else if (AddPartOrientation == "M90") { + spicelineposx = Imp_InstCoordX - Imp_SpiceLineSmashY; + spicelineposy = Imp_InstCoordY - Imp_SpiceLineSmashX; + } + else if (AddPartOrientation == "M180") { + spicelineposx = Imp_InstCoordX + Imp_SpiceLineSmashX; + spicelineposy = Imp_InstCoordY - Imp_SpiceLineSmashY; + } + else if (AddPartOrientation == "M270") { + spicelineposx = Imp_InstCoordX + Imp_SpiceLineSmashY; + spicelineposy = Imp_InstCoordY + Imp_SpiceLineSmashX; + } + + // den Wert des Attribute mit Textplatzhalter anzeigen + sprintf(Imp_MemSpiceline, "%s> (%.4f %.4f)>%s", + imp_secondstr(l, s[1]), // der Value für Spiceline kannen mehrere Wörter durch Space getrennt enthalten + spicelineposx, spicelineposy, + TextAlignSpiceLine + ); + } + else { + sprintf(h, "ATTRIBUTE %s %s '%s';\n", strupr(Imp_InstanceName), s[1], imp_secondstr(l, s[1])); + Imp_Cmd += h; + } + return; + } + + else if(s[1] == "SpiceLine2") { // [40] + if (Imp_Winattrib[40]) { // wenn es eine Koordinate für das Atrribute gibt, dann anzeigen, sonst nur ein Attribute definieren + real spiceline2posx, spiceline2posy; + if (AddPartOrientation == "R0") { + spiceline2posx = Imp_InstCoordX + Imp_SpiceLine2SmashX; + spiceline2posy = Imp_InstCoordY + Imp_SpiceLine2SmashY; + } + else if (AddPartOrientation == "R90") { + spiceline2posx = Imp_InstCoordX + Imp_SpiceLine2SmashY; // wegen der der 90Drehung muß X und Y getauscht werden + spiceline2posy = Imp_InstCoordY - Imp_SpiceLine2SmashX; + } + else if (AddPartOrientation == "R180") { + spiceline2posx = Imp_InstCoordX - Imp_SpiceLine2SmashX; + spiceline2posy = Imp_InstCoordY - Imp_SpiceLine2SmashY; + } + else if (AddPartOrientation == "R270") { // Verkehrtes Vorzeichen der Y-Achse + spiceline2posx = Imp_InstCoordX - Imp_SpiceLine2SmashY; // wegen der 270 Grad-Drehung muß der Offset X und Y getauscht werden + spiceline2posy = Imp_InstCoordY + Imp_SpiceLine2SmashX; + } + else if (AddPartOrientation == "M0") { + spiceline2posx = Imp_InstCoordX - Imp_SpiceLine2SmashX; + spiceline2posy = Imp_InstCoordY + Imp_SpiceLine2SmashY; + } + else if (AddPartOrientation == "M90") { + spiceline2posx = Imp_InstCoordX - Imp_SpiceLine2SmashY; + spiceline2posy = Imp_InstCoordY - Imp_SpiceLine2SmashX; + } + else if (AddPartOrientation == "M180") { + spiceline2posx = Imp_InstCoordX + Imp_SpiceLine2SmashX; + spiceline2posy = Imp_InstCoordY - Imp_SpiceLine2SmashY; + } + else if (AddPartOrientation == "M270") { + spiceline2posx = Imp_InstCoordX + Imp_SpiceLine2SmashY; + spiceline2posy = Imp_InstCoordY + Imp_SpiceLine2SmashX; + } + + // den Wert des Attribute mit Textplatzhalter anzeigen + sprintf(Imp_MemSpiceline2, "%s> (%.4f %.4f)>%s", + imp_secondstr(l, s[1]), // Der Value von Spiceline kann mehrere Wörter durch Space getrennt enthalten + spiceline2posx, spiceline2posy, + TextAlignSpiceLine2 + ); + } + else { + sprintf(h, "CHANGE Display Off;\nATTRIBUTE %s %s '%s';\n", strupr(Imp_InstanceName), s[1], imp_secondstr(l, s[1])); + Imp_Cmd += h; + } + return; + } + + // SYMATTR Description Capacitor + else if(s[1] == "Description") { // kein WINDOW für SYMATTR Description - deshalb die Description im Schaltplan als Attribute anlegen + if (!Imp_InstanceName) { + sprintf(h, "CHANGE Display OFF;\nATTRIBUTE (%.4f %.4f) 'SPICE_DESCRIPTION' '%s';\n", Imp_InstCoordX, Imp_InstCoordY, s[2]); // 2012-12-17 + } + else sprintf(h, "CHANGE Display OFF;\nATTRIBUTE '%s' 'SPICE_DESCRIPTION' '%s';\n", strupr(Imp_InstanceName), s[2]); + Imp_Cmd += h; + return; + } + + // SYMATTR Type cap + else if(s[1] == "Type") { + if (!Imp_InstanceName) { + sprintf(h, "ATTRIBUTE (%.4f %.4f) 'SpiceType' '%s';\n", Imp_InstCoordX, Imp_InstCoordY, s[2]); + } + else sprintf(h, "ATTRIBUTE '%s' 'SpiceType' '%s';\n", strupr(Imp_InstanceName), s[2]); + Imp_Cmd += h; + return; + } + return; +} + + +void imp_bustap(string l) { + if (!Imp_WireChecked) { + imp_get_net_segment(); // nachdem alle Wire gesammelt wurden, müssen die Segmente ermittelt werden + } + // BUSTAP 864 208 880 208 + string s[]; + int n = strsplit(s, l, ' '); + + imp_check_bus(strtod(s[1]), strtod(s[2])); // Die erste Koordinate ist der Anschluss an den BUS, + // die zweite Koordinate an das Netz. + + sprintf(h, "NET (%.4f %.4f)(%.4f %.4f);\n", // zeichne das fehlende NET-Stück. + imp_eagle_coordvalue(strtod(s[1])), + imp_eagle_coordvalue(strtod(s[2])*-1.0), + imp_eagle_coordvalue(strtod(s[3])), + imp_eagle_coordvalue(strtod(s[4])*-1.0) + ); + Imp_Cmd += h; + return; +} + + +void call_system(string exportfile) { // DOS comand execute + string syscommand; + // Das executable und der Dateiname müssen in " " eingeschlossen werden, wegen Spaces im Pfad-Dateinamen! + sprintf(syscommand, "\"%s\" \"%s\"", lash2backslash(LTSpiceExecute), lash2backslash(exportfile)); + system(syscommand); // externes Programm starten + return; +} + + +/****** IMPORT SETUP MENU ******/ +void imp_setupmenu(void) { + int editspicesym = 0; + int editspicesch = 0; + int fImport_All_Symbols = strtol(Import_All_Symbols); + int fExternalSymbol = strtol(ExternalSymbol); + + dlgDialog("LT-Spice import") { + dlgHBoxLayout dlgSpacing(600); + + if (library) { /*** SYMBOL ***/ + //library(L) NewLbrName = L.name; + if (!SpiceSymbol) { + SpiceSymbol = LTSpiceLibDir + "*.asy"; + } + FileSpiceSym[0] = SpiceSymbol; + + dlgGridLayout { + dlgCell( 1, 1) dlgLabel("Directory of Eagle connect scrips"); + dlgCell( 1, 2) dlgStringEdit(Imp_ConnectScriptDir); + + dlgCell( 2, 1) dlgLabel("LTspice symbol:"); + dlgCell( 2, 2) dlgStringEdit(SpiceSymbol); + dlgCell( 2, 3) dlgPushButton("&Browse") { + string mFileSpiceSym = backslash2lash(dlgFileOpen("Select a LTspice symbol", SpiceSymbol, "*.asy")); + if (mFileSpiceSym) { + EagleSpiceLbrDir = filedir(mFileSpiceSym); + SpiceSymbol = mFileSpiceSym; + FileSpiceSym[0] = mFileSpiceSym; + CntFileSpiceSym = 1; + editspicesym = 1; + string f[]; + int cntf = strsplit(f, FileSpiceSym[0], '/'); + if (cntf > 2) LbrName = f[cntf-2] + ".lbr"; // Bibliotheksname = Verzeichnisname + else LbrName = filesetext(FileSpiceSym[0], ".lbr"); + if (Import_All_Symbols) NewLbrName = filedir(NewLbrName) + imp_dirname(SpiceSymbol) + ".lbr"; + else NewLbrName = ""; // filedir(NewLbrName) + filesetext(filename(SpiceSymbol), ".lbr"); + } + } + + dlgCell( 3, 1) ; + dlgCell( 3, 2) dlgCheckBox("Import &all symbols from directory", fImport_All_Symbols) { + if (fImport_All_Symbols) { + NewLbrName = filedir(NewLbrName) + imp_dirname(SpiceSymbol) + ".lbr"; + Import_All_Symbols = "1"; + } + else { + NewLbrName = ""; // filedir(NewLbrName) + filesetext(filename(SpiceSymbol), ".lbr"); + Import_All_Symbols = ""; + } + } + dlgCell( 3, 3) ; + + dlgCell( 4, 1) ; + dlgCell( 4, 2) dlgCheckBox("Import as simulation &part ( generate ATTRIBUTE _EXTERNAL_ )", fExternalSymbol) imp_helpSimulationSymbols(); + dlgCell( 4, 3) ; + + dlgCell( 7, 1) dlgLabel("&New EAGLE library name "); + dlgCell( 7, 2) dlgStringEdit(NewLbrName); + dlgCell( 7, 3) dlgPushButton("Br&owse") { + string mNewLbrName = backslash2lash(dlgFileSave("Select a Spice symbol", NewLbrName, "*.lbr")); + if (mNewLbrName) NewLbrName = mNewLbrName; + }; + dlgCell( 8, 2) dlgLabel("(let this line empty to import symbol at current lbr.
    )"); + } + } + + else if (schematic) { /*** SHEMATIC ***/ + string schname; + schematic(SCH) schname = SCH.name; + dlgGridLayout { + dlgCell( 0, 1) dlgLabel(" "); + dlgCell( 0, 2) dlgSpacing(300); + dlgCell( 0, 3) dlgLabel(" "); + + /********************************************************************************* + Für LT-Spice gibt es Standard-Symbole (default) die nicht als Datei angelegt sind, + für diese Symbole muß es in Eagle eine entsprechende Bibliothek geben, die exakt + dem Aussehen in LT-Spice entsprechen. + Hier wird der Pfad und Dateiname dieser Bibliothek eingetragen. + **********************************************************************************/ + dlgCell( 1 , 1 ) dlgLabel("Spice default symbols"); + dlgCell( 1 , 2 ) dlgLabel(SpiceDefaultSymLbr, 1); // = lt-spice-simulation.lbr + //dlgCell( 1 , 3 ) dlgPushButton("B&rowse") { + // string mSpiceDefaultSymLbr = backslash2lash(dlgFileOpen("Select a spice default symbol library", SpiceDefaultSymLbr)); + // if (mSpiceDefaultSymLbr) SpiceDefaultSymLbr = mSpiceDefaultSymLbr; + //} + + // Die Symbol-LBR für Generatorn, Messgeräte, Lastwiderstände etc. + /***************************************************************************** + Symbole die für die Simulation von Bedeutung sind, müssen in einer Bibliothek + angelegt werden, und mit dem ATTRIBUTE "_EXTERNAL_" versehen sein. + Hier wird der Pfad und Dateiname dieser Bibliothek eingetragen. + ******************************************************************************/ + dlgCell( 2 , 1 ) dlgLabel("Spice simulation library"); + dlgCell( 2 , 2 ) dlgLabel(SpiceSimulationLbr, 1); + //dlgCell( 2 , 3 ) dlgPushButton("&Browse") { + // string mSpiceSimulationLbr = backslash2lash(dlgFileOpen("Select Simuation-Symbol-LBR", SpiceSimulationLbr , "*.lbr")); + // if (mSpiceSimulationLbr) { + // SpiceSimulationLbr = mSpiceSimulationLbr; + // } + //} + + dlgCell( 4 , 1 ) dlgLabel("


    "); + dlgCell( 4 , 2 ) dlgLabel("
    "); + dlgCell( 4 , 3 ) dlgLabel("
    "); + + dlgCell( 6 , 1 ) dlgLabel("Spice schematic"); + dlgCell( 6 , 2 ) dlgStringEdit(ImpSpiceSchematicAsc); + dlgCell( 6 , 3 ) dlgPushButton("&Browse") { + string mImpSpiceSchematicAsc = backslash2lash(dlgFileOpen("Select a spice schematic", ImpSpiceSchematicAsc , "*.asc")); + if (mImpSpiceSchematicAsc) { + ImpSpiceSchematicAsc = mImpSpiceSchematicAsc; + SchName = filedir(schname) + filesetext(filename(mImpSpiceSchematicAsc), ".sch"); + string f[]; + int exist = fileglob(f, SchName); + if (exist) { + dlgMessageBox("!Schematic '" + SchName + "' exist.", "CANCEL"); exit(-3960); + } + } + } + + + dlgCell( 7 , 1 ) dlgLabel("Eagle schematic "); + dlgCell( 7 , 2 ) dlgStringEdit(SchName); + dlgCell( 7 , 3 ) dlgPushButton("&Browse") { + string mSchName = backslash2lash(dlgFileOpen("Select eagle schematic", SpiceSimulationLbr , "*.sch")); + if (mSchName) { + SchName = mSchName; + } + } + } + } + + else { + dlgMessageBox("!Start this ULP in a schematic or library.", "OK"); + exit(-4); + } + dlgHBoxLayout { + dlgPushButton("+OK") { + if (fileext(ImpSpiceSchematicAsc) == ".asc" || fileext(FileSpiceSym[0]) == ".asy") { + if (schematic) { + if (!SchName) SchName = filename(filesetext(ImpSpiceSchematicAsc, ".sch")); + ScriptFile = filesetext(SchName, Imp_ScriptExt); + dlgAccept(); + } + else if (library) { + CntFileSpiceSym = fileglob(FileSpiceSym, SpiceSymbol); + dlgAccept(); + } + } + else { + if (schematic) dlgMessageBox("Select a LTC schematic file (*.asc) first!", "OK"); + else if (library) { + if (fileext(FileSpiceSym[0]) != ".asy" ) dlgMessageBox("Select a LTC symbol file (*.asy) first!", "OK"); + } + } + } + dlgPushButton("-CANCEL") { dlgReject(); exit(-5); } + dlgStretch(1); + dlgLabel(ULP_Version); + dlgPushButton("&Save config") saveconfig(); + } + }; + return; +} + +/***** EXPORT menu *****/ +void ex_setupmenu(void) { + string schexportname; + dlgDialog("Eagle-LTspice Setup") { + dlgHBoxLayout dlgSpacing(200); + dlgLabel("spice.asy = "+ LTSpiceLibDir); + dlgLabel("eagle.asy = "+ ExpEagleSpiceSymDir); + + if (schematic) { /*** SCHEMATIC ***/ //2012-10-10 alf + schematic(SCH) schexportname = filesetext(SCH.name, ".asc"); + dlgLabel("SCH = "+ schexportname); + } + else if (library) { /*** LIBRARY ***/ + dlgGridLayout { + ExOnceLib = 1; + if (deviceset) { + dlgCell( 5 , 2 ) dlgGroup("Export") { + dlgRadioButton("Export &all devices", ExOnceLib); + dlgRadioButton("EXPORT &only this deviceset to LTspice symbol (*.asy)", ExOnceLib); + } + } + else { + dlgCell( 5 , 2 ) dlgLabel("EXPORT all devicesets to LTspice symbols (*.asy)"); + } + } + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); exit(-2); } + dlgStretch(1); + dlgLabel(ULP_Version); + } + }; + saveconfig(); + return; +} + + +void dosfilecopy( string source, string target, string option) { + string DOScommand; + sprintf(DOScommand, "XCOPY \"%s\" \"%s\" %s", lash2backslash(source), lash2backslash(target), option); + /* + dlgDialog("DOS command") { + dlgHBoxLayout dlgSpacing(800); + dlgStringEdit(DOScommand); + dlgPushButton("ok") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-4056); } + }; + */ + system(DOScommand); + return; +} + +void autosetupinfo(string dlgheader, string cntscrsetup) { + dlgDialog(dlgheader) { + dlgGridLayout { + dlgCell( 0, 1) dlgLabel("Program:"); + dlgCell( 0, 2) dlgLabel(EAGLE_SIGNATURE); + dlgCell( 1, 1) dlgLabel("System:"); + dlgCell( 1, 2) dlgLabel(OS_SIGNATURE); + dlgCell( 2, 1) dlgLabel("Eagle Path:"); + dlgCell( 2, 2) dlgLabel(EAGLE_PATH); + dlgCell( 3, 1) dlgLabel("Eagle Dir:"); + dlgCell( 3, 2) dlgLabel(EAGLE_DIR); + dlgCell( 4, 1) dlgLabel("User Dir:"); + dlgCell( 4, 2) dlgLabel(EAGLE_HOME); + dlgCell( 5, 1) dlgLabel("
    "); + dlgCell( 5, 2) dlgLabel("
    "); + dlgCell( 6, 1) dlgLabel("LTSpiceExecute"); + dlgCell( 6, 2) dlgLabel(LTSpiceExecute); + dlgCell( 7, 1) dlgLabel("LTSpiceLibDir"); + dlgCell( 7, 2) dlgLabel(LTSpiceLibDir); + dlgCell( 8, 1) dlgLabel("ExpEagleSpiceSymDir"); + dlgCell( 8, 2) dlgLabel(ExpEagleSpiceSymDir); + dlgCell( 9, 1) dlgLabel("
    "); + dlgCell( 9, 2) dlgLabel("
    "); + dlgCell( 10, 1) dlgLabel("EagleExecute"); + dlgCell( 10, 2) dlgLabel(EagleExecute); + dlgCell( 11, 1) dlgLabel("Imp_ConnectScriptDir"); + dlgCell( 11, 2) dlgLabel(Imp_ConnectScriptDir); + dlgCell( 12, 2) dlgLabel(cntscrsetup); + dlgCell( 13, 1) dlgLabel("SpiceSimulationLbr"); + dlgCell( 13, 2) dlgLabel(SpiceSimulationLbr); + dlgCell( 14, 1) dlgLabel("SpiceDefaultSymLbr"); + dlgCell( 14, 2) dlgLabel(SpiceDefaultSymLbr); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + //dlgPushButton("-CANCEL") {dlgReject(); exit(-10); } + dlgStretch(1); + if (dlgheader == "Diagnose") { + dlgPushButton("Save") { + string rptfile = filesetext(argv[0], ".rpt"); + output(rptfile, "wt") { + printf("Program:\t%s\n", EAGLE_SIGNATURE); + printf("System:\t%s\n", OS_SIGNATURE); + printf("Eagle Path:\t%s\n", EAGLE_PATH); + printf("Eagle Dir:\t%s\n", EAGLE_DIR); + printf("User Dir:\t%s\n", EAGLE_HOME); + printf("LTSpiceExecute:\t%s\n", LTSpiceExecute); + printf("LTSpiceLibDir:\t%s\n", LTSpiceLibDir); + printf("ExpEagleSpiceSymDir:\t%s\n", ExpEagleSpiceSymDir); + printf("EagleExecute:\t%s\n", EagleExecute); + printf("Imp_ConnectScriptDir:\t%s\n", Imp_ConnectScriptDir); + printf("%s\n", cntscrsetup); + printf("SpiceSimulationLbr:\t%s\n", SpiceSimulationLbr); + printf("SpiceDefaultSymLbr:\t%s\n", SpiceDefaultSymLbr); + } + dlgMessageBox("Saved to:"+rptfile, "OK"); + } + } + } + }; + return; +} + +/* *********************** + ******** MAIN *********** + *********************** */ +readconfig(); +int CntScr = 0; +if (!LTSpiceExecute || argv[2] == "/S") { + string rootpath[] = { "C:/Programme/", "C:/Program files (x86)/", "C:/Program files/", "D:/Program files (x86)/", "D:/Program files/" }; // 2012-10-11 + int nroot = 0; + do { + LTSpiceExecute = file_search("LTspiceIV/scad3.exe", rootpath[nroot], 3, "4085"); // 2012-11-27 das LTspice executable, in Pfad LTspiceIV, das es ältere Versionen gibt, mit unterschiedlichen Pfadnamen! + nroot++; + } while (!LTSpiceExecute && rootpath[nroot]); + + if (!LTSpiceExecute) { + dlgMessageBox("!LTspiceIV (scad3.exe) not found.", "OK"); + exit(-4141); + } + else { + ExpEagleSpiceSymDir = filedir(LTSpiceExecute) + "lib/sym/eagle/"; // 2012-12-05 + LTSpiceLibDir = filedir(LTSpiceExecute) + "lib/"; // 2012-11-27 + } + + int pos = strstr(EagleExecute, "bin/"); // 2012-11-27 nur den Hauptpfad zu den Unterordnern + string eagleroot = strsub(EagleExecute, 0, pos); + + string cfgdirlbr = cfgget("EAGLE:Directories.Lbr"); // 2012-10-30 den Pfad unter Optionen Verzeichnisse zu den importierten LTspice-LBRs erweitern! + pos = strstr(cfgdirlbr, "lbr/ltspice"); + if (pos <0) { + cfgdirlbr = eagleroot + "lbr/ltspice;" + cfgdirlbr; + cfgset("EAGLE:Directories.Lbr", cfgdirlbr); + } + + // prüfe Verzeichnis für Scripte zum erzeugen der Devices von LT + Imp_ConnectScriptDir = file_search("misc/ltspice/scr", eagleroot, 4, "4109"); // Das Directory der Scripte von LT zum erzeugen der Devices CONNECT, PACKAGE, ATTRIBUTE... + if (!Imp_ConnectScriptDir) { + if (dlgMessageBox("!Directory of LT connect scripts not found:\n" + eagleroot + "scr/ltc", "MAKE DIR", "CANCEL") != 0) exit(-4161); + // makedir(eagleroot, "scr/ltc"); + } + else { + string scr[]; + CntScr = fileglob(scr, Imp_ConnectScriptDir + "*.scr"); + if (!CntScr) { + sprintf(h, "!No scripts found in:\n%s\n\nCopy first LT connect scripts!", Imp_ConnectScriptDir); + dlgMessageBox(h, "CANCEL"); + exit(-4170); + } + } + string copyeaglesym2spice = file_search( "eagle", LTSpiceLibDir, 3, "4123"); // prüfe ob Unterordner /eagle unter /sym besteht? + string copysource = eagleroot+"misc/ltspice/lib/*.*"; + if (copyeaglesym2spice) { + dosfilecopy( copysource, LTSpiceLibDir, "/S /Y"); // 2012-11-27 XCOPY mit Unterordner und ohne Eingabe/Quittierung + } + else { + if (!makedir(LTSpiceLibDir, "/sym/eagle")) { // Returnwert 0 wenn das Verzeichnis nicht angelegt werden konnte. + dlgMessageBox("!Can't creat directory:\n" + LTSpiceLibDir + "eagle", "CANCEL"); + exit(-4181); + } + // kopiere die Spice Symbole vom Eagle-Paket nach LTC lib/sym/eagle inkl. Unterordner + // 2012-11-27 neu ist der Ordner sub mit der Datei note.sub + dosfilecopy( copysource, LTSpiceLibDir, "/S /Y"); // 2012-11-27 XCOPY mit Unterordner und ohne Eingabe/Quittierung + } + + SpiceSimulationLbr = file_search("ltspice/lt-spice-simulation.lbr", EAGLE_DIR, 4, "4138"); // die Symbole zum simulieren, Stimuli (V, I, F Generatoren) + if (!SpiceSimulationLbr) { + dlgMessageBox("!Default LTspice simulation library not found, please import first:" + EAGLE_DIR + "/lbr/ltspice/lt-spice-simulation.lbr", "CANCEL"); + // 2013-10-01 Pfadtrenner nach EAGLE_DIR und lbr... + exit(-4192); + } +dlgMessageBox("!Default LTspice simulation library found on:\n" + EAGLE_DIR + "/lbr/ltspice/lt-spice-simulation.lbr", "CANCEL"); + + SpiceDefaultSymLbr = file_search("ltspice/sym.lbr", EAGLE_DIR, 4, "4144"); // die Default-Lbr für R, L, C, D, Res... + if (!SpiceDefaultSymLbr) { + dlgMessageBox("!Default LTspice symbol library (R C L D ...) not found, please import first:" + EAGLE_DIR + "lbr/ltspice/sym.lbr", "CANCEL"); + exit(-4199); + } + string cntscrsetup; + sprintf(cntscrsetup, "%d scripts", CntScr); + autosetupinfo("Auto Setup Info", cntscrsetup); + saveconfig(); + // 2012-10-30 die LTspice LBRs (den gesamten Ordner) in die USE-Liste eintragen! + string uselbr; + sprintf(uselbr, "USE -*;\nUSE '%slbr/ltspice';\nUSE '%slbr/eagle-ltspice'; #4222\n", eagleroot, eagleroot); + // Pfade immer in ' einschließen, besonders bei Windows 7/8 64-Bit, + // da es den Ordner "Programm (x86)" gibt, und die Klammern () von Eagle als Koordinate ausgewertet werden! + // für die eagle-ltspice.lbr muß der absolute Pfad angegeben werden, + // da der Pfad für die "eagl-lbrs" jetzt an zweiter Stelle steht! 2012-10-30 + exit(uselbr); +} + + +/* ****************************** + ******** main Export *********** + ****************************** */ +if (strupr(argv[1]) == "/E") { + if (library) { /*** LIBRARY ***/ + library(L) { + ex_setupmenu(); // runs always with setup menu + if (deviceset && ExOnceLib) { + deviceset(DEV) { + DEV.devices(D) ex_draw_device(D, DEV); + /* ***************************************************************************************** + Kein Handshake, das ULP wartet auf die Beendigung des aufgerufenen Programm (DOS-BOX) + und kehrt dann zum aufrufenden Fenster zurück. + Vorteil, das Fenster (Schaltplan) hat den Fokus wieder! + ****************************************************************************************** */ + //call_system(Ex_AsyName); + //exit("RUN ulpmessage 'DEVICESET " + DEV.name + ".dev
    exported to
    " + ExpEagleSpiceSymDir + filename(filesetext(L.name, "/")) + DEV.name + ".asy'"); + string rmsg; + sprintf(rmsg, "RUN ulpmessage 'DEVICESET %s.dev (%d)
    exported to
    %s", DEV.name, CntOutput, filedir(Ex_AsyName)); + exit(rmsg); + } + } + else { + int cnt = 0; + L.devicesets(DEV) DEV.devices(D) { + cnt++; + ex_draw_device(D, DEV); + } + //exit("RUN ulpmessage '" + L.name + "
    exported to
    " + ExpEagleSpiceSymDir + filename(filesetext(L.name, "/")) + "*.asy'"); + exit("RUN ulpmessage '" + L.name + "
    exported to
    " + filedir(Ex_AsyName) + "*.asy"); + } + } + } + + else if (sheet) { /*** SHEET ***/ + if (strupr(argv[2]) == "/G") ExportAll = 0; // export only selected group + + schematic(SCH) { + if (!ExportAll) ExpSchematic2LTpice = filesetext(SCH.name, "_group.asc"); // 2012-06-22 + else ExpSchematic2LTpice = filesetext(SCH.name, ".asc"); // 2012-05-10 + } + if (strupr(argv[2]) == "/S") { + ex_setupmenu(); + exit(0); + } + + if (Test) if (dlgMessageBox("Export Schematic to:\n" + ExpSchematic2LTpice, "OK", "CANCEL") != 0) exit(-6); + + output(ExpSchematic2LTpice, "wt") { + printf("Version 4\n"); + sheet(S) { + printf("SHEET %d %.0f %.0f\n", S.number, ex_spicegrid(u2mil(S.area.x2)), ex_spicegrid(u2mil(S.area.y2)*-1.0)); // SHEET 1 1684 1612 + S.nets(N) N.segments(SEG) SEG.wires(W) if (ingroup(W) || ExportAll) ex_draw_net_wire(W); + S.nets(N) N.segments(SEG) SEG.labels(LAB) if (ingroup(LAB) || ExportAll) ex_draw_label(LAB); + S.parts(P) P.instances(I) if (ingroup(I) || ExportAll) ex_draw_instance(I, P); + S.wires(W) if (ingroup(W) || ExportAll) ex_draw_wire(W); + S.rectangles(R) if (ingroup(R) || ExportAll) ex_draw_rectangle(R); + S.circles(C) if (ingroup(C) || ExportAll) ex_draw_circle(C); + S.texts(T) if (ingroup(T) || ExportAll) ex_draw_text(T, "SCH", ""); // 2012-05-11 + } + } + + //string ExportedFile = ExpSchematic2LTpice; + int ExportedFileTime = -1; + int newfiletim = -1; + string f[]; + int cnt = fileglob(f, ExpSchematic2LTpice); + if (cnt) { + ExportedFileTime = filetime(ExpSchematic2LTpice); + } + else { + dlgMessageBox("Warning, file '"+ExpSchematic2LTpice+"' does not exist!", "Break"); + exit(-7); + } + status(" Waiting for return of "+filename(LTSpiceExecute)); + string syscommand; + + // Handshake mit LT-Spice über eine Datei (momentan der LTspice-Schaltplan selber, über den Zeitstempel) + if (Ex_WaitOnHandShake) { + sprintf(syscommand, "cmd.exe /c \"%s\" \"%s\"", LTSpiceExecute, ExpSchematic2LTpice); + system(syscommand); // externes Programm starten + + ExportedFileTime = filetime(ExpSchematic2LTpice); + newfiletim = filetime(ExpSchematic2LTpice); + status("Waiting for LTspice response"); + do { + newfiletim = filetime(ExpSchematic2LTpice); + } while (newfiletim == ExportedFileTime); + exit ("RUN 'ltspice.ulp /I' '"+ ExpSchematic2LTpice + "' 'RELOAD'"); + } + /****************************************************************************************** + Kein Handshake, das ULP wartet auf die Beendigung des aufgerufenen Programm (DOS-BOX) + und kehrt dann zum aufrufenden Fenster zurück. + Vorteil, das Fenster (Schaltplan) hat den Fokus wieder! + *******************************************************************************************/ + call_system(ExpSchematic2LTpice); + + newfiletim = filetime(ExpSchematic2LTpice); + // Überprüfe den Timestamp der Datei, falls geändert, dann starte das ULP mit der Option RELOAD! + if (newfiletim == ExportedFileTime) exit(0); // nothing changed! + exit ("RUN 'ltspice.ulp' '/I' '"+ ExpSchematic2LTpice + "' 'RELOAD'"); + } + + else dlgMessageBox("Start this ULP in a library or schematic!", "OK"); + exit(-4320); +} + +/* ******************************* + ******** main Imxport *********** + ******************************* */ +else if (strupr(argv[1]) == "/I") { + sprintf(h, "%d", argc); + readconfig(); + if (argc == 4) { + if (fileext(argv[2]) == ".asc") { // work with schematic + Imp_CntFileSpiceAsc = 1; + ImpSpiceSchematicAsc = argv[2]; + } + else if (fileext(argv[2]) == ".asy") { // work with symbol + CntFileSpiceSym = 1; + FileSpiceSym[0] = argv[2]; + } + ScriptFile = filesetext(argv[2], "~spice2eagle.scr"); + } + + else { + // ### main menu SYMBOL/SCHEMATIC ### + imp_setupmenu(); + saveconfig(); + } + if (!FileSpiceSym[0] && !ImpSpiceSchematicAsc) exit(-8); + + + /**** Import a library ****/ + if (CntFileSpiceSym) { + int t = time(); + string fext = "*.asy"; + string libsource; + if (Import_All_Symbols) { + CntFileSpiceSym = fileglob(FileSpiceSym, filedir(FileSpiceSym[0])+fext); + if (!LbrName) LbrName = imp_dirname(FileSpiceSym[0]); + libsource = filedir(FileSpiceSym[0]) + "*.asy"; + } + else { + if (!LbrName) LbrName = filesetext(FileSpiceSym[0], ".lbr"); + libsource = filesetext(FileSpiceSym[0], "*.asy"); + } + ScriptFile = filesetext(FileSpiceSym[0], Imp_ScriptExt); + + if (NewLbrName) sprintf(Imp_Cmd, "OPEN '%s';\n", NewLbrName); + sprintf(h, "DESCRIPTION 'LT-Spice library generated with :
    \\n%s
    \\nfrom: %s
    \\nat %s';\n", + filename(argv[0]), libsource, t2string(t) + ); + Imp_Cmd+=h; + sprintf(h, "LAYER %d SpiceOrder;\n", LayerSpiceOrder); + Imp_Cmd+=h; + sprintf(h, "SET COLOR_LAYER %d %d;\n", LayerSpiceOrder, ColorViolett); // SET COLOR_LAYER layer color; + Imp_Cmd+=h; + + int nf = 0; + if (ScriptFile && FileSpiceSym[nf]) { + for (nf = 0; nf < CntFileSpiceSym; nf++) { + attribute2script("#4232\n", FileSpiceSym[nf], FileNewTemp); // neues Script anlegen, um die Attribute die in den PAckage-Varianten + // angelegt werden müssen, zwischen zu speichern. Denn das anlegen einer + // Package-Variante löscht die ATTRIBUTE, die vorher angelegt wurden! + string cmd; + Imp_CntPinname = 0; + int len = strlen(FileSpiceSym[nf]); + if (FileSpiceSym[nf] && FileSpiceSym[nf][len-1] != '/') { // can not use directories, cut last character / + CntLines = fileread(Lines, FileSpiceSym[nf]); + status(FileSpiceSym[nf]); // ein Lebenszeichen + Imp_SymDevName = strupr(filesetext(filename(FileSpiceSym[nf]), "")); + if (imp_checkexist_dev(Imp_SymDevName)) { + if (dlgMessageBox("! Attention: " + Imp_SymDevName + ".DEV exist.

    DELETE ?", "YES", "NO") != 0) { + exit("EDIT " + Imp_SymDevName + ".SYM"); + } + else sprintf(Imp_Cmd, "SET CONFIRM YES;\nREMOVE %s.DEV;\nSET CONFIRM OFF;\n", Imp_SymDevName); + } + if (imp_checkexist_sym(Imp_SymDevName)) { + if (dlgMessageBox("! Attention: " + Imp_SymDevName + ".SYM exist.

    DELETE ?", "YES", "NO") != 0) { + exit("EDIT " + Imp_SymDevName + ".SYM"); + } + else sprintf(Imp_Cmd, "SET CONFIRM YES;\nREMOVE %s.SYM;\nSET CONFIRM OFF;\n", Imp_SymDevName); + } + + sprintf(cmd, "EDIT %s.SYM;\nCHANGE LAYER 96;\nGRID MIL 50 2 LINES ON;\nCHANGE WIDTH 0;\nCHANGE STYLE Continuous;\n", Imp_SymDevName); + Imp_Cmd+=cmd; + + if (ExternalSymbol) { + sprintf(Imp_CmdDev, "EDIT %s.DEV;\nVALUE ON;\nADD %s '%s' (0 0);\n", Imp_SymDevName, Imp_SymDevName, Imp_DefaultGateName); // add new gate (symbol) + sprintf(cmd, "ATTRIBUTE '%s';\n", ExternalAttributeName); + Imp_CmdDev+=cmd; + } + + string pincoord[]; // remember pin coordinate for attribute + int cntpin; + + for (n = 0; n < CntLines; n++) { + if (strstr(Lines[n], "Version") == 0) imp_version(Lines[n]); + else if (strstr(Lines[n], "SymbolType") == 0) imp_symboltype(Lines[n]); + else if (strstr(Lines[n], "LINE") == 0) imp_line(Lines[n]); + else if (strstr(Lines[n], "RECTANGLE") == 0) imp_rectangle(Lines[n]); + else if (strstr(Lines[n], "CIRCLE") == 0) imp_circle(Lines[n]); + else if (strstr(Lines[n], "ARC") == 0) imp_arc(Lines[n]); + else if (strstr(Lines[n], "TEXT") == 0) imp_text(Lines[n]); + else if (strstr(Lines[n], "WINDOW") == 0) imp_window_sym(Lines[n], n); + else if (strstr(Lines[n], "SYMATTR") == 0) Imp_CmdDev += imp_symattr_sym(Lines[n], n, FileSpiceSym[nf]); + // PIN -48 -32 LEFT 8 + else if (strstr(Lines[n], "PIN ") == 0) cntpin = strsplit(pincoord, imp_pin(Lines[n]), '\t'); + else if (strstr(Lines[n], "PINATTR") == 0) imp_pinattr(Lines[n], pincoord[0], pincoord[1], pincoord[2]); + else if (Lines[n] == ""); // empty line in LTC3703-5.asy + else { + sprintf(h, "Symbol: Line %d unknown:\n%s", n+1, Lines[n]); + if (dlgMessageBox(h, "OK", "CANCEL") != 0) exit(-4429); + } + } + Imp_Cmd += Imp_CmdDev + "WIN FIT;\n"; // make a device and use generated symbol + if (Test) { + dlgDialog("Test") { + dlgHBoxLayout dlgSpacing(700); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(700); + dlgTextEdit(Imp_Cmd); + } + dlgHBoxLayout { + dlgPushButton("ok") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-9); } + dlgPushButton("weiter ohne Scriptanzeige") { dlgAccept(); Test = 0; } + } + }; + } + } + sprintf(cmd, "EDIT %s.DEV;\nVALUE ON;\n", Imp_SymDevName); // add new empty device + Imp_Cmd+=cmd; + string connectscript = file_search(filename(filesetext(FileSpiceSym[nf], ".scr")), Imp_ConnectScriptDir, 3, "4434"); + if (connectscript) { + string usedpacname = get_pac_from_script(connectscript); + int pacexist = check_exist_packname(usedpacname); + if (!pacexist) { + exit(-10); // without package can not define ATTRIBUTEs + } + sprintf(cmd, "SCRIPT '%s';\n", connectscript); + Imp_Cmd += cmd; + sprintf(cmd, "SCRIPT '%s';\n", filesetext(FileSpiceSym[nf], ".scr")); + Imp_Cmd += cmd; // die zuvor geretteten ATTRIBUTE in das Device schreiben + Imp_Cmd += "RUN 'copy-attribute-at-deviceset';\n"; // kopiert alle Attribute in alle Packagevarianten, + // und benennt die ertse Variante um zu '', damit die + // Schaltpläne reibungslos importiert werden können. 2012-10-07 + } + } + output(ScriptFile, "wtD") { + printf("#Generated with %s\n#from %s\n# at %s\n", argv[0], libsource, t2string(time(), "dd-MM-yyyy hh:mm:ss")); + printf("%s", Imp_Cmd); + } + exit ("SCRIPT '"+ ScriptFile + "'"); + } + } + + /*** Import a schematic ***/ + if (ImpSpiceSchematicAsc) { + if (schematic) { + string schname; + string spicename = filesetext(filename(ImpSpiceSchematicAsc), ""); + schematic(SCH) { + schname = filesetext(filename(SCH.name), ""); + if (spicename == schname) { + if (argv[3] == "RELOAD") { // return from export (RUN ltpsice.ulp /E) + RELOAD = 1; + exit(-4484); /* include here the different import */ + } + } + } + } + string FileImpSpiceSchematicAsc[]; + Imp_CntFileSpiceAsc = fileglob(FileImpSpiceSchematicAsc, ImpSpiceSchematicAsc); + if (ScriptFile && ImpSpiceSchematicAsc) { + if (ImpSpiceSchematicAsc) { + CntLines = fileread(Lines, ImpSpiceSchematicAsc); + status(ImpSpiceSchematicAsc); // ein Lebenszeichen + if (!imp_checkexist_sch(SchName)) { + string cmd; + sprintf(cmd, "EDIT '%s';\nCHANGE LAYER 96;\nGRID MIL 50 2 LINES ON;\nCHANGE WIDTH 10;\n", SchName); + Imp_Cmd+=cmd; + Imp_Cmd+= "SET CONFIRM YES;\n"; + Imp_Cmd+= "CHANGE STYLE Continuous;\n"; + Imp_Cmd+= "USE '"+ SpiceSimulationLbr + "'; #4516\n"; // set simulation symbol lbr to use list + Imp_Cmd+= "USE '"+ SpiceDefaultSymLbr + "';\n"; // set spice default symbol lbr to use list + for (n = 0; n < CntLines; n++) { + if (strstr(Lines[n], "Version") == 0) imp_version(Lines[n]); + else if (strstr(Lines[n], "SHEET") == 0) imp_sheet(Lines[n]); + else if (strstr(Lines[n], "WIRE") == 0) imp_wire(Lines[n]); + else if (strstr(Lines[n], "FLAG") == 0) imp_flag(Lines[n]); + else if (strstr(Lines[n], "IOPIN") == 0) imp_iopin(Lines[n]); + else if (strstr(Lines[n], "BUSTAP") == 0) imp_bustap(Lines[n]); + else if (strstr(Lines[n], "SYMBOL") == 0) imp_symbol_sch(Lines[n]); + else if (strstr(Lines[n], "WINDOW") == 0) imp_window_sch(Lines[n], n); + else if (strstr(Lines[n], "SYMATTR") == 0) imp_symattr_sch(Lines[n], n); + else if (strstr(Lines[n], "CIRCLE") == 0) imp_circle(Lines[n]); + else if (strstr(Lines[n], "RECTANGLE") == 0) imp_rectangle(Lines[n]); + else if (strstr(Lines[n], "ARC") == 0) imp_arc(Lines[n]); + else if (strstr(Lines[n], "TEXT") == 0) imp_text(Lines[n]); + else if (strstr(Lines[n], "text") == 0) imp_text(Lines[n]); + else if (strstr(Lines[n], "LINE") == 0) imp_line(Lines[n]); + else if (strstr(Lines[n], "DATAFLAG") == 0) imp_dataflag(Lines[n]); + else { + sprintf(h, "Schematic: Line %d unknown:\n%s", n+1, Lines[n]); + if (dlgMessageBox(h, "OK", "CANCEL") != 0) exit(-4); + } + } + imp_draw_net(); + if (RememberFlag) CmdNameLabel += RememberFlag; + Imp_Cmd += CmdNameLabel; + Imp_Cmd += Imp_CmdDev + "WIN FIT;\n"; // make a device and use generated symbol + Imp_Cmd += "SET CONFIRM OFF;\n"; + } + } + } + + if (Test) { // Testview("nach allem"); + dlgDialog("Das Rückgabe-SCRIPT") { + dlgHBoxLayout dlgSpacing(700); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(700); + dlgTextEdit(Imp_Cmd); + } + dlgHBoxLayout { + dlgPushButton("ok") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-4544); } + dlgPushButton("weiter") dlgAccept(); + } + }; + } + + output(ScriptFile, "wtD") { + printf("#Generated with %s\n#from %s\n# at %s\n", argv[0], ImpSpiceSchematicAsc, t2string(time(), "dd-MM-yyyy hh:mm:ss")); + + printf("%s", Imp_Cmd); + printf("DISPLAY NONE 91 92 94 95 96 97 98;\n"); // Display Layer 99 'SpiceOrder' off ! + } + exit ("SCRIPT '"+ ScriptFile + "'"); + } +} +/* ****************************** + ******** main Diagnostic ******* + ****************************** */ +else if (strupr(argv[1]) == "/?") { // 2013-10-01 + string cntscrsetup; + sprintf(cntscrsetup, "%d scripts", CntScr); + autosetupinfo("Diagnose", cntscrsetup); + exit(-4565); +} + +dlgDialog("Help") { + dlgHBoxLayout dlgSpacing(800); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgTextView(usage); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("OK") dlgAccept(); + dlgPushButton("LTspice Info") dlgMessageBox(LTspiceFormatInfo, "OK"); + dlgStretch(1); + } +}; + + + + + + + diff --git a/trunk/ulp/make-group2pac.ulp b/trunk/ulp/make-group2pac.ulp new file mode 100644 index 00000000..c73dbed7 --- /dev/null +++ b/trunk/ulp/make-group2pac.ulp @@ -0,0 +1,327 @@ +#usage "en:Generate a package from a GROUP of elements and their pads you selected in the layout.

    " + "Layer 20 Dimension is always considered as selected. " + "HOLEs and TEXTs can be selected (GROUP) as well.

    " + "Author: alf@cadsoft.de" + , + "de:Erzeuge ein Package aus den PADs einer selektierten GROUP im Board.

    " + "Der Layer 20 Dimension wird immer als selektiert betrachtet
    " + "HOLEs und TEXTe müssen im Board entsprechen selektiert werden (GROUP)
    " + "Author: alf@cadsoft.de" + +string Verison = "1.0.1"; // 2011-05-25 alf@cadsoft.de + // 2011-05-27 board loop correted + +int Group = 0; +string Lbrname = ""; + +string h, Cmd; +int Trash_layer = 250; // put anything here which is in wrong layers + + +/**** functions ****/ +void PrintValidLayer(int LNr) { + // put anything not allowed in trash_layer + + if (LNr>90 && LNr<100) { + LNr = Trash_layer; + sprintf(h, "Layer trash %d;\n", Trash_layer); + Cmd += h; + } + sprintf(h, "Layer %d;\n", LNr); + Cmd += h; + return; +} + + + +string addApostroph(string s) { + int len = strlen(s); + int pos = strrchr(s, '\''); + string l; + if (pos >= 0) { + l = strsub(s, 0, pos) + "'" + strsub(s, pos, len-pos); + s = l; + } + return s; +} + +/* main */ +if (board) { + board(B) { + B.elements(E) { + if (ingroup(E)) { + Group = 1; + if (!Lbrname) { // make the package on the first element library + Lbrname = E.package.library; + sprintf(h, "OPEN '%s.lbr';\nEDIT %s_%s.PAC;\nGRID MM;\nSET WIRE_BEND 2;\n", Lbrname, E.name, filename(filesetext(B.name, "")) ); + Cmd += h; + } + E.package.contacts(C) { + string ShapeString; + string ShapeFlag; + if (C.pad) { + switch(C.pad.shape[17]) { + case PAD_SHAPE_SQUARE : ShapeString = "Square"; break; + case PAD_SHAPE_ROUND : ShapeString = "Round"; break; + case PAD_SHAPE_OCTAGON : ShapeString = "Octagon"; break; + case PAD_SHAPE_LONG : ShapeString = "Long"; break; + case PAD_SHAPE_OFFSET : ShapeString = "Offset"; break; + } + if (!(C.pad.flags & PAD_FLAG_STOP) ) ShapeFlag = "NOSTOP "; + if (!(C.pad.flags & PAD_FLAG_THERMALS) ) ShapeFlag += "NOTHERMALS "; + if ((C.pad.flags & PAD_FLAG_FIRST) ) ShapeFlag += "FIRST "; + // + // PAD [diameter] [shape] [orientation] [flags] ['name'] *.. + // + sprintf(h, "Change Drill %f;\n", u2mm(C.pad.drill)); + Cmd += h; + sprintf(h, "Pad %f %s R%.1f %s '%s' (%f %f);\n", + u2mm(C.pad.diameter[17]), + ShapeString, + C.pad.angle, + ShapeFlag, + addApostroph(C.pad.name+"@"+E.name), + u2mm(C.pad.x), u2mm(C.pad.y)); + Cmd += h; + } + else if (C.smd) { + if (!(C.smd.flags & PAD_FLAG_STOP) ) ShapeFlag = "NOSTOP "; + if (!(C.smd.flags & SMD_FLAG_THERMALS) ) ShapeFlag += "NOTHERMALS "; + if (!(C.smd.flags & SMD_FLAG_CREAM) ) ShapeFlag += "NOCREAM "; + + sprintf(h, "Layer %d;\n", C.smd.layer); + Cmd += h; + sprintf(h, "CHANGE Roundness %d;\n", C.smd.roundness); + Cmd += h; + // + // SMD [x_width y_width] [-roundness] [orientation] [flags] ['name'] *.. + // + sprintf(h, "SMD %f %f -%d R%.1f %s '%s' (%f %f);\n", + u2mm(C.smd.dx), u2mm(C.smd.dy), + C.smd.roundness, + C.smd.angle, + ShapeFlag, + addApostroph(C.smd.name), + u2mm(C.smd.x), u2mm(C.smd.y) + ); + Cmd += h; + } + } + E.package.holes(H) { + sprintf(h, "Change Drill %f;\n", u2mm(H.drill)); + Cmd += h; + sprintf(h, "Hole (%f %f);\n", u2mm(H.x), u2mm(H.y)); + Cmd += h; + } + E.package.wires(W) { + sprintf(h, "Layer %d;\n", W.layer); + Cmd += h; + if (W.arc) { // 2008-09-11 + sprintf(h, "WIRE %f (%f %f) %+f (%.f %.f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2)); + Cmd += h; + } + else { + sprintf(h, "Wire %f (%f %f) (%f %f);\n", + u2mm(W.width), u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2)); + Cmd += h; + } + } + + E.package.circles(C) { + sprintf(h, "Layer %d;\n", C.layer); + Cmd += h; + sprintf(h, "Circle %f (%f %f) (%f %f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x + C.radius), u2mm(C.y) + ); + Cmd += h; + } + + E.package.rectangles(R) { + sprintf(h, "Rect R%.1f (%f %f) (%f %f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), + u2mm(R.x2), u2mm(R.y2) + ); + Cmd += h; + } + + E.package.polygons(P) { + sprintf(h, "Layer %d;\n", P.layer); + Cmd += h; + sprintf(h, "Change Isolate %f;\n", u2mm(P.isolate)); + Cmd += h; + sprintf(h, "Change Spacing %f;\n", u2mm(P.spacing)); + Cmd += h; + if (P.orphans) { + sprintf(h, "Change Orphans On;\n"); + Cmd += h; + } + else { + sprintf(h, "Change Orphans Off;\n"); + Cmd += h; + } + if (P.thermals) { + sprintf(h, "Change Thermals On;\n"); + Cmd += h; + } + else { + sprintf(h, "Change Thermals Off;\n"); + Cmd += h; + } + if (P.pour == POLYGON_POUR_SOLID) { + sprintf(h, "Change Pour Solid;\n"); + Cmd += h; + } + else { + sprintf(h, "Change Pour Hatch;\n"); + Cmd += h; + } + sprintf(h, "Polygon %f ", u2mm(P.width)); + Cmd += h; + P.wires(W) { + sprintf(h, "(%f %f) ", u2mm(W.x1), u2mm(W.y1)); + Cmd += h; /*start coord.*/ + break; + } + P.wires(W) { + sprintf(h, " %+f (%f %f) ", W.curve, u2mm(W.x2), u2mm(W.y2)); + Cmd += h; + } + sprintf(h, ";\n"); Cmd += h; + } + + E.package.texts(T) { + sprintf(h, "Layer %d;\n", T.layer); + Cmd += h; + switch(T.font) { + case FONT_VECTOR : sprintf(h, "CHANGE FONT VECTOR;\n"); + Cmd += h; + break; + case FONT_PROPORTIONAL : sprintf(h, "CHANGE FONT PROPORTIONAL;\n"); + Cmd += h; + break; + case FONT_FIXED : sprintf(h, "CHANGE FONT FIXED;\n"); + Cmd += h; + break; + } + string Spin = ""; + string Mirror = ""; + if (T.spin) Spin = "S"; + if (T.mirror) Mirror = "M"; + + sprintf(h, "Change Size %f;\n", u2mm(T.size)); + Cmd += h; + sprintf(h, "Change Ratio %d;\n", T.ratio); + Cmd += h; + sprintf(h, "Text %s%sR%.1f '%s' (%f %f);\n", + Spin, Mirror, T.angle, T.value, u2mm(T.x), u2mm(T.y) + ); + Cmd += h; + } + } + } + // 2011-05-27 Board contour + B.wires(W) { + if (W.layer == 20) { + sprintf(h, "Layer %d;\n", W.layer); + Cmd += h; + if (W.arc) { // 2008-09-11 + sprintf(h, "WIRE %f (%f %f) %+f (%.f %.f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2)); + Cmd += h; + } + else { + sprintf(h, "Wire %f (%f %f) (%f %f);\n", + u2mm(W.width), u2mm(W.x1), u2mm(W.y1), u2mm(W.x2), u2mm(W.y2)); + Cmd += h; + } + } + } + + B.circles(C) { + if (C.layer == 20) { + sprintf(h, "Layer %d;\n", C.layer); + Cmd += h; + sprintf(h, "Circle %f (%f %f) (%f %f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x + C.radius), u2mm(C.y) + ); + Cmd += h; + } + } + B.texts(T) { + if (ingroup(T)) { + sprintf(h, "Layer %d;\n", T.layer); + Cmd += h; + switch(T.font) { + case FONT_VECTOR : sprintf(h, "CHANGE FONT VECTOR;\n"); + Cmd += h; + break; + case FONT_PROPORTIONAL : sprintf(h, "CHANGE FONT PROPORTIONAL;\n"); + Cmd += h; + break; + case FONT_FIXED : sprintf(h, "CHANGE FONT FIXED;\n"); + Cmd += h; + break; + } + string Spin = ""; + string Mirror = ""; + if (T.spin) Spin = "S"; + if (T.mirror) Mirror = "M"; + + sprintf(h, "Change Size %f;\n", u2mm(T.size)); + Cmd += h; + sprintf(h, "Change Ratio %d;\n", T.ratio); + Cmd += h; + sprintf(h, "Text %s%sR%.1f '%s' (%f %f);\n", + Spin, Mirror, T.angle, T.value, u2mm(T.x), u2mm(T.y) + ); + Cmd += h; + } + } + B.holes(H) { + if (ingroup(H)) { + sprintf(h, "Change Drill %f;\n", u2mm(H.drill)); + Cmd += h; + sprintf(h, "Hole (%f %f);\n", u2mm(H.x), u2mm(H.y)); + Cmd += h; + } + } + + sprintf(h, "WIN FIT;\n"); + Cmd += h; + sprintf(h, "DESCRIPTION 'Package generated by %s

    \nfrom: %s
    \nat: %s';\n", + filename(argv[0]), B.name, t2string(time()) + ); + Cmd += h; + } + + if (!Group) { + dlgMessageBox("!First define a GROUP. Read HELP GROUP (enter)", "OK"); + } + else { + dlgDialog("Return script") { + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgTextEdit(Cmd); + } + dlgHBoxLayout { + dlgPushButton("Run Script") { dlgAccept(); exit(Cmd); } + dlgPushButton("ESC") { dlgReject(); exit(-1); } + } + }; + } +} + +else dlgMessageBox("!Start this ULP in a board.", "OK"); \ No newline at end of file diff --git a/trunk/ulp/make-long-pad-inner-layer.ulp b/trunk/ulp/make-long-pad-inner-layer.ulp new file mode 100644 index 00000000..3f07ffb3 --- /dev/null +++ b/trunk/ulp/make-long-pad-inner-layer.ulp @@ -0,0 +1,180 @@ +#usage "en:This ULP generates for LONG and OFFSET pads in inner layers the same diameter and shape as it is in the outer layers.

    " + "EAGLE basically uses for all pads in inner layers a round pad shape.
    " + "If you are using a LONG or OFFSET pad for a oblong soldering lug, and you defined a slotted hole with contours " + "drawn in layer 46, Milling, it is necessary to expand the pad in the inner layers with additional WIRE " + "segments. So the DRC is able to check possible conflicts with the slotted hole, and polygons with a different " + "signal name can be calculated properly.
    " + "However, there might occur a problem with thermals because the ULP can't recognize whether the pad is " + "connected to a polygon with thermals in the current layer. It can happen that the pad extension connects " + "fully with the copper plane.
    " + "If a (list of) Element_name(s) is given, the extended shape will be generated for the given element(s); " + "if there is no Element_name given, extended shapes are generated for all elements that have long pads.

    " + "RUN make-long-pad-inner-layer [Element_name [Element_name] .. ]
    " + "The inner layers must be used.!
    There has to be at least one WIRE oder POLYGON " + "in the inner layer.

    " + "In order to avoid DRC Overlap errors, you have to connect each pad. " + "The wires must have the correct signal name! Therefore connect each referring pin in the schematic with a NET. " + "The ERC reports 'Only one pin on net...' then, but this has to be approved. " + "

    " + "Author: support@cadsoft.de" + , + "de:Dieses ULP generiert für LONG- und OFFSET-Pads für die Innenlagen die gleiche Größe und Form wie in den Aussenlagen.

    " + "EAGLE generiert grundsätzlich für Pads in Innenlagen eine runde Padform.
    " + "Wird für längliche Lötanschlüsse (Lötfahnen) ein LONG- oder OFFSET-Pad benutzt und die Bohrung zusätzlich " + "geschlitzt, wobei die Fräskontur für den Längsschlitz im Layer 46 (Milling) definiert wird, so muß " + "in den Innenlagen das Pad zusätzlich mit WIRE-Segmenten erweitert werden. Dadurch kann der DRC Konflikte " + "mit dem Längsschlitz überprüfen bzw. ein Polygon mit fremden Signalnamen entsprechend freirechnen.
    " + "Es gibt allerdings ein Problem bei Thermalstegen, da über das ULP nicht ohne weiteres erkannt werden kann, " + "ob das Pad in diesem Layer an eine Kupferfläche über Thermalstege angeschlossen ist. " + "Diese Pads werden durch die Paderweiterung teilweise vollflächig angebunden.
    " + "Bei Angabe eines (einer Liste von) Bauteilnamen werden nur für dieses (diese) Bauteil(e) die " + "Paderweiterung erzeugt. Ohne Angabe von Bauteilnamen wird bei allen Bauteilen, die LONG-Pads enthalten, die " + "Paderweiterung erzeugt.

    " + "RUN make-long-pad-inner-layer [Bauteilname [Bauteilname] .. ]

    " + "Die Innenlagen müssen benutzt sein!
    Es muß also mindestens ein WIRE oder ein POLYGON " + "in der Innenlage vorhanden sein.

    " + "Um Overlap-Fehler im DRC zu vermeiden, muß jedes PAD angeschlossen sein; " + "somit haben die erzeugten WIREs auch den entsprechenden Signal-Namen. " + "Dazu verbinden Sie im Schaltplan die Pins mit einem NETz. " + "Dadurch bedingt, meldet der ERC 'Nur ein Pin an Net... Diese Meldung kann aber toleriert werden.'" + "

    " + "Autor: support@cadsoft.de" + +#require 6.0400; + +string Version = "1.4"; // 1.0 2007-11-29 alf@cadsoft.de + // 1.1 2008-01-08 check if connect with signal + // generate error messages + // 1.2 2008-01-15 Option - Element-Name list + // check if schematic consistent + // 1.3 2011-11-14 also use unused Layer + // 1.4 2013-01-15 Version 6 has no more supply option ($) of inner layer + // more detail info about pad without signal name + // real values extended to new resolution .9f +string s; +string cmd = "GRID mm;\nSET WIRE_BEND 2;\n"; +string error = ""; +int usedLayer[]; +string nameLayer[]; + + +void err(string name, string padname, int x, int y) { + sprintf(s, "%s Pad %s (%.9f %.9f) mm : No signal connected\n", + name, padname, u2mm(x), u2mm(y) ); + error += s; + return; +} + + +string checkname(string s) { // check signal name, if name add ' ' 2008.01.08 alf@cadsoft.de + if (s) sprintf(s, "'%s'", s); + return s; +} + + +int checkEname(string s) { + for (int n = 1; n < argc; n++ ) { + if (strupr(argv[n]) == s) return 1; + } + return 0; +} + + +if (board) { + int usedsum = 0; + if (dlgMessageBox(usage + "

    Version " + Version, "OK", "Cancel") != 0) exit(-1); + board(B) { + B.layers(L) { + if (L.number < 16 & L.number > 1) { + if (L.used) { + usedLayer[L.number] = 1; + nameLayer[L.number] = L.name; + usedsum++; + } + } + } + B.elements(E) { + if (!argv[1] || checkEname(E.name) ) { + E.package.contacts(C) { + if (C.pad) { + string p, m; + real l; + if (C.pad.shape[16] == PAD_SHAPE_LONG) { + l = u2mm(C.pad.diameter[1]) * C.pad.elongation * 0.005; + sprintf(m, "MARK (%.9f %.9f);\n", u2mm(C.x), u2mm(C.y)); + sprintf(s, "WIRE %s %.9f (R0 0) (P%.9f %0.1f);\n", // 2013-01-15 more resolution + checkname(C.pad.signal), + u2mm(C.pad.diameter[1]), + l, C.pad.angle + ); + p += s; + sprintf(s, "WIRE %s %.9f (R0 0) (P%.9f %.1f);\n", // 2013-01-15 more resolution + checkname(C.pad.signal), + u2mm(C.pad.diameter[1]), + l, C.pad.angle+180.0 + ); + p += s; + if (!C.pad.signal) err(E.name, C.pad.name, u2mm(C.x), u2mm(C.y) ); + } + else if (C.pad.shape[16] == PAD_SHAPE_OFFSET) { + real l = u2mm(C.pad.diameter[1]) * C.pad.elongation * 0.01; + sprintf(m, "MARK (%.9f %.9f);\n", u2mm(C.x), u2mm(C.y)); + sprintf(s, "WIRE %s %.9f (R0 0) (P%.9f %0.1f);\n", // 2013-01-15 more resolution + checkname(C.pad.signal), + u2mm(C.pad.diameter[1]), + l, C.pad.angle + ); + + p += s; + if (!C.pad.signal) err(E.name, C.pad.name, u2mm(C.x), u2mm(C.y) ); + } + if (p) { + cmd += m; + for (int n = 2; n < 16; n++) { + if (usedLayer[n]) { // 2011-11-14 + sprintf(s, "CHANGE LAYER %d;\n", n); + cmd += s; + cmd += p; + } // 2011-11-14 + } + } + } + } + } + } + } + + if (!usedsum) { + dlgMessageBox("!Inner layer not used!
    No Wire or Polygon in inner layer!", "OK"); + exit(-1); + } + + if (error) { // check and view errors + string Message = ""; + if (project.schematic) { + Message = "Consitent schematic is loaded!
    First conect unconected Pins/Pads in schematic, please cancel.
    "; + } + dlgDialog("ERROR " + filename(argv[0])) { + dlgHBoxLayout dlgSpacing(400); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgTextView(error); + } + dlgLabel("Can not place Signal-Wires on Pads with Signal-Name.
    "+ + "Please draw a NET on this PIN in Schematic to connect this PAD with an signal!" + ); + dlgLabel(Message); + + dlgHBoxLayout { + dlgPushButton("Ignore") dlgAccept(); + dlgPushButton("Cancel") { dlgReject(); exit(-1); } + dlgStretch(1); + } + }; + } + cmd += "MARK;\nGRID LAST;\nRATSNEST;"; + // dlgMessageBox(cmd, "OK"); // show generated script + exit(cmd); +} + +else dlgMessageBox("Start this ULP in Board", "OK"); diff --git a/trunk/ulp/make-package-consistent-brd-sch.ulp b/trunk/ulp/make-package-consistent-brd-sch.ulp new file mode 100644 index 00000000..16f21fbd --- /dev/null +++ b/trunk/ulp/make-package-consistent-brd-sch.ulp @@ -0,0 +1,139 @@ +#usage "Make schematic and board package consistent, use packages from board." + "

    " + "Author: alf@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED +string Version = "1.0.0"; // 2011-05-30 alf@cadsoft.de + +string Error = ""; +int NotConsist = 0; +string ScrName; +int CntChange = 0; + +// ### Functions ### +// Replace character with string (to replace technologie "*" and Package-Variant "?" in Deviceset name) +string ChrStrRep(string str, char a, string b) { + string s[]; + strsplit(s, str, a); + if (a) { + if (b == "''") return s[0] + s[1]; + return s[0] + b + s[1]; + } + return str; +} + + +void change_pac(string ename, string epackagename, string elibraryname) { + string s; + project.schematic(SCH) { + SCH.parts(P) { + if (P.name == ename) { + if (P.deviceset.library == elibraryname) { + string DevNname; + string techno = P.device.technologies; + string tech[]; + int cntt; + int found = 0; + int foundtech = 0; + P.deviceset.devices(D) { + if (D.package.name == epackagename) { // check exist technologie in nue package variant + DevNname = D.name; + cntt = strsplit(tech, D.technologies, ' '); + for (int n = 0; n < cntt; n++) { + if (techno == tech[n]) { + foundtech = 1; + break; + } + } + } + } + if (foundtech) { + if (P.device.package.name != epackagename) { // different packages in sch and brd? + P.deviceset.devices(D) { + if (D.package.name == epackagename) { + string dev_name = ChrStrRep(P.deviceset.name, '*', techno); // replace first with technologie + dev_name = ChrStrRep(dev_name, '?', D.name); // replace second with package variant + P.instances(I) { + string cmd; + sprintf(s, "EDIT .S%d;\n", I.sheet); + cmd+= s; + sprintf(s, "CHANGE PACKAGE %s %s;\n", ename, dev_name); + cmd+= s; + printf(cmd); + NotConsist = 1; + found = 1; + CntChange++; + break; + } + } + } + if (!found) { + sprintf(s, "%s : Package-Variant %s on Deviceset %s not found!\n", + ename, epackagename, P.deviceset.name); + Error += s; + } + break; // parts + } + } + else { + sprintf(s, "%s : Technologie %s in Package-Variant %s not exist! Check device in library %s.lbr\n", + ename, techno, DevNname, P.deviceset.library); + Error += s; + } + } + else { + sprintf(s, "%s : Different libraries BRD:%s.lbr SCH:%s.lbr\n", + ename, P.deviceset.library, elibraryname); + Error += s; + } + } + } + } + return; +} + + +// ### Main ### +if (library) { + dlgMessageBox("Start this ULP in a consistent board or schematic.", "OK"); + exit(0); +} + +if (project.schematic && project.board) { + if (project.board) { + project.board(B){ + ScrName = filesetext(B.name, "~pac~consistent~.scr"); // temporary script file + output(ScrName, "wtD") { + B.elements(E) { + int PACcontact = 0; + E.package.contacts(C) { // check only packages with contacts + change_pac(E.name, E.package.name, E.package.library); + break; + } + } + } + } + if (Error) { + dlgDialog("Make PAC consistent errors") { + dlgHBoxLayout dlgSpacing(600); + dlgTextView(Error); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; + exit(-1); + } + else { + if (!NotConsist) { + dlgMessageBox("Schematic and Board are Package consistent!", "OK"); + exit(0); + } + string cmd; + sprintf(cmd, "SCRIPT '%s'\nEDIT .BRD;\nRUN ulpmessage '%d packages changed.';\n\nRUN '%s'", ScrName, CntChange, argv[0]); + exit(cmd); + } + } +} +dlgMessageBox("!Board an Schematic are not consistent.\nCheck Element/Part - Value - Netlist!", "OK"); diff --git a/trunk/ulp/make-symbol-device-package-bsdl.ulp b/trunk/ulp/make-symbol-device-package-bsdl.ulp new file mode 100644 index 00000000..fb558c83 --- /dev/null +++ b/trunk/ulp/make-symbol-device-package-bsdl.ulp @@ -0,0 +1,3833 @@ +#usage "Make Symbol, Device, Package or use Package in LBR\n" + "

    " + "Generates Symbol and Device from a text file containing a list of pin names.
    " + "This version can use BSDL (Boundary Scan Description Language) files to create a Package for BGA
    " + "or use a set of parameters to generate a Package.
    " + "

    " + "Author: ed@anuff.com / librarian@cadsoft.de" + +#require 5.7001 + +/* + * Copyright (c) 2004 Ed Anuff . All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * +*/ + +// Rev: 1 (Eagle 4.12r04) - 2004-08-13 alf@cadsoft.de +// ***************************************************************** +// Rev: 2 (Eagle 4.13) - 2004-14-09 +// special sorting for Pad names with 2-Alpha-Character +// *** Xilix BSM-Files without ";" in line ************************* +// Xilinx = "linkage bit_vector (" and ": inout bit -- " +// BSDL = "linkage bit_vector; (" and ": inout bit; -- " +// ***************************************************************** +// Rev: 3 (Eagle 4.13) - 2004-11-23 +// corrected parse line with "port" +// *** Xilinx BSM-Files +// "port (" - without spaces +// *** Intel .bsdl-Files +// " port (" - with spaces +// corrected Function: [Replace] character string +// ***************************************************************** +// Rev: 4 (Eagle 4.13) - 2005-01-10 +// port: trim left spaces from string +// pars_map() corrected counter +// ***************************************************************** +// Rev: 5 (Eagle 4.13) - 2005-01-27 +// AnalogDevice uses Tabulator not Space characters and +// some times places no space before use direction +// ***************************************************************** +// Rev: 6 (Eagle 4.13) - 2005-03-23 +// Device and Package description font bold/italic +// ***************************************************************** +// Rev: 7 (Eagle 4.14) - 2005-06-06 +// Accept comment "--" in line +// ***************************************************************** +// Rev: 8 (Eagle 4.15) - 2005-06-28 +// Corrected grid and Package outlines +// allways set grid to 1.0 mm (default) +// ***************************************************************** +// Rev: 9 (Eagle 4.15) - 2005-08-02 +// change TAB with SPACE "\t" --> " " +// Improved search end of "port" list for Xilinx-BSDL-Files +// ***************************************************************** +// Rev: 10 (Eagle 4.15) - 2005-08-19 +// Menu to generate quad and dual pin packages +// correct port-end-parse with ");" and for AnalogDevice == "));" +// ***************************************************************** +// Rev: 11 (Eagle 4.15) - 2005-10-18 +// new parse end of port, counts open-close Bracked +// BSDL can use multiple packages, now can select one, if more than one defined +// Also generate Symbol only +// Generate Package variant +// Scan "BSDL" in text to set BSDL-Parse-Option if any file extension +// ***************************************************************** +// Rev: 12 (Eagle 4.15) - 2005-12-01 +// If !file use lbrname for path/script +// Correct package_name handling +// Change bit-map if select quad or dual package +// Use also thrue hole PADs for Packages +// ***************************************************************** +// Rev: 13 (Eagle 4.16r1) - 2006-06-01 +// round coordinates to 0.1 inch in symbol +// Menu BGA: [] Accept copy local parameter to global parameter +// ***************************************************************** +// Rev: 14 (Eagle 4.16r1) - 2006-06-09 +// Menu BGA: add Cream-Mask Parameter +// ***************************************************************** +// Rev: 15 (Eagle 4.16r1) - 2006-07-06 +// more at 1 Pin-Pad definition in Xilinx-BSDL Files, at +// constant CP56 : PIN_MAP_STRING := +// "TCK : K10, TDI : J10, TDO : A6, TMS : K9, " & +// ***************************************************************** +// Rev: 16 (Eagle 14.16r1) - 2006-10-19 +// Plus menu entry: delete Pad-Prefix in BSDL-List +// Example: Xilinx - xcs20_PQ208.bsd +// Check if exist Pad names +// ***************************************************************** +// Rev: 17 (Eagle 14.16r1) - 2006-11-09 +// Delete Lines with Textstring extendet to EXACT / INCLUDE +// ***************************************************************** +// Rev: 18 (Eagle 14.16r1) - 2006-12-05 +// Pad-Names to upper case +// on linkage, check by pin-name (VDD, VCC, VSS, VDD) if the pin really power-pin +// Set direction on all pins of a group of pins in a text-block +// Generate a new symbol! +// If more es 160 pins used, placed the pins as stripes by max (64) pins. +// This make no large symbol if too much pins in device. +// ***************************************************************** +// Rev: 19 (Eagle 4.16r2) - 2007-01-10 +// Start argument "edit-no-description" to switch of red marker in desciption; +// ***************************************************************** +// Rev: 20 (Eagle 4.16r2) - 2007-10-15 +// Button: SortPin (List) +// ***************************************************************** +// Rev: 21 (Eagle 4.16r2) - 2008-04-02 +// Button: Delete Column in Text field +// Button: Delete double pad number in pin-pad-direction list if copy +// text from a document like pdf ... +// ***************************************************************** +// Rev: 22 (Eagle 5.0) - 2008-05-20 +// [Save text as] [Load Text] in Text-Menu +// Rev: 23 (Eagle 5.0) - 2008-06-16 Texas BSDL files are use UPPER-CASE for "PORT" +// Rev: 24 (Eagle 5.0) - 2008-06-19 no check for PIN-coordinates if not symbol generated +// Rev: 25 (Eagle 5.0) - 2008-07-03 numbering pins, set Pin-Direction +// ***************************************************************** +// Rev: 26 (Eagle 5.3) - 2008-11-07 Text-Options [Rename PAD] +// Check pin list with pad names if package generated with option Package +// Generate Device-Descriptin also by Text-Option +// New changeable parameter GRID for Package generation, +// if measurements in data sheet in inch, mil, mm. +// remember last bsdl-file path +// +// Rev: 27 (Eagle 5.3) - 2008-12-03 +// Option for Padname use as in list, or generate by counter +// ***************************************************************** +// Rev: 28 (Eagle 5.4) - 2009-02-18 +// check if list sorted by pad name, to generate correct symbol +// by ascending pad namnes. +// - correct edit option delte x th. line +// ***************************************************************** +// Rev: 29 (Eagle 5.4.3) - 2009-03-09 +// no pad sorting if used bsdl file to generate symbol +// +// Rev: 30 (Eagle 5.6.1) - 2009-10-12 +// check if exist package definition in bsdl file +// +// Rev: 31 (Eagle 5.6.1) - 2009-10-16 +// generate only BGAs without file +// +// Rev: 32 (Eagle 5.6.1) - 2009-11-12 +// change character ';' ',' to '_' in parse function +// +// Rev: 33 (Eagle 5.6.2) - 2009-11-24 +// Split text and merge 1. helf text-lines with 2nd half text-lines +// +// Rev: 34 (Eagle 5.7.2) - 2010-02-15 +// Change wire width 10 mil on symbol outline +// +// Rev: 35 (Eagle 5.9.3) - 2010-05-25 +// Change PIN legth SHORT +// Check if text parsed for generate symbol +// +// Rev: 36 (Eagle 5.9.3) - 2010-12-02 +// Info Text-Optoins ** use word separator also for delete column +// +// Rev. 37 (Eagle 5.11.1) 2011-03-07 +// Option ganerate pad names for generate only package (not BGA) +// +// Rev. 38 (Eagle 5.11.1) 2011-04-01 +// shrink menus for smaler Display (MacBook Pro user) now 823 to 667 pixel +// ULP Scripts Panel too large for MacBook Pro +// Help is now a Dialog with textview +// Check package name if generate a package +// New Rename PIN in tab List Options +// New help for list tab +// +// Rev. 39 (Eagle 5.11.1) 2011-05-23 +// Check continuous pad number in function check_pad_sorting() +// change to uppercase in function +// +// Rev. 40 (Eagle 5.11.2) 2011-09-20 +// Check directions of eagle bevor create symbol +// Save package config, save BGA config +// +// Rev. 41 (Eagle 5.90.0) 2011-09-20 +// Check on empty pin list used make symbol +// Check on empty pad list used make package +// +// Rev. 42 (Eagle 5.11.2) 2011-11-03 alf@cadsoft.de +// No symbol (name) check, if only generated package +// Edit Package-Name also in Package Tab +// +// Rev. 43 (Eagle 6.0.1) 2011-12-15 alf@cadsoft.de +// Corrected check max/min coordinate with INT_MAX to check +// coordinates of pads and pins. +// +// Rev. 44 (Eagle 6.5.0) 2013-12-02 Button to open manual as pdf +// + +string Revision = "Rev. 44"; + +string HelpDE = "Dieses ULP unterstützt die Generierung von Symbolen, Devices und Packages.
    " + + "Eine BSDL-Datei (Boundary Scan Description Language .bsdl) wird automatisch geparsed.

    " + + "Pin-Direction:
    " + "Der Bezeichner 'linkage' wird für No-Connects (NC), Power (VCC), oder Ground (GND) benutzt, wobei anhand der BSDL-Daten
    " + "nicht unterschieden werden kann ob es sich um einen NC oder PWR Pin handelt.
    "+ + "In einigen Fällen kann es vorkommen, daß dadurch Signal-Pins die Direction PWR erhalten, die man manuell im Symbol-Editor ändern muß.
    "+ + "Bei Text-Dateien wird über die Anzahl der Trennzeichen der word separator ermittelt und voreingestellt.

    " + + "Um Text-Dateien (Tabellen) zu bearbeiten, gibt es folgende Möglichkeiten:" + + "

      " + + "
    • Split with word separator: Damit wird im Text an der Stelle an der sich ein nicht druckbares Zeichen befindet ein NewLine eingefügt." + + "
    • Split with Character: An der Stelle im Text an der sich dieses druckbare Zeichen befindet, wird ein NewLine eingefügt." + + "
    • Merge: Es werden, entsprechend dem angegebenen Wert, so viele Zeilen zu einer Zeile zusammengefügt." + + "
    • Merge 1/2 Text: Die Zeilen der zweiten Texthälfte wird an die Zeilen der ertsen Texthälfte angefügt." + + "Als Trennzeichen zwischen den Wörtern wird der gewählte word separator benutzt." + + "
    • Replace character string .. with .. : Zeichenketten im Text, die exakt der angegebenen Definition entsprechen, werden ausgetauscht." + + "
    • Delete lines with text: Zeilen die exakt dem angegebenen Text entsprechen, wenn das Flag Exact gesetzt ist,
      " + "oder Zeilen die den angegebenen Text enthalten, wenn das Flag Include gesetzt ist, werden entfernt." + + "
    • Delete every x th line [x], Start at line [n] - Löscht jede X-te Zeile ab der n-ten Zeile im Text." + + "
    • Delete empty lines: Zeilen, die leer sind bzw. nur nicht druckbare Zeichen enthalten, werden entfernt."+ + "
    • <<-- Copy kopiert die Tabelle wieder in den Text(-Editor)." + + "
    • Sort Pad sortiert die Liste nach Pad-Namen." + + "
    • Sort Pin sortiert die Liste nach Pin-Namen." + + "
    • Parse -->> übersetzt den Text (Tabelle) in die Pin-Pad-Direction-Tabelle." + + " Als Trennzeichen zwischen den Wörtern wird der gewählte word separator benutzt." + + "
    " + + "Durch Anwenden der einzelnen Möglichkeiten kann ein beliebiger Text zu einer brauchbaren Tabelle umgestaltet werden.
    " + + "Es ist auch möglich einen Text aus der Zwischenablage (Clipboard) einzufügen (Ctrg+V)." + + "

    " + + "Bei Text-Dateien kann ein Package aus der vorhandenen Use-Liste der geladenen LBR gewählt, oder über Package automatisch generiert werden.
    " + + "Bei BSDL-Dateien (.bsdl) kann ebenfalls ein Package automatisch generiert werden.
    " + + "Es wird überprüft ob im benutzten Package genügend Pads vorhanden sind um jeden Symbol-Pin zu verbinden." + + "

    " + + "BGA-Package generieren (BSDL): Es wird davon ausgegangen, daß das Gehäuse symmetrisch aufgebaut ist.
    " + + " - Package Width: Die Gehäuseaussenmaße (Kunststoffkörper).
    " + + " - PAD Grid: Der Abstand zwischen den SMD-Pads.
    " + + " - PAD Diameter: Der Durchmesser der SMD-Pads.
    " + + " - Stop Mask: Ein positiver Wert erzeugt eine Stopmaske um den angegebenen Wert größer als das Pad, ein negativer Wert erzeugt
    " + + "eine Maske um den Betrag kleiner als das Pad.
    " + + "Package generieren: Durch Angabe der Parameter in der Karte Package können zweireihige oder vierseitige Packages generiert werden.
    " + + "Der Start-Parameter edit-no-description verhindert daß in der Description des Device der Hinweis " + + " edit this description eingetragen wird.

    " + + "Author: librarian@cadsoft.de"; + ""; + +string HelpEN = "This ULP supports the generation of Symbols, Devices, and Packages.
    " + + "A BSDL (Boundary Scan Description Language) file will be parsed automatically
    " + + "PIN-Direction: In addition to in, out, and inout, a pin can be identified as type linkage.
    "+ + "This is used for no-connects (NC), power (VCC), or ground (GND).
    "+ + "The number of separators in the text file determins and presets the word separator.

    " + + "There are the following possibilities to edit text files (spreadsheets):" + + "

      " + + "
    • Split with word separator: Insert NewLine at the position of a non-printable character." + + "
    • Split with Character: Insert NewLine in the text at the position of the given printable character." + + "
    • Merge: Joins the given number of lines to one common line.
      " + + "The given word separator is used as separator between words." + + "
    • Replace character string with: For replacing the given string." + + "
    • Delete lines with text: For deleting lines that contain exactly the given text." + + "
    • Delete every x th line [x], Start at line [n]: Deletes every x th line, beginning with line number n." + + "
    • Delete empty lines: For deleting lines that do not contain characters or contain non-printable characters only." + + "
    • <<-- Copy: Copies the spreadsheet into the text editor again. The given word separator will be used between words." + + "
    • Sort Pad The list will be sorted by pad names." + + "
    • Sort Pin The list will be sorted by pin names." + + "
    • Parse -->>: Transfers the text (spreadsheet) into the Pin-Pad-Direction spreadsheet." + + "
    " + + "These tools allow to make a usable spreadsheet from any text." + + "It is also possible to insert text from the operating sytem's clipboard.
    " + + "If you are working with text files you have to choose an already existing package from the currently loaded library or use Package.
    " + + "It is also possible to generate a new package from a BSDL file (*.bsdl).
    " + + "First the ULP will check if there are sufficient pads for the pins of the symbol." + + "

    " + + "Generate a package (BSDL files only): The package is assumed to be designed symmetrically.
    " + + " - Package width: The dimension of the (plastic) case .
    " + + " - PAD grid: The distance between the smds.
    " + + " - PAD diameter: The diameter of the smds." + + "

    " + + "Author: librarian@cadsoft.de"; + ""; + + // 2011-04-01 +string HelpLiDE = "List Optoins

    " + + "

      " + + "
    • Swap PIN-PAD: tauscht in der Liste die Pins-Pads-Spalte." + + "
    • Swap PAD-DIR: tauscht in der Liste die Pads-Direction-Spalte." + + "
    • Direction Change: Ändert die Direction der Liste nach Angaben." + + "
    • Direction Set: Setzt alle Direction-Einträge auf den gewählten Wert." + + "
    • Direction Delete: Löscht alle Diretion-Einträge in der Liste." + + "
    • Clear leading zeros in BGA-Pad: Löscht alle führenden Nullen die evtl. bei BGA-Pads aus der BSDL-Datei übernommen worden sind." + + "
    • Delete double pad number: Löscht alle doppelt vorkommenden Zeilen mit gleicher Padnummer.
      " + + "Das kann vorkommen, wenn aus Text, PDF oder sonstigen Seiten, Tabellen kopiert werden." + + "
    • Rename PIN: Alle Teile der Pinnamen in denen die Suchzeichenkette [Replace] character string aus der Karteikarte Text Options vorkommen,
      " + + "werden mit der Zeichenkette with ersetzt." + + "
    • Rename PAD: Alle Teile der Padnamen in denen die Suchzeichenkette [Replace] character string aus der Karteikarte Text Options vorkommen,
      " + + "werden mit der Zeichenkette with ersetzt." + + "
    • Numbering pads für pins: Die Spalte Pads wird neu durchnummeriert.
      " + + "
    " + + "Author: librarian@cadsoft.de" + + ""; + +string HelpLiEN = "List Option

    " + + "

      " + + "
    • Swap Pin-Pad Exchanges the pin and pad coloumn." + + "
    • Swap Pin-Pad Exchanges the pad and direction coloumn." + + "
    • Direction Change: Cahnge Direction of list at your input." + + "
    • Direction Set: Setzt all Direction entry of selected value." + + "
    • Direction Delete: Delete all Diretion entry of list." + + "
    • Clear leading zeros in BGA-Pad: Delete all leading zeros of BGA-Pad names (possibly include from BSDL file." + + "
    • Delete double pad number: Löscht alle doppelt vorkommenden Zeilen mit gleicher Padnummer.
      " + + "Das kann vorkommen, wenn aus Text, PDF oder sonstigen Seiten, Tabellen kopiert werden." + + "
    • Rename PIN: Search character in pin name and replace [Replace] character string at with of register card \"Text Options\".
      " + + "
    • Rename PAD: Search character in pad name and replace [Replace] character string at with of register card \"Text Options\".
      " + + "
    • Numbering renumbering column Pads.
      " + + "
    " + + "Author: librarian@cadsoft.de" + + "
    "; + + +string Help; +string HelpList; +if (language() == "de") { + Help = HelpDE; + HelpList = HelpLiDE; +} +else { + Help = HelpEN; + HelpList = HelpLiEN; +} + + +int TextHigh = 220; // high of the text and list window +int TextWidth = 450; // width of the text window +int ListWidth = 250; // width of the list window (Pins Pads Direc.) +int TextStatusHigh = 18; // distance of Text an Tap filed to display text status + +string editMode = " edit this description"; +string infile, Source_file = "DESCRIPTION '';\n"; +string symbol_file, symbol_name; +string device_file, device_name; +string packagefile; +string package_name; +string pac_variant_name = ""; +string packages[]; +int n_packages = 0; +int package_selected = 0; +real package_wire_width = 0.1016; // to create a new package from BSDL file +real pac_width = 17.0; // to create a quad package from BSDL file +real textsize = 1.27; +real grid_val = 1.0; // for BallGridArea packages +real SMD_diameter = 0.5; // for BallGridArea packages +real MaskRestring = 0.0; // for BallGridArea packages +real CreamDiameter = 0.0; // for BallGridArea packages 2006-06-09 +string genpac_grid = "MM"; // 2008-11-07 default grid to generate package, can change in menu to mil, inch, mic. + +int smd_pad = 0; // use SMD or PAD for generate Package 2005-12-01 +// PAD_SHAPE_SQUARE, PAD_SHAPE_ROUND, PAD_SHAPE_OCTAGON, PAD_SHAPE_LONG, PAD_SHAPE_OFFSET +string PadShape[] = { "SQUARE", "ROUND", "OCTAGON" }; +int pad_shape = PAD_SHAPE_ROUND; +string packinfomess = ""; + +// new Menu Paramter to auto generate +int pad_layout; +int Pad_Count = 1; // the pads of package +int cnt_side = 0; // calculated pads on one side of package +real xA_pac = 14.0; // width of the metall pins +real yA_pac = 14.0; // width of the metall pins for quad package +real xD_pac = 12.0; // width of the plastic package in x +real yD_pac = 12.0; // width of the plastic package in y +real basic_pad_grid = 0.65; // the Basic grid Pad to Pad +real pad_width = 0.35; // the width of solder pin +real pad_stand_out = 0.5; // stand out the pad over the metall pin +real ypad_length = 0.4; // the pad width +real xpad_length = 0.9; // the pad length +real mark_length = 0.6; // length of corner edge to mark pad 1 +real roundness_restring = 0; // the SMD roundness for QFP/LCC/DualInline +string round_restring = "Roundness %"; +int packageparameter_accept; // if all parameter Ok for QFP/LCC/DualInline +int BGAparameter_accept; // if BGA parameter accept for generate package +string paccmd; // the script to generate qfp/lcc/Dual-Inline + +int pin_map_cnt = 0; // count the maps in the file +string pin_map_name; // the name of actual pin map + + +char w_separator[] = { ' ' , '\b', '\f', + '\n', '\r', '\t', + '\v', 0 }; + +string separator[] = { "SPACE", "Backspace", "Form Feed", + "New Line", "Carriage Return", "Horizontal tab", + "Vertical tab", "" }; + +int select_separ = 0; +char Word_separator = w_separator[select_separ]; +string String_separator; + +string Vector_name[]; +int sVector[], eVector[]; +int cnt_vector; +string up_down; + +string text; +string lines[]; +int n_lines; + +numeric string pin_names[]; +int n_pin_names = 0; +numeric string pad_names[]; +int n_pad_names = 0; +int use_pad_names = 0; +enum { useNONE, useBGA, usePACwithPrefix } // for use Padnames to generate Device +string pad_prefix; +string old_pad_prefix; +string checkPadname = ""; + + +numeric string pins_pads_direc[]; +numeric string pins[]; +numeric string pads[]; +string Pin_Direc[]; +int suffix[]; +int suffix_cnt, suffix_point; +int suffix_s, suffix_e; + +int n_pins = 0; +int n_pads = 0; + +int maxPinCnt = 100; +int maxStripeCnt = 64; // maximum of pins on a stripe in symbol +string pinCntInfo = " "; // Info if more as maxPinCnt pins used in one Symbol 2006-12-05 + + +// extend this list to set pin direction on power by linkage 2006-12-05 +string PowerName[] = { + "GND", + "VCC", + "VDD", + "VSS", + "VEE", + "+5V", + "-5V", + "" // the last must be empty "" + } ; + +enum { k_single, k_dual, k_dual2, k_quad , k_stripe }; +int pin_layout = k_dual; + + +int is_bsdl = 0; +int pars_mode; + +int breacked_status = 0; +enum { mode_null, mode_port, mode_map }; + +string bsdl_map_pin; // the actual map pin name + // more as one pins can named as the same + +string bsdl_pin_name[]; +string bsdl_Pin_Dir[]; +int cnt_bsdl_port; +string parsed_pins = " "; +string bsdl_package_name; +int make_Package; // generate Package by generated script + + +char port_separator = ':'; +char PIN_MAP_separator = ':'; + +string tinfo = " "; +string MakePacInfo = " "; +int select = 0; +int sorting = 0; // view list + +int index[]; +string used_pad_number[]; // 2008-11-07 +enum { e_symbol, bga_pac, e_pac }; // editor type to check max value of grid + +string rememberBSDLpath; // 2008-11-07 +string rememberLastPathFile = "~remember-make-bsdl~.mem"; + + // 2009-10-16 +string bga_pad_name[] = { "A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "P", "R", "T", "U", "V", "W", "Y", "" }; +int cntBGApadX = 44; +int cntBGApadY = 44; +int only_generate_bga = 0; +int only_generate_pac = 0; // to generate only a qfp/plcc ... package + +string Pin_Dir[] = { + "NC", + "IN", + "OUT", + "IO", // 2011-09-20 V6 use IO + "OC", + "PWR", + "PAS", + "HIZ", + "SUP" + }; + +string Existdir = "" + // 2011-05-23 + "" + + "" + + "" + + "" + + "" + + "" + // 2011-09-20 V6 use IO + "" + + "" + + "" + + "" + + "" + "
    Existing
    Directions:
    NCNot Connected (not used)
    INInput
    OUTOutput
    IOIn/Out programmable
    OCOpen Collector
    HIZTristate
    SUPSupply pin (without package)
    PASPassive
    PWRPower pin of device
    "; + + +real m_pac_width = pac_width; // 2006-06-01 -- 2011-09-20 +real m_grid_val = grid_val; +real m_SMD_diameter = SMD_diameter; +real m_MaskRestring = MaskRestring; +real m_CreamDiameter = CreamDiameter; + +string packinfo = ""; + + +string ExecutableAcrobatReader = cfgget("ULP:AcrobatReader_ulp"); +string PdfDocLink; + +/* *************************************** + ########## Functions ########### + *************************************** */ +// change Eagle slash in path names to backslash for windows +string getDOSname(string s) { + string sx[]; + int n = strsplit(sx, s, '/'); + return strjoin(sx, '\\'); +} + +void getexecutable(void) { + string execute = dlgFileOpen("Wähle PDF-Anzeige-Programm", "", "*.exe"); + if (execute) { + ExecutableAcrobatReader = execute; + cfgset("ULP:AcrobatReader_ulp", execute); // setze die Optiopn in der eaglerc.usr + return; + } + else exit(-1); +} + +void system_call(string loadpdffile) { // 2013-12-02 DOS comand execute + if (!ExecutableAcrobatReader) getexecutable(); + string syscommand; + // Das executable und der Dateiname müssen in " " eingeschlossen werden, wegen Spaces im Pfad-Dateinamen! + // "CMD.EXE /C START " ist nötig, da sonst auf das Beenden des Acrobat-Reader gewartet wird. + sprintf(syscommand, "CMD.EXE /C START \"%s\" \"%s\"", getDOSname(ExecutableAcrobatReader), getDOSname(loadpdffile)); + system(syscommand); // externes Programm starten + return; +} + +/* ************************************ */ +int check_pin_direction(string pindir) { // 2011-09-20 + int pn = 0; + do { + if (pindir == Pin_Dir[pn]) return 0; + pn++; + } while (Pin_Dir[pn]); + return -1; +} + + +string check_pin_dir(void) { // 2011-09-20 + for (int n = 0; n < n_pins; n++) { + if (!Pin_Direc[n]) return "empty pin direction!"; + if (check_pin_direction(Pin_Direc[n])) return Pin_Direc[n]; + } + return ""; +} + + +// 2008-11-07 check if exist package, but do not generate +int check_exist_pac(string pacname) { + int exist = 0; + library(L) { + L.packages(PAC) { + if (PAC.name == pacname) return 1; + } + } + return 0; +} + + +int check_Coordinate(string name, real x, real y, string grid_unit, int edit_type) { // 2008-11-07 new, grid unit, editor type + string s; + real maxminxy; + // 2008-11-07 check max x-y by used grid + if (grid_unit == "MM") maxminxy = u2mm(INT_MAX); // 2011-12-15 the internal maximum + else if (grid_unit == "INCH") maxminxy = u2inch(INT_MAX); + else if (grid_unit == "MIL") maxminxy = u2mil(INT_MAX); + else if (grid_unit == "MIC") maxminxy = u2mic(INT_MAX); + else { + if (edit_type == bga_pac) dlgMessageBox("Check grid parameter in BGA menu!", "OK"); + else if (edit_type == e_pac) dlgMessageBox("Check grid parameter in Package menu!", "OK"); + return -1; + } + if (x > maxminxy || x < -maxminxy ) { + sprintf(s, "Too much pins to generate symbol in X
    Coordinate (%.4f) %s out of range %.4f %s

    ", x, grid_unit, maxminxy, grid_unit); + } + if (y > maxminxy || y < -maxminxy) { + sprintf(s, "Too much pins to generate symbol in Y
    Coordinate (%.4f) %s out of range %.4f %s

    ", y, grid_unit, maxminxy, grid_unit); + } + if (s) { + if (edit_type == e_symbol) s += "Check Symbol Pin Layout: Single | Dual | Quad before exiting this ULP"; + else if (edit_type == bga_pac) s += "Check pad names in BSDL file
    " + infile + "
    and/or measures in BGA menu."; + else if (edit_type == e_pac) s += "Check pad names
    " + infile + "
    and/or measures in Packlage menu."; + dlgMessageBox(s, "Ok"); + return -1; + } + return 0; +} + + +string replaceString(string source, string find, string replace) { + string result = source; + int i = strstr(source, find); + string head; + string tail; + + if (i > -1) { + if(i == 0) { + head = ""; + tail = strsub(source, i + strlen(find)); + } + else { + head = strsub(source, 0, i); + tail = strsub(source, i + strlen(find)); + } + result = head + replace + tail; + } + return result; +} + + +string replaceCharacter(string source, char find, char replace) { + string result = source; + int i = strchr(source, find); + string head; + string tail; + + if (i > -1) { + if(i == 0) { + head = ""; + tail = strsub(source, i + 1); + } + else { + head = strsub(source, 0, i); + tail = strsub(source, i + 1); + } + sprintf(result, "%s%c%s", head, replace, tail); + } + return result; +} + + + +// cut spaces on left and on right of string 2005-10-05 +string trimString(string source) { + if(!source) return source; + string result; + int i, head = 0; + for (i = 0; source[i]; i++) { + if (!isspace(source[i])) { + head = i; + break; + } + } + int send = strlen(source); + int len = send; + if (len) { + for (i = len-1; i >= 0; i--) { + if (!isspace(source[i])) { + send = i+1; + break; + } + } + } + return strsub(source, head, send-head); +} + + +string cleanWhitespace(string line) { + string oldtext = ""; + do { + oldtext = line; + line = replaceString(line, "\t", " "); + line = replaceString(line, " ", " "); + } while (line != oldtext); + return trimString(line); +} + + +string spaceCharacter(string l, char c) { + string oldtext = ""; + do { + oldtext = l; + l = replaceCharacter(l, c, ' '); + } while (l != oldtext); + return l; +} + + +string clear_line(string l) { + if(!l) return l; + + int comment = strstr(l, "--"); // comment + if (comment > 0) l = strsub(l, 0, comment); // strip comment 02.06.2005 + + for (int n = 0; n < strlen(l); n++) { + if (l[n] == '\"' || l[n] == '(' || l[n] == ')' || l[n] == '&' ) { + l[n] = ' '; + } + else if ( l[n] == ';') l[n] = ','; // *** replace ';' with ',' for last MAP_LINE + } + l = trimString(l); + return l; +} + + +string cleanName(string name) { + name = cleanWhitespace(name); + name = replaceString(name, " ", "_"); + name = replaceString(name, ".", "_"); + name = replaceString(name, "(", "_"); + name = replaceString(name, ")", "_"); + name = replaceString(name, "\\", "-"); + // 2009-11-12 alf@cadsoft.de + name = replaceString(name, ",", "_"); + name = replaceString(name, ";", "_"); + return name; +} + + +void replaceWord(string search, string replace) { + string s; + tinfo = " "; + dlgRedisplay(); + if (search == replace) { + dlgMessageBox("!Search string equal Replace string", "Cancel"); + return; + } + int found, newfound; + int ct = 0; + do { + newfound = strstr(text, search, found); + if (newfound >= 0) { + sprintf(s, "(%d)", newfound); + status(s); + text = strsub(text, 0, newfound) + replace + strsub(text, newfound+strlen(search) ); + found = newfound + strlen(replace); + ct++; + } + else break; + } while (text); + + status(" "); + sprintf(tinfo, "%d words replaced", ct); + dlgRedisplay(); + return; +} + + +void gen_viewlist(int cnt) { + status ("generate list"); // 2008-11-07 display working + for (int i = 0; i < cnt; i++) { + sprintf( pins_pads_direc[i], "%s\t%s\t%s", pin_names[i], pad_names[i], Pin_Direc[i]); + } + pins_pads_direc[i] = ""; // 2008-04-02 + return; +} + + +string clear_textline(string line, char c) { + int pos; + do { + pos = strchr(line, c); + if (pos >= 0) line[pos] = '_'; // 2009-11-12 + } while (pos >= 0); + return line; +} + + +void filter_pin_pad( int use_pad_names) { + for (int d = 0; d <= n_pins; d++) { + pins_pads_direc[d] = ""; + pin_names[d] = ""; + pad_names[d] = ""; + pins[d] = ""; + pads[d] = ""; + Pin_Direc[d] = ""; + suffix[d] = 0; + } + n_pins = 0; + for (int i = 0; i < n_lines; i++) { + lines[i] = clear_textline(lines[i], ';'); + string pin_name = cleanName(lines[i]); + string pad_name = ""; + int n; + string items[]; + n = strsplit(items, lines[i], Word_separator); + if (n > 0) { + pin_name = cleanName(items[0]); + if (use_pad_names = useBGA) { // ## useNONE, useBGA, usePACwithPrefix, isePACwithoutPrefix ## + pad_name = cleanName(items[1]); + } + + if (strlen(pin_name) > 0) { + pins[n_pins] = pin_name; + if (use_pad_names) pads[n_pads++] = pad_name; + + if (n > 2) Pin_Direc[n_pins] = items[2]; // 2008-04-02 + pin_names[n_pins] = pin_name; + pad_names[n_pins] = pad_name; + n_pins++; + } + } + } + pins[n_pins] = ""; + pads[n_pins] = ""; + pin_names[n_pins] = ""; + pad_names[n_pins] = ""; + pins_pads_direc[n_pins] = ""; + Pin_Direc[n_pins] = ""; + Pin_Direc[n_pins] = ""; + suffix[n_pins] = 0; + gen_viewlist(n_pins); + return; +} + + +void filter_text( int use_pad_names) { + n_lines = strsplit(lines, text, '\n'); + filter_pin_pad( use_pad_names); + sprintf( parsed_pins, "%d pins parsed", n_pins); // 2008-11-07 + Pad_Count = n_pins; // set pin counter for package option on text + return; +} + + +// ** scratch line after position n ** +string scratch(string p, char c, int n) { + int pos = strchr(p, c, n); + if (pos > 0) return strsub(p, 0, pos); + else return p; +} + + +/* ****************************************************** + Analog-Device use "linkage" also for signal pins!! + Example: + CLKIN: linkage bit; + XTAL: linkage bit; + VROUT: linkage bit_vector(0 to 1)); + ******************************************************* + + http://www.actel.com/documents/BSDLformat.pdf + In addition to in, out, and inout, a pin can be identified as type linkage. + This is used for no-connects (NC), power (VCC), or ground (GND). + ******************************************************** */ + +string Pin_Direction( string bsdldir) { + string pin_dir; + bsdldir = scratch( bsdldir, ' ', 1); // for Xilinx BSM-Files 14.09.2004 + bsdldir = scratch( bsdldir, ';', 1); + + if (bsdldir == "inout") pin_dir = "IO"; // 2011-09-20 V6 use IO + else if (bsdldir == "out") pin_dir = "OUT"; + else if (bsdldir == "in") pin_dir = "IN"; + else if (bsdldir == "linkage") pin_dir = "PWR"; + else if (bsdldir == "buffer") pin_dir = "HIZ"; + else { + bsdldir = scratch( bsdldir, '(', 0); + } + if (bsdldir == "linkage bit_vector") pin_dir = "PWR"; + // ** 09.09.2004 place a ';' in Xilinx BSD-Files ** + // ** to separate " linkage bit_vector" ! ** + return pin_dir; +} + + +string get_dir( string name) { // ** direction of pin ** + for (int i = 0; i < cnt_bsdl_port; i++) { + if (bsdl_pin_name[i] == name) { + return bsdl_Pin_Dir[i]; + break; + } + } + return ""; +} + + +string getVector(string v) { // ** count up or down ** + string Vname, vs[]; + int pos; + pos = strsplit(vs, v, ':'); + pos = strsplit(vs, vs[0], ' '); + for (int n = pos; pos; n--) { + if (vs[n]) break; + } + if (vs[n][0] == '(') vs[n] = strsub(vs[n], 1); + return vs[n]; +} + + +void parse_bit_vector(string l) { + /* EXAMPLE ************************************************** + XILINX-BSM-File + VCCAUX: linkage bit_vector; (1 to 16); + VCCINT: linkage bit_vector; (1 to 16); + + INTEL-BSDL-File + port (pci_ad : inout bit_vector(31 downto 0); + pci_cbe_n : inout bit_vector(3 downto 0); + ** ^ ^ ** + ** counter direction up = to / down = downto. ** + ********************************************************** */ + + int pos = strstr(l, "bit_vector", 0); + if (pos > 0) { + Vector_name[cnt_vector] = getVector(l); + status(Vector_name[cnt_vector]); // 2008-11-07 display working + string s, v, vs[]; + s = strsub(l, pos); + int n = strsplit(vs, s, '(' ); // cut up to ( + s = vs[1]; + n = strsplit(vs, s, ')' ); // cut ) + s = vs[0]; + n = strsplit(vs, s, ' ' ); + sVector[cnt_vector] = strtol(vs[0]); + eVector[cnt_vector] = strtol(vs[2]); + up_down = vs[1]; + cnt_vector++; + } + return; +} + + +// search & count breackeds for parse end 05.10.2005 +void brackeds(string l) { + string br[]; + int open_breacked = strsplit(br, l, '('); + int close_breacked = strsplit(br, l, ')'); + breacked_status += (open_breacked - close_breacked); + return; +} + + +// ** BSDL parser ** +void pars_port(string l) { + status("parse port"); + brackeds(l); + if (!breacked_status) { // end of port list 2005-10-05 + pars_mode = mode_null; + } + string k[]; + // if more as 1 port in line, it's a group of ports in line! 2006-12-05 + int cntk = strsplit(k, l, ','); + for (int nk = 0; nk < cntk; nk++) { + string p[]; + int n = strsplit(p, k[nk], port_separator); // ':' + if (n > 1) { + bsdl_pin_name[cnt_bsdl_port] = trimString(p[0]); + bsdl_Pin_Dir[cnt_bsdl_port] = Pin_Direction(trimString(p[1])); + if (bsdl_Pin_Dir[cnt_bsdl_port] == "PWR") { // check if realy a power pin by name 2006-12-05 + int cntpwr = 0, np = 0; + do { + cntpwr += strstr(bsdl_pin_name[cnt_bsdl_port], PowerName[np])+1; // to check more names, extend the line PowerName[]... + if (cntpwr) break; + np++; + } while (PowerName[np]); + if (!cntpwr) bsdl_Pin_Dir[cnt_bsdl_port] = "PAS"; // no powerpin 2006-12-05 + } + parse_bit_vector(l); + cnt_bsdl_port++; + } + } + return; +} + + +int get_suffix(string vector) { + int n; + for (n = cnt_vector; n >= 0; n--) { + if (vector == Vector_name[n]) break; + } + return n; +} + + +void pars_map(string l) { + status("parse maping"); + + if (strstr(l, ";") >= 0 ) { // semikolon marks end of map list + pars_mode = mode_null; // set parse mode + } + l = clear_line(l); // replace '"' and '(' and ')' with space, and replace ';' with ',' + l = cleanWhitespace(l); + + string lq[]; + int nlq = strsplit(lq, l, ','); // 2006-07-06 more as 1 Pin-Pad-Definition in Xilinx-BSDL files + // Example : xc2c32a_cp56.bsd + // constant CP56 : PIN_MAP_STRING := + // "TCK : K10, TDI : J10, TDO : A6, TMS : K9, " & + for (int nq = 0; nq <= nlq; nq++) { + l = lq[nq]; + string p[]; + string pad_map; + int n = strsplit(p, l, PIN_MAP_separator); // ':' + + if (n > 1) { // pin name + string ps[]; + int nn = strsplit(ps, trimString(p[0]), ' '); + bsdl_map_pin = ps[0]; // a new pin name + pad_map = p[1]; // pad name(s) + status(pad_map); // 2008-11-07 display working + suffix_point = get_suffix(bsdl_map_pin); + if (suffix_point < 0) { + suffix_cnt = -1; // set counter negativ -1 + } + else { + suffix_s = sVector[suffix_point]; + suffix_e = eVector[suffix_point]; + suffix_cnt = suffix_s; + } + } + else { // only pad names + pad_map = p[0]; + } + pad_map = spaceCharacter(pad_map, ','); + pad_map = cleanWhitespace(pad_map); + n = strsplit(p, pad_map, ' '); + for (int i = 0; i <= n; i++) { + if (p[i]) { // ** 2005-01-10 + // line can start with ", ..." + // line can end with ...," + pins[n_pins] = bsdl_map_pin; + pads[n_pins] = strupr(trimString(p[i])); // upper case ** 2006-12-05 + suffix[n_pins] = suffix_cnt; + if (suffix_cnt >= 0) { + if (up_down == "to") suffix_cnt++; + else if (up_down == "downto") suffix_cnt--; + } + n_pins++; + } + } + pins[n_pins] = ""; // clear +1 + pads[n_pins] = ""; + pin_names[n_pins] = ""; + pad_names[n_pins] = ""; + suffix[n_pins] = 0; + } + return; +} + + +string get_devName(string l) { + l = cleanWhitespace(l); + string s[]; + int n = strsplit(s, l, ' '); + if (n > 1) return strupr(s[1]); + return "--"; +} + + +string get_pacName(string l) { + string s[]; + int n = strsplit(s, l, '"'); + if (n > 1) return strupr(s[1]); + return ""; +} + + +string get_pin_map_name(string l) { + l = cleanWhitespace(l); + string s[]; + int n = strsplit(s, l, ' '); + n = strsplit(s, s[1], ':'); + return s[0]; +} + + +/* EXAMPLE ************************************************ +entity IXP4XX is + generic(PHYSICAL_PIN_MAP : string:= "BGA"); + port (pci_ad : inout bit_vector(31 downto 0); + pci_cbe_n : inout bit_vector(3 downto 0); + pci_par : inout bit; + pci_frame_n : inout bit; + .... + ... + .. + constant BGA:PIN_MAP_STRING := + "pci_ad : (D3, C2, J6, B1, A1, C1, D1, G3,"& + " E1, J4, G1, F1, K5, H2, K3, H1,"& + " N5, P2, P3, P5, N1, R1, R3, U1,"& + " U4, T1, V1, R5, V3, T4, W1, U3),"& + "pci_cbe_n : (H4, K1, M1, P1),"& + "pci_par : M2,"& +******************************************************** */ +void filter_bsdl(void) { + n_lines = strsplit(lines, text, '\n'); + int n; + /** counter and strings reset **/ + suffix_cnt = 0; + pars_mode = mode_null; + cnt_bsdl_port = 0; + pin_map_cnt = 0; // use multiple PIN_MAP_STRING: in BSDL + n_pins = 0; + package_name = ""; + package_selected = 0; + + + for ( n = 0; n < n_lines; n++) { + string line = lines[n]; + + if (strstr(line, "--") == 0); // comment + + else { + switch(pars_mode) { + case mode_port: /*** parse port lines pin-names and function ***/ + pars_port(trimString(line)); // 2005-01-10 trim spaces on left side of string + break; + + case mode_map: /*** parse pad-name ***/ + pars_map(line); + break; + + default : int pos = strstr(strlwr(line), "port"); // 2008-06-16 Texas BSDL files are UPPER-CASE for "PORT" + if (pos >= 0) { + brackeds(line); + pars_mode = mode_port; + pos = strstr(line, "(", pos); + string p = strsub(line, pos+1); + pars_port(trimString(p)); + } + + else if (strstr(line, "constant") >= 0 && strstr(line, "PIN_MAP_STRING") > 8) { + if (!pin_map_cnt) { + package_name = strupr(get_pin_map_name(line)); + pin_map_cnt++; + pars_mode = mode_map; + package_selected = 0; + } + else { + string next_pin_map = get_pin_map_name(line); + pin_map_cnt++; + if (dlgMessageBox("found next MAP list " + next_pin_map + " (Package), last Map list " + package_name + " (Package)

    Use MAP?", next_pin_map, package_name) != 0) ; + else { + package_name = strupr(next_pin_map); + pars_mode = mode_map; + suffix_cnt = 0; // reset counter an arrays 06.10.2005 + n_pins = 0; // reset pin list counter + } + } + } + + if (strstr(line, "entity") == 0) { + device_name = get_devName(line); // 23.11.2004 + } + + if (strstr(line, "generic") >= 0) { + package_name = strupr(get_pacName(line)); // 23.11.2004 + package_selected = 0; + } + break; + } + } + } + status ("generate direction"); // 2008-11-07 display working + for ( n = 0; n < n_pins; n++) { + Pin_Direc[n] = get_dir( pins[n]); + if (suffix[n] >= 0) { + if (Pin_Direc[n] == "PWR") { + sprintf( pin_names[n], "%s@%d", pins[n], suffix[n]); + } + else { + sprintf( pin_names[n], "%s%d", pins[n], suffix[n]); + } + pins[n] = pin_names[n]; + } + else pin_names[n] = pins[n]; + pad_names[n] = pads[n]; + } + // ** in a text block, only the last line define the direction ** + // ** fill down the pindirection in list 2006-12-05 ** + for ( n = n_pins - 1; n; n--) { + if (!Pin_Direc[n-1] && Pin_Direc[n]) Pin_Direc[n-1] = Pin_Direc[n]; + } + pins_pads_direc[n_pins] = ""; // make shure the last in the list is empty! + pin_names[n_pins] = ""; + pad_names[n_pins] = ""; + Pad_Count = n_pins; // 2008-11-07 set pad counter + sprintf( parsed_pins, "%d pins parsed", n_pins); + dlgRedisplay(); + if (n_pins > 160) { // 2008-11-07 + sprintf(pinCntInfo, "Too many pins for a small symbol. Tip: Generate symbol with stripes of max pins in line."); // 2006-12-05 + pin_layout = k_stripe; + } + else if (n_pins > maxPinCnt) { + sprintf(pinCntInfo, "Too many pins for a small symbol. Generate symbol with four sides."); + pin_layout = k_quad; // 2008-11-07 + } + sprintf( bsdl_package_name, "Used package in BSDL file: %s", package_name ); + gen_viewlist(n_pins); + return; +} + + +void check_separator(void) { + string tx[]; + int scnt = 0; + int n = -1; + do { + n++; + int i = strsplit(tx, text, w_separator[n]); + if (scnt < i) { + scnt = i; + select_separ = n; + Word_separator = w_separator[select_separ]; + sprintf(String_separator, "%c", Word_separator); + } + } while(w_separator[n]); + return; +} + + +// is in Text "BSDL" then mark Text as BSDL 2005-10-18 +int scan_isbsdl(void) { + int bsdl = 0; + bsdl = strstr(text, "BSDL"); + if (bsdl > 0) return 1; + return 0; +} + + +void readText( string file) { + string base_file = filename(file); + string base_name = cleanName(strsub(filename(file), 0, strrchr(base_file, '.'))); + symbol_name = base_name; + device_name = base_name; + + // reset all counters + for (int d = 0; d <= n_pins; d++) { + pins_pads_direc[d] = ""; + pin_names[d] = ""; + pad_names[d] = ""; + pins[d] = ""; + pads[d] = ""; + Pin_Direc[d] = ""; + suffix[d] = 0; + } + n_pins = 0; + n_pads = 0; + n_pin_names = 0; + n_pad_names = 0; + package_name = ""; + + int n = fileread(text, file); + status("parse ..."); // 2008-11-07 display, im working + is_bsdl = scan_isbsdl(); + string f = strlwr(fileext(file)); + if (f == ".bsm" || f == ".bsd" || f == ".bsdl" || is_bsdl) { + // ** clear tabulator in text ** + tinfo = "Parsing BSDL file, please wait!"; + parsed_pins = "Please wait!"; + dlgRedisplay(); + int i; + do { + i = strchr(text, '\t'); + if(i > 0) { + text[i] = ' '; + } + } while (i > 0); + + use_pad_names = useBGA; + pad_prefix = ""; + filter_bsdl(); // file parse + is_bsdl = 1; + } + if (!is_bsdl) check_separator(); + sprintf(tinfo, "[text length %d character]", strlen(text) ); + dlgRedisplay(); + return; +} + + +string split_row_column(string p, int type) { + int n; + for (n = 0; n < strlen(p); n++) { + if (p[n] > '@'); + else break; + } + if (type) return strsub(p, n); + return strsub(p, 0, n); +} + +string merge_half_text_lines(string t) { // 2009-11-24 +/* +Example: +1 +2 +3 +4 +5 +6 +1DIR +1B1 +1B2 +GND +1B3 +1B4 + +--- merge to --- + +1 1DIR +2 1B1 +3 1B2 +4 GND +5 1B3 +6 1B4 +*/ + string newtext; + string l[]; + int cnt = strsplit(l, t, '\n'); + if (cnt & 1) { + string m; + sprintf(m, "Count of lines are odd number (%d), only a even number of lines can merge.", cnt); + dlgMessageBox(m, "OK"); + return t; + } + cnt = cnt / 2; + if (cnt >= 1) { + for (int n = 0; n < cnt; n++) { + newtext += l[n] + String_separator + l[cnt+n] + "\n"; + } + sprintf(tinfo, "Text to %d lines merged.", cnt); + } + else { + dlgMessageBox("Less than two lines.", "OK"); + return t; + } + return newtext; +} + + +// *** BGAs can use 2 Alpha-Character for Pad-Name *** +void padsort(void) { + int n; + for (n = 0; n < n_pins; n++) { + if(isalpha(pad_names[n][1])) { + pad_names[n] = "~" + pad_names[n]; + } + } + sort(n_pins, index, pad_names); + for (n = 0; n < n_pins; n++) { + if(pad_names[n][0] == '~') { + pad_names[n] = strsub(pad_names[n], 1); + } + } +} + + +void makePackage(string file) { + real maxcolumn; + packagefile = filesetext(file, "~package.scr"); + output(packagefile, "wtD") { + if(packageparameter_accept) printf("%s", paccmd); /** generate QFP/LCC/DUAL-Line **/ + else if (BGAparameter_accept) { /** generate BGA **/ + printf("EDIT %s.PAC;\n", package_name); + printf("GRID %s %.4f ON;\n", genpac_grid, grid_val/2); // 2008-11-07 set actual grid to generate package + printf("SET WIRE_BEND 2;\n"); + printf("CHANGE ROUNDNESS 100;\n"); + printf("CHANGE LAYER 1;\n"); + printf("CHANGE SMD %.4f %.4f;\n", SMD_diameter, SMD_diameter); + padsort(); + int cntrow, column, cntcolumn; // Zeile/Spalte + string row_name, last_name; + + for (int n = n_pins-1; n >= 0; n--) { + row_name = split_row_column(pad_names[index[n]], 0); + column = strtol(split_row_column(pad_names[index[n]], 1)); + if(maxcolumn < column) maxcolumn = column; + if (last_name != row_name) { + cntrow++; + last_name = row_name; + } + if (check_Coordinate(pad_names[index[n]], grid_val*column, grid_val*cntrow, genpac_grid, bga_pac)) exit(0); // 2008-11-07 grid from bga + printf("CHANGE LAYER 1;\n"); + printf("SMD NOSTOP NOCREAM '%s' (%.4f %.4f);\n", pad_names[index[n]], grid_val*column, grid_val*cntrow ); + printf("CHANGE LAYER 29;\n"); // tStop + printf("CIRCLE 0 (%.4f %.4f) (%.4f %.4f);\n", grid_val*column, grid_val*cntrow, grid_val*column + SMD_diameter/2+MaskRestring, grid_val*cntrow); + if (CreamDiameter) { + printf("CHANGE LAYER 31;\n"); // tCream + printf("CIRCLE 0 (%.4f %.4f) (%.4f %.4f);\n", grid_val*column, grid_val*cntrow, grid_val*column + CreamDiameter/2, grid_val*cntrow); + } + } + printf("GROUP (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (>%.4f %.4f);\n", + -1.0 * grid_val, -1.0 * grid_val, + grid_val * (maxcolumn+1), -1.0 * grid_val, + grid_val * (maxcolumn+1), grid_val * (cntrow+1), + -1.0 * grid_val, grid_val * (cntrow+1), + -1.0 * grid_val, -1.0 * grid_val ); + + real centerx, centery; + centerx = (grid_val * (maxcolumn+1)) / 2; + centery = (grid_val * (cntrow+1)) / 2; + printf("MOVE (>%.4f %.4f) (0 0);\n", centerx, centery); + + printf("SET WIRE_BEND 0;\n"); + printf("CHANGE LAYER 21;\n"); + printf("WIRE .2032 (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + -pac_width /2 + package_wire_width, -pac_width /2 + package_wire_width, + pac_width /2 - package_wire_width, pac_width /2 - package_wire_width, + -pac_width /2 + package_wire_width, -pac_width /2 + package_wire_width); + // *** mark edge on pin 1 *** + printf("SET WIRE_BEND 2;\n"); + printf("WIRE .2032 (%.4f %.4f) (%.4f %.4f);\n", + -pac_width /2 + package_wire_width, pac_width /2 - grid_val, + -pac_width /2 + grid_val, pac_width /2 - package_wire_width); + + printf("CHANGE SIZE %.2f;\n", textsize); + printf("CHANGE LAYER 25;\n"); + printf("TEXT >NAME (%.4f %.4f);\n", + -pac_width/2, pac_width/2 + textsize*0.5); + + printf("CHANGE LAYER 27;\n"); + printf("TEXT >VALUE (%.4f %.4f);\n", + -pac_width/2, -pac_width/2 - textsize*1.5); + printf("%s\n", Source_file); + } + } + return; +} + + +int device_exist(string dev_name) { + library(L) { + L.devicesets(DEV) { + if (DEV.name == dev_name) { + return 1; + } + } + } + return 0; +} + + +string makeSymbol_Device(string Libfile, int pin_layout, string pac_name, int use_pad_names, string pad_prefix) { + symbol_file = filesetext(Libfile, "~symbol.scr"); + device_file = filesetext(Libfile, "~device.scr"); + string partlib = "EDIT " + symbol_name + ".sym;\nGRID INCH 0.1 1;\n"; + partlib += "CHANGE LENGTH SHORT;\n"; // 2010-05-25 new PIN legth + partlib += "CHANGE DIRECTION PAS;\n"; // ** default direction + + string devicelib = "EDIT " + device_name + ".dev;\n"; + devicelib += "GRID INCH 0.1 1 ON;\n"; + devicelib += "PACKAGE " + pac_name + " '" + pac_variant_name + "';\n"; + devicelib += "Technology '';\n"; + if (device_exist(device_name)) return "Device " + device_name + "exist!\nPlease use a different name for tis device."; // 2008-11-07 check existing devices and return error + else { + // 2008-11-07 generate always description + sprintf(Source_file, "DESCRIPTION '%s%s

    \\n\\\nAuto generated by %s %s
    \\n\\\nSource: %s';\n", + filesetext(filename(infile), ""), editMode, filename(argv[0]), Revision, filename(infile) ); + devicelib += Source_file; + devicelib += "Prefix 'IC';\n"; + devicelib += "Value Off;\n"; + devicelib += "ADD " + symbol_name + " 'G$1' 0 NEXT (0 0);\n"; + } + int i; + int index[]; + string last_pin; + suffix_cnt = 0; + sort( n_pins, index, pins); + for (i = 0; i < n_pins; i++) { + if (last_pin != pins[index[i]]) { + last_pin = pins[index[i]]; + suffix_cnt = 0; + } + else { + suffix_cnt++; + } + suffix[index[i]] = suffix_cnt; + } + real x = 0; + real y = 0; + real dx = 0; + real dy = -.1; + int terminal_i = 1; + int s2 = 0; + int s3 = 0; + int s4 = 0; + int rot = 0; + real spacer = .8; + + if (pin_layout == k_stripe) { + s2 = (n_pins / maxStripeCnt) / 2; + s3 = maxStripeCnt / 2; + x = -1.0 * s2 + -0.2; + y = 0.1 * s3; + dx = 0.0; + dy = -0.1; + } + else if (pin_layout == k_quad) { + y = (.1 * n_pins / 4) + spacer; + s2 = (n_pins / 4) + 1; + s3 = (2 * n_pins / 4) + 1; + s4 = (3 * n_pins / 4) + 1; + } + else if (pin_layout == k_dual) { + y = .1 * n_pins / 2; + s2 = (n_pins / 2) + 1; + } + else if (pin_layout == k_dual2) { + y = .1 * n_pins / 2; + } + else { + y = .1 * n_pins; + } + + for (i = 0; i < n_pins; i++) { + int pin_num = i + 1; + if (suffix[i]) { + sprintf( pin_names[i], "%s@%d", pins[i], suffix[i]); + pins[i] = pin_names[i]; + } + string pin_name = pin_names[i]; + string pad_name = ""; + + if (use_pad_names) { + if (use_pad_names == useBGA) pad_name = pad_names[i]; // use Padname as is for BGA + else if (use_pad_names == usePACwithPrefix) pad_name = pad_names[i]; // use Padname for existing Package with Prefix + devicelib += "CONNECT 'G$1." + pin_name + "' '" + pad_name + "';\n"; + } + else { + string pin_num_str; + sprintf(pin_num_str, "%u", pin_num); // genberate padname by number + devicelib += "CONNECT 'G$1." + pin_name + "' '" + pad_prefix + pin_num_str + "';\n"; + } + + if (check_Coordinate(pin_name, x, y, "INCH", e_symbol)) { + string ck; + sprintf(ck, "Pin %s, coordinate out of range (%.4f %.4f)", pin_name, x, y); + return ck; + } + + string x_str; + string y_str; + sprintf(x_str, "%.4f", round(x * 10) / 10); // set to 0.1 Inch Grid 2006-06-01 + sprintf(y_str, "%.4f", round(y * 10) / 10); + + partlib += "PIN '" + pin_name + "' " + Pin_Direc[i] + " (" + x_str + " " + y_str + ");\n"; + if (rot > 0) partlib += "ROTATE (" + x_str + " " + y_str + ");\n"; + if (rot > 1) partlib += "ROTATE (" + x_str + " " + y_str + ");\n"; + if (rot > 2) partlib += "ROTATE (" + x_str + " " + y_str + ");\n"; + + x += dx; + y += dy; + terminal_i ++; + + if (pin_layout == k_stripe) { + if (terminal_i > maxStripeCnt) { // 2008-12-03 correct counts + terminal_i = 1; + s2--; + x = -1.0 * s2 + -0.1; // PIN leght SHORT 2010-05-25, -0.2 for legth MIDDLE + y = 0.1 * s3; + } + } + else if (pin_layout == k_quad) { + if (terminal_i == s2) { + dy = 0; + dx = .1; + x = spacer + .1; + y = 0; + rot = 1; + } + else if (terminal_i == s3) { + dy = .1; + dx = 0; + x += spacer; + y = spacer + .1; + rot = 2; + } + else if (terminal_i == s4) { + dy = 0; + dx = -.1; + y += spacer; + x -= spacer + .1; + rot = 3; + } + } + else if (pin_layout == k_dual) { + if (terminal_i == s2) { + dy = .1; + dx = 0; + x = spacer * 3; + y = .1; + rot = 2; + } + } + else if (pin_layout == k_dual2) { + int terminal_row = (terminal_i - 1) / 2; + y = (.1 * n_pins / 2) - .1 * terminal_row; + if ((terminal_i % 2) == 1) { + x = 0; + rot = 0; + } + else { + x = spacer * 3; + rot = 2; + } + } + } + + real left = .1; // 0.2 for PIN legth MIDDLE 2010-05-25 + real bottom = 0; + real top = (.1 * n_pins) + .1; + real right = spacer * 1.5; + + if (pin_layout == k_stripe) { + ; // no frame for this symbol + } + else if (pin_layout == k_quad) { + left = 0.1; // 0.2 for PIN legth MIDDLE 2010-05-25 + bottom = 0.1; // 0.2 for PIN legth MIDDLE + top = (spacer * 2) + (.1 * n_pins / 4) - 0.0; // -0.1 for Pin legth MIDDLE + right = (spacer * 2) + (.1 * n_pins / 4) - 0.0; // -0.1 for Pin legth MIDDLE + } + else if ((pin_layout == k_dual) || (pin_layout == k_dual2)) { + top = (.1 * n_pins / 2) + .1; + right = (spacer * 3) - .1; // 0.2 for PIN legth MIDDLE 2010-05-25 + } + + real cx = ((right - left) / 2) + left - .1; // 0.2 for PIN legth MIDDLE 2010-05-25 + real cy = ((top - bottom) / 2) + bottom; + + if (pin_layout == k_single) { + cx = right - .4; + } + + string left_str; + string bottom_str; + string top_str; + string right_str; + string movexy05 = ""; + string name_x; + string name_y; + string value_x; + string value_y; + + if (pin_layout == k_stripe) { // place >NAME and >VALUE in stripe symbol + s2 = (n_pins / maxStripeCnt) / 2; + s3 = maxStripeCnt / 2; + x = -1.0 * s2; + y = 0.1 * s3; + + sprintf(name_x, "%.4f", x - 0.2); + sprintf(name_y, "%.4f", y + .2); + sprintf(value_x, "%.4f", x - 0.2); + sprintf(value_y, "%.4f", y + .1); + } + else { // set to 0.1 Inch Grid 2006-06-01 + sprintf(left_str, "%.4f", round(left * 10) / 10); + sprintf(bottom_str, "%.4f", round(bottom * 10) / 10); + sprintf(top_str, "%.4f", round(top * 10) / 10); + sprintf(right_str, "%.4f", round(right * 10) / 10); + // ** move Origin to center ** + sprintf(movexy05, "GROUP (-29.9 -29.9) (29.9 -29.9) (29.9 29.9) (-29.9 29.9) (>-29.9 -29.9);\nMOVE (>%.4f %.4f) (0 0);\n", + round(((left + right) / 2) * 10) / 10, + round(((bottom + top) / 2) * 10) / 10); + sprintf(name_x, "%.4f", round(cx * 10) / 10); + sprintf(name_y, "%.4f", round(cy * 10) / 10 + .05); + sprintf(value_x, "%.4f", round(cx * 10) / 10); + sprintf(value_y, "%.4f", round(cy * 10) / 10 - .1); + // place no frame on stripe symbol + partlib += "LAYER 94;\n"; + // change wire width 10mil 2010-02-15 + partlib += "WIRE 10mil (" + left_str + " " + bottom_str + ") (" + right_str + " " + bottom_str + ") (" + right_str + " " + top_str + ") (" + left_str + " " + top_str + ") (" + left_str + " " + bottom_str + ");\n"; + } + partlib += "CHANGE SIZE .07;\n"; + partlib += "LAYER 95;\n"; + partlib += "TEXT \'>NAME\' (" + name_x + " " + name_y + ");\n"; + partlib += "LAYER 96;\n"; + partlib += "TEXT \'>VALUE\' (" + value_x + " " + value_y + ");\n"; + partlib += "LAYER 94;\n"; + partlib += movexy05; + partlib += "WINDOW FIT;\n"; + + output(symbol_file, "wtD") { + printf("%s", partlib); + } + + output(device_file, "wtD") { + printf("%s", devicelib); + } + return ""; +} + + +string viewPadname(string t, string pacname) { // 2008-11-07 return 0 or error, Cancel = check padname + int sel; + if (t) { + dlgDialog("Make Device Package") { + dlgLabel("Pads not found in parsed list."); + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel(pacname + ".PAC"); + dlgTextView(t); + } + dlgVBoxLayout { + dlgLabel("Parsed from text"); + dlgListView("Pads", pad_names, sel); + } + } + if (packageparameter_accept) { + dlgLabel(" Checke Pad-Name if Prefix used."); + dlgLabel(" Possibly delete PAD Prefix in BSDL-Pad Name."); + dlgLabel(" Use Text Options [Rename PAD] to rename."); + } + dlgHBoxLayout { + dlgPushButton("+OK") { dlgAccept(); if (t) t = "Check pad name(s) in package " + pacname; } + dlgPushButton("-Cancel") { dlgReject(); return "Check pad name(s) in package " + pacname; } + dlgSpacing(20); + dlgLabel(" Package is a BGA "); + dlgPushButton("Accept") { dlgAccept(); t = ""; } + dlgStretch(1); + } + }; + } + return t; +} + + +string check_Padname(string name) { + for (int i = 0; i < n_pins; i++) { + if (name == pad_names[i]) { + name = ""; + break; + } + } + if (name) name += "\n"; + return name; +} + + +string getPackagePadCount(string pac_name) { + checkPadname = ""; + int pcount = 0; + string s; + sprintf(s, " NOT found"); + library(L) { + L.packages(PAC) { + if (PAC.name == pac_name) { + status("count pads " + pac_name); + PAC.contacts(C) { + checkPadname += check_Padname(C.name); + used_pad_number[pcount] = C.name; // 2008-11-07 + pcount++; + } + sprintf(s, "%d Contacts", pcount); + break; + } + } + } + return s; +} + + +// 2008-11-07 if make package with bsdl. +// Check used all pad-names in list with on generated Package. +// Vergleiche padnamen des bsdl file mit generierten padnamen aus package. +// Alle Pad-Namen in der Liste müssen im Package vorkommen. +// +string check_pin_pad_list(int n, int p) { + status("check pads in used package"); + string ti = tinfo; + tinfo = "Please wait, check pad names!"; + dlgRedisplay(); + string tp; + int x = 0; + for (x = 0; x < n; x++) { + int notfound = 1; + for (int i = 0; i < p; i++) { + if (used_pad_number[i] == pad_names[x]) { + notfound = 0; + break; + } + } + if (notfound) tp += pad_names[x]+"\n"; + } + tinfo = ti; + dlgRedisplay(); + if (tp) return "Pads not found in Package\nCheck pad name in parsed list by 'Text Options'!\n"+tp; + return tp; +} + + +int check_exist_sym(string symname) { + int exist = 0; + library(L) { + L.symbols(SYM) { + if (SYM.name == symname) return 1; + } + } + return 0; +} + + +int getSymbolPinCount(string sym_name) { + int scount = -1; + library(L) { + L.symbols(SYM) { + if (SYM.name == sym_name) { + SYM.pins(P) scount++; + scount++; + break; + } + } + } + return scount; +} + + +string getPackagePadPrefix(string pac_name) { + library(L) { + L.packages(PAC) { + if (PAC.name == pac_name) { + PAC.contacts(C) { + string pad_name = C.name; + int i = strstr(pad_name, "1"); + if (i != -1) { + string prefix = strsub(pad_name, 0, i); + return prefix; + } + } + } + } + } + return "P$"; +} + + +// ** collect Packages ** +void coll_packages(void) { + packages[0] = " "; + n_packages = 1; + library(L) { + L.packages(PAC) { + packages[n_packages++] = PAC.name; + } + } + return; +} + + +// ***** change n.ts character to new character ***** +void change_char_text(char text_char, char to_char, int counter) { + int cc; + int cnt = 0; + for ( int n = 0; n < strlen(text); n ++) { + if (text[n] == text_char) { + if (cnt == counter) { + text[n] = to_char; + cc++; + cnt = 0; + } + else if (counter) cnt++; + } + } + sprintf(tinfo, "%d characters changed.", cc); + return; +} + + +string check_space(string s) { + int a; + for (int i = 0; i < strlen(s); i++) { + a = (isgraph(s[i])); + if (a) break; + } + if (a) return s; + else return ""; +} + + + +void delete_x_line(int start, int x) { + if (x < 2) { + dlgMessageBox("!The value of the counter must be greater 1", "Ok"); + tinfo = "It is absurd to delete all lines! Check the value of x. line"; + return; + } + if (start > 1) start--; // 2009-02-18 counts from zero + string xt[]; + int cntst = strsplit(xt, text, '\n'); + text = ""; + int cdel = 0; + for (int s = start; s < cntst; s+=x) { + xt[s] = ""; + } + for (int n = 0; n < cntst; n++) { + if (xt[n]) text += xt[n] + "\n"; + else cdel++; + } + text[strlen(text)-1] = 0; + if (x > 2) sprintf(tinfo, "%d %d. lines deleted", cdel, x); + else sprintf(tinfo, "%d second lines deleted", cdel); + return; +} + + +void delete_empty_lines(void) { + if(!text) { + tinfo = "List is empty!"; + return; + } + string st[]; + int cntst = strsplit(st, text, '\n'); + text = ""; + int cc = 0; + for (int n = 0; n < cntst; n++) { + st[n] = check_space(st[n]); + if (st[n]) text += st[n] + "\n"; + else cc++; + } + text[strlen(text)-1] = 0; + sprintf(tinfo, "%d empty lines deleted", cc); + return; +} + + +void delete_column(int del_column) { // 2008-04-02 + int cntdelcol = 0; + if (!text) { + tinfo = "List is empty!"; + return; + } + if (!del_column) { + tinfo = "First set the number of column to delete!"; + return; + } + string lines[]; + string columns[]; + int cntl = strsplit(lines, text, '\n'); + text = ""; + for (int n = 0; n < cntl; n++) { + int cntc = strsplit(columns, lines[n], Word_separator); + if (cntc > del_column) cntdelcol++; + columns[del_column -1] = ""; + lines[n] = ""; + for (int c = 0; c < cntc; c++) { + lines[n] += columns[c]; + if (c < cntc -1 && columns[c]) lines[n] += " "; + } + text += lines[n] += "\n"; + } + tinfo = ""; // 2011-05-23 + if (cntdelcol) { + sprintf(tinfo, "%d column deleted", cntdelcol); + } + return; +} + + +void sorting_pad(int cnt) { + numeric string sort_pad[], sort_pin[], sort_dir[]; + int index[], i; + for (i = 0; i < cnt; i++) { + pins[i] = pads[i]; + sort_pin[i] = pin_names[i]; + sort_pad[i] = pad_names[i]; + sort_dir[i] = Pin_Direc[i]; + } + sort(cnt, index, sort_pad, sort_pin); + for (i = 0; i < cnt; i++) { + pin_names[i] = sort_pin[index[i]]; + pad_names[i] = sort_pad[index[i]]; + Pin_Direc[i] = sort_dir[index[i]]; + pins[i] = pin_names[i]; + pads[i] = pin_names[i]; + } + return; +} + + +void sorting_pin(int cnt) { + numeric string sort_pad[], sort_pin[], sort_dir[]; + int index[], i; + for (i = 0; i < cnt; i++) { + pins[i] = pads[i]; + sort_pin[i] = pin_names[i]; + sort_pad[i] = pad_names[i]; + sort_dir[i] = Pin_Direc[i]; + } + sort(cnt, index, sort_pin, sort_pad); + for (i = 0; i < cnt; i++) { + pin_names[i] = sort_pin[index[i]]; + pad_names[i] = sort_pad[index[i]]; + Pin_Direc[i] = sort_dir[index[i]]; + pins[i] = pin_names[i]; + pads[i] = pin_names[i]; + } + return; +} + + +string check_pad_sorting(int cnt, int mkpac) { // 2009-02-18 + int sortflagPAD = 0; + string RESULT = ""; + if (!mkpac && use_pad_names == useBGA) sortflagPAD = 1; // option for use existing BGA 2009-03-09 + + else if (!mkpac && package_name) { + for (int n1 = 1; n1 <= cnt; n1++) { + int found = 0; + for (int n = 0; n < cnt; n++) { + if (strtol(pad_names[n]) == n1) { + found = 1; + break; + } + } + if (!found) { + sortflagPAD++; + string h; + sprintf(h, "Missing Pad number %d !", n1); // 2011-05-23 + if (dlgMessageBox(h, "OK", "Cancel") != 0) return h; + } + } + if (sortflagPAD) { + dlgDialog("Make PAC/SYM/DEV") { + dlgLabel("To generate a correct symbol by count pad name, the list must sorted by pad number!"); + dlgLabel("Check if Pin/Pad/Direction list sorted by PADs?"); + dlgHBoxLayout { + dlgPushButton("Yes/Ignore") { dlgAccept(); RESULT = ""; } + dlgPushButton("Sort") { + sorting_pad(cnt); + gen_viewlist(cnt); + dlgAccept(); + RESULT = "Check PAD list"; + } + dlgPushButton("Cancel") { dlgReject(); RESULT = "CANCEL"; } + } + }; + } + } + return RESULT; +} + + +string clear_z(string s) { // delete leading zero + parsed_pins = s; + if (isalpha(s[0]) && isalpha(s[1]) && s[2] == '0') s = strsub(s, 0, 2) + strsub(s, 3); + else if (isalpha(s[0]) && s[1] == '0') s = strsub(s, 0, 1) + strsub(s, 2); + else if (s[0] == '0') s = strsub(s, 1); + return s; +} + + +void clear_leading_z(int cnt) { + for (int i = 0; i < cnt; i++) { + pad_names[i] = clear_z(pad_names[i]); + } + gen_viewlist(cnt); + parsed_pins = "Finsh clear leading zeros"; + return; +} + + +int del_double_pad(int cnt) { // 2008-04-02 delete double pad names if parsed from text + sorting_pad(cnt); + string npad = ""; + string npin_names[]; + string npad_names[]; + string nPin_Direc[]; + + int newcnt = 0; + for (int i = 0; i < cnt; i++) { + if (npad == pad_names[i]) { + ; // is double + } + else { + npad = pad_names[i]; + npin_names[newcnt] = pin_names[i]; + npad_names[newcnt] = pad_names[i]; + nPin_Direc[newcnt] = Pin_Direc[i]; + newcnt++; + } + } + sprintf(parsed_pins, "Finsh delete double (%d) pad name, new count %d", cnt-newcnt, newcnt); + for (int n = 0; n < newcnt; n++) { + pin_names[n] = npin_names[n]; + pad_names[n] = npad_names[n]; + Pin_Direc[n] = nPin_Direc[n]; + } + cnt = newcnt; + gen_viewlist(cnt); + return cnt; +} + + +// 2008-11-07 rename pad in parsed list +void rename_pad(int cnt, string search, string replace) { + int cntrenamed = 0; + if (!search) { + dlgMessageBox("First define search string!
    See Text Option:
    [ Replace ] character string ..... with ....", "OK"); + return; + } + if (search == replace) { + dlgMessageBox("Search string = Replace string, please change!
    See option:
    [ Replace ] character string .... with .....", "OK"); + return; + } + for ( int n = 0; n < cnt; n++) { + int pos = strstr(pad_names[n], search); + if (pos >= 0) { + pad_names[n] = strsub(pad_names[n], 0, pos) + replace + strsub(pad_names[n], pos+strlen(search) ); + cntrenamed++; + } + } + gen_viewlist(cnt); + sprintf(parsed_pins, "%d pads renamed", cntrenamed); + return; +} + + +// 2011-04-01 rename pin in parsed list +void rename_pin(int cnt, string search, string replace) { + int cntrenamed = 0; + if (!search) { + dlgMessageBox("First define search string!
    See Text Option:
    [ Replace ] character string ..... with ....", "OK"); + return; + } + if (search == replace) { + dlgMessageBox("Search string = Replace string, please change!
    See option:
    [ Replace ] character string .... with .....", "OK"); + return; + } + for ( int n = 0; n < cnt; n++) { + int pos = strstr(pin_names[n], search); + if (pos >= 0) { + pin_names[n] = strsub(pin_names[n], 0, pos) + replace + strsub(pin_names[n], pos+strlen(search) ); + cntrenamed++; + } + } + gen_viewlist(cnt); + sprintf(parsed_pins, "%d pins renamed", cntrenamed); + return; +} + + +// 2008-07-03 +void number_pads(int cnt) { + if (is_bsdl) { // 2011-04-01 + dlgMessageBox("Do not numbering pads if used a BSDL file", "OK"); + return; + } + for ( int n = 0; n < cnt; n++) { + sprintf(pad_names[n], "%d", n+1); + } + gen_viewlist(cnt); + return; +} + + +// 2008-07-03 +void set_Pin_Direction(int cnt) { + int setdir = 0; + dlgDialog("Set PIN-Directon") { + dlgHBoxLayout { + dlgGroup("Direction") { + dlgRadioButton("NC", setdir); + dlgRadioButton("IN", setdir); + dlgRadioButton("OUT", setdir); + dlgRadioButton("IO", setdir); // 2011-09-20 V6 use IO + dlgRadioButton("OC", setdir); + dlgRadioButton("PWR", setdir); + dlgRadioButton("PAS", setdir); + dlgRadioButton("HIZ", setdir); + dlgRadioButton("SUP", setdir); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("-Cancel") { dlgReject(); return; } + dlgStretch(1); + } + }; + for ( int n = 0; n < cnt; n++) { + sprintf(Pin_Direc[n], "%s", Pin_Dir[setdir]); + } + gen_viewlist(cnt); + return; +} + + +string ch_dir(string dir) { + string s[]; + strsplit(s, dir, '\t'); + if (!s[1]) s[1] = s[0]; + int psel = -1; + dlgDialog("New Direction") { + dlgHBoxLayout { + dlgLabel(s[0]); + dlgLabel(" &new "); + dlgListView("Dir.", Pin_Dir, psel) { s[1] = Pin_Dir[psel]; dlgAccept(); } // 2011-05-23 + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + }; + return s[0]+"\t"+s[1]; +} + + +// ** change direction of pin in parsed list ** 2008-04-02 +void change_dir(int cnt) { + string ndir[]; + int cntdirection = 0; + int found = 0; + for (int n = 0; n < cnt; n++) { + found = 0; + for (int i = 0; i < cntdirection; i++) { + if (ndir[i] == Pin_Direc[n]) { + found = 1; + break; + } + } + if (!found) { + ndir[cntdirection] = Pin_Direc[n]; + cntdirection++; + } + } + string info; + sprintf(info, "found %d directions", cntdirection); + int sel; + for (int i = 0; i < cntdirection; i++) { + ndir[i] += "\t" + ndir[i]; + } + int Result = dlgDialog("Change Direction") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel(info); + dlgListView("Direction\tnew", ndir, sel) ndir[sel] = strupr(ch_dir(ndir[sel])); // 2011-05-23 + } + dlgLabel(Existdir); // 2011-05-23 + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + }; + if (!Result) return; + for (n = 0; n < cnt; n++) { + string s[]; + for (int i = 0; i < cntdirection; i++) { + strsplit(s, ndir[i], '\t'); + if (Pin_Direc[n] == s[0]) { + Pin_Direc[n] = s[1]; + break; + } + } + } + gen_viewlist(cnt); + return; +} + + +// *** generate package for NOT BGA *** +void gen_package(string PacName) { + real mpad_stand_out = pad_stand_out; // 2005-12-01 save parameter for display + real mypad_length = ypad_length; + real mxpad_length = xpad_length; + real center_offset; + int middle = cnt_side % 2; + if (middle) { + center_offset = cnt_side / 2 * basic_pad_grid; + } + else { + center_offset = cnt_side / 2 * basic_pad_grid - basic_pad_grid / 2; + } + real pin_length = (xA_pac - xD_pac) / 2; + + string h; + real k; // koordinate for Pad line + real xcoord, ycoord; + string SMDdirection; + string pad_rect; + int padnumber = 1; + sprintf(h, "#2010-09-24\nEDIT %s.PAC;\n", PacName); // 2005-11-03 + paccmd += h; + sprintf(h, "GRID %s %.4f ON;\n", genpac_grid, grid_val/2); // 2008-11-07 set actual grid to generate package + paccmd += h; + sprintf(h, "SET WIRE_BEND 2;\n"); + paccmd += h; + sprintf(h, "CHANGE ROUNDNESS %.0f;\n", roundness_restring); + paccmd += h; + sprintf(h, "CHANGE LAYER 1;\n"); + paccmd += h; + + + // ** make SMD or PAD ** 2005-12-01 + if (smd_pad) { + pad_stand_out = 0; // no offset from mechanical-pin to pad-drill + ypad_length = 0; + sprintf(h, "CHANGE DRILL %.4f;\n", xpad_length); // PAD drill diameter + paccmd += h; + sprintf(h, "CHANGE SHAPE %s;\n", PadShape[pad_shape]); + paccmd += h; + sprintf(h, "CHANGE DIAMETER %.4f;\n", xpad_length + roundness_restring); + paccmd += h; + xpad_length = 0; // 2005-12-01 + } + else { + sprintf(h, "CHANGE SMD %.4f %.4f;\n", SMD_diameter, SMD_diameter); + paccmd += h; + } + + switch (pad_layout) { // check Package PAD placement + case 0 : // ### quad package with Pin 1 on TOP of LEFT side (corner) ### + for (int q = 0; q < 4; q++) { + for (int n = 0; n < cnt_side; n++) { + k = n * basic_pad_grid - center_offset; + switch(q) { + case 0 : // 1. quadrant 1.-Pad TOP of LEFT side + sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length); + ycoord = k * -1; + xcoord = -xA_pac / 2 - pad_stand_out + xpad_length/2; + pin_length = (xA_pac - xD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + -xA_pac/2, ycoord - pad_width/2, + -xA_pac/2 + pin_length, ycoord + pad_width/2 + ); + break; + + case 1 : // 2. quadrant + sprintf(SMDdirection, " %.4f %.4f ", ypad_length, xpad_length); + xcoord = k; + ycoord = -xA_pac / 2 - pad_stand_out + xpad_length/2; + pin_length = (yA_pac - yD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + xcoord - pad_width/2, -yA_pac/2, + xcoord + pad_width/2, -yA_pac/2 + pin_length + ); + break; + + case 2 : // 3. quadrant + sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length); + xcoord = xA_pac / 2 + pad_stand_out - xpad_length/2; + ycoord = k; + pin_length = (xA_pac - xD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + xA_pac/2, ycoord - pad_width/2, + xA_pac/2 - pin_length, ycoord + pad_width/2 + ); + break; + + case 3 : // 4. quadrant + sprintf(SMDdirection, " %.4f %.4f ", ypad_length, xpad_length); + xcoord = k * -1; + ycoord = xA_pac / 2 + pad_stand_out - xpad_length/2; + pin_length = (yA_pac - yD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + xcoord - pad_width/2, yA_pac/2, + xcoord + pad_width/2, yA_pac/2 - pin_length + ); + break; + + } + + if (smd_pad) { // 2005-12-01 + sprintf(h, "PAD '%d' (%.4f %.4f);\n", padnumber, xcoord, ycoord); + } + else { + sprintf(h, "SMD %s '%d' (%.4f %.4f);\n", SMDdirection, padnumber, xcoord, ycoord); + } + paccmd += h; + paccmd += pad_rect; + sprintf(used_pad_number[padnumber], "%d", padnumber); // 2008-11-07 for check package pad names + padnumber++; + } + } + sprintf(h, "LAYER 21;\nWIRE .2032 (%.4f %.4f) (%.4f %.4f);\n", + -xD_pac/2 + package_wire_width, + yD_pac/2 - mark_length, + -xD_pac/2 + mark_length, + yD_pac/2 - package_wire_width + ); + paccmd += h; + break; + + case 1 : // ### quad package with Pin 1 on MIDDLE of LEFT side ### + for (int qm = 0; qm < 5; qm++) { + for (int n = 0; n < cnt_side; n++) { + k = n * basic_pad_grid - center_offset; + switch(qm) { + case 0 : // 1. quadrant 1.-Pad MIDDLE of LEFT side + if (n >= cnt_side/2 - 0.5) { + sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length); + xcoord = -xA_pac / 2 - pad_stand_out + xpad_length/2; + ycoord = k * -1; + pin_length = (xA_pac - xD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + -xA_pac/2, ycoord - pad_width/2, + -xA_pac/2 + pin_length, ycoord + pad_width/2 + ); + } + else SMDdirection = ""; // ** clear, do not genearate line ** + break; + + case 1 : // 2. quadrant + sprintf(SMDdirection, " %.4f %.4f ", ypad_length, xpad_length); + xcoord = k; + ycoord = -xA_pac / 2 - pad_stand_out + xpad_length/2; + pin_length = (yA_pac - yD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + xcoord - pad_width/2, -yA_pac/2, + xcoord + pad_width/2, -yA_pac/2 + pin_length + ); + break; + + case 2 : // 3. quadrant + sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length); + xcoord = xA_pac / 2 + pad_stand_out - xpad_length/2; + ycoord = k; + pin_length = (xA_pac - xD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + xA_pac/2, ycoord - pad_width/2, + xA_pac/2 - pin_length, ycoord + pad_width/2 + ); + break; + + case 3 : // 4. quadrant + sprintf(SMDdirection, " %.4f %.4f ", ypad_length, xpad_length); + xcoord = k * -1; + ycoord = yA_pac / 2 + pad_stand_out - xpad_length/2; + pin_length = (yA_pac - yD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + xcoord - pad_width/2, yA_pac/2, + xcoord + pad_width/2, yA_pac/2 - pin_length + ); + break; + + case 4 : // 1. quadrant pad right side to middle + if (n < cnt_side/2 - 0.5) { + sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length); + ycoord = k * -1; + xcoord = -xA_pac / 2 - pad_stand_out + xpad_length/2; + pin_length = (xA_pac - xD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + -yA_pac/2, ycoord - pad_width/2, + -yA_pac/2 + pin_length, ycoord + pad_width/2 + ); + } + else SMDdirection = ""; // ** clear, do not genearate line ** + break; + } + if (SMDdirection) { + if (smd_pad) { // 2005-12-01 + sprintf(h, "PAD '%d' (%.4f %.4f);\n", padnumber, xcoord, ycoord); + } + else { + sprintf(h, "SMD %s '%d' (%.4f %.4f);\n", SMDdirection, padnumber, xcoord, ycoord); + } + paccmd += h; + paccmd += pad_rect; + sprintf(used_pad_number[padnumber], "%d", padnumber); // 2008-11-07 for check package pad names + padnumber++; + } + } + } + sprintf(h, "LAYER 21;\nCIRCLE .2032 (%.4f 0) (%.4f 0);\n", + -xD_pac/2 + xpad_length + mark_length/2, + -xD_pac/2 + xpad_length + mark_length + ); + paccmd += h; + break; + + case 2 : // dual in line package + for (int qd = 0; qd < 2; qd++) { + for (int n = 0; n < cnt_side; n++) { + k = n * basic_pad_grid - center_offset; + switch(qd) { + case 0 : // 1. quadrant + sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length); + ycoord = k * -1; + xcoord = -xA_pac / 2 - pad_stand_out + xpad_length/2; + pin_length = (xA_pac - xD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + -xA_pac/2, ycoord - pad_width/2, + -xA_pac/2 + pin_length, ycoord + pad_width/2 + ); + break; + + case 1 : // 2. quadrant + sprintf(SMDdirection, " %.4f %.4f ", xpad_length, ypad_length); + xcoord = xA_pac / 2 + pad_stand_out - xpad_length/2; + ycoord = k; + pin_length = (xA_pac - xD_pac) / 2; + sprintf(pad_rect, "LAYER 51;\nRECT (%.4f %.4f) (%.4f %.4f);\n", + xA_pac/2, ycoord - pad_width/2, + xA_pac/2 - pin_length, ycoord + pad_width/2 + ); + break; + } + if (smd_pad) { // 2005-12-01 + sprintf(h, "PAD '%d' (%.4f %.4f);\n", padnumber, xcoord, ycoord); + } + else { + sprintf(h, "SMD %s '%d' (%.4f %.4f);\n", SMDdirection, padnumber, xcoord, ycoord); + } + paccmd += h; + paccmd += pad_rect; + sprintf(used_pad_number[padnumber], "%d", padnumber); // 2008-11-07 for check package pad names + padnumber++; + } + } + sprintf(h, "LAYER 21;\nARC CCW .2032 (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + -mark_length, + yD_pac/2 - package_wire_width, + mark_length, + yD_pac/2 - package_wire_width, + mark_length, + yD_pac/2 - package_wire_width + ); + paccmd += h; + break; + } + + sprintf(h, "SET WIRE_BEND 0;\n"); + paccmd += h; + sprintf(h, "CHANGE LAYER 21;\n"); + paccmd += h; + sprintf(h, "WIRE .2032 (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + -xD_pac /2 + package_wire_width, + -yD_pac /2 + package_wire_width, + xD_pac /2 - package_wire_width, + yD_pac /2 - package_wire_width, + -xD_pac /2 + package_wire_width, + -yD_pac /2 + package_wire_width + ); + paccmd += h; + // mark edge on pin 1 + sprintf(h, "SET WIRE_BEND 2;\n"); + paccmd += h; + sprintf(h, "CHANGE SIZE %.2f;\n", textsize); + paccmd += h; + sprintf(h, "CHANGE LAYER 25;\n"); + paccmd += h; + sprintf(h, "TEXT >NAME (%.4f %.4f);\n", + -xA_pac/2, yA_pac/2 + textsize*0.5); + paccmd += h; + sprintf(h, "CHANGE LAYER 27;\n"); + paccmd += h; + sprintf(h, "TEXT >VALUE (%.4f %.4f);\n", + -xA_pac/2, -yA_pac/2 - textsize*1.5); + paccmd += h; + sprintf(h, "DESCRIPTION '%s

    \\n\\\nAuto generated by %s %s
    \\n';\n", + PacName, filename(argv[0]), Revision ); + paccmd += h; + + pad_stand_out = mpad_stand_out; // 2005-12-01 + ypad_length = mypad_length; + xpad_length = mxpad_length; + return; +} + + +void display_error(string er) { // 2008-11-07 display error text/messages + dlgDialog(filename(argv[0])) { + dlgHBoxLayout dlgSpacing(300); + dlgLabel("Errors"); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgTextView(er); + } + dlgHBoxLayout { + dlgPushButton("Back") dlgAccept(); + dlgPushButton("Cancel") { dlgReject(); exit(-2); } + dlgStretch(1); + } + }; +} + + +int checkSymbolName(string Sname) { // 2009-11-24 + library(L) L.symbols(S) { + if (S.name == Sname) { + return 1; + } + } + return 0; +} + + +int checkPackageName(string Pname) { // 2009-11-24 + library(L) L.packages(P) { + if (P.name == Pname) { + return 1; + } + } + return 0; +} + + +int checkDeviceName(string DSname) { // 2009-11-24 + library(L) L.devicesets(DS) { + if (DS.name == DSname) { + return 1; + } + } + return 0; +} + + +// Generate BGA-Pad-List to generate only GBA package 2009-10-16 +void genBGAlist(int x, int y) { + int existnpadname = 0; + do { + existnpadname++; + } while(bga_pad_name[existnpadname]); + string bga1 = ""; + string bga2 = bga_pad_name[0]; + string s; + int n = 0; + for (int ny = 0; ny < y; ny++) { + for (int nx = 0; nx < x; nx++) { + if (ny >= existnpadname) { + int firstcolumn = ny / existnpadname; + if (firstcolumn) { + bga2 = bga_pad_name[ny - firstcolumn*(existnpadname)]; + bga1 = bga_pad_name[firstcolumn-1]; + } + else bga2 = bga_pad_name[ny]; + } + else bga2 = bga_pad_name[ny]; + sprintf(pins_pads_direc[n], " \t%s%s%d\t ", bga1, bga2, nx+1); + sprintf(pad_names[n],"%s%s%d", bga1, bga2, nx+1); + n++; + } + } + pins_pads_direc[n] = ""; // clear last line in array + n_pins = x*y; // pins "parsed"! + sprintf(parsed_pins, "%d BGA pads generated", n_pins); + return; +} + + +void genBGA_PadList(void) { // 2009-10-16 + dlgDialog("Generate BGA pad list") { + if (!is_bsdl) { + dlgLabel("Generate PAD list without a BSDL file to autogenerate a BGA package."); + dlgHBoxLayout { + dlgGridLayout { + dlgCell(0,0) dlgLabel("pad lines "); + dlgCell(0,1) dlgIntEdit(cntBGApadY, 1 , 500); + dlgCell(1,0) dlgLabel("pads in row "); + dlgCell(1,1) dlgIntEdit(cntBGApadX, 1 ,500); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+OK") { dlgAccept(); only_generate_bga = 1; genBGAlist(cntBGApadX, cntBGApadY); } + dlgPushButton("-CANCEL") dlgReject(); + dlgStretch(1); + } + } + else { + dlgLabel("Can not use this option, while bsdl file is loaded!"); + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgStretch(1); + } + } + }; + return; +} + + +// Generate Pad-List to generate only package 2011-03-07 +void genPADlist(int x) { + string s; + for (int n = 0; n < x; n++) { + sprintf(pins_pads_direc[n], " \t%d\t ", n+1); + sprintf(pad_names[n],"%d", n+1); + } + pins_pads_direc[n] = ""; // clear last line in array + n_pins = x; // pins "parsed"! + sprintf(parsed_pins, "%d PAD generated", n_pins); + Pad_Count = x; + return; +} + + + +int genPAC_PadList(int cntPAD) { // 2011-03-07 + int cnt = cntPAD; // 2011-04-01 + dlgDialog("Generate PAC pad list") { + if (!is_bsdl) { + dlgLabel("Generate PAD list without a BSDL file to autogenerate a package."); + dlgHBoxLayout { + dlgGridLayout { + dlgCell(0,0) dlgLabel("Pad count "); // 2011-04-01 + dlgCell(0,1) dlgIntEdit(cnt, 1 , 1500); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+OK") { dlgAccept(); only_generate_pac = 1; genPADlist(cnt); cntPAD = cnt;} // 2011-04-01 + dlgPushButton("-CANCEL") dlgReject(); + dlgStretch(1); + } + } + else { + dlgLabel("Can not use this option, while bsdl file is loaded!"); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + } + }; + return cntPAD; +} + +void infohelp(string i) { // 2011-04-01 + dlgDialog("Help") { + dlgHBoxLayout dlgSpacing(800); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgTextView(i); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + + +void saveBGAconfig(void) { // 2011-09-20 + string bgacfg = filesetext(argv[0], "@bga.cfg"); + output(bgacfg, "wt") { + printf("%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%s", + m_pac_width, + m_grid_val, + m_SMD_diameter, + m_MaskRestring, + m_CreamDiameter, + genpac_grid + ); + } + return; +} + +void loadBGAconfig(void) { // 2011-09-20 + string bgacfg = filesetext(argv[0], "@bga.cfg"); + string files[]; + int bgacfgexist = fileglob(files, bgacfg); + if (!bgacfgexist) { + dlgMessageBox("!First save BGA config.", "OK"); + return; + } + string bgalines[]; + int bgalcnt = fileread(bgalines, bgacfg); + m_pac_width = strtod(bgalines[0]); + m_grid_val = strtod(bgalines[1]); + m_SMD_diameter = strtod(bgalines[2]); + m_MaskRestring = strtod(bgalines[3]); + m_CreamDiameter = strtod(bgalines[4]); + genpac_grid = bgalines[5]; + return; +} + + +void savePACconfig(void) { // 2011-09-20 + string paccfg = filesetext(argv[0], "@pac.cfg"); + output(paccfg, "wt") { + printf("%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%s\n%d\n%s\n%d\n%d", + xA_pac, + yA_pac, + xD_pac, + yD_pac, + mark_length, + pad_width, + basic_pad_grid, + pad_stand_out, + xpad_length, + ypad_length, + roundness_restring, + genpac_grid, + pad_layout, + round_restring, + pad_shape, + smd_pad + ); + } + return; +} + +void loadPACconfig(void) { // 2011-09-20 + string paccfg = filesetext(argv[0], "@pac.cfg"); + string files[]; + int paccfgexist = fileglob(files, paccfg); + if (!paccfgexist) { + dlgMessageBox("!First save PAC config", "OK"); + return; + } + string paclines[]; + int paclcnt = fileread(paclines, paccfg); + xA_pac = strtod(paclines[0]); + yA_pac = strtod(paclines[1]); + xD_pac = strtod(paclines[2]); + yD_pac = strtod(paclines[3]); + mark_length = strtod(paclines[4]); + pad_width = strtod(paclines[5]); + basic_pad_grid = strtod(paclines[6]); + pad_stand_out = strtod(paclines[7]); + xpad_length = strtod(paclines[8]); + ypad_length = strtod(paclines[9]); + roundness_restring = strtod(paclines[10]); + genpac_grid = paclines[11]; + pad_layout = strtol(paclines[12]); + round_restring = paclines[13]; + pad_shape = strtol(paclines[14]); + smd_pad = strtol(paclines[15]); + + switch(pad_layout) { + case 0 : packinfo = ""; + break; + case 1 : packinfo = ""; + break; + case 2 : packinfo = ""; + break; + } + switch(smd_pad) { + case 0 : packinfomess = ""; + round_restring = "Roundness %"; + break; + case 1 : round_restring = "Restring"; + switch(pad_shape) { + case PAD_SHAPE_SQUARE : packinfomess = ""; + break; + case PAD_SHAPE_ROUND : packinfomess = ""; + break; + case PAD_SHAPE_OCTAGON : packinfomess = ""; + break; + } + break; + } + return; +} + + +/*********************** main *************************/ +if (library) { + string rf[]; // 2008-11-07 check exist remember file + int nrf = fileglob(rf, filedir(argv[0])+rememberLastPathFile); + if (nrf) nrf = fileread(rememberBSDLpath, rf[0]); + + if (argv[1] == "edit-no-description") editMode = ""; + + int make_Symbol; + int make_Device; + + int exact_include = 0; + string del_line; + int delColumn = 1; + string st[]; + int separator_counter = 2; + string c_separator; + int start_line, x_line; + int cc; + tinfo = " "; + int do_copy = 1; + string search, replace; + coll_packages(); + package_name = ""; // default + + string PadCount; + sprintf(String_separator, "%c", Word_separator); + string cmd; + + int result = dlgDialog("Make Symbol / Device / Package ") { + dlgHBoxLayout { + dlgLabel("&File:"); + dlgStringEdit(infile); + dlgPushButton("&Browse") { + infile = dlgFileOpen("Select a File", rememberBSDLpath, "*.bsdl *.bsd *.bsm *.txt"); + if (infile) { // 23.03.2005 + // 2008-11-07 write last path in file to remember for next start + output(filedir(argv[0])+rememberLastPathFile, "wt") printf("%s", filedir(infile)); + readText(infile); + status(" "); // 2008-11-07 // clear display working + if (is_bsdl) { + make_Symbol = 1; + make_Device = 1; + make_Package = 1; + if (check_exist_pac(package_name)) make_Package = 0; // 2009-10-12 reset flag + m_pac_width = pac_width; + m_grid_val = grid_val; + m_SMD_diameter = SMD_diameter; + m_MaskRestring = MaskRestring; + m_CreamDiameter = CreamDiameter; + } + } + } + } + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(TextHigh); // 2011-04-01 + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(TextWidth); + dlgHBoxLayout { + dlgLabel("Text"); + dlgStretch(1); + dlgLabel(bsdl_package_name, 1); + } + dlgTextEdit(text); + } + dlgVBoxLayout { + dlgSpacing(25); // + dlgPushButton(" &<<-- Copy") { + if (is_bsdl) { + do_copy = 0; + if (dlgMessageBox("!BSDL file loaded. Are you sure you want to copy listing to text?", "Ok", "Cancel") == 0) do_copy = 1; + } + if (do_copy) { + text = ""; + for (int i = 0; i < n_pins; i++) { + if (i) text += "\n"; + text += pin_names[i] + String_separator + pad_names[i]; + if (Pin_Direc[i]) text += String_separator + Pin_Direc[i]; + } + //infile = ""; // delete filename while text is copy from list // 2008-11-07 use for DESCRIPTION + is_bsdl = 0; + delete_empty_lines(); + tinfo = "Text is a copy of pin/pad list."; + dlgRedisplay(); + } + } + dlgStretch(1); + dlgPushButton("S&ort PAD") { + parsed_pins = "sorted by pad"; + sorting_pad(n_pins); + gen_viewlist(n_pins); + } + dlgStretch(1); + dlgPushButton("So&rt PIN") { + parsed_pins = "sorted by pin"; + sorting_pin(n_pins); + gen_viewlist(n_pins); + } + dlgStretch(1); + dlgPushButton("Parse -->&>") { + parsed_pins = "parsing text, please wait..."; + dlgRedisplay(); + if (!is_bsdl) filter_text(use_pad_names); + else dlgMessageBox(";Only text files can be parsed. BSDL files will be parsed automatically!", "Ok"); + } + } + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(ListWidth); + dlgListView( "Pins\tPads\tDirect.", pins_pads_direc, select, sorting); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgVBoxLayout { dlgSpacing(TextStatusHigh); } + dlgLabel(tinfo, 1); + dlgStretch(1); + dlgLabel(parsed_pins, 1); + dlgSpacing(8); + } + + dlgTabWidget { + dlgTabPage("Ma&ke") { // ####################################### + dlgHBoxLayout { + dlgSpacing(4); + dlgVBoxLayout { + // hier das symbol pin layout + dlgSpacing(4); + dlgGroup("Symbol Pin Layout") { + dlgGridLayout { + dlgCell(0, 1) dlgLabel(""); + dlgCell(1, 1) dlgRadioButton("Sing&le", pin_layout) pinCntInfo = " "; + dlgCell(0, 2) dlgLabel(""); + dlgCell(1, 2) dlgRadioButton("Dual &1", pin_layout) pinCntInfo = " "; + dlgCell(0, 3) dlgLabel(""); + dlgCell(1, 3) dlgRadioButton("Dual &2", pin_layout) pinCntInfo = " "; + dlgCell(0, 4) dlgLabel(""); + dlgCell(1, 4) dlgRadioButton("&Quad", pin_layout) pinCntInfo = " "; + dlgCell(0, 5) dlgLabel(""); + dlgCell(1, 5) dlgRadioButton("Str&ipe", pin_layout) pinCntInfo = "Tip: Use split-device-symbol.ulp to generate a Device with multiple small symbols! Read HELP."; // 2006-12-05 + dlgCell(0, 6) dlgVBoxLayout { + dlgStretch(1); + dlgLabel("Ma&x. Pins\nper Stripe"); + dlgHBoxLayout { + dlgIntEdit(maxStripeCnt); + dlgStretch(1); + } + } + } + dlgStretch(1); + dlgLabel(pinCntInfo, 1); + dlgStretch(1); + } + dlgSpacing(4); + dlgHBoxLayout { + dlgGridLayout { + dlgCell(1,0) dlgCheckBox("&Symbol", make_Symbol) { // 2009-11-24 + if (make_Symbol) { + if (!n_pins) { + dlgMessageBox("!First define a pin list.", "OK"); + make_Symbol = 0; + } + else { + if(!symbol_name) { // 2011-09-20 + dlgMessageBox("! Define a Symbol name", "OK"); + make_Symbol = 0; + } + else if (checkSymbolName(strupr(symbol_name))) { // 2009-11-24 + make_Symbol = 0; + dlgMessageBox("Symbol " + symbol_name + " exist.\nChange symbol name!", "OK"); + } + string dirfault = check_pin_dir(); // 2011-09-20 + if (dirfault) { + make_Symbol = 0; + dlgMessageBox("Fault pin direction '" + dirfault + "'\nChange to card List Options and check PIN-Direction with Direction [change]!", "OK"); + } + } + } + } + dlgCell(1,1) dlgLabel("&Name "); + dlgCell(1,2) { dlgStringEdit(symbol_name); dlgLabel(".SYM"); } + + dlgCell(1,4) dlgLabel("|"); + + dlgCell(1,5) dlgCheckBox("Pa&ckage ", make_Package) { // 2009-11-24 + if (make_Package) { // 2011-09-20 + if (!n_pads) { + dlgMessageBox("!First define pad list.", "OK"); + make_Package = 0; + } + else { + if(!package_name) { + dlgMessageBox("! Define a Package name", "OK"); + make_Package = 0; + } + else if (checkPackageName(strupr(package_name))) { // 2009-11-24 + make_Package = 0; + dlgMessageBox("Package " + package_name + " exist.\nChange package name!", "OK"); + } + } + } + } + dlgCell(1,6) dlgLabel("Na&me "); + dlgCell(1,7) { dlgStringEdit(package_name); dlgLabel(".PAC"); } + + dlgCell(2,4) dlgLabel("|"); + + dlgCell(2,6) dlgLabel("&Variant "); + dlgCell(2,7) dlgStringEdit(pac_variant_name); + + dlgCell(2,0) dlgCheckBox("&Device", make_Device) + if(make_Device) { + if (!device_name) { + dlgMessageBox("! Define a Device name", "OK"); + make_Device = 0; + } + else if (checkDeviceName(strupr(device_name))) { // 2009-11-24 + make_Device = 0; + dlgMessageBox("Device " +device_name + " exist.\nChange device name!", "OK"); + } + } + dlgCell(2,1) dlgLabel("Nam&e "); + dlgCell(2,2) { dlgStringEdit(device_name); dlgLabel(".DEV"); } + } + dlgStretch(1); // rechts eben [] Symbol []Package [] Device + } + dlgStretch(1); // unter [] Symbol []Package [] Device + } + dlgStretch(1); + } + dlgStretch(1); + dlgHBoxLayout { dlgSpacing(4); dlgLabel(MakePacInfo, 1); } // info what package parameter in use + + dlgStretch(1); + dlgHBoxLayout { + dlgSpacing(4); + dlgPushButton("Ok") { + string error = ""; + string Libfile; + if (!Libfile) { + library(L) Libfile = L.name; + } + if (make_Symbol) { // 2008-11-07 + if (!n_pins) { // 2010-05-25 check lines parsed? + error = "No lines paresd!"; + } + error = check_pad_sorting(n_pins, make_Package); // // 2009-02-18 check if pads sorted ascending + // error = "Cancelt by check pad number!"; + if (check_exist_sym(strupr(symbol_name))) { + error = "Check symbol name, symbol exist!"; + } + if (!error) error = makeSymbol_Device(Libfile, pin_layout, package_name, use_pad_names, pad_prefix); + if (!error) { + int sympincount = getSymbolPinCount(strupr(symbol_name)); + if (sympincount >= 0) { // ** symbol exist, do not change or add pins ** + string s; sprintf(s, "Symbol %s has %d pins", symbol_name, sympincount); + error = "Symbol " + symbol_name + " exists, use another name for this new symbol!"; + // make_Symbol = 0; // 2008-11-07 reset/set this option by hand + } + } + } + else { + if (only_generate_bga || only_generate_pac) { // 2009-10-19 / 2011-03-07 + ; // accept + } + else { + if (check_exist_pac(strupr(package_name))) error = "Check package, package exist!"; // 2011-11-03 + } + } + if (make_Package) { // do not generate package while exist 2008-11-07 + if (check_exist_pac(package_name)) make_Package = 0; // reset flag + } + else PadCount = ""; + if (make_Device && !error) { + if (!make_Package && package_name) ; + else if (make_Package && BGAparameter_accept || make_Package && packageparameter_accept) ; // 2005-12-01 + else { + package_selected = 0; + error = "Accept Package parameter to generate a Package,
    " + + "or accept BGA parameter,
    or Use an existing Package.
    "; + PadCount = " "; + } + } + if (!error) { + if ((package_name && !make_Package) && (make_Device && !make_Package)) { + // 2008-11-07 if use a existing package, + // first check padnames in used package + + if (!check_exist_pac(strupr(package_name))) error = "Package not exit " + package_name; + else PadCount = getPackagePadCount(package_name); // generate pad list from used package, used_pad_number[] + if (!error) error += check_pin_pad_list(n_pins, strtol(PadCount)); // 2008-11-07 + } + + if (make_Package) { + if (BGAparameter_accept || packageparameter_accept) ; + else { + error = "Accept BGA or Package parameter."; + } + if (BGAparameter_accept && !n_pins) { + error = "No BSDL file has parsed."; + } + if (package_name) { + m_pac_width = pac_width; + m_grid_val = grid_val; + m_SMD_diameter = SMD_diameter; + m_MaskRestring = MaskRestring; + m_CreamDiameter = CreamDiameter; + } + else { + error = "Define a Package name"; + } + } + } + if (!error) { + pac_width = m_pac_width; + grid_val = m_grid_val; + SMD_diameter = m_SMD_diameter; + MaskRestring = m_MaskRestring; + CreamDiameter = m_CreamDiameter; + dlgAccept(); { + // *** make package after set parameter (grid & diameter) 2005-06-28 *** + if (make_Package) { + pac_width = m_pac_width; + grid_val = m_grid_val; + SMD_diameter = m_SMD_diameter; + MaskRestring = m_MaskRestring; + CreamDiameter = m_CreamDiameter; + if (!infile) { library(L) infile = L.name; } // set default path for temporary script 2005-11-03 + makePackage(infile); + cmd += "SCRIPT '" + packagefile + "';\nWIN FIT;\n"; + } + } + } + else { + display_error(error); // 2008-11-07 + } + } + dlgSpacing(8); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + if (strstr(OS_SIGNATURE, "Windows") == 0) { + dlgPushButton("Manual") { + sprintf(PdfDocLink, "%s/doc/make-symbol-device-package-bsdl-2011-en.pdf", EAGLE_DIR ); + if (language() == "de") { + sprintf(PdfDocLink, "%s/doc/make-symbol-device-package-bsdl-2011-de.pdf", EAGLE_DIR); + } + system_call(PdfDocLink); + } + } + dlgLabel(Revision); + } + } + + dlgTabPage("BG&A") { // ####################################### + dlgHBoxLayout { + dlgSpacing(8); + dlgVBoxLayout { + dlgGroup("Generate Ball Grid Area") { + dlgGridLayout { + dlgCell(2,0) dlgLabel("Body &Width "); + dlgCell(2,1) dlgRealEdit(m_pac_width); + + dlgCell(3,0) dlgLabel("PAD &Grid "); + dlgCell(3,1) dlgRealEdit(m_grid_val); + + dlgCell(4,0) dlgLabel("PAD &Diameter "); + dlgCell(4,1) dlgRealEdit(m_SMD_diameter); + + dlgCell(5,0) dlgLabel("&Stop Mask +/- "); + dlgCell(5,1) dlgRealEdit(m_MaskRestring); + + dlgCell(6,0) dlgLabel("&Cream Mask Diam. "); + dlgCell(6,1) dlgRealEdit(m_CreamDiameter); + dlgCell(6,2) dlgLabel(" 0 = OFF"); + + dlgCell(7,0) dlgLabel("Drawing grid "); + dlgCell(7,1) dlgStringEdit(genpac_grid); + } + } + } + dlgLabel(""); + dlgStretch(1); + } + dlgHBoxLayout { // 2011-90-20 + dlgSpacing(20); + dlgPushButton("Save config") saveBGAconfig(); + dlgPushButton("Load config") loadBGAconfig(); + dlgStretch(1); + } + dlgStretch(1); + dlgHBoxLayout { // 2009-10-16 + dlgLabel("Generate only BGA pad names, to generate BGA package without a BSDL- or a TEXT-file "); + dlgPushButton("Generate PAD list") genBGA_PadList(); // 2009-10.16 + dlgStretch(1); + } + dlgStretch(1); + dlgHBoxLayout { + dlgSpacing(8); + dlgCheckBox("Accept para&meter ", BGAparameter_accept) { + genpac_grid = strupr(genpac_grid); // 2008-11-07 use always in upper case + pac_width = m_pac_width; // 2006-06-01 + grid_val = m_grid_val; + SMD_diameter = m_SMD_diameter; + MaskRestring = m_MaskRestring; + CreamDiameter = m_CreamDiameter; // 2006-06-09 + if (BGAparameter_accept) { + if (!n_pins) { + dlgMessageBox("No BSDL file has parsed.", "OK"); + BGAparameter_accept = 0; + } + else { + use_pad_names = useBGA; + packageparameter_accept = 0; // *** only one parameter can accept *** + if (!package_name) { // 2011-04-01 check empty package name + BGAparameter_accept = 0; // reset accept + dlgMessageBox("!No package name defined.\nSwitch to tab Make and define a package name.", "OK"); + } + else { + package_name = strupr(package_name); + gen_package(package_name); // 2005-08-02 + make_Package = 1; + MakePacInfo = "Use BGA parameter to generate Package"; + } + } + } + else { + MakePacInfo = " "; + } + } + dlgStretch(1); + dlgLabel(Revision); + } + } + + dlgTabPage("&Package") { // ####################################### + packageparameter_accept = 0; + dlgSpacing(8); + dlgHBoxLayout { + dlgSpacing(8); + dlgVBoxLayout { + dlgGroup("Parameter (generate new package)") { + dlgGridLayout { + dlgCell( 1,0) dlgLabel(" &L "); + dlgCell( 1,1) dlgRealEdit(xA_pac); + dlgCell( 1,2) dlgSpacing(10); + + dlgCell( 2,0) dlgLabel(" L1 "); + dlgCell( 2,1) dlgRealEdit(yA_pac); + + dlgCell( 4,0) dlgLabel(" &D "); + dlgCell( 4,1) dlgRealEdit(xD_pac); + + dlgCell( 5,0) dlgLabel(" D1 "); + dlgCell( 5,1) dlgRealEdit(yD_pac); + + dlgCell( 1,4) dlgLabel(" &m "); + dlgCell( 1,5) dlgRealEdit(mark_length); + + dlgCell( 2,4) dlgLabel(" &b "); + dlgCell( 2,5) dlgRealEdit(pad_width); + + dlgCell( 3,4) dlgLabel(" &e "); + dlgCell( 3,5) dlgRealEdit(basic_pad_grid); + + dlgCell( 4,4) dlgLabel(" &w "); + dlgCell( 4,5) dlgRealEdit(pad_stand_out); + + dlgCell( 5,4) dlgLabel(" &x "); + dlgCell( 5,5) dlgRealEdit(xpad_length); + + dlgCell( 6,4) dlgLabel(" &y"); // 2008-05-20 + dlgCell( 6,5) dlgRealEdit(ypad_length); + + dlgCell( 7,1) dlgLabel(round_restring, 1); // 2005-12-01 + dlgCell( 7,4) dlgLabel(" &r "); + dlgCell( 7,5) dlgRealEdit(roundness_restring, 0, 100); + + } + dlgHBoxLayout { + dlgLabel("&Grid "); + dlgStringEdit(genpac_grid); + dlgStretch(1); + } + } + dlgStretch(1); + } + dlgVBoxLayout { + dlgLabel(packinfo, 1); + dlgSpacing(50); + dlgLabel(packinfomess, 1); // 2005-12-01 + dlgStretch(2); + } + dlgVBoxLayout { + dlgGroup("Package PAD Layout") { + dlgGridLayout { + dlgCell(0, 1) dlgLabel(""); + dlgCell(0, 3) dlgLabel(""); + dlgCell(0, 5) dlgLabel(""); + dlgCell(1, 1) dlgRadioButton("Quad &1", pad_layout) packinfo = ""; + dlgCell(1, 3) dlgRadioButton("Quad &2", pad_layout) packinfo = ""; + dlgCell(1, 5) dlgRadioButton("Dual &3", pad_layout) packinfo = ""; + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgGroup("Contact") { // 2005-12-01 + dlgGridLayout { + dlgCell( 1,0) dlgRadioButton("SMD", smd_pad) { + packinfomess = ""; + round_restring = "Roundness %"; + } + dlgCell( 2,0) dlgRadioButton("PAD", smd_pad) { + round_restring = "Restring"; + switch(pad_shape) { + case PAD_SHAPE_SQUARE : packinfomess = ""; + break; + case PAD_SHAPE_ROUND : packinfomess = ""; + break; + case PAD_SHAPE_OCTAGON : packinfomess = ""; + break; + } + } + } + } + //dlgSpacing(4); + dlgGroup("Shape") { + dlgGridLayout { + dlgCell( 1,0) { + dlgVBoxLayout { + dlgRadioButton("Square", pad_shape) if (smd_pad) packinfomess = ""; + dlgRadioButton("Round", pad_shape) if (smd_pad) packinfomess = ""; + dlgRadioButton("Oct.", pad_shape) if (smd_pad) packinfomess = ""; + } + } + } + } + dlgStretch(1); + } + } + dlgStretch(1); + } + dlgStretch(1); + + dlgHBoxLayout { // 2011-90-20 + dlgSpacing(20); + dlgPushButton("Save config") savePACconfig(); + dlgPushButton("Load config") loadPACconfig(); + dlgStretch(1); + dlgLabel("PAC &Name"); // 2011-11-03 + dlgStringEdit(package_name); + } + + dlgHBoxLayout { + dlgSpacing(8); + dlgCheckBox("A&ccept parameter ", packageparameter_accept) { + genpac_grid = strupr(genpac_grid); // 2008-11-07 use always in upper case + switch (pad_layout) { // check Package PAD placement + case 0 : // quad package with Pin 1 on left side + cnt_side = Pad_Count / 4; + break; + case 1 : // quad package with Pin 1 on middle of top + cnt_side = Pad_Count / 4; + break; + case 2 : // dual in line package + cnt_side = Pad_Count / 2; + break; + } + if (packageparameter_accept) { + string e; + if (pad_layout == 0 || pad_layout == 1) { + int chkpad = Pad_Count % 4; // modulo 4 + if (chkpad) { + sprintf(e, "Error: Number of Pads %d can't be devided by 4,\nplease check Package PAD Layout!", Pad_Count); + packageparameter_accept = 0; + } + if (!e) { + int middle = cnt_side % 2; + if (!middle && pad_layout == 1) { + sprintf(e, "Error: Pad layout middle can only be used for an odd number of pads at a side."); + packageparameter_accept = 0; + } + } + } + else if (pad_layout == 2) { + int chkpad = Pad_Count % 2; // modulo 2 + if (chkpad) { + sprintf(e, "Error: Number of Pads %d can't be devided by 2", Pad_Count); + packageparameter_accept = 0; + } + } + if (!e) { + if (packageparameter_accept) { + BGAparameter_accept = 0; + use_pad_names = usePACwithPrefix; + if (!package_name) { // 2011-04-01 first chek if package name defined + packageparameter_accept = 0; // no, reset accept + dlgMessageBox("!No package name defined.\nSwitch to tab Make and define a package name.", "OK"); + } + else { + package_name = strupr(package_name); + gen_package(package_name); // 2005-08-02 + make_Package = 1; + MakePacInfo = "Use package parameter"; + } + } + } + else { // show error message + MakePacInfo = " "; + dlgMessageBox(e, "OK"); + } + } + } + dlgLabel(" not for BGA "); + dlgSpacing(4); + dlgLabel(" Pads Cou&nt "); + dlgIntEdit(Pad_Count, 1, 2000); + dlgSpacing(12); + dlgLabel("Generate pad name list \n(without a BSDL- or TEXT-file) "); + dlgPushButton("Generate PAD list") { + Pad_Count = genPAC_PadList(Pad_Count); // 2011-04-01 + n_pins = Pad_Count; // 2011-09-20 + n_pads = Pad_Count; + make_Symbol = 0; // reset make Symbol + } + dlgStretch(1); + dlgLabel(Revision); + } + } + + dlgTabPage("&Use Package") { // ####################################### + dlgSpacing(8); + dlgHBoxLayout { + dlgSpacing(12); + dlgVBoxLayout { + dlgHBoxLayout { + dlgGroup("Package options ") { + dlgRadioButton(" &None", use_pad_names) { + package_selected = 0; + package_name = ""; + old_pad_prefix = strupr(pad_prefix); + pad_prefix = ""; + } + dlgRadioButton(" Use PAD Na&mes supplied with BSDL file (for BGA parts) ", use_pad_names) { + old_pad_prefix = strupr(pad_prefix); + pad_prefix = ""; + } + dlgRadioButton(" Use PAD Prefi&x if existing package is used ", use_pad_names) { // 2011-05-23 + old_pad_prefix = strupr(pad_prefix); + pad_prefix = old_pad_prefix; + } + } + dlgSpacing(8); + dlgStretch(1); + } + dlgSpacing(8); + dlgHBoxLayout { + dlgLabel(" Use &existing package "); + dlgComboBox(packages, package_selected) { + PadCount = "check pad names, please wait.. "; // 2008-11-07 + dlgRedisplay(); + package_name = packages[package_selected]; + if (!package_selected) { + pad_prefix = getPackagePadPrefix(packages[package_selected]); + package_name = ""; + use_pad_names = useNONE; // 2011-05-23 + } + else { + package_name = packages[package_selected]; // 2008-11-07 + use_pad_names = usePACwithPrefix; // 2011-05-23 + } + status("generate pad list from package"); + PadCount = getPackagePadCount(package_name); // generate pad list from used package, used_pad_number[] + dlgRedisplay(); + status(""); + if (package_selected) make_Package = 0; // if use a package do not generate package + } + dlgLabel(PadCount, 1); + dlgStretch(1); + } + dlgSpacing(8); + dlgHBoxLayout { + dlgLabel(" Pad prefi&x "); + dlgStringEdit(pad_prefix); + dlgSpacing(560); + dlgStretch(1); + } + dlgSpacing(8); + } + } + dlgStretch(1); + dlgHBoxLayout { + dlgStretch(1); + dlgLabel(Revision); + } + } + + dlgTabPage("&Text Options") { // ####################################### + if (is_bsdl) { + dlgLabel("BSDL file in use! Do not change this text!"); + } + else { + dlgHBoxLayout { + dlgGroup("Use with text only, not with a BSDL file") { + dlgVBoxLayout { + dlgHBoxLayout { + dlgSpacing(100); + dlgLabel("** use word separator also for Parse -->> to list and delete column."); // 2011-04-01 + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("Spl&it") { + change_char_text(w_separator[select_separ], '\n', 0); + } + dlgLabel(" with word &separator "); + dlgComboBox(separator, select_separ) { + Word_separator = w_separator[select_separ]; + sprintf(String_separator, "%c", Word_separator); + } + dlgSpacing(16); + dlgLabel("Split with "); + dlgPushButton("&Character ") { + if (strlen(c_separator) == 1) + change_char_text(c_separator[0], '\n', 0); + else if (c_separator) + dlgMessageBox("!Split with character.\nMore than 1 character in this field.", "Ok"); + else + dlgMessageBox("!Split with character\nNo character defined.", "Ok"); + } + dlgLabel(" separator "); + dlgStringEdit(c_separator); + } + + dlgHBoxLayout { + dlgPushButton("&Merge") { + if (separator_counter > 1) { + int cntnl = strsplit(st, text, '\n'); + text = ""; + cc = 0; + int cnt = 0; + for (int n = 0; n < cntnl; n++) { + text += st[n]; + if (cnt < separator_counter-1) { + text += String_separator; + cnt++; + } + else { + text += "\n"; + cnt = 0; + cc++; + } + } + if(strlen(text) > 0) { + text[strlen(text)-1] = 0; + sprintf(tinfo, "shrink %d to %d lines", cntnl, cc); + } + } + else { + dlgMessageBox("Counter must be >= 2", "ok"); + } + } + dlgSpacing(4); + dlgIntEdit(separator_counter); + dlgLabel(" lines with word separator"); + dlgStretch(1); + dlgPushButton("Merge 1/2 text") text = merge_half_text_lines(text); // 2009-11-124 + } + + dlgHBoxLayout { + dlgPushButton("&Replace" ) replaceWord(search, replace); + dlgLabel(" character strin&g "); + dlgStringEdit(search); + dlgLabel(" &with "); + dlgStringEdit(replace); + } + + dlgHBoxLayout { + dlgPushButton("D&elete") { + int cntst = strsplit(st, text, '\n'); + text = ""; + for (int n = 0; n < cntst; n++) { + if (exact_include) { + if (strstr(st[n], del_line) < 0) text += st[n] + "\n"; + } + else if (st[n] != del_line) text += st[n] + "\n"; + } + } + dlgLabel(" lines with te&xt string "); + dlgStringEdit(del_line); + dlgSpacing(8); + dlgRadioButton("Exact", exact_include); + dlgRadioButton("Include", exact_include); + dlgStretch(1); + } + + dlgHBoxLayout { + dlgPushButton("&Delete") delete_x_line(start_line, x_line); + dlgLabel(" e&very "); + dlgIntEdit(x_line); + dlgLabel("th. line. Start at &line "); + dlgIntEdit(start_line); + dlgStretch(1); + dlgPushButton("Delete empt&y lines") delete_empty_lines(); + } + + dlgHBoxLayout { + dlgPushButton("Delete column") delete_column(delColumn); // 2008-04-02 + dlgLabel(" column &# "); + dlgIntEdit(delColumn, 1, 100); + dlgLabel("(count from 1. ** use word separator to count column)."); + dlgStretch(1); + } + } + } + dlgStretch(1); // stretch waagrecht nach Group + } + dlgStretch(1); // stretch senktrecht nach Group + dlgHBoxLayout { + dlgGroup("Quick file option") { + dlgHBoxLayout { + dlgPushButton("Load") { + string fl = infile; + if (!fl) fl = path_epf[0] + "/~make.txt"; // 2011-04-01 path_epf[0] + else { + if (strstr(fl, "/~make.txt") < 0) { // 2009-02-18 + fl = filedir(infile) + "~make.txt"; + } + } + string fn[]; // 2008-11-07 first check if file exist + int fc = fileglob(fn, fl); + if (!fc) { + fl = dlgFileOpen(fl, "", "*.txt *.*"); + } + if (fl) { + infile = fl; // 2008-11-07 show actual filename + int cnt = fileread(text, fl); + parsed_pins = "Text loaded:"+fl; + is_bsdl = 0; // 2011-04-01 reset bsdl flag + } + } + dlgPushButton("Save") { + string fs = infile; + if (!fs) fs = path_epf[0] + "/~make.txt"; // 2008-03-26 + else { + if (strstr(fs, "/~make.txt") < 0) { // 2009-02-18 + fs = filedir(infile) + "~make.txt"; + } + } + output(fs, "wt") printf("%s", text); + parsed_pins = "Text saved:"+fs; + } + dlgPushButton("Save as") { + string fsa = dlgFileSave("Text-Save", path_epf[0], "*.txt"); + if (fsa) { + output(fsa, "wt") printf("%s", text); + parsed_pins = "Text saved:"+fsa; + } + } + } + } + dlgStretch(1); + dlgPushButton("&Help") infohelp(Help); // 2011-04-01 + dlgLabel(Revision); + } + } + } + + dlgTabPage("&List Options") { /*** 2011-04-01 ***/ + if (is_bsdl) { + dlgLabel("BSDL file in use! Do not change this text!"); + } + else { + dlgHBoxLayout { + dlgStretch(1); + dlgGridLayout { + dlgCell(0, 0) dlgLabel("Swap "); + dlgCell(0, 1) dlgPushButton("PIN <-> PAD") { + if (is_bsdl) { + dlgMessageBox("!Do not swap Pin - Pad if a BSDL file is used!", "Ok"); + } + else { + for (int i = 0; i < n_pins; i++) { + string tt; + tt = pins[i]; + pins[i] = pads[i]; + pads[i] = tt; + tt = pin_names[i]; + pin_names[i] = pad_names[i]; + pad_names[i] = tt; + } + gen_viewlist(n_pins); + } + } + dlgCell(0, 2) dlgPushButton("PAD <&-> DIR") { + if (is_bsdl) { + dlgMessageBox("!Do not swap PAD - DIR if a BSDL file is used!", "Ok"); + } + else { + for (int i = 0; i < n_pins; i++) { + string tt; + tt = pad_names[i]; + pad_names[i] = Pin_Direc[i]; + Pin_Direc[i] = tt; + pads[i] = pad_names[i]; + } + gen_viewlist(n_pins); + } + } + + dlgCell(1, 0) dlgLabel(" "); + dlgCell(2, 0) dlgLabel("Direction "); + dlgCell(2, 1) dlgPushButton("change") change_dir(n_pins); // 2008-04-02 + dlgCell(2, 2) dlgPushButton("set") set_Pin_Direction(n_pins); // 2008-07-03 + dlgCell(2, 3) dlgPushButton("delete") { + if (is_bsdl) { + dlgMessageBox("!Do not delete DIR if a BSDL file is used!", "Ok"); + } + else { + for (int i = 0; i < n_pins; i++) { + Pin_Direc[i] = ""; + } + gen_viewlist(n_pins); + } + } + + dlgCell(3, 0) dlgLabel("Clear leading zeros in"); + dlgCell(3, 1) dlgPushButton("BGA") clear_leading_z(n_pins); + dlgCell(3, 2) dlgLabel(" pad"); + + dlgCell(4, 0) dlgLabel("Double pad number"); + dlgCell(4, 1) dlgPushButton("delete") n_pins = del_double_pad(n_pins); // 2008-04-02 + + dlgCell(5, 0) dlgLabel("Rename "); + dlgCell(5, 1) dlgPushButton("PIN") rename_pin(n_pins, search, replace); // 2011-04-01 + + dlgCell(6, 0) dlgLabel("Rename "); + dlgCell(6, 1) dlgPushButton("PAD") rename_pad(n_pins, search, replace); // 2008-11-07 + + dlgCell(7, 0) dlgLabel("Pads for pins"); + dlgCell(7, 1) dlgPushButton("numbering") number_pads(n_pins); // 2008-07-03 + } + } + dlgStretch(1); + dlgHBoxLayout { + dlgPushButton("&Help") infohelp(HelpList); // 2011-04-01 + dlgStretch(1); + if (strstr(OS_SIGNATURE, "Windows") == 0) { + dlgPushButton("Manual") { + sprintf(PdfDocLink, "%s/doc/make-symbol-device-package-bsdl-2011-en.pdf", EAGLE_DIR ); + if (language() == "de") { + sprintf(PdfDocLink, "%s/doc/make-symbol-device-package-bsdl-2011-de.pdf", EAGLE_DIR); + } + system_call(PdfDocLink); + } + } + dlgLabel(Revision); + } + } + } + } + }; + + if (result) { + if (make_Symbol) cmd += "SCRIPT '" + symbol_file + "';\nWIN FIT;\n"; + if (make_Device) cmd += "SCRIPT '" + device_file + "';\nWIN FIT;"; + } + exit(cmd); +} + +else { + dlgMessageBox("!This is no Library!\nThis program can only work in the Library editor."); + exit(0); +} \ No newline at end of file diff --git a/trunk/ulp/make-value-consistent.ulp b/trunk/ulp/make-value-consistent.ulp new file mode 100644 index 00000000..da7fd336 --- /dev/null +++ b/trunk/ulp/make-value-consistent.ulp @@ -0,0 +1,589 @@ +#usage "Make SCH/BRD consistent by values." + "

    " + "Start this ULP in the editor which contains the source values.
    " + "Author: support@cadsoft.de
    " + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED +string Version = "1.2"; // 2012.11.19 element list numerical sort + +numeric string sch_name[], sch_value[]; +numeric string sch_package[]; +int sch_sheet[]; +int sch_Index[]; +int sch_cnt = 0; +numeric string s_name[]; +numeric string DeviceList[]; + +numeric string brd_name[], brd_value[]; +numeric string brd_package[]; +int brd_Index[]; +int brd_cnt = 0; +numeric string ElementList[]; + +numeric string sch_name_no_pac[], sch_value_no_pac[], sch_package_no_pac[]; +numeric string DeviceList_no_pac[]; +int sch_sheet_no_pac[]; +int sch_cnt_no_pac = 0; + + +numeric string brd_name_only_pac[], brd_value_only_pac[], brd_package_only_pac[]; +numeric string ElementList_only_pac[]; +int brd_Index_only_pac[]; +int brd_cnt_only_pac; + + +string lines[]; +int lines_cnt; + +string diff_values[]; +string command; +int runcount = 0; + +string notfound[]; +int cnt_nf= 0; + +string changeValue = ""; + +string readfile, readfile_only_pac, readfile_no_pac; +string ext = ".~cv"; // extension for temp file + +string emptySchList[], emptyBrdList[]; +int cnt_SCHempty = 0, cnt_BRDempty = 0; + +int n; + + +// ### Functions ### +if (board) { + board(B) { + readfile = filesetext(B.name, ext); + readfile_only_pac = filesetext(B.name, "_only_pac"+ext); + readfile_no_pac = filesetext(B.name, "_no_pac"+ext); + } +} +if (schematic) { + schematic(S) { + readfile = filesetext(S.name, ext); + readfile_only_pac = filesetext(S.name, "_only_pac"+ext); + readfile_no_pac = filesetext(S.name, "_no_pac"+ext); + } +} + + +int genscript(void) { + int xcnt = 0; + numeric string ch_name[], ch_value[]; + int ch_sheet[]; + int bIndex[], sIndex[]; + sort(brd_cnt, bIndex, brd_name); // sort by name + sort(sch_cnt, sIndex, sch_name); // sort by name + for (int x = 0; x < sch_cnt; x++) { + if ( sch_value[sIndex[x]] != brd_value[bIndex[x]]) { // change only values are different + if (board) { + ch_name[xcnt] = brd_name[bIndex[x]]; + ch_value[xcnt] = sch_value[sIndex[x]]; + ch_sheet[xcnt] = 0; // no sheet in bard + } + if (schematic) { + ch_name[xcnt] = sch_name[sIndex[x]]; + ch_value[xcnt] = brd_value[bIndex[x]]; + ch_sheet[xcnt] = sch_sheet[sIndex[x]]; + } + xcnt++; + } + } + string s; + int actualsheet = 0; + if (xcnt) { + for (int n = 0; n < xcnt; n++) { + if (actualsheet != ch_sheet[n]) { + sprintf(s, "EDIT .s%d;\n", ch_sheet[n]); + command += s; + actualsheet = ch_sheet[n]; + } + sprintf( s, "VALUE %s '%s';\n", ch_name[n], ch_value[n] ); + command += s; + } + } + return xcnt; +} + + +void checkdiff(void) { + int n1, n2, found; + for (n1 = 0; n1 < brd_cnt; n1++) { + found = 0; + for (n2 = 0; n2 < sch_cnt; n2++) { + if(brd_name[n1] == sch_name[n2]) { + found = 1; + break; + } + } + if (!found) { + sprintf(notfound[cnt_nf], "%s\t%s", ElementList[n1],".brd"); + cnt_nf++; + } + } + for (n1 = 0; n1 < sch_cnt; n1++) { + found = 0; + for (n2 = 0; n2 < brd_cnt; n2++) { + if(sch_name[n1] == brd_name[n2]) { + found = 1; + break; + } + } + if (!found) { + sprintf(notfound[cnt_nf], "%s\t%s", DeviceList[n1], ".sch"); + cnt_nf++; + } + } + return; +} + + +string getBrdValue(string name) { + for (int n = 0; n < brd_cnt; n++) { + if (name == brd_name[n]) if (brd_value[n]) return brd_value[n]; + } + return ""; +} + + +string getSchValue(string name) { + for (int n = 0; n < sch_cnt; n++) { + if (name == sch_name[n]) if (sch_value[n]) return sch_value[n]; + } + return ""; +} + + +void checkSCHempty(void) { + for (int n = 0; n < sch_cnt; n++) { + if (!sch_value[n]) { + emptySchList[cnt_SCHempty] = sch_name[n] + "\t" + getBrdValue(sch_name[n]); + cnt_SCHempty++; + } + } + return; +} + + +void checkBRDempty(void) { + for (int n = 0; n < brd_cnt; n++) { + if (!brd_value[n]) { + emptyBrdList[cnt_BRDempty] = brd_name[n] + "\t" + getSchValue(brd_name[n]); + cnt_BRDempty++; + } + } + return; +} + + +void setVal(string namev) { + string s[], cmd; + int cnt = strsplit(s, namev, '\t'); + if (board) { + for (int n = 0; n < sch_cnt; n++) { + if (s[0] == sch_name[n]) { + sprintf(cmd, "EDIT .S%d;\n", sch_sheet[n]); + break; + } + } + } + if (schematic) sprintf(cmd, "EDIT .brd;"); + cmd += "VALUE " + s[0]; + int Result = dlgDialog("Value for " + s[0]) { + dlgLabel("Change VALUE for "+s[0]+""); + dlgStringEdit(s[1]); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; + if (!Result) return; + cmd += " '"+s[1]+"';\nRUN '"+argv[0]+"';"; + exit(cmd); +} + + +void cmd_exit(string t) { + string s[]; + string f; + string cmd; + int cnts = strsplit(s, t, '\t'); + if (board && s[4] == ".brd" || schematic && s[4] == ".sch") { + sprintf(cmd, "RUN find '%s';\n", s[0]); + } + else { + f = filesetext(readfile, s[4]); + sprintf(cmd, "EDIT '%s';\nRUN find '%s';\n", f, s[0]); + } + exit(cmd); + return; +} + + +void show_no_contact(void) { + int sel_onlypac, sel_nopac; + dlgDialog(argv[0]) { + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel("Devices without Contacts"); + dlgListView("Name\tValue\tPackage\tSheet", DeviceList_no_pac, sel_onlypac); + } + dlgVBoxLayout { + dlgLabel("Elements without Contacts"); + dlgListView("Name\tValue\tPackage", ElementList_only_pac, sel_nopac); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + + +void menue(void) { + int devsel = -1, pacsel = -1; + string Error = ""; + string InfoSch, InfoBrd; + sprintf(InfoSch, "&Schematic : %d Devices", sch_cnt); + sprintf(InfoBrd, "&Board : %d Elements", brd_cnt); + checkdiff(); + if (board) checkSCHempty(); + if (schematic) checkBRDempty(); + int dif = genscript(); // generate SCRIPT + + if (cnt_nf || cnt_SCHempty || cnt_BRDempty) { + if (cnt_nf || sch_cnt != brd_cnt) { + sprintf( Error, "STOP

    Different counts of parts

    %5d Devices/SCH
    %5d Packages/BRD

    STOP
    ", sch_cnt, brd_cnt); + if(sch_cnt > brd_cnt) Error += "
    Place Package in BRD or
    delete Device in SCH
    "; + else Error += "
    Place Device in SCH or delete Package in BRD!"; + } + int Result = dlgDialog("Make Value Consistent") { + int sel_nf, sell = -1, ssort = -2 ,dsl = 1 , psl = 1; + dlgHBoxLayout { + dlgGridLayout { + if (Error) { + dlgCell( 0, 0) { + dlgLabel(Error); + } + if (cnt_nf) { + dlgCell( 0, 1) { + dlgVBoxLayout { + dlgLabel("To many Devices respectively Elements in Editor, see list."); + dlgLabel("&For show selected Device/Element, double-click in list"); + dlgListView("Name\tValue\tPackage\tSheet\tEditor", notfound, sel_nf) cmd_exit(notfound[sel_nf]); + } + } + } + } + else { + if (board) { + if (cnt_SCHempty) { + dlgCell( 1, 0) { + dlgVBoxLayout { + dlgLabel("Do not use empty values when use this ULP!"); + dlgLabel(" First set VALUE in SCHEMATIC "); + dlgLabel(" (double-click in list)"); + dlgStretch(1); + } + } + dlgCell( 1, 1) { + dlgVBoxLayout { + string evSch; sprintf(evSch, "%d empty &Values in Schematic!", cnt_SCHempty); + dlgLabel(evSch); + dlgListView("NAME\tValue in BRD", emptySchList, sell, ssort) setVal(emptySchList[sell]); + } + } + } + } + if (schematic) { + if (cnt_BRDempty) { + dlgCell( 1, 0) { + dlgVBoxLayout { + dlgLabel("Do not use empty values when use this ULP!"); + dlgLabel(" First set VALUE in BOARD "); + dlgLabel(" (double-click in list)"); + dlgStretch(1); + } + } + dlgCell( 1, 1) { + dlgVBoxLayout { + string evBrd; sprintf(evBrd, "%d empty &Values in Board!", cnt_BRDempty); + dlgLabel(evBrd); + dlgListView("Name\tValue in SCH", emptyBrdList, sell, ssort) setVal(emptyBrdList[sell]); + } + } + } + } + } + + dlgCell( 1, 2) { + dlgHBoxLayout { + dlgSpacing(12); + dlgPushButton("Show Device and Package without Contacts") show_no_contact(); + } + } + } + dlgStretch(1); + } + if (!command) { + dlgSpacing(8); + dlgLabel("VALUES are consistent"); + } + + dlgLabel("


    "); + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel(InfoSch); + dlgListView("Name\tValue\tPackage", DeviceList, devsel, dsl); + } + dlgVBoxLayout { + dlgLabel(InfoBrd); + dlgListView("Name\tValue\tPackage", ElementList, pacsel, psl); + } + } + dlgHBoxLayout { + if (!Error && !cnt_SCHempty && !cnt_BRDempty) { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + else { + dlgPushButton("OK") dlgReject(); + dlgPushButton("Do it") dlgAccept(); // 2010-01-22 + } + dlgStretch(1); + dlgLabel(usage); + dlgStretch(1); + dlgLabel("Version " + Version); + } + }; + if (!Result) exit(0); + if (!command) exit(0); + } + + // ****** show script ****** +// int ssel, bsel, dsel; + int Result = dlgDialog("Make VALUE consistent") { + dlgHBoxLayout { + if (command) { + dlgVBoxLayout { + dlgLabel("Change values in " + argv[1]); + dlgLabel("Command"); + dlgTextEdit(command); + } + } + else { + dlgVBoxLayout { + dlgLabel("Values are consistent"); + } + } + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgLabel(" Version " + Version); + } + }; + if (Result) { + if (command) { + string scriptfile = filesetext(readfile, "~.scr"); + output(scriptfile, "wtD") printf("%s",command); + exit("script '" + scriptfile + "';ERC\n"); + } + } + exit (0); +} + + +int noexist(string name, int cnt) { + int is = 1; + for (int n = 0; n < cnt; n++) { + if (s_name[n] == name) { + is = 0; + break; + } + } + return is; +} + + +// ### Main ### +runcount = strtol(argv[2]); +if (runcount == 1) { + string cmd; + lines_cnt = fileread( lines, readfile); + if (board) { + int rnp = fileread(DeviceList_no_pac, readfile_no_pac); + } + if (schematic) { + int rop = fileread(ElementList_only_pac, readfile_only_pac); + } +} + + +// *** Board *** +if (board) { + string b_name[], b_value[], b_package[]; + string b_name_only_pac[], b_value_only_pac[], b_package_only_pac[]; + + board(B) { + B.elements(E) { + int PACcontact = 0; + E.package.contacts(C) { + b_name[brd_cnt] = E.name; + b_value[brd_cnt] = E.value; + b_package[brd_cnt] = E.package.name; + brd_cnt++; + PACcontact++; + break; + } + if (!PACcontact) { + b_name_only_pac[brd_cnt_only_pac] = E.name; + b_value_only_pac[brd_cnt_only_pac] = E.value; + b_package_only_pac[brd_cnt_only_pac] = E.package.name; + brd_cnt_only_pac++; + } + } + + sort (brd_cnt, brd_Index, b_value, b_name); + for (n = 0; n < brd_cnt; n++) { + brd_name[n] = b_name[brd_Index[n]] ; + brd_value[n] = b_value[brd_Index[n]] ; + brd_package[n] = b_package[brd_Index[n]]; + sprintf(ElementList[n], "%s\t%s\t%s\t0", brd_name[n], brd_value[n], brd_package[n] ); + } + sort (brd_cnt_only_pac, brd_Index_only_pac, b_value_only_pac, b_name_only_pac); + for (n = 0; n < brd_cnt_only_pac; n++) { + brd_name_only_pac[n] = b_name_only_pac[brd_Index_only_pac[n]] ; + brd_value_only_pac[n] = b_value_only_pac[brd_Index_only_pac[n]] ; + brd_package_only_pac[n] = b_package_only_pac[brd_Index_only_pac[n]]; + sprintf(ElementList_only_pac[n], "%s\t%s\t%s", brd_name_only_pac[n], brd_value_only_pac[n], brd_package_only_pac[n] ); + } + + if (runcount < 1) { + output(readfile, "wtD") { + for(int x = 0; x < brd_cnt; x++) { + printf("%s\t%s\t%s\t0\n", brd_name[x], brd_value[x], brd_package[x] ); + } + } + output(readfile_only_pac, "wtD") { + for(int x = 0; x < brd_cnt_only_pac; x++) { + printf("%s\t%s\t%s\n", brd_name_only_pac[x], brd_value_only_pac[x], brd_package_only_pac[x] ); + } + } + runcount++; + string cmd; + sprintf( cmd, "edit '%s';\n run '%s' SCH %d;\n", filesetext(B.name, ".sch"), argv[0], runcount ); + exit(cmd); + } + sch_cnt = lines_cnt; + string s[]; + for (n = 0; n < sch_cnt; n++) { + strsplit(s, lines[n], '\t'); + sch_name[n] = s[0]; + sch_value[n] = s[1]; + sch_package[n] = s[2]; + sch_sheet[n] = strtol(s[3]); + sprintf(DeviceList[n], "%s\t%s\t%s\t%d", sch_name[n] , sch_value[n], sch_package[n], sch_sheet[n] ); + } + } + menue(); +} + +// *** Schematic *** +if (schematic) { + string s_value[], s_package[]; + int s_sheet[]; + string s_name_no_pac[]; + string s_value_no_pac[]; + string s_package_no_pac[]; + int s_sheet_no_pac[]; + + schematic(S) { + S.sheets(SH) { + SH.parts(PA) { + if (PA.device.package) { + int PACcontact = 0; + PA.device.package.contacts(C) { + PACcontact++; + break; + } + if (PACcontact) { + if (noexist(PA.name, sch_cnt)) { + s_name[sch_cnt] = PA.name; + s_value[sch_cnt] = PA.value; + s_package[sch_cnt] = PA.device.package.name; + PA.instances(IN) { // Gate + if (IN.sheet) { + s_sheet[sch_cnt] = IN.sheet; + sch_cnt++; + break; + } + } + } + } + else { + s_name_no_pac[sch_cnt_no_pac] = PA.name; + s_value_no_pac[sch_cnt_no_pac] = PA.value; + s_package_no_pac[sch_cnt_no_pac] = PA.device.package.name; + PA.instances(IN) { // Gate + if (IN.sheet) { + s_sheet_no_pac[sch_cnt_no_pac] = IN.sheet; + sch_cnt_no_pac++; + break; + } + } + } + } + } + } + sort (sch_cnt, sch_Index, s_name); + for (n = 0; n < sch_cnt; n++) { + sch_name[n] = s_name[sch_Index[n]] ; + sch_value[n] = s_value[sch_Index[n]] ; + sch_package[n] = s_package[sch_Index[n]]; + sch_sheet[n] = s_sheet[sch_Index[n]]; + sprintf(DeviceList[n], "%s\t%s\t%s\t%d", sch_name[n] , sch_value[n], sch_package[n], sch_sheet[n]); + } + for (n = 0; n < sch_cnt_no_pac; n++) { + sch_name_no_pac[n] = s_name_no_pac[n] ; + sch_value_no_pac[n] = s_value_no_pac[n] ; + sch_package_no_pac[n] = s_package_no_pac[n]; + sch_sheet_no_pac[n] = s_sheet_no_pac[n]; + sprintf(DeviceList_no_pac[n], "%s\t%s\t%s\t%d", sch_name_no_pac[n] , sch_value_no_pac[n], sch_package_no_pac[n], sch_sheet_no_pac[n]); + } + + if (runcount < 1) { + output(readfile, "wtD") { + for(int x = 0; x < sch_cnt; x++) { + printf("%s\t%s\t%s\t%d\n", sch_name[x], sch_value[x], sch_package[x], sch_sheet[x] ); + } + } + output(readfile_no_pac, "wtD") { + for(int x = 0; x < sch_cnt_no_pac; x++) { + printf("%s\t%s\t%s\t%d\n", sch_name_no_pac[x], sch_value_no_pac[x], sch_package_no_pac[x], sch_sheet_no_pac[x] ); + } + } + runcount++; + string cmd; + sprintf( cmd, "edit '%s';\n run '%s' BRD %d;\n", filesetext(S.name, ".brd"), argv[0], runcount ); + exit(cmd); + } + brd_cnt = lines_cnt; + string s[]; + for ( n = 0; n < brd_cnt; n++) { + strsplit(s, lines[n], '\t'); + brd_name[n] = s[0]; + brd_value[n] = s[1]; + brd_package[n] = s[2]; + sprintf(ElementList[n], "%s\t%s\t%s\t0", brd_name[n], brd_value[n], brd_package[n] ); + } + } + menue(); +} diff --git a/trunk/ulp/make_bga_package.bmp b/trunk/ulp/make_bga_package.bmp new file mode 100644 index 00000000..1930fc47 Binary files /dev/null and b/trunk/ulp/make_bga_package.bmp differ diff --git a/trunk/ulp/make_package_dual.bmp b/trunk/ulp/make_package_dual.bmp new file mode 100644 index 00000000..ae5eeb9c Binary files /dev/null and b/trunk/ulp/make_package_dual.bmp differ diff --git a/trunk/ulp/make_package_meass_pacinfo.bmp b/trunk/ulp/make_package_meass_pacinfo.bmp new file mode 100644 index 00000000..9d5a3553 Binary files /dev/null and b/trunk/ulp/make_package_meass_pacinfo.bmp differ diff --git a/trunk/ulp/make_package_meass_pacinfo2.bmp b/trunk/ulp/make_package_meass_pacinfo2.bmp new file mode 100644 index 00000000..3f66416c Binary files /dev/null and b/trunk/ulp/make_package_meass_pacinfo2.bmp differ diff --git a/trunk/ulp/make_package_meass_padinfo-oct.bmp b/trunk/ulp/make_package_meass_padinfo-oct.bmp new file mode 100644 index 00000000..969b9a54 Binary files /dev/null and b/trunk/ulp/make_package_meass_padinfo-oct.bmp differ diff --git a/trunk/ulp/make_package_meass_padinfo-round.bmp b/trunk/ulp/make_package_meass_padinfo-round.bmp new file mode 100644 index 00000000..67865d6b Binary files /dev/null and b/trunk/ulp/make_package_meass_padinfo-round.bmp differ diff --git a/trunk/ulp/make_package_meass_padinfo-sqr.bmp b/trunk/ulp/make_package_meass_padinfo-sqr.bmp new file mode 100644 index 00000000..8ed8ac8a Binary files /dev/null and b/trunk/ulp/make_package_meass_padinfo-sqr.bmp differ diff --git a/trunk/ulp/make_package_meass_smdinfo.bmp b/trunk/ulp/make_package_meass_smdinfo.bmp new file mode 100644 index 00000000..3db9de0f Binary files /dev/null and b/trunk/ulp/make_package_meass_smdinfo.bmp differ diff --git a/trunk/ulp/make_package_quad_left.bmp b/trunk/ulp/make_package_quad_left.bmp new file mode 100644 index 00000000..6e0510c8 Binary files /dev/null and b/trunk/ulp/make_package_quad_left.bmp differ diff --git a/trunk/ulp/make_package_quad_middle.bmp b/trunk/ulp/make_package_quad_middle.bmp new file mode 100644 index 00000000..719d6d49 Binary files /dev/null and b/trunk/ulp/make_package_quad_middle.bmp differ diff --git a/trunk/ulp/make_symbol_dual1.bmp b/trunk/ulp/make_symbol_dual1.bmp new file mode 100644 index 00000000..c9382bce Binary files /dev/null and b/trunk/ulp/make_symbol_dual1.bmp differ diff --git a/trunk/ulp/make_symbol_dual2.bmp b/trunk/ulp/make_symbol_dual2.bmp new file mode 100644 index 00000000..c09a12d8 Binary files /dev/null and b/trunk/ulp/make_symbol_dual2.bmp differ diff --git a/trunk/ulp/make_symbol_quad.bmp b/trunk/ulp/make_symbol_quad.bmp new file mode 100644 index 00000000..f65171a2 Binary files /dev/null and b/trunk/ulp/make_symbol_quad.bmp differ diff --git a/trunk/ulp/make_symbol_single.bmp b/trunk/ulp/make_symbol_single.bmp new file mode 100644 index 00000000..7097a61f Binary files /dev/null and b/trunk/ulp/make_symbol_single.bmp differ diff --git a/trunk/ulp/make_symbol_stripe.bmp b/trunk/ulp/make_symbol_stripe.bmp new file mode 100644 index 00000000..d5d72e3c Binary files /dev/null and b/trunk/ulp/make_symbol_stripe.bmp differ diff --git a/trunk/ulp/maskdata.ulp b/trunk/ulp/maskdata.ulp new file mode 100644 index 00000000..d94ff808 --- /dev/null +++ b/trunk/ulp/maskdata.ulp @@ -0,0 +1,752 @@ +#usage "This EAGLE User Language Program generates a script file " + "maskdata.scr that generates new layers for solder stop mask " + "and cream frame. See parameter section in this file.

    " + "
    " + "In these layers each symbol can be edited separately." + "
    " + "Known limitation: Octagon shaped pads are covered with a round stop symbol." + "

    " + "Das ULP erzeugt ein Script-File maskdata.scr, das vier " + "neue Layer fuer die Loetstop- und Lotpastensymbole erzuegt. " + "Die Definition kann im Abschnitt parameter veraendert werden. " + "
    " + "In diesem Layer kann jedes Symbol einzeln bearbeitet werden." + "
    " + "Einschraenkungen: Octagon Pads erhalten eine runde Loetstoppmake!" + "" + +/* +Tue Nov 23 14:21:02 1999 +This ULP generates new layers for solder stop mask and cream frame. +This allows to edit/delete certain symbols. +Mit diesem ULP kann man eigene Layer fuer die Loetstoppmaske bzw. +Lotpastenmaske erzeugen. Diese Symbole koennen einzeln editiert werden. +Uploaded by Richard Hammerl from CadSoft Computer GmbH +*/ + +#require 5.0600 + +string Version = "1.0.1"; // 2010-05-11 adapted to Eagle Version 5.x alf@cadsoft.de + // extended to Long- and Offset-PAD, + // draw also RECTS, CIRCLES, WIRES, POLYGONS in packages on Layer 29,30,31,32 + // and RECTS, CIRCLES, WIRES, POLYGONS in board on Layer 29,30,31,32 to new layer + // 2010-05-18 accept Rountness of SMD alf@cadsoft.de + + +// ------------------------------------------------------------------ +// ---------- parameter section ------------------------------------- + +real stopframe = 0.00; // Defines the parameter STOPFRAME in mm +real creamframe = 0.00; // Defines the parameter CREAMFRAME in mm + +int tstop_new = 129, // To define the new mask data layers + bstop_new = 130, // here you can change the layer numbers + tcream_new = 131, // as you like + bcream_new = 132; + + +// ------------------------------------------------------------------ +// ---------- program section --------------------------------------- + + +real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } +} + +real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } +} + + +board(B) { + string scrfile = filesetext(B.name, "~maskdata.scr"); + + output(scrfile, "wtD") { + printf("grid mm finest;\n"); + printf("SET WIRE_BEND 2;\n"); + printf("Layer %d mytstop;\n", tstop_new); + printf("Layer %d mybstop;\n", bstop_new); + printf("Layer %d mytcream;\n", tcream_new); + printf("Layer %d mybcream;\n", bcream_new); + + + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + if (C.pad.flags & PAD_FLAG_STOP) { + if (C.pad.shape[16] == PAD_SHAPE_ROUND) { + printf("Change Layer %d;\n", tstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.pad.x), u2mm(C.pad.y), + u2mm(C.pad.x), stopframe + u2mm((C.pad.y)+((C.pad.diameter[16])/2)) + ); + printf("Change Layer %d;\n", bstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.pad.x), u2mm(C.pad.y), + u2mm(C.pad.x), stopframe + u2mm((C.pad.y)+((C.pad.diameter[16])/2)) + ); + } + + if (C.pad.shape[16] == PAD_SHAPE_SQUARE) { + + printf("Change Layer %d;\n", tstop_new); + printf("Rect (%.4f %.4f) (%.4f %.4f);\n", + u2mm((C.pad.x)-(C.pad.diameter[16]/2)) - stopframe, u2mm((C.pad.y)+(C.pad.diameter[16]/2)) + stopframe, + u2mm((C.pad.x)+(C.pad.diameter[16]/2)) + stopframe, u2mm((C.pad.y)-(C.pad.diameter[16]/2)) - stopframe + ); + + printf("Change Layer %d;\n", bstop_new); + printf("Rect (%.4f %.4f) (%.4f %.4f);\n", + u2mm((C.pad.x)-(C.pad.diameter[16]/2)) - stopframe, u2mm((C.pad.y)+(C.pad.diameter[16]/2)) + stopframe, + u2mm((C.pad.x)+(C.pad.diameter[16]/2)) + stopframe, u2mm((C.pad.y)-(C.pad.diameter[16]/2)) - stopframe + ); + } + + if (C.pad.shape[16] == PAD_SHAPE_OCTAGON) { //the same way like ROUND!! + + printf("Change Layer %d;\n", tstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.pad.x), u2mm(C.pad.y), + u2mm(C.pad.x), stopframe + u2mm((C.pad.y)+((C.pad.diameter[16])/2)) + ); + + printf("Change Layer %d;\n", bstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.pad.x), u2mm(C.pad.y), + u2mm(C.pad.x), stopframe + u2mm((C.pad.y)+((C.pad.diameter[16])/2)) + ); + } + + if (C.pad.shape[16] == PAD_SHAPE_LONG) { + printf("Change Layer %d;\n", tstop_new); + printf("Wire %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.pad.diameter[16]) + (2 * stopframe), //Wirewidth+Uebermass + u2mm(C.pad.x) + Xneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x+C.pad.diameter[16]/2), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.y) + Yneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x+C.pad.diameter[16]/2), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.x) + Xneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x-C.pad.diameter[16]/2), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.y) + Yneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x-C.pad.diameter[16]/2), u2mm(C.pad.y), C.pad.angle) + ); + printf("Change Layer %d;\n", bstop_new); + printf("Wire %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.pad.diameter[16]) + (2 * stopframe), //Wirewidth+Uebermass + u2mm(C.pad.x) + Xneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x+C.pad.diameter[16]/2), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.y) + Yneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x+C.pad.diameter[16]/2), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.x) + Xneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x-C.pad.diameter[16]/2), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.y) + Yneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x-C.pad.diameter[16]/2), u2mm(C.pad.y), C.pad.angle) + ); + } + + // Bei den laenglichen Pads ist der groessere der beiden Durchmesser als Parameter anzugeben. + // Das Seitenverhaeltnis ist fest auf 2:1 eingestellt. + + if (C.pad.shape[16] == PAD_SHAPE_OFFSET) { + printf("Change Layer %d;\n", tstop_new); + printf("Wire %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.pad.diameter[16]) + (2 * stopframe), + u2mm(C.pad.x) + Xneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x-C.pad.diameter[16]*1), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.y) + Yneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x-C.pad.diameter[16]*1), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.x) + Xneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.y) + Yneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x), u2mm(C.pad.y), C.pad.angle) + ); + printf("Change Layer %d;\n", bstop_new); + printf("Wire %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.pad.diameter[16]) + (2 * stopframe), + u2mm(C.pad.x) + Xneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x-C.pad.diameter[16]*1), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.y) + Yneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x-C.pad.diameter[16]*1), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.x) + Xneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x), u2mm(C.pad.y), C.pad.angle), + u2mm(C.pad.y) + Yneu(u2mm(C.pad.x), u2mm(C.pad.y), u2mm(C.pad.x), u2mm(C.pad.y), C.pad.angle) + ); + } + } + } + else if (C.smd) { + if (C.smd.flags & SMD_FLAG_STOP) { + if (C.smd.layer == 1) { //solder stop and cream frame for top smds + printf("Change Layer %d;\n", tstop_new); + } + else if (C.smd.layer == 16) { //solder stop and cream frame for bottom smds + printf("Change Layer %d;\n", bstop_new); + } + if (C.smd.roundness) { // 2010-05-12 alf@cadsoft.de + if (C.smd.roundness == 100) { + if (C.smd.dx == C.smd.dy) { + printf("CIRCLE 0.0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.smd.x), u2mm(C.smd.y), + u2mm((C.smd.x)+(C.smd.dx/2)) + stopframe, u2mm(C.smd.y) + ); + } + else { + if (C.smd.dx > C.smd.dy) { + printf("WIRE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.smd.dy) + 2 * stopframe, + u2mm(C.smd.x) + Xneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-(C.smd.dx/2-C.smd.dy/2))-stopframe/4, u2mm(C.smd.y), C.smd.angle), + u2mm(C.smd.y) + Yneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-(C.smd.dx/2-C.smd.dy/2))-stopframe/4, u2mm(C.smd.y), C.smd.angle), + u2mm(C.smd.x) + Xneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+(C.smd.dx/2-C.smd.dy/2))+stopframe/4, u2mm(C.smd.y), C.smd.angle), + u2mm(C.smd.y) + Yneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+(C.smd.dx/2-C.smd.dy/2))+stopframe/4, u2mm(C.smd.y), C.smd.angle) + ); + } + else { + printf("WIRE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.smd.dx) + 2 * stopframe, + u2mm(C.smd.x) + Xneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x), u2mm(C.smd.y-(C.smd.dy/2-C.smd.dx/2))-stopframe/4, C.smd.angle), + u2mm(C.smd.y) + Yneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x), u2mm(C.smd.y-(C.smd.dy/2-C.smd.dx/2))-stopframe/4, C.smd.angle), + u2mm(C.smd.x) + Xneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x), u2mm(C.smd.y+(C.smd.dy/2-C.smd.dx/2))+stopframe/4, C.smd.angle), + u2mm(C.smd.y) + Yneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x), u2mm(C.smd.y+(C.smd.dy/2-C.smd.dx/2))+stopframe/4, C.smd.angle) + ); + } + } + } + else { + real pw = u2mm(C.smd.dx) / 100 * C.smd.roundness; // 2010-05-18 alf@cadsoft.de + if (C.smd.dy < C.smd.dx) pw = u2mm(C.smd.dy) / 100 * C.smd.roundness / 1.0; + printf("POLyGON %.4f (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + pw, + // 1. 90 + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-stopframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-stopframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-stopframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-stopframe, C.smd.angle), + // 1 gerade + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+C.smd.dx/2)-pw/2+stopframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-stopframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+C.smd.dx/2)-pw/2+stopframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-stopframe, C.smd.angle), + // 2 gerade + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+C.smd.dx/2)-pw/2+stopframe, u2mm(C.smd.y+C.smd.dy/2)-pw/2+stopframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+C.smd.dx/2)-pw/2+stopframe, u2mm(C.smd.y+C.smd.dy/2)-pw/2+stopframe, C.smd.angle), + // 3 gerade + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-stopframe, u2mm(C.smd.y+C.smd.dy/2)-pw/2+stopframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-stopframe, u2mm(C.smd.y+C.smd.dy/2)-pw/2+stopframe, C.smd.angle), + // 4 gerade + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-stopframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-stopframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-stopframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-stopframe, C.smd.angle) + ); + } + } + else { + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + C.smd.angle, + u2mm((C.smd.x)-(C.smd.dx/2)) - stopframe, u2mm((C.smd.y)+(C.smd.dy/2)) + stopframe, + u2mm((C.smd.x)+(C.smd.dx/2)) + stopframe, u2mm((C.smd.y)-(C.smd.dy/2)) - stopframe + ); + } + } + if (C.smd.flags & SMD_FLAG_CREAM) { + if (C.smd.layer == 1) { //solder stop and cream frame for top smds + printf("Change Layer %d;\n", tcream_new); + } + if (C.smd.layer == 16) { //solder stop and cream frame for top smds + printf("Change Layer %d;\n", bcream_new); + } + if (C.smd.roundness) { // 2010-05-12 alf@cadsoft.de + if (C.smd.roundness == 100) { + if (C.smd.dx == C.smd.dy) { + printf("CIRCLE 0.0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.smd.x), u2mm(C.smd.y), + u2mm((C.smd.x)+(C.smd.dx/2)) + creamframe, u2mm(C.smd.y) + ); + } + else { + if (C.smd.dy < C.smd.dx) { + printf("WIRE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.smd.dy) + 2 * creamframe, + u2mm(C.smd.x) + Xneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-(C.smd.dx/2-C.smd.dy/2))-creamframe/4, u2mm(C.smd.y), C.smd.angle), + u2mm(C.smd.y) + Yneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-(C.smd.dx/2-C.smd.dy/2))-creamframe/4, u2mm(C.smd.y), C.smd.angle), + u2mm(C.smd.x) + Xneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+(C.smd.dx/2-C.smd.dy/2))+creamframe/4, u2mm(C.smd.y), C.smd.angle), + u2mm(C.smd.y) + Yneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+(C.smd.dx/2-C.smd.dy/2))+creamframe/4, u2mm(C.smd.y), C.smd.angle) + ); + } + else { + printf("WIRE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.smd.dx) + 2 * creamframe, + u2mm(C.smd.x) + Xneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x), u2mm(C.smd.y-(C.smd.dy/2-C.smd.dx/2))-creamframe/4, C.smd.angle), + u2mm(C.smd.y) + Yneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x), u2mm(C.smd.y-(C.smd.dy/2-C.smd.dx/2))-creamframe/4, C.smd.angle), + u2mm(C.smd.x) + Xneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x), u2mm(C.smd.y+(C.smd.dy/2-C.smd.dx/2))+creamframe/4, C.smd.angle), + u2mm(C.smd.y) + Yneu(u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x), u2mm(C.smd.y+(C.smd.dy/2-C.smd.dx/2))+creamframe/4, C.smd.angle) + ); + } + } + } + else { + real pw = u2mm(C.smd.dx) / 100 * C.smd.roundness; // 2010-05-18 alf@cadsoft.de + if (C.smd.dy < C.smd.dx) pw = u2mm(C.smd.dy) / 100 * C.smd.roundness / 1.0; + printf("POLyGON %.4f (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + pw, + // 1. 90 + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-creamframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-creamframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-creamframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-creamframe, C.smd.angle), + // 1 gerade + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+C.smd.dx/2)-pw/2+creamframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-creamframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+C.smd.dx/2)-pw/2+creamframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-creamframe, C.smd.angle), + // 2 gerade + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+C.smd.dx/2)-pw/2+creamframe, u2mm(C.smd.y+C.smd.dy/2)-pw/2+creamframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x+C.smd.dx/2)-pw/2+creamframe, u2mm(C.smd.y+C.smd.dy/2)-pw/2+creamframe, C.smd.angle), + // 3 gerade + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-creamframe, u2mm(C.smd.y+C.smd.dy/2)-pw/2+creamframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-creamframe, u2mm(C.smd.y+C.smd.dy/2)-pw/2+creamframe, C.smd.angle), + // 4 gerade + u2mm(C.smd.x) + Xneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-creamframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-creamframe, C.smd.angle), + u2mm(C.smd.y) + Yneu( u2mm(C.smd.x), u2mm(C.smd.y), u2mm(C.smd.x-C.smd.dx/2)+pw/2-creamframe, u2mm(C.smd.y-C.smd.dy/2)+pw/2-creamframe, C.smd.angle) + ); + } + } + else { + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + C.smd.angle, + u2mm((C.smd.x)-(C.smd.dx/2)) - creamframe, u2mm((C.smd.y)+(C.smd.dy/2)) + creamframe, + u2mm((C.smd.x)+(C.smd.dx/2)) + creamframe, u2mm((C.smd.y)-(C.smd.dy/2)) - creamframe + ); + + } + } + } + } + + E.package.holes(H) { + printf("Change Layer %d;\n", tstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(H.x), u2mm(H.y), + u2mm(H.x), u2mm((H.y)+((H.drill)/2)) + stopframe + ); + printf("Change Layer %d;\n", bstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(H.x), u2mm(H.y), + u2mm(H.x), u2mm((H.y)+((H.drill)/2)) + stopframe + ); + } + + E.package.rectangles(R) { + if (R.layer == 29) { + printf("Change Layer %d;\n", tstop_new); + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), + u2mm(R.x2), u2mm(R.y2) + ); + } + else if (R.layer == 30) { + printf("Change Layer %d;\n", bstop_new); + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), + u2mm(R.x2), u2mm(R.y2) + ); + } + else if (R.layer == 31) { + printf("Change Layer %d;\n", tcream_new); + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), + u2mm(R.x2), u2mm(R.y2) + ); + } + else if (R.layer == 32) { + printf("Change Layer %d;\n", bcream_new); + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), + u2mm(R.x2), u2mm(R.y2) + ); + } + } + E.package.polygons(P) { + if (P.layer == 29) { + printf("Change Layer %d;\n", tstop_new); + int first = 1; + P.wires(W) { + if (first) { + printf("POLYGON %.1f (%.4f %.4f) %+.4f (%.4f %.4f) \n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + first = 0; + } + else { + printf(" %+.4f (%.4f %.4f) \n", + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + } + printf(";\n"); + } + if (P.layer == 30) { + printf("Change Layer %d;\n", bstop_new); + int first = 1; + P.wires(W) { + if (first) { + printf("POLYGON %.1f (%.4f %.4f) %+.4f (%.4f %.4f) \n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + first = 0; + } + else { + printf(" %+.4f (%.4f %.4f) \n", + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + } + printf(";\n"); + } + if (P.layer == 31) { + printf("Change Layer %d;\n", tcream_new); + int first = 1; + P.wires(W) { + if (first) { + printf("POLYGON %.1f (%.4f %.4f) %+.4f (%.4f %.4f) \n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + first = 0; + } + else { + printf(" %+.4f (%.4f %.4f) \n", + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + } + printf(";\n"); + } + if (P.layer == 32) { + printf("Change Layer %d;\n", bcream_new); + int first = 1; + P.wires(W) { + if (first) { + printf("POLYGON %.1f (%.4f %.4f) %+.4f (%.4f %.4f) \n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + first = 0; + } + else { + printf(" %+.4f (%.4f %.4f) \n", + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + } + printf(";\n"); + } + } + + E.package.circles(C) { + if (C.layer == 29) { + printf("Change Layer %d;\n", tstop_new); + printf("CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x) + u2mm(C.radius), u2mm(C.y) + ); + } + else if (C.layer == 30) { + printf("Change Layer %d;\n", bstop_new); + printf("CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x) + u2mm(C.radius), u2mm(C.y) + ); + } + else if (C.layer == 31) { + printf("Change Layer %d;\n", tcream_new); + printf("CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x) + u2mm(C.radius), u2mm(C.y) + ); + } + else if (C.layer == 32) { + printf("Change Layer %d;\n", bcream_new); + printf("CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x) + u2mm(C.radius), u2mm(C.y) + ); + } + } + E.package.wires(W) { + if (W.layer == 29) { + printf("Change Layer %d;\n", tstop_new); + printf("WIRE %.4f (%.4f %.4f) %+.4f (%.4f %.4f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + else if (W.layer == 30) { + printf("Change Layer %d;\n", bstop_new); + printf("WIRE %.4f (%.4f %.4f) %+.4f (%.4f %.4f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + else if (W.layer == 31) { + printf("Change Layer %d;\n", tcream_new); + printf("WIRE %.4f (%.4f %.4f) %+.4f (%.4f %.4f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + else if (W.layer == 32) { + printf("Change Layer %d;\n", bcream_new); + printf("WIRE %.4f (%.4f %.4f) %+.4f (%.4f %.4f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + } + } + + B.holes(HO) { + printf("Change Layer %d;\n", tstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(HO.x), u2mm(HO.y), + u2mm(HO.x), u2mm((HO.y)+((HO.drill)/2)) + stopframe + ); + + printf("Change Layer %d;\n", bstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(HO.x), u2mm(HO.y), + u2mm(HO.x), u2mm((HO.y)+((HO.drill)/2)) + stopframe + ); + } + + B.signals(S) { + S.vias(V) { + if (V.shape[16] == VIA_SHAPE_ROUND) { + printf("Change Layer %d;\n", tstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(V.x), u2mm(V.y), + u2mm(V.x), stopframe + u2mm((V.y)+((V.diameter[16])/2)) + ); + printf("Change Layer %d;\n", bstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(V.x), u2mm(V.y), + u2mm(V.x), stopframe + u2mm((V.y)+((V.diameter[16])/2)) + ); + } + + if (V.shape[16] == VIA_SHAPE_OCTAGON) { //the same way as ROUND + printf("Change Layer %d;\n", tstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(V.x), u2mm(V.y), + u2mm(V.x), stopframe + u2mm((V.y)+((V.diameter[16])/2)) + ); + printf("Change Layer %d;\n", bstop_new); + printf("Circle 0 (%.4f %.4f) (%.4f %.4f);\n", + u2mm(V.x), u2mm(V.y), + u2mm(V.x), stopframe + u2mm((V.y)+((V.diameter[16])/2)) + ); + } + + if (V.shape[16] == VIA_SHAPE_SQUARE) { + printf("Change Layer %d;\n", tstop_new); + printf("Rect (%.4f %.4f) (%.4f %.4f);\n", + u2mm((V.x)-(V.diameter[16]/2)) - stopframe, u2mm((V.y)+(V.diameter[16]/2)) + stopframe, + u2mm((V.x)+(V.diameter[16]/2)) + stopframe, u2mm((V.y)-(V.diameter[16]/2)) - stopframe + ); + printf("Change Layer %d;\n", bstop_new); + printf("Rect (%.4f %.4f) (%.4f %.4f);\n", + u2mm((V.x)-(V.diameter[16]/2)) - stopframe, u2mm((V.y)+(V.diameter[16]/2)) + stopframe, + u2mm((V.x)+(V.diameter[16]/2)) + stopframe, u2mm((V.y)-(V.diameter[16]/2)) - stopframe + ); + } + } + } + B.rectangles(R) { + if (R.layer == 29) { + printf("Change Layer %d;\n", tstop_new); + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), + u2mm(R.x2), u2mm(R.y2) + ); + } + else if (R.layer == 30) { + printf("Change Layer %d;\n", bstop_new); + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), + u2mm(R.x2), u2mm(R.y2) + ); + } + else if (R.layer == 31) { + printf("Change Layer %d;\n", tcream_new); + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), + u2mm(R.x2), u2mm(R.y2) + ); + } + else if (R.layer == 32) { + printf("Change Layer %d;\n", bcream_new); + printf("Rect R%.1f (%.4f %.4f) (%.4f %.4f);\n", + R.angle, + u2mm(R.x1), u2mm(R.y1), + u2mm(R.x2), u2mm(R.y2) + ); + } + } + B.circles(C) { + if (C.layer == 29) { + printf("Change Layer %d;\n", tstop_new); + printf("CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x) + u2mm(C.radius), u2mm(C.y) + ); + } + else if (C.layer == 30) { + printf("Change Layer %d;\n", bstop_new); + printf("CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x) + u2mm(C.radius), u2mm(C.y) + ); + } + else if (C.layer == 31) { + printf("Change Layer %d;\n", tcream_new); + printf("CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x) + u2mm(C.radius), u2mm(C.y) + ); + } + else if (C.layer == 32) { + printf("Change Layer %d;\n", bcream_new); + printf("CIRCLE %.4f (%.4f %.4f) (%.4f %.4f);\n", + u2mm(C.width), + u2mm(C.x), u2mm(C.y), + u2mm(C.x) + u2mm(C.radius), u2mm(C.y) + ); + } + } + B.wires(W) { + if (W.layer == 29) { + printf("Change Layer %d;\n", tstop_new); + printf("WIRE %.4f (%.4f %.4f) %+.4f (%.4f %.4f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + else if (W.layer == 30) { + printf("Change Layer %d;\n", bstop_new); + printf("WIRE %.4f (%.4f %.4f) %+.4f (%.4f %.4f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + else if (W.layer == 31) { + printf("Change Layer %d;\n", tcream_new); + printf("WIRE %.4f (%.4f %.4f) %+.4f (%.4f %.4f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + else if (W.layer == 32) { + printf("Change Layer %d;\n", bcream_new); + printf("WIRE %.4f (%.4f %.4f) %+.4f (%.4f %.4f);\n", + u2mm(W.width), + u2mm(W.x1), u2mm(W.y1), + W.curve, + u2mm(W.x2), u2mm(W.y2) + ); + } + } + printf("grid last;"); + } + exit("SCRIPT '" + scrfile + "'"); +} diff --git a/trunk/ulp/microstrip-radial-stub.bmp b/trunk/ulp/microstrip-radial-stub.bmp new file mode 100644 index 00000000..123a04c0 Binary files /dev/null and b/trunk/ulp/microstrip-radial-stub.bmp differ diff --git a/trunk/ulp/microstrip-radial-stub.ulp b/trunk/ulp/microstrip-radial-stub.ulp new file mode 100644 index 00000000..a3c176b3 --- /dev/null +++ b/trunk/ulp/microstrip-radial-stub.ulp @@ -0,0 +1,298 @@ +#usage "Draw a Microstrip Radial Stub

    " + "RUN microstrip-radial-stub" + "

    " + "Author: support@cadsoft.de " + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +int grid = 1; +string GridUnit[] = { "MIC", "MM", "MIL", "INCH" }; +real GridWidth[] = { 10.2, 0.0102, 0.4, 0.0004 }; // default by grid +if (board) { board(B) grid = B.grid.unit; } +if (library) { library(L) grid = L.grid.unit; } + +real width = GridWidth[grid]; +string layer = "1"; +string gridstr = ""; +real D = 0.01; +real L = 0.99; + +real angle = 30.0; // angle of Stub +int arcres = angle / 3; // resolution of angle in steps +real angle_offset = 0.0; // rotate the complete stub +int polygon = 1; // draw as polygon +real arcsinXa; +real arcsinYa; +real arcsinXe; +real arcsinYe; +real ox, oy; // offset X Y +string signame = ""; + +string cmd_draw_info = ""; +string s; +string h; +string err = " "; + +int rank = 0; +if (board) rank = 1; +string polyinit; +sprintf (polyinit, "CHANGE ORPHANS ON;\nCHANGE POUR SOLID;\nCHANGE RANK %d;\n", rank); + +real wwidth2; +real RadiusL; +real angleL; + +int test = 0; + +// ******************** Functions **************************** +string esigname(string sig) { + if (sig) sig = "'" + sig + "'"; + return sig; +} + +// ************************************************************************ +string xy_arc( real ang, real radius, real offx, real offy) { + string xy; + real rad = PI / 180 * ang; + sprintf(xy, "(%.4f %.4f)\n", + offx + (cos(rad) * radius), + offy + (sin(rad) * radius) ); + return xy; +} + +real bogenY2( real ang, real radius) { + real rad = PI / 180 * (ang/2); + return sin(rad) * radius; +} + +real bogenX( real ang, real radius) { + real rad = PI / 180 * (ang/2); + return cos(rad) * radius; +} + + +// *** +real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); } +} + +real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); } +} + + +real radiusY(real ang, real rry) { + real r = (rry*2) / sin(PI / 180 * ang) / 2; + return r; +} + + +string check_values(void) { + string error = ""; + wwidth2 = width/2; + RadiusL = D + L - wwidth2; + angleL = angle - (width / ((RadiusL * 2 * PI) / 360)); + arcsinXa = bogenX( angle, D) + wwidth2; + arcsinYa = bogenY2( angle, D + wwidth2) - wwidth2; + arcsinXe = arcsinXa; + arcsinYe = -arcsinYa; + if (arcsinYa < 0) { + sprintf(error, "Set D to %.4f while W %.4f < wire width %.4f", + radiusY(angle/2, wwidth2), bogenX( angle, D), width ); + } + return error; +} + + +// *** draw arc *** +string draw_arc(int draw_resol, real draw_radius, real draw_arc_degree, real draw_ang_off, real offx, real offy) { + real start_arc_degree = draw_ang_off - draw_arc_degree/2; + if (start_arc_degree < 0) start_arc_degree += 360; + real end_arc_degree = start_arc_degree + draw_arc_degree; + real arcstep = (end_arc_degree - start_arc_degree) / draw_resol; + string e; + for (real winkel = start_arc_degree; winkel < end_arc_degree + 0.0001; winkel += arcstep) { + e += xy_arc(winkel, draw_radius, offx, offy) ; + } + return e; +} + + +// ************************************************************* +void menue(void) { + dlgDialog("Radial Stub") { + dlgHBoxLayout { + dlgSpacing(150); + dlgLabel("Measures in " + GridUnit[grid] + " (Grid)"); + dlgStretch(1); + dlgGroup(" Draw as") { + dlgVBoxLayout { + dlgRadioButton("W&ire", polygon); + dlgRadioButton("&Polygon", polygon); + dlgHBoxLayout { + dlgLabel("&Width"); + dlgSpacing(15); + dlgRealEdit(width); + dlgStretch(1); + } + } + } + } + dlgHBoxLayout { + dlgLabel(cmd_draw_info, 1); + dlgGridLayout { + dlgCell( 1, 1) dlgLabel(" "); + dlgCell( 2, 1) dlgLabel("Lay&er"); + dlgCell( 2, 2) dlgStringEdit(layer); + dlgCell( 2, 3) dlgSpacing(8); + if (board) { + dlgCell( 2, 4) dlgLabel("&Signal name"); + dlgCell( 2, 5) dlgStringEdit(signame); + } + dlgCell( 6, 1) dlgLabel("&L"); + dlgCell( 6, 2) dlgRealEdit(L, 0, +1600); + dlgCell( 7, 1) dlgLabel("&D"); + dlgCell( 7, 2) dlgRealEdit(D, 0, +1600); + dlgCell( 9, 1) dlgLabel("&Angle"); + dlgCell( 9, 2) dlgRealEdit(angle, 0.0, 180.0); + dlgCell( 9, 4) dlgLabel("Angle &offset "); + dlgCell( 9, 5) dlgRealEdit(angle_offset, 0.0, 360.0); + dlgCell( 10, 1) dlgLabel("A&rc res."); + dlgCell( 10, 2) dlgIntEdit(arcres, 6, 180); + dlgCell( 11, 2) dlgLabel(" (steps)"); + + dlgCell( 14, 4) dlgLabel("&X offset"); + dlgCell( 14, 5) dlgRealEdit(ox, -800.0, +800.0); + dlgCell( 15, 4) dlgLabel("&Y offset"); + dlgCell( 15, 5) dlgRealEdit(oy, -800.0, +800.0); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgVBoxLayout { + dlgSpacing(50); + } + dlgLabel(err, 1); + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+OK") { + err = check_values(); + if (err) { + if (dlgMessageBox(err, "Accept", "No") == 0) { + D = radiusY(angle/2, wwidth2); + err = ""; + } + else if (dlgMessageBox("Confirm (the values) ?", "Yes", "No") == 0) dlgAccept(); + } + else dlgAccept(); + } + dlgPushButton("-Cancel") { dlgReject(); exit(0); } + dlgStretch(1); + } + }; + return; +} + +// ***** Main ****** +void main(void) { + if (library) signame = ""; + menue(); + if (angle_offset) { + real nX = Xneu(arcsinXa, arcsinYa, 0, 0, angle_offset); + real nY = Yneu(arcsinXa, arcsinYa, 0, 0, angle_offset); + arcsinXa = nX; + arcsinYa = nY; + nX = Xneu(arcsinXe, arcsinYe, 0, 0, angle_offset); + nY = Yneu(arcsinXe, arcsinYe, 0, 0, angle_offset); + arcsinXe = nX; + arcsinYe = nY; + } + esigname(signame); + gridstr = GridUnit[grid]; + + sprintf(s, "SET WIRE_BEND 2;\n"); + if (gridstr) s += "GRID " + gridstr + ";\n"; + if (layer) s += "CHANGE LAYER " + layer + ";\n"; + sprintf(h, "CHANGE WIDTH %.4f;\n", width); + s += h; + if (polygon) { + s += polyinit; + sprintf(h, "POLY %s ", signame ); + } + else sprintf(h, "WIRE %s ", signame ); + s += h; + sprintf(h, " (%.4f %.4f)", arcsinXa + ox, arcsinYa + oy); // *** draw sinw *** + s += h; + sprintf(h, " (%.4f %.4f)", arcsinXe + ox, arcsinYe + oy); + s += h; + s += draw_arc(arcres, RadiusL, angleL, angle_offset, ox, oy); // *** draw arc *** + sprintf(h, " (%.4f %.4f)", arcsinXa + ox, arcsinYa +oy); + s += h; + if (gridstr) { + sprintf(h, ";\nGRID LAST;\n"); + s += h; + } + if (test) if (dlgMessageBox(s, "OK", "ESC") != 0) exit (-1); + exit (s); +} diff --git a/trunk/ulp/mill-outlines-bott.bmp b/trunk/ulp/mill-outlines-bott.bmp new file mode 100644 index 00000000..23c59011 Binary files /dev/null and b/trunk/ulp/mill-outlines-bott.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-dim-down.bmp b/trunk/ulp/mill-outlines-cnc-dim-down.bmp new file mode 100644 index 00000000..bf3200bc Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-dim-down.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-down.bmp b/trunk/ulp/mill-outlines-cnc-down.bmp new file mode 100644 index 00000000..16c8897a Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-down.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-drill-down.bmp b/trunk/ulp/mill-outlines-cnc-drill-down.bmp new file mode 100644 index 00000000..78024534 Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-drill-down.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-drill-safety.bmp b/trunk/ulp/mill-outlines-cnc-drill-safety.bmp new file mode 100644 index 00000000..78024534 Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-drill-safety.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-fastvelocity.bmp b/trunk/ulp/mill-outlines-cnc-fastvelocity.bmp new file mode 100644 index 00000000..488481a1 Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-fastvelocity.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-parkposition.bmp b/trunk/ulp/mill-outlines-cnc-parkposition.bmp new file mode 100644 index 00000000..8f6821e4 Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-parkposition.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-rpm.bmp b/trunk/ulp/mill-outlines-cnc-rpm.bmp new file mode 100644 index 00000000..038b6648 Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-rpm.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-safety.bmp b/trunk/ulp/mill-outlines-cnc-safety.bmp new file mode 100644 index 00000000..36ad043c Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-safety.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-up.bmp b/trunk/ulp/mill-outlines-cnc-up.bmp new file mode 100644 index 00000000..225c4c7e Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-up.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc-velocity.bmp b/trunk/ulp/mill-outlines-cnc-velocity.bmp new file mode 100644 index 00000000..bec12bc6 Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc-velocity.bmp differ diff --git a/trunk/ulp/mill-outlines-cnc.bmp b/trunk/ulp/mill-outlines-cnc.bmp new file mode 100644 index 00000000..00f22459 Binary files /dev/null and b/trunk/ulp/mill-outlines-cnc.bmp differ diff --git a/trunk/ulp/mill-outlines-coppdim.bmp b/trunk/ulp/mill-outlines-coppdim.bmp new file mode 100644 index 00000000..802ff0a4 Binary files /dev/null and b/trunk/ulp/mill-outlines-coppdim.bmp differ diff --git a/trunk/ulp/mill-outlines-dimension-contours.bmp b/trunk/ulp/mill-outlines-dimension-contours.bmp new file mode 100644 index 00000000..032a07a2 Binary files /dev/null and b/trunk/ulp/mill-outlines-dimension-contours.bmp differ diff --git a/trunk/ulp/mill-outlines-drc-info.bmp b/trunk/ulp/mill-outlines-drc-info.bmp new file mode 100644 index 00000000..c6566f95 Binary files /dev/null and b/trunk/ulp/mill-outlines-drc-info.bmp differ diff --git a/trunk/ulp/mill-outlines-drill-velocity.bmp b/trunk/ulp/mill-outlines-drill-velocity.bmp new file mode 100644 index 00000000..726037cd Binary files /dev/null and b/trunk/ulp/mill-outlines-drill-velocity.bmp differ diff --git a/trunk/ulp/mill-outlines-drill.bmp b/trunk/ulp/mill-outlines-drill.bmp new file mode 100644 index 00000000..bbf8457a Binary files /dev/null and b/trunk/ulp/mill-outlines-drill.bmp differ diff --git a/trunk/ulp/mill-outlines-eagle.bmp b/trunk/ulp/mill-outlines-eagle.bmp new file mode 100644 index 00000000..2abf5f0b Binary files /dev/null and b/trunk/ulp/mill-outlines-eagle.bmp differ diff --git a/trunk/ulp/mill-outlines-free.bmp b/trunk/ulp/mill-outlines-free.bmp new file mode 100644 index 00000000..515cf1fd Binary files /dev/null and b/trunk/ulp/mill-outlines-free.bmp differ diff --git a/trunk/ulp/mill-outlines-get_board_zero.bmp b/trunk/ulp/mill-outlines-get_board_zero.bmp new file mode 100644 index 00000000..1a0218cc Binary files /dev/null and b/trunk/ulp/mill-outlines-get_board_zero.bmp differ diff --git a/trunk/ulp/mill-outlines-hole.bmp b/trunk/ulp/mill-outlines-hole.bmp new file mode 100644 index 00000000..24d1c85f Binary files /dev/null and b/trunk/ulp/mill-outlines-hole.bmp differ diff --git a/trunk/ulp/mill-outlines-hpgl.bmp b/trunk/ulp/mill-outlines-hpgl.bmp new file mode 100644 index 00000000..ab60d250 Binary files /dev/null and b/trunk/ulp/mill-outlines-hpgl.bmp differ diff --git a/trunk/ulp/mill-outlines-inner-polygon-contour.bmp b/trunk/ulp/mill-outlines-inner-polygon-contour.bmp new file mode 100644 index 00000000..98e4afb3 Binary files /dev/null and b/trunk/ulp/mill-outlines-inner-polygon-contour.bmp differ diff --git a/trunk/ulp/mill-outlines-inner-polygon-contour1.bmp b/trunk/ulp/mill-outlines-inner-polygon-contour1.bmp new file mode 100644 index 00000000..6e060227 Binary files /dev/null and b/trunk/ulp/mill-outlines-inner-polygon-contour1.bmp differ diff --git a/trunk/ulp/mill-outlines-inside-milling.bmp b/trunk/ulp/mill-outlines-inside-milling.bmp new file mode 100644 index 00000000..0ef33849 Binary files /dev/null and b/trunk/ulp/mill-outlines-inside-milling.bmp differ diff --git a/trunk/ulp/mill-outlines-isel.bmp b/trunk/ulp/mill-outlines-isel.bmp new file mode 100644 index 00000000..be6a44bd Binary files /dev/null and b/trunk/ulp/mill-outlines-isel.bmp differ diff --git a/trunk/ulp/mill-outlines-isol-pour.bmp b/trunk/ulp/mill-outlines-isol-pour.bmp new file mode 100644 index 00000000..09cfd719 Binary files /dev/null and b/trunk/ulp/mill-outlines-isol-pour.bmp differ diff --git a/trunk/ulp/mill-outlines-mildimension.bmp b/trunk/ulp/mill-outlines-mildimension.bmp new file mode 100644 index 00000000..d1562bdf Binary files /dev/null and b/trunk/ulp/mill-outlines-mildimension.bmp differ diff --git a/trunk/ulp/mill-outlines-mirror-nc-bottom.bmp b/trunk/ulp/mill-outlines-mirror-nc-bottom.bmp new file mode 100644 index 00000000..4acdc8cb Binary files /dev/null and b/trunk/ulp/mill-outlines-mirror-nc-bottom.bmp differ diff --git a/trunk/ulp/mill-outlines-mirror-nc-top.bmp b/trunk/ulp/mill-outlines-mirror-nc-top.bmp new file mode 100644 index 00000000..923af5d0 Binary files /dev/null and b/trunk/ulp/mill-outlines-mirror-nc-top.bmp differ diff --git a/trunk/ulp/mill-outlines-mirror.bmp b/trunk/ulp/mill-outlines-mirror.bmp new file mode 100644 index 00000000..a6c160cf Binary files /dev/null and b/trunk/ulp/mill-outlines-mirror.bmp differ diff --git a/trunk/ulp/mill-outlines-multi-dimension.bmp b/trunk/ulp/mill-outlines-multi-dimension.bmp new file mode 100644 index 00000000..453ec17c Binary files /dev/null and b/trunk/ulp/mill-outlines-multi-dimension.bmp differ diff --git a/trunk/ulp/mill-outlines-no-blowup.bmp b/trunk/ulp/mill-outlines-no-blowup.bmp new file mode 100644 index 00000000..26f18cc2 Binary files /dev/null and b/trunk/ulp/mill-outlines-no-blowup.bmp differ diff --git a/trunk/ulp/mill-outlines-nomir.bmp b/trunk/ulp/mill-outlines-nomir.bmp new file mode 100644 index 00000000..b0e64b21 Binary files /dev/null and b/trunk/ulp/mill-outlines-nomir.bmp differ diff --git a/trunk/ulp/mill-outlines-null_reference-drilling.bmp b/trunk/ulp/mill-outlines-null_reference-drilling.bmp new file mode 100644 index 00000000..0d42ed8c Binary files /dev/null and b/trunk/ulp/mill-outlines-null_reference-drilling.bmp differ diff --git a/trunk/ulp/mill-outlines-null_reference.bmp b/trunk/ulp/mill-outlines-null_reference.bmp new file mode 100644 index 00000000..1a3d8888 Binary files /dev/null and b/trunk/ulp/mill-outlines-null_reference.bmp differ diff --git a/trunk/ulp/mill-outlines-ovrlpfp.bmp b/trunk/ulp/mill-outlines-ovrlpfp.bmp new file mode 100644 index 00000000..8eb4e964 Binary files /dev/null and b/trunk/ulp/mill-outlines-ovrlpfp.bmp differ diff --git a/trunk/ulp/mill-outlines-ovrlppp.bmp b/trunk/ulp/mill-outlines-ovrlppp.bmp new file mode 100644 index 00000000..7b7c60c0 Binary files /dev/null and b/trunk/ulp/mill-outlines-ovrlppp.bmp differ diff --git a/trunk/ulp/mill-outlines-plus-text.bmp b/trunk/ulp/mill-outlines-plus-text.bmp new file mode 100644 index 00000000..e3cdf24e Binary files /dev/null and b/trunk/ulp/mill-outlines-plus-text.bmp differ diff --git a/trunk/ulp/mill-outlines-pour.bmp b/trunk/ulp/mill-outlines-pour.bmp new file mode 100644 index 00000000..09cfd719 Binary files /dev/null and b/trunk/ulp/mill-outlines-pour.bmp differ diff --git a/trunk/ulp/mill-outlines-question.bmp b/trunk/ulp/mill-outlines-question.bmp new file mode 100644 index 00000000..03038de2 Binary files /dev/null and b/trunk/ulp/mill-outlines-question.bmp differ diff --git a/trunk/ulp/mill-outlines-resolution.bmp b/trunk/ulp/mill-outlines-resolution.bmp new file mode 100644 index 00000000..6ee483a2 Binary files /dev/null and b/trunk/ulp/mill-outlines-resolution.bmp differ diff --git a/trunk/ulp/mill-outlines-script.bmp b/trunk/ulp/mill-outlines-script.bmp new file mode 100644 index 00000000..a1803653 Binary files /dev/null and b/trunk/ulp/mill-outlines-script.bmp differ diff --git a/trunk/ulp/mill-outlines-sec-isol.bmp b/trunk/ulp/mill-outlines-sec-isol.bmp new file mode 100644 index 00000000..be1c6418 Binary files /dev/null and b/trunk/ulp/mill-outlines-sec-isol.bmp differ diff --git a/trunk/ulp/mill-outlines-sec-isolate.bmp b/trunk/ulp/mill-outlines-sec-isolate.bmp new file mode 100644 index 00000000..f5e3c14e Binary files /dev/null and b/trunk/ulp/mill-outlines-sec-isolate.bmp differ diff --git a/trunk/ulp/mill-outlines-spacing.bmp b/trunk/ulp/mill-outlines-spacing.bmp new file mode 100644 index 00000000..a2aa8d43 Binary files /dev/null and b/trunk/ulp/mill-outlines-spacing.bmp differ diff --git a/trunk/ulp/mill-outlines-top.bmp b/trunk/ulp/mill-outlines-top.bmp new file mode 100644 index 00000000..12d690b3 Binary files /dev/null and b/trunk/ulp/mill-outlines-top.bmp differ diff --git a/trunk/ulp/mill-outlines-via.bmp b/trunk/ulp/mill-outlines-via.bmp new file mode 100644 index 00000000..32d66c47 Binary files /dev/null and b/trunk/ulp/mill-outlines-via.bmp differ diff --git a/trunk/ulp/mill-outlines.def b/trunk/ulp/mill-outlines.def new file mode 100644 index 00000000..aec8539f --- /dev/null +++ b/trunk/ulp/mill-outlines.def @@ -0,0 +1,61 @@ +HPGL +2; 1 SelectedDevice +0.20000000; 2 MillToolOutl +0.00000000; 3 MillToolIsolate fuer Polygon-Isolate +0.60000000; 4 MillToolFree +1; 5 SelectedLayer1 +16; 6 SelectedLayer16 +0.8; 7 DrillPad +0.8; 8 DrillVia +0.8; 9 DrillHole +20; 10 OverlapOutlPercent +20; 11 OverlapRubOutPercent +0.50000000; 12 Distance_Copper_Dimension +2.00000000; 13 DimensionMillTool +1; 14 Millfreeyes +10.00000000; 15 Holder_Spacing +0; 16 Onlydrill +1; 17 Generatedrills +2.0; 18 Max_Drill_Diameter +0.00000000; 19 Z_down +0.00000000; 20 Drill_z_deep +0.00000000; 21 Mill_z_safety +0; 22 Spindle_rpm +0.00000000; 23 Tool_vel +0.00000000; 24 Fast_vel +0.00000000; 25 Drill_Vel +0; 26 DrillRefOn +3.00000000; 27 DrillRefDiameter +-6.00000000; 28 DrillRefDeep +1; 29 UseRack +0; 30 SelectedPlusLayerTop +0; 31 SelectedPlusLayerBot +1; 32 Mirror_On +1; 33 MachineMenuOn +0.00000000; 34 ParkXposition +0.00000000; 35 ParkYposition +0.00000000; 36 ParkZposition +0.00000000; 37 Z_dimension +1; 38 Dim_on_off +-2.00000000; 39 Mz_down +-3.80000000; 40 Mdrill_z_deep +1.00000000; 41 Mmill_z_safety +15000; 42 Mspindle_rpm +2.00000000; 43 Mtool_vel +5.00000000; 44 Mfast_vel +0.50000000; 45 MDrill_Vel +0; 46 MdrillRefOn +3.00000000; 47 MdrillRefDiameter +-6.00000000; 48 MdrillRefDeep +10.00000000; 49 MparkXposition +10.00000000; 50 MparkYposition +80.00000000; 51 MparkZposition +-3.80000000; 52 Mz_dimension +1; 53 Mdim_on_off +1; 54 Mmillfreeyes +0.60000000; 55 MMillToolFree +2.00000000; 56 MDimensionMillTool +1; 57 MInner_contour +3; 58 CNCmillResolution +0; 58 MillOnlyContour +! *** Do not change the order of this lines *** ! diff --git a/trunk/ulp/mill-outlines.ulp b/trunk/ulp/mill-outlines.ulp new file mode 100644 index 00000000..ddd0023c --- /dev/null +++ b/trunk/ulp/mill-outlines.ulp @@ -0,0 +1,5688 @@ +#usage "en: Export milling data for a board layout in SCRIPT, HPGL, ISEL, CNC\n" + "

    " + "Author: support@cadsoft.de" + , + "de: Export von Fräsdaten aus einem Board in SCRIPT, HPGL, ISEL, CNC" + "

    " + "Author: support@cadsoft.de" + +#require 6.0500 + +// ****************** History ************************************************* +// place VIA with SIGNAL '~_REAL_OUTLINEMILL_~' in to break throgh for milling +// this as outside contour. + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED +// 2002-05-08 - reverse milling +// 2002-06-23 - Polygon:CHANGE THERMAL OFF +// 2003-05-14 - With REFERENCE-Circle (Drill) to mirror for drilling machine +// - Switch On/Off 2. isolate/cupper pouring +// 2003-09-02 - Switch On/Off drills +// 2004-04-24 - String ulp_path no longer necessary +// 2004-07-21 - expand reference package menu +// by select layer, switch mirror on/off +// place VIAs with SIGNAL '~_REAL_OUTLINEMILL_~' +// in to break throgh for milling as outside contour. +// Language en/de +// 2004-08-12 - ISEL Interface/Isel-Zwischenformat +// Referenz: +// | Übersicht des isel Zwischenformat zur Maschinensteuerung +// | "isel ZF in deutsch.pdf" Stand 08.11.1999 +// 2004-10-18 - Abfrage ob DRC fehlerfrei durchlaufen wurde. +// - bei vorhandener .def-Datei werden diese Parameter als Defaultgeladen. +// - Sichern der Einstellungen in def-Datei. +// 2005-05-18 - ** output no shorter filling wires as MillToolFree diameter ** +// - Hinweis auf den erfolgreichen (fehlerfreien) Design-Rule-Check +// damit man im voraus abklären kann ob auch alles mit dem +// benutztenFräser isoliert (gefräst) werden kann. +// - Überprüfung der CLASS-Clerance mit dem Durchmesser des +// Isolationsfräser Tool#1. +// 2005-05-23 - UseRack: (switch), to can use also a Rack with HPGL and Nc-Machine-Code +// for users to have a machine with automaticle tool change. +// UseRack: Wenn mehr als die 3 Standarddurchmesser benutzt werden, +// werden zusätzliche Tools (1/10mm gerundet) generiert für das Bohren +// (auch in HPGL --> SPxx / Script) für Anwender die eine Fräsmaschine mit +// automatischen Werkzeugwechsel besitzen. +// - SP8 in HPGL bedeutet: Die Platine muß auf dem Frästisch umgedreht werden +// ** nur HPGL ** www.cnc-papst.de * reiner_marcus@hotmail.com ** +// 2005-06-16 - Isel-Zwischenformat Extension ".cnp" +// 2005-06-23 - Drilling way optimised / Bohrwege Streckenoptimiert +// - Beim RubOut wird der Fräser nicht angehoben, wenn sich die X-Koordinate +// weniger als der Fräserradius ändert. +// Schalter 'Lift_Off' wird nicht im Menu angezeigt, sondern ist fix im ULP. +// - Zusätzlicher (plus) Layer zum fräsen von Texten in Kupferflächen (Polygon). +// - Maschinen-Menu kann abgeschaltet werden für _nur_ Benutzer von HPGL +// Schalter 'MachineMenuOn' +// ** nur HPGL ** www.cnc-papst.de * reiner_marcus@hotmail.com ** +// +// 2005-09-28 *** für LPKF laut Hr. Böhm (agfeo) keine Formatbeschreibung zu erhalten +// *** wird also wieder gecancelt *** +// +// 2005-09-30 - Device-Reinit bei Layer 45 Holes nicht offset 100 addieren. +// - CNC +// +// 2005-11-21 - LPKF entfernt +// +// 2005-12-22 - Unit & Format bei [Masch. Nullpunkt] [Lade Beispiel] auf mm und 2.4 setzen +// 2006-01-23 - Only Drills gibt jetzt nur die Drills aus +// (ohne Meldung von fehlerhaften Parametern bzw. Layern) +// 2006-01-25 - $ in temporären Namen in ~ (Tilde) geändert. +// - Temporäre Files werden mit "wtD" geöffnet +// - !Generatedrills; keine Abfrage der Bohrdurchmeser auf Gültigkeit +// 2006-02-13 - Wegen Rechenungenauigkeit muß für Fräswege zwischen den Leiterbahnen und +// einem evtl. vorhandenem Füll-Polygon die Spurbreite (Clearance/Isolate) +// zu WIRE (Arc) um Inaccurateness breiter eingestellt werden, da es sonst +// an gebogenen Leiterbahnsegmenten zu Fehlerhaften nicht berechneten Fräswegen +// kommen kann. Also die gefräste Isolation nicht komplett geschlossen ist. +// * Nur Isolationsfräsen: +// Hier wird die Drehrichtung (Rotation) der berechneten Polygon-Kontur +// zu der Kontur von Signal-Polygonen ermittelt, da sich die Kontur der Füllung +// einmal rechts-drehend an den Leiterzug (WIRE/PAD/VIA-Struktur) und einmal +// links-drehend an ein evtl. vorhandenes Polygon (Versorgungs-Polygon)um den +// Leiterzug anschmiegt. +// Dadurch würde die Isolation also der Fräsweg doppelt ausgegeben werden. +// Bei inaktiven [] Rub out werden nur linksdrehende Polygonkonturen ausgegeben +// um den Fräsaufwand zum reinen Isolieren zu minimieren. +// Bei aktiven [] Rub out werden linksdrehende wie auch rechtsdrehende Polygon- +// konturen ausgegeben, um der geätzten Version einer Leiterplatte so nah wie +// Möglich zu kommen. * +// +// 2006-07-26 - Generate separated layer +100 +101 +102 for milling tools. +// - check Polygons of Rank 6. +// - Use Rank 1 of polygon to generate real outline contour +// to milling out from holder. +// - Correct Rank on all generated Polygons. +// 2006-08-01 - Check if POLYGON placed. If Yes, check if CLASS-Clearance 0.005 mm > Tool#1 +// but if problem with routet WIRE out of 0 45 90 Degree. +// Es kann vorkommen, dass durch math. Rundung der Coordinaten das Polygon +// nicht in die Isolationskanäle fliessen kann. +// 2006-11-07 - Ausfräsen aus dem Träger (Dimensionlinie) berichtigt, war nur bei Script aktiv. +// - dru Datei wird gelesen um den tatsächlichen Copper-Dimension Wert zu erhalten, +// ist keine .dru gespeichert wird der defaultvalue benutzt und darauf hingewiesen. +// 2006-12-11 - Maschinen-Menu aus/einschalten mit Checkbox. +// +// 2007-10-08 - Fräserbreiten ab 5 micron zulassen wg. Laser. +// +// 2008-11-12 - Layerzuordnung berichtigt, nicht das Flag, sondern die Layernummer benutzen. +// - Delete von Polygon mit SHIFT und Via mit Ripup. +// - Layerzuweisung vor Kontour fräsen. +// +// 2009-02-04 - Clear via airwire +// 2009-02-05 - Correct mill tool for millout +// 2009-03-31 - Correct koordinate delete special polygon and via # alf@cadsoft.de +// corrected layer to millout (if only Layer 16 selected) +// Holder spacing in script +// Check if Dimension placed +// +// 2010-01-20 - Check DRC-Layer-Setup (1*16) +// Check counts of outlines at layer Dimension +// +// 2010-01-25 - Use contour option positiv/negativ (rotation) +// to switch on/off draw also polygon inside contours +// +// 2010-02-02 - Check and Set DRC-Layer-Setup and CLASS clearance to mill tool #1 + Inaccurateness +// +// 2010-04-08 - Milling always inner contour of pooring +// CNC data finished +// +// 2010-08-06 - Info Durchbrüche als Dialog +// Die gespeicherten Designregeln dürfen bis zu 30 Sekunden alt sein. +// +// 2010-10-28 - Prüfe die Designrules und benutze CLASSen, falls CLASSen benutzt sind, +// sonst ändere die Design-Regeln. +// +// 2011-01-27 - Z-Achse in CNC-Device G00 / G01 Z.. +// Referenzfahrt am Anfang +// Z_down -> Actualmilldeep, zum hochfahren mit -1 multipliziert (pos. Vorzeichen) +// +// 2011-02-02 - Wenn 2. Milling (und Rubout) abgeschaltet waren, dann wurde auch das 1. mal nicht isoliert. +// Milling [ ] innercontour BitMap waren getauscht. +// Wählbare Auflösung 3.2 3.3 3.4 im CNC Menu. +// Programmierter Halt für umdrehen der Platine. +// +// 2011-02-03 - Auflösung in mit und ohne Kommastelle. +// Mill_z_safety, Drill_z_deep, Z_down, Z_dimension als Option bei RUN ... +// +// 2011-02-09 - Generiere ein Refpackage mit 2 Circle und platziere dieses Package +// an der berechneten linken unteren Ecke. +// * Anfrage am 2010-10-13 * +// ISEL-Device berichtigt: MOVE Z -> MOVEABS Z +// Überprüfung der Erzeugungszeit der DRU-Datei auf 120 Sekunden erhöht. +// Ist ein Refpackge platziert, darf die Dimension nicht gefräst werden, +// sonst würde man in die Haltestifte fräsen! +// Abfrage ob trotzdem gefräst werden soll. +// +// 2011-03-10 Nur Kontur fräsen +// +// 2011-06-17 Fehlermeldung bezüglich Mehrfachkonturen (Dimesion) um außerhalb der Dimension +// stehende Texte oder Logos erweitert. +// +// 2011-09-28 Holderspacing corrected und Stegbreite 0.2mm, unabhängig vom Fräserdurchmesser +// WIRE_BEND wieder auf 2 (diagonal stellen). +// +// 2011-10-04 Durchbrüche/Mehrfachkonturen berichtigt, Info Durchbrüche erweitert. +// +// 2011-10-20 Hinweis auf "Only milling Dimension". +// Brichtigt: Bohrungen fräsen von Holes größer maximal vorkommenden Fräserdurchmesser. +// Milling und Z-Achsen menu auf Tabs getrennt. +// +// 2011-11-21 Isel-Format: Fräser Z-Achse wieder hoch. +// +// 2012-01-12 Auflösung mit 8 Nachkommastellen. Wird der erweiterten internen Auflösung gerecht, +// da es sonst zu fehlenden Wires kommen kann. +// +// 2012-01-13 Dimension immer in Layer 103 zeichnen. +// ScriptDrillFile wird nicht mehr automatisch eingelesen, +// da sonst die Holes doppelt vorhanden sind und DRC-Fehler erzeugen. +// Im Device SCRIPT wird je nach benutzten Layer die Außenkontur im Layer 103 bzw. 118 erzeugt. +// +// 2012-01-16 Überprüfung der CLASSen vor der Überprüfung der Design-Regeln. +// Die Design-Regeln werden jetzt immer zuerst gespeichert. +// +// 2012-01-20 Menu Prüfe Einstellungen "OK" Button geändert [Change &Tool #1] +// +// 2012-01-25 MillOnlyContour : Nur aus Träger fräsen berichtigt. +// Layer 103 bzw. 118 anlegen. +// Jetzt mit Tool #1 an DRC-Clearance / CLASS-Clearance anpassen und nicht die Clearance ändern. +// +// 2012-02-09 Korrigietre DRC-Parameter (minDistWireWire) Überprüfung. +// Wenn der Parameter minDistWireWire groß genug ist, dann +// werden die CLASSen nicht mehr geprüft. +// +// 2012-03-09 Zum ändern der Breite des Fräs-Polygon wurde das B.area. benutzt, +// was aber nicht einer der Koordinaten des "Fräs-Polygon" entsprach! +// Dadurch wurde unter Umständen ein anderes Element gewählt. +// Jetzt wird eine Wire-Koordinate des Fräs-Polygon selbst herangezogen. +// +// 2012-03-20 Behandlung der Bohrungen (HOLE) größer Max. drill diam berichtigt. +// Die Fräswege werden in der Option Script im Layer 118 erzeugt und in die *_drl.scr geschrieben. +// +// 2013-03-05 Holder Spacing berichtigt. +// Drills und Holes werden in die Scriptdatei geschrieben und im Layer 144 145 gezeichnet +// ScriptDrillFile und *_drl.scr wird nicht mehr benötigt. +// Bohrungen größer Maxdrill berichtigt, in Script + HPGL. +// Fehlermeldung bez. der Vias des Signal '~_REAL_OUTLINEMILL_~' ohne Option Tool#2 blow up berichtigt. +// GRID (last) zurück stellen. +// Kommentarzeilen in HPGL entfernt (Markierung #HPGLxxxx), da GC-Prevue damit Probleme hat. +// +// 2013-04-18 Tool 9 eingerichtet, zum Fräs-Bohren von Drills größer Max_Drill_Diameter +// Initialisierung bei HPGL nur einmal +// 2013-04-19 Abfrage bez. des Ausfräsen aus dem Trägermateriel bei platzierten Fangzapfen +// Menüpunkt und Parameter zum Referenzbohrungen bohren auskommentiert. +// 2013-04-30 Versatz/Offset berichtigt, beim fräsen von nur Bottom-Seite und platzierten Referen-Package +// HPGL wird nun in zwei Dateien geschrieben, da die Fräse der FU-Berlin die Tools +// zu einem optimierten Fräsweg zusammen fasst. +// 2014-10-06 HPGL_TOP_ext = "_top.plt" Namenserweiterung bei HPGL für Daten des Top layer +// Am Ende wird eine Nachricht ausgegeben, in welche Datei die Fräsdaten geschrieben wurden, +// wichtig bei HPGL da auf Wunsch der FU Berlin nun je Seite (Top/Bottom) eine Datei erzeugt wird. +// 2014-11-26 InfoREFPack in englisch +// +// 2015-03-24 RIPUP der VIA '~_REAL_OUTLINEMILL_~' innerhalb eines Innendurchbruch erst am Ende löschen +// Devices SCRIPT wird am Ende wieder eingelesen +// +/* ** to do : +Scalierung bei HPGL vorwahl 2/5/10 +** */ + +string Version = "Version 6.2.2"; // 2015-03-24 alf@cadsoft.de + +string Header = "Outlines generator for PCB milling."; + +int test = 0; // Flag zum debuggen +int test2 = 0; // 2. Flag zum debuggen + +/* **************************************************** + Complete the following steps to add a new output device definition: + + 1. Add a new member to the 'enum { devScript = 1, ...' + 2. Add the new (unique!) device name to 'DeviceNames[]' + 3. Add the necessary 'case dev...' branches to + 'DeviceInit()', + 'DeviceReInit()', + 'DeviceDraw()', + 'CircleDraw()', + 'ArcDraw()' + and 'DeviceEnd()' + + 4. Add also new Tool values to + 'toolFiles()' + and 'ValueInit()' +***************************************************** */ + +// Actually draw a line on the output device. +// 'state' is defined as +// 0 = this is the first line of a partial polygon +// 1 = this is a "middle" line (neither the first nor the last one) +// 2 = this is the last line of a partial polygon +// 3 = this is a drill coordinate +// 4 = this is one line (polygon fillings) + +/* ********************************************************************************* + 2006-02-08 + Achtung bei Kupferflächen die durch ein POLYGON gefüllt sind! + Durch die Rechenungenauigkeit (max. Auflösung der Eagle-Einheit) muß man + die CLASS-Clearance um den Betrag breiter angegeben werden, da sonst um + gekrümmte Leiterbahnen (Arc) teilweise keine Polygon-Kontur berechnet wird. + Aber nur wenn das Isolate kleiner der Fräserbreite + dem Ungenauigkeitsfaktor ist. +************************************************************************************ */ +real Inaccurateness = 0.005; // 2006-02-08 + +string DRC_CopperDimension = "mdCopperDimension"; // der Parameter in der .dru + +enum { false = -1 }; +enum { First_line, Middle_line, Last_line, Drill_coord, One_line } ; + +string INFOhelp = usage; +string INFOhelpBut = "Help"; +string CANCEL = "-Cancel"; +string BACK = "-Back"; +string ACCEPT = "Accept"; +string YES = "YES"; +string NO = "NO"; +string ON = "ON"; +string OFF = "OFF"; +string BREAK = "<--"; +string NEXT = "Further"; +string DRCCHECK = "Check CLASS"; +string DRC_checked = "Befor milling the PCB, start the DRC (Design Rule Check) " + + "with the milling diameter (isolate) in CLASS clearance.
    " + + "
    All Clearance ERROR define a not isolated wire track!
    "; + +int Class_used[]; +string SClass[]; // 2010-02-02 + +string INFOpolyClass; +sprintf(INFOpolyClass, "If used a filling Polygon on Board, please check Clearance of Design-Rules/Classes if %.8f mm greater
    " + + "as Milling Tool #1, damit bei Leiterbahnen die nicht im 0°45°oder 90°Winkel also mit beliebigen Winkel
    " + + "verlegt sind, eventuelle Füllprobleme wegen Rechenungenauigkeit vermieden werden.
    ", Inaccurateness); + +string SavePar = "&Save parameter"; +string Machine_Menu_Info = "Switch On Off the Mashine Menu for Z-Axis mashines!
    " + + "If accept to change this the ULP save the aktual Parameter und restart!
    "; +string Z_Machine_Menu = "Z Axis Menu"; + +string INFOinside = "Info Break through"; + +string INFOinnerContour = "If inside the board one or more breakthruogh you can place a VIA with SIGNAL name
    " + + "'~_REAL_OUTLINEMILL_~' to milling this.
    "; +string PlaceVIA = "place VIA"; +string DRCinfo = "Distance info:
    Distance Copper/Dimension (see DRC) this is the distance between
    " + "the polygon and outline of the board.
    " + "Do not use value 0 for Copper/Dimension in Design-Rules-Distance (DRC).
    "; + "
    "; + +string Ref_pac = "_REFERENCE_HOLE_"; // *** special package for mirror milling data *** + +string InfoREFERENCE = "Generate a special package with
    " + + "REFERENCE circles in Layer 45 Holes.
    " + + "Place it in the layout for milling and
    " + + "mirroring (bottom side) with offset and
    " + + "start this ULP again.
    " + + "The position of the circles are defined
    " + + "in the NC drill data file which comes
    " + + "from the NC machine (eg. Excellon).

    "; + +string InfoREFPack = "There is placed a reference package in order to take the catching pins of the " + + "milling machine for calculating the axis of reflection. " + + "In this case milling the board out of the carrier should be switched off!
    " + + "However, if you prefer to have the board contour milled out, please check the distance " + "between the circles and layer Dimension!"; + +string A_refpack = "A reference package is placed!"; +string InfoRefHole = "Drill referenz holes (fixing bolt) "; +string InfoRefOff = "Drill reference holes OFF."; +string InfoRefOn = "Drill reference holes ON."; + +string DrBrowse = "Browse"; +string REFdialog = " - generate refernece and place on Board"; +string LoadRefFile = "&Load ref. File"; +string Example_Ref = "Load Example"; +string DRILLref = "Select drill reference file (Holes)"; +string PLACErefpac1 = "After reference package placing start the
    "; +string PLACErefpac2 = "
    to set the USEed libraries back."; +string SHOWRackFile = "Show rack file"; +string SAVE_file = "Save Outlines file"; +string REFinfo2 = "Press button Zero reference to generate a reference Package from a NC-Drill file
    " + + "to place reference safety grip (circles) on PCB for exact mirroring the bottom side
    " + + "of PCB on milling machine.
    "; + +string ZeroRef = "Zero refere&nce"; +string No_reftext = "!No reference file loaded."; + +string Script_Used = "SCRIPT used!
    Return the millings as WIRE to Board-Editor.
    "; + +string OnlyDrillHpgl = "Generate only drill file."; +string INFOtext1_on = "Milling top side."; +string INFOtext16_on = "Milling bottom side (mirror)."; +string INFOtext1_off = "Milling top side."; +string INFOtext16_off = "Milling bottom side (mirror)."; +string TextInfoPlus = "Plus milling layer (to milling text inverting in a ploygon).
    " + + "Only can use with Top or Bottom layer."; +string TOOLdiamIso = "Tool diameter for isolate.
    "; +string OVERlapIso = "Overlap isolate - blow up in percent (%)."; +string OVERlapRubOut = "Overlap rub-out diameter in percent %."; +string TOOLdiamBlow = "Tool diameter for Blow-Up/Rub-Out
    If value set to 0, no Blow-Up (second isolate)
    and Rub-Out (free milling) is generated.
    "; +string TOOLdiamRub = "Rub-Out is off!
    Tool diameter for sec. isolate
    If value set, Blow-Up (second isolate) is generated.
    "; +string MILLfreeYes = "You must set value to Blow-Up."; +string MILLfreeNo = "No blow up and Rub-Out is generated while value is set to 0."; +string INFOmirror0 = "Layer 16 (Bottom) not mirrored."; +string INFOmirror1 = "Layer 16 (Bottom) is mirrored."; + +string GENdrilON = "Generate drill data."; +string GENdrilOFF = "Drills (PAD, VIA, HOLE) are disabled.
    "; +string PADdrildiam = "
    PAD drill diameter"; +string VIAdrilldiam = "VIA drill diameter."; +string HOLEdrildiam = "HOLE drill diameter."; +string USErackON = "Use drill rack (1/10mm) see also Tool Assignment."; +string USErackOFF = "Use only 3 drills (Pad, Via, Hole)."; +string DrillLabel = "HPGL file include drills"; + +string DIMmiltoolOFF = "Mill diameter for cut out.
    Cut out OFF.
    "; +string DIMmiltoolON = "Mill diameter for cut out.
    Cut out ON.
    "; +string INFOspacing = "This value determins the minimum length of a edge where a spacer will be set.

    " + + "Spacers will be set on vertical & horizontal and in HPGL-Format only.

    " + + "The width of the spacer depends on the diameter of Mill Board/Dim.
    " + + "The value 0 switch off this functioon."; + +string INFOresolution = "Integer digits, fractional digits."; // 2011-02-02 +string INFOdeep = "Drilling deep value."; +string INFOzsafety = "This is the value of lift up the milling tool to change the tool."; +string INFOzAxisUp = "This is the value of lift up the milling tool to move fast (safty)."; +string INFOzAxisDown = "This is the value of push down the milling tool in to the PCB."; + +string INFOvdrill = "Drilling velocity mm/s."; +string INFOvelocity = "Milling velocity mm/s."; +string INFOfastVel = "Move velocity (no milling) mm/s."; +string INFOrpm = "Spindle rotation per minute."; +string INFOmaxdrill = "The maximum used drill diamter."; +string DIMdown = "The z parameter for milling Board-Dimension."; +string PARKinfo = "The park position of milling tool to mirror the board."; +string SaveInfo = "Menu parameter saved!<\nobr>"; +string FaultDRCdist1 = "!The value for Copper/Dimension is greater than the Mill Board/&Dim diameter.

    " + + "Check/change Distance Copper/Dimension in Design Rules DRC

    " + + "or accept a distance of "; + +string FaultDRCdist2 = "mm to board dimension."; + +string Error5 = "The CLASS clearance is lower at milling diameter (tool #1)!
    " + + "Befor milling the PCB, start the DRC (Design Rule Check)
    " + + "with the milling diameter (isolate) in CLASS clearance.
    " + + "All Clearance ERROR define a not isolated wire track!
    "; // 2005-12-22 alf@cadsoft.de + +string INFOInaccurat = "Due to possible arithmetic imprecision you have to increase " + + "the value for the track width the cutter uses for milling between " + + "traces and possible copper planes - Clearance/Isolate to Wire " + + "(Arc) - by %.3f mm. Otherwise it could happen that curved wires " + + "won't be milled correctly. The isolating area won't be a closed " + + "one, then."; + +string Mill_mInner_contour = "Process inner milling contours as well, for example, the isolation " + "of thermal reliefs inside polygons."; + +string MissingDimension = "!Missing Dimension.\nFirst place dimension outline in layer 20."; + +string RefDrillDiameter = "Drill diameter "; +string RefDrillDeep = " Deep "; + +string Get_Board_Zero = "Set board &zero"; // 2010-10-13 +string Info_Board_Zero = "Generate a package with two circle
    and placed this package at the
    left bottom corner, to mark the
    machine zero.
    "; // 2011-02-07 + + +/***** deutche Sprache *****/ +if (language() == "de") { + INFOhelp = usage; + INFOhelpBut = "Hilfe"; + CANCEL = "-Abbruch"; + BACK = "-Zurück"; + ACCEPT = "Akzeptieren"; + YES = "JA"; + NO = "NEIN"; + ON = "EIN"; + OFF = "AUS"; + BREAK = "<--"; + NEXT = "Weiter"; + DRCCHECK = "Prüfe &CLASS"; + sprintf(DRC_checked, "Bevor Sie die Fräsdatengenerierung starten, müssen Sie zuerst das Layout mit dem " + + "DRC (Design Rule Check) überprüfen. " + + "Stellen Sie die Clearance der benutzten CLASS(en) um mindestens %.3f mm größer dem Fräserdurchmesser ein.
    " + + "Jeder Clearance-ERROR bedeutet eine nicht isolierte Leiterbahn!
    ", Inaccurateness); + + sprintf(INFOpolyClass, "Ist ein füllendes Polygon im Board plaziert, dann muß die Clearance der Design-Rules/Class um %.3f mm größer
    " + + "als der Fräserdurchmesser sein. Damit bei Leiterbahnen die nicht im 0 45 oder 90 Winkel also mit
    " + + "beliebigen Winkel verlegt sind, eventuelle Füllprobleme wegen Rechenungenauigkeit vermieden werden.", Inaccurateness); + + SavePar = "Parameter &sichern"; + Machine_Menu_Info = "Ein/Ausschalten der Maschinenparamter für die Z-Achse.
    Nach Ändernung des Paramter werden die aktuellen Einstellungen
    gespeichert und das ULP neu gestartet.
    "; + + Z_Machine_Menu = "Z-Achsen Menü"; + + Script_Used = "SCRIPT-Ausgabe!
    Die Fräsbahnen (Daten) werden als WIRE in das Board geladen.
    "; + + INFOinside = "Info Durchbrüche"; + INFOinnerContour = "

    Damit Durchbrüche innerhalb der Platine ebenfalls ausgefräst werden,
    " + + "muß in jedem Durchbruch eine VIA mit dem SIGNAL Namen
    " + + "'~_REAL_OUTLINEMILL_~' platziert werden.
    " + + "Ein Durchbruch darf kein HOLE sein, daß bedeutet,bei kreisrunden
    " + "Durchbrüchen muß ein CIRCLE im Layer Dimension gezeichnet werden.
    "; // 2011-10-04 + + DRCinfo = "Distance info:

    " + // geändert 2010-08-04 + "Distance Copper/Dimension (siehe auch DRC) das ist die Distanz
    " + // der Wert wird jetz aus den Design-Reglen gelesen, + "zwischen dem Polygon (Kupfer) und der Kontur (Layer 20 Dimension) des Board.

    "+ // daher wird der Hinweiß nicht merh beötigt. + "" + + "Dieser Wert wird aus den Design-Rules gelesen!
    " + + "Benutzen Sie nicht den Wert 0 für Copper/Dimension
    " + + "in den Design-Rules - Distance.
    " + + ""; + + InfoREFERENCE = "Generiert ein spezielles Package mit Referenzkreisen (Circle) im Layer 45 Holes.
    " + + "Platzieren Sie das Package im Layout für fräsen und spiegeln (Bottom Seite)
    " + + "mit Offset und starten das ULP erneut.
    " + + "Als Dateneingabe für die Koordinaten dieser Kreise kann das NC-Drill-File
    " + + "von der NC-Maschine (Excellon) benutzt werden.
    " + + "Es kann auch jedes Package mit der Bezeichnung   " + Ref_pac + "
    " + + "als Referenz für den Maschinennullpunkt und die Spiegellinie benutzt werden." + + "

    " + + "Achtung: Die Referenzfangzapfen dürfen nicht über das Maß von Leiterplattenstärke " + "minus Frästiefe hinausschauen, sonst werden diese Fangzapfen angefräst, was zum abbrechen des Fräser " + "führen kann." + + ""; // 2011-02-09 + + REFinfo2 = "Klicken Sie auf Masch. Nullpunkt zum generieren " + + "eines Referenzpackage aus
    " + + "NC-Drill Daten um Referenzfangzapfen (Circle) im Board zu platzieren für
    " + + "die exakte Berechnung der Fräsdaten bezogen auf den Nullpunkt der
    " + + "NC-Anlage und für die Spiegelung der Unterseite.
    "; + + InfoREFPack = "Es ist ein Referenzpackage platziert, um die Fangzapfen der Fräsmaschine zur Berechnung der " + + "Spiegelachse heranzuziehen. Dadurch darf das Ausfräsen aus dem Träger an der Dimension unter Umständen nicht " + + "eingeschaltet werden!
    Wollen Sie die Platine trotzdem aus dem Träger fräsen, überprüfen Sie die " + + "Abstände der Circle zum Layer Dimension!"; // englisch!? + + ZeroRef = "Masch. &Nullpunkt"; + + No_reftext = "!Keine Referenzdatei geladen."; + + DrBrowse = "Durchsuchen"; + LoadRefFile = "&Lade ref. Datei"; + Example_Ref = "Lade Beispiel"; + + REFdialog = " - Generiere Referenz-Package und platziere auf Board"; + DRILLref = " Wähle Drill reference Datei (Holes)"; + A_refpack = "Ein Referenzpackage ist platziert!"; + InfoRefHole = " Fangzapfen bohren "; + InfoRefOff = "Bohren der Fangzapfen AUS."; + InfoRefOn = "Bohren der Fangzapfen EIN."; + + PLACErefpac1 = "Starten Sie nach der Platzierung des Referenzpackage das Script
    "; + PLACErefpac2 = "
    um die erzeugte LBR aus der USE-Liste zu löschen."; + + SHOWRackFile = "Bohrer definition"; + SAVE_file = "Outline Datei sichern"; + + DrillLabel = "
    Drills in HPGL Datei enthalten"; + + OnlyDrillHpgl = "Nur Bohrdaten erzeugen!."; + + INFOtext1_on = "Top Layer (Oberseite) wird gefräst."; + INFOtext16_on = "Bottom Layer (Unterseite) wird gefräst (gespiegelt) "; + INFOtext1_off = "Top Layer (Oberseite) AUS."; + INFOtext16_off = "Bottom Layer (Unterseite) AUS."; + TextInfoPlus = "Zusätzlicher Layer zum fräsen von Texten für Frontplatten.
    " + + "(bzw. Texte in einem Polygon invertiert zu fräsen.)
    " + + "Kann nur in Verbindung mit einem Top- oder Bottom-Layer benutzt werden."; + + TOOLdiamIso = "Werkzeugdurchmesser zum Isolationsfräsen.
    "; + OVERlapIso = "Überlappung von 1. Isolation zu 2. Isolation/Freifräsung in Prozent (%)."; + OVERlapRubOut = "Überlappung innerhalb der Freifräsung in Prozent %."; + TOOLdiamBlow = "Werkzeugdurchmesser für erweiterte Isolation und Freifräsung.
    " + + "Wird der Wert auf 0 gesetzt wird keine erweiterte Isolation
    " + + "und Freifräsung generiert.
    "; + + TOOLdiamRub = "Freifräsung (Rub-Out) ist ausgeschaltet!
    " + + "Es werden nur die Fräswege für eine 2. Isoilation generiert.

    " + + "Wird der Wert auf 0 gesetzt wird keine erweiterte Isolation
    " + + "und Freifräsung generiert."; + + MILLfreeYes = "Es muß ein Wert in Blow-Up (Freifräsung) gesetzt sein."; + MILLfreeNo = "Es wird kein 2. Isolationsfräsen plus Freifräsen generiert,
    da der Wert auf 0 gesetzt ist.
    "; + INFOmirror0 = "Layer 16 (Bottom) wird NICHT gespiegelt."; + INFOmirror1 = "Layer 16 (Bottom) wird gespiegelt."; + + GENdrilON = "Bohrdaten generierung aktiv."; + GENdrilOFF = "Bohrdaten generierung (PAD, VIA, HOLE) ausgeschaltet.
    "; + + PADdrildiam = "
    PAD Bohrdurchmesser.

    " + + "Wenn kein Rack benutzt wird, dann werden alle PADs
    " + + "mit diesem Durchmesser gebohrt.
    " + + "Wenn [] Use Rack aktiviert ist, dann werden die PADs
    " + + "in 1/10 mm Abstufung gebohrt.
    Siehe Tool Assignment.
    "; + + VIAdrilldiam = "VIA Bohrdurchmesser.

    " + + "Wenn kein Rack benutzt wird, dann werden alle VIAs
    " + + "mit diesem Durchmesser gebohrt.
    " + + "Wenn [] Use Rack aktiviert ist, dann werden die VIAs
    " + + "in 1/10 mm Abstufung gebohrt.
    Siehe Tool Assignment.
    "; + + HOLEdrildiam = "HOLE Bohrdurchmesser.

    " + + "Wenn kein Rack benutzt wird, dann werden alle HOLEs
    " + "mit diesem Durchmesser gebohrt.
    " + + "Wenn [] Use Rack aktiviert ist, dann werden die HOLEs
    " + + "in 1/10 mm Abstufung gebohrt.
    Siehe Tool Assignment.
    "; + + USErackON = "Benutze Bohrertabelle (1/10mm), siehe auch Tool Assignment.
    " + + "Die Bohrungen werden auf 1/10 mm gerundet gebohrt.
    "; + USErackOFF = "Benutze nur 3 Bohrer für Pad, Via, Hole.

    " + + "Alle PADs, VIAs und HOLEs werden mit den im Menu
    " + + "angegeben Werten gebohrt.
    "; + + DIMmiltoolOFF = "Fräserdurchmeser zum ausfräsen aus dem Träger.
    Ausfräsen AUS.
    "; + DIMmiltoolON = "Fräserdurchmeser zum ausfräsen aus dem Träger.
    Ausfräsen EIN.
    "; + + INFOspacing = "Dieser Wert definiert die Mindestkantenlänge der Platine damit
    " + + "ein Haltesteg (Spacer) erzeugt wird.
    " + + "Haltestege werden nur an horizontalen oder vertikalen Kanten erzeugt.
    " + + "Die Breite der Stege ist abhängig vom Durchmesser des Fräser
    " + + "(Mill Board/Dim).
    Der Wert 0 schaltet die Funktion ab.
    "; + + INFOresolution = "Auflösung, Vor- Nachkommastellen der Koordinaten."; // 2011-02-02 + INFOdeep = "Bohrtiefe in/durch die Platine."; + INFOzsafety = "Der Wert um den der Fräser in der Z-Achse über das Werkstück
    " + + "gefahren wird, z.B. für Werkzeugwechsel (Rueckzugsebene).
    "; + + INFOzAxisUp = "Der Wert um den der Fräser in der Z-Achse über das Werkstück
    " + + "gefahren wird, für Schnellvorschub (Sicherheitsabstand).
    "; + + INFOzAxisDown = "Die Frästiefe der Z-Achse."; + + INFOvdrill = "Bohrgeschwindigkeit mm/s."; + INFOvelocity = "Fräsgeschwindgkeit mm/sec."; + INFOfastVel = "Schnellvorschub (Geschwindigkeit) mm/s"; + INFOrpm = "Spindlumdrehungen pro Minute"; + INFOmaxdrill = "Der maximal nutzbare Bohrerdurchmesser.
    " + + "Grössere Bohrungen werden gefräst!
    " + + "Siehe auch Tool Assignment.
    "; + + DIMdown = "Z-Parameter für ausfräsen der Boardkontur."; + PARKinfo = "Die Parkposition des Fräskopf zum umdrehen der Leiterplatte."; + + SaveInfo = "Einstellungen gespeichert!<\nobr>"; + + FaultDRCdist1 = "!Der Wert von Copper/Dimension ist größer als der Radius von Mill Board/Dim.
    " + + "Überprüfen Sie den Wert von Distance Copper/Dimension in den Design Rules (DRC)
    " + + "oder akzeptieren Sie die Distanz von "; + FaultDRCdist2 = " mm zur Boardaussenkannte.
    "; + + PlaceVIA = "platziere VIA"; + + Error5 = "Die CLASS-Clearance ist kleiner als der Fäserdurchmesser von Tool #1!
    " + + "Dadurch kann nicht alles isoliert (gefräst) werden.
    " + + "Stellen Sie die CLASS-Clearance auf den Fräserdurchmesser und starten Sie den DRC.
    " + + "Jeder Clearance-Error bedeutet eine nicht isolierte Leiterbahn!
    "; + + sprintf(INFOInaccurat, "Wegen Rechenungenauigkeiten muß für Fräswege zwischen den Leiterbahnen und " + // 2006-02-15 + "einem evtl. vorhandenem Füll-Polygon die Spurbreite (Clearance/Isolate) zu WIRE (Arc) um " + + "%.3f mm breiter eingestellt werden, da es sonst an gebogenen Leiterbahnsegmenten " + + "zu Fehlerhaften nicht berechneten Fräswegen kommen kann. Also die gefräste Isolation nicht " + + "komplett geschlossen ist. ", + Inaccurateness); + + Mill_mInner_contour = "Auch Innenkonturen fräsen (z.B. die Isolation von Termal-Stegen von Polygonen). " + // 2010-01-25 + "Daruch kann es vorkommen, daß wenn ein (Masse) Polygon im Layout vorhanden ist, " + + "die Isolation doppelt, mit entsprechendem Versatz gefräst wird.
    " + + "Die Ursache ist, daß sich eine Kontur an den Leiterbahnzug anlegt, und eine entgegengesetzt " + + "verlaufende Kontur an die berechnete Kontur des (Masse) Polygon.
    " + + "Soll ein evtl. zweifaches Freifräsen wegen diesem Umstand verhindert werden, so schalten " + + "Sie die Option
    Milling [] inner contour
    einfach ab."; + + MissingDimension = "!Keine Dimension.\nPlatzierern Sie zuerst die Aussendimension in Layer 20."; + RefDrillDiameter = "Bohrduchmesser "; + RefDrillDeep = "Tiefe "; + Get_Board_Zero = "Setze Maschinen-&Nullpunkt an linke unter Ecke"; // 2010-10-13 + Info_Board_Zero = "Erzeugt ein Package mit zwei Kreisen und platziert
    es an der linken untere Ecke des Board als
    Manschinen-Nullpunkt.
    "; // 2011-02-07 +} // *** ende language de *** + +// ########################### +// The various output devices +// ########################### +enum { none, devScript, devHPGL, devISEL, devCNC }; +int Defaultdevice = devScript; // set default device +int SelectedDevice = Defaultdevice; // overwritten by load_menu_values() +int LastSelectedDevice; +string HPGL_TOP_ext = "_top.plt"; // Namenserweierung bei HPGL für Daten des Top-Layer 2014-10-06 + +string Device; +string Layer1, Layer16; +int SelectedLayer1 = 0; +int SelectedLayer16 = 0; +int SelectedPlusLayerTop = 0; // 2005-06-08 +int SelectedPlusLayerBot = 0; // to milling a Text inverse in a copper polygon +int Mirror_On = 1; // flag can switch mirror off for Layer 16 + +int ToMillLayer1 = 0; +int ToMillLayer16 = 0; +int OutlineMillSignalLayer; // 2004-10-05 + +string DeviceNames[] = { "Select a device", "SCRIPT", "HPGL", "ISEL", "CNC" }; +string DeviceExt[] = { ".~~~" , ".scr", ".plt", ".ncp", ".ncd" }; +string DefaultSuffix = DeviceExt[SelectedDevice]; +string Ftop = ""; // Fräsdaten für HPGL in zwei Dateien schreiben. 2013-04-30 + // Die Fräse der FU Berlin optimiert die Fräs- und Bohrwege, + // so daß alle Bohrungen und Fräswege mit dem selben Werkzeug zusammengefasst werden. + +real GridDistance; +int GridUnit; +int GridUnitdist; +string Gridunit[]; + Gridunit[GRID_UNIT_MIC] = "mic"; + Gridunit[GRID_UNIT_MM] = "MM"; + Gridunit[GRID_UNIT_MIL] = "mil"; + Gridunit[GRID_UNIT_INCH] = "INCH"; + +int InitDone = 0; // nur einmal Initialisieren, siehe DeviceInit() + +// * set default device and values * +// Parmameters +// *** The milling tool diameter *** +real MillToolOutl = 0.2; +real MillToolIsolate = 0.0; // das Isolate des Polygon zum Isolationsfräsen +real minClearance = 0.15; // to check can filled the complete aray with the + // special polygon width +int OverlapOutlPercent = 20; // percent, to avoid fine copper lines while milling out the area +real MillToolFree = 0.8; // Blow up & free pouring +int Millfreeyes = 1; // free pouring on/off +int MInner_contour = 1; // milling positiv/negativ polygon contour 2010-01-25 + +int Lift_Off = 1; // ** do not lift up the tool for Rubout of polygon filling ** + // ** if change the direction and X-coordinate < tool radius ** + +int OverlapRubOutPercent = 20; // percent, to avoid fine copper lines while milling out the area +real DrillPad = 0.8; +real DrillVia = 0.8; +real DrillHole = 0.8; +int Onlydrill = 0; // output only drill on HPGL +int Generatedrills = 1; // aktivate drills only in one export file + // while drills crashed in 2. run. + +real Max_Drill_Diameter = 2.0; // the maximum of drill diameter in mm of T-Code table for ISEL and CNC + // editierbar gemacht 2004-12-01 + +real DimensionMillTool = 2.0; // milling board outline from holder +int Dim_on_off = 1; // 2006-01-25 +int MillOnlyContour = 0; // 2011-03-10 nur Kontur fräsen + +enum { Res32, Res33, Res34, Res3_2, Res3_3, Res3_4 }; // CNC-Resolution ohne und mit Komma 2011-02-03 +int CNCmillResolution = Res3_2; // Auflösung der Koorinaten Vor- Nachkommastellen 2011-02-02 +real Drill_z_deep = -3.8; // drill deep for drilling pads, via, holes +real Mill_z_safety = 2.0; // safety distance to pcb for change tool +real Z_down = -2.0; // milling z-axis down for milling +real Actualmilldeep; // 2011-01-27 in den Funktionen wird nur die aktuelle Frästiefe benutzt +int Spindle_rpm = 15000; // spindel rotation per minute +real Tool_vel = 2; // velocity to milling +real Fast_vel = 5; // velocity to move tool +real Drill_Vel = 0.5; // drill velocity to drilling in to pcb +real ParkZposition = 80.0; // 80mm Park poistion to turn pcb for 2.nd side milling +real ParkXposition = 10.0; // 10mm Park poistion to turn pcb for 2.nd side milling +real ParkYposition = 10.0; // 10mm Park poistion to turn pcb for 2.nd side milling +real Z_dimension = -3.8; // 3.8mm Z-Down for milling dimension (contur) + +real DistanceDimension; +real Distance_Copper_Dimension = 0.0001; // default value +real Holder_Spacing = 10.0; // in mm, the distance to make a holder spacing for outline milling. + +// Class check +string Clearance_check; + +// Design-Rules-Chek 2010-10-28 +int UseClass = 0; +int MinDistCLass = 0; +string drufile = ""; +string DRUvalues[]; +int DRUlcnt = 0; +int DRC_changed = 0; +string DRC_changed_message = ""; + +// Design Rule Ceck - Values from .dru 2010-01-26 +real mtCopper[]; +real mtIsolate[]; +real minDistWireWire; +real minDistWirePad; +real minDistWireVia; +real minDistPadPad; +real minDistPadVia; +real minDistViaVia; +real minDistSmdPad; +real minDistSmdVia; +real minDistSmdSmd; +real MOI = 0.0; // round((MillToolOutl + Inaccurateness) *1000) / 1000; // Problem bei vergleich von Realzahlen +real MDW = 0.0; // round(minDistWireWire * 1000) / 1000; + +string LayerStack; +string DelPoly; // 2012-01-13 to delete vitual polygon and via outside off bord + +// The HPGL PEN list +enum { PadDrill = 1, ViaDrill, Contour, BlowUp_RubOut, HoleDrill, DimensionLine, DrillRef, MirrorPCB, nrMaxDrillDiameter } // HPGL Pen select "SP.." + /*** MirrorPCB = TOOL (PEN) #8 is reseved for switch PCB on milling machin for milling second side ***/ + /*** nrMaxDrillDiameter == TOOL (PEN) 9 is reseved for milling drill biger then max drill diameter ***/ +string PenList[]; +PenList[PadDrill] = "PadDrill"; +PenList[ViaDrill] = "ViaDrill"; +PenList[Contour] = "Contour"; +PenList[BlowUp_RubOut] = "Blow-Up/Rub-Out"; +PenList[HoleDrill] = "HoleDrill"; +PenList[DimensionLine] = "DimensionLine"; +PenList[DrillRef] = "DrillRef"; +PenList[MirrorPCB] = "MirrorPCB"; +PenList[nrMaxDrillDiameter] = "max.Drill-Diameter"; // 2013-04-18 + +string sToolValue[]; // Tool diameter as String + +enum { HPGLsolution = 1016 } // Inch/1016 = 0.025 mm +enum { ISELsolution = 1000 } // mm/1000 Isel format + +real Mirror = 1.0; +int Mill_OffsetX = 0; +int MillMirr_Offset = 0; +int Ref_null_offsetY = 0; +int Ref_offsetX[]; +int Ref_offsetY[]; +int Ref_cnto = 0; +real RefHoleCircle = 3.0; // Der Durchmesser für den Circle der im Referenz-Package für den Maschinennullpunkt + // benutzt wird. +string Mirror_axis; +real Drill_mirrorPCB = -1; // for message to mirror the PCB by personal + +int MachineMenuOn = 1; // 2011-10-20 maschine menu in seperate Tab + // * for www.cnc-papst.de * 2005-06-23 + +int DrillRefOn = 0; // drill first the referenz holes to fix the pcb on machine +real DrillRefDiameter = 3.0; // the diameter of referenz holes +real DrillRefDeep = -6; // the deep of referen holes + +// to swap for menu +real MDrillPad = DrillPad; +real MDrillVia = DrillVia; +real MDrillHole = DrillHole; +real MDimensionMillTool = DimensionMillTool; +real MHolder_Spacing = Holder_Spacing; +real MMillToolOutl = MillToolOutl; +real MOverlapOutlPercent = OverlapOutlPercent; +real MMillToolFree = MillToolFree; +real MOverlapRubOutPercent = OverlapRubOutPercent; +int Mmillfreeyes = Millfreeyes; +real Mz_down = Z_down; +real Mdrill_z_deep = Drill_z_deep; // drill deep for drilling pads, via, holes +real Mmill_z_safety = Mill_z_safety; // safety distance to pcb for change tool +int Mspindle_rpm = Spindle_rpm; // spindel rotation per minute +real Mtool_vel = Tool_vel; +real Mfast_vel = Fast_vel; +real MDrill_Vel = Drill_Vel; +real MparkXposition = ParkXposition; +real MparkYposition = ParkYposition; +real MparkZposition = ParkZposition; +real Mz_dimension = Z_dimension; +int Mdim_on_off = Dim_on_off; +int MCNCmillResolution = CNCmillResolution; +real CNCsolution = 100; // mm/100 CNC format (default) + +int MdrillRefOn = 0; +real MdrillRefDiameter = 3.0; +real MdrillRefDeep = -6.0; + +string TrueOutline_coordinate; // The generatet polygon outlines for the milling polygon 2009-03-31 + // get polygon coordinate from actual design. + +string ReservedOutlineSignalName = "_OUTLINES_"; // reserved Signal name for special polygon +string OutlineMillSignal = "~_REAL_OUTLINEMILL_~"; // used Signal name for calculate the real outline +string PassDimensionPoly = "PASSDIMESION"; // the true output line, defined by Layer 20 Dimension +string Pass2 = "PASS_2"; +string PassPour = "PASS_POUR"; +string PassOutmill = "PASS_OUTLINE"; +string InPassDimensionPoly; +string InPass2; +string InPassPour; +string InPassOutmill; +int menu = 0; +int cntcontvia = 0; // 2011-10-04 + +string Showpic[]; +string info; // 2011-10-20 first tab +string Infotext; +string zinfo; // 2011-10-20 second tab +string zInfotext; + +string Path; +string Xfile, MillFileName; + +string Fillstyle16 = "CloseDot"; +string Fillstyle1 = "Interleave"; // fill style for layer to return the millings + // as wire in to the board layer (if Device == SCRIPT) + +string Machineparameter = ""; + +// ------------- use a rack for drilling extend the tool list --------------------- +int UseRack = 0; // Use drills with 1/10 mm as in generated Rack + // or use only 3 drills 2005-05-23 +real Drill_tools[]; // 2005-05-24 +string Drill_comment[]; +int Cnt_tools = MirrorPCB+2; // the last milling tool +string Tool_Rack_string; +string Drilltoolsplus; + +int Nc_drill[]; +int Nc_drilld[]; +real Nc_drilldround[]; +int Nc_drillx[]; +int Nc_drilly[]; +int Cnt_ncdrill = 0; +int Dindex[]; +int index[]; +//int Mark = -1; + +int Cntpcw; // the counter of contour wire 2006-02-08 +int Pcwx[], Pcwy[]; // the polygon countour coordinates to calcultae + +int maxX = INT_MIN; // 2010-10-13 +int minX = INT_MAX; +int maxY = INT_MIN; +int minY = INT_MAX; + + +/* ------------------------------------------------------------------------------- + ? weiterer Isolationswert (noch eine Fräserbreite) zwischen Isolation und Blow up + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +CNC-Programmierung: + +datron.de: + + Vom CAT3D Konverter unterstützte Befehle der DIN 66025 (ISO) + G 00 Positionierung / Eilgang + G 01 Linearinterpolation + G 02 Kreisinterpolation UZ + Schraubenlinieninterpolation UZ + + G 03 Kreisinterpolation GUZ + Schraubenlinieninterpolation GUZ + + G 20 Maßangaben Zoll + G 21 Maßangabe metrisch + + G 40 Werkzeugradiuskorrektur, Löschung + G 41 Werkzeugradiuskorrektur, links + G 42 Werkzeugradiuskorrektur, rechts + G 90 Absolute Maßangabe + G 91 Inkrementale Maßangabe + + Weitere ISO-Code Befehle, die vom CATPC berücksichtigt werden: + N Satznummer wird ignoriert + F Vorschub + T Werkzeugwechsel + + +ENGELHARDT GmbH - BedienPCNC.pdf + + G00 POSITIONIEREN IM EILGANG + G01 LINEARINTERPOLATION + G36 WERKZEUGWECHSEL + G74 REFERENZPUNKT FAHREN + + M00 PROGRAMMIERTER HALT + M01 PROGRAMMIERTER HALT MIT AKUSTISCHEM SIGNAL +------------------------------------------------------------------------------- */ + + +/************* Functions ******************/ +int viewtest(string nachricht, string cmd) { + dlgDialog("Debug/Test") { + dlgLabel(nachricht); + dlgHBoxLayout dlgSpacing(900); + dlgHBoxLayout { + dlgTextEdit(cmd); + dlgVBoxLayout dlgSpacing(250); + } + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgSpacing(400); + dlgPushButton(CANCEL) { dlgReject(); return -1; } + } + }; + return 0; +} + +string filenametop(string s) { // wenn Device HPGL, dann extra Dateiname für Toplayer + if (SelectedDevice == devHPGL) { + return filesetext(s, HPGL_TOP_ext); // 2014-10-06 + } + return s; +} + +// wait in seconds +void wait(int sec) { + int t = time(); + while(t+sec > time() ); + return; +} + +void Warning(string Message, string Details) { + dlgMessageBox("Warning: " + Message + " " + Details, "OK"); + return; +} + +void Fatal(string Message, string Details) { + dlgMessageBox("ERROR: " + Message + "


    \n" + Details); + exit(1); +} + +int Error(string Message, string Details, string butt_ok, string butt_esc) { + if (butt_esc) return dlgMessageBox("!ERROR: " + Message + "

    " + Details, butt_ok, butt_esc); + return dlgMessageBox("!ERROR: " + Message + "

    " + Details, butt_ok); +} + +if (!board) Fatal("No board!", "This program can only work in the board editor."); + +void dirtest(void) { + string a[]; + int n = fileglob(a, "*.*"); + if (n) { + dlgMessageBox("Working directory:\n" + filedir(a[0]), "OK"); + } + return; +} + +string vunit(int val, int unit) { + string s; + if (unit) sprintf(s, "%.8f", u2mm(val)); + else sprintf(s, "%.8f",u2inch(val)); + return s; +} + +string getval(string line, real exf, real refholediameter) { + int Y = strchr(line, 'Y'); + string s; + sprintf(s, "(%.8f %.8f) (%.8f %.8f);\n", + strtol(strsub(line, 1)) * exf, + strtol(strsub(line, Y+1)) * exf, + strtol(strsub(line, 1)) * exf + refholediameter/2 * exf, + strtol(strsub(line,Y+1)) * exf ); + return s; +} + +// get Design Rules Layer-Setup +string get_DesignRules(string bfile) { // read Copper Dimension from boardname.dru 2010-02-08 + drufile = filesetext(bfile, ".dru"); + string f[]; + int fcnt = fileglob(f, drufile); + string h; + if (fcnt) { + DRUlcnt = fileread(DRUvalues, drufile); // get Design Rules min. distance (clearance) + string s[]; + int n; + for (int line = 0; line < DRUlcnt; line++) { + n = strsplit(s, DRUvalues[line], ' '); + + if (s[0] == "layerSetup") { + LayerStack = s[2]; + if (LayerStack != "(1*16)") { + if (language() == "de") { + sprintf(h, "%s

    Layer-Setup = %s, muss (1*16) sein.

    Soll das Layer-Setup geändert werden?
    ", + drufile, LayerStack); + } + else { + sprintf(h, "%s

    Layer Setup = %d, must be (1*16).

    Change layer setup now?
    ", + drufile, LayerStack); + } + DRC_changed_message += h; + sprintf(DRUvalues[1], "%s %s (1*16)", s[0], s[1]); // set Layer Setup to default + DRC_changed++; + } + } + + else if (s[0] == "mdCopperDimension") { + if (strstr(s[2], "mm") > 0) Distance_Copper_Dimension = strtod(s[2]); + else Distance_Copper_Dimension = strtod(s[2])*0.0254; + } + + else if (s[0] == "mdWireWire") { + if (strstr(s[2], "mm") > 0) minDistWireWire = strtod(s[2]); + else if (strstr(s[2], "mil") > 0) minDistWireWire = strtod(s[2])*0.0254; + MDW = round(minDistWireWire*1000) / 1000; + if (MOI > MDW) { // 2012-02-09 + sprintf(h, "Clearance: Wire to Wire %.8f < %.8f mm\n", + minDistWireWire, + MOI + ); + DRC_changed_message += h; + sprintf(DRUvalues[line], "%s %s %.8fmm", s[0], s[1], MillToolOutl + Inaccurateness); + DRC_changed++; + } + } + else if (s[0] == "mdWirePad") { + if (strstr(s[2], "mm") > 0) minDistWirePad = strtod(s[2]); + else minDistWirePad = strtod(s[2])*0.0254; + if (MOI > round(minDistWirePad*1000) / 1000) { + sprintf(h, "Clearance: Wire to Pad %.8f < %.8f mm\n", + minDistWirePad, + MOI + ); + DRC_changed_message += h; + sprintf(DRUvalues[line], "%s %s %.8fmm", s[0], s[1], MOI); + DRC_changed++; + } + } + else if (s[0] == "mdWireVia") { + if (strstr(s[2], "mm") > 0) minDistWireVia = strtod(s[2]); + else minDistWireVia = strtod(s[2])*0.0254; + if (MOI > round(minDistWireVia*1000) / 1000) { + sprintf(h, "Clearance: Wire to Via %.8f < %.8f mm\n", + minDistWireVia, + MOI + ); + DRC_changed_message += h; + sprintf(DRUvalues[line], "%s %s %.8fmm", s[0], s[1], MOI); + DRC_changed++; + } + } + else if (s[0] == "mdPadPad") { + if (strstr(s[2], "mm") > 0) minDistPadPad = strtod(s[2]); + else minDistPadPad = strtod(s[2])*0.0254; + if (MOI > round(minDistPadPad*1000) / 1000) { + sprintf(h, "Clearance: Pad to Pad %.8f < %.8f mm\n", + minDistPadPad, + MOI + ); + DRC_changed_message += h; + sprintf(DRUvalues[line], "%s %s %.8fmm", s[0], s[1], MOI); + DRC_changed++; + } + } + else if (s[0] == "mdPadVia") { + if (strstr(s[2], "mm") > 0) minDistPadVia = strtod(s[2]); + else minDistPadVia = strtod(s[2])*0.0254; + if (MOI > round(minDistPadVia*1000) / 1000) { + sprintf(h, "Clearance: Pad to Via %.8f < %.8f mm\n", + minDistPadVia, + MOI + ); + DRC_changed_message += h; + sprintf(DRUvalues[line], "%s %s %.8fmm", s[0], s[1], MOI); + DRC_changed++; + } + } + else if (s[0] == "mdViaVia") { + if (strstr(s[2], "mm") > 0) minDistViaVia = strtod(s[2]); + else minDistViaVia = strtod(s[2])*0.0254; + if (MOI > round(minDistViaVia*1000) / 1000) { + sprintf(h, "Clearance: Via to Via %.8f < %.8f mm\n", + minDistViaVia, + MOI + ); + DRC_changed_message += h; + sprintf(DRUvalues[line], "%s %s %.8fmm", s[0], s[1], MOI); + DRC_changed++; + } + } + } + } + else { + string message; + if (language() == "de") + message = "Keine Design-Rules-Datei gefunden:
    " + + drufile + + "

    Möchten Sie diese Datei jetzt erzeugen und speichern?
    "; + + else + message = "No Design Rules file found:
    " + + drufile + + "

    Do you want to create and save this file now?
    "; + + dlgDialog("Mill Outlines Design Rules") { + dlgLabel(message); + dlgStretch(1); + dlgHBoxLayout { + dlgPushButton("+"+YES) { + dlgAccept(); + exit("SET Interface.PreferredUnit 2;\nDRC SAVE '" + drufile + "';\nRUN '" + argv[0] + "'"); // 2010-02-08 setze Einheiten auf metrisch + } + dlgPushButton(CANCEL) { dlgReject(); exit(0); } + dlgStretch(1); + } + }; + } + return drufile; +} + +string checkClassClear(UL_BOARD B) { // check CLASS Clearance + string classchanged = ""; + Clearance_check = ""; + real ClassClearance; + int CheckDrcWirWire = 0; + //real MOI = round((MillToolOutl + Inaccurateness) *1000) / 1000; // Problem bei vergleich von Realzahlen + //real MDW = round(minDistWireWire * 1000) / 1000; + if (MDW >= MOI) return ""; // 2012-02-09 // 2011-03-10 nur wenn DRC-Clearance kleiner MillToolOutl, dann prüfe CLASSen + else CheckDrcWirWire = 1; + + B.classes(CL) { + if (Class_used[CL.number]) { // nur benutzte Classen prüfen 2010-02-05 + UseClass = 1; + string s; + int n; + for (n = 0; n <= CL.number; n++) { + ClassClearance = u2mm(CL.clearance[n]); + if (ClassClearance < MillToolOutl + Inaccurateness) { // *** 2009-02-05 *** + MinDistCLass = n+1; + ClassClearance = MillToolOutl + Inaccurateness; + sprintf(s, "CLASS %d '%s' %.8fmm %.8fmm %.8fmm %d:%.8fmm;\n", + CL.number, + CL.name, + u2mm(CL.width), + u2mm(CL.clearance), + u2mm(CL.drill), + n, + ClassClearance + ); + SClass[CL.number] += s; + classchanged += s; + } + } + } + } + if (classchanged) { + string drc_clearance_wire_wire; + if (language() == "de") { + sprintf(Clearance_check, "Setze Netzklassen-Clearance:
    "+ + "Durchmesser Tool #1 = %.8f mm plus Rechenungenauigkeit = %.3f
    "+ + "Setze Class Clearance auf %.8f mm oder Fräserdurchmesser <= kleinster CLASS Clearance - %.3f.

    " + + "Starten Sie anschließend den DRC und überprüfen Sie die Abstände.", + MillToolOutl, Inaccurateness, + MillToolOutl + Inaccurateness, + Inaccurateness + ); + sprintf(drc_clearance_wire_wire, "Prüfen Sie auch im DRC Clearance Wire/Wire: %.8f, oder ändern Sie die CLASS(en).", minDistWireWire); // 2011-03-10 + } + else { + sprintf(Clearance_check, "Set Clearance of Net Classes:
    "+ + "Diameter of tool #1 = %.8f mm plus Inaccurateness = %.8f
    "+ + "Set Clearance to %.8f mm or use a milling tool <= lowest clearance value - %.3f.

    " + + "Be sure to start the DRC to have the clearances checked then.", + MillToolOutl, Inaccurateness, + MillToolOutl + Inaccurateness, + Inaccurateness + ); + sprintf(drc_clearance_wire_wire, "Please check also DRC Clearance Wire/Wire: %.8f, or change CLASS(s).", minDistWireWire); // 2011-03-10 + } + dlgDialog("Change CLASS") { + dlgLabel(drc_clearance_wire_wire); + dlgTextView(classchanged); + dlgLabel(Clearance_check); + dlgHBoxLayout { + dlgPushButton("Set &CLASS") dlgAccept(); + if (CheckDrcWirWire) dlgPushButton("Check DRC clearance") { dlgAccept(); exit("DRC"); } // 2012-02-09 + dlgPushButton("Change &Tool #1") { dlgReject(); return ""; } // 2010-02-08 no classes change + dlgStretch(1); + } + }; + } + return classchanged; +} + +// *************************** +void resetMaxMin(void) { // 2010-10-13 + maxX = INT_MIN; + minX = INT_MAX; + maxY = INT_MIN; + minY = INT_MAX; + return; +} + +void checkmaxmin(int x1, int x2, int y1, int y2, int width) { + int w = 0; + if (width) w = width/2; // 2010-10-13 + if (x1 > maxX) maxX = x1+w; + if (x2 > maxX) maxX = x2+w; + if (y1 > maxY) maxY = y1+w; + if (y2 > maxY) maxY = y2+w; + if (x1 < minX) minX = x1-w; + if (x2 < minX) minX = x2-w; + if (y1 < minY) minY = y1-w; + if (y2 < minY) minY = y2-w; + return; +} + +void checkarc( int x1, int x2, int y1, int y2, int xc, int yc, real angle1, real angle2, real radius, int width) { // 2010-10-13 + checkmaxmin( x1, x2, y1, y2, width ); + if ( angle2 > angle1 + 270.0) { + if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, yc - radius, width ); + else if( angle1 < 180 ) checkmaxmin( xc - radius, xc + radius, y1 , yc - radius, width ); + else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, yc + radius, width ); + else if( angle1 < 360 ) checkmaxmin( xc + radius, xc - radius, y1 , yc + radius, width ); + } + else if( angle2 > angle1 + 180.0) { + if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, y2 , width ); + else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, yc - radius, y2 , width ); + else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, y2 , width ); + else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, yc + radius, y2 , width ); + } + else if( angle2 > angle1 + 90.0 ) { + if ( angle1 < 90 ) checkmaxmin( x1 , x2 , yc + radius, y2 , width ); + else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, y1 , y2 , width ); + else if( angle1 < 270 ) checkmaxmin( x1 , x2 , yc - radius, y2 , width ); + else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, y1 , y2 , width ); + } + else { + if ( angle1 < 90 && angle2 > 90 ) checkmaxmin( x1 , x2 , yc + radius, y2 , width ); + else if( angle1 < 180 && angle2 > 180 ) checkmaxmin( x1 , xc - radius, y1 , y2 , width ); + else if( angle1 < 270 && angle2 > 270 ) checkmaxmin( x1 , x2 , yc - radius, y2 , width ); + else if( angle1 < 360 && angle2 > 360 ) checkmaxmin( x1 , xc + radius, y1 , y2 , width ); + } + return; +} + +// calculate Wire length WL +real WireLength( real x1, real y1, real x2, real y2) { + real WL = sqrt(pow(x2-x1,2) + pow(y2-y1,2)); + return WL; +} + +void get_null(void) { // 2010-10-13 + resetMaxMin(); + board(B) { + B.wires(W) { + if (W.layer == 20) { + if (W.arc) checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius, W.width); + else checkmaxmin( W.x1, W.x2, W.y1, W.y2, W.width ); + } + } + status("Circles"); + B.circles(C) { + if (C.layer == 20) checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius, C.width ); + } + B.elements(E) { // *** Dimension in Packages *** + status("Element:"+E.name); + E.package.wires(W) { + if (W.layer == 20) checkmaxmin( W.x1, W.x2, W.y1, W.y2, W.width ); + } + E.package.circles(C) { + if (C.layer == 20) checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius, C.width ); + } + } + } + return; +} + +string make_zerro_ref_pac(string used_scr, string usedlibraries) { // 2011-02-07 + string s; + string cmd; + get_null(); // Nullpunkt des Board an der linken unteren Kante ermitteln + + real null_offx = u2mm(minX); + real null_offy = u2mm(minY); + real board_length = WireLength( null_offx, 0.0, u2mm(maxX), 0.0); + real board_high = WireLength( 0.0, null_offy, 0.0, u2mm(maxY)); + + output(used_scr, "wt") { + printf("%s", usedlibraries); + } + /*** Generate a REFERENCE-Package for machine zero point ***/ + // 2011-02-04 + string lbrname; + string bname; + board(B) { + bname = B.name; + lbrname = filesetext(B.name, "~~~ref_tmp.lbr"); + } + sprintf( cmd, "OPEN '%s';\n", lbrname ); + cmd += "SET CONFIRM YES;\nEdit '" + Ref_pac + ".PAC';\nCHANGE LAYER 45;\nGRID mm; #1325\n"; // 2011-02-10 + cmd += "GROUP ALL;\nDELETE (>0 0);\n"; // DELETE evtl. vorhandene Circle um mehrfach platzierung zu vermeiden, + // falls diese Option schon mal durchgeführt wurde. 2011-02-09 + sprintf(s, "CIRCLE 0 (%.8f %.8f) (%.8f %.8f);\n", + RefHoleCircle/2 *-1, board_high / 2, // 2011-02-04 Circle mit 3mm Durchmesser + 0.0, board_high / 2 + ); + cmd += s; + sprintf(s, "CIRCLE 0 (%.8f %.8f) (%.8f %.8f);\n", + board_length + RefHoleCircle/2, board_high / 2, + board_length, board_high / 2 + ); + cmd += s; + cmd += "WIN FIT;\nWRITE;\n"; + /* ***************** Generate a REFERENCE-Package for machine zero point ***********************/ + cmd += "SET CONFIRM OFF;\n"; // Schalte Automatische Bestätigung wieder aus. 2011-02-10 + /* *** open the board again and place the REF-Package *** */ + // cmd += "CLOSE;\n"; // close the lbr, go back to board erzeugt einen Absturz bei Stringrückgabe. + cmd += "EDIT '" + bname + "';\n"; + cmd += "DISPLAY 45;\n"; + cmd += "GRId mm;\n"; + cmd += "WIN FIT;\n", + cmd += "USE -*; USE '" + lbrname + "';\n"; + sprintf(s, "ADD %s '_REFERENCE_HOLE_' (%.8fmm %.8fmm);\n", Ref_pac , null_offx, null_offy); + cmd += s; + sprintf(s, "RUN '%s';\n", argv[0]); // 2011-02-07 + cmd += s; + + dlgDialog(Get_Board_Zero) { + dlgLabel(Showpic[33]); + dlgLabel(Info_Board_Zero); + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(250); + dlgTextView(cmd); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton(BACK) { dlgReject(); return ""; } + dlgStretch(1); + } + }; + + if (test) if (viewtest("setZeroReference():\n", cmd) != 0) exit(-1376); + exit(cmd); // das erzeugt einen Absturz wegen CLOSE in der Kommandozeile 2011-02-10 + return cmd; +} + +void setZeroReference(void) { + int refunit = 0; + int format = 0; + enum { inch, millimeter }; // 2005-12-22 + enum { format23, format24 }; + string ReferenceUnit[] = { "INCH", "MM", "INCH", "MM" }; + real exf[] = { 0.001, 0.0001, 0.001, 0.0001 }; + // Drillformat 2.3 2.4 2.3 2.4 + // Unit Inch Inch MM MM + real refhdiameter[] = { 118, 1180, 3000, 30000 }; + + string cmd; + string reference_file; + string ref[]; + string ref_text; + int l; + int select; + string used_scr; + string usedlibraries; + + board(B) { + usedlibraries = "USE -*;\n"; + int u = 0; + do { + if (used_libraries[u]) { + usedlibraries += "USE '" + used_libraries[u] + "';\n"; + u++; + } + } while(used_libraries[u]); + used_scr = filedir(B.name) + "used-lbrs-" + filesetext(filename(B.name), ".scr"); + } + // *** Reference Menue Dialog *** + int Result = dlgDialog(filename(argv[0]) + REFdialog) { + dlgHBoxLayout { + dlgLabel(Showpic[17]); + dlgLabel(InfoREFERENCE); + dlgStretch(1); + } + dlgLabel("Reference file"); + dlgHBoxLayout { + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(200); + dlgTextEdit(ref_text); + } + dlgVBoxLayout { + dlgHBoxLayout { + dlgPushButton(LoadRefFile) { + reference_file = dlgFileOpen( DRILLref, "", "*.ncd\n*.*"); + if (!reference_file) return; + ref_text = ""; + l = fileread(ref_text, reference_file); + } + dlgPushButton(Example_Ref) { + ref_text = "Example:\nEXCELLON in mm 2.4\n%\nT25\nX500000Y900000\nX2500000Y900000\nM30"; + refunit = millimeter; // 2005-12-22 set the unit to mm for example + format = format24; + } + dlgStretch(1); + } + dlgSpacing(10); + dlgHBoxLayout { + dlgGroup("Unit") { + dlgHBoxLayout { + dlgRadioButton("INCH", refunit); + dlgRadioButton("MM", refunit); + dlgStretch(1); + } + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgGroup("Format") { + dlgHBoxLayout { + dlgRadioButton("2.3", format); + dlgRadioButton("2.4", format); + dlgStretch(1); + } + } + dlgStretch(1); + } + dlgSpacing(8); + dlgHBoxLayout { + dlgPushButton(Get_Board_Zero) { // 2011-02-07 + ref_text = make_zerro_ref_pac(used_scr, usedlibraries); + } + dlgStretch(1); + } + dlgLabel(Info_Board_Zero); + } + dlgStretch(1); + } + dlgLabel(PLACErefpac1 + used_scr + PLACErefpac2); + dlgHBoxLayout { + dlgPushButton("+OK") { + if (ref_text) dlgAccept(); + else dlgMessageBox(No_reftext, "Ok"); + } + dlgPushButton(CANCEL) dlgReject(); + dlgStretch(1); + } + }; + if (Result) { + board(B) { + int unit_format = refunit * 2 + format; + output(used_scr, "wt") { + printf("%s", usedlibraries); + } + /* ***************** Generate a REFERENCE-Package for machine zero point ***********************/ + l = strsplit(ref, ref_text, '\n'); + string lbrname; + lbrname = filesetext(B.name, "~~~ref_tmp.lbr"); + sprintf( cmd, "OPEN '%s';\n", lbrname ); + cmd += "Edit '" + Ref_pac + ".PAC';\ncHANGE LAYER 45;\nGRiD " + ReferenceUnit[refunit] + ";\n"; + for (int n = 0; n <= l; n++) { + string s = ref[n]; + if(s[0] == 'X') cmd += "CIRCLE 0 " + getval(ref[n], exf[unit_format], refhdiameter[unit_format]); + } + cmd += "WRITE;\n"; + /* *** Generate a REFERENCE-Package for machine zero point ***/ + /* *** open the board again and place the REF-Package *** */ + cmd += "EDIT '" + B.name + "';\n"; + cmd += "DISPLAY 45;\n"; + cmd += "GrID " + ReferenceUnit[refunit] + ";\n"; + cmd += "WIN FIT; WIN (" + + vunit((B.area.x1 + B.area.x2 )/2, refunit) + " " + + vunit((B.area.y1 + B.area.y2 )/2, refunit) + ") (" + + vunit((B.area.x1 + B.area.x2 )/2 + 1000, refunit) + " " + + vunit((B.area.y1 + B.area.y2 )/2 + 1000, refunit) + ") (" + + vunit((B.area.x1 + B.area.x2 )/2 + 150 , refunit) + " " + + vunit((B.area.y1 + B.area.y2 )/2 + 150 , refunit) + ");\n", + cmd += "USE -*; USE '" + lbrname + "';\n"; + cmd += "ADD " + Ref_pac + " '_REFERENCE_HOLE_' \n"; + if (test) if (viewtest("setZeroReference():\n", cmd) != 0) exit(-1513); + exit(cmd); + } + } + return; +} + +void set_tool_rack(void) { // ** generate tool list ** + string tool_type; + switch (SelectedDevice) { + case devScript: tool_type = ""; + break; + case devHPGL : tool_type = "Pen #"; + break; + case devISEL : tool_type = "T"; + break; + case devCNC : tool_type = "T"; + break; + } + //enum { PadDrill = 1, ViaDrill, Contour, BlowUp_RubOut, HoleDrill, DimensionLine, DrillRef, MirrorPCB, nrMaxDrillDiameter } // HPGL Pen select "SP.." + Drill_tools[PadDrill] = DrillPad; Drill_comment[PadDrill] = "PadDrill"; + Drill_tools[ViaDrill] = DrillVia; Drill_comment[ViaDrill] = "ViaDrill"; + Drill_tools[Contour] = MillToolOutl; Drill_comment[Contour] = "Contour #1"; + Drill_tools[BlowUp_RubOut] = MillToolFree; Drill_comment[BlowUp_RubOut] = "Blow-Up/Rub-Out #2"; + Drill_tools[HoleDrill] = DrillHole; Drill_comment[HoleDrill] = "HoleDrill"; + Drill_tools[DimensionLine] = DimensionMillTool; Drill_comment[DimensionLine] = "DimensionLine"; + Drill_tools[DrillRef] = DrillRefDiameter; Drill_comment[DrillRef] = "RefDiameter holder"; + Drill_tools[MirrorPCB] = Drill_mirrorPCB; Drill_comment[MirrorPCB] = "MirrorPCB"; + Drill_tools[nrMaxDrillDiameter] = Max_Drill_Diameter; Drill_comment[nrMaxDrillDiameter] = "Milling Drill Diameter"; // 2013-04-18 + Tool_Rack_string = ""; + string t; + if (UseRack) { + for (int n = 1; n < Cnt_tools; n++) { // erzeuge Rackliste + if (n > nrMaxDrillDiameter && Drill_tools[n] > Max_Drill_Diameter) Drill_comment[n] = " > Max_Drill_Diameter"; + sprintf(t, "%s%02d % 4.2f mm : %s\n", tool_type, n, Drill_tools[n], Drill_comment[n]); + Tool_Rack_string += t; + } + } + else { + for (int n = 1; n < MirrorPCB+1; n++) { + sprintf(t, "nur 3 bohrer %s%02d % 4.2f mm : %s\n", tool_type, n, Drill_tools[n], Drill_comment[n]); + Tool_Rack_string += t; + } + } + return; +} + +// *** Tools in EXCELLON and GERBER (mm) +void toolFiles(void) { + board(B) { + output(filesetext(B.name, ".pen"), "wt") { + printf(";PEN definition file generated by %s %s %s %s\n", EAGLE_SIGNATURE, filename(argv[0]), Header, Version ); + printf("%s", Tool_Rack_string); + } + output(filesetext(B.name, ".rac"), "wt") { + printf(";RACK file generated by %s %s %s %s\n", EAGLE_SIGNATURE, filename(argv[0]), Header, Version ); + printf(";remove the above line to prevent this file from being overwritten!\n"); + + printf("T01 % 2.1f mm\n", DrillPad); + printf("T02 % 2.1f mm\n", DrillVia); + printf("T03 % 2.1f mm\n", MillToolOutl); + printf("T04 % 2.1f mm\n", MillToolFree); + printf("T05 % 2.1f mm\n", DrillHole); + printf("T06 % 2.1f mm\n", DimensionMillTool); + printf("T07 % 2.1f mm\n", DrillRefDiameter); + printf("T08 % 2.1f mm\n", 0.001); + // 2005-05-25 + if (UseRack) { + for (int n = MirrorPCB+1; n < Cnt_tools; n++) { + printf("T%02d % 2.1f mm\n", n, Drill_tools[n]); + } + } + } + output(filesetext(B.name, ".whl"), "wt") { + printf(";WHEEL (Aperture) file generated by %s %s %s %s\n", EAGLE_SIGNATURE, filename(argv[0]), Header, Version ); + printf(";remove the above line to prevent this file from being overwritten!\n"); + printf("D11 round %6.4fmm\n", DrillPad); + printf("D12 round %6.4fmm\n", DrillVia); + printf("D13 round %6.4fmm\n", MillToolOutl); + printf("D14 round %6.4fmm\n", MillToolFree); + printf("D15 round %6.4fmm\n", DrillHole); + printf("D16 round %6.4fmm\n", DimensionMillTool); + printf("D17 round %6.4fmm\n", DrillRefDiameter); + printf("D18 round %6.4fmm\n", 0.001); + // 2005-05-25 + if (UseRack) { + for (int n = MirrorPCB+1; n < Cnt_tools; n++) { + printf("D%2d round %6.4fmm\n", n+10, Drill_tools[n]); + } + } + } + } + return; +} + +void showHPGLinfo(void) { + string text; + int nChars = fileread(text, filesetext(MillFileName, ".pli")); + dlgDialog("Show plot Info") { + dlgTextView(text); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + dlgSpacing(200); + } + }; + return; +} + +void showISELinfo(void) { + string text; + int nChars = fileread(text, filesetext(MillFileName, ".isi")); + dlgDialog("Show ISEL Info") { + dlgTextView(text); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + dlgSpacing(200); + } + }; + return; +} + +void showCNCinfo(void) { + string text; + int nChars = fileread(text, filesetext(MillFileName, ".nci")); + dlgDialog("Show CNC Info") { + dlgTextView(text); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + dlgSpacing(200); + } + }; + return; +} + +void ValueInit(void) { + sprintf( sToolValue[PadDrill], "%.8f", DrillPad); + sprintf( sToolValue[ViaDrill], "%.8f", DrillVia); + sprintf( sToolValue[Contour], "%.8f", MillToolOutl); + sprintf( sToolValue[BlowUp_RubOut], "%.8f", MillToolFree); + sprintf( sToolValue[HoleDrill], "%.8f", DrillHole); + sprintf( sToolValue[DimensionLine], "%.8f", DimensionMillTool); + sprintf( sToolValue[DrillRef], "%.8f", DrillRefDiameter); + sprintf( sToolValue[MirrorPCB], "Message"); // 2005-05-23 + return; +} + +int get_tool(real drill) { + int tool = 0; + if (drill > Max_Drill_Diameter && UseRack) { + drill = Max_Drill_Diameter; // 2013-02-20 preset to Max_Drill_Diameter + return nrMaxDrillDiameter; + } + if (UseRack) tool = nrMaxDrillDiameter+1; // wenn Rack benutzt, suche ab benutzerdefinierten Tools + for (int n = tool; n < Cnt_tools; n++) { + if(Drill_tools[n] == drill) return n; + } + return -1; +} + +void firstlinewire(int x1, int y1, int x2, int y2) { // 2013-04-25 + printf(";wIRE (%.8f %.8f) (%.8f %.8f) #1668 %.1f mx%d mo%d\n", // 2006-01-25 + Mirror * u2mm(x1 + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(y1 + Ref_null_offsetY), + Mirror * u2mm(x2 + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(y2 + Ref_null_offsetY), Mirror, Mill_OffsetX, MillMirr_Offset + ); + return; +} +void middlelinewire(int x2, int y2) { + printf("(%.8f %.8f) #1677 %.1f mx%d mo%d\n", + Mirror * u2mm(x2 + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(y2 + Ref_null_offsetY), Mirror, Mill_OffsetX, MillMirr_Offset + ); + return; +} + +void lastlinewire(int x2, int y2) { + printf("(%.8f %.8f); #1685 %.1f mx%d mo%d\n", // ** OK ** 2012-01-13 + Mirror * u2mm(x2 + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(y2 + Ref_null_offsetY), Mirror, Mill_OffsetX, MillMirr_Offset + ); + return; +} + +void onelinewire(int x1, int y1, int x2, int y2) { + printf(";WiRE (%.8f %.8f) (%.8f %.8f) #1693 %.1f mx%d mo%d\n", + Mirror * u2mm(x1 + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(y1 + Ref_null_offsetY), + Mirror * u2mm(x2 + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(y2 + Ref_null_offsetY), Mirror, Mill_OffsetX, MillMirr_Offset + ); + return; +} + +// *** SCRIPT output HOLDER spacing*** 2009-03-31 +void lineprintScript( int x1, int y1, int x2, int y2) { + printf("WIRE (%.8f %.8f) (%.f %.8f); #1704 %.1f mx%d mo%d\n", + Mirror * u2mm(x1 + Mill_OffsetX) + u2mm(MillMirr_Offset), //stopstop + u2mm(y1 + Ref_null_offsetY), + Mirror * u2mm(x2 + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(y2 + Ref_null_offsetY), Mirror, Mill_OffsetX, MillMirr_Offset + ); + return; +} + + +// *** HPGL output HOLDER spacing*** 2009-03-31 +void startlineprintHpgl( int x1, int y1, int x2, int y2) { + printf("\nPA%.0f,%.0f;PD;\nPA%.0f,%.0f;", + Mirror * u2inch(x1 + Mill_OffsetX)*HPGLsolution + u2inch(MillMirr_Offset)*HPGLsolution, + u2inch(y1 + Ref_null_offsetY)*HPGLsolution, + Mirror * u2inch(x2 + Mill_OffsetX)*HPGLsolution + u2inch(MillMirr_Offset)*HPGLsolution, + u2inch(y2 + Ref_null_offsetY)*HPGLsolution + ); + return; +} + +void nextlineprintHpgl( int x2, int y2) { + printf("\nPA%.0f,%.0f;", + Mirror * u2inch(x2 + Mill_OffsetX)*HPGLsolution + u2inch(MillMirr_Offset)*HPGLsolution, + u2inch(y2 + Ref_null_offsetY)*HPGLsolution + ); + return; +} + +void endlineprintHpgl( int x2, int y2) { + printf("\nPA%.0f,%.0f;PU;", + Mirror * u2inch(x2 + Mill_OffsetX)*HPGLsolution + u2inch(MillMirr_Offset)*HPGLsolution, + u2inch(y2 + Ref_null_offsetY)*HPGLsolution + ); + return; +} + +void fullineprintHpgl( int x1, int y1, int x2, int y2) { + printf("\nPA%.0f,%.0f;PD;\nPA%.0f,%.0f;PU;", + Mirror * u2inch(x1 + Mill_OffsetX)*HPGLsolution + u2inch(MillMirr_Offset)*HPGLsolution, + u2inch(y1 + Ref_null_offsetY)*HPGLsolution, + Mirror * u2inch(x2 + Mill_OffsetX)*HPGLsolution + u2inch(MillMirr_Offset)*HPGLsolution, + u2inch(y2 + Ref_null_offsetY)*HPGLsolution + ); + return; +} + +// *** ISEL output *** +void startlineIsel( int x1, int y1, int x2, int y2) { + printf("FASTABS X%.0f Y%.0f ; Start line\nMOVEABS Z%.0f\nMOVEABS X%.0f Y%.0f\n", + Mirror * u2mm(x1 + Mill_OffsetX)*ISELsolution + u2mm(MillMirr_Offset)*ISELsolution, + u2mm(y1 + Ref_null_offsetY)*ISELsolution, + Actualmilldeep*ISELsolution , + Mirror * u2mm(x2 + Mill_OffsetX)*ISELsolution + u2mm(MillMirr_Offset)*ISELsolution, + u2mm(y2 + Ref_null_offsetY)*ISELsolution + ); + return; +} + +void nextlineIsel( int x2, int y2) { + printf("MOVEABS X%.0f Y%.0f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*ISELsolution + u2mm(MillMirr_Offset)*ISELsolution, + u2mm(y2 + Ref_null_offsetY)*ISELsolution + ); + return; +} + +void endlineIsel( int x2, int y2) { + printf("MOVEABS X%.0f Y%.0f\nMOVEABS Z%.0f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*ISELsolution + u2mm(MillMirr_Offset)*ISELsolution, + u2mm(y2 + Ref_null_offsetY)*ISELsolution, Actualmilldeep * -1 * ISELsolution // 2011-11-21 Fräser Z-Achse wieder hoch + ); + return; +} + +void fullineIsel( int x1, int y1, int x2, int y2) { + printf("FASTABS X%.0f Y%.0f\nMOVEABS Z%.0f\nMOVEABS X%.0f Y%.0f\n", + Mirror * u2mm(x1 + Mill_OffsetX)*ISELsolution + u2mm(MillMirr_Offset)*ISELsolution, + u2mm(y1 + Ref_null_offsetY)*ISELsolution, Actualmilldeep*ISELsolution, + Mirror * u2mm(x2 + Mill_OffsetX)*ISELsolution + u2mm(MillMirr_Offset)*ISELsolution, + u2mm(y2 + Ref_null_offsetY)*ISELsolution + ); + printf("MOVEABS X%.0f Y%.0f\nMOVEABS Z%.0f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*ISELsolution + u2mm(MillMirr_Offset)*ISELsolution, + u2mm(y2 + Ref_null_offsetY)*ISELsolution, + Actualmilldeep * -1 * ISELsolution + ); + return; +} + +// *** CNC output *** +// **************************************************** +// *** Source cnc750a.pdf *** 2005-05-16 alf@cadsoft.de +// **************************************************** +void startlineCnc( int x1, int y1, int x2, int y2) { + switch(CNCmillResolution) { // 2011-02-02 + case Res32 : CNCsolution = 100; + printf("G00 X%05.0f Y%05.0f\nG01 Z%05.0f\nG01 X%05.0f Y%05.0f\n", // Format 3 2 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen 2011-01-27 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + + case Res33 : CNCsolution = 1000; + printf("G00 X%06.0f Y%06.0f\nG01 Z%06.0f\nG01 X%06.0f Y%06.0f\n", // Format 3 3 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen 2011-01-27 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + + case Res34 : CNCsolution = 10000; + printf("G00 X%07.0f Y%07.0f\nG01 Z%07.0f\nG01 X%07.0f Y%07.0f\n", // Format 3 4 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen 2011-01-27 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + case Res3_2 : CNCsolution = 1; // 2011-02-03 + printf("G00 X%05.2f Y%05.2f\nG01 Z%05.2f\nG01 X%05.2f Y%05.2f\n", // Format 3.2 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen 2011-01-27 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + + case Res3_3 : CNCsolution = 1; + printf("G00 X%06.3f Y%06.3f\nG01 Z%06.3f\nG01 X%06.3f Y%06.3f\n", // Format 3.3 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen 2011-01-27 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + + case Res3_4 : CNCsolution = 1; + printf("G00 X%07.4f Y%07.4f\nG01 Z%07.4f\nG01 X%07.4f Y%07.4f\n", // Format 3.4 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen 2011-01-27 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + } + return; +} + +void nextlineCnc( int x2, int y2) { + switch(CNCmillResolution) { // 2011-02-02 + case Res32 : CNCsolution = 100; + printf("G01 X%05.0f Y%05.0f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + case Res33 : CNCsolution = 1000; + printf("G01 X%06.0f Y%06.0f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + case Res34 : CNCsolution = 10000; + printf("G01 X%07.0f Y%07.0f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + case Res3_2 : CNCsolution = 1; + printf("G01 X%05.2f Y%05.2f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + case Res3_3 : CNCsolution = 1; + printf("G01 X%06.3f Y%06.3f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + case Res3_4 : CNCsolution = 1; + printf("G01 X%07.4f Y%07.4f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + break; + } + return; +} + +void endlineCnc( int x2, int y2) { + switch(CNCmillResolution) { // 2011-02-02 + case Res32 : CNCsolution = 100; + printf("G01 X%05.0f Y%05.0f\nG00 Z%05.0f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch + ); + break; + case Res33 : CNCsolution = 1000; + printf("G01 X%06.0f Y%06.0f\nG00 Z%06.0f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch + ); + break; + case Res34 : CNCsolution = 10000; + printf("G01 X%07.0f Y%07.0f\nG00 Z%07.0f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch + ); + break; + case Res3_2 : CNCsolution = 1; + printf("G01 X%05.2f Y%05.2f\nG00 Z%05.2f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch + ); + break; + case Res3_3 : CNCsolution = 1; + printf("G01 X%06.3f Y%06.3f\nG00 Z%06.3f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch + ); + break; + case Res3_4 : CNCsolution = 1; + printf("G01 X%07.4f Y%07.4f\nG00 Z%07.4f\n", + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch + ); + break; + } + return; +} + +void fullineCnc( int x1, int y1, int x2, int y2) { + switch(CNCmillResolution) { // 2011-02-02 + case Res32 : CNCsolution = 100; + printf("G00 X%05.0f Y%05.0f\nG01 Z%05.0f\nG01 X%05.0f Y%05.0f\nG00 Z%05.0f\n", // Format 3.2 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch 2011-01-27 + ); + break; + case Res33 : CNCsolution = 1000; + printf("G00 X%06.0f Y%06.0f\nG01 Z%06.0f\nG01 X%06.0f Y%06.0f\nG00 Z%06.0f\n", // Format 3.3 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch 2011-01-27 + ); + break; + case Res34 : CNCsolution = 10000; + printf("G00 X%07.0f Y%07.0f\nG01 Z%07.0f\nG01 X%07.0f Y%07.0f\nG00 Z%07.0f\n", // Format 3.4 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch 2011-01-27 + ); + break; + case Res3_2 : CNCsolution = 1; + printf("G00 X%05.2f Y%05.2f\nG01 Z%05.2f\nG01 X%05.2f Y%05.2f\nG00 Z%05.2f\n", // Format 3.2 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch 2011-01-27 + ); + break; + case Res3_3 : CNCsolution = 1; + printf("G00 X%06.3f Y%06.3f\nG01 Z%06.3f\nG01 X%06.3f Y%06.3f\nG00 Z%06.3f\n", // Format 3.3 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch 2011-01-27 + ); + break; + case Res3_4 : CNCsolution = 1; + printf("G00 X%07.4f Y%07.4f\nG01 Z%07.4f\nG01 X%07.4f Y%07.4f\nG00 Z%07.4f\n", // Format 3.4 + Mirror * u2mm(x1 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y1 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*CNCsolution, // Z-Achse eintauchen + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution // Z-Achse wieder hoch 2011-01-27 + ); + break; + } + return; +} + +// if the wire longer as longdistance and vertical or horizontal +// then make a holder spacing +void checkBridge(int x1, int y1, int x2, int y2, int state) { + real WL = WireLength(u2mm(x2),u2mm(y2),u2mm(x1),u2mm(y1)); + if (Holder_Spacing && (WL >= Holder_Spacing) && (x1 == x2 || y1 == y2) ) { // 2011-09-28 + int bridgewidth = mm2u(DimensionMillTool); // 2013-03-05 an neue Eagle-Einheit angepasst + real bridglength = 2.25; // 2011-09-28 Stegbreite + int xa, xb, ya, yb; + if (x2 > x1 && x2 >= 0) { + xa = x2 - (bridglength * bridgewidth); + xb = x2 - bridgewidth; + } + else if (x2 < x1 && x2 >= 0) { + xa = x2 + (bridglength * bridgewidth); + xb = x2 + bridgewidth; + } + else if (x2 > x1 && x2 < 0) { + xa = x2 - (bridglength * bridgewidth); + xb = x2 - bridgewidth; + } + else if (x2 < x1 && x2 < 0) { + xa = x2 + (bridglength * bridgewidth); + xb = x2 + bridgewidth; + } + else if (y2 > y1 && y2 >= 0 ) { + ya = y2 - (bridglength * bridgewidth); + yb = y2 - bridgewidth; + } + else if (y2 < y1 && y2 >= 0) { + ya = y2 + (bridglength * bridgewidth); + yb = y2 + bridgewidth; + } + else if (y2 > y1 && y2 < 0 ) { + ya = y2 - (bridglength * bridgewidth); + yb = y2 - bridgewidth; + } + else if (y2 < y1 && y2 < 0) { + ya = y2 + (bridglength * bridgewidth); + yb = y2 + bridgewidth; + } + switch (SelectedDevice) { + case (devScript) : // holder spacing for SCRIPT 2009-03-31 + if (x1 == x2) { // vertical + lineprintScript(x1, y1, x1, ya); + lineprintScript(x1, yb, x1, y2); + } + else { // horizontal + lineprintScript(x1, y1, xa, y1); + lineprintScript(xb, y1, x2, y2); + } + break; + case (devHPGL) : + switch (state) { + case First_line : startlineprintHpgl(x1, y1, x2, y2); + break; + case Middle_line : + if (x1 == x2) { + endlineprintHpgl(x1, ya); + startlineprintHpgl(x1, yb, x1, y2); + } + else { + endlineprintHpgl(xa, y1); + startlineprintHpgl(xb, y1, x2, y2); + } + break; + + case Last_line : endlineprintHpgl(x2, y2); + break; + } + break; + case (devISEL) : + switch (state) { + case First_line : startlineIsel(x1, y1, x2, y2); + break; + case Middle_line : + if (x1 == x2) { + endlineIsel(x1, ya); + startlineIsel(x1, yb, x1, y2); + } + else { + endlineIsel(xa, y1); + startlineIsel(xb, y1, x2, y2); + } + break; + + case Last_line : endlineIsel(x2, y2); + break; + } + break; + case (devCNC) : + switch (state) { + case First_line : startlineCnc(x1, y1, x2, y2); + break; + case Middle_line : + if (x1 == x2) { + endlineCnc(x1, ya); + startlineCnc(x1, yb, x1, y2); + } + else { + endlineCnc(xa, y1); + startlineCnc(xb, y1, x2, y2); + } + break; + + case Last_line : endlineCnc(x2, y2); + break; + } + break; + } + return; + } + + else { + switch (SelectedDevice) { + case (devScript) : // to short for holder spacing for Script 2009-03-31 + switch (state) { + case First_line : lineprintScript(x1, y1, x2, y2); + break; + case Middle_line : lineprintScript(x1, y1, x2, y2); + break; + case Last_line : lineprintScript(x1, y1, x2, y2); + break; + } + break; + + case (devHPGL) : + switch (state) { + case First_line : startlineprintHpgl(x1, y1, x2, y2); + break; + case Middle_line : nextlineprintHpgl(x2, y2); + break; + case Last_line : endlineprintHpgl(x2, y2); + break; + } + break; + case (devISEL) : + switch (state) { + case First_line : startlineIsel(x1, y1, x2, y2); + break; + case Middle_line : nextlineIsel(x2, y2); + break; + case Last_line : endlineIsel(x2, y2); + break; + } + break; + case (devCNC) : + switch (state) { + case First_line : startlineCnc(x1, y1, x2, y2); + break; + case Middle_line : nextlineCnc(x2, y2); + break; + case Last_line : endlineCnc(x2, y2); + break; + } + break; + + } + return; + } +} + +// 2012-03-20 Bohrungen größer max drill werden gefräst +void CircleDraw(int centerx, int centery, int diam, real drilldiamround, int drilltool) { + int tool_diameter = mm2u(Max_Drill_Diameter); // 2012-03-20 + + switch (SelectedDevice) { + case devScript: // 2012-03-20 die Fräswege der goßen Bohrungen werden in das drl-script geschrieben! + printf("CIRCLE %.8f (%.9f %.9f) (%.9f %.9f); #2185 %.1f mx%d xo%d\n", + Max_Drill_Diameter, + Mirror * u2mm(centerx + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(centery + Ref_null_offsetY), + Mirror * u2mm(centerx + Mill_OffsetX) + u2mm(MillMirr_Offset) + u2mm(diam)/2 - u2mm(tool_diameter)/2, // 2012-03-20 + u2mm(centery + Ref_null_offsetY), Mirror, Mill_OffsetX, MillMirr_Offset + ); + break; + + case devHPGL: int hpMax_Drill_Diameter = mm2u(Max_Drill_Diameter); // 2013-03-05 + // AR Arc Relative + // 1. Start point arc, + // 2. Center point arc = Radius-Koordinate Relativ zur letzten Koordinate + // 3. angel + /* vvvv Die Zeilen aktivieren, wenn die Fräse AR benötigt vvvv + printf("\nPA%.0f,%.0f;PD;AR%.0f,%.0f,360;PU;", + (Mirror * u2inch(centerx + Mill_OffsetX) + u2inch(MillMirr_Offset)) * HPGLsolution, // 2013-04-18 + (u2inch(centery + Ref_null_offsetY) - (u2inch(diam/2) - u2inch(tool_diameter/2))) * HPGLsolution, + 0.0, + (u2inch(diam/2) - u2inch(tool_diameter/2)) * HPGLsolution + ); + ^^^^ Die Zeilen aktivieren, wenn die Fräse AA benötigt ^^^^ */ + // AA Arc Absolute + // 1. Start point arc, + // 2. Center point arc == Radius-Koordinate Absolute + // 3. angel + /* Die Zeilen deaktivieren, wenn die Fräse AR benötigt */ + printf("\nPA%.0f,%.0f;PD;AA%.0f,%.0f,360;PU;", + (Mirror * u2inch(centerx + Mill_OffsetX) + u2inch(MillMirr_Offset)) * HPGLsolution, // 2013-04-18 + (u2inch(centery + Ref_null_offsetY) - (u2inch(diam/2) - u2inch(tool_diameter/2))) * HPGLsolution, + (Mirror * u2inch(centerx + Mill_OffsetX) + u2inch(MillMirr_Offset)) * HPGLsolution, + u2inch(centery + Ref_null_offsetY) * HPGLsolution + ); + /* Die Zeilen deaktivieren, wenn die Fräse AR benötigt */ + break; + + case devISEL: + // 1. festlegen der Interpolationsebene + // 2. Startpunkt anfahren + // 3. Kreis fräsen + printf("PLANE XY\n"); + printf("MOVEABS X%.0f Y%.0f\nMOVEABS Z-%.0f\n", + Mirror * u2mm(centerx + Mill_OffsetX) * ISELsolution, + u2mm(centery + Ref_null_offsetY) * ISELsolution, + Drill_z_deep * ISELsolution + ); + printf("CWREL I%06.0f J00000 X000000 Y000000 A000000\n", + u2mm(diam) / 2.0 * ISELsolution + ); + printf("MOVEABS Z%.0f\n", + Mill_z_safety * ISELsolution + ); + break; + + case devCNC: + // for CNC 1. Start point arc, + // 2. Center point arc + switch(CNCmillResolution) { + case Res32 : CNCsolution = 100; + printf("G00 X%05.0f Y%05.0f\nG01 Z%05.0f\n", // Format 3 2 + Mirror * (u2mm((centerx + diam / 2 - tool_diameter / 2) + Mill_OffsetX))*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY) * CNCsolution, + Actualmilldeep*CNCsolution + ); + printf("G03 X%05.0f Y%05.0f\nG00 Z%05.0f\n", // Format 3 2 + Mirror * u2mm(centerx + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + case Res33 : CNCsolution = 1000; + printf("G00 X%06.3f Y%06.3f\nG01 Z%06.3f\n", // Format 3 3 + Mirror * (u2mm((centerx + diam / 2 - tool_diameter / 2) + Mill_OffsetX))*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY) * CNCsolution, + Actualmilldeep*CNCsolution + ); + printf("G03 X%06.3f Y%06.3f\nG00 Z%06.3f\n", // Format 3 3 + Mirror * u2mm(centerx + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + case Res34 : CNCsolution = 10000; + printf("G00 X%07.0f Y%07.0f\nG01 Z%07.0f\n", // Format 3 4 + Mirror * (u2mm((centerx + diam / 2 - tool_diameter / 2) + Mill_OffsetX))*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY) * CNCsolution, + Actualmilldeep*CNCsolution + ); + printf("G03 X%07.0f Y%07.0f\nG00 Z%07.0f\n", // Format 3 4 + Mirror * u2mm(centerx + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + case Res3_2 : CNCsolution = 1; + printf("G00 X%05.2f Y%05.2f\nG01 Z%05.2f\n", // Format 3.2 + Mirror * (u2mm((centerx + diam / 2 - tool_diameter / 2) + Mill_OffsetX))*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY) * CNCsolution, + Actualmilldeep*CNCsolution + ); + printf("G03 X%05.2f Y%05.2f\nG00 Z%05.2f\n", // Format 3.2 + Mirror * u2mm(centerx + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + case Res3_3 : CNCsolution = 1; + printf("G00 X%06.3f Y%06.3f\nG01 Z%06.3f\n", // Format 3.3 + Mirror * (u2mm((centerx + diam / 2 - tool_diameter / 2) + Mill_OffsetX))*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY) * CNCsolution, + Actualmilldeep*CNCsolution + ); + printf("G03 X%06.3f Y%06.3f\nG00 Z%06.3f\n", // Format 3.3 + Mirror * u2mm(centerx + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + case Res3_4 : CNCsolution = 1; + printf("G00 X%07.4f Y%07.4f\nG01 Z%07.4f\n", // Format 3.4 + Mirror * (u2mm((centerx + diam / 2 - tool_diameter / 2) + Mill_OffsetX))*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY) * CNCsolution, + Actualmilldeep*CNCsolution + ); + printf("G03 X%07.4f Y%07.4f\nG00 Z%07.4f\n", // Format 3.4 + Mirror * u2mm(centerx + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(centery + Ref_null_offsetY)*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + } + break; + } + return; +} + + +// *** draw lines and drills/holes *** +void DeviceDraw(int x1, int y1, int x2, int y2, int state) { + // Actually draw a line on the output device. + // 'state' is defined as + // 0 = this is the first line of a partial polygon + // 1 = this is a "normal" line (neither the first nor the last one) + // 2 = this is the last line of a partial polygon + // 3 = this is a drill coordinate // 2013-03-05 x1 = Diameter y1 = Diameter + // 4 = this is one line + real drilldiam = round(u2mm(x1)*10) / 10; // 2013-04-18 // real-vergleich ist Problematisch bei Nachkommastellen + + if (InPassPour && state == One_line) { // *** print no shorter horizontal fillings as MillToolFree *** + if (y2 == y1) { // *** OK 2005-05-18 alf *** + real check_legth = WireLength(u2mm(x2), u2mm(y2), u2mm(x1), u2mm(y1) ); + if (abs(check_legth) < MillToolFree) return; + } + } + switch (SelectedDevice) { + case devScript: + switch (state) { + case First_line : if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else firstlinewire(x1, y1, x2, y2); + break; + case Middle_line : if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else middlelinewire(x2, y2); + break; + case Last_line : if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else lastlinewire(x2, y2); + break; + case Drill_coord : if (drilldiam > Max_Drill_Diameter) { // 2013-03-05 + printf("CIRCLE %.8f (%.8f %.8f) (%.8f %.8f); #2352 %.1f mx%d mo%d milling Drill/Hole\n", + Max_Drill_Diameter, + Mirror * u2mm(x2 + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(y2 + Ref_null_offsetY), + Mirror * u2mm(x2+ (x1/2) + Mill_OffsetX) + u2mm(MillMirr_Offset) - (Mirror * (Max_Drill_Diameter/2)), // 2013-03-05 x1 = Diameter + u2mm(y2 + Ref_null_offsetY), Mirror, Mill_OffsetX, MillMirr_Offset + ); + } + else { + printf("CIRCLE 0 (%.8f %.8f) (%.8f %.8f); #2361 %.1f mx%d mo%d Drill/Hole\n", + Mirror * u2mm(x2 + Mill_OffsetX) + u2mm(MillMirr_Offset), + u2mm(y2 + Ref_null_offsetY), + Mirror * u2mm(x2+ (x1/2) + Mill_OffsetX) + u2mm(MillMirr_Offset), // x1 = Diameter + u2mm(y2 + Ref_null_offsetY), Mirror, Mill_OffsetX, MillMirr_Offset + ); + } + break; + case One_line : // polygon filling + onelinewire(x1, y1, x2, y2); + break; + } + break; + + case devHPGL: + switch (state) { + case First_line : + if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else startlineprintHpgl(x1, y1, x2, y2); + break; + + case Middle_line : + if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else nextlineprintHpgl(x2, y2); + break; + + case Last_line : + if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else endlineprintHpgl(x2, y2); + break; + + case Drill_coord : /* Option mit nur 3 Bohrern ohne Use rack! + if (drilldiam > Max_Drill_Diameter) { + string dtool; + sprintf(dtool, "#2403 Use rack?\nDrill %.1f > Max. Drill %.1f Tool %d", drilldiam, Max_Drill_Diameter, get_tool(drilldiam)); + if (dlgMessageBox(dtool, "OK", "Abort milling") != 0) exit(-2404); + CircleDraw( x1, y1, x2, y2, get_tool(drilldiam)); + } + */ + printf("\nPA%.0f,%.0f;PD;", // Drill bohren 2013-04-18 + (Mirror * u2inch(x2 + Mill_OffsetX) + u2inch(MillMirr_Offset)) * HPGLsolution, + u2inch(y2 + Ref_null_offsetY)*HPGLsolution + ); + printf("\nPA%.0f,%.0f;PU;", + (Mirror * u2inch(x2 + Mill_OffsetX) + u2inch(MillMirr_Offset)) * HPGLsolution, + u2inch(y2 + Ref_null_offsetY) * HPGLsolution + ); + + break; + + case One_line : // polygon filling + fullineprintHpgl(x1, y1, x2, y2); + break; + } + break; + + case devISEL: + switch (state) { + case First_line : printf("; Start LINE\n"); + if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else startlineIsel(x1, y1, x2, y2); + break; + + case Middle_line : + if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else nextlineIsel(x2, y2); + break; + + case Last_line : if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else endlineIsel(x2, y2); + printf("; End line\n"); + break; + + case Drill_coord : printf("; Zyklus Zentrierbohren begin\n"); + printf("FASTABS X%.0f Y%.0f ; Positionieren\n", + Mirror * u2mm(x2 + Mill_OffsetX)*ISELsolution + u2mm(MillMirr_Offset)*ISELsolution, + u2mm(y2 + Ref_null_offsetY)*ISELsolution + ); + printf("MOVEABS Z%.0f\n", Drill_z_deep*ISELsolution); + printf("FASTABS Z%.0f\n", Actualmilldeep*-1*ISELsolution); + printf("; Zyklus Zentrierbohren end\n"); + break; + + case One_line : printf("; polygon filling\n"); // polygon filling + fullineIsel(x1, y1, x2, y2); + break; + } + break; + + case devCNC: + switch (state) { + case First_line : if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else startlineCnc(x1, y1, x2, y2); + break; + + case Middle_line : if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else nextlineCnc(x2, y2); + break; + + case Last_line : if (InPassOutmill) checkBridge(x1, y1, x2, y2, state); + else endlineCnc(x2, y2); + break; + + case Drill_coord : switch(CNCmillResolution) { // 2011-02-02 + case Res32 : CNCsolution = 100; + printf("G00 X%05.0f Y%05.0f\n", // Format 2.4 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + printf("G01 Z%05.0f\nG00 Z%05.0f\n", // langsam Eintauchen, schnell hoch 2011-01-27 + Actualmilldeep*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + case Res33 : CNCsolution = 1000; + printf("G00 X%06.0f Y%06.0f\n", // Format 2.4 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + printf("G01 Z%06.0f\nG00 Z%06.0f\n", // langsam Eintauchen, schnell hoch 2011-01-27 + Actualmilldeep*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + case Res34 : CNCsolution = 10000; + printf("G00 X%07.0f Y%07.0f\n", // Format 2.4 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + printf("G01 Z%07.0f\nG00 Z%07.0f\n", // langsam Eintauchen, schnell hoch 2011-01-27 + Actualmilldeep*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + + case Res3_2 : CNCsolution = 1; + printf("G00 X%05.2f Y%05.2f\n", // Format 2.4 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + printf("G01 Z%05.2f\nG00 Z%05.2f\n", // langsam Eintauchen, schnell hoch 2011-01-27 + Actualmilldeep*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + case Res3_3 : CNCsolution = 1; + printf("G00 X%06.3f Y%06.3f\n", // Format 2.4 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + printf("G01 Z%06.3f\nG00 Z%06.3f\n", // langsam Eintauchen, schnell hoch 2011-01-27 + Actualmilldeep*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + case Res3_4 : CNCsolution = 1; + printf("G00 X%07.4f Y%07.4f\n", // Format 2.4 + Mirror * u2mm(x2 + Mill_OffsetX)*CNCsolution + u2mm(MillMirr_Offset)*CNCsolution, + u2mm(y2 + Ref_null_offsetY)*CNCsolution + ); + printf("G01 Z%07.4f\nG00 Z%07.4f\n", // langsam Eintauchen, schnell hoch 2011-01-27 + Actualmilldeep*CNCsolution, + Actualmilldeep*-1*CNCsolution + ); + break; + } + break; + + case One_line : fullineCnc(x1, y1, x2, y2); + break; + } + break; + } + return; +} + + +// *** reinitialize the machine *** +void DeviceReInit(int tool_pass, int Layer, string info) { + // Do anything necessary the secondary initialize the output device + set_tool_rack(); // 2013-04-25 + switch (SelectedDevice) { + case devScript: // *** SCRIPT *** + switch (tool_pass) { + case PadDrill: + printf("\n#2554 CHANGE DRILL %.2f;# PAD\n", DrillPad); // 2013-02-19 + break; + + case ViaDrill: + printf("\n#2558 CHANGE DRILL %.2f; # VIA\n", DrillVia); // 2013-02-19 + break; + + case HoleDrill: + printf("\n#2562 CHANGE DRILL %.2f; # HOLE\n", DrillHole); // 2013-02-19 + break; + + case Contour: + printf("#2566 DeviceReinit case Contour:\n"); + printf("ChANGE LAYER %d;\n", Layer + 100); + printf("CHANGE wIDTH %.8f;\n", MillToolOutl); + break; + + case BlowUp_RubOut: + printf("#2572 DeviceReinit case BlowUp_RubOut:\n"); + if (Layer == 45) { + printf("CHaNGE LAYER %d;\n", Layer); // Layer 45 Holes 2005-09-30 + } + else { + printf("CHAnGE LAYER %d;\n", Layer + 101); // 2006-07-26 separate Layer for RubOut + } + printf("#2579 BlowUp_RubOut or drills\n"); // 2011-10-20 + printf("\nCHANGE WiDTH %.8f;\nWIRe\n", MillToolFree);// 2010-10-14 + break; + + case DimensionLine: + printf("\n#2584 DeviceReinit case DimensionLine:\n"); + if (SelectedLayer1) { + if (MillOnlyContour) printf("LAYER Milloutlines103 %d;\n", 103); // 2012-01-25 + printf("CHANgE LAYER %d; #2579 layer for milling dimension outline in script\n", 103); // 2012-01-13 separate Layer for out milling of raw material + } + else { + if (MillOnlyContour) printf("LAYER Milloutlines118 %d;\n", 118); // 2012-01-25 + printf("CHANgE LAYER %d; #2583 layer for milling dimension outline in script\n", 118); // 2012-01-13 separate Layer for out milling of raw material + } + printf("CHANGE WIdTH %.8f;\n", DimensionMillTool); // die Fräserbreite um das PCB aus dem Träger zu fräsen + break; + + case MirrorPCB: + printf("\n#2597 swap/mirror PCB for other side\n"); + break; + + case nrMaxDrillDiameter: + printf("\n#2601 drill are milling\n"); + break; + default: + printf("#2605 CHANGE DRILL %.2f;\n", Drill_tools[tool_pass] ); + break; + } + break; + + case devHPGL: // *** HPGL *** + printf("\nSP%d;\nPU;", tool_pass); // pen select // \n#2610 Reinit\n // + output(filesetext(MillFileName,".pli"), "at") { + string pli; + if (InPassDimensionPoly) pli = PassDimensionPoly; + else if (InPass2) pli = Pass2; + else if (InPassPour) pli = PassPour; + else if (InPassOutmill) pli = PassOutmill; + else pli = "Drill"; + printf("use PEN #%02d %s %.2f #2610 <- %s\n", tool_pass, pli, Drill_tools[tool_pass], info); + } + break; + + case devISEL: // *** ISEL *** + /* ********************************************************** + #### Beispiel von Herr Koppel 2005-08-12 alf@cadsoft.de #### + MOVEABS Y99850 + FASTABS Z2000 ; Werkzeugwechselpos. + COOLANT OFF ; Kühlung aus + SPINDLE OFF + ; *** BLOCK INSERTED BY PROTRAP *** + FASTABS Z80000 + HALT + ; ********************** + ; * PLATINE UMDREHEN * + ; ********************** + ; *** BLOCK INSERTED BY PROTRAP *** + SPINDLE CW RPM15000 + ; BLOCK 2 + FASTABS Z2000 ; Werkzeugwechselpos. soll Sicherheitshöhe sein. alf + GETTOOL 15 ; D0.3 - HSS - STICHEL 90 GRAD + SPINDLE CW RPM15000 + COOLANT ON ; Kühlung ein + ************************************************************* */ + + printf("FASTABS Z%.0f ; Sicherheitshöhe\n", Mill_z_safety*ISELsolution); + printf("SPINDLE OFF\n"); + printf("COOLANT OFF\n"); + + if (tool_pass == MirrorPCB) { // Platine umdrehen ** + printf("FASTABS Z%.0f; Parkposition Z\n", ParkZposition*ISELsolution); // 80mm + printf("FASTABS X%.0f; Parkposition X\n", ParkXposition*ISELsolution); // 10mm + printf("FASTABS Y%.0f; Parkposition Y\n", ParkYposition*ISELsolution); // 10mm + printf("HALT\n"); + printf("; **********************\n"); + printf("; * PLATINE UMDREHEN *\n"); + printf("; **********************\n"); + } + else { + printf("GETTOOL %d ; %s %.1f mm \n", tool_pass, PenList[tool_pass], Drill_tools[tool_pass]); + printf("SPINDLE CW RPM%d\n", Spindle_rpm); + printf("COOLANT ON\n"); + } + if(test) printf("; # ISEL tools\n"); + output(filesetext(MillFileName,".isi"), "at") { + if (Onlydrill && tool_pass == Contour); + printf("Tool #%d = %s mm\t%s\n", tool_pass, sToolValue[tool_pass], PenList[tool_pass]); + } + break; + + case devCNC: // *** CNC *** + if (tool_pass == MirrorPCB) { // Platine umdrehen ** + // Meldung an CNC um Platine umzudrehen 2005-11-15 + printf("M01 'CNC' Platine umdrehen!\n"); + } + else { + printf("G36 T%2d\n", tool_pass); // Werkzeugwechsel 2001-02-01 + } + if(test) printf("; # CNC tools\n"); + output(filesetext(MillFileName,".nci"), "at") { + if (Onlydrill && tool_pass == Contour); + printf("Tool #%d = %s mm\t%s\n", tool_pass, sToolValue[tool_pass], PenList[tool_pass]); + } + break; + } + return; +} + +real Length(real x1, real y1, real x2, real y2) { + return sqrt((pow(x2 - x1, 2) + pow(y2 - y1, 2)) ); +} + +// *** collect Rack data +void AddRack(int Size) { + real r = round(u2mm(Size) * pow(10, 1)) / pow(10, 1); + if (!r) dlgMessageBox("!Drill zero 0.0 diamter found.", "Ok"); + if (r) { // <= Max_Drill_Diameter) 2013-02-20 alle Drills auflisten + for (int i = Cnt_tools; --i > nrMaxDrillDiameter; ) { + if (Drill_tools[i] == r) return; + } + Drill_tools[Cnt_tools] = r; + Cnt_tools++; + } + else { + string h; + sprintf(h, "Found drill diameter %.1f mm\n", r); + Drilltoolsplus += h; + } + return; +} + +// *** collect Drill/Hole data **** +void AddDrilling(int Size, int x, int y) { + real r = round(u2mm(Size) * pow(10, 1)) / pow(10, 1); + if (!r) dlgMessageBox("!Drill zero 0.0 diamter found.", "Ok"); + Nc_drill[Cnt_ncdrill] = Size; // nicht benutzt -->> Mark; // Mark this drill not calculated + Nc_drilld[Cnt_ncdrill] = Size; + Nc_drilldround[Cnt_ncdrill] = r; // gerundet auf 0.1mm + Nc_drillx[Cnt_ncdrill] = x; + Nc_drilly[Cnt_ncdrill] = y; + Cnt_ncdrill++; + return; +} + +void get_rack(UL_BOARD B) { + status(" collect Rack"); + B.elements(E) { + E.package.contacts(C) if(C.pad) AddRack(C.pad.drill); + E.package.holes(H) AddRack(H.drill); + } + B.signals(S) S.vias(V) AddRack(V.drill); + B.holes(H) AddRack(H.drill); + status(" finish, collect Rack"); + sort(Cnt_tools, Drill_tools); + return; +} + +void get_drills(UL_BOARD B) { + status(" collect Drills"); + B.elements(E) { + E.package.contacts(C) if(C.pad) AddDrilling(C.pad.drill, C.pad.x, C.pad.y); + } + B.signals(S) S.vias(V) AddDrilling(V.drill, V.x, V.y); + status(" finish, collect Drills"); + return; +} + +void get_holes(UL_BOARD B) { // nach dem isolieren und evtl. blow-up die Holes bohren + Cnt_ncdrill = 0; + status("collect Holes"); + B.elements(E) { + E.package.holes(H) AddDrilling(H.drill, H.x, H.y); + } + B.holes(H) AddDrilling(H.drill, H.x, H.y); + status(" finish, collect Holes"); + return; +} + +void output_drills(string s) { + sort(Cnt_ncdrill, Dindex, Nc_drilldround, Nc_drillx, Nc_drilly); + int n; + int Tcode = -1; + real new_drill = -1; + switch (SelectedDevice) { + case devScript: if (s) printf("# Layer 145 Mil_sDrill; # Gesamt %d %s\n", Cnt_ncdrill, s); + break; + case devHPGL : //if (s) printf(";\nLBGesamt %d %s%c\n", Cnt_ncdrill, s, 3); + break; + case devISEL : if (s) printf(";Isel: Gesamt %d %s\n", Cnt_ncdrill, s); + break; + case devCNC : if (s) printf("M999 Gesamt %d %s\n", Cnt_ncdrill, s); + break; + } + int initCode = 0; // Flag zum initiaisieren des T-Code zum Fräsen von grossen Löchern. 2011-02-14 + // die Drills sind nach Durchmesser sortiert, als muß nur einmal mit T9 + // Reinitialisiert werden. + + for (n = 0; n < Cnt_ncdrill; n++) { + if (Nc_drilldround[Dindex[n]] != new_drill) { + new_drill = Nc_drilldround[Dindex[n]]; + Tcode = get_tool(new_drill); + if (Tcode > false) { + if (test2) { string h; sprintf(h, "# Tcode == %d in #2773", Tcode); if(dlgMessageBox(h, "ok2759", "esc2759") != 0) exit(-2781); } + if (initCode != nrMaxDrillDiameter) { + initCode = Tcode; + if (test2) printf("#2784"); + DeviceReInit(Tcode, 45, "2785"); // the Hole layer + } + } + } + if (Tcode == nrMaxDrillDiameter) { // T-Code 9 ist fräsen + + switch (SelectedDevice) { + case devScript: if (s) printf("#2792 fräsen von Bohrungen grösser Tn\n"); + printf("CHANGe LAYER %d;\n", 145); // holes > maxdiameter milling in Mil_Hole layer 2013-02-19 + break; + case devHPGL : + break; + case devISEL : if (s) printf(";isel fräsen von Bohrungen grösser Tn mit T'%d'\n", Tcode); // 2011-02-11 zum testen + break; + case devCNC : if (s) printf("M998 fräsen von Bohrungen grösser Tn\n"); + break; + } + // große Drills werden gefräst, 2012-03-20 + CircleDraw( Nc_drillx[Dindex[n]], Nc_drilly[Dindex[n]], Nc_drilld[Dindex[n]], Nc_drilldround[Dindex[n]], Tcode); + } + else DeviceDraw(Nc_drilld[Dindex[n]], mm2u(Nc_drilldround[Dindex[n]]), Nc_drillx[Dindex[n]], Nc_drilly[Dindex[n]], 3); // Nc_drilldround[] is real! 2013-03-05 + } + return; +} + + + +// ** generate plus layer data for Text milling ** 2005-06-08 +void genPlusLayer(int Layer) { + board(B) { + B.texts(T) { + int firstinit = 1; + if (T.layer == Layer) { + if (firstinit) { + DeviceReInit(Contour, Layer, "2778"); // *** additional Text-Layer milling with Contour-Tool *** + firstinit = 0; + } + string tl; + int State = One_line; + int lastX = INT_MAX, lastY = INT_MAX; + int x1[], y1[], x2[], y2[], cnt = 0; + T.wires(W) { + x1[cnt] = W.x1; + y1[cnt] = W.y1; + x2[cnt] = W.x2; + y2[cnt] = W.y2; + cnt++; + } + for (int n = 0; n < cnt; n++) { + if (lastX != x1[n] || lastY != y1[n]) { + if (x2[n] == x1[n+1] && y2[n] == y1[n]) { + if (State == First_line) State == Middle_line; + else State == First_line; + } + else { + if (State == Middle_line) State = Last_line; + else State = One_line; + } + } + else if (x2[n] != x1[n+1] || y2[n] != y1[n]) State = One_line; + if (n == cnt-1 && (State == First_line || State == Middle_line) ) State = Last_line; + lastX = x2[n]; + lastY = y2[n]; + DeviceDraw(x1[n], y1[n], x2[n], y2[n], State); + } + } + } + } + return; +} + + +void scriptHeader(void) { + board(B) printf("# Generated with %s at %s\n# from %s\n", filename(argv[0]), t2string(time()), B.name); + printf("gRID mm;\n"); + printf("CHANGE SIZE 0.1;\n"); + printf("SET OPTIMIZING OFF;\nSET WIRE_BEND 2;\n"); // 2010-10-28 Optimizing ON kann man nicht erwarten, bei einer Vielzahl von WIRE. + if (!test) printf("#SET UNDO_LOG OFF;\n"); + printf("LAYER %d Mill_Isol%d;\n", 1 + 100, 1); // 2008-11-12 use not flag, use 1 + printf("SET FILL_LAYER %d %s;\n", 1 + 100, Fillstyle1); + printf("SET COLOR_LAYER %d %s;\n", 1 + 100, "Brown"); + // *** 2006-07-26 *** + printf("LAYER %d Mill_Pour%d;\nSET FILL_LAYER %d %s;\n", + 1 + 101, 1 + 101, 1 + 101, Fillstyle1); + printf("SET COLOR_LAYER %d %s;\n", 1 + 101, "Magenta"); + printf("LAYER %d Mill_Out%d;\nSET FILL_LAYER %d %s;\n", + 1 + 102, 1 + 102, 1 + 102, Fillstyle1); + printf("SET COLOR_LAYER %d %s;\n", 1 + 102, "LGray"); + //printf("CHANGE lAYER %d;\n", 1 + 100 ); + printf("LAYER %d Mill_Isol%d;\n", 16 + 100, 16); // 2008-11-12 use not flag, use 16 + printf("SET FILL_LAYER %d %s;\n", 16 + 100, Fillstyle16); + printf("SET COLOR_LAYER %d %s;\n", 16 + 100, "Brown"); + // *** 2006-07-26 *** + printf("LAYER %d Mill_Pour%d;\nSET FILL_LAYER %d %s;\n", + 16 + 101, 16 + 101, 16 + 101, Fillstyle16); + printf("SET COLOR_LAYER %d %s;\n", 16 + 101, "Cyan"); + printf("LAYER %d Mill_Out%d;\nSET FILL_LAYER %d %s;\n", + 16 + 102, 16 + 102, 16 + 102, Fillstyle16); + printf("SET COLOR_LAYER %d %s;\n", 16 + 102, "LGray"); + // 2013-02-19 + printf("LAYER %d Mill_Dril;\nSET FILL_LAYER %d %s;\n", + 144, 144, Fillstyle16); + printf("SET COLOR_LAYER %d %s;\n", 144, "LGray"); + printf("LAYER %d Mill_Hole;\nSET FILL_LAYER %d %s;\n", + 145, 145, Fillstyle16); + printf("SET COLOR_LAYER %d %s;\n", 145, "LGray"); + + // 2005-06-21 + if (SelectedPlusLayerTop) { + printf("LAYER %d plusLayerTop%d;\n", SelectedPlusLayerTop + 100, SelectedPlusLayerTop); + printf("SET COLOR_LAYER %d %s;\n", SelectedPlusLayerTop + 100, "LRed"); + } + if (SelectedPlusLayerBot) { + printf("LAYER %d plusLayerBot%d;\n", SelectedPlusLayerBot + 100, SelectedPlusLayerBot); + printf("SET COLOR_LAYER %d %s;\n", SelectedPlusLayerBot + 100, "LCyan"); + } + return; +} + + +// ***Device output functions *** +void DeviceInit(int tool, int Layer) { + int n; + set_tool_rack(); + // Do anything necessary to initialize the output device + switch (SelectedDevice) { + case devScript: + // TODO make the layer user definable? + if (Layer == 45) { + printf("CHANGE LAYER %d;\n", Layer + 100); // 2013-02-19 + } + else if (InPassPour) { + real overlap = MillToolFree * OverlapOutlPercent / 100; + if (Layer == 44) { + printf("CHANGE Layer %d;\n", Layer + 100); // 2013-02-19 + } + else { + printf("CHANGE LAyER %d;\n", Layer + 101); // 2006-07-26 + printf("CHANGE WIDtH %.8f;\n", MillToolFree); + printf("SET WIRE_BEND 2;\n"); + } + } + break; + + case devHPGL: + if (Generatedrills) { + if (!InPassDimensionPoly && !InPass2 && !InPassPour && !InPassOutmill) { + output(filesetext(MillFileName,".pli"), "at") { + printf("#2933\n%s\n", Tool_Rack_string); + } + } + if (!InitDone) { + printf ("IN;\nIP 0,0,100,100;\nSC 0,100,0,100;\nPU;"); // #HPGL2929"); // 2013-04-18 + InitDone = 1; + } + } + break; + + case devISEL: + // Source: Übersicht des isel Zwischenformat zur Maschinensteuerung + // Stand: 1.2/g 08.11.99 + output(filesetext(MillFileName,".isi"), "at") { + for (n = 0; n < Cnt_tools; n++) { + printf("; T%02dC%.1f\n", n+1, Drill_tools[n]); // als Kommentar + // ** defintion T = Tool C = Diameter ** + } + } + if (!InPassDimensionPoly && !InPass2 && !InPassPour && !InPassOutmill) { + printf("IMF_PBL_V1.0 - PICTURES BY PC\n"); // 2005-06-16 + // printf("REF X0Y0Z0\n"); + printf("VEL %.0f\n", Tool_vel * ISELsolution); + printf("FASTVEL %.0f\n", Fast_vel * ISELsolution); + string tr[]; + int cntr = strsplit(tr, Tool_Rack_string, '\n'); + for (int n = 0; n < cntr; n++) { + printf("; %s\n", tr[n]); + } + } + break; + + case devCNC : + output(filesetext(MillFileName,".nci"), "at") { + printf("T%-2d = %s mm\t%s\n", tool, sToolValue[tool], PenList[tool]); + } + // Source: Programmierung Excellon Format Multi-Control X10 + // MANIA Electronic 05.03.1985 / 27.02.1986 + printf("%%\n"); // Excellon format + printf("M48\n"); // Header start + printf("M71\n"); // Unit mm | M72 = Inch + printf("G21\n"); // datron.de: CAT3D Konverter 2005-11-15 alf@cadsoft.de + printf("G90\n"); // Absolute mode | G91 incremental + for (n = 0; n < Cnt_tools; n++) { + printf("T%02dC%.1f\n", n+1, Drill_tools[n]); + // ** defintion T = Tool C = Diameter ** + } + printf("%%\n"); // end of block / new block + if (tool == Contour) { + printf("%%\n"); // end of block / new block + } + break; + } + return; +} + + +void DeviceEnd(void) { + // Do anything necessary to end output to the device + switch (SelectedDevice) { + case devScript: + break; + + case devHPGL: + printf("\nSP0;\n"); // 2013-03-06 #HPGL2989 ende der Fräsdaten\n"); // Ende der Fräsdaten + break; + + case devISEL: + printf("\FASTABS Z2000\nCOOLANT OFF\nSPINDLE OFF\nPROGEND\n"); + break; + + case devCNC: + printf("M74\nM30 Device ende\n"); // referenzpunkt anfahren 2011-01-27 + break; + } + return; +} + + +// *** generate HOLES with short way *** +void WriteHoles(int Layer) { + board(B) get_holes(B); + output_drills("; Holes"); + return; +} + + +void genDrills(void) { + Actualmilldeep = Drill_z_deep; // 2011-01-27 + board(B) { + set_tool_rack(); + output(MillFileName, "wt") { // 2008-12-05 new file = "wt" + if (test2) printf("#3025 *** Drills bohren\n"); + switch (SelectedDevice) { + case devScript: + scriptHeader(); + if (Generatedrills) { + DeviceInit(PadDrill, 44); // 2013-02-19 , OutlineMillSignalLayer); + output_drills("#3031 Script-Drills"); + } + break; + + case devHPGL: + if (Generatedrills) { + DeviceInit(PadDrill, 44); // 2004-10-05 , OutlineMillSignalLayer); + output_drills("#3038 HPGL drills"); // no message in actual drill file + } + break; + + case devISEL: + // Source: Übersicht des isel Zwischenformat zur Maschinensteuerung + // Stand: 1.2/g 08.11.99 + if (Generatedrills) { + DeviceInit(PadDrill, 44); // 2004-10-05 , OutlineMillSignalLayer); + output_drills("Isel-Drills (Pads/Vias)"); + } + break; + + case devCNC: + // Source: Programmierung Excellon Format Multi-Control X10 + // MANIA Electronic 05.03.1985 / 27.02.1986 + if (Generatedrills) { + DeviceInit(PadDrill, 44); // 2004-10-05 , OutlineMillSignalLayer); + output_drills("; CNC-Drills"); + } + break; + } + if(test2) printf("\n#3060 Drills bohren Ende\n"); + } + } + return; +} + + +// TRUE OUTLINE *** +void trueOutlineDraw(string SignalName) { + board(B) { + B.signals(S) { + if (S.name == SignalName) { + S.polygons(P) { + int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN; + int x0, y0; + int FrameWire; + string s; + int first = 1; + + P.wires(W) { + x1 = min(x1, W.x1); + x2 = max(x2, W.x1); + y1 = min(y1, W.y1); + y2 = max(y2, W.y1); + } + string lasts = ""; + P.contours(W) { + if (first) { + // a new partial polygon is starting + x0 = W.x1; + y0 = W.y1; + FrameWire = (x1 == x0 || x2 == x0) && (y1 == y0 || y2 == y0); + sprintf(s, " (%.8f %.8f)", u2mm(W.x1), u2mm(W.y1) ); + TrueOutline_coordinate = s; + lasts = s; + first = 0; + } + else if (W.x2 == x0 && W.y2 == y0) { + // this was the last wire of the partial polygon, + // so the next wire (if any) will be the first wire + // of the next partial polygon + sprintf(s, " (%.8f %.8f)", u2mm(W.x2), u2mm(W.y2) ); + if (lasts != s) TrueOutline_coordinate += s; + lasts = s; + first = 1; + } + else ; + if (!FrameWire) { + sprintf(s, " (%.8f %.8f)", u2mm(W.x2), u2mm(W.y2) ); + if (lasts != s) TrueOutline_coordinate += s; + lasts = s; + } + } + } + } + } + return ; + } +} + + +// *** the return string to start the ULP rekursiv *** +string RUN_pass(string run_Pass) { + string s; + sprintf(s, "RUN '%s' '%s' '%.8f' '%.8f' '%.8f' '%d' '%d' '%d' '%d' '%s' '%s' '%.1f' '%.1f' '%.1f' '%d' '%d' '%.8f' '%.8f' '%d' '%.8f' '%d' '%d' '%s' '%d' '%.1f' '%d' '%d' '%d' '%d' '%d' '%d' '%d' '%.8f' '%.8f' '%.8f' '%.8f' '%d' '%.8f' '%d' '%d' '%d';\n", + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 35 35 36 37 38 39 40 + argv[0], + Device, // argv[1] + MillToolOutl, // argv[2] + MillToolIsolate, // argv[3] + MillToolFree, // argv[4] + SelectedLayer1, // argv[5] + ToMillLayer1, // ergv[6] + SelectedLayer16, // argv[7] + ToMillLayer16, // argv[8] + MillFileName, // argv[9] + run_Pass, // argv[10] + DrillPad, // argv[11] + DrillVia, // argv[12] + DrillHole, // argv[13] + OverlapOutlPercent, // argv[14] + OverlapRubOutPercent, // argv[15] + Distance_Copper_Dimension, // argv[16] + DimensionMillTool, // argv[17] + Millfreeyes, // argv[18] + Holder_Spacing, // argv[19] + Onlydrill, // argv[20] + Generatedrills, // argv[21] + TrueOutline_coordinate, // argv[22] + OutlineMillSignalLayer, // argv[23] + Max_Drill_Diameter, // argv[24] + UseRack, // argv[25] + SelectedPlusLayerTop, // argv[26] + SelectedPlusLayerBot, // argv[27] + Mirror_On, // argv[28] + Dim_on_off, // argv[29] + MInner_contour, // argv[30] + CNCmillResolution, // argv[31] 2011-02-02 + Mill_z_safety, // argv[32] 2011-02-03 + Drill_z_deep, // argv[33] + Z_down, // argv[34] + Z_dimension, // argv[35] + MillOnlyContour, // argv[36] 2011-03-10 + GridDistance, // argv[37] + GridUnit, // argv[38] + GridUnitdist, // argv[39] 2013-03-05 + InitDone // argv[40] 2013-04-18 + ); + if (test) if (viewtest(" RUN_pass ("+run_Pass+") Returnstring:", s) != 0) exit(-3168); + + return s; +} + + +void save_defaults(void) { + output(filesetext(argv[0], ".def"), "wt") { + printf("%s\n", DeviceNames[SelectedDevice]); + printf("%d; 1 SelectedDevice\n", SelectedDevice); + printf("%.8f; 2 MillToolOutl\n", MillToolOutl); + printf("%.8f; 3 MillToolIsolate fuer Polygon-Isolate\n", MillToolIsolate); + printf("%.8f; 4 MillToolFree\n", MillToolFree); + printf("%d; 5 SelectedLayer1\n", SelectedLayer1); + printf("%d; 6 SelectedLayer16\n", SelectedLayer16); + printf("%.1f; 7 DrillPad\n", DrillPad); + printf("%.1f; 8 DrillVia\n", DrillVia); + printf("%.1f; 9 DrillHole\n", DrillHole); + printf("%d; 10 OverlapOutlPercent\n", OverlapOutlPercent); + printf("%d; 11 OverlapRubOutPercent\n", OverlapRubOutPercent); + printf("%.8f; 12 Distance_Copper_Dimension\n", Distance_Copper_Dimension); + printf("%.8f; 13 DimensionMillTool\n", DimensionMillTool); + printf("%d; 14 Millfreeyes\n", Millfreeyes); + printf("%.8f; 15 Holder_Spacing\n", Holder_Spacing); + printf("%d; 16 Onlydrill\n", Onlydrill); + printf("%d; 17 Generatedrills\n", Generatedrills); + printf("%.1f; 18 Max_Drill_Diameter\n", Max_Drill_Diameter); + printf("%.8f; 19 Z_down\n", Z_down); + printf("%.8f; 20 Drill_z_deep\n", Drill_z_deep); // drill deep for drilling pads, via, holes + printf("%.8f; 21 Mill_z_safety\n", Mill_z_safety); // safety distance to pcb for change tool + printf("%d; 22 Spindle_rpm\n", Spindle_rpm); // spindel rotation per minute + printf("%.8f; 23 Tool_vel\n", Tool_vel); + printf("%.8f; 24 Fast_vel\n", Fast_vel); + printf("%.8f; 25 Drill_Vel\n", Drill_Vel); + printf("%d; 26 DrillRefOn\n", DrillRefOn); + printf("%.8f; 27 DrillRefDiameter\n", DrillRefDiameter); + printf("%.8f; 28 DrillRefDeep\n", DrillRefDeep); + printf("%d; 29 UseRack\n", UseRack); + printf("%d; 30 SelectedPlusLayerTop\n", SelectedPlusLayerTop); + printf("%d; 31 SelectedPlusLayerBot\n", SelectedPlusLayerBot); + printf("%d; 32 Mirror_On\n", Mirror_On); + printf("%d; 33 MachineMenuOn\n", MachineMenuOn); + printf("%.8f; 34 ParkXposition\n", ParkXposition); + printf("%.8f; 35 ParkYposition\n", ParkYposition); + printf("%.8f; 36 ParkZposition\n", ParkZposition); + printf("%.8f; 37 Z_dimension\n", Z_dimension); + printf("%d; 38 Dim_on_off\n", Dim_on_off); + printf("%.8f; 39 Mz_down\n", Mz_down); + printf("%.8f; 40 Mdrill_z_deep\n", Mdrill_z_deep); + printf("%.8f; 41 Mmill_z_safety\n", Mmill_z_safety); + printf("%d; 42 Mspindle_rpm\n", Mspindle_rpm); + printf("%.8f; 43 Mtool_vel\n", Mtool_vel); + printf("%.8f; 44 Mfast_vel\n", Mfast_vel); + printf("%.8f; 45 MDrill_Vel\n", MDrill_Vel); + printf("%d; 46 MdrillRefOn\n", MdrillRefOn); + printf("%.8f; 47 MdrillRefDiameter\n", MdrillRefDiameter); + printf("%.8f; 48 MdrillRefDeep\n", MdrillRefDeep); + printf("%.8f; 49 MparkXposition\n", MparkXposition); + printf("%.8f; 50 MparkYposition\n", MparkYposition); + printf("%.8f; 51 MparkZposition\n", MparkZposition); + printf("%.8f; 52 Mz_dimension\n", Mz_dimension); + printf("%d; 53 Mdim_on_off\n", Mdim_on_off); + printf("%d; 54 Mmillfreeyes\n", Mmillfreeyes); + printf("%.8f; 55 MMillToolFree\n", MMillToolFree); + printf("%.8f; 56 MDimensionMillTool\n", MDimensionMillTool); + printf("%d; 57 MInner_contour\n", MInner_contour); + printf("%d; 58 CNCmillResolution\n", CNCmillResolution); + printf("%d; 59 MillOnlyContour\n", MillOnlyContour); // 2011-03-10 + printf("! *** Do not change the order of this lines *** !\n"); + } + string sinfo = info; + string sinfotext = Infotext; + info = "

    "; + Infotext = SaveInfo; + dlgRedisplay(); + wait(2); + info = sinfo; + Infotext = sinfotext; + dlgRedisplay(); + return; +} + + +void load_menu_values(string file) { + string l[]; + int n = fileread(l, file); + n = 0; + Device = l[n++]; // 0 + SelectedDevice = strtol(l[n++]); // 1 + LastSelectedDevice = SelectedDevice; + MillToolOutl = strtod(l[n++]); // 2 + MillToolIsolate = strtod(l[n++]); // 3 für Polygon-Isolate + MillToolFree = strtod(l[n++]); // 4 + SelectedLayer1 = strtol(l[n++]); // 5 + SelectedLayer16 = strtol(l[n++]); // 6 + DrillPad = strtod(l[n++]); // 7 + DrillVia = strtod(l[n++]); // 8 + DrillHole = strtod(l[n++]); // 9 + OverlapOutlPercent = strtol(l[n++]); // 10 + OverlapRubOutPercent = strtol(l[n++]); // 11 + Distance_Copper_Dimension = strtod(l[n++]); // 12 + DimensionMillTool = strtod(l[n++]); // 13 + Millfreeyes = strtol(l[n++]); // 14 + Holder_Spacing = strtod(l[n++]); // 15 + Onlydrill = strtol(l[n++]); // 16 + Generatedrills = strtol(l[n++]); // 17 + Max_Drill_Diameter = round(strtod(l[n++]) * 10) / 10; // 18 + Z_down = strtod(l[n++]); // 19 + Drill_z_deep = strtod(l[n++]); // 20 + Mill_z_safety = strtod(l[n++]); // 21 + Spindle_rpm = strtol(l[n++]); // 22 + Tool_vel = strtod(l[n++]); // 23 + Fast_vel = strtod(l[n++]); // 24 + Drill_Vel = strtod(l[n++]); // 25 + DrillRefOn = strtol(l[n++]); // 26 + DrillRefDiameter = strtod(l[n++]); // 27 + DrillRefDeep = strtod(l[n++]); // 28 + UseRack = strtol(l[n++]); // 29 + SelectedPlusLayerTop = strtol(l[n++]); // 30 + SelectedPlusLayerBot = strtol(l[n++]); // 31 + Mirror_On = strtol(l[n++]); // 32 + MachineMenuOn = strtol(l[n++]); // 33 + ParkXposition = strtod(l[n++]); // 34 + ParkYposition = strtod(l[n++]); // 35 + ParkZposition = strtod(l[n++]); // 36 + Z_dimension = strtod(l[n++]); // 37 + Dim_on_off = strtol(l[n++]); // 38 + Mz_down = strtod(l[n++]); // 39 + Mdrill_z_deep = strtod(l[n++]); // 40 + Mmill_z_safety = strtod(l[n++]); // 41 + Mspindle_rpm = strtod(l[n++]); // 42 + Mtool_vel = strtod(l[n++]); // 43 + Mfast_vel = strtod(l[n++]); // 44 + MDrill_Vel = strtod(l[n++]); // 45 + MdrillRefOn = strtol(l[n++]); // 46 + MdrillRefDiameter = strtod(l[n++]); // 47 + MdrillRefDeep = strtod(l[n++]); // 48 + MparkXposition = strtod(l[n++]); // 49 + MparkYposition = strtod(l[n++]); // 50 + MparkZposition = strtod(l[n++]); // 51 + Mz_dimension = strtod(l[n++]); // 52 + Mdim_on_off = strtol(l[n++]); // 53 + Mmillfreeyes = strtod(l[n++]); // 54 + MMillToolFree = strtod(l[n++]); // 55 + MDimensionMillTool = strtod(l[n++]); // 56 + MInner_contour = strtod(l[n++]); // 57 + CNCmillResolution = strtod(l[n++]); // 58 // 2011-02-02 + MillOnlyContour = strtol(l[n++]); // 59 // 2011-03-10 + + MOI = round((MillToolOutl + Inaccurateness) *1000) / 1000; // 2012-02-09 Problem bei vergleich von Realzahlen + return; +} + + +// ** check if exist a control file ** +void read_defaults(void) { + string def_file = filesetext(argv[0], ".def"); + string f[]; + int n = fileglob(f, def_file); + if (n) load_menu_values(def_file); + return; +} + + +// *** first place a VIA outside the board with the same signal name +// *** for used polygon to calculate the true Board-Outline (Dimesion) +void generateTruePolygonOutlines(void) { // the true outlines of board + board(B) { + int temp_millMirr_Offset = MillMirr_Offset; + if(SelectedLayer16 && ToMillLayer16) { + if (Mirror_On) { + MillMirr_Offset += MillMirr_Offset; // ** set mirror offset ** 2005-06-21 + Mirror = -1.0; // *** Mirror flag for Layer 16 *** + } + else { + MillMirr_Offset = 0; // ** reset mirror offset ** + Mirror = 1.0; + } + } + else if(SelectedLayer1 && ToMillLayer1) { + MillMirr_Offset = 0; // ** reset mirror offset ** + Mirror = 1.0; + } + if (Onlydrill) { // *** only export Drill Holes 2006-01-23 + genDrills(); // generate Drill data + output(MillFileName, "at") { // 2013-02-19 + printf("\n#3354"); + WriteHoles(OutlineMillSignalLayer); // generate Holes | 2008-12-05 new file == "wt" + } + } + else { + // *************************** + genDrills(); // *** generate Drill data *** + // *************************** + MillMirr_Offset = temp_millMirr_Offset; // ** OK ** restore the origin value 2005-05-23 + + real x1 = u2mm(B.area.x1) - DimensionMillTool, y1 = u2mm(B.area.y1) - DimensionMillTool, + x2 = u2mm(B.area.x2) + DimensionMillTool, y2 = u2mm(B.area.y2) + DimensionMillTool; + DistanceDimension = DimensionMillTool - Distance_Copper_Dimension*2; // 2009-02-05 + string h; + if (DistanceDimension < 0) { + DistanceDimension = 0; + } + + string Cmd; + sprintf(Cmd, "GRid mm FINEST;\n" + "CHANGE DRILL 0.3;\nCHANGE DIAMETER 0.5;\nCHANGE SHAPE ROUND;\n" + "SET POLYGON_RATSNEST ON;\n" + "SET WIRE_BEND 0;\n" + "CHANGE RANK 1;\n" // 2006-07-26 to generate the true outline of dimension + "CHANGE POUR SOLID;\n" + "CHANGE THERMAL OFF;\n" + "DISPLAY NONE 17 %d;\n", OutlineMillSignalLayer ); + + // make the 1st temporary Net for Normal Polygon Orphans OFF + // to generate the true outline for place the spacial polygon + // make a partial VIA for generate Polygon with orphans off + string millout; + sprintf(millout, "VIA '%s' (%.8f %.8f);\nCHANGE LAYeR %d;\n", + OutlineMillSignal, + x1 - Distance_Copper_Dimension - 2, + y1 - Distance_Copper_Dimension - 2, + OutlineMillSignalLayer + ); + Cmd += millout; + sprintf(millout, "CHANGE ISOLATE 0;\nCHANGE ORPHANS OFF;\n"); + Cmd += millout; + sprintf(millout, "CHANGE LAYEr %d;\n", OutlineMillSignalLayer); + Cmd += millout; + sprintf(millout, "POLYGON '%s' %.8f (%.8f %.8f) (%.8f %.8f)(%.8f %.8f);\nRATSNEST;\n", + OutlineMillSignal, MillToolOutl, // 2008-11-12 tool#1 + x1 - DimensionMillTool - Distance_Copper_Dimension - 4, + y1 - DimensionMillTool - Distance_Copper_Dimension - 4, + x2 + DimensionMillTool + Distance_Copper_Dimension + 4, // der Abstand muß größer sein damit das Umschliessende Polygon + y2 + DimensionMillTool + Distance_Copper_Dimension + 4, // wirklich groß genug wird + x1 - DimensionMillTool - Distance_Copper_Dimension - 4, + y1 - DimensionMillTool - Distance_Copper_Dimension - 4 + ); + Cmd += millout; + Cmd += "WINDOW FIT;\nSET WIRE_BEND 2;\n"; // 2011-09-28 wieder auf Diagonal schalten + MillMirr_Offset = temp_millMirr_Offset; // restore the origin value 2013-04-30 + Cmd += RUN_pass(PassDimensionPoly); + if (test) if (viewtest("2008-11-12 *****************:", Cmd) != 0) exit(-3410); + if (test) output(filesetext(B.name, "-cmd.txt"), "wtD") printf("%s", Cmd); + exit(Cmd); + } + } +} + + +real wire_angle(int x1, int y1, int x2, int y2) { // + real xa = u2mm(x2); + real ya = u2mm(y2); + real xe = u2mm(x1); + real ye = u2mm(y1); + real RADIUS = sqrt(((xa - xe) * (xa - xe)) + ((ya - ye) * (ya - ye))); + + if ((xa > xe) && (ya >= ye)) { /* Quadrant 1 */ + return acos((xa - xe) / RADIUS) * 57.29578; + } + if ((xa < xe) && (ya >= ye)) { /* Quadrant 2 */ + return acos((xa - xe) / RADIUS) * 57.29578; + } + if ((xa < xe) && (ya < ye)) { /* Quadrant 3 */ + return 360 - acos((xa - xe) / RADIUS) * 57.29578; + } + if ((xa > xe) && (ya < ye)) { /* Quadrant 4 */ + return 360 - acos((xa - xe) / RADIUS) * 57.29578; + } + if ((xa == xe) && (ya == ye)) { /* 0 */ + return (xa - xe); + } + if ((xa == xe) && (ya > ye)) { /* 90 */ + return (xa - xe + 90); + } + if ((xa == xe) && (ya < ye)) { /* 270 */ + return (xa - xe + 270); + } +} + + + +void draw_contour(void) { // draw polygon contour 2006-02-14 + if (SelectedDevice == devScript) printf("#3451 Polygon contour rechts-drehend!\n"); // only in Script + DeviceDraw( Pcwx[0], Pcwy[0], Pcwx[1], Pcwy[1], First_line); + for (int n = 1; n < Cntpcw-1; n++) { + DeviceDraw( Pcwx[n], Pcwy[n], Pcwx[n+1], Pcwy[n+1], Middle_line); + } + DeviceDraw( Pcwx[n], Pcwy[n], Pcwx[0], Pcwy[0], Last_line); + return; +} + + +// 2010-01-25 collect contour +void collect_contour(int lx, int ly) { + Pcwx[Cntpcw] = lx; + Pcwy[Cntpcw] = ly; + Cntpcw++; + return; +} + + +string polycoord1(string polcoord) { // // 2012-03-09 + string sp[]; + int scnt = strsplit(sp, polcoord, ' '); + if (!scnt) { + dlgMessageBox("#3474 Fehler in polycoord1() string:"+polcoord, "OK"); + exit(-3475); + } + return sp[1] + " " + sp[2]; // der String beginnt immer mit einem Space! +} + + +// ReservedOutlineSignalName +string WriteOutlines( string SignalName, int Layer) { + if (Layer == 16) { + if (Mirror_On) { + MillMirr_Offset += MillMirr_Offset; // ** set mirror offset ** 2005-05-21 + Mirror = -1.0; // *** mirror flag for Layer 16 *** 2005-06-21 + } + else { + MillMirr_Offset = 0; // ** set mirror offset ** 2005-06-21 + Mirror = 1.0; + } + } + else { + MillMirr_Offset = 0; // ** set mirror offset ** 2005-06-21 + Mirror = 1.0; + } + + board(B) { + string Cmd; + B.signals(S) { + if (S.name == SignalName && !Onlydrill) { + S.polygons(P) { + if (P.layer == Layer) { + if (InPass2) DeviceReInit(Contour, Layer, "3462"); + if (InPassPour) DeviceReInit(BlowUp_RubOut, Layer, "3463"); + if (InPassOutmill) { + if (test2) printf("\n#3507 jetzt holes bohren"); + WriteHoles(OutlineMillSignalLayer); // zuerst bohren! + DeviceReInit(DimensionLine, Layer, "3487"); if (test2) printf("\n#3509 jetzt aus Träger fräsen"); + InPassPour = ""; // Reset pouring 2006-10-10 + MillToolFree = 0.0; + } + + int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN; + int x0, y0; + int State; + int first = 1; + + P.wires(W) { + x1 = min(x1, W.x1); + x2 = max(x2, W.x1); + y1 = min(y1, W.y1); + y2 = max(y2, W.y1); + } + + // *** check more at one contours inside the board *** + if (InPass2 || InPassPour || MillToolFree) { // 2011-02-02 auch wenn nur 1. Isolation + int i = -1; + int active; + do { // 2020-01-25 use contour index + active = 0; + first = 1; + Cntpcw = 0; // Reset polygon contour wiresegment counter + P.contours(W, i) { // start milling polygon contours ** + active = 1; + if (first) { + collect_contour( W.x1, W.y1); // count polygon contour wire + collect_contour( W.x2, W.y2); // count polygon contour wire + first = 0; + } + else collect_contour(W.x2, W.y2); + } + draw_contour(); + i--; + } while (active); + + if (MInner_contour || InPassPour) { // 2010-04-08 milling always contour of pooring + i = 1; // draw also right rotation contours inside SIGNAL-Filling Polygon + do { + active = 0; + first = 1; + Cntpcw = 0; // Reset polygon contour wiresegment counter + P.contours(W, i) { // start milling polygon contours ** + active = 1; + if (first) { + collect_contour( W.x1, W.y1); // count polygon contour wire + collect_contour( W.x2, W.y2); // count polygon contour wire + first = 0; + } + else collect_contour(W.x2, W.y2); + } + draw_contour(); + i++; + } while (active); + } + + if (InPassPour && Millfreeyes) { + if (SelectedDevice == devScript) { + printf("\n#3569 start pouring\n"); + } + DeviceReInit(BlowUp_RubOut, Layer, "3529"); + int fx1[], fy1[], fx2[], fy2[], dir[], down[]; + int fcnt = 0; + P.fillings(F) { + fx1[fcnt] = F.x1; + fy1[fcnt] = F.y1; + fx2[fcnt] = F.x2; + fy2[fcnt] = F.y2; + fcnt++; + } + int diry = fy1[0]; + int m; + for (m = 0; m < fcnt; m++) { + if (diry == fy1[m]) { + dir[m] = 0; + } + else { + // ****** milling reverse ****** + diry = fy1[m]; // set direction next y_line + int mbx1[], mby1[], mbx2[], mby2[];; + for (int mb = m; mb <= fcnt; mb++) { + if (diry == fy1[mb]) { + mbx1[mb] = fx1[mb]; + mby1[mb] = fy1[mb]; + mbx2[mb] = fx2[mb]; + mby2[mb] = fy2[mb]; + dir[mb] = -1; + } + else break; // Y is changed also change direction back + } + --mb; // *** OK for/break beendet bei counter +1 + + for(int mback = mb ; mback >= m; mback--) { + // DeviceDraw(fx2[mback], fy2[mback], fx1[mback], fy1[mback], State); + // reverse milling 2002-05-08 alf@cadsoft.de + // swap array backward + int xdif = mback - m; + int nx = m + (mb - mback); + fx1[nx] = mbx2[mback]; + fy1[nx] = mby2[mback]; + fx2[nx] = mbx1[mback]; + fy2[nx] = mby1[mback]; + } + m = ++mb; // *** OK for beendet bei counter -1 + diry = fy1[m]; // set direction next y_line + } + } + + // check X, if not changed do not lift up milling tool + int downdist = MillToolFree * 10000 / 2; // tool radius + for (m = 0; m < fcnt-1; m++) { + int lx = abs(fx2[m] - fx1[m+1]); + if (lx < downdist) { // *** do not lift up if distance < tool radius 2005-06-08 *** + if (fy2[m] != fy1[m+1]) { // 2005-06-28 + down[m] = 1; + down[m+1] = 1; + } + } + if (m) { + int lx1 = abs(fx2[m-1] - fx1[m]); + int lx2 = abs(fx2[m] - fx1[m+1]); + if (lx1 < downdist && lx2 < downdist) { // *** do not lift up if distance < tool radius 2005-06-08 *** + down[m]++; + } + } + } + + // enum { First_line, Middle_line, Last_line, Drill_coord, One_line } + State = One_line; + int LastLine; + for (m = 0; m < fcnt; m++) { + if (Lift_Off) { + switch(down[m]) { + case 0 : State = One_line; + break; + + case 1 : // 2005-06-28 + if (State == First_line) { + DeviceDraw(0, 0, fx1[m], fy1[m], Middle_line); + State = Last_line; + } + else if (State == Last_line) State = First_line; + else if (State == Middle_line) { + DeviceDraw(0, 0, fx1[m], fy1[m], Middle_line); + State = Last_line; + } + else if (State == One_line) State = First_line; + break; + + case 2 : State = Middle_line; + DeviceDraw(0, 0, fx1[m], fy1[m], State); + break; + } + } + if (test) if (SelectedDevice == devScript) printf("#test m %d\n", m); // nur zum testen mit SCRIPT !!! 2005-06-24 + DeviceDraw(fx1[m], fy1[m], fx2[m], fy2[m], State); + } + } + } + + // start board out milling + // nur die berechnete Kontur zum ausfräsen aus dem Träger ausgeben. // + if (InPassOutmill) { + // ReservedOutlineSignalName == "~_REAL_OUTLINEMILL_~") + int pw1x, pw1y; + P.wires(W) { + pw1x = W.x1; + pw1y = W.y1; + } + int countContourP = 0; // 2011-10-04 + int countContourN = 0; + int ip = 0; + int in = 0; + int active; + do { + countContourP = 0; + P.contours(W, ip) { + countContourP = 1; + break; + } + if (countContourP) ip++; + else break; + } while (ip); + countContourP = ip-1; // 2011-10-04 do not draw defined polygon contour + // the last polygonoutline ist the defined outline + do { + countContourN = 0; + P.contours(W, in) { + countContourN = 1; + break; + } + if (countContourN) in--; + else break; + } while (in); + countContourN = in; + + first = 1; + // printf("M999 die Platine aus dem Träger fräsen.\n"); + //**** 2011-10-04 + int i = -1; // draw left rotation contours inside SIGNAL-Filling Polygon + active; + do { + if (i == countContourN) break; + active = 0; + first = 1; + Cntpcw = 0; // Reset polygon contour wire segment counter + P.contours(W, i) { // start milling polygon contours ** + active = 1; + if (first) { + collect_contour( W.x1, W.y1); // count polygon contour wire + collect_contour( W.x2, W.y2); // count polygon contour wire + first = 0; + } + else collect_contour(W.x2, W.y2); + } + draw_contour(); + i--; + } while (active); + + i = 1; // draw right rotation contours inside SIGNAL-Filling Polygon + do { + if (i == countContourP) break; + active = 0; + first = 1; + Cntpcw = 0; // Reset polygon contour wiresegment counter + P.contours(W, i) { // start milling polygon contours ** + active = 1; + if (first) { + collect_contour( W.x1, W.y1); // count polygon contour wire + collect_contour( W.x2, W.y2); // count polygon contour wire + first = 0; + } + else collect_contour(W.x2, W.y2); + } + draw_contour(); + i++; + } while (active); + //**** 2011-10-04 + } + // end of board out milling + } + break; + } + } + } + return Cmd; + } +} + + +// *** Pen assign *** +void toolAssign(void) { + set_tool_rack(); + dlgDialog("Mill outlines - Tool Assignment") { + dlgHBoxLayout dlgSpacing(300); + switch (SelectedDevice) { + case devScript : dlgLabel(Script_Used); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgVBoxLayout { + dlgLabel("Drill Rack"); + dlgTextView(Tool_Rack_string); + } + } + if (Drilltoolsplus) { + dlgHBoxLayout { + dlgTextView(Drilltoolsplus + "! This drills are milling !"); + } + } + break; + + case devHPGL : dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgVBoxLayout { + dlgLabel("PEN definition #3777"); + dlgTextView(Tool_Rack_string); + } + } + if (Drilltoolsplus) { + dlgHBoxLayout { + dlgTextView(Drilltoolsplus + "! This drills are milling !"); + } + } + break; + + case devISEL : dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgVBoxLayout { + dlgLabel("Drill Rack"); + dlgTextView(Tool_Rack_string); + } + } + if (Drilltoolsplus) { + dlgHBoxLayout { + dlgTextView(Drilltoolsplus + "! This drills are milling !"); + } + } + break; + + case devCNC : dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgVBoxLayout { + dlgLabel("Drill Rack"); + dlgTextView(Tool_Rack_string); + } + } + if (Drilltoolsplus) { + dlgHBoxLayout { + dlgTextView(Drilltoolsplus + "! This drills are milling !"); + } + } + break; + + default : dlgLabel("No device selected!
    "); + break; + } + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + + +void selectDevice(void) { + Xfile = filesetext(MillFileName, DeviceExt[SelectedDevice]); + switch (SelectedDevice) { + case devScript : info = Showpic[13]; + zinfo = Showpic[13]; + if (language() == "de") { + Infotext = "
    Erzeugt Fräswege als Eagle-SCRIPT
    und liest das Script in das Board ein.
    " + + "Der Ziel-Layer ist der Layer 101 bzw. 116 für die Isolation.

    " + + "Layer 102 / 117 für das Freifräsen (Pouring).
    " + + "Layer 103 / 118 für die Aussenkontur (Dimension).
    " + + "Layer 144 für die Drills (PAD/VIA).
    " + "Layer 145 für die Holes."; // 2013-02-27 + } + else { + Infotext = "Generate the milling tracks in to a Eagle SCRIPT
    " + "and read this script in to the Board.
    " + + "The target layer is the layer 101 respectively 116.

    " + + "Layer 102 / 117 to read copper pouring milling.
    " + + "Layer 103 / 118 to read real outlines milling (Dimension).
    " + "Layer 144 to read drills (PAD/VIA).
    " + "Layer 145 to read holes."; // 2013-02-27 + } + DrillLabel = "Drill file"; + if (LastSelectedDevice != devScript && LastSelectedDevice != devHPGL) { // 2006-02-15 + Mz_down = Z_down; + Mdrill_z_deep = Drill_z_deep; + Mmill_z_safety = Mill_z_safety; + Mspindle_rpm = Spindle_rpm; + Mtool_vel = Tool_vel; + Mfast_vel = Fast_vel; + MDrill_Vel = Drill_Vel; + MdrillRefOn = DrillRefOn; + MdrillRefDeep = DrillRefDeep; + MparkXposition = ParkXposition; + MparkYposition = ParkYposition; + MparkZposition = ParkZposition; + Mz_dimension = Z_dimension; + } + Z_down = 0; + Drill_z_deep = 0; + Mill_z_safety = 0; + Spindle_rpm = 0; + Tool_vel = 0; + Fast_vel = 0; + Drill_Vel = 0; + ParkXposition = 0; + ParkYposition = 0; + ParkZposition = 0; + Z_dimension = 0; + LastSelectedDevice = devScript; + Machineparameter = "Not used for SCRIPT"; + break; + + case devHPGL : info = Showpic[14]; + if (language() == "de") { + Infotext = "Generiert die Daten (Fräswege) als HPGL Datei.
    " + + "PEN #8 ist reserviert zum wechseln der Platine
    " + + "Vorder - Rückseite (spiegeln).
    "; + DrillLabel = "Drills in HPGL Datei enthalten"; + } + else { + Infotext = "Generate the milling tracks as HPGL file.
    " + + "PEN #8 is reserved for switch pcb to milling second side.
    "; + DrillLabel = "HPGL file include drills"; + } + if (LastSelectedDevice != devScript && LastSelectedDevice != devHPGL) { // 2006-02-15 + Mz_down = Z_down; + Mdrill_z_deep = Drill_z_deep; + Mmill_z_safety = Mill_z_safety; + Mspindle_rpm = Spindle_rpm; + Mtool_vel = Tool_vel; + Mfast_vel = Fast_vel; + MDrill_Vel = Drill_Vel; + MdrillRefOn = DrillRefOn; + MdrillRefDeep = DrillRefDeep; + MparkXposition = ParkXposition; + MparkYposition = ParkYposition; + MparkZposition = ParkZposition; + Mz_dimension = Z_dimension; + } + Z_down = 0; + Drill_z_deep = 0; + Mill_z_safety = 0; + Spindle_rpm = 0; + Tool_vel = 0; + Fast_vel = 0; + Drill_Vel = 0; + ParkXposition = 0; + ParkYposition = 0; + ParkZposition = 0; + Z_dimension = 0; + LastSelectedDevice = devHPGL; + Machineparameter = "Not used for HPGL"; + break; + + case devISEL : info = Showpic[23]; + if (language() == "de") { + Infotext = "Generiert die Daten (Fräswege) als ISEL Zwischenformat."; + DrillLabel = "Drills in ISEL Datei enthalten"; + } + else { + Infotext = "Generate the milling tracks as ISEL intermediate format file."; + DrillLabel = "ISEL file include drils"; + } + if (LastSelectedDevice == devScript || LastSelectedDevice == devHPGL) { // 2006-02-15 + Z_down = Mz_down; + Drill_z_deep = Mdrill_z_deep; + Mill_z_safety = Mmill_z_safety; + Spindle_rpm = Mspindle_rpm; + Tool_vel = Mtool_vel; + Fast_vel = Mfast_vel; + Drill_Vel = MDrill_Vel; + DrillRefOn = MdrillRefOn; + DrillRefDeep = MdrillRefDeep; + ParkXposition = MparkXposition; + ParkYposition = MparkYposition; + ParkZposition = MparkZposition; + Z_dimension = Mz_dimension; + } + LastSelectedDevice = devISEL; + Machineparameter = "Use for ISEL"; + break; + + case devCNC : info = Showpic[24]; + if (language() == "de") { + Infotext = "Generiert die Daten (Fräswege) als CNC Datei."; + DrillLabel = "Drills in CNC Datei enthalten"; + } + else { + Infotext = "Generate the milling tracks as CNC file."; + DrillLabel = "CNC file include drills"; + } + if (LastSelectedDevice == devScript || LastSelectedDevice == devHPGL) { // 2006-02-15 + Z_down = Mz_down; + Drill_z_deep = Mdrill_z_deep; + Mill_z_safety = Mmill_z_safety; + Spindle_rpm = Mspindle_rpm; + Tool_vel = Mtool_vel; + Fast_vel = Mfast_vel; + Drill_Vel = MDrill_Vel; + DrillRefOn = MdrillRefOn; + DrillRefDeep = MdrillRefDeep; + ParkXposition = MparkXposition; + ParkYposition = MparkYposition; + ParkZposition = MparkZposition; + Z_dimension = Mz_dimension; + } + LastSelectedDevice = devCNC; + Machineparameter = "Use for CNC"; + break; + + default : info = Showpic[21]; + Infotext = "
    No device selected!
    "; + Xfile = ""; + DrillLabel = "D&rill file"; + Mz_down = Z_down; + Mdrill_z_deep = Drill_z_deep; + Mmill_z_safety = Mill_z_safety; + Mspindle_rpm = Spindle_rpm; + Mtool_vel = Tool_vel; + Mfast_vel = Fast_vel; + MDrill_Vel = Drill_Vel; + MdrillRefOn = DrillRefOn; + MdrillRefDeep = DrillRefDeep; + Z_down = 0; + Drill_z_deep = 0; + Mill_z_safety = 0; + Spindle_rpm = 0; + Tool_vel = 0; + Fast_vel = 0; + Drill_Vel = 0; + ParkXposition = MparkXposition; + ParkYposition = MparkYposition; + ParkZposition = MparkZposition; + Z_dimension = Mz_dimension; + Z_dimension = 0; + Machineparameter = "Not used"; + break; + } + + return; +} + + +// *** the milling offset, if reference package placed *** +void setMillOffset(void) { + board(B) { + Path = filedir(B.name); + B.elements(E) { + if (E.package.name == Ref_pac) { + Ref_offsetX[Ref_cnto] = E.x; + Ref_offsetY[Ref_cnto] = E.y; + Ref_cnto++; + E.package.circles(C) { + if (C.layer == 45) { + Ref_offsetX[Ref_cnto] = C.x; + Ref_offsetY[Ref_cnto] = C.y; + Ref_cnto++; + } + } + if (Ref_cnto == 3) { // *** a reference package is found *** + // *** OK 2005-05-12 *** + Ref_null_offsetY = abs(Ref_offsetY[0]); + Mill_OffsetX = abs(Ref_offsetX[0]); + MillMirr_Offset = abs(Ref_offsetX[0]) + ((Ref_offsetX[1] + Ref_offsetX[2]) / 2); + if (language() == "de") + sprintf(Mirror_axis, "Spiegeloffset (0 0) %.8f / Spiegelachse (0 0) %.8f mm", u2mm(MillMirr_Offset), u2mm(MillMirr_Offset - Mill_OffsetX) ); + else + sprintf(Mirror_axis, "Mirror offset (0 0) %.8f / Mirror axis (0 0) %.8f mm", u2mm(MillMirr_Offset), u2mm(MillMirr_Offset - Mill_OffsetX) ); + } + else { + Ref_cnto = 0; // more then 2 circles can't use as reference + if (language() == "de") { + if (dlgMessageBox("Das Referenzpackage enthält mehr als 2 Kreise im Layer 45,
    " + + "die Fräsdaten werden nicht auf den Nullpunkt der Anlage bezogen berechnet.", ACCEPT, CANCEL) != 0) exit(0); + } + else { + if (dlgMessageBox("The reference Hole-Package contains more then 2 Circles in Layer 45\n" + + "generate outlines without reference-offset", ACCEPT, CANCEL) != 0) exit(0); + } + } + } + } + } + return; +} + + +void mirror_info(void) { + if (Mirror_On) Infotext = INFOmirror1; + else Infotext = INFOmirror0; + return; +} + + +void layer_info(void) { + if (SelectedLayer1 && SelectedLayer16) { + Infotext = INFOtext1_on + "

    " + INFOtext16_on; + } + else if (!SelectedLayer1 && !SelectedLayer16) { + info = ""; + Infotext = "Kein Layer gewählt!"; + } + else if (SelectedLayer1 && !SelectedLayer16) { + Infotext = INFOtext1_on + "

    " + INFOtext16_off; + } + else if (!SelectedLayer1 && SelectedLayer16) { + Infotext = INFOtext1_off + "

    " + INFOtext16_on; + } + return; +} + + +void setblowinfo(void) { + if (MillToolFree) { + if (Millfreeyes) { + info = Showpic[18]; + if (Millfreeyes && !MillToolFree) Infotext = MILLfreeYes; + else Infotext = TOOLdiamBlow; + } + else { + info = Showpic[20]; + Infotext = TOOLdiamRub; + } + } + else { + if(Millfreeyes) { + info = Showpic[21]; // Question? + Infotext = MILLfreeYes; + } + else { + info = Showpic[19]; // No second isolate grey + Infotext = MILLfreeNo; + } + } + return; +} + + +void checkDimension(UL_BOARD B) { + B.layers(L) { + if (L.number == 20) { + if (L.used) return; + dlgMessageBox(MissingDimension, "OK"); + exit(-4121); + } + } +} + + +void dlg_PlaceVia(void) { // 2010-08-04 dlgMessageBox kann keine Bitmaps mit Texten gemixt als String anzeigen. + dlgDialog("mill-outlines place VIA") { + dlgLabel(Showpic[22]); + dlgLabel(INFOinnerContour); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("PlaceVIA") { dlgAccept(); exit ("VIA '~_REAL_OUTLINEMILL_~'"); } + dlgPushButton(CANCEL) dlgReject(); + dlgStretch(1); + } + }; + return; +} + +// *************** +// Main program: +// *************** + +if (!argv[1]) { + board(B) drufile = filesetext(B.name , ".dru"); + string cmd ="DRC SAVE '"+drufile+"'; RUN '"+argv[0]+"' DRCsaved"; + exit(cmd); // 2012-01-16 immer Design-Regeln aktuell speichern +} + +setMillOffset(); // get info if special package placed + +// get Command-Line parameter if use RUN +if (argv[1]) { + if (argv[1] == "DRCsaved") ; // 2012-01-16 + else { + Device = argv[1]; + if (argv[2]) { + MillToolOutl = strtod(argv[2]); + if (MillToolOutl <= 0) { + if (language() == "de") { + Fatal("Falscher Durchmesser für das Isolieren (tool #1): " + argv[2], "Der Durchmesser grösser als 0 sein."); + } + else { + Fatal("Illegal diameter for milling tool #1: " + argv[2], "The diameter must be greater than zero."); + } + } + MillToolIsolate = strtod(argv[3]); // für Polygon Isolate + MillToolFree = strtod(argv[4]); + SelectedLayer1 = strtol(argv[5]); + ToMillLayer1 = strtol(argv[6]); + SelectedLayer16 = strtol(argv[7]); + ToMillLayer16 = strtol(argv[8]); + MillFileName = argv[9]; + + if (argv[10] == PassDimensionPoly) { + InPassDimensionPoly = argv[10]; // 1. generate true outlines + } + else if (argv[10] == Pass2) { + InPass2 = argv[10]; // 2. smal isolate + } + else if (argv[10] == PassPour) { + InPassPour = argv[10]; // 3. wide isolate plus pouring + } + else if (argv[10] == PassOutmill) { + InPassOutmill = argv[10]; // 4. milling out from big material + } + else { + dlgMessageBox("! argv[11] unknown!\n" + argv[10], "OK"); + exit(-4190); + } + + DrillPad = strtod(argv[11]); + DrillVia = strtod(argv[12]); + DrillHole = strtod(argv[13]); + OverlapOutlPercent = strtol(argv[14]); + OverlapRubOutPercent = strtol(argv[15]); + Distance_Copper_Dimension = strtod(argv[16]); + DimensionMillTool = strtod(argv[17]); + Millfreeyes = strtol(argv[18]); + Holder_Spacing = strtod(argv[19]); + Onlydrill = strtol(argv[20]); + Generatedrills = strtol(argv[21]); + TrueOutline_coordinate = argv[22]; + OutlineMillSignalLayer = strtol(argv[23]); + Max_Drill_Diameter = round(strtod(argv[24]) * 10) / 10; + UseRack = strtol(argv[25]); + SelectedPlusLayerTop = strtol(argv[26]); + SelectedPlusLayerBot = strtol(argv[27]); + Mirror_On = strtol(argv[28]); + Dim_on_off = strtol(argv[29]); + MInner_contour = strtol(argv[30]); + CNCmillResolution = strtol(argv[31]); // 2011-02-02 + Mill_z_safety = strtod(argv[32]); + Drill_z_deep = strtod(argv[33]); + Z_down = strtod(argv[34]); + Z_dimension = strtod(argv[35]); + MillOnlyContour = strtol(argv[36]); // 2011-03-10 + GridDistance = strtod(argv[37]); + GridUnit = strtol(argv[38]); + GridUnitdist = strtol(argv[39]); // 2013-03-05 + InitDone = strtol(argv[40]); // 2013-04-18 + // check parameters + if (!SelectedLayer1 && !SelectedLayer16) + Fatal("Illegal layer: " + argv[5] + " /" + argv[6], "The layer(s) must be 1 or/and 16."); + + if (Generatedrills) { // wenn keine Drills erzeugt werden, + // muß auch die Gültigkeit nicht abgefragt werden 2006-01-26 + if (DrillPad <= 0) { + if (language() == "de") { + Fatal("Verbotener Bohrdurchmasser für Pad: " + argv[10], "Der diameter muß größer als 0 sein."); + } + else { + Fatal("Illegal diameter for Pad drill tool: " + argv[10], "The diameter must be greater than zero."); + } + } + if (DrillVia <= 0) { + if (language() == "de") { + Fatal("Verbotener Bohrdurchmasser für Via: " + argv[11], "Der diameter muß größer als 0 sein."); + } + else { + Fatal("Illegal diameter for Via drill tool: " + argv[11], "The diameter must be greater than zero."); + } + } + if (DrillHole <= 0) { + if (language() == "de") { + Fatal("Verbotener Bohrdurchmasser für Hole: " + argv[12], "Der diameter muß größer als 0 sein."); + } + else { + Fatal("Illegal diameter for Hole drill tool: " + argv[12], "The diameter must be greater than zero."); + } + } + } + } + } +} + +if (!MillFileName) board(B) MillFileName = filesetext(B.name, DefaultSuffix); + + +if (Device) { + ValueInit(); + int n; + while (DeviceNames[n]) { // upper case + if (strupr(DeviceNames[n]) == strupr(Device)) { + SelectedDevice = n; + break; + } + n++; + } + if (!SelectedDevice) { + if (language() == "de") { + Fatal("Kein Device gewählt: " + Device, "Wählen Sie ein gültiges Device."); + } + else { + Fatal("Illegal device: " + Device, "Please select one of the known devices."); + } + } +} + + +// ******** main menu ******** +if ( !InPass2 && !InPassPour && !InPassOutmill && !InPassDimensionPoly) { + int ForceDialog = (!Device || !MillToolOutl); + + board(B) { + checkDimension(B); + int n; + string del_pol; + B.signals(S) { + if (S.name == ReservedOutlineSignalName) { // 2008-11-12 if exist reseved polygon, first delete + S.polygons(POL) { + POL.wires(W) { + sprintf(del_pol, "GriD MM;\nDELETE (S %.8f %.8f);", u2mm(W.x1), u2mm(W.y1) ); + break; + } + break; + } + if (language() == "de") { + if (Error("Es existiert ein Signal " + ReservedOutlineSignalName + " in dem Board!", + "Dieser Signalname ist für das ULP reserviert!
    Stellen Sie sicher das kein Signal mit diesem Namen im Layout benutzt wird.
    ", + "OK", "Delete") != 0) exit(del_pol); + exit(-4303); + } + else { + Fatal("There is already a signal named " + ReservedOutlineSignalName + " in this board!", "Please make sure that there is no such signal in this board."); + } + } + + // *** Check if used Rank 6 - 2006-07-26 *** + string s; + int is_polygon = 0; + S.polygons(P) { + is_polygon++; + if (P.rank == 6) { + P.contours(W) { + if (language() == "de") { + sprintf(s, "!%s Polygon in Layer %d an (%.8f %.8f)mm hat Rank 6.\n\nBenutzen Sie nicht Rank 6 wenn Sie dieses ULP nutzen.\n" + + "Prüfen Sie die Ranks 1..5 bevor Sie dieses ULP nochmal starten.", S.name, P.layer, u2mm(W.x1), u2mm(W.y1) ); + } + else { + sprintf(s, "!%s Polygon in Layer %d at (%.8f %.8f)mm has Rank 6.\n\nDo not use Rank 6 while working with this ULP.\n" + + "Change the rank to 1..5 before using this ULP again.", S.name, P.layer, u2mm(W.x1), u2mm(W.y1) ); + } + break; + } + dlgMessageBox(s, "OK"); + exit(0); + } + } + Class_used[S.class.number]++; + } + + if (!SelectedLayer1 && !SelectedLayer16) { + ForceDialog = 1; + } + + // ******************* + int fault; + + if (ForceDialog) { + GridDistance = B.grid.distance; // argv[37] + GridUnit = B.grid.unit; // argv[38] + GridUnitdist = B.grid.unitdist; // argv[39] 2013-03-05 + + SelectedDevice = Defaultdevice; // overwritten by load_menu_values() + string plus_Text[] = { "none" }; + int cnt_plusText = 1; + B.layers(L) { + if (L.used) { + sprintf(plus_Text[L.number], "%2d %s", L.number, L.name); + ++cnt_plusText; + } + else { + sprintf(plus_Text[L.number], "%2d nu", L.number); + } + + if (L.number == 1 && L.visible && L.used) { + SelectedLayer1 = 1; + sprintf(Layer1, "%d %s", L.number, L.name); + } + if (L.number == 16 && L.visible && L.used) { + SelectedLayer16 = 16; + sprintf(Layer16, "%d %s", L.number, L.name); + } + } + read_defaults(); // 2012-01-13 + string dru_file = get_DesignRules(B.name); // 2006-11-08 / 2012-02-09 read the CopperDimension value from Designrules + + // check CLASS and change if not enuff + string chclass = checkClassClear(B); + if (chclass) { + chclass += "\n CLASS\n"; + exit(chclass); // 2012-01-16 return CLASS definition + } + get_rack(B); // collect Rackdata for drilling machine + get_drills(B); // collect Drilldata for drilling Pad and Via + + selectDevice(); // 2005-05-18 *** set the default device and filenames *** + if (!Distance_Copper_Dimension) { + if (language() == "de") { + dlgMessageBox("!Benutzen Sie nicht den Wert 0, für Distance Copper/Dimension
    ULP gestoppt!", "OK"); + } + else { + dlgMessageBox("!Do not use zero for Distance Copper/Dimension\nULP Stoped!", "OK"); + } + exit("DRC"); + } + if (DRC_changed) { + string h; + sprintf(h, "%s\nSet all %d values to tool diameter #1 + %.8f = %.8f mm ?", + DRC_changed_message, + DRC_changed, + Inaccurateness, + MillToolOutl + Inaccurateness + ); + dlgDialog("Design Rules") { + dlgLabel(h); // 2020-10-28 + dlgHBoxLayout { + dlgPushButton("+"+YES) dlgAccept(); + dlgPushButton("Change Tool #1") { // 2012-01-25 + DRC_changed = 0; + MillToolOutl = minDistWireWire - Inaccurateness; + Clearance_check = ""; // reset clearance check + save_defaults(); + dlgAccept(); + } + dlgStretch(1); + } + }; + output(drufile, "wt") { + for (int n = 0; n < DRUlcnt; n++) { + printf("%s\n", DRUvalues[n]); + } + } + if (test) dlgMessageBox("Jetzt werden die Design-Reglen geladen und wieder gespeichert", "OK"); + if (DRC_changed) exit("SET Interface.PreferredUnit 2;\nDRC LOAD '"+drufile+"';\n DRC SAVE '"+drufile+"';\nDRC;\n RUN '" + argv[0]+"'"); + } + + if (Clearance_check) { + fault = Error(Error5, "" + Clearance_check + "", "Change &Tool #1", DRCCHECK); // [Change &Tool #1] 2012-01-20 + if (fault) exit("CLASS"); + } + + Showpic[0] = ""; + Showpic[1] = ""; + Showpic[2] = ""; + Showpic[3] = ""; + Showpic[4] = ""; + Showpic[5] = ""; + Showpic[6] = ""; + Showpic[7] = ""; + Showpic[8] = ""; + Showpic[9] = ""; + Showpic[10] = ""; + Showpic[11] = ""; + Showpic[12] = ""; + Showpic[13] = ""; + Showpic[14] = ""; + Showpic[15] = ""; + Showpic[16] = ""; + Showpic[17] = ""; + Showpic[18] = ""; + Showpic[19] = ""; + Showpic[20] = ""; + Showpic[21] = ""; + Showpic[22] = ""; + Showpic[23] = ""; + Showpic[24] = ""; + Showpic[25] = ""; + Showpic[26] = ""; + Showpic[27] = ""; + Showpic[28] = ""; + Showpic[29] = ""; + Showpic[30] = ""; + Showpic[31] = ""; + Showpic[32] = ""; + Showpic[33] = ""; // 2011-02-07 Nullpunkt des Board = Maschinennullpunkt + Showpic[34] = ""; + Showpic[35] = ""; + Showpic[36] = ""; // 2010-01-25 inner/outer polygon contour + Showpic[37] = ""; + Showpic[38] = ""; // 2011-02-02 Auflösung Vor- Nachkommastellen + Showpic[39] = ""; // 2011-02-11 + info = Showpic[10]; + zinfo = Showpic[24]; + zInfotext = Z_Machine_Menu; + + if (Mill_OffsetX) { + Infotext = DRCinfo; + } + else { + Infotext = REFinfo2 + DRCinfo; + } + + Xfile = MillFileName; + string sDistance_Copper_Dimension; + sprintf(sDistance_Copper_Dimension, "%.6f mm", Distance_Copper_Dimension); + selectDevice(); + if (Ref_cnto == 3) { + if (dlgMessageBox(InfoREFPack+"

    Option Mill Board/Dim = On?", YES, NO) != 0) { // 2013-04-19 Ausfräsen aus Träger, trotzt Fangzapfen? + Dim_on_off = 0; // wenn ein Refpackage platziert ist, darf die Aussenkontur eventuell nicht gefräst werden, + // denn sonst würde/könnte der Fräser die Haltestifte durchfräsen und dabei zerstört werden. + // 2011-02-09 + } + } + dlgDialog(Header) { + dlgTabWidget { + dlgTabPage("General") { + dlgHBoxLayout { + dlgGridLayout { + dlgCell( 0, 0) dlgLabel("&Device"); + dlgCell( 0, 1) dlgComboBox(DeviceNames, SelectedDevice) selectDevice(); + dlgCell( 0, 3) dlgLabel(LayerStack); // 2012-01-16 + dlgCell( 0, 4) dlgPushButton("Tool &Assignment") toolAssign(); + + dlgCell( 1, 4) dlgCheckBox("&Gen. drills", Generatedrills) { + info = Showpic[7]; + if (Generatedrills) { + Infotext = GENdrilON; + DrillPad = MDrillPad; + DrillVia = MDrillVia; + DrillHole = MDrillHole; + } + else { + Infotext = GENdrilOFF; + MDrillPad = DrillPad; + MDrillVia = DrillVia; + MDrillHole = DrillHole; + DrillPad = 0; + DrillVia = 0; + DrillHole = 0; + } + } + + dlgCell( 2, 4) dlgCheckBox("Use rac&k", UseRack) { + info = Showpic[6]; + if (!UseRack) { + Infotext = USErackOFF; + } + else { + Infotext = USErackON; + } + } + + dlgCell( 3, 4) dlgCheckBox("Onl&y Drills ", Onlydrill) { + if (Onlydrill) { + Generatedrills = 1; + info = Showpic[7]; + Infotext = OnlyDrillHpgl; + DrillPad = MDrillPad; + DrillVia = MDrillVia; + DrillHole = MDrillHole; + MMillToolOutl = MillToolOutl; + MillToolOutl = 0; + MOverlapOutlPercent = OverlapOutlPercent; + OverlapOutlPercent = 0; + MMillToolFree = MillToolFree; + MillToolFree = 0; + MOverlapRubOutPercent = OverlapRubOutPercent; + OverlapRubOutPercent = 0; + Mmillfreeyes = Millfreeyes; + Millfreeyes = 0; + MDimensionMillTool = DimensionMillTool; + DimensionMillTool = 0; + Mdim_on_off = Dim_on_off; + Dim_on_off = 0; + MHolder_Spacing = Holder_Spacing; + Holder_Spacing = 0; + } + else { + MillToolOutl = MMillToolOutl; + OverlapOutlPercent = MOverlapOutlPercent; + MillToolFree = MMillToolFree; + OverlapRubOutPercent = MOverlapRubOutPercent; + Millfreeyes = Mmillfreeyes; + DimensionMillTool = MDimensionMillTool; + Holder_Spacing = MHolder_Spacing; + Dim_on_off = Mdim_on_off; + } + } + + dlgCell( 1, 1) dlgHBoxLayout { + dlgLabel("Layer "); + dlgCheckBox("Top ", SelectedLayer1) { + info = ""; + layer_info(); + } + dlgStretch(1); + } + + dlgCell( 1, 3) dlgHBoxLayout { + dlgLabel("plus Layer"); + dlgComboBox(plus_Text, SelectedPlusLayerTop) { + info = ""; + Infotext = TextInfoPlus; + } + dlgStretch(1); + } + + dlgCell( 2, 0) dlgHBoxLayout { + dlgCheckBox("&Mirror ", Mirror_On) { + if (Mirror_On) info = ""; + else info = ""; + mirror_info(); + } + dlgStretch(1); + } + + dlgCell( 2, 1) dlgHBoxLayout { + dlgLabel("Layer "); + dlgCheckBox("Bottom ", SelectedLayer16) { + info = ""; + layer_info(); + } + dlgStretch(1); + } + + dlgCell( 2, 3) dlgHBoxLayout { + dlgLabel("plus Layer"); + dlgComboBox(plus_Text, SelectedPlusLayerBot) { + info = ""; + Infotext = TextInfoPlus; + } + dlgStretch(1); + } + + dlgCell( 3, 0) dlgLabel("Tool#&1 Isolate"); + dlgCell( 3, 1) dlgRealEdit(MillToolOutl, 0.005, 3.0); // 2007-10-08 min. 5 micron wg. Laser + dlgCell( 3, 2) dlgLabel("mm "); + dlgCell( 3, 3) dlgPushButton("Isolate Info") { + info = Showpic[1]; + Infotext = TOOLdiamIso + "
    " + DRC_checked + INFOInaccurat; + } + + dlgCell( 4, 0) dlgLabel("Milling"); + dlgCell( 4, 1) dlgCheckBox("inner &contour", MInner_contour) { + if (MInner_contour) info = Showpic[37]; //2010-01-25 + else info = Showpic[36]; //2010-01-25 + Infotext = Mill_mInner_contour; + } + dlgCell( 4, 2) dlgLabel("On/Off"); + dlgCell( 4, 3) dlgPushButton("Contour Info") { + if (MInner_contour) info = Showpic[37]; //2010-01-25 + else info = Showpic[36]; //2010-01-25 + Infotext = Mill_mInner_contour; + } + dlgCell( 5, 0) dlgLabel("Overlap\nisolate/blo&w-up"); + dlgCell( 5, 1) dlgIntEdit(OverlapOutlPercent, 0, 99); + dlgCell( 5, 2) dlgLabel("%"); + dlgCell( 5, 3) dlgPushButton("Overlap Info") { + info = Showpic[2]; + Infotext = OVERlapIso; + } + dlgCell( 6, 0) dlgLabel("Tool#&2 blow-up"); + dlgCell( 6, 1) dlgRealEdit(MillToolFree, 0.0, 10); + dlgCell( 6, 2) dlgLabel("mm"); + dlgCell( 6, 3) dlgCheckBox("Rub &out", Millfreeyes) { + //Mmillfreeyes = Millfreeyes; + if (Millfreeyes) { + MillToolFree = MMillToolFree; + OverlapOutlPercent = MOverlapOutlPercent; + OverlapRubOutPercent = MOverlapRubOutPercent; + } + else { + MOverlapRubOutPercent = OverlapRubOutPercent; + //OverlapRubOutPercent = 0; + MMillToolFree = MillToolFree; // 2006-01-26 + //MillToolFree = 0; + } + setblowinfo(); + } + dlgCell( 7, 0) dlgLabel("Overlap rub-o&ut"); + dlgCell( 7, 1) dlgIntEdit(OverlapRubOutPercent, 0, 99); + dlgCell( 7, 2) dlgLabel("%"); + dlgCell( 7, 3) dlgPushButton("Overlap Info") { + info = Showpic[4]; + Infotext = OVERlapRubOut; + } + dlgCell( 8, 0) dlgLabel("&Pad drill"); + dlgCell( 8, 1) dlgRealEdit(DrillPad, 0.0, 10); + dlgCell( 8, 2) dlgLabel("mm"); + dlgCell( 8, 3) dlgPushButton("Pad Info") { + info = Showpic[5]; Infotext = PADdrildiam; + } + dlgCell( 9, 0) dlgLabel("&Via drill"); + dlgCell( 9, 1) dlgRealEdit(DrillVia, 0.0, 10); + dlgCell( 9, 2) dlgLabel("mm "); + dlgCell( 9, 3) dlgPushButton("Via Info") { + info = Showpic[6]; + Infotext = VIAdrilldiam; + } + dlgCell(10, 0) dlgLabel("&Hole drill"); + dlgCell(10, 1) dlgRealEdit(DrillHole, 0.0, 10); + dlgCell(10, 2) dlgLabel("mm "); + dlgCell(10, 3) dlgPushButton("Hole Info") { + info = Showpic[7]; + Infotext = HOLEdrildiam; + } + dlgCell(11, 0) dlgLabel("Max. drill diam "); + dlgCell(11, 1) dlgRealEdit(Max_Drill_Diameter); + dlgCell(11, 2) dlgLabel("mm "); + dlgCell(11, 3) dlgPushButton("Max. Info") { + info = Showpic[7]; + Infotext = INFOmaxdrill; + } + dlgCell(12, 0) dlgLabel("Dist. Copper/Dim"); + dlgCell(12, 1) dlgLabel(sDistance_Copper_Dimension); + dlgCell(12, 3) dlgPushButton("Distance Info") { + info = Showpic[10]; + Infotext = DRCinfo; + } + dlgCell(13, 0) dlgLabel("Mill Board/D&im"); + dlgCell(13, 1) dlgRealEdit(DimensionMillTool, 0.0, 5); + dlgCell(13, 2) dlgLabel("mm "); + dlgCell(13, 3) dlgHBoxLayout { + dlgCheckBox("On&/Off", Dim_on_off) { + info = Showpic[16]; + if (Dim_on_off) { + if (Ref_cnto == 3) { + if (dlgMessageBox(InfoREFPack, YES, NO) != 0) { + MDimensionMillTool = DimensionMillTool; + DimensionMillTool = 0; // 2006-01-26 + Dim_on_off = 0; + Mdim_on_off = Dim_on_off; + MHolder_Spacing = Holder_Spacing; + Holder_Spacing = 0; + Infotext = DIMmiltoolOFF; + } + else { + // Dim_on_off = 1; + DimensionMillTool = MDimensionMillTool; + Mdim_on_off = Dim_on_off; + Holder_Spacing = MHolder_Spacing; + Infotext = DIMmiltoolON; + } + } + DimensionMillTool = MDimensionMillTool; + Mdim_on_off = Dim_on_off; + Holder_Spacing = MHolder_Spacing; + Infotext = DIMmiltoolON; + } + else { + MDimensionMillTool = DimensionMillTool; + DimensionMillTool = 0; // 2006-01-26 + Mdim_on_off = Dim_on_off; + MHolder_Spacing = Holder_Spacing; + Holder_Spacing = 0; + Infotext = DIMmiltoolOFF; + } + } + dlgCheckBox("mill. only Dim.", MillOnlyContour) { // 2011-03-10 + if (MillOnlyContour) { + info = Showpic[16]; + Infotext = "Nur Konturfräsen aus dem Träger.!
    " + + "Option Gen. drill wurde abgewählt!"; + Holder_Spacing = 0; + Generatedrills = 0; + Dim_on_off = 1; + } + else { + info = Showpic[0]; + Infotext = "Aktivieren Sie evtl. weitere benötigte Optionen!"; + } + } + } + + dlgCell(14, 0) dlgLabel("Holde&r spacing"); + dlgCell(14, 1) dlgRealEdit(Holder_Spacing, 0.0, 800); + dlgCell(14, 2) dlgLabel("mm"); + dlgCell(14, 3) dlgPushButton("Spacing Info") { + info = Showpic[15]; + Infotext = INFOspacing; + } + } // Gridlayout Ende + dlgStretch(0); + + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(400); // Breite des Infofenster (Bild) sonst sprintg des Menu + dlgLabel(info, 1); + dlgLabel(Infotext, 1); + dlgStretch(1); + dlgHBoxLayout { + if (Ref_cnto == 3) { // ist ein Ref-Package platziert? 2011-02-09 + dlgLabel(A_refpack); + /* *** a reference package is found *** + dlgGroup(A_refpack) { + dlgVBoxLayout { + dlgHBoxLayout { + dlgCheckBox(InfoRefHole, DrillRefOn) { + if (DrillRefOn) { + info = Showpic[39]; + Infotext = InfoRefOn; + DrillRefDiameter = MdrillRefDiameter; + DrillRefDeep = MdrillRefDeep; + } + else { + info = Showpic[17]; + Infotext = InfoRefOff; + MdrillRefDiameter = DrillRefDiameter; + MdrillRefDeep = DrillRefDeep; + } + } + dlgStretch(1); + dlgPushButton("Do it") dlgMessageBox("Not implemented yet", "OK"); // 2013-04-30 + } + dlgVBoxLayout { + dlgHBoxLayout { + dlgLabel(RefDrillDiameter); + dlgRealEdit(DrillRefDiameter); + dlgLabel(" mm "); + dlgStretch(1); + } + dlgHBoxLayout { + if (language() == "de") dlgSpacing(56); + else dlgSpacing(34); + dlgLabel(RefDrillDeep); + dlgRealEdit(DrillRefDeep); + dlgLabel(" mm "); + dlgStretch(1); + } + } + } + } */ + } + else { + dlgSpacing(60); + dlgPushButton(ZeroRef) { + info = Showpic[17]; + Infotext = InfoREFERENCE; + setZeroReference(); + } + } + dlgStretch(1); + } + // unterer Rand des Menu + } // Vbox ende + } // Hbox Ende + } // Tab 1 Ende + + dlgTabPage("Z axis") { + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(420); // die Tabhöhe vorgeben + dlgVBoxLayout { + dlgLabel(Machineparameter, 1); + dlgHBoxLayout { + dlgVBoxLayout { + dlgStretch(1); + dlgGroup("Resolution: Integer/Fractioal Digits") { // 2011-02-02 + dlgHBoxLayout { + dlgRadioButton("3 2 ", CNCmillResolution) { MCNCmillResolution = CNCmillResolution; zinfo = Showpic[38]; zInfotext = INFOresolution; } + dlgRadioButton("3 3 ", CNCmillResolution) { MCNCmillResolution = CNCmillResolution; zinfo = Showpic[38]; zInfotext = INFOresolution; } + dlgRadioButton("3 4 ", CNCmillResolution) { MCNCmillResolution = CNCmillResolution; zinfo = Showpic[38]; zInfotext = INFOresolution; } + dlgRadioButton("3.2 ", CNCmillResolution) { MCNCmillResolution = CNCmillResolution; zinfo = Showpic[38]; zInfotext = INFOresolution; } + dlgRadioButton("3.3 ", CNCmillResolution) { MCNCmillResolution = CNCmillResolution; zinfo = Showpic[38]; zInfotext = INFOresolution; } + dlgRadioButton("3.4 ", CNCmillResolution) { MCNCmillResolution = CNCmillResolution; zinfo = Showpic[38]; zInfotext = INFOresolution; } + } + } + } + dlgSpacing(60); // Abstand zum Bild + dlgVBoxLayout { + dlgStretch(1); + dlgLabel(zinfo, 1); + } + dlgVBoxLayout { + dlgStretch(1); + dlgLabel(zInfotext, 1); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgGroup("Machine parameter") { + dlgHBoxLayout { + + dlgStretch(1); + } + dlgGridLayout { + + dlgCell( 1, 0) dlgLabel("Z safety "); + dlgCell( 1, 1) dlgRealEdit(Mill_z_safety); + dlgCell( 1, 2) dlgLabel(" mm "); + dlgCell( 1, 3) dlgPushButton("Safety Info") { + zinfo = Showpic[25]; + zInfotext = INFOzsafety; + } + + dlgCell( 1, 4) dlgSpacing(8); + + dlgCell( 2, 0) dlgLabel("Z drill deep "); + dlgCell( 2, 1) dlgRealEdit(Drill_z_deep); + dlgCell( 2, 2) dlgLabel(" mm "); + dlgCell( 2, 3) dlgPushButton("Deep Info") { + zinfo = Showpic[26]; + zInfotext = INFOdeep; + } + + + dlgCell( 3, 0) dlgLabel("Z milling down "); + dlgCell( 3, 1) dlgRealEdit(Z_down); + dlgCell( 3, 2) dlgLabel(" mm "); + dlgCell( 3, 3) dlgPushButton("Z down Info") { + zinfo = Showpic[28]; + zInfotext = INFOzAxisDown; + } + + dlgCell( 4, 0) dlgLabel("Z Board Dim. "); + dlgCell( 4, 1) dlgRealEdit(Z_dimension); + dlgCell( 4, 2) dlgLabel(" mm "); + dlgCell( 4, 3) dlgPushButton("Z Dim. Info") { + zinfo = Showpic[34]; + zInfotext = DIMdown; + } + dlgCell( 5, 0) dlgLabel("


    "); + dlgCell( 5, 1) dlgLabel("
    "); + dlgCell( 5, 2) dlgLabel("
    "); + dlgCell( 5, 3) dlgLabel("
    "); + + dlgCell( 6, 0) dlgLabel("* Park pos. Z "); + dlgCell( 6, 1) dlgRealEdit(ParkZposition); + dlgCell( 6, 2) dlgLabel(" mm "); + dlgCell( 6, 3) dlgPushButton("Park Info") { + zinfo = Showpic[35]; + zInfotext = PARKinfo; + } + + dlgCell( 1, 9) dlgSpacing(8); + + dlgCell( 1, 5) dlgLabel("* Spindle "); + dlgCell( 1, 6) dlgIntEdit(Spindle_rpm); + dlgCell( 1, 7) dlgLabel(" rpm "); + dlgCell( 1, 8) dlgPushButton("RPM Info") { + zinfo = Showpic[31]; + zInfotext = INFOrpm; + } + + + dlgCell( 2, 5) dlgLabel("* Tool velocity "); + dlgCell( 2, 6) dlgRealEdit(Tool_vel); + dlgCell( 2, 7) dlgLabel(" mm/s "); + dlgCell( 2, 8) dlgPushButton("Velocity Info") { + zinfo = Showpic[29]; + zInfotext = INFOvelocity; + } + + dlgCell( 3, 5) dlgLabel("* Fast velocity "); + dlgCell( 3, 6) dlgRealEdit(Fast_vel); + dlgCell( 3, 7) dlgLabel(" mm/s "); + dlgCell( 3, 8) dlgPushButton("Fast Info") { + zinfo = Showpic[30]; + zInfotext = INFOfastVel; + } + + + dlgCell( 4, 5) dlgLabel("* Drill velocity "); + dlgCell( 4, 6) dlgRealEdit(Drill_Vel); + dlgCell( 4, 7) dlgLabel(" mm/s "); + dlgCell( 4, 8) dlgPushButton("V-Drill Info") { + zinfo = Showpic[32]; + zInfotext = INFOvdrill; + } + + dlgCell( 4, 9) dlgLabel(" * currently not used."); + + dlgCell( 6, 5) dlgLabel("* Park pos. X "); + dlgCell( 6, 6) dlgRealEdit(ParkXposition); + + + dlgCell( 6, 8) dlgLabel("* Park pos. Y "); + dlgCell( 6, 9) dlgRealEdit(ParkYposition); + + } + } + dlgStretch(1); + } + } + } + } // tab Ende + } // tab Widget Ende + dlgStretch(1); // 2013-02-19 + // the file Path/name + dlgHBoxLayout { + dlgGridLayout { + dlgCell( 0, 1) dlgSpacing(15); + dlgCell( 0, 2) dlgSpacing(500); + dlgCell( 1, 1) { dlgStretch(1); dlgLabel("Mill fil&e"); } + dlgCell( 1, 2) dlgStringEdit(Xfile); + dlgCell( 1, 3) dlgPushButton(DrBrowse) { + string fn = dlgFileSave(SAVE_file, Xfile); + if (fn) { + Xfile = fn; + MillFileName = fn; + info = Showpic[1]; + } + } + } + dlgStretch(1); + } + dlgHBoxLayout dlgSpacing(600); + dlgLabel("Design Rules:" + dru_file); + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("OK") { + //Z_up = Z_down * -1.0; // 2011-01-27 Up und Down muss immer der gleiche Wert sein! + if (!SelectedDevice) Error("No device selected!", "Please select a device.", NEXT, CANCEL); + else { + if (DimensionMillTool) { // **** if used ? **** + DistanceDimension = DimensionMillTool - Distance_Copper_Dimension*2; // 2009-02-05 + if (DistanceDimension < 0) { // 2009-02-05 correct wire width for millout + string d, d2; + sprintf(d, "%.8f", DistanceDimension/2); // 2009-02-05 + if (language() == "de") { // 2008-11-12 + sprintf(d2, "Achtung!
    Die Platine wird um %.8f mm ausserhalb der Dimension aus dem Träger gefäst!", + DistanceDimension/2); + } + else { + sprintf(d2, "Attention!\nThe millout is %.8f mm outher the dimension!", + DistanceDimension/2); + } + fault = dlgMessageBox(FaultDRCdist1 + d + FaultDRCdist2 + d2, ACCEPT, BACK); + DistanceDimension = 0; + } + } + if(!Onlydrill) { // + if (!MillToolOutl) { + fault = Error("Illegal diameter: 0", "The Isolate diameter must be greater than zero.", NEXT, CANCEL); + } + + if (!SelectedLayer1 && !SelectedLayer16) { + if (!MillOnlyContour) { // 2011-03-10 nur Kontur fräsen + fault = Error("No layer selected!", "Select layer 1 or 16 or both.", BREAK, CANCEL); + } + } + + if (Clearance_check) { + fault = Error(Error5, "" + Clearance_check + "", "Change &Tool #1", DRCCHECK); + if (fault) exit("CLASS"); + fault = 1; + } + } + if (Holder_Spacing && Holder_Spacing < DimensionMillTool*3) { // 2011-09-28 nur wenn der Fräsweg min. 3 mal länger als der Fräser im Durchmesser ist. + fault = Error("", "Holder spacing to smal.", "OK", BACK); + } + if (!fault) { + if (MillOnlyContour) dlgMessageBox("!Milling only Dimension selected.", "OK"); + MillFileName = Xfile; + if (test) output(filesetext(B.name, "-cmd.txt"), "at"); + Max_Drill_Diameter = round(Max_Drill_Diameter*10) / 10; + dlgAccept(); + } + } + } + dlgPushButton(CANCEL) { + dlgReject(); + exit(0); + } + dlgSpacing(32); + dlgPushButton(SavePar) save_defaults(); + dlgSpacing(32); + dlgPushButton(INFOinside) { + dlg_PlaceVia(); + } + dlgStretch(5); + dlgLabel(Version); + dlgStretch(1); + dlgPushButton(INFOhelpBut) dlgMessageBox(INFOhelp, "OK"); + } + }; + } + + Device = DeviceNames[SelectedDevice]; + if (SelectedLayer1) { + ToMillLayer1 = SelectedLayer1; + OutlineMillSignalLayer = SelectedLayer1; // set OutlineMillSignalLayer to last used layer + } + if (SelectedLayer16) { + ToMillLayer16 = SelectedLayer16; + OutlineMillSignalLayer = SelectedLayer16; + } + + fileerror(); + output(MillFileName, "wt"); // creat new file + Ftop = filenametop(MillFileName); + if (Ftop != MillFileName) output(Ftop, "wt"); // erzeuge zusätzliche Datei für Top bei HPGL 2013-04-30 + if (fileerror()) exit (-1); + + output(filesetext(B.name, "_display~tmp.scr"), "wtD") { + printf("DISPLAY NONE 17 18 20 "); + board(B) { + B.layers(L) { + if (L.visible) printf("%d ",L.number); + } + } + switch (SelectedDevice) { + case devScript: if (MillOnlyContour) { // 2011-03-10 + printf(" %d %d ", 1 + 102, 118); + } + else { + if (SelectedLayer1) printf(" %d %d %d", 1 + 100, 1 + 101, 1 + 102); // 2008-11-12 + if (SelectedLayer16) printf(" %d %d %d", 16 + 100, 16 + 101, 16 + 102); + if (SelectedPlusLayerTop) printf(" %d", SelectedPlusLayerTop + 100); + if (SelectedPlusLayerBot) printf(" %d", SelectedPlusLayerBot + 100); + printf(" 144 145 "); // 2013-02-19 die beiden Layer auch noch anzeigen + printf(";#5076 layer reset\n"); + } + break; + + case devHPGL: + output(filesetext(MillFileName,".pli"), "wt") { + printf("# Plot info generated by:\n# %s\n# %s\n# from %s\n# at %s\n# Drill tools\n", argv[0], Version, B.name, t2string(time()) ); + } + toolFiles(); // generate Rack and Wheel file + break; + + case devISEL: + output(filesetext(MillFileName,".isi"), "wt") { + printf("IMF_PBL_V1.0 - PICTURES BY PC - Eagle mill-outline.ulp\n"); + printf("; Plot info generated by %s %s\n# from %s\n# at %s\n# Used tools\n", argv[0], Version, B.name, t2string(time()) ); + } + toolFiles(); // generate Rack and Wheel file + break; + + case devCNC: + output(filesetext(MillFileName,".nci"), "wt") { + printf("#M48 Plot info generated by %s %s\n# from %s\n# at %s\n# Used tools\n", argv[0], Version, B.name, t2string(time()) ); + } + break; + } + } + if (MillOnlyContour) { // ***** 2011-03-10 ***** + string omillout; + string Cmd; + + sprintf(Cmd, "LAYER Milloutlines %d;\n", 1 + 102); + + DistanceDimension = DimensionMillTool - Distance_Copper_Dimension*2; + if (DistanceDimension < 0) { // 2009-02-05 correct wire width for millout + DistanceDimension = 0; + } + + real x1 = u2mm(B.area.x1) - DimensionMillTool/2, y1 = u2mm(B.area.y1) - MillToolFree/2, + x2 = u2mm(B.area.x2) + DimensionMillTool/2, y2 = u2mm(B.area.y2) + MillToolFree/2; + + + sprintf(omillout, "grID MM;\nDISPLAY NONE 17 %d;\n", ToMillLayer1 + ToMillLayer16); + Cmd += omillout; + // ** make temporary Net for Normal Polygon Orphen OFF + // ** to milling the pcb-contour with holder ** + sprintf(omillout, "chANGE laYER 1;\n"); /**** mit dieser Option immer von Top fräsen *****/ + Cmd += omillout; + Cmd += "SET WIRE_BEND 2;\n"; + sprintf(omillout, "VIA '%s' (%.8f %.8f);\n", + OutlineMillSignal, + x1 - DimensionMillTool/2, // plaziere Via innerhalb des Polygon + y1 - DimensionMillTool/2 // damit es kein Orphan wird. + ); + Cmd += omillout; + sprintf(omillout, "CHANGE ISOLATE 0;\n"); + Cmd += omillout; + sprintf(omillout, "CHANGE ORPHANS OFF;\n"); + Cmd += omillout; + Cmd += "SET WIRE_BEND 0;\n"; + Cmd += "CHANGE RANK 1;\n"; // 2006-07-26 + + + sprintf(omillout, "POLyGON '%s' %.8f (%.8f %.8f) (%.8f %.8f) (%.8f %.8f);\nRATSNEST;\n", + OutlineMillSignal, DistanceDimension, + x1 - DimensionMillTool - Distance_Copper_Dimension, + y1 - DimensionMillTool - Distance_Copper_Dimension, + x2 + DimensionMillTool + Distance_Copper_Dimension, + y2 + DimensionMillTool + Distance_Copper_Dimension, + x1 - DimensionMillTool - Distance_Copper_Dimension, + y1 - DimensionMillTool - Distance_Copper_Dimension); + Cmd += omillout; + Cmd += "SET WIRE_BEND 2;\n"; // 2011-09-28 + Cmd += RUN_pass(PassOutmill); + exit(Cmd); + } + generateTruePolygonOutlines(); // generate the true Dimension outline as polygon. + } +} + +// *** generate Copper pouring *** +void genInPassPour(int Layer) { + string fname = MillFileName; + if (Layer == 1) fname = filenametop(MillFileName); // 2013-04-30 + if(SelectedLayer16 && ToMillLayer16) { + if (Mirror_On) { + Mirror = -1.0; // *** mirror flag for Layer 16 *** 2005-06-21 + } + else { + MillMirr_Offset = 0; // ** reset mirror offset ** + Mirror = 1.0; + } + } + else if(SelectedLayer1 && ToMillLayer1) { + MillMirr_Offset = 0; // ** reset mirror offset ** + Mirror = 1.0; + } + output(fname, "at") { + if (test) printf(";#*** InPassPour\n"); + if (SelectedDevice == devScript) printf("\n# 2. isolate\n"); + if (InPassPour && MillToolFree == 0) return; // 2011-02-08 + printf("%s", WriteOutlines(ReservedOutlineSignalName, Layer )); + } + return; +} + +// *** generate outlines by polygon.contours.wires *** +void genPass2(int Layer) { + board(B) { + Actualmilldeep = Z_down; // 2011-01-27 milling Z Achse + real x1 = u2mm(B.area.x1) - MillToolFree/2 , y1 = u2mm(B.area.y1) - MillToolFree/2 ; + + string fname = MillFileName; + if(Layer == 1) { // wenn Top und HPGL dann in 2. Datei schreiben + fname = filenametop(MillFileName); + } + output(fname, "at") { + if (SelectedDevice == devScript) { + printf("\n#5200 InPass2 1. isolate Layer %d \n", Layer); // 2013-04-30 + } + DeviceInit(Contour, Layer); + printf("%s", WriteOutlines(ReservedOutlineSignalName, Layer )); // the isolated contour gecheckt 2001-01-31 + if (SelectedPlusLayerTop && Layer == 1) genPlusLayer(SelectedPlusLayerTop); + if (SelectedPlusLayerBot && Layer == 16) genPlusLayer(SelectedPlusLayerBot); + } + if (MillToolFree < 0) MillToolFree = 0.2; + real overlapfree = MillToolFree * OverlapRubOutPercent / 100; + real overlapoutl = MillToolOutl * OverlapOutlPercent / 100; + + string Cmd; + sprintf(Cmd, "CHANGe wIDTH %.8f %s;\nCHANGe iSOLATE %.8f %s;\n", + MillToolFree - overlapfree, polycoord1(TrueOutline_coordinate), // x1, y1, waren die falschen Koordinaten! + MillToolOutl + ( (overlapfree / 2 ) - overlapoutl), polycoord1(TrueOutline_coordinate) ); // 2012-03-09 benutze zum ändern der Breite eine Koordinate des Polygon selbst. + if (test2) if (dlgMessageBox("!5168 Anschliesend muß das Polygon die untenstehende Breite erhalten!\n" + Cmd, "OK", "CANCEL") != 0) exit(-5215); + + Cmd += "RATSNEST;\n" + RUN_pass(PassPour); + if (test) output(filesetext(B.name, "-cmd.txt"), "at") printf("%s", Cmd); + if (test) if (viewtest("5389 if (InPass2) Jetzt bekommt das Polygon die andere Breite!!! genPass2() " + PassPour +":", Cmd) != 0) exit(-5219); + exit(Cmd); + } +} + +/****************** +*** run passes **** +*******************/ +if (InPassDimensionPoly) { // ## first run calculate the real outline ## + if (test2) if (dlgMessageBox("#5228 1. Dimension ermitteln", "ok", "esc") != 0) exit(-5228); + // + // The actual outlines (Dimension) generator + // + board(B) { + Actualmilldeep = Z_dimension; + trueOutlineDraw(OutlineMillSignal); + string s; + string Cmd; + real x1 = u2mm(B.area.x1) - MillToolFree, y1 = u2mm(B.area.y1) - MillToolFree, + x2 = u2mm(B.area.x2) + MillToolFree, y2 = u2mm(B.area.y2) + MillToolFree; + DistanceDimension = (DimensionMillTool / 2 - Distance_Copper_Dimension); + if (DistanceDimension < 0) DistanceDimension = 0.001; + + // ** delete the temporary Polygon ** + // 2008-11-12 get actual coordinate + B.signals(S) { + if (S.name == OutlineMillSignal) { + int cntco = 0; + S.polygons(PL) { + int i = 1; + int active; + do { + active = 0; + PL.contours(W, i) { + active = 1; + // do something with the wire + cntco++; // 2010-01-20 Anzahl der Konturen ermitteln, + break; + } + i++; + } while (active); + i = -1; + + PL.wires(W) { + sprintf( s, "DELETE (S%.8f %.8f);\n", u2mm(W.x1), u2mm(W.y1) ); + Cmd += s; + break; + } + break; + } + S.vias(V) { // get absolut coordiante of via + // ** delete the temporary Via after board outline contour and inner contour** + cntcontvia++; + // 2015-03-24 do not ripup the via befor milling a exist inner contour + // sprintf( s, "RIPUP (%.8f %.8f);\n", u2mm(V.x), u2mm(V.y) ); + // if (dlgMessageBox(s, "nein", "ja") != 0) { + // Cmd += s; + // } + } + if (cntco > cntcontvia+1) { // 2011-10-04 wenn Anzahl der Kontouren+1 größer als vorhandene Vias, + // dann ist die Diemension nicht in Ordnung! + string i1, i2; + sprintf(i1, "%d Konturen im Polygon %s gefunden

    " + + "Überprüfen Sie die Dimension (Layer 20). " + + "Das Layout besteht aus mehreren Outlines. ", + cntco, S.name); + + sprintf(i2, "Beispiel:
    Auf der linken Seite im Bild ist ausserhalb der Platine ein Kreis im Layer 20. " + + "Verbinden Sie die zweite Kontur mit einer Linie im Layer 20, wie auf der rechten Seite zu sehen ist.

    " + + "


    " + + "Anschliessend an diese Meldung wird nur der Layer Dimension angezeigt!
    " + + "Schalten Sie entsprechende Layer wieder mit DISPLAY ein.

    "); + + dlgDialog("Contour error") { // 2010-01-20 + dlgLabel(i1); + dlgLabel(""); + dlgLabel(i2); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("OK") dlgAccept(); + dlgStretch(1); + } + }; + exit (Cmd+"DISPLAY NONE 20;\nWIN FIT;LAYER 20 "); // 2010-01-20 Polygon und Via löschen, und nur Layer Dimension anzeigen. + } + } + } + Cmd += "SET WIRE_BEND 2;\n"; + sprintf(s, "CHANGE ISOLATE %.8f;\n", MillToolIsolate); // 2006-07-26 + Cmd += s; + sprintf(s, "CHANGE RANK 6;\n"); // 2006-07-26 + Cmd += s; + if (SelectedLayer16) { + sprintf(s, "CHANGE LAYER 16;\n"); // first milling bottom layer + Cmd += s; + } + else if (SelectedLayer1) { + sprintf(s, "CHANGE LAYER 1;\n"); + Cmd += s; + } + sprintf(s, "POLYGOn '%s' %.8f %s;\nRATSNEST;\n", + ReservedOutlineSignalName, MillToolOutl, TrueOutline_coordinate); + Cmd += s; + Cmd += RUN_pass(Pass2); + + if (test) if (viewtest("if (InPassDimensionPoly) 2008-11-12 *****************:", Cmd) != 0) exit(-5324); + if (test) output(filesetext(B.name, "-cmd.txt"), "at") printf("%s", Cmd); + exit(Cmd); + } +} + + + +// ****************** the passes **************************** +// *** milling the isolation #1 *** +if (InPass2) { // second run, first isolate + if (test2) if (dlgMessageBox("#5335 2. Erste Isolation fräsen Pass2\nPolygonstart: " + TrueOutline_coordinate, "ok", "esc") != 0) exit(-5335); + Actualmilldeep = Z_down; // 2011-01-27 milling Z Achse + /*** after InPass2 must/can Copper pouring ***/ + if(SelectedLayer16 && ToMillLayer16) { + if (Mirror_On) { + Mirror = -1.0; + } + else { + MillMirr_Offset = 0; // ** reset mirror offset ** + Mirror = 1.0; + } + OutlineMillSignalLayer = SelectedLayer16; + genPass2(16); // 2008-11-12 nicht das Flag übergeben, sondern den Layer + } + else if(SelectedLayer1 && ToMillLayer1) { + MillMirr_Offset = 0; // ** reset mirror offset ** + Mirror = 1.0; + OutlineMillSignalLayer = SelectedLayer1; + genPass2(1); // 2008-11-12 nicht das Flag übergeben, sondern den Layer + } +} + + +// *** Copper pouring *** +if (InPassPour) { // third run, wide isolate und copper pouring + if (test2) if (dlgMessageBox("#5360 3. zweites mal Isolation fräsen mit breiteren Fräser und ausräumen!", "ok", "esc") != 0) exit(-5360); + string Cmd; + string millout; + string s; + string coordoutline; + Actualmilldeep = Z_down; // 2011-01-27 milling Z Achse + board(B) { + real x1 = u2mm(B.area.x1) - MillToolFree/2, y1 = u2mm(B.area.y1) - MillToolFree/2; + real x2 = u2mm(B.area.x2) + MillToolFree/2, y2 = u2mm(B.area.y2) + MillToolFree/2; + // 2008-11-12 Polygon-Layer ermitteln + B.signals(S) { + if (S.name == ReservedOutlineSignalName) { + S.polygons(P) { + sprintf(s, "DISPLAY %d;\n", P.layer); // 2008-11-12 ermittle den aktuellen Polygon Layer + Cmd += s; + P.wires(W) { + sprintf(coordoutline, "(%.8f %.8f)", u2mm(W.x1), u2mm(W.y1) ); + break; + } + break; + } + break; + } + } + + if(ToMillLayer16 && ToMillLayer1) { + // *** if double layer, first generate Layer 16 (mirrored) *** + genInPassPour(16); // 2008-11-12 use layer not flag + ToMillLayer16 = 0; + output(MillFileName, "at") { // *** the first run is finished *** + // *** ReInit with mirror PCB on machine *** + // *** 2005-05-24 + DeviceReInit(MirrorPCB, ToMillLayer16, "5338"); // *** message to personal must mirror the milling PCB on machine *** + } + sprintf(s, "CHANGE ISOLATE 0 %s;\nCHANGE LAYER 1 %s;\nCHANGE WIDTH %.8f %s;\nRATSNEST;\n", + coordoutline, + coordoutline, + MillToolOutl, coordoutline); + if (test2) if (dlgMessageBox("#5398 Breiter Fräser:\n" + s, "ok", "esc") != 0) exit(-5398); + Cmd += s; + Cmd += RUN_pass(Pass2); + exit(Cmd); + } + else if(ToMillLayer16 || ToMillLayer1) { + if(ToMillLayer16) genInPassPour(16); // 2008-11-12 + else if (ToMillLayer1) { + MillMirr_Offset = 0; // ** OK reset mirror offset ** 2005-05-23 + genInPassPour(1); + } + B.signals(S) { + if (S.name == ReservedOutlineSignalName) { + S.polygons(P) { + P.wires(W) { + sprintf(DelPoly, "DELETE (S %.8f %.8f);\n", u2mm(W.x1), u2mm(W.y1) ); // 2009-03-31 gesamtes Polygon löschen + Cmd += DelPoly; + break; + } + break; + } + break; + } + } + sprintf(millout, "DISPLAY NONE 17 %d;\n", ToMillLayer1 + ToMillLayer16); + Cmd += millout; + + // ** make temporary Net for Normal Polygon Orphen OFF + // ** to milling the pcb-contour with holder ** + string millout; + + // 2009-03-31 set correct layer for milling out + if (SelectedLayer16 && ToMillLayer16) OutlineMillSignalLayer = 16; // 2009-03-31 + sprintf(millout, "cHANGE lAYER %d;\n", OutlineMillSignalLayer); + Cmd += millout; + sprintf(millout, "VIA '%s' (%.8f %.8f);\n", + OutlineMillSignal, + x1 + .1, // plaziere Via innerhalb des Polygon 2006-05-17 + y1 + .1 // damit es kein Orphan wird. + ); + Cmd += millout; + sprintf(millout, "CHANGE ISOLATE 0;\n"); + Cmd += millout; + sprintf(millout, "CHANGE ORPHANS OFF;\n"); + Cmd += millout; + Cmd += "SET WIRE_BEND 0;\n"; + Cmd += "CHANGE RANK 1;\n"; // 2006-07-26 + + DistanceDimension = DimensionMillTool - Distance_Copper_Dimension*2; + if (DistanceDimension < 0) { // 2009-02-05 correct wire width for millout + DistanceDimension = 0; + } + } + sprintf(millout, "POLyGON '%s' %.8f (%.8f %.8f) (%.8f %.8f) (%.8f %.8f);\nRATSNEST;\n", + OutlineMillSignal, DistanceDimension, + x1 - DimensionMillTool - Distance_Copper_Dimension, + y1 - DimensionMillTool - Distance_Copper_Dimension, + x2 + DimensionMillTool + Distance_Copper_Dimension, + y2 + DimensionMillTool + Distance_Copper_Dimension, + x1 - DimensionMillTool - Distance_Copper_Dimension, + y1 - DimensionMillTool - Distance_Copper_Dimension); + Cmd += millout; + Cmd += "SET WIRE_BEND 2;\n"; // 2011-09-28 + Cmd += RUN_pass(PassOutmill); + if (test) output(filesetext(B.name, "-cmd.txt"), "at") printf("%s", Cmd); + if (test) if (viewtest("if (InPassPour) >> " + PassOutmill + ": jetzt kommt aus dem Träger ausfräsen:", Cmd) != 0) exit(-5463); + exit(Cmd); + } +} + + +// *** drill holes (milling bigger holes) and milling out from holder *** +if (InPassOutmill) { // ## fourth run, drill holes, milling big holes and milling out from raw matarial by dimension + if (test2) if (dlgMessageBox("#5471 4. Aus dem Träger fräsen!", "ok", "esc") != 0) exit(-5471); + Actualmilldeep = Drill_z_deep; // 2011-01-27 + string fname = MillFileName; + + if (SelectedLayer16 && ToMillLayer16) OutlineMillSignalLayer = 16; // 2009-03-31 + if (OutlineMillSignalLayer == 16) { + if (Mirror_On) { + Mirror = -1.0; // *** mirror flag for Layer 16 *** + } + else { + MillMirr_Offset = 0; // ** reset mirror offset ** + Mirror = 1.0; + } + } + else if(OutlineMillSignalLayer == 1) { + fname = filenametop(MillFileName); + MillMirr_Offset = 0; // ** reset mirror offset ** + Mirror = 1.0; + } // ** OK ** 2005-06-23 + + board(B) { + Actualmilldeep = Drill_z_deep; // 2011-01-27 + get_rack(B); + set_tool_rack(); // ** set tool rack again for Holes drilling + string Cmd; + output(fname, "at") { + + if (test2) if (dlgMessageBox("#5498 Aus dem Träger fräsen!\n" + MillFileName, "ok", "esc") != 0) exit(-5498); + // *** now milling PCB from holder outside Dimension Line *** 2006-11-07 + if (SelectedDevice == devScript) printf("\n# milling dimension #5500\n"); + if (Dim_on_off) { // soll überhaupt die Dimension gefräst werden? 2011-02-09 + if (MillOnlyContour) OutlineMillSignalLayer = 1; /**** 2011-03-10 wenn nur Konturfräsen, dann immer Layer 1 ****/ + printf("%s", WriteOutlines( OutlineMillSignal, OutlineMillSignalLayer )) ; // milling outline(Dimension) 2009-03-31 + } + // *** last but not least the HOLE(s) *** + switch (SelectedDevice) { + case devScript: /**** 2008-12-05 new file == "wt" ****/ + printf("#5508 WriteHoles() in the same script\n"); // 2013-02-19 + // WriteHoles(OutlineMillSignalLayer); ist schon erledigt + printf("SET UNDO_LOG ON;\n"); + printf("WIN FIT;\n"); + break; + + case devHPGL: + break; + + case devISEL: + if (Generatedrills) { printf("#5518\n"); WriteHoles(OutlineMillSignalLayer); } + break; + + case devCNC: + if (Generatedrills) { printf("#5522\n"); WriteHoles(OutlineMillSignalLayer); } + break; + + default: + dlgMessageBox("undefined Device!\nULP aborted.", "OK"); exit(0); + break; + } + DeviceEnd(); + + real x1 = u2mm(B.area.x1) - DimensionMillTool/2, y1 = u2mm(B.area.y1) - MillToolFree/2, + x2 = u2mm(B.area.x2) + DimensionMillTool/2, y2 = u2mm(B.area.y2) + MillToolFree/2; + + // delete temporary Polygon and VIA + B.signals(S) { // 2008-11-12 get absolute coordinate of reseved polygon + if (S.name == OutlineMillSignal) { + int cntcontp = 0; + int cntcontn = 0; + int cntvia = 0; + S.vias(V) { + cntvia++; + } + string del_pol; + S.polygons(POL) { + POL.wires(W) { + sprintf(del_pol, "Grid MM;\nDELETE (S %.8f %.8f);", u2mm(W.x1), u2mm(W.y1) ); + Cmd += del_pol; + break; + } + break; + } + S.vias(V) { // 2008-11-12 get actual coordiante of via + // ** delete the temporary Via ** + sprintf( del_pol, "RIPUP (%.8f %.8f);\nRATSNEST;\n", u2mm(V.x), u2mm(V.y) ); // 2009-02-04 clear via airwire + Cmd += del_pol; + } + int activ; + S.polygons(POL) { // 2011-03-10 check Elemente ausserhalb der Dimension + do { + activ = 0; + POL.contours(W, cntcontp+1) { + cntcontp++; + activ = 1; + break; + } + POL.contours(W, cntcontn-1) { + cntcontn--; + activ = 1; + break; + } + } while (activ); + } + cntcontn *= -1; + if (cntcontp == cntvia && cntcontn == 1) { // 2011-10-04 + ; // alles in bester Ordnung + } + else { + if (MillToolFree) { // 2013-03-05 nur wenn Tool#2 blow-up benutzt + string polerror; + string polerrorimg = ""; + sprintf(polerror, "ERROR: %d VIA, %d positive und %d negative Konturen im Polygon %s

    " + + "Überprüfen Sie, ob außerhalb der Boardkontur, Texte, Logos oder sonstige Elemente im Top oder Bottom Layer " + + "platziert sind und entweder entfernen Sie diese Elemente oder wechseln sie in einen nicht Kupferlayer.
    " + + "Entfernen Sie mit DELETE/RIPUP alle Elemente außerhalb der Dimension, bzw. verbinden
    " + + "Sie evtl. mehrfach vorhandene Dimensionen (Konturen) miteinander.
    Beispiel:", + cntvia, cntcontp, cntcontn, OutlineMillSignal + ); + dlgDialog("Polygon Error") { + dlgLabel(polerror); + dlgLabel(polerrorimg); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("OK") dlgAccept(); + dlgStretch(1); + } + }; + } + Cmd += "SCRIPT '" + filesetext(B.name, "_display~tmp.scr") + "';\n"; + string g; + sprintf(g, "GRID %s %.f;\nWIN FIT;", Gridunit[GridUnitdist], GridDistance); + Cmd+=g; + } + } + } + if (SelectedDevice == devScript) { + printf("\n#5607 *** InPassOutmill\n"); + printf("# milling dimension\n"); + } + } + + // SelectedLayer1 beim letzten PASS2 muß 1 ToMillLayerX noch übrig bleiben !!! + // SelectedLayer16 überprüfen ob noch ein Layer aktiv ist, der letzte !! 2006-10-05 + + switch (SelectedDevice) { + case devScript: if (MillOnlyContour) { // 2011-03-10 + Cmd += "SCRIPT '" + MillFileName + "';\n"; // execute script + Cmd += "SCRIPT '" + filesetext(B.name, "_display~tmp.scr") + "';\n"; + } + + else { + Cmd += "SCRIPT '" + MillFileName + "';\n"; // execute script + Cmd += "SCRIPT '" + filesetext(B.name, "_display~tmp.scr") + "';\n"; + string s; + if (ToMillLayer1) { + sprintf(s, "DISPLAY %d;\n", SelectedLayer1 + 101); // 2006-07-26 + Cmd += s; + sprintf(s, "DISPLAY %d;\n", SelectedLayer1 + 102); + Cmd += s; + } + if (ToMillLayer16) { + sprintf(s, "DISPLAY %d;\n", SelectedLayer16 + 101); // 2012-01-13 + Cmd += s; + sprintf(s, "DISPLAY %d;\n", SelectedLayer16 + 102); // 2012-01-13 + Cmd += s; + } + } + break; + + case devHPGL: + Cmd += "script '" + filesetext(B.name, "_display~tmp.scr") + "';\n"; + break; + + case devISEL: + Cmd += "script '" + filesetext(B.name, "_display~tmp.scr") + "';\n"; + break; + + case devCNC: + Cmd += "script '" + filesetext(B.name, "_display~tmp.scr") + "';\n"; + break; + + } + string g; + if (test) output(filesetext(B.name, "-cmd.txt"), "at") printf("%s", Cmd); + sprintf(g, "GRID %s %.f;\nWIN FIT;\n", Gridunit[GridUnitdist], GridDistance); + Cmd += g + "SET OPTIMIZING ON;\n"; + if (!test) Cmd += "SET UNDO_LOG ON;\n"; + + switch (SelectedDevice) { + case devScript: + break; + + case devHPGL: + if (test) showHPGLinfo(); + break; + + case devISEL: + if (test) showISELinfo(); + break; + + case devCNC: + if (test) showCNCinfo(); + break; + } + if (test) if (viewtest("if (InPassOutmill) :", Cmd) != 0) exit(-5675); + sprintf(g, "GRID %s %.f;\nWIN FIT;\n", Gridunit[GridUnitdist], GridDistance); + Cmd+=g; + if (SelectedDevice == devHPGL) { + sprintf(g, "RUN ulpmessage 'Erzeugte Dateien:
    %s
    %s'", MillFileName, filenametop(MillFileName)); // 2014-10-06 + } + else { + sprintf(g, "RUN ulpmessage 'Erzeugte Datei
    %s'", MillFileName); // 2014-10-06 + } + Cmd+=g; + exit(Cmd); + } +} + diff --git a/trunk/ulp/mirror-board-remirror-element-swap-layer.ulp b/trunk/ulp/mirror-board-remirror-element-swap-layer.ulp new file mode 100644 index 00000000..41e96fae --- /dev/null +++ b/trunk/ulp/mirror-board-remirror-element-swap-layer.ulp @@ -0,0 +1,432 @@ +#usage "de:Spiegelt das gesamte Board, spiegelt dann die Bauteile an ihrem Origin zurück und zeichnet die Leiterbahnen " + "(Top/Bottom) gespiegelt ohne die Layer zu tauschen.
    " + "Um zum Beispiel aus dem Layout für einem linken Scheinwerfer das Layout für einen rechten Scheinwerfer zu erzeugen.

    " + "Bei symmetrischen zweipoligen Bauteilen in senkrechter Ausrichtung reicht es die Bauteile einfach zurück zu spiegeln, " + "symmetrische zweipolige Bauteile in waagerechter Ausrichtung müssen zusätzlich um 180 gedreht werden " + "um die Position der PADs mit den Leiterbahnen wieder in Einklang zu bringen.

    " + "Achtung: Asymmetrische und mehrreihige Bauteile wie SOT23 SO14 ... können nicht ohne weiteres gespiegelt und " + "die Anbindung der Leiterbahnen an den PADs behalten werden. " + "Hier muß der Layouter die gerouteten Wire (Leiterbahnen) teilweise aufripen und neu verlegen.
    " + "Um die Anschlüsse zu überprüfen wird der DRC gestartet und die die Fehlerliste angezeigt. Jeder Overlap bedeutet " + "eine falsch angeschlossene Leiterbahn die entsprechend behandelt werden muß.
    " + "Je nach Symmetrie des Bauteiles muß entweder das Bauteil verschoben/gedreht und/oder die Wire neu verlegt werden " + "(RIPUP und ROUTE).

    " + "Interessant ist schon die Definition beim Anlegen in der Bibliothek, so wie beim platzieren der Bauteile " + "im Board ob man den entsprechenden Platz für die gespiegelte Version freihalten kann. " + "Das erspart einiges an Nacharbeit.
    " + "Unter Umständen mach es Sinn das Bauteil symmetrisch in Bezug auf die PADs und asymmetrisch zu den Packagekonturen " + "anzulegen, damit dann der Origin zwischen den Pads liegt und man das Bauteil nur noch drehen mus.

    " + "Die Meldung ! Alle Signale umwandeln? muß mit Ja beanbtwortet werden, damit die Leiterbahnen aufgeript " + "werden können." + "

    " + "Author: alf@cadsoft.de" + , + "en: Mirrors the whole board, flips the components back to their original positions and draws the " + "mirrored traces in top and bottom without changing the original layer.

    " + "For example, for creating the layout for a headlamp on the left out of the layout of a headlamp on the right side. " + "In case you are using symmetrical two-pole components in a vertical orientation it suffices to mirror the components, " + "if they are in a horizontal orientation you additionally have to rotate them by 180 degrees in order to conciliate " + "the position of the pads and the traces.
    " + "Note: Asymmetric and multi-row components like SOT23, SO14.... can't be mirrored without mixing up the connections " + "between pads and traces. In this case you have to ripup the traces and layout them correctly afterwards.
    " + "For checking the connections, run the DRC and look into the errors list. Each overlap error shows a mis-connected " + "trace you have to take care on.
    " + "Depending on the symmetry of the component you have to move/rotate it and/or re-route the traces (RIPUP and ROUTE).

    " + "Think of this already when creating the library element and placing the component in the layout, and try to " + "reserve some space for the mirrored component. This can save a lot of effort.
    " + "I can be senseful to create the component symmetric in terms of the pads and asymmetric in terms of the package " + "contours so that the origin is located between the pads and you finally only have to rotate the component.

    " + "The message Ripup all signals? has to be answered with Yes in order to ripup all signals." + "

    " + "Author: alf@cadsoft.de" + +#require 5.1100 + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string Version = "1.0.0"; // 2011-05-25 + +int test = 0; + +string Sname = ""; +string CheckPos = ""; +int CntCheckPos = 0; +int CntSymPos = 0; +int CntSymPos180 = 0; + +string cmd, s; +int lVisible[]; +int useLayer[]; +int lcolor[]; +int lfill[]; +string lNames[] = { " " }; + +string lockName[]; +int cntlock = 0; + +int maxX = INT_MIN; +int minX = INT_MAX; +int maxY = INT_MIN; +int minY = INT_MAX; +int bminx, bmaxx, bminy, bmaxy; + + +string vShape[]; + vShape[VIA_SHAPE_SQUARE] = "square"; + vShape[VIA_SHAPE_ROUND] = "round"; + vShape[VIA_SHAPE_OCTAGON] = "octagon"; + vShape[VIA_SHAPE_ANNULUS] = "annulus"; + vShape[VIA_SHAPE_THERMAL] = "thermal"; + + + +/**** functions ****/ +void checkmaxmin(int x1, int x2, int y1, int y2) { + if (x1 > maxX) maxX = x1; + if (x2 > maxX) maxX = x2; + if (y1 > maxY) maxY = y1; + if (y2 > maxY) maxY = y2; + if (x1 < minX) minX = x1; + if (x2 < minX) minX = x2; + if (y1 < minY) minY = y1; + if (y2 < minY) minY = y2; + return; +} + + +void checkarc( int x1, int x2, int y1, int y2, int xc, int yc, real angle1, real angle2, real radius) { + checkmaxmin( x1, x2, y1, y2 ); + if ( angle2 > angle1 + 270.0) { + if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, yc - radius ); + else if( angle1 < 180 ) checkmaxmin( xc - radius, xc + radius, y1 , yc - radius ); + else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, yc + radius ); + else if( angle1 < 360 ) checkmaxmin( xc + radius, xc - radius, y1 , yc + radius ); + } + else if( angle2 > angle1 + 180.0) { + if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, y2 ); + else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, yc - radius, y2 ); + else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, y2 ); + else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, yc + radius, y2 ); + } + else if( angle2 > angle1 + 90.0 ) { + if ( angle1 < 90 ) checkmaxmin( x1 , x2 , yc + radius, y2 ); + else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, y1 , y2 ); + else if( angle1 < 270 ) checkmaxmin( x1 , x2 , yc - radius, y2 ); + else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, y1 , y2 ); + } + return; +} + + +void lock_elements(void) { + for (int lc = 0; lc < cntlock; lc++) { + cmd += "LOCK " + lockName[lc] + ";\n"; + } + return; +} + + +void setcolor(void) { + string s; + sprintf(s, "SET COLOR_LAYER 1 %d;\n", lcolor[16]); // shwap layer color and fill + cmd += s; + sprintf(s, "SET FILL_LAYER 1 %d;\n", lfill[16]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 16 %d;\n", lcolor[1]); + cmd += s; + sprintf(s, "SET FILL_LAYER 16 %d;\n", lfill[1]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 21 %d;\n", lcolor[22]); + cmd += s; + sprintf(s, "SET FILL_LAYER 21 %d;\n", lfill[22]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 22 %d;\n", lcolor[21]); + cmd += s; + sprintf(s, "SET FILL_LAYER 22 %d;\n", lfill[21]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 23 %d;\n", lcolor[24]); + cmd += s; + sprintf(s, "SET FILL_LAYER 23 %d;\n", lfill[24]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 24 %d;\n", lcolor[23]); + cmd += s; + sprintf(s, "SET FILL_LAYER 24 %d;\n", lfill[23]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 25 %d;\n", lcolor[26]); + cmd += s; + sprintf(s, "SET FILL_LAYER 25 %d;\n", lfill[26]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 26 %d;\n", lcolor[25]); + cmd += s; + sprintf(s, "SET FILL_LAYER 26 %d;\n", lfill[25]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 27 %d;\n", lcolor[28]); + cmd += s; + sprintf(s, "SET FILL_LAYER 27 %d;\n", lfill[28]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 28 %d;\n", lcolor[27]); + cmd += s; + sprintf(s, "SET FILL_LAYER 28 %d;\n", lfill[27]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 29 %d;\n", lcolor[30]); + cmd += s; + sprintf(s, "SET FILL_LAYER 29 %d;\n", lfill[30]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 30 %d;\n", lcolor[29]); + cmd += s; + sprintf(s, "SET FILL_LAYER 30 %d;\n", lfill[29]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 31 %d;\n", lcolor[32]); + cmd += s; + sprintf(s, "SET FILL_LAYER 31 %d;\n", lfill[32]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 32 %d;\n", lcolor[31]); + cmd += s; + sprintf(s, "SET FILL_LAYER 32 %d;\n", lfill[31]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 51 %d;\n", lcolor[52]); + cmd += s; + sprintf(s, "SET FILL_LAYER 51 %d;\n", lfill[52]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 52 %d;\n", lcolor[51]); + cmd += s; + sprintf(s, "SET FILL_LAYER 52 %d;\n", lfill[51]); + cmd += s; + return; +} + + +int checkVia(UL_VIA V) { + if (V.start != 1 || V.end != 16) return 1; + return 0; +} + + +// main +if (board) { + board(B) { + if (argc < 2) { + int verror = 0; + B.signals(S) S.vias(V) verror += checkVia(V); + if (verror) { + dlgMessageBox("!Do not use this ULP if used blind or micro via(s)!", "OK"); + exit(-1); + } + bminx = B.area.x1; + bmaxx = B.area.x2; + bminy = B.area.y1; + bmaxy = B.area.y2; + B.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + lcolor[L.number] = L.color; + lfill[L.number] = L.fill; + } + B.wires(W) { + if (W.layer == 20) { + if (W.arc) { + checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius); + } + else { + checkmaxmin( W.x1, W.x2, W.y1, W.y2 ); + } + } + } + B.circles(C) { + if (C.layer == 20) { + checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius ); + } + } + B.elements(E) { + E.package.wires(W) { + if (W.layer == 20) { + // *** Dimension in Packages *** + if (W.arc) { + checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius); + } + else { + checkmaxmin( W.x1, W.x2, W.y1, W.y2 ); + } + } + } + E.package.circles(C) { + if (C.layer == 20) { + checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius ); + } + } + } + real mirrorline = (u2mm(maxX) + u2mm(minX)) / 2; + + sprintf(s, "DISPLAY ALL;\n"); + cmd += s; + sprintf(s, "GROUP ALL;\n"); + cmd += s; + cmd += "LOCK (>S 0 0);\n"; // unlock all + sprintf(s, "GRID MM FINEST;\nMIRROR (>%.4fmm %.4fmm);\nGRID LAST;\n", mirrorline, u2mm(minY) ); + cmd += s; + cmd += "SET CONFIRM YES;\n"; // die folgende Abfrage mit Ja beantworten. + cmd += "RIPUP;\n"; // alles aufripen bevor die Wire neu gezeichnet werden. + cmd += "SET CONFIRM OFF;\n"; + + B.elements(E) { + //checkMirrorRotate(E); + int ccnt = 0; + int east = 0, south = 0, west = 0, north = 0, un_defined = 0; // Ost- Süd- West- Nord-Ausrichtung der Pads + E.package.contacts(C) { + ccnt++; + if (C.x == E.x && C.y < E.y) south++; // ist im Westen + else if (C.x == E.x && C.y > E.y) north++; // ist im Osten + else if (C.y == E.y && C.x < E.x) west++; // ist im Süden + else if (C.y == E.y && C.x > E.x) east++; // ist im Norden + else un_defined++; // undefiniert + } + if (un_defined) { + // nur spiegeln, der Anwender muß sich das ansehen + sprintf(s, "MIRROR %s; # un_defined \n", E.name); + cmd += s; + CntCheckPos++; + } + else if (east || west) { + // spiegen und 180 drehen X-Achse + sprintf(s, "MIrror %s; # east || west\nROTATE R180 %s; # east || west\n", E.name, E.name); + cmd += s; + sprintf(s, "%s\n", E.name); + CheckPos += s; + CntSymPos180++; + } + else if (north || south) { + // nur spiegeln Y-Achse + sprintf(s, "MIRROR %s; # north || south \n", E.name); + cmd += s; + CntSymPos ++; + } + else { + if (ccnt) { + sprintf(s, "MIRROR %s; # any \n", E.name); + cmd += s; + CntCheckPos++; + } + // ccnt = 0 - Packages ohne Pads nicht zurückspiegeln, kann Dimesion-Package oder sonstiges sein. + } + } + + B.signals(S) { + S.wires(W) { + if (W.layer != 19) { + if (W.layer == 1) cmd += "CHANGE LAYER 1;\n"; + else if (W.layer == 16) cmd += "CHANGE LAYER 16;\n"; + + else { + if (dlgMessageBox("!Es werden nur Layer 1 und 16 unterstützt.", "OK", "CANCEL") != 0) exit(-99); + } + + sprintf(s, "WIRE '%s' %.4fmm (%.4fmm %.4fmm ) %+.3f (%.4fmm %.4fmm );\n", + S.name, u2mm(W.width), + u2mm(W.x1) * -1.0 + mirrorline*2, u2mm(W.y1), + W.curve, + u2mm(W.x2) * -1.0 + mirrorline*2 , u2mm(W.y2) + ); + cmd += s; + } + } + S.vias(V) { + string vFlag = ""; + if (V.flags) vFlag = "STOP"; + sprintf(s, "CHANGE DRILL %.4fmm;\n", u2mm(V.drill)); + sprintf(s, "VIA '%s' %.4fmm %s %d-%d %s (%.4fmm %.4fmm);\n", + S.name, + u2mm(V.diameter[16]), + vShape[V.shape[16]], + V.start, V.end, + vFlag, + u2mm(V.x) * -1.0 + mirrorline*2, u2mm(V.y) + ); + cmd += s; + } + S.polygons(P) { // swap polygon to origin layer + P.wires(W) { + sprintf(s, "CHANGE LAYER %d (%.4fmm %.4fmm);\n", W.layer, u2mm(W.x1) * -1.0 + mirrorline*2, u2mm(W.y1)); + cmd += s; + break; + } + } + } + cmd += ";\n"; + B.elements(E) if (E.locked) cmd += "LOCK " + E.name + ";\n"; // 2009-12-01 + + cmd += "DISPLAY NONE "; + for(int l = 1; l < 256; l++) { + if (lNames[l]) { // Layer defined + if (lVisible[l]) { + if (l == 1 || l == 16 || l == 21 || l == 22 || l == 23 || l == 24 || l == 25 || l == 26 || l == 27 || l == 28 || l == 29 || l == 30 || l == 31 || l == 32 || l == 51 || l == 52 ) { + if (l == 1) sprintf(s, " %d", 16); // 2009-12-01 shwap visible layers + else if (l == 16) sprintf(s, " %d", 1); + else if (l == 21) sprintf(s, " %d", 22); + else if (l == 22) sprintf(s, " %d", 21); + else if (l == 23) sprintf(s, " %d", 24); + else if (l == 24) sprintf(s, " %d", 23); + else if (l == 25) sprintf(s, " %d", 26); + else if (l == 26) sprintf(s, " %d", 25); + else if (l == 27) sprintf(s, " %d", 28); + else if (l == 28) sprintf(s, " %d", 27); + else if (l == 29) sprintf(s, " %d", 30); + else if (l == 30) sprintf(s, " %d", 29); + else if (l == 31) sprintf(s, " %d", 32); + else if (l == 32) sprintf(s, " %d", 31); + else if (l == 51) sprintf(s, " %d", 52); + else if (l == 52) sprintf(s, " %d", 51); + } + else sprintf(s, " %d", l); + cmd += s; + } + } + } + cmd += ";\n"; + } + Sname = filesetext(B.name, "~mirror~script~.scr"); + string saveas = dlgFileSave("Save as", B.name, "*.brd"); + if (saveas) { + sprintf(s, "WRITE '@%s';\n", saveas); // 2011-05-25 save as + cmd += s; + } + else { + cmd += "RUN ulpmessage 'Do not forgot to save the board by a new name.

    Vergessen Sie nicht die Datei unter einem anderen Namen zu speichern.';\n"; + } + cmd += "DRC ; \n ERRORS "; + output(Sname, "wtD") printf("%s", cmd); + } +} + +if (CheckPos) { + sprintf(s, "%d Elements mirrord / Bauteile bespiegelt.\n%d Elements mirrord an 180 degree rotated / Bauteile gespiegelt und 180 gedreht.\n\n%d Elements to check, see list / Bauteile zum überpüfen nach Liste.\n", + CntSymPos, CntSymPos180, CntCheckPos + ); + dlgDialog("Check routig of elements") { + dlgHBoxLayout dlgSpacing(800); + dlgLabel(usage); + dlgSpacing(12); + dlgLabel(s); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(300); + dlgTextView(CheckPos); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); exit(-1); } + dlgStretch(1); + } + }; +} +if (test) { + dlgDialog("Test") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("ok") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-2); } + } + }; +} + +exit("SCRIPT '" + Sname + "'"); \ No newline at end of file diff --git a/trunk/ulp/mirror-board.ulp b/trunk/ulp/mirror-board.ulp new file mode 100644 index 00000000..69b44ee2 --- /dev/null +++ b/trunk/ulp/mirror-board.ulp @@ -0,0 +1,280 @@ +#usage "Mirror board (with all Layers)

    " + "Author: support@cadsoft.de" + +#require 5.0600 + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED +// Version 1.01 -- 2006-09-15 alf@cadsoft.de +// 2008-04-10 changed GROUP ... (>x y); alf@cadsoft.de +// +// Version 1.02 -- 2009-12-01 unlock and lock emlements, swap layer colors and fill alf@cadsoft.de +// check via stack for blind or micro vias + +string Version = "1.02"; +int test = 0; + +string cmd; +int lVisible[]; +int useLayer[]; +int lcolor[]; +int lfill[]; +string lNames[] = { " " }; + +string lockName[]; +int cntlock = 0; + +int maxX = INT_MIN; +int minX = INT_MAX; +int maxY = INT_MIN; +int minY = INT_MAX; +int bminx, bmaxx, bminy, bmaxy; + +int uval = 1; + +if (board) board(B) uval = B.grid.unit; +string unit[] = { "Micron", "mm", "Mil", "Inch" }; +int unitPrec[] = { 0, 1, 1, 3 }, RoundFactor = pow(10, unitPrec[uval]); + +real u2u(int v) { + switch (uval) { + case GRID_UNIT_MIC : return u2mic(v); + break; + + case GRID_UNIT_MM : return u2mm(v); + break; + + case GRID_UNIT_MIL : return u2mil(v); + break; + + case GRID_UNIT_INCH : return u2inch(v); + break; + } +} + + +void checkmaxmin(int x1, int x2, int y1, int y2) { + if (x1 > maxX) maxX = x1; + if (x2 > maxX) maxX = x2; + if (y1 > maxY) maxY = y1; + if (y2 > maxY) maxY = y2; + if (x1 < minX) minX = x1; + if (x2 < minX) minX = x2; + if (y1 < minY) minY = y1; + if (y2 < minY) minY = y2; + return; +} + +void checkarc( int x1, int x2, int y1, int y2, int xc, int yc, real angle1, real angle2, real radius) { + checkmaxmin( x1, x2, y1, y2 ); + if ( angle2 > angle1 + 270.0) { + if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, yc - radius ); + else if( angle1 < 180 ) checkmaxmin( xc - radius, xc + radius, y1 , yc - radius ); + else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, yc + radius ); + else if( angle1 < 360 ) checkmaxmin( xc + radius, xc - radius, y1 , yc + radius ); + } + else if( angle2 > angle1 + 180.0) { + if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, y2 ); + else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, yc - radius, y2 ); + else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, y2 ); + else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, yc + radius, y2 ); + } + else if( angle2 > angle1 + 90.0 ) { + if ( angle1 < 90 ) checkmaxmin( x1 , x2 , yc + radius, y2 ); + else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, y1 , y2 ); + else if( angle1 < 270 ) checkmaxmin( x1 , x2 , yc - radius, y2 ); + else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, y1 , y2 ); + } + return; +} + + +real WireLength(int x1, int x2, int y1, int y2) { + return sqrt( pow(u2u(x2) - u2u(x1), 2) + pow( u2u(y2) - u2u(y1), 2)); +} + + +void lock_elements(void) { + for (int lc = 0; lc < cntlock; lc++) { + cmd += "LOCK " + lockName[lc] + ";\n"; + } + return; +} + +void setcolor(void) { + string s; + sprintf(s, "SET COLOR_LAYER 1 %d;\n", lcolor[16]); // 2009-12-01 shwap layer color and fill + cmd += s; + sprintf(s, "SET FILL_LAYER 1 %d;\n", lfill[16]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 16 %d;\n", lcolor[1]); + cmd += s; + sprintf(s, "SET FILL_LAYER 16 %d;\n", lfill[1]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 21 %d;\n", lcolor[22]); + cmd += s; + sprintf(s, "SET FILL_LAYER 21 %d;\n", lfill[22]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 22 %d;\n", lcolor[21]); + cmd += s; + sprintf(s, "SET FILL_LAYER 22 %d;\n", lfill[21]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 23 %d;\n", lcolor[24]); + cmd += s; + sprintf(s, "SET FILL_LAYER 23 %d;\n", lfill[24]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 24 %d;\n", lcolor[23]); + cmd += s; + sprintf(s, "SET FILL_LAYER 24 %d;\n", lfill[23]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 25 %d;\n", lcolor[26]); + cmd += s; + sprintf(s, "SET FILL_LAYER 25 %d;\n", lfill[26]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 26 %d;\n", lcolor[25]); + cmd += s; + sprintf(s, "SET FILL_LAYER 26 %d;\n", lfill[25]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 27 %d;\n", lcolor[28]); + cmd += s; + sprintf(s, "SET FILL_LAYER 27 %d;\n", lfill[28]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 28 %d;\n", lcolor[27]); + cmd += s; + sprintf(s, "SET FILL_LAYER 28 %d;\n", lfill[27]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 29 %d;\n", lcolor[30]); + cmd += s; + sprintf(s, "SET FILL_LAYER 29 %d;\n", lfill[30]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 30 %d;\n", lcolor[29]); + cmd += s; + sprintf(s, "SET FILL_LAYER 30 %d;\n", lfill[29]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 31 %d;\n", lcolor[32]); + cmd += s; + sprintf(s, "SET FILL_LAYER 31 %d;\n", lfill[32]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 32 %d;\n", lcolor[31]); + cmd += s; + sprintf(s, "SET FILL_LAYER 32 %d;\n", lfill[31]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 51 %d;\n", lcolor[52]); + cmd += s; + sprintf(s, "SET FILL_LAYER 51 %d;\n", lfill[52]); + cmd += s; + sprintf(s, "SET COLOR_LAYER 52 %d;\n", lcolor[51]); + cmd += s; + sprintf(s, "SET FILL_LAYER 52 %d;\n", lfill[51]); + cmd += s; + return; +} + +int checkVia(UL_VIA V) { + if (V.start != 1 || V.end != 16) return 1; + return 0; +} + +// main +if (board) { + board(B) { + int verror = 0; + B.signals(S) S.vias(V) verror += checkVia(V); + if (verror) { + dlgMessageBox("!Do not use this ULP if used blind or micro via(s)!", "OK"); + exit(-1); + } + bminx = B.area.x1; + bmaxx = B.area.x2; + bminy = B.area.y1; + bmaxy = B.area.y2; + B.layers(L) { + lNames[L.number] = L.name; + lVisible[L.number] = L.visible; + useLayer[L.number] = L.used; + lcolor[L.number] = L.color; + lfill[L.number] = L.fill; + } + B.wires(W) { + if (W.layer == 20) { + if (W.arc) { + checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius); + } + else { + checkmaxmin( W.x1, W.x2, W.y1, W.y2 ); + } + } + } + B.circles(C) { + if (C.layer == 20) { + checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius ); + } + } + B.elements(E) { + E.package.wires(W) { + if (W.layer == 20) { + // *** Dimension in Packages *** + if (W.arc) { + checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius); + } + else { + checkmaxmin( W.x1, W.x2, W.y1, W.y2 ); + } + } + } + E.package.circles(C) { + if (C.layer == 20) { + checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius ); + } + } + } + string s; + sprintf(s, "DISPLAY ALL;\n"); + cmd += s; + sprintf(s, "GROUP ALL;\n"); + cmd += s; + cmd += "LOCK (>S 0 0);\n"; // unlock all 2009-11-01 + + sprintf(s, "GRID FINEST;\nMIRROR (>%.4f %.4f);\nGRID LAST;\n", + (u2u(maxX) + u2u(minX)) / 2, u2u(minY) ); + cmd += s; + cmd += "DISPLAY NONE "; + for(int l = 1; l < 256; l++) { + if (lNames[l]) { // Layer defined + if (lVisible[l]) { + if (l == 1 || l == 16 || l == 21 || l == 22 || l == 23 || l == 24 || l == 25 || l == 26 || l == 27 || l == 28 || l == 29 || l == 30 || l == 31 || l == 32 || l == 51 || l == 52 ) { + if (l == 1) sprintf(s, " %d", 16); // 2009-12-01 shwap visible layers + else if (l == 16) sprintf(s, " %d", 1); + else if (l == 21) sprintf(s, " %d", 22); + else if (l == 22) sprintf(s, " %d", 21); + else if (l == 23) sprintf(s, " %d", 24); + else if (l == 24) sprintf(s, " %d", 23); + else if (l == 25) sprintf(s, " %d", 26); + else if (l == 26) sprintf(s, " %d", 25); + else if (l == 27) sprintf(s, " %d", 28); + else if (l == 28) sprintf(s, " %d", 27); + else if (l == 29) sprintf(s, " %d", 30); + else if (l == 30) sprintf(s, " %d", 29); + else if (l == 31) sprintf(s, " %d", 32); + else if (l == 32) sprintf(s, " %d", 31); + else if (l == 51) sprintf(s, " %d", 52); + else if (l == 52) sprintf(s, " %d", 51); + } + else sprintf(s, " %d", l); + cmd += s; + } + } + } + cmd += ";\n"; + B.elements(E) if (E.locked) cmd += "LOCK " + E.name + ";\n"; // 2009-12-01 + setcolor(); + } +} + +if (test) dlgDialog("Test") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("ok") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-1); } + } +}; +exit(cmd); \ No newline at end of file diff --git a/trunk/ulp/mkdir.ulp b/trunk/ulp/mkdir.ulp new file mode 100644 index 00000000..37c86eba --- /dev/null +++ b/trunk/ulp/mkdir.ulp @@ -0,0 +1,62 @@ +#usage "Example: Make Directory with a ULP.

    " + "RUN mkdir subdirectoryname

    " + "alf@cadsoft.de" + +string Version = "1.0.0"; // 2012-04-10 alf@cadsoft.de +string Directory; +string SubDirectory = argv[1]; +string DOScommand; + +if (!argv[1]) { + dlgMessageBox("!Missing subdirectoryname.

    " + usage, "OK"); + exit(-1); +} + + +/* ********************************************************************************** + Der MicroSoft-Fehler: BACKSLASH + Ein Backslach ist ein Escape-Zeichen um ein Steuerzeichen zu maskieren. + Unter Windows wird als Pfad-Trennzeichen der Backslash '\' benutzt, + und nicht wie unter UNIX der Slash '/'! + Eagle benutzt aus Kompatibilitätsgründen zu Linux und Macintosh intern als + Pfad-Trennzeichen den Slash '/'. + Unter Windows wird in allen File-Funktionen im ULP vor der Ausführung der Slash + zu einem Backslash gewandelt. Damit funktionieren alle ULPs auf allen Plattformen. + Soll unter Windows einem system()-Aufruf ein Pfad- oder Datei-Name übergeben werden, + so muß man zuerst den Slash zu einen Backslash wandeln, da nicht unterschieden + werden kann, ob es sich um einen Pfad oder eine Option des Aufrufes handelt. +********************************************************************************** */ + +// change slash to backslash for windows +string cs2bs(string s) { + int pos; + do { + pos = strchr(s, '/'); + if (pos >= 0) s[pos] = '\\'; + } while (pos >= 0); + return s; +} + + +if (board) board(B) { + Directory = filedir(B.name); +} +else if (schematic) schematic(S) { + Directory = filedir(S.name); +} +else if (library) library(L) { + Directory = filedir(L.name); +} + +// Check if exist subdirectory. +string f[]; +int n = fileglob(f, Directory+SubDirectory); +if (n) { + //dlgMessageBox("!Directory exist:\n\n" + Directory+SubDirectory, "OK"); + exit(0); +} + +/*** generate DOS command ***/ +sprintf(DOScommand, "CMD.EXE /C MKDIR \"%s%s\"", cs2bs(Directory), cs2bs(SubDirectory) ); +system(DOScommand); + diff --git a/trunk/ulp/mount-marks-smd.ulp b/trunk/ulp/mount-marks-smd.ulp new file mode 100644 index 00000000..efad11c1 --- /dev/null +++ b/trunk/ulp/mount-marks-smd.ulp @@ -0,0 +1,82 @@ +#usage "Data generation for mounting machines

    \n" + "This ULP generates files for top and bottom layers " + "wich can be used with mounting machines. " + "Use x and y coordinates of the origin points (units: mm) of the SMD elements" + "and packages from defined lbr." + "The syntax of the output data looks like this:

    " + "Name x-coord y-coord Rotation Value Package

    " + "Author: support@cadsoft.de" + +string Version = "1.0.2"; // 2013-10-25 no duplicate listing + // 2013-10-16 if(C.smd) ... delete if C.smd.layer alf@cadsoft.de + // now Display exported data +string def_lbr = "marks"; // define a library name to export also place coordinates + // 2006-04-18 alf@cadsoft.de + + +char Tab = '\t'; // ';'; + + +board(B) { + // Get filename + string fileNameTop = dlgFileSave("Save File", filesetext(B.name, ".mnt"), "*.mnt"); + if (fileNameTop == "") exit(0); + string fileNameBot = dlgFileSave("Save File", filesetext(B.name, ".mnb"), "*.mnb"); + if (fileNameBot == "") exit(0); + + int wasSmd = 0; + output(fileNameBot, "wt") ; + output(fileNameTop, "wt") { + B.elements(E) { + if (strlwr(E.package.library) == def_lbr) { // 2013-10-25 + if (E.mirror == 0) { + printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n", + E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab, + E.angle, Tab, E.value, Tab, E.package.name); + } + else { + output(fileNameBot, "at") { + printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n", + E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab, + E.angle, Tab, E.value, Tab, E.package.name); + } + } + } + else { + E.package.contacts(C) { + if (C.smd ) { // && C.smd.layer == 1) { + if (E.mirror == 0) { + printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n", + E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab, + E.angle, Tab, E.value, Tab, E.package.name); + } + else { + output(fileNameBot, "at") { + printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n", + E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab, + E.angle, Tab, E.value, Tab, E.package.name); + } + } + break; + } + } + } + } + } + string mt, mb; + int cntt = fileread(mt, fileNameTop); + int cntb = fileread(mb, fileNameBot); + dlgDialog("Mount data") { + dlgHBoxLayout dlgSpacing(500); + dlgLabel("Top place"); + dlgTextView(mt); + dlgLabel("Bottom place"); + dlgTextView(mb); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("OK") dlgAccept(); + dlgStretch(1); + } + }; +} + diff --git a/trunk/ulp/mount-marks.ulp b/trunk/ulp/mount-marks.ulp new file mode 100644 index 00000000..338bec6e --- /dev/null +++ b/trunk/ulp/mount-marks.ulp @@ -0,0 +1,75 @@ +#usage "Data generation for mounting machines

    \n" + "This ULP generates files for top and bottom layers " + "wich can be used with mounting machines. " + "Use x and y coordinates of the origin points (units: mm) of the SMD elements" + "and packages from defined lbr." + "The syntax of the output data looks like this:

    " + "Name x-coord y-coord Rotation Value Package

    " + "Author: support@cadsoft.de" + +string def_lbr = "marks"; // 2013-10-25 open the exported list in a dialog to show + // define a library name to export also place coordinates + // 2006.04.18 alf@cadsoft.de + +char Tab = '\t'; // ';'; + + +board(B) { + // Get filename + string fileNameTop = dlgFileSave("Save File", filesetext(B.name, ".mnt"), "*.mnt"); + if (fileNameTop == "") exit(0); + string fileNameBot = dlgFileSave("Save File", filesetext(B.name, ".mnb"), "*.mnb"); + if (fileNameBot == "") exit(0); + + int wasSmd = 0; + output(fileNameBot, "wt") ; + output(fileNameTop, "wt") { + B.elements(E) { + E.package.contacts(C) { + if (E.mirror == 0) { + printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n", + E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab, + E.angle, Tab, E.value, Tab, E.package.name); + } + else { + output(fileNameBot, "at") { + printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n", + E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab, + E.angle, Tab, E.value, Tab, E.package.name); + } + } + break; + } + if (strupr(E.package.library) == strupr(def_lbr)) { + if (E.mirror == 0) { + printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n", + E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab, + E.angle, Tab, E.value, Tab, E.package.name); + } + else { + output(fileNameBot, "at") { + printf("%s%c%.4f%c%.4f%c%.1f%c%s%c%s\n", + E.name, Tab, u2mm(E.x), Tab, u2mm(E.y), Tab, + E.angle, Tab, E.value, Tab, E.package.name); + } + } + } + } + } + string mt, mb; + int cntt = fileread(mt, fileNameTop); + int cntb = fileread(mb, fileNameBot); + dlgDialog("Mount data") { + dlgHBoxLayout dlgSpacing(500); + dlgLabel("Top place"); + dlgTextView(mt); + dlgLabel("Bottom place"); + dlgTextView(mb); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("OK") dlgAccept(); + dlgStretch(1); + } + }; +} + diff --git a/trunk/ulp/mount-trace.ulp b/trunk/ulp/mount-trace.ulp new file mode 100644 index 00000000..414a8a4d --- /dev/null +++ b/trunk/ulp/mount-trace.ulp @@ -0,0 +1,290 @@ +#usage "MOUNT TRACE shows all parts on the top layer with the same values of a board for manual assembling.

    " + "RUN mount-trace (this help page)
    " + "RUN mount-trace -L generate a trace list from current board.
    " + "RUN mount-trace 0 set pointer to zero.
    " + "RUN mount-trace + pointer+1, show the next value(s).
    " + "RUN mount-trace ++ pointer+1, show a dialog with the counts, value and package.
    " + "RUN mount-trace - pointer-1, show the previous value(s).
    " + "RUN mount-trace -- pointer-1, show a dialog with the counts, value and package.
    " + "RUN mount-trace -M mirror the whole board [make Bottom to Top] " + " save board with an extended name and generate trace list from this side.

    " + "Tip: Define function key(s) with ASSIGN for easier use of this ULP.

    " + "Author: support@cadsoft.de" + +string Hilfe = "MOUNT TRACE zeigt alle Bauteile auf der Top-Seite mit gleichem Value für manuelles Bestücken.

    " + + "RUN mount-trace (diese Hilfeseite)
    " + + "RUN mount-trace -L generiert die Trace-Liste des aktuellen Boards.
    " + + "RUN mount-trace 0 setzt den Zeiger auf null.
    " + + "RUN mount-trace + Zeiger+1, zeige die Bauteile mit dem nächsten Wert an.
    " + + "RUN mount-trace ++ Zeiger+1, zeige die Anzahl, den Wert und das Package der Bauteile in einem Dialog.
    " + + "RUN mount-trace - Zeiger-1, zeige die Bauteile mit dem vorhergehenden Wert an.
    " + + "
    RUN mount-trace -- Zeiger-1, zeige die Anzahl, den Wert und das Package der Bauteile in einem Dialog.
    " + + "RUN mount-trace -M Spiegelt das ganze Board [Unten nach Oben], speichert das Board mit
    " + + "Namenserweiterung und generiert dafür eine Liste der Bauteile auf der Oberseite.

    " + + "Tip: Setzen Sie sich Funktionstasten [ASSIGN] mit den Optionen für eine einfachere Bedienung.

    " + + "Author: support@cadsoft.de"; + +#require 5.1000; + +string Version = "Version 1.3.0"; // 2006-04-27 + // 2008-04-10 changed GROUP ... (>x y); alf@cadsoft.de + // 2008-11-03 correct SHOW comand Version 5.x + // 2010-09-06 Tippfehler in Description berichtigt + // Mit Option ++ -- um auch die Stückzahl anzuzeigen. + // Der SHOW-Befehl kann nur Bauteile anzeigen, deshalb + // muß die Anzahl und der Wert gesondert angezeigt werden, + // was nur mit dem entsprechenden ulpmessage.ulp durchführbar ist. + // Das aber eine weitere Bestätigung (Testendruck) benötigt. + // 2010-09-08 Packagevarianten werden berücksichtigt npackage[]; + // + +numeric string nshow[], nvalue[], npackage[]; +int ncnt[]; +int cnt; +int lcnt; +string empty = "~/empty/~"; + +int optshow = 0; // Only board. Option to manually placing 2006.04.25 + +string mirrorext = "-~~mirror"; // file extension if Board mirrored + +string traceext = "~~trace.trc"; +string tracefile = "~~trace.cnt"; +string fname, mname, ftrace; +string cmd; + + +void test(void) { + dlgDialog("test") { + int sel = 0; + dlgListView("Element", nshow, sel); + dlgPushButton("+OK") dlgAccept(); + }; + return; +} + + +void add_list(string name, string value, string pac) { + if (!value) { + string s; + sprintf(s, "!Element %s has no value.
    Add to view list?", name); + if (dlgMessageBox(s, "YES", "NO") != 0) return; + value = empty; + } + int new = 1; + for (int n = 0; n < cnt; n++) { + if (nvalue[n] == value && npackage[n] == pac) { + nshow[n] += " " + name + ""; + ncnt[n]++; + return; + } + } + nvalue[cnt] = value; + npackage[cnt] = pac; + nshow[cnt] += " " + name + ""; + ncnt[cnt] = 1; + cnt++; + return; +} + + +void set_trace_zero(void) { + output(ftrace, "wt") { + printf("0"); + } + return; +} + +void generate_list(void) { + board(B) { + B.elements(E) { + E.package.contacts(S) { // only Packages with Pads or Smds + if (!E.mirror) add_list(E.name, E.value, E.package.name); // only packages on Top : 2010-09-06 case sensitive + break; + } + } + int index[]; + sort( cnt, index, nvalue, npackage); + output(fname, "wt") { + for (int n = 0; n < cnt; n++) { + printf("%d\t%s\t%s\t%s\n", ncnt[index[n]], nvalue[index[n]], npackage[index[n]], nshow[index[n]]); + } + } + set_trace_zero(); + } + cmd = "DISPLAY NONE 21 -23 25 27 51;\nRUN '" + argv[0] + "' +;\n"; + exit(cmd); +} + + +void read(void) { + string l[]; + lcnt = fileread(l, fname); + for (int n = 0; n < lcnt; n++) { + string s[]; + int x = strsplit(s, l[n], '\t'); + ncnt[n] = strtol(s[0]); + nvalue[n] = s[1]; + npackage[n] = s[2]; + nshow[n] = s[3]; + } + string t; + cnt = fileread(t, ftrace); + cnt = strtol(t); + return; +} + + +void checkfile(void) { // check exist trace-list of this board + string s[]; + int n = fileglob(s, ftrace); + if (!n) { + generate_list(); + } + return; +} + + +void traceplus() { + if (argv[1] == "+") sprintf(cmd, "SHOW %s", nshow[cnt]); + else if (argv[1] == "++") { + if (language() == "de") { + sprintf(cmd, "RUN ulpmessage '%d Stück %s
    Package %s';\nSHOW %s", ncnt[cnt], nvalue[cnt], npackage[cnt], nshow[cnt]); + } + else { + sprintf(cmd, "RUN ulpmessage '%d part(s) %s
    Package %s';\nSHOW %s", ncnt[cnt], nvalue[cnt], npackage[cnt], nshow[cnt]); + } + } + cnt++; + if (cnt < lcnt) { + output(ftrace, "wt") { + printf("%d", cnt); + } + } + else { + if (language() == "de") { + dlgMessageBox("Letzter Eintrag!" , "OK"); + } + else { + dlgMessageBox("Last entry!" , "OK"); + } + } + exit(cmd); +} + + +void traceminus() { + cnt--; + if (cnt < 0) { + cnt = 0; + if (language() == "de") { + dlgMessageBox("Erster Eintrag!", "OK"); + } + else { + dlgMessageBox("First entry!", "OK"); + } + } + if (argv[1] == "-") sprintf(cmd, "SHOW %s", nshow[cnt]); + if (argv[1] == "--") { + if (language() == "de") { + sprintf(cmd, "RUN ulpmessage '%d Stück %s
    Package %s';\nSHOW %s", ncnt[cnt], nvalue[cnt], npackage[cnt], nshow[cnt]); + } + else { + sprintf(cmd, "RUN ulpmessage '%d part(s) %s
    Package %s';\nSHOW %s", ncnt[cnt], nvalue[cnt], npackage[cnt], nshow[cnt]); + } + } + output(ftrace, "wt") { + printf("%d", cnt); + } + exit(cmd); +} + + +void opt_Mirror(void) { // 2006.04.25 + string cmd; + int pos = strstr(mname , mirrorext); + if (pos > 0) { + if (language() == "de") { + if (dlgMessageBox("Board ist gespiegelt! Siehe Dateiname.
    Möchten Sie das nicht-gespiegelte Board laden?
    ", "JA", "NEIN") != 0) exit(0); + set_trace_zero(); + sprintf(cmd, "EDIT '%s.brd';\nDISPLAY NONE 21 -23 25 27;\n", strsub(mname, 0, pos)); + exit(cmd); + } + else { + if (dlgMessageBox("Board is mirrored! See file name.
    Do you want load the non-mirrored board?
    ", "YES", "NO") != 0) exit(0); + } + set_trace_zero(); + sprintf(cmd, "EDIT '%s';\nDISPLAY NONE 21 -23 25 27;\n", mname); + exit(cmd); + } + else { + fname = filesetext(mname, mirrorext+".brd"); + string f[]; + int cnt = fileglob(f, fname); + if (cnt) { + set_trace_zero(); + sprintf(cmd, "EDIT '%s';\nDISPLAY NONE 21 -23 25 27;\n", fname); + } + else { + if (language() == "de") { + if (dlgMessageBox("
    Das Board wird mit der Namenserweiteung " + mirrorext + " gespiegelt gespeichert!", "OK" , "ABBRUCH") != 0) exit(0); + } + else { + if (dlgMessageBox("Save board with extended name " + mirrorext + "!", "OK" , "CANCEL") != 0) exit(0); + } + set_trace_zero(); + sprintf(cmd, "WRITE '%s';\nEDIT '%s';\n" + + "DISPLAY ALL;\n" + + "GRID MM;\n" + + "GROUP (-800 -800) (800 -800) (800 800) (-800 800) (>-800 -800);\n" + + "MIRROR (> 0 0);\n" + + "WIN FIT;\n" + + "DISPLAY NONE 21 -23 25 27;\nWRITE;\nRUN '%s' -L;\n", fname, fname, argv[0]); + } + exit(cmd); + } +} + + + +if (board) { + board(B) { + mname = B.name; + fname = filesetext(B.name, traceext); + ftrace = filesetext(B.name, tracefile); + } + if (!argv[1]) { + if (language() == "de") { + dlgMessageBox(Hilfe + Version, "OK"); + } + else { + dlgMessageBox(usage + Version, "OK"); + } + exit(0); + } + if (argv[1] == "-M") opt_Mirror(); // Mirror option + else if (argv[1] == "-L") generate_list(); + else if (argv[1] == "+" || argv[1] == "++" || argv[1] == "-" || argv[1] == "--" || argv[1] == "0") { + checkfile(); + read(); + if (argv[1] == "+" || argv[1] == "++") traceplus(); + if (argv[1] == "-" || argv[1] == "--") traceminus(); + if (argv[1] == "0") { + set_trace_zero(); + exit(";"); // view nothing + } + } + else { + if (language() == "de") { + dlgMessageBox("Unbekannte Option " + argv[1], "OK"); + dlgMessageBox(Hilfe + Version, "OK"); + } + else { + dlgMessageBox("Unknown option " + argv[1], "OK"); + dlgMessageBox(usage + Version, "OK"); + } + exit(-2); + } +} + +else dlgMessageBox("!Start this ULP from a Board", "OK"); \ No newline at end of file diff --git a/trunk/ulp/mount.ulp b/trunk/ulp/mount.ulp new file mode 100644 index 00000000..47157c09 --- /dev/null +++ b/trunk/ulp/mount.ulp @@ -0,0 +1,54 @@ +#usage "Data generation for mounting machines\n" + "

    " + "Generates a file that can be used with mounting machines. " + "The x- and y- coordinates (units: mil) are calculated as mean of " + "maximum and mimimum value of the pads or smds origin points. " + "The calculated value does not necessarily fit with the origin " + "point of the part in the layout." + "All elements populated in currently set assembly variant are considered." + "

    " + "The syntax of the output data looks like this:" + "

    " + "value;x-coord;y-coord;rotation;name" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +// History: +// 2012-06-12: Extended to assembly variants + +if (board) board(B) { + + // Get filename + string fileName = dlgFileSave("Save File", filesetext(B.name, ".mnt"), "*.mnt"); + if (fileName == "") exit(0); + + output(fileName) { + + B.elements(E) if (E.populate) { + + int xmax =-2147483648, + xmin = 2147483647, + ymax = xmax, + ymin = xmin; + + E.package.contacts(C) { + + if (C.x > xmax) xmax = C.x; + if (C.y > ymax) ymax = C.y; + if (C.x < xmin) xmin = C.x; + if (C.y < ymin) ymin = C.y; } + + + printf("%s;%5.0f;%5.0f;%3.0f;%s \n", + E.value, u2mil((xmin + xmax)/2), u2mil((ymin + ymax)/2), + E.angle, E.name ); + } + } +} + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); +} diff --git a/trunk/ulp/mountsmd.ulp b/trunk/ulp/mountsmd.ulp new file mode 100644 index 00000000..413f8557 --- /dev/null +++ b/trunk/ulp/mountsmd.ulp @@ -0,0 +1,93 @@ +#usage "Data generation for mounting machines\n" + "

    " + "Generates files for smds on the top and bottom layers " + "wich can be used with mounting machines. " + "The x and y coordinates (units: mm) of the SMD elements are calculated " + "as mean of maximum and mimimum value of the smds origin points. " + "The calculated value does not necessarily fit with the origin " + "point of the part in the layout." + "All SMD elements populated in currently set assembly variant are considered." + "

    " + "The syntax of the output data looks like this:" + "

    " + "name x-coord y-coord rotation value package" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +if (board) board(B) { + + // Get filename + string fileName = dlgFileSave("Save File", filesetext(B.name, ".mnt"), "*.mnt"); + if (fileName == "") exit(0); + + output(fileName) { + + B.elements(E) if (E.populate) { + + int wasSmd, + xmax =-2147483648, + xmin = 2147483647, + ymax = xmax, + ymin = xmin; + + wasSmd = 0; + + E.package.contacts(C) { + if (C.smd && C.smd.layer == 1) { + wasSmd = 1; + + if (C.x > xmax) xmax = C.x; + if (C.y > ymax) ymax = C.y; + if (C.x < xmin) xmin = C.x; + if (C.y < ymin) ymin = C.y; + } + } + + if (wasSmd) + printf("%s %5.2f %5.2f %3.0f %s %s\n", + E.name, u2mm((xmin + xmax)/2), u2mm((ymin + ymax)/2), + E.angle, E.value, E.package.name); + } + } + + // Get filename + fileName = dlgFileSave("Save File", filesetext(B.name, ".mnb"), "*.mnb"); + if (fileName == "") exit(0); + + output(fileName) { + + B.elements(E) if (E.populate) { + + int wasSmd, + xmax =-2147483648, + xmin = 2147483647, + ymax = xmax, + ymin = xmin; + + wasSmd = 0; + + E.package.contacts(C) { + if (C.smd && C.smd.layer == 16) { + wasSmd = 1; + + if (C.x > xmax) xmax = C.x; + if (C.y > ymax) ymax = C.y; + if (C.x < xmin) xmin = C.x; + if (C.y < ymin) ymin = C.y; + } + } + + if (wasSmd) + printf("%s %5.2f %5.2f %3.0f %s %s\n", + E.name, u2mm((xmin + xmax)/2), u2mm((ymin + ymax)/2), + E.angle, E.value, E.package.name); + } + } +} + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); +} diff --git a/trunk/ulp/net-bus-labeling.ulp b/trunk/ulp/net-bus-labeling.ulp new file mode 100644 index 00000000..56dea6e0 --- /dev/null +++ b/trunk/ulp/net-bus-labeling.ulp @@ -0,0 +1,266 @@ +#usage "de:NET/BUS LABEL platzieren

    " + "Um Netze automatisch mit einem Label zu versehen, muß man eine Gruppe um den Bereich " + "der NET/BUS-Wire definieren, an denen ein LABEL platziert werden soll. " + "Es wird an jedem selektierten Ende eines NET/BUS-Wire in der Gruppe ein LABEL platziert. " + "Man sollte also die Gruppe so wählen, daß nur eine Ende des Wire groupiert wird." + "Das LABEL wird bei einem NET mit einem Offset von 10 Mil, bei einem BUS mit einem Offset 20 Mil " + "über die waagrechte Linie gestellt, bzw. bei einer senkrechten Linie links daneben. " + "Ein zweiter Offset sorgt dafür, daß das LABEL um ein halbes GRID (50 Mil) vom Beginn des Wire, " + "in der selben Richtung wie sich der Wire erstreckt, platziert wird. " + "Das LABEL wird entsprechend der Ausrichtung des Wire gedreht. " + "Die Textgröße des LABEL wird auc 70 Mil gesetzt." + "

    " + "Author alf@cadsoft.de" + , + "en:NET/BUS labeling

    " + "For labeling nets automatically you have to draw a GROUP around the area you want to " + "have labels placed. " + "There can be labels at net/bus bends only. Which is usually the location where " + "two bus or net coordinates converge." + "A label for a net will be placed with an offset of 10 mil, for a bus with an offset of 20 mils " + "above a horizontal wire, or left of a vertical wire. A second offset places the label half the " + "grid (50 mil) from the beginning in wire direction. The label will be placed in the " + "same rotation the wire has. The text size of the label is 70 mil. " + "

    " + "Author alf@cadsoft.de" + +#require 5.1200 + +string Version = "1.0.0"; // 2013-05-28 + +real NetLabelOffset = 10.0; // offset zur Netlinie in MIL +real BusLabelOffset = 25.0; // offset zur Buslinie in MIL +real LabelLineOffset = 50.0; // in Mil +real LabelSize = 70.0; // Mil +int cntS = 0; +int SegWireX1[], SegWireY1[], SegWireX2[], SegWireY2[], WireDirection[], WireType[], SegWireSide[]; +int GroupSelect = 0; +int islabelgen = 0; + +enum { None, Buswire, Netwire, Horizontal, Vertical, Diagonal, Left, Right, Up, Down, Cross }; +string Cmd; +string s; + +int test = 0; + +/*** Functions ***/ +void header(void) { + sprintf(s, "DISPLAY NONE 91 92;\n"); + Cmd+=s; + sprintf(s, "CHANGE Size %.4fmil;\n", LabelSize); + Cmd+=s; + return; +} + +void trailer(void) { + sprintf(s, "DISPLAY LAST;\n"); + Cmd+=s; + return; +} + +void gencmd(int index1, int direction, int side) { + // Jetzt muß nur ermittelt werden, + // in welche Richtung der Wire steht, + // und ob das Label verschoben werden muß, + // wenn der weiterführende Wire senkrecht und auf der + // rechten oder linken Seite des Wire steht. + + int x, y; + string mirror = ""; + real lxoffset, lyoffset; + int wirealignment, rotateangle = 0; + real labeloffset; + if (WireType[index1] == Buswire) labeloffset = BusLabelOffset; + else if (WireType[index1] == Netwire) labeloffset = NetLabelOffset; + else if (dlgMessageBox("WireType?", "OK", "CANCEL") != 0) exit(-65); + + if (direction == Horizontal) { // also eine waagrechte Linie + if (side == 1) { + x = SegWireX1[index1]; + y = SegWireY1[index1]; + + if (SegWireX1[index1] < SegWireX2[index1]) { + wirealignment = Right; + } + else { + wirealignment = Left; + } + } + else if (side == 2) { + x = SegWireX2[index1]; + y = SegWireY2[index1]; + if (SegWireX2[index1] < SegWireX1[index1]) { + wirealignment = Right; + } + else { + wirealignment = Left; + } + } + else { + if (dlgMessageBox("Error horizontal", "OK", "Cancel") != 0) exit(-96); + return; + } + } + else if (direction == Vertical) { // also eine senkrechte Linie + if (side == 1) { + x = SegWireX1[index1]; + y = SegWireY1[index1]; + + if (SegWireY1[index1] < SegWireY2[index1]) { + wirealignment = Up; + } + else { + wirealignment = Down; + } + } + else if (side == 2) { + x = SegWireX2[index1]; + y = SegWireY2[index1]; + if (SegWireY2[index1] < SegWireY1[index1]) { + wirealignment = Up; + } + else { + wirealignment = Down; + } + } + else { + if (dlgMessageBox("Error vertical", "OK") != 0) exit(-123); + return; + } + } + else { + dlgMessageBox("Error cross", "ok"); + } + + if (wirealignment == Right) { + lyoffset = labeloffset; // oberhalb der Linie + lxoffset = LabelLineOffset; // nach rechts versetzt + mirror = ""; + } + if (wirealignment == Left) { + lyoffset = labeloffset; // oberhalb der Linie + lxoffset = LabelLineOffset * -1.0; // nach links versetzt + mirror = "M"; + } + if (wirealignment == Up) { + lxoffset = labeloffset * -1.0; // links von der Linie + lyoffset = LabelLineOffset; // nach oben versetzt + mirror = ""; + rotateangle = 90; + } + if (wirealignment == Down) { + lxoffset = labeloffset * -1.0; // links von der Linie + lyoffset = LabelLineOffset * -1.0; // nach unten versetzt + mirror = "M"; + rotateangle = 270; + } + + sprintf(s, "LABEL (%.4fmil %.4fmil) (%.4fmil %.4fmil);\n", + u2mil(x), u2mil(y), + u2mil(x)+lxoffset, u2mil(y)+lyoffset + ); + Cmd+=s; + sprintf(s, "ROTATE =R0 (%.4fmil %.4fmil);\n", u2mil(x)+lxoffset, u2mil(y)+lyoffset); // stelle rotate wieder auf 0 + Cmd+=s; + + if (!rotateangle && mirror) { + sprintf(s, "MIRROR (%.4fmil %.4fmil);\n", u2mil(x)+lxoffset, u2mil(y)+lyoffset); + Cmd+=s; + } + if (rotateangle) { + sprintf(s, "ROTATE =%sR%d (%.4fmil %.4fmil);\n", mirror, rotateangle, u2mil(x)+lxoffset, u2mil(y)+lyoffset); + Cmd+=s; + } + islabelgen++; + return; +} + +void genlabel(void) { + for (int n = 0; n < cntS; n++) { + gencmd(n, WireDirection[n], SegWireSide[n]); + } + return; +} + +void addwireseg(UL_WIRE W, string wname, int type, int side) { + SegWireX1[cntS] = W.x1; + SegWireY1[cntS] = W.y1; + SegWireX2[cntS] = W.x2; + SegWireY2[cntS] = W.y2; + WireType[cntS] = type; + SegWireSide[cntS] = side; + + if (SegWireX1[cntS] == SegWireX2[cntS] || SegWireY1[cntS] == SegWireY2[cntS]) { + if (SegWireX1[cntS] == SegWireX2[cntS]) { + WireDirection[cntS] = Vertical;// wire senkrecht + } + else if (SegWireY1[cntS] == SegWireY2[cntS]) { + WireDirection[cntS] = Horizontal;// wire waagrecht + } + cntS++; + } + return; +} + +/*** main ***/ +if (sheet) { + sheet(S) { + S.nets(N) { + status(N.name); + N.segments(SEG) { + SEG.wires(W) { + int side = ingroup(W); + if (side == 1 || side == 2) { // Wire bei denen beide Seiten in der Group sind, werden nicht benutzt + GroupSelect = 1; + addwireseg(W, N.name, Netwire, side); + } + } + } + } + S.busses(B) { + status(B.name); + B.segments(SEG) { + SEG.wires(W) { + int side = ingroup(W); + if (side == 1 || side == 2) { // Wire bei denen beide Seiten in der Group sind, werden nicht benutzt + GroupSelect = 1; + addwireseg(W, B.name, Buswire, side); + } + } + } + } + } + if (!GroupSelect) { + dlgMessageBox("!Selektieren Sie zuerst mit GROUP die NET/BUS-Wire.", "OK"); + exit(0); + } + else { + header(); + genlabel(); + trailer(); + } + + if (test) { + string scmd; + sprintf(scmd, "%d Wire gefunden", cntS); + dlgDialog("test") { + dlgLabel(scmd); + dlgHBoxLayout dlgSpacing(800); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(600); + dlgTextEdit(Cmd); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-ESC") { dlgReject(); exit(-99); } + } + }; + } + if (!islabelgen) { + dlgMessageBox("!No wire (horizontal/vertical) for LABEL found, check GROUP.

    "+usage, "OK"); + exit(-1); + } + exit(Cmd); +} + +else dlgMessageBox("Starten Sie das ULP in einem Schaltplan", "OK"); \ No newline at end of file diff --git a/trunk/ulp/netlist-converter.ulp b/trunk/ulp/netlist-converter.ulp new file mode 100644 index 00000000..ca3a05f2 --- /dev/null +++ b/trunk/ulp/netlist-converter.ulp @@ -0,0 +1,577 @@ +#usage "Netlist converter for netlist from other CAD-System." + "Author: alf@cadsoft.de" + +string Version = "Version 1.2"; // 2009-02-26 alf@cadsoft.de + // 2009-05-20 Mentor, PADS2000, Accel, Allegro alf@cadsoft.de + // 2010-06-17 Allegro 16.2 alf@cadsoft.de + +enum { Unknown, + Multiwire, +// OrCad, +// Tango, + Mentor, + PADS2000, + Accel, + Allegro, + Allegro162, + // insert new types are here + Last }; + +string netListType[]; + netListType[Unknown] = "Unknown"; + netListType[Multiwire] = "Multiwire"; +// netListType[OrCad] = "OrCad"; +// netListType[Tango] = "Tango"; + netListType[Mentor] = "Mentor"; + netListType[PADS2000] = "PADS2000"; + netListType[Accel] = "Accel"; + netListType[Allegro] = "Allegro"; + netListType[Allegro162] = "Allegro 16.2"; + // insert new types are here + netListType[Last] = ""; + + +string NetlistInfo = "Netlist"; +string text, netscript; + +int t; +string line[]; +int lines = 0; + +string fname; +string saveinfo = ""; + +string L_separator = "SPACE"; +string W_separator = "."; + +char Lseparator; +if (L_separator == "SPACE") Lseparator = ' '; +else Lseparator = L_separator[0]; +char Wseparator = W_separator[0]; +int NetRow = 1, PartRow = 2, PadRow = 3; + + +/*** Functions ***/ +void genScriptUnknown(void) { + saveinfo = ""; + dlgRedisplay(); + string Lnet, Lpart, Lpad; + netscript = ""; + string actualsigname = ""; + for (int n = 0; n < lines; n++) { + status(line[n]); + string s[]; + int cnt; + int ls = strsplit(s, line[n], Lseparator); + int scnt = 0; + string startnet; + for (int ln = 0; ln < ls; ln++) { + if (s[ln]) { + scnt++; + if (scnt == NetRow) { + Lnet = s[ln]; + if (actualsigname != Lnet) { + sprintf(startnet, ";\nSIGNAL '%s' \n", Lnet); + actualsigname = Lnet; + } + else startnet = "\n "; + + } + else if (scnt == PartRow) Lpart = s[ln]; + else if (scnt == PadRow) Lpad = s[ln]; + } + } + string h; + if (scnt == 3) { + sprintf(h, "%s %s %s", startnet, Lpart, Lpad); + netscript+=h; + } + } + netscript+=";\n"; // close last command + return; +} + + +void genScriptMultiwire(void) { + // defintion of separator for Multiwire; + Lseparator = ' '; + Wseparator = '.'; + NetRow = 1; + PartRow = 2; + PadRow = 3; + saveinfo = ""; + dlgRedisplay(); + string Lnet, Lpart, Lpad; + netscript = ""; + string actualsigname = ""; + for (int n = 0; n < lines; n++) { + status(line[n]); + string s[]; + int cnt; + int ls = strsplit(s, line[n], Lseparator); + int scnt = 0; + string startnet; + for (int ln = 0; ln < ls; ln++) { + if (s[ln]) { + scnt++; + if (scnt == NetRow) { + Lnet = s[ln]; + if (actualsigname != Lnet) { + sprintf(startnet, ";\nSIGNAL '%s' \n", Lnet); + actualsigname = Lnet; + } + else startnet = "\n"; + + } + else if (scnt == PartRow) Lpart = s[ln]; + else if (scnt == PadRow) Lpad = s[ln]; + } + } + string h; + if (scnt == 3) { + sprintf(h, "%s %s %s", startnet, Lpart, Lpad); + netscript+=h; + } + } + netscript+=";\n"; // close last command + return; +} + + +void genScriptOrCad(void) { + // defintion of separator for Orcad; + dlgMessageBox("Orcad converter not defined!", "OK"); + Lseparator = ' '; + Wseparator = '.'; + NetRow = 1; + PartRow = 2; + PadRow = 3; + saveinfo = ""; + dlgRedisplay(); + string Lnet, Lpart, Lpad; + netscript = ""; + string actualsigname = ""; + for (int n = 0; n < lines; n++) { + status(line[n]); + string s[]; + int cnt; + int ls = strsplit(s, line[n], Lseparator); + int scnt = 0; + string startnet; + for (int ln = 0; ln < ls; ln++) { + if (s[ln]) { + scnt++; + if (scnt == NetRow) { + Lnet = s[ln]; + if (actualsigname != Lnet) { + sprintf(startnet, ";\nSIGNAL '%s'", Lnet); + actualsigname = Lnet; + } + else startnet = "\n "; + + } + else if (scnt == PartRow) Lpart = s[ln]; + else if (scnt == PadRow) Lpad = s[ln]; + } + } + string h; + if (scnt == 3) { + sprintf(h, "%s %s %s", startnet, Lpart, Lpad); + netscript+=h; + } + } + netscript+=";\n"; // close last command + return; +} + + +void genScriptTango(void) { + dlgMessageBox("Tango converter not defined!", "OK"); + return; + saveinfo = ""; + dlgRedisplay(); + string Lnet, Lpart, Lpad; + netscript = ""; + string actualsigname = ""; + for (int n = 0; n < lines; n++) { + status(line[n]); + string s[]; + int cnt; + int ls = strsplit(s, line[n], Lseparator); + int scnt = 0; + string startnet; + for (int ln = 0; ln < ls; ln++) { + if (s[ln]) { + scnt++; + if (scnt == NetRow) { + Lnet = s[ln]; + if (actualsigname != Lnet) { + sprintf(startnet, ";\nSIGNAL '%s'", Lnet); + actualsigname = Lnet; + } + else startnet = "\n "; + + } + else if (scnt == PartRow) Lpart = s[ln]; + else if (scnt == PadRow) Lpad = s[ln]; + } + } + string h; + if (scnt == 3) { + sprintf(h, "%s %s %s", startnet, Lpart, Lpad); + netscript+=h; + } + } + netscript+=";\n"; // close last command + return; +} + + +void genScriptMentor(void) { + // defintion of separator for Multiwire; + Lseparator = ' '; + Wseparator = '.'; + NetRow = 1; + PartRow = 2; + PadRow = 3; + saveinfo = ""; + dlgRedisplay(); + string Lnet, Lpart, Lpad; + netscript = ""; + string actualsigname = ""; + for (int n = 0; n < lines; n++) { + status(line[n]); + string s[]; + int cnt; + int ls = strsplit(s, line[n], Lseparator); + int scnt = 0; + string startnet; + if (s[0] == "NET") { // check if a NET line + sprintf(startnet, "SIGNAL %s \n", s[1]); + for (int ln = 2; ln < ls; ln++) { + string pp[]; + strsplit(pp, s[ln], '-'); + startnet += " "+pp[0] + " " + pp[1] + "\n"; + } + netscript+=startnet+";\n"; + } + } + return; +} + + +void genScriptPADS2000(void) { + // defintion of separator for PADS 2000; + if (line[0] != "*PADS2000*") { + dlgMessageBox("it's not a *PADS2000* netlist!", "OK"); + return; + } + Lseparator = ' '; + Wseparator = '.'; + NetRow = 1; + PartRow = 2; + PadRow = 3; + saveinfo = ""; + dlgRedisplay(); + string Lnet, Lpart, Lpad; + netscript = ""; + string actualsigname = ""; + string startnet = ""; + int startflag = 0; + string s[]; + for (int n = 0; n < lines; n++) { + if (startflag) { + status(line[n]); + int ls = strsplit(s, line[n], Lseparator); + if (s[0] == "*SIGNAL*") { // check if a Signal line + if (!startnet) { + sprintf(startnet, "SIGNAL '%s' \n", s[1]); + } + else { + netscript += startnet+";\n"; + sprintf(startnet, "SIGNAL '%s' \n", s[1]); + } + } + else if (s[0] == "*END*") { // check if a END of list + netscript += startnet+";\n"; + } + else { + string pp[]; + int cntpp = strsplit(pp, line[n], Lseparator); + string sp[]; + for (int np = 0; np < cntpp; np++) { + strsplit(sp, pp[np], Wseparator); + startnet += " "+sp[0] + " " + sp[1] + "\n"; + } + } + } + if (line[n] == "*NET*") { + startflag = 1; + } + } + return; +} + + +void genScriptAccel(void) { + // defintion of separator for Accel; + Lseparator = ' '; + Wseparator = '.'; + saveinfo = ""; + dlgRedisplay(); + netscript = ""; + string startnet = ""; + int startflag = 0; + string s[]; + string nn[]; + for (int n = 0; n < lines; n++) { + status(line[n]); + int ls = strsplit(s, line[n], Lseparator); + if (s[0] == "(net") { // check if a Signal line + strsplit(nn, line[n], '"'); + sprintf(startnet, ";\nSIGNAL '%s' \n", nn[1]); + netscript += startnet; + } + else if (s[0] == "(node") { + strsplit(nn, line[n], '"'); + netscript += nn[1] + " " + nn[3] + "\n"; + } + } + netscript += ";\n"; + return; +} + + +void genScriptAllegro(void) { + // defintion of separator for allegro; + Lseparator = ' '; + Wseparator = '.'; + NetRow = 1; + PartRow = 2; + PadRow = 3; + saveinfo = ""; + dlgRedisplay(); + string Lnet, Lpart, Lpad; + netscript = ""; + string actualsigname = ""; + string startnet = ""; + int startflag = 0; + string s[]; + for (int n = 0; n < lines; n++) { + if (startflag) { + status(line[n]); + int ls = strsplit(s, line[n], Lseparator); + if (s[0] == "$END") { // check if a END of list + netscript += ";\n"; + } + else { + ls = strsplit(s, line[n], ';'); + sprintf(startnet, "SIGNAL %s \n", s[0]); + netscript += startnet; + ls = strsplit(s, line[n], Lseparator); + string sp[]; + for (int np = 1; np < ls; np++) { + int cntpp = strsplit(sp, s[np], Wseparator); + netscript += " "+sp[0] + " " + sp[1] + "\n"; + } + } + } + if (line[n] == "$NETS") { + startflag = 1; + } + } + return; +} + +void genScriptAllegro162(void) { // 2010-06-17 alf + // (GENERATED BY: ALLEGRO 16.2 S034 (v16-2-57BX)) + // defintion of separator for allegro; + Lseparator = ' '; + Wseparator = '.'; + NetRow = 1; + PartRow = 2; + PadRow = 3; + saveinfo = ""; + dlgRedisplay(); + string Lnet, Lpart, Lpad; + netscript = ""; + string actualsigname = ""; + string startnet = ""; + int startflag = 0; + string s[]; + for (int n = 0; n < lines; n++) { + if (startflag) { + if (line[n] == "$NETS") { + netscript += ";\n"; + startflag = 0; + break; + } + status(line[n]); + int semipos = strchr(line[n], ';'); + if (semipos > 0) line[n][semipos] = ' '; // replace semikolon to Space 2020-06-17 alf + int kommapos = strchr(line[n], ','); // Weiterführungszeichen, dass es in dernächsten Zeile mit dem Signalnamen weiter geht. + if (kommapos > 0) line[n][kommapos] = ' '; // replace komma to Space 2020-06-17 alf + int ls = strsplit(s, line[n], Lseparator); + if (s[0]) { + if (startflag == 1) { + sprintf(startnet, "SIGNAL '%s' \n", s[0]); + startflag++; + } + else sprintf(startnet, ";\nSIGNAL '%s' \n", s[0]); + netscript += startnet; + } + string sp[]; + for (int np = 1; np < ls; np++) { + if (s[np]) { // 2010-06-16 alf + int cntpp = strsplit(sp, s[np], Wseparator); + netscript += " "+sp[0] + " " + sp[1] + "\n"; + } + } + } + if (line[n] == "$NETS") { + if (!startflag) startflag = 1; + } + } + return; +} + + +void save(string f) { + dlgRedisplay(); + string fn = filesetext(f, ".scr"); + output(fn, "wt") printf("%s", netscript); + sprintf(saveinfo, "Scripte saved as: %s", fn); + dlgRedisplay(); + return; +} + + +string getList(string TypeName) { + return dlgFileOpen("Select a " + TypeName + " netlist'", path_epf[0]+"/*.*"); +} + + +int autocheckFormat(void) { // auto check CAD-Format in first 10 lines 2010-06-17 alf + for (int n = 0; n < 10; n++) { + if (strstr(line[n], "ALLEGRO 16.2") >= 0) return Allegro162; + } + return 0; +} + + +// --- main --- +if (board) { + int selType = Unknown; + int RESULT = dlgDialog("Netlist Converter") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel(NetlistInfo, 1); + dlgTextEdit(text); + } + dlgVBoxLayout { + dlgLabel("EAGLE net script"); + dlgTextEdit(netscript); + } + } + dlgHBoxLayout { + dlgGridLayout { + dlgCell(0, 0) dlgLabel("Line separator"); + dlgCell(0, 1) dlgStringEdit(L_separator); + dlgCell(0, 2) dlgLabel("Word separator"); + dlgCell(0, 3) dlgStringEdit(W_separator); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgGridLayout { + dlgCell(0, 0) dlgLabel("Net in row"); + dlgCell(0, 1) dlgIntEdit(NetRow); + dlgCell(0, 3) dlgLabel("Part in row"); + dlgCell(0, 4) dlgIntEdit(PartRow); + dlgCell(0, 5) dlgLabel("Pad in row"); + dlgCell(0, 6) dlgIntEdit(PadRow); + } + dlgSpacing(200); + dlgStretch(1); + } + dlgHBoxLayout { + dlgGroup("Netlist from CAD System") { + for (int t = 0; t < Last; t++) { + dlgRadioButton(netListType[t], selType) { + NetlistInfo = netListType[selType]+ " Netlist"; + dlgRedisplay(); + } + } + } + dlgStretch(3); + dlgVBoxLayout { + dlgLabel("EAGLE NET-SCRIPT Example:"); + dlgLabel("SIGNAL 'N$1'
    X1 1
    R2 1;
    SIGNAL 'N$2'
    R2 2
    C2 1
    R3 2;
    "); + dlgStretch(1); + } + dlgStretch(2); + } + dlgLabel(saveinfo, 1); + dlgHBoxLayout { + dlgPushButton("&Read list") { + fname = getList(netListType[selType]); + if (!fname) { + dlgMessageBox("no file selected", "OK"); + } + else { + lines = fileread(text, fname); + lines = strsplit(line, text, '\n'); + selType = autocheckFormat(); + } + } + dlgPushButton("&Generate net script") { + switch(selType) { + case Unknown : if(L_separator == "SPACE") Lseparator = ' '; + else if(L_separator == "TAB") Lseparator = '\t'; + else Lseparator = L_separator[0]; + Wseparator = W_separator[0]; + genScriptUnknown(); + break; + case Multiwire : genScriptMultiwire(); + break; +// case OrCad : genScriptOrCad(); + break; +// case Tango : genScriptTango(); + break; + case Mentor : genScriptMentor(); + break; + case PADS2000 : genScriptPADS2000(); + break; + case Accel : genScriptAccel(); + break; + case Allegro : genScriptAllegro(); + break; + case Allegro162 : genScriptAllegro162(); + break; + + } + } + dlgPushButton("&Run net script") { + if (!saveinfo) { + dlgMessageBox("First save the script.", "OK"); + } + else { + if (project.schematic) { + dlgMessageBox("!This Script can not start if a consitence schematic loaded!

    DO NOT CLOSE SCHEMATIC, YOU LOST CONSISTENCE!", "OK"); + } + else dlgAccept(); + } + } + dlgPushButton("&Save net script") { + if (netscript) save(fname); + else dlgMessageBox("First generate script!", "OK"); + } + dlgPushButton("-CANCEL") dlgReject(); + dlgStretch(1); + dlgLabel(Version); + } + }; + if (RESULT) exit("SCRIPT '" + filesetext(fname, ".scr") + "'"); +} + +else dlgMessageBox("!Start this ULP in board.", "OK"); \ No newline at end of file diff --git a/trunk/ulp/netlist_protel.ulp b/trunk/ulp/netlist_protel.ulp new file mode 100644 index 00000000..d75a4dcd --- /dev/null +++ b/trunk/ulp/netlist_protel.ulp @@ -0,0 +1,93 @@ +/* + * This EAGLE User Language Program prints the netlist of a board + * in standard Protel format (1.0) (very similar to Tango netlist format) + * to import it to Protel PCB software. + * + * It is also possible to print the netlist of a schematic, + * but this will not adhere to the correct Protel format: + * package names are missing, pin names instead of pad names. + * + * If you have only the schematic, just generate the board and run this + * ULP in the EAGLE board editor. + * + * 19.09.2001 Hans Lederer, Ingenieurbüro Lederer, Emmendingen + * Hans.Lederer@ib-lederer.de + */ + +if (board) board(B) { + output(filesetext(B.name, ".NET")) { + + B.elements(E) { + printf("%s\n","["); + printf("%s\n",E.name); + printf("%s\n",E.package.name); + printf("%s\n",E.value); + printf("\n\n\n%s\n","]"); + } + + B.signals(S) { + numeric string Part[], Pad[]; + int cnt = 0, index[]; + + S.contactrefs(C) { + Part[cnt] = C.element.name; + Pad[cnt] = C.contact.name; + cnt++; + } + if (cnt) { + sort(cnt, index, Part, Pad); + printf("%s\n","("); + printf("%s\n",S.name); + for (int i = 0; i < cnt; i++) + printf("%s%s%s\n",Part[index[i]],"-",Pad[index[i]]); + printf("%s\n",")"); + } + } + } + } + +if (schematic) schematic(SCH) { + output(filesetext(SCH.name, ".net")) { + + SCH.parts(P) { + int pos_g = strrstr(P.device.name,"GND"); + int pos_v = strrstr(P.device.name,"VCC"); + int pos_p = strrstr(P.device.name,"VPP"); + + if ((pos_g < 0) && (pos_v < 0) && (pos_p < 0)) { + string pkg = P.device.package.name; + int dip_dil = strrstr(pkg,"DIL"); + if ( dip_dil >= 0) + pkg[2]='P'; + printf("%s\n","["); + printf("%s\n",P.name); + printf("%s\n",pkg); + // printf("%s\n",P.device.name); + printf("%s\n",P.value); + printf("\n\n\n%s\n","]"); + } + } + + SCH.nets(N) { + numeric string Part[], Pin[], trimmed, Pad[]; + int cnt = 0, index[]; + + N.pinrefs(P) { + Part[cnt] = P.part.name; + Pin[cnt] = P.pin.name; + Pad[cnt] = P.pin.contact.name; + cnt++; + } + + if (cnt) { + sort(cnt, index, Part, Pin); + printf("%s\n","("); + printf("%s\n",N.name); + for (int i = 0; i < cnt; i++) { + printf("%s%s%s\n",Part[index[i]],"-",Pad[index[i]]); + } + printf("%s\n",")"); + } + } + } + } diff --git a/trunk/ulp/netlist_protel.ulp.INF b/trunk/ulp/netlist_protel.ulp.INF new file mode 100644 index 00000000..0826d173 --- /dev/null +++ b/trunk/ulp/netlist_protel.ulp.INF @@ -0,0 +1,5 @@ +Name: Hans Lederer +Email: Hans.Lederer at ib-lederer.de +Organization: Ingenieurbuero Lederer +Description: +Generates a netlist in Protel Standard format (similar to Tango) diff --git a/trunk/ulp/nextdevdescript.ulp b/trunk/ulp/nextdevdescript.ulp new file mode 100644 index 00000000..b92daf60 --- /dev/null +++ b/trunk/ulp/nextdevdescript.ulp @@ -0,0 +1,43 @@ +#usage "Edit next device description\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string dev[]; +string edit = ""; +int count = 0; +int n = 0; + +if (library) library(L) { + L.devicesets(D) { + count++; + dev[count] = D.name; + cmd += D.name + "\n"; + } + } + +if (deviceset) deviceset(D) { + edit = D.name; + } + +for (n = 1; n < count; n++) { + if (edit == dev[n]) { + break; + } + } + +if (n < count) { + cmd = "EDIT " + dev[n + 1] + ".dev;\n DESCRIPT\n" ; + // ************************************************** + // a ";" must not follow DESCRIPT + // otherwise the description is overwritten + // with an empty string + // ************************************************** + + } +else + cmd = "EDIT " + dev[1] + ".dev;\n DESCRIPT\n" ; + +exit(cmd); diff --git a/trunk/ulp/nextpacdescript.ulp b/trunk/ulp/nextpacdescript.ulp new file mode 100644 index 00000000..7903ac4c --- /dev/null +++ b/trunk/ulp/nextpacdescript.ulp @@ -0,0 +1,44 @@ +#usage "Edit next package description\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string pac[]; +string edit = ""; +int count = 0; +int n = 0; + +if (library) library(L) { + L.packages(P) { + count++; + pac[count] = P.name; + cmd += P.name + "\n"; + } + } + +if (package) package(P) { + edit = P.name; + } + +for (n = 1; n < count; n++) { + if (edit == pac[n]) { + // dlgMessageBox(dev[n+1], "+Ok", "-Cancel"); + break; + } + } + +if (n < count) { + cmd = "EDIT " + pac[n + 1] + ".pac;\n DESCRIPT\n" ; + // ************************************************** + // a ";" must not follow DESCRIPT + // otherwise the description is overwritten + // with an empty string + // ************************************************** + + } +else + cmd = "EDIT " + pac[1] + ".pac;\n DESCRIPT\n" ; + +exit(cmd); diff --git a/trunk/ulp/normalize-text.ulp b/trunk/ulp/normalize-text.ulp new file mode 100644 index 00000000..a69336b6 --- /dev/null +++ b/trunk/ulp/normalize-text.ulp @@ -0,0 +1,245 @@ +#usage "Normalize silkscreen text sizes


    \n" + "

    This ULP program smashes all texts on the silkscreen layers. It then normalizes the " + "texts so that they all have the same size and thickness. Ratio is calculated from " + "the desired thickness.

    " + "Author: Tennessee Carmel-Veilleux (veilleux@ameth.org)" + +/**************************************************************************************** +* * +* Normalize silkscreen text sizes * +* * +* Filename: normalize-text.ulp * +* Version: 1.0 * +* Author: Tennessee Carmel-Veilleux * +* Date: March 31st 2005 * +* Company: Entreprises Ten Tech * +* * * +* This ULP program smashes all texts on the silkscreen layers. It then normalizes the * +* texts so that they all have the same size and thickness. Ratio is calculated from * +* the desired thickness. * +* * +****************************************************************************************/ + +#require 5.0300; + +string VERSION = "1.1"; // 2008-11-07 alf@cadsoft.de + +int result = 0; // Dialog result + +string str; // Temporary string +string cmd = "SET UNDO_LOG OFF;\n"; // Script command to execute +real text_size = 40.0; // Text size for all texts +real text_thickness = 8.0; // Text thickness for all texts +int text_ratio; // Calculated text ratio + +int silk_screen_layers[] = {LAYER_TPLACE, LAYER_BPLACE, LAYER_TNAMES, + LAYER_BNAMES, LAYER_TVALUES, LAYER_BVALUES, + LAYER_TDOCU, LAYER_BDOCU, 125, 126 }; + // 2008-11-07 Layer 125, 126 is created by panalize.ulp. + +enum {UNIT_MIL, UNIT_MM}; +int units = UNIT_MM; +int lastunit = units; +text_size = 1.0; +text_thickness = 0.1; + +int visibleLayer[]; +int actualvisible = 0; + + +/* ------------- UTILITY FUNCTIONS --------------- */ + +// +// Redisplays the layers that were visible when the ULP was started +// + +void ResetVisible(UL_BOARD B) { + sprintf(str, "DISP NONE;\nDISP "); + cmd += str; + B.layers(L) { + if (L.visible) { + sprintf(str, "%d ", L.number); + cmd += str; + } + } + cmd += ";\n"; +} + +// +// Returns 1 if a layer is a silkscreen layer +// + +int SilkScreenText(int layer) { + int i = 0; + int found = 0; + do { // 2008-11-07 + if (layer == silk_screen_layers[i]) { + found = 1; + if (actualvisible != layer) { // display only the layer with text to change + // in a script can not select texts by thew same coodiante + sprintf(str, "DISPLAY NONE %d;\n", layer); + cmd += str; + } + break; + } + i++; + } while(silk_screen_layers[i]); + + return found; +} + +// +// Resizes a text element to the specified size and ratio +// +void ResizeText(UL_TEXT T, real size, int ratio) { + if (SilkScreenText(T.layer)) { + switch (units) { + case UNIT_MIL: + sprintf(str,"CHANGE SIZE %.4f (%.4f %.4f);\nCHANGE RATIO %d (%.4f %.4f);\n", + size, u2mil(T.x), u2mil(T.y), ratio, u2mil(T.x), u2mil(T.y)); + break; + case UNIT_MM: + sprintf(str,"CHANGE SIZE %.4f (%.4f %.4f);\nCHANGE RATIO %d (%.4f %.4f);\n", + size, u2mm(T.x), u2mm(T.y), ratio, u2mm(T.x), u2mm(T.y)); + break; + } + cmd += str; + } +} + +// +// Smashes all parts that have an associated package on the board and resize +// all text to SIZE and RATIO. +// +void ProcessTexts(real size, int ratio) { + // Display the origins of components + switch (units) { + case UNIT_MIL: + sprintf(str,"GRID MIL 1;\n"); + break; + case UNIT_MM: + sprintf(str,"GRID MM 0.1;\n"); + break; + } + cmd += str; + + cmd += "DISPLAY NONE 23 24;\n"; + + board(B) { + B.elements(E) { + if (E.package) { + // Smash the package to make sure text is CHANGE-able + sprintf(str,"SMASH %s;\n", E.name); + cmd += str; + // Change smashed texts + E.texts(T) { + ResizeText(T, size, ratio); + } + + // Change unsmashed texts + E.package.texts(T) { + ResizeText(T, size, ratio); + } + } + } + + // Change all manually-added texts + B.texts(T) { + ResizeText(T, size, ratio); + } + + ResetVisible(B); + } + cmd += "GRID LAST;\nSET UNDO_LOG ON;\n"; +} + +/* ------------- MAIN ROUTINE --------------- */ +if (board) { + int actsize; + result = dlgDialog("Normalize silkscreen text sizes") { + sprintf(str,"

    Normalize silkscreen text sizes %s

    "+ + "

    By Tennessee Carmel-Veilleux (veilleux@ameth.org)

    "+ + "

    This ULP normalizes all the text on the silkscreen layers to "+ + "the specified size and thickness. The ratio is automatically calculated " + + "from the size and thickness.

    ", VERSION); + dlgLabel(str); + + // Options + dlgHBoxLayout { + dlgGroup("Output units") { + dlgRadioButton("m&il",units) { + if (lastunit != units) { + actsize = text_size*10000; // 2008-11-07 calculate the value in changed unit + text_size = u2mil(actsize); + actsize = text_thickness*10000; + text_thickness = u2mil(actsize); + lastunit = units; + } + } + dlgRadioButton("&mm",units) { + if (lastunit != units) { + actsize = text_size*(1/39.3701)*10000; + text_size = u2mm(actsize); + actsize = text_thickness*(1/39.3701)*10000; + text_thickness = u2mm(actsize); + lastunit = units; + } + } + } + dlgSpacing(20); + dlgGridLayout { + dlgCell(0,0) dlgLabel("Text size:"); + dlgCell(0,1) dlgRealEdit(text_size,0.1,2000.0); + + + dlgCell(1,0) dlgLabel("Text Thickness:"); + dlgCell(1,1) dlgRealEdit(text_thickness,0.01,500.0); + } + } + + // Buttons + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+Normalize") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; + + if (!result) exit(0); + + text_ratio = int(round((text_thickness / text_size) * 100.0)) + 1; + if (text_ratio > 31) { + text_ratio = 31; + dlgMessageBox("!

    Ratio clipped to 31 !

    "+ + "

    Make sure that text thickness is not too large for proper ratio.

    "); + } + if (units == UNIT_MM) { + if (text_size > 5.0) { + text_size = 5.0; + dlgMessageBox("!

    Text size clipped to 5.0mm !

    "); + } + } + ProcessTexts(text_size, text_ratio); + + + // EditBox + result = dlgDialog("Edit and execute script") { + dlgHBoxLayout { + dlgSpacing(500); // Force width of dialog to 500 + } + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+Execute") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; + + // Execute script if it was accepted + if (!result) + exit(0); + else + exit(cmd); +} else { + dlgMessageBox(":You must run this ULP in board !"); + exit(1); +} \ No newline at end of file diff --git a/trunk/ulp/outlines.ulp b/trunk/ulp/outlines.ulp new file mode 100644 index 00000000..ce8c6d2c --- /dev/null +++ b/trunk/ulp/outlines.ulp @@ -0,0 +1,430 @@ +#require 4.1105 + +#usage "en: Export outlines data\n" + "

    " + "Generates outlines data for a board layout." + "

    " + "Usage: RUN outlines [ device [ width [ layer [ filename ]]]]" + "

    " + "" + "" + "" + "" + "" + "
    device:Script | HPGL
    width:outlines width [mm]
    layer:1..16 (0 = active layer)
    filename:output file name
    " + "

    " + "Author: support@cadsoft.de", + "de: Konturdaten exportieren\n" + "

    " + "Erzeugt Konturdaten für ein Platinenlayout." + "

    " + "Aufruf: RUN outlines [ device [ width [ layer [ filename ]]]]" + "

    " + "" + "" + "" + "" + "" + "
    device:Script | HPGL
    width:Breite der Konturlinien [mm]
    layer:1..16 (0 = aktiver Layer)
    filename:Ausgabedatei
    " + "

    " + "Autor: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +/* + Complete the following steps to add a new output device definition: + + 1. Add a new member to the 'enum { devScript = 1, ...' + 2. Add the new (unique!) device name to 'DeviceNames[]' + 3. Add the necessary 'case dev...' branches to 'DeviceInit()', 'DeviceDraw()' and 'DeviceEnd()' +*/ + +string I18N[] = { + "en\v" + "de\v" + , + "ERROR: \v" + "FEHLER: \v" + , + "No board!\v" + "Kein Board!\v" + , + "This program can only work in the board editor.\v" + "Dieses Programm kann nur im Board-Editor angewendet werden.\v" + , + "Illegal width: \v" + "Ungültige Breite: \v" + , + "The width must be greater than zero.\v" + "Die Breite muß größer als 0 sein.\v" + , + "Illegal layer: \v" + "Ungültiger Layer: \v" + , + "The layer must be one of 1..16 or 0 to use the current layer.\v" + "Der Layer muß im Bereich 1..16 liegen, oder 0 sein um den aktuellen Layer zu wählen.\v" + , + "Select a device\v" + "Wählen Sie ein Ausgabegerät\v" + , + "There is already a signal named \v" + "Es existiert bereits ein Signal namens \v" + , + " in this board!\v" + " in diesem Board!\v" + , + "Please make sure that there is no such signal in this board.\v" + "Bitte sorgen Sie dafür, daß es kein solches Signal in diesem Board gibt.\v" + , + "Illegal device: \v" + "Ungültiges Ausgabegerät: \v" + , + "Please select one of the known devices.\v" + "Bitte wählen Sie eines der bekannten Ausgabegeräte aus.\v" + , + "No signal layer active!\v" + "Kein Signal-Layer aktiv!\v" + , + "Please activate the signal layer to generate outlines for.\v" + "Bitte aktivieren den Signal-Layer für den Konturdaten generiert werden sollen.\v" + , + "Invalid layer: \v" + "Ungültiger Layer: \v" + , + "The layer was not found or is not active.\v" + "Der Layer konnte nicht gefunden werden oder ist nicht aktiv.\v" + , + "Outlines Generator\v" + "Konturdaten-Generator\v" + , + "&Width\v" + "&Breite\v" + , + "&Layer\v" + "&Layer\v" + , + "&Output file\v" + "&Ausgabedatei\v" + , + "&Browse\v" + "&Durchsuchen\v" + , + "Save Outlines file\v" + "Konturdaten speichern\v" + , + "+OK\v" + "+OK\v" + , + "No device selected!\v" + "Kein Ausgabegerät ausgewählt!\v" + , + "Please select a device.\v" + "Bitte wählen Sie ein Ausgabegerät.\v" + , + "Illegal width: 0\v" + "Ungültige Breite: 0\v" + , + "The width must be greater than zero.\v" + "Die Breite muß größer als Null sein.\v" + , + "-Cancel\v" + "-Abbrechen\v" + , + "About\v" + "Info\v" + }; + +int Language = strstr(I18N[0], language()) / 3; + +string tr(string s) +{ + string t = lookup(I18N, s, Language, '\v'); + return t ? t : s; +} + +void Fatal(string Message, string Details) +{ + dlgMessageBox(usage + "


    " + tr("ERROR: ") + Message + "

    \n" + Details); + exit(1); +} + +void Error(string Message, string Details) +{ + dlgMessageBox("" + tr("ERROR: ") + Message + "

    \n" + Details); +} + +// +// Parmameters +// + +string DefaultSuffix = ".out"; + +string Device; +real Width = 0; +int Layer = 0; +string FileName; + +if (!board) + Fatal(tr("No board!"), tr("This program can only work in the board editor.")); + +if (argv[1]) { + Device = argv[1]; + if (argv[2]) { + Width = strtod(argv[2]); + if (Width <= 0) + Fatal(tr("Illegal width: ") + argv[2], tr("The width must be greater than zero.")); + if (argv[3]) { + Layer = strtol(argv[3]); + if (Layer < 0 || Layer > 16) + Fatal(tr("Illegal layer: ") + argv[3], tr("The layer must be one of 1..16 or 0 to use the current layer.")); + if (argv[4]) { + FileName = argv[4]; + } + } + } + } + +if (!FileName) + board(B) FileName = filesetext(B.name, DefaultSuffix); + +// +// The various output devices +// + +enum { devScript = 1, devHPGL }; +string DeviceNames[] = { tr("Select a device"), "Script", "HPGL" }; +int SelectedDevice; + +void DeviceInit(void) +{ + // Do anything necessary to initialize the output device + switch (SelectedDevice) { + case devScript: + // TODO make the layer user definable? + printf("layer %d;\nset wire_bend 2; grid mm; change width %f;\n", Layer + 100, Width); + break; + case devHPGL: + break; + } +} + +void DeviceDraw(int x1, int y1, int x2, int y2, int state) +{ + // Actually draw a line on the output device. + // 'state' is defined as + // 0 = this is the first line of a partial polygon + // 1 = this is a "normal" line (neither the first nor the last one) + // 2 = this is the last line of a partial polygon + switch (SelectedDevice) { + case devScript: + if (state == 0) + printf("wire (%f %f) (%f %f)", u2mm(x1), u2mm(y1), u2mm(x2), u2mm(y2)); + else { + printf(" (%f %f)", u2mm(x2), u2mm(y2)); + if (state == 2) + printf(";\n"); + } + break; + case devHPGL: + if (state == 0) + printf("PU; PA %f %f; PD; PA %f %f;", u2mm(x1), u2mm(y1), u2mm(x2), u2mm(y2)); + else { + printf(" PA %f %f", u2mm(x2), u2mm(y2)); + if (state == 2) + printf("\n"); + } + break; + } +} + +void DeviceEnd(void) +{ + // Do anything necessary to end output to the device + switch (SelectedDevice) { + case devScript: + break; + case devHPGL: + printf("PU;\n"); + break; + } +} + +// +// The actual outlines generator +// + +string OutlinesSignalName = "_OUTLINES_"; +string Pass2 = "PASS_2"; + +int InPass2 = argv[5] == Pass2; + +void GenerateOutlines(void) +{ + board(B) { + real f = 20, // mm frame + x1 = u2mm(B.area.x1) - f, y1 = u2mm(B.area.y1) - f, + x2 = u2mm(B.area.x2) + f, y2 = u2mm(B.area.y2) + f; + B.signals(S) { + if (S.name == OutlinesSignalName) + Fatal(tr("There is already a signal named ") + OutlinesSignalName + tr(" in this board!"), tr("Please make sure that there is no such signal in this board.")); + } + string Cmd; + sprintf(Cmd, "grid mm;\n" + "window fit;\n" + "change isolate 0;\n" + "change rank 6;\n" + "change pour solid;\n" + "change orphans on;\n" + "layer %d;\n" + "polygon %s %f (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n" + "ratsnest;\n" + "run '%s' '%s' '%f' '%d' '%s' '%s';", + Layer, + OutlinesSignalName, Width, x1, y1, x2, y1, x2, y2, x1, y2, x1, y1, + argv[0], Device, Width, Layer, FileName, Pass2); + exit(Cmd); + } +} + +void WriteOutlines(void) +{ + board(B) { + output(FileName) { + string Cmd; + B.signals(S) { + if (S.name == OutlinesSignalName) { + S.polygons(P) { + int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN; + int x0, y0, first = 1; + int FrameWire; + int State; + + P.wires(W) { + x1 = min(x1, W.x1); + x2 = max(x2, W.x1); + y1 = min(y1, W.y1); + y2 = max(y2, W.y1); + } + DeviceInit(); + P.contours(W) { + if (first) { + // a new partial polygon is starting + x0 = W.x1; + y0 = W.y1; + FrameWire = (x1 == x0 || x2 == x0) && (y1 == y0 || y2 == y0); + State = 0; + first = 0; + } + else if (W.x2 == x0 && W.y2 == y0) { + // this was the last wire of the partial polygon, + // so the next wire (if any) will be the first wire + // of the next partial polygon + State = 2; + first = 1; + } + else + State = 1; + if (!FrameWire) + DeviceDraw(W.x1, W.y1, W.x2, W.y2, State); + } + DeviceEnd(); + sprintf(Cmd, "delete (%f %f) (%f %f); window fit;\n", u2mm(x1), u2mm(y1), u2mm(x2), u2mm(y2)); + } + break; + } + } + exit(Cmd); + } + } +} + +// +// Main program: +// + +if (Device) { + int n; + while (DeviceNames[n]) { + if (strupr(DeviceNames[n]) == strupr(Device)) { + SelectedDevice = n; + break; + } + n++; + } + if (!SelectedDevice) + Fatal(tr("Illegal device: ") + Device, tr("Please select one of the known devices.")); + } + +if (!InPass2) { + string Layers[]; + int SelectedLayer = -1; + int ForceDialog = (!Device || !Width); + + board(B) { + int n; + B.layers(L) { + if (L.number <= 16 && L.visible) { + if (Layer == L.number) + SelectedLayer = n; + sprintf(Layers[n++], "%d %s", L.number, L.name); + } + } + if (n == 0) + Fatal(tr("No signal layer active!"), tr("Please activate the signal layer to generate outlines for.")); + if (!Layer) { + if (n > 1) + ForceDialog = 1; + SelectedLayer = 0; + } + if (SelectedLayer < 0) { + string s; + sprintf(s, "%d", Layer); + Fatal(tr("Invalid layer: ") + s, tr("The layer was not found or is not active.")); + } + } + + if (ForceDialog) { + dlgDialog(tr("Outlines Generator")) { + dlgGridLayout { + dlgCell(0, 0) dlgLabel("&Device"); + dlgCell(0, 1) dlgComboBox(DeviceNames, SelectedDevice) { + // TODO should we generalize this? + if (FileName && SelectedDevice == devScript) + FileName = filesetext(FileName, ".scr"); + } + dlgCell(1, 0) dlgLabel(tr("&Width")); + dlgCell(1, 1) dlgRealEdit(Width, 0, 10); + dlgCell(2, 0) dlgLabel(tr("&Layer")); + dlgCell(2, 1) dlgComboBox(Layers, SelectedLayer); + } + dlgHBoxLayout { + dlgLabel(tr("&Output file")); + dlgStringEdit(FileName); + dlgPushButton(tr("&Browse")) { + string fn = dlgFileSave(tr("Save Outlines file"), FileName); + if (fn) + FileName = fn; + } + } + dlgStretch(1); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton(tr("+OK")) { + if (!SelectedDevice) + Error(tr("No device selected!"), tr("Please select a device.")); + else if (!Width) + Error(tr("Illegal width: 0"), tr("The width must be greater than zero.")); + else + dlgAccept(); + } + dlgPushButton(tr("-Cancel")) { dlgReject(); exit(1); } + dlgPushButton(tr("About")) dlgMessageBox(usage); + } + }; + } + Device = DeviceNames[SelectedDevice]; + Layer = strtol(Layers[SelectedLayer]); + GenerateOutlines(); + } +else + WriteOutlines(); diff --git a/trunk/ulp/panelize.ulp b/trunk/ulp/panelize.ulp new file mode 100644 index 00000000..486d5b19 --- /dev/null +++ b/trunk/ulp/panelize.ulp @@ -0,0 +1,131 @@ +#usage "Generate name layers to panelize board\n" + "

    " + "Generates a command sequence which copies the name texts (support spin-flag) " + "of all elements of your layout into newly generated layers (125 and 126). " + "After running the ULP you can GROUP, CUT and PASTE your layout " + "to get an array of several boards. Make sure all layers are displayed before." + "

    " + "The duplicated name texts in the new layers will not be changed. " + "Please notice that you have to deactivate layers 25 and 26 if you use " + "the CAM processor e.g. for generating gerber data. Instead, you have to activate " + "the new layers 125 and 126. Thus you get an identical silk screen for all " + "your layouts in this array." + "

    " + "Texts must be SMASHed before we can duplicate them! " + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#require 4.1106; + +// 6.12.2004 Text with Spin-Flag support@cadsoft.de +// 28.06.2006 accept Sigle-Quote on end of name of element support@cadsoft.de + +int offset = 100; +string tcolor = "yellow"; +string bcolor = "magenta"; +int used_name_layers[]; +string used_name_[]; + +string cmd_header; +string cmd = "\nSET UNDO_LOG OFF;\nGRID MIL;\n"; // advisable for speed reasons +string h; + +string check_single_quote(string s) { // 2006.06.28 + int l = strlen(s); + if (s[l-1] == '\'') s+="'"; + return s; +} + +void test(void) { + string txt = "Used Layers for >NAME\n"; + for (int n = 0; n < 256; n++) { + if(used_name_layers[n]) { + sprintf(h, "Layer %3d count %d\t%s\n", n, used_name_layers[n], used_name_[n]); + txt += h; + } + } + if (dlgMessageBox(txt, "OK", "Cancel") != 0) exit(-1); + return; +} + +void header(void) { + for (int n = 0; n < 256; n++) { + if(used_name_layers[n]) { + sprintf(h, "layer %d _%s;\n", n + offset, used_name_[n]); + cmd_header += h; + if (n & 1) sprintf(h, "set color_layer %d %s;\n", n + offset, tcolor); + else sprintf(h, "set color_layer %d %s;\n", n + offset, bcolor); + cmd_header += h; + } + } +} + +void Text(string Ename, int Tlayer, int Tx, int Ty, int Tsize, real Tangle, int Tratio, int Tmirror, int Tspin) { + sprintf(h, "Change Layer %d;\n", Tlayer + offset); + cmd += h; + sprintf(h, "Change Size %5.3f;\n", u2mil(Tsize)); + cmd += h; + sprintf(h, "Change Ratio %d;\n", Tratio); + cmd += h; + string mirr, spin; + if (Tmirror) mirr = "M"; + else mirr = ""; + if (Tspin) spin = "S"; + else spin = ""; + sprintf(h, "Text '%s' %s%sR%.1f (%5.3f %5.3f);\n", check_single_quote(Ename), spin, mirr, Tangle, u2mil(Tx), u2mil(Ty)); + cmd += h; + return; +} + + + +if (board) { + board(B) { + B.layers(L) { + used_name_[L.number] = L.name; + } + header(); + B.elements(E) { // smashed texts + E.texts(T) { + if (T.value == E.name) { + used_name_layers[T.layer]++; + Text(E.name, T.layer, T.x, T.y, T.size, T.angle, T.ratio, T.mirror, T.spin); + } + } + E.package.texts(T) { // unsmashed texts + if (T.value == E.name) { + used_name_layers[T.layer]++; + Text(E.name, T.layer, T.x, T.y, T.size, T.angle, T.ratio, T.mirror, T.spin); + } + } + } + } + // test(); + + cmd += "SET UNDO_LOG ON;\nGRID LAST;\n"; + header(); + cmd_header += cmd; + cmd = cmd_header; + + // EditBox + int Result = dlgDialog("Descriptions") { + dlgHBoxLayout { + dlgVBoxLayout { dlgSpacing(500); } + dlgTextEdit(cmd); + } + dlgHBoxLayout { + dlgPushButton("+Execute") dlgAccept(); + dlgSpacing(100); + dlgPushButton("-Cancel") dlgReject(); + } + }; + if (Result == 0) exit(0); + exit(cmd); +} + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); +} diff --git a/trunk/ulp/part2html.ulp b/trunk/ulp/part2html.ulp new file mode 100644 index 00000000..f7fe8a9c --- /dev/null +++ b/trunk/ulp/part2html.ulp @@ -0,0 +1,58 @@ +#usage "Export an HTML partlist\n" + "

    " + "Generates an HTML file of a board's partlist for publishing on an intranet." + "

    " + "Author: Sean D. Alcorn (SYD)
    Extended by support@cadsoft.de
    " + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +if (board) board(B) { + string fileName = dlgFileSave("Save File", filesetext(B.name, ".htm"), "*.htm"); + if (fileName == "") exit(0); + output(fileName) { + printf("\n\n"); + printf("\n"); + printf("\n"); + printf("\n"); + printf("Parts Listing for %s\n", B.name); + printf("\n\n"); + printf("\n\n"); + printf("

    Parts List for

    \n\n"); + printf("

    %s

    \n", B.name); + printf("
    \n\n"); + printf("
    \n"); + printf("

    Parts Listing

    \n"); + printf("
    \n"); + printf("
    \n\n"); + printf("\n"); + printf(" \n"); + printf(" \n"); + printf(" \n"); + printf(" \n"); + printf(" \n"); + printf(" \n"); + + B.elements(E) { + + printf(" \n"); + printf("\n", E.name); + printf("\n", E.value); + printf("\n", E.package.name); + printf("\n", E.package.library); + printf(" \n"); + } + printf("
    PartValuePackageLibrary
    %s%s%s%s
    \n"); + printf("
    \n\n"); + printf("

    \n\n"); + printf("
    \n"); + printf("

    Generated by PART2HTM v0.4 by Sean D. Alcorn
    \n"); + printf(" © 1997
    Avion\n"); + printf(" International Co. Ltd.
    \n"); + printf(" Bangkok • Sydney • Taipei

    \n"); + printf("
    \n"); + printf("\n"); + printf(""); + } + } diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/README b/trunk/ulp/pcb-gcode-3.6.0.4/README new file mode 100644 index 00000000..dbce6f21 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/README @@ -0,0 +1 @@ +Please see docs/pcbgcode.pdf. diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/artistic-license.txt b/trunk/ulp/pcb-gcode-3.6.0.4/docs/artistic-license.txt new file mode 100644 index 00000000..eb310598 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/artistic-license.txt @@ -0,0 +1,51 @@ +The Artistic License + +Preamble + +The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. + +Definitions: + +"Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. +"Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. +"Copyright Holder" is whoever is named in the copyright or copyrights for the package. +"You" is you, if you're thinking about copying or distributing this Package. +"Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) +"Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. + +1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. + +2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. + +3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: + +a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. + +b) use the modified Package only within your corporation or organization. + +c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. + +d) make other distribution arrangements with the Copyright Holder. + +4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: + +a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. + +b) accompany the distribution with the machine-readable source of the Package with your modifications. + +c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. + +d) make other distribution arrangements with the Copyright Holder. + +5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. + +6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. + +7. User Language Program subroutines and GCODE supplied by you and linked into this Package shall not be considered part of this Package. + +8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. + +9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +The End + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/changelog.txt b/trunk/ulp/pcb-gcode-3.6.0.4/docs/changelog.txt new file mode 100644 index 00000000..a7d3a08a --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/changelog.txt @@ -0,0 +1,29 @@ +3.6.0.4 16-Jan-2013 John +Forgot to bump version numbers in ULPs. +Forgot to update changelog.txt. +I think the rakefile is finally creating the .zip file correctly. + +3.6.0.3 John +Went back to the old way of determining the path after the new way crashed and burned on Windows if there were spaces in the path (which is nearly always). + +3.6.0.2 02-Jan-2013 John +Moved pcbgcode.pdf and pcbgcode.tex into the docs folder. +Removed old documentation. + +Zip file now does not contain docs/figs/*, to save ~2MB in file size. + +Zip is now created in a pcb-gcode-version folder so files will unarchive into a folder. + +3.6.0.1 16-Dec-2012 John +Changed math.h to work with Eagle 5 or 6. Updated math.ulp to perform more tests on math.h to ensure conversions work correctly. + +Removed progress menu options in pcb-gcode-setup.ulp, as no one uses them, and it can confuse new users. + +Changed Isolation|Default label to Minimum. Globally changed DEFAULT_ISOLATE variable to ISO_MIN. + +Added a drill sub for the examples/04151_lcdi2c.drl file so it wouldn't complain about the 0.086in drill. +Added name of drill rack file to drill not found message in drill.h. + +Added a Single pass option. Maximum and Step size labels are changed to "not used" when Single pass is on. + +The path to pcb-gcode is no longer required to be the first entry in Eagle's Control Panel | Options | Directories. Should save some new users some trouble. diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.drill.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.drill.tap new file mode 100644 index 00000000..c7d06ace --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.drill.tap @@ -0,0 +1,130 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +( Tool| Size | Min Sub | Max Sub | Count ) +( T02 | 0.813mm 0.0320in | 0.0320in | 0.0320in | 49 ) +( T03 | 1.016mm 0.0400in | 0.0400in | 0.0400in | 17 ) +( T06 | 2.159mm 0.0850in | 0.0850in | 0.1250in | 5 ) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T02 ; 0.0320 +G01 Z0.0000 F10 +M06 T01 ; 0.0320 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.4100 Y1.0000 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.5100 Y1.0000 +G82 X-0.6000 Y0.2700 +G82 X-0.7234 Y0.6709 +G82 X-0.7628 Y0.7891 +G82 X-0.8000 Y0.3700 +G82 X-0.8021 Y0.6709 +G82 X-0.8415 Y0.7891 +G82 X-0.8809 Y0.6709 +G82 X-0.9202 Y0.7891 +G82 X-1.1000 Y0.2700 +G82 X-1.1300 Y1.1800 +G82 X-1.2300 Y1.1800 +G82 X-1.2700 Y0.2300 +G82 X-1.2700 Y0.3400 +G82 X-1.2700 Y0.4400 +G82 X-1.2700 Y0.5400 +G82 X-1.2700 Y0.6400 +G82 X-1.2700 Y0.7400 +G82 X-1.2700 Y0.8400 +G82 X-1.2700 Y0.9400 +G82 X-1.2700 Y1.0400 +G82 X-1.3700 Y0.2300 +G82 X-1.3900 Y1.1700 +G82 X-1.4400 Y1.2450 +G82 X-1.4900 Y1.1700 +G82 X-1.5700 Y0.3400 +G82 X-1.5700 Y0.4400 +G82 X-1.5700 Y0.5400 +G82 X-1.5700 Y0.6400 +G82 X-1.5700 Y0.7400 +G82 X-1.5700 Y0.8400 +G82 X-1.5700 Y0.9400 +G82 X-1.5700 Y1.0400 +G82 X-1.7500 Y1.1200 +G82 X-1.7500 Y1.2200 +G82 X-1.8000 Y0.4800 +G82 X-1.8000 Y0.6800 +G82 X-1.8500 Y0.1500 +G82 X-1.8500 Y0.2500 +G82 X-1.8500 Y0.3500 +G82 X-1.9200 Y0.4800 +G82 X-1.9200 Y0.6800 +G82 X-2.0400 Y0.4800 +G82 X-2.0400 Y0.6800 +G82 X-2.1500 Y0.1500 +G82 X-2.1500 Y0.2500 +G82 X-2.1500 Y0.3500 +M05 +G00 Z1.0000 +M06 T03 ; 0.0400 +G01 Z0.0000 F10 +M06 T02 ; 0.0400 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.1900 Y0.4000 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.1900 Y0.5000 +G82 X-0.1900 Y0.6000 +G82 X-0.1900 Y0.7000 +G82 X-0.1900 Y0.8000 +G82 X-0.1900 Y0.9000 +G82 X-0.1900 Y1.0000 +G82 X-0.2900 Y0.4000 +G82 X-0.2900 Y0.5000 +G82 X-0.2900 Y0.6000 +G82 X-0.2900 Y0.7000 +G82 X-0.2900 Y0.8000 +G82 X-0.2900 Y0.9000 +G82 X-0.2900 Y1.0000 +G82 X-2.0000 Y1.0300 +G82 X-2.3000 Y1.0300 +M05 +G00 Z1.0000 +M06 T06 ; 0.0850 +G01 Z0.0000 F10 +M06 T03 ; 0.0850 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.1500 Y0.1300 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.1500 Y1.1900 +G82 X-0.5029 Y0.7576 +G82 X-1.1171 Y0.7576 +T01 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.etch.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.etch.tap new file mode 100644 index 00000000..bdc5ffd2 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.etch.tap @@ -0,0 +1,5982 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-1.3311 Y0.8601 +G01 Z-0.0070 F10 +G01 X-1.3211 Y0.8701 F20 +G01 X-1.3081 Y0.8755 +G01 X-1.2319 Y0.8755 +G01 X-1.2189 Y0.8701 +G01 X-1.2089 Y0.8601 +G01 X-1.2085 Y0.8592 +G01 X-1.1552 Y0.9125 +G01 X-1.1448 Y0.9125 +G01 X-0.4948 Y0.9125 +G01 X-0.4875 Y0.9052 +G01 X-0.3448 Y0.7625 +G01 X-0.3084 Y0.7625 +G01 X-0.3295 Y0.7836 +G01 X-0.3295 Y0.7875 +G01 X-0.3301 Y0.7875 +G01 X-0.3303 Y0.7873 +G01 X-0.3352 Y0.7875 +G01 X-0.3402 Y0.7875 +G01 X-0.3404 Y0.7877 +G01 X-0.3406 Y0.7877 +G01 X-0.3440 Y0.7913 +G01 X-0.3475 Y0.7948 +G01 X-0.3475 Y0.7951 +G01 X-0.4704 Y0.9275 +G01 X-1.2058 Y0.9275 +G01 X-1.2089 Y0.9199 +G01 X-1.2189 Y0.9099 +G01 X-1.2319 Y0.9045 +G01 X-1.3081 Y0.9045 +G01 X-1.3211 Y0.9099 +G01 X-1.3311 Y0.9199 +G01 X-1.3325 Y0.9233 +G01 X-1.3325 Y0.8567 +G01 X-1.3311 Y0.8601 +G00 Z0.1000 +G00 X-0.1702 Y0.5365 +G01 Z-0.0070 F10 +G01 X-0.1710 Y0.5368 F20 +G01 X-0.1525 Y0.5184 +G01 X-0.1525 Y0.5435 +G01 X-0.1630 Y0.5394 +G01 X-0.1648 Y0.5375 +G01 X-0.1676 Y0.5375 +G01 X-0.1702 Y0.5365 +G00 Z0.1000 +G00 X-0.2084 Y0.8625 +G01 Z-0.0070 F10 +G01 X-0.2295 Y0.8836 F20 +G01 X-0.2295 Y0.9164 +G01 X-0.2268 Y0.9191 +G01 X-0.2452 Y0.9375 +G01 X-0.2716 Y0.9375 +G01 X-0.2505 Y0.9164 +G01 X-0.2505 Y0.8836 +G01 X-0.2532 Y0.8809 +G01 X-0.2348 Y0.8625 +G01 X-0.2084 Y0.8625 +G00 Z0.1000 +G00 X-0.2295 Y0.6836 +G01 Z-0.0070 F10 +G01 X-0.2295 Y0.7164 F20 +G01 X-0.2064 Y0.7395 +G01 X-0.1736 Y0.7395 +G01 X-0.1505 Y0.7164 +G01 X-0.1505 Y0.6836 +G01 X-0.1641 Y0.6700 +G01 X-0.1425 Y0.6862 +G01 X-0.1425 Y0.8137 +G01 X-0.1641 Y0.8299 +G01 X-0.1505 Y0.8164 +G01 X-0.1505 Y0.7836 +G01 X-0.1736 Y0.7605 +G01 X-0.2064 Y0.7605 +G01 X-0.2091 Y0.7632 +G01 X-0.2275 Y0.7448 +G01 X-0.2348 Y0.7375 +G01 X-0.2716 Y0.7375 +G01 X-0.2505 Y0.7164 +G01 X-0.2505 Y0.6836 +G01 X-0.2716 Y0.6625 +G01 X-0.2084 Y0.6625 +G01 X-0.2295 Y0.6836 +G00 Z0.1000 +G00 X-0.2505 Y0.6164 +G01 Z-0.0070 F10 +G01 X-0.2505 Y0.5836 F20 +G01 X-0.2716 Y0.5625 +G01 X-0.2084 Y0.5625 +G01 X-0.2295 Y0.5836 +G01 X-0.2295 Y0.6164 +G01 X-0.2084 Y0.6375 +G01 X-0.2716 Y0.6375 +G01 X-0.2505 Y0.6164 +G00 Z0.1000 +G00 X-0.2064 Y0.4395 +G01 Z-0.0070 F10 +G01 X-0.1736 Y0.4395 F20 +G01 X-0.1525 Y0.4184 +G01 X-0.1525 Y0.4816 +G01 X-0.1736 Y0.4605 +G01 X-0.2064 Y0.4605 +G01 X-0.2091 Y0.4632 +G01 X-0.2275 Y0.4448 +G01 X-0.2275 Y0.4184 +G01 X-0.2064 Y0.4395 +G00 Z0.1000 +G00 X-1.5319 Y0.7045 +G01 Z-0.0070 F10 +G01 X-1.6081 Y0.7045 F20 +G01 X-1.6211 Y0.7099 +G01 X-1.6311 Y0.7199 +G01 X-1.6322 Y0.7225 +G01 X-1.6398 Y0.7225 +G01 X-1.6475 Y0.7148 +G01 X-1.6475 Y0.5748 +G01 X-1.6548 Y0.5675 +G01 X-1.6848 Y0.5375 +G01 X-1.6952 Y0.5375 +G01 X-2.0648 Y0.5375 +G01 X-2.0975 Y0.5048 +G01 X-2.0975 Y0.4702 +G01 X-2.0548 Y0.4275 +G01 X-2.0248 Y0.4275 +G01 X-2.0175 Y0.4202 +G01 X-1.9975 Y0.4002 +G01 X-1.9975 Y0.3898 +G01 X-1.9975 Y0.1852 +G01 X-1.9048 Y0.0925 +G01 X-0.5402 Y0.0925 +G01 X-0.2525 Y0.3802 +G01 X-0.2525 Y0.3816 +G01 X-0.2736 Y0.3605 +G01 X-0.3064 Y0.3605 +G01 X-0.3091 Y0.3632 +G01 X-0.5675 Y0.1048 +G01 X-0.5748 Y0.0975 +G01 X-1.4548 Y0.0975 +G01 X-1.4652 Y0.0975 +G01 X-1.5025 Y0.1348 +G01 X-1.5025 Y0.1452 +G01 X-1.5025 Y0.6194 +G01 X-1.5029 Y0.6240 +G01 X-1.5025 Y0.6245 +G01 X-1.5025 Y0.6252 +G01 X-1.4992 Y0.6284 +G01 X-1.4775 Y0.6545 +G01 X-1.4775 Y0.7953 +G01 X-1.5057 Y0.8275 +G01 X-1.5089 Y0.8199 +G01 X-1.5189 Y0.8099 +G01 X-1.5319 Y0.8045 +G01 X-1.6081 Y0.8045 +G01 X-1.6211 Y0.8099 +G01 X-1.6311 Y0.8199 +G01 X-1.6365 Y0.8329 +G01 X-1.6365 Y0.8471 +G01 X-1.6311 Y0.8601 +G01 X-1.6211 Y0.8701 +G01 X-1.6081 Y0.8755 +G01 X-1.5319 Y0.8755 +G01 X-1.5189 Y0.8701 +G01 X-1.5089 Y0.8601 +G01 X-1.5058 Y0.8525 +G01 X-1.5047 Y0.8525 +G01 X-1.5043 Y0.8528 +G01 X-1.4996 Y0.8525 +G01 X-1.4948 Y0.8525 +G01 X-1.4945 Y0.8522 +G01 X-1.4940 Y0.8521 +G01 X-1.4909 Y0.8485 +G01 X-1.4875 Y0.8452 +G01 X-1.4875 Y0.8447 +G01 X-1.4559 Y0.8086 +G01 X-1.4525 Y0.8052 +G01 X-1.4525 Y0.8047 +G01 X-1.4522 Y0.8043 +G01 X-1.4525 Y0.7996 +G01 X-1.4525 Y0.6506 +G01 X-1.4521 Y0.6460 +G01 X-1.4525 Y0.6455 +G01 X-1.4525 Y0.6448 +G01 X-1.4558 Y0.6416 +G01 X-1.4775 Y0.6155 +G01 X-1.4775 Y0.1452 +G01 X-1.4548 Y0.1225 +G01 X-0.5852 Y0.1225 +G01 X-0.3268 Y0.3809 +G01 X-0.3295 Y0.3836 +G01 X-0.3295 Y0.4164 +G01 X-0.3064 Y0.4395 +G01 X-0.2736 Y0.4395 +G01 X-0.2525 Y0.4184 +G01 X-0.2525 Y0.4448 +G01 X-0.2525 Y0.4552 +G01 X-0.2268 Y0.4809 +G01 X-0.2295 Y0.4836 +G01 X-0.2295 Y0.5164 +G01 X-0.2084 Y0.5375 +G01 X-0.2716 Y0.5375 +G01 X-0.2505 Y0.5164 +G01 X-0.2505 Y0.4836 +G01 X-0.2736 Y0.4605 +G01 X-0.3064 Y0.4605 +G01 X-0.3091 Y0.4632 +G01 X-0.3675 Y0.4048 +G01 X-0.3675 Y0.3648 +G01 X-0.3748 Y0.3575 +G01 X-0.5975 Y0.1348 +G01 X-0.6048 Y0.1275 +G01 X-1.4252 Y0.1275 +G01 X-1.4325 Y0.1348 +G01 X-1.4625 Y0.1648 +G01 X-1.4625 Y0.1752 +G01 X-1.4625 Y0.5991 +G01 X-1.4631 Y0.6034 +G01 X-1.4625 Y0.6042 +G01 X-1.4625 Y0.6052 +G01 X-1.4595 Y0.6082 +G01 X-1.4475 Y0.6242 +G01 X-1.4475 Y0.8251 +G01 X-1.4955 Y0.8775 +G01 X-1.6148 Y0.8775 +G01 X-1.6375 Y0.8548 +G01 X-1.6375 Y0.8152 +G01 X-1.6248 Y0.8025 +G01 X-1.5029 Y0.8025 +G01 X-1.5010 Y0.8035 +G01 X-1.4980 Y0.8025 +G01 X-1.4948 Y0.8025 +G01 X-1.4932 Y0.8009 +G01 X-1.4911 Y0.8002 +G01 X-1.4897 Y0.7974 +G01 X-1.4875 Y0.7952 +G01 X-1.4875 Y0.7929 +G01 X-1.4847 Y0.7874 +G01 X-1.4825 Y0.7852 +G01 X-1.4825 Y0.7829 +G01 X-1.4815 Y0.7810 +G01 X-1.4825 Y0.7780 +G01 X-1.4825 Y0.6706 +G01 X-1.4821 Y0.6660 +G01 X-1.4825 Y0.6655 +G01 X-1.4825 Y0.6648 +G01 X-1.4858 Y0.6616 +G01 X-1.5035 Y0.6403 +G01 X-1.5035 Y0.6329 +G01 X-1.5089 Y0.6199 +G01 X-1.5189 Y0.6099 +G01 X-1.5319 Y0.6045 +G01 X-1.6081 Y0.6045 +G01 X-1.6211 Y0.6099 +G01 X-1.6311 Y0.6199 +G01 X-1.6365 Y0.6329 +G01 X-1.6365 Y0.6471 +G01 X-1.6311 Y0.6601 +G01 X-1.6211 Y0.6701 +G01 X-1.6081 Y0.6755 +G01 X-1.5319 Y0.6755 +G01 X-1.5189 Y0.6701 +G01 X-1.5147 Y0.6659 +G01 X-1.5075 Y0.6745 +G01 X-1.5075 Y0.7233 +G01 X-1.5089 Y0.7199 +G01 X-1.5189 Y0.7099 +G01 X-1.5319 Y0.7045 +G00 Z0.1000 +G00 X-1.5319 Y0.3045 +G01 Z-0.0070 F10 +G01 X-1.5878 Y0.3045 F20 +G01 X-1.7407 Y0.1516 +G01 X-1.7436 Y0.1481 +G01 X-1.7443 Y0.1480 +G01 X-1.7448 Y0.1475 +G01 X-1.7494 Y0.1475 +G01 X-1.7835 Y0.1441 +G01 X-1.7835 Y0.1429 +G01 X-1.7889 Y0.1299 +G01 X-1.7989 Y0.1199 +G01 X-1.8119 Y0.1145 +G01 X-1.8881 Y0.1145 +G01 X-1.9011 Y0.1199 +G01 X-1.9111 Y0.1299 +G01 X-1.9165 Y0.1429 +G01 X-1.9165 Y0.1571 +G01 X-1.9163 Y0.1575 +G01 X-1.9746 Y0.2075 +G01 X-1.9752 Y0.2075 +G01 X-1.9785 Y0.2108 +G01 X-1.9821 Y0.2139 +G01 X-1.9821 Y0.2144 +G01 X-1.9825 Y0.2148 +G01 X-1.9825 Y0.2195 +G01 X-1.9829 Y0.2242 +G01 X-1.9825 Y0.2246 +G01 X-1.9825 Y0.3953 +G01 X-2.0255 Y0.4445 +G01 X-2.0547 Y0.4445 +G01 X-2.0755 Y0.4653 +G01 X-2.0755 Y0.4947 +G01 X-2.0547 Y0.5155 +G01 X-2.0253 Y0.5155 +G01 X-2.0045 Y0.4947 +G01 X-2.0045 Y0.4653 +G01 X-2.0077 Y0.4621 +G01 X-1.9609 Y0.4086 +G01 X-1.9575 Y0.4052 +G01 X-1.9575 Y0.4047 +G01 X-1.9572 Y0.4043 +G01 X-1.9575 Y0.3996 +G01 X-1.9575 Y0.2257 +G01 X-1.9026 Y0.1786 +G01 X-1.9011 Y0.1801 +G01 X-1.8881 Y0.1855 +G01 X-1.8119 Y0.1855 +G01 X-1.7989 Y0.1801 +G01 X-1.7889 Y0.1701 +G01 X-1.7883 Y0.1687 +G01 X-1.7557 Y0.1720 +G01 X-1.6187 Y0.3089 +G01 X-1.6211 Y0.3099 +G01 X-1.6311 Y0.3199 +G01 X-1.6365 Y0.3329 +G01 X-1.6365 Y0.3471 +G01 X-1.6311 Y0.3601 +G01 X-1.6211 Y0.3701 +G01 X-1.6081 Y0.3755 +G01 X-1.5319 Y0.3755 +G01 X-1.5189 Y0.3701 +G01 X-1.5089 Y0.3601 +G01 X-1.5035 Y0.3471 +G01 X-1.5035 Y0.3329 +G01 X-1.5089 Y0.3199 +G01 X-1.5189 Y0.3099 +G01 X-1.5319 Y0.3045 +G00 Z0.1000 +G00 X-1.5319 Y0.4045 +G01 Z-0.0070 F10 +G01 X-1.6081 Y0.4045 F20 +G01 X-1.6211 Y0.4099 +G01 X-1.6311 Y0.4199 +G01 X-1.6342 Y0.4275 +G01 X-1.6348 Y0.4275 +G01 X-1.7906 Y0.2718 +G01 X-1.7889 Y0.2701 +G01 X-1.7835 Y0.2571 +G01 X-1.7835 Y0.2429 +G01 X-1.7889 Y0.2299 +G01 X-1.7989 Y0.2199 +G01 X-1.8119 Y0.2145 +G01 X-1.8881 Y0.2145 +G01 X-1.9011 Y0.2199 +G01 X-1.9111 Y0.2299 +G01 X-1.9165 Y0.2429 +G01 X-1.9165 Y0.2566 +G01 X-1.9347 Y0.2725 +G01 X-1.9352 Y0.2725 +G01 X-1.9385 Y0.2759 +G01 X-1.9421 Y0.2790 +G01 X-1.9422 Y0.2795 +G01 X-1.9425 Y0.2798 +G01 X-1.9425 Y0.2846 +G01 X-1.9428 Y0.2893 +G01 X-1.9425 Y0.2897 +G01 X-1.9425 Y0.4523 +G01 X-1.9555 Y0.4653 +G01 X-1.9555 Y0.4947 +G01 X-1.9347 Y0.5155 +G01 X-1.9053 Y0.5155 +G01 X-1.8845 Y0.4947 +G01 X-1.8845 Y0.4653 +G01 X-1.9053 Y0.4445 +G01 X-1.9175 Y0.4445 +G01 X-1.9175 Y0.2907 +G01 X-1.9031 Y0.2781 +G01 X-1.9011 Y0.2801 +G01 X-1.8881 Y0.2855 +G01 X-1.8122 Y0.2855 +G01 X-1.6452 Y0.4525 +G01 X-1.6348 Y0.4525 +G01 X-1.6342 Y0.4525 +G01 X-1.6311 Y0.4601 +G01 X-1.6211 Y0.4701 +G01 X-1.6081 Y0.4755 +G01 X-1.5319 Y0.4755 +G01 X-1.5189 Y0.4701 +G01 X-1.5089 Y0.4601 +G01 X-1.5035 Y0.4471 +G01 X-1.5035 Y0.4329 +G01 X-1.5089 Y0.4199 +G01 X-1.5189 Y0.4099 +G01 X-1.5319 Y0.4045 +G00 Z0.1000 +G00 X-1.5319 Y0.5045 +G01 Z-0.0070 F10 +G01 X-1.6081 Y0.5045 F20 +G01 X-1.6211 Y0.5099 +G01 X-1.6268 Y0.5156 +G01 X-1.6675 Y0.4748 +G01 X-1.6748 Y0.4675 +G01 X-1.7645 Y0.4675 +G01 X-1.7645 Y0.4653 +G01 X-1.7853 Y0.4445 +G01 X-1.8078 Y0.4445 +G01 X-1.8375 Y0.4148 +G01 X-1.8375 Y0.3855 +G01 X-1.8119 Y0.3855 +G01 X-1.7989 Y0.3801 +G01 X-1.7889 Y0.3701 +G01 X-1.7835 Y0.3571 +G01 X-1.7835 Y0.3429 +G01 X-1.7889 Y0.3299 +G01 X-1.7989 Y0.3199 +G01 X-1.8119 Y0.3145 +G01 X-1.8881 Y0.3145 +G01 X-1.9011 Y0.3199 +G01 X-1.9111 Y0.3299 +G01 X-1.9165 Y0.3429 +G01 X-1.9165 Y0.3571 +G01 X-1.9111 Y0.3701 +G01 X-1.9011 Y0.3801 +G01 X-1.8881 Y0.3855 +G01 X-1.8625 Y0.3855 +G01 X-1.8625 Y0.4252 +G01 X-1.8552 Y0.4325 +G01 X-1.8289 Y0.4587 +G01 X-1.8355 Y0.4653 +G01 X-1.8355 Y0.4947 +G01 X-1.8147 Y0.5155 +G01 X-1.7853 Y0.5155 +G01 X-1.7645 Y0.4947 +G01 X-1.7645 Y0.4925 +G01 X-1.6852 Y0.4925 +G01 X-1.6365 Y0.5412 +G01 X-1.6365 Y0.5471 +G01 X-1.6311 Y0.5601 +G01 X-1.6211 Y0.5701 +G01 X-1.6081 Y0.5755 +G01 X-1.5319 Y0.5755 +G01 X-1.5189 Y0.5701 +G01 X-1.5089 Y0.5601 +G01 X-1.5035 Y0.5471 +G01 X-1.5035 Y0.5329 +G01 X-1.5089 Y0.5199 +G01 X-1.5189 Y0.5099 +G01 X-1.5319 Y0.5045 +G00 Z0.1000 +G00 X-0.8060 Y0.8581 +G01 Z-0.0070 F10 +G01 X-0.8060 Y0.7820 F20 +G01 X-0.8114 Y0.7689 +G01 X-0.8214 Y0.7590 +G01 X-0.8325 Y0.7544 +G01 X-0.8325 Y0.7498 +G01 X-0.8398 Y0.7425 +G01 X-0.8698 Y0.7125 +G01 X-0.8802 Y0.7125 +G01 X-0.9098 Y0.7125 +G01 X-0.9448 Y0.6775 +G01 X-0.9552 Y0.6775 +G01 X-1.3248 Y0.6775 +G01 X-1.3475 Y0.6548 +G01 X-1.3475 Y0.6152 +G01 X-1.3078 Y0.5755 +G01 X-1.2319 Y0.5755 +G01 X-1.2189 Y0.5701 +G01 X-1.2089 Y0.5601 +G01 X-1.2035 Y0.5471 +G01 X-1.2035 Y0.5329 +G01 X-1.2089 Y0.5199 +G01 X-1.2189 Y0.5099 +G01 X-1.2319 Y0.5045 +G01 X-1.3081 Y0.5045 +G01 X-1.3211 Y0.5099 +G01 X-1.3311 Y0.5199 +G01 X-1.3365 Y0.5329 +G01 X-1.3365 Y0.5471 +G01 X-1.3311 Y0.5601 +G01 X-1.3294 Y0.5618 +G01 X-1.3725 Y0.6048 +G01 X-1.3725 Y0.6152 +G01 X-1.3725 Y0.6652 +G01 X-1.3652 Y0.6725 +G01 X-1.3352 Y0.7025 +G01 X-1.3248 Y0.7025 +G01 X-0.9552 Y0.7025 +G01 X-0.9275 Y0.7302 +G01 X-0.9202 Y0.7375 +G01 X-0.8802 Y0.7375 +G01 X-0.8596 Y0.7581 +G01 X-0.8616 Y0.7590 +G01 X-0.8716 Y0.7689 +G01 X-0.8770 Y0.7820 +G01 X-0.8770 Y0.8581 +G01 X-0.8716 Y0.8712 +G01 X-0.8616 Y0.8811 +G01 X-0.8486 Y0.8866 +G01 X-0.8344 Y0.8866 +G01 X-0.8214 Y0.8811 +G01 X-0.8114 Y0.8712 +G01 X-0.8060 Y0.8581 +G00 Z0.1000 +G00 X-0.7589 Y0.6019 +G01 Z-0.0070 F10 +G01 X-0.7589 Y0.6780 F20 +G01 X-0.7535 Y0.6911 +G01 X-0.7435 Y0.7010 +G01 X-0.7304 Y0.7064 +G01 X-0.7163 Y0.7064 +G01 X-0.7033 Y0.7010 +G01 X-0.6933 Y0.6911 +G01 X-0.6879 Y0.6780 +G01 X-0.6879 Y0.6019 +G01 X-0.6933 Y0.5888 +G01 X-0.7033 Y0.5789 +G01 X-0.7075 Y0.5771 +G01 X-0.7075 Y0.5698 +G01 X-0.7148 Y0.5625 +G01 X-0.8398 Y0.4375 +G01 X-0.8502 Y0.4375 +G01 X-1.2035 Y0.4375 +G01 X-1.2035 Y0.4329 +G01 X-1.2089 Y0.4199 +G01 X-1.2189 Y0.4099 +G01 X-1.2319 Y0.4045 +G01 X-1.3081 Y0.4045 +G01 X-1.3211 Y0.4099 +G01 X-1.3311 Y0.4199 +G01 X-1.3365 Y0.4329 +G01 X-1.3365 Y0.4471 +G01 X-1.3311 Y0.4601 +G01 X-1.3211 Y0.4701 +G01 X-1.3081 Y0.4755 +G01 X-1.2319 Y0.4755 +G01 X-1.2189 Y0.4701 +G01 X-1.2113 Y0.4625 +G01 X-0.8502 Y0.4625 +G01 X-0.7366 Y0.5760 +G01 X-0.7435 Y0.5789 +G01 X-0.7535 Y0.5888 +G01 X-0.7589 Y0.6019 +G00 Z0.1000 +G00 X-0.8847 Y0.8581 +G01 Z-0.0070 F10 +G01 X-0.8847 Y0.7820 F20 +G01 X-0.8901 Y0.7689 +G01 X-0.9001 Y0.7590 +G01 X-0.9132 Y0.7536 +G01 X-0.9273 Y0.7536 +G01 X-0.9403 Y0.7590 +G01 X-0.9503 Y0.7689 +G01 X-0.9557 Y0.7820 +G01 X-0.9557 Y0.8075 +G01 X-1.1598 Y0.8075 +G01 X-1.1898 Y0.7775 +G01 X-1.2002 Y0.7775 +G01 X-1.3352 Y0.7775 +G01 X-1.3425 Y0.7848 +G01 X-1.3575 Y0.7998 +G01 X-1.3575 Y0.8102 +G01 X-1.3575 Y0.9798 +G01 X-1.5025 Y1.1248 +G01 X-1.5025 Y1.1345 +G01 X-1.5047 Y1.1345 +G01 X-1.5255 Y1.1553 +G01 X-1.5255 Y1.1847 +G01 X-1.5239 Y1.1863 +G01 X-1.5252 Y1.1875 +G01 X-1.7080 Y1.1875 +G01 X-1.7110 Y1.1865 +G01 X-1.7129 Y1.1875 +G01 X-1.7152 Y1.1875 +G01 X-1.7231 Y1.1797 +G01 X-1.7405 Y1.1725 +G01 X-1.7594 Y1.1725 +G01 X-1.7769 Y1.1797 +G01 X-1.7903 Y1.1931 +G01 X-1.7975 Y1.2105 +G01 X-1.7975 Y1.2294 +G01 X-1.7903 Y1.2469 +G01 X-1.7769 Y1.2603 +G01 X-1.7594 Y1.2675 +G01 X-1.7405 Y1.2675 +G01 X-1.7231 Y1.2603 +G01 X-1.7097 Y1.2469 +G01 X-1.7025 Y1.2294 +G01 X-1.7025 Y1.2125 +G01 X-1.5148 Y1.2125 +G01 X-1.5075 Y1.2052 +G01 X-1.5063 Y1.2039 +G01 X-1.5047 Y1.2055 +G01 X-1.4753 Y1.2055 +G01 X-1.4545 Y1.1847 +G01 X-1.4545 Y1.1553 +G01 X-1.4753 Y1.1345 +G01 X-1.4768 Y1.1345 +G01 X-1.3448 Y1.0025 +G01 X-1.3348 Y1.0025 +G01 X-0.5455 Y1.0025 +G01 X-0.5455 Y1.0147 +G01 X-0.5247 Y1.0355 +G01 X-0.4953 Y1.0355 +G01 X-0.4745 Y1.0147 +G01 X-0.4745 Y0.9853 +G01 X-0.4953 Y0.9645 +G01 X-0.5247 Y0.9645 +G01 X-0.5377 Y0.9775 +G01 X-1.3325 Y0.9775 +G01 X-1.3325 Y0.9567 +G01 X-1.3311 Y0.9601 +G01 X-1.3211 Y0.9701 +G01 X-1.3081 Y0.9755 +G01 X-1.2319 Y0.9755 +G01 X-1.2189 Y0.9701 +G01 X-1.2089 Y0.9601 +G01 X-1.2058 Y0.9525 +G01 X-0.4699 Y0.9525 +G01 X-0.4697 Y0.9527 +G01 X-0.4648 Y0.9525 +G01 X-0.4598 Y0.9525 +G01 X-0.4596 Y0.9523 +G01 X-0.4594 Y0.9523 +G01 X-0.4560 Y0.9487 +G01 X-0.4525 Y0.9452 +G01 X-0.4525 Y0.9449 +G01 X-0.3296 Y0.8125 +G01 X-0.3295 Y0.8164 +G01 X-0.3064 Y0.8395 +G01 X-0.2736 Y0.8395 +G01 X-0.2505 Y0.8164 +G01 X-0.2505 Y0.7836 +G01 X-0.2716 Y0.7625 +G01 X-0.2452 Y0.7625 +G01 X-0.2268 Y0.7809 +G01 X-0.2295 Y0.7836 +G01 X-0.2295 Y0.8164 +G01 X-0.2084 Y0.8375 +G01 X-0.2348 Y0.8375 +G01 X-0.2452 Y0.8375 +G01 X-0.2709 Y0.8632 +G01 X-0.2736 Y0.8605 +G01 X-0.3064 Y0.8605 +G01 X-0.3295 Y0.8836 +G01 X-0.3295 Y0.9164 +G01 X-0.3084 Y0.9375 +G01 X-0.4352 Y0.9375 +G01 X-0.4425 Y0.9448 +G01 X-0.4725 Y0.9748 +G01 X-0.4725 Y0.9852 +G01 X-0.4725 Y1.0148 +G01 X-0.4952 Y1.0375 +G01 X-1.2035 Y1.0375 +G01 X-1.2035 Y1.0329 +G01 X-1.2089 Y1.0199 +G01 X-1.2189 Y1.0099 +G01 X-1.2319 Y1.0045 +G01 X-1.3081 Y1.0045 +G01 X-1.3211 Y1.0099 +G01 X-1.3311 Y1.0199 +G01 X-1.3365 Y1.0329 +G01 X-1.3365 Y1.0471 +G01 X-1.3311 Y1.0601 +G01 X-1.3211 Y1.0701 +G01 X-1.3081 Y1.0755 +G01 X-1.2319 Y1.0755 +G01 X-1.2189 Y1.0701 +G01 X-1.2113 Y1.0625 +G01 X-0.4952 Y1.0625 +G01 X-0.4848 Y1.0625 +G01 X-0.4548 Y1.0325 +G01 X-0.4475 Y1.0252 +G01 X-0.4475 Y0.9852 +G01 X-0.4248 Y0.9625 +G01 X-0.3084 Y0.9625 +G01 X-0.3234 Y0.9775 +G01 X-0.3823 Y0.9775 +G01 X-0.3953 Y0.9645 +G01 X-0.4247 Y0.9645 +G01 X-0.4455 Y0.9853 +G01 X-0.4455 Y1.0147 +G01 X-0.4339 Y1.0263 +G01 X-0.5052 Y1.0975 +G01 X-1.1548 Y1.0975 +G01 X-1.1652 Y1.0975 +G01 X-1.2052 Y1.1376 +G01 X-1.2103 Y1.1325 +G01 X-1.2497 Y1.1325 +G01 X-1.2647 Y1.1476 +G01 X-1.2975 Y1.1148 +G01 X-1.3048 Y1.1075 +G01 X-1.4148 Y1.1075 +G01 X-1.4252 Y1.1075 +G01 X-1.4452 Y1.1275 +G01 X-1.4525 Y1.1348 +G01 X-1.4525 Y1.2095 +G01 X-1.4547 Y1.2095 +G01 X-1.4755 Y1.2303 +G01 X-1.4755 Y1.2597 +G01 X-1.4739 Y1.2613 +G01 X-1.4902 Y1.2775 +G01 X-1.7648 Y1.2775 +G01 X-1.8075 Y1.2348 +G01 X-1.8075 Y1.1952 +G01 X-1.7747 Y1.1624 +G01 X-1.7697 Y1.1675 +G01 X-1.7303 Y1.1675 +G01 X-1.7025 Y1.1397 +G01 X-1.7025 Y1.1003 +G01 X-1.7303 Y1.0725 +G01 X-1.7697 Y1.0725 +G01 X-1.7975 Y1.1003 +G01 X-1.7975 Y1.1397 +G01 X-1.7924 Y1.1447 +G01 X-1.8252 Y1.1775 +G01 X-2.2948 Y1.1775 +G01 X-2.3975 Y1.0748 +G01 X-2.3975 Y0.9952 +G01 X-2.3548 Y0.9525 +G01 X-2.1952 Y0.9525 +G01 X-2.1125 Y1.0352 +G01 X-2.1125 Y1.0652 +G01 X-2.1052 Y1.0725 +G01 X-2.0452 Y1.1325 +G01 X-2.0348 Y1.1325 +G01 X-1.9648 Y1.1325 +G01 X-1.9575 Y1.1252 +G01 X-1.9075 Y1.0752 +G01 X-1.9075 Y1.0648 +G01 X-1.9075 Y0.9902 +G01 X-1.8848 Y0.9675 +G01 X-1.7948 Y0.9675 +G01 X-1.7352 Y0.9675 +G01 X-1.6702 Y1.0325 +G01 X-1.6598 Y1.0325 +G01 X-1.6363 Y1.0325 +G01 X-1.6365 Y1.0329 +G01 X-1.6365 Y1.0471 +G01 X-1.6311 Y1.0601 +G01 X-1.6211 Y1.0701 +G01 X-1.6081 Y1.0755 +G01 X-1.5319 Y1.0755 +G01 X-1.5189 Y1.0701 +G01 X-1.5089 Y1.0601 +G01 X-1.5035 Y1.0471 +G01 X-1.5035 Y1.0329 +G01 X-1.5040 Y1.0318 +G01 X-1.5011 Y1.0287 +G01 X-1.4975 Y1.0252 +G01 X-1.4975 Y1.0250 +G01 X-1.3960 Y0.9187 +G01 X-1.3925 Y0.9152 +G01 X-1.3925 Y0.9150 +G01 X-1.3924 Y0.9149 +G01 X-1.3925 Y0.9098 +G01 X-1.3925 Y0.5502 +G01 X-1.3875 Y0.5452 +G01 X-1.3875 Y0.5348 +G01 X-1.3925 Y0.5298 +G01 X-1.3925 Y0.5025 +G01 X-0.8902 Y0.5025 +G01 X-0.8163 Y0.5764 +G01 X-0.8222 Y0.5789 +G01 X-0.8322 Y0.5888 +G01 X-0.8376 Y0.6019 +G01 X-0.8376 Y0.6780 +G01 X-0.8322 Y0.6911 +G01 X-0.8222 Y0.7010 +G01 X-0.8092 Y0.7064 +G01 X-0.7951 Y0.7064 +G01 X-0.7820 Y0.7010 +G01 X-0.7720 Y0.6911 +G01 X-0.7666 Y0.6780 +G01 X-0.7666 Y0.6019 +G01 X-0.7720 Y0.5888 +G01 X-0.7820 Y0.5789 +G01 X-0.7875 Y0.5766 +G01 X-0.7875 Y0.5698 +G01 X-0.8798 Y0.4775 +G01 X-0.8902 Y0.4775 +G01 X-1.3925 Y0.4775 +G01 X-1.3925 Y0.3552 +G01 X-1.3648 Y0.3275 +G01 X-1.3575 Y0.3202 +G01 X-1.3575 Y0.2655 +G01 X-1.3553 Y0.2655 +G01 X-1.3345 Y0.2447 +G01 X-1.3345 Y0.2222 +G01 X-1.3048 Y0.1925 +G01 X-1.0352 Y0.1925 +G01 X-0.9552 Y0.2725 +G01 X-0.9448 Y0.2725 +G01 X-0.6665 Y0.2725 +G01 X-0.6665 Y0.2771 +G01 X-0.6611 Y0.2901 +G01 X-0.6511 Y0.3001 +G01 X-0.6381 Y0.3055 +G01 X-0.5619 Y0.3055 +G01 X-0.5489 Y0.3001 +G01 X-0.5389 Y0.2901 +G01 X-0.5335 Y0.2771 +G01 X-0.5335 Y0.2629 +G01 X-0.5389 Y0.2499 +G01 X-0.5489 Y0.2399 +G01 X-0.5619 Y0.2345 +G01 X-0.6381 Y0.2345 +G01 X-0.6511 Y0.2399 +G01 X-0.6587 Y0.2475 +G01 X-0.9448 Y0.2475 +G01 X-1.0175 Y0.1748 +G01 X-1.0248 Y0.1675 +G01 X-1.3048 Y0.1675 +G01 X-1.3152 Y0.1675 +G01 X-1.3487 Y0.2011 +G01 X-1.3553 Y0.1945 +G01 X-1.3847 Y0.1945 +G01 X-1.4055 Y0.2153 +G01 X-1.4055 Y0.2447 +G01 X-1.3847 Y0.2655 +G01 X-1.3825 Y0.2655 +G01 X-1.3825 Y0.3098 +G01 X-1.4175 Y0.3448 +G01 X-1.4175 Y0.3552 +G01 X-1.4175 Y0.4952 +G01 X-1.4175 Y0.5298 +G01 X-1.4175 Y0.5348 +G01 X-1.4175 Y0.9050 +G01 X-1.5153 Y1.0075 +G01 X-1.5247 Y1.0075 +G01 X-1.5319 Y1.0045 +G01 X-1.6081 Y1.0045 +G01 X-1.6153 Y1.0075 +G01 X-1.6598 Y1.0075 +G01 X-1.7175 Y0.9498 +G01 X-1.7248 Y0.9425 +G01 X-1.7875 Y0.9425 +G01 X-1.7875 Y0.7155 +G01 X-1.7853 Y0.7155 +G01 X-1.7645 Y0.6947 +G01 X-1.7645 Y0.6653 +G01 X-1.7853 Y0.6445 +G01 X-1.8147 Y0.6445 +G01 X-1.8277 Y0.6575 +G01 X-1.8923 Y0.6575 +G01 X-1.9053 Y0.6445 +G01 X-1.9347 Y0.6445 +G01 X-1.9477 Y0.6575 +G01 X-2.0123 Y0.6575 +G01 X-2.0253 Y0.6445 +G01 X-2.0547 Y0.6445 +G01 X-2.0755 Y0.6653 +G01 X-2.0755 Y0.6947 +G01 X-2.0547 Y0.7155 +G01 X-2.0253 Y0.7155 +G01 X-2.0045 Y0.6947 +G01 X-2.0045 Y0.6825 +G01 X-1.9555 Y0.6825 +G01 X-1.9555 Y0.6947 +G01 X-1.9347 Y0.7155 +G01 X-1.9053 Y0.7155 +G01 X-1.8845 Y0.6947 +G01 X-1.8845 Y0.6825 +G01 X-1.8355 Y0.6825 +G01 X-1.8355 Y0.6947 +G01 X-1.8147 Y0.7155 +G01 X-1.8125 Y0.7155 +G01 X-1.8125 Y0.9425 +G01 X-1.8848 Y0.9425 +G01 X-1.8952 Y0.9425 +G01 X-1.9325 Y0.9798 +G01 X-1.9325 Y0.9902 +G01 X-1.9325 Y1.0648 +G01 X-1.9752 Y1.1075 +G01 X-2.0348 Y1.1075 +G01 X-2.0875 Y1.0548 +G01 X-2.0875 Y1.0352 +G01 X-2.0875 Y1.0248 +G01 X-2.1775 Y0.9348 +G01 X-2.1848 Y0.9275 +G01 X-2.3548 Y0.9275 +G01 X-2.3652 Y0.9275 +G01 X-2.4152 Y0.9775 +G01 X-2.4225 Y0.9848 +G01 X-2.4225 Y1.0748 +G01 X-2.4225 Y1.0852 +G01 X-2.3125 Y1.1952 +G01 X-2.3052 Y1.2025 +G01 X-1.8325 Y1.2025 +G01 X-1.8325 Y1.2348 +G01 X-1.8325 Y1.2452 +G01 X-1.7825 Y1.2952 +G01 X-1.7752 Y1.3025 +G01 X-1.4798 Y1.3025 +G01 X-1.4725 Y1.2952 +G01 X-1.4563 Y1.2789 +G01 X-1.4547 Y1.2805 +G01 X-1.4253 Y1.2805 +G01 X-1.4045 Y1.2597 +G01 X-1.4045 Y1.2303 +G01 X-1.4253 Y1.2095 +G01 X-1.4275 Y1.2095 +G01 X-1.4275 Y1.1452 +G01 X-1.4148 Y1.1325 +G01 X-1.3152 Y1.1325 +G01 X-1.2809 Y1.1668 +G01 X-1.2802 Y1.1689 +G01 X-1.2775 Y1.1702 +G01 X-1.2775 Y1.1997 +G01 X-1.2497 Y1.2275 +G01 X-1.2103 Y1.2275 +G01 X-1.1825 Y1.1997 +G01 X-1.1825 Y1.1603 +G01 X-1.1876 Y1.1552 +G01 X-1.1548 Y1.1225 +G01 X-0.4948 Y1.1225 +G01 X-0.4875 Y1.1152 +G01 X-0.4078 Y1.0355 +G01 X-0.3953 Y1.0355 +G01 X-0.3745 Y1.0147 +G01 X-0.3745 Y1.0025 +G01 X-0.3295 Y1.0025 +G01 X-0.3295 Y1.0164 +G01 X-0.3064 Y1.0395 +G01 X-0.2736 Y1.0395 +G01 X-0.2505 Y1.0164 +G01 X-0.2505 Y0.9836 +G01 X-0.2716 Y0.9625 +G01 X-0.2452 Y0.9625 +G01 X-0.2348 Y0.9625 +G01 X-0.2091 Y0.9368 +G01 X-0.2064 Y0.9395 +G01 X-0.1736 Y0.9395 +G01 X-0.1505 Y0.9164 +G01 X-0.1505 Y0.8836 +G01 X-0.1716 Y0.8625 +G01 X-0.1709 Y0.8625 +G01 X-0.1666 Y0.8631 +G01 X-0.1658 Y0.8625 +G01 X-0.1648 Y0.8625 +G01 X-0.1618 Y0.8595 +G01 X-0.1258 Y0.8325 +G01 X-0.1248 Y0.8325 +G01 X-0.1218 Y0.8295 +G01 X-0.1184 Y0.8269 +G01 X-0.1182 Y0.8259 +G01 X-0.1175 Y0.8252 +G01 X-0.1175 Y0.8209 +G01 X-0.1169 Y0.8166 +G01 X-0.1175 Y0.8158 +G01 X-0.1175 Y0.6842 +G01 X-0.1169 Y0.6834 +G01 X-0.1175 Y0.6791 +G01 X-0.1175 Y0.6748 +G01 X-0.1182 Y0.6741 +G01 X-0.1184 Y0.6731 +G01 X-0.1218 Y0.6705 +G01 X-0.1248 Y0.6675 +G01 X-0.1258 Y0.6675 +G01 X-0.1618 Y0.6405 +G01 X-0.1648 Y0.6375 +G01 X-0.1658 Y0.6375 +G01 X-0.1666 Y0.6369 +G01 X-0.1709 Y0.6375 +G01 X-0.1716 Y0.6375 +G01 X-0.1505 Y0.6164 +G01 X-0.1505 Y0.5836 +G01 X-0.1711 Y0.5630 +G01 X-0.1520 Y0.5706 +G01 X-0.1502 Y0.5725 +G01 X-0.1125 Y0.6102 +G01 X-0.1125 Y0.9096 +G01 X-0.1701 Y0.9640 +G01 X-0.1736 Y0.9605 +G01 X-0.2064 Y0.9605 +G01 X-0.2295 Y0.9836 +G01 X-0.2295 Y1.0164 +G01 X-0.2243 Y1.0216 +G01 X-0.3502 Y1.1475 +G01 X-1.0880 Y1.1475 +G01 X-1.0910 Y1.1465 +G01 X-1.0929 Y1.1475 +G01 X-1.0952 Y1.1475 +G01 X-1.1031 Y1.1397 +G01 X-1.1205 Y1.1325 +G01 X-1.1394 Y1.1325 +G01 X-1.1569 Y1.1397 +G01 X-1.1703 Y1.1531 +G01 X-1.1775 Y1.1705 +G01 X-1.1775 Y1.1894 +G01 X-1.1715 Y1.2039 +G01 X-1.2052 Y1.2375 +G01 X-1.2448 Y1.2375 +G01 X-1.3148 Y1.1675 +G01 X-1.3252 Y1.1675 +G01 X-1.3545 Y1.1675 +G01 X-1.3545 Y1.1553 +G01 X-1.3753 Y1.1345 +G01 X-1.4047 Y1.1345 +G01 X-1.4255 Y1.1553 +G01 X-1.4255 Y1.1847 +G01 X-1.4047 Y1.2055 +G01 X-1.3753 Y1.2055 +G01 X-1.3623 Y1.1925 +G01 X-1.3252 Y1.1925 +G01 X-1.2625 Y1.2552 +G01 X-1.2552 Y1.2625 +G01 X-1.2052 Y1.2625 +G01 X-1.1948 Y1.2625 +G01 X-1.1539 Y1.2215 +G01 X-1.1394 Y1.2275 +G01 X-1.1205 Y1.2275 +G01 X-1.1031 Y1.2203 +G01 X-1.0897 Y1.2069 +G01 X-1.0825 Y1.1894 +G01 X-1.0825 Y1.1725 +G01 X-0.3502 Y1.1725 +G01 X-0.3398 Y1.1725 +G01 X-0.2066 Y1.0393 +G01 X-0.2064 Y1.0395 +G01 X-0.1736 Y1.0395 +G01 X-0.1505 Y1.0164 +G01 X-0.1505 Y0.9836 +G01 X-0.1524 Y0.9817 +G01 X-0.0950 Y0.9275 +G01 X-0.0948 Y0.9275 +G01 X-0.0913 Y0.9239 +G01 X-0.0877 Y0.9205 +G01 X-0.0876 Y0.9203 +G01 X-0.0875 Y0.9202 +G01 X-0.0875 Y0.9151 +G01 X-0.0874 Y0.9102 +G01 X-0.0875 Y0.9100 +G01 X-0.0875 Y0.5998 +G01 X-0.0948 Y0.5925 +G01 X-0.1275 Y0.5598 +G01 X-0.1275 Y0.3652 +G01 X-0.1275 Y0.3548 +G01 X-0.4748 Y0.0075 +G01 X-0.4852 Y0.0075 +G01 X-2.2352 Y0.0075 +G01 X-2.2425 Y0.0148 +G01 X-2.3352 Y0.1075 +G01 X-2.3425 Y0.1148 +G01 X-2.3425 Y0.3448 +G01 X-2.3425 Y0.3552 +G01 X-2.3425 Y0.7748 +G01 X-2.3425 Y0.7852 +G01 X-2.2802 Y0.8475 +G01 X-2.2698 Y0.8475 +G01 X-2.1902 Y0.8475 +G01 X-2.0424 Y0.9953 +G01 X-2.0545 Y1.0074 +G01 X-2.0545 Y1.0526 +G01 X-2.0226 Y1.0845 +G01 X-1.9774 Y1.0845 +G01 X-1.9455 Y1.0526 +G01 X-1.9455 Y1.0074 +G01 X-1.9774 Y0.9755 +G01 X-2.0226 Y0.9755 +G01 X-2.0247 Y0.9776 +G01 X-2.1725 Y0.8298 +G01 X-2.1798 Y0.8225 +G01 X-2.2698 Y0.8225 +G01 X-2.3175 Y0.7748 +G01 X-2.3175 Y0.3625 +G01 X-2.2142 Y0.3625 +G01 X-2.2111 Y0.3701 +G01 X-2.2011 Y0.3801 +G01 X-2.1881 Y0.3855 +G01 X-2.1119 Y0.3855 +G01 X-2.0989 Y0.3801 +G01 X-2.0889 Y0.3701 +G01 X-2.0835 Y0.3571 +G01 X-2.0835 Y0.3429 +G01 X-2.0889 Y0.3299 +G01 X-2.0989 Y0.3199 +G01 X-2.1013 Y0.3189 +G01 X-2.0975 Y0.3152 +G01 X-2.0975 Y0.3048 +G01 X-2.0975 Y0.2787 +G01 X-2.0889 Y0.2701 +G01 X-2.0835 Y0.2571 +G01 X-2.0835 Y0.2429 +G01 X-2.0889 Y0.2299 +G01 X-2.0989 Y0.2199 +G01 X-2.1013 Y0.2189 +G01 X-2.0975 Y0.2152 +G01 X-2.0975 Y0.2048 +G01 X-2.0975 Y0.1787 +G01 X-2.0889 Y0.1701 +G01 X-2.0835 Y0.1571 +G01 X-2.0835 Y0.1429 +G01 X-2.0889 Y0.1299 +G01 X-2.0989 Y0.1199 +G01 X-2.1119 Y0.1145 +G01 X-2.1881 Y0.1145 +G01 X-2.2011 Y0.1199 +G01 X-2.2111 Y0.1299 +G01 X-2.2165 Y0.1429 +G01 X-2.2165 Y0.1571 +G01 X-2.2111 Y0.1701 +G01 X-2.2011 Y0.1801 +G01 X-2.1881 Y0.1855 +G01 X-2.1225 Y0.1855 +G01 X-2.1225 Y0.2048 +G01 X-2.1322 Y0.2145 +G01 X-2.1881 Y0.2145 +G01 X-2.2011 Y0.2199 +G01 X-2.2111 Y0.2299 +G01 X-2.2165 Y0.2429 +G01 X-2.2165 Y0.2571 +G01 X-2.2111 Y0.2701 +G01 X-2.2011 Y0.2801 +G01 X-2.1881 Y0.2855 +G01 X-2.1225 Y0.2855 +G01 X-2.1225 Y0.3048 +G01 X-2.1322 Y0.3145 +G01 X-2.1881 Y0.3145 +G01 X-2.2011 Y0.3199 +G01 X-2.2111 Y0.3299 +G01 X-2.2142 Y0.3375 +G01 X-2.3175 Y0.3375 +G01 X-2.3175 Y0.1252 +G01 X-2.2248 Y0.0325 +G01 X-0.4852 Y0.0325 +G01 X-0.1525 Y0.3652 +G01 X-0.1525 Y0.3816 +G01 X-0.1736 Y0.3605 +G01 X-0.1818 Y0.3605 +G01 X-0.4975 Y0.0448 +G01 X-0.5048 Y0.0375 +G01 X-2.0502 Y0.0375 +G01 X-2.0575 Y0.0448 +G01 X-2.0702 Y0.0575 +G01 X-2.0775 Y0.0648 +G01 X-2.0775 Y0.3735 +G01 X-2.1540 Y0.4275 +G01 X-2.1552 Y0.4275 +G01 X-2.1581 Y0.4304 +G01 X-2.1614 Y0.4328 +G01 X-2.1616 Y0.4340 +G01 X-2.1625 Y0.4348 +G01 X-2.1625 Y0.4389 +G01 X-2.1632 Y0.4430 +G01 X-2.1625 Y0.4440 +G01 X-2.1625 Y0.5248 +G01 X-2.1625 Y0.5352 +G01 X-2.0952 Y0.6025 +G01 X-2.0848 Y0.6025 +G01 X-1.7552 Y0.6025 +G01 X-1.7225 Y0.6352 +G01 X-1.7225 Y0.9152 +G01 X-1.7152 Y0.9225 +G01 X-1.6925 Y0.9452 +G01 X-1.6852 Y0.9525 +G01 X-1.6342 Y0.9525 +G01 X-1.6311 Y0.9601 +G01 X-1.6211 Y0.9701 +G01 X-1.6081 Y0.9755 +G01 X-1.5319 Y0.9755 +G01 X-1.5189 Y0.9701 +G01 X-1.5089 Y0.9601 +G01 X-1.5035 Y0.9471 +G01 X-1.5035 Y0.9329 +G01 X-1.5089 Y0.9199 +G01 X-1.5189 Y0.9099 +G01 X-1.5319 Y0.9045 +G01 X-1.6081 Y0.9045 +G01 X-1.6211 Y0.9099 +G01 X-1.6311 Y0.9199 +G01 X-1.6342 Y0.9275 +G01 X-1.6748 Y0.9275 +G01 X-1.6975 Y0.9048 +G01 X-1.6975 Y0.6352 +G01 X-1.6975 Y0.6248 +G01 X-1.7375 Y0.5848 +G01 X-1.7448 Y0.5775 +G01 X-2.0848 Y0.5775 +G01 X-2.1375 Y0.5248 +G01 X-2.1375 Y0.4465 +G01 X-2.0610 Y0.3925 +G01 X-2.0598 Y0.3925 +G01 X-2.0569 Y0.3896 +G01 X-2.0536 Y0.3872 +G01 X-2.0534 Y0.3860 +G01 X-2.0525 Y0.3852 +G01 X-2.0525 Y0.3811 +G01 X-2.0518 Y0.3770 +G01 X-2.0525 Y0.3760 +G01 X-2.0525 Y0.0752 +G01 X-2.0398 Y0.0625 +G01 X-0.5152 Y0.0625 +G01 X-0.2118 Y0.3659 +G01 X-0.2275 Y0.3816 +G01 X-0.2275 Y0.3802 +G01 X-0.2275 Y0.3698 +G01 X-0.5298 Y0.0675 +G01 X-0.5402 Y0.0675 +G01 X-1.9152 Y0.0675 +G01 X-1.9225 Y0.0748 +G01 X-2.0152 Y0.1675 +G01 X-2.0225 Y0.1748 +G01 X-2.0225 Y0.3898 +G01 X-2.0352 Y0.4025 +G01 X-2.0548 Y0.4025 +G01 X-2.0652 Y0.4025 +G01 X-2.1225 Y0.4598 +G01 X-2.1225 Y0.4702 +G01 X-2.1225 Y0.5152 +G01 X-2.1152 Y0.5225 +G01 X-2.0825 Y0.5552 +G01 X-2.0752 Y0.5625 +G01 X-1.6952 Y0.5625 +G01 X-1.6725 Y0.5852 +G01 X-1.6725 Y0.7148 +G01 X-1.6725 Y0.7252 +G01 X-1.6575 Y0.7402 +G01 X-1.6502 Y0.7475 +G01 X-1.6363 Y0.7475 +G01 X-1.6311 Y0.7601 +G01 X-1.6211 Y0.7701 +G01 X-1.6081 Y0.7755 +G01 X-1.5319 Y0.7755 +G01 X-1.5189 Y0.7701 +G01 X-1.5089 Y0.7601 +G01 X-1.5075 Y0.7567 +G01 X-1.5075 Y0.7770 +G01 X-1.5077 Y0.7775 +G01 X-1.6248 Y0.7775 +G01 X-1.6352 Y0.7775 +G01 X-1.6552 Y0.7975 +G01 X-1.6625 Y0.8048 +G01 X-1.6625 Y0.8548 +G01 X-1.6625 Y0.8652 +G01 X-1.6325 Y0.8952 +G01 X-1.6252 Y0.9025 +G01 X-1.4949 Y0.9025 +G01 X-1.4946 Y0.9027 +G01 X-1.4897 Y0.9025 +G01 X-1.4848 Y0.9025 +G01 X-1.4846 Y0.9023 +G01 X-1.4843 Y0.9023 +G01 X-1.4810 Y0.8987 +G01 X-1.4775 Y0.8952 +G01 X-1.4775 Y0.8949 +G01 X-1.4260 Y0.8386 +G01 X-1.4225 Y0.8352 +G01 X-1.4225 Y0.8349 +G01 X-1.4223 Y0.8346 +G01 X-1.4225 Y0.8297 +G01 X-1.4225 Y0.6209 +G01 X-1.4219 Y0.6166 +G01 X-1.4225 Y0.6158 +G01 X-1.4225 Y0.6148 +G01 X-1.4255 Y0.6118 +G01 X-1.4375 Y0.5958 +G01 X-1.4375 Y0.1752 +G01 X-1.4148 Y0.1525 +G01 X-0.6152 Y0.1525 +G01 X-0.3925 Y0.3752 +G01 X-0.3925 Y0.4048 +G01 X-0.3925 Y0.4152 +G01 X-0.3268 Y0.4809 +G01 X-0.3295 Y0.4836 +G01 X-0.3295 Y0.5164 +G01 X-0.3084 Y0.5375 +G01 X-0.3298 Y0.5375 +G01 X-0.5125 Y0.3548 +G01 X-0.5198 Y0.3475 +G01 X-0.6498 Y0.3475 +G01 X-0.6925 Y0.3048 +G01 X-0.6998 Y0.2975 +G01 X-0.9248 Y0.2975 +G01 X-0.9352 Y0.2975 +G01 X-0.9748 Y0.2975 +G01 X-1.0048 Y0.2675 +G01 X-1.0152 Y0.2675 +G01 X-1.0335 Y0.2675 +G01 X-1.0335 Y0.2629 +G01 X-1.0389 Y0.2499 +G01 X-1.0489 Y0.2399 +G01 X-1.0619 Y0.2345 +G01 X-1.1381 Y0.2345 +G01 X-1.1511 Y0.2399 +G01 X-1.1611 Y0.2499 +G01 X-1.1665 Y0.2629 +G01 X-1.1665 Y0.2771 +G01 X-1.1660 Y0.2783 +G01 X-1.2085 Y0.3208 +G01 X-1.2089 Y0.3199 +G01 X-1.2189 Y0.3099 +G01 X-1.2319 Y0.3045 +G01 X-1.2475 Y0.3045 +G01 X-1.2475 Y0.2577 +G01 X-1.2345 Y0.2447 +G01 X-1.2345 Y0.2153 +G01 X-1.2553 Y0.1945 +G01 X-1.2847 Y0.1945 +G01 X-1.3055 Y0.2153 +G01 X-1.3055 Y0.2447 +G01 X-1.2847 Y0.2655 +G01 X-1.2725 Y0.2655 +G01 X-1.2725 Y0.3045 +G01 X-1.3081 Y0.3045 +G01 X-1.3211 Y0.3099 +G01 X-1.3311 Y0.3199 +G01 X-1.3365 Y0.3329 +G01 X-1.3365 Y0.3471 +G01 X-1.3311 Y0.3601 +G01 X-1.3211 Y0.3701 +G01 X-1.3081 Y0.3755 +G01 X-1.2319 Y0.3755 +G01 X-1.2189 Y0.3701 +G01 X-1.2089 Y0.3601 +G01 X-1.2064 Y0.3541 +G01 X-1.1518 Y0.2994 +G01 X-1.1511 Y0.3001 +G01 X-1.1381 Y0.3055 +G01 X-1.0619 Y0.3055 +G01 X-1.0489 Y0.3001 +G01 X-1.0413 Y0.2925 +G01 X-1.0152 Y0.2925 +G01 X-0.9852 Y0.3225 +G01 X-0.9748 Y0.3225 +G01 X-0.9375 Y0.3225 +G01 X-0.9375 Y0.4252 +G01 X-0.9302 Y0.4325 +G01 X-0.9198 Y0.4325 +G01 X-0.8202 Y0.4325 +G01 X-0.6825 Y0.5702 +G01 X-0.6825 Y0.6848 +G01 X-0.7525 Y0.7549 +G01 X-0.7557 Y0.7536 +G01 X-0.7698 Y0.7536 +G01 X-0.7829 Y0.7590 +G01 X-0.7928 Y0.7689 +G01 X-0.7983 Y0.7820 +G01 X-0.7983 Y0.8581 +G01 X-0.7928 Y0.8712 +G01 X-0.7829 Y0.8811 +G01 X-0.7698 Y0.8866 +G01 X-0.7557 Y0.8866 +G01 X-0.7426 Y0.8811 +G01 X-0.7327 Y0.8712 +G01 X-0.7273 Y0.8581 +G01 X-0.7273 Y0.7820 +G01 X-0.7323 Y0.7699 +G01 X-0.6575 Y0.6952 +G01 X-0.6575 Y0.6848 +G01 X-0.6575 Y0.5702 +G01 X-0.6575 Y0.5598 +G01 X-0.8025 Y0.4148 +G01 X-0.8098 Y0.4075 +G01 X-0.9125 Y0.4075 +G01 X-0.9125 Y0.3225 +G01 X-0.7102 Y0.3225 +G01 X-0.6602 Y0.3725 +G01 X-0.6498 Y0.3725 +G01 X-0.5302 Y0.3725 +G01 X-0.3402 Y0.5625 +G01 X-0.3298 Y0.5625 +G01 X-0.3084 Y0.5625 +G01 X-0.3295 Y0.5836 +G01 X-0.3295 Y0.6164 +G01 X-0.3084 Y0.6375 +G01 X-0.3348 Y0.6375 +G01 X-0.4675 Y0.5048 +G01 X-0.4675 Y0.4998 +G01 X-0.5425 Y0.4248 +G01 X-0.5498 Y0.4175 +G01 X-0.6898 Y0.4175 +G01 X-0.7335 Y0.3738 +G01 X-0.7335 Y0.3629 +G01 X-0.7389 Y0.3499 +G01 X-0.7489 Y0.3399 +G01 X-0.7619 Y0.3345 +G01 X-0.8381 Y0.3345 +G01 X-0.8511 Y0.3399 +G01 X-0.8611 Y0.3499 +G01 X-0.8665 Y0.3629 +G01 X-0.8665 Y0.3771 +G01 X-0.8611 Y0.3901 +G01 X-0.8511 Y0.4001 +G01 X-0.8381 Y0.4055 +G01 X-0.7619 Y0.4055 +G01 X-0.7489 Y0.4001 +G01 X-0.7457 Y0.3969 +G01 X-0.7002 Y0.4425 +G01 X-0.6898 Y0.4425 +G01 X-0.5602 Y0.4425 +G01 X-0.4925 Y0.5102 +G01 X-0.4925 Y0.5152 +G01 X-0.4852 Y0.5225 +G01 X-0.3452 Y0.6625 +G01 X-0.3348 Y0.6625 +G01 X-0.3084 Y0.6625 +G01 X-0.3295 Y0.6836 +G01 X-0.3295 Y0.7164 +G01 X-0.3084 Y0.7375 +G01 X-0.3448 Y0.7375 +G01 X-0.3552 Y0.7375 +G01 X-0.5052 Y0.8875 +G01 X-1.1448 Y0.8875 +G01 X-1.1975 Y0.8348 +G01 X-1.2048 Y0.8275 +G01 X-1.2058 Y0.8275 +G01 X-1.2089 Y0.8199 +G01 X-1.2189 Y0.8099 +G01 X-1.2319 Y0.8045 +G01 X-1.3081 Y0.8045 +G01 X-1.3211 Y0.8099 +G01 X-1.3311 Y0.8199 +G01 X-1.3325 Y0.8233 +G01 X-1.3325 Y0.8102 +G01 X-1.3248 Y0.8025 +G01 X-1.2002 Y0.8025 +G01 X-1.1775 Y0.8252 +G01 X-1.1702 Y0.8325 +G01 X-0.9557 Y0.8325 +G01 X-0.9557 Y0.8581 +G01 X-0.9503 Y0.8712 +G01 X-0.9403 Y0.8811 +G01 X-0.9273 Y0.8866 +G01 X-0.9132 Y0.8866 +G01 X-0.9001 Y0.8811 +G01 X-0.8901 Y0.8712 +G01 X-0.8847 Y0.8581 +G00 Z0.1000 +G00 X-1.2319 Y0.6045 +G01 Z-0.0070 F10 +G01 X-1.3081 Y0.6045 F20 +G01 X-1.3211 Y0.6099 +G01 X-1.3311 Y0.6199 +G01 X-1.3365 Y0.6329 +G01 X-1.3365 Y0.6471 +G01 X-1.3311 Y0.6601 +G01 X-1.3211 Y0.6701 +G01 X-1.3081 Y0.6755 +G01 X-1.2319 Y0.6755 +G01 X-1.2189 Y0.6701 +G01 X-1.2089 Y0.6601 +G01 X-1.2035 Y0.6471 +G01 X-1.2035 Y0.6425 +G01 X-0.9164 Y0.6425 +G01 X-0.9164 Y0.6780 +G01 X-0.9110 Y0.6911 +G01 X-0.9010 Y0.7010 +G01 X-0.8879 Y0.7064 +G01 X-0.8738 Y0.7064 +G01 X-0.8608 Y0.7010 +G01 X-0.8508 Y0.6911 +G01 X-0.8454 Y0.6780 +G01 X-0.8454 Y0.6019 +G01 X-0.8508 Y0.5888 +G01 X-0.8608 Y0.5789 +G01 X-0.8738 Y0.5734 +G01 X-0.8879 Y0.5734 +G01 X-0.9010 Y0.5789 +G01 X-0.9110 Y0.5888 +G01 X-0.9164 Y0.6019 +G01 X-0.9164 Y0.6175 +G01 X-1.2113 Y0.6175 +G01 X-1.2189 Y0.6099 +G01 X-1.2319 Y0.6045 +G00 Z0.1000 +G00 X-2.3545 Y1.0074 +G01 Z-0.0070 F10 +G01 X-2.3545 Y1.0526 F20 +G01 X-2.3226 Y1.0845 +G01 X-2.2774 Y1.0845 +G01 X-2.2455 Y1.0526 +G01 X-2.2455 Y1.0522 +G01 X-2.1825 Y1.1152 +G01 X-2.1752 Y1.1225 +G01 X-2.1652 Y1.1225 +G01 X-2.1225 Y1.1652 +G01 X-2.1152 Y1.1725 +G01 X-1.9252 Y1.1725 +G01 X-1.9148 Y1.1725 +G01 X-1.7748 Y1.0325 +G01 X-1.7252 Y1.0325 +G01 X-1.6452 Y1.1125 +G01 X-1.6348 Y1.1125 +G01 X-1.5048 Y1.1125 +G01 X-1.4975 Y1.1052 +G01 X-1.4675 Y1.0752 +G01 X-1.4675 Y1.0648 +G01 X-1.4675 Y1.0450 +G01 X-1.3660 Y0.9387 +G01 X-1.3625 Y0.9352 +G01 X-1.3625 Y0.9350 +G01 X-1.3624 Y0.9349 +G01 X-1.3625 Y0.9298 +G01 X-1.3625 Y0.7757 +G01 X-1.3354 Y0.7525 +G01 X-1.3342 Y0.7525 +G01 X-1.3311 Y0.7601 +G01 X-1.3211 Y0.7701 +G01 X-1.3081 Y0.7755 +G01 X-1.2319 Y0.7755 +G01 X-1.2189 Y0.7701 +G01 X-1.2089 Y0.7601 +G01 X-1.2035 Y0.7471 +G01 X-1.2035 Y0.7329 +G01 X-1.2089 Y0.7199 +G01 X-1.2189 Y0.7099 +G01 X-1.2319 Y0.7045 +G01 X-1.3081 Y0.7045 +G01 X-1.3211 Y0.7099 +G01 X-1.3311 Y0.7199 +G01 X-1.3342 Y0.7275 +G01 X-1.3395 Y0.7275 +G01 X-1.3442 Y0.7271 +G01 X-1.3446 Y0.7275 +G01 X-1.3452 Y0.7275 +G01 X-1.3485 Y0.7309 +G01 X-1.3796 Y0.7575 +G01 X-1.3802 Y0.7575 +G01 X-1.3835 Y0.7608 +G01 X-1.3871 Y0.7639 +G01 X-1.3871 Y0.7644 +G01 X-1.3875 Y0.7648 +G01 X-1.3875 Y0.7695 +G01 X-1.3879 Y0.7742 +G01 X-1.3875 Y0.7746 +G01 X-1.3875 Y0.9250 +G01 X-1.4890 Y1.0313 +G01 X-1.4925 Y1.0348 +G01 X-1.4925 Y1.0350 +G01 X-1.4926 Y1.0351 +G01 X-1.4925 Y1.0402 +G01 X-1.4925 Y1.0648 +G01 X-1.5152 Y1.0875 +G01 X-1.6348 Y1.0875 +G01 X-1.7075 Y1.0148 +G01 X-1.7148 Y1.0075 +G01 X-1.7748 Y1.0075 +G01 X-1.7852 Y1.0075 +G01 X-1.9252 Y1.1475 +G01 X-2.1048 Y1.1475 +G01 X-2.1475 Y1.1048 +G01 X-2.1548 Y1.0975 +G01 X-2.1648 Y1.0975 +G01 X-2.2375 Y1.0248 +G01 X-2.2448 Y1.0175 +G01 X-2.2455 Y1.0175 +G01 X-2.2455 Y1.0074 +G01 X-2.2774 Y0.9755 +G01 X-2.3226 Y0.9755 +G01 X-2.3545 Y1.0074 +G00 Z0.1000 +G00 X-0.2188 Y0.3659 +G01 Z-0.0070 F10 +G01 X-0.2225 Y0.3696 F20 +G01 X-0.2225 Y0.3677 +G01 X-0.5228 Y0.0675 +G01 X-0.5172 Y0.0675 +G01 X-0.2188 Y0.3659 +G00 Z0.1000 +G00 X-2.3595 Y1.0054 +G01 Z-0.0070 F10 +G01 X-2.3595 Y1.0546 F20 +G01 X-2.3246 Y1.0895 +G01 X-2.2754 Y1.0895 +G01 X-2.2453 Y1.0594 +G01 X-2.1875 Y1.1172 +G01 X-2.1772 Y1.1275 +G01 X-2.1672 Y1.1275 +G01 X-2.1275 Y1.1672 +G01 X-2.1222 Y1.1725 +G01 X-2.2927 Y1.1725 +G01 X-2.3925 Y1.0727 +G01 X-2.3925 Y0.9972 +G01 X-2.3527 Y0.9575 +G01 X-2.1972 Y0.9575 +G01 X-2.1175 Y1.0372 +G01 X-2.1175 Y1.0672 +G01 X-2.1072 Y1.0775 +G01 X-2.0472 Y1.1375 +G01 X-2.0327 Y1.1375 +G01 X-1.9627 Y1.1375 +G01 X-1.9525 Y1.1272 +G01 X-1.9025 Y1.0772 +G01 X-1.9025 Y1.0627 +G01 X-1.9025 Y0.9922 +G01 X-1.8827 Y0.9725 +G01 X-1.7927 Y0.9725 +G01 X-1.7372 Y0.9725 +G01 X-1.6722 Y1.0375 +G01 X-1.6577 Y1.0375 +G01 X-1.6415 Y1.0375 +G01 X-1.6415 Y1.0481 +G01 X-1.6353 Y1.0629 +G01 X-1.6239 Y1.0743 +G01 X-1.6091 Y1.0805 +G01 X-1.5309 Y1.0805 +G01 X-1.5161 Y1.0743 +G01 X-1.5047 Y1.0629 +G01 X-1.4985 Y1.0481 +G01 X-1.4985 Y1.0333 +G01 X-1.4975 Y1.0322 +G01 X-1.4925 Y1.0272 +G01 X-1.4925 Y1.0270 +G01 X-1.3925 Y0.9222 +G01 X-1.3925 Y0.9230 +G01 X-1.4925 Y1.0278 +G01 X-1.4975 Y1.0327 +G01 X-1.4975 Y1.0330 +G01 X-1.4977 Y1.0332 +G01 X-1.4975 Y1.0402 +G01 X-1.4975 Y1.0627 +G01 X-1.5172 Y1.0825 +G01 X-1.6327 Y1.0825 +G01 X-1.7025 Y1.0127 +G01 X-1.7127 Y1.0025 +G01 X-1.7727 Y1.0025 +G01 X-1.7872 Y1.0025 +G01 X-1.9272 Y1.1425 +G01 X-2.1027 Y1.1425 +G01 X-2.1425 Y1.1027 +G01 X-2.1527 Y1.0925 +G01 X-2.1628 Y1.0925 +G01 X-2.2325 Y1.0228 +G01 X-2.2405 Y1.0148 +G01 X-2.2405 Y1.0054 +G01 X-2.2754 Y0.9705 +G01 X-2.3246 Y0.9705 +G01 X-2.3595 Y1.0054 +G00 Z0.1000 +G00 X-1.9031 Y0.2847 +G01 Z-0.0070 F10 +G01 X-1.8891 Y0.2905 F20 +G01 X-1.8142 Y0.2905 +G01 X-1.6472 Y0.4575 +G01 X-1.6376 Y0.4575 +G01 X-1.6353 Y0.4629 +G01 X-1.6239 Y0.4743 +G01 X-1.6091 Y0.4805 +G01 X-1.5309 Y0.4805 +G01 X-1.5161 Y0.4743 +G01 X-1.5075 Y0.4658 +G01 X-1.5075 Y0.5142 +G01 X-1.5161 Y0.5057 +G01 X-1.5309 Y0.4995 +G01 X-1.6091 Y0.4995 +G01 X-1.6239 Y0.5057 +G01 X-1.6268 Y0.5085 +G01 X-1.6625 Y0.4728 +G01 X-1.6727 Y0.4625 +G01 X-1.7602 Y0.4625 +G01 X-1.7832 Y0.4395 +G01 X-1.8058 Y0.4395 +G01 X-1.8325 Y0.4127 +G01 X-1.8325 Y0.3905 +G01 X-1.8109 Y0.3905 +G01 X-1.7961 Y0.3843 +G01 X-1.7847 Y0.3729 +G01 X-1.7785 Y0.3581 +G01 X-1.7785 Y0.3419 +G01 X-1.7847 Y0.3271 +G01 X-1.7961 Y0.3157 +G01 X-1.8109 Y0.3095 +G01 X-1.8891 Y0.3095 +G01 X-1.9039 Y0.3157 +G01 X-1.9125 Y0.3242 +G01 X-1.9125 Y0.2929 +G01 X-1.9031 Y0.2847 +G00 Z0.1000 +G00 X-1.9525 Y0.4072 +G01 Z-0.0070 F10 +G01 X-1.9525 Y0.4066 F20 +G01 X-1.9521 Y0.4061 +G01 X-1.9525 Y0.3994 +G01 X-1.9525 Y0.2280 +G01 X-1.9023 Y0.1850 +G01 X-1.8891 Y0.1905 +G01 X-1.8109 Y0.1905 +G01 X-1.7961 Y0.1843 +G01 X-1.7857 Y0.1740 +G01 X-1.7580 Y0.1768 +G01 X-1.6265 Y0.3082 +G01 X-1.6353 Y0.3171 +G01 X-1.6415 Y0.3319 +G01 X-1.6415 Y0.3481 +G01 X-1.6353 Y0.3629 +G01 X-1.6239 Y0.3743 +G01 X-1.6091 Y0.3805 +G01 X-1.5309 Y0.3805 +G01 X-1.5161 Y0.3743 +G01 X-1.5075 Y0.3658 +G01 X-1.5075 Y0.4142 +G01 X-1.5161 Y0.4057 +G01 X-1.5309 Y0.3995 +G01 X-1.6091 Y0.3995 +G01 X-1.6239 Y0.4057 +G01 X-1.6353 Y0.4171 +G01 X-1.6362 Y0.4191 +G01 X-1.7840 Y0.2713 +G01 X-1.7785 Y0.2581 +G01 X-1.7785 Y0.2419 +G01 X-1.7847 Y0.2271 +G01 X-1.7961 Y0.2157 +G01 X-1.8109 Y0.2095 +G01 X-1.8891 Y0.2095 +G01 X-1.9039 Y0.2157 +G01 X-1.9153 Y0.2271 +G01 X-1.9215 Y0.2419 +G01 X-1.9215 Y0.2543 +G01 X-1.9366 Y0.2675 +G01 X-1.9372 Y0.2675 +G01 X-1.9420 Y0.2722 +G01 X-1.9470 Y0.2766 +G01 X-1.9470 Y0.2773 +G01 X-1.9475 Y0.2777 +G01 X-1.9475 Y0.2844 +G01 X-1.9479 Y0.2911 +G01 X-1.9475 Y0.2916 +G01 X-1.9475 Y0.4502 +G01 X-1.9605 Y0.4632 +G01 X-1.9605 Y0.4968 +G01 X-1.9368 Y0.5205 +G01 X-1.9032 Y0.5205 +G01 X-1.8795 Y0.4968 +G01 X-1.8795 Y0.4632 +G01 X-1.9032 Y0.4395 +G01 X-1.9125 Y0.4395 +G01 X-1.9125 Y0.3758 +G01 X-1.9039 Y0.3843 +G01 X-1.8891 Y0.3905 +G01 X-1.8675 Y0.3905 +G01 X-1.8675 Y0.4272 +G01 X-1.8572 Y0.4375 +G01 X-1.8360 Y0.4587 +G01 X-1.8405 Y0.4632 +G01 X-1.8405 Y0.4968 +G01 X-1.8168 Y0.5205 +G01 X-1.7832 Y0.5205 +G01 X-1.7602 Y0.4975 +G01 X-1.6872 Y0.4975 +G01 X-1.6415 Y0.5432 +G01 X-1.6415 Y0.5481 +G01 X-1.6353 Y0.5629 +G01 X-1.6239 Y0.5743 +G01 X-1.6091 Y0.5805 +G01 X-1.5309 Y0.5805 +G01 X-1.5161 Y0.5743 +G01 X-1.5075 Y0.5658 +G01 X-1.5075 Y0.6142 +G01 X-1.5161 Y0.6057 +G01 X-1.5309 Y0.5995 +G01 X-1.6091 Y0.5995 +G01 X-1.6239 Y0.6057 +G01 X-1.6353 Y0.6171 +G01 X-1.6415 Y0.6319 +G01 X-1.6415 Y0.6481 +G01 X-1.6353 Y0.6629 +G01 X-1.6239 Y0.6743 +G01 X-1.6091 Y0.6805 +G01 X-1.5309 Y0.6805 +G01 X-1.5161 Y0.6743 +G01 X-1.5150 Y0.6733 +G01 X-1.5125 Y0.6763 +G01 X-1.5125 Y0.7092 +G01 X-1.5161 Y0.7057 +G01 X-1.5309 Y0.6995 +G01 X-1.6091 Y0.6995 +G01 X-1.6239 Y0.7057 +G01 X-1.6353 Y0.7171 +G01 X-1.6355 Y0.7175 +G01 X-1.6377 Y0.7175 +G01 X-1.6425 Y0.7127 +G01 X-1.6425 Y0.5727 +G01 X-1.6527 Y0.5625 +G01 X-1.6827 Y0.5325 +G01 X-1.6972 Y0.5325 +G01 X-2.0627 Y0.5325 +G01 X-2.0925 Y0.5028 +G01 X-2.0925 Y0.4722 +G01 X-2.0527 Y0.4325 +G01 X-2.0227 Y0.4325 +G01 X-2.0142 Y0.4240 +G01 X-2.0278 Y0.4395 +G01 X-2.0568 Y0.4395 +G01 X-2.0805 Y0.4632 +G01 X-2.0805 Y0.4968 +G01 X-2.0568 Y0.5205 +G01 X-2.0232 Y0.5205 +G01 X-1.9995 Y0.4968 +G01 X-1.9995 Y0.4632 +G01 X-2.0009 Y0.4619 +G01 X-1.9572 Y0.4120 +G01 X-1.9525 Y0.4072 +G00 Z0.1000 +G00 X-1.8109 Y0.1095 +G01 Z-0.0070 F10 +G01 X-1.8891 Y0.1095 F20 +G01 X-1.9039 Y0.1157 +G01 X-1.9153 Y0.1271 +G01 X-1.9215 Y0.1419 +G01 X-1.9215 Y0.1554 +G01 X-1.9765 Y0.2025 +G01 X-1.9772 Y0.2025 +G01 X-1.9819 Y0.2072 +G01 X-1.9869 Y0.2114 +G01 X-1.9869 Y0.2122 +G01 X-1.9875 Y0.2127 +G01 X-1.9875 Y0.2193 +G01 X-1.9880 Y0.2259 +G01 X-1.9875 Y0.2265 +G01 X-1.9875 Y0.3934 +G01 X-1.9925 Y0.3991 +G01 X-1.9925 Y0.3877 +G01 X-1.9925 Y0.1872 +G01 X-1.9028 Y0.0975 +G01 X-1.4722 Y0.0975 +G01 X-1.5075 Y0.1327 +G01 X-1.5075 Y0.1472 +G01 X-1.5075 Y0.3142 +G01 X-1.5161 Y0.3057 +G01 X-1.5309 Y0.2995 +G01 X-1.5857 Y0.2995 +G01 X-1.7370 Y0.1482 +G01 X-1.7410 Y0.1433 +G01 X-1.7420 Y0.1432 +G01 X-1.7427 Y0.1425 +G01 X-1.7491 Y0.1425 +G01 X-1.7795 Y0.1395 +G01 X-1.7847 Y0.1271 +G01 X-1.7961 Y0.1157 +G01 X-1.8109 Y0.1095 +G00 Z0.1000 +G00 X-1.3495 Y1.1532 +G01 Z-0.0070 F10 +G01 X-1.3652 Y1.1375 F20 +G01 X-1.3172 Y1.1375 +G01 X-1.2853 Y1.1694 +G01 X-1.2843 Y1.1724 +G01 X-1.2825 Y1.1733 +G01 X-1.2825 Y1.1928 +G01 X-1.3127 Y1.1625 +G01 X-1.3272 Y1.1625 +G01 X-1.3495 Y1.1625 +G01 X-1.3495 Y1.1532 +G00 Z0.1000 +G00 X-1.2427 Y1.2325 +G01 Z-0.0070 F10 +G01 X-1.2428 Y1.2325 F20 +G01 X-1.2083 Y1.2325 +G01 X-1.1777 Y1.2020 +G01 X-1.1774 Y1.2027 +G01 X-1.2072 Y1.2325 +G01 X-1.2427 Y1.2325 +G00 Z0.1000 +G00 X-1.1985 Y0.4319 +G01 Z-0.0070 F10 +G01 X-1.2047 Y0.4171 F20 +G01 X-1.2161 Y0.4057 +G01 X-1.2309 Y0.3995 +G01 X-1.3091 Y0.3995 +G01 X-1.3239 Y0.4057 +G01 X-1.3353 Y0.4171 +G01 X-1.3415 Y0.4319 +G01 X-1.3415 Y0.4481 +G01 X-1.3353 Y0.4629 +G01 X-1.3258 Y0.4725 +G01 X-1.3875 Y0.4725 +G01 X-1.3875 Y0.3572 +G01 X-1.3627 Y0.3325 +G01 X-1.3525 Y0.3222 +G01 X-1.3525 Y0.2698 +G01 X-1.3295 Y0.2468 +G01 X-1.3295 Y0.2242 +G01 X-1.3027 Y0.1975 +G01 X-1.2948 Y0.1975 +G01 X-1.3105 Y0.2132 +G01 X-1.3105 Y0.2468 +G01 X-1.2868 Y0.2705 +G01 X-1.2775 Y0.2705 +G01 X-1.2775 Y0.2995 +G01 X-1.3091 Y0.2995 +G01 X-1.3239 Y0.3057 +G01 X-1.3353 Y0.3171 +G01 X-1.3415 Y0.3319 +G01 X-1.3415 Y0.3481 +G01 X-1.3353 Y0.3629 +G01 X-1.3239 Y0.3743 +G01 X-1.3091 Y0.3805 +G01 X-1.2309 Y0.3805 +G01 X-1.2161 Y0.3743 +G01 X-1.2047 Y0.3629 +G01 X-1.2022 Y0.3569 +G01 X-1.1509 Y0.3056 +G01 X-1.1391 Y0.3105 +G01 X-1.0609 Y0.3105 +G01 X-1.0461 Y0.3043 +G01 X-1.0392 Y0.2975 +G01 X-1.0172 Y0.2975 +G01 X-0.9872 Y0.3275 +G01 X-0.9727 Y0.3275 +G01 X-0.9425 Y0.3275 +G01 X-0.9425 Y0.4272 +G01 X-0.9372 Y0.4325 +G01 X-1.1985 Y0.4325 +G01 X-1.1985 Y0.4319 +G00 Z0.1000 +G00 X-0.8222 Y0.4375 +G01 Z-0.0070 F10 +G01 X-0.6875 Y0.5722 F20 +G01 X-0.6875 Y0.5898 +G01 X-0.6891 Y0.5860 +G01 X-0.7004 Y0.5746 +G01 X-0.7025 Y0.5738 +G01 X-0.7025 Y0.5677 +G01 X-0.7127 Y0.5575 +G01 X-0.8328 Y0.4375 +G01 X-0.8222 Y0.4375 +G00 Z0.1000 +G00 X-0.7463 Y0.5746 +G01 Z-0.0070 F10 +G01 X-0.7577 Y0.5860 F20 +G01 X-0.7628 Y0.5982 +G01 X-0.7678 Y0.5860 +G01 X-0.7792 Y0.5746 +G01 X-0.7825 Y0.5732 +G01 X-0.7825 Y0.5677 +G01 X-0.8777 Y0.4725 +G01 X-0.8922 Y0.4725 +G01 X-1.2142 Y0.4725 +G01 X-1.2092 Y0.4675 +G01 X-0.8522 Y0.4675 +G01 X-0.7455 Y0.5743 +G01 X-0.7463 Y0.5746 +G00 Z0.1000 +G00 X-0.3975 Y0.3772 +G01 Z-0.0070 F10 +G01 X-0.3975 Y0.4027 F20 +G01 X-0.3975 Y0.4172 +G01 X-0.3338 Y0.4809 +G01 X-0.3345 Y0.4816 +G01 X-0.3345 Y0.5184 +G01 X-0.3204 Y0.5325 +G01 X-0.3277 Y0.5325 +G01 X-0.5075 Y0.3527 +G01 X-0.5177 Y0.3425 +G01 X-0.6477 Y0.3425 +G01 X-0.6875 Y0.3027 +G01 X-0.6977 Y0.2925 +G01 X-0.9227 Y0.2925 +G01 X-0.9372 Y0.2925 +G01 X-0.9727 Y0.2925 +G01 X-1.0027 Y0.2625 +G01 X-1.0172 Y0.2625 +G01 X-1.0285 Y0.2625 +G01 X-1.0285 Y0.2619 +G01 X-1.0347 Y0.2471 +G01 X-1.0461 Y0.2357 +G01 X-1.0609 Y0.2295 +G01 X-1.1391 Y0.2295 +G01 X-1.1539 Y0.2357 +G01 X-1.1653 Y0.2471 +G01 X-1.1715 Y0.2619 +G01 X-1.1715 Y0.2767 +G01 X-1.2082 Y0.3135 +G01 X-1.2161 Y0.3057 +G01 X-1.2309 Y0.2995 +G01 X-1.2425 Y0.2995 +G01 X-1.2425 Y0.2598 +G01 X-1.2295 Y0.2468 +G01 X-1.2295 Y0.2132 +G01 X-1.2452 Y0.1975 +G01 X-1.0372 Y0.1975 +G01 X-0.9572 Y0.2775 +G01 X-0.9427 Y0.2775 +G01 X-0.6715 Y0.2775 +G01 X-0.6715 Y0.2781 +G01 X-0.6653 Y0.2929 +G01 X-0.6539 Y0.3043 +G01 X-0.6391 Y0.3105 +G01 X-0.5609 Y0.3105 +G01 X-0.5461 Y0.3043 +G01 X-0.5347 Y0.2929 +G01 X-0.5285 Y0.2781 +G01 X-0.5285 Y0.2619 +G01 X-0.5347 Y0.2471 +G01 X-0.5461 Y0.2357 +G01 X-0.5609 Y0.2295 +G01 X-0.6391 Y0.2295 +G01 X-0.6539 Y0.2357 +G01 X-0.6608 Y0.2425 +G01 X-0.9427 Y0.2425 +G01 X-1.0125 Y0.1727 +G01 X-1.0227 Y0.1625 +G01 X-1.3027 Y0.1625 +G01 X-1.3172 Y0.1625 +G01 X-1.3487 Y0.1940 +G01 X-1.3532 Y0.1895 +G01 X-1.3868 Y0.1895 +G01 X-1.4105 Y0.2132 +G01 X-1.4105 Y0.2468 +G01 X-1.3875 Y0.2698 +G01 X-1.3875 Y0.3077 +G01 X-1.4225 Y0.3427 +G01 X-1.4225 Y0.3572 +G01 X-1.4225 Y0.4972 +G01 X-1.4225 Y0.5277 +G01 X-1.4225 Y0.5327 +G01 X-1.4225 Y0.6075 +G01 X-1.4325 Y0.5942 +G01 X-1.4325 Y0.1772 +G01 X-1.4127 Y0.1575 +G01 X-0.6172 Y0.1575 +G01 X-0.3975 Y0.3772 +G00 Z0.1000 +G00 X-0.2084 Y0.4445 +G01 Z-0.0070 F10 +G01 X-0.1716 Y0.4445 F20 +G01 X-0.1575 Y0.4304 +G01 X-0.1575 Y0.4696 +G01 X-0.1716 Y0.4555 +G01 X-0.2084 Y0.4555 +G01 X-0.2091 Y0.4562 +G01 X-0.2225 Y0.4427 +G01 X-0.2225 Y0.4304 +G01 X-0.2084 Y0.4445 +G00 Z0.1000 +G00 X-0.5422 Y0.0975 +G01 Z-0.0070 F10 +G01 X-0.2842 Y0.3555 F20 +G01 X-0.3084 Y0.3555 +G01 X-0.3091 Y0.3562 +G01 X-0.5625 Y0.1027 +G01 X-0.5678 Y0.0975 +G01 X-0.5422 Y0.0975 +G00 Z0.1000 +G00 X-0.2575 Y0.4427 +G01 Z-0.0070 F10 +G01 X-0.2575 Y0.4572 F20 +G01 X-0.2338 Y0.4809 +G01 X-0.2345 Y0.4816 +G01 X-0.2345 Y0.5184 +G01 X-0.2204 Y0.5325 +G01 X-0.2596 Y0.5325 +G01 X-0.2455 Y0.5184 +G01 X-0.2455 Y0.4816 +G01 X-0.2716 Y0.4555 +G01 X-0.3084 Y0.4555 +G01 X-0.3091 Y0.4562 +G01 X-0.3625 Y0.4027 +G01 X-0.3625 Y0.3627 +G01 X-0.3727 Y0.3525 +G01 X-0.5925 Y0.1327 +G01 X-0.5978 Y0.1275 +G01 X-0.5872 Y0.1275 +G01 X-0.3338 Y0.3809 +G01 X-0.3345 Y0.3816 +G01 X-0.3345 Y0.4184 +G01 X-0.3084 Y0.4445 +G01 X-0.2716 Y0.4445 +G01 X-0.2575 Y0.4304 +G01 X-0.2575 Y0.4427 +G00 Z0.1000 +G00 X-1.5047 Y0.8171 +G01 Z-0.0070 F10 +G01 X-1.5142 Y0.8075 F20 +G01 X-1.5041 Y0.8075 +G01 X-1.5013 Y0.8089 +G01 X-1.4972 Y0.8075 +G01 X-1.4948 Y0.8075 +G01 X-1.5042 Y0.8182 +G01 X-1.5047 Y0.8171 +G00 Z0.1000 +G00 X-1.4525 Y0.8232 +G01 Z-0.0070 F10 +G01 X-1.4977 Y0.8725 F20 +G01 X-1.5142 Y0.8725 +G01 X-1.5047 Y0.8629 +G01 X-1.5025 Y0.8577 +G01 X-1.4994 Y0.8575 +G01 X-1.4927 Y0.8575 +G01 X-1.4923 Y0.8570 +G01 X-1.4916 Y0.8570 +G01 X-1.4872 Y0.8520 +G01 X-1.4825 Y0.8472 +G01 X-1.4825 Y0.8466 +G01 X-1.4525 Y0.8123 +G01 X-1.4525 Y0.8232 +G00 Z0.1000 +G00 X-1.4825 Y0.6577 +G01 Z-0.0070 F10 +G01 X-1.4985 Y0.6385 F20 +G01 X-1.4985 Y0.6371 +G01 X-1.4825 Y0.6563 +G01 X-1.4825 Y0.6577 +G00 Z0.1000 +G00 X-0.4872 Y0.0375 +G01 Z-0.0070 F10 +G01 X-0.1575 Y0.3672 F20 +G01 X-0.1575 Y0.3696 +G01 X-0.1716 Y0.3555 +G01 X-0.1797 Y0.3555 +G01 X-0.4925 Y0.0427 +G01 X-0.4978 Y0.0375 +G01 X-0.4872 Y0.0375 +G00 Z0.1000 +G00 X-0.1575 Y0.5304 +G01 Z-0.0070 F10 +G01 X-0.1575 Y0.5362 F20 +G01 X-0.1602 Y0.5351 +G01 X-0.1612 Y0.5341 +G01 X-0.1575 Y0.5304 +G00 Z0.1000 +G00 X-0.8579 Y0.7053 +G01 Z-0.0070 F10 +G01 X-0.8465 Y0.6939 F20 +G01 X-0.8415 Y0.6817 +G01 X-0.8365 Y0.6939 +G01 X-0.8251 Y0.7053 +G01 X-0.8102 Y0.7114 +G01 X-0.7941 Y0.7114 +G01 X-0.7792 Y0.7053 +G01 X-0.7678 Y0.6939 +G01 X-0.7628 Y0.6817 +G01 X-0.7577 Y0.6939 +G01 X-0.7463 Y0.7053 +G01 X-0.7314 Y0.7114 +G01 X-0.7162 Y0.7114 +G01 X-0.7537 Y0.7490 +G01 X-0.7547 Y0.7486 +G01 X-0.7708 Y0.7486 +G01 X-0.7857 Y0.7547 +G01 X-0.7971 Y0.7661 +G01 X-0.8021 Y0.7783 +G01 X-0.8072 Y0.7661 +G01 X-0.8186 Y0.7547 +G01 X-0.8275 Y0.7510 +G01 X-0.8275 Y0.7477 +G01 X-0.8377 Y0.7375 +G01 X-0.8664 Y0.7088 +G01 X-0.8579 Y0.7053 +G00 Z0.1000 +G00 X-0.3254 Y0.9725 +G01 Z-0.0070 F10 +G01 X-0.3802 Y0.9725 F20 +G01 X-0.3852 Y0.9675 +G01 X-0.3204 Y0.9675 +G01 X-0.3254 Y0.9725 +G00 Z0.1000 +G00 X-0.8072 Y0.8740 +G01 Z-0.0070 F10 +G01 X-0.8021 Y0.8618 F20 +G01 X-0.7971 Y0.8740 +G01 X-0.7886 Y0.8825 +G01 X-0.8157 Y0.8825 +G01 X-0.8072 Y0.8740 +G00 Z0.1000 +G00 X-0.8859 Y0.8740 +G01 Z-0.0070 F10 +G01 X-0.8809 Y0.8618 F20 +G01 X-0.8758 Y0.8740 +G01 X-0.8673 Y0.8825 +G01 X-0.8944 Y0.8825 +G01 X-0.8859 Y0.8740 +G00 Z0.1000 +G00 X-0.1455 Y0.6184 +G01 Z-0.0070 F10 +G01 X-0.1455 Y0.5842 F20 +G01 X-0.1175 Y0.6122 +G01 X-0.1175 Y0.6675 +G01 X-0.1185 Y0.6667 +G01 X-0.1227 Y0.6625 +G01 X-0.1242 Y0.6625 +G01 X-0.1585 Y0.6367 +G01 X-0.1612 Y0.6341 +G01 X-0.1455 Y0.6184 +G00 Z0.1000 +G00 X-0.1227 Y0.8375 +G01 Z-0.0070 F10 +G01 X-0.1185 Y0.8333 F20 +G01 X-0.1175 Y0.8325 +G01 X-0.1175 Y0.9075 +G01 X-0.1700 Y0.9571 +G01 X-0.1716 Y0.9555 +G01 X-0.2084 Y0.9555 +G01 X-0.2345 Y0.9816 +G01 X-0.2345 Y1.0184 +G01 X-0.2313 Y1.0216 +G01 X-0.3522 Y1.1425 +G01 X-1.0872 Y1.1425 +G01 X-1.0913 Y1.1411 +G01 X-1.0935 Y1.1422 +G01 X-1.1003 Y1.1355 +G01 X-1.1196 Y1.1275 +G01 X-1.1404 Y1.1275 +G01 X-1.1597 Y1.1355 +G01 X-1.1745 Y1.1503 +G01 X-1.1777 Y1.1580 +G01 X-1.1805 Y1.1552 +G01 X-1.1527 Y1.1275 +G01 X-0.4927 Y1.1275 +G01 X-0.4825 Y1.1172 +G01 X-0.4058 Y1.0405 +G01 X-0.3932 Y1.0405 +G01 X-0.3695 Y1.0168 +G01 X-0.3695 Y1.0075 +G01 X-0.3345 Y1.0075 +G01 X-0.3345 Y1.0184 +G01 X-0.3084 Y1.0445 +G01 X-0.2716 Y1.0445 +G01 X-0.2455 Y1.0184 +G01 X-0.2455 Y0.9816 +G01 X-0.2596 Y0.9675 +G01 X-0.2472 Y0.9675 +G01 X-0.2327 Y0.9675 +G01 X-0.2091 Y0.9438 +G01 X-0.2084 Y0.9445 +G01 X-0.1716 Y0.9445 +G01 X-0.1455 Y0.9184 +G01 X-0.1455 Y0.8816 +G01 X-0.1612 Y0.8659 +G01 X-0.1585 Y0.8633 +G01 X-0.1242 Y0.8375 +G01 X-0.1227 Y0.8375 +G00 Z0.1000 +G00 X-0.3084 Y0.8445 +G01 Z-0.0070 F10 +G01 X-0.2716 Y0.8445 F20 +G01 X-0.2455 Y0.8184 +G01 X-0.2455 Y0.7816 +G01 X-0.2596 Y0.7675 +G01 X-0.2472 Y0.7675 +G01 X-0.2338 Y0.7809 +G01 X-0.2345 Y0.7816 +G01 X-0.2345 Y0.8184 +G01 X-0.2204 Y0.8325 +G01 X-0.2327 Y0.8325 +G01 X-0.2472 Y0.8325 +G01 X-0.2709 Y0.8562 +G01 X-0.2716 Y0.8555 +G01 X-0.3084 Y0.8555 +G01 X-0.3345 Y0.8816 +G01 X-0.3345 Y0.9184 +G01 X-0.3204 Y0.9325 +G01 X-0.4342 Y0.9325 +G01 X-0.3312 Y0.8217 +G01 X-0.3084 Y0.8445 +G00 Z0.1000 +G00 X-0.2204 Y0.8675 +G01 Z-0.0070 F10 +G01 X-0.2345 Y0.8816 F20 +G01 X-0.2345 Y0.9184 +G01 X-0.2338 Y0.9191 +G01 X-0.2472 Y0.9325 +G01 X-0.2596 Y0.9325 +G01 X-0.2455 Y0.9184 +G01 X-0.2455 Y0.8816 +G01 X-0.2462 Y0.8809 +G01 X-0.2327 Y0.8675 +G01 X-0.2204 Y0.8675 +G00 Z0.1000 +G00 X-0.2455 Y0.6184 +G01 Z-0.0070 F10 +G01 X-0.2455 Y0.5816 F20 +G01 X-0.2596 Y0.5675 +G01 X-0.2204 Y0.5675 +G01 X-0.2345 Y0.5816 +G01 X-0.2345 Y0.6184 +G01 X-0.2204 Y0.6325 +G01 X-0.2596 Y0.6325 +G01 X-0.2455 Y0.6184 +G00 Z0.1000 +G00 X-0.7285 Y0.3619 +G01 Z-0.0070 F10 +G01 X-0.7347 Y0.3471 F20 +G01 X-0.7461 Y0.3357 +G01 X-0.7609 Y0.3295 +G01 X-0.8391 Y0.3295 +G01 X-0.8539 Y0.3357 +G01 X-0.8653 Y0.3471 +G01 X-0.8715 Y0.3619 +G01 X-0.8715 Y0.3781 +G01 X-0.8653 Y0.3929 +G01 X-0.8558 Y0.4025 +G01 X-0.9075 Y0.4025 +G01 X-0.9075 Y0.3275 +G01 X-0.7122 Y0.3275 +G01 X-0.6622 Y0.3775 +G01 X-0.6477 Y0.3775 +G01 X-0.5322 Y0.3775 +G01 X-0.3422 Y0.5675 +G01 X-0.3277 Y0.5675 +G01 X-0.3204 Y0.5675 +G01 X-0.3345 Y0.5816 +G01 X-0.3345 Y0.6184 +G01 X-0.3204 Y0.6325 +G01 X-0.3327 Y0.6325 +G01 X-0.4625 Y0.5027 +G01 X-0.4625 Y0.4977 +G01 X-0.5375 Y0.4227 +G01 X-0.5477 Y0.4125 +G01 X-0.6877 Y0.4125 +G01 X-0.7285 Y0.3717 +G01 X-0.7285 Y0.3619 +G00 Z0.1000 +G00 X-0.3345 Y0.6816 +G01 Z-0.0070 F10 +G01 X-0.3345 Y0.7184 F20 +G01 X-0.3204 Y0.7325 +G01 X-0.3427 Y0.7325 +G01 X-0.3572 Y0.7325 +G01 X-0.5072 Y0.8825 +G01 X-0.7369 Y0.8825 +G01 X-0.7284 Y0.8740 +G01 X-0.7223 Y0.8591 +G01 X-0.7223 Y0.7810 +G01 X-0.7264 Y0.7711 +G01 X-0.6525 Y0.6972 +G01 X-0.6525 Y0.6827 +G01 X-0.6525 Y0.5722 +G01 X-0.6525 Y0.5577 +G01 X-0.7975 Y0.4127 +G01 X-0.7998 Y0.4105 +G01 X-0.7609 Y0.4105 +G01 X-0.7461 Y0.4043 +G01 X-0.7457 Y0.4040 +G01 X-0.7022 Y0.4475 +G01 X-0.6877 Y0.4475 +G01 X-0.5622 Y0.4475 +G01 X-0.4975 Y0.5122 +G01 X-0.4975 Y0.5172 +G01 X-0.4872 Y0.5275 +G01 X-0.3472 Y0.6675 +G01 X-0.3327 Y0.6675 +G01 X-0.3204 Y0.6675 +G01 X-0.3345 Y0.6816 +G00 Z0.1000 +G00 X-0.1716 Y0.7555 +G01 Z-0.0070 F10 +G01 X-0.2084 Y0.7555 F20 +G01 X-0.2091 Y0.7562 +G01 X-0.2225 Y0.7427 +G01 X-0.2327 Y0.7325 +G01 X-0.2596 Y0.7325 +G01 X-0.2455 Y0.7184 +G01 X-0.2455 Y0.6816 +G01 X-0.2596 Y0.6675 +G01 X-0.2204 Y0.6675 +G01 X-0.2345 Y0.6816 +G01 X-0.2345 Y0.7184 +G01 X-0.2084 Y0.7445 +G01 X-0.1716 Y0.7445 +G01 X-0.1475 Y0.7204 +G01 X-0.1475 Y0.7796 +G01 X-0.1716 Y0.7555 +G00 Z0.1000 +G00 X-1.2309 Y0.5995 +G01 Z-0.0070 F10 +G01 X-1.3091 Y0.5995 F20 +G01 X-1.3239 Y0.6057 +G01 X-1.3353 Y0.6171 +G01 X-1.3415 Y0.6319 +G01 X-1.3415 Y0.6481 +G01 X-1.3375 Y0.6578 +G01 X-1.3425 Y0.6527 +G01 X-1.3425 Y0.6172 +G01 X-1.3058 Y0.5805 +G01 X-1.2309 Y0.5805 +G01 X-1.2161 Y0.5743 +G01 X-1.2047 Y0.5629 +G01 X-1.1985 Y0.5481 +G01 X-1.1985 Y0.5319 +G01 X-1.2047 Y0.5171 +G01 X-1.2142 Y0.5075 +G01 X-0.8922 Y0.5075 +G01 X-0.8251 Y0.5746 +G01 X-0.8365 Y0.5860 +G01 X-0.8415 Y0.5982 +G01 X-0.8465 Y0.5860 +G01 X-0.8579 Y0.5746 +G01 X-0.8728 Y0.5684 +G01 X-0.8889 Y0.5684 +G01 X-0.9038 Y0.5746 +G01 X-0.9152 Y0.5860 +G01 X-0.9214 Y0.6009 +G01 X-0.9214 Y0.6125 +G01 X-1.2092 Y0.6125 +G01 X-1.2161 Y0.6057 +G01 X-1.2309 Y0.5995 +G00 Z0.1000 +G00 X-0.9214 Y0.6790 +G01 Z-0.0070 F10 +G01 X-0.9152 Y0.6939 F20 +G01 X-0.9038 Y0.7053 +G01 X-0.8984 Y0.7075 +G01 X-0.9077 Y0.7075 +G01 X-0.9427 Y0.6725 +G01 X-0.9572 Y0.6725 +G01 X-1.2142 Y0.6725 +G01 X-1.2047 Y0.6629 +G01 X-1.1985 Y0.6481 +G01 X-1.1985 Y0.6475 +G01 X-0.9214 Y0.6475 +G01 X-0.9214 Y0.6790 +G00 Z0.1000 +G00 X-1.3258 Y1.0075 +G01 Z-0.0070 F10 +G01 X-1.3353 Y1.0171 F20 +G01 X-1.3415 Y1.0319 +G01 X-1.3415 Y1.0481 +G01 X-1.3353 Y1.0629 +G01 X-1.3239 Y1.0743 +G01 X-1.3091 Y1.0805 +G01 X-1.2309 Y1.0805 +G01 X-1.2161 Y1.0743 +G01 X-1.2092 Y1.0675 +G01 X-0.4972 Y1.0675 +G01 X-0.4827 Y1.0675 +G01 X-0.4527 Y1.0375 +G01 X-0.4425 Y1.0272 +G01 X-0.4425 Y1.0248 +G01 X-0.4410 Y1.0263 +G01 X-0.5072 Y1.0925 +G01 X-1.1527 Y1.0925 +G01 X-1.1672 Y1.0925 +G01 X-1.2052 Y1.1305 +G01 X-1.2083 Y1.1275 +G01 X-1.2517 Y1.1275 +G01 X-1.2647 Y1.1405 +G01 X-1.2925 Y1.1128 +G01 X-1.3027 Y1.1025 +G01 X-1.4127 Y1.1025 +G01 X-1.4272 Y1.1025 +G01 X-1.4472 Y1.1225 +G01 X-1.4575 Y1.1327 +G01 X-1.4575 Y1.1452 +G01 X-1.4690 Y1.1337 +G01 X-1.3427 Y1.0075 +G01 X-1.3327 Y1.0075 +G01 X-1.3258 Y1.0075 +G00 Z0.1000 +G00 X-1.3575 Y0.7780 +G01 Z-0.0070 F10 +G01 X-1.3365 Y0.7601 F20 +G01 X-1.3353 Y0.7629 +G01 X-1.3258 Y0.7725 +G01 X-1.3372 Y0.7725 +G01 X-1.3475 Y0.7827 +G01 X-1.3575 Y0.7928 +G01 X-1.3575 Y0.7780 +G00 Z0.1000 +G00 X-0.9607 Y0.8591 +G01 Z-0.0070 F10 +G01 X-0.9546 Y0.8740 F20 +G01 X-0.9461 Y0.8825 +G01 X-1.1427 Y0.8825 +G01 X-1.1925 Y0.8327 +G01 X-1.2022 Y0.8231 +G01 X-1.2047 Y0.8171 +G01 X-1.2142 Y0.8075 +G01 X-1.2022 Y0.8075 +G01 X-1.1825 Y0.8272 +G01 X-1.1722 Y0.8375 +G01 X-0.9607 Y0.8375 +G01 X-0.9607 Y0.8591 +G00 Z0.1000 +G00 X-1.2047 Y0.7629 +G01 Z-0.0070 F10 +G01 X-1.1985 Y0.7481 F20 +G01 X-1.1985 Y0.7319 +G01 X-1.2047 Y0.7171 +G01 X-1.2142 Y0.7075 +G01 X-0.9572 Y0.7075 +G01 X-0.9325 Y0.7322 +G01 X-0.9222 Y0.7425 +G01 X-0.8822 Y0.7425 +G01 X-0.8672 Y0.7575 +G01 X-0.8758 Y0.7661 +G01 X-0.8809 Y0.7783 +G01 X-0.8859 Y0.7661 +G01 X-0.8973 Y0.7547 +G01 X-0.9122 Y0.7486 +G01 X-0.9283 Y0.7486 +G01 X-0.9432 Y0.7547 +G01 X-0.9546 Y0.7661 +G01 X-0.9607 Y0.7810 +G01 X-0.9607 Y0.8025 +G01 X-1.1577 Y0.8025 +G01 X-1.1877 Y0.7725 +G01 X-1.2022 Y0.7725 +G01 X-1.2142 Y0.7725 +G01 X-1.2047 Y0.7629 +G00 Z0.1000 +G00 X-1.5075 Y1.1227 +G01 Z-0.0070 F10 +G01 X-1.5075 Y1.1302 F20 +G01 X-1.5305 Y1.1532 +G01 X-1.5305 Y1.1825 +G01 X-1.7072 Y1.1825 +G01 X-1.7113 Y1.1811 +G01 X-1.7135 Y1.1822 +G01 X-1.7203 Y1.1755 +G01 X-1.7280 Y1.1723 +G01 X-1.6975 Y1.1417 +G01 X-1.6975 Y1.0983 +G01 X-1.7283 Y1.0675 +G01 X-1.7717 Y1.0675 +G01 X-1.8025 Y1.0983 +G01 X-1.8025 Y1.1417 +G01 X-1.7995 Y1.1447 +G01 X-1.8272 Y1.1725 +G01 X-1.9078 Y1.1725 +G01 X-1.7727 Y1.0375 +G01 X-1.7272 Y1.0375 +G01 X-1.6472 Y1.1175 +G01 X-1.6327 Y1.1175 +G01 X-1.5027 Y1.1175 +G01 X-1.4925 Y1.1072 +G01 X-1.4625 Y1.0772 +G01 X-1.4625 Y1.0627 +G01 X-1.4625 Y1.0470 +G01 X-1.3625 Y0.9422 +G01 X-1.3625 Y0.9777 +G01 X-1.5075 Y1.1227 +G00 Z0.1000 +G00 X-1.3258 Y0.9725 +G01 Z-0.0070 F10 +G01 X-1.3275 Y0.9725 F20 +G01 X-1.3275 Y0.9708 +G01 X-1.3258 Y0.9725 +G00 Z0.1000 +G00 X-1.2309 Y0.8995 +G01 Z-0.0070 F10 +G01 X-1.3091 Y0.8995 F20 +G01 X-1.3239 Y0.9057 +G01 X-1.3275 Y0.9092 +G01 X-1.3275 Y0.8708 +G01 X-1.3239 Y0.8743 +G01 X-1.3091 Y0.8805 +G01 X-1.2309 Y0.8805 +G01 X-1.2161 Y0.8743 +G01 X-1.2082 Y0.8665 +G01 X-1.1572 Y0.9175 +G01 X-1.1427 Y0.9175 +G01 X-0.4927 Y0.9175 +G01 X-0.4825 Y0.9072 +G01 X-0.3427 Y0.7675 +G01 X-0.3204 Y0.7675 +G01 X-0.3345 Y0.7816 +G01 X-0.3345 Y0.7825 +G01 X-0.3353 Y0.7825 +G01 X-0.3422 Y0.7825 +G01 X-0.3425 Y0.7828 +G01 X-0.3429 Y0.7828 +G01 X-0.3476 Y0.7879 +G01 X-0.3525 Y0.7927 +G01 X-0.3525 Y0.7931 +G01 X-0.4726 Y0.9225 +G01 X-1.2024 Y0.9225 +G01 X-1.2047 Y0.9171 +G01 X-1.2161 Y0.9057 +G01 X-1.2309 Y0.8995 +G00 Z0.1000 +G00 X-1.2047 Y0.9629 +G01 Z-0.0070 F10 +G01 X-1.2024 Y0.9575 F20 +G01 X-0.4719 Y0.9575 +G01 X-0.4716 Y0.9578 +G01 X-0.4647 Y0.9575 +G01 X-0.4622 Y0.9575 +G01 X-0.4775 Y0.9727 +G01 X-0.4775 Y0.9752 +G01 X-0.4932 Y0.9595 +G01 X-0.5268 Y0.9595 +G01 X-0.5398 Y0.9725 +G01 X-1.2142 Y0.9725 +G01 X-1.2047 Y0.9629 +G00 Z0.1000 +G00 X-0.5505 Y1.0168 +G01 Z-0.0070 F10 +G01 X-0.5348 Y1.0325 F20 +G01 X-1.1985 Y1.0325 +G01 X-1.1985 Y1.0319 +G01 X-1.2047 Y1.0171 +G01 X-1.2142 Y1.0075 +G01 X-0.5505 Y1.0075 +G01 X-0.5505 Y1.0168 +G00 Z0.1000 +G00 X-1.4732 Y1.2105 +G01 Z-0.0070 F10 +G01 X-1.4575 Y1.1948 F20 +G01 X-1.4575 Y1.2052 +G01 X-1.4805 Y1.2282 +G01 X-1.4805 Y1.2607 +G01 X-1.4922 Y1.2725 +G01 X-1.7627 Y1.2725 +G01 X-1.7644 Y1.2709 +G01 X-1.7604 Y1.2725 +G01 X-1.7396 Y1.2725 +G01 X-1.7203 Y1.2645 +G01 X-1.7055 Y1.2497 +G01 X-1.6975 Y1.2304 +G01 X-1.6975 Y1.2175 +G01 X-1.5127 Y1.2175 +G01 X-1.5058 Y1.2105 +G01 X-1.4732 Y1.2105 +G00 Z0.1000 +G00 X-1.3875 Y0.5522 +G01 Z-0.0070 F10 +G01 X-1.3825 Y0.5472 F20 +G01 X-1.3825 Y0.5327 +G01 X-1.3875 Y0.5277 +G01 X-1.3875 Y0.5075 +G01 X-1.3258 Y0.5075 +G01 X-1.3353 Y0.5171 +G01 X-1.3415 Y0.5319 +G01 X-1.3415 Y0.5481 +G01 X-1.3360 Y0.5613 +G01 X-1.3775 Y0.6027 +G01 X-1.3775 Y0.6172 +G01 X-1.3775 Y0.6672 +G01 X-1.3672 Y0.6775 +G01 X-1.3372 Y0.7075 +G01 X-1.3258 Y0.7075 +G01 X-1.3353 Y0.7171 +G01 X-1.3376 Y0.7225 +G01 X-1.3393 Y0.7225 +G01 X-1.3459 Y0.7220 +G01 X-1.3465 Y0.7225 +G01 X-1.3472 Y0.7225 +G01 X-1.3519 Y0.7271 +G01 X-1.3815 Y0.7525 +G01 X-1.3822 Y0.7525 +G01 X-1.3869 Y0.7572 +G01 X-1.3875 Y0.7577 +G01 X-1.3875 Y0.5522 +G00 Z0.1000 +G00 X-1.5125 Y0.7708 +G01 Z-0.0070 F10 +G01 X-1.5125 Y0.7725 F20 +G01 X-1.5142 Y0.7725 +G01 X-1.5125 Y0.7708 +G00 Z0.1000 +G00 X-1.4322 Y0.1275 +G01 Z-0.0070 F10 +G01 X-1.4375 Y0.1327 F20 +G01 X-1.4675 Y0.1627 +G01 X-1.4675 Y0.1772 +G01 X-1.4675 Y0.5987 +G01 X-1.4683 Y0.6047 +G01 X-1.4675 Y0.6058 +G01 X-1.4675 Y0.6072 +G01 X-1.4633 Y0.6115 +G01 X-1.4525 Y0.6258 +G01 X-1.4525 Y0.6377 +G01 X-1.4725 Y0.6137 +G01 X-1.4725 Y0.1472 +G01 X-1.4527 Y0.1275 +G01 X-1.4322 Y0.1275 +G00 Z0.1000 +G00 X-1.7720 Y1.1723 +G01 Z-0.0070 F10 +G01 X-1.7797 Y1.1755 F20 +G01 X-1.7945 Y1.1903 +G01 X-1.8025 Y1.2096 +G01 X-1.8025 Y1.2304 +G01 X-1.8009 Y1.2344 +G01 X-1.8025 Y1.2327 +G01 X-1.8025 Y1.1972 +G01 X-1.7747 Y1.1695 +G01 X-1.7720 Y1.1723 +G00 Z0.1000 +G00 X-2.0847 Y0.1271 +G01 Z-0.0070 F10 +G01 X-2.0961 Y0.1157 F20 +G01 X-2.1109 Y0.1095 +G01 X-2.1891 Y0.1095 +G01 X-2.2039 Y0.1157 +G01 X-2.2153 Y0.1271 +G01 X-2.2215 Y0.1419 +G01 X-2.2215 Y0.1581 +G01 X-2.2153 Y0.1729 +G01 X-2.2039 Y0.1843 +G01 X-2.1891 Y0.1905 +G01 X-2.1275 Y0.1905 +G01 X-2.1275 Y0.2027 +G01 X-2.1342 Y0.2095 +G01 X-2.1891 Y0.2095 +G01 X-2.2039 Y0.2157 +G01 X-2.2153 Y0.2271 +G01 X-2.2215 Y0.2419 +G01 X-2.2215 Y0.2581 +G01 X-2.2153 Y0.2729 +G01 X-2.2039 Y0.2843 +G01 X-2.1891 Y0.2905 +G01 X-2.1275 Y0.2905 +G01 X-2.1275 Y0.3027 +G01 X-2.1342 Y0.3095 +G01 X-2.1891 Y0.3095 +G01 X-2.2039 Y0.3157 +G01 X-2.2153 Y0.3271 +G01 X-2.2176 Y0.3325 +G01 X-2.3125 Y0.3325 +G01 X-2.3125 Y0.1272 +G01 X-2.2228 Y0.0375 +G01 X-2.0572 Y0.0375 +G01 X-2.0625 Y0.0427 +G01 X-2.0722 Y0.0525 +G01 X-2.0825 Y0.0627 +G01 X-2.0825 Y0.1323 +G01 X-2.0847 Y0.1271 +G00 Z0.1000 +G00 X-2.0847 Y0.2271 +G01 Z-0.0070 F10 +G01 X-2.0935 Y0.2182 F20 +G01 X-2.0925 Y0.2172 +G01 X-2.0925 Y0.2027 +G01 X-2.0925 Y0.1808 +G01 X-2.0847 Y0.1729 +G01 X-2.0825 Y0.1677 +G01 X-2.0825 Y0.2323 +G01 X-2.0847 Y0.2271 +G00 Z0.1000 +G00 X-2.0847 Y0.3271 +G01 Z-0.0070 F10 +G01 X-2.0935 Y0.3182 F20 +G01 X-2.0925 Y0.3172 +G01 X-2.0925 Y0.3027 +G01 X-2.0925 Y0.2808 +G01 X-2.0847 Y0.2729 +G01 X-2.0825 Y0.2677 +G01 X-2.0825 Y0.3323 +G01 X-2.0847 Y0.3271 +G00 Z0.1000 +G00 X-2.0825 Y0.3677 +G01 Z-0.0070 F10 +G01 X-2.0825 Y0.3709 F20 +G01 X-2.0844 Y0.3723 +G01 X-2.0825 Y0.3677 +G00 Z0.1000 +G00 X-2.0577 Y0.3975 +G01 Z-0.0070 F10 +G01 X-2.0537 Y0.3934 F20 +G01 X-2.0490 Y0.3901 +G01 X-2.0487 Y0.3884 +G01 X-2.0475 Y0.3872 +G01 X-2.0475 Y0.3815 +G01 X-2.0465 Y0.3758 +G01 X-2.0475 Y0.3744 +G01 X-2.0475 Y0.0772 +G01 X-2.0378 Y0.0675 +G01 X-1.9222 Y0.0675 +G01 X-1.9275 Y0.0727 +G01 X-2.0172 Y0.1625 +G01 X-2.0275 Y0.1727 +G01 X-2.0275 Y0.3877 +G01 X-2.0372 Y0.3975 +G01 X-2.0527 Y0.3975 +G01 X-2.0595 Y0.3975 +G01 X-2.0577 Y0.3975 +G00 Z0.1000 +G00 X-2.1275 Y0.4577 +G01 Z-0.0070 F10 +G01 X-2.1275 Y0.4722 F20 +G01 X-2.1275 Y0.5172 +G01 X-2.1172 Y0.5275 +G01 X-2.0875 Y0.5572 +G01 X-2.0772 Y0.5675 +G01 X-1.6972 Y0.5675 +G01 X-1.6775 Y0.5872 +G01 X-1.6775 Y0.7127 +G01 X-1.6775 Y0.7272 +G01 X-1.6625 Y0.7422 +G01 X-1.6522 Y0.7525 +G01 X-1.6397 Y0.7525 +G01 X-1.6353 Y0.7629 +G01 X-1.6258 Y0.7725 +G01 X-1.6372 Y0.7725 +G01 X-1.6572 Y0.7925 +G01 X-1.6675 Y0.8027 +G01 X-1.6675 Y0.8527 +G01 X-1.6675 Y0.8672 +G01 X-1.6375 Y0.8972 +G01 X-1.6272 Y0.9075 +G01 X-1.6258 Y0.9075 +G01 X-1.6353 Y0.9171 +G01 X-1.6376 Y0.9225 +G01 X-1.6727 Y0.9225 +G01 X-1.6925 Y0.9027 +G01 X-1.6925 Y0.6372 +G01 X-1.6925 Y0.6227 +G01 X-1.7325 Y0.5827 +G01 X-1.7427 Y0.5725 +G01 X-2.0827 Y0.5725 +G01 X-2.1325 Y0.5227 +G01 X-2.1325 Y0.4491 +G01 X-2.0859 Y0.4162 +G01 X-2.1275 Y0.4577 +G00 Z0.1000 +G00 X-2.1572 Y0.4225 +G01 Z-0.0070 F10 +G01 X-2.1613 Y0.4266 F20 +G01 X-2.1660 Y0.4299 +G01 X-2.1663 Y0.4316 +G01 X-2.1675 Y0.4327 +G01 X-2.1675 Y0.4385 +G01 X-2.1685 Y0.4442 +G01 X-2.1675 Y0.4455 +G01 X-2.1675 Y0.5227 +G01 X-2.1675 Y0.5372 +G01 X-2.0972 Y0.6075 +G01 X-2.0827 Y0.6075 +G01 X-1.7572 Y0.6075 +G01 X-1.7275 Y0.6372 +G01 X-1.7275 Y0.9172 +G01 X-1.7172 Y0.9275 +G01 X-1.6975 Y0.9472 +G01 X-1.6872 Y0.9575 +G01 X-1.6376 Y0.9575 +G01 X-1.6353 Y0.9629 +G01 X-1.6239 Y0.9743 +G01 X-1.6091 Y0.9805 +G01 X-1.5309 Y0.9805 +G01 X-1.5161 Y0.9743 +G01 X-1.5047 Y0.9629 +G01 X-1.4985 Y0.9481 +G01 X-1.4985 Y0.9319 +G01 X-1.5047 Y0.9171 +G01 X-1.5142 Y0.9075 +G01 X-1.4968 Y0.9075 +G01 X-1.4965 Y0.9078 +G01 X-1.4896 Y0.9075 +G01 X-1.4827 Y0.9075 +G01 X-1.4824 Y0.9072 +G01 X-1.4820 Y0.9072 +G01 X-1.4774 Y0.9021 +G01 X-1.4725 Y0.8972 +G01 X-1.4725 Y0.8968 +G01 X-1.4225 Y0.8423 +G01 X-1.4225 Y0.9030 +G01 X-1.5175 Y1.0025 +G01 X-1.5237 Y1.0025 +G01 X-1.5309 Y0.9995 +G01 X-1.6091 Y0.9995 +G01 X-1.6163 Y1.0025 +G01 X-1.6577 Y1.0025 +G01 X-1.7125 Y0.9477 +G01 X-1.7227 Y0.9375 +G01 X-1.7825 Y0.9375 +G01 X-1.7825 Y0.7198 +G01 X-1.7595 Y0.6968 +G01 X-1.7595 Y0.6632 +G01 X-1.7832 Y0.6395 +G01 X-1.8168 Y0.6395 +G01 X-1.8298 Y0.6525 +G01 X-1.8902 Y0.6525 +G01 X-1.9032 Y0.6395 +G01 X-1.9368 Y0.6395 +G01 X-1.9498 Y0.6525 +G01 X-2.0102 Y0.6525 +G01 X-2.0232 Y0.6395 +G01 X-2.0568 Y0.6395 +G01 X-2.0805 Y0.6632 +G01 X-2.0805 Y0.6968 +G01 X-2.0568 Y0.7205 +G01 X-2.0232 Y0.7205 +G01 X-1.9995 Y0.6968 +G01 X-1.9995 Y0.6875 +G01 X-1.9605 Y0.6875 +G01 X-1.9605 Y0.6968 +G01 X-1.9368 Y0.7205 +G01 X-1.9032 Y0.7205 +G01 X-1.8795 Y0.6968 +G01 X-1.8795 Y0.6875 +G01 X-1.8405 Y0.6875 +G01 X-1.8405 Y0.6968 +G01 X-1.8175 Y0.7198 +G01 X-1.8175 Y0.9375 +G01 X-1.8827 Y0.9375 +G01 X-1.8972 Y0.9375 +G01 X-1.9375 Y0.9777 +G01 X-1.9375 Y0.9922 +G01 X-1.9375 Y1.0627 +G01 X-1.9772 Y1.1025 +G01 X-2.0327 Y1.1025 +G01 X-2.0825 Y1.0527 +G01 X-2.0825 Y1.0372 +G01 X-2.0825 Y1.0227 +G01 X-2.1725 Y0.9327 +G01 X-2.1827 Y0.9225 +G01 X-2.3527 Y0.9225 +G01 X-2.3672 Y0.9225 +G01 X-2.4172 Y0.9725 +G01 X-2.4275 Y0.9827 +G01 X-2.4275 Y1.0727 +G01 X-2.4275 Y1.0872 +G01 X-2.3175 Y1.1972 +G01 X-2.3072 Y1.2075 +G01 X-1.8375 Y1.2075 +G01 X-1.8375 Y1.2327 +G01 X-1.8375 Y1.2472 +G01 X-1.7875 Y1.2972 +G01 X-1.7772 Y1.3075 +G01 X-1.4777 Y1.3075 +G01 X-1.4675 Y1.2972 +G01 X-1.4557 Y1.2855 +G01 X-1.4232 Y1.2855 +G01 X-1.3995 Y1.2618 +G01 X-1.3995 Y1.2282 +G01 X-1.4225 Y1.2052 +G01 X-1.4225 Y1.1948 +G01 X-1.4068 Y1.2105 +G01 X-1.3732 Y1.2105 +G01 X-1.3602 Y1.1975 +G01 X-1.3272 Y1.1975 +G01 X-1.2675 Y1.2572 +G01 X-1.2572 Y1.2675 +G01 X-1.2072 Y1.2675 +G01 X-1.1927 Y1.2675 +G01 X-1.1527 Y1.2274 +G01 X-1.1404 Y1.2325 +G01 X-1.1196 Y1.2325 +G01 X-1.1003 Y1.2245 +G01 X-1.0855 Y1.2097 +G01 X-1.0775 Y1.1904 +G01 X-1.0775 Y1.1775 +G01 X-0.3522 Y1.1775 +G01 X-0.3377 Y1.1775 +G01 X-0.2048 Y1.0445 +G01 X-0.1716 Y1.0445 +G01 X-0.1455 Y1.0184 +G01 X-0.1455 Y0.9820 +G01 X-0.0930 Y0.9325 +G01 X-0.0927 Y0.9325 +G01 X-0.0878 Y0.9276 +G01 X-0.0827 Y0.9227 +G01 X-0.0827 Y0.9224 +G01 X-0.0825 Y0.9222 +G01 X-0.0825 Y0.9153 +G01 X-0.0823 Y0.9083 +G01 X-0.0825 Y0.9080 +G01 X-0.0825 Y0.5977 +G01 X-0.0927 Y0.5875 +G01 X-0.1225 Y0.5578 +G01 X-0.1225 Y0.3672 +G01 X-0.1225 Y0.3527 +G01 X-0.4727 Y0.0025 +G01 X-0.4872 Y0.0025 +G01 X-2.2372 Y0.0025 +G01 X-2.2475 Y0.0127 +G01 X-2.3372 Y0.1025 +G01 X-2.3475 Y0.1127 +G01 X-2.3475 Y0.3427 +G01 X-2.3475 Y0.3572 +G01 X-2.3475 Y0.7727 +G01 X-2.3475 Y0.7872 +G01 X-2.2822 Y0.8525 +G01 X-2.2677 Y0.8525 +G01 X-2.1922 Y0.8525 +G01 X-2.0494 Y0.9953 +G01 X-2.0595 Y1.0054 +G01 X-2.0595 Y1.0546 +G01 X-2.0246 Y1.0895 +G01 X-1.9754 Y1.0895 +G01 X-1.9405 Y1.0546 +G01 X-1.9405 Y1.0054 +G01 X-1.9754 Y0.9705 +G01 X-2.0246 Y0.9705 +G01 X-2.1675 Y0.8277 +G01 X-2.1777 Y0.8175 +G01 X-2.2677 Y0.8175 +G01 X-2.3125 Y0.7727 +G01 X-2.3125 Y0.3675 +G01 X-2.2176 Y0.3675 +G01 X-2.2153 Y0.3729 +G01 X-2.2039 Y0.3843 +G01 X-2.1891 Y0.3905 +G01 X-2.1109 Y0.3905 +G01 X-2.1092 Y0.3898 +G01 X-2.1556 Y0.4225 +G01 X-2.1572 Y0.4225 +G00 Z0.1000 +G00 X-1.7025 Y0.9493 +G01 Z-0.0070 F10 +G01 X-1.6893 Y0.9625 F20 +G01 X-1.6409 Y0.9625 +G01 X-1.6396 Y0.9658 +G01 X-1.6268 Y0.9786 +G01 X-1.6101 Y0.9855 +G01 X-1.5299 Y0.9855 +G01 X-1.5132 Y0.9786 +G01 X-1.5004 Y0.9658 +G01 X-1.4935 Y0.9491 +G01 X-1.4935 Y0.9309 +G01 X-1.5004 Y0.9142 +G01 X-1.5022 Y0.9125 +G01 X-1.4987 Y0.9125 +G01 X-1.4983 Y0.9129 +G01 X-1.4895 Y0.9125 +G01 X-1.4807 Y0.9125 +G01 X-1.4803 Y0.9121 +G01 X-1.4797 Y0.9121 +G01 X-1.4737 Y0.9056 +G01 X-1.4675 Y0.8993 +G01 X-1.4675 Y0.8987 +G01 X-1.4275 Y0.8551 +G01 X-1.4275 Y0.9010 +G01 X-1.5196 Y0.9975 +G01 X-1.5227 Y0.9975 +G01 X-1.5299 Y0.9945 +G01 X-1.6101 Y0.9945 +G01 X-1.6173 Y0.9975 +G01 X-1.6557 Y0.9975 +G01 X-1.7075 Y0.9457 +G01 X-1.7207 Y0.9325 +G01 X-1.7775 Y0.9325 +G01 X-1.7775 Y0.7218 +G01 X-1.7545 Y0.6988 +G01 X-1.7545 Y0.6612 +G01 X-1.7812 Y0.6345 +G01 X-1.8188 Y0.6345 +G01 X-1.8318 Y0.6475 +G01 X-1.8882 Y0.6475 +G01 X-1.9012 Y0.6345 +G01 X-1.9388 Y0.6345 +G01 X-1.9518 Y0.6475 +G01 X-2.0082 Y0.6475 +G01 X-2.0212 Y0.6345 +G01 X-2.0588 Y0.6345 +G01 X-2.0855 Y0.6612 +G01 X-2.0855 Y0.6988 +G01 X-2.0588 Y0.7255 +G01 X-2.0212 Y0.7255 +G01 X-1.9945 Y0.6988 +G01 X-1.9945 Y0.6925 +G01 X-1.9655 Y0.6925 +G01 X-1.9655 Y0.6988 +G01 X-1.9388 Y0.7255 +G01 X-1.9012 Y0.7255 +G01 X-1.8745 Y0.6988 +G01 X-1.8745 Y0.6925 +G01 X-1.8455 Y0.6925 +G01 X-1.8455 Y0.6988 +G01 X-1.8225 Y0.7218 +G01 X-1.8225 Y0.9325 +G01 X-1.8807 Y0.9325 +G01 X-1.8993 Y0.9325 +G01 X-1.9425 Y0.9757 +G01 X-1.9425 Y0.9943 +G01 X-1.9425 Y0.9963 +G01 X-1.9733 Y0.9655 +G01 X-2.0227 Y0.9655 +G01 X-2.1625 Y0.8257 +G01 X-2.1757 Y0.8125 +G01 X-2.2657 Y0.8125 +G01 X-2.3075 Y0.7707 +G01 X-2.3075 Y0.3725 +G01 X-2.2209 Y0.3725 +G01 X-2.2196 Y0.3758 +G01 X-2.2068 Y0.3886 +G01 X-2.1901 Y0.3955 +G01 X-2.1260 Y0.3955 +G01 X-2.1571 Y0.4175 +G01 X-2.1593 Y0.4175 +G01 X-2.1646 Y0.4227 +G01 X-2.1706 Y0.4270 +G01 X-2.1710 Y0.4291 +G01 X-2.1725 Y0.4307 +G01 X-2.1725 Y0.4381 +G01 X-2.1738 Y0.4454 +G01 X-2.1725 Y0.4471 +G01 X-2.1725 Y0.5207 +G01 X-2.1725 Y0.5393 +G01 X-2.0993 Y0.6125 +G01 X-2.0807 Y0.6125 +G01 X-1.7593 Y0.6125 +G01 X-1.7325 Y0.6393 +G01 X-1.7325 Y0.9193 +G01 X-1.7193 Y0.9325 +G01 X-1.7025 Y0.9493 +G00 Z0.1000 +G00 X-2.0875 Y0.3172 +G01 Z-0.0070 F10 +G01 X-2.0875 Y0.3007 F20 +G01 X-2.0875 Y0.2828 +G01 X-2.0875 Y0.3172 +G00 Z0.1000 +G00 X-2.0875 Y0.2172 +G01 Z-0.0070 F10 +G01 X-2.0875 Y0.2007 F20 +G01 X-2.0875 Y0.1828 +G01 X-2.0875 Y0.2172 +G00 Z0.1000 +G00 X-2.0932 Y0.1114 +G01 Z-0.0070 F10 +G01 X-2.1099 Y0.1045 F20 +G01 X-2.1901 Y0.1045 +G01 X-2.2068 Y0.1114 +G01 X-2.2196 Y0.1242 +G01 X-2.2265 Y0.1409 +G01 X-2.2265 Y0.1591 +G01 X-2.2196 Y0.1758 +G01 X-2.2068 Y0.1886 +G01 X-2.1901 Y0.1955 +G01 X-2.1325 Y0.1955 +G01 X-2.1325 Y0.2007 +G01 X-2.1363 Y0.2045 +G01 X-2.1901 Y0.2045 +G01 X-2.2068 Y0.2114 +G01 X-2.2196 Y0.2242 +G01 X-2.2265 Y0.2409 +G01 X-2.2265 Y0.2591 +G01 X-2.2196 Y0.2758 +G01 X-2.2068 Y0.2886 +G01 X-2.1901 Y0.2955 +G01 X-2.1325 Y0.2955 +G01 X-2.1325 Y0.3007 +G01 X-2.1363 Y0.3045 +G01 X-2.1901 Y0.3045 +G01 X-2.2068 Y0.3114 +G01 X-2.2196 Y0.3242 +G01 X-2.2209 Y0.3275 +G01 X-2.3075 Y0.3275 +G01 X-2.3075 Y0.1293 +G01 X-2.2207 Y0.0425 +G01 X-2.0693 Y0.0425 +G01 X-2.0743 Y0.0475 +G01 X-2.0875 Y0.0607 +G01 X-2.0875 Y0.1172 +G01 X-2.0932 Y0.1114 +G00 Z0.1000 +G00 X-2.0357 Y0.0725 +G01 Z-0.0070 F10 +G01 X-1.9343 Y0.0725 F20 +G01 X-2.0193 Y0.1575 +G01 X-2.0325 Y0.1707 +G01 X-2.0325 Y0.3857 +G01 X-2.0393 Y0.3925 +G01 X-2.0443 Y0.3925 +G01 X-2.0440 Y0.3909 +G01 X-2.0425 Y0.3893 +G01 X-2.0425 Y0.3819 +G01 X-2.0412 Y0.3746 +G01 X-2.0425 Y0.3729 +G01 X-2.0425 Y0.0793 +G01 X-2.0357 Y0.0725 +G00 Z0.1000 +G00 X-1.6993 Y0.5725 +G01 Z-0.0070 F10 +G01 X-1.6825 Y0.5893 F20 +G01 X-1.6825 Y0.7107 +G01 X-1.6825 Y0.7293 +G01 X-1.6675 Y0.7443 +G01 X-1.6543 Y0.7575 +G01 X-1.6430 Y0.7575 +G01 X-1.6396 Y0.7658 +G01 X-1.6378 Y0.7675 +G01 X-1.6393 Y0.7675 +G01 X-1.6593 Y0.7875 +G01 X-1.6725 Y0.8007 +G01 X-1.6725 Y0.8507 +G01 X-1.6725 Y0.8693 +G01 X-1.6425 Y0.8993 +G01 X-1.6336 Y0.9082 +G01 X-1.6396 Y0.9142 +G01 X-1.6409 Y0.9175 +G01 X-1.6707 Y0.9175 +G01 X-1.6875 Y0.9007 +G01 X-1.6875 Y0.6393 +G01 X-1.6875 Y0.6207 +G01 X-1.7275 Y0.5807 +G01 X-1.7357 Y0.5725 +G01 X-1.6993 Y0.5725 +G00 Z0.1000 +G00 X-1.3487 Y0.1869 +G01 Z-0.0070 F10 +G01 X-1.3512 Y0.1845 F20 +G01 X-1.3888 Y0.1845 +G01 X-1.4155 Y0.2112 +G01 X-1.4155 Y0.2488 +G01 X-1.3925 Y0.2718 +G01 X-1.3925 Y0.3057 +G01 X-1.4275 Y0.3407 +G01 X-1.4275 Y0.3593 +G01 X-1.4275 Y0.4993 +G01 X-1.4275 Y0.5257 +G01 X-1.4275 Y0.5307 +G01 X-1.4275 Y0.5925 +G01 X-1.4275 Y0.1793 +G01 X-1.4107 Y0.1625 +G01 X-1.3243 Y0.1625 +G01 X-1.3487 Y0.1869 +G00 Z0.1000 +G00 X-0.5554 Y0.2264 +G01 Z-0.0070 F10 +G01 X-0.5599 Y0.2245 F20 +G01 X-0.6401 Y0.2245 +G01 X-0.6568 Y0.2314 +G01 X-0.6628 Y0.2375 +G01 X-0.9407 Y0.2375 +G01 X-1.0075 Y0.1707 +G01 X-1.0157 Y0.1625 +G01 X-0.6193 Y0.1625 +G01 X-0.5554 Y0.2264 +G00 Z0.1000 +G00 X-0.1695 Y0.4495 +G01 Z-0.0070 F10 +G01 X-0.1625 Y0.4425 F20 +G01 X-0.1625 Y0.4575 +G01 X-0.1695 Y0.4505 +G01 X-0.2077 Y0.4505 +G01 X-0.2087 Y0.4495 +G01 X-0.1695 Y0.4495 +G00 Z0.1000 +G00 X-0.2395 Y0.5205 +G01 Z-0.0070 F10 +G01 X-0.2325 Y0.5275 F20 +G01 X-0.2475 Y0.5275 +G01 X-0.2405 Y0.5205 +G01 X-0.2405 Y0.4813 +G01 X-0.2395 Y0.4823 +G01 X-0.2395 Y0.5205 +G00 Z0.1000 +G00 X-0.2695 Y0.4505 +G01 Z-0.0070 F10 +G01 X-0.3077 Y0.4505 F20 +G01 X-0.3087 Y0.4495 +G01 X-0.2695 Y0.4495 +G01 X-0.2625 Y0.4425 +G01 X-0.2625 Y0.4575 +G01 X-0.2695 Y0.4505 +G00 Z0.1000 +G00 X-0.8817 Y0.8768 +G01 Z-0.0070 F10 +G01 X-0.8809 Y0.8749 F20 +G01 X-0.8801 Y0.8768 +G01 X-0.8794 Y0.8775 +G01 X-0.8823 Y0.8775 +G01 X-0.8817 Y0.8768 +G00 Z0.1000 +G00 X-0.8029 Y0.8768 +G01 Z-0.0070 F10 +G01 X-0.8021 Y0.8749 F20 +G01 X-0.8013 Y0.8768 +G01 X-0.8006 Y0.8775 +G01 X-0.8036 Y0.8775 +G01 X-0.8029 Y0.8768 +G00 Z0.1000 +G00 X-0.2395 Y0.9795 +G01 Z-0.0070 F10 +G01 X-0.2395 Y1.0205 F20 +G01 X-0.2384 Y1.0216 +G01 X-0.3543 Y1.1375 +G01 X-1.0864 Y1.1375 +G01 X-1.0917 Y1.1357 +G01 X-1.0926 Y1.1361 +G01 X-1.0962 Y1.1325 +G01 X-0.4907 Y1.1325 +G01 X-0.4775 Y1.1193 +G01 X-0.4037 Y1.0455 +G01 X-0.3912 Y1.0455 +G01 X-0.3645 Y1.0188 +G01 X-0.3645 Y1.0125 +G01 X-0.3395 Y1.0125 +G01 X-0.3395 Y1.0205 +G01 X-0.3105 Y1.0495 +G01 X-0.2695 Y1.0495 +G01 X-0.2405 Y1.0205 +G01 X-0.2405 Y0.9795 +G01 X-0.2475 Y0.9725 +G01 X-0.2325 Y0.9725 +G01 X-0.2395 Y0.9795 +G00 Z0.1000 +G00 X-2.1343 Y1.1675 +G01 Z-0.0070 F10 +G01 X-2.2907 Y1.1675 F20 +G01 X-2.3875 Y1.0707 +G01 X-2.3875 Y0.9993 +G01 X-2.3507 Y0.9625 +G01 X-2.1993 Y0.9625 +G01 X-2.1225 Y1.0393 +G01 X-2.1225 Y1.0693 +G01 X-2.1093 Y1.0825 +G01 X-2.0543 Y1.1375 +G01 X-2.1007 Y1.1375 +G01 X-2.1375 Y1.1007 +G01 X-2.1507 Y1.0875 +G01 X-2.1607 Y1.0875 +G01 X-2.2275 Y1.0207 +G01 X-2.2355 Y1.0127 +G01 X-2.2355 Y1.0033 +G01 X-2.2733 Y0.9655 +G01 X-2.3267 Y0.9655 +G01 X-2.3645 Y1.0033 +G01 X-2.3645 Y1.0567 +G01 X-2.3267 Y1.0945 +G01 X-2.2733 Y1.0945 +G01 X-2.2453 Y1.0665 +G01 X-2.1925 Y1.1193 +G01 X-2.1793 Y1.1325 +G01 X-2.1693 Y1.1325 +G01 X-2.1343 Y1.1675 +G00 Z0.1000 +G00 X-1.5355 Y1.1512 +G01 Z-0.0070 F10 +G01 X-1.5355 Y1.1775 F20 +G01 X-1.7064 Y1.1775 +G01 X-1.7117 Y1.1757 +G01 X-1.7126 Y1.1761 +G01 X-1.7174 Y1.1713 +G01 X-1.7192 Y1.1705 +G01 X-1.6925 Y1.1438 +G01 X-1.6925 Y1.0962 +G01 X-1.7262 Y1.0625 +G01 X-1.7738 Y1.0625 +G01 X-1.8075 Y1.0962 +G01 X-1.8075 Y1.1438 +G01 X-1.8066 Y1.1447 +G01 X-1.8293 Y1.1675 +G01 X-1.8957 Y1.1675 +G01 X-1.7707 Y1.0425 +G01 X-1.7293 Y1.0425 +G01 X-1.6493 Y1.1225 +G01 X-1.6307 Y1.1225 +G01 X-1.5125 Y1.1225 +G01 X-1.5125 Y1.1282 +G01 X-1.5355 Y1.1512 +G00 Z0.1000 +G00 X-1.3396 Y1.0142 +G01 Z-0.0070 F10 +G01 X-1.3465 Y1.0309 F20 +G01 X-1.3465 Y1.0491 +G01 X-1.3396 Y1.0658 +G01 X-1.3268 Y1.0786 +G01 X-1.3101 Y1.0855 +G01 X-1.2299 Y1.0855 +G01 X-1.2132 Y1.0786 +G01 X-1.2071 Y1.0725 +G01 X-0.4993 Y1.0725 +G01 X-0.4943 Y1.0725 +G01 X-0.5093 Y1.0875 +G01 X-1.1507 Y1.0875 +G01 X-1.1693 Y1.0875 +G01 X-1.2052 Y1.1234 +G01 X-1.2062 Y1.1225 +G01 X-1.2538 Y1.1225 +G01 X-1.2647 Y1.1334 +G01 X-1.2875 Y1.1107 +G01 X-1.3007 Y1.0975 +G01 X-1.4107 Y1.0975 +G01 X-1.4257 Y1.0975 +G01 X-1.3407 Y1.0125 +G01 X-1.3378 Y1.0125 +G01 X-1.3396 Y1.0142 +G00 Z0.1000 +G00 X-1.3525 Y0.7803 +G01 Z-0.0070 F10 +G01 X-1.3501 Y0.7783 F20 +G01 X-1.3525 Y0.7807 +G01 X-1.3525 Y0.7803 +G00 Z0.1000 +G00 X-0.9657 Y0.8601 +G01 Z-0.0070 F10 +G01 X-0.9588 Y0.8768 F20 +G01 X-0.9581 Y0.8775 +G01 X-1.1407 Y0.8775 +G01 X-1.1875 Y0.8307 +G01 X-1.1979 Y0.8202 +G01 X-1.1989 Y0.8179 +G01 X-1.1875 Y0.8293 +G01 X-1.1743 Y0.8425 +G01 X-0.9657 Y0.8425 +G01 X-0.9657 Y0.8601 +G00 Z0.1000 +G00 X-1.2004 Y0.7658 +G01 Z-0.0070 F10 +G01 X-1.1935 Y0.7491 F20 +G01 X-1.1935 Y0.7309 +G01 X-1.2004 Y0.7142 +G01 X-1.2022 Y0.7125 +G01 X-0.9593 Y0.7125 +G01 X-0.9375 Y0.7343 +G01 X-0.9283 Y0.7436 +G01 X-0.9293 Y0.7436 +G01 X-0.9460 Y0.7505 +G01 X-0.9588 Y0.7633 +G01 X-0.9657 Y0.7800 +G01 X-0.9657 Y0.7975 +G01 X-1.1557 Y0.7975 +G01 X-1.1857 Y0.7675 +G01 X-1.2022 Y0.7675 +G01 X-1.2004 Y0.7658 +G00 Z0.1000 +G00 X-1.4575 Y1.0657 +G01 Z-0.0070 F10 +G01 X-1.4575 Y1.0607 F20 +G01 X-1.4575 Y1.0490 +G01 X-1.3675 Y0.9547 +G01 X-1.3675 Y0.9757 +G01 X-1.4575 Y1.0657 +G00 Z0.1000 +G00 X-1.2299 Y0.8945 +G01 Z-0.0070 F10 +G01 X-1.3101 Y0.8945 F20 +G01 X-1.3225 Y0.8997 +G01 X-1.3225 Y0.8803 +G01 X-1.3101 Y0.8855 +G01 X-1.2299 Y0.8855 +G01 X-1.2132 Y0.8786 +G01 X-1.2082 Y0.8736 +G01 X-1.1643 Y0.9175 +G01 X-1.1991 Y0.9175 +G01 X-1.2004 Y0.9142 +G01 X-1.2132 Y0.9014 +G01 X-1.2299 Y0.8945 +G00 Z0.1000 +G00 X-1.2004 Y0.9658 +G01 Z-0.0070 F10 +G01 X-1.1991 Y0.9625 F20 +G01 X-0.5368 Y0.9625 +G01 X-0.5418 Y0.9675 +G01 X-1.2022 Y0.9675 +G01 X-1.2004 Y0.9658 +G00 Z0.1000 +G00 X-0.5555 Y1.0188 +G01 Z-0.0070 F10 +G01 X-0.5468 Y1.0275 F20 +G01 X-1.1949 Y1.0275 +G01 X-1.2004 Y1.0142 +G01 X-1.2022 Y1.0125 +G01 X-0.5555 Y1.0125 +G01 X-0.5555 Y1.0188 +G00 Z0.1000 +G00 X-1.4748 Y1.2155 +G01 Z-0.0070 F10 +G01 X-1.4855 Y1.2262 F20 +G01 X-1.4855 Y1.2587 +G01 X-1.4943 Y1.2675 +G01 X-1.7162 Y1.2675 +G01 X-1.7013 Y1.2526 +G01 X-1.6925 Y1.2314 +G01 X-1.6925 Y1.2225 +G01 X-1.5107 Y1.2225 +G01 X-1.5037 Y1.2155 +G01 X-1.4748 Y1.2155 +G00 Z0.1000 +G00 X-1.9557 Y1.1375 +G01 Z-0.0070 F10 +G01 X-1.9475 Y1.1293 F20 +G01 X-1.8975 Y1.0793 +G01 X-1.8975 Y1.0607 +G01 X-1.8975 Y0.9943 +G01 X-1.8807 Y0.9775 +G01 X-1.7907 Y0.9775 +G01 X-1.7393 Y0.9775 +G01 X-1.7193 Y0.9975 +G01 X-1.7707 Y0.9975 +G01 X-1.7893 Y0.9975 +G01 X-1.9293 Y1.1375 +G01 X-1.9557 Y1.1375 +G00 Z0.1000 +G00 X-1.6557 Y1.0425 +G01 Z-0.0070 F10 +G01 X-1.6465 Y1.0425 F20 +G01 X-1.6465 Y1.0491 +G01 X-1.6396 Y1.0658 +G01 X-1.6278 Y1.0775 +G01 X-1.6307 Y1.0775 +G01 X-1.6657 Y1.0425 +G01 X-1.6557 Y1.0425 +G00 Z0.1000 +G00 X-1.3825 Y0.5543 +G01 Z-0.0070 F10 +G01 X-1.3775 Y0.5493 F20 +G01 X-1.3775 Y0.5307 +G01 X-1.3825 Y0.5257 +G01 X-1.3825 Y0.5125 +G01 X-1.3378 Y0.5125 +G01 X-1.3396 Y0.5142 +G01 X-1.3465 Y0.5309 +G01 X-1.3465 Y0.5491 +G01 X-1.3419 Y0.5601 +G01 X-1.3825 Y0.6007 +G01 X-1.3825 Y0.6193 +G01 X-1.3825 Y0.6693 +G01 X-1.3693 Y0.6825 +G01 X-1.3393 Y0.7125 +G01 X-1.3378 Y0.7125 +G01 X-1.3396 Y0.7142 +G01 X-1.3409 Y0.7174 +G01 X-1.3476 Y0.7169 +G01 X-1.3483 Y0.7175 +G01 X-1.3493 Y0.7175 +G01 X-1.3553 Y0.7235 +G01 X-1.3825 Y0.7468 +G01 X-1.3825 Y0.5543 +G00 Z0.1000 +G00 X-0.4775 Y0.9093 +G01 Z-0.0070 F10 +G01 X-0.3407 Y0.7725 F20 +G01 X-0.3325 Y0.7725 +G01 X-0.3375 Y0.7775 +G01 X-0.3443 Y0.7775 +G01 X-0.3447 Y0.7778 +G01 X-0.3451 Y0.7779 +G01 X-0.3512 Y0.7844 +G01 X-0.3575 Y0.7907 +G01 X-0.3575 Y0.7912 +G01 X-0.4748 Y0.9175 +G01 X-0.4857 Y0.9175 +G01 X-0.4775 Y0.9093 +G00 Z0.1000 +G00 X-0.4787 Y0.9669 +G01 Z-0.0070 F10 +G01 X-0.4832 Y0.9625 F20 +G01 X-0.4743 Y0.9625 +G01 X-0.4787 Y0.9669 +G00 Z0.1000 +G00 X-0.1695 Y0.7505 +G01 Z-0.0070 F10 +G01 X-0.2077 Y0.7505 F20 +G01 X-0.2087 Y0.7495 +G01 X-0.1695 Y0.7495 +G01 X-0.1525 Y0.7325 +G01 X-0.1525 Y0.7675 +G01 X-0.1695 Y0.7505 +G00 Z0.1000 +G00 X-0.2395 Y0.9177 +G01 Z-0.0070 F10 +G01 X-0.2405 Y0.9187 F20 +G01 X-0.2405 Y0.8823 +G01 X-0.2395 Y0.8813 +G01 X-0.2395 Y0.9177 +G00 Z0.1000 +G00 X-0.2405 Y0.8205 +G01 Z-0.0070 F10 +G01 X-0.2405 Y0.7813 F20 +G01 X-0.2395 Y0.7823 +G01 X-0.2395 Y0.8205 +G01 X-0.2325 Y0.8275 +G01 X-0.2475 Y0.8275 +G01 X-0.2405 Y0.8205 +G00 Z0.1000 +G00 X-0.3105 Y0.8495 +G01 Z-0.0070 F10 +G01 X-0.2713 Y0.8495 F20 +G01 X-0.2723 Y0.8505 +G01 X-0.3105 Y0.8505 +G01 X-0.3395 Y0.8795 +G01 X-0.3395 Y0.9205 +G01 X-0.3325 Y0.9275 +G01 X-0.4227 Y0.9275 +G01 X-0.3311 Y0.8289 +G01 X-0.3105 Y0.8495 +G00 Z0.1000 +G00 X-0.1225 Y0.8425 +G01 Z-0.0070 F10 +G01 X-0.1225 Y0.9053 F20 +G01 X-0.1704 Y0.9505 +G01 X-0.2087 Y0.9505 +G01 X-0.2077 Y0.9495 +G01 X-0.1695 Y0.9495 +G01 X-0.1405 Y0.9205 +G01 X-0.1405 Y0.8795 +G01 X-0.1539 Y0.8661 +G01 X-0.1225 Y0.8425 +G00 Z0.1000 +G00 X-0.2395 Y0.6795 +G01 Z-0.0070 F10 +G01 X-0.2395 Y0.7205 F20 +G01 X-0.2325 Y0.7275 +G01 X-0.2475 Y0.7275 +G01 X-0.2405 Y0.7205 +G01 X-0.2405 Y0.6795 +G01 X-0.2475 Y0.6725 +G01 X-0.2325 Y0.6725 +G01 X-0.2395 Y0.6795 +G00 Z0.1000 +G00 X-0.3395 Y0.6795 +G01 Z-0.0070 F10 +G01 X-0.3395 Y0.7205 F20 +G01 X-0.3325 Y0.7275 +G01 X-0.3407 Y0.7275 +G01 X-0.3593 Y0.7275 +G01 X-0.5093 Y0.8775 +G01 X-0.7249 Y0.8775 +G01 X-0.7242 Y0.8768 +G01 X-0.7173 Y0.8601 +G01 X-0.7173 Y0.7800 +G01 X-0.7205 Y0.7723 +G01 X-0.6475 Y0.6993 +G01 X-0.6475 Y0.6807 +G01 X-0.6475 Y0.5743 +G01 X-0.6475 Y0.5557 +G01 X-0.7877 Y0.4155 +G01 X-0.7599 Y0.4155 +G01 X-0.7468 Y0.4100 +G01 X-0.7043 Y0.4525 +G01 X-0.6857 Y0.4525 +G01 X-0.5643 Y0.4525 +G01 X-0.5025 Y0.5143 +G01 X-0.5025 Y0.5193 +G01 X-0.4893 Y0.5325 +G01 X-0.3493 Y0.6725 +G01 X-0.3325 Y0.6725 +G01 X-0.3395 Y0.6795 +G00 Z0.1000 +G00 X-0.7235 Y0.3609 +G01 Z-0.0070 F10 +G01 X-0.7304 Y0.3442 F20 +G01 X-0.7422 Y0.3325 +G01 X-0.7143 Y0.3325 +G01 X-0.6643 Y0.3825 +G01 X-0.6457 Y0.3825 +G01 X-0.5343 Y0.3825 +G01 X-0.3443 Y0.5725 +G01 X-0.3325 Y0.5725 +G01 X-0.3395 Y0.5795 +G01 X-0.3395 Y0.6187 +G01 X-0.4575 Y0.5007 +G01 X-0.4575 Y0.4957 +G01 X-0.5325 Y0.4207 +G01 X-0.5457 Y0.4075 +G01 X-0.6857 Y0.4075 +G01 X-0.7235 Y0.3697 +G01 X-0.7235 Y0.3609 +G00 Z0.1000 +G00 X-0.2405 Y0.6205 +G01 Z-0.0070 F10 +G01 X-0.2405 Y0.5795 F20 +G01 X-0.2475 Y0.5725 +G01 X-0.2325 Y0.5725 +G01 X-0.2395 Y0.5795 +G01 X-0.2395 Y0.6205 +G01 X-0.2325 Y0.6275 +G01 X-0.2475 Y0.6275 +G01 X-0.2405 Y0.6205 +G00 Z0.1000 +G00 X-0.1405 Y0.6205 +G01 Z-0.0070 F10 +G01 X-0.1405 Y0.5963 F20 +G01 X-0.1225 Y0.6143 +G01 X-0.1225 Y0.6575 +G01 X-0.1539 Y0.6339 +G01 X-0.1405 Y0.6205 +G00 Z0.1000 +G00 X-1.3445 Y1.1512 +G01 Z-0.0070 F10 +G01 X-1.3532 Y1.1425 F20 +G01 X-1.3193 Y1.1425 +G01 X-1.2897 Y1.1722 +G01 X-1.2884 Y1.1760 +G01 X-1.2875 Y1.1764 +G01 X-1.2875 Y1.1807 +G01 X-1.3107 Y1.1575 +G01 X-1.3293 Y1.1575 +G01 X-1.3445 Y1.1575 +G01 X-1.3445 Y1.1512 +G00 Z0.1000 +G00 X-0.3395 Y0.5137 +G01 Z-0.0070 F10 +G01 X-0.5025 Y0.3507 F20 +G01 X-0.5157 Y0.3375 +G01 X-0.6457 Y0.3375 +G01 X-0.6825 Y0.3007 +G01 X-0.6957 Y0.2875 +G01 X-0.9207 Y0.2875 +G01 X-0.9393 Y0.2875 +G01 X-0.9707 Y0.2875 +G01 X-1.0007 Y0.2575 +G01 X-1.0193 Y0.2575 +G01 X-1.0249 Y0.2575 +G01 X-1.0304 Y0.2442 +G01 X-1.0432 Y0.2314 +G01 X-1.0599 Y0.2245 +G01 X-1.1401 Y0.2245 +G01 X-1.1568 Y0.2314 +G01 X-1.1696 Y0.2442 +G01 X-1.1765 Y0.2609 +G01 X-1.1765 Y0.2747 +G01 X-1.2082 Y0.3064 +G01 X-1.2132 Y0.3014 +G01 X-1.2299 Y0.2945 +G01 X-1.2375 Y0.2945 +G01 X-1.2375 Y0.2618 +G01 X-1.2245 Y0.2488 +G01 X-1.2245 Y0.2112 +G01 X-1.2332 Y0.2025 +G01 X-1.0393 Y0.2025 +G01 X-0.9593 Y0.2825 +G01 X-0.9407 Y0.2825 +G01 X-0.6751 Y0.2825 +G01 X-0.6696 Y0.2958 +G01 X-0.6568 Y0.3086 +G01 X-0.6401 Y0.3155 +G01 X-0.5599 Y0.3155 +G01 X-0.5432 Y0.3086 +G01 X-0.5304 Y0.2958 +G01 X-0.5235 Y0.2791 +G01 X-0.5235 Y0.2609 +G01 X-0.5254 Y0.2564 +G01 X-0.4025 Y0.3793 +G01 X-0.4025 Y0.4007 +G01 X-0.4025 Y0.4193 +G01 X-0.3395 Y0.4823 +G01 X-0.3395 Y0.5137 +G00 Z0.1000 +G00 X-1.2132 Y0.6014 +G01 Z-0.0070 F10 +G01 X-1.2299 Y0.5945 F20 +G01 X-1.3101 Y0.5945 +G01 X-1.3146 Y0.5964 +G01 X-1.3037 Y0.5855 +G01 X-1.2299 Y0.5855 +G01 X-1.2132 Y0.5786 +G01 X-1.2004 Y0.5658 +G01 X-1.1935 Y0.5491 +G01 X-1.1935 Y0.5309 +G01 X-1.2004 Y0.5142 +G01 X-1.2022 Y0.5125 +G01 X-0.8943 Y0.5125 +G01 X-0.8322 Y0.5746 +G01 X-0.8407 Y0.5832 +G01 X-0.8415 Y0.5851 +G01 X-0.8423 Y0.5832 +G01 X-0.8551 Y0.5704 +G01 X-0.8718 Y0.5634 +G01 X-0.8899 Y0.5634 +G01 X-0.9066 Y0.5704 +G01 X-0.9194 Y0.5832 +G01 X-0.9264 Y0.5999 +G01 X-0.9264 Y0.6075 +G01 X-1.2071 Y0.6075 +G01 X-1.2132 Y0.6014 +G00 Z0.1000 +G00 X-1.2022 Y0.6675 +G01 Z-0.0070 F10 +G01 X-1.2004 Y0.6658 F20 +G01 X-1.1949 Y0.6525 +G01 X-0.9264 Y0.6525 +G01 X-0.9264 Y0.6800 +G01 X-0.9251 Y0.6831 +G01 X-0.9407 Y0.6675 +G01 X-0.9593 Y0.6675 +G01 X-1.2022 Y0.6675 +G00 Z0.1000 +G00 X-0.8551 Y0.7095 +G01 Z-0.0070 F10 +G01 X-0.8423 Y0.6967 F20 +G01 X-0.8415 Y0.6948 +G01 X-0.8407 Y0.6967 +G01 X-0.8279 Y0.7095 +G01 X-0.8112 Y0.7164 +G01 X-0.7931 Y0.7164 +G01 X-0.7764 Y0.7095 +G01 X-0.7636 Y0.6967 +G01 X-0.7628 Y0.6948 +G01 X-0.7620 Y0.6967 +G01 X-0.7492 Y0.7095 +G01 X-0.7324 Y0.7164 +G01 X-0.7283 Y0.7164 +G01 X-0.7554 Y0.7436 +G01 X-0.7718 Y0.7436 +G01 X-0.7885 Y0.7505 +G01 X-0.8013 Y0.7633 +G01 X-0.8021 Y0.7652 +G01 X-0.8029 Y0.7633 +G01 X-0.8157 Y0.7505 +G01 X-0.8225 Y0.7477 +G01 X-0.8225 Y0.7457 +G01 X-0.8357 Y0.7325 +G01 X-0.8576 Y0.7106 +G01 X-0.8551 Y0.7095 +G00 Z0.1000 +G00 X-0.8801 Y0.7633 +G01 Z-0.0070 F10 +G01 X-0.8809 Y0.7652 F20 +G01 X-0.8817 Y0.7633 +G01 X-0.8945 Y0.7505 +G01 X-0.9017 Y0.7475 +G01 X-0.8843 Y0.7475 +G01 X-0.8743 Y0.7575 +G01 X-0.8801 Y0.7633 +G00 Z0.1000 +G00 X-0.8578 Y0.3325 +G01 Z-0.0070 F10 +G01 X-0.8696 Y0.3442 F20 +G01 X-0.8765 Y0.3609 +G01 X-0.8765 Y0.3791 +G01 X-0.8696 Y0.3958 +G01 X-0.8678 Y0.3975 +G01 X-0.9025 Y0.3975 +G01 X-0.9025 Y0.3325 +G01 X-0.8578 Y0.3325 +G00 Z0.1000 +G00 X-1.2004 Y0.4142 +G01 Z-0.0070 F10 +G01 X-1.2132 Y0.4014 F20 +G01 X-1.2299 Y0.3945 +G01 X-1.3101 Y0.3945 +G01 X-1.3268 Y0.4014 +G01 X-1.3396 Y0.4142 +G01 X-1.3465 Y0.4309 +G01 X-1.3465 Y0.4491 +G01 X-1.3396 Y0.4658 +G01 X-1.3378 Y0.4675 +G01 X-1.3825 Y0.4675 +G01 X-1.3825 Y0.3593 +G01 X-1.3607 Y0.3375 +G01 X-1.3475 Y0.3243 +G01 X-1.3475 Y0.2718 +G01 X-1.3245 Y0.2488 +G01 X-1.3245 Y0.2263 +G01 X-1.3155 Y0.2173 +G01 X-1.3155 Y0.2488 +G01 X-1.2888 Y0.2755 +G01 X-1.2825 Y0.2755 +G01 X-1.2825 Y0.2945 +G01 X-1.3101 Y0.2945 +G01 X-1.3268 Y0.3014 +G01 X-1.3396 Y0.3142 +G01 X-1.3465 Y0.3309 +G01 X-1.3465 Y0.3491 +G01 X-1.3396 Y0.3658 +G01 X-1.3268 Y0.3786 +G01 X-1.3101 Y0.3855 +G01 X-1.2299 Y0.3855 +G01 X-1.2132 Y0.3786 +G01 X-1.2004 Y0.3658 +G01 X-1.1979 Y0.3597 +G01 X-1.1497 Y0.3115 +G01 X-1.1401 Y0.3155 +G01 X-1.0599 Y0.3155 +G01 X-1.0432 Y0.3086 +G01 X-1.0372 Y0.3025 +G01 X-1.0193 Y0.3025 +G01 X-0.9893 Y0.3325 +G01 X-0.9707 Y0.3325 +G01 X-0.9475 Y0.3325 +G01 X-0.9475 Y0.4275 +G01 X-1.1949 Y0.4275 +G01 X-1.2004 Y0.4142 +G00 Z0.1000 +G00 X-0.6925 Y0.5743 +G01 Z-0.0070 F10 +G01 X-0.6925 Y0.5755 F20 +G01 X-0.6975 Y0.5705 +G01 X-0.6975 Y0.5693 +G01 X-0.6925 Y0.5743 +G00 Z0.1000 +G00 X-0.7620 Y0.5832 +G01 Z-0.0070 F10 +G01 X-0.7628 Y0.5851 F20 +G01 X-0.7636 Y0.5832 +G01 X-0.7764 Y0.5704 +G01 X-0.7775 Y0.5699 +G01 X-0.7775 Y0.5657 +G01 X-0.8707 Y0.4725 +G01 X-0.8543 Y0.4725 +G01 X-0.7528 Y0.5740 +G01 X-0.7620 Y0.5832 +G00 Z0.1000 +G00 X-1.8099 Y0.1045 +G01 Z-0.0070 F10 +G01 X-1.8901 Y0.1045 F20 +G01 X-1.9068 Y0.1114 +G01 X-1.9196 Y0.1242 +G01 X-1.9265 Y0.1409 +G01 X-1.9265 Y0.1531 +G01 X-1.9783 Y0.1975 +G01 X-1.9793 Y0.1975 +G01 X-1.9853 Y0.2035 +G01 X-1.9875 Y0.2054 +G01 X-1.9875 Y0.1893 +G01 X-1.9007 Y0.1025 +G01 X-1.4843 Y0.1025 +G01 X-1.5125 Y0.1307 +G01 X-1.5125 Y0.1493 +G01 X-1.5125 Y0.3022 +G01 X-1.5132 Y0.3014 +G01 X-1.5299 Y0.2945 +G01 X-1.5837 Y0.2945 +G01 X-1.7333 Y0.1449 +G01 X-1.7385 Y0.1385 +G01 X-1.7398 Y0.1384 +G01 X-1.7407 Y0.1375 +G01 X-1.7489 Y0.1375 +G01 X-1.7761 Y0.1348 +G01 X-1.7804 Y0.1242 +G01 X-1.7932 Y0.1114 +G01 X-1.8099 Y0.1045 +G00 Z0.1000 +G00 X-1.9525 Y0.4482 +G01 Z-0.0070 F10 +G01 X-1.9655 Y0.4612 F20 +G01 X-1.9655 Y0.4988 +G01 X-1.9388 Y0.5255 +G01 X-1.9012 Y0.5255 +G01 X-1.8745 Y0.4988 +G01 X-1.8745 Y0.4612 +G01 X-1.9012 Y0.4345 +G01 X-1.9075 Y0.4345 +G01 X-1.9075 Y0.3878 +G01 X-1.9068 Y0.3886 +G01 X-1.8901 Y0.3955 +G01 X-1.8725 Y0.3955 +G01 X-1.8725 Y0.4293 +G01 X-1.8593 Y0.4425 +G01 X-1.8431 Y0.4587 +G01 X-1.8455 Y0.4612 +G01 X-1.8455 Y0.4988 +G01 X-1.8188 Y0.5255 +G01 X-1.7812 Y0.5255 +G01 X-1.7582 Y0.5025 +G01 X-1.6893 Y0.5025 +G01 X-1.6465 Y0.5453 +G01 X-1.6465 Y0.5491 +G01 X-1.6396 Y0.5658 +G01 X-1.6268 Y0.5786 +G01 X-1.6101 Y0.5855 +G01 X-1.5299 Y0.5855 +G01 X-1.5132 Y0.5786 +G01 X-1.5125 Y0.5778 +G01 X-1.5125 Y0.6022 +G01 X-1.5132 Y0.6014 +G01 X-1.5299 Y0.5945 +G01 X-1.6101 Y0.5945 +G01 X-1.6268 Y0.6014 +G01 X-1.6375 Y0.6122 +G01 X-1.6375 Y0.5707 +G01 X-1.6507 Y0.5575 +G01 X-1.6807 Y0.5275 +G01 X-1.6993 Y0.5275 +G01 X-2.0607 Y0.5275 +G01 X-2.0875 Y0.5007 +G01 X-2.0875 Y0.4743 +G01 X-2.0855 Y0.4723 +G01 X-2.0855 Y0.4988 +G01 X-2.0588 Y0.5255 +G01 X-2.0212 Y0.5255 +G01 X-1.9945 Y0.4988 +G01 X-1.9945 Y0.4622 +G01 X-1.9536 Y0.4154 +G01 X-1.9525 Y0.4143 +G01 X-1.9525 Y0.4482 +G00 Z0.1000 +G00 X-1.8901 Y0.1955 +G01 Z-0.0070 F10 +G01 X-1.8099 Y0.1955 F20 +G01 X-1.7932 Y0.1886 +G01 X-1.7839 Y0.1792 +G01 X-1.7602 Y0.1816 +G01 X-1.6336 Y0.3082 +G01 X-1.6396 Y0.3142 +G01 X-1.6465 Y0.3309 +G01 X-1.6465 Y0.3491 +G01 X-1.6396 Y0.3658 +G01 X-1.6268 Y0.3786 +G01 X-1.6101 Y0.3855 +G01 X-1.5299 Y0.3855 +G01 X-1.5132 Y0.3786 +G01 X-1.5125 Y0.3778 +G01 X-1.5125 Y0.4022 +G01 X-1.5132 Y0.4014 +G01 X-1.5299 Y0.3945 +G01 X-1.6101 Y0.3945 +G01 X-1.6268 Y0.4014 +G01 X-1.6368 Y0.4114 +G01 X-1.7781 Y0.2701 +G01 X-1.7735 Y0.2591 +G01 X-1.7735 Y0.2409 +G01 X-1.7804 Y0.2242 +G01 X-1.7932 Y0.2114 +G01 X-1.8099 Y0.2045 +G01 X-1.8901 Y0.2045 +G01 X-1.9068 Y0.2114 +G01 X-1.9196 Y0.2242 +G01 X-1.9265 Y0.2409 +G01 X-1.9265 Y0.2520 +G01 X-1.9385 Y0.2625 +G01 X-1.9393 Y0.2625 +G01 X-1.9454 Y0.2686 +G01 X-1.9475 Y0.2704 +G01 X-1.9475 Y0.2303 +G01 X-1.9014 Y0.1908 +G01 X-1.8901 Y0.1955 +G00 Z0.1000 +G00 X-1.9021 Y0.2905 +G01 Z-0.0070 F10 +G01 X-1.8901 Y0.2955 F20 +G01 X-1.8163 Y0.2955 +G01 X-1.8054 Y0.3064 +G01 X-1.8099 Y0.3045 +G01 X-1.8901 Y0.3045 +G01 X-1.9068 Y0.3114 +G01 X-1.9075 Y0.3122 +G01 X-1.9075 Y0.2952 +G01 X-1.9021 Y0.2905 +G00 Z0.1000 +G00 X-1.6268 Y0.6786 +G01 Z-0.0070 F10 +G01 X-1.6101 Y0.6855 F20 +G01 X-1.5299 Y0.6855 +G01 X-1.5175 Y0.6803 +G01 X-1.5175 Y0.6997 +G01 X-1.5299 Y0.6945 +G01 X-1.6101 Y0.6945 +G01 X-1.6268 Y0.7014 +G01 X-1.6368 Y0.7114 +G01 X-1.6375 Y0.7107 +G01 X-1.6375 Y0.6678 +G01 X-1.6268 Y0.6786 +G00 Z0.1000 +G00 X-0.3395 Y0.4187 +G01 Z-0.0070 F10 +G01 X-0.3575 Y0.4007 F20 +G01 X-0.3575 Y0.3643 +G01 X-0.3395 Y0.3823 +G01 X-0.3395 Y0.4187 +G00 Z0.1000 +G00 X-0.5443 Y0.1025 +G01 Z-0.0070 F10 +G01 X-0.2963 Y0.3505 F20 +G01 X-0.3077 Y0.3505 +G01 X-0.5557 Y0.1025 +G01 X-0.5443 Y0.1025 +G00 Z0.1000 +G00 X-1.4999 Y0.8675 +G01 Z-0.0070 F10 +G01 X-1.5022 Y0.8675 F20 +G01 X-1.5004 Y0.8658 +G01 X-1.4991 Y0.8625 +G01 X-1.4953 Y0.8625 +G01 X-1.4999 Y0.8675 +G00 Z0.1000 +G00 X-1.4443 Y0.1325 +G01 Z-0.0070 F10 +G01 X-1.4675 Y0.1557 F20 +G01 X-1.4675 Y0.1493 +G01 X-1.4507 Y0.1325 +G01 X-1.4443 Y0.1325 +G00 Z0.1000 +G00 X-1.6396 Y0.4658 +G01 Z-0.0070 F10 +G01 X-1.6268 Y0.4786 F20 +G01 X-1.6101 Y0.4855 +G01 X-1.5299 Y0.4855 +G01 X-1.5132 Y0.4786 +G01 X-1.5125 Y0.4778 +G01 X-1.5125 Y0.5022 +G01 X-1.5132 Y0.5014 +G01 X-1.5299 Y0.4945 +G01 X-1.6101 Y0.4945 +G01 X-1.6268 Y0.5014 +G01 X-1.6575 Y0.4707 +G01 X-1.6707 Y0.4575 +G01 X-1.7582 Y0.4575 +G01 X-1.7812 Y0.4345 +G01 X-1.8037 Y0.4345 +G01 X-1.8275 Y0.4107 +G01 X-1.8275 Y0.3955 +G01 X-1.8099 Y0.3955 +G01 X-1.7932 Y0.3886 +G01 X-1.7804 Y0.3758 +G01 X-1.7735 Y0.3591 +G01 X-1.7735 Y0.3409 +G01 X-1.7754 Y0.3364 +G01 X-1.6493 Y0.4625 +G01 X-1.6409 Y0.4625 +G01 X-1.6396 Y0.4658 +G00 Z0.1000 +G00 X-2.1943 Y0.8575 +G01 Z-0.0070 F10 +G01 X-2.0565 Y0.9953 F20 +G01 X-2.0645 Y1.0033 +G01 X-2.0645 Y1.0567 +G01 X-2.0267 Y1.0945 +G01 X-1.9763 Y1.0945 +G01 X-1.9793 Y1.0975 +G01 X-2.0307 Y1.0975 +G01 X-2.0775 Y1.0507 +G01 X-2.0775 Y1.0393 +G01 X-2.0775 Y1.0207 +G01 X-2.1675 Y0.9307 +G01 X-2.1807 Y0.9175 +G01 X-2.3507 Y0.9175 +G01 X-2.3693 Y0.9175 +G01 X-2.4193 Y0.9675 +G01 X-2.4325 Y0.9807 +G01 X-2.4325 Y1.0707 +G01 X-2.4325 Y1.0893 +G01 X-2.3225 Y1.1993 +G01 X-2.3093 Y1.2125 +G01 X-1.8425 Y1.2125 +G01 X-1.8425 Y1.2307 +G01 X-1.8425 Y1.2493 +G01 X-1.7925 Y1.2993 +G01 X-1.7793 Y1.3125 +G01 X-1.4757 Y1.3125 +G01 X-1.4625 Y1.2993 +G01 X-1.4537 Y1.2905 +G01 X-1.4212 Y1.2905 +G01 X-1.3945 Y1.2638 +G01 X-1.3945 Y1.2262 +G01 X-1.4052 Y1.2155 +G01 X-1.3712 Y1.2155 +G01 X-1.3582 Y1.2025 +G01 X-1.3293 Y1.2025 +G01 X-1.2725 Y1.2593 +G01 X-1.2593 Y1.2725 +G01 X-1.2093 Y1.2725 +G01 X-1.1907 Y1.2725 +G01 X-1.1515 Y1.2333 +G01 X-1.1414 Y1.2375 +G01 X-1.1186 Y1.2375 +G01 X-1.0974 Y1.2287 +G01 X-1.0813 Y1.2126 +G01 X-1.0725 Y1.1914 +G01 X-1.0725 Y1.1825 +G01 X-0.3543 Y1.1825 +G01 X-0.3357 Y1.1825 +G01 X-0.2027 Y1.0495 +G01 X-0.1695 Y1.0495 +G01 X-0.1405 Y1.0205 +G01 X-0.1405 Y0.9842 +G01 X-0.0911 Y0.9375 +G01 X-0.0907 Y0.9375 +G01 X-0.0843 Y0.9311 +G01 X-0.0778 Y0.9250 +G01 X-0.0778 Y0.9246 +G01 X-0.0775 Y0.9243 +G01 X-0.0775 Y0.9153 +G01 X-0.0772 Y0.9063 +G01 X-0.0775 Y0.9061 +G01 X-0.0775 Y0.5957 +G01 X-0.0907 Y0.5825 +G01 X-0.1175 Y0.5557 +G01 X-0.1175 Y0.3693 +G01 X-0.1175 Y0.3507 +G01 X-0.4707 Y-0.0025 +G01 X-0.4893 Y-0.0025 +G01 X-2.2393 Y-0.0025 +G01 X-2.2525 Y0.0107 +G01 X-2.3393 Y0.0975 +G01 X-2.3525 Y0.1107 +G01 X-2.3525 Y0.3407 +G01 X-2.3525 Y0.3593 +G01 X-2.3525 Y0.7707 +G01 X-2.3525 Y0.7893 +G01 X-2.2843 Y0.8575 +G01 X-2.2657 Y0.8575 +G01 X-2.1943 Y0.8575 +G00 Z0.1000 +G00 X-1.3515 Y0.3500 +G01 Z-0.0070 F10 +G01 X-1.3438 Y0.3686 F20 +G01 X-1.3296 Y0.3828 +G01 X-1.3122 Y0.3900 +G01 X-1.3296 Y0.3972 +G01 X-1.3438 Y0.4114 +G01 X-1.3515 Y0.4300 +G01 X-1.3515 Y0.4500 +G01 X-1.3463 Y0.4625 +G01 X-1.3775 Y0.4625 +G01 X-1.3775 Y0.3614 +G01 X-1.3544 Y0.3383 +G01 X-1.3515 Y0.3354 +G01 X-1.3515 Y0.3500 +G00 Z0.1000 +G00 X-1.5278 Y0.9900 +G01 Z-0.0070 F10 +G01 X-1.5139 Y0.9843 F20 +G01 X-1.5217 Y0.9925 +G01 X-1.5278 Y0.9900 +G00 Z0.1000 +G00 X-1.3110 Y0.2895 +G01 Z-0.0070 F10 +G01 X-1.3296 Y0.2972 F20 +G01 X-1.3425 Y0.3101 +G01 X-1.3425 Y0.2739 +G01 X-1.3200 Y0.2514 +G01 X-1.2909 Y0.2805 +G01 X-1.2875 Y0.2805 +G01 X-1.2875 Y0.2895 +G01 X-1.3110 Y0.2895 +G00 Z0.1000 +G00 X-1.3395 Y1.1491 +G01 Z-0.0070 F10 +G01 X-1.3411 Y1.1475 F20 +G01 X-1.3214 Y1.1475 +G01 X-1.3164 Y1.1525 +G01 X-1.3255 Y1.1525 +G01 X-1.3395 Y1.1525 +G01 X-1.3395 Y1.1491 +G00 Z0.1000 +G00 X-0.1629 Y0.7500 +G01 Z-0.0070 F10 +G01 X-0.1575 Y0.7446 F20 +G01 X-0.1575 Y0.7554 +G01 X-0.1629 Y0.7500 +G00 Z0.1000 +G00 X-0.1355 Y0.8774 +G01 Z-0.0070 F10 +G01 X-0.1463 Y0.8666 F20 +G01 X-0.1275 Y0.8525 +G01 X-0.1275 Y0.9031 +G01 X-0.1355 Y0.9107 +G01 X-0.1355 Y0.8774 +G00 Z0.1000 +G00 X-0.1355 Y0.6226 +G01 Z-0.0070 F10 +G01 X-0.1355 Y0.6084 F20 +G01 X-0.1275 Y0.6164 +G01 X-0.1275 Y0.6475 +G01 X-0.1463 Y0.6334 +G01 X-0.1355 Y0.6226 +G00 Z0.1000 +G00 X-0.9314 Y0.6697 +G01 Z-0.0070 F10 +G01 X-0.9344 Y0.6667 F20 +G01 X-0.9445 Y0.6625 +G01 X-0.9555 Y0.6625 +G01 X-1.1937 Y0.6625 +G01 X-1.1916 Y0.6575 +G01 X-0.9314 Y0.6575 +G01 X-0.9314 Y0.6697 +G00 Z0.1000 +G00 X-1.2104 Y0.5972 +G01 Z-0.0070 F10 +G01 X-1.2278 Y0.5900 F20 +G01 X-1.2104 Y0.5828 +G01 X-1.1962 Y0.5686 +G01 X-1.1885 Y0.5500 +G01 X-1.1885 Y0.5300 +G01 X-1.1937 Y0.5175 +G01 X-0.8964 Y0.5175 +G01 X-0.8392 Y0.5746 +G01 X-0.8415 Y0.5769 +G01 X-0.8523 Y0.5661 +G01 X-0.8708 Y0.5584 +G01 X-0.8909 Y0.5584 +G01 X-0.9095 Y0.5661 +G01 X-0.9237 Y0.5803 +G01 X-0.9314 Y0.5989 +G01 X-0.9314 Y0.6025 +G01 X-1.2051 Y0.6025 +G01 X-1.2104 Y0.5972 +G00 Z0.1000 +G00 X-0.3171 Y0.8500 +G01 Z-0.0070 F10 +G01 X-0.3445 Y0.8774 F20 +G01 X-0.3445 Y0.9225 +G01 X-0.4112 Y0.9225 +G01 X-0.3310 Y0.8361 +G01 X-0.3171 Y0.8500 +G00 Z0.1000 +G00 X-0.5605 Y1.0209 +G01 Z-0.0070 F10 +G01 X-0.5589 Y1.0225 F20 +G01 X-1.1916 Y1.0225 +G01 X-1.1937 Y1.0175 +G01 X-0.5605 Y1.0175 +G01 X-0.5605 Y1.0209 +G00 Z0.1000 +G00 X-1.1962 Y0.9114 +G01 Z-0.0070 F10 +G01 X-1.2104 Y0.8972 F20 +G01 X-1.2278 Y0.8900 +G01 X-1.2104 Y0.8828 +G01 X-1.2082 Y0.8806 +G01 X-1.1764 Y0.9125 +G01 X-1.1957 Y0.9125 +G01 X-1.1962 Y0.9114 +G00 Z0.1000 +G00 X-0.9707 Y0.8611 +G01 Z-0.0070 F10 +G01 X-0.9660 Y0.8725 F20 +G01 X-1.1386 Y0.8725 +G01 X-1.1636 Y0.8475 +G01 X-0.9707 Y0.8475 +G01 X-0.9707 Y0.8611 +G00 Z0.1000 +G00 X-0.9488 Y0.7462 +G01 Z-0.0070 F10 +G01 X-0.9630 Y0.7604 F20 +G01 X-0.9707 Y0.7790 +G01 X-0.9707 Y0.7925 +G01 X-1.1536 Y0.7925 +G01 X-1.1794 Y0.7667 +G01 X-1.1895 Y0.7625 +G01 X-1.1937 Y0.7625 +G01 X-1.1885 Y0.7500 +G01 X-1.1885 Y0.7300 +G01 X-1.1937 Y0.7175 +G01 X-0.9614 Y0.7175 +G01 X-0.9383 Y0.7406 +G01 X-0.9374 Y0.7415 +G01 X-0.9488 Y0.7462 +G00 Z0.1000 +G00 X-0.7123 Y0.8611 +G01 Z-0.0070 F10 +G01 X-0.7123 Y0.7790 F20 +G01 X-0.7146 Y0.7734 +G01 X-0.6467 Y0.7056 +G01 X-0.6425 Y0.6955 +G01 X-0.6425 Y0.6845 +G01 X-0.6425 Y0.5705 +G01 X-0.6425 Y0.5595 +G01 X-0.6467 Y0.5494 +G01 X-0.7756 Y0.4205 +G01 X-0.7590 Y0.4205 +G01 X-0.7479 Y0.4159 +G01 X-0.7106 Y0.4533 +G01 X-0.7005 Y0.4575 +G01 X-0.6895 Y0.4575 +G01 X-0.5664 Y0.4575 +G01 X-0.5068 Y0.5170 +G01 X-0.5033 Y0.5256 +G01 X-0.4956 Y0.5333 +G01 X-0.3556 Y0.6733 +G01 X-0.3455 Y0.6775 +G01 X-0.3445 Y0.6775 +G01 X-0.3445 Y0.7225 +G01 X-0.3555 Y0.7225 +G01 X-0.3656 Y0.7267 +G01 X-0.5114 Y0.8725 +G01 X-0.7170 Y0.8725 +G01 X-0.7123 Y0.8611 +G00 Z0.1000 +G00 X-0.7185 Y0.3600 +G01 Z-0.0070 F10 +G01 X-0.7262 Y0.3414 F20 +G01 X-0.7301 Y0.3375 +G01 X-0.7164 Y0.3375 +G01 X-0.6706 Y0.3833 +G01 X-0.6605 Y0.3875 +G01 X-0.6495 Y0.3875 +G01 X-0.5364 Y0.3875 +G01 X-0.3506 Y0.5733 +G01 X-0.3434 Y0.5763 +G01 X-0.3445 Y0.5774 +G01 X-0.3445 Y0.6066 +G01 X-0.4532 Y0.4980 +G01 X-0.4567 Y0.4894 +G01 X-0.5317 Y0.4144 +G01 X-0.5394 Y0.4067 +G01 X-0.5495 Y0.4025 +G01 X-0.6836 Y0.4025 +G01 X-0.7185 Y0.3676 +G01 X-0.7185 Y0.3600 +G00 Z0.1000 +G00 X-1.3122 Y0.8900 +G01 Z-0.0070 F10 +G01 X-1.3175 Y0.8922 F20 +G01 X-1.3175 Y0.8878 +G01 X-1.3122 Y0.8900 +G00 Z0.1000 +G00 X-1.4525 Y1.0510 +G01 Z-0.0070 F10 +G01 X-1.3725 Y0.9672 F20 +G01 X-1.3725 Y0.9736 +G01 X-1.4525 Y1.0536 +G01 X-1.4525 Y1.0510 +G00 Z0.1000 +G00 X-0.5114 Y1.0825 +G01 Z-0.0070 F10 +G01 X-1.1545 Y1.0825 F20 +G01 X-1.1655 Y1.0825 +G01 X-1.1756 Y1.0867 +G01 X-1.2064 Y1.1175 +G01 X-1.2559 Y1.1175 +G01 X-1.2647 Y1.1264 +G01 X-1.2867 Y1.1044 +G01 X-1.2944 Y1.0967 +G01 X-1.3045 Y1.0925 +G01 X-1.4136 Y1.0925 +G01 X-1.3515 Y1.0304 +G01 X-1.3515 Y1.0500 +G01 X-1.3438 Y1.0686 +G01 X-1.3296 Y1.0828 +G01 X-1.3110 Y1.0905 +G01 X-1.2290 Y1.0905 +G01 X-1.2104 Y1.0828 +G01 X-1.2051 Y1.0775 +G01 X-0.5064 Y1.0775 +G01 X-0.5114 Y1.0825 +G00 Z0.1000 +G00 X-2.1464 Y1.1625 +G01 Z-0.0070 F10 +G01 X-2.2886 Y1.1625 F20 +G01 X-2.3825 Y1.0686 +G01 X-2.3825 Y1.0014 +G01 X-2.3486 Y0.9675 +G01 X-2.3358 Y0.9675 +G01 X-2.3695 Y1.0012 +G01 X-2.3695 Y1.0588 +G01 X-2.3288 Y1.0995 +G01 X-2.2712 Y1.0995 +G01 X-2.2453 Y1.0736 +G01 X-2.1933 Y1.1256 +G01 X-2.1856 Y1.1333 +G01 X-2.1755 Y1.1375 +G01 X-2.1714 Y1.1375 +G01 X-2.1464 Y1.1625 +G00 Z0.1000 +G00 X-2.2305 Y1.0012 +G01 Z-0.0070 F10 +G01 X-2.2642 Y0.9675 F20 +G01 X-2.2014 Y0.9675 +G01 X-2.1275 Y1.0414 +G01 X-2.1275 Y1.0655 +G01 X-2.1233 Y1.0756 +G01 X-2.1156 Y1.0833 +G01 X-2.0664 Y1.1325 +G01 X-2.0986 Y1.1325 +G01 X-2.1367 Y1.0944 +G01 X-2.1444 Y1.0867 +G01 X-2.1545 Y1.0825 +G01 X-2.1586 Y1.0825 +G01 X-2.2267 Y1.0144 +G01 X-2.2305 Y1.0106 +G01 X-2.2305 Y1.0012 +G00 Z0.1000 +G00 X-1.5405 Y1.1491 +G01 Z-0.0070 F10 +G01 X-1.5405 Y1.1725 F20 +G01 X-1.7055 Y1.1725 +G01 X-1.7065 Y1.1722 +G01 X-1.7092 Y1.1724 +G01 X-1.7116 Y1.1700 +G01 X-1.6875 Y1.1459 +G01 X-1.6875 Y1.0941 +G01 X-1.7241 Y1.0575 +G01 X-1.7759 Y1.0575 +G01 X-1.8125 Y1.0941 +G01 X-1.8125 Y1.1436 +G01 X-1.8314 Y1.1625 +G01 X-1.8836 Y1.1625 +G01 X-1.7686 Y1.0475 +G01 X-1.7314 Y1.0475 +G01 X-1.6556 Y1.1233 +G01 X-1.6455 Y1.1275 +G01 X-1.6345 Y1.1275 +G01 X-1.5189 Y1.1275 +G01 X-1.5405 Y1.1491 +G00 Z0.1000 +G00 X-1.4869 Y1.2205 +G01 Z-0.0070 F10 +G01 X-1.4905 Y1.2241 F20 +G01 X-1.4905 Y1.2566 +G01 X-1.4964 Y1.2625 +G01 X-1.7041 Y1.2625 +G01 X-1.6970 Y1.2554 +G01 X-1.6875 Y1.2324 +G01 X-1.6875 Y1.2275 +G01 X-1.5145 Y1.2275 +G01 X-1.5044 Y1.2233 +G01 X-1.5016 Y1.2205 +G01 X-1.4869 Y1.2205 +G00 Z0.1000 +G00 X-1.9436 Y1.1325 +G01 Z-0.0070 F10 +G01 X-1.8967 Y1.0856 F20 +G01 X-1.8925 Y1.0755 +G01 X-1.8925 Y1.0645 +G01 X-1.8925 Y0.9964 +G01 X-1.8786 Y0.9825 +G01 X-1.7945 Y0.9825 +G01 X-1.7414 Y0.9825 +G01 X-1.7314 Y0.9925 +G01 X-1.7745 Y0.9925 +G01 X-1.7855 Y0.9925 +G01 X-1.7956 Y0.9967 +G01 X-1.9314 Y1.1325 +G01 X-1.9436 Y1.1325 +G00 Z0.1000 +G00 X-1.6515 Y1.0475 +G01 Z-0.0070 F10 +G01 X-1.6515 Y1.0496 F20 +G01 X-1.6536 Y1.0475 +G01 X-1.6515 Y1.0475 +G00 Z0.1000 +G00 X-1.3775 Y0.6814 +G01 Z-0.0070 F10 +G01 X-1.3756 Y0.6833 F20 +G01 X-1.3461 Y0.7128 +G01 X-1.3495 Y0.7142 +G01 X-1.3537 Y0.7156 +G01 X-1.3546 Y0.7163 +G01 X-1.3556 Y0.7167 +G01 X-1.3587 Y0.7198 +G01 X-1.3775 Y0.7359 +G01 X-1.3775 Y0.6814 +G00 Z0.1000 +G00 X-0.8129 Y0.7462 +G01 Z-0.0070 F10 +G01 X-0.8201 Y0.7433 F20 +G01 X-0.8217 Y0.7394 +G01 X-0.8294 Y0.7317 +G01 X-0.8498 Y0.7113 +G01 X-0.8415 Y0.7030 +G01 X-0.8307 Y0.7138 +G01 X-0.8122 Y0.7214 +G01 X-0.7921 Y0.7214 +G01 X-0.7735 Y0.7138 +G01 X-0.7628 Y0.7030 +G01 X-0.7520 Y0.7138 +G01 X-0.7383 Y0.7194 +G01 X-0.7574 Y0.7386 +G01 X-0.7728 Y0.7386 +G01 X-0.7914 Y0.7462 +G01 X-0.8021 Y0.7570 +G01 X-0.8129 Y0.7462 +G00 Z0.1000 +G00 X-1.3775 Y0.5564 +G01 Z-0.0070 F10 +G01 X-1.3767 Y0.5556 F20 +G01 X-1.3725 Y0.5455 +G01 X-1.3725 Y0.5345 +G01 X-1.3767 Y0.5244 +G01 X-1.3775 Y0.5236 +G01 X-1.3775 Y0.5175 +G01 X-1.3463 Y0.5175 +G01 X-1.3515 Y0.5300 +G01 X-1.3515 Y0.5500 +G01 X-1.3478 Y0.5589 +G01 X-1.3775 Y0.5886 +G01 X-1.3775 Y0.5564 +G00 Z0.1000 +G00 X-1.0216 Y0.2525 +G01 Z-0.0070 F10 +G01 X-1.0262 Y0.2414 F20 +G01 X-1.0404 Y0.2272 +G01 X-1.0590 Y0.2195 +G01 X-1.1410 Y0.2195 +G01 X-1.1596 Y0.2272 +G01 X-1.1738 Y0.2414 +G01 X-1.1815 Y0.2600 +G01 X-1.1815 Y0.2726 +G01 X-1.2082 Y0.2994 +G01 X-1.2104 Y0.2972 +G01 X-1.2290 Y0.2895 +G01 X-1.2325 Y0.2895 +G01 X-1.2325 Y0.2639 +G01 X-1.2195 Y0.2509 +G01 X-1.2195 Y0.2091 +G01 X-1.2211 Y0.2075 +G01 X-1.0414 Y0.2075 +G01 X-0.9664 Y0.2825 +G01 X-0.9686 Y0.2825 +G01 X-0.9944 Y0.2567 +G01 X-1.0045 Y0.2525 +G01 X-1.0155 Y0.2525 +G01 X-1.0216 Y0.2525 +G00 Z0.1000 +G00 X-0.8738 Y0.3414 +G01 Z-0.0070 F10 +G01 X-0.8815 Y0.3600 F20 +G01 X-0.8815 Y0.3800 +G01 X-0.8763 Y0.3925 +G01 X-0.8975 Y0.3925 +G01 X-0.8975 Y0.3375 +G01 X-0.8699 Y0.3375 +G01 X-0.8738 Y0.3414 +G00 Z0.1000 +G00 X-0.7628 Y0.5769 +G01 Z-0.0070 F10 +G01 X-0.7735 Y0.5661 F20 +G01 X-0.7740 Y0.5659 +G01 X-0.7767 Y0.5594 +G01 X-0.8586 Y0.4775 +G01 X-0.8564 Y0.4775 +G01 X-0.7599 Y0.5740 +G01 X-0.7628 Y0.5769 +G00 Z0.1000 +G00 X-1.1962 Y0.4114 +G01 Z-0.0070 F10 +G01 X-1.2104 Y0.3972 F20 +G01 X-1.2278 Y0.3900 +G01 X-1.2104 Y0.3828 +G01 X-1.1962 Y0.3686 +G01 X-1.1937 Y0.3626 +G01 X-1.1485 Y0.3174 +G01 X-1.1410 Y0.3205 +G01 X-1.0590 Y0.3205 +G01 X-1.0404 Y0.3128 +G01 X-1.0351 Y0.3075 +G01 X-1.0214 Y0.3075 +G01 X-0.9956 Y0.3333 +G01 X-0.9855 Y0.3375 +G01 X-0.9745 Y0.3375 +G01 X-0.9525 Y0.3375 +G01 X-0.9525 Y0.4225 +G01 X-1.1916 Y0.4225 +G01 X-1.1962 Y0.4114 +G00 Z0.1000 +G00 X-1.5278 Y0.6900 +G01 Z-0.0070 F10 +G01 X-1.5225 Y0.6878 F20 +G01 X-1.5225 Y0.6922 +G01 X-1.5278 Y0.6900 +G00 Z0.1000 +G00 X-1.4325 Y0.8990 +G01 Z-0.0070 F10 +G01 X-1.4941 Y0.9635 F20 +G01 X-1.4885 Y0.9500 +G01 X-1.4885 Y0.9300 +G01 X-1.4936 Y0.9177 +G01 X-1.4894 Y0.9175 +G01 X-1.4845 Y0.9175 +G01 X-1.4840 Y0.9173 +G01 X-1.4833 Y0.9172 +G01 X-1.4789 Y0.9152 +G01 X-1.4744 Y0.9133 +G01 X-1.4740 Y0.9129 +G01 X-1.4734 Y0.9126 +G01 X-1.4701 Y0.9090 +G01 X-1.4667 Y0.9056 +G01 X-1.4664 Y0.9050 +G01 X-1.4325 Y0.8680 +G01 X-1.4325 Y0.8990 +G00 Z0.1000 +G00 X-0.5694 Y0.2195 +G01 Z-0.0070 F10 +G01 X-0.6410 Y0.2195 F20 +G01 X-0.6596 Y0.2272 +G01 X-0.6649 Y0.2325 +G01 X-0.9386 Y0.2325 +G01 X-1.0036 Y0.1675 +G01 X-0.6214 Y0.1675 +G01 X-0.5694 Y0.2195 +G00 Z0.1000 +G00 X-1.3487 Y0.1799 +G01 Z-0.0070 F10 +G01 X-1.3491 Y0.1795 F20 +G01 X-1.3909 Y0.1795 +G01 X-1.4205 Y0.2091 +G01 X-1.4205 Y0.2509 +G01 X-1.3975 Y0.2739 +G01 X-1.3975 Y0.3036 +G01 X-1.4225 Y0.3286 +G01 X-1.4225 Y0.1814 +G01 X-1.4086 Y0.1675 +G01 X-1.3364 Y0.1675 +G01 X-1.3487 Y0.1799 +G00 Z0.1000 +G00 X-0.6784 Y0.2875 +G01 Z-0.0070 F10 +G01 X-0.6738 Y0.2986 F20 +G01 X-0.6596 Y0.3128 +G01 X-0.6410 Y0.3205 +G01 X-0.5590 Y0.3205 +G01 X-0.5404 Y0.3128 +G01 X-0.5262 Y0.2986 +G01 X-0.5185 Y0.2800 +G01 X-0.5185 Y0.2704 +G01 X-0.4075 Y0.3814 +G01 X-0.4075 Y0.4045 +G01 X-0.4075 Y0.4155 +G01 X-0.4033 Y0.4256 +G01 X-0.3445 Y0.4844 +G01 X-0.3445 Y0.5016 +G01 X-0.5017 Y0.3444 +G01 X-0.5094 Y0.3367 +G01 X-0.5195 Y0.3325 +G01 X-0.6436 Y0.3325 +G01 X-0.6817 Y0.2944 +G01 X-0.6886 Y0.2875 +G01 X-0.6784 Y0.2875 +G00 Z0.1000 +G00 X-0.4836 Y1.1325 +G01 Z-0.0070 F10 +G01 X-0.4767 Y1.1256 F20 +G01 X-0.4016 Y1.0505 +G01 X-0.3891 Y1.0505 +G01 X-0.3595 Y1.0209 +G01 X-0.3595 Y1.0175 +G01 X-0.3445 Y1.0175 +G01 X-0.3445 Y1.0226 +G01 X-0.3126 Y1.0545 +G01 X-0.2784 Y1.0545 +G01 X-0.3564 Y1.1325 +G01 X-0.4836 Y1.1325 +G00 Z0.1000 +G00 X-1.5278 Y0.3900 +G01 Z-0.0070 F10 +G01 X-1.5175 Y0.3857 F20 +G01 X-1.5175 Y0.3942 +G01 X-1.5278 Y0.3900 +G00 Z0.1000 +G00 X-1.5278 Y0.4900 +G01 Z-0.0070 F10 +G01 X-1.5175 Y0.4857 F20 +G01 X-1.5175 Y0.4942 +G01 X-1.5278 Y0.4900 +G00 Z0.1000 +G00 X-1.5278 Y0.5900 +G01 Z-0.0070 F10 +G01 X-1.5175 Y0.5857 F20 +G01 X-1.5175 Y0.5942 +G01 X-1.5278 Y0.5900 +G00 Z0.1000 +G00 X-1.6515 Y0.5474 +G01 Z-0.0070 F10 +G01 X-1.6515 Y0.5496 F20 +G01 X-1.6744 Y0.5267 +G01 X-1.6845 Y0.5225 +G01 X-1.6955 Y0.5225 +G01 X-1.7711 Y0.5225 +G01 X-1.7561 Y0.5075 +G01 X-1.6914 Y0.5075 +G01 X-1.6515 Y0.5474 +G00 Z0.1000 +G00 X-1.8910 Y0.4005 +G01 Z-0.0070 F10 +G01 X-1.8775 Y0.4005 F20 +G01 X-1.8775 Y0.4255 +G01 X-1.8733 Y0.4356 +G01 X-1.8656 Y0.4433 +G01 X-1.8501 Y0.4587 +G01 X-1.8505 Y0.4591 +G01 X-1.8505 Y0.5009 +G01 X-1.8289 Y0.5225 +G01 X-1.8911 Y0.5225 +G01 X-1.8695 Y0.5009 +G01 X-1.8695 Y0.4591 +G01 X-1.8991 Y0.4295 +G01 X-1.9025 Y0.4295 +G01 X-1.9025 Y0.3957 +G01 X-1.8910 Y0.4005 +G00 Z0.1000 +G00 X-1.9004 Y0.1966 +G01 Z-0.0070 F10 +G01 X-1.8922 Y0.2000 F20 +G01 X-1.9096 Y0.2072 +G01 X-1.9238 Y0.2214 +G01 X-1.9315 Y0.2400 +G01 X-1.9315 Y0.2498 +G01 X-1.9425 Y0.2594 +G01 X-1.9425 Y0.2326 +G01 X-1.9004 Y0.1966 +G00 Z0.1000 +G00 X-1.9705 Y0.4591 +G01 Z-0.0070 F10 +G01 X-1.9705 Y0.5009 F20 +G01 X-1.9489 Y0.5225 +G01 X-2.0111 Y0.5225 +G01 X-1.9895 Y0.5009 +G01 X-1.9895 Y0.4640 +G01 X-1.9575 Y0.4275 +G01 X-1.9575 Y0.4461 +G01 X-1.9705 Y0.4591 +G00 Z0.1000 +G00 X-1.9825 Y0.1914 +G01 Z-0.0070 F10 +G01 X-1.9315 Y0.1404 F20 +G01 X-1.9315 Y0.1508 +G01 X-1.9825 Y0.1945 +G01 X-1.9825 Y0.1914 +G00 Z0.1000 +G00 X-1.9012 Y0.2963 +G01 Z-0.0070 F10 +G01 X-1.8922 Y0.3000 F20 +G01 X-1.9025 Y0.3042 +G01 X-1.9025 Y0.2975 +G01 X-1.9012 Y0.2963 +G00 Z0.1000 +G00 X-1.7762 Y0.1214 +G01 Z-0.0070 F10 +G01 X-1.7901 Y0.1075 F20 +G01 X-1.4964 Y0.1075 +G01 X-1.5133 Y0.1244 +G01 X-1.5175 Y0.1345 +G01 X-1.5175 Y0.1455 +G01 X-1.5175 Y0.2942 +G01 X-1.5290 Y0.2895 +G01 X-1.5816 Y0.2895 +G01 X-1.7296 Y0.1415 +G01 X-1.7322 Y0.1384 +G01 X-1.7334 Y0.1377 +G01 X-1.7344 Y0.1367 +G01 X-1.7382 Y0.1351 +G01 X-1.7418 Y0.1332 +G01 X-1.7432 Y0.1330 +G01 X-1.7445 Y0.1325 +G01 X-1.7486 Y0.1325 +G01 X-1.7726 Y0.1301 +G01 X-1.7762 Y0.1214 +G00 Z0.1000 +G00 X-1.7685 Y0.2600 +G01 Z-0.0070 F10 +G01 X-1.7685 Y0.2400 F20 +G01 X-1.7762 Y0.2214 +G01 X-1.7904 Y0.2072 +G01 X-1.8078 Y0.2000 +G01 X-1.7904 Y0.1928 +G01 X-1.7820 Y0.1844 +G01 X-1.7625 Y0.1864 +G01 X-1.6406 Y0.3082 +G01 X-1.6438 Y0.3114 +G01 X-1.6515 Y0.3300 +G01 X-1.6515 Y0.3500 +G01 X-1.6438 Y0.3686 +G01 X-1.6296 Y0.3828 +G01 X-1.6122 Y0.3900 +G01 X-1.6296 Y0.3972 +G01 X-1.6368 Y0.4044 +G01 X-1.7722 Y0.2689 +G01 X-1.7685 Y0.2600 +G00 Z0.1000 +G00 X-1.8090 Y0.4005 +G01 Z-0.0070 F10 +G01 X-1.7904 Y0.3928 F20 +G01 X-1.7762 Y0.3786 +G01 X-1.7685 Y0.3600 +G01 X-1.7685 Y0.3504 +G01 X-1.6556 Y0.4633 +G01 X-1.6455 Y0.4675 +G01 X-1.6443 Y0.4675 +G01 X-1.6438 Y0.4686 +G01 X-1.6296 Y0.4828 +G01 X-1.6122 Y0.4900 +G01 X-1.6256 Y0.4955 +G01 X-1.6567 Y0.4644 +G01 X-1.6644 Y0.4567 +G01 X-1.6745 Y0.4525 +G01 X-1.7561 Y0.4525 +G01 X-1.7791 Y0.4295 +G01 X-1.8016 Y0.4295 +G01 X-1.8225 Y0.4086 +G01 X-1.8225 Y0.4005 +G01 X-1.8090 Y0.4005 +G00 Z0.1000 +G00 X-0.3445 Y0.4066 +G01 Z-0.0070 F10 +G01 X-0.3525 Y0.3986 F20 +G01 X-0.3525 Y0.3764 +G01 X-0.3445 Y0.3844 +G01 X-0.3445 Y0.4066 +G00 Z0.1000 +G00 X-1.6683 Y0.7506 +G01 Z-0.0070 F10 +G01 X-1.6606 Y0.7583 F20 +G01 X-1.6505 Y0.7625 +G01 X-1.6463 Y0.7625 +G01 X-1.6447 Y0.7663 +G01 X-1.6456 Y0.7667 +G01 X-1.6656 Y0.7867 +G01 X-1.6733 Y0.7944 +G01 X-1.6775 Y0.8045 +G01 X-1.6775 Y0.8545 +G01 X-1.6775 Y0.8655 +G01 X-1.6733 Y0.8756 +G01 X-1.6433 Y0.9056 +G01 X-1.6406 Y0.9082 +G01 X-1.6438 Y0.9114 +G01 X-1.6443 Y0.9125 +G01 X-1.6686 Y0.9125 +G01 X-1.6825 Y0.8986 +G01 X-1.6825 Y0.7364 +G01 X-1.6683 Y0.7506 +G00 Z0.1000 +G00 X-1.7614 Y0.6175 +G01 Z-0.0070 F10 +G01 X-1.7375 Y0.6414 F20 +G01 X-1.7375 Y0.9155 +G01 X-1.7333 Y0.9256 +G01 X-1.7314 Y0.9275 +G01 X-1.7725 Y0.9275 +G01 X-1.7725 Y0.7239 +G01 X-1.7495 Y0.7009 +G01 X-1.7495 Y0.6591 +G01 X-1.7791 Y0.6295 +G01 X-1.8209 Y0.6295 +G01 X-1.8339 Y0.6425 +G01 X-1.8861 Y0.6425 +G01 X-1.8991 Y0.6295 +G01 X-1.9409 Y0.6295 +G01 X-1.9539 Y0.6425 +G01 X-2.0061 Y0.6425 +G01 X-2.0191 Y0.6295 +G01 X-2.0609 Y0.6295 +G01 X-2.0905 Y0.6591 +G01 X-2.0905 Y0.7009 +G01 X-2.0609 Y0.7305 +G01 X-2.0191 Y0.7305 +G01 X-1.9895 Y0.7009 +G01 X-1.9895 Y0.6975 +G01 X-1.9705 Y0.6975 +G01 X-1.9705 Y0.7009 +G01 X-1.9409 Y0.7305 +G01 X-1.8991 Y0.7305 +G01 X-1.8695 Y0.7009 +G01 X-1.8695 Y0.6975 +G01 X-1.8505 Y0.6975 +G01 X-1.8505 Y0.7009 +G01 X-1.8275 Y0.7239 +G01 X-1.8275 Y0.9275 +G01 X-1.8845 Y0.9275 +G01 X-1.8955 Y0.9275 +G01 X-1.9056 Y0.9317 +G01 X-1.9433 Y0.9694 +G01 X-1.9475 Y0.9795 +G01 X-1.9475 Y0.9842 +G01 X-1.9712 Y0.9605 +G01 X-2.0206 Y0.9605 +G01 X-2.1617 Y0.8194 +G01 X-2.1694 Y0.8117 +G01 X-2.1795 Y0.8075 +G01 X-2.2636 Y0.8075 +G01 X-2.3025 Y0.7686 +G01 X-2.3025 Y0.3775 +G01 X-2.2243 Y0.3775 +G01 X-2.2238 Y0.3786 +G01 X-2.2096 Y0.3928 +G01 X-2.1910 Y0.4005 +G01 X-2.1417 Y0.4005 +G01 X-2.1633 Y0.4158 +G01 X-2.1656 Y0.4167 +G01 X-2.1678 Y0.4189 +G01 X-2.1703 Y0.4207 +G01 X-2.1716 Y0.4227 +G01 X-2.1733 Y0.4244 +G01 X-2.1745 Y0.4273 +G01 X-2.1762 Y0.4299 +G01 X-2.1766 Y0.4323 +G01 X-2.1775 Y0.4345 +G01 X-2.1775 Y0.4377 +G01 X-2.1780 Y0.4407 +G01 X-2.1775 Y0.4431 +G01 X-2.1775 Y0.5245 +G01 X-2.1775 Y0.5355 +G01 X-2.1733 Y0.5456 +G01 X-2.1056 Y0.6133 +G01 X-2.0955 Y0.6175 +G01 X-2.0845 Y0.6175 +G01 X-1.7614 Y0.6175 +G00 Z0.1000 +G00 X-2.1090 Y0.0995 +G01 Z-0.0070 F10 +G01 X-2.1910 Y0.0995 F20 +G01 X-2.2096 Y0.1072 +G01 X-2.2238 Y0.1214 +G01 X-2.2315 Y0.1400 +G01 X-2.2315 Y0.1600 +G01 X-2.2238 Y0.1786 +G01 X-2.2096 Y0.1928 +G01 X-2.1922 Y0.2000 +G01 X-2.2096 Y0.2072 +G01 X-2.2238 Y0.2214 +G01 X-2.2315 Y0.2400 +G01 X-2.2315 Y0.2600 +G01 X-2.2238 Y0.2786 +G01 X-2.2096 Y0.2928 +G01 X-2.1922 Y0.3000 +G01 X-2.2096 Y0.3072 +G01 X-2.2238 Y0.3214 +G01 X-2.2243 Y0.3225 +G01 X-2.3025 Y0.3225 +G01 X-2.3025 Y0.1314 +G01 X-2.2186 Y0.0475 +G01 X-2.0814 Y0.0475 +G01 X-2.0883 Y0.0544 +G01 X-2.0925 Y0.0645 +G01 X-2.0925 Y0.1063 +G01 X-2.1090 Y0.0995 +G00 Z0.1000 +G00 X-2.0375 Y0.3836 +G01 Z-0.0070 F10 +G01 X-2.0375 Y0.3836 F20 +G01 X-2.0375 Y0.3823 +G01 X-2.0375 Y0.3836 +G00 Z0.1000 +G00 X-2.0336 Y0.0775 +G01 Z-0.0070 F10 +G01 X-1.9464 Y0.0775 F20 +G01 X-2.0256 Y0.1567 +G01 X-2.0333 Y0.1644 +G01 X-2.0375 Y0.1745 +G01 X-2.0375 Y0.3770 +G01 X-2.0375 Y0.0814 +G01 X-2.0336 Y0.0775 +G00 Z0.1000 +G00 X-1.7014 Y0.5775 +G01 Z-0.0070 F10 +G01 X-1.6875 Y0.5914 F20 +G01 X-1.6875 Y0.6136 +G01 X-1.7236 Y0.5775 +G01 X-1.7014 Y0.5775 +G00 Z0.1000 +G00 X-1.6438 Y0.9686 +G01 Z-0.0070 F10 +G01 X-1.6296 Y0.9828 F20 +G01 X-1.6122 Y0.9900 +G01 X-1.6183 Y0.9925 +G01 X-1.6536 Y0.9925 +G01 X-1.6786 Y0.9675 +G01 X-1.6443 Y0.9675 +G01 X-1.6438 Y0.9686 +G00 Z0.1000 +G00 X-1.6296 Y0.5828 +G01 Z-0.0070 F10 +G01 X-1.6122 Y0.5900 F20 +G01 X-1.6296 Y0.5972 +G01 X-1.6325 Y0.6001 +G01 X-1.6325 Y0.5799 +G01 X-1.6296 Y0.5828 +G00 Z0.1000 +G00 X-1.6296 Y0.6828 +G01 Z-0.0070 F10 +G01 X-1.6122 Y0.6900 F20 +G01 X-1.6296 Y0.6972 +G01 X-1.6325 Y0.7001 +G01 X-1.6325 Y0.6799 +G01 X-1.6296 Y0.6828 +G00 Z0.1000 +G00 X-2.1964 Y0.8625 +G01 Z-0.0070 F10 +G01 X-2.0636 Y0.9953 F20 +G01 X-2.0695 Y1.0012 +G01 X-2.0695 Y1.0516 +G01 X-2.0725 Y1.0486 +G01 X-2.0725 Y1.0355 +G01 X-2.0725 Y1.0245 +G01 X-2.0767 Y1.0144 +G01 X-2.1667 Y0.9244 +G01 X-2.1744 Y0.9167 +G01 X-2.1845 Y0.9125 +G01 X-2.3545 Y0.9125 +G01 X-2.3655 Y0.9125 +G01 X-2.3756 Y0.9167 +G01 X-2.4256 Y0.9667 +G01 X-2.4333 Y0.9744 +G01 X-2.4375 Y0.9845 +G01 X-2.4375 Y1.0745 +G01 X-2.4375 Y1.0855 +G01 X-2.4333 Y1.0956 +G01 X-2.3233 Y1.2056 +G01 X-2.3156 Y1.2133 +G01 X-2.3055 Y1.2175 +G01 X-1.8475 Y1.2175 +G01 X-1.8475 Y1.2345 +G01 X-1.8475 Y1.2455 +G01 X-1.8433 Y1.2556 +G01 X-1.7933 Y1.3056 +G01 X-1.7856 Y1.3133 +G01 X-1.7755 Y1.3175 +G01 X-1.4795 Y1.3175 +G01 X-1.4694 Y1.3133 +G01 X-1.4617 Y1.3056 +G01 X-1.4516 Y1.2955 +G01 X-1.4191 Y1.2955 +G01 X-1.3895 Y1.2659 +G01 X-1.3895 Y1.2241 +G01 X-1.3931 Y1.2205 +G01 X-1.3691 Y1.2205 +G01 X-1.3561 Y1.2075 +G01 X-1.3314 Y1.2075 +G01 X-1.2733 Y1.2656 +G01 X-1.2656 Y1.2733 +G01 X-1.2555 Y1.2775 +G01 X-1.2055 Y1.2775 +G01 X-1.1945 Y1.2775 +G01 X-1.1844 Y1.2733 +G01 X-1.1503 Y1.2392 +G01 X-1.1424 Y1.2425 +G01 X-1.1176 Y1.2425 +G01 X-1.0946 Y1.2330 +G01 X-1.0770 Y1.2154 +G01 X-1.0675 Y1.1924 +G01 X-1.0675 Y1.1875 +G01 X-0.3505 Y1.1875 +G01 X-0.3395 Y1.1875 +G01 X-0.3294 Y1.1833 +G01 X-0.2006 Y1.0545 +G01 X-0.1674 Y1.0545 +G01 X-0.1355 Y1.0226 +G01 X-0.1355 Y0.9863 +G01 X-0.0848 Y0.9385 +G01 X-0.0844 Y0.9383 +G01 X-0.0808 Y0.9347 +G01 X-0.0771 Y0.9312 +G01 X-0.0770 Y0.9309 +G01 X-0.0767 Y0.9306 +G01 X-0.0747 Y0.9258 +G01 X-0.0727 Y0.9213 +G01 X-0.0727 Y0.9208 +G01 X-0.0725 Y0.9205 +G01 X-0.0725 Y0.9154 +G01 X-0.0724 Y0.9103 +G01 X-0.0725 Y0.9099 +G01 X-0.0725 Y0.5995 +G01 X-0.0767 Y0.5894 +G01 X-0.0844 Y0.5817 +G01 X-0.1125 Y0.5536 +G01 X-0.1125 Y0.3655 +G01 X-0.1125 Y0.3545 +G01 X-0.1167 Y0.3444 +G01 X-0.4644 Y-0.0033 +G01 X-0.4745 Y-0.0075 +G01 X-0.4855 Y-0.0075 +G01 X-2.2355 Y-0.0075 +G01 X-2.2456 Y-0.0033 +G01 X-2.2533 Y0.0044 +G01 X-2.3456 Y0.0967 +G01 X-2.3533 Y0.1044 +G01 X-2.3575 Y0.1145 +G01 X-2.3575 Y0.3445 +G01 X-2.3575 Y0.3555 +G01 X-2.3575 Y0.7745 +G01 X-2.3575 Y0.7855 +G01 X-2.3533 Y0.7956 +G01 X-2.2906 Y0.8583 +G01 X-2.2805 Y0.8625 +G01 X-2.2695 Y0.8625 +G01 X-2.1964 Y0.8625 +G00 Z0.1000 +G00 X-1.7635 Y0.2610 +G01 Z-0.0070 F10 +G01 X-1.7635 Y0.2390 F20 +G01 X-1.7719 Y0.2186 +G01 X-1.7876 Y0.2029 +G01 X-1.7947 Y0.2000 +G01 X-1.7876 Y0.1970 +G01 X-1.7802 Y0.1896 +G01 X-1.7648 Y0.1912 +G01 X-1.6477 Y0.3082 +G01 X-1.6480 Y0.3086 +G01 X-1.6565 Y0.3290 +G01 X-1.6565 Y0.3510 +G01 X-1.6480 Y0.3714 +G01 X-1.6324 Y0.3870 +G01 X-1.6253 Y0.3900 +G01 X-1.6324 Y0.3929 +G01 X-1.6368 Y0.3973 +G01 X-1.7663 Y0.2678 +G01 X-1.7635 Y0.2610 +G00 Z0.1000 +G00 X-1.7719 Y0.1186 +G01 Z-0.0070 F10 +G01 X-1.7780 Y0.1125 F20 +G01 X-1.5085 Y0.1125 +G01 X-1.5175 Y0.1216 +G01 X-1.5225 Y0.1335 +G01 X-1.5225 Y0.1465 +G01 X-1.5225 Y0.2868 +G01 X-1.5280 Y0.2845 +G01 X-1.5795 Y0.2845 +G01 X-1.7259 Y0.1382 +G01 X-1.7289 Y0.1344 +G01 X-1.7304 Y0.1336 +G01 X-1.7316 Y0.1324 +G01 X-1.7361 Y0.1306 +G01 X-1.7403 Y0.1283 +G01 X-1.7420 Y0.1281 +G01 X-1.7435 Y0.1275 +G01 X-1.7484 Y0.1275 +G01 X-1.7691 Y0.1254 +G01 X-1.7719 Y0.1186 +G00 Z0.1000 +G00 X-1.8080 Y0.4055 +G01 Z-0.0070 F10 +G01 X-1.7876 Y0.3970 F20 +G01 X-1.7719 Y0.3814 +G01 X-1.7639 Y0.3620 +G01 X-1.6785 Y0.4475 +G01 X-1.7540 Y0.4475 +G01 X-1.7770 Y0.4245 +G01 X-1.7995 Y0.4245 +G01 X-1.8175 Y0.4065 +G01 X-1.8175 Y0.4055 +G01 X-1.8080 Y0.4055 +G00 Z0.1000 +G00 X-1.9755 Y0.4570 +G01 Z-0.0070 F10 +G01 X-1.9755 Y0.5030 F20 +G01 X-1.9610 Y0.5175 +G01 X-1.9990 Y0.5175 +G01 X-1.9845 Y0.5030 +G01 X-1.9845 Y0.4659 +G01 X-1.9625 Y0.4408 +G01 X-1.9625 Y0.4440 +G01 X-1.9755 Y0.4570 +G00 Z0.1000 +G00 X-1.9334 Y0.2314 +G01 Z-0.0070 F10 +G01 X-1.9365 Y0.2390 F20 +G01 X-1.9365 Y0.2475 +G01 X-1.9375 Y0.2484 +G01 X-1.9375 Y0.2349 +G01 X-1.9334 Y0.2314 +G00 Z0.1000 +G00 X-1.8555 Y0.5030 +G01 Z-0.0070 F10 +G01 X-1.8410 Y0.5175 F20 +G01 X-1.8790 Y0.5175 +G01 X-1.8645 Y0.5030 +G01 X-1.8645 Y0.4570 +G01 X-1.8970 Y0.4245 +G01 X-1.8975 Y0.4245 +G01 X-1.8975 Y0.4032 +G01 X-1.8920 Y0.4055 +G01 X-1.8825 Y0.4055 +G01 X-1.8825 Y0.4265 +G01 X-1.8775 Y0.4384 +G01 X-1.8684 Y0.4475 +G01 X-1.8555 Y0.4605 +G01 X-1.8555 Y0.5030 +G00 Z0.1000 +G00 X-1.6885 Y0.5175 +G01 Z-0.0070 F10 +G01 X-1.6965 Y0.5175 F20 +G01 X-1.7590 Y0.5175 +G01 X-1.7540 Y0.5125 +G01 X-1.6935 Y0.5125 +G01 X-1.6885 Y0.5175 +G00 Z0.1000 +G00 X-2.1080 Y0.0945 +G01 Z-0.0070 F10 +G01 X-2.1920 Y0.0945 F20 +G01 X-2.2124 Y0.1029 +G01 X-2.2280 Y0.1186 +G01 X-2.2365 Y0.1390 +G01 X-2.2365 Y0.1610 +G01 X-2.2280 Y0.1814 +G01 X-2.2124 Y0.1970 +G01 X-2.2053 Y0.2000 +G01 X-2.2124 Y0.2029 +G01 X-2.2280 Y0.2186 +G01 X-2.2365 Y0.2390 +G01 X-2.2365 Y0.2610 +G01 X-2.2280 Y0.2814 +G01 X-2.2124 Y0.2970 +G01 X-2.2053 Y0.3000 +G01 X-2.2124 Y0.3029 +G01 X-2.2270 Y0.3175 +G01 X-2.2975 Y0.3175 +G01 X-2.2975 Y0.1335 +G01 X-2.2165 Y0.0525 +G01 X-2.0929 Y0.0525 +G01 X-2.0975 Y0.0635 +G01 X-2.0975 Y0.0988 +G01 X-2.1080 Y0.0945 +G00 Z0.1000 +G00 X-2.0315 Y0.0825 +G01 Z-0.0070 F10 +G01 X-1.9585 Y0.0825 F20 +G01 X-2.0284 Y0.1524 +G01 X-2.0325 Y0.1565 +G01 X-2.0325 Y0.0835 +G01 X-2.0315 Y0.0825 +G00 Z0.1000 +G00 X-1.6253 Y0.6900 +G01 Z-0.0070 F10 +G01 X-1.6275 Y0.6909 F20 +G01 X-1.6275 Y0.6891 +G01 X-1.6253 Y0.6900 +G00 Z0.1000 +G00 X-1.6324 Y0.9870 +G01 Z-0.0070 F10 +G01 X-1.6313 Y0.9875 F20 +G01 X-1.6515 Y0.9875 +G01 X-1.6665 Y0.9725 +G01 X-1.6470 Y0.9725 +G01 X-1.6324 Y0.9870 +G00 Z0.1000 +G00 X-1.6485 Y0.9075 +G01 Z-0.0070 F10 +G01 X-1.6665 Y0.9075 F20 +G01 X-1.6775 Y0.8965 +G01 X-1.6775 Y0.8785 +G01 X-1.6485 Y0.9075 +G00 Z0.1000 +G00 X-1.6725 Y0.7534 +G01 Z-0.0070 F10 +G01 X-1.6634 Y0.7625 F20 +G01 X-1.6529 Y0.7669 +G01 X-1.6684 Y0.7824 +G01 X-1.6775 Y0.7915 +G01 X-1.6775 Y0.7485 +G01 X-1.6725 Y0.7534 +G00 Z0.1000 +G00 X-1.7635 Y0.6225 +G01 Z-0.0070 F10 +G01 X-1.7425 Y0.6435 F20 +G01 X-1.7425 Y0.9165 +G01 X-1.7400 Y0.9225 +G01 X-1.7675 Y0.9225 +G01 X-1.7675 Y0.7260 +G01 X-1.7445 Y0.7030 +G01 X-1.7445 Y0.6570 +G01 X-1.7770 Y0.6245 +G01 X-1.8230 Y0.6245 +G01 X-1.8360 Y0.6375 +G01 X-1.8840 Y0.6375 +G01 X-1.8970 Y0.6245 +G01 X-1.9430 Y0.6245 +G01 X-1.9560 Y0.6375 +G01 X-2.0040 Y0.6375 +G01 X-2.0170 Y0.6245 +G01 X-2.0630 Y0.6245 +G01 X-2.0955 Y0.6570 +G01 X-2.0955 Y0.7030 +G01 X-2.0630 Y0.7355 +G01 X-2.0170 Y0.7355 +G01 X-1.9845 Y0.7030 +G01 X-1.9845 Y0.7025 +G01 X-1.9755 Y0.7025 +G01 X-1.9755 Y0.7030 +G01 X-1.9430 Y0.7355 +G01 X-1.8970 Y0.7355 +G01 X-1.8645 Y0.7030 +G01 X-1.8645 Y0.7025 +G01 X-1.8555 Y0.7025 +G01 X-1.8555 Y0.7030 +G01 X-1.8325 Y0.7260 +G01 X-1.8325 Y0.9225 +G01 X-1.8835 Y0.9225 +G01 X-1.8965 Y0.9225 +G01 X-1.9084 Y0.9274 +G01 X-1.9475 Y0.9666 +G01 X-1.9506 Y0.9740 +G01 X-1.9691 Y0.9555 +G01 X-2.0185 Y0.9555 +G01 X-2.1574 Y0.8166 +G01 X-2.1666 Y0.8074 +G01 X-2.1785 Y0.8025 +G01 X-2.2615 Y0.8025 +G01 X-2.2975 Y0.7665 +G01 X-2.2975 Y0.3825 +G01 X-2.2270 Y0.3825 +G01 X-2.2124 Y0.3970 +G01 X-2.1920 Y0.4055 +G01 X-2.1575 Y0.4055 +G01 X-2.1658 Y0.4114 +G01 X-2.1684 Y0.4124 +G01 X-2.1710 Y0.4151 +G01 X-2.1740 Y0.4172 +G01 X-2.1755 Y0.4196 +G01 X-2.1775 Y0.4216 +G01 X-2.1790 Y0.4250 +G01 X-2.1809 Y0.4281 +G01 X-2.1814 Y0.4309 +G01 X-2.1825 Y0.4335 +G01 X-2.1825 Y0.4372 +G01 X-2.1831 Y0.4409 +G01 X-2.1825 Y0.4436 +G01 X-2.1825 Y0.5235 +G01 X-2.1825 Y0.5365 +G01 X-2.1775 Y0.5484 +G01 X-2.1084 Y0.6175 +G01 X-2.0965 Y0.6225 +G01 X-2.0835 Y0.6225 +G01 X-1.7635 Y0.6225 +G00 Z0.1000 +G00 X-1.7035 Y0.5825 +G01 Z-0.0070 F10 +G01 X-1.6925 Y0.5935 F20 +G01 X-1.6925 Y0.6015 +G01 X-1.7115 Y0.5825 +G01 X-1.7035 Y0.5825 +G00 Z0.1000 +G00 X-1.6253 Y0.5900 +G01 Z-0.0070 F10 +G01 X-1.6275 Y0.5909 F20 +G01 X-1.6275 Y0.5891 +G01 X-1.6253 Y0.5900 +G00 Z0.1000 +G00 X-1.2076 Y0.5929 +G01 Z-0.0070 F10 +G01 X-1.2147 Y0.5900 F20 +G01 X-1.2076 Y0.5870 +G01 X-1.1919 Y0.5714 +G01 X-1.1835 Y0.5510 +G01 X-1.1835 Y0.5290 +G01 X-1.1862 Y0.5225 +G01 X-0.8985 Y0.5225 +G01 X-0.8659 Y0.5551 +G01 X-0.8698 Y0.5534 +G01 X-0.8919 Y0.5534 +G01 X-0.9123 Y0.5619 +G01 X-0.9279 Y0.5775 +G01 X-0.9362 Y0.5975 +G01 X-1.2030 Y0.5975 +G01 X-1.2076 Y0.5929 +G00 Z0.1000 +G00 X-0.7135 Y0.3590 +G01 Z-0.0070 F10 +G01 X-0.7203 Y0.3425 F20 +G01 X-0.7185 Y0.3425 +G01 X-0.6734 Y0.3875 +G01 X-0.6615 Y0.3925 +G01 X-0.6485 Y0.3925 +G01 X-0.5385 Y0.3925 +G01 X-0.3534 Y0.5775 +G01 X-0.3495 Y0.5792 +G01 X-0.3495 Y0.5945 +G01 X-0.4489 Y0.4951 +G01 X-0.4524 Y0.4866 +G01 X-0.5274 Y0.4116 +G01 X-0.5366 Y0.4024 +G01 X-0.5485 Y0.3975 +G01 X-0.6815 Y0.3975 +G01 X-0.7135 Y0.3655 +G01 X-0.7135 Y0.3590 +G00 Z0.1000 +G00 X-0.7073 Y0.8621 +G01 Z-0.0070 F10 +G01 X-0.7073 Y0.7780 F20 +G01 X-0.7087 Y0.7746 +G01 X-0.6424 Y0.7084 +G01 X-0.6375 Y0.6965 +G01 X-0.6375 Y0.6835 +G01 X-0.6375 Y0.5715 +G01 X-0.6375 Y0.5585 +G01 X-0.6424 Y0.5466 +G01 X-0.7635 Y0.4255 +G01 X-0.7580 Y0.4255 +G01 X-0.7491 Y0.4218 +G01 X-0.7134 Y0.4575 +G01 X-0.7015 Y0.4625 +G01 X-0.6885 Y0.4625 +G01 X-0.5685 Y0.4625 +G01 X-0.5111 Y0.5199 +G01 X-0.5075 Y0.5284 +G01 X-0.4984 Y0.5375 +G01 X-0.3584 Y0.6775 +G01 X-0.3495 Y0.6812 +G01 X-0.3495 Y0.7175 +G01 X-0.3565 Y0.7175 +G01 X-0.3684 Y0.7224 +G01 X-0.5135 Y0.8675 +G01 X-0.7095 Y0.8675 +G01 X-0.7073 Y0.8621 +G00 Z0.1000 +G00 X-0.9757 Y0.8621 +G01 Z-0.0070 F10 +G01 X-0.9735 Y0.8675 F20 +G01 X-1.1365 Y0.8675 +G01 X-1.1515 Y0.8525 +G01 X-0.9757 Y0.8525 +G01 X-0.9757 Y0.8621 +G00 Z0.1000 +G00 X-0.9517 Y0.7420 +G01 Z-0.0070 F10 +G01 X-0.9673 Y0.7576 F20 +G01 X-0.9757 Y0.7780 +G01 X-0.9757 Y0.7875 +G01 X-1.1515 Y0.7875 +G01 X-1.1766 Y0.7624 +G01 X-1.1865 Y0.7583 +G01 X-1.1835 Y0.7510 +G01 X-1.1835 Y0.7290 +G01 X-1.1862 Y0.7225 +G01 X-0.9635 Y0.7225 +G01 X-0.9462 Y0.7397 +G01 X-0.9517 Y0.7420 +G00 Z0.1000 +G00 X-0.3241 Y0.8500 +G01 Z-0.0070 F10 +G01 X-0.3495 Y0.8754 F20 +G01 X-0.3495 Y0.9175 +G01 X-0.3998 Y0.9175 +G01 X-0.3308 Y0.8433 +G01 X-0.3241 Y0.8500 +G00 Z0.1000 +G00 X-1.2076 Y0.8929 +G01 Z-0.0070 F10 +G01 X-1.2147 Y0.8900 F20 +G01 X-1.2085 Y0.8874 +G01 X-1.1885 Y0.9075 +G01 X-1.1930 Y0.9075 +G01 X-1.2076 Y0.8929 +G00 Z0.1000 +G00 X-1.2085 Y1.1125 +G01 Z-0.0070 F10 +G01 X-1.2580 Y1.1125 F20 +G01 X-1.2647 Y1.1193 +G01 X-1.2824 Y1.1016 +G01 X-1.2885 Y1.0955 +G01 X-1.2280 Y1.0955 +G01 X-1.2076 Y1.0870 +G01 X-1.2030 Y1.0825 +G01 X-1.1785 Y1.0825 +G01 X-1.2085 Y1.1125 +G00 Z0.1000 +G00 X-0.8101 Y0.7420 +G01 Z-0.0070 F10 +G01 X-0.8163 Y0.7394 F20 +G01 X-0.8174 Y0.7366 +G01 X-0.8266 Y0.7274 +G01 X-0.8427 Y0.7113 +G01 X-0.8415 Y0.7101 +G01 X-0.8336 Y0.7180 +G01 X-0.8132 Y0.7264 +G01 X-0.7911 Y0.7264 +G01 X-0.7707 Y0.7180 +G01 X-0.7628 Y0.7101 +G01 X-0.7548 Y0.7180 +G01 X-0.7471 Y0.7212 +G01 X-0.7595 Y0.7336 +G01 X-0.7738 Y0.7336 +G01 X-0.7942 Y0.7420 +G01 X-0.8021 Y0.7499 +G01 X-0.8101 Y0.7420 +G00 Z0.1000 +G00 X-1.0219 Y0.2386 +G01 Z-0.0070 F10 +G01 X-1.0376 Y0.2229 F20 +G01 X-1.0580 Y0.2145 +G01 X-1.1420 Y0.2145 +G01 X-1.1624 Y0.2229 +G01 X-1.1780 Y0.2386 +G01 X-1.1865 Y0.2590 +G01 X-1.1865 Y0.2705 +G01 X-1.2085 Y0.2926 +G01 X-1.2275 Y0.2847 +G01 X-1.2275 Y0.2660 +G01 X-1.2145 Y0.2530 +G01 X-1.2145 Y0.2125 +G01 X-1.0435 Y0.2125 +G01 X-1.0085 Y0.2475 +G01 X-1.0165 Y0.2475 +G01 X-1.0182 Y0.2475 +G01 X-1.0219 Y0.2386 +G00 Z0.1000 +G00 X-0.8865 Y0.3590 +G01 Z-0.0070 F10 +G01 X-0.8865 Y0.3810 F20 +G01 X-0.8838 Y0.3875 +G01 X-0.8925 Y0.3875 +G01 X-0.8925 Y0.3425 +G01 X-0.8797 Y0.3425 +G01 X-0.8865 Y0.3590 +G00 Z0.1000 +G00 X-1.1919 Y0.4086 +G01 Z-0.0070 F10 +G01 X-1.2076 Y0.3929 F20 +G01 X-1.2147 Y0.3900 +G01 X-1.2076 Y0.3870 +G01 X-1.1919 Y0.3714 +G01 X-1.1895 Y0.3654 +G01 X-1.1473 Y0.3233 +G01 X-1.1420 Y0.3255 +G01 X-1.0580 Y0.3255 +G01 X-1.0376 Y0.3170 +G01 X-1.0330 Y0.3125 +G01 X-1.0235 Y0.3125 +G01 X-0.9984 Y0.3375 +G01 X-0.9865 Y0.3425 +G01 X-0.9735 Y0.3425 +G01 X-0.9575 Y0.3425 +G01 X-0.9575 Y0.4175 +G01 X-1.1882 Y0.4175 +G01 X-1.1919 Y0.4086 +G00 Z0.1000 +G00 X-1.4375 Y0.8970 +G01 Z-0.0070 F10 +G01 X-1.4835 Y0.9452 F20 +G01 X-1.4835 Y0.9290 +G01 X-1.4862 Y0.9225 +G01 X-1.4835 Y0.9225 +G01 X-1.4829 Y0.9222 +G01 X-1.4821 Y0.9222 +G01 X-1.4769 Y0.9197 +G01 X-1.4716 Y0.9175 +G01 X-1.4711 Y0.9170 +G01 X-1.4704 Y0.9167 +G01 X-1.4665 Y0.9125 +G01 X-1.4624 Y0.9084 +G01 X-1.4622 Y0.9077 +G01 X-1.4375 Y0.8808 +G01 X-1.4375 Y0.8970 +G00 Z0.1000 +G00 X-0.6420 Y0.2145 +G01 Z-0.0070 F10 +G01 X-0.6624 Y0.2229 F20 +G01 X-0.6670 Y0.2275 +G01 X-0.9365 Y0.2275 +G01 X-0.9915 Y0.1725 +G01 X-0.6235 Y0.1725 +G01 X-0.5815 Y0.2145 +G01 X-0.6420 Y0.2145 +G00 Z0.1000 +G00 X-1.3505 Y0.1745 +G01 Z-0.0070 F10 +G01 X-1.3930 Y0.1745 F20 +G01 X-1.4175 Y0.1990 +G01 X-1.4175 Y0.1835 +G01 X-1.4065 Y0.1725 +G01 X-1.3485 Y0.1725 +G01 X-1.3505 Y0.1745 +G00 Z0.1000 +G00 X-1.4025 Y0.2760 +G01 Z-0.0070 F10 +G01 X-1.4025 Y0.3015 F20 +G01 X-1.4175 Y0.3165 +G01 X-1.4175 Y0.2610 +G01 X-1.4025 Y0.2760 +G00 Z0.1000 +G00 X-0.6420 Y0.3255 +G01 Z-0.0070 F10 +G01 X-0.5580 Y0.3255 F20 +G01 X-0.5376 Y0.3170 +G01 X-0.5219 Y0.3014 +G01 X-0.5139 Y0.2820 +G01 X-0.4125 Y0.3835 +G01 X-0.4125 Y0.4035 +G01 X-0.4125 Y0.4165 +G01 X-0.4075 Y0.4284 +G01 X-0.3495 Y0.4865 +G01 X-0.3495 Y0.4895 +G01 X-0.4974 Y0.3416 +G01 X-0.5066 Y0.3324 +G01 X-0.5185 Y0.3275 +G01 X-0.6415 Y0.3275 +G01 X-0.6446 Y0.3244 +G01 X-0.6420 Y0.3255 +G00 Z0.1000 +G00 X-0.4715 Y1.1275 +G01 Z-0.0070 F10 +G01 X-0.3995 Y1.0555 F20 +G01 X-0.3870 Y1.0555 +G01 X-0.3545 Y1.0230 +G01 X-0.3545 Y1.0225 +G01 X-0.3495 Y1.0225 +G01 X-0.3495 Y1.0246 +G01 X-0.3146 Y1.0595 +G01 X-0.2905 Y1.0595 +G01 X-0.3585 Y1.1275 +G01 X-0.4715 Y1.1275 +G00 Z0.1000 +G00 X-0.1325 Y0.8734 +G01 Z-0.0070 F10 +G01 X-0.1387 Y0.8671 F20 +G01 X-0.1325 Y0.8625 +G01 X-0.1325 Y0.8734 +G00 Z0.1000 +G00 X-0.1325 Y0.6266 +G01 Z-0.0070 F10 +G01 X-0.1325 Y0.6375 F20 +G01 X-0.1387 Y0.6328 +G01 X-0.1325 Y0.6266 +G00 Z0.1000 +G00 X-1.3565 Y1.0510 +G01 Z-0.0070 F10 +G01 X-1.3480 Y1.0714 F20 +G01 X-1.3324 Y1.0870 +G01 X-1.3313 Y1.0875 +G01 X-1.4015 Y1.0875 +G01 X-1.3565 Y1.0425 +G01 X-1.3565 Y1.0510 +G00 Z0.1000 +G00 X-1.5455 Y1.1470 +G01 Z-0.0070 F10 +G01 X-1.5455 Y1.1675 F20 +G01 X-1.7020 Y1.1675 +G01 X-1.6825 Y1.1480 +G01 X-1.6825 Y1.1035 +G01 X-1.6584 Y1.1275 +G01 X-1.6465 Y1.1325 +G01 X-1.6335 Y1.1325 +G01 X-1.5310 Y1.1325 +G01 X-1.5455 Y1.1470 +G00 Z0.1000 +G00 X-1.4955 Y1.2255 +G01 Z-0.0070 F10 +G01 X-1.4955 Y1.2545 F20 +G01 X-1.4985 Y1.2575 +G01 X-1.6925 Y1.2575 +G01 X-1.6825 Y1.2334 +G01 X-1.6825 Y1.2325 +G01 X-1.5135 Y1.2325 +G01 X-1.5016 Y1.2275 +G01 X-1.4995 Y1.2255 +G01 X-1.4955 Y1.2255 +G00 Z0.1000 +G00 X-2.1585 Y1.1575 +G01 Z-0.0070 F10 +G01 X-2.2865 Y1.1575 F20 +G01 X-2.3775 Y1.0665 +G01 X-2.3775 Y1.0035 +G01 X-2.3745 Y1.0005 +G01 X-2.3745 Y1.0609 +G01 X-2.3309 Y1.1045 +G01 X-2.2691 Y1.1045 +G01 X-2.2453 Y1.0807 +G01 X-2.1975 Y1.1284 +G01 X-2.1884 Y1.1375 +G01 X-2.1765 Y1.1425 +G01 X-2.1735 Y1.1425 +G01 X-2.1585 Y1.1575 +G00 Z0.1000 +G00 X-2.2255 Y0.9991 +G01 Z-0.0070 F10 +G01 X-2.2521 Y0.9725 F20 +G01 X-2.2035 Y0.9725 +G01 X-2.1325 Y1.0435 +G01 X-2.1325 Y1.0665 +G01 X-2.1275 Y1.0784 +G01 X-2.1184 Y1.0875 +G01 X-2.0785 Y1.1275 +G01 X-2.0965 Y1.1275 +G01 X-2.1324 Y1.0916 +G01 X-2.1416 Y1.0824 +G01 X-2.1535 Y1.0775 +G01 X-2.1565 Y1.0775 +G01 X-2.2224 Y1.0116 +G01 X-2.2255 Y1.0085 +G01 X-2.2255 Y0.9991 +G00 Z0.1000 +G00 X-1.8175 Y1.1415 +G01 Z-0.0070 F10 +G01 X-1.8335 Y1.1575 F20 +G01 X-1.8715 Y1.1575 +G01 X-1.8175 Y1.1035 +G01 X-1.8175 Y1.1415 +G00 Z0.1000 +G00 X-1.8875 Y1.0765 +G01 Z-0.0070 F10 +G01 X-1.8875 Y1.0635 F20 +G01 X-1.8875 Y0.9985 +G01 X-1.8765 Y0.9875 +G01 X-1.7935 Y0.9875 +G01 X-1.7435 Y0.9875 +G01 X-1.7735 Y0.9875 +G01 X-1.7865 Y0.9875 +G01 X-1.7984 Y0.9924 +G01 X-1.8911 Y1.0851 +G01 X-1.8875 Y1.0765 +G00 Z0.1000 +G00 X-1.7335 Y1.0525 +G01 Z-0.0070 F10 +G01 X-1.7335 Y1.0525 F20 +G01 X-1.7665 Y1.0525 +G01 X-1.7335 Y1.0525 +G00 Z0.1000 +G00 X-1.3725 Y0.6935 +G01 Z-0.0070 F10 +G01 X-1.3552 Y0.7108 F20 +G01 X-1.3562 Y0.7111 +G01 X-1.3572 Y0.7120 +G01 X-1.3584 Y0.7124 +G01 X-1.3621 Y0.7161 +G01 X-1.3725 Y0.7251 +G01 X-1.3725 Y0.6935 +G00 Z0.1000 +G00 X-1.3725 Y0.5585 +G01 Z-0.0070 F10 +G01 X-1.3724 Y0.5584 F20 +G01 X-1.3675 Y0.5465 +G01 X-1.3675 Y0.5335 +G01 X-1.3721 Y0.5225 +G01 X-1.3538 Y0.5225 +G01 X-1.3565 Y0.5290 +G01 X-1.3565 Y0.5510 +G01 X-1.3537 Y0.5578 +G01 X-1.3725 Y0.5765 +G01 X-1.3725 Y0.5585 +G00 Z0.1000 +G00 X-1.3200 Y0.2585 +G01 Z-0.0070 F10 +G01 X-1.2940 Y0.2845 F20 +G01 X-1.3120 Y0.2845 +G01 X-1.3324 Y0.2929 +G01 X-1.3375 Y0.2980 +G01 X-1.3375 Y0.2760 +G01 X-1.3200 Y0.2585 +G00 Z0.1000 +G00 X-1.3565 Y0.3510 +G01 Z-0.0070 F10 +G01 X-1.3480 Y0.3714 F20 +G01 X-1.3324 Y0.3870 +G01 X-1.3253 Y0.3900 +G01 X-1.3324 Y0.3929 +G01 X-1.3480 Y0.4086 +G01 X-1.3565 Y0.4290 +G01 X-1.3565 Y0.4510 +G01 X-1.3538 Y0.4575 +G01 X-1.3725 Y0.4575 +G01 X-1.3725 Y0.3635 +G01 X-1.3565 Y0.3475 +G01 X-1.3565 Y0.3510 +G00 Z0.1000 +G00 X-2.1985 Y0.8675 +G01 Z-0.0070 F10 +G01 X-2.0707 Y0.9953 F20 +G01 X-2.0745 Y0.9991 +G01 X-2.0745 Y1.0095 +G01 X-2.1624 Y0.9216 +G01 X-2.1716 Y0.9124 +G01 X-2.1835 Y0.9075 +G01 X-2.3535 Y0.9075 +G01 X-2.3665 Y0.9075 +G01 X-2.3784 Y0.9124 +G01 X-2.4284 Y0.9624 +G01 X-2.4375 Y0.9716 +G01 X-2.4425 Y0.9835 +G01 X-2.4425 Y1.0735 +G01 X-2.4425 Y1.0865 +G01 X-2.4375 Y1.0984 +G01 X-2.3275 Y1.2084 +G01 X-2.3184 Y1.2175 +G01 X-2.3065 Y1.2225 +G01 X-1.8525 Y1.2225 +G01 X-1.8525 Y1.2335 +G01 X-1.8525 Y1.2465 +G01 X-1.8475 Y1.2584 +G01 X-1.7975 Y1.3084 +G01 X-1.7884 Y1.3175 +G01 X-1.7765 Y1.3225 +G01 X-1.4785 Y1.3225 +G01 X-1.4666 Y1.3175 +G01 X-1.4574 Y1.3084 +G01 X-1.4495 Y1.3005 +G01 X-1.4170 Y1.3005 +G01 X-1.3845 Y1.2680 +G01 X-1.3845 Y1.2255 +G01 X-1.3670 Y1.2255 +G01 X-1.3540 Y1.2125 +G01 X-1.3335 Y1.2125 +G01 X-1.2775 Y1.2684 +G01 X-1.2684 Y1.2775 +G01 X-1.2565 Y1.2825 +G01 X-1.2065 Y1.2825 +G01 X-1.1935 Y1.2825 +G01 X-1.1816 Y1.2775 +G01 X-1.1492 Y1.2451 +G01 X-1.1434 Y1.2475 +G01 X-1.1166 Y1.2475 +G01 X-1.0918 Y1.2372 +G01 X-1.0728 Y1.2182 +G01 X-1.0625 Y1.1934 +G01 X-1.0625 Y1.1925 +G01 X-0.3515 Y1.1925 +G01 X-0.3385 Y1.1925 +G01 X-0.3266 Y1.1875 +G01 X-0.1985 Y1.0595 +G01 X-0.1654 Y1.0595 +G01 X-0.1305 Y1.0246 +G01 X-0.1305 Y0.9885 +G01 X-0.0820 Y0.9427 +G01 X-0.0816 Y0.9425 +G01 X-0.0773 Y0.9383 +G01 X-0.0730 Y0.9342 +G01 X-0.0728 Y0.9337 +G01 X-0.0724 Y0.9334 +G01 X-0.0702 Y0.9279 +G01 X-0.0677 Y0.9224 +G01 X-0.0677 Y0.9219 +G01 X-0.0675 Y0.9215 +G01 X-0.0675 Y0.9155 +G01 X-0.0673 Y0.9095 +G01 X-0.0675 Y0.9090 +G01 X-0.0675 Y0.5985 +G01 X-0.0724 Y0.5866 +G01 X-0.0816 Y0.5774 +G01 X-0.1075 Y0.5515 +G01 X-0.1075 Y0.3665 +G01 X-0.1075 Y0.3535 +G01 X-0.1124 Y0.3416 +G01 X-0.4616 Y-0.0075 +G01 X-0.4735 Y-0.0125 +G01 X-0.4865 Y-0.0125 +G01 X-2.2365 Y-0.0125 +G01 X-2.2484 Y-0.0075 +G01 X-2.2575 Y0.0016 +G01 X-2.3484 Y0.0924 +G01 X-2.3575 Y0.1016 +G01 X-2.3625 Y0.1135 +G01 X-2.3625 Y0.3435 +G01 X-2.3625 Y0.3565 +G01 X-2.3625 Y0.7735 +G01 X-2.3625 Y0.7865 +G01 X-2.3575 Y0.7984 +G01 X-2.2934 Y0.8625 +G01 X-2.2815 Y0.8675 +G01 X-2.2685 Y0.8675 +G01 X-2.1985 Y0.8675 +G00 Z0.1000 +G82 X-0.1500 Y1.1900 Z-0.0110 F10 R0.1000 P1.000000 +G82 X-0.1500 Y0.1300 +G82 X-1.2700 Y0.2300 +G82 X-1.3700 Y0.2300 +G82 X-0.5100 Y1.0000 +G82 X-0.4100 Y1.0000 +G82 X-1.1300 Y1.1800 +G82 X-1.2300 Y1.1800 +G82 X-1.7500 Y1.2200 +G82 X-1.7500 Y1.1200 +G82 X-1.5700 Y0.3400 +G82 X-1.5700 Y0.4400 +G82 X-1.5700 Y0.5400 +G82 X-1.5700 Y0.6400 +G82 X-1.5700 Y0.7400 +G82 X-1.5700 Y0.8400 +G82 X-1.5700 Y0.9400 +G82 X-1.5700 Y1.0400 +G82 X-1.2700 Y1.0400 +G82 X-1.2700 Y0.9400 +G82 X-1.2700 Y0.8400 +G82 X-1.2700 Y0.7400 +G82 X-1.2700 Y0.6400 +G82 X-1.2700 Y0.5400 +G82 X-1.2700 Y0.4400 +G82 X-1.2700 Y0.3400 +G82 X-1.3900 Y1.1700 +G82 X-1.4400 Y1.2450 +G82 X-1.4900 Y1.1700 +G82 X-0.6000 Y0.2700 +G82 X-1.1000 Y0.2700 +G82 X-0.8000 Y0.3700 +G82 X-1.8000 Y0.6800 +G82 X-1.8000 Y0.4800 +G82 X-1.9200 Y0.6800 +G82 X-1.9200 Y0.4800 +G82 X-2.0400 Y0.6800 +G82 X-2.0400 Y0.4800 +G82 X-2.1500 Y0.1500 +G82 X-2.1500 Y0.2500 +G82 X-2.1500 Y0.3500 +G82 X-1.8500 Y0.3500 +G82 X-1.8500 Y0.2500 +G82 X-1.8500 Y0.1500 +G82 X-2.0000 Y1.0300 +G82 X-2.3000 Y1.0300 +G82 X-0.7234 Y0.6709 +G82 X-0.7628 Y0.7891 +G82 X-0.8021 Y0.6709 +G82 X-0.8415 Y0.7891 +G82 X-0.8809 Y0.6709 +G82 X-0.9202 Y0.7891 +G82 X-1.1171 Y0.7576 +G82 X-0.5029 Y0.7576 +G82 X-0.2900 Y1.0000 +G82 X-0.1900 Y1.0000 +G82 X-0.2900 Y0.9000 +G82 X-0.1900 Y0.9000 +G82 X-0.2900 Y0.8000 +G82 X-0.1900 Y0.8000 +G82 X-0.2900 Y0.7000 +G82 X-0.1900 Y0.7000 +G82 X-0.2900 Y0.6000 +G82 X-0.1900 Y0.6000 +G82 X-0.2900 Y0.5000 +G82 X-0.1900 Y0.5000 +G82 X-0.2900 Y0.4000 +G82 X-0.1900 Y0.4000 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.mill.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.mill.tap new file mode 100644 index 00000000..e57bc889 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.mill.tap @@ -0,0 +1,46 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0100 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G01 X-0.0100 Y-0.0100 +G01 X-2.7900 Y-0.0100 +G01 X-2.7900 Y1.3300 +G00 Z0.1000 +G00 X0.0100 Y1.3200 +G01 Z-0.0100 F10 +G01 X0.0100 Y0.0000 F20 +G00 Z0.1000 +G00 X0.0100 Y1.3300 +G01 Z-0.0100 F10 +G01 X-2.7900 Y1.3300 F20 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.text.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.text.tap new file mode 100644 index 00000000..24866e60 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.bot.text.tap @@ -0,0 +1,93 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0050 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-2.5800 Y0.1407 +G01 Z-0.0050 F10 +G01 X-2.6701 Y0.1407 F20 +G01 X-2.6926 Y0.1632 +G01 X-2.6926 Y0.2082 +G01 X-2.6701 Y0.2308 +G01 X-2.5800 Y0.2308 +G01 X-2.5575 Y0.2082 +G01 X-2.5575 Y0.1632 +G01 X-2.5800 Y0.1407 +G01 X-2.6701 Y0.2308 +G00 Z0.1000 +G00 X-2.5575 Y0.3463 +G01 Z-0.0050 F10 +G01 X-2.6926 Y0.3463 F20 +G01 X-2.6251 Y0.2788 +G01 X-2.6251 Y0.3689 +G00 Z0.1000 +G00 X-2.6476 Y0.4169 +G01 Z-0.0050 F10 +G01 X-2.6926 Y0.4619 F20 +G01 X-2.5575 Y0.4619 +G00 Z0.1000 +G00 X-2.5575 Y0.4169 +G01 Z-0.0050 F10 +G01 X-2.5575 Y0.5070 F20 +G00 Z0.1000 +G00 X-2.6926 Y0.6451 +G01 Z-0.0050 F10 +G01 X-2.6926 Y0.5550 F20 +G01 X-2.6251 Y0.5550 +G01 X-2.6476 Y0.6001 +G01 X-2.6476 Y0.6226 +G01 X-2.6251 Y0.6451 +G01 X-2.5800 Y0.6451 +G01 X-2.5575 Y0.6226 +G01 X-2.5575 Y0.5775 +G01 X-2.5800 Y0.5550 +G00 Z0.1000 +G00 X-2.6476 Y0.6931 +G01 Z-0.0050 F10 +G01 X-2.6926 Y0.7382 F20 +G01 X-2.5575 Y0.7382 +G00 Z0.1000 +G00 X-2.5575 Y0.6931 +G01 Z-0.0050 F10 +G01 X-2.5575 Y0.7832 F20 +G00 Z0.1000 +G00 X-2.5575 Y0.9694 +G01 Z-0.0050 F10 +G01 X-2.6476 Y0.9694 F20 +G01 X-2.6926 Y1.0144 +G01 X-2.6476 Y1.0594 +G01 X-2.5575 Y1.0594 +G00 Z0.1000 +G00 X-2.6251 Y0.9694 +G01 Z-0.0050 F10 +G01 X-2.6251 Y1.0594 F20 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.brd b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.brd new file mode 100644 index 00000000..60d37332 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.brd differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.drl b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.drl new file mode 100644 index 00000000..1753e72d --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.drl @@ -0,0 +1,27 @@ +# +# Sample drill rack file for the enabtmr board. +# +# Drill is the size of the drill bit. +# Min is the smallest hole the bit will be used for. +# Max is the largest hole the bit will be used for. +# +# Each value can have a "unit of measure" added to it, +# such as 0.500mm . If you do not provide the unit of measure, +# values over 0.250 are considered millimeters, and +# values under 0.250 are considered inches. For example: +# 0.400 would be considered 0.400 mm. +# 0.125 would be considered 0.125 inches. +# +# Please note that you must use a TAB character +# between each setting on a line. +# +# Tip: Set the TAB size of your editor to 12 characters. +# +tool drill_size minimum maximum length +T01 0.500mm 0.000in 0.025in 1.5in +T02 0.032in 0.025in 0.035in 1.5in +T03 0.040in 0.035in 0.045in 1.5in +T04 0.050in 0.045in 0.055in 1.5in +T05 0.062in 0.055in 0.070in 1.5in +T06 0.085in 0.070in 0.125in 1.5in +T07 0.125in 0.100in 0.125in 1.5in diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.sch b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.sch new file mode 100644 index 00000000..720db951 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.sch differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.drill.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.drill.tap new file mode 100644 index 00000000..b3646281 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.drill.tap @@ -0,0 +1,278 @@ +(.../src/pcbgcode-work/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/16/12 2:10 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0030 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0002) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +( Tool| Size | Min Sub | Max Sub | Count ) +( T02 | 0.813mm 0.0320in | 0.0320in | 0.0320in | 49 ) +( T03 | 1.016mm 0.0400in | 0.0400in | 0.0400in | 17 ) +( T03 | 2.184mm 0.0860in | 0.0400in | 0.0400in | 17 ) +( T07 | 3.175mm 0.1250in | 0.1250in | 0.1250in | 3 ) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T02 ; 0.0320 +G01 Z0.0000 F10 +M06 T01 ; 0.0320 +G00 Z0.1000 +M03 +G04 P3.000000 +G00 X0.4100 Y1.0000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.5100 Y1.0000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.6000 Y0.2700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.7234 Y0.6709 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.7628 Y0.7891 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.8000 Y0.3700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.8021 Y0.6709 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.8415 Y0.7891 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.8809 Y0.6709 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.9202 Y0.7891 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.1000 Y0.2700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.1300 Y1.1800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2300 Y1.1800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.2300 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.3400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.4400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.5400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.6400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.7400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.8400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y0.9400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.2700 Y1.0400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.3700 Y0.2300 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.3900 Y1.1700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.4400 Y1.2450 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.4900 Y1.1700 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.3400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.4400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.5400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.6400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.7400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.8400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y0.9400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.5700 Y1.0400 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.7500 Y1.1200 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.7500 Y1.2200 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8000 Y0.4800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8000 Y0.6800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8500 Y0.1500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8500 Y0.2500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.8500 Y0.3500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.9200 Y0.4800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.9200 Y0.6800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.0400 Y0.4800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.0400 Y0.6800 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.1500 Y0.1500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.1500 Y0.2500 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.1500 Y0.3500 +G01 Z-0.0320 F10 +G00 Z0.1000 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T03 ; 0.0400 +G01 Z0.0000 F10 +M06 T02 ; 0.0400 +G00 Z0.1000 +M03 +G04 P3.000000 +G00 X0.1900 Y0.4000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.5000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.6000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.7000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.8000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y0.9000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1900 Y1.0000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.4000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.5000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.6000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.7000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.8000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y0.9000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.2900 Y1.0000 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.0000 Y1.0300 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X2.3000 Y1.0300 +G01 Z-0.0320 F10 +G00 Z0.1000 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T03 ; 0.0860 +G01 Z0.0000 F10 +M06 T03 ; 0.0860 +G00 Z0.1000 +M03 +G04 P3.000000 +G00 X0.5029 Y0.7576 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X1.1171 Y0.7576 +G01 Z-0.0320 F10 +G00 Z0.1000 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T07 ; 0.1250 +G01 Z0.0000 F10 +M06 T04 ; 0.1250 +G00 Z0.1000 +M03 +G04 P3.000000 +G00 X0.1500 Y0.1300 +G01 Z-0.0320 F10 +G00 Z0.1000 +G00 X0.1500 Y1.1900 +G01 Z-0.0320 F10 +G00 Z0.1000 +T01 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.etch.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.etch.tap new file mode 100644 index 00000000..65c135ba --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.etch.tap @@ -0,0 +1,4707 @@ +(.../src/pcbgcode-work/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/16/12 4:41 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0030 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, bottom outlines, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X0.8356 Y0.6023 +G01 Z-0.0070 F10 +G01 X0.8356 Y0.6776 F20 +G01 X0.8305 Y0.6899 +G01 X0.8211 Y0.6993 +G01 X0.8088 Y0.7044 +G01 X0.7955 Y0.7044 +G01 X0.7831 Y0.6993 +G01 X0.7737 Y0.6899 +G01 X0.7686 Y0.6776 +G01 X0.7686 Y0.6023 +G01 X0.7737 Y0.5900 +G01 X0.7831 Y0.5805 +G01 X0.7955 Y0.5754 +G01 X0.8088 Y0.5754 +G01 X0.8211 Y0.5805 +G01 X0.8305 Y0.5900 +G01 X0.8356 Y0.6023 +G00 Z0.1000 +G00 X0.8080 Y0.8577 +G01 Z-0.0070 F10 +G01 X0.8080 Y0.7824 F20 +G01 X0.8131 Y0.7701 +G01 X0.8225 Y0.7607 +G01 X0.8348 Y0.7556 +G01 X0.8482 Y0.7556 +G01 X0.8605 Y0.7607 +G01 X0.8699 Y0.7701 +G01 X0.8750 Y0.7824 +G01 X0.8750 Y0.8577 +G01 X0.8699 Y0.8700 +G01 X0.8605 Y0.8795 +G01 X0.8482 Y0.8846 +G01 X0.8348 Y0.8846 +G01 X0.8225 Y0.8795 +G01 X0.8131 Y0.8700 +G01 X0.8080 Y0.8577 +G00 Z0.1000 +G00 X0.7569 Y0.6023 +G01 Z-0.0070 F10 +G01 X0.7569 Y0.6776 F20 +G01 X0.7518 Y0.6899 +G01 X0.7424 Y0.6993 +G01 X0.7300 Y0.7044 +G01 X0.7167 Y0.7044 +G01 X0.7044 Y0.6993 +G01 X0.6950 Y0.6899 +G01 X0.6899 Y0.6776 +G01 X0.6899 Y0.6023 +G01 X0.6950 Y0.5900 +G01 X0.7044 Y0.5805 +G01 X0.7167 Y0.5754 +G01 X0.7300 Y0.5754 +G01 X0.7424 Y0.5805 +G01 X0.7518 Y0.5900 +G01 X0.7569 Y0.6023 +G00 Z0.1000 +G00 X0.9144 Y0.6023 +G01 Z-0.0070 F10 +G01 X0.9144 Y0.6776 F20 +G01 X0.9093 Y0.6899 +G01 X0.8998 Y0.6993 +G01 X0.8875 Y0.7044 +G01 X0.8742 Y0.7044 +G01 X0.8619 Y0.6993 +G01 X0.8525 Y0.6899 +G01 X0.8474 Y0.6776 +G01 X0.8474 Y0.6023 +G01 X0.8525 Y0.5900 +G01 X0.8619 Y0.5805 +G01 X0.8742 Y0.5754 +G01 X0.8875 Y0.5754 +G01 X0.8998 Y0.5805 +G01 X0.9093 Y0.5900 +G01 X0.9144 Y0.6023 +G00 Z0.1000 +G00 X0.8867 Y0.8577 +G01 Z-0.0070 F10 +G01 X0.8867 Y0.7824 F20 +G01 X0.8918 Y0.7701 +G01 X0.9013 Y0.7607 +G01 X0.9136 Y0.7556 +G01 X0.9269 Y0.7556 +G01 X0.9392 Y0.7607 +G01 X0.9486 Y0.7701 +G01 X0.9537 Y0.7824 +G01 X0.9537 Y0.8577 +G01 X0.9486 Y0.8700 +G01 X0.9392 Y0.8795 +G01 X0.9269 Y0.8846 +G01 X0.9136 Y0.8846 +G01 X0.9013 Y0.8795 +G01 X0.8918 Y0.8700 +G01 X0.8867 Y0.8577 +G00 Z0.1000 +G00 X0.7293 Y0.8577 +G01 Z-0.0070 F10 +G01 X0.7293 Y0.7824 F20 +G01 X0.7344 Y0.7701 +G01 X0.7438 Y0.7607 +G01 X0.7561 Y0.7556 +G01 X0.7694 Y0.7556 +G01 X0.7817 Y0.7607 +G01 X0.7912 Y0.7701 +G01 X0.7963 Y0.7824 +G01 X0.7963 Y0.8577 +G01 X0.7912 Y0.8700 +G01 X0.7817 Y0.8795 +G01 X0.7694 Y0.8846 +G01 X0.7561 Y0.8846 +G01 X0.7438 Y0.8795 +G01 X0.7344 Y0.8700 +G01 X0.7293 Y0.8577 +G00 Z0.1000 +G00 X1.5323 Y0.3065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.3065 F20 +G01 X1.6200 Y0.3116 +G01 X1.6294 Y0.3210 +G01 X1.6345 Y0.3333 +G01 X1.6345 Y0.3467 +G01 X1.6294 Y0.3590 +G01 X1.6200 Y0.3684 +G01 X1.6077 Y0.3735 +G01 X1.5323 Y0.3735 +G01 X1.5200 Y0.3684 +G01 X1.5106 Y0.3590 +G01 X1.5055 Y0.3467 +G01 X1.5055 Y0.3333 +G01 X1.5106 Y0.3210 +G01 X1.5200 Y0.3116 +G01 X1.5323 Y0.3065 +G00 Z0.1000 +G00 X1.5323 Y0.4065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.4065 F20 +G01 X1.6200 Y0.4116 +G01 X1.6294 Y0.4210 +G01 X1.6345 Y0.4333 +G01 X1.6345 Y0.4467 +G01 X1.6294 Y0.4590 +G01 X1.6200 Y0.4684 +G01 X1.6077 Y0.4735 +G01 X1.5323 Y0.4735 +G01 X1.5200 Y0.4684 +G01 X1.5106 Y0.4590 +G01 X1.5055 Y0.4467 +G01 X1.5055 Y0.4333 +G01 X1.5106 Y0.4210 +G01 X1.5200 Y0.4116 +G01 X1.5323 Y0.4065 +G00 Z0.1000 +G00 X1.5323 Y0.5065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.5065 F20 +G01 X1.6200 Y0.5116 +G01 X1.6294 Y0.5210 +G01 X1.6345 Y0.5333 +G01 X1.6345 Y0.5467 +G01 X1.6294 Y0.5590 +G01 X1.6200 Y0.5684 +G01 X1.6077 Y0.5735 +G01 X1.5323 Y0.5735 +G01 X1.5200 Y0.5684 +G01 X1.5106 Y0.5590 +G01 X1.5055 Y0.5467 +G01 X1.5055 Y0.5333 +G01 X1.5106 Y0.5210 +G01 X1.5200 Y0.5116 +G01 X1.5323 Y0.5065 +G00 Z0.1000 +G00 X1.5323 Y0.6065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.6065 F20 +G01 X1.6200 Y0.6116 +G01 X1.6294 Y0.6210 +G01 X1.6345 Y0.6333 +G01 X1.6345 Y0.6467 +G01 X1.6294 Y0.6590 +G01 X1.6200 Y0.6684 +G01 X1.6077 Y0.6735 +G01 X1.5323 Y0.6735 +G01 X1.5200 Y0.6684 +G01 X1.5106 Y0.6590 +G01 X1.5055 Y0.6467 +G01 X1.5055 Y0.6333 +G01 X1.5106 Y0.6210 +G01 X1.5200 Y0.6116 +G01 X1.5323 Y0.6065 +G00 Z0.1000 +G00 X1.5323 Y0.7065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.7065 F20 +G01 X1.6200 Y0.7116 +G01 X1.6294 Y0.7210 +G01 X1.6345 Y0.7333 +G01 X1.6345 Y0.7467 +G01 X1.6294 Y0.7590 +G01 X1.6200 Y0.7684 +G01 X1.6077 Y0.7735 +G01 X1.5323 Y0.7735 +G01 X1.5200 Y0.7684 +G01 X1.5106 Y0.7590 +G01 X1.5055 Y0.7467 +G01 X1.5055 Y0.7333 +G01 X1.5106 Y0.7210 +G01 X1.5200 Y0.7116 +G01 X1.5323 Y0.7065 +G00 Z0.1000 +G00 X1.5323 Y0.8065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.8065 F20 +G01 X1.6200 Y0.8116 +G01 X1.6294 Y0.8210 +G01 X1.6345 Y0.8333 +G01 X1.6345 Y0.8467 +G01 X1.6294 Y0.8590 +G01 X1.6200 Y0.8684 +G01 X1.6077 Y0.8735 +G01 X1.5323 Y0.8735 +G01 X1.5200 Y0.8684 +G01 X1.5106 Y0.8590 +G01 X1.5055 Y0.8467 +G01 X1.5055 Y0.8333 +G01 X1.5106 Y0.8210 +G01 X1.5200 Y0.8116 +G01 X1.5323 Y0.8065 +G00 Z0.1000 +G00 X1.5323 Y0.9065 +G01 Z-0.0070 F10 +G01 X1.6077 Y0.9065 F20 +G01 X1.6200 Y0.9116 +G01 X1.6294 Y0.9210 +G01 X1.6345 Y0.9333 +G01 X1.6345 Y0.9467 +G01 X1.6294 Y0.9590 +G01 X1.6200 Y0.9684 +G01 X1.6077 Y0.9735 +G01 X1.5323 Y0.9735 +G01 X1.5200 Y0.9684 +G01 X1.5106 Y0.9590 +G01 X1.5055 Y0.9467 +G01 X1.5055 Y0.9333 +G01 X1.5106 Y0.9210 +G01 X1.5200 Y0.9116 +G01 X1.5323 Y0.9065 +G00 Z0.1000 +G00 X1.5323 Y1.0065 +G01 Z-0.0070 F10 +G01 X1.6077 Y1.0065 F20 +G01 X1.6200 Y1.0116 +G01 X1.6294 Y1.0210 +G01 X1.6345 Y1.0333 +G01 X1.6345 Y1.0467 +G01 X1.6294 Y1.0590 +G01 X1.6200 Y1.0684 +G01 X1.6077 Y1.0735 +G01 X1.5323 Y1.0735 +G01 X1.5200 Y1.0684 +G01 X1.5106 Y1.0590 +G01 X1.5055 Y1.0467 +G01 X1.5055 Y1.0333 +G01 X1.5106 Y1.0210 +G01 X1.5200 Y1.0116 +G01 X1.5323 Y1.0065 +G00 Z0.1000 +G00 X1.2323 Y1.0065 +G01 Z-0.0070 F10 +G01 X1.3077 Y1.0065 F20 +G01 X1.3200 Y1.0116 +G01 X1.3294 Y1.0210 +G01 X1.3345 Y1.0333 +G01 X1.3345 Y1.0467 +G01 X1.3294 Y1.0590 +G01 X1.3200 Y1.0684 +G01 X1.3077 Y1.0735 +G01 X1.2323 Y1.0735 +G01 X1.2200 Y1.0684 +G01 X1.2106 Y1.0590 +G01 X1.2055 Y1.0467 +G01 X1.2055 Y1.0333 +G01 X1.2106 Y1.0210 +G01 X1.2200 Y1.0116 +G01 X1.2323 Y1.0065 +G00 Z0.1000 +G00 X1.2323 Y0.9065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.9065 F20 +G01 X1.3200 Y0.9116 +G01 X1.3294 Y0.9210 +G01 X1.3345 Y0.9333 +G01 X1.3345 Y0.9467 +G01 X1.3294 Y0.9590 +G01 X1.3200 Y0.9684 +G01 X1.3077 Y0.9735 +G01 X1.2323 Y0.9735 +G01 X1.2200 Y0.9684 +G01 X1.2106 Y0.9590 +G01 X1.2055 Y0.9467 +G01 X1.2055 Y0.9333 +G01 X1.2106 Y0.9210 +G01 X1.2200 Y0.9116 +G01 X1.2323 Y0.9065 +G00 Z0.1000 +G00 X1.2323 Y0.8065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.8065 F20 +G01 X1.3200 Y0.8116 +G01 X1.3294 Y0.8210 +G01 X1.3345 Y0.8333 +G01 X1.3345 Y0.8467 +G01 X1.3294 Y0.8590 +G01 X1.3200 Y0.8684 +G01 X1.3077 Y0.8735 +G01 X1.2323 Y0.8735 +G01 X1.2200 Y0.8684 +G01 X1.2106 Y0.8590 +G01 X1.2055 Y0.8467 +G01 X1.2055 Y0.8333 +G01 X1.2106 Y0.8210 +G01 X1.2200 Y0.8116 +G01 X1.2323 Y0.8065 +G00 Z0.1000 +G00 X1.2323 Y0.7065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.7065 F20 +G01 X1.3200 Y0.7116 +G01 X1.3294 Y0.7210 +G01 X1.3345 Y0.7333 +G01 X1.3345 Y0.7467 +G01 X1.3294 Y0.7590 +G01 X1.3200 Y0.7684 +G01 X1.3077 Y0.7735 +G01 X1.2323 Y0.7735 +G01 X1.2200 Y0.7684 +G01 X1.2106 Y0.7590 +G01 X1.2055 Y0.7467 +G01 X1.2055 Y0.7333 +G01 X1.2106 Y0.7210 +G01 X1.2200 Y0.7116 +G01 X1.2323 Y0.7065 +G00 Z0.1000 +G00 X1.2323 Y0.6065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.6065 F20 +G01 X1.3200 Y0.6116 +G01 X1.3294 Y0.6210 +G01 X1.3345 Y0.6333 +G01 X1.3345 Y0.6467 +G01 X1.3294 Y0.6590 +G01 X1.3200 Y0.6684 +G01 X1.3077 Y0.6735 +G01 X1.2323 Y0.6735 +G01 X1.2200 Y0.6684 +G01 X1.2106 Y0.6590 +G01 X1.2055 Y0.6467 +G01 X1.2055 Y0.6333 +G01 X1.2106 Y0.6210 +G01 X1.2200 Y0.6116 +G01 X1.2323 Y0.6065 +G00 Z0.1000 +G00 X1.2323 Y0.5065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.5065 F20 +G01 X1.3200 Y0.5116 +G01 X1.3294 Y0.5210 +G01 X1.3345 Y0.5333 +G01 X1.3345 Y0.5467 +G01 X1.3294 Y0.5590 +G01 X1.3200 Y0.5684 +G01 X1.3077 Y0.5735 +G01 X1.2323 Y0.5735 +G01 X1.2200 Y0.5684 +G01 X1.2106 Y0.5590 +G01 X1.2055 Y0.5467 +G01 X1.2055 Y0.5333 +G01 X1.2106 Y0.5210 +G01 X1.2200 Y0.5116 +G01 X1.2323 Y0.5065 +G00 Z0.1000 +G00 X1.2323 Y0.4065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.4065 F20 +G01 X1.3200 Y0.4116 +G01 X1.3294 Y0.4210 +G01 X1.3345 Y0.4333 +G01 X1.3345 Y0.4467 +G01 X1.3294 Y0.4590 +G01 X1.3200 Y0.4684 +G01 X1.3077 Y0.4735 +G01 X1.2323 Y0.4735 +G01 X1.2200 Y0.4684 +G01 X1.2106 Y0.4590 +G01 X1.2055 Y0.4467 +G01 X1.2055 Y0.4333 +G01 X1.2106 Y0.4210 +G01 X1.2200 Y0.4116 +G01 X1.2323 Y0.4065 +G00 Z0.1000 +G00 X1.2323 Y0.3065 +G01 Z-0.0070 F10 +G01 X1.3077 Y0.3065 F20 +G01 X1.3200 Y0.3116 +G01 X1.3294 Y0.3210 +G01 X1.3345 Y0.3333 +G01 X1.3345 Y0.3467 +G01 X1.3294 Y0.3590 +G01 X1.3200 Y0.3684 +G01 X1.3077 Y0.3735 +G01 X1.2323 Y0.3735 +G01 X1.2200 Y0.3684 +G01 X1.2106 Y0.3590 +G01 X1.2055 Y0.3467 +G01 X1.2055 Y0.3333 +G01 X1.2106 Y0.3210 +G01 X1.2200 Y0.3116 +G01 X1.2323 Y0.3065 +G00 Z0.1000 +G00 X0.3275 Y0.9845 +G01 Z-0.0070 F10 +G01 X0.3275 Y1.0155 F20 +G01 X0.3055 Y1.0375 +G01 X0.2745 Y1.0375 +G01 X0.2525 Y1.0155 +G01 X0.2525 Y0.9845 +G01 X0.2745 Y0.9625 +G01 X0.3055 Y0.9625 +G01 X0.3275 Y0.9845 +G00 Z0.1000 +G00 X0.3275 Y0.8845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.9155 F20 +G01 X0.3055 Y0.9375 +G01 X0.2745 Y0.9375 +G01 X0.2525 Y0.9155 +G01 X0.2525 Y0.8845 +G01 X0.2745 Y0.8625 +G01 X0.3055 Y0.8625 +G01 X0.3275 Y0.8845 +G00 Z0.1000 +G00 X0.3275 Y0.7845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.8155 F20 +G01 X0.3055 Y0.8375 +G01 X0.2745 Y0.8375 +G01 X0.2525 Y0.8155 +G01 X0.2525 Y0.7845 +G01 X0.2745 Y0.7625 +G01 X0.3055 Y0.7625 +G01 X0.3275 Y0.7845 +G00 Z0.1000 +G00 X0.3275 Y0.6845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.7155 F20 +G01 X0.3055 Y0.7375 +G01 X0.2745 Y0.7375 +G01 X0.2525 Y0.7155 +G01 X0.2525 Y0.6845 +G01 X0.2745 Y0.6625 +G01 X0.3055 Y0.6625 +G01 X0.3275 Y0.6845 +G00 Z0.1000 +G00 X0.3275 Y0.5845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.6155 F20 +G01 X0.3055 Y0.6375 +G01 X0.2745 Y0.6375 +G01 X0.2525 Y0.6155 +G01 X0.2525 Y0.5845 +G01 X0.2745 Y0.5625 +G01 X0.3055 Y0.5625 +G01 X0.3275 Y0.5845 +G00 Z0.1000 +G00 X0.3275 Y0.4845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.5155 F20 +G01 X0.3055 Y0.5375 +G01 X0.2745 Y0.5375 +G01 X0.2525 Y0.5155 +G01 X0.2525 Y0.4845 +G01 X0.2745 Y0.4625 +G01 X0.3055 Y0.4625 +G01 X0.3275 Y0.4845 +G00 Z0.1000 +G00 X0.2275 Y0.9845 +G01 Z-0.0070 F10 +G01 X0.2275 Y1.0155 F20 +G01 X0.2055 Y1.0375 +G01 X0.1745 Y1.0375 +G01 X0.1525 Y1.0155 +G01 X0.1525 Y0.9845 +G01 X0.1745 Y0.9625 +G01 X0.2055 Y0.9625 +G01 X0.2275 Y0.9845 +G00 Z0.1000 +G00 X0.2275 Y0.8845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.9155 F20 +G01 X0.2055 Y0.9375 +G01 X0.1745 Y0.9375 +G01 X0.1525 Y0.9155 +G01 X0.1525 Y0.8845 +G01 X0.1745 Y0.8625 +G01 X0.2055 Y0.8625 +G01 X0.2275 Y0.8845 +G00 Z0.1000 +G00 X0.2275 Y0.7845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.8155 F20 +G01 X0.2055 Y0.8375 +G01 X0.1745 Y0.8375 +G01 X0.1525 Y0.8155 +G01 X0.1525 Y0.7845 +G01 X0.1745 Y0.7625 +G01 X0.2055 Y0.7625 +G01 X0.2275 Y0.7845 +G00 Z0.1000 +G00 X0.2275 Y0.6845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.7155 F20 +G01 X0.2055 Y0.7375 +G01 X0.1745 Y0.7375 +G01 X0.1525 Y0.7155 +G01 X0.1525 Y0.6845 +G01 X0.1745 Y0.6625 +G01 X0.2055 Y0.6625 +G01 X0.2275 Y0.6845 +G00 Z0.1000 +G00 X0.2275 Y0.5845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.6155 F20 +G01 X0.2055 Y0.6375 +G01 X0.1745 Y0.6375 +G01 X0.1525 Y0.6155 +G01 X0.1525 Y0.5845 +G01 X0.1745 Y0.5625 +G01 X0.2055 Y0.5625 +G01 X0.2275 Y0.5845 +G00 Z0.1000 +G00 X0.2275 Y0.4845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.5155 F20 +G01 X0.2055 Y0.5375 +G01 X0.1745 Y0.5375 +G01 X0.1525 Y0.5155 +G01 X0.1525 Y0.4845 +G01 X0.1745 Y0.4625 +G01 X0.2055 Y0.4625 +G01 X0.2275 Y0.4845 +G00 Z0.1000 +G00 X0.3275 Y0.3845 +G01 Z-0.0070 F10 +G01 X0.3275 Y0.4155 F20 +G01 X0.3055 Y0.4375 +G01 X0.2745 Y0.4375 +G01 X0.2525 Y0.4155 +G01 X0.2525 Y0.3845 +G01 X0.2745 Y0.3625 +G01 X0.3055 Y0.3625 +G01 X0.3275 Y0.3845 +G00 Z0.1000 +G00 X0.2275 Y0.3845 +G01 Z-0.0070 F10 +G01 X0.2275 Y0.4155 F20 +G01 X0.2055 Y0.4375 +G01 X0.1745 Y0.4375 +G01 X0.1525 Y0.4155 +G01 X0.1525 Y0.3845 +G01 X0.1745 Y0.3625 +G01 X0.2055 Y0.3625 +G01 X0.2275 Y0.3845 +G00 Z0.1000 +G00 X0.8377 Y0.4035 +G01 Z-0.0070 F10 +G01 X0.7623 Y0.4035 F20 +G01 X0.7500 Y0.3984 +G01 X0.7406 Y0.3890 +G01 X0.7355 Y0.3767 +G01 X0.7355 Y0.3633 +G01 X0.7406 Y0.3510 +G01 X0.7500 Y0.3416 +G01 X0.7623 Y0.3365 +G01 X0.8377 Y0.3365 +G01 X0.8500 Y0.3416 +G01 X0.8594 Y0.3510 +G01 X0.8645 Y0.3633 +G01 X0.8645 Y0.3767 +G01 X0.8594 Y0.3890 +G01 X0.8500 Y0.3984 +G01 X0.8377 Y0.4035 +G00 Z0.1000 +G00 X1.1377 Y0.3035 +G01 Z-0.0070 F10 +G01 X1.0623 Y0.3035 F20 +G01 X1.0500 Y0.2984 +G01 X1.0406 Y0.2890 +G01 X1.0355 Y0.2767 +G01 X1.0355 Y0.2633 +G01 X1.0406 Y0.2510 +G01 X1.0500 Y0.2416 +G01 X1.0623 Y0.2365 +G01 X1.1377 Y0.2365 +G01 X1.1500 Y0.2416 +G01 X1.1594 Y0.2510 +G01 X1.1645 Y0.2633 +G01 X1.1645 Y0.2767 +G01 X1.1594 Y0.2890 +G01 X1.1500 Y0.2984 +G01 X1.1377 Y0.3035 +G00 Z0.1000 +G00 X0.6377 Y0.3035 +G01 Z-0.0070 F10 +G01 X0.5623 Y0.3035 F20 +G01 X0.5500 Y0.2984 +G01 X0.5406 Y0.2890 +G01 X0.5355 Y0.2767 +G01 X0.5355 Y0.2633 +G01 X0.5406 Y0.2510 +G01 X0.5500 Y0.2416 +G01 X0.5623 Y0.2365 +G01 X0.6377 Y0.2365 +G01 X0.6500 Y0.2416 +G01 X0.6594 Y0.2510 +G01 X0.6645 Y0.2633 +G01 X0.6645 Y0.2767 +G01 X0.6594 Y0.2890 +G01 X0.6500 Y0.2984 +G01 X0.6377 Y0.3035 +G00 Z0.1000 +G00 X2.1123 Y0.1165 +G01 Z-0.0070 F10 +G01 X2.1877 Y0.1165 F20 +G01 X2.2000 Y0.1216 +G01 X2.2094 Y0.1310 +G01 X2.2145 Y0.1433 +G01 X2.2145 Y0.1567 +G01 X2.2094 Y0.1690 +G01 X2.2000 Y0.1784 +G01 X2.1877 Y0.1835 +G01 X2.1123 Y0.1835 +G01 X2.1000 Y0.1784 +G01 X2.0906 Y0.1690 +G01 X2.0855 Y0.1567 +G01 X2.0855 Y0.1433 +G01 X2.0906 Y0.1310 +G01 X2.1000 Y0.1216 +G01 X2.1123 Y0.1165 +G00 Z0.1000 +G00 X2.1123 Y0.2165 +G01 Z-0.0070 F10 +G01 X2.1877 Y0.2165 F20 +G01 X2.2000 Y0.2216 +G01 X2.2094 Y0.2310 +G01 X2.2145 Y0.2433 +G01 X2.2145 Y0.2567 +G01 X2.2094 Y0.2690 +G01 X2.2000 Y0.2784 +G01 X2.1877 Y0.2835 +G01 X2.1123 Y0.2835 +G01 X2.1000 Y0.2784 +G01 X2.0906 Y0.2690 +G01 X2.0855 Y0.2567 +G01 X2.0855 Y0.2433 +G01 X2.0906 Y0.2310 +G01 X2.1000 Y0.2216 +G01 X2.1123 Y0.2165 +G00 Z0.1000 +G00 X2.1123 Y0.3165 +G01 Z-0.0070 F10 +G01 X2.1877 Y0.3165 F20 +G01 X2.2000 Y0.3216 +G01 X2.2094 Y0.3310 +G01 X2.2145 Y0.3433 +G01 X2.2145 Y0.3567 +G01 X2.2094 Y0.3690 +G01 X2.2000 Y0.3784 +G01 X2.1877 Y0.3835 +G01 X2.1123 Y0.3835 +G01 X2.1000 Y0.3784 +G01 X2.0906 Y0.3690 +G01 X2.0855 Y0.3567 +G01 X2.0855 Y0.3433 +G01 X2.0906 Y0.3310 +G01 X2.1000 Y0.3216 +G01 X2.1123 Y0.3165 +G00 Z0.1000 +G00 X1.8123 Y0.3165 +G01 Z-0.0070 F10 +G01 X1.8877 Y0.3165 F20 +G01 X1.9000 Y0.3216 +G01 X1.9094 Y0.3310 +G01 X1.9145 Y0.3433 +G01 X1.9145 Y0.3567 +G01 X1.9094 Y0.3690 +G01 X1.9000 Y0.3784 +G01 X1.8877 Y0.3835 +G01 X1.8123 Y0.3835 +G01 X1.8000 Y0.3784 +G01 X1.7906 Y0.3690 +G01 X1.7855 Y0.3567 +G01 X1.7855 Y0.3433 +G01 X1.7906 Y0.3310 +G01 X1.8000 Y0.3216 +G01 X1.8123 Y0.3165 +G00 Z0.1000 +G00 X1.8123 Y0.2165 +G01 Z-0.0070 F10 +G01 X1.8877 Y0.2165 F20 +G01 X1.9000 Y0.2216 +G01 X1.9094 Y0.2310 +G01 X1.9145 Y0.2433 +G01 X1.9145 Y0.2567 +G01 X1.9094 Y0.2690 +G01 X1.9000 Y0.2784 +G01 X1.8877 Y0.2835 +G01 X1.8123 Y0.2835 +G01 X1.8000 Y0.2784 +G01 X1.7906 Y0.2690 +G01 X1.7855 Y0.2567 +G01 X1.7855 Y0.2433 +G01 X1.7906 Y0.2310 +G01 X1.8000 Y0.2216 +G01 X1.8123 Y0.2165 +G00 Z0.1000 +G00 X1.8123 Y0.1165 +G01 Z-0.0070 F10 +G01 X1.8877 Y0.1165 F20 +G01 X1.9000 Y0.1216 +G01 X1.9094 Y0.1310 +G01 X1.9145 Y0.1433 +G01 X1.9145 Y0.1567 +G01 X1.9094 Y0.1690 +G01 X1.9000 Y0.1784 +G01 X1.8877 Y0.1835 +G01 X1.8123 Y0.1835 +G01 X1.8000 Y0.1784 +G01 X1.7906 Y0.1690 +G01 X1.7855 Y0.1567 +G01 X1.7855 Y0.1433 +G01 X1.7906 Y0.1310 +G01 X1.8000 Y0.1216 +G01 X1.8123 Y0.1165 +G00 Z0.1000 +G00 X1.8335 Y0.6661 +G01 Z-0.0070 F10 +G01 X1.8335 Y0.6939 F20 +G01 X1.8139 Y0.7135 +G01 X1.7861 Y0.7135 +G01 X1.7665 Y0.6939 +G01 X1.7665 Y0.6661 +G01 X1.7861 Y0.6465 +G01 X1.8139 Y0.6465 +G01 X1.8335 Y0.6661 +G00 Z0.1000 +G00 X1.8335 Y0.4661 +G01 Z-0.0070 F10 +G01 X1.8335 Y0.4939 F20 +G01 X1.8139 Y0.5135 +G01 X1.7861 Y0.5135 +G01 X1.7665 Y0.4939 +G01 X1.7665 Y0.4661 +G01 X1.7861 Y0.4465 +G01 X1.8139 Y0.4465 +G01 X1.8335 Y0.4661 +G00 Z0.1000 +G00 X1.9535 Y0.6661 +G01 Z-0.0070 F10 +G01 X1.9535 Y0.6939 F20 +G01 X1.9339 Y0.7135 +G01 X1.9061 Y0.7135 +G01 X1.8865 Y0.6939 +G01 X1.8865 Y0.6661 +G01 X1.9061 Y0.6465 +G01 X1.9339 Y0.6465 +G01 X1.9535 Y0.6661 +G00 Z0.1000 +G00 X1.9535 Y0.4661 +G01 Z-0.0070 F10 +G01 X1.9535 Y0.4939 F20 +G01 X1.9339 Y0.5135 +G01 X1.9061 Y0.5135 +G01 X1.8865 Y0.4939 +G01 X1.8865 Y0.4661 +G01 X1.9061 Y0.4465 +G01 X1.9339 Y0.4465 +G01 X1.9535 Y0.4661 +G00 Z0.1000 +G00 X2.0735 Y0.6661 +G01 Z-0.0070 F10 +G01 X2.0735 Y0.6939 F20 +G01 X2.0539 Y0.7135 +G01 X2.0261 Y0.7135 +G01 X2.0065 Y0.6939 +G01 X2.0065 Y0.6661 +G01 X2.0261 Y0.6465 +G01 X2.0539 Y0.6465 +G01 X2.0735 Y0.6661 +G00 Z0.1000 +G00 X2.0735 Y0.4661 +G01 Z-0.0070 F10 +G01 X2.0735 Y0.4939 F20 +G01 X2.0539 Y0.5135 +G01 X2.0261 Y0.5135 +G01 X2.0065 Y0.4939 +G01 X2.0065 Y0.4661 +G01 X2.0261 Y0.4465 +G01 X2.0539 Y0.4465 +G01 X2.0735 Y0.4661 +G00 Z0.1000 +G00 X1.3035 Y0.2161 +G01 Z-0.0070 F10 +G01 X1.3035 Y0.2439 F20 +G01 X1.2839 Y0.2635 +G01 X1.2561 Y0.2635 +G01 X1.2365 Y0.2439 +G01 X1.2365 Y0.2161 +G01 X1.2561 Y0.1965 +G01 X1.2839 Y0.1965 +G01 X1.3035 Y0.2161 +G00 Z0.1000 +G00 X1.4035 Y0.2161 +G01 Z-0.0070 F10 +G01 X1.4035 Y0.2439 F20 +G01 X1.3839 Y0.2635 +G01 X1.3561 Y0.2635 +G01 X1.3365 Y0.2439 +G01 X1.3365 Y0.2161 +G01 X1.3561 Y0.1965 +G01 X1.3839 Y0.1965 +G01 X1.4035 Y0.2161 +G00 Z0.1000 +G00 X2.3525 Y1.0083 +G01 Z-0.0070 F10 +G01 X2.3525 Y1.0517 F20 +G01 X2.3217 Y1.0825 +G01 X2.2783 Y1.0825 +G01 X2.2475 Y1.0517 +G01 X2.2475 Y1.0083 +G01 X2.2783 Y0.9775 +G01 X2.3217 Y0.9775 +G01 X2.3525 Y1.0083 +G00 Z0.1000 +G00 X2.0525 Y1.0083 +G01 Z-0.0070 F10 +G01 X2.0525 Y1.0517 F20 +G01 X2.0217 Y1.0825 +G01 X1.9783 Y1.0825 +G01 X1.9475 Y1.0517 +G01 X1.9475 Y1.0083 +G01 X1.9783 Y0.9775 +G01 X2.0217 Y0.9775 +G01 X2.0525 Y1.0083 +G00 Z0.1000 +G00 X0.5435 Y0.9861 +G01 Z-0.0070 F10 +G01 X0.5435 Y1.0139 F20 +G01 X0.5239 Y1.0335 +G01 X0.4961 Y1.0335 +G01 X0.4765 Y1.0139 +G01 X0.4765 Y0.9861 +G01 X0.4961 Y0.9665 +G01 X0.5239 Y0.9665 +G01 X0.5435 Y0.9861 +G00 Z0.1000 +G00 X0.4435 Y0.9861 +G01 Z-0.0070 F10 +G01 X0.4435 Y1.0139 F20 +G01 X0.4239 Y1.0335 +G01 X0.3961 Y1.0335 +G01 X0.3765 Y1.0139 +G01 X0.3765 Y0.9861 +G01 X0.3961 Y0.9665 +G01 X0.4239 Y0.9665 +G01 X0.4435 Y0.9861 +G00 Z0.1000 +G00 X1.4235 Y1.1561 +G01 Z-0.0070 F10 +G01 X1.4235 Y1.1839 F20 +G01 X1.4039 Y1.2035 +G01 X1.3761 Y1.2035 +G01 X1.3565 Y1.1839 +G01 X1.3565 Y1.1561 +G01 X1.3761 Y1.1365 +G01 X1.4039 Y1.1365 +G01 X1.4235 Y1.1561 +G00 Z0.1000 +G00 X1.4735 Y1.2311 +G01 Z-0.0070 F10 +G01 X1.4735 Y1.2589 F20 +G01 X1.4539 Y1.2785 +G01 X1.4261 Y1.2785 +G01 X1.4065 Y1.2589 +G01 X1.4065 Y1.2311 +G01 X1.4261 Y1.2115 +G01 X1.4539 Y1.2115 +G01 X1.4735 Y1.2311 +G00 Z0.1000 +G00 X1.5235 Y1.1561 +G01 Z-0.0070 F10 +G01 X1.5235 Y1.1839 F20 +G01 X1.5039 Y1.2035 +G01 X1.4761 Y1.2035 +G01 X1.4565 Y1.1839 +G01 X1.4565 Y1.1561 +G01 X1.4761 Y1.1365 +G01 X1.5039 Y1.1365 +G01 X1.5235 Y1.1561 +G00 Z0.1000 +G00 X1.1755 Y1.1709 +G01 Z-0.0070 F10 +G01 X1.1755 Y1.1891 F20 +G01 X1.1686 Y1.2058 +G01 X1.1558 Y1.2186 +G01 X1.1391 Y1.2255 +G01 X1.1209 Y1.2255 +G01 X1.1042 Y1.2186 +G01 X1.0914 Y1.2058 +G01 X1.0845 Y1.1891 +G01 X1.0845 Y1.1709 +G01 X1.0914 Y1.1542 +G01 X1.1042 Y1.1414 +G01 X1.1209 Y1.1345 +G01 X1.1391 Y1.1345 +G01 X1.1558 Y1.1414 +G01 X1.1686 Y1.1542 +G01 X1.1755 Y1.1709 +G00 Z0.1000 +G00 X1.2755 Y1.1612 +G01 Z-0.0070 F10 +G01 X1.2755 Y1.1988 F20 +G01 X1.2488 Y1.2255 +G01 X1.2112 Y1.2255 +G01 X1.1845 Y1.1988 +G01 X1.1845 Y1.1612 +G01 X1.2112 Y1.1345 +G01 X1.2488 Y1.1345 +G01 X1.2755 Y1.1612 +G00 Z0.1000 +G00 X1.7955 Y1.2109 +G01 Z-0.0070 F10 +G01 X1.7955 Y1.2291 F20 +G01 X1.7886 Y1.2458 +G01 X1.7758 Y1.2586 +G01 X1.7591 Y1.2655 +G01 X1.7409 Y1.2655 +G01 X1.7242 Y1.2586 +G01 X1.7114 Y1.2458 +G01 X1.7045 Y1.2291 +G01 X1.7045 Y1.2109 +G01 X1.7114 Y1.1942 +G01 X1.7242 Y1.1814 +G01 X1.7409 Y1.1745 +G01 X1.7591 Y1.1745 +G01 X1.7758 Y1.1814 +G01 X1.7886 Y1.1942 +G01 X1.7955 Y1.2109 +G00 Z0.1000 +G00 X1.7955 Y1.1012 +G01 Z-0.0070 F10 +G01 X1.7955 Y1.1388 F20 +G01 X1.7688 Y1.1655 +G01 X1.7312 Y1.1655 +G01 X1.7045 Y1.1388 +G01 X1.7045 Y1.1012 +G01 X1.7312 Y1.0745 +G01 X1.7688 Y1.0745 +G01 X1.7955 Y1.1012 +G00 Z0.1000 +G00 X1.8005 Y1.2100 +G01 Z-0.0070 F10 +G01 X1.8005 Y1.2300 F20 +G01 X1.7928 Y1.2486 +G01 X1.7786 Y1.2628 +G01 X1.7600 Y1.2705 +G01 X1.7400 Y1.2705 +G01 X1.7214 Y1.2628 +G01 X1.7072 Y1.2486 +G01 X1.6995 Y1.2300 +G01 X1.6995 Y1.2100 +G01 X1.7072 Y1.1914 +G01 X1.7214 Y1.1772 +G01 X1.7376 Y1.1705 +G01 X1.7291 Y1.1705 +G01 X1.6995 Y1.1409 +G01 X1.6995 Y1.0991 +G01 X1.7291 Y1.0695 +G01 X1.7709 Y1.0695 +G01 X1.8005 Y1.0991 +G01 X1.8005 Y1.1409 +G01 X1.7709 Y1.1705 +G01 X1.7624 Y1.1705 +G01 X1.7786 Y1.1772 +G01 X1.7928 Y1.1914 +G01 X1.8005 Y1.2100 +G00 Z0.1000 +G00 X1.4785 Y1.2291 +G01 Z-0.0070 F10 +G01 X1.4785 Y1.2609 F20 +G01 X1.4559 Y1.2835 +G01 X1.4241 Y1.2835 +G01 X1.4015 Y1.2609 +G01 X1.4015 Y1.2291 +G01 X1.4241 Y1.2065 +G01 X1.4559 Y1.2065 +G01 X1.4785 Y1.2291 +G00 Z0.1000 +G00 X0.8406 Y0.6013 +G01 Z-0.0070 F10 +G01 X0.8406 Y0.6786 F20 +G01 X0.8348 Y0.6928 +G01 X0.8239 Y0.7036 +G01 X0.8098 Y0.7094 +G01 X0.7945 Y0.7094 +G01 X0.7803 Y0.7036 +G01 X0.7695 Y0.6928 +G01 X0.7636 Y0.6786 +G01 X0.7636 Y0.6013 +G01 X0.7695 Y0.5871 +G01 X0.7803 Y0.5763 +G01 X0.7945 Y0.5704 +G01 X0.8098 Y0.5704 +G01 X0.8239 Y0.5763 +G01 X0.8348 Y0.5871 +G01 X0.8406 Y0.6013 +G00 Z0.1000 +G00 X0.8030 Y0.8587 +G01 Z-0.0070 F10 +G01 X0.8030 Y0.7814 F20 +G01 X0.8089 Y0.7672 +G01 X0.8197 Y0.7564 +G01 X0.8338 Y0.7506 +G01 X0.8492 Y0.7506 +G01 X0.8633 Y0.7564 +G01 X0.8741 Y0.7672 +G01 X0.8800 Y0.7814 +G01 X0.8800 Y0.8587 +G01 X0.8741 Y0.8729 +G01 X0.8633 Y0.8837 +G01 X0.8492 Y0.8896 +G01 X0.8338 Y0.8896 +G01 X0.8197 Y0.8837 +G01 X0.8089 Y0.8729 +G01 X0.8030 Y0.8587 +G00 Z0.1000 +G00 X0.7619 Y0.6013 +G01 Z-0.0070 F10 +G01 X0.7619 Y0.6786 F20 +G01 X0.7560 Y0.6928 +G01 X0.7452 Y0.7036 +G01 X0.7310 Y0.7094 +G01 X0.7157 Y0.7094 +G01 X0.7016 Y0.7036 +G01 X0.6907 Y0.6928 +G01 X0.6849 Y0.6786 +G01 X0.6849 Y0.6013 +G01 X0.6907 Y0.5871 +G01 X0.7016 Y0.5763 +G01 X0.7157 Y0.5704 +G01 X0.7310 Y0.5704 +G01 X0.7452 Y0.5763 +G01 X0.7560 Y0.5871 +G01 X0.7619 Y0.6013 +G00 Z0.1000 +G00 X0.9194 Y0.6013 +G01 Z-0.0070 F10 +G01 X0.9194 Y0.6786 F20 +G01 X0.9135 Y0.6928 +G01 X0.9027 Y0.7036 +G01 X0.8885 Y0.7094 +G01 X0.8732 Y0.7094 +G01 X0.8591 Y0.7036 +G01 X0.8482 Y0.6928 +G01 X0.8424 Y0.6786 +G01 X0.8424 Y0.6013 +G01 X0.8482 Y0.5871 +G01 X0.8591 Y0.5763 +G01 X0.8732 Y0.5704 +G01 X0.8885 Y0.5704 +G01 X0.9027 Y0.5763 +G01 X0.9135 Y0.5871 +G01 X0.9194 Y0.6013 +G00 Z0.1000 +G00 X0.8817 Y0.8587 +G01 Z-0.0070 F10 +G01 X0.8817 Y0.7814 F20 +G01 X0.8876 Y0.7672 +G01 X0.8984 Y0.7564 +G01 X0.9126 Y0.7506 +G01 X0.9279 Y0.7506 +G01 X0.9420 Y0.7564 +G01 X0.9529 Y0.7672 +G01 X0.9587 Y0.7814 +G01 X0.9587 Y0.8587 +G01 X0.9529 Y0.8729 +G01 X0.9420 Y0.8837 +G01 X0.9279 Y0.8896 +G01 X0.9126 Y0.8896 +G01 X0.8984 Y0.8837 +G01 X0.8876 Y0.8729 +G01 X0.8817 Y0.8587 +G00 Z0.1000 +G00 X0.7243 Y0.8587 +G01 Z-0.0070 F10 +G01 X0.7243 Y0.7814 F20 +G01 X0.7301 Y0.7672 +G01 X0.7409 Y0.7564 +G01 X0.7551 Y0.7506 +G01 X0.7704 Y0.7506 +G01 X0.7846 Y0.7564 +G01 X0.7954 Y0.7672 +G01 X0.8013 Y0.7814 +G01 X0.8013 Y0.8587 +G01 X0.7954 Y0.8729 +G01 X0.7846 Y0.8837 +G01 X0.7704 Y0.8896 +G01 X0.7551 Y0.8896 +G01 X0.7409 Y0.8837 +G01 X0.7301 Y0.8729 +G01 X0.7243 Y0.8587 +G00 Z0.1000 +G00 X1.5313 Y0.3015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.3015 F20 +G01 X1.6228 Y0.3074 +G01 X1.6336 Y0.3182 +G01 X1.6395 Y0.3323 +G01 X1.6395 Y0.3477 +G01 X1.6336 Y0.3618 +G01 X1.6228 Y0.3726 +G01 X1.6087 Y0.3785 +G01 X1.5313 Y0.3785 +G01 X1.5172 Y0.3726 +G01 X1.5064 Y0.3618 +G01 X1.5005 Y0.3477 +G01 X1.5005 Y0.3323 +G01 X1.5064 Y0.3182 +G01 X1.5172 Y0.3074 +G01 X1.5313 Y0.3015 +G00 Z0.1000 +G00 X1.5313 Y0.4015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.4015 F20 +G01 X1.6228 Y0.4074 +G01 X1.6336 Y0.4182 +G01 X1.6395 Y0.4323 +G01 X1.6395 Y0.4477 +G01 X1.6336 Y0.4618 +G01 X1.6228 Y0.4726 +G01 X1.6087 Y0.4785 +G01 X1.5313 Y0.4785 +G01 X1.5172 Y0.4726 +G01 X1.5064 Y0.4618 +G01 X1.5005 Y0.4477 +G01 X1.5005 Y0.4323 +G01 X1.5064 Y0.4182 +G01 X1.5172 Y0.4074 +G01 X1.5313 Y0.4015 +G00 Z0.1000 +G00 X1.5313 Y0.5015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.5015 F20 +G01 X1.6228 Y0.5074 +G01 X1.6336 Y0.5182 +G01 X1.6395 Y0.5323 +G01 X1.6395 Y0.5477 +G01 X1.6336 Y0.5618 +G01 X1.6228 Y0.5726 +G01 X1.6087 Y0.5785 +G01 X1.5313 Y0.5785 +G01 X1.5172 Y0.5726 +G01 X1.5064 Y0.5618 +G01 X1.5005 Y0.5477 +G01 X1.5005 Y0.5323 +G01 X1.5064 Y0.5182 +G01 X1.5172 Y0.5074 +G01 X1.5313 Y0.5015 +G00 Z0.1000 +G00 X1.5313 Y0.6015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.6015 F20 +G01 X1.6228 Y0.6074 +G01 X1.6336 Y0.6182 +G01 X1.6395 Y0.6323 +G01 X1.6395 Y0.6477 +G01 X1.6336 Y0.6618 +G01 X1.6228 Y0.6726 +G01 X1.6087 Y0.6785 +G01 X1.5313 Y0.6785 +G01 X1.5172 Y0.6726 +G01 X1.5064 Y0.6618 +G01 X1.5005 Y0.6477 +G01 X1.5005 Y0.6323 +G01 X1.5064 Y0.6182 +G01 X1.5172 Y0.6074 +G01 X1.5313 Y0.6015 +G00 Z0.1000 +G00 X1.5313 Y0.7015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.7015 F20 +G01 X1.6228 Y0.7074 +G01 X1.6336 Y0.7182 +G01 X1.6395 Y0.7323 +G01 X1.6395 Y0.7477 +G01 X1.6336 Y0.7618 +G01 X1.6228 Y0.7726 +G01 X1.6087 Y0.7785 +G01 X1.5313 Y0.7785 +G01 X1.5172 Y0.7726 +G01 X1.5064 Y0.7618 +G01 X1.5005 Y0.7477 +G01 X1.5005 Y0.7323 +G01 X1.5064 Y0.7182 +G01 X1.5172 Y0.7074 +G01 X1.5313 Y0.7015 +G00 Z0.1000 +G00 X1.5313 Y0.8015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.8015 F20 +G01 X1.6228 Y0.8074 +G01 X1.6336 Y0.8182 +G01 X1.6395 Y0.8323 +G01 X1.6395 Y0.8477 +G01 X1.6336 Y0.8618 +G01 X1.6228 Y0.8726 +G01 X1.6087 Y0.8785 +G01 X1.5313 Y0.8785 +G01 X1.5172 Y0.8726 +G01 X1.5064 Y0.8618 +G01 X1.5005 Y0.8477 +G01 X1.5005 Y0.8323 +G01 X1.5064 Y0.8182 +G01 X1.5172 Y0.8074 +G01 X1.5313 Y0.8015 +G00 Z0.1000 +G00 X1.5313 Y0.9015 +G01 Z-0.0070 F10 +G01 X1.6087 Y0.9015 F20 +G01 X1.6228 Y0.9074 +G01 X1.6336 Y0.9182 +G01 X1.6395 Y0.9323 +G01 X1.6395 Y0.9477 +G01 X1.6336 Y0.9618 +G01 X1.6228 Y0.9726 +G01 X1.6087 Y0.9785 +G01 X1.5313 Y0.9785 +G01 X1.5172 Y0.9726 +G01 X1.5064 Y0.9618 +G01 X1.5005 Y0.9477 +G01 X1.5005 Y0.9323 +G01 X1.5064 Y0.9182 +G01 X1.5172 Y0.9074 +G01 X1.5313 Y0.9015 +G00 Z0.1000 +G00 X1.5313 Y1.0015 +G01 Z-0.0070 F10 +G01 X1.6087 Y1.0015 F20 +G01 X1.6228 Y1.0074 +G01 X1.6336 Y1.0182 +G01 X1.6395 Y1.0323 +G01 X1.6395 Y1.0477 +G01 X1.6336 Y1.0618 +G01 X1.6228 Y1.0726 +G01 X1.6087 Y1.0785 +G01 X1.5313 Y1.0785 +G01 X1.5172 Y1.0726 +G01 X1.5064 Y1.0618 +G01 X1.5005 Y1.0477 +G01 X1.5005 Y1.0323 +G01 X1.5064 Y1.0182 +G01 X1.5172 Y1.0074 +G01 X1.5313 Y1.0015 +G00 Z0.1000 +G00 X1.2313 Y1.0015 +G01 Z-0.0070 F10 +G01 X1.3087 Y1.0015 F20 +G01 X1.3228 Y1.0074 +G01 X1.3336 Y1.0182 +G01 X1.3395 Y1.0323 +G01 X1.3395 Y1.0477 +G01 X1.3336 Y1.0618 +G01 X1.3228 Y1.0726 +G01 X1.3087 Y1.0785 +G01 X1.2313 Y1.0785 +G01 X1.2172 Y1.0726 +G01 X1.2064 Y1.0618 +G01 X1.2005 Y1.0477 +G01 X1.2005 Y1.0323 +G01 X1.2064 Y1.0182 +G01 X1.2172 Y1.0074 +G01 X1.2313 Y1.0015 +G00 Z0.1000 +G00 X1.2313 Y0.9015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.9015 F20 +G01 X1.3228 Y0.9074 +G01 X1.3336 Y0.9182 +G01 X1.3395 Y0.9323 +G01 X1.3395 Y0.9477 +G01 X1.3336 Y0.9618 +G01 X1.3228 Y0.9726 +G01 X1.3087 Y0.9785 +G01 X1.2313 Y0.9785 +G01 X1.2172 Y0.9726 +G01 X1.2064 Y0.9618 +G01 X1.2005 Y0.9477 +G01 X1.2005 Y0.9323 +G01 X1.2064 Y0.9182 +G01 X1.2172 Y0.9074 +G01 X1.2313 Y0.9015 +G00 Z0.1000 +G00 X1.2313 Y0.8015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.8015 F20 +G01 X1.3228 Y0.8074 +G01 X1.3336 Y0.8182 +G01 X1.3395 Y0.8323 +G01 X1.3395 Y0.8477 +G01 X1.3336 Y0.8618 +G01 X1.3228 Y0.8726 +G01 X1.3087 Y0.8785 +G01 X1.2313 Y0.8785 +G01 X1.2172 Y0.8726 +G01 X1.2064 Y0.8618 +G01 X1.2005 Y0.8477 +G01 X1.2005 Y0.8323 +G01 X1.2064 Y0.8182 +G01 X1.2172 Y0.8074 +G01 X1.2313 Y0.8015 +G00 Z0.1000 +G00 X1.2313 Y0.7015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.7015 F20 +G01 X1.3228 Y0.7074 +G01 X1.3336 Y0.7182 +G01 X1.3395 Y0.7323 +G01 X1.3395 Y0.7477 +G01 X1.3336 Y0.7618 +G01 X1.3228 Y0.7726 +G01 X1.3087 Y0.7785 +G01 X1.2313 Y0.7785 +G01 X1.2172 Y0.7726 +G01 X1.2064 Y0.7618 +G01 X1.2005 Y0.7477 +G01 X1.2005 Y0.7323 +G01 X1.2064 Y0.7182 +G01 X1.2172 Y0.7074 +G01 X1.2313 Y0.7015 +G00 Z0.1000 +G00 X1.2313 Y0.6015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.6015 F20 +G01 X1.3228 Y0.6074 +G01 X1.3336 Y0.6182 +G01 X1.3395 Y0.6323 +G01 X1.3395 Y0.6477 +G01 X1.3336 Y0.6618 +G01 X1.3228 Y0.6726 +G01 X1.3087 Y0.6785 +G01 X1.2313 Y0.6785 +G01 X1.2172 Y0.6726 +G01 X1.2064 Y0.6618 +G01 X1.2005 Y0.6477 +G01 X1.2005 Y0.6323 +G01 X1.2064 Y0.6182 +G01 X1.2172 Y0.6074 +G01 X1.2313 Y0.6015 +G00 Z0.1000 +G00 X1.2313 Y0.5015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.5015 F20 +G01 X1.3228 Y0.5074 +G01 X1.3336 Y0.5182 +G01 X1.3395 Y0.5323 +G01 X1.3395 Y0.5477 +G01 X1.3336 Y0.5618 +G01 X1.3228 Y0.5726 +G01 X1.3087 Y0.5785 +G01 X1.2313 Y0.5785 +G01 X1.2172 Y0.5726 +G01 X1.2064 Y0.5618 +G01 X1.2005 Y0.5477 +G01 X1.2005 Y0.5323 +G01 X1.2064 Y0.5182 +G01 X1.2172 Y0.5074 +G01 X1.2313 Y0.5015 +G00 Z0.1000 +G00 X1.2313 Y0.4015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.4015 F20 +G01 X1.3228 Y0.4074 +G01 X1.3336 Y0.4182 +G01 X1.3395 Y0.4323 +G01 X1.3395 Y0.4477 +G01 X1.3336 Y0.4618 +G01 X1.3228 Y0.4726 +G01 X1.3087 Y0.4785 +G01 X1.2313 Y0.4785 +G01 X1.2172 Y0.4726 +G01 X1.2064 Y0.4618 +G01 X1.2005 Y0.4477 +G01 X1.2005 Y0.4323 +G01 X1.2064 Y0.4182 +G01 X1.2172 Y0.4074 +G01 X1.2313 Y0.4015 +G00 Z0.1000 +G00 X1.2313 Y0.3015 +G01 Z-0.0070 F10 +G01 X1.3087 Y0.3015 F20 +G01 X1.3228 Y0.3074 +G01 X1.3336 Y0.3182 +G01 X1.3395 Y0.3323 +G01 X1.3395 Y0.3477 +G01 X1.3336 Y0.3618 +G01 X1.3228 Y0.3726 +G01 X1.3087 Y0.3785 +G01 X1.2313 Y0.3785 +G01 X1.2172 Y0.3726 +G01 X1.2064 Y0.3618 +G01 X1.2005 Y0.3477 +G01 X1.2005 Y0.3323 +G01 X1.2064 Y0.3182 +G01 X1.2172 Y0.3074 +G01 X1.2313 Y0.3015 +G00 Z0.1000 +G00 X0.3325 Y0.9824 +G01 Z-0.0070 F10 +G01 X0.3325 Y1.0176 F20 +G01 X0.3076 Y1.0425 +G01 X0.2724 Y1.0425 +G01 X0.2475 Y1.0176 +G01 X0.2475 Y0.9824 +G01 X0.2724 Y0.9575 +G01 X0.3076 Y0.9575 +G01 X0.3325 Y0.9824 +G00 Z0.1000 +G00 X0.3325 Y0.8824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.9176 F20 +G01 X0.3076 Y0.9425 +G01 X0.2724 Y0.9425 +G01 X0.2475 Y0.9176 +G01 X0.2475 Y0.8824 +G01 X0.2724 Y0.8575 +G01 X0.3076 Y0.8575 +G01 X0.3325 Y0.8824 +G00 Z0.1000 +G00 X0.3325 Y0.7824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.8176 F20 +G01 X0.3076 Y0.8425 +G01 X0.2724 Y0.8425 +G01 X0.2475 Y0.8176 +G01 X0.2475 Y0.7824 +G01 X0.2724 Y0.7575 +G01 X0.3076 Y0.7575 +G01 X0.3325 Y0.7824 +G00 Z0.1000 +G00 X0.3325 Y0.6824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.7176 F20 +G01 X0.3076 Y0.7425 +G01 X0.2724 Y0.7425 +G01 X0.2475 Y0.7176 +G01 X0.2475 Y0.6824 +G01 X0.2724 Y0.6575 +G01 X0.3076 Y0.6575 +G01 X0.3325 Y0.6824 +G00 Z0.1000 +G00 X0.3325 Y0.5824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.6176 F20 +G01 X0.3076 Y0.6425 +G01 X0.2724 Y0.6425 +G01 X0.2475 Y0.6176 +G01 X0.2475 Y0.5824 +G01 X0.2724 Y0.5575 +G01 X0.3076 Y0.5575 +G01 X0.3325 Y0.5824 +G00 Z0.1000 +G00 X0.3325 Y0.4824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.5176 F20 +G01 X0.3076 Y0.5425 +G01 X0.2724 Y0.5425 +G01 X0.2475 Y0.5176 +G01 X0.2475 Y0.4824 +G01 X0.2724 Y0.4575 +G01 X0.3076 Y0.4575 +G01 X0.3325 Y0.4824 +G00 Z0.1000 +G00 X0.2325 Y0.9824 +G01 Z-0.0070 F10 +G01 X0.2325 Y1.0176 F20 +G01 X0.2076 Y1.0425 +G01 X0.1724 Y1.0425 +G01 X0.1475 Y1.0176 +G01 X0.1475 Y0.9824 +G01 X0.1724 Y0.9575 +G01 X0.2076 Y0.9575 +G01 X0.2325 Y0.9824 +G00 Z0.1000 +G00 X0.2325 Y0.8824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.9176 F20 +G01 X0.2076 Y0.9425 +G01 X0.1724 Y0.9425 +G01 X0.1475 Y0.9176 +G01 X0.1475 Y0.8824 +G01 X0.1724 Y0.8575 +G01 X0.2076 Y0.8575 +G01 X0.2325 Y0.8824 +G00 Z0.1000 +G00 X0.2325 Y0.7824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.8176 F20 +G01 X0.2076 Y0.8425 +G01 X0.1724 Y0.8425 +G01 X0.1475 Y0.8176 +G01 X0.1475 Y0.7824 +G01 X0.1724 Y0.7575 +G01 X0.2076 Y0.7575 +G01 X0.2325 Y0.7824 +G00 Z0.1000 +G00 X0.2325 Y0.6824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.7176 F20 +G01 X0.2076 Y0.7425 +G01 X0.1724 Y0.7425 +G01 X0.1475 Y0.7176 +G01 X0.1475 Y0.6824 +G01 X0.1724 Y0.6575 +G01 X0.2076 Y0.6575 +G01 X0.2325 Y0.6824 +G00 Z0.1000 +G00 X0.2325 Y0.5824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.6176 F20 +G01 X0.2076 Y0.6425 +G01 X0.1724 Y0.6425 +G01 X0.1475 Y0.6176 +G01 X0.1475 Y0.5824 +G01 X0.1724 Y0.5575 +G01 X0.2076 Y0.5575 +G01 X0.2325 Y0.5824 +G00 Z0.1000 +G00 X0.2325 Y0.4824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.5176 F20 +G01 X0.2076 Y0.5425 +G01 X0.1724 Y0.5425 +G01 X0.1475 Y0.5176 +G01 X0.1475 Y0.4824 +G01 X0.1724 Y0.4575 +G01 X0.2076 Y0.4575 +G01 X0.2325 Y0.4824 +G00 Z0.1000 +G00 X0.3325 Y0.3824 +G01 Z-0.0070 F10 +G01 X0.3325 Y0.4176 F20 +G01 X0.3076 Y0.4425 +G01 X0.2724 Y0.4425 +G01 X0.2475 Y0.4176 +G01 X0.2475 Y0.3824 +G01 X0.2724 Y0.3575 +G01 X0.3076 Y0.3575 +G01 X0.3325 Y0.3824 +G00 Z0.1000 +G00 X0.2325 Y0.3824 +G01 Z-0.0070 F10 +G01 X0.2325 Y0.4176 F20 +G01 X0.2076 Y0.4425 +G01 X0.1724 Y0.4425 +G01 X0.1475 Y0.4176 +G01 X0.1475 Y0.3824 +G01 X0.1724 Y0.3575 +G01 X0.2076 Y0.3575 +G01 X0.2325 Y0.3824 +G00 Z0.1000 +G00 X0.8387 Y0.4085 +G01 Z-0.0070 F10 +G01 X0.7613 Y0.4085 F20 +G01 X0.7472 Y0.4026 +G01 X0.7364 Y0.3918 +G01 X0.7305 Y0.3777 +G01 X0.7305 Y0.3623 +G01 X0.7364 Y0.3482 +G01 X0.7472 Y0.3374 +G01 X0.7613 Y0.3315 +G01 X0.8387 Y0.3315 +G01 X0.8528 Y0.3374 +G01 X0.8636 Y0.3482 +G01 X0.8695 Y0.3623 +G01 X0.8695 Y0.3777 +G01 X0.8636 Y0.3918 +G01 X0.8528 Y0.4026 +G01 X0.8387 Y0.4085 +G00 Z0.1000 +G00 X1.1387 Y0.3085 +G01 Z-0.0070 F10 +G01 X1.0613 Y0.3085 F20 +G01 X1.0472 Y0.3026 +G01 X1.0364 Y0.2918 +G01 X1.0305 Y0.2777 +G01 X1.0305 Y0.2623 +G01 X1.0364 Y0.2482 +G01 X1.0472 Y0.2374 +G01 X1.0613 Y0.2315 +G01 X1.1387 Y0.2315 +G01 X1.1528 Y0.2374 +G01 X1.1636 Y0.2482 +G01 X1.1695 Y0.2623 +G01 X1.1695 Y0.2777 +G01 X1.1636 Y0.2918 +G01 X1.1528 Y0.3026 +G01 X1.1387 Y0.3085 +G00 Z0.1000 +G00 X0.6387 Y0.3085 +G01 Z-0.0070 F10 +G01 X0.5613 Y0.3085 F20 +G01 X0.5472 Y0.3026 +G01 X0.5364 Y0.2918 +G01 X0.5305 Y0.2777 +G01 X0.5305 Y0.2623 +G01 X0.5364 Y0.2482 +G01 X0.5472 Y0.2374 +G01 X0.5613 Y0.2315 +G01 X0.6387 Y0.2315 +G01 X0.6528 Y0.2374 +G01 X0.6636 Y0.2482 +G01 X0.6695 Y0.2623 +G01 X0.6695 Y0.2777 +G01 X0.6636 Y0.2918 +G01 X0.6528 Y0.3026 +G01 X0.6387 Y0.3085 +G00 Z0.1000 +G00 X2.1113 Y0.1115 +G01 Z-0.0070 F10 +G01 X2.1887 Y0.1115 F20 +G01 X2.2028 Y0.1174 +G01 X2.2136 Y0.1282 +G01 X2.2195 Y0.1423 +G01 X2.2195 Y0.1577 +G01 X2.2136 Y0.1718 +G01 X2.2028 Y0.1826 +G01 X2.1887 Y0.1885 +G01 X2.1113 Y0.1885 +G01 X2.0972 Y0.1826 +G01 X2.0864 Y0.1718 +G01 X2.0805 Y0.1577 +G01 X2.0805 Y0.1423 +G01 X2.0864 Y0.1282 +G01 X2.0972 Y0.1174 +G01 X2.1113 Y0.1115 +G00 Z0.1000 +G00 X2.1113 Y0.2115 +G01 Z-0.0070 F10 +G01 X2.1887 Y0.2115 F20 +G01 X2.2028 Y0.2174 +G01 X2.2136 Y0.2282 +G01 X2.2195 Y0.2423 +G01 X2.2195 Y0.2577 +G01 X2.2136 Y0.2718 +G01 X2.2028 Y0.2826 +G01 X2.1887 Y0.2885 +G01 X2.1113 Y0.2885 +G01 X2.0972 Y0.2826 +G01 X2.0864 Y0.2718 +G01 X2.0805 Y0.2577 +G01 X2.0805 Y0.2423 +G01 X2.0864 Y0.2282 +G01 X2.0972 Y0.2174 +G01 X2.1113 Y0.2115 +G00 Z0.1000 +G00 X2.1113 Y0.3115 +G01 Z-0.0070 F10 +G01 X2.1887 Y0.3115 F20 +G01 X2.2028 Y0.3174 +G01 X2.2136 Y0.3282 +G01 X2.2195 Y0.3423 +G01 X2.2195 Y0.3577 +G01 X2.2136 Y0.3718 +G01 X2.2028 Y0.3826 +G01 X2.1887 Y0.3885 +G01 X2.1113 Y0.3885 +G01 X2.0972 Y0.3826 +G01 X2.0864 Y0.3718 +G01 X2.0805 Y0.3577 +G01 X2.0805 Y0.3423 +G01 X2.0864 Y0.3282 +G01 X2.0972 Y0.3174 +G01 X2.1113 Y0.3115 +G00 Z0.1000 +G00 X1.8113 Y0.3115 +G01 Z-0.0070 F10 +G01 X1.8887 Y0.3115 F20 +G01 X1.9028 Y0.3174 +G01 X1.9136 Y0.3282 +G01 X1.9195 Y0.3423 +G01 X1.9195 Y0.3577 +G01 X1.9136 Y0.3718 +G01 X1.9028 Y0.3826 +G01 X1.8887 Y0.3885 +G01 X1.8113 Y0.3885 +G01 X1.7972 Y0.3826 +G01 X1.7864 Y0.3718 +G01 X1.7805 Y0.3577 +G01 X1.7805 Y0.3423 +G01 X1.7864 Y0.3282 +G01 X1.7972 Y0.3174 +G01 X1.8113 Y0.3115 +G00 Z0.1000 +G00 X1.8113 Y0.2115 +G01 Z-0.0070 F10 +G01 X1.8887 Y0.2115 F20 +G01 X1.9028 Y0.2174 +G01 X1.9136 Y0.2282 +G01 X1.9195 Y0.2423 +G01 X1.9195 Y0.2577 +G01 X1.9136 Y0.2718 +G01 X1.9028 Y0.2826 +G01 X1.8887 Y0.2885 +G01 X1.8113 Y0.2885 +G01 X1.7972 Y0.2826 +G01 X1.7864 Y0.2718 +G01 X1.7805 Y0.2577 +G01 X1.7805 Y0.2423 +G01 X1.7864 Y0.2282 +G01 X1.7972 Y0.2174 +G01 X1.8113 Y0.2115 +G00 Z0.1000 +G00 X1.8113 Y0.1115 +G01 Z-0.0070 F10 +G01 X1.8887 Y0.1115 F20 +G01 X1.9028 Y0.1174 +G01 X1.9136 Y0.1282 +G01 X1.9195 Y0.1423 +G01 X1.9195 Y0.1577 +G01 X1.9136 Y0.1718 +G01 X1.9028 Y0.1826 +G01 X1.8887 Y0.1885 +G01 X1.8113 Y0.1885 +G01 X1.7972 Y0.1826 +G01 X1.7864 Y0.1718 +G01 X1.7805 Y0.1577 +G01 X1.7805 Y0.1423 +G01 X1.7864 Y0.1282 +G01 X1.7972 Y0.1174 +G01 X1.8113 Y0.1115 +G00 Z0.1000 +G00 X1.8385 Y0.6641 +G01 Z-0.0070 F10 +G01 X1.8385 Y0.6959 F20 +G01 X1.8159 Y0.7185 +G01 X1.7841 Y0.7185 +G01 X1.7615 Y0.6959 +G01 X1.7615 Y0.6641 +G01 X1.7841 Y0.6415 +G01 X1.8159 Y0.6415 +G01 X1.8385 Y0.6641 +G00 Z0.1000 +G00 X1.8385 Y0.4641 +G01 Z-0.0070 F10 +G01 X1.8385 Y0.4959 F20 +G01 X1.8159 Y0.5185 +G01 X1.7841 Y0.5185 +G01 X1.7615 Y0.4959 +G01 X1.7615 Y0.4641 +G01 X1.7841 Y0.4415 +G01 X1.8159 Y0.4415 +G01 X1.8385 Y0.4641 +G00 Z0.1000 +G00 X1.9585 Y0.6641 +G01 Z-0.0070 F10 +G01 X1.9585 Y0.6959 F20 +G01 X1.9359 Y0.7185 +G01 X1.9041 Y0.7185 +G01 X1.8815 Y0.6959 +G01 X1.8815 Y0.6641 +G01 X1.9041 Y0.6415 +G01 X1.9359 Y0.6415 +G01 X1.9585 Y0.6641 +G00 Z0.1000 +G00 X1.9585 Y0.4641 +G01 Z-0.0070 F10 +G01 X1.9585 Y0.4959 F20 +G01 X1.9359 Y0.5185 +G01 X1.9041 Y0.5185 +G01 X1.8815 Y0.4959 +G01 X1.8815 Y0.4641 +G01 X1.9041 Y0.4415 +G01 X1.9359 Y0.4415 +G01 X1.9585 Y0.4641 +G00 Z0.1000 +G00 X2.0785 Y0.6641 +G01 Z-0.0070 F10 +G01 X2.0785 Y0.6959 F20 +G01 X2.0559 Y0.7185 +G01 X2.0241 Y0.7185 +G01 X2.0015 Y0.6959 +G01 X2.0015 Y0.6641 +G01 X2.0241 Y0.6415 +G01 X2.0559 Y0.6415 +G01 X2.0785 Y0.6641 +G00 Z0.1000 +G00 X2.0785 Y0.4641 +G01 Z-0.0070 F10 +G01 X2.0785 Y0.4959 F20 +G01 X2.0559 Y0.5185 +G01 X2.0241 Y0.5185 +G01 X2.0015 Y0.4959 +G01 X2.0015 Y0.4641 +G01 X2.0241 Y0.4415 +G01 X2.0559 Y0.4415 +G01 X2.0785 Y0.4641 +G00 Z0.1000 +G00 X1.3085 Y0.2141 +G01 Z-0.0070 F10 +G01 X1.3085 Y0.2459 F20 +G01 X1.2859 Y0.2685 +G01 X1.2541 Y0.2685 +G01 X1.2315 Y0.2459 +G01 X1.2315 Y0.2141 +G01 X1.2541 Y0.1915 +G01 X1.2859 Y0.1915 +G01 X1.3085 Y0.2141 +G00 Z0.1000 +G00 X1.4085 Y0.2141 +G01 Z-0.0070 F10 +G01 X1.4085 Y0.2459 F20 +G01 X1.3859 Y0.2685 +G01 X1.3541 Y0.2685 +G01 X1.3315 Y0.2459 +G01 X1.3315 Y0.2141 +G01 X1.3541 Y0.1915 +G01 X1.3859 Y0.1915 +G01 X1.4085 Y0.2141 +G00 Z0.1000 +G00 X2.3575 Y1.0062 +G01 Z-0.0070 F10 +G01 X2.3575 Y1.0538 F20 +G01 X2.3238 Y1.0875 +G01 X2.2762 Y1.0875 +G01 X2.2425 Y1.0538 +G01 X2.2425 Y1.0062 +G01 X2.2762 Y0.9725 +G01 X2.3238 Y0.9725 +G01 X2.3575 Y1.0062 +G00 Z0.1000 +G00 X2.0575 Y1.0062 +G01 Z-0.0070 F10 +G01 X2.0575 Y1.0538 F20 +G01 X2.0238 Y1.0875 +G01 X1.9762 Y1.0875 +G01 X1.9425 Y1.0538 +G01 X1.9425 Y1.0062 +G01 X1.9762 Y0.9725 +G01 X2.0238 Y0.9725 +G01 X2.0575 Y1.0062 +G00 Z0.1000 +G00 X0.5485 Y0.9841 +G01 Z-0.0070 F10 +G01 X0.5485 Y1.0159 F20 +G01 X0.5259 Y1.0385 +G01 X0.4941 Y1.0385 +G01 X0.4715 Y1.0159 +G01 X0.4715 Y0.9841 +G01 X0.4941 Y0.9615 +G01 X0.5259 Y0.9615 +G01 X0.5485 Y0.9841 +G00 Z0.1000 +G00 X0.4485 Y0.9841 +G01 Z-0.0070 F10 +G01 X0.4485 Y1.0159 F20 +G01 X0.4259 Y1.0385 +G01 X0.3941 Y1.0385 +G01 X0.3715 Y1.0159 +G01 X0.3715 Y0.9841 +G01 X0.3941 Y0.9615 +G01 X0.4259 Y0.9615 +G01 X0.4485 Y0.9841 +G00 Z0.1000 +G00 X1.4285 Y1.1541 +G01 Z-0.0070 F10 +G01 X1.4285 Y1.1859 F20 +G01 X1.4059 Y1.2085 +G01 X1.3741 Y1.2085 +G01 X1.3515 Y1.1859 +G01 X1.3515 Y1.1541 +G01 X1.3741 Y1.1315 +G01 X1.4059 Y1.1315 +G01 X1.4285 Y1.1541 +G00 Z0.1000 +G00 X1.5285 Y1.1541 +G01 Z-0.0070 F10 +G01 X1.5285 Y1.1859 F20 +G01 X1.5059 Y1.2085 +G01 X1.4741 Y1.2085 +G01 X1.4515 Y1.1859 +G01 X1.4515 Y1.1541 +G01 X1.4741 Y1.1315 +G01 X1.5059 Y1.1315 +G01 X1.5285 Y1.1541 +G00 Z0.1000 +G00 X1.1728 Y1.2086 +G01 Z-0.0070 F10 +G01 X1.1586 Y1.2228 F20 +G01 X1.1400 Y1.2305 +G01 X1.1200 Y1.2305 +G01 X1.1014 Y1.2228 +G01 X1.0872 Y1.2086 +G01 X1.0795 Y1.1900 +G01 X1.0795 Y1.1700 +G01 X1.0872 Y1.1514 +G01 X1.1014 Y1.1372 +G01 X1.1200 Y1.1295 +G01 X1.1400 Y1.1295 +G01 X1.1586 Y1.1372 +G01 X1.1728 Y1.1514 +G01 X1.1795 Y1.1676 +G01 X1.1795 Y1.1591 +G01 X1.2091 Y1.1295 +G01 X1.2509 Y1.1295 +G01 X1.2805 Y1.1591 +G01 X1.2805 Y1.2009 +G01 X1.2509 Y1.2305 +G01 X1.2091 Y1.2305 +G01 X1.1795 Y1.2009 +G01 X1.1795 Y1.1924 +G01 X1.1728 Y1.2086 +G00 Z0.1000 +G00 X1.8055 Y1.2090 +G01 Z-0.0070 F10 +G01 X1.8055 Y1.2310 F20 +G01 X1.7970 Y1.2514 +G01 X1.7814 Y1.2670 +G01 X1.7610 Y1.2755 +G01 X1.7390 Y1.2755 +G01 X1.7186 Y1.2670 +G01 X1.7029 Y1.2514 +G01 X1.6945 Y1.2310 +G01 X1.6945 Y1.2090 +G01 X1.7029 Y1.1886 +G01 X1.7186 Y1.1729 +G01 X1.7227 Y1.1712 +G01 X1.6945 Y1.1430 +G01 X1.6945 Y1.0970 +G01 X1.7270 Y1.0645 +G01 X1.7730 Y1.0645 +G01 X1.8055 Y1.0970 +G01 X1.8055 Y1.1430 +G01 X1.7773 Y1.1712 +G01 X1.7814 Y1.1729 +G01 X1.7970 Y1.1886 +G01 X1.8055 Y1.2090 +G00 Z0.1000 +G00 X1.4835 Y1.2270 +G01 Z-0.0070 F10 +G01 X1.4835 Y1.2630 F20 +G01 X1.4580 Y1.2885 +G01 X1.4220 Y1.2885 +G01 X1.3965 Y1.2630 +G01 X1.3965 Y1.2270 +G01 X1.4220 Y1.2015 +G01 X1.4580 Y1.2015 +G01 X1.4835 Y1.2270 +G00 Z0.1000 +G00 X0.8390 Y0.6956 +G01 Z-0.0070 F10 +G01 X0.8268 Y0.7078 F20 +G01 X0.8108 Y0.7144 +G01 X0.7935 Y0.7144 +G01 X0.7775 Y0.7078 +G01 X0.7652 Y0.6956 +G01 X0.7628 Y0.6896 +G01 X0.7603 Y0.6956 +G01 X0.7480 Y0.7078 +G01 X0.7320 Y0.7144 +G01 X0.7147 Y0.7144 +G01 X0.6987 Y0.7078 +G01 X0.6865 Y0.6956 +G01 X0.6799 Y0.6796 +G01 X0.6799 Y0.6003 +G01 X0.6865 Y0.5843 +G01 X0.6987 Y0.5721 +G01 X0.7147 Y0.5654 +G01 X0.7320 Y0.5654 +G01 X0.7480 Y0.5721 +G01 X0.7603 Y0.5843 +G01 X0.7628 Y0.5903 +G01 X0.7652 Y0.5843 +G01 X0.7775 Y0.5721 +G01 X0.7935 Y0.5654 +G01 X0.8108 Y0.5654 +G01 X0.8268 Y0.5721 +G01 X0.8390 Y0.5843 +G01 X0.8415 Y0.5903 +G01 X0.8440 Y0.5843 +G01 X0.8562 Y0.5721 +G01 X0.8722 Y0.5654 +G01 X0.8895 Y0.5654 +G01 X0.9055 Y0.5721 +G01 X0.9177 Y0.5843 +G01 X0.9244 Y0.6003 +G01 X0.9244 Y0.6796 +G01 X0.9177 Y0.6956 +G01 X0.9055 Y0.7078 +G01 X0.8895 Y0.7144 +G01 X0.8722 Y0.7144 +G01 X0.8562 Y0.7078 +G01 X0.8440 Y0.6956 +G01 X0.8415 Y0.6896 +G01 X0.8390 Y0.6956 +G00 Z0.1000 +G00 X0.8046 Y0.7644 +G01 Z-0.0070 F10 +G01 X0.8169 Y0.7522 F20 +G01 X0.8328 Y0.7456 +G01 X0.8501 Y0.7456 +G01 X0.8661 Y0.7522 +G01 X0.8784 Y0.7644 +G01 X0.8809 Y0.7704 +G01 X0.8834 Y0.7644 +G01 X0.8956 Y0.7522 +G01 X0.9116 Y0.7456 +G01 X0.9289 Y0.7456 +G01 X0.9449 Y0.7522 +G01 X0.9571 Y0.7644 +G01 X0.9637 Y0.7804 +G01 X0.9637 Y0.8597 +G01 X0.9571 Y0.8757 +G01 X0.9449 Y0.8879 +G01 X0.9289 Y0.8946 +G01 X0.9116 Y0.8946 +G01 X0.8956 Y0.8879 +G01 X0.8834 Y0.8757 +G01 X0.8809 Y0.8697 +G01 X0.8784 Y0.8757 +G01 X0.8661 Y0.8879 +G01 X0.8501 Y0.8946 +G01 X0.8328 Y0.8946 +G01 X0.8169 Y0.8879 +G01 X0.8046 Y0.8757 +G01 X0.8021 Y0.8697 +G01 X0.7996 Y0.8757 +G01 X0.7874 Y0.8879 +G01 X0.7714 Y0.8946 +G01 X0.7541 Y0.8946 +G01 X0.7381 Y0.8879 +G01 X0.7259 Y0.8757 +G01 X0.7193 Y0.8597 +G01 X0.7193 Y0.7804 +G01 X0.7259 Y0.7644 +G01 X0.7381 Y0.7522 +G01 X0.7541 Y0.7456 +G01 X0.7714 Y0.7456 +G01 X0.7874 Y0.7522 +G01 X0.7996 Y0.7644 +G01 X0.8021 Y0.7704 +G01 X0.8046 Y0.7644 +G00 Z0.1000 +G00 X1.5303 Y0.2965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.2965 F20 +G01 X1.6256 Y0.3031 +G01 X1.6379 Y0.3154 +G01 X1.6445 Y0.3313 +G01 X1.6445 Y0.3487 +G01 X1.6379 Y0.3646 +G01 X1.6256 Y0.3769 +G01 X1.6097 Y0.3835 +G01 X1.5303 Y0.3835 +G01 X1.5144 Y0.3769 +G01 X1.5021 Y0.3646 +G01 X1.4955 Y0.3487 +G01 X1.4955 Y0.3313 +G01 X1.5021 Y0.3154 +G01 X1.5144 Y0.3031 +G01 X1.5303 Y0.2965 +G00 Z0.1000 +G00 X1.5303 Y0.3965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.3965 F20 +G01 X1.6256 Y0.4031 +G01 X1.6379 Y0.4154 +G01 X1.6445 Y0.4313 +G01 X1.6445 Y0.4487 +G01 X1.6379 Y0.4646 +G01 X1.6256 Y0.4769 +G01 X1.6097 Y0.4835 +G01 X1.5303 Y0.4835 +G01 X1.5144 Y0.4769 +G01 X1.5021 Y0.4646 +G01 X1.4955 Y0.4487 +G01 X1.4955 Y0.4313 +G01 X1.5021 Y0.4154 +G01 X1.5144 Y0.4031 +G01 X1.5303 Y0.3965 +G00 Z0.1000 +G00 X1.5303 Y0.4965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.4965 F20 +G01 X1.6256 Y0.5031 +G01 X1.6379 Y0.5154 +G01 X1.6445 Y0.5313 +G01 X1.6445 Y0.5487 +G01 X1.6379 Y0.5646 +G01 X1.6256 Y0.5769 +G01 X1.6097 Y0.5835 +G01 X1.5303 Y0.5835 +G01 X1.5144 Y0.5769 +G01 X1.5021 Y0.5646 +G01 X1.4955 Y0.5487 +G01 X1.4955 Y0.5313 +G01 X1.5021 Y0.5154 +G01 X1.5144 Y0.5031 +G01 X1.5303 Y0.4965 +G00 Z0.1000 +G00 X1.5303 Y0.5965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.5965 F20 +G01 X1.6256 Y0.6031 +G01 X1.6379 Y0.6154 +G01 X1.6445 Y0.6313 +G01 X1.6445 Y0.6487 +G01 X1.6379 Y0.6646 +G01 X1.6256 Y0.6769 +G01 X1.6097 Y0.6835 +G01 X1.5303 Y0.6835 +G01 X1.5144 Y0.6769 +G01 X1.5021 Y0.6646 +G01 X1.4955 Y0.6487 +G01 X1.4955 Y0.6313 +G01 X1.5021 Y0.6154 +G01 X1.5144 Y0.6031 +G01 X1.5303 Y0.5965 +G00 Z0.1000 +G00 X1.5303 Y0.6965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.6965 F20 +G01 X1.6256 Y0.7031 +G01 X1.6379 Y0.7154 +G01 X1.6445 Y0.7313 +G01 X1.6445 Y0.7487 +G01 X1.6379 Y0.7646 +G01 X1.6256 Y0.7769 +G01 X1.6097 Y0.7835 +G01 X1.5303 Y0.7835 +G01 X1.5144 Y0.7769 +G01 X1.5021 Y0.7646 +G01 X1.4955 Y0.7487 +G01 X1.4955 Y0.7313 +G01 X1.5021 Y0.7154 +G01 X1.5144 Y0.7031 +G01 X1.5303 Y0.6965 +G00 Z0.1000 +G00 X1.5303 Y0.7965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.7965 F20 +G01 X1.6256 Y0.8031 +G01 X1.6379 Y0.8154 +G01 X1.6445 Y0.8313 +G01 X1.6445 Y0.8487 +G01 X1.6379 Y0.8646 +G01 X1.6256 Y0.8769 +G01 X1.6097 Y0.8835 +G01 X1.5303 Y0.8835 +G01 X1.5144 Y0.8769 +G01 X1.5021 Y0.8646 +G01 X1.4955 Y0.8487 +G01 X1.4955 Y0.8313 +G01 X1.5021 Y0.8154 +G01 X1.5144 Y0.8031 +G01 X1.5303 Y0.7965 +G00 Z0.1000 +G00 X1.5303 Y0.8965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.8965 F20 +G01 X1.6256 Y0.9031 +G01 X1.6379 Y0.9154 +G01 X1.6445 Y0.9313 +G01 X1.6445 Y0.9487 +G01 X1.6379 Y0.9646 +G01 X1.6256 Y0.9769 +G01 X1.6097 Y0.9835 +G01 X1.5303 Y0.9835 +G01 X1.5144 Y0.9769 +G01 X1.5021 Y0.9646 +G01 X1.4955 Y0.9487 +G01 X1.4955 Y0.9313 +G01 X1.5021 Y0.9154 +G01 X1.5144 Y0.9031 +G01 X1.5303 Y0.8965 +G00 Z0.1000 +G00 X1.5303 Y0.9965 +G01 Z-0.0070 F10 +G01 X1.6097 Y0.9965 F20 +G01 X1.6256 Y1.0031 +G01 X1.6379 Y1.0154 +G01 X1.6445 Y1.0313 +G01 X1.6445 Y1.0487 +G01 X1.6379 Y1.0646 +G01 X1.6256 Y1.0769 +G01 X1.6097 Y1.0835 +G01 X1.5303 Y1.0835 +G01 X1.5144 Y1.0769 +G01 X1.5021 Y1.0646 +G01 X1.4955 Y1.0487 +G01 X1.4955 Y1.0313 +G01 X1.5021 Y1.0154 +G01 X1.5144 Y1.0031 +G01 X1.5303 Y0.9965 +G00 Z0.1000 +G00 X1.2303 Y0.9965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.9965 F20 +G01 X1.3256 Y1.0031 +G01 X1.3379 Y1.0154 +G01 X1.3445 Y1.0313 +G01 X1.3445 Y1.0487 +G01 X1.3379 Y1.0646 +G01 X1.3256 Y1.0769 +G01 X1.3097 Y1.0835 +G01 X1.2303 Y1.0835 +G01 X1.2144 Y1.0769 +G01 X1.2021 Y1.0646 +G01 X1.1955 Y1.0487 +G01 X1.1955 Y1.0313 +G01 X1.2021 Y1.0154 +G01 X1.2144 Y1.0031 +G01 X1.2303 Y0.9965 +G00 Z0.1000 +G00 X1.2303 Y0.8965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.8965 F20 +G01 X1.3256 Y0.9031 +G01 X1.3379 Y0.9154 +G01 X1.3445 Y0.9313 +G01 X1.3445 Y0.9487 +G01 X1.3379 Y0.9646 +G01 X1.3256 Y0.9769 +G01 X1.3097 Y0.9835 +G01 X1.2303 Y0.9835 +G01 X1.2144 Y0.9769 +G01 X1.2021 Y0.9646 +G01 X1.1955 Y0.9487 +G01 X1.1955 Y0.9313 +G01 X1.2021 Y0.9154 +G01 X1.2144 Y0.9031 +G01 X1.2303 Y0.8965 +G00 Z0.1000 +G00 X1.2303 Y0.7965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.7965 F20 +G01 X1.3256 Y0.8031 +G01 X1.3379 Y0.8154 +G01 X1.3445 Y0.8313 +G01 X1.3445 Y0.8487 +G01 X1.3379 Y0.8646 +G01 X1.3256 Y0.8769 +G01 X1.3097 Y0.8835 +G01 X1.2303 Y0.8835 +G01 X1.2144 Y0.8769 +G01 X1.2021 Y0.8646 +G01 X1.1955 Y0.8487 +G01 X1.1955 Y0.8313 +G01 X1.2021 Y0.8154 +G01 X1.2144 Y0.8031 +G01 X1.2303 Y0.7965 +G00 Z0.1000 +G00 X1.2303 Y0.6965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.6965 F20 +G01 X1.3256 Y0.7031 +G01 X1.3379 Y0.7154 +G01 X1.3445 Y0.7313 +G01 X1.3445 Y0.7487 +G01 X1.3379 Y0.7646 +G01 X1.3256 Y0.7769 +G01 X1.3097 Y0.7835 +G01 X1.2303 Y0.7835 +G01 X1.2144 Y0.7769 +G01 X1.2021 Y0.7646 +G01 X1.1955 Y0.7487 +G01 X1.1955 Y0.7313 +G01 X1.2021 Y0.7154 +G01 X1.2144 Y0.7031 +G01 X1.2303 Y0.6965 +G00 Z0.1000 +G00 X1.2303 Y0.5965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.5965 F20 +G01 X1.3256 Y0.6031 +G01 X1.3379 Y0.6154 +G01 X1.3445 Y0.6313 +G01 X1.3445 Y0.6487 +G01 X1.3379 Y0.6646 +G01 X1.3256 Y0.6769 +G01 X1.3097 Y0.6835 +G01 X1.2303 Y0.6835 +G01 X1.2144 Y0.6769 +G01 X1.2021 Y0.6646 +G01 X1.1955 Y0.6487 +G01 X1.1955 Y0.6313 +G01 X1.2021 Y0.6154 +G01 X1.2144 Y0.6031 +G01 X1.2303 Y0.5965 +G00 Z0.1000 +G00 X1.2303 Y0.4965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.4965 F20 +G01 X1.3256 Y0.5031 +G01 X1.3379 Y0.5154 +G01 X1.3445 Y0.5313 +G01 X1.3445 Y0.5487 +G01 X1.3379 Y0.5646 +G01 X1.3256 Y0.5769 +G01 X1.3097 Y0.5835 +G01 X1.2303 Y0.5835 +G01 X1.2144 Y0.5769 +G01 X1.2021 Y0.5646 +G01 X1.1955 Y0.5487 +G01 X1.1955 Y0.5313 +G01 X1.2021 Y0.5154 +G01 X1.2144 Y0.5031 +G01 X1.2303 Y0.4965 +G00 Z0.1000 +G00 X1.2303 Y0.3965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.3965 F20 +G01 X1.3256 Y0.4031 +G01 X1.3379 Y0.4154 +G01 X1.3445 Y0.4313 +G01 X1.3445 Y0.4487 +G01 X1.3379 Y0.4646 +G01 X1.3256 Y0.4769 +G01 X1.3097 Y0.4835 +G01 X1.2303 Y0.4835 +G01 X1.2144 Y0.4769 +G01 X1.2021 Y0.4646 +G01 X1.1955 Y0.4487 +G01 X1.1955 Y0.4313 +G01 X1.2021 Y0.4154 +G01 X1.2144 Y0.4031 +G01 X1.2303 Y0.3965 +G00 Z0.1000 +G00 X1.2303 Y0.2965 +G01 Z-0.0070 F10 +G01 X1.3097 Y0.2965 F20 +G01 X1.3256 Y0.3031 +G01 X1.3379 Y0.3154 +G01 X1.3445 Y0.3313 +G01 X1.3445 Y0.3487 +G01 X1.3379 Y0.3646 +G01 X1.3256 Y0.3769 +G01 X1.3097 Y0.3835 +G01 X1.2303 Y0.3835 +G01 X1.2144 Y0.3769 +G01 X1.2021 Y0.3646 +G01 X1.1955 Y0.3487 +G01 X1.1955 Y0.3313 +G01 X1.2021 Y0.3154 +G01 X1.2144 Y0.3031 +G01 X1.2303 Y0.2965 +G00 Z0.1000 +G00 X0.3375 Y0.9803 +G01 Z-0.0070 F10 +G01 X0.3375 Y1.0197 F20 +G01 X0.3097 Y1.0475 +G01 X0.2703 Y1.0475 +G01 X0.2425 Y1.0197 +G01 X0.2425 Y0.9803 +G01 X0.2703 Y0.9525 +G01 X0.3097 Y0.9525 +G01 X0.3375 Y0.9803 +G00 Z0.1000 +G00 X0.3375 Y0.8803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.9197 F20 +G01 X0.3097 Y0.9475 +G01 X0.2703 Y0.9475 +G01 X0.2425 Y0.9197 +G01 X0.2425 Y0.8803 +G01 X0.2703 Y0.8525 +G01 X0.3097 Y0.8525 +G01 X0.3375 Y0.8803 +G00 Z0.1000 +G00 X0.3375 Y0.7803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.8197 F20 +G01 X0.3097 Y0.8475 +G01 X0.2703 Y0.8475 +G01 X0.2425 Y0.8197 +G01 X0.2425 Y0.7803 +G01 X0.2703 Y0.7525 +G01 X0.3097 Y0.7525 +G01 X0.3375 Y0.7803 +G00 Z0.1000 +G00 X0.3375 Y0.6803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.7197 F20 +G01 X0.3097 Y0.7475 +G01 X0.2703 Y0.7475 +G01 X0.2425 Y0.7197 +G01 X0.2425 Y0.6803 +G01 X0.2703 Y0.6525 +G01 X0.3097 Y0.6525 +G01 X0.3375 Y0.6803 +G00 Z0.1000 +G00 X0.3375 Y0.5803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.6197 F20 +G01 X0.3097 Y0.6475 +G01 X0.2703 Y0.6475 +G01 X0.2425 Y0.6197 +G01 X0.2425 Y0.5803 +G01 X0.2703 Y0.5525 +G01 X0.3097 Y0.5525 +G01 X0.3375 Y0.5803 +G00 Z0.1000 +G00 X0.3375 Y0.4803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.5197 F20 +G01 X0.3097 Y0.5475 +G01 X0.2703 Y0.5475 +G01 X0.2425 Y0.5197 +G01 X0.2425 Y0.4803 +G01 X0.2703 Y0.4525 +G01 X0.3097 Y0.4525 +G01 X0.3375 Y0.4803 +G00 Z0.1000 +G00 X0.2375 Y0.9803 +G01 Z-0.0070 F10 +G01 X0.2375 Y1.0197 F20 +G01 X0.2097 Y1.0475 +G01 X0.1703 Y1.0475 +G01 X0.1425 Y1.0197 +G01 X0.1425 Y0.9803 +G01 X0.1703 Y0.9525 +G01 X0.2097 Y0.9525 +G01 X0.2375 Y0.9803 +G00 Z0.1000 +G00 X0.2375 Y0.8803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.9197 F20 +G01 X0.2097 Y0.9475 +G01 X0.1703 Y0.9475 +G01 X0.1425 Y0.9197 +G01 X0.1425 Y0.8803 +G01 X0.1703 Y0.8525 +G01 X0.2097 Y0.8525 +G01 X0.2375 Y0.8803 +G00 Z0.1000 +G00 X0.2375 Y0.7803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.8197 F20 +G01 X0.2097 Y0.8475 +G01 X0.1703 Y0.8475 +G01 X0.1425 Y0.8197 +G01 X0.1425 Y0.7803 +G01 X0.1703 Y0.7525 +G01 X0.2097 Y0.7525 +G01 X0.2375 Y0.7803 +G00 Z0.1000 +G00 X0.2375 Y0.6803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.7197 F20 +G01 X0.2097 Y0.7475 +G01 X0.1703 Y0.7475 +G01 X0.1425 Y0.7197 +G01 X0.1425 Y0.6803 +G01 X0.1703 Y0.6525 +G01 X0.2097 Y0.6525 +G01 X0.2375 Y0.6803 +G00 Z0.1000 +G00 X0.2375 Y0.5803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.6197 F20 +G01 X0.2097 Y0.6475 +G01 X0.1703 Y0.6475 +G01 X0.1425 Y0.6197 +G01 X0.1425 Y0.5803 +G01 X0.1703 Y0.5525 +G01 X0.2097 Y0.5525 +G01 X0.2375 Y0.5803 +G00 Z0.1000 +G00 X0.2375 Y0.4803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.5197 F20 +G01 X0.2097 Y0.5475 +G01 X0.1703 Y0.5475 +G01 X0.1425 Y0.5197 +G01 X0.1425 Y0.4803 +G01 X0.1703 Y0.4525 +G01 X0.2097 Y0.4525 +G01 X0.2375 Y0.4803 +G00 Z0.1000 +G00 X0.3375 Y0.3803 +G01 Z-0.0070 F10 +G01 X0.3375 Y0.4197 F20 +G01 X0.3097 Y0.4475 +G01 X0.2703 Y0.4475 +G01 X0.2425 Y0.4197 +G01 X0.2425 Y0.3803 +G01 X0.2703 Y0.3525 +G01 X0.3097 Y0.3525 +G01 X0.3375 Y0.3803 +G00 Z0.1000 +G00 X0.2375 Y0.3803 +G01 Z-0.0070 F10 +G01 X0.2375 Y0.4197 F20 +G01 X0.2097 Y0.4475 +G01 X0.1703 Y0.4475 +G01 X0.1425 Y0.4197 +G01 X0.1425 Y0.3803 +G01 X0.1703 Y0.3525 +G01 X0.2097 Y0.3525 +G01 X0.2375 Y0.3803 +G00 Z0.1000 +G00 X0.8397 Y0.4135 +G01 Z-0.0070 F10 +G01 X0.7603 Y0.4135 F20 +G01 X0.7444 Y0.4069 +G01 X0.7321 Y0.3946 +G01 X0.7255 Y0.3787 +G01 X0.7255 Y0.3613 +G01 X0.7321 Y0.3454 +G01 X0.7444 Y0.3331 +G01 X0.7603 Y0.3265 +G01 X0.8397 Y0.3265 +G01 X0.8556 Y0.3331 +G01 X0.8679 Y0.3454 +G01 X0.8745 Y0.3613 +G01 X0.8745 Y0.3787 +G01 X0.8679 Y0.3946 +G01 X0.8556 Y0.4069 +G01 X0.8397 Y0.4135 +G00 Z0.1000 +G00 X1.1397 Y0.3135 +G01 Z-0.0070 F10 +G01 X1.0603 Y0.3135 F20 +G01 X1.0444 Y0.3069 +G01 X1.0321 Y0.2946 +G01 X1.0255 Y0.2787 +G01 X1.0255 Y0.2613 +G01 X1.0321 Y0.2454 +G01 X1.0444 Y0.2331 +G01 X1.0603 Y0.2265 +G01 X1.1397 Y0.2265 +G01 X1.1556 Y0.2331 +G01 X1.1679 Y0.2454 +G01 X1.1745 Y0.2613 +G01 X1.1745 Y0.2787 +G01 X1.1679 Y0.2946 +G01 X1.1556 Y0.3069 +G01 X1.1397 Y0.3135 +G00 Z0.1000 +G00 X0.6397 Y0.3135 +G01 Z-0.0070 F10 +G01 X0.5603 Y0.3135 F20 +G01 X0.5444 Y0.3069 +G01 X0.5321 Y0.2946 +G01 X0.5255 Y0.2787 +G01 X0.5255 Y0.2613 +G01 X0.5321 Y0.2454 +G01 X0.5444 Y0.2331 +G01 X0.5603 Y0.2265 +G01 X0.6397 Y0.2265 +G01 X0.6556 Y0.2331 +G01 X0.6679 Y0.2454 +G01 X0.6745 Y0.2613 +G01 X0.6745 Y0.2787 +G01 X0.6679 Y0.2946 +G01 X0.6556 Y0.3069 +G01 X0.6397 Y0.3135 +G00 Z0.1000 +G00 X2.1103 Y0.1065 +G01 Z-0.0070 F10 +G01 X2.1897 Y0.1065 F20 +G01 X2.2056 Y0.1131 +G01 X2.2179 Y0.1254 +G01 X2.2245 Y0.1413 +G01 X2.2245 Y0.1587 +G01 X2.2179 Y0.1746 +G01 X2.2056 Y0.1869 +G01 X2.1897 Y0.1935 +G01 X2.1103 Y0.1935 +G01 X2.0944 Y0.1869 +G01 X2.0821 Y0.1746 +G01 X2.0755 Y0.1587 +G01 X2.0755 Y0.1413 +G01 X2.0821 Y0.1254 +G01 X2.0944 Y0.1131 +G01 X2.1103 Y0.1065 +G00 Z0.1000 +G00 X2.1103 Y0.2065 +G01 Z-0.0070 F10 +G01 X2.1897 Y0.2065 F20 +G01 X2.2056 Y0.2131 +G01 X2.2179 Y0.2254 +G01 X2.2245 Y0.2413 +G01 X2.2245 Y0.2587 +G01 X2.2179 Y0.2746 +G01 X2.2056 Y0.2869 +G01 X2.1897 Y0.2935 +G01 X2.1103 Y0.2935 +G01 X2.0944 Y0.2869 +G01 X2.0821 Y0.2746 +G01 X2.0755 Y0.2587 +G01 X2.0755 Y0.2413 +G01 X2.0821 Y0.2254 +G01 X2.0944 Y0.2131 +G01 X2.1103 Y0.2065 +G00 Z0.1000 +G00 X2.1103 Y0.3065 +G01 Z-0.0070 F10 +G01 X2.1897 Y0.3065 F20 +G01 X2.2056 Y0.3131 +G01 X2.2179 Y0.3254 +G01 X2.2245 Y0.3413 +G01 X2.2245 Y0.3587 +G01 X2.2179 Y0.3746 +G01 X2.2056 Y0.3869 +G01 X2.1897 Y0.3935 +G01 X2.1103 Y0.3935 +G01 X2.0944 Y0.3869 +G01 X2.0821 Y0.3746 +G01 X2.0755 Y0.3587 +G01 X2.0755 Y0.3413 +G01 X2.0821 Y0.3254 +G01 X2.0944 Y0.3131 +G01 X2.1103 Y0.3065 +G00 Z0.1000 +G00 X1.8103 Y0.3065 +G01 Z-0.0070 F10 +G01 X1.8897 Y0.3065 F20 +G01 X1.9056 Y0.3131 +G01 X1.9179 Y0.3254 +G01 X1.9245 Y0.3413 +G01 X1.9245 Y0.3587 +G01 X1.9179 Y0.3746 +G01 X1.9056 Y0.3869 +G01 X1.8897 Y0.3935 +G01 X1.8103 Y0.3935 +G01 X1.7944 Y0.3869 +G01 X1.7821 Y0.3746 +G01 X1.7755 Y0.3587 +G01 X1.7755 Y0.3413 +G01 X1.7821 Y0.3254 +G01 X1.7944 Y0.3131 +G01 X1.8103 Y0.3065 +G00 Z0.1000 +G00 X1.8103 Y0.2065 +G01 Z-0.0070 F10 +G01 X1.8897 Y0.2065 F20 +G01 X1.9056 Y0.2131 +G01 X1.9179 Y0.2254 +G01 X1.9245 Y0.2413 +G01 X1.9245 Y0.2587 +G01 X1.9179 Y0.2746 +G01 X1.9056 Y0.2869 +G01 X1.8897 Y0.2935 +G01 X1.8103 Y0.2935 +G01 X1.7944 Y0.2869 +G01 X1.7821 Y0.2746 +G01 X1.7755 Y0.2587 +G01 X1.7755 Y0.2413 +G01 X1.7821 Y0.2254 +G01 X1.7944 Y0.2131 +G01 X1.8103 Y0.2065 +G00 Z0.1000 +G00 X1.8103 Y0.1065 +G01 Z-0.0070 F10 +G01 X1.8897 Y0.1065 F20 +G01 X1.9056 Y0.1131 +G01 X1.9179 Y0.1254 +G01 X1.9245 Y0.1413 +G01 X1.9245 Y0.1587 +G01 X1.9179 Y0.1746 +G01 X1.9056 Y0.1869 +G01 X1.8897 Y0.1935 +G01 X1.8103 Y0.1935 +G01 X1.7944 Y0.1869 +G01 X1.7821 Y0.1746 +G01 X1.7755 Y0.1587 +G01 X1.7755 Y0.1413 +G01 X1.7821 Y0.1254 +G01 X1.7944 Y0.1131 +G01 X1.8103 Y0.1065 +G00 Z0.1000 +G00 X1.8435 Y0.6620 +G01 Z-0.0070 F10 +G01 X1.8435 Y0.6980 F20 +G01 X1.8180 Y0.7235 +G01 X1.7820 Y0.7235 +G01 X1.7565 Y0.6980 +G01 X1.7565 Y0.6620 +G01 X1.7820 Y0.6365 +G01 X1.8180 Y0.6365 +G01 X1.8435 Y0.6620 +G00 Z0.1000 +G00 X1.8435 Y0.4620 +G01 Z-0.0070 F10 +G01 X1.8435 Y0.4980 F20 +G01 X1.8180 Y0.5235 +G01 X1.7820 Y0.5235 +G01 X1.7565 Y0.4980 +G01 X1.7565 Y0.4620 +G01 X1.7820 Y0.4365 +G01 X1.8180 Y0.4365 +G01 X1.8435 Y0.4620 +G00 Z0.1000 +G00 X1.9635 Y0.6620 +G01 Z-0.0070 F10 +G01 X1.9635 Y0.6980 F20 +G01 X1.9380 Y0.7235 +G01 X1.9020 Y0.7235 +G01 X1.8765 Y0.6980 +G01 X1.8765 Y0.6620 +G01 X1.9020 Y0.6365 +G01 X1.9380 Y0.6365 +G01 X1.9635 Y0.6620 +G00 Z0.1000 +G00 X1.9635 Y0.4620 +G01 Z-0.0070 F10 +G01 X1.9635 Y0.4980 F20 +G01 X1.9380 Y0.5235 +G01 X1.9020 Y0.5235 +G01 X1.8765 Y0.4980 +G01 X1.8765 Y0.4620 +G01 X1.9020 Y0.4365 +G01 X1.9380 Y0.4365 +G01 X1.9635 Y0.4620 +G00 Z0.1000 +G00 X2.0835 Y0.6620 +G01 Z-0.0070 F10 +G01 X2.0835 Y0.6980 F20 +G01 X2.0580 Y0.7235 +G01 X2.0220 Y0.7235 +G01 X1.9965 Y0.6980 +G01 X1.9965 Y0.6620 +G01 X2.0220 Y0.6365 +G01 X2.0580 Y0.6365 +G01 X2.0835 Y0.6620 +G00 Z0.1000 +G00 X2.0835 Y0.4620 +G01 Z-0.0070 F10 +G01 X2.0835 Y0.4980 F20 +G01 X2.0580 Y0.5235 +G01 X2.0220 Y0.5235 +G01 X1.9965 Y0.4980 +G01 X1.9965 Y0.4620 +G01 X2.0220 Y0.4365 +G01 X2.0580 Y0.4365 +G01 X2.0835 Y0.4620 +G00 Z0.1000 +G00 X1.3135 Y0.2120 +G01 Z-0.0070 F10 +G01 X1.3135 Y0.2480 F20 +G01 X1.2880 Y0.2735 +G01 X1.2520 Y0.2735 +G01 X1.2265 Y0.2480 +G01 X1.2265 Y0.2120 +G01 X1.2520 Y0.1865 +G01 X1.2880 Y0.1865 +G01 X1.3135 Y0.2120 +G00 Z0.1000 +G00 X1.4135 Y0.2120 +G01 Z-0.0070 F10 +G01 X1.4135 Y0.2480 F20 +G01 X1.3880 Y0.2735 +G01 X1.3520 Y0.2735 +G01 X1.3265 Y0.2480 +G01 X1.3265 Y0.2120 +G01 X1.3520 Y0.1865 +G01 X1.3880 Y0.1865 +G01 X1.4135 Y0.2120 +G00 Z0.1000 +G00 X2.3625 Y1.0041 +G01 Z-0.0070 F10 +G01 X2.3625 Y1.0559 F20 +G01 X2.3259 Y1.0925 +G01 X2.2741 Y1.0925 +G01 X2.2375 Y1.0559 +G01 X2.2375 Y1.0041 +G01 X2.2741 Y0.9675 +G01 X2.3259 Y0.9675 +G01 X2.3625 Y1.0041 +G00 Z0.1000 +G00 X2.0625 Y1.0041 +G01 Z-0.0070 F10 +G01 X2.0625 Y1.0559 F20 +G01 X2.0259 Y1.0925 +G01 X1.9741 Y1.0925 +G01 X1.9375 Y1.0559 +G01 X1.9375 Y1.0041 +G01 X1.9741 Y0.9675 +G01 X2.0259 Y0.9675 +G01 X2.0625 Y1.0041 +G00 Z0.1000 +G00 X0.5535 Y0.9820 +G01 Z-0.0070 F10 +G01 X0.5535 Y1.0180 F20 +G01 X0.5280 Y1.0435 +G01 X0.4920 Y1.0435 +G01 X0.4665 Y1.0180 +G01 X0.4665 Y0.9820 +G01 X0.4920 Y0.9565 +G01 X0.5280 Y0.9565 +G01 X0.5535 Y0.9820 +G00 Z0.1000 +G00 X0.4535 Y0.9820 +G01 Z-0.0070 F10 +G01 X0.4535 Y1.0180 F20 +G01 X0.4280 Y1.0435 +G01 X0.3920 Y1.0435 +G01 X0.3665 Y1.0180 +G01 X0.3665 Y0.9820 +G01 X0.3920 Y0.9565 +G01 X0.4280 Y0.9565 +G01 X0.4535 Y0.9820 +G00 Z0.1000 +G00 X1.4335 Y1.1520 +G01 Z-0.0070 F10 +G01 X1.4335 Y1.1880 F20 +G01 X1.4080 Y1.2135 +G01 X1.3720 Y1.2135 +G01 X1.3465 Y1.1880 +G01 X1.3465 Y1.1520 +G01 X1.3720 Y1.1265 +G01 X1.4080 Y1.1265 +G01 X1.4335 Y1.1520 +G00 Z0.1000 +G00 X1.5335 Y1.1520 +G01 Z-0.0070 F10 +G01 X1.5335 Y1.1880 F20 +G01 X1.5080 Y1.2135 +G01 X1.4720 Y1.2135 +G01 X1.4465 Y1.1880 +G01 X1.4465 Y1.1520 +G01 X1.4720 Y1.1265 +G01 X1.5080 Y1.1265 +G01 X1.5335 Y1.1520 +G00 Z0.1000 +G00 X1.1770 Y1.2114 +G01 Z-0.0070 F10 +G01 X1.1614 Y1.2270 F20 +G01 X1.1410 Y1.2355 +G01 X1.1190 Y1.2355 +G01 X1.0986 Y1.2270 +G01 X1.0829 Y1.2114 +G01 X1.0745 Y1.1910 +G01 X1.0745 Y1.1690 +G01 X1.0829 Y1.1486 +G01 X1.0986 Y1.1329 +G01 X1.1190 Y1.1245 +G01 X1.1410 Y1.1245 +G01 X1.1614 Y1.1329 +G01 X1.1770 Y1.1486 +G01 X1.1788 Y1.1527 +G01 X1.2070 Y1.1245 +G01 X1.2530 Y1.1245 +G01 X1.2855 Y1.1570 +G01 X1.2855 Y1.2030 +G01 X1.2530 Y1.2355 +G01 X1.2070 Y1.2355 +G01 X1.1788 Y1.2073 +G01 X1.1770 Y1.2114 +G00 Z0.1000 +G00 X0.2400 Y0.9758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.9500 F20 +G01 X0.2400 Y0.9242 +G01 X0.2142 Y0.9500 +G01 X0.2400 Y0.9758 +G00 Z0.1000 +G00 X0.2400 Y0.7758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.7500 F20 +G01 X0.2400 Y0.7242 +G01 X0.2142 Y0.7500 +G01 X0.2400 Y0.7758 +G00 Z0.1000 +G00 X0.2400 Y0.5758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.5500 F20 +G01 X0.2400 Y0.5242 +G01 X0.2142 Y0.5500 +G01 X0.2400 Y0.5758 +G00 Z0.1000 +G00 X0.2400 Y0.4758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.4500 F20 +G01 X0.2400 Y0.4242 +G01 X0.2142 Y0.4500 +G01 X0.2400 Y0.4758 +G00 Z0.1000 +G00 X0.2400 Y0.6758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.6500 F20 +G01 X0.2400 Y0.6242 +G01 X0.2142 Y0.6500 +G01 X0.2400 Y0.6758 +G00 Z0.1000 +G00 X0.2400 Y0.8758 +G01 Z-0.0070 F10 +G01 X0.2658 Y0.8500 F20 +G01 X0.2400 Y0.8242 +G01 X0.2142 Y0.8500 +G01 X0.2400 Y0.8758 +G00 Z0.1000 +G00 X1.8105 Y1.2080 +G01 Z-0.0070 F10 +G01 X1.8105 Y1.2320 F20 +G01 X1.8013 Y1.2543 +G01 X1.7843 Y1.2713 +G01 X1.7620 Y1.2805 +G01 X1.7380 Y1.2805 +G01 X1.7157 Y1.2713 +G01 X1.6987 Y1.2543 +G01 X1.6895 Y1.2320 +G01 X1.6895 Y1.2080 +G01 X1.6987 Y1.1857 +G01 X1.7144 Y1.1700 +G01 X1.6895 Y1.1451 +G01 X1.6895 Y1.0949 +G01 X1.7249 Y1.0595 +G01 X1.7751 Y1.0595 +G01 X1.8105 Y1.0949 +G01 X1.8105 Y1.1451 +G01 X1.7856 Y1.1700 +G01 X1.8013 Y1.1857 +G01 X1.8105 Y1.2080 +G00 Z0.1000 +G00 X0.3425 Y0.9783 +G01 Z-0.0070 F10 +G01 X0.3425 Y1.0217 F20 +G01 X0.3117 Y1.0525 +G01 X0.2683 Y1.0525 +G01 X0.2400 Y1.0242 +G01 X0.2117 Y1.0525 +G01 X0.1683 Y1.0525 +G01 X0.1375 Y1.0217 +G01 X0.1375 Y0.9783 +G01 X0.1658 Y0.9500 +G01 X0.1375 Y0.9217 +G01 X0.1375 Y0.8783 +G01 X0.1658 Y0.8500 +G01 X0.1375 Y0.8217 +G01 X0.1375 Y0.7783 +G01 X0.1658 Y0.7500 +G01 X0.1375 Y0.7217 +G01 X0.1375 Y0.6783 +G01 X0.1658 Y0.6500 +G01 X0.1375 Y0.6217 +G01 X0.1375 Y0.5783 +G01 X0.1658 Y0.5500 +G01 X0.1375 Y0.5217 +G01 X0.1375 Y0.4783 +G01 X0.1658 Y0.4500 +G01 X0.1375 Y0.4217 +G01 X0.1375 Y0.3783 +G01 X0.1683 Y0.3475 +G01 X0.2117 Y0.3475 +G01 X0.2400 Y0.3758 +G01 X0.2683 Y0.3475 +G01 X0.3117 Y0.3475 +G01 X0.3425 Y0.3783 +G01 X0.3425 Y0.4217 +G01 X0.3142 Y0.4500 +G01 X0.3425 Y0.4783 +G01 X0.3425 Y0.5217 +G01 X0.3142 Y0.5500 +G01 X0.3425 Y0.5783 +G01 X0.3425 Y0.6217 +G01 X0.3142 Y0.6500 +G01 X0.3425 Y0.6783 +G01 X0.3425 Y0.7217 +G01 X0.3142 Y0.7500 +G01 X0.3425 Y0.7783 +G01 X0.3425 Y0.8217 +G01 X0.3142 Y0.8500 +G01 X0.3425 Y0.8783 +G01 X0.3425 Y0.9217 +G01 X0.3142 Y0.9500 +G01 X0.3425 Y0.9783 +G00 Z0.1000 +G00 X1.2294 Y0.2915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.2915 F20 +G01 X1.3285 Y0.2989 +G01 X1.3421 Y0.3125 +G01 X1.3495 Y0.3304 +G01 X1.3495 Y0.3496 +G01 X1.3421 Y0.3675 +G01 X1.3285 Y0.3811 +G01 X1.3106 Y0.3885 +G01 X1.2294 Y0.3885 +G01 X1.2115 Y0.3811 +G01 X1.1979 Y0.3675 +G01 X1.1905 Y0.3496 +G01 X1.1905 Y0.3304 +G01 X1.1979 Y0.3125 +G01 X1.2115 Y0.2989 +G01 X1.2294 Y0.2915 +G00 Z0.1000 +G00 X1.2294 Y0.3915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.3915 F20 +G01 X1.3285 Y0.3989 +G01 X1.3421 Y0.4125 +G01 X1.3495 Y0.4304 +G01 X1.3495 Y0.4496 +G01 X1.3421 Y0.4675 +G01 X1.3285 Y0.4811 +G01 X1.3106 Y0.4885 +G01 X1.2294 Y0.4885 +G01 X1.2115 Y0.4811 +G01 X1.1979 Y0.4675 +G01 X1.1905 Y0.4496 +G01 X1.1905 Y0.4304 +G01 X1.1979 Y0.4125 +G01 X1.2115 Y0.3989 +G01 X1.2294 Y0.3915 +G00 Z0.1000 +G00 X1.2294 Y0.4915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.4915 F20 +G01 X1.3285 Y0.4989 +G01 X1.3421 Y0.5125 +G01 X1.3495 Y0.5304 +G01 X1.3495 Y0.5496 +G01 X1.3421 Y0.5675 +G01 X1.3285 Y0.5811 +G01 X1.3106 Y0.5885 +G01 X1.2294 Y0.5885 +G01 X1.2115 Y0.5811 +G01 X1.1979 Y0.5675 +G01 X1.1905 Y0.5496 +G01 X1.1905 Y0.5304 +G01 X1.1979 Y0.5125 +G01 X1.2115 Y0.4989 +G01 X1.2294 Y0.4915 +G00 Z0.1000 +G00 X1.2294 Y0.5915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.5915 F20 +G01 X1.3285 Y0.5989 +G01 X1.3421 Y0.6125 +G01 X1.3495 Y0.6304 +G01 X1.3495 Y0.6496 +G01 X1.3421 Y0.6675 +G01 X1.3285 Y0.6811 +G01 X1.3106 Y0.6885 +G01 X1.2294 Y0.6885 +G01 X1.2115 Y0.6811 +G01 X1.1979 Y0.6675 +G01 X1.1905 Y0.6496 +G01 X1.1905 Y0.6304 +G01 X1.1979 Y0.6125 +G01 X1.2115 Y0.5989 +G01 X1.2294 Y0.5915 +G00 Z0.1000 +G00 X1.2294 Y0.6915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.6915 F20 +G01 X1.3285 Y0.6989 +G01 X1.3421 Y0.7125 +G01 X1.3495 Y0.7304 +G01 X1.3495 Y0.7496 +G01 X1.3421 Y0.7675 +G01 X1.3285 Y0.7811 +G01 X1.3106 Y0.7885 +G01 X1.2294 Y0.7885 +G01 X1.2115 Y0.7811 +G01 X1.1979 Y0.7675 +G01 X1.1905 Y0.7496 +G01 X1.1905 Y0.7304 +G01 X1.1979 Y0.7125 +G01 X1.2115 Y0.6989 +G01 X1.2294 Y0.6915 +G00 Z0.1000 +G00 X1.2294 Y0.7915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.7915 F20 +G01 X1.3285 Y0.7989 +G01 X1.3421 Y0.8125 +G01 X1.3495 Y0.8304 +G01 X1.3495 Y0.8496 +G01 X1.3421 Y0.8675 +G01 X1.3285 Y0.8811 +G01 X1.3106 Y0.8885 +G01 X1.2294 Y0.8885 +G01 X1.2115 Y0.8811 +G01 X1.1979 Y0.8675 +G01 X1.1905 Y0.8496 +G01 X1.1905 Y0.8304 +G01 X1.1979 Y0.8125 +G01 X1.2115 Y0.7989 +G01 X1.2294 Y0.7915 +G00 Z0.1000 +G00 X1.2294 Y0.8915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.8915 F20 +G01 X1.3285 Y0.8989 +G01 X1.3421 Y0.9125 +G01 X1.3495 Y0.9304 +G01 X1.3495 Y0.9496 +G01 X1.3421 Y0.9675 +G01 X1.3285 Y0.9811 +G01 X1.3106 Y0.9885 +G01 X1.2294 Y0.9885 +G01 X1.2115 Y0.9811 +G01 X1.1979 Y0.9675 +G01 X1.1905 Y0.9496 +G01 X1.1905 Y0.9304 +G01 X1.1979 Y0.9125 +G01 X1.2115 Y0.8989 +G01 X1.2294 Y0.8915 +G00 Z0.1000 +G00 X1.2294 Y0.9915 +G01 Z-0.0070 F10 +G01 X1.3106 Y0.9915 F20 +G01 X1.3285 Y0.9989 +G01 X1.3421 Y1.0125 +G01 X1.3495 Y1.0304 +G01 X1.3495 Y1.0496 +G01 X1.3421 Y1.0675 +G01 X1.3285 Y1.0811 +G01 X1.3106 Y1.0885 +G01 X1.2294 Y1.0885 +G01 X1.2115 Y1.0811 +G01 X1.1979 Y1.0675 +G01 X1.1905 Y1.0496 +G01 X1.1905 Y1.0304 +G01 X1.1979 Y1.0125 +G01 X1.2115 Y0.9989 +G01 X1.2294 Y0.9915 +G00 Z0.1000 +G00 X1.5294 Y0.9915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.9915 F20 +G01 X1.6285 Y0.9989 +G01 X1.6421 Y1.0125 +G01 X1.6495 Y1.0304 +G01 X1.6495 Y1.0496 +G01 X1.6421 Y1.0675 +G01 X1.6285 Y1.0811 +G01 X1.6106 Y1.0885 +G01 X1.5294 Y1.0885 +G01 X1.5115 Y1.0811 +G01 X1.4979 Y1.0675 +G01 X1.4905 Y1.0496 +G01 X1.4905 Y1.0304 +G01 X1.4979 Y1.0125 +G01 X1.5115 Y0.9989 +G01 X1.5294 Y0.9915 +G00 Z0.1000 +G00 X1.5294 Y0.8915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.8915 F20 +G01 X1.6285 Y0.8989 +G01 X1.6421 Y0.9125 +G01 X1.6495 Y0.9304 +G01 X1.6495 Y0.9496 +G01 X1.6421 Y0.9675 +G01 X1.6285 Y0.9811 +G01 X1.6106 Y0.9885 +G01 X1.5294 Y0.9885 +G01 X1.5115 Y0.9811 +G01 X1.4979 Y0.9675 +G01 X1.4905 Y0.9496 +G01 X1.4905 Y0.9304 +G01 X1.4979 Y0.9125 +G01 X1.5115 Y0.8989 +G01 X1.5294 Y0.8915 +G00 Z0.1000 +G00 X1.5294 Y0.7915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.7915 F20 +G01 X1.6285 Y0.7989 +G01 X1.6421 Y0.8125 +G01 X1.6495 Y0.8304 +G01 X1.6495 Y0.8496 +G01 X1.6421 Y0.8675 +G01 X1.6285 Y0.8811 +G01 X1.6106 Y0.8885 +G01 X1.5294 Y0.8885 +G01 X1.5115 Y0.8811 +G01 X1.4979 Y0.8675 +G01 X1.4905 Y0.8496 +G01 X1.4905 Y0.8304 +G01 X1.4979 Y0.8125 +G01 X1.5115 Y0.7989 +G01 X1.5294 Y0.7915 +G00 Z0.1000 +G00 X1.5294 Y0.6915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.6915 F20 +G01 X1.6285 Y0.6989 +G01 X1.6421 Y0.7125 +G01 X1.6495 Y0.7304 +G01 X1.6495 Y0.7496 +G01 X1.6421 Y0.7675 +G01 X1.6285 Y0.7811 +G01 X1.6106 Y0.7885 +G01 X1.5294 Y0.7885 +G01 X1.5115 Y0.7811 +G01 X1.4979 Y0.7675 +G01 X1.4905 Y0.7496 +G01 X1.4905 Y0.7304 +G01 X1.4979 Y0.7125 +G01 X1.5115 Y0.6989 +G01 X1.5294 Y0.6915 +G00 Z0.1000 +G00 X1.5294 Y0.5915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.5915 F20 +G01 X1.6285 Y0.5989 +G01 X1.6421 Y0.6125 +G01 X1.6495 Y0.6304 +G01 X1.6495 Y0.6496 +G01 X1.6421 Y0.6675 +G01 X1.6285 Y0.6811 +G01 X1.6106 Y0.6885 +G01 X1.5294 Y0.6885 +G01 X1.5115 Y0.6811 +G01 X1.4979 Y0.6675 +G01 X1.4905 Y0.6496 +G01 X1.4905 Y0.6304 +G01 X1.4979 Y0.6125 +G01 X1.5115 Y0.5989 +G01 X1.5294 Y0.5915 +G00 Z0.1000 +G00 X1.5294 Y0.4915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.4915 F20 +G01 X1.6285 Y0.4989 +G01 X1.6421 Y0.5125 +G01 X1.6495 Y0.5304 +G01 X1.6495 Y0.5496 +G01 X1.6421 Y0.5675 +G01 X1.6285 Y0.5811 +G01 X1.6106 Y0.5885 +G01 X1.5294 Y0.5885 +G01 X1.5115 Y0.5811 +G01 X1.4979 Y0.5675 +G01 X1.4905 Y0.5496 +G01 X1.4905 Y0.5304 +G01 X1.4979 Y0.5125 +G01 X1.5115 Y0.4989 +G01 X1.5294 Y0.4915 +G00 Z0.1000 +G00 X1.5294 Y0.3915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.3915 F20 +G01 X1.6285 Y0.3989 +G01 X1.6421 Y0.4125 +G01 X1.6495 Y0.4304 +G01 X1.6495 Y0.4496 +G01 X1.6421 Y0.4675 +G01 X1.6285 Y0.4811 +G01 X1.6106 Y0.4885 +G01 X1.5294 Y0.4885 +G01 X1.5115 Y0.4811 +G01 X1.4979 Y0.4675 +G01 X1.4905 Y0.4496 +G01 X1.4905 Y0.4304 +G01 X1.4979 Y0.4125 +G01 X1.5115 Y0.3989 +G01 X1.5294 Y0.3915 +G00 Z0.1000 +G00 X1.5294 Y0.2915 +G01 Z-0.0070 F10 +G01 X1.6106 Y0.2915 F20 +G01 X1.6285 Y0.2989 +G01 X1.6421 Y0.3125 +G01 X1.6495 Y0.3304 +G01 X1.6495 Y0.3496 +G01 X1.6421 Y0.3675 +G01 X1.6285 Y0.3811 +G01 X1.6106 Y0.3885 +G01 X1.5294 Y0.3885 +G01 X1.5115 Y0.3811 +G01 X1.4979 Y0.3675 +G01 X1.4905 Y0.3496 +G01 X1.4905 Y0.3304 +G01 X1.4979 Y0.3125 +G01 X1.5115 Y0.2989 +G01 X1.5294 Y0.2915 +G00 Z0.1000 +G00 X0.8140 Y0.7479 +G01 Z-0.0070 F10 +G01 X0.8318 Y0.7406 F20 +G01 X0.8511 Y0.7406 +G01 X0.8690 Y0.7479 +G01 X0.8809 Y0.7598 +G01 X0.8928 Y0.7479 +G01 X0.9106 Y0.7406 +G01 X0.9299 Y0.7406 +G01 X0.9477 Y0.7479 +G01 X0.9614 Y0.7616 +G01 X0.9687 Y0.7794 +G01 X0.9687 Y0.8607 +G01 X0.9614 Y0.8785 +G01 X0.9477 Y0.8922 +G01 X0.9299 Y0.8996 +G01 X0.9106 Y0.8996 +G01 X0.8928 Y0.8922 +G01 X0.8809 Y0.8803 +G01 X0.8690 Y0.8922 +G01 X0.8511 Y0.8996 +G01 X0.8318 Y0.8996 +G01 X0.8140 Y0.8922 +G01 X0.8021 Y0.8803 +G01 X0.7902 Y0.8922 +G01 X0.7724 Y0.8996 +G01 X0.7531 Y0.8996 +G01 X0.7353 Y0.8922 +G01 X0.7216 Y0.8785 +G01 X0.7143 Y0.8607 +G01 X0.7143 Y0.7794 +G01 X0.7216 Y0.7616 +G01 X0.7353 Y0.7479 +G01 X0.7531 Y0.7406 +G01 X0.7724 Y0.7406 +G01 X0.7902 Y0.7479 +G01 X0.8021 Y0.7598 +G01 X0.8140 Y0.7479 +G00 Z0.1000 +G00 X0.8296 Y0.7121 +G01 Z-0.0070 F10 +G01 X0.8118 Y0.7194 F20 +G01 X0.7925 Y0.7194 +G01 X0.7746 Y0.7121 +G01 X0.7628 Y0.7002 +G01 X0.7509 Y0.7121 +G01 X0.7330 Y0.7194 +G01 X0.7137 Y0.7194 +G01 X0.6959 Y0.7121 +G01 X0.6823 Y0.6984 +G01 X0.6749 Y0.6806 +G01 X0.6749 Y0.5993 +G01 X0.6823 Y0.5815 +G01 X0.6959 Y0.5678 +G01 X0.7137 Y0.5604 +G01 X0.7330 Y0.5604 +G01 X0.7509 Y0.5678 +G01 X0.7628 Y0.5797 +G01 X0.7746 Y0.5678 +G01 X0.7925 Y0.5604 +G01 X0.8118 Y0.5604 +G01 X0.8296 Y0.5678 +G01 X0.8415 Y0.5797 +G01 X0.8534 Y0.5678 +G01 X0.8712 Y0.5604 +G01 X0.8905 Y0.5604 +G01 X0.9083 Y0.5678 +G01 X0.9220 Y0.5815 +G01 X0.9294 Y0.5993 +G01 X0.9294 Y0.6806 +G01 X0.9220 Y0.6984 +G01 X0.9083 Y0.7121 +G01 X0.8905 Y0.7194 +G01 X0.8712 Y0.7194 +G01 X0.8534 Y0.7121 +G01 X0.8415 Y0.7002 +G01 X0.8296 Y0.7121 +G00 Z0.1000 +G00 X0.8406 Y0.4185 +G01 Z-0.0070 F10 +G01 X0.7594 Y0.4185 F20 +G01 X0.7415 Y0.4111 +G01 X0.7279 Y0.3975 +G01 X0.7205 Y0.3796 +G01 X0.7205 Y0.3604 +G01 X0.7279 Y0.3425 +G01 X0.7415 Y0.3289 +G01 X0.7594 Y0.3215 +G01 X0.8406 Y0.3215 +G01 X0.8585 Y0.3289 +G01 X0.8721 Y0.3425 +G01 X0.8795 Y0.3604 +G01 X0.8795 Y0.3796 +G01 X0.8721 Y0.3975 +G01 X0.8585 Y0.4111 +G01 X0.8406 Y0.4185 +G00 Z0.1000 +G00 X1.1406 Y0.3185 +G01 Z-0.0070 F10 +G01 X1.0594 Y0.3185 F20 +G01 X1.0415 Y0.3111 +G01 X1.0279 Y0.2975 +G01 X1.0205 Y0.2796 +G01 X1.0205 Y0.2604 +G01 X1.0279 Y0.2425 +G01 X1.0415 Y0.2289 +G01 X1.0594 Y0.2215 +G01 X1.1406 Y0.2215 +G01 X1.1585 Y0.2289 +G01 X1.1721 Y0.2425 +G01 X1.1795 Y0.2604 +G01 X1.1795 Y0.2796 +G01 X1.1721 Y0.2975 +G01 X1.1585 Y0.3111 +G01 X1.1406 Y0.3185 +G00 Z0.1000 +G00 X0.6406 Y0.3185 +G01 Z-0.0070 F10 +G01 X0.5594 Y0.3185 F20 +G01 X0.5415 Y0.3111 +G01 X0.5279 Y0.2975 +G01 X0.5205 Y0.2796 +G01 X0.5205 Y0.2604 +G01 X0.5279 Y0.2425 +G01 X0.5415 Y0.2289 +G01 X0.5594 Y0.2215 +G01 X0.6406 Y0.2215 +G01 X0.6585 Y0.2289 +G01 X0.6721 Y0.2425 +G01 X0.6795 Y0.2604 +G01 X0.6795 Y0.2796 +G01 X0.6721 Y0.2975 +G01 X0.6585 Y0.3111 +G01 X0.6406 Y0.3185 +G00 Z0.1000 +G00 X2.1094 Y0.1015 +G01 Z-0.0070 F10 +G01 X2.1906 Y0.1015 F20 +G01 X2.2085 Y0.1089 +G01 X2.2221 Y0.1225 +G01 X2.2295 Y0.1404 +G01 X2.2295 Y0.1596 +G01 X2.2221 Y0.1775 +G01 X2.2085 Y0.1911 +G01 X2.1906 Y0.1985 +G01 X2.1094 Y0.1985 +G01 X2.0915 Y0.1911 +G01 X2.0779 Y0.1775 +G01 X2.0705 Y0.1596 +G01 X2.0705 Y0.1404 +G01 X2.0779 Y0.1225 +G01 X2.0915 Y0.1089 +G01 X2.1094 Y0.1015 +G00 Z0.1000 +G00 X2.1094 Y0.2015 +G01 Z-0.0070 F10 +G01 X2.1906 Y0.2015 F20 +G01 X2.2085 Y0.2089 +G01 X2.2221 Y0.2225 +G01 X2.2295 Y0.2404 +G01 X2.2295 Y0.2596 +G01 X2.2221 Y0.2775 +G01 X2.2085 Y0.2911 +G01 X2.1906 Y0.2985 +G01 X2.1094 Y0.2985 +G01 X2.0915 Y0.2911 +G01 X2.0779 Y0.2775 +G01 X2.0705 Y0.2596 +G01 X2.0705 Y0.2404 +G01 X2.0779 Y0.2225 +G01 X2.0915 Y0.2089 +G01 X2.1094 Y0.2015 +G00 Z0.1000 +G00 X2.1094 Y0.3015 +G01 Z-0.0070 F10 +G01 X2.1906 Y0.3015 F20 +G01 X2.2085 Y0.3089 +G01 X2.2221 Y0.3225 +G01 X2.2295 Y0.3404 +G01 X2.2295 Y0.3596 +G01 X2.2221 Y0.3775 +G01 X2.2085 Y0.3911 +G01 X2.1906 Y0.3985 +G01 X2.1094 Y0.3985 +G01 X2.0915 Y0.3911 +G01 X2.0779 Y0.3775 +G01 X2.0705 Y0.3596 +G01 X2.0705 Y0.3404 +G01 X2.0779 Y0.3225 +G01 X2.0915 Y0.3089 +G01 X2.1094 Y0.3015 +G00 Z0.1000 +G00 X1.8094 Y0.3015 +G01 Z-0.0070 F10 +G01 X1.8906 Y0.3015 F20 +G01 X1.9085 Y0.3089 +G01 X1.9221 Y0.3225 +G01 X1.9295 Y0.3404 +G01 X1.9295 Y0.3596 +G01 X1.9221 Y0.3775 +G01 X1.9085 Y0.3911 +G01 X1.8906 Y0.3985 +G01 X1.8094 Y0.3985 +G01 X1.7915 Y0.3911 +G01 X1.7779 Y0.3775 +G01 X1.7705 Y0.3596 +G01 X1.7705 Y0.3404 +G01 X1.7779 Y0.3225 +G01 X1.7915 Y0.3089 +G01 X1.8094 Y0.3015 +G00 Z0.1000 +G00 X1.8094 Y0.2015 +G01 Z-0.0070 F10 +G01 X1.8906 Y0.2015 F20 +G01 X1.9085 Y0.2089 +G01 X1.9221 Y0.2225 +G01 X1.9295 Y0.2404 +G01 X1.9295 Y0.2596 +G01 X1.9221 Y0.2775 +G01 X1.9085 Y0.2911 +G01 X1.8906 Y0.2985 +G01 X1.8094 Y0.2985 +G01 X1.7915 Y0.2911 +G01 X1.7779 Y0.2775 +G01 X1.7705 Y0.2596 +G01 X1.7705 Y0.2404 +G01 X1.7779 Y0.2225 +G01 X1.7915 Y0.2089 +G01 X1.8094 Y0.2015 +G00 Z0.1000 +G00 X1.8094 Y0.1015 +G01 Z-0.0070 F10 +G01 X1.8906 Y0.1015 F20 +G01 X1.9085 Y0.1089 +G01 X1.9221 Y0.1225 +G01 X1.9295 Y0.1404 +G01 X1.9295 Y0.1596 +G01 X1.9221 Y0.1775 +G01 X1.9085 Y0.1911 +G01 X1.8906 Y0.1985 +G01 X1.8094 Y0.1985 +G01 X1.7915 Y0.1911 +G01 X1.7779 Y0.1775 +G01 X1.7705 Y0.1596 +G01 X1.7705 Y0.1404 +G01 X1.7779 Y0.1225 +G01 X1.7915 Y0.1089 +G01 X1.8094 Y0.1015 +G00 Z0.1000 +G00 X1.8485 Y0.6599 +G01 Z-0.0070 F10 +G01 X1.8485 Y0.7001 F20 +G01 X1.8201 Y0.7285 +G01 X1.7799 Y0.7285 +G01 X1.7515 Y0.7001 +G01 X1.7515 Y0.6599 +G01 X1.7799 Y0.6315 +G01 X1.8201 Y0.6315 +G01 X1.8485 Y0.6599 +G00 Z0.1000 +G00 X1.8485 Y0.4599 +G01 Z-0.0070 F10 +G01 X1.8485 Y0.5001 F20 +G01 X1.8201 Y0.5285 +G01 X1.7799 Y0.5285 +G01 X1.7515 Y0.5001 +G01 X1.7515 Y0.4599 +G01 X1.7799 Y0.4315 +G01 X1.8201 Y0.4315 +G01 X1.8485 Y0.4599 +G00 Z0.1000 +G00 X1.9685 Y0.6599 +G01 Z-0.0070 F10 +G01 X1.9685 Y0.7001 F20 +G01 X1.9401 Y0.7285 +G01 X1.8999 Y0.7285 +G01 X1.8715 Y0.7001 +G01 X1.8715 Y0.6599 +G01 X1.8999 Y0.6315 +G01 X1.9401 Y0.6315 +G01 X1.9685 Y0.6599 +G00 Z0.1000 +G00 X1.9685 Y0.4599 +G01 Z-0.0070 F10 +G01 X1.9685 Y0.5001 F20 +G01 X1.9401 Y0.5285 +G01 X1.8999 Y0.5285 +G01 X1.8715 Y0.5001 +G01 X1.8715 Y0.4599 +G01 X1.8999 Y0.4315 +G01 X1.9401 Y0.4315 +G01 X1.9685 Y0.4599 +G00 Z0.1000 +G00 X2.0885 Y0.6599 +G01 Z-0.0070 F10 +G01 X2.0885 Y0.7001 F20 +G01 X2.0601 Y0.7285 +G01 X2.0199 Y0.7285 +G01 X1.9915 Y0.7001 +G01 X1.9915 Y0.6599 +G01 X2.0199 Y0.6315 +G01 X2.0601 Y0.6315 +G01 X2.0885 Y0.6599 +G00 Z0.1000 +G00 X2.0885 Y0.4599 +G01 Z-0.0070 F10 +G01 X2.0885 Y0.5001 F20 +G01 X2.0601 Y0.5285 +G01 X2.0199 Y0.5285 +G01 X1.9915 Y0.5001 +G01 X1.9915 Y0.4599 +G01 X2.0199 Y0.4315 +G01 X2.0601 Y0.4315 +G01 X2.0885 Y0.4599 +G00 Z0.1000 +G00 X1.3185 Y0.2099 +G01 Z-0.0070 F10 +G01 X1.3185 Y0.2501 F20 +G01 X1.2901 Y0.2785 +G01 X1.2499 Y0.2785 +G01 X1.2215 Y0.2501 +G01 X1.2215 Y0.2099 +G01 X1.2499 Y0.1815 +G01 X1.2901 Y0.1815 +G01 X1.3185 Y0.2099 +G00 Z0.1000 +G00 X1.4185 Y0.2099 +G01 Z-0.0070 F10 +G01 X1.4185 Y0.2501 F20 +G01 X1.3901 Y0.2785 +G01 X1.3499 Y0.2785 +G01 X1.3215 Y0.2501 +G01 X1.3215 Y0.2099 +G01 X1.3499 Y0.1815 +G01 X1.3901 Y0.1815 +G01 X1.4185 Y0.2099 +G00 Z0.1000 +G00 X2.3675 Y1.0020 +G01 Z-0.0070 F10 +G01 X2.3675 Y1.0580 F20 +G01 X2.3280 Y1.0975 +G01 X2.2720 Y1.0975 +G01 X2.2325 Y1.0580 +G01 X2.2325 Y1.0020 +G01 X2.2720 Y0.9625 +G01 X2.3280 Y0.9625 +G01 X2.3675 Y1.0020 +G00 Z0.1000 +G00 X2.0675 Y1.0020 +G01 Z-0.0070 F10 +G01 X2.0675 Y1.0580 F20 +G01 X2.0280 Y1.0975 +G01 X1.9720 Y1.0975 +G01 X1.9325 Y1.0580 +G01 X1.9325 Y1.0020 +G01 X1.9720 Y0.9625 +G01 X2.0280 Y0.9625 +G01 X2.0675 Y1.0020 +G00 Z0.1000 +G00 X0.5585 Y0.9799 +G01 Z-0.0070 F10 +G01 X0.5585 Y1.0201 F20 +G01 X0.5301 Y1.0485 +G01 X0.4899 Y1.0485 +G01 X0.4615 Y1.0201 +G01 X0.4615 Y0.9799 +G01 X0.4899 Y0.9515 +G01 X0.5301 Y0.9515 +G01 X0.5585 Y0.9799 +G00 Z0.1000 +G00 X0.4585 Y0.9799 +G01 Z-0.0070 F10 +G01 X0.4585 Y1.0201 F20 +G01 X0.4301 Y1.0485 +G01 X0.3899 Y1.0485 +G01 X0.3615 Y1.0201 +G01 X0.3615 Y0.9799 +G01 X0.3899 Y0.9515 +G01 X0.4301 Y0.9515 +G01 X0.4585 Y0.9799 +G00 Z0.1000 +G00 X1.4385 Y1.1499 +G01 Z-0.0070 F10 +G01 X1.4385 Y1.1901 F20 +G01 X1.4321 Y1.1965 +G01 X1.4479 Y1.1965 +G01 X1.4415 Y1.1901 +G01 X1.4415 Y1.1499 +G01 X1.4699 Y1.1215 +G01 X1.5101 Y1.1215 +G01 X1.5385 Y1.1499 +G01 X1.5385 Y1.1901 +G01 X1.5101 Y1.2185 +G01 X1.4821 Y1.2185 +G01 X1.4885 Y1.2249 +G01 X1.4885 Y1.2651 +G01 X1.4601 Y1.2935 +G01 X1.4199 Y1.2935 +G01 X1.3915 Y1.2651 +G01 X1.3915 Y1.2249 +G01 X1.3979 Y1.2185 +G01 X1.3699 Y1.2185 +G01 X1.3415 Y1.1901 +G01 X1.3415 Y1.1499 +G01 X1.3699 Y1.1215 +G01 X1.4101 Y1.1215 +G01 X1.4385 Y1.1499 +G00 Z0.1000 +G00 X1.1643 Y1.2313 +G01 Z-0.0070 F10 +G01 X1.1420 Y1.2405 F20 +G01 X1.1180 Y1.2405 +G01 X1.0957 Y1.2313 +G01 X1.0787 Y1.2143 +G01 X1.0695 Y1.1920 +G01 X1.0695 Y1.1680 +G01 X1.0787 Y1.1457 +G01 X1.0957 Y1.1287 +G01 X1.1180 Y1.1195 +G01 X1.1420 Y1.1195 +G01 X1.1643 Y1.1287 +G01 X1.1800 Y1.1444 +G01 X1.2049 Y1.1195 +G01 X1.2551 Y1.1195 +G01 X1.2905 Y1.1549 +G01 X1.2905 Y1.2051 +G01 X1.2551 Y1.2405 +G01 X1.2049 Y1.2405 +G01 X1.1800 Y1.2156 +G01 X1.1643 Y1.2313 +G00 Z0.1000 +G00 X0.2400 Y0.9687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.9500 F20 +G01 X0.2400 Y0.9313 +G01 X0.2213 Y0.9500 +G01 X0.2400 Y0.9687 +G00 Z0.1000 +G00 X0.2400 Y0.7687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.7500 F20 +G01 X0.2400 Y0.7313 +G01 X0.2213 Y0.7500 +G01 X0.2400 Y0.7687 +G00 Z0.1000 +G00 X0.2400 Y0.5687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.5500 F20 +G01 X0.2400 Y0.5313 +G01 X0.2213 Y0.5500 +G01 X0.2400 Y0.5687 +G00 Z0.1000 +G00 X0.2400 Y0.4687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.4500 F20 +G01 X0.2400 Y0.4313 +G01 X0.2213 Y0.4500 +G01 X0.2400 Y0.4687 +G00 Z0.1000 +G00 X0.2400 Y0.6687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.6500 F20 +G01 X0.2400 Y0.6313 +G01 X0.2213 Y0.6500 +G01 X0.2400 Y0.6687 +G00 Z0.1000 +G00 X0.2400 Y0.8687 +G01 Z-0.0070 F10 +G01 X0.2587 Y0.8500 F20 +G01 X0.2400 Y0.8313 +G01 X0.2213 Y0.8500 +G01 X0.2400 Y0.8687 +G00 Z0.1000 +G00 X1.8155 Y1.2070 +G01 Z-0.0070 F10 +G01 X1.8155 Y1.2330 F20 +G01 X1.8055 Y1.2571 +G01 X1.7871 Y1.2755 +G01 X1.7630 Y1.2855 +G01 X1.7370 Y1.2855 +G01 X1.7129 Y1.2755 +G01 X1.6945 Y1.2571 +G01 X1.6845 Y1.2330 +G01 X1.6845 Y1.2070 +G01 X1.6945 Y1.1829 +G01 X1.7074 Y1.1700 +G01 X1.6845 Y1.1471 +G01 X1.6845 Y1.0929 +G01 X1.7229 Y1.0545 +G01 X1.7771 Y1.0545 +G01 X1.8155 Y1.0929 +G01 X1.8155 Y1.1471 +G01 X1.7926 Y1.1700 +G01 X1.8055 Y1.1829 +G01 X1.8155 Y1.2070 +G00 Z0.1000 +G00 X0.5635 Y0.9778 +G01 Z-0.0070 F10 +G01 X0.5635 Y1.0222 F20 +G01 X0.5322 Y1.0535 +G01 X0.4878 Y1.0535 +G01 X0.4600 Y1.0257 +G01 X0.4322 Y1.0535 +G01 X0.3878 Y1.0535 +G01 X0.3565 Y1.0222 +G01 X0.3565 Y0.9778 +G01 X0.3878 Y0.9465 +G01 X0.4322 Y0.9465 +G01 X0.4600 Y0.9743 +G01 X0.4878 Y0.9465 +G01 X0.5322 Y0.9465 +G01 X0.5635 Y0.9778 +G00 Z0.1000 +G00 X2.0725 Y1.0000 +G01 Z-0.0070 F10 +G01 X2.0725 Y1.0600 F20 +G01 X2.0300 Y1.1025 +G01 X1.9700 Y1.1025 +G01 X1.9275 Y1.0600 +G01 X1.9275 Y1.0000 +G01 X1.9700 Y0.9575 +G01 X2.0300 Y0.9575 +G01 X2.0725 Y1.0000 +G00 Z0.1000 +G00 X2.3725 Y1.0000 +G01 Z-0.0070 F10 +G01 X2.3725 Y1.0600 F20 +G01 X2.3300 Y1.1025 +G01 X2.2700 Y1.1025 +G01 X2.2275 Y1.0600 +G01 X2.2275 Y1.0000 +G01 X2.2700 Y0.9575 +G01 X2.3300 Y0.9575 +G01 X2.3725 Y1.0000 +G00 Z0.1000 +G00 X0.3475 Y0.9762 +G01 Z-0.0070 F10 +G01 X0.3475 Y1.0238 F20 +G01 X0.3138 Y1.0575 +G01 X0.2662 Y1.0575 +G01 X0.2400 Y1.0313 +G01 X0.2138 Y1.0575 +G01 X0.1662 Y1.0575 +G01 X0.1325 Y1.0238 +G01 X0.1325 Y0.9762 +G01 X0.1587 Y0.9500 +G01 X0.1325 Y0.9238 +G01 X0.1325 Y0.8762 +G01 X0.1587 Y0.8500 +G01 X0.1325 Y0.8238 +G01 X0.1325 Y0.7762 +G01 X0.1587 Y0.7500 +G01 X0.1325 Y0.7238 +G01 X0.1325 Y0.6762 +G01 X0.1587 Y0.6500 +G01 X0.1325 Y0.6238 +G01 X0.1325 Y0.5762 +G01 X0.1587 Y0.5500 +G01 X0.1325 Y0.5238 +G01 X0.1325 Y0.4762 +G01 X0.1587 Y0.4500 +G01 X0.1325 Y0.4238 +G01 X0.1325 Y0.3762 +G01 X0.1662 Y0.3425 +G01 X0.2138 Y0.3425 +G01 X0.2400 Y0.3687 +G01 X0.2662 Y0.3425 +G01 X0.3138 Y0.3425 +G01 X0.3475 Y0.3762 +G01 X0.3475 Y0.4238 +G01 X0.3213 Y0.4500 +G01 X0.3475 Y0.4762 +G01 X0.3475 Y0.5238 +G01 X0.3213 Y0.5500 +G01 X0.3475 Y0.5762 +G01 X0.3475 Y0.6238 +G01 X0.3213 Y0.6500 +G01 X0.3475 Y0.6762 +G01 X0.3475 Y0.7238 +G01 X0.3213 Y0.7500 +G01 X0.3475 Y0.7762 +G01 X0.3475 Y0.8238 +G01 X0.3213 Y0.8500 +G01 X0.3475 Y0.8762 +G01 X0.3475 Y0.9238 +G01 X0.3213 Y0.9500 +G01 X0.3475 Y0.9762 +G00 Z0.1000 +G00 X1.5284 Y0.2865 +G01 Z-0.0070 F10 +G01 X1.6116 Y0.2865 F20 +G01 X1.6313 Y0.2946 +G01 X1.6464 Y0.3097 +G01 X1.6545 Y0.3294 +G01 X1.6545 Y0.3506 +G01 X1.6464 Y0.3703 +G01 X1.6313 Y0.3854 +G01 X1.6201 Y0.3900 +G01 X1.6313 Y0.3946 +G01 X1.6464 Y0.4097 +G01 X1.6545 Y0.4294 +G01 X1.6545 Y0.4506 +G01 X1.6464 Y0.4703 +G01 X1.6313 Y0.4854 +G01 X1.6201 Y0.4900 +G01 X1.6313 Y0.4946 +G01 X1.6464 Y0.5097 +G01 X1.6545 Y0.5294 +G01 X1.6545 Y0.5506 +G01 X1.6464 Y0.5703 +G01 X1.6313 Y0.5854 +G01 X1.6201 Y0.5900 +G01 X1.6313 Y0.5946 +G01 X1.6464 Y0.6097 +G01 X1.6545 Y0.6294 +G01 X1.6545 Y0.6506 +G01 X1.6464 Y0.6703 +G01 X1.6313 Y0.6854 +G01 X1.6201 Y0.6900 +G01 X1.6313 Y0.6946 +G01 X1.6464 Y0.7097 +G01 X1.6545 Y0.7294 +G01 X1.6545 Y0.7506 +G01 X1.6464 Y0.7703 +G01 X1.6313 Y0.7854 +G01 X1.6201 Y0.7900 +G01 X1.6313 Y0.7946 +G01 X1.6464 Y0.8097 +G01 X1.6545 Y0.8294 +G01 X1.6545 Y0.8506 +G01 X1.6464 Y0.8703 +G01 X1.6313 Y0.8854 +G01 X1.6201 Y0.8900 +G01 X1.6313 Y0.8946 +G01 X1.6464 Y0.9097 +G01 X1.6545 Y0.9294 +G01 X1.6545 Y0.9506 +G01 X1.6464 Y0.9703 +G01 X1.6313 Y0.9854 +G01 X1.6201 Y0.9900 +G01 X1.6313 Y0.9946 +G01 X1.6464 Y1.0097 +G01 X1.6545 Y1.0294 +G01 X1.6545 Y1.0506 +G01 X1.6464 Y1.0703 +G01 X1.6313 Y1.0854 +G01 X1.6116 Y1.0935 +G01 X1.5284 Y1.0935 +G01 X1.5087 Y1.0854 +G01 X1.4936 Y1.0703 +G01 X1.4855 Y1.0506 +G01 X1.4855 Y1.0294 +G01 X1.4936 Y1.0097 +G01 X1.5087 Y0.9946 +G01 X1.5199 Y0.9900 +G01 X1.5087 Y0.9854 +G01 X1.4936 Y0.9703 +G01 X1.4855 Y0.9506 +G01 X1.4855 Y0.9294 +G01 X1.4936 Y0.9097 +G01 X1.5087 Y0.8946 +G01 X1.5199 Y0.8900 +G01 X1.5087 Y0.8854 +G01 X1.4936 Y0.8703 +G01 X1.4855 Y0.8506 +G01 X1.4855 Y0.8294 +G01 X1.4936 Y0.8097 +G01 X1.5087 Y0.7946 +G01 X1.5199 Y0.7900 +G01 X1.5087 Y0.7854 +G01 X1.4936 Y0.7703 +G01 X1.4855 Y0.7506 +G01 X1.4855 Y0.7294 +G01 X1.4936 Y0.7097 +G01 X1.5087 Y0.6946 +G01 X1.5199 Y0.6900 +G01 X1.5087 Y0.6854 +G01 X1.4936 Y0.6703 +G01 X1.4855 Y0.6506 +G01 X1.4855 Y0.6294 +G01 X1.4936 Y0.6097 +G01 X1.5087 Y0.5946 +G01 X1.5199 Y0.5900 +G01 X1.5087 Y0.5854 +G01 X1.4936 Y0.5703 +G01 X1.4855 Y0.5506 +G01 X1.4855 Y0.5294 +G01 X1.4936 Y0.5097 +G01 X1.5087 Y0.4946 +G01 X1.5199 Y0.4900 +G01 X1.5087 Y0.4854 +G01 X1.4936 Y0.4703 +G01 X1.4855 Y0.4506 +G01 X1.4855 Y0.4294 +G01 X1.4936 Y0.4097 +G01 X1.5087 Y0.3946 +G01 X1.5199 Y0.3900 +G01 X1.5087 Y0.3854 +G01 X1.4936 Y0.3703 +G01 X1.4855 Y0.3506 +G01 X1.4855 Y0.3294 +G01 X1.4936 Y0.3097 +G01 X1.5087 Y0.2946 +G01 X1.5284 Y0.2865 +G00 Z0.1000 +G00 X0.8112 Y0.7437 +G01 Z-0.0070 F10 +G01 X0.8309 Y0.7356 F20 +G01 X0.8521 Y0.7356 +G01 X0.8718 Y0.7437 +G01 X0.8809 Y0.7528 +G01 X0.8899 Y0.7437 +G01 X0.9096 Y0.7356 +G01 X0.9309 Y0.7356 +G01 X0.9505 Y0.7437 +G01 X0.9656 Y0.7587 +G01 X0.9737 Y0.7784 +G01 X0.9737 Y0.8617 +G01 X0.9656 Y0.8814 +G01 X0.9505 Y0.8964 +G01 X0.9309 Y0.9046 +G01 X0.9096 Y0.9046 +G01 X0.8899 Y0.8964 +G01 X0.8809 Y0.8873 +G01 X0.8718 Y0.8964 +G01 X0.8521 Y0.9046 +G01 X0.8309 Y0.9046 +G01 X0.8112 Y0.8964 +G01 X0.8021 Y0.8873 +G01 X0.7931 Y0.8964 +G01 X0.7734 Y0.9046 +G01 X0.7521 Y0.9046 +G01 X0.7324 Y0.8964 +G01 X0.7174 Y0.8814 +G01 X0.7093 Y0.8617 +G01 X0.7093 Y0.7784 +G01 X0.7174 Y0.7587 +G01 X0.7324 Y0.7437 +G01 X0.7521 Y0.7356 +G01 X0.7734 Y0.7356 +G01 X0.7931 Y0.7437 +G01 X0.8021 Y0.7528 +G01 X0.8112 Y0.7437 +G00 Z0.1000 +G00 X0.8324 Y0.7163 +G01 Z-0.0070 F10 +G01 X0.8128 Y0.7244 F20 +G01 X0.7915 Y0.7244 +G01 X0.7718 Y0.7163 +G01 X0.7628 Y0.7072 +G01 X0.7537 Y0.7163 +G01 X0.7340 Y0.7244 +G01 X0.7127 Y0.7244 +G01 X0.6931 Y0.7163 +G01 X0.6780 Y0.7012 +G01 X0.6699 Y0.6816 +G01 X0.6699 Y0.5983 +G01 X0.6780 Y0.5786 +G01 X0.6931 Y0.5636 +G01 X0.7127 Y0.5554 +G01 X0.7340 Y0.5554 +G01 X0.7537 Y0.5636 +G01 X0.7628 Y0.5727 +G01 X0.7718 Y0.5636 +G01 X0.7915 Y0.5554 +G01 X0.8128 Y0.5554 +G01 X0.8324 Y0.5636 +G01 X0.8415 Y0.5727 +G01 X0.8506 Y0.5636 +G01 X0.8702 Y0.5554 +G01 X0.8915 Y0.5554 +G01 X0.9112 Y0.5636 +G01 X0.9262 Y0.5786 +G01 X0.9344 Y0.5983 +G01 X0.9344 Y0.6816 +G01 X0.9262 Y0.7012 +G01 X0.9112 Y0.7163 +G01 X0.8915 Y0.7244 +G01 X0.8702 Y0.7244 +G01 X0.8506 Y0.7163 +G01 X0.8415 Y0.7072 +G01 X0.8324 Y0.7163 +G00 Z0.1000 +G00 X1.3313 Y0.9946 +G01 Z-0.0070 F10 +G01 X1.3464 Y1.0097 F20 +G01 X1.3545 Y1.0294 +G01 X1.3545 Y1.0506 +G01 X1.3464 Y1.0703 +G01 X1.3313 Y1.0854 +G01 X1.3116 Y1.0935 +G01 X1.2284 Y1.0935 +G01 X1.2087 Y1.0854 +G01 X1.1936 Y1.0703 +G01 X1.1855 Y1.0506 +G01 X1.1855 Y1.0294 +G01 X1.1936 Y1.0097 +G01 X1.2087 Y0.9946 +G01 X1.2199 Y0.9900 +G01 X1.2087 Y0.9854 +G01 X1.1936 Y0.9703 +G01 X1.1855 Y0.9506 +G01 X1.1855 Y0.9294 +G01 X1.1936 Y0.9097 +G01 X1.2087 Y0.8946 +G01 X1.2199 Y0.8900 +G01 X1.2087 Y0.8854 +G01 X1.1936 Y0.8703 +G01 X1.1855 Y0.8506 +G01 X1.1855 Y0.8294 +G01 X1.1936 Y0.8097 +G01 X1.2087 Y0.7946 +G01 X1.2199 Y0.7900 +G01 X1.2087 Y0.7854 +G01 X1.1936 Y0.7703 +G01 X1.1855 Y0.7506 +G01 X1.1855 Y0.7294 +G01 X1.1936 Y0.7097 +G01 X1.2087 Y0.6946 +G01 X1.2199 Y0.6900 +G01 X1.2087 Y0.6854 +G01 X1.1936 Y0.6703 +G01 X1.1855 Y0.6506 +G01 X1.1855 Y0.6294 +G01 X1.1936 Y0.6097 +G01 X1.2087 Y0.5946 +G01 X1.2199 Y0.5900 +G01 X1.2087 Y0.5854 +G01 X1.1936 Y0.5703 +G01 X1.1855 Y0.5506 +G01 X1.1855 Y0.5294 +G01 X1.1936 Y0.5097 +G01 X1.2087 Y0.4946 +G01 X1.2199 Y0.4900 +G01 X1.2087 Y0.4854 +G01 X1.1936 Y0.4703 +G01 X1.1855 Y0.4506 +G01 X1.1855 Y0.4294 +G01 X1.1936 Y0.4097 +G01 X1.2087 Y0.3946 +G01 X1.2199 Y0.3900 +G01 X1.2087 Y0.3854 +G01 X1.1936 Y0.3703 +G01 X1.1855 Y0.3506 +G01 X1.1855 Y0.3294 +G01 X1.1936 Y0.3097 +G01 X1.2087 Y0.2946 +G01 X1.2284 Y0.2865 +G01 X1.3116 Y0.2865 +G01 X1.3313 Y0.2946 +G01 X1.3464 Y0.3097 +G01 X1.3545 Y0.3294 +G01 X1.3545 Y0.3506 +G01 X1.3464 Y0.3703 +G01 X1.3313 Y0.3854 +G01 X1.3201 Y0.3900 +G01 X1.3313 Y0.3946 +G01 X1.3464 Y0.4097 +G01 X1.3545 Y0.4294 +G01 X1.3545 Y0.4506 +G01 X1.3464 Y0.4703 +G01 X1.3313 Y0.4854 +G01 X1.3201 Y0.4900 +G01 X1.3313 Y0.4946 +G01 X1.3464 Y0.5097 +G01 X1.3545 Y0.5294 +G01 X1.3545 Y0.5506 +G01 X1.3464 Y0.5703 +G01 X1.3313 Y0.5854 +G01 X1.3201 Y0.5900 +G01 X1.3313 Y0.5946 +G01 X1.3464 Y0.6097 +G01 X1.3545 Y0.6294 +G01 X1.3545 Y0.6506 +G01 X1.3464 Y0.6703 +G01 X1.3313 Y0.6854 +G01 X1.3201 Y0.6900 +G01 X1.3313 Y0.6946 +G01 X1.3464 Y0.7097 +G01 X1.3545 Y0.7294 +G01 X1.3545 Y0.7506 +G01 X1.3464 Y0.7703 +G01 X1.3313 Y0.7854 +G01 X1.3201 Y0.7900 +G01 X1.3313 Y0.7946 +G01 X1.3464 Y0.8097 +G01 X1.3545 Y0.8294 +G01 X1.3545 Y0.8506 +G01 X1.3464 Y0.8703 +G01 X1.3313 Y0.8854 +G01 X1.3201 Y0.8900 +G01 X1.3313 Y0.8946 +G01 X1.3464 Y0.9097 +G01 X1.3545 Y0.9294 +G01 X1.3545 Y0.9506 +G01 X1.3464 Y0.9703 +G01 X1.3313 Y0.9854 +G01 X1.3201 Y0.9900 +G01 X1.3313 Y0.9946 +G00 Z0.1000 +G00 X0.8416 Y0.4235 +G01 Z-0.0070 F10 +G01 X0.7584 Y0.4235 F20 +G01 X0.7387 Y0.4154 +G01 X0.7236 Y0.4003 +G01 X0.7155 Y0.3806 +G01 X0.7155 Y0.3594 +G01 X0.7236 Y0.3397 +G01 X0.7387 Y0.3246 +G01 X0.7584 Y0.3165 +G01 X0.8416 Y0.3165 +G01 X0.8613 Y0.3246 +G01 X0.8764 Y0.3397 +G01 X0.8845 Y0.3594 +G01 X0.8845 Y0.3806 +G01 X0.8764 Y0.4003 +G01 X0.8613 Y0.4154 +G01 X0.8416 Y0.4235 +G00 Z0.1000 +G00 X1.1416 Y0.3235 +G01 Z-0.0070 F10 +G01 X1.0584 Y0.3235 F20 +G01 X1.0387 Y0.3154 +G01 X1.0236 Y0.3003 +G01 X1.0155 Y0.2806 +G01 X1.0155 Y0.2594 +G01 X1.0236 Y0.2397 +G01 X1.0387 Y0.2246 +G01 X1.0584 Y0.2165 +G01 X1.1416 Y0.2165 +G01 X1.1613 Y0.2246 +G01 X1.1764 Y0.2397 +G01 X1.1845 Y0.2594 +G01 X1.1845 Y0.2806 +G01 X1.1764 Y0.3003 +G01 X1.1613 Y0.3154 +G01 X1.1416 Y0.3235 +G00 Z0.1000 +G00 X0.6416 Y0.3235 +G01 Z-0.0070 F10 +G01 X0.5584 Y0.3235 F20 +G01 X0.5387 Y0.3154 +G01 X0.5236 Y0.3003 +G01 X0.5155 Y0.2806 +G01 X0.5155 Y0.2594 +G01 X0.5236 Y0.2397 +G01 X0.5387 Y0.2246 +G01 X0.5584 Y0.2165 +G01 X0.6416 Y0.2165 +G01 X0.6613 Y0.2246 +G01 X0.6764 Y0.2397 +G01 X0.6845 Y0.2594 +G01 X0.6845 Y0.2806 +G01 X0.6764 Y0.3003 +G01 X0.6613 Y0.3154 +G01 X0.6416 Y0.3235 +G00 Z0.1000 +G00 X2.1084 Y0.0965 +G01 Z-0.0070 F10 +G01 X2.1916 Y0.0965 F20 +G01 X2.2113 Y0.1046 +G01 X2.2264 Y0.1197 +G01 X2.2345 Y0.1394 +G01 X2.2345 Y0.1606 +G01 X2.2264 Y0.1803 +G01 X2.2113 Y0.1954 +G01 X2.2001 Y0.2000 +G01 X2.2113 Y0.2046 +G01 X2.2264 Y0.2197 +G01 X2.2345 Y0.2394 +G01 X2.2345 Y0.2606 +G01 X2.2264 Y0.2803 +G01 X2.2113 Y0.2954 +G01 X2.2001 Y0.3000 +G01 X2.2113 Y0.3046 +G01 X2.2264 Y0.3197 +G01 X2.2345 Y0.3394 +G01 X2.2345 Y0.3606 +G01 X2.2264 Y0.3803 +G01 X2.2113 Y0.3954 +G01 X2.1916 Y0.4035 +G01 X2.1084 Y0.4035 +G01 X2.0887 Y0.3954 +G01 X2.0736 Y0.3803 +G01 X2.0655 Y0.3606 +G01 X2.0655 Y0.3394 +G01 X2.0736 Y0.3197 +G01 X2.0887 Y0.3046 +G01 X2.0999 Y0.3000 +G01 X2.0887 Y0.2954 +G01 X2.0736 Y0.2803 +G01 X2.0655 Y0.2606 +G01 X2.0655 Y0.2394 +G01 X2.0736 Y0.2197 +G01 X2.0887 Y0.2046 +G01 X2.0999 Y0.2000 +G01 X2.0887 Y0.1954 +G01 X2.0736 Y0.1803 +G01 X2.0655 Y0.1606 +G01 X2.0655 Y0.1394 +G01 X2.0736 Y0.1197 +G01 X2.0887 Y0.1046 +G01 X2.1084 Y0.0965 +G00 Z0.1000 +G00 X1.9113 Y0.3046 +G01 Z-0.0070 F10 +G01 X1.9264 Y0.3197 F20 +G01 X1.9345 Y0.3394 +G01 X1.9345 Y0.3606 +G01 X1.9264 Y0.3803 +G01 X1.9113 Y0.3954 +G01 X1.8916 Y0.4035 +G01 X1.8084 Y0.4035 +G01 X1.7887 Y0.3954 +G01 X1.7736 Y0.3803 +G01 X1.7655 Y0.3606 +G01 X1.7655 Y0.3394 +G01 X1.7736 Y0.3197 +G01 X1.7887 Y0.3046 +G01 X1.7999 Y0.3000 +G01 X1.7887 Y0.2954 +G01 X1.7736 Y0.2803 +G01 X1.7655 Y0.2606 +G01 X1.7655 Y0.2394 +G01 X1.7736 Y0.2197 +G01 X1.7887 Y0.2046 +G01 X1.7999 Y0.2000 +G01 X1.7887 Y0.1954 +G01 X1.7736 Y0.1803 +G01 X1.7655 Y0.1606 +G01 X1.7655 Y0.1394 +G01 X1.7736 Y0.1197 +G01 X1.7887 Y0.1046 +G01 X1.8084 Y0.0965 +G01 X1.8916 Y0.0965 +G01 X1.9113 Y0.1046 +G01 X1.9264 Y0.1197 +G01 X1.9345 Y0.1394 +G01 X1.9345 Y0.1606 +G01 X1.9264 Y0.1803 +G01 X1.9113 Y0.1954 +G01 X1.9001 Y0.2000 +G01 X1.9113 Y0.2046 +G01 X1.9264 Y0.2197 +G01 X1.9345 Y0.2394 +G01 X1.9345 Y0.2606 +G01 X1.9264 Y0.2803 +G01 X1.9113 Y0.2954 +G01 X1.9001 Y0.3000 +G01 X1.9113 Y0.3046 +G00 Z0.1000 +G00 X1.8535 Y0.6578 +G01 Z-0.0070 F10 +G01 X1.8535 Y0.7022 F20 +G01 X1.8222 Y0.7335 +G01 X1.7778 Y0.7335 +G01 X1.7465 Y0.7022 +G01 X1.7465 Y0.6578 +G01 X1.7778 Y0.6265 +G01 X1.8222 Y0.6265 +G01 X1.8535 Y0.6578 +G00 Z0.1000 +G00 X1.8535 Y0.4578 +G01 Z-0.0070 F10 +G01 X1.8535 Y0.5022 F20 +G01 X1.8222 Y0.5335 +G01 X1.7778 Y0.5335 +G01 X1.7465 Y0.5022 +G01 X1.7465 Y0.4578 +G01 X1.7778 Y0.4265 +G01 X1.8222 Y0.4265 +G01 X1.8535 Y0.4578 +G00 Z0.1000 +G00 X1.9735 Y0.6578 +G01 Z-0.0070 F10 +G01 X1.9735 Y0.7022 F20 +G01 X1.9422 Y0.7335 +G01 X1.8978 Y0.7335 +G01 X1.8665 Y0.7022 +G01 X1.8665 Y0.6578 +G01 X1.8978 Y0.6265 +G01 X1.9422 Y0.6265 +G01 X1.9735 Y0.6578 +G00 Z0.1000 +G00 X1.9735 Y0.4578 +G01 Z-0.0070 F10 +G01 X1.9735 Y0.5022 F20 +G01 X1.9422 Y0.5335 +G01 X1.8978 Y0.5335 +G01 X1.8665 Y0.5022 +G01 X1.8665 Y0.4578 +G01 X1.8978 Y0.4265 +G01 X1.9422 Y0.4265 +G01 X1.9735 Y0.4578 +G00 Z0.1000 +G00 X2.0935 Y0.6578 +G01 Z-0.0070 F10 +G01 X2.0935 Y0.7022 F20 +G01 X2.0622 Y0.7335 +G01 X2.0178 Y0.7335 +G01 X1.9865 Y0.7022 +G01 X1.9865 Y0.6578 +G01 X2.0178 Y0.6265 +G01 X2.0622 Y0.6265 +G01 X2.0935 Y0.6578 +G00 Z0.1000 +G00 X2.0935 Y0.4578 +G01 Z-0.0070 F10 +G01 X2.0935 Y0.5022 F20 +G01 X2.0622 Y0.5335 +G01 X2.0178 Y0.5335 +G01 X1.9865 Y0.5022 +G01 X1.9865 Y0.4578 +G01 X2.0178 Y0.4265 +G01 X2.0622 Y0.4265 +G01 X2.0935 Y0.4578 +G00 Z0.1000 +G00 X1.2922 Y0.2835 +G01 Z-0.0070 F10 +G01 X1.2478 Y0.2835 F20 +G01 X1.2165 Y0.2522 +G01 X1.2165 Y0.2078 +G01 X1.2478 Y0.1765 +G01 X1.2922 Y0.1765 +G01 X1.3200 Y0.2043 +G01 X1.3478 Y0.1765 +G01 X1.3922 Y0.1765 +G01 X1.4235 Y0.2078 +G01 X1.4235 Y0.2522 +G01 X1.3922 Y0.2835 +G01 X1.3478 Y0.2835 +G01 X1.3200 Y0.2557 +G01 X1.2922 Y0.2835 +G00 Z0.1000 +G00 X1.4935 Y1.2672 +G01 Z-0.0070 F10 +G01 X1.4622 Y1.2985 F20 +G01 X1.4178 Y1.2985 +G01 X1.3865 Y1.2672 +G01 X1.3865 Y1.2235 +G01 X1.3678 Y1.2235 +G01 X1.3365 Y1.1922 +G01 X1.3365 Y1.1478 +G01 X1.3678 Y1.1165 +G01 X1.4122 Y1.1165 +G01 X1.4400 Y1.1443 +G01 X1.4678 Y1.1165 +G01 X1.5122 Y1.1165 +G01 X1.5435 Y1.1478 +G01 X1.5435 Y1.1922 +G01 X1.5122 Y1.2235 +G01 X1.4935 Y1.2235 +G01 X1.4935 Y1.2672 +G00 Z0.1000 +G00 X1.1671 Y1.2355 +G01 Z-0.0070 F10 +G01 X1.1430 Y1.2455 F20 +G01 X1.1170 Y1.2455 +G01 X1.0929 Y1.2355 +G01 X1.0745 Y1.2171 +G01 X1.0645 Y1.1930 +G01 X1.0645 Y1.1670 +G01 X1.0745 Y1.1429 +G01 X1.0929 Y1.1245 +G01 X1.1170 Y1.1145 +G01 X1.1430 Y1.1145 +G01 X1.1671 Y1.1245 +G01 X1.1800 Y1.1374 +G01 X1.2029 Y1.1145 +G01 X1.2571 Y1.1145 +G01 X1.2955 Y1.1529 +G01 X1.2955 Y1.2071 +G01 X1.2571 Y1.2455 +G01 X1.2029 Y1.2455 +G01 X1.1800 Y1.2226 +G01 X1.1671 Y1.2355 +G00 Z0.1000 +G00 X0.1500 Y1.1900 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1500 Y0.1300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.2300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.3700 Y0.2300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.5100 Y1.0000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.4100 Y1.0000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.1300 Y1.1800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2300 Y1.1800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.7500 Y1.2200 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.7500 Y1.1200 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.3400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.4400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.5400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.6400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.7400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.8400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y0.9400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.5700 Y1.0400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y1.0400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.9400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.8400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.7400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.6400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.5400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.4400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.2700 Y0.3400 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.3900 Y1.1700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.4400 Y1.2450 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.4900 Y1.1700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.6000 Y0.2700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.1000 Y0.2700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.8000 Y0.3700 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8000 Y0.6800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8000 Y0.4800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.9200 Y0.6800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.9200 Y0.4800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.0400 Y0.6800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.0400 Y0.4800 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.1500 Y0.1500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.1500 Y0.2500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.1500 Y0.3500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8500 Y0.3500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8500 Y0.2500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.8500 Y0.1500 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.0000 Y1.0300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X2.3000 Y1.0300 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.7234 Y0.6709 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.7628 Y0.7891 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.8021 Y0.6709 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.8415 Y0.7891 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.8809 Y0.6709 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.9202 Y0.7891 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X1.1171 Y0.7576 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.5029 Y0.7576 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y1.0000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y1.0000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.9000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.9000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.8000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.8000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.7000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.7000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.6000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.6000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.5000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.5000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.2900 Y0.4000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 X0.1900 Y0.4000 +G01 Z-0.0110 F10 +G00 Z0.1000 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.mill.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.mill.tap new file mode 100644 index 00000000..d41e9bcd --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.mill.tap @@ -0,0 +1,46 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G01 X0.0100 Y-0.0100 +G01 X2.7900 Y-0.0100 +G01 X2.7900 Y1.3300 +G00 Z0.1000 +G00 X-0.0100 Y1.3200 +G01 Z-0.0100 F10 +G01 X-0.0100 Y0.0000 F20 +G00 Z0.1000 +G00 X-0.0100 Y1.3300 +G01 Z-0.0100 F10 +G01 X2.7900 Y1.3300 F20 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.text.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.text.tap new file mode 100644 index 00000000..20ccd74b --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/04151_lcdi2c.top.text.tap @@ -0,0 +1,35 @@ +(.../Documents/src/3.6.0.2/pcb-gcode.ulp) +(Copyright 2005 - 2012 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../docs/examples/04151_lcdi2c.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/28/12 11:20 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0100 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.drill.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.drill.tap new file mode 100644 index 00000000..9501c375 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.drill.tap @@ -0,0 +1,163 @@ +(.../src/pcbgcode-work/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode-work/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/16/12 5:51 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0050 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0030) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +( Tool| Size | Min Sub | Max Sub | Count ) +( T01 | 0.600mm 0.0236in | 0.0000in | 0.0000in | 0 ) +( T02 | 0.813mm 0.0320in | 0.0000in | 0.0000in | 0 ) +( T03 | 1.118mm 0.0440in | 0.0000in | 0.0000in | 0 ) +( T04 | 1.194mm 0.0470in | 0.0000in | 0.0000in | 0 ) +( T05 | 2.800mm 0.1102in | 0.0000in | 0.0000in | 0 ) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +M05 +G00 Z1.0000 +G00 X0.5000 Y0.6000 +M06 T01 ; 0.0236 +G01 Z0.0000 F10 +M06 T01 ; 0.0236 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-1.6400 Y1.2700 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-1.9000 Y0.5700 +G82 X-1.9700 Y1.4700 +G82 X-1.9700 Y1.7900 +G82 X-2.2100 Y1.4700 +G82 X-2.2100 Y1.7400 +G82 X-2.5100 Y0.4600 +G82 X-2.5100 Y0.9100 +M05 +G00 Z1.0000 +M06 T02 ; 0.0320 +G01 Z0.0000 F10 +M06 T02 ; 0.0320 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.5600 Y0.9100 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.5600 Y1.1100 +G82 X-0.7200 Y1.3100 +G82 X-0.7200 Y1.5100 +G82 X-0.7600 Y1.8600 +G82 X-0.7800 Y0.3400 +G82 X-0.7800 Y0.5400 +G82 X-0.9500 Y0.8100 +G82 X-0.9500 Y0.9100 +G82 X-0.9500 Y1.0100 +G82 X-0.9500 Y1.1100 +G82 X-0.9500 Y1.2100 +G82 X-0.9500 Y1.3100 +G82 X-0.9500 Y1.4100 +G82 X-1.2500 Y0.8100 +G82 X-1.2500 Y0.9100 +G82 X-1.2500 Y1.0100 +G82 X-1.2500 Y1.1100 +G82 X-1.2500 Y1.2100 +G82 X-1.2500 Y1.3100 +G82 X-1.2500 Y1.4100 +G82 X-1.3200 Y0.2000 +G82 X-1.3600 Y1.8600 +G82 X-1.4300 Y0.7100 +G82 X-1.4300 Y1.2100 +G82 X-1.5000 Y1.9100 +G82 X-1.5500 Y0.6600 +G82 X-1.7500 Y0.6600 +G82 X-1.7700 Y1.2000 +G82 X-1.7700 Y1.7000 +G82 X-1.8200 Y0.2000 +G82 X-1.9600 Y1.0100 +G82 X-1.9600 Y1.1100 +G82 X-1.9600 Y1.2100 +G82 X-1.9600 Y1.3100 +G82 X-2.0000 Y1.9100 +G82 X-2.1400 Y0.2600 +G82 X-2.2600 Y1.0100 +G82 X-2.2600 Y1.1100 +G82 X-2.2600 Y1.2100 +G82 X-2.2600 Y1.3100 +G82 X-2.3000 Y1.4400 +G82 X-2.3400 Y1.7400 +G82 X-2.3900 Y1.6650 +G82 X-2.4400 Y1.7400 +G82 X-2.6400 Y0.2600 +G82 X-2.6600 Y1.6100 +G82 X-2.6700 Y0.7500 +G82 X-2.6700 Y1.2500 +G82 X-2.6700 Y1.7200 +G82 X-2.6700 Y1.8200 +G82 X-2.9000 Y1.4400 +G82 X-2.9500 Y1.1300 +G82 X-2.9500 Y1.3300 +G82 X-3.1600 Y1.6100 +M05 +G00 Z1.0000 +M06 T03 ; 0.0440 +G01 Z0.0000 F10 +M06 T03 ; 0.0440 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-1.4200 Y0.3400 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-1.4200 Y0.5000 +G82 X-1.5000 Y1.3100 +G82 X-1.5000 Y1.7100 +G82 X-1.8200 Y0.3400 +G82 X-1.8200 Y0.5000 +G82 X-2.0100 Y0.2600 +G82 X-2.0100 Y0.6600 +M05 +G00 Z1.0000 +M06 T04 ; 0.0470 +G01 Z0.0000 F10 +M06 T04 ; 0.0470 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.2000 Y0.7116 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.2000 Y0.9084 +G82 X-0.2000 Y1.1116 +G82 X-0.2000 Y1.3084 +G82 X-0.2000 Y1.5916 +G82 X-0.2000 Y1.7884 +G82 X-2.9200 Y0.5516 +G82 X-2.9200 Y0.7484 +M05 +G00 Z1.0000 +M06 T05 ; 0.1102 +G01 Z0.0000 F10 +M06 T05 ; 0.1102 +G00 Z0.1000 +M03 +G04 P3.000000 +G82 X-0.2200 Y0.1800 Z-0.0320 F10 R0.1000 P1.000000 +G82 X-0.2300 Y2.0300 +G82 X-3.0700 Y0.1900 +G82 X-3.0700 Y2.0100 +T01 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.etch.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.etch.tap new file mode 100644 index 00000000..8a0f9c45 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.etch.tap @@ -0,0 +1,15522 @@ +(.../src/pcbgcode-work/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode-work/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode-work/profiles/mach.pp ) +(This file generated 12/16/12 5:50 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0050 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.0000 ) +(feed rate xy = F20 ) +(feed rate z = F10 ) +(Settings from pcb-defaults.h) +(isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0030) +(Generated bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-0.4315 Y0.2844 +G01 Z-0.0070 F10 +G01 X-0.4315 Y0.2844 F20 +G01 X-0.4435 Y0.2555 +G01 X-0.4655 Y0.2335 +G01 X-0.4944 Y0.2215 +G01 X-0.5043 Y0.2215 +G01 X-0.5100 Y0.2215 +G01 X-0.5157 Y0.2215 +G01 X-1.0400 Y0.2215 +G01 X-1.0442 Y0.2211 +G01 X-1.0519 Y0.2179 +G01 X-1.0579 Y0.2119 +G01 X-1.0611 Y0.2042 +G01 X-1.0615 Y0.2000 +G01 X-1.0615 Y0.1970 +G01 X-1.0615 Y0.1943 +G01 X-1.0615 Y0.1443 +G01 X-1.0615 Y0.1344 +G01 X-1.0735 Y0.1055 +G01 X-1.0955 Y0.0835 +G01 X-1.1244 Y0.0715 +G01 X-1.1343 Y0.0715 +G01 X-1.6057 Y0.0715 +G01 X-1.6156 Y0.0715 +G01 X-1.6445 Y0.0835 +G01 X-1.6665 Y0.1055 +G01 X-1.6785 Y0.1344 +G01 X-1.6785 Y0.1443 +G01 X-1.6785 Y0.1509 +G01 X-1.6785 Y0.1557 +G01 X-1.6785 Y0.8657 +G01 X-1.6785 Y0.8756 +G01 X-1.6665 Y0.9045 +G01 X-1.6445 Y0.9265 +G01 X-1.6156 Y0.9385 +G01 X-1.6057 Y0.9385 +G01 X-1.6000 Y0.9385 +G01 X-1.5943 Y0.9385 +G01 X-1.3372 Y0.9385 +G01 X-1.3305 Y0.9452 +G01 X-1.3153 Y0.9515 +G01 X-1.1847 Y0.9515 +G01 X-1.1695 Y0.9452 +G01 X-1.1578 Y0.9335 +G01 X-1.1515 Y0.9183 +G01 X-1.1515 Y0.9017 +G01 X-1.1578 Y0.8865 +G01 X-1.1695 Y0.8748 +G01 X-1.1847 Y0.8685 +G01 X-1.3153 Y0.8685 +G01 X-1.3305 Y0.8748 +G01 X-1.3372 Y0.8815 +G01 X-1.5943 Y0.8815 +G01 X-1.6000 Y0.8815 +G01 X-1.6042 Y0.8811 +G01 X-1.6119 Y0.8779 +G01 X-1.6179 Y0.8719 +G01 X-1.6211 Y0.8642 +G01 X-1.6215 Y0.8600 +G01 X-1.6215 Y0.1557 +G01 X-1.6215 Y0.1508 +G01 X-1.6215 Y0.1500 +G01 X-1.6211 Y0.1458 +G01 X-1.6179 Y0.1381 +G01 X-1.6119 Y0.1321 +G01 X-1.6042 Y0.1289 +G01 X-1.6000 Y0.1285 +G01 X-1.1400 Y0.1285 +G01 X-1.1358 Y0.1289 +G01 X-1.1281 Y0.1321 +G01 X-1.1221 Y0.1381 +G01 X-1.1189 Y0.1458 +G01 X-1.1185 Y0.1500 +G01 X-1.1185 Y0.1943 +G01 X-1.1185 Y0.1970 +G01 X-1.1185 Y0.2057 +G01 X-1.1185 Y0.2156 +G01 X-1.1065 Y0.2445 +G01 X-1.0845 Y0.2665 +G01 X-1.0556 Y0.2785 +G01 X-1.0457 Y0.2785 +G01 X-0.5157 Y0.2785 +G01 X-0.5100 Y0.2785 +G01 X-0.5058 Y0.2789 +G01 X-0.4981 Y0.2821 +G01 X-0.4921 Y0.2881 +G01 X-0.4889 Y0.2958 +G01 X-0.4885 Y0.3000 +G01 X-0.4885 Y0.6543 +G01 X-0.4885 Y0.6553 +G01 X-0.4885 Y0.6657 +G01 X-0.4885 Y0.6756 +G01 X-0.4765 Y0.7045 +G01 X-0.4545 Y0.7265 +G01 X-0.4256 Y0.7385 +G01 X-0.4157 Y0.7385 +G01 X-0.4131 Y0.7385 +G01 X-0.4100 Y0.7385 +G01 X-0.4043 Y0.7385 +G01 X-0.3101 Y0.7385 +G01 X-0.3098 Y0.7393 +G01 X-0.2960 Y0.7531 +G01 X-0.2780 Y0.7606 +G01 X-0.1220 Y0.7606 +G01 X-0.1040 Y0.7531 +G01 X-0.0902 Y0.7393 +G01 X-0.0828 Y0.7213 +G01 X-0.0828 Y0.7018 +G01 X-0.0902 Y0.6838 +G01 X-0.1040 Y0.6700 +G01 X-0.1220 Y0.6626 +G01 X-0.2780 Y0.6626 +G01 X-0.2960 Y0.6700 +G01 X-0.3075 Y0.6815 +G01 X-0.4043 Y0.6815 +G01 X-0.4100 Y0.6815 +G01 X-0.4142 Y0.6811 +G01 X-0.4219 Y0.6779 +G01 X-0.4279 Y0.6719 +G01 X-0.4311 Y0.6642 +G01 X-0.4315 Y0.6600 +G01 X-0.4315 Y0.6553 +G01 X-0.4315 Y0.6543 +G01 X-0.4315 Y0.2943 +G01 X-0.4315 Y0.2844 +G00 Z0.1000 +G00 X-0.4036 Y0.8815 +G01 Z-0.0070 F10 +G01 X-0.4036 Y0.8815 F20 +G01 X-0.4288 Y0.8919 +G01 X-0.4481 Y0.9112 +G01 X-0.4585 Y0.9364 +G01 X-0.4585 Y0.9443 +G01 X-0.4585 Y0.9497 +G01 X-0.4585 Y0.9500 +G01 X-0.4585 Y0.9557 +G01 X-0.4585 Y0.9600 +G01 X-0.4589 Y0.9642 +G01 X-0.4621 Y0.9719 +G01 X-0.4681 Y0.9779 +G01 X-0.4758 Y0.9811 +G01 X-0.4800 Y0.9815 +G01 X-0.4857 Y0.9815 +G01 X-0.8628 Y0.9815 +G01 X-0.8695 Y0.9748 +G01 X-0.8847 Y0.9685 +G01 X-1.0153 Y0.9685 +G01 X-1.0305 Y0.9748 +G01 X-1.0422 Y0.9865 +G01 X-1.0485 Y1.0017 +G01 X-1.0485 Y1.0183 +G01 X-1.0422 Y1.0335 +G01 X-1.0305 Y1.0452 +G01 X-1.0153 Y1.0515 +G01 X-0.8847 Y1.0515 +G01 X-0.8695 Y1.0452 +G01 X-0.8628 Y1.0385 +G01 X-0.4857 Y1.0385 +G01 X-0.4800 Y1.0385 +G01 X-0.4798 Y1.0385 +G01 X-0.4743 Y1.0385 +G01 X-0.4644 Y1.0385 +G01 X-0.4355 Y1.0265 +G01 X-0.4135 Y1.0045 +G01 X-0.4015 Y0.9756 +G01 X-0.4015 Y0.9657 +G01 X-0.4015 Y0.9557 +G01 X-0.4015 Y0.9500 +G01 X-0.4013 Y0.9478 +G01 X-0.3996 Y0.9436 +G01 X-0.3964 Y0.9404 +G01 X-0.3922 Y0.9387 +G01 X-0.3900 Y0.9385 +G01 X-0.3075 Y0.9385 +G01 X-0.2960 Y0.9500 +G01 X-0.2780 Y0.9574 +G01 X-0.1220 Y0.9574 +G01 X-0.1040 Y0.9500 +G01 X-0.0902 Y0.9362 +G01 X-0.0828 Y0.9182 +G01 X-0.0828 Y0.8987 +G01 X-0.0902 Y0.8807 +G01 X-0.1040 Y0.8669 +G01 X-0.1220 Y0.8594 +G01 X-0.2780 Y0.8594 +G01 X-0.2960 Y0.8669 +G01 X-0.3098 Y0.8807 +G01 X-0.3101 Y0.8815 +G01 X-0.3957 Y0.8815 +G01 X-0.4036 Y0.8815 +G00 Z0.1000 +G00 X-0.4457 Y1.2385 +G01 Z-0.0070 F10 +G01 X-0.4400 Y1.2385 F20 +G01 X-0.4369 Y1.2385 +G01 X-0.4343 Y1.2385 +G01 X-0.4264 Y1.2385 +G01 X-0.4012 Y1.2281 +G01 X-0.3819 Y1.2088 +G01 X-0.3715 Y1.1836 +G01 X-0.3715 Y1.1757 +G01 X-0.3715 Y1.1690 +G01 X-0.3715 Y1.1643 +G01 X-0.3715 Y1.1616 +G01 X-0.3711 Y1.1574 +G01 X-0.3679 Y1.1496 +G01 X-0.3619 Y1.1437 +G01 X-0.3542 Y1.1405 +G01 X-0.3500 Y1.1401 +G01 X-0.3454 Y1.1401 +G01 X-0.3443 Y1.1401 +G01 X-0.3090 Y1.1401 +G01 X-0.2960 Y1.1531 +G01 X-0.2780 Y1.1606 +G01 X-0.1220 Y1.1606 +G01 X-0.1040 Y1.1531 +G01 X-0.0902 Y1.1393 +G01 X-0.0828 Y1.1213 +G01 X-0.0828 Y1.1018 +G01 X-0.0902 Y1.0838 +G01 X-0.1040 Y1.0700 +G01 X-0.1220 Y1.0626 +G01 X-0.2780 Y1.0626 +G01 X-0.2960 Y1.0700 +G01 X-0.3090 Y1.0831 +G01 X-0.3443 Y1.0831 +G01 X-0.3454 Y1.0831 +G01 X-0.3557 Y1.0831 +G01 X-0.3656 Y1.0831 +G01 X-0.3945 Y1.0950 +G01 X-0.4165 Y1.1171 +G01 X-0.4285 Y1.1460 +G01 X-0.4285 Y1.1559 +G01 X-0.4285 Y1.1643 +G01 X-0.4285 Y1.1690 +G01 X-0.4285 Y1.1700 +G01 X-0.4287 Y1.1722 +G01 X-0.4304 Y1.1764 +G01 X-0.4336 Y1.1796 +G01 X-0.4378 Y1.1813 +G01 X-0.4400 Y1.1815 +G01 X-0.4457 Y1.1815 +G01 X-0.8628 Y1.1815 +G01 X-0.8695 Y1.1748 +G01 X-0.8847 Y1.1685 +G01 X-1.0153 Y1.1685 +G01 X-1.0305 Y1.1748 +G01 X-1.0422 Y1.1865 +G01 X-1.0485 Y1.2017 +G01 X-1.0485 Y1.2183 +G01 X-1.0422 Y1.2335 +G01 X-1.0305 Y1.2452 +G01 X-1.0153 Y1.2515 +G01 X-0.8847 Y1.2515 +G01 X-0.8695 Y1.2452 +G01 X-0.8628 Y1.2385 +G01 X-0.4457 Y1.2385 +G00 Z0.1000 +G00 X-0.5744 Y1.4385 +G01 Z-0.0070 F10 +G01 X-0.5744 Y1.4385 F20 +G01 X-0.5455 Y1.4265 +G01 X-0.5235 Y1.4045 +G01 X-0.5115 Y1.3756 +G01 X-0.5115 Y1.3657 +G01 X-0.5115 Y1.3602 +G01 X-0.5115 Y1.3600 +G01 X-0.5115 Y1.3584 +G01 X-0.5111 Y1.3542 +G01 X-0.5079 Y1.3465 +G01 X-0.5019 Y1.3405 +G01 X-0.4942 Y1.3373 +G01 X-0.4900 Y1.3369 +G01 X-0.4892 Y1.3369 +G01 X-0.4843 Y1.3369 +G01 X-0.3090 Y1.3369 +G01 X-0.2960 Y1.3500 +G01 X-0.2780 Y1.3574 +G01 X-0.1220 Y1.3574 +G01 X-0.1040 Y1.3500 +G01 X-0.0902 Y1.3362 +G01 X-0.0828 Y1.3182 +G01 X-0.0828 Y1.2987 +G01 X-0.0902 Y1.2807 +G01 X-0.1040 Y1.2669 +G01 X-0.1220 Y1.2594 +G01 X-0.2780 Y1.2594 +G01 X-0.2960 Y1.2669 +G01 X-0.3090 Y1.2799 +G01 X-0.4843 Y1.2799 +G01 X-0.4892 Y1.2799 +G01 X-0.4900 Y1.2799 +G01 X-0.4957 Y1.2799 +G01 X-0.5056 Y1.2799 +G01 X-0.5345 Y1.2919 +G01 X-0.5565 Y1.3140 +G01 X-0.5685 Y1.3428 +G01 X-0.5685 Y1.3527 +G01 X-0.5685 Y1.3543 +G01 X-0.5685 Y1.3600 +G01 X-0.5689 Y1.3642 +G01 X-0.5721 Y1.3719 +G01 X-0.5781 Y1.3779 +G01 X-0.5858 Y1.3811 +G01 X-0.5900 Y1.3815 +G01 X-0.8628 Y1.3815 +G01 X-0.8695 Y1.3748 +G01 X-0.8847 Y1.3685 +G01 X-1.0153 Y1.3685 +G01 X-1.0305 Y1.3748 +G01 X-1.0422 Y1.3865 +G01 X-1.0485 Y1.4017 +G01 X-1.0485 Y1.4183 +G01 X-1.0422 Y1.4335 +G01 X-1.0305 Y1.4452 +G01 X-1.0153 Y1.4515 +G01 X-0.8847 Y1.4515 +G01 X-0.8695 Y1.4452 +G01 X-0.8628 Y1.4385 +G01 X-0.5843 Y1.4385 +G01 X-0.5744 Y1.4385 +G00 Z0.1000 +G00 X-2.5553 Y0.4412 +G01 Z-0.0070 F10 +G01 X-2.5553 Y0.4788 F20 +G01 X-2.5288 Y0.5053 +G01 X-2.4912 Y0.5053 +G01 X-2.4647 Y0.4788 +G01 X-2.4647 Y0.4412 +G01 X-2.4715 Y0.4344 +G01 X-2.4715 Y0.2677 +G01 X-2.4715 Y0.1900 +G01 X-2.4714 Y0.1882 +G01 X-2.4702 Y0.1848 +G01 X-2.4681 Y0.1819 +G01 X-2.4652 Y0.1797 +G01 X-2.4618 Y0.1786 +G01 X-2.4600 Y0.1785 +G01 X-2.4533 Y0.1785 +G01 X-2.4523 Y0.1785 +G01 X-1.8700 Y0.1785 +G01 X-1.8682 Y0.1786 +G01 X-1.8648 Y0.1797 +G01 X-1.8619 Y0.1819 +G01 X-1.8613 Y0.1826 +G01 X-1.8615 Y0.1828 +G01 X-1.8615 Y0.2172 +G01 X-1.8372 Y0.2415 +G01 X-1.8028 Y0.2415 +G01 X-1.7785 Y0.2172 +G01 X-1.7785 Y0.1828 +G01 X-1.7815 Y0.1798 +G01 X-1.7815 Y0.1760 +G01 X-1.7902 Y0.1493 +G01 X-1.8066 Y0.1266 +G01 X-1.8293 Y0.1102 +G01 X-1.8560 Y0.1015 +G01 X-1.8623 Y0.1015 +G01 X-2.4523 Y0.1015 +G01 X-2.4533 Y0.1015 +G01 X-2.4677 Y0.1015 +G01 X-2.4740 Y0.1015 +G01 X-2.5007 Y0.1102 +G01 X-2.5234 Y0.1266 +G01 X-2.5398 Y0.1493 +G01 X-2.5485 Y0.1760 +G01 X-2.5485 Y0.1823 +G01 X-2.5485 Y0.2315 +G01 X-2.6098 Y0.2315 +G01 X-2.6228 Y0.2185 +G01 X-2.6572 Y0.2185 +G01 X-2.6815 Y0.2428 +G01 X-2.6815 Y0.2772 +G01 X-2.6572 Y0.3015 +G01 X-2.6228 Y0.3015 +G01 X-2.6098 Y0.2885 +G01 X-2.5485 Y0.2885 +G01 X-2.5485 Y0.4344 +G01 X-2.5553 Y0.4412 +G00 Z0.1000 +G00 X-1.9315 Y1.4356 +G01 Z-0.0070 F10 +G01 X-1.9315 Y1.4356 F20 +G01 X-1.9315 Y1.4257 +G01 X-1.9315 Y1.3515 +G01 X-1.8947 Y1.3515 +G01 X-1.8795 Y1.3452 +G01 X-1.8678 Y1.3335 +G01 X-1.8615 Y1.3183 +G01 X-1.8615 Y1.3017 +G01 X-1.8678 Y1.2865 +G01 X-1.8795 Y1.2748 +G01 X-1.8947 Y1.2685 +G01 X-2.0253 Y1.2685 +G01 X-2.0405 Y1.2748 +G01 X-2.0522 Y1.2865 +G01 X-2.0585 Y1.3017 +G01 X-2.0585 Y1.3183 +G01 X-2.0522 Y1.3335 +G01 X-2.0405 Y1.3452 +G01 X-2.0253 Y1.3515 +G01 X-1.9885 Y1.3515 +G01 X-1.9885 Y1.4200 +G01 X-1.9889 Y1.4242 +G01 X-1.9894 Y1.4253 +G01 X-2.0047 Y1.4406 +G01 X-2.0058 Y1.4411 +G01 X-2.0100 Y1.4415 +G01 X-2.1744 Y1.4415 +G01 X-2.1912 Y1.4247 +G01 X-2.2288 Y1.4247 +G01 X-2.2355 Y1.4314 +G01 X-2.2540 Y1.4253 +G01 X-2.2540 Y1.4209 +G01 X-2.2809 Y1.3940 +G01 X-2.3191 Y1.3940 +G01 X-2.3460 Y1.4209 +G01 X-2.3460 Y1.4591 +G01 X-2.3191 Y1.4860 +G01 X-2.2809 Y1.4860 +G01 X-2.2737 Y1.4788 +G01 X-2.2553 Y1.4849 +G01 X-2.2553 Y1.4888 +G01 X-2.2288 Y1.5153 +G01 X-2.1912 Y1.5153 +G01 X-2.1744 Y1.4985 +G01 X-2.0056 Y1.4985 +G01 X-1.9888 Y1.5153 +G01 X-1.9512 Y1.5153 +G01 X-1.9247 Y1.4888 +G01 X-1.9247 Y1.4512 +G01 X-1.9341 Y1.4418 +G01 X-1.9315 Y1.4356 +G00 Z0.1000 +G00 X-1.3615 Y0.1828 +G01 Z-0.0070 F10 +G01 X-1.3615 Y0.2172 F20 +G01 X-1.3385 Y0.2402 +G01 X-1.3385 Y0.3115 +G01 X-1.3813 Y0.3115 +G01 X-1.3931 Y0.2997 +G01 X-1.4105 Y0.2925 +G01 X-1.4294 Y0.2925 +G01 X-1.4469 Y0.2997 +G01 X-1.4603 Y0.3131 +G01 X-1.4675 Y0.3305 +G01 X-1.4675 Y0.3494 +G01 X-1.4603 Y0.3669 +G01 X-1.4469 Y0.3803 +G01 X-1.4294 Y0.3875 +G01 X-1.4105 Y0.3875 +G01 X-1.3931 Y0.3803 +G01 X-1.3813 Y0.3685 +G01 X-1.3043 Y0.3685 +G01 X-0.8102 Y0.3685 +G01 X-0.7972 Y0.3815 +G01 X-0.7628 Y0.3815 +G01 X-0.7385 Y0.3572 +G01 X-0.7385 Y0.3228 +G01 X-0.7628 Y0.2985 +G01 X-0.7972 Y0.2985 +G01 X-0.8102 Y0.3115 +G01 X-1.2815 Y0.3115 +G01 X-1.2815 Y0.2202 +G01 X-1.2785 Y0.2172 +G01 X-1.2785 Y0.1828 +G01 X-1.3028 Y0.1585 +G01 X-1.3372 Y0.1585 +G01 X-1.3615 Y0.1828 +G00 Z0.1000 +G00 X-1.5415 Y1.8928 +G01 Z-0.0070 F10 +G01 X-1.5415 Y1.9272 F20 +G01 X-1.5172 Y1.9515 +G01 X-1.4828 Y1.9515 +G01 X-1.4585 Y1.9272 +G01 X-1.4585 Y1.8928 +G01 X-1.4715 Y1.8798 +G01 X-1.4715 Y1.7487 +G01 X-1.4597 Y1.7369 +G01 X-1.4525 Y1.7194 +G01 X-1.4525 Y1.7005 +G01 X-1.4534 Y1.6985 +G01 X-1.4516 Y1.6985 +G01 X-1.4475 Y1.6989 +G01 X-1.4459 Y1.6985 +G01 X-0.7757 Y1.6985 +G01 X-0.7700 Y1.6985 +G01 X-0.7665 Y1.6985 +G01 X-0.7643 Y1.6985 +G01 X-0.7544 Y1.6985 +G01 X-0.7255 Y1.6865 +G01 X-0.7035 Y1.6645 +G01 X-0.6915 Y1.6356 +G01 X-0.6915 Y1.6257 +G01 X-0.6915 Y1.5402 +G01 X-0.6785 Y1.5272 +G01 X-0.6785 Y1.4928 +G01 X-0.7028 Y1.4685 +G01 X-0.7372 Y1.4685 +G01 X-0.7615 Y1.4928 +G01 X-0.7615 Y1.5272 +G01 X-0.7485 Y1.5402 +G01 X-0.7485 Y1.6200 +G01 X-0.7489 Y1.6242 +G01 X-0.7521 Y1.6319 +G01 X-0.7581 Y1.6379 +G01 X-0.7658 Y1.6411 +G01 X-0.7700 Y1.6415 +G01 X-0.7757 Y1.6415 +G01 X-1.4484 Y1.6415 +G01 X-1.4614 Y1.6401 +G01 X-1.4896 Y1.6482 +G01 X-1.5075 Y1.6625 +G01 X-1.5094 Y1.6625 +G01 X-1.5269 Y1.6697 +G01 X-1.5403 Y1.6831 +G01 X-1.5475 Y1.7005 +G01 X-1.5475 Y1.7194 +G01 X-1.5403 Y1.7369 +G01 X-1.5285 Y1.7487 +G01 X-1.5285 Y1.8798 +G01 X-1.5415 Y1.8928 +G00 Z0.1000 +G00 X-1.7285 Y1.2172 +G01 Z-0.0070 F10 +G01 X-1.7285 Y1.1828 F20 +G01 X-1.7528 Y1.1585 +G01 X-1.7872 Y1.1585 +G01 X-1.8002 Y1.1715 +G01 X-1.8875 Y1.1715 +G01 X-1.8947 Y1.1685 +G01 X-2.0253 Y1.1685 +G01 X-2.0405 Y1.1748 +G01 X-2.0522 Y1.1865 +G01 X-2.0585 Y1.2017 +G01 X-2.0585 Y1.2183 +G01 X-2.0522 Y1.2335 +G01 X-2.0405 Y1.2452 +G01 X-2.0253 Y1.2515 +G01 X-1.8947 Y1.2515 +G01 X-1.8795 Y1.2452 +G01 X-1.8678 Y1.2335 +G01 X-1.8657 Y1.2285 +G01 X-1.8002 Y1.2285 +G01 X-1.7985 Y1.2302 +G01 X-1.7985 Y1.2815 +G01 X-1.8043 Y1.2815 +G01 X-1.8157 Y1.2815 +G01 X-1.8261 Y1.2858 +G01 X-1.8342 Y1.2939 +G01 X-1.8385 Y1.3043 +G01 X-1.8385 Y1.5343 +G01 X-1.8385 Y1.5400 +G01 X-1.8387 Y1.5422 +G01 X-1.8404 Y1.5464 +G01 X-1.8436 Y1.5496 +G01 X-1.8478 Y1.5513 +G01 X-1.8500 Y1.5515 +G01 X-1.8557 Y1.5515 +G01 X-2.3343 Y1.5515 +G01 X-2.3361 Y1.5515 +G01 X-2.3457 Y1.5515 +G01 X-2.3556 Y1.5515 +G01 X-2.3845 Y1.5635 +G01 X-2.4065 Y1.5855 +G01 X-2.4185 Y1.6144 +G01 X-2.4185 Y1.6243 +G01 X-2.4185 Y1.6348 +G01 X-2.4315 Y1.6478 +G01 X-2.4315 Y1.6822 +G01 X-2.4072 Y1.7065 +G01 X-2.3728 Y1.7065 +G01 X-2.3485 Y1.6822 +G01 X-2.3485 Y1.6478 +G01 X-2.3615 Y1.6348 +G01 X-2.3615 Y1.6300 +G01 X-2.3611 Y1.6258 +G01 X-2.3579 Y1.6181 +G01 X-2.3519 Y1.6121 +G01 X-2.3442 Y1.6089 +G01 X-2.3400 Y1.6085 +G01 X-2.3360 Y1.6085 +G01 X-2.3343 Y1.6085 +G01 X-1.8557 Y1.6085 +G01 X-1.8443 Y1.6085 +G01 X-1.8364 Y1.6085 +G01 X-1.8112 Y1.5981 +G01 X-1.7919 Y1.5788 +G01 X-1.7815 Y1.5536 +G01 X-1.7815 Y1.5457 +G01 X-1.7815 Y1.5401 +G01 X-1.7815 Y1.5400 +G01 X-1.7815 Y1.5343 +G01 X-1.7815 Y1.3385 +G01 X-1.7757 Y1.3385 +G01 X-1.7643 Y1.3385 +G01 X-1.6457 Y1.3385 +G01 X-1.6343 Y1.3385 +G01 X-1.5387 Y1.3385 +G01 X-1.5269 Y1.3503 +G01 X-1.5094 Y1.3575 +G01 X-1.4905 Y1.3575 +G01 X-1.4731 Y1.3503 +G01 X-1.4597 Y1.3369 +G01 X-1.4525 Y1.3194 +G01 X-1.4525 Y1.3005 +G01 X-1.4597 Y1.2831 +G01 X-1.4731 Y1.2697 +G01 X-1.4905 Y1.2625 +G01 X-1.5094 Y1.2625 +G01 X-1.5269 Y1.2697 +G01 X-1.5387 Y1.2815 +G01 X-1.5947 Y1.2815 +G01 X-1.5947 Y1.2512 +G01 X-1.6212 Y1.2247 +G01 X-1.6588 Y1.2247 +G01 X-1.6853 Y1.2512 +G01 X-1.6853 Y1.2815 +G01 X-1.7415 Y1.2815 +G01 X-1.7415 Y1.2302 +G01 X-1.7285 Y1.2172 +G00 Z0.1000 +G00 X-2.9915 Y1.1128 +G01 Z-0.0070 F10 +G01 X-2.9915 Y1.1472 F20 +G01 X-2.9672 Y1.1715 +G01 X-2.9328 Y1.1715 +G01 X-2.9085 Y1.1472 +G01 X-2.9085 Y1.1128 +G01 X-2.9215 Y1.0998 +G01 X-2.9215 Y1.0600 +G01 X-2.9211 Y1.0558 +G01 X-2.9179 Y1.0480 +G01 X-2.9119 Y1.0421 +G01 X-2.9042 Y1.0389 +G01 X-2.9000 Y1.0385 +G01 X-2.8950 Y1.0385 +G01 X-2.8943 Y1.0385 +G01 X-2.3472 Y1.0385 +G01 X-2.3405 Y1.0452 +G01 X-2.3253 Y1.0515 +G01 X-2.1947 Y1.0515 +G01 X-2.1795 Y1.0452 +G01 X-2.1678 Y1.0335 +G01 X-2.1615 Y1.0183 +G01 X-2.1615 Y1.0017 +G01 X-2.1678 Y0.9865 +G01 X-2.1795 Y0.9748 +G01 X-2.1947 Y0.9685 +G01 X-2.3253 Y0.9685 +G01 X-2.3405 Y0.9748 +G01 X-2.3472 Y0.9815 +G01 X-2.8943 Y0.9815 +G01 X-2.8950 Y0.9815 +G01 X-2.9057 Y0.9815 +G01 X-2.9156 Y0.9815 +G01 X-2.9445 Y0.9935 +G01 X-2.9665 Y1.0155 +G01 X-2.9785 Y1.0444 +G01 X-2.9785 Y1.0543 +G01 X-2.9785 Y1.0998 +G01 X-2.9915 Y1.1128 +G00 Z0.1000 +G00 X-2.6872 Y1.7615 +G01 Z-0.0070 F10 +G01 X-2.6528 Y1.7615 F20 +G01 X-2.6398 Y1.7485 +G01 X-2.6300 Y1.7485 +G01 X-2.6258 Y1.7489 +G01 X-2.6181 Y1.7521 +G01 X-2.6121 Y1.7581 +G01 X-2.6089 Y1.7658 +G01 X-2.6085 Y1.7700 +G01 X-2.6085 Y1.7730 +G01 X-2.6085 Y1.7757 +G01 X-2.6085 Y1.7857 +G01 X-2.6085 Y1.7956 +G01 X-2.5965 Y1.8245 +G01 X-2.5745 Y1.8465 +G01 X-2.5456 Y1.8585 +G01 X-2.5357 Y1.8585 +G01 X-2.3843 Y1.8585 +G01 X-2.3744 Y1.8585 +G01 X-2.3455 Y1.8465 +G01 X-2.3235 Y1.8245 +G01 X-2.3115 Y1.7956 +G01 X-2.3115 Y1.7857 +G01 X-2.3115 Y1.7702 +G01 X-2.3098 Y1.7685 +G01 X-2.2456 Y1.7685 +G01 X-2.2288 Y1.7853 +G01 X-2.1912 Y1.7853 +G01 X-2.1647 Y1.7588 +G01 X-2.1647 Y1.7212 +G01 X-2.1912 Y1.6947 +G01 X-2.2288 Y1.6947 +G01 X-2.2456 Y1.7115 +G01 X-2.3098 Y1.7115 +G01 X-2.3228 Y1.6985 +G01 X-2.3572 Y1.6985 +G01 X-2.3815 Y1.7228 +G01 X-2.3815 Y1.7572 +G01 X-2.3685 Y1.7702 +G01 X-2.3685 Y1.7800 +G01 X-2.3689 Y1.7842 +G01 X-2.3721 Y1.7919 +G01 X-2.3781 Y1.7979 +G01 X-2.3858 Y1.8011 +G01 X-2.3900 Y1.8015 +G01 X-2.5300 Y1.8015 +G01 X-2.5342 Y1.8011 +G01 X-2.5419 Y1.7979 +G01 X-2.5479 Y1.7919 +G01 X-2.5511 Y1.7842 +G01 X-2.5515 Y1.7800 +G01 X-2.5515 Y1.7757 +G01 X-2.5515 Y1.7730 +G01 X-2.5515 Y1.7643 +G01 X-2.5515 Y1.7544 +G01 X-2.5635 Y1.7255 +G01 X-2.5855 Y1.7035 +G01 X-2.6144 Y1.6915 +G01 X-2.6243 Y1.6915 +G01 X-2.6398 Y1.6915 +G01 X-2.6528 Y1.6785 +G01 X-2.6872 Y1.6785 +G01 X-2.7002 Y1.6915 +G01 X-2.7300 Y1.6915 +G01 X-2.7342 Y1.6911 +G01 X-2.7419 Y1.6879 +G01 X-2.7479 Y1.6819 +G01 X-2.7511 Y1.6742 +G01 X-2.7515 Y1.6700 +G01 X-2.7515 Y1.6656 +G01 X-2.7515 Y1.6643 +G01 X-2.7515 Y1.5943 +G01 X-2.7515 Y1.5864 +G01 X-2.7619 Y1.5612 +G01 X-2.7812 Y1.5419 +G01 X-2.8064 Y1.5315 +G01 X-2.8143 Y1.5315 +G01 X-2.8198 Y1.5315 +G01 X-2.8200 Y1.5315 +G01 X-2.8257 Y1.5315 +G01 X-2.9600 Y1.5315 +G01 X-2.9603 Y1.5315 +G01 X-2.9608 Y1.5312 +G01 X-2.9612 Y1.5308 +G01 X-2.9615 Y1.5303 +G01 X-2.9615 Y1.5300 +G01 X-2.9615 Y1.5243 +G01 X-2.9615 Y1.3715 +G01 X-2.9328 Y1.3715 +G01 X-2.9085 Y1.3472 +G01 X-2.9085 Y1.3128 +G01 X-2.9328 Y1.2885 +G01 X-2.9672 Y1.2885 +G01 X-2.9915 Y1.3128 +G01 X-2.9915 Y1.3146 +G01 X-3.0081 Y1.3312 +G01 X-3.0185 Y1.3564 +G01 X-3.0185 Y1.3643 +G01 X-3.0185 Y1.3665 +G01 X-3.0185 Y1.3700 +G01 X-3.0185 Y1.5243 +G01 X-3.0185 Y1.5300 +G01 X-3.0185 Y1.5416 +G01 X-3.0096 Y1.5631 +G01 X-2.9931 Y1.5796 +G01 X-2.9716 Y1.5885 +G01 X-2.9657 Y1.5885 +G01 X-2.8257 Y1.5885 +G01 X-2.8200 Y1.5885 +G01 X-2.8178 Y1.5887 +G01 X-2.8136 Y1.5904 +G01 X-2.8104 Y1.5936 +G01 X-2.8087 Y1.5978 +G01 X-2.8085 Y1.6000 +G01 X-2.8085 Y1.6643 +G01 X-2.8085 Y1.6656 +G01 X-2.8085 Y1.6757 +G01 X-2.8085 Y1.6856 +G01 X-2.7965 Y1.7145 +G01 X-2.7745 Y1.7365 +G01 X-2.7456 Y1.7485 +G01 X-2.7357 Y1.7485 +G01 X-2.7002 Y1.7485 +G01 X-2.6872 Y1.7615 +G00 Z0.1000 +G00 X-1.5915 Y0.6428 +G01 Z-0.0070 F10 +G01 X-1.5915 Y0.6772 F20 +G01 X-1.5785 Y0.6902 +G01 X-1.5785 Y0.7543 +G01 X-1.5785 Y0.7555 +G01 X-1.5785 Y0.7657 +G01 X-1.5785 Y0.7756 +G01 X-1.5665 Y0.8045 +G01 X-1.5445 Y0.8265 +G01 X-1.5156 Y0.8385 +G01 X-1.5057 Y0.8385 +G01 X-1.3372 Y0.8385 +G01 X-1.3305 Y0.8452 +G01 X-1.3153 Y0.8515 +G01 X-1.1847 Y0.8515 +G01 X-1.1695 Y0.8452 +G01 X-1.1578 Y0.8335 +G01 X-1.1515 Y0.8183 +G01 X-1.1515 Y0.8017 +G01 X-1.1578 Y0.7865 +G01 X-1.1695 Y0.7748 +G01 X-1.1847 Y0.7685 +G01 X-1.3153 Y0.7685 +G01 X-1.3305 Y0.7748 +G01 X-1.3372 Y0.7815 +G01 X-1.5000 Y0.7815 +G01 X-1.5042 Y0.7811 +G01 X-1.5119 Y0.7779 +G01 X-1.5179 Y0.7719 +G01 X-1.5211 Y0.7642 +G01 X-1.5215 Y0.7600 +G01 X-1.5215 Y0.7555 +G01 X-1.5215 Y0.7543 +G01 X-1.5215 Y0.6902 +G01 X-1.5085 Y0.6772 +G01 X-1.5085 Y0.6428 +G01 X-1.5328 Y0.6185 +G01 X-1.5672 Y0.6185 +G01 X-1.5915 Y0.6428 +G00 Z0.1000 +G00 X-0.5772 Y1.1515 +G01 Z-0.0070 F10 +G01 X-0.5428 Y1.1515 F20 +G01 X-0.5185 Y1.1272 +G01 X-0.5185 Y1.0928 +G01 X-0.5428 Y1.0685 +G01 X-0.5772 Y1.0685 +G01 X-0.5902 Y1.0815 +G01 X-0.8628 Y1.0815 +G01 X-0.8695 Y1.0748 +G01 X-0.8847 Y1.0685 +G01 X-1.0153 Y1.0685 +G01 X-1.0305 Y1.0748 +G01 X-1.0422 Y1.0865 +G01 X-1.0485 Y1.1017 +G01 X-1.0485 Y1.1183 +G01 X-1.0422 Y1.1335 +G01 X-1.0305 Y1.1452 +G01 X-1.0153 Y1.1515 +G01 X-0.8847 Y1.1515 +G01 X-0.8695 Y1.1452 +G01 X-0.8628 Y1.1385 +G01 X-0.5902 Y1.1385 +G01 X-0.5772 Y1.1515 +G00 Z0.1000 +G00 X-2.8420 Y0.5026 +G01 Z-0.0070 F10 +G01 X-2.9980 Y0.5026 F20 +G01 X-3.0160 Y0.5100 +G01 X-3.0298 Y0.5238 +G01 X-3.0372 Y0.5418 +G01 X-3.0372 Y0.5613 +G01 X-3.0298 Y0.5793 +G01 X-3.0160 Y0.5931 +G01 X-2.9980 Y0.6006 +G01 X-2.8420 Y0.6006 +G01 X-2.8240 Y0.5931 +G01 X-2.8102 Y0.5793 +G01 X-2.8099 Y0.5785 +G01 X-2.2757 Y0.5785 +G01 X-2.2700 Y0.5785 +G01 X-2.2678 Y0.5787 +G01 X-2.2636 Y0.5804 +G01 X-2.2604 Y0.5836 +G01 X-2.2587 Y0.5878 +G01 X-2.2585 Y0.5900 +G01 X-2.2585 Y0.5933 +G01 X-2.2585 Y0.5957 +G01 X-2.2585 Y0.7157 +G01 X-2.2585 Y0.7236 +G01 X-2.2481 Y0.7488 +G01 X-2.2288 Y0.7681 +G01 X-2.2036 Y0.7785 +G01 X-2.1957 Y0.7785 +G01 X-2.1906 Y0.7785 +G01 X-2.1900 Y0.7785 +G01 X-2.1843 Y0.7785 +G01 X-1.7857 Y0.7785 +G01 X-1.7800 Y0.7785 +G01 X-1.7758 Y0.7789 +G01 X-1.7681 Y0.7821 +G01 X-1.7621 Y0.7881 +G01 X-1.7589 Y0.7958 +G01 X-1.7585 Y0.8000 +G01 X-1.7585 Y0.9643 +G01 X-1.7585 Y0.9651 +G01 X-1.7585 Y0.9757 +G01 X-1.7585 Y0.9836 +G01 X-1.7481 Y1.0088 +G01 X-1.7288 Y1.0281 +G01 X-1.7036 Y1.0385 +G01 X-1.6957 Y1.0385 +G01 X-1.3372 Y1.0385 +G01 X-1.3305 Y1.0452 +G01 X-1.3153 Y1.0515 +G01 X-1.1847 Y1.0515 +G01 X-1.1695 Y1.0452 +G01 X-1.1578 Y1.0335 +G01 X-1.1515 Y1.0183 +G01 X-1.1515 Y1.0017 +G01 X-1.1578 Y0.9865 +G01 X-1.1695 Y0.9748 +G01 X-1.1847 Y0.9685 +G01 X-1.3153 Y0.9685 +G01 X-1.3305 Y0.9748 +G01 X-1.3372 Y0.9815 +G01 X-1.6900 Y0.9815 +G01 X-1.6922 Y0.9813 +G01 X-1.6964 Y0.9796 +G01 X-1.6996 Y0.9764 +G01 X-1.7013 Y0.9722 +G01 X-1.7015 Y0.9700 +G01 X-1.7015 Y0.9651 +G01 X-1.7015 Y0.9643 +G01 X-1.7015 Y0.7943 +G01 X-1.7015 Y0.7844 +G01 X-1.7135 Y0.7555 +G01 X-1.7355 Y0.7335 +G01 X-1.7644 Y0.7215 +G01 X-1.7743 Y0.7215 +G01 X-1.7767 Y0.7215 +G01 X-1.7800 Y0.7215 +G01 X-1.7857 Y0.7215 +G01 X-2.1843 Y0.7215 +G01 X-2.1900 Y0.7215 +G01 X-2.1922 Y0.7213 +G01 X-2.1964 Y0.7196 +G01 X-2.1996 Y0.7164 +G01 X-2.2013 Y0.7122 +G01 X-2.2015 Y0.7100 +G01 X-2.2015 Y0.5957 +G01 X-2.2015 Y0.5932 +G01 X-2.2015 Y0.5843 +G01 X-2.2015 Y0.5764 +G01 X-2.2119 Y0.5512 +G01 X-2.2312 Y0.5319 +G01 X-2.2564 Y0.5215 +G01 X-2.2643 Y0.5215 +G01 X-2.2689 Y0.5215 +G01 X-2.2700 Y0.5215 +G01 X-2.2757 Y0.5215 +G01 X-2.8125 Y0.5215 +G01 X-2.8240 Y0.5100 +G01 X-2.8420 Y0.5026 +G00 Z0.1000 +G00 X-1.3153 Y1.3515 +G01 Z-0.0070 F10 +G01 X-1.1847 Y1.3515 F20 +G01 X-1.1695 Y1.3452 +G01 X-1.1578 Y1.3335 +G01 X-1.1515 Y1.3183 +G01 X-1.1515 Y1.3017 +G01 X-1.1578 Y1.2865 +G01 X-1.1695 Y1.2748 +G01 X-1.1847 Y1.2685 +G01 X-1.3153 Y1.2685 +G01 X-1.3305 Y1.2748 +G01 X-1.3422 Y1.2865 +G01 X-1.3485 Y1.3017 +G01 X-1.3485 Y1.3183 +G01 X-1.3422 Y1.3335 +G01 X-1.3305 Y1.3452 +G01 X-1.3153 Y1.3515 +G00 Z0.1000 +G00 X-1.3153 Y1.2515 +G01 Z-0.0070 F10 +G01 X-1.1847 Y1.2515 F20 +G01 X-1.1695 Y1.2452 +G01 X-1.1578 Y1.2335 +G01 X-1.1515 Y1.2183 +G01 X-1.1515 Y1.2017 +G01 X-1.1578 Y1.1865 +G01 X-1.1695 Y1.1748 +G01 X-1.1847 Y1.1685 +G01 X-1.3153 Y1.1685 +G01 X-1.3305 Y1.1748 +G01 X-1.3422 Y1.1865 +G01 X-1.3485 Y1.2017 +G01 X-1.3485 Y1.2183 +G01 X-1.3422 Y1.2335 +G01 X-1.3305 Y1.2452 +G01 X-1.3153 Y1.2515 +G00 Z0.1000 +G00 X-1.3153 Y1.1515 +G01 Z-0.0070 F10 +G01 X-1.1847 Y1.1515 F20 +G01 X-1.1695 Y1.1452 +G01 X-1.1578 Y1.1335 +G01 X-1.1515 Y1.1183 +G01 X-1.1515 Y1.1017 +G01 X-1.1578 Y1.0865 +G01 X-1.1695 Y1.0748 +G01 X-1.1847 Y1.0685 +G01 X-1.3153 Y1.0685 +G01 X-1.3305 Y1.0748 +G01 X-1.3372 Y1.0815 +G01 X-1.7815 Y1.0815 +G01 X-1.7815 Y0.8743 +G01 X-1.7815 Y0.8644 +G01 X-1.7935 Y0.8355 +G01 X-1.8155 Y0.8135 +G01 X-1.8444 Y0.8015 +G01 X-1.8543 Y0.8015 +G01 X-2.2800 Y0.8015 +G01 X-2.2842 Y0.8011 +G01 X-2.2919 Y0.7979 +G01 X-2.2979 Y0.7919 +G01 X-2.3011 Y0.7842 +G01 X-2.3015 Y0.7800 +G01 X-2.3015 Y0.7543 +G01 X-2.3015 Y0.7504 +G01 X-2.3089 Y0.7325 +G01 X-2.3225 Y0.7189 +G01 X-2.3404 Y0.7115 +G01 X-2.3500 Y0.7115 +G01 X-2.3557 Y0.7115 +G01 X-2.6498 Y0.7115 +G01 X-2.6528 Y0.7085 +G01 X-2.6872 Y0.7085 +G01 X-2.7002 Y0.7215 +G01 X-2.8099 Y0.7215 +G01 X-2.8102 Y0.7207 +G01 X-2.8240 Y0.7069 +G01 X-2.8420 Y0.6994 +G01 X-2.9980 Y0.6994 +G01 X-3.0160 Y0.7069 +G01 X-3.0298 Y0.7207 +G01 X-3.0372 Y0.7387 +G01 X-3.0372 Y0.7582 +G01 X-3.0298 Y0.7762 +G01 X-3.0160 Y0.7900 +G01 X-2.9980 Y0.7974 +G01 X-2.8420 Y0.7974 +G01 X-2.8240 Y0.7900 +G01 X-2.8125 Y0.7785 +G01 X-2.7002 Y0.7785 +G01 X-2.6872 Y0.7915 +G01 X-2.6528 Y0.7915 +G01 X-2.6298 Y0.7685 +G01 X-2.3585 Y0.7685 +G01 X-2.3585 Y0.7857 +G01 X-2.3585 Y0.7956 +G01 X-2.3465 Y0.8245 +G01 X-2.3245 Y0.8465 +G01 X-2.2956 Y0.8585 +G01 X-2.2857 Y0.8585 +G01 X-1.8600 Y0.8585 +G01 X-1.8558 Y0.8589 +G01 X-1.8481 Y0.8621 +G01 X-1.8421 Y0.8681 +G01 X-1.8389 Y0.8758 +G01 X-1.8385 Y0.8800 +G01 X-1.8385 Y1.0815 +G01 X-1.8728 Y1.0815 +G01 X-1.8795 Y1.0748 +G01 X-1.8947 Y1.0685 +G01 X-2.0253 Y1.0685 +G01 X-2.0405 Y1.0748 +G01 X-2.0522 Y1.0865 +G01 X-2.0585 Y1.1017 +G01 X-2.0585 Y1.1183 +G01 X-2.0522 Y1.1335 +G01 X-2.0405 Y1.1452 +G01 X-2.0253 Y1.1515 +G01 X-1.8947 Y1.1515 +G01 X-1.8795 Y1.1452 +G01 X-1.8728 Y1.1385 +G01 X-1.8157 Y1.1385 +G01 X-1.8043 Y1.1385 +G01 X-1.3372 Y1.1385 +G01 X-1.3305 Y1.1452 +G01 X-1.3153 Y1.1515 +G00 Z0.1000 +G00 X-1.0153 Y0.9515 +G01 Z-0.0070 F10 +G01 X-0.8847 Y0.9515 F20 +G01 X-0.8695 Y0.9452 +G01 X-0.8628 Y0.9385 +G01 X-0.8357 Y0.9385 +G01 X-0.8336 Y0.9385 +G01 X-0.8243 Y0.9385 +G01 X-0.8144 Y0.9385 +G01 X-0.7855 Y0.9265 +G01 X-0.7635 Y0.9045 +G01 X-0.7515 Y0.8756 +G01 X-0.7515 Y0.8657 +G01 X-0.7515 Y0.5702 +G01 X-0.7385 Y0.5572 +G01 X-0.7385 Y0.5228 +G01 X-0.7628 Y0.4985 +G01 X-0.7972 Y0.4985 +G01 X-0.8215 Y0.5228 +G01 X-0.8215 Y0.5572 +G01 X-0.8085 Y0.5702 +G01 X-0.8085 Y0.8600 +G01 X-0.8089 Y0.8642 +G01 X-0.8121 Y0.8719 +G01 X-0.8181 Y0.8779 +G01 X-0.8258 Y0.8811 +G01 X-0.8300 Y0.8815 +G01 X-0.8337 Y0.8815 +G01 X-0.8357 Y0.8815 +G01 X-0.8628 Y0.8815 +G01 X-0.8695 Y0.8748 +G01 X-0.8847 Y0.8685 +G01 X-1.0153 Y0.8685 +G01 X-1.0305 Y0.8748 +G01 X-1.0422 Y0.8865 +G01 X-1.0485 Y0.9017 +G01 X-1.0485 Y0.9183 +G01 X-1.0422 Y0.9335 +G01 X-1.0305 Y0.9452 +G01 X-1.0153 Y0.9515 +G00 Z0.1000 +G00 X-1.0153 Y1.3515 +G01 Z-0.0070 F10 +G01 X-0.8847 Y1.3515 F20 +G01 X-0.8695 Y1.3452 +G01 X-0.8628 Y1.3385 +G01 X-0.7502 Y1.3385 +G01 X-0.7372 Y1.3515 +G01 X-0.7028 Y1.3515 +G01 X-0.6785 Y1.3272 +G01 X-0.6785 Y1.2928 +G01 X-0.7028 Y1.2685 +G01 X-0.7372 Y1.2685 +G01 X-0.7502 Y1.2815 +G01 X-0.8628 Y1.2815 +G01 X-0.8695 Y1.2748 +G01 X-0.8847 Y1.2685 +G01 X-1.0153 Y1.2685 +G01 X-1.0305 Y1.2748 +G01 X-1.0422 Y1.2865 +G01 X-1.0485 Y1.3017 +G01 X-1.0485 Y1.3183 +G01 X-1.0422 Y1.3335 +G01 X-1.0305 Y1.3452 +G01 X-1.0153 Y1.3515 +G00 Z0.1000 +G00 X-2.7015 Y1.5928 +G01 Z-0.0070 F10 +G01 X-2.7015 Y1.6272 F20 +G01 X-2.6772 Y1.6515 +G01 X-2.6428 Y1.6515 +G01 X-2.6298 Y1.6385 +G01 X-2.5285 Y1.6385 +G01 X-2.5285 Y1.7043 +G01 X-2.5285 Y1.7053 +G01 X-2.5285 Y1.7157 +G01 X-2.5285 Y1.7216 +G01 X-2.5196 Y1.7431 +G01 X-2.5031 Y1.7596 +G01 X-2.4816 Y1.7685 +G01 X-2.4757 Y1.7685 +G01 X-2.4702 Y1.7685 +G01 X-2.4572 Y1.7815 +G01 X-2.4228 Y1.7815 +G01 X-2.3985 Y1.7572 +G01 X-2.3985 Y1.7228 +G01 X-2.4228 Y1.6985 +G01 X-2.4572 Y1.6985 +G01 X-2.4702 Y1.7115 +G01 X-2.4703 Y1.7115 +G01 X-2.4708 Y1.7112 +G01 X-2.4712 Y1.7108 +G01 X-2.4715 Y1.7103 +G01 X-2.4715 Y1.7100 +G01 X-2.4715 Y1.7053 +G01 X-2.4715 Y1.7043 +G01 X-2.4715 Y1.6043 +G01 X-2.4758 Y1.5939 +G01 X-2.4839 Y1.5858 +G01 X-2.4915 Y1.5827 +G01 X-2.4915 Y1.4457 +G01 X-2.4915 Y1.4343 +G01 X-2.4915 Y1.2600 +G01 X-2.4911 Y1.2558 +G01 X-2.4879 Y1.2481 +G01 X-2.4819 Y1.2421 +G01 X-2.4742 Y1.2389 +G01 X-2.4700 Y1.2385 +G01 X-2.4663 Y1.2385 +G01 X-2.4643 Y1.2385 +G01 X-2.3472 Y1.2385 +G01 X-2.3405 Y1.2452 +G01 X-2.3253 Y1.2515 +G01 X-2.1947 Y1.2515 +G01 X-2.1795 Y1.2452 +G01 X-2.1678 Y1.2335 +G01 X-2.1615 Y1.2183 +G01 X-2.1615 Y1.2017 +G01 X-2.1678 Y1.1865 +G01 X-2.1795 Y1.1748 +G01 X-2.1947 Y1.1685 +G01 X-2.2315 Y1.1685 +G01 X-2.2315 Y1.1515 +G01 X-2.1947 Y1.1515 +G01 X-2.1795 Y1.1452 +G01 X-2.1678 Y1.1335 +G01 X-2.1615 Y1.1183 +G01 X-2.1615 Y1.1017 +G01 X-2.1678 Y1.0865 +G01 X-2.1795 Y1.0748 +G01 X-2.1947 Y1.0685 +G01 X-2.3253 Y1.0685 +G01 X-2.3405 Y1.0748 +G01 X-2.3522 Y1.0865 +G01 X-2.3585 Y1.1017 +G01 X-2.3585 Y1.1183 +G01 X-2.3522 Y1.1335 +G01 X-2.3405 Y1.1452 +G01 X-2.3253 Y1.1515 +G01 X-2.2885 Y1.1515 +G01 X-2.2885 Y1.1685 +G01 X-2.3253 Y1.1685 +G01 X-2.3405 Y1.1748 +G01 X-2.3472 Y1.1815 +G01 X-2.4643 Y1.1815 +G01 X-2.4664 Y1.1815 +G01 X-2.4757 Y1.1815 +G01 X-2.4856 Y1.1815 +G01 X-2.5145 Y1.1935 +G01 X-2.5365 Y1.2155 +G01 X-2.5485 Y1.2444 +G01 X-2.5485 Y1.2543 +G01 X-2.5485 Y1.4115 +G01 X-2.8634 Y1.4115 +G01 X-2.8739 Y1.4010 +G01 X-2.8908 Y1.3940 +G01 X-2.9091 Y1.3940 +G01 X-2.9261 Y1.4010 +G01 X-2.9390 Y1.4139 +G01 X-2.9460 Y1.4308 +G01 X-2.9460 Y1.4491 +G01 X-2.9390 Y1.4661 +G01 X-2.9261 Y1.4790 +G01 X-2.9091 Y1.4860 +G01 X-2.8908 Y1.4860 +G01 X-2.8739 Y1.4790 +G01 X-2.8634 Y1.4685 +G01 X-2.5485 Y1.4685 +G01 X-2.5485 Y1.5815 +G01 X-2.6298 Y1.5815 +G01 X-2.6428 Y1.5685 +G01 X-2.6772 Y1.5685 +G01 X-2.7015 Y1.5928 +G00 Z0.1000 +G00 X-2.0575 Y0.2505 +G01 Z-0.0070 F10 +G01 X-2.0575 Y0.2694 F20 +G01 X-2.0503 Y0.2869 +G01 X-2.0385 Y0.2987 +G01 X-2.0385 Y0.3056 +G01 X-2.0265 Y0.3345 +G01 X-2.0045 Y0.3565 +G01 X-1.9756 Y0.3685 +G01 X-1.9657 Y0.3685 +G01 X-1.8587 Y0.3685 +G01 X-1.8485 Y0.3787 +G01 X-1.8485 Y0.4613 +G01 X-1.8587 Y0.4715 +G01 X-1.8656 Y0.4715 +G01 X-1.8945 Y0.4835 +G01 X-1.9165 Y0.5055 +G01 X-1.9285 Y0.5344 +G01 X-1.9453 Y0.5512 +G01 X-1.9453 Y0.5888 +G01 X-1.9188 Y0.6153 +G01 X-1.8812 Y0.6153 +G01 X-1.8547 Y0.5888 +G01 X-1.8547 Y0.5512 +G01 X-1.8679 Y0.5381 +G01 X-1.8619 Y0.5321 +G01 X-1.8571 Y0.5301 +G01 X-1.8469 Y0.5403 +G01 X-1.8294 Y0.5475 +G01 X-1.8105 Y0.5475 +G01 X-1.7931 Y0.5403 +G01 X-1.7797 Y0.5269 +G01 X-1.7725 Y0.5094 +G01 X-1.7725 Y0.4905 +G01 X-1.7797 Y0.4731 +G01 X-1.7915 Y0.4613 +G01 X-1.7915 Y0.3787 +G01 X-1.7797 Y0.3669 +G01 X-1.7725 Y0.3494 +G01 X-1.7725 Y0.3305 +G01 X-1.7797 Y0.3131 +G01 X-1.7931 Y0.2997 +G01 X-1.8105 Y0.2925 +G01 X-1.8294 Y0.2925 +G01 X-1.8469 Y0.2997 +G01 X-1.8587 Y0.3115 +G01 X-1.9600 Y0.3115 +G01 X-1.9642 Y0.3111 +G01 X-1.9719 Y0.3079 +G01 X-1.9779 Y0.3019 +G01 X-1.9799 Y0.2971 +G01 X-1.9697 Y0.2869 +G01 X-1.9625 Y0.2694 +G01 X-1.9625 Y0.2505 +G01 X-1.9697 Y0.2331 +G01 X-1.9831 Y0.2197 +G01 X-2.0005 Y0.2125 +G01 X-2.0194 Y0.2125 +G01 X-2.0369 Y0.2197 +G01 X-2.0503 Y0.2331 +G01 X-2.0575 Y0.2505 +G00 Z0.1000 +G00 X-0.5856 Y1.5715 +G01 Z-0.0070 F10 +G01 X-0.5856 Y1.5715 F20 +G01 X-0.6145 Y1.5835 +G01 X-0.6365 Y1.6055 +G01 X-0.6485 Y1.6344 +G01 X-0.6485 Y1.6443 +G01 X-0.6485 Y1.6500 +G01 X-0.6485 Y1.6557 +G01 X-0.6485 Y1.7200 +G01 X-0.6487 Y1.7222 +G01 X-0.6504 Y1.7264 +G01 X-0.6536 Y1.7296 +G01 X-0.6578 Y1.7313 +G01 X-0.6600 Y1.7315 +G01 X-1.3043 Y1.7315 +G01 X-1.3055 Y1.7315 +G01 X-1.3157 Y1.7315 +G01 X-1.3256 Y1.7315 +G01 X-1.3545 Y1.7435 +G01 X-1.3765 Y1.7655 +G01 X-1.3885 Y1.7944 +G01 X-1.3885 Y1.8043 +G01 X-1.3885 Y1.8234 +G01 X-1.4060 Y1.8409 +G01 X-1.4060 Y1.8791 +G01 X-1.3885 Y1.8966 +G01 X-1.3885 Y1.9543 +G01 X-1.3885 Y1.9590 +G01 X-1.3885 Y1.9600 +G01 X-1.3889 Y1.9642 +G01 X-1.3921 Y1.9719 +G01 X-1.3981 Y1.9779 +G01 X-1.4058 Y1.9811 +G01 X-1.4100 Y1.9815 +G01 X-1.4157 Y1.9815 +G01 X-1.5643 Y1.9815 +G01 X-1.5700 Y1.9815 +G01 X-1.5742 Y1.9811 +G01 X-1.5819 Y1.9779 +G01 X-1.5879 Y1.9719 +G01 X-1.5911 Y1.9642 +G01 X-1.5915 Y1.9600 +G01 X-1.5915 Y1.7957 +G01 X-1.5915 Y1.7743 +G01 X-1.5915 Y1.6357 +G01 X-1.5915 Y1.6300 +G01 X-1.5911 Y1.6258 +G01 X-1.5879 Y1.6181 +G01 X-1.5819 Y1.6121 +G01 X-1.5742 Y1.6089 +G01 X-1.5700 Y1.6085 +G01 X-1.5694 Y1.6085 +G01 X-1.5643 Y1.6085 +G01 X-1.1443 Y1.6085 +G01 X-1.1344 Y1.6085 +G01 X-1.1055 Y1.5965 +G01 X-1.0835 Y1.5745 +G01 X-1.0715 Y1.5456 +G01 X-1.0715 Y1.5357 +G01 X-1.0715 Y1.5304 +G01 X-1.0715 Y1.5300 +G01 X-1.0715 Y1.5243 +G01 X-1.0715 Y0.8600 +G01 X-1.0711 Y0.8558 +G01 X-1.0679 Y0.8480 +G01 X-1.0619 Y0.8421 +G01 X-1.0542 Y0.8389 +G01 X-1.0500 Y0.8385 +G01 X-1.0450 Y0.8385 +G01 X-1.0443 Y0.8385 +G01 X-1.0372 Y0.8385 +G01 X-1.0305 Y0.8452 +G01 X-1.0153 Y0.8515 +G01 X-0.8847 Y0.8515 +G01 X-0.8695 Y0.8452 +G01 X-0.8578 Y0.8335 +G01 X-0.8515 Y0.8183 +G01 X-0.8515 Y0.8017 +G01 X-0.8578 Y0.7865 +G01 X-0.8695 Y0.7748 +G01 X-0.8847 Y0.7685 +G01 X-1.0153 Y0.7685 +G01 X-1.0305 Y0.7748 +G01 X-1.0372 Y0.7815 +G01 X-1.0443 Y0.7815 +G01 X-1.0450 Y0.7815 +G01 X-1.0557 Y0.7815 +G01 X-1.0656 Y0.7815 +G01 X-1.0945 Y0.7935 +G01 X-1.1165 Y0.8155 +G01 X-1.1285 Y0.8444 +G01 X-1.1285 Y0.8543 +G01 X-1.1285 Y1.5243 +G01 X-1.1285 Y1.5300 +G01 X-1.1289 Y1.5342 +G01 X-1.1321 Y1.5419 +G01 X-1.1381 Y1.5479 +G01 X-1.1458 Y1.5511 +G01 X-1.1500 Y1.5515 +G01 X-1.5643 Y1.5515 +G01 X-1.5694 Y1.5515 +G01 X-1.5757 Y1.5515 +G01 X-1.5856 Y1.5515 +G01 X-1.6145 Y1.5635 +G01 X-1.6365 Y1.5855 +G01 X-1.6485 Y1.6144 +G01 X-1.6485 Y1.6243 +G01 X-1.6485 Y1.6299 +G01 X-1.6485 Y1.6357 +G01 X-1.6485 Y1.7615 +G01 X-1.9344 Y1.7615 +G01 X-1.9512 Y1.7447 +G01 X-1.9888 Y1.7447 +G01 X-2.0153 Y1.7712 +G01 X-2.0153 Y1.8088 +G01 X-1.9888 Y1.8353 +G01 X-1.9512 Y1.8353 +G01 X-1.9344 Y1.8185 +G01 X-1.6485 Y1.8185 +G01 X-1.6485 Y1.9657 +G01 X-1.6485 Y1.9756 +G01 X-1.6365 Y2.0045 +G01 X-1.6145 Y2.0265 +G01 X-1.5856 Y2.0385 +G01 X-1.5757 Y2.0385 +G01 X-1.5707 Y2.0385 +G01 X-1.5700 Y2.0385 +G01 X-1.5643 Y2.0385 +G01 X-1.4157 Y2.0385 +G01 X-1.4100 Y2.0385 +G01 X-1.4065 Y2.0385 +G01 X-1.4043 Y2.0385 +G01 X-1.3944 Y2.0385 +G01 X-1.3655 Y2.0265 +G01 X-1.3435 Y2.0045 +G01 X-1.3315 Y1.9756 +G01 X-1.3315 Y1.9657 +G01 X-1.3315 Y1.9590 +G01 X-1.3315 Y1.9543 +G01 X-1.3315 Y1.8966 +G01 X-1.3140 Y1.8791 +G01 X-1.3140 Y1.8409 +G01 X-1.3315 Y1.8234 +G01 X-1.3315 Y1.8100 +G01 X-1.3311 Y1.8058 +G01 X-1.3279 Y1.7981 +G01 X-1.3219 Y1.7921 +G01 X-1.3142 Y1.7889 +G01 X-1.3100 Y1.7885 +G01 X-1.3055 Y1.7885 +G01 X-1.3043 Y1.7885 +G01 X-0.6543 Y1.7885 +G01 X-0.6464 Y1.7885 +G01 X-0.6212 Y1.7781 +G01 X-0.6019 Y1.7588 +G01 X-0.5915 Y1.7336 +G01 X-0.5915 Y1.7257 +G01 X-0.5915 Y1.6557 +G01 X-0.5915 Y1.6500 +G01 X-0.5911 Y1.6458 +G01 X-0.5879 Y1.6381 +G01 X-0.5819 Y1.6321 +G01 X-0.5742 Y1.6289 +G01 X-0.5700 Y1.6285 +G01 X-0.3006 Y1.6285 +G01 X-0.2960 Y1.6331 +G01 X-0.2780 Y1.6406 +G01 X-0.1220 Y1.6406 +G01 X-0.1040 Y1.6331 +G01 X-0.0902 Y1.6193 +G01 X-0.0828 Y1.6013 +G01 X-0.0828 Y1.5818 +G01 X-0.0902 Y1.5638 +G01 X-0.1040 Y1.5500 +G01 X-0.1220 Y1.5426 +G01 X-0.2780 Y1.5426 +G01 X-0.2960 Y1.5500 +G01 X-0.3098 Y1.5638 +G01 X-0.3130 Y1.5715 +G01 X-0.5757 Y1.5715 +G01 X-0.5856 Y1.5715 +G00 Z0.1000 +G00 X-2.9215 Y1.7664 +G01 Z-0.0070 F10 +G01 X-2.9215 Y1.7664 F20 +G01 X-2.9319 Y1.7412 +G01 X-2.9512 Y1.7219 +G01 X-2.9764 Y1.7115 +G01 X-2.9843 Y1.7115 +G01 X-2.9896 Y1.7115 +G01 X-2.9900 Y1.7115 +G01 X-2.9957 Y1.7115 +G01 X-3.1100 Y1.7115 +G01 X-3.1142 Y1.7111 +G01 X-3.1219 Y1.7079 +G01 X-3.1279 Y1.7019 +G01 X-3.1311 Y1.6942 +G01 X-3.1315 Y1.6900 +G01 X-3.1315 Y1.6850 +G01 X-3.1315 Y1.6843 +G01 X-3.1315 Y1.6402 +G01 X-3.1185 Y1.6272 +G01 X-3.1185 Y1.5928 +G01 X-3.1315 Y1.5798 +G01 X-3.1315 Y0.9600 +G01 X-3.1311 Y0.9558 +G01 X-3.1279 Y0.9481 +G01 X-3.1219 Y0.9421 +G01 X-3.1142 Y0.9389 +G01 X-3.1100 Y0.9385 +G01 X-3.1057 Y0.9385 +G01 X-3.1043 Y0.9385 +G01 X-2.5456 Y0.9385 +G01 X-2.5288 Y0.9553 +G01 X-2.4912 Y0.9553 +G01 X-2.4744 Y0.9385 +G01 X-2.1657 Y0.9385 +G01 X-2.1600 Y0.9385 +G01 X-2.1558 Y0.9389 +G01 X-2.1481 Y0.9421 +G01 X-2.1421 Y0.9481 +G01 X-2.1389 Y0.9558 +G01 X-2.1385 Y0.9600 +G01 X-2.1385 Y1.0657 +G01 X-2.1385 Y1.2782 +G01 X-2.1418 Y1.2815 +G01 X-2.1728 Y1.2815 +G01 X-2.1795 Y1.2748 +G01 X-2.1947 Y1.2685 +G01 X-2.3253 Y1.2685 +G01 X-2.3405 Y1.2748 +G01 X-2.3522 Y1.2865 +G01 X-2.3585 Y1.3017 +G01 X-2.3585 Y1.3183 +G01 X-2.3522 Y1.3335 +G01 X-2.3405 Y1.3452 +G01 X-2.3253 Y1.3515 +G01 X-2.1947 Y1.3515 +G01 X-2.1795 Y1.3452 +G01 X-2.1728 Y1.3385 +G01 X-2.1243 Y1.3385 +G01 X-2.1204 Y1.3385 +G01 X-2.1025 Y1.3311 +G01 X-2.0889 Y1.3175 +G01 X-2.0815 Y1.2996 +G01 X-2.0815 Y1.2957 +G01 X-2.0815 Y1.2843 +G01 X-2.0815 Y1.0657 +G01 X-2.0815 Y1.0518 +G01 X-2.0682 Y1.0385 +G01 X-2.0472 Y1.0385 +G01 X-2.0405 Y1.0452 +G01 X-2.0253 Y1.0515 +G01 X-1.8947 Y1.0515 +G01 X-1.8795 Y1.0452 +G01 X-1.8678 Y1.0335 +G01 X-1.8615 Y1.0183 +G01 X-1.8615 Y1.0017 +G01 X-1.8678 Y0.9865 +G01 X-1.8795 Y0.9748 +G01 X-1.8947 Y0.9685 +G01 X-2.0253 Y0.9685 +G01 X-2.0405 Y0.9748 +G01 X-2.0472 Y0.9815 +G01 X-2.0743 Y0.9815 +G01 X-2.0815 Y0.9815 +G01 X-2.0815 Y0.9543 +G01 X-2.0815 Y0.9444 +G01 X-2.0935 Y0.9155 +G01 X-2.1155 Y0.8935 +G01 X-2.1444 Y0.8815 +G01 X-2.1543 Y0.8815 +G01 X-2.1588 Y0.8815 +G01 X-2.1600 Y0.8815 +G01 X-2.1657 Y0.8815 +G01 X-2.4744 Y0.8815 +G01 X-2.4912 Y0.8647 +G01 X-2.5288 Y0.8647 +G01 X-2.5456 Y0.8815 +G01 X-3.1043 Y0.8815 +G01 X-3.1057 Y0.8815 +G01 X-3.1157 Y0.8815 +G01 X-3.1256 Y0.8815 +G01 X-3.1545 Y0.8935 +G01 X-3.1765 Y0.9155 +G01 X-3.1885 Y0.9444 +G01 X-3.1885 Y0.9543 +G01 X-3.1885 Y1.5798 +G01 X-3.2015 Y1.5928 +G01 X-3.2015 Y1.6272 +G01 X-3.1885 Y1.6402 +G01 X-3.1885 Y1.6843 +G01 X-3.1885 Y1.6850 +G01 X-3.1885 Y1.6957 +G01 X-3.1885 Y1.7056 +G01 X-3.1765 Y1.7345 +G01 X-3.1545 Y1.7565 +G01 X-3.1256 Y1.7685 +G01 X-3.1157 Y1.7685 +G01 X-2.9957 Y1.7685 +G01 X-2.9900 Y1.7685 +G01 X-2.9878 Y1.7687 +G01 X-2.9836 Y1.7704 +G01 X-2.9804 Y1.7736 +G01 X-2.9787 Y1.7778 +G01 X-2.9785 Y1.7800 +G01 X-2.9785 Y1.8543 +G01 X-2.9785 Y1.8559 +G01 X-2.9785 Y1.8657 +G01 X-2.9785 Y1.8756 +G01 X-2.9665 Y1.9045 +G01 X-2.9445 Y1.9265 +G01 X-2.9156 Y1.9385 +G01 X-2.9057 Y1.9385 +G01 X-2.0957 Y1.9385 +G01 X-2.0843 Y1.9385 +G01 X-2.0302 Y1.9385 +G01 X-2.0172 Y1.9515 +G01 X-1.9828 Y1.9515 +G01 X-1.9698 Y1.9385 +G01 X-1.7700 Y1.9385 +G01 X-1.7658 Y1.9389 +G01 X-1.7581 Y1.9421 +G01 X-1.7521 Y1.9481 +G01 X-1.7489 Y1.9558 +G01 X-1.7485 Y1.9600 +G01 X-1.7485 Y1.9644 +G01 X-1.7485 Y1.9657 +G01 X-1.7485 Y2.0657 +G01 X-1.7485 Y2.0756 +G01 X-1.7365 Y2.1045 +G01 X-1.7145 Y2.1265 +G01 X-1.6856 Y2.1385 +G01 X-1.6757 Y2.1385 +G01 X-1.6703 Y2.1385 +G01 X-1.6700 Y2.1385 +G01 X-1.6643 Y2.1385 +G01 X-1.2543 Y2.1385 +G01 X-1.2444 Y2.1385 +G01 X-1.2155 Y2.1265 +G01 X-1.1935 Y2.1045 +G01 X-1.1815 Y2.0756 +G01 X-1.1815 Y2.0657 +G01 X-1.1815 Y2.0606 +G01 X-1.1815 Y2.0600 +G01 X-1.1815 Y2.0543 +G01 X-1.1815 Y1.9157 +G01 X-1.1815 Y1.9100 +G01 X-1.1811 Y1.9058 +G01 X-1.1779 Y1.8981 +G01 X-1.1719 Y1.8921 +G01 X-1.1642 Y1.8889 +G01 X-1.1600 Y1.8885 +G01 X-1.1559 Y1.8885 +G01 X-1.1543 Y1.8885 +G01 X-0.7966 Y1.8885 +G01 X-0.7861 Y1.8990 +G01 X-0.7691 Y1.9060 +G01 X-0.7508 Y1.9060 +G01 X-0.7339 Y1.8990 +G01 X-0.7234 Y1.8885 +G01 X-0.2659 Y1.8885 +G01 X-0.2517 Y1.8885 +G01 X-0.2149 Y1.8733 +G01 X-0.1867 Y1.8451 +G01 X-0.1836 Y1.8374 +G01 X-0.1220 Y1.8374 +G01 X-0.1040 Y1.8300 +G01 X-0.0902 Y1.8162 +G01 X-0.0828 Y1.7982 +G01 X-0.0828 Y1.7787 +G01 X-0.0902 Y1.7607 +G01 X-0.1040 Y1.7469 +G01 X-0.1220 Y1.7394 +G01 X-0.2780 Y1.7394 +G01 X-0.2960 Y1.7469 +G01 X-0.3098 Y1.7607 +G01 X-0.3172 Y1.7787 +G01 X-0.3172 Y1.7982 +G01 X-0.3098 Y1.8162 +G01 X-0.2960 Y1.8300 +G01 X-0.2923 Y1.8315 +G01 X-0.7234 Y1.8315 +G01 X-0.7339 Y1.8210 +G01 X-0.7508 Y1.8140 +G01 X-0.7691 Y1.8140 +G01 X-0.7861 Y1.8210 +G01 X-0.7966 Y1.8315 +G01 X-1.1543 Y1.8315 +G01 X-1.1559 Y1.8315 +G01 X-1.1657 Y1.8315 +G01 X-1.1756 Y1.8315 +G01 X-1.2045 Y1.8435 +G01 X-1.2265 Y1.8655 +G01 X-1.2385 Y1.8944 +G01 X-1.2385 Y1.9043 +G01 X-1.2385 Y1.9060 +G01 X-1.2385 Y1.9100 +G01 X-1.2385 Y1.9157 +G01 X-1.2385 Y2.0543 +G01 X-1.2385 Y2.0600 +G01 X-1.2389 Y2.0642 +G01 X-1.2421 Y2.0719 +G01 X-1.2481 Y2.0779 +G01 X-1.2558 Y2.0811 +G01 X-1.2600 Y2.0815 +G01 X-1.6643 Y2.0815 +G01 X-1.6700 Y2.0815 +G01 X-1.6742 Y2.0811 +G01 X-1.6819 Y2.0779 +G01 X-1.6879 Y2.0719 +G01 X-1.6911 Y2.0642 +G01 X-1.6915 Y2.0600 +G01 X-1.6915 Y1.9657 +G01 X-1.6915 Y1.9644 +G01 X-1.6915 Y1.9543 +G01 X-1.6915 Y1.9444 +G01 X-1.7035 Y1.9155 +G01 X-1.7255 Y1.8935 +G01 X-1.7544 Y1.8815 +G01 X-1.7643 Y1.8815 +G01 X-1.9698 Y1.8815 +G01 X-1.9828 Y1.8685 +G01 X-2.0172 Y1.8685 +G01 X-2.0302 Y1.8815 +G01 X-2.0615 Y1.8815 +G01 X-2.0615 Y1.7500 +G01 X-2.0611 Y1.7458 +G01 X-2.0579 Y1.7381 +G01 X-2.0519 Y1.7321 +G01 X-2.0442 Y1.7289 +G01 X-2.0400 Y1.7285 +G01 X-2.0354 Y1.7285 +G01 X-2.0343 Y1.7285 +G01 X-1.8002 Y1.7285 +G01 X-1.7872 Y1.7415 +G01 X-1.7528 Y1.7415 +G01 X-1.7398 Y1.7285 +G01 X-1.7343 Y1.7285 +G01 X-1.7284 Y1.7285 +G01 X-1.7069 Y1.7196 +G01 X-1.6904 Y1.7031 +G01 X-1.6815 Y1.6816 +G01 X-1.6815 Y1.6757 +G01 X-1.6815 Y1.5100 +G01 X-1.6811 Y1.5058 +G01 X-1.6779 Y1.4981 +G01 X-1.6719 Y1.4921 +G01 X-1.6642 Y1.4889 +G01 X-1.6600 Y1.4885 +G01 X-1.6578 Y1.4885 +G01 X-1.6543 Y1.4885 +G01 X-1.4657 Y1.4885 +G01 X-1.4600 Y1.4885 +G01 X-1.4567 Y1.4885 +G01 X-1.4543 Y1.4885 +G01 X-1.4444 Y1.4885 +G01 X-1.4155 Y1.4765 +G01 X-1.3935 Y1.4545 +G01 X-1.3852 Y1.4345 +G01 X-1.3756 Y1.4385 +G01 X-1.3657 Y1.4385 +G01 X-1.3596 Y1.4385 +G01 X-1.3543 Y1.4385 +G01 X-1.3372 Y1.4385 +G01 X-1.3305 Y1.4452 +G01 X-1.3153 Y1.4515 +G01 X-1.1847 Y1.4515 +G01 X-1.1695 Y1.4452 +G01 X-1.1578 Y1.4335 +G01 X-1.1515 Y1.4183 +G01 X-1.1515 Y1.4017 +G01 X-1.1578 Y1.3865 +G01 X-1.1695 Y1.3748 +G01 X-1.1847 Y1.3685 +G01 X-1.3153 Y1.3685 +G01 X-1.3305 Y1.3748 +G01 X-1.3372 Y1.3815 +G01 X-1.3543 Y1.3815 +G01 X-1.3596 Y1.3815 +G01 X-1.3600 Y1.3815 +G01 X-1.3642 Y1.3811 +G01 X-1.3719 Y1.3779 +G01 X-1.3779 Y1.3719 +G01 X-1.3811 Y1.3642 +G01 X-1.3815 Y1.3600 +G01 X-1.3815 Y1.2543 +G01 X-1.3815 Y1.2450 +G01 X-1.3815 Y1.2351 +G01 X-1.3885 Y1.2182 +G01 X-1.3885 Y1.1928 +G01 X-1.4128 Y1.1685 +G01 X-1.4472 Y1.1685 +G01 X-1.4715 Y1.1928 +G01 X-1.4715 Y1.2272 +G01 X-1.4472 Y1.2515 +G01 X-1.4385 Y1.2515 +G01 X-1.4385 Y1.2543 +G01 X-1.4385 Y1.4100 +G01 X-1.4389 Y1.4142 +G01 X-1.4421 Y1.4219 +G01 X-1.4481 Y1.4279 +G01 X-1.4558 Y1.4311 +G01 X-1.4600 Y1.4315 +G01 X-1.4657 Y1.4315 +G01 X-1.6543 Y1.4315 +G01 X-1.6578 Y1.4315 +G01 X-1.6657 Y1.4315 +G01 X-1.6756 Y1.4315 +G01 X-1.7045 Y1.4435 +G01 X-1.7265 Y1.4655 +G01 X-1.7385 Y1.4944 +G01 X-1.7385 Y1.5043 +G01 X-1.7385 Y1.6700 +G01 X-1.7385 Y1.6703 +G01 X-1.7387 Y1.6708 +G01 X-1.7392 Y1.6712 +G01 X-1.7397 Y1.6715 +G01 X-1.7398 Y1.6715 +G01 X-1.7528 Y1.6585 +G01 X-1.7872 Y1.6585 +G01 X-1.7999 Y1.6712 +G01 X-1.8011 Y1.6715 +G01 X-2.0343 Y1.6715 +G01 X-2.0354 Y1.6715 +G01 X-2.0457 Y1.6715 +G01 X-2.0556 Y1.6715 +G01 X-2.0845 Y1.6835 +G01 X-2.1065 Y1.7055 +G01 X-2.1185 Y1.7344 +G01 X-2.1185 Y1.7443 +G01 X-2.1185 Y1.8815 +G01 X-2.9000 Y1.8815 +G01 X-2.9042 Y1.8811 +G01 X-2.9119 Y1.8779 +G01 X-2.9179 Y1.8719 +G01 X-2.9211 Y1.8642 +G01 X-2.9215 Y1.8600 +G01 X-2.9215 Y1.8559 +G01 X-2.9215 Y1.8543 +G01 X-2.9215 Y1.7743 +G01 X-2.9215 Y1.7664 +G00 Z0.1000 +G00 X-3.0985 Y1.6156 +G01 Z-0.0070 F10 +G01 X-3.0985 Y1.6156 F20 +G01 X-3.0865 Y1.6445 +G01 X-3.0645 Y1.6665 +G01 X-3.0356 Y1.6785 +G01 X-3.0257 Y1.6785 +G01 X-3.0197 Y1.6785 +G01 X-3.0143 Y1.6785 +G01 X-2.9000 Y1.6785 +G01 X-2.8997 Y1.6785 +G01 X-2.8992 Y1.6787 +G01 X-2.8987 Y1.6792 +G01 X-2.8985 Y1.6797 +G01 X-2.8985 Y1.6800 +G01 X-2.8985 Y1.6843 +G01 X-2.8985 Y1.6857 +G01 X-2.8985 Y1.7757 +G01 X-2.8985 Y1.7856 +G01 X-2.8865 Y1.8145 +G01 X-2.8645 Y1.8365 +G01 X-2.8356 Y1.8485 +G01 X-2.8257 Y1.8485 +G01 X-2.8204 Y1.8485 +G01 X-2.8200 Y1.8485 +G01 X-2.8143 Y1.8485 +G01 X-2.7002 Y1.8485 +G01 X-2.6872 Y1.8615 +G01 X-2.6528 Y1.8615 +G01 X-2.6285 Y1.8372 +G01 X-2.6285 Y1.8028 +G01 X-2.6528 Y1.7785 +G01 X-2.6872 Y1.7785 +G01 X-2.7002 Y1.7915 +G01 X-2.8143 Y1.7915 +G01 X-2.8200 Y1.7915 +G01 X-2.8242 Y1.7911 +G01 X-2.8319 Y1.7879 +G01 X-2.8379 Y1.7819 +G01 X-2.8411 Y1.7742 +G01 X-2.8415 Y1.7700 +G01 X-2.8415 Y1.6857 +G01 X-2.8415 Y1.6842 +G01 X-2.8415 Y1.6743 +G01 X-2.8415 Y1.6684 +G01 X-2.8504 Y1.6469 +G01 X-2.8669 Y1.6304 +G01 X-2.8884 Y1.6215 +G01 X-2.8943 Y1.6215 +G01 X-3.0143 Y1.6215 +G01 X-3.0198 Y1.6215 +G01 X-3.0200 Y1.6215 +G01 X-3.0242 Y1.6211 +G01 X-3.0319 Y1.6179 +G01 X-3.0379 Y1.6119 +G01 X-3.0411 Y1.6042 +G01 X-3.0415 Y1.6000 +G01 X-3.0415 Y1.2900 +G01 X-3.0411 Y1.2858 +G01 X-3.0379 Y1.2781 +G01 X-3.0319 Y1.2721 +G01 X-3.0242 Y1.2689 +G01 X-3.0200 Y1.2685 +G01 X-2.7228 Y1.2685 +G01 X-2.7200 Y1.2691 +G01 X-2.7172 Y1.2685 +G01 X-2.7143 Y1.2685 +G01 X-2.7117 Y1.2674 +G01 X-2.7113 Y1.2673 +G01 X-2.6872 Y1.2915 +G01 X-2.6528 Y1.2915 +G01 X-2.6285 Y1.2672 +G01 X-2.6285 Y1.2328 +G01 X-2.6528 Y1.2085 +G01 X-2.6783 Y1.2085 +G01 X-2.6999 Y1.2042 +G01 X-2.7251 Y1.2092 +G01 X-2.7286 Y1.2115 +G01 X-3.0257 Y1.2115 +G01 X-3.0356 Y1.2115 +G01 X-3.0645 Y1.2235 +G01 X-3.0865 Y1.2455 +G01 X-3.0985 Y1.2744 +G01 X-3.0985 Y1.2843 +G01 X-3.0985 Y1.6057 +G01 X-3.0985 Y1.6156 +G00 Z0.1000 +G00 X-2.1685 Y0.6256 +G01 Z-0.0070 F10 +G01 X-2.1685 Y0.6256 F20 +G01 X-2.1565 Y0.6545 +G01 X-2.1345 Y0.6765 +G01 X-2.1056 Y0.6885 +G01 X-2.0957 Y0.6885 +G01 X-2.0899 Y0.6885 +G01 X-2.0843 Y0.6885 +G01 X-2.0487 Y0.6885 +G01 X-2.0369 Y0.7003 +G01 X-2.0194 Y0.7075 +G01 X-2.0005 Y0.7075 +G01 X-1.9831 Y0.7003 +G01 X-1.9713 Y0.6885 +G01 X-1.7802 Y0.6885 +G01 X-1.7672 Y0.7015 +G01 X-1.7328 Y0.7015 +G01 X-1.7085 Y0.6772 +G01 X-1.7085 Y0.6428 +G01 X-1.7328 Y0.6185 +G01 X-1.7672 Y0.6185 +G01 X-1.7802 Y0.6315 +G01 X-1.9713 Y0.6315 +G01 X-1.9831 Y0.6197 +G01 X-2.0005 Y0.6125 +G01 X-2.0194 Y0.6125 +G01 X-2.0369 Y0.6197 +G01 X-2.0487 Y0.6315 +G01 X-2.0843 Y0.6315 +G01 X-2.0900 Y0.6315 +G01 X-2.0942 Y0.6311 +G01 X-2.1019 Y0.6279 +G01 X-2.1079 Y0.6219 +G01 X-2.1111 Y0.6142 +G01 X-2.1115 Y0.6100 +G01 X-2.1115 Y0.2902 +G01 X-2.0985 Y0.2772 +G01 X-2.0985 Y0.2428 +G01 X-2.1228 Y0.2185 +G01 X-2.1572 Y0.2185 +G01 X-2.1815 Y0.2428 +G01 X-2.1815 Y0.2772 +G01 X-2.1685 Y0.2902 +G01 X-2.1685 Y0.6157 +G01 X-2.1685 Y0.6256 +G00 Z0.1000 +G00 X-0.5315 Y0.4744 +G01 Z-0.0070 F10 +G01 X-0.5315 Y0.4744 F20 +G01 X-0.5435 Y0.4455 +G01 X-0.5655 Y0.4235 +G01 X-0.5944 Y0.4115 +G01 X-0.6043 Y0.4115 +G01 X-0.6100 Y0.4115 +G01 X-0.6157 Y0.4115 +G01 X-1.3757 Y0.4115 +G01 X-1.3856 Y0.4115 +G01 X-1.4145 Y0.4235 +G01 X-1.4365 Y0.4455 +G01 X-1.4415 Y0.4575 +G01 X-1.4469 Y0.4597 +G01 X-1.4603 Y0.4731 +G01 X-1.4675 Y0.4905 +G01 X-1.4675 Y0.5094 +G01 X-1.4603 Y0.5269 +G01 X-1.4585 Y0.5287 +G01 X-1.4585 Y0.6798 +G01 X-1.4715 Y0.6928 +G01 X-1.4715 Y0.7272 +G01 X-1.4472 Y0.7515 +G01 X-1.4128 Y0.7515 +G01 X-1.3885 Y0.7272 +G01 X-1.3885 Y0.6928 +G01 X-1.4015 Y0.6798 +G01 X-1.4015 Y0.5437 +G01 X-1.3931 Y0.5403 +G01 X-1.3797 Y0.5269 +G01 X-1.3725 Y0.5094 +G01 X-1.3725 Y0.4905 +G01 X-1.3797 Y0.4731 +G01 X-1.3811 Y0.4718 +G01 X-1.3742 Y0.4689 +G01 X-1.3700 Y0.4685 +G01 X-0.6157 Y0.4685 +G01 X-0.6100 Y0.4685 +G01 X-0.6058 Y0.4689 +G01 X-0.5981 Y0.4721 +G01 X-0.5921 Y0.4781 +G01 X-0.5889 Y0.4858 +G01 X-0.5885 Y0.4900 +G01 X-0.5885 Y0.8798 +G01 X-0.6015 Y0.8928 +G01 X-0.6015 Y0.9272 +G01 X-0.5772 Y0.9515 +G01 X-0.5428 Y0.9515 +G01 X-0.5185 Y0.9272 +G01 X-0.5185 Y0.8928 +G01 X-0.5315 Y0.8798 +G01 X-0.5315 Y0.4843 +G01 X-0.5315 Y0.4744 +G00 Z0.1000 +G00 X-0.4285 Y0.2838 +G01 Z-0.0070 F10 +G01 X-0.4285 Y0.2838 F20 +G01 X-0.4409 Y0.2538 +G01 X-0.4638 Y0.2309 +G01 X-0.4938 Y0.2185 +G01 X-0.5037 Y0.2185 +G01 X-0.5100 Y0.2185 +G01 X-0.5163 Y0.2185 +G01 X-1.0400 Y0.2185 +G01 X-1.0436 Y0.2181 +G01 X-1.0503 Y0.2154 +G01 X-1.0554 Y0.2103 +G01 X-1.0581 Y0.2036 +G01 X-1.0585 Y0.2000 +G01 X-1.0585 Y0.1964 +G01 X-1.0585 Y0.1937 +G01 X-1.0585 Y0.1437 +G01 X-1.0585 Y0.1338 +G01 X-1.0709 Y0.1038 +G01 X-1.0938 Y0.0809 +G01 X-1.1238 Y0.0685 +G01 X-1.1337 Y0.0685 +G01 X-1.1393 Y0.0685 +G01 X-1.1400 Y0.0685 +G01 X-1.1463 Y0.0685 +G01 X-1.5937 Y0.0685 +G01 X-1.6000 Y0.0685 +G01 X-1.6037 Y0.0685 +G01 X-1.6063 Y0.0685 +G01 X-1.6162 Y0.0685 +G01 X-1.6462 Y0.0809 +G01 X-1.6691 Y0.1038 +G01 X-1.6815 Y0.1338 +G01 X-1.6815 Y0.1437 +G01 X-1.6815 Y0.1511 +G01 X-1.6815 Y0.1563 +G01 X-1.6815 Y0.8663 +G01 X-1.6815 Y0.8762 +G01 X-1.6691 Y0.9062 +G01 X-1.6462 Y0.9291 +G01 X-1.6162 Y0.9415 +G01 X-1.6063 Y0.9415 +G01 X-1.6000 Y0.9415 +G01 X-1.5937 Y0.9415 +G01 X-1.3384 Y0.9415 +G01 X-1.3322 Y0.9477 +G01 X-1.3159 Y0.9545 +G01 X-1.1841 Y0.9545 +G01 X-1.1678 Y0.9477 +G01 X-1.1553 Y0.9352 +G01 X-1.1485 Y0.9189 +G01 X-1.1485 Y0.9011 +G01 X-1.1553 Y0.8848 +G01 X-1.1678 Y0.8723 +G01 X-1.1841 Y0.8655 +G01 X-1.3159 Y0.8655 +G01 X-1.3322 Y0.8723 +G01 X-1.3384 Y0.8785 +G01 X-1.5937 Y0.8785 +G01 X-1.6000 Y0.8785 +G01 X-1.6036 Y0.8781 +G01 X-1.6103 Y0.8754 +G01 X-1.6154 Y0.8703 +G01 X-1.6181 Y0.8636 +G01 X-1.6185 Y0.8600 +G01 X-1.6185 Y0.1563 +G01 X-1.6185 Y0.1511 +G01 X-1.6185 Y0.1500 +G01 X-1.6181 Y0.1464 +G01 X-1.6154 Y0.1397 +G01 X-1.6103 Y0.1346 +G01 X-1.6036 Y0.1319 +G01 X-1.6000 Y0.1315 +G01 X-1.5937 Y0.1315 +G01 X-1.1463 Y0.1315 +G01 X-1.1400 Y0.1315 +G01 X-1.1364 Y0.1319 +G01 X-1.1297 Y0.1346 +G01 X-1.1246 Y0.1397 +G01 X-1.1219 Y0.1464 +G01 X-1.1215 Y0.1500 +G01 X-1.1215 Y0.1937 +G01 X-1.1215 Y0.1964 +G01 X-1.1215 Y0.2063 +G01 X-1.1215 Y0.2162 +G01 X-1.1091 Y0.2462 +G01 X-1.0862 Y0.2691 +G01 X-1.0562 Y0.2815 +G01 X-1.0463 Y0.2815 +G01 X-0.5163 Y0.2815 +G01 X-0.5100 Y0.2815 +G01 X-0.5064 Y0.2819 +G01 X-0.4997 Y0.2846 +G01 X-0.4946 Y0.2897 +G01 X-0.4919 Y0.2964 +G01 X-0.4915 Y0.3000 +G01 X-0.4915 Y0.6537 +G01 X-0.4915 Y0.6548 +G01 X-0.4915 Y0.6663 +G01 X-0.4915 Y0.6762 +G01 X-0.4791 Y0.7062 +G01 X-0.4562 Y0.7291 +G01 X-0.4262 Y0.7415 +G01 X-0.4163 Y0.7415 +G01 X-0.4132 Y0.7415 +G01 X-0.4100 Y0.7415 +G01 X-0.4037 Y0.7415 +G01 X-0.3119 Y0.7415 +G01 X-0.2977 Y0.7557 +G01 X-0.2786 Y0.7636 +G01 X-0.1214 Y0.7636 +G01 X-0.1023 Y0.7557 +G01 X-0.0877 Y0.7410 +G01 X-0.0798 Y0.7219 +G01 X-0.0798 Y0.7012 +G01 X-0.0877 Y0.6821 +G01 X-0.1023 Y0.6675 +G01 X-0.1214 Y0.6596 +G01 X-0.2786 Y0.6596 +G01 X-0.2977 Y0.6675 +G01 X-0.3087 Y0.6785 +G01 X-0.4037 Y0.6785 +G01 X-0.4100 Y0.6785 +G01 X-0.4136 Y0.6781 +G01 X-0.4203 Y0.6754 +G01 X-0.4254 Y0.6703 +G01 X-0.4281 Y0.6636 +G01 X-0.4285 Y0.6600 +G01 X-0.4285 Y0.6548 +G01 X-0.4285 Y0.6537 +G01 X-0.4285 Y0.2937 +G01 X-0.4285 Y0.2838 +G00 Z0.1000 +G00 X-2.1715 Y0.6262 +G01 Z-0.0070 F10 +G01 X-2.1715 Y0.6262 F20 +G01 X-2.1591 Y0.6562 +G01 X-2.1362 Y0.6791 +G01 X-2.1062 Y0.6915 +G01 X-2.0963 Y0.6915 +G01 X-2.0897 Y0.6915 +G01 X-2.0837 Y0.6915 +G01 X-2.0499 Y0.6915 +G01 X-2.0386 Y0.7028 +G01 X-2.0200 Y0.7105 +G01 X-2.0000 Y0.7105 +G01 X-1.9814 Y0.7028 +G01 X-1.9701 Y0.6915 +G01 X-1.7814 Y0.6915 +G01 X-1.7684 Y0.7045 +G01 X-1.7316 Y0.7045 +G01 X-1.7055 Y0.6784 +G01 X-1.7055 Y0.6416 +G01 X-1.7316 Y0.6155 +G01 X-1.7684 Y0.6155 +G01 X-1.7814 Y0.6285 +G01 X-1.9701 Y0.6285 +G01 X-1.9814 Y0.6172 +G01 X-2.0000 Y0.6095 +G01 X-2.0200 Y0.6095 +G01 X-2.0386 Y0.6172 +G01 X-2.0499 Y0.6285 +G01 X-2.0837 Y0.6285 +G01 X-2.0898 Y0.6285 +G01 X-2.0900 Y0.6285 +G01 X-2.0936 Y0.6281 +G01 X-2.1003 Y0.6254 +G01 X-2.1054 Y0.6203 +G01 X-2.1081 Y0.6136 +G01 X-2.1085 Y0.6100 +G01 X-2.1085 Y0.2914 +G01 X-2.0955 Y0.2784 +G01 X-2.0955 Y0.2416 +G01 X-2.1216 Y0.2155 +G01 X-2.1584 Y0.2155 +G01 X-2.1845 Y0.2416 +G01 X-2.1845 Y0.2784 +G01 X-2.1715 Y0.2914 +G01 X-2.1715 Y0.6163 +G01 X-2.1715 Y0.6262 +G00 Z0.1000 +G00 X-3.1015 Y1.6162 +G01 Z-0.0070 F10 +G01 X-3.1015 Y1.6162 F20 +G01 X-3.0891 Y1.6462 +G01 X-3.0662 Y1.6691 +G01 X-3.0362 Y1.6815 +G01 X-3.0263 Y1.6815 +G01 X-3.0195 Y1.6815 +G01 X-3.0137 Y1.6815 +G01 X-2.9015 Y1.6815 +G01 X-2.9015 Y1.6848 +G01 X-2.9015 Y1.6863 +G01 X-2.9015 Y1.7763 +G01 X-2.9015 Y1.7862 +G01 X-2.8891 Y1.8162 +G01 X-2.8662 Y1.8391 +G01 X-2.8362 Y1.8515 +G01 X-2.8263 Y1.8515 +G01 X-2.8203 Y1.8515 +G01 X-2.8200 Y1.8515 +G01 X-2.8137 Y1.8515 +G01 X-2.7014 Y1.8515 +G01 X-2.6884 Y1.8645 +G01 X-2.6516 Y1.8645 +G01 X-2.6255 Y1.8384 +G01 X-2.6255 Y1.8016 +G01 X-2.6516 Y1.7755 +G01 X-2.6884 Y1.7755 +G01 X-2.7014 Y1.7885 +G01 X-2.8137 Y1.7885 +G01 X-2.8200 Y1.7885 +G01 X-2.8236 Y1.7881 +G01 X-2.8303 Y1.7854 +G01 X-2.8354 Y1.7803 +G01 X-2.8381 Y1.7736 +G01 X-2.8385 Y1.7700 +G01 X-2.8385 Y1.6863 +G01 X-2.8385 Y1.6848 +G01 X-2.8385 Y1.6737 +G01 X-2.8385 Y1.6678 +G01 X-2.8479 Y1.6452 +G01 X-2.8652 Y1.6279 +G01 X-2.8878 Y1.6185 +G01 X-2.8937 Y1.6185 +G01 X-3.0137 Y1.6185 +G01 X-3.0196 Y1.6185 +G01 X-3.0200 Y1.6185 +G01 X-3.0236 Y1.6181 +G01 X-3.0303 Y1.6154 +G01 X-3.0354 Y1.6103 +G01 X-3.0381 Y1.6036 +G01 X-3.0385 Y1.6000 +G01 X-3.0385 Y1.2900 +G01 X-3.0381 Y1.2864 +G01 X-3.0354 Y1.2797 +G01 X-3.0303 Y1.2746 +G01 X-3.0236 Y1.2719 +G01 X-3.0200 Y1.2715 +G01 X-3.0137 Y1.2715 +G01 X-2.7231 Y1.2715 +G01 X-2.7200 Y1.2721 +G01 X-2.7169 Y1.2715 +G01 X-2.7137 Y1.2715 +G01 X-2.7121 Y1.2708 +G01 X-2.6884 Y1.2945 +G01 X-2.6516 Y1.2945 +G01 X-2.6255 Y1.2684 +G01 X-2.6255 Y1.2316 +G01 X-2.6516 Y1.2055 +G01 X-2.6780 Y1.2055 +G01 X-2.6999 Y1.2011 +G01 X-2.7263 Y1.2063 +G01 X-2.7295 Y1.2085 +G01 X-3.0137 Y1.2085 +G01 X-3.0200 Y1.2085 +G01 X-3.0202 Y1.2085 +G01 X-3.0263 Y1.2085 +G01 X-3.0362 Y1.2085 +G01 X-3.0662 Y1.2209 +G01 X-3.0891 Y1.2438 +G01 X-3.1015 Y1.2738 +G01 X-3.1015 Y1.2837 +G01 X-3.1015 Y1.6063 +G01 X-3.1015 Y1.6162 +G00 Z0.1000 +G00 X-2.5583 Y0.4400 +G01 Z-0.0070 F10 +G01 X-2.5583 Y0.4800 F20 +G01 X-2.5300 Y0.5083 +G01 X-2.4900 Y0.5083 +G01 X-2.4617 Y0.4800 +G01 X-2.4617 Y0.4400 +G01 X-2.4685 Y0.4332 +G01 X-2.4685 Y0.2683 +G01 X-2.4685 Y0.1900 +G01 X-2.4684 Y0.1887 +G01 X-2.4676 Y0.1861 +G01 X-2.4660 Y0.1840 +G01 X-2.4639 Y0.1824 +G01 X-2.4613 Y0.1816 +G01 X-2.4600 Y0.1815 +G01 X-2.4528 Y0.1815 +G01 X-2.4517 Y0.1815 +G01 X-1.8700 Y0.1815 +G01 X-1.8687 Y0.1816 +G01 X-1.8661 Y0.1824 +G01 X-1.8645 Y0.1836 +G01 X-1.8645 Y0.2184 +G01 X-1.8384 Y0.2445 +G01 X-1.8016 Y0.2445 +G01 X-1.7755 Y0.2184 +G01 X-1.7755 Y0.1816 +G01 X-1.7785 Y0.1786 +G01 X-1.7785 Y0.1755 +G01 X-1.7875 Y0.1479 +G01 X-1.8045 Y0.1245 +G01 X-1.8279 Y0.1075 +G01 X-1.8555 Y0.0985 +G01 X-1.8617 Y0.0985 +G01 X-2.4517 Y0.0985 +G01 X-2.4528 Y0.0985 +G01 X-2.4683 Y0.0985 +G01 X-2.4745 Y0.0985 +G01 X-2.5021 Y0.1075 +G01 X-2.5255 Y0.1245 +G01 X-2.5425 Y0.1479 +G01 X-2.5515 Y0.1755 +G01 X-2.5515 Y0.1817 +G01 X-2.5515 Y0.2285 +G01 X-2.6086 Y0.2285 +G01 X-2.6216 Y0.2155 +G01 X-2.6584 Y0.2155 +G01 X-2.6845 Y0.2416 +G01 X-2.6845 Y0.2784 +G01 X-2.6584 Y0.3045 +G01 X-2.6216 Y0.3045 +G01 X-2.6086 Y0.2915 +G01 X-2.5515 Y0.2915 +G01 X-2.5515 Y0.4332 +G01 X-2.5583 Y0.4400 +G00 Z0.1000 +G00 X-1.9285 Y1.4362 +G01 Z-0.0070 F10 +G01 X-1.9285 Y1.4362 F20 +G01 X-1.9285 Y1.4263 +G01 X-1.9285 Y1.3545 +G01 X-1.8941 Y1.3545 +G01 X-1.8778 Y1.3477 +G01 X-1.8653 Y1.3352 +G01 X-1.8585 Y1.3189 +G01 X-1.8585 Y1.3011 +G01 X-1.8653 Y1.2848 +G01 X-1.8778 Y1.2723 +G01 X-1.8941 Y1.2655 +G01 X-2.0259 Y1.2655 +G01 X-2.0422 Y1.2723 +G01 X-2.0547 Y1.2848 +G01 X-2.0615 Y1.3011 +G01 X-2.0615 Y1.3189 +G01 X-2.0547 Y1.3352 +G01 X-2.0422 Y1.3477 +G01 X-2.0259 Y1.3545 +G01 X-1.9915 Y1.3545 +G01 X-1.9915 Y1.4200 +G01 X-1.9918 Y1.4235 +G01 X-2.0065 Y1.4382 +G01 X-2.0100 Y1.4385 +G01 X-2.1732 Y1.4385 +G01 X-2.1900 Y1.4217 +G01 X-2.2300 Y1.4217 +G01 X-2.2363 Y1.4280 +G01 X-2.2510 Y1.4231 +G01 X-2.2510 Y1.4197 +G01 X-2.2797 Y1.3910 +G01 X-2.3203 Y1.3910 +G01 X-2.3490 Y1.4197 +G01 X-2.3490 Y1.4603 +G01 X-2.3203 Y1.4890 +G01 X-2.2797 Y1.4890 +G01 X-2.2729 Y1.4822 +G01 X-2.2583 Y1.4871 +G01 X-2.2583 Y1.4900 +G01 X-2.2300 Y1.5183 +G01 X-2.1900 Y1.5183 +G01 X-2.1732 Y1.5015 +G01 X-2.0068 Y1.5015 +G01 X-1.9900 Y1.5183 +G01 X-1.9500 Y1.5183 +G01 X-1.9217 Y1.4900 +G01 X-1.9217 Y1.4500 +G01 X-1.9305 Y1.4411 +G01 X-1.9285 Y1.4362 +G00 Z0.1000 +G00 X-1.5445 Y1.8916 +G01 Z-0.0070 F10 +G01 X-1.5445 Y1.9284 F20 +G01 X-1.5184 Y1.9545 +G01 X-1.4816 Y1.9545 +G01 X-1.4555 Y1.9284 +G01 X-1.4555 Y1.8916 +G01 X-1.4685 Y1.8786 +G01 X-1.4685 Y1.7499 +G01 X-1.4572 Y1.7386 +G01 X-1.4495 Y1.7200 +G01 X-1.4495 Y1.7017 +G01 X-1.4472 Y1.7020 +G01 X-1.4455 Y1.7015 +G01 X-0.7763 Y1.7015 +G01 X-0.7700 Y1.7015 +G01 X-0.7664 Y1.7015 +G01 X-0.7637 Y1.7015 +G01 X-0.7538 Y1.7015 +G01 X-0.7238 Y1.6891 +G01 X-0.7009 Y1.6662 +G01 X-0.6885 Y1.6362 +G01 X-0.6885 Y1.6263 +G01 X-0.6885 Y1.5414 +G01 X-0.6755 Y1.5284 +G01 X-0.6755 Y1.4916 +G01 X-0.7016 Y1.4655 +G01 X-0.7384 Y1.4655 +G01 X-0.7645 Y1.4916 +G01 X-0.7645 Y1.5284 +G01 X-0.7515 Y1.5414 +G01 X-0.7515 Y1.6200 +G01 X-0.7518 Y1.6236 +G01 X-0.7546 Y1.6303 +G01 X-0.7597 Y1.6354 +G01 X-0.7664 Y1.6381 +G01 X-0.7700 Y1.6385 +G01 X-0.7763 Y1.6385 +G01 X-1.4483 Y1.6385 +G01 X-1.4617 Y1.6370 +G01 X-1.4910 Y1.6455 +G01 X-1.5085 Y1.6595 +G01 X-1.5100 Y1.6595 +G01 X-1.5286 Y1.6672 +G01 X-1.5428 Y1.6814 +G01 X-1.5505 Y1.7000 +G01 X-1.5505 Y1.7200 +G01 X-1.5428 Y1.7386 +G01 X-1.5315 Y1.7499 +G01 X-1.5315 Y1.8786 +G01 X-1.5445 Y1.8916 +G00 Z0.1000 +G00 X-2.9945 Y1.1116 +G01 Z-0.0070 F10 +G01 X-2.9945 Y1.1484 F20 +G01 X-2.9684 Y1.1745 +G01 X-2.9316 Y1.1745 +G01 X-2.9055 Y1.1484 +G01 X-2.9055 Y1.1116 +G01 X-2.9185 Y1.0986 +G01 X-2.9185 Y1.0600 +G01 X-2.9181 Y1.0564 +G01 X-2.9154 Y1.0497 +G01 X-2.9103 Y1.0446 +G01 X-2.9036 Y1.0419 +G01 X-2.9000 Y1.0415 +G01 X-2.8945 Y1.0415 +G01 X-2.8937 Y1.0415 +G01 X-2.3484 Y1.0415 +G01 X-2.3422 Y1.0477 +G01 X-2.3259 Y1.0545 +G01 X-2.1941 Y1.0545 +G01 X-2.1778 Y1.0477 +G01 X-2.1653 Y1.0352 +G01 X-2.1585 Y1.0189 +G01 X-2.1585 Y1.0011 +G01 X-2.1653 Y0.9848 +G01 X-2.1778 Y0.9723 +G01 X-2.1941 Y0.9655 +G01 X-2.3259 Y0.9655 +G01 X-2.3422 Y0.9723 +G01 X-2.3484 Y0.9785 +G01 X-2.8937 Y0.9785 +G01 X-2.8945 Y0.9785 +G01 X-2.9063 Y0.9785 +G01 X-2.9162 Y0.9785 +G01 X-2.9462 Y0.9909 +G01 X-2.9691 Y1.0138 +G01 X-2.9815 Y1.0438 +G01 X-2.9815 Y1.0537 +G01 X-2.9815 Y1.0986 +G01 X-2.9945 Y1.1116 +G00 Z0.1000 +G00 X-1.5945 Y0.6416 +G01 Z-0.0070 F10 +G01 X-1.5945 Y0.6784 F20 +G01 X-1.5815 Y0.6914 +G01 X-1.5815 Y0.7537 +G01 X-1.5815 Y0.7549 +G01 X-1.5815 Y0.7663 +G01 X-1.5815 Y0.7762 +G01 X-1.5691 Y0.8062 +G01 X-1.5462 Y0.8291 +G01 X-1.5162 Y0.8415 +G01 X-1.5063 Y0.8415 +G01 X-1.3384 Y0.8415 +G01 X-1.3322 Y0.8477 +G01 X-1.3159 Y0.8545 +G01 X-1.1841 Y0.8545 +G01 X-1.1678 Y0.8477 +G01 X-1.1553 Y0.8352 +G01 X-1.1485 Y0.8189 +G01 X-1.1485 Y0.8011 +G01 X-1.1553 Y0.7848 +G01 X-1.1678 Y0.7723 +G01 X-1.1841 Y0.7655 +G01 X-1.3159 Y0.7655 +G01 X-1.3322 Y0.7723 +G01 X-1.3384 Y0.7785 +G01 X-1.5000 Y0.7785 +G01 X-1.5036 Y0.7781 +G01 X-1.5103 Y0.7754 +G01 X-1.5154 Y0.7703 +G01 X-1.5181 Y0.7636 +G01 X-1.5185 Y0.7600 +G01 X-1.5185 Y0.7549 +G01 X-1.5185 Y0.7537 +G01 X-1.5185 Y0.6914 +G01 X-1.5055 Y0.6784 +G01 X-1.5055 Y0.6416 +G01 X-1.5316 Y0.6155 +G01 X-1.5684 Y0.6155 +G01 X-1.5945 Y0.6416 +G00 Z0.1000 +G00 X-0.7984 Y0.3845 +G01 Z-0.0070 F10 +G01 X-0.7616 Y0.3845 F20 +G01 X-0.7355 Y0.3584 +G01 X-0.7355 Y0.3216 +G01 X-0.7616 Y0.2955 +G01 X-0.7984 Y0.2955 +G01 X-0.8114 Y0.3085 +G01 X-1.2785 Y0.3085 +G01 X-1.2785 Y0.2214 +G01 X-1.2755 Y0.2184 +G01 X-1.2755 Y0.1816 +G01 X-1.3016 Y0.1555 +G01 X-1.3384 Y0.1555 +G01 X-1.3645 Y0.1816 +G01 X-1.3645 Y0.2184 +G01 X-1.3415 Y0.2414 +G01 X-1.3415 Y0.3085 +G01 X-1.3801 Y0.3085 +G01 X-1.3914 Y0.2972 +G01 X-1.4100 Y0.2895 +G01 X-1.4300 Y0.2895 +G01 X-1.4486 Y0.2972 +G01 X-1.4628 Y0.3114 +G01 X-1.4705 Y0.3300 +G01 X-1.4705 Y0.3500 +G01 X-1.4628 Y0.3686 +G01 X-1.4486 Y0.3828 +G01 X-1.4300 Y0.3905 +G01 X-1.4100 Y0.3905 +G01 X-1.3914 Y0.3828 +G01 X-1.3801 Y0.3715 +G01 X-1.3037 Y0.3715 +G01 X-0.8114 Y0.3715 +G01 X-0.7984 Y0.3845 +G00 Z0.1000 +G00 X-0.5784 Y1.1545 +G01 Z-0.0070 F10 +G01 X-0.5416 Y1.1545 F20 +G01 X-0.5155 Y1.1284 +G01 X-0.5155 Y1.0916 +G01 X-0.5416 Y1.0655 +G01 X-0.5784 Y1.0655 +G01 X-0.5914 Y1.0785 +G01 X-0.8616 Y1.0785 +G01 X-0.8678 Y1.0723 +G01 X-0.8841 Y1.0655 +G01 X-1.0159 Y1.0655 +G01 X-1.0322 Y1.0723 +G01 X-1.0447 Y1.0848 +G01 X-1.0515 Y1.1011 +G01 X-1.0515 Y1.1189 +G01 X-1.0447 Y1.1352 +G01 X-1.0322 Y1.1477 +G01 X-1.0159 Y1.1545 +G01 X-0.8841 Y1.1545 +G01 X-0.8678 Y1.1477 +G01 X-0.8616 Y1.1415 +G01 X-0.5914 Y1.1415 +G01 X-0.5784 Y1.1545 +G00 Z0.1000 +G00 X-1.3159 Y1.3545 +G01 Z-0.0070 F10 +G01 X-1.1841 Y1.3545 F20 +G01 X-1.1678 Y1.3477 +G01 X-1.1553 Y1.3352 +G01 X-1.1485 Y1.3189 +G01 X-1.1485 Y1.3011 +G01 X-1.1553 Y1.2848 +G01 X-1.1678 Y1.2723 +G01 X-1.1841 Y1.2655 +G01 X-1.3159 Y1.2655 +G01 X-1.3322 Y1.2723 +G01 X-1.3447 Y1.2848 +G01 X-1.3515 Y1.3011 +G01 X-1.3515 Y1.3189 +G01 X-1.3447 Y1.3352 +G01 X-1.3322 Y1.3477 +G01 X-1.3159 Y1.3545 +G00 Z0.1000 +G00 X-1.3159 Y1.2545 +G01 Z-0.0070 F10 +G01 X-1.1841 Y1.2545 F20 +G01 X-1.1678 Y1.2477 +G01 X-1.1553 Y1.2352 +G01 X-1.1485 Y1.2189 +G01 X-1.1485 Y1.2011 +G01 X-1.1553 Y1.1848 +G01 X-1.1678 Y1.1723 +G01 X-1.1841 Y1.1655 +G01 X-1.3159 Y1.1655 +G01 X-1.3322 Y1.1723 +G01 X-1.3447 Y1.1848 +G01 X-1.3515 Y1.2011 +G01 X-1.3515 Y1.2189 +G01 X-1.3447 Y1.2352 +G01 X-1.3322 Y1.2477 +G01 X-1.3159 Y1.2545 +G00 Z0.1000 +G00 X-1.3159 Y1.1545 +G01 Z-0.0070 F10 +G01 X-1.1841 Y1.1545 F20 +G01 X-1.1678 Y1.1477 +G01 X-1.1553 Y1.1352 +G01 X-1.1485 Y1.1189 +G01 X-1.1485 Y1.1011 +G01 X-1.1553 Y1.0848 +G01 X-1.1678 Y1.0723 +G01 X-1.1841 Y1.0655 +G01 X-1.3159 Y1.0655 +G01 X-1.3322 Y1.0723 +G01 X-1.3384 Y1.0785 +G01 X-1.7785 Y1.0785 +G01 X-1.7785 Y0.8737 +G01 X-1.7785 Y0.8638 +G01 X-1.7909 Y0.8338 +G01 X-1.8138 Y0.8109 +G01 X-1.8438 Y0.7985 +G01 X-1.8537 Y0.7985 +G01 X-1.8562 Y0.7985 +G01 X-1.8600 Y0.7985 +G01 X-1.8663 Y0.7985 +G01 X-2.2737 Y0.7985 +G01 X-2.2800 Y0.7985 +G01 X-2.2836 Y0.7981 +G01 X-2.2903 Y0.7954 +G01 X-2.2954 Y0.7903 +G01 X-2.2981 Y0.7836 +G01 X-2.2985 Y0.7800 +G01 X-2.2985 Y0.7537 +G01 X-2.2985 Y0.7498 +G01 X-2.3063 Y0.7308 +G01 X-2.3208 Y0.7163 +G01 X-2.3398 Y0.7085 +G01 X-2.3500 Y0.7085 +G01 X-2.3563 Y0.7085 +G01 X-2.6486 Y0.7085 +G01 X-2.6516 Y0.7055 +G01 X-2.6884 Y0.7055 +G01 X-2.7014 Y0.7185 +G01 X-2.8081 Y0.7185 +G01 X-2.8223 Y0.7043 +G01 X-2.8414 Y0.6964 +G01 X-2.9986 Y0.6964 +G01 X-3.0177 Y0.7043 +G01 X-3.0323 Y0.7190 +G01 X-3.0402 Y0.7381 +G01 X-3.0402 Y0.7588 +G01 X-3.0323 Y0.7779 +G01 X-3.0177 Y0.7925 +G01 X-2.9986 Y0.8004 +G01 X-2.8414 Y0.8004 +G01 X-2.8223 Y0.7925 +G01 X-2.8113 Y0.7815 +G01 X-2.7014 Y0.7815 +G01 X-2.6884 Y0.7945 +G01 X-2.6516 Y0.7945 +G01 X-2.6286 Y0.7715 +G01 X-2.3615 Y0.7715 +G01 X-2.3615 Y0.7863 +G01 X-2.3615 Y0.7962 +G01 X-2.3491 Y0.8262 +G01 X-2.3262 Y0.8491 +G01 X-2.2962 Y0.8615 +G01 X-2.2863 Y0.8615 +G01 X-2.2807 Y0.8615 +G01 X-2.2800 Y0.8615 +G01 X-2.2737 Y0.8615 +G01 X-1.8663 Y0.8615 +G01 X-1.8600 Y0.8615 +G01 X-1.8564 Y0.8619 +G01 X-1.8497 Y0.8646 +G01 X-1.8446 Y0.8697 +G01 X-1.8419 Y0.8764 +G01 X-1.8415 Y0.8800 +G01 X-1.8415 Y1.0785 +G01 X-1.8716 Y1.0785 +G01 X-1.8778 Y1.0723 +G01 X-1.8941 Y1.0655 +G01 X-2.0259 Y1.0655 +G01 X-2.0422 Y1.0723 +G01 X-2.0547 Y1.0848 +G01 X-2.0615 Y1.1011 +G01 X-2.0615 Y1.1189 +G01 X-2.0547 Y1.1352 +G01 X-2.0422 Y1.1477 +G01 X-2.0259 Y1.1545 +G01 X-1.8941 Y1.1545 +G01 X-1.8778 Y1.1477 +G01 X-1.8716 Y1.1415 +G01 X-1.8163 Y1.1415 +G01 X-1.8037 Y1.1415 +G01 X-1.3384 Y1.1415 +G01 X-1.3322 Y1.1477 +G01 X-1.3159 Y1.1545 +G00 Z0.1000 +G00 X-1.0159 Y0.9545 +G01 Z-0.0070 F10 +G01 X-0.8841 Y0.9545 F20 +G01 X-0.8678 Y0.9477 +G01 X-0.8616 Y0.9415 +G01 X-0.8363 Y0.9415 +G01 X-0.8342 Y0.9415 +G01 X-0.8237 Y0.9415 +G01 X-0.8138 Y0.9415 +G01 X-0.7838 Y0.9291 +G01 X-0.7609 Y0.9062 +G01 X-0.7485 Y0.8762 +G01 X-0.7485 Y0.8663 +G01 X-0.7485 Y0.5714 +G01 X-0.7355 Y0.5584 +G01 X-0.7355 Y0.5216 +G01 X-0.7616 Y0.4955 +G01 X-0.7984 Y0.4955 +G01 X-0.8245 Y0.5216 +G01 X-0.8245 Y0.5584 +G01 X-0.8115 Y0.5714 +G01 X-0.8115 Y0.8600 +G01 X-0.8119 Y0.8636 +G01 X-0.8146 Y0.8703 +G01 X-0.8197 Y0.8754 +G01 X-0.8264 Y0.8781 +G01 X-0.8300 Y0.8785 +G01 X-0.8342 Y0.8785 +G01 X-0.8363 Y0.8785 +G01 X-0.8616 Y0.8785 +G01 X-0.8678 Y0.8723 +G01 X-0.8841 Y0.8655 +G01 X-1.0159 Y0.8655 +G01 X-1.0322 Y0.8723 +G01 X-1.0447 Y0.8848 +G01 X-1.0515 Y0.9011 +G01 X-1.0515 Y0.9189 +G01 X-1.0447 Y0.9352 +G01 X-1.0322 Y0.9477 +G01 X-1.0159 Y0.9545 +G00 Z0.1000 +G00 X-1.0159 Y1.3545 +G01 Z-0.0070 F10 +G01 X-0.8841 Y1.3545 F20 +G01 X-0.8678 Y1.3477 +G01 X-0.8616 Y1.3415 +G01 X-0.7514 Y1.3415 +G01 X-0.7384 Y1.3545 +G01 X-0.7016 Y1.3545 +G01 X-0.6755 Y1.3284 +G01 X-0.6755 Y1.2916 +G01 X-0.7016 Y1.2655 +G01 X-0.7384 Y1.2655 +G01 X-0.7514 Y1.2785 +G01 X-0.8616 Y1.2785 +G01 X-0.8678 Y1.2723 +G01 X-0.8841 Y1.2655 +G01 X-1.0159 Y1.2655 +G01 X-1.0322 Y1.2723 +G01 X-1.0447 Y1.2848 +G01 X-1.0515 Y1.3011 +G01 X-1.0515 Y1.3189 +G01 X-1.0447 Y1.3352 +G01 X-1.0322 Y1.3477 +G01 X-1.0159 Y1.3545 +G00 Z0.1000 +G00 X-2.7045 Y1.5916 +G01 Z-0.0070 F10 +G01 X-2.7045 Y1.6284 F20 +G01 X-2.6784 Y1.6545 +G01 X-2.6416 Y1.6545 +G01 X-2.6286 Y1.6415 +G01 X-2.5315 Y1.6415 +G01 X-2.5315 Y1.7037 +G01 X-2.5315 Y1.7047 +G01 X-2.5315 Y1.7163 +G01 X-2.5315 Y1.7222 +G01 X-2.5221 Y1.7448 +G01 X-2.5048 Y1.7621 +G01 X-2.4822 Y1.7715 +G01 X-2.4763 Y1.7715 +G01 X-2.4714 Y1.7715 +G01 X-2.4584 Y1.7845 +G01 X-2.4216 Y1.7845 +G01 X-2.3955 Y1.7584 +G01 X-2.3955 Y1.7216 +G01 X-2.4076 Y1.7095 +G01 X-2.3724 Y1.7095 +G01 X-2.3845 Y1.7216 +G01 X-2.3845 Y1.7584 +G01 X-2.3715 Y1.7714 +G01 X-2.3715 Y1.7800 +G01 X-2.3719 Y1.7836 +G01 X-2.3746 Y1.7903 +G01 X-2.3797 Y1.7954 +G01 X-2.3864 Y1.7981 +G01 X-2.3900 Y1.7985 +G01 X-2.5300 Y1.7985 +G01 X-2.5336 Y1.7981 +G01 X-2.5403 Y1.7954 +G01 X-2.5454 Y1.7903 +G01 X-2.5481 Y1.7836 +G01 X-2.5485 Y1.7800 +G01 X-2.5485 Y1.7763 +G01 X-2.5485 Y1.7733 +G01 X-2.5485 Y1.7637 +G01 X-2.5485 Y1.7538 +G01 X-2.5609 Y1.7238 +G01 X-2.5838 Y1.7009 +G01 X-2.6138 Y1.6885 +G01 X-2.6237 Y1.6885 +G01 X-2.6386 Y1.6885 +G01 X-2.6516 Y1.6755 +G01 X-2.6884 Y1.6755 +G01 X-2.7014 Y1.6885 +G01 X-2.7300 Y1.6885 +G01 X-2.7336 Y1.6881 +G01 X-2.7403 Y1.6854 +G01 X-2.7454 Y1.6803 +G01 X-2.7481 Y1.6736 +G01 X-2.7485 Y1.6700 +G01 X-2.7485 Y1.6651 +G01 X-2.7485 Y1.6637 +G01 X-2.7485 Y1.5937 +G01 X-2.7485 Y1.5858 +G01 X-2.7594 Y1.5595 +G01 X-2.7795 Y1.5394 +G01 X-2.8058 Y1.5285 +G01 X-2.8137 Y1.5285 +G01 X-2.8198 Y1.5285 +G01 X-2.8200 Y1.5285 +G01 X-2.8263 Y1.5285 +G01 X-2.9585 Y1.5285 +G01 X-2.9585 Y1.5237 +G01 X-2.9585 Y1.3745 +G01 X-2.9316 Y1.3745 +G01 X-2.9055 Y1.3484 +G01 X-2.9055 Y1.3116 +G01 X-2.9316 Y1.2855 +G01 X-2.9684 Y1.2855 +G01 X-2.9945 Y1.3116 +G01 X-2.9945 Y1.3134 +G01 X-3.0106 Y1.3295 +G01 X-3.0215 Y1.3558 +G01 X-3.0215 Y1.3637 +G01 X-3.0215 Y1.3664 +G01 X-3.0215 Y1.3700 +G01 X-3.0215 Y1.5237 +G01 X-3.0215 Y1.5300 +G01 X-3.0215 Y1.5422 +G01 X-3.0121 Y1.5648 +G01 X-2.9948 Y1.5821 +G01 X-2.9722 Y1.5915 +G01 X-2.9663 Y1.5915 +G01 X-2.8263 Y1.5915 +G01 X-2.8200 Y1.5915 +G01 X-2.8183 Y1.5917 +G01 X-2.8153 Y1.5929 +G01 X-2.8129 Y1.5953 +G01 X-2.8117 Y1.5983 +G01 X-2.8115 Y1.6000 +G01 X-2.8115 Y1.6637 +G01 X-2.8115 Y1.6651 +G01 X-2.8115 Y1.6763 +G01 X-2.8115 Y1.6862 +G01 X-2.7991 Y1.7162 +G01 X-2.7762 Y1.7391 +G01 X-2.7462 Y1.7515 +G01 X-2.7363 Y1.7515 +G01 X-2.7014 Y1.7515 +G01 X-2.6884 Y1.7645 +G01 X-2.6516 Y1.7645 +G01 X-2.6386 Y1.7515 +G01 X-2.6300 Y1.7515 +G01 X-2.6264 Y1.7519 +G01 X-2.6197 Y1.7546 +G01 X-2.6146 Y1.7597 +G01 X-2.6119 Y1.7664 +G01 X-2.6115 Y1.7700 +G01 X-2.6115 Y1.7733 +G01 X-2.6115 Y1.7763 +G01 X-2.6115 Y1.7863 +G01 X-2.6115 Y1.7962 +G01 X-2.5991 Y1.8262 +G01 X-2.5762 Y1.8491 +G01 X-2.5462 Y1.8615 +G01 X-2.5363 Y1.8615 +G01 X-2.3837 Y1.8615 +G01 X-2.3738 Y1.8615 +G01 X-2.3438 Y1.8491 +G01 X-2.3209 Y1.8262 +G01 X-2.3085 Y1.7962 +G01 X-2.3085 Y1.7863 +G01 X-2.3085 Y1.7715 +G01 X-2.2468 Y1.7715 +G01 X-2.2300 Y1.7883 +G01 X-2.1900 Y1.7883 +G01 X-2.1617 Y1.7600 +G01 X-2.1617 Y1.7200 +G01 X-2.1900 Y1.6917 +G01 X-2.2300 Y1.6917 +G01 X-2.2468 Y1.7085 +G01 X-2.3086 Y1.7085 +G01 X-2.3216 Y1.6955 +G01 X-2.3576 Y1.6955 +G01 X-2.3455 Y1.6834 +G01 X-2.3455 Y1.6466 +G01 X-2.3585 Y1.6336 +G01 X-2.3585 Y1.6300 +G01 X-2.3581 Y1.6264 +G01 X-2.3554 Y1.6197 +G01 X-2.3503 Y1.6146 +G01 X-2.3436 Y1.6119 +G01 X-2.3400 Y1.6115 +G01 X-2.3355 Y1.6115 +G01 X-2.3337 Y1.6115 +G01 X-1.8563 Y1.6115 +G01 X-1.8437 Y1.6115 +G01 X-1.8358 Y1.6115 +G01 X-1.8095 Y1.6006 +G01 X-1.7894 Y1.5805 +G01 X-1.7785 Y1.5542 +G01 X-1.7785 Y1.5463 +G01 X-1.7785 Y1.5401 +G01 X-1.7785 Y1.5400 +G01 X-1.7785 Y1.5337 +G01 X-1.7785 Y1.3415 +G01 X-1.7763 Y1.3415 +G01 X-1.7637 Y1.3415 +G01 X-1.6463 Y1.3415 +G01 X-1.6337 Y1.3415 +G01 X-1.5399 Y1.3415 +G01 X-1.5286 Y1.3528 +G01 X-1.5100 Y1.3605 +G01 X-1.4900 Y1.3605 +G01 X-1.4714 Y1.3528 +G01 X-1.4572 Y1.3386 +G01 X-1.4495 Y1.3200 +G01 X-1.4495 Y1.3000 +G01 X-1.4572 Y1.2814 +G01 X-1.4714 Y1.2672 +G01 X-1.4900 Y1.2595 +G01 X-1.5100 Y1.2595 +G01 X-1.5286 Y1.2672 +G01 X-1.5399 Y1.2785 +G01 X-1.5917 Y1.2785 +G01 X-1.5917 Y1.2500 +G01 X-1.6200 Y1.2217 +G01 X-1.6600 Y1.2217 +G01 X-1.6883 Y1.2500 +G01 X-1.6883 Y1.2785 +G01 X-1.7385 Y1.2785 +G01 X-1.7385 Y1.2314 +G01 X-1.7255 Y1.2184 +G01 X-1.7255 Y1.1816 +G01 X-1.7516 Y1.1555 +G01 X-1.7884 Y1.1555 +G01 X-1.8014 Y1.1685 +G01 X-1.8869 Y1.1685 +G01 X-1.8941 Y1.1655 +G01 X-2.0259 Y1.1655 +G01 X-2.0422 Y1.1723 +G01 X-2.0547 Y1.1848 +G01 X-2.0615 Y1.2011 +G01 X-2.0615 Y1.2189 +G01 X-2.0547 Y1.2352 +G01 X-2.0422 Y1.2477 +G01 X-2.0259 Y1.2545 +G01 X-1.8941 Y1.2545 +G01 X-1.8778 Y1.2477 +G01 X-1.8653 Y1.2352 +G01 X-1.8637 Y1.2315 +G01 X-1.8015 Y1.2315 +G01 X-1.8015 Y1.2785 +G01 X-1.8037 Y1.2785 +G01 X-1.8163 Y1.2785 +G01 X-1.8278 Y1.2833 +G01 X-1.8367 Y1.2922 +G01 X-1.8415 Y1.3037 +G01 X-1.8415 Y1.5337 +G01 X-1.8415 Y1.5400 +G01 X-1.8417 Y1.5417 +G01 X-1.8429 Y1.5447 +G01 X-1.8453 Y1.5471 +G01 X-1.8483 Y1.5483 +G01 X-1.8500 Y1.5485 +G01 X-1.8563 Y1.5485 +G01 X-2.3337 Y1.5485 +G01 X-2.3355 Y1.5485 +G01 X-2.3463 Y1.5485 +G01 X-2.3562 Y1.5485 +G01 X-2.3862 Y1.5609 +G01 X-2.4091 Y1.5838 +G01 X-2.4215 Y1.6138 +G01 X-2.4215 Y1.6237 +G01 X-2.4215 Y1.6336 +G01 X-2.4345 Y1.6466 +G01 X-2.4345 Y1.6834 +G01 X-2.4224 Y1.6955 +G01 X-2.4584 Y1.6955 +G01 X-2.4685 Y1.7056 +G01 X-2.4685 Y1.7047 +G01 X-2.4685 Y1.7037 +G01 X-2.4685 Y1.6037 +G01 X-2.4733 Y1.5922 +G01 X-2.4822 Y1.5833 +G01 X-2.4885 Y1.5807 +G01 X-2.4885 Y1.4463 +G01 X-2.4885 Y1.4337 +G01 X-2.4885 Y1.2600 +G01 X-2.4881 Y1.2564 +G01 X-2.4854 Y1.2497 +G01 X-2.4803 Y1.2446 +G01 X-2.4736 Y1.2419 +G01 X-2.4700 Y1.2415 +G01 X-2.4658 Y1.2415 +G01 X-2.4637 Y1.2415 +G01 X-2.3484 Y1.2415 +G01 X-2.3422 Y1.2477 +G01 X-2.3259 Y1.2545 +G01 X-2.1941 Y1.2545 +G01 X-2.1778 Y1.2477 +G01 X-2.1653 Y1.2352 +G01 X-2.1585 Y1.2189 +G01 X-2.1585 Y1.2011 +G01 X-2.1653 Y1.1848 +G01 X-2.1778 Y1.1723 +G01 X-2.1941 Y1.1655 +G01 X-2.2285 Y1.1655 +G01 X-2.2285 Y1.1545 +G01 X-2.1941 Y1.1545 +G01 X-2.1778 Y1.1477 +G01 X-2.1653 Y1.1352 +G01 X-2.1585 Y1.1189 +G01 X-2.1585 Y1.1011 +G01 X-2.1653 Y1.0848 +G01 X-2.1778 Y1.0723 +G01 X-2.1941 Y1.0655 +G01 X-2.3259 Y1.0655 +G01 X-2.3422 Y1.0723 +G01 X-2.3547 Y1.0848 +G01 X-2.3615 Y1.1011 +G01 X-2.3615 Y1.1189 +G01 X-2.3547 Y1.1352 +G01 X-2.3422 Y1.1477 +G01 X-2.3259 Y1.1545 +G01 X-2.2915 Y1.1545 +G01 X-2.2915 Y1.1655 +G01 X-2.3259 Y1.1655 +G01 X-2.3422 Y1.1723 +G01 X-2.3484 Y1.1785 +G01 X-2.4637 Y1.1785 +G01 X-2.4658 Y1.1785 +G01 X-2.4763 Y1.1785 +G01 X-2.4862 Y1.1785 +G01 X-2.5162 Y1.1909 +G01 X-2.5391 Y1.2138 +G01 X-2.5515 Y1.2438 +G01 X-2.5515 Y1.2537 +G01 X-2.5515 Y1.4085 +G01 X-2.8622 Y1.4085 +G01 X-2.8722 Y1.3985 +G01 X-2.8903 Y1.3910 +G01 X-2.9097 Y1.3910 +G01 X-2.9278 Y1.3985 +G01 X-2.9415 Y1.4122 +G01 X-2.9490 Y1.4303 +G01 X-2.9490 Y1.4497 +G01 X-2.9415 Y1.4678 +G01 X-2.9278 Y1.4815 +G01 X-2.9097 Y1.4890 +G01 X-2.8903 Y1.4890 +G01 X-2.8722 Y1.4815 +G01 X-2.8622 Y1.4715 +G01 X-2.5515 Y1.4715 +G01 X-2.5515 Y1.5785 +G01 X-2.6286 Y1.5785 +G01 X-2.6416 Y1.5655 +G01 X-2.6784 Y1.5655 +G01 X-2.7045 Y1.5916 +G00 Z0.1000 +G00 X-2.0605 Y0.2500 +G01 Z-0.0070 F10 +G01 X-2.0605 Y0.2700 F20 +G01 X-2.0528 Y0.2886 +G01 X-2.0415 Y0.2999 +G01 X-2.0415 Y0.3062 +G01 X-2.0291 Y0.3362 +G01 X-2.0062 Y0.3591 +G01 X-1.9762 Y0.3715 +G01 X-1.9663 Y0.3715 +G01 X-1.8599 Y0.3715 +G01 X-1.8515 Y0.3799 +G01 X-1.8515 Y0.4601 +G01 X-1.8599 Y0.4685 +G01 X-1.8662 Y0.4685 +G01 X-1.8962 Y0.4809 +G01 X-1.9191 Y0.5038 +G01 X-1.9311 Y0.5327 +G01 X-1.9483 Y0.5500 +G01 X-1.9483 Y0.5900 +G01 X-1.9200 Y0.6183 +G01 X-1.8800 Y0.6183 +G01 X-1.8517 Y0.5900 +G01 X-1.8517 Y0.5500 +G01 X-1.8637 Y0.5380 +G01 X-1.8603 Y0.5346 +G01 X-1.8578 Y0.5336 +G01 X-1.8486 Y0.5428 +G01 X-1.8300 Y0.5505 +G01 X-1.8100 Y0.5505 +G01 X-1.7914 Y0.5428 +G01 X-1.7772 Y0.5286 +G01 X-1.7695 Y0.5100 +G01 X-1.7695 Y0.4900 +G01 X-1.7772 Y0.4714 +G01 X-1.7885 Y0.4601 +G01 X-1.7885 Y0.3799 +G01 X-1.7772 Y0.3686 +G01 X-1.7695 Y0.3500 +G01 X-1.7695 Y0.3300 +G01 X-1.7772 Y0.3114 +G01 X-1.7914 Y0.2972 +G01 X-1.8100 Y0.2895 +G01 X-1.8300 Y0.2895 +G01 X-1.8486 Y0.2972 +G01 X-1.8599 Y0.3085 +G01 X-1.9600 Y0.3085 +G01 X-1.9636 Y0.3081 +G01 X-1.9703 Y0.3054 +G01 X-1.9754 Y0.3003 +G01 X-1.9764 Y0.2978 +G01 X-1.9672 Y0.2886 +G01 X-1.9595 Y0.2700 +G01 X-1.9595 Y0.2500 +G01 X-1.9672 Y0.2314 +G01 X-1.9814 Y0.2172 +G01 X-2.0000 Y0.2095 +G01 X-2.0200 Y0.2095 +G01 X-2.0386 Y0.2172 +G01 X-2.0528 Y0.2314 +G01 X-2.0605 Y0.2500 +G00 Z0.1000 +G00 X-0.5862 Y1.5685 +G01 Z-0.0070 F10 +G01 X-0.5862 Y1.5685 F20 +G01 X-0.6162 Y1.5809 +G01 X-0.6391 Y1.6038 +G01 X-0.6515 Y1.6338 +G01 X-0.6515 Y1.6437 +G01 X-0.6515 Y1.6500 +G01 X-0.6515 Y1.6563 +G01 X-0.6515 Y1.7200 +G01 X-0.6517 Y1.7217 +G01 X-0.6529 Y1.7247 +G01 X-0.6553 Y1.7271 +G01 X-0.6583 Y1.7283 +G01 X-0.6600 Y1.7285 +G01 X-1.3037 Y1.7285 +G01 X-1.3050 Y1.7285 +G01 X-1.3163 Y1.7285 +G01 X-1.3262 Y1.7285 +G01 X-1.3562 Y1.7409 +G01 X-1.3791 Y1.7638 +G01 X-1.3915 Y1.7938 +G01 X-1.3915 Y1.8037 +G01 X-1.3915 Y1.8222 +G01 X-1.4090 Y1.8397 +G01 X-1.4090 Y1.8803 +G01 X-1.3915 Y1.8978 +G01 X-1.3915 Y1.9537 +G01 X-1.3915 Y1.9589 +G01 X-1.3915 Y1.9600 +G01 X-1.3919 Y1.9636 +G01 X-1.3946 Y1.9703 +G01 X-1.3997 Y1.9754 +G01 X-1.4064 Y1.9781 +G01 X-1.4100 Y1.9785 +G01 X-1.4163 Y1.9785 +G01 X-1.5637 Y1.9785 +G01 X-1.5700 Y1.9785 +G01 X-1.5736 Y1.9781 +G01 X-1.5803 Y1.9754 +G01 X-1.5854 Y1.9703 +G01 X-1.5881 Y1.9636 +G01 X-1.5885 Y1.9600 +G01 X-1.5885 Y1.7963 +G01 X-1.5885 Y1.7737 +G01 X-1.5885 Y1.6363 +G01 X-1.5885 Y1.6300 +G01 X-1.5881 Y1.6264 +G01 X-1.5854 Y1.6197 +G01 X-1.5803 Y1.6146 +G01 X-1.5736 Y1.6119 +G01 X-1.5700 Y1.6115 +G01 X-1.5693 Y1.6115 +G01 X-1.5637 Y1.6115 +G01 X-1.1437 Y1.6115 +G01 X-1.1338 Y1.6115 +G01 X-1.1038 Y1.5991 +G01 X-1.0809 Y1.5762 +G01 X-1.0685 Y1.5462 +G01 X-1.0685 Y1.5363 +G01 X-1.0685 Y1.5304 +G01 X-1.0685 Y1.5300 +G01 X-1.0685 Y1.5237 +G01 X-1.0685 Y0.8600 +G01 X-1.0681 Y0.8564 +G01 X-1.0654 Y0.8497 +G01 X-1.0603 Y0.8446 +G01 X-1.0536 Y0.8419 +G01 X-1.0500 Y0.8415 +G01 X-1.0445 Y0.8415 +G01 X-1.0437 Y0.8415 +G01 X-1.0384 Y0.8415 +G01 X-1.0322 Y0.8477 +G01 X-1.0159 Y0.8545 +G01 X-0.8841 Y0.8545 +G01 X-0.8678 Y0.8477 +G01 X-0.8553 Y0.8352 +G01 X-0.8485 Y0.8189 +G01 X-0.8485 Y0.8011 +G01 X-0.8553 Y0.7848 +G01 X-0.8678 Y0.7723 +G01 X-0.8841 Y0.7655 +G01 X-1.0159 Y0.7655 +G01 X-1.0322 Y0.7723 +G01 X-1.0384 Y0.7785 +G01 X-1.0437 Y0.7785 +G01 X-1.0445 Y0.7785 +G01 X-1.0563 Y0.7785 +G01 X-1.0662 Y0.7785 +G01 X-1.0962 Y0.7909 +G01 X-1.1191 Y0.8138 +G01 X-1.1315 Y0.8438 +G01 X-1.1315 Y0.8537 +G01 X-1.1315 Y1.5237 +G01 X-1.1315 Y1.5300 +G01 X-1.1319 Y1.5336 +G01 X-1.1346 Y1.5403 +G01 X-1.1397 Y1.5454 +G01 X-1.1464 Y1.5481 +G01 X-1.1500 Y1.5485 +G01 X-1.5637 Y1.5485 +G01 X-1.5694 Y1.5485 +G01 X-1.5763 Y1.5485 +G01 X-1.5862 Y1.5485 +G01 X-1.6162 Y1.5609 +G01 X-1.6391 Y1.5838 +G01 X-1.6515 Y1.6138 +G01 X-1.6515 Y1.6237 +G01 X-1.6515 Y1.6299 +G01 X-1.6515 Y1.6363 +G01 X-1.6515 Y1.7585 +G01 X-1.9332 Y1.7585 +G01 X-1.9500 Y1.7417 +G01 X-1.9900 Y1.7417 +G01 X-2.0183 Y1.7700 +G01 X-2.0183 Y1.8100 +G01 X-1.9900 Y1.8383 +G01 X-1.9500 Y1.8383 +G01 X-1.9332 Y1.8215 +G01 X-1.6515 Y1.8215 +G01 X-1.6515 Y1.9663 +G01 X-1.6515 Y1.9762 +G01 X-1.6391 Y2.0062 +G01 X-1.6162 Y2.0291 +G01 X-1.5862 Y2.0415 +G01 X-1.5763 Y2.0415 +G01 X-1.5707 Y2.0415 +G01 X-1.5700 Y2.0415 +G01 X-1.5637 Y2.0415 +G01 X-1.4163 Y2.0415 +G01 X-1.4100 Y2.0415 +G01 X-1.4063 Y2.0415 +G01 X-1.4037 Y2.0415 +G01 X-1.3938 Y2.0415 +G01 X-1.3638 Y2.0291 +G01 X-1.3409 Y2.0062 +G01 X-1.3285 Y1.9762 +G01 X-1.3285 Y1.9663 +G01 X-1.3285 Y1.9589 +G01 X-1.3285 Y1.9537 +G01 X-1.3285 Y1.8978 +G01 X-1.3110 Y1.8803 +G01 X-1.3110 Y1.8397 +G01 X-1.3285 Y1.8222 +G01 X-1.3285 Y1.8100 +G01 X-1.3281 Y1.8064 +G01 X-1.3254 Y1.7997 +G01 X-1.3203 Y1.7946 +G01 X-1.3136 Y1.7919 +G01 X-1.3100 Y1.7915 +G01 X-1.3050 Y1.7915 +G01 X-1.3037 Y1.7915 +G01 X-0.6537 Y1.7915 +G01 X-0.6458 Y1.7915 +G01 X-0.6195 Y1.7806 +G01 X-0.5994 Y1.7605 +G01 X-0.5885 Y1.7342 +G01 X-0.5885 Y1.7263 +G01 X-0.5885 Y1.6563 +G01 X-0.5885 Y1.6500 +G01 X-0.5881 Y1.6464 +G01 X-0.5854 Y1.6397 +G01 X-0.5803 Y1.6346 +G01 X-0.5736 Y1.6319 +G01 X-0.5700 Y1.6315 +G01 X-0.3019 Y1.6315 +G01 X-0.2977 Y1.6357 +G01 X-0.2786 Y1.6436 +G01 X-0.1214 Y1.6436 +G01 X-0.1023 Y1.6357 +G01 X-0.0877 Y1.6210 +G01 X-0.0798 Y1.6019 +G01 X-0.0798 Y1.5812 +G01 X-0.0877 Y1.5621 +G01 X-0.1023 Y1.5475 +G01 X-0.1214 Y1.5396 +G01 X-0.2786 Y1.5396 +G01 X-0.2977 Y1.5475 +G01 X-0.3123 Y1.5621 +G01 X-0.3150 Y1.5685 +G01 X-0.5763 Y1.5685 +G01 X-0.5862 Y1.5685 +G00 Z0.1000 +G00 X-2.9185 Y1.7658 +G01 Z-0.0070 F10 +G01 X-2.9185 Y1.7658 F20 +G01 X-2.9294 Y1.7395 +G01 X-2.9495 Y1.7194 +G01 X-2.9758 Y1.7085 +G01 X-2.9837 Y1.7085 +G01 X-2.9896 Y1.7085 +G01 X-2.9900 Y1.7085 +G01 X-2.9963 Y1.7085 +G01 X-3.1100 Y1.7085 +G01 X-3.1136 Y1.7081 +G01 X-3.1203 Y1.7054 +G01 X-3.1254 Y1.7003 +G01 X-3.1281 Y1.6936 +G01 X-3.1285 Y1.6900 +G01 X-3.1285 Y1.6845 +G01 X-3.1285 Y1.6837 +G01 X-3.1285 Y1.6414 +G01 X-3.1155 Y1.6284 +G01 X-3.1155 Y1.5916 +G01 X-3.1285 Y1.5786 +G01 X-3.1285 Y0.9600 +G01 X-3.1281 Y0.9564 +G01 X-3.1254 Y0.9497 +G01 X-3.1203 Y0.9446 +G01 X-3.1136 Y0.9419 +G01 X-3.1100 Y0.9415 +G01 X-3.1052 Y0.9415 +G01 X-3.1037 Y0.9415 +G01 X-2.5468 Y0.9415 +G01 X-2.5300 Y0.9583 +G01 X-2.4900 Y0.9583 +G01 X-2.4732 Y0.9415 +G01 X-2.1663 Y0.9415 +G01 X-2.1600 Y0.9415 +G01 X-2.1564 Y0.9419 +G01 X-2.1497 Y0.9446 +G01 X-2.1446 Y0.9497 +G01 X-2.1419 Y0.9564 +G01 X-2.1415 Y0.9600 +G01 X-2.1415 Y1.0663 +G01 X-2.1415 Y1.2769 +G01 X-2.1430 Y1.2785 +G01 X-2.1716 Y1.2785 +G01 X-2.1778 Y1.2723 +G01 X-2.1941 Y1.2655 +G01 X-2.3259 Y1.2655 +G01 X-2.3422 Y1.2723 +G01 X-2.3547 Y1.2848 +G01 X-2.3615 Y1.3011 +G01 X-2.3615 Y1.3189 +G01 X-2.3547 Y1.3352 +G01 X-2.3422 Y1.3477 +G01 X-2.3259 Y1.3545 +G01 X-2.1941 Y1.3545 +G01 X-2.1778 Y1.3477 +G01 X-2.1716 Y1.3415 +G01 X-2.1237 Y1.3415 +G01 X-2.1198 Y1.3415 +G01 X-2.1008 Y1.3337 +G01 X-2.0863 Y1.3192 +G01 X-2.0785 Y1.3002 +G01 X-2.0785 Y1.2963 +G01 X-2.0785 Y1.2837 +G01 X-2.0785 Y1.0663 +G01 X-2.0785 Y1.0530 +G01 X-2.0669 Y1.0415 +G01 X-2.0484 Y1.0415 +G01 X-2.0422 Y1.0477 +G01 X-2.0259 Y1.0545 +G01 X-1.8941 Y1.0545 +G01 X-1.8778 Y1.0477 +G01 X-1.8653 Y1.0352 +G01 X-1.8585 Y1.0189 +G01 X-1.8585 Y1.0011 +G01 X-1.8653 Y0.9848 +G01 X-1.8778 Y0.9723 +G01 X-1.8941 Y0.9655 +G01 X-2.0259 Y0.9655 +G01 X-2.0422 Y0.9723 +G01 X-2.0484 Y0.9785 +G01 X-2.0737 Y0.9785 +G01 X-2.0785 Y0.9785 +G01 X-2.0785 Y0.9537 +G01 X-2.0785 Y0.9438 +G01 X-2.0909 Y0.9138 +G01 X-2.1138 Y0.8909 +G01 X-2.1438 Y0.8785 +G01 X-2.1537 Y0.8785 +G01 X-2.1588 Y0.8785 +G01 X-2.1600 Y0.8785 +G01 X-2.1663 Y0.8785 +G01 X-2.4732 Y0.8785 +G01 X-2.4900 Y0.8617 +G01 X-2.5300 Y0.8617 +G01 X-2.5468 Y0.8785 +G01 X-3.1037 Y0.8785 +G01 X-3.1052 Y0.8785 +G01 X-3.1163 Y0.8785 +G01 X-3.1262 Y0.8785 +G01 X-3.1562 Y0.8909 +G01 X-3.1791 Y0.9138 +G01 X-3.1915 Y0.9438 +G01 X-3.1915 Y0.9537 +G01 X-3.1915 Y1.5786 +G01 X-3.2045 Y1.5916 +G01 X-3.2045 Y1.6284 +G01 X-3.1915 Y1.6414 +G01 X-3.1915 Y1.6837 +G01 X-3.1915 Y1.6845 +G01 X-3.1915 Y1.6963 +G01 X-3.1915 Y1.7062 +G01 X-3.1791 Y1.7362 +G01 X-3.1562 Y1.7591 +G01 X-3.1262 Y1.7715 +G01 X-3.1163 Y1.7715 +G01 X-2.9963 Y1.7715 +G01 X-2.9900 Y1.7715 +G01 X-2.9883 Y1.7717 +G01 X-2.9853 Y1.7729 +G01 X-2.9829 Y1.7753 +G01 X-2.9817 Y1.7783 +G01 X-2.9815 Y1.7800 +G01 X-2.9815 Y1.8537 +G01 X-2.9815 Y1.8554 +G01 X-2.9815 Y1.8663 +G01 X-2.9815 Y1.8762 +G01 X-2.9691 Y1.9062 +G01 X-2.9462 Y1.9291 +G01 X-2.9162 Y1.9415 +G01 X-2.9063 Y1.9415 +G01 X-2.0963 Y1.9415 +G01 X-2.0837 Y1.9415 +G01 X-2.0314 Y1.9415 +G01 X-2.0184 Y1.9545 +G01 X-1.9816 Y1.9545 +G01 X-1.9686 Y1.9415 +G01 X-1.7700 Y1.9415 +G01 X-1.7664 Y1.9419 +G01 X-1.7597 Y1.9446 +G01 X-1.7546 Y1.9497 +G01 X-1.7519 Y1.9564 +G01 X-1.7515 Y1.9600 +G01 X-1.7515 Y1.9649 +G01 X-1.7515 Y1.9663 +G01 X-1.7515 Y2.0663 +G01 X-1.7515 Y2.0762 +G01 X-1.7391 Y2.1062 +G01 X-1.7162 Y2.1291 +G01 X-1.6862 Y2.1415 +G01 X-1.6763 Y2.1415 +G01 X-1.6703 Y2.1415 +G01 X-1.6700 Y2.1415 +G01 X-1.6637 Y2.1415 +G01 X-1.2537 Y2.1415 +G01 X-1.2438 Y2.1415 +G01 X-1.2138 Y2.1291 +G01 X-1.1909 Y2.1062 +G01 X-1.1785 Y2.0762 +G01 X-1.1785 Y2.0663 +G01 X-1.1785 Y2.0607 +G01 X-1.1785 Y2.0600 +G01 X-1.1785 Y2.0537 +G01 X-1.1785 Y1.9163 +G01 X-1.1785 Y1.9100 +G01 X-1.1781 Y1.9064 +G01 X-1.1754 Y1.8997 +G01 X-1.1703 Y1.8946 +G01 X-1.1636 Y1.8919 +G01 X-1.1600 Y1.8915 +G01 X-1.1554 Y1.8915 +G01 X-1.1537 Y1.8915 +G01 X-0.7978 Y1.8915 +G01 X-0.7878 Y1.9015 +G01 X-0.7697 Y1.9090 +G01 X-0.7503 Y1.9090 +G01 X-0.7322 Y1.9015 +G01 X-0.7222 Y1.8915 +G01 X-0.2653 Y1.8915 +G01 X-0.2552 Y1.8915 +G01 X-0.2242 Y1.8814 +G01 X-0.1978 Y1.8622 +G01 X-0.1819 Y1.8404 +G01 X-0.1214 Y1.8404 +G01 X-0.1023 Y1.8325 +G01 X-0.0877 Y1.8179 +G01 X-0.0798 Y1.7988 +G01 X-0.0798 Y1.7781 +G01 X-0.0877 Y1.7590 +G01 X-0.1023 Y1.7443 +G01 X-0.1214 Y1.7364 +G01 X-0.2786 Y1.7364 +G01 X-0.2977 Y1.7443 +G01 X-0.3123 Y1.7590 +G01 X-0.3202 Y1.7781 +G01 X-0.3202 Y1.7988 +G01 X-0.3123 Y1.8179 +G01 X-0.3017 Y1.8285 +G01 X-0.7222 Y1.8285 +G01 X-0.7322 Y1.8185 +G01 X-0.7503 Y1.8110 +G01 X-0.7697 Y1.8110 +G01 X-0.7878 Y1.8185 +G01 X-0.7978 Y1.8285 +G01 X-1.1537 Y1.8285 +G01 X-1.1555 Y1.8285 +G01 X-1.1663 Y1.8285 +G01 X-1.1762 Y1.8285 +G01 X-1.2062 Y1.8409 +G01 X-1.2291 Y1.8638 +G01 X-1.2415 Y1.8938 +G01 X-1.2415 Y1.9037 +G01 X-1.2415 Y1.9059 +G01 X-1.2415 Y1.9100 +G01 X-1.2415 Y1.9163 +G01 X-1.2415 Y2.0537 +G01 X-1.2415 Y2.0600 +G01 X-1.2419 Y2.0636 +G01 X-1.2446 Y2.0703 +G01 X-1.2497 Y2.0754 +G01 X-1.2564 Y2.0781 +G01 X-1.2600 Y2.0785 +G01 X-1.6637 Y2.0785 +G01 X-1.6700 Y2.0785 +G01 X-1.6736 Y2.0781 +G01 X-1.6803 Y2.0754 +G01 X-1.6854 Y2.0703 +G01 X-1.6881 Y2.0636 +G01 X-1.6885 Y2.0600 +G01 X-1.6885 Y1.9663 +G01 X-1.6885 Y1.9649 +G01 X-1.6885 Y1.9537 +G01 X-1.6885 Y1.9438 +G01 X-1.7009 Y1.9138 +G01 X-1.7238 Y1.8909 +G01 X-1.7538 Y1.8785 +G01 X-1.7637 Y1.8785 +G01 X-1.9686 Y1.8785 +G01 X-1.9816 Y1.8655 +G01 X-2.0184 Y1.8655 +G01 X-2.0314 Y1.8785 +G01 X-2.0585 Y1.8785 +G01 X-2.0585 Y1.7500 +G01 X-2.0581 Y1.7464 +G01 X-2.0554 Y1.7397 +G01 X-2.0503 Y1.7346 +G01 X-2.0436 Y1.7319 +G01 X-2.0400 Y1.7315 +G01 X-2.0349 Y1.7315 +G01 X-2.0337 Y1.7315 +G01 X-1.8014 Y1.7315 +G01 X-1.7884 Y1.7445 +G01 X-1.7516 Y1.7445 +G01 X-1.7386 Y1.7315 +G01 X-1.7337 Y1.7315 +G01 X-1.7278 Y1.7315 +G01 X-1.7052 Y1.7221 +G01 X-1.6879 Y1.7048 +G01 X-1.6785 Y1.6822 +G01 X-1.6785 Y1.6763 +G01 X-1.6785 Y1.5100 +G01 X-1.6781 Y1.5064 +G01 X-1.6754 Y1.4997 +G01 X-1.6703 Y1.4946 +G01 X-1.6636 Y1.4919 +G01 X-1.6600 Y1.4915 +G01 X-1.6575 Y1.4915 +G01 X-1.6537 Y1.4915 +G01 X-1.4663 Y1.4915 +G01 X-1.4600 Y1.4915 +G01 X-1.4566 Y1.4915 +G01 X-1.4537 Y1.4915 +G01 X-1.4438 Y1.4915 +G01 X-1.4138 Y1.4791 +G01 X-1.3909 Y1.4562 +G01 X-1.3836 Y1.4384 +G01 X-1.3762 Y1.4415 +G01 X-1.3663 Y1.4415 +G01 X-1.3595 Y1.4415 +G01 X-1.3537 Y1.4415 +G01 X-1.3384 Y1.4415 +G01 X-1.3322 Y1.4477 +G01 X-1.3159 Y1.4545 +G01 X-1.1841 Y1.4545 +G01 X-1.1678 Y1.4477 +G01 X-1.1553 Y1.4352 +G01 X-1.1485 Y1.4189 +G01 X-1.1485 Y1.4011 +G01 X-1.1553 Y1.3848 +G01 X-1.1678 Y1.3723 +G01 X-1.1841 Y1.3655 +G01 X-1.3159 Y1.3655 +G01 X-1.3322 Y1.3723 +G01 X-1.3384 Y1.3785 +G01 X-1.3537 Y1.3785 +G01 X-1.3596 Y1.3785 +G01 X-1.3600 Y1.3785 +G01 X-1.3636 Y1.3781 +G01 X-1.3703 Y1.3754 +G01 X-1.3754 Y1.3703 +G01 X-1.3781 Y1.3636 +G01 X-1.3785 Y1.3600 +G01 X-1.3785 Y1.2537 +G01 X-1.3785 Y1.2444 +G01 X-1.3785 Y1.2345 +G01 X-1.3855 Y1.2176 +G01 X-1.3855 Y1.1916 +G01 X-1.4116 Y1.1655 +G01 X-1.4484 Y1.1655 +G01 X-1.4745 Y1.1916 +G01 X-1.4745 Y1.2284 +G01 X-1.4484 Y1.2545 +G01 X-1.4415 Y1.2545 +G01 X-1.4415 Y1.4100 +G01 X-1.4419 Y1.4136 +G01 X-1.4446 Y1.4203 +G01 X-1.4497 Y1.4254 +G01 X-1.4564 Y1.4281 +G01 X-1.4600 Y1.4285 +G01 X-1.4663 Y1.4285 +G01 X-1.6537 Y1.4285 +G01 X-1.6576 Y1.4285 +G01 X-1.6663 Y1.4285 +G01 X-1.6762 Y1.4285 +G01 X-1.7062 Y1.4409 +G01 X-1.7291 Y1.4638 +G01 X-1.7415 Y1.4938 +G01 X-1.7415 Y1.5037 +G01 X-1.7415 Y1.6656 +G01 X-1.7516 Y1.6555 +G01 X-1.7884 Y1.6555 +G01 X-1.8014 Y1.6685 +G01 X-2.0337 Y1.6685 +G01 X-2.0349 Y1.6685 +G01 X-2.0463 Y1.6685 +G01 X-2.0562 Y1.6685 +G01 X-2.0862 Y1.6809 +G01 X-2.1091 Y1.7038 +G01 X-2.1215 Y1.7338 +G01 X-2.1215 Y1.7437 +G01 X-2.1215 Y1.8785 +G01 X-2.9000 Y1.8785 +G01 X-2.9036 Y1.8781 +G01 X-2.9103 Y1.8754 +G01 X-2.9154 Y1.8703 +G01 X-2.9181 Y1.8636 +G01 X-2.9185 Y1.8600 +G01 X-2.9185 Y1.8554 +G01 X-2.9185 Y1.8537 +G01 X-2.9185 Y1.7737 +G01 X-2.9185 Y1.7658 +G00 Z0.1000 +G00 X-0.5285 Y0.4738 +G01 Z-0.0070 F10 +G01 X-0.5285 Y0.4738 F20 +G01 X-0.5409 Y0.4438 +G01 X-0.5638 Y0.4209 +G01 X-0.5938 Y0.4085 +G01 X-0.6037 Y0.4085 +G01 X-0.6100 Y0.4085 +G01 X-0.6163 Y0.4085 +G01 X-1.3763 Y0.4085 +G01 X-1.3862 Y0.4085 +G01 X-1.4162 Y0.4209 +G01 X-1.4391 Y0.4438 +G01 X-1.4438 Y0.4552 +G01 X-1.4486 Y0.4572 +G01 X-1.4628 Y0.4714 +G01 X-1.4705 Y0.4900 +G01 X-1.4705 Y0.5100 +G01 X-1.4628 Y0.5286 +G01 X-1.4615 Y0.5299 +G01 X-1.4615 Y0.6786 +G01 X-1.4745 Y0.6916 +G01 X-1.4745 Y0.7284 +G01 X-1.4484 Y0.7545 +G01 X-1.4116 Y0.7545 +G01 X-1.3855 Y0.7284 +G01 X-1.3855 Y0.6916 +G01 X-1.3985 Y0.6786 +G01 X-1.3985 Y0.5457 +G01 X-1.3914 Y0.5428 +G01 X-1.3772 Y0.5286 +G01 X-1.3695 Y0.5100 +G01 X-1.3695 Y0.4900 +G01 X-1.3765 Y0.4731 +G01 X-1.3736 Y0.4719 +G01 X-1.3700 Y0.4715 +G01 X-0.6163 Y0.4715 +G01 X-0.6100 Y0.4715 +G01 X-0.6064 Y0.4719 +G01 X-0.5997 Y0.4746 +G01 X-0.5946 Y0.4797 +G01 X-0.5919 Y0.4864 +G01 X-0.5915 Y0.4900 +G01 X-0.5915 Y0.8786 +G01 X-0.6045 Y0.8916 +G01 X-0.6045 Y0.9284 +G01 X-0.5784 Y0.9545 +G01 X-0.5416 Y0.9545 +G01 X-0.5155 Y0.9284 +G01 X-0.5155 Y0.8916 +G01 X-0.5285 Y0.8786 +G01 X-0.5285 Y0.4837 +G01 X-0.5285 Y0.4738 +G00 Z0.1000 +G00 X-1.6985 Y0.7838 +G01 Z-0.0070 F10 +G01 X-1.6985 Y0.7838 F20 +G01 X-1.7109 Y0.7538 +G01 X-1.7338 Y0.7309 +G01 X-1.7638 Y0.7185 +G01 X-1.7737 Y0.7185 +G01 X-1.7766 Y0.7185 +G01 X-1.7800 Y0.7185 +G01 X-1.7863 Y0.7185 +G01 X-2.1837 Y0.7185 +G01 X-2.1900 Y0.7185 +G01 X-2.1917 Y0.7183 +G01 X-2.1947 Y0.7171 +G01 X-2.1971 Y0.7147 +G01 X-2.1983 Y0.7117 +G01 X-2.1985 Y0.7100 +G01 X-2.1985 Y0.5963 +G01 X-2.1985 Y0.5938 +G01 X-2.1985 Y0.5837 +G01 X-2.1985 Y0.5758 +G01 X-2.2094 Y0.5495 +G01 X-2.2295 Y0.5294 +G01 X-2.2558 Y0.5185 +G01 X-2.2637 Y0.5185 +G01 X-2.2688 Y0.5185 +G01 X-2.2700 Y0.5185 +G01 X-2.2763 Y0.5185 +G01 X-2.8113 Y0.5185 +G01 X-2.8223 Y0.5075 +G01 X-2.8414 Y0.4996 +G01 X-2.9986 Y0.4996 +G01 X-3.0177 Y0.5075 +G01 X-3.0323 Y0.5221 +G01 X-3.0402 Y0.5412 +G01 X-3.0402 Y0.5619 +G01 X-3.0323 Y0.5810 +G01 X-3.0177 Y0.5957 +G01 X-2.9986 Y0.6036 +G01 X-2.8414 Y0.6036 +G01 X-2.8223 Y0.5957 +G01 X-2.8081 Y0.5815 +G01 X-2.2763 Y0.5815 +G01 X-2.2700 Y0.5815 +G01 X-2.2683 Y0.5817 +G01 X-2.2653 Y0.5829 +G01 X-2.2629 Y0.5853 +G01 X-2.2617 Y0.5883 +G01 X-2.2615 Y0.5900 +G01 X-2.2615 Y0.5938 +G01 X-2.2615 Y0.5963 +G01 X-2.2615 Y0.7163 +G01 X-2.2615 Y0.7242 +G01 X-2.2506 Y0.7505 +G01 X-2.2305 Y0.7706 +G01 X-2.2042 Y0.7815 +G01 X-2.1963 Y0.7815 +G01 X-2.1906 Y0.7815 +G01 X-2.1900 Y0.7815 +G01 X-2.1837 Y0.7815 +G01 X-1.7863 Y0.7815 +G01 X-1.7800 Y0.7815 +G01 X-1.7764 Y0.7819 +G01 X-1.7697 Y0.7846 +G01 X-1.7646 Y0.7897 +G01 X-1.7619 Y0.7964 +G01 X-1.7615 Y0.8000 +G01 X-1.7615 Y0.9637 +G01 X-1.7615 Y0.9645 +G01 X-1.7615 Y0.9763 +G01 X-1.7615 Y0.9842 +G01 X-1.7506 Y1.0105 +G01 X-1.7305 Y1.0306 +G01 X-1.7042 Y1.0415 +G01 X-1.6963 Y1.0415 +G01 X-1.6901 Y1.0415 +G01 X-1.6837 Y1.0415 +G01 X-1.3384 Y1.0415 +G01 X-1.3322 Y1.0477 +G01 X-1.3159 Y1.0545 +G01 X-1.1841 Y1.0545 +G01 X-1.1678 Y1.0477 +G01 X-1.1553 Y1.0352 +G01 X-1.1485 Y1.0189 +G01 X-1.1485 Y1.0011 +G01 X-1.1553 Y0.9848 +G01 X-1.1678 Y0.9723 +G01 X-1.1841 Y0.9655 +G01 X-1.3159 Y0.9655 +G01 X-1.3322 Y0.9723 +G01 X-1.3384 Y0.9785 +G01 X-1.6837 Y0.9785 +G01 X-1.6900 Y0.9785 +G01 X-1.6917 Y0.9783 +G01 X-1.6947 Y0.9771 +G01 X-1.6971 Y0.9747 +G01 X-1.6983 Y0.9717 +G01 X-1.6985 Y0.9700 +G01 X-1.6985 Y0.9645 +G01 X-1.6985 Y0.9637 +G01 X-1.6985 Y0.7937 +G01 X-1.6985 Y0.7838 +G00 Z0.1000 +G00 X-0.5738 Y1.4415 +G01 Z-0.0070 F10 +G01 X-0.5738 Y1.4415 F20 +G01 X-0.5438 Y1.4291 +G01 X-0.5209 Y1.4062 +G01 X-0.5085 Y1.3762 +G01 X-0.5085 Y1.3663 +G01 X-0.5085 Y1.3601 +G01 X-0.5085 Y1.3600 +G01 X-0.5085 Y1.3584 +G01 X-0.5081 Y1.3548 +G01 X-0.5054 Y1.3481 +G01 X-0.5003 Y1.3430 +G01 X-0.4936 Y1.3403 +G01 X-0.4900 Y1.3399 +G01 X-0.4882 Y1.3399 +G01 X-0.4837 Y1.3399 +G01 X-0.3103 Y1.3399 +G01 X-0.2977 Y1.3525 +G01 X-0.2786 Y1.3604 +G01 X-0.1214 Y1.3604 +G01 X-0.1023 Y1.3525 +G01 X-0.0877 Y1.3379 +G01 X-0.0798 Y1.3188 +G01 X-0.0798 Y1.2981 +G01 X-0.0877 Y1.2790 +G01 X-0.1023 Y1.2643 +G01 X-0.1214 Y1.2564 +G01 X-0.2786 Y1.2564 +G01 X-0.2977 Y1.2643 +G01 X-0.3103 Y1.2769 +G01 X-0.4837 Y1.2769 +G01 X-0.4882 Y1.2769 +G01 X-0.4900 Y1.2769 +G01 X-0.4963 Y1.2769 +G01 X-0.5062 Y1.2769 +G01 X-0.5362 Y1.2893 +G01 X-0.5591 Y1.3123 +G01 X-0.5715 Y1.3422 +G01 X-0.5715 Y1.3522 +G01 X-0.5715 Y1.3537 +G01 X-0.5715 Y1.3600 +G01 X-0.5719 Y1.3636 +G01 X-0.5746 Y1.3703 +G01 X-0.5797 Y1.3754 +G01 X-0.5864 Y1.3781 +G01 X-0.5900 Y1.3785 +G01 X-0.8616 Y1.3785 +G01 X-0.8678 Y1.3723 +G01 X-0.8841 Y1.3655 +G01 X-1.0159 Y1.3655 +G01 X-1.0322 Y1.3723 +G01 X-1.0447 Y1.3848 +G01 X-1.0515 Y1.4011 +G01 X-1.0515 Y1.4189 +G01 X-1.0447 Y1.4352 +G01 X-1.0322 Y1.4477 +G01 X-1.0159 Y1.4545 +G01 X-0.8841 Y1.4545 +G01 X-0.8678 Y1.4477 +G01 X-0.8616 Y1.4415 +G01 X-0.5837 Y1.4415 +G01 X-0.5738 Y1.4415 +G00 Z0.1000 +G00 X-0.4463 Y1.2415 +G01 Z-0.0070 F10 +G01 X-0.4400 Y1.2415 F20 +G01 X-0.4368 Y1.2415 +G01 X-0.4337 Y1.2415 +G01 X-0.4258 Y1.2415 +G01 X-0.3995 Y1.2306 +G01 X-0.3794 Y1.2105 +G01 X-0.3685 Y1.1842 +G01 X-0.3685 Y1.1763 +G01 X-0.3685 Y1.1616 +G01 X-0.3681 Y1.1580 +G01 X-0.3654 Y1.1513 +G01 X-0.3603 Y1.1462 +G01 X-0.3536 Y1.1434 +G01 X-0.3500 Y1.1431 +G01 X-0.3449 Y1.1431 +G01 X-0.3437 Y1.1431 +G01 X-0.3103 Y1.1431 +G01 X-0.2977 Y1.1557 +G01 X-0.2786 Y1.1636 +G01 X-0.1214 Y1.1636 +G01 X-0.1023 Y1.1557 +G01 X-0.0877 Y1.1410 +G01 X-0.0798 Y1.1219 +G01 X-0.0798 Y1.1012 +G01 X-0.0877 Y1.0821 +G01 X-0.1023 Y1.0675 +G01 X-0.1214 Y1.0596 +G01 X-0.2786 Y1.0596 +G01 X-0.2977 Y1.0675 +G01 X-0.3103 Y1.0801 +G01 X-0.3437 Y1.0801 +G01 X-0.3449 Y1.0801 +G01 X-0.3563 Y1.0801 +G01 X-0.3662 Y1.0801 +G01 X-0.3962 Y1.0925 +G01 X-0.4191 Y1.1154 +G01 X-0.4315 Y1.1454 +G01 X-0.4315 Y1.1553 +G01 X-0.4315 Y1.1700 +G01 X-0.4317 Y1.1717 +G01 X-0.4329 Y1.1747 +G01 X-0.4353 Y1.1771 +G01 X-0.4383 Y1.1783 +G01 X-0.4400 Y1.1785 +G01 X-0.4463 Y1.1785 +G01 X-0.8616 Y1.1785 +G01 X-0.8678 Y1.1723 +G01 X-0.8841 Y1.1655 +G01 X-1.0159 Y1.1655 +G01 X-1.0322 Y1.1723 +G01 X-1.0447 Y1.1848 +G01 X-1.0515 Y1.2011 +G01 X-1.0515 Y1.2189 +G01 X-1.0447 Y1.2352 +G01 X-1.0322 Y1.2477 +G01 X-1.0159 Y1.2545 +G01 X-0.8841 Y1.2545 +G01 X-0.8678 Y1.2477 +G01 X-0.8616 Y1.2415 +G01 X-0.4463 Y1.2415 +G00 Z0.1000 +G00 X-0.4042 Y0.8785 +G01 Z-0.0070 F10 +G01 X-0.4042 Y0.8785 F20 +G01 X-0.4305 Y0.8894 +G01 X-0.4506 Y0.9095 +G01 X-0.4615 Y0.9358 +G01 X-0.4615 Y0.9437 +G01 X-0.4615 Y0.9497 +G01 X-0.4615 Y0.9500 +G01 X-0.4615 Y0.9563 +G01 X-0.4615 Y0.9600 +G01 X-0.4619 Y0.9636 +G01 X-0.4646 Y0.9703 +G01 X-0.4697 Y0.9754 +G01 X-0.4764 Y0.9781 +G01 X-0.4800 Y0.9785 +G01 X-0.4863 Y0.9785 +G01 X-0.8616 Y0.9785 +G01 X-0.8678 Y0.9723 +G01 X-0.8841 Y0.9655 +G01 X-1.0159 Y0.9655 +G01 X-1.0322 Y0.9723 +G01 X-1.0447 Y0.9848 +G01 X-1.0515 Y1.0011 +G01 X-1.0515 Y1.0189 +G01 X-1.0447 Y1.0352 +G01 X-1.0322 Y1.0477 +G01 X-1.0159 Y1.0545 +G01 X-0.8841 Y1.0545 +G01 X-0.8678 Y1.0477 +G01 X-0.8616 Y1.0415 +G01 X-0.4863 Y1.0415 +G01 X-0.4800 Y1.0415 +G01 X-0.4799 Y1.0415 +G01 X-0.4737 Y1.0415 +G01 X-0.4638 Y1.0415 +G01 X-0.4338 Y1.0291 +G01 X-0.4109 Y1.0062 +G01 X-0.3985 Y0.9762 +G01 X-0.3985 Y0.9663 +G01 X-0.3985 Y0.9563 +G01 X-0.3985 Y0.9500 +G01 X-0.3983 Y0.9483 +G01 X-0.3971 Y0.9453 +G01 X-0.3947 Y0.9429 +G01 X-0.3917 Y0.9417 +G01 X-0.3900 Y0.9415 +G01 X-0.3087 Y0.9415 +G01 X-0.2977 Y0.9525 +G01 X-0.2786 Y0.9604 +G01 X-0.1214 Y0.9604 +G01 X-0.1023 Y0.9525 +G01 X-0.0877 Y0.9379 +G01 X-0.0798 Y0.9188 +G01 X-0.0798 Y0.8981 +G01 X-0.0877 Y0.8790 +G01 X-0.1023 Y0.8643 +G01 X-0.1214 Y0.8564 +G01 X-0.2786 Y0.8564 +G01 X-0.2977 Y0.8643 +G01 X-0.3119 Y0.8785 +G01 X-0.3963 Y0.8785 +G01 X-0.4042 Y0.8785 +G00 Z0.1000 +G00 X-0.4255 Y0.2832 +G01 Z-0.0070 F10 +G01 X-0.4255 Y0.2832 F20 +G01 X-0.4384 Y0.2521 +G01 X-0.4621 Y0.2284 +G01 X-0.4932 Y0.2155 +G01 X-0.5031 Y0.2155 +G01 X-0.5100 Y0.2155 +G01 X-0.5169 Y0.2155 +G01 X-1.0400 Y0.2155 +G01 X-1.0430 Y0.2152 +G01 X-1.0486 Y0.2129 +G01 X-1.0529 Y0.2086 +G01 X-1.0552 Y0.2030 +G01 X-1.0555 Y0.2000 +G01 X-1.0555 Y0.1958 +G01 X-1.0555 Y0.1931 +G01 X-1.0555 Y0.1431 +G01 X-1.0555 Y0.1332 +G01 X-1.0684 Y0.1021 +G01 X-1.0921 Y0.0784 +G01 X-1.1232 Y0.0655 +G01 X-1.1400 Y0.0655 +G01 X-1.1469 Y0.0655 +G01 X-1.5931 Y0.0655 +G01 X-1.6000 Y0.0655 +G01 X-1.6168 Y0.0655 +G01 X-1.6479 Y0.0784 +G01 X-1.6716 Y0.1021 +G01 X-1.6845 Y0.1332 +G01 X-1.6845 Y0.1431 +G01 X-1.6845 Y0.8669 +G01 X-1.6845 Y0.8768 +G01 X-1.6716 Y0.9079 +G01 X-1.6479 Y0.9316 +G01 X-1.6168 Y0.9445 +G01 X-1.6069 Y0.9445 +G01 X-1.6000 Y0.9445 +G01 X-1.5931 Y0.9445 +G01 X-1.3397 Y0.9445 +G01 X-1.3339 Y0.9503 +G01 X-1.3164 Y0.9575 +G01 X-1.1835 Y0.9575 +G01 X-1.1661 Y0.9503 +G01 X-1.1527 Y0.9369 +G01 X-1.1455 Y0.9194 +G01 X-1.1455 Y0.9005 +G01 X-1.1527 Y0.8831 +G01 X-1.1661 Y0.8697 +G01 X-1.1835 Y0.8625 +G01 X-1.3164 Y0.8625 +G01 X-1.3339 Y0.8697 +G01 X-1.3397 Y0.8755 +G01 X-1.5931 Y0.8755 +G01 X-1.6000 Y0.8755 +G01 X-1.6030 Y0.8752 +G01 X-1.6086 Y0.8729 +G01 X-1.6129 Y0.8686 +G01 X-1.6152 Y0.8630 +G01 X-1.6155 Y0.8600 +G01 X-1.6155 Y0.1500 +G01 X-1.6152 Y0.1470 +G01 X-1.6129 Y0.1414 +G01 X-1.6086 Y0.1371 +G01 X-1.6030 Y0.1348 +G01 X-1.6000 Y0.1345 +G01 X-1.5931 Y0.1345 +G01 X-1.1469 Y0.1345 +G01 X-1.1400 Y0.1345 +G01 X-1.1370 Y0.1348 +G01 X-1.1314 Y0.1371 +G01 X-1.1271 Y0.1414 +G01 X-1.1248 Y0.1470 +G01 X-1.1245 Y0.1500 +G01 X-1.1245 Y0.1931 +G01 X-1.1245 Y0.1958 +G01 X-1.1245 Y0.2069 +G01 X-1.1245 Y0.2168 +G01 X-1.1116 Y0.2479 +G01 X-1.0879 Y0.2716 +G01 X-1.0568 Y0.2845 +G01 X-1.0469 Y0.2845 +G01 X-0.5169 Y0.2845 +G01 X-0.5100 Y0.2845 +G01 X-0.5070 Y0.2848 +G01 X-0.5014 Y0.2871 +G01 X-0.4971 Y0.2914 +G01 X-0.4948 Y0.2970 +G01 X-0.4945 Y0.3000 +G01 X-0.4945 Y0.6531 +G01 X-0.4945 Y0.6542 +G01 X-0.4945 Y0.6669 +G01 X-0.4945 Y0.6768 +G01 X-0.4816 Y0.7079 +G01 X-0.4579 Y0.7316 +G01 X-0.4268 Y0.7445 +G01 X-0.4100 Y0.7445 +G01 X-0.4031 Y0.7445 +G01 X-0.3131 Y0.7445 +G01 X-0.2994 Y0.7582 +G01 X-0.2792 Y0.7666 +G01 X-0.1208 Y0.7666 +G01 X-0.1006 Y0.7582 +G01 X-0.0851 Y0.7427 +G01 X-0.0768 Y0.7225 +G01 X-0.0768 Y0.7006 +G01 X-0.0851 Y0.6804 +G01 X-0.1006 Y0.6649 +G01 X-0.1208 Y0.6566 +G01 X-0.2792 Y0.6566 +G01 X-0.2994 Y0.6649 +G01 X-0.3100 Y0.6755 +G01 X-0.4031 Y0.6755 +G01 X-0.4100 Y0.6755 +G01 X-0.4130 Y0.6752 +G01 X-0.4186 Y0.6729 +G01 X-0.4229 Y0.6686 +G01 X-0.4252 Y0.6630 +G01 X-0.4255 Y0.6600 +G01 X-0.4255 Y0.6542 +G01 X-0.4255 Y0.6531 +G01 X-0.4255 Y0.2931 +G01 X-0.4255 Y0.2832 +G00 Z0.1000 +G00 X-0.5732 Y1.4445 +G01 Z-0.0070 F10 +G01 X-0.5732 Y1.4445 F20 +G01 X-0.5421 Y1.4316 +G01 X-0.5184 Y1.4079 +G01 X-0.5055 Y1.3768 +G01 X-0.5055 Y1.3669 +G01 X-0.5055 Y1.3650 +G01 X-0.5055 Y1.3600 +G01 X-0.5055 Y1.3584 +G01 X-0.5052 Y1.3554 +G01 X-0.5029 Y1.3498 +G01 X-0.4986 Y1.3455 +G01 X-0.4930 Y1.3432 +G01 X-0.4900 Y1.3429 +G01 X-0.4873 Y1.3429 +G01 X-0.4831 Y1.3429 +G01 X-0.3115 Y1.3429 +G01 X-0.2994 Y1.3550 +G01 X-0.2792 Y1.3634 +G01 X-0.1208 Y1.3634 +G01 X-0.1006 Y1.3550 +G01 X-0.0851 Y1.3396 +G01 X-0.0768 Y1.3194 +G01 X-0.0768 Y1.2975 +G01 X-0.0851 Y1.2773 +G01 X-0.1006 Y1.2618 +G01 X-0.1208 Y1.2534 +G01 X-0.2792 Y1.2534 +G01 X-0.2994 Y1.2618 +G01 X-0.3115 Y1.2739 +G01 X-0.4831 Y1.2739 +G01 X-0.4874 Y1.2739 +G01 X-0.4969 Y1.2739 +G01 X-0.5068 Y1.2739 +G01 X-0.5379 Y1.2868 +G01 X-0.5616 Y1.3106 +G01 X-0.5745 Y1.3416 +G01 X-0.5745 Y1.3516 +G01 X-0.5745 Y1.3531 +G01 X-0.5745 Y1.3600 +G01 X-0.5748 Y1.3630 +G01 X-0.5771 Y1.3686 +G01 X-0.5814 Y1.3729 +G01 X-0.5870 Y1.3752 +G01 X-0.5900 Y1.3755 +G01 X-0.8603 Y1.3755 +G01 X-0.8661 Y1.3697 +G01 X-0.8835 Y1.3625 +G01 X-1.0164 Y1.3625 +G01 X-1.0339 Y1.3697 +G01 X-1.0473 Y1.3831 +G01 X-1.0545 Y1.4005 +G01 X-1.0545 Y1.4194 +G01 X-1.0473 Y1.4369 +G01 X-1.0339 Y1.4503 +G01 X-1.0164 Y1.4575 +G01 X-0.8835 Y1.4575 +G01 X-0.8661 Y1.4503 +G01 X-0.8603 Y1.4445 +G01 X-0.5831 Y1.4445 +G01 X-0.5732 Y1.4445 +G00 Z0.1000 +G00 X-1.6955 Y0.7832 +G01 Z-0.0070 F10 +G01 X-1.6955 Y0.7832 F20 +G01 X-1.7084 Y0.7521 +G01 X-1.7321 Y0.7284 +G01 X-1.7632 Y0.7155 +G01 X-1.7800 Y0.7155 +G01 X-1.7869 Y0.7155 +G01 X-2.1831 Y0.7155 +G01 X-2.1900 Y0.7155 +G01 X-2.1911 Y0.7154 +G01 X-2.1931 Y0.7146 +G01 X-2.1946 Y0.7131 +G01 X-2.1954 Y0.7111 +G01 X-2.1955 Y0.7100 +G01 X-2.1955 Y0.5969 +G01 X-2.1955 Y0.5944 +G01 X-2.1955 Y0.5831 +G01 X-2.1955 Y0.5752 +G01 X-2.2068 Y0.5478 +G01 X-2.2278 Y0.5268 +G01 X-2.2552 Y0.5155 +G01 X-2.2631 Y0.5155 +G01 X-2.2688 Y0.5155 +G01 X-2.2700 Y0.5155 +G01 X-2.2769 Y0.5155 +G01 X-2.8100 Y0.5155 +G01 X-2.8206 Y0.5049 +G01 X-2.8408 Y0.4966 +G01 X-2.9992 Y0.4966 +G01 X-3.0194 Y0.5049 +G01 X-3.0349 Y0.5204 +G01 X-3.0432 Y0.5406 +G01 X-3.0432 Y0.5625 +G01 X-3.0349 Y0.5827 +G01 X-3.0194 Y0.5982 +G01 X-2.9992 Y0.6066 +G01 X-2.8408 Y0.6066 +G01 X-2.8206 Y0.5982 +G01 X-2.8069 Y0.5845 +G01 X-2.2769 Y0.5845 +G01 X-2.2700 Y0.5845 +G01 X-2.2689 Y0.5846 +G01 X-2.2669 Y0.5854 +G01 X-2.2654 Y0.5869 +G01 X-2.2646 Y0.5889 +G01 X-2.2645 Y0.5900 +G01 X-2.2645 Y0.5944 +G01 X-2.2645 Y0.5969 +G01 X-2.2645 Y0.7169 +G01 X-2.2645 Y0.7248 +G01 X-2.2532 Y0.7522 +G01 X-2.2322 Y0.7732 +G01 X-2.2048 Y0.7845 +G01 X-2.1969 Y0.7845 +G01 X-2.1906 Y0.7845 +G01 X-2.1900 Y0.7845 +G01 X-2.1831 Y0.7845 +G01 X-1.7869 Y0.7845 +G01 X-1.7800 Y0.7845 +G01 X-1.7770 Y0.7848 +G01 X-1.7714 Y0.7871 +G01 X-1.7671 Y0.7914 +G01 X-1.7648 Y0.7970 +G01 X-1.7645 Y0.8000 +G01 X-1.7645 Y0.9631 +G01 X-1.7645 Y0.9640 +G01 X-1.7645 Y0.9769 +G01 X-1.7645 Y0.9848 +G01 X-1.7532 Y1.0122 +G01 X-1.7322 Y1.0331 +G01 X-1.7048 Y1.0445 +G01 X-1.6969 Y1.0445 +G01 X-1.6900 Y1.0445 +G01 X-1.6831 Y1.0445 +G01 X-1.3397 Y1.0445 +G01 X-1.3339 Y1.0503 +G01 X-1.3164 Y1.0575 +G01 X-1.1835 Y1.0575 +G01 X-1.1661 Y1.0503 +G01 X-1.1527 Y1.0369 +G01 X-1.1455 Y1.0194 +G01 X-1.1455 Y1.0005 +G01 X-1.1527 Y0.9831 +G01 X-1.1661 Y0.9697 +G01 X-1.1835 Y0.9625 +G01 X-1.3164 Y0.9625 +G01 X-1.3339 Y0.9697 +G01 X-1.3397 Y0.9755 +G01 X-1.6831 Y0.9755 +G01 X-1.6900 Y0.9755 +G01 X-1.6911 Y0.9754 +G01 X-1.6931 Y0.9746 +G01 X-1.6946 Y0.9731 +G01 X-1.6954 Y0.9711 +G01 X-1.6955 Y0.9700 +G01 X-1.6955 Y0.9640 +G01 X-1.6955 Y0.9631 +G01 X-1.6955 Y0.7931 +G01 X-1.6955 Y0.7832 +G00 Z0.1000 +G00 X-2.1745 Y0.6268 +G01 Z-0.0070 F10 +G01 X-2.1745 Y0.6268 F20 +G01 X-2.1616 Y0.6579 +G01 X-2.1379 Y0.6816 +G01 X-2.1068 Y0.6945 +G01 X-2.0969 Y0.6945 +G01 X-2.0895 Y0.6945 +G01 X-2.0831 Y0.6945 +G01 X-2.0512 Y0.6945 +G01 X-2.0403 Y0.7054 +G01 X-2.0206 Y0.7135 +G01 X-1.9994 Y0.7135 +G01 X-1.9797 Y0.7054 +G01 X-1.9688 Y0.6945 +G01 X-1.7827 Y0.6945 +G01 X-1.7697 Y0.7075 +G01 X-1.7303 Y0.7075 +G01 X-1.7025 Y0.6797 +G01 X-1.7025 Y0.6403 +G01 X-1.7303 Y0.6125 +G01 X-1.7697 Y0.6125 +G01 X-1.7827 Y0.6255 +G01 X-1.9688 Y0.6255 +G01 X-1.9797 Y0.6146 +G01 X-1.9994 Y0.6065 +G01 X-2.0206 Y0.6065 +G01 X-2.0403 Y0.6146 +G01 X-2.0512 Y0.6255 +G01 X-2.0831 Y0.6255 +G01 X-2.0895 Y0.6255 +G01 X-2.0900 Y0.6255 +G01 X-2.0930 Y0.6252 +G01 X-2.0986 Y0.6229 +G01 X-2.1029 Y0.6186 +G01 X-2.1052 Y0.6130 +G01 X-2.1055 Y0.6100 +G01 X-2.1055 Y0.2927 +G01 X-2.0925 Y0.2797 +G01 X-2.0925 Y0.2403 +G01 X-2.1203 Y0.2125 +G01 X-2.1597 Y0.2125 +G01 X-2.1875 Y0.2403 +G01 X-2.1875 Y0.2797 +G01 X-2.1745 Y0.2927 +G01 X-2.1745 Y0.6169 +G01 X-2.1745 Y0.6268 +G00 Z0.1000 +G00 X-3.1045 Y1.6168 +G01 Z-0.0070 F10 +G01 X-3.1045 Y1.6168 F20 +G01 X-3.0916 Y1.6479 +G01 X-3.0679 Y1.6716 +G01 X-3.0368 Y1.6845 +G01 X-3.0269 Y1.6845 +G01 X-3.0193 Y1.6845 +G01 X-3.0131 Y1.6845 +G01 X-2.9045 Y1.6845 +G01 X-2.9045 Y1.6853 +G01 X-2.9045 Y1.6869 +G01 X-2.9045 Y1.7769 +G01 X-2.9045 Y1.7868 +G01 X-2.8916 Y1.8179 +G01 X-2.8679 Y1.8416 +G01 X-2.8368 Y1.8545 +G01 X-2.8200 Y1.8545 +G01 X-2.8131 Y1.8545 +G01 X-2.7027 Y1.8545 +G01 X-2.6897 Y1.8675 +G01 X-2.6503 Y1.8675 +G01 X-2.6225 Y1.8397 +G01 X-2.6225 Y1.8003 +G01 X-2.6503 Y1.7725 +G01 X-2.6897 Y1.7725 +G01 X-2.7027 Y1.7855 +G01 X-2.8131 Y1.7855 +G01 X-2.8200 Y1.7855 +G01 X-2.8230 Y1.7852 +G01 X-2.8286 Y1.7829 +G01 X-2.8329 Y1.7786 +G01 X-2.8352 Y1.7730 +G01 X-2.8355 Y1.7700 +G01 X-2.8355 Y1.6869 +G01 X-2.8355 Y1.6853 +G01 X-2.8355 Y1.6731 +G01 X-2.8355 Y1.6672 +G01 X-2.8453 Y1.6435 +G01 X-2.8635 Y1.6253 +G01 X-2.8872 Y1.6155 +G01 X-2.8931 Y1.6155 +G01 X-3.0131 Y1.6155 +G01 X-3.0194 Y1.6155 +G01 X-3.0200 Y1.6155 +G01 X-3.0230 Y1.6152 +G01 X-3.0286 Y1.6129 +G01 X-3.0329 Y1.6086 +G01 X-3.0352 Y1.6030 +G01 X-3.0355 Y1.6000 +G01 X-3.0355 Y1.2900 +G01 X-3.0352 Y1.2870 +G01 X-3.0329 Y1.2814 +G01 X-3.0286 Y1.2771 +G01 X-3.0230 Y1.2748 +G01 X-3.0200 Y1.2745 +G01 X-3.0131 Y1.2745 +G01 X-2.7234 Y1.2745 +G01 X-2.7200 Y1.2752 +G01 X-2.7166 Y1.2745 +G01 X-2.7131 Y1.2745 +G01 X-2.7128 Y1.2744 +G01 X-2.6897 Y1.2975 +G01 X-2.6503 Y1.2975 +G01 X-2.6225 Y1.2697 +G01 X-2.6225 Y1.2303 +G01 X-2.6503 Y1.2025 +G01 X-2.6777 Y1.2025 +G01 X-2.6999 Y1.1981 +G01 X-2.7275 Y1.2035 +G01 X-2.7304 Y1.2055 +G01 X-3.0131 Y1.2055 +G01 X-3.0200 Y1.2055 +G01 X-3.0368 Y1.2055 +G01 X-3.0679 Y1.2184 +G01 X-3.0916 Y1.2421 +G01 X-3.1045 Y1.2732 +G01 X-3.1045 Y1.2831 +G01 X-3.1045 Y1.6069 +G01 X-3.1045 Y1.6168 +G00 Z0.1000 +G00 X-1.9255 Y1.4368 +G01 Z-0.0070 F10 +G01 X-1.9255 Y1.4368 F20 +G01 X-1.9255 Y1.4269 +G01 X-1.9255 Y1.3575 +G01 X-1.8935 Y1.3575 +G01 X-1.8761 Y1.3503 +G01 X-1.8627 Y1.3369 +G01 X-1.8555 Y1.3194 +G01 X-1.8555 Y1.3005 +G01 X-1.8627 Y1.2831 +G01 X-1.8761 Y1.2697 +G01 X-1.8935 Y1.2625 +G01 X-2.0264 Y1.2625 +G01 X-2.0439 Y1.2697 +G01 X-2.0573 Y1.2831 +G01 X-2.0645 Y1.3005 +G01 X-2.0645 Y1.3194 +G01 X-2.0573 Y1.3369 +G01 X-2.0439 Y1.3503 +G01 X-2.0264 Y1.3575 +G01 X-1.9945 Y1.3575 +G01 X-1.9945 Y1.4200 +G01 X-1.9947 Y1.4221 +G01 X-2.0078 Y1.4353 +G01 X-2.0100 Y1.4355 +G01 X-2.1719 Y1.4355 +G01 X-2.1887 Y1.4187 +G01 X-2.2313 Y1.4187 +G01 X-2.2371 Y1.4246 +G01 X-2.2480 Y1.4210 +G01 X-2.2480 Y1.4185 +G01 X-2.2785 Y1.3880 +G01 X-2.3215 Y1.3880 +G01 X-2.3520 Y1.4185 +G01 X-2.3520 Y1.4615 +G01 X-2.3215 Y1.4920 +G01 X-2.2785 Y1.4920 +G01 X-2.2721 Y1.4857 +G01 X-2.2613 Y1.4893 +G01 X-2.2613 Y1.4913 +G01 X-2.2313 Y1.5213 +G01 X-2.1887 Y1.5213 +G01 X-2.1719 Y1.5045 +G01 X-2.0081 Y1.5045 +G01 X-1.9913 Y1.5213 +G01 X-1.9487 Y1.5213 +G01 X-1.9187 Y1.4913 +G01 X-1.9187 Y1.4487 +G01 X-1.9270 Y1.4404 +G01 X-1.9255 Y1.4368 +G00 Z0.1000 +G00 X-2.6875 Y0.2403 +G01 Z-0.0070 F10 +G01 X-2.6875 Y0.2797 F20 +G01 X-2.6597 Y0.3075 +G01 X-2.6203 Y0.3075 +G01 X-2.6073 Y0.2945 +G01 X-2.5545 Y0.2945 +G01 X-2.5545 Y0.4319 +G01 X-2.5613 Y0.4387 +G01 X-2.5613 Y0.4813 +G01 X-2.5313 Y0.5113 +G01 X-2.4887 Y0.5113 +G01 X-2.4587 Y0.4813 +G01 X-2.4587 Y0.4387 +G01 X-2.4655 Y0.4319 +G01 X-2.4655 Y0.2689 +G01 X-2.4655 Y0.1900 +G01 X-2.4654 Y0.1891 +G01 X-2.4649 Y0.1875 +G01 X-2.4639 Y0.1861 +G01 X-2.4625 Y0.1851 +G01 X-2.4609 Y0.1846 +G01 X-2.4600 Y0.1845 +G01 X-2.4522 Y0.1845 +G01 X-2.4511 Y0.1845 +G01 X-1.8700 Y0.1845 +G01 X-1.8691 Y0.1846 +G01 X-1.8675 Y0.1851 +G01 X-1.8675 Y0.2197 +G01 X-1.8397 Y0.2475 +G01 X-1.8003 Y0.2475 +G01 X-1.7725 Y0.2197 +G01 X-1.7725 Y0.1803 +G01 X-1.7755 Y0.1773 +G01 X-1.7755 Y0.1750 +G01 X-1.7848 Y0.1466 +G01 X-1.8023 Y0.1224 +G01 X-1.8266 Y0.1048 +G01 X-1.8550 Y0.0955 +G01 X-1.8611 Y0.0955 +G01 X-2.4511 Y0.0955 +G01 X-2.4522 Y0.0955 +G01 X-2.4689 Y0.0955 +G01 X-2.4750 Y0.0955 +G01 X-2.5034 Y0.1048 +G01 X-2.5276 Y0.1223 +G01 X-2.5452 Y0.1466 +G01 X-2.5545 Y0.1750 +G01 X-2.5545 Y0.1811 +G01 X-2.5545 Y0.2255 +G01 X-2.6073 Y0.2255 +G01 X-2.6203 Y0.2125 +G01 X-2.6597 Y0.2125 +G01 X-2.6875 Y0.2403 +G00 Z0.1000 +G00 X-2.3264 Y1.0575 +G01 Z-0.0070 F10 +G01 X-2.1935 Y1.0575 F20 +G01 X-2.1761 Y1.0503 +G01 X-2.1627 Y1.0369 +G01 X-2.1555 Y1.0194 +G01 X-2.1555 Y1.0005 +G01 X-2.1627 Y0.9831 +G01 X-2.1761 Y0.9697 +G01 X-2.1935 Y0.9625 +G01 X-2.3264 Y0.9625 +G01 X-2.3439 Y0.9697 +G01 X-2.3497 Y0.9755 +G01 X-2.8931 Y0.9755 +G01 X-2.8939 Y0.9755 +G01 X-2.9069 Y0.9755 +G01 X-2.9168 Y0.9755 +G01 X-2.9479 Y0.9884 +G01 X-2.9716 Y1.0121 +G01 X-2.9845 Y1.0432 +G01 X-2.9845 Y1.0531 +G01 X-2.9845 Y1.0973 +G01 X-2.9975 Y1.1103 +G01 X-2.9975 Y1.1497 +G01 X-2.9697 Y1.1775 +G01 X-2.9303 Y1.1775 +G01 X-2.9025 Y1.1497 +G01 X-2.9025 Y1.1103 +G01 X-2.9155 Y1.0973 +G01 X-2.9155 Y1.0600 +G01 X-2.9152 Y1.0570 +G01 X-2.9129 Y1.0514 +G01 X-2.9086 Y1.0471 +G01 X-2.9030 Y1.0448 +G01 X-2.9000 Y1.0445 +G01 X-2.8939 Y1.0445 +G01 X-2.8931 Y1.0445 +G01 X-2.3497 Y1.0445 +G01 X-2.3439 Y1.0503 +G01 X-2.3264 Y1.0575 +G00 Z0.1000 +G00 X-1.5303 Y1.3554 +G01 Z-0.0070 F10 +G01 X-1.5106 Y1.3635 F20 +G01 X-1.4894 Y1.3635 +G01 X-1.4697 Y1.3554 +G01 X-1.4546 Y1.3403 +G01 X-1.4465 Y1.3206 +G01 X-1.4465 Y1.2994 +G01 X-1.4546 Y1.2797 +G01 X-1.4697 Y1.2646 +G01 X-1.4894 Y1.2565 +G01 X-1.5106 Y1.2565 +G01 X-1.5303 Y1.2646 +G01 X-1.5412 Y1.2755 +G01 X-1.5887 Y1.2755 +G01 X-1.5887 Y1.2487 +G01 X-1.6187 Y1.2187 +G01 X-1.6613 Y1.2187 +G01 X-1.6913 Y1.2487 +G01 X-1.6913 Y1.2755 +G01 X-1.7355 Y1.2755 +G01 X-1.7355 Y1.2327 +G01 X-1.7225 Y1.2197 +G01 X-1.7225 Y1.1803 +G01 X-1.7503 Y1.1525 +G01 X-1.7897 Y1.1525 +G01 X-1.8027 Y1.1655 +G01 X-1.8863 Y1.1655 +G01 X-1.8935 Y1.1625 +G01 X-2.0264 Y1.1625 +G01 X-2.0439 Y1.1697 +G01 X-2.0573 Y1.1831 +G01 X-2.0645 Y1.2005 +G01 X-2.0645 Y1.2194 +G01 X-2.0573 Y1.2369 +G01 X-2.0439 Y1.2503 +G01 X-2.0264 Y1.2575 +G01 X-1.8935 Y1.2575 +G01 X-1.8761 Y1.2503 +G01 X-1.8627 Y1.2369 +G01 X-1.8617 Y1.2345 +G01 X-1.8045 Y1.2345 +G01 X-1.8045 Y1.2755 +G01 X-1.8169 Y1.2755 +G01 X-1.8295 Y1.2808 +G01 X-1.8392 Y1.2905 +G01 X-1.8445 Y1.3031 +G01 X-1.8445 Y1.5331 +G01 X-1.8445 Y1.5400 +G01 X-1.8446 Y1.5411 +G01 X-1.8454 Y1.5431 +G01 X-1.8469 Y1.5446 +G01 X-1.8489 Y1.5454 +G01 X-1.8500 Y1.5455 +G01 X-1.8569 Y1.5455 +G01 X-2.3331 Y1.5455 +G01 X-2.3350 Y1.5455 +G01 X-2.3469 Y1.5455 +G01 X-2.3568 Y1.5455 +G01 X-2.3879 Y1.5584 +G01 X-2.4116 Y1.5821 +G01 X-2.4245 Y1.6132 +G01 X-2.4245 Y1.6231 +G01 X-2.4245 Y1.6323 +G01 X-2.4375 Y1.6453 +G01 X-2.4375 Y1.6847 +G01 X-2.4297 Y1.6925 +G01 X-2.4597 Y1.6925 +G01 X-2.4655 Y1.6983 +G01 X-2.4655 Y1.6031 +G01 X-2.4708 Y1.5905 +G01 X-2.4805 Y1.5808 +G01 X-2.4855 Y1.5787 +G01 X-2.4855 Y1.4469 +G01 X-2.4855 Y1.4331 +G01 X-2.4855 Y1.2600 +G01 X-2.4852 Y1.2570 +G01 X-2.4829 Y1.2514 +G01 X-2.4786 Y1.2471 +G01 X-2.4730 Y1.2448 +G01 X-2.4700 Y1.2445 +G01 X-2.4652 Y1.2445 +G01 X-2.4631 Y1.2445 +G01 X-2.3497 Y1.2445 +G01 X-2.3439 Y1.2503 +G01 X-2.3264 Y1.2575 +G01 X-2.1935 Y1.2575 +G01 X-2.1761 Y1.2503 +G01 X-2.1627 Y1.2369 +G01 X-2.1555 Y1.2194 +G01 X-2.1555 Y1.2005 +G01 X-2.1627 Y1.1831 +G01 X-2.1761 Y1.1697 +G01 X-2.1935 Y1.1625 +G01 X-2.2255 Y1.1625 +G01 X-2.2255 Y1.1575 +G01 X-2.1935 Y1.1575 +G01 X-2.1761 Y1.1503 +G01 X-2.1627 Y1.1369 +G01 X-2.1555 Y1.1194 +G01 X-2.1555 Y1.1005 +G01 X-2.1627 Y1.0831 +G01 X-2.1761 Y1.0697 +G01 X-2.1935 Y1.0625 +G01 X-2.3264 Y1.0625 +G01 X-2.3439 Y1.0697 +G01 X-2.3573 Y1.0831 +G01 X-2.3645 Y1.1005 +G01 X-2.3645 Y1.1194 +G01 X-2.3573 Y1.1369 +G01 X-2.3439 Y1.1503 +G01 X-2.3264 Y1.1575 +G01 X-2.2945 Y1.1575 +G01 X-2.2945 Y1.1625 +G01 X-2.3264 Y1.1625 +G01 X-2.3439 Y1.1697 +G01 X-2.3497 Y1.1755 +G01 X-2.4631 Y1.1755 +G01 X-2.4652 Y1.1755 +G01 X-2.4769 Y1.1755 +G01 X-2.4868 Y1.1755 +G01 X-2.5179 Y1.1884 +G01 X-2.5416 Y1.2121 +G01 X-2.5545 Y1.2432 +G01 X-2.5545 Y1.2531 +G01 X-2.5545 Y1.4055 +G01 X-2.8610 Y1.4055 +G01 X-2.8705 Y1.3959 +G01 X-2.8897 Y1.3880 +G01 X-2.9103 Y1.3880 +G01 X-2.9295 Y1.3959 +G01 X-2.9441 Y1.4105 +G01 X-2.9520 Y1.4297 +G01 X-2.9520 Y1.4503 +G01 X-2.9441 Y1.4695 +G01 X-2.9295 Y1.4841 +G01 X-2.9103 Y1.4920 +G01 X-2.8897 Y1.4920 +G01 X-2.8705 Y1.4841 +G01 X-2.8610 Y1.4745 +G01 X-2.5545 Y1.4745 +G01 X-2.5545 Y1.5755 +G01 X-2.6273 Y1.5755 +G01 X-2.6403 Y1.5625 +G01 X-2.6797 Y1.5625 +G01 X-2.7075 Y1.5903 +G01 X-2.7075 Y1.6297 +G01 X-2.6797 Y1.6575 +G01 X-2.6403 Y1.6575 +G01 X-2.6273 Y1.6445 +G01 X-2.5345 Y1.6445 +G01 X-2.5345 Y1.7031 +G01 X-2.5345 Y1.7042 +G01 X-2.5345 Y1.7169 +G01 X-2.5345 Y1.7228 +G01 X-2.5247 Y1.7465 +G01 X-2.5065 Y1.7647 +G01 X-2.4828 Y1.7745 +G01 X-2.4769 Y1.7745 +G01 X-2.4727 Y1.7745 +G01 X-2.4597 Y1.7875 +G01 X-2.4203 Y1.7875 +G01 X-2.3925 Y1.7597 +G01 X-2.3925 Y1.7203 +G01 X-2.4003 Y1.7125 +G01 X-2.3797 Y1.7125 +G01 X-2.3875 Y1.7203 +G01 X-2.3875 Y1.7597 +G01 X-2.3745 Y1.7727 +G01 X-2.3745 Y1.7800 +G01 X-2.3748 Y1.7830 +G01 X-2.3771 Y1.7886 +G01 X-2.3814 Y1.7929 +G01 X-2.3870 Y1.7952 +G01 X-2.3900 Y1.7955 +G01 X-2.5300 Y1.7955 +G01 X-2.5330 Y1.7952 +G01 X-2.5386 Y1.7929 +G01 X-2.5429 Y1.7886 +G01 X-2.5452 Y1.7830 +G01 X-2.5455 Y1.7800 +G01 X-2.5455 Y1.7769 +G01 X-2.5455 Y1.7736 +G01 X-2.5455 Y1.7631 +G01 X-2.5455 Y1.7532 +G01 X-2.5584 Y1.7221 +G01 X-2.5821 Y1.6984 +G01 X-2.6132 Y1.6855 +G01 X-2.6231 Y1.6855 +G01 X-2.6373 Y1.6855 +G01 X-2.6503 Y1.6725 +G01 X-2.6897 Y1.6725 +G01 X-2.7027 Y1.6855 +G01 X-2.7300 Y1.6855 +G01 X-2.7330 Y1.6852 +G01 X-2.7386 Y1.6829 +G01 X-2.7429 Y1.6786 +G01 X-2.7452 Y1.6730 +G01 X-2.7455 Y1.6700 +G01 X-2.7455 Y1.6647 +G01 X-2.7455 Y1.6631 +G01 X-2.7455 Y1.5931 +G01 X-2.7455 Y1.5852 +G01 X-2.7568 Y1.5578 +G01 X-2.7778 Y1.5368 +G01 X-2.8052 Y1.5255 +G01 X-2.8131 Y1.5255 +G01 X-2.8198 Y1.5255 +G01 X-2.8200 Y1.5255 +G01 X-2.8269 Y1.5255 +G01 X-2.9555 Y1.5255 +G01 X-2.9555 Y1.5231 +G01 X-2.9555 Y1.3775 +G01 X-2.9303 Y1.3775 +G01 X-2.9025 Y1.3497 +G01 X-2.9025 Y1.3103 +G01 X-2.9303 Y1.2825 +G01 X-2.9697 Y1.2825 +G01 X-2.9975 Y1.3103 +G01 X-2.9975 Y1.3121 +G01 X-3.0132 Y1.3278 +G01 X-3.0245 Y1.3552 +G01 X-3.0245 Y1.3631 +G01 X-3.0245 Y1.3662 +G01 X-3.0245 Y1.3700 +G01 X-3.0245 Y1.5231 +G01 X-3.0245 Y1.5300 +G01 X-3.0245 Y1.5301 +G01 X-3.0245 Y1.5369 +G01 X-3.0245 Y1.5428 +G01 X-3.0147 Y1.5665 +G01 X-2.9965 Y1.5847 +G01 X-2.9728 Y1.5945 +G01 X-2.9669 Y1.5945 +G01 X-2.8269 Y1.5945 +G01 X-2.8200 Y1.5945 +G01 X-2.8189 Y1.5946 +G01 X-2.8169 Y1.5954 +G01 X-2.8154 Y1.5969 +G01 X-2.8146 Y1.5989 +G01 X-2.8145 Y1.6000 +G01 X-2.8145 Y1.6631 +G01 X-2.8145 Y1.6647 +G01 X-2.8145 Y1.6769 +G01 X-2.8145 Y1.6868 +G01 X-2.8016 Y1.7179 +G01 X-2.7779 Y1.7416 +G01 X-2.7468 Y1.7545 +G01 X-2.7369 Y1.7545 +G01 X-2.7027 Y1.7545 +G01 X-2.6897 Y1.7675 +G01 X-2.6503 Y1.7675 +G01 X-2.6373 Y1.7545 +G01 X-2.6300 Y1.7545 +G01 X-2.6270 Y1.7548 +G01 X-2.6214 Y1.7571 +G01 X-2.6171 Y1.7614 +G01 X-2.6148 Y1.7670 +G01 X-2.6145 Y1.7700 +G01 X-2.6145 Y1.7736 +G01 X-2.6145 Y1.7769 +G01 X-2.6145 Y1.7869 +G01 X-2.6145 Y1.7968 +G01 X-2.6016 Y1.8279 +G01 X-2.5779 Y1.8516 +G01 X-2.5468 Y1.8645 +G01 X-2.5369 Y1.8645 +G01 X-2.3831 Y1.8645 +G01 X-2.3732 Y1.8645 +G01 X-2.3421 Y1.8516 +G01 X-2.3184 Y1.8279 +G01 X-2.3055 Y1.7968 +G01 X-2.3055 Y1.7869 +G01 X-2.3055 Y1.7745 +G01 X-2.2481 Y1.7745 +G01 X-2.2313 Y1.7913 +G01 X-2.1887 Y1.7913 +G01 X-2.1587 Y1.7613 +G01 X-2.1587 Y1.7187 +G01 X-2.1887 Y1.6887 +G01 X-2.2313 Y1.6887 +G01 X-2.2481 Y1.7055 +G01 X-2.3073 Y1.7055 +G01 X-2.3203 Y1.6925 +G01 X-2.3503 Y1.6925 +G01 X-2.3425 Y1.6847 +G01 X-2.3425 Y1.6453 +G01 X-2.3555 Y1.6323 +G01 X-2.3555 Y1.6300 +G01 X-2.3552 Y1.6270 +G01 X-2.3529 Y1.6214 +G01 X-2.3486 Y1.6171 +G01 X-2.3430 Y1.6148 +G01 X-2.3400 Y1.6145 +G01 X-2.3350 Y1.6145 +G01 X-2.3331 Y1.6145 +G01 X-1.8569 Y1.6145 +G01 X-1.8431 Y1.6145 +G01 X-1.8352 Y1.6145 +G01 X-1.8078 Y1.6031 +G01 X-1.7868 Y1.5822 +G01 X-1.7755 Y1.5548 +G01 X-1.7755 Y1.5469 +G01 X-1.7755 Y1.5401 +G01 X-1.7755 Y1.5331 +G01 X-1.7755 Y1.3445 +G01 X-1.7631 Y1.3445 +G01 X-1.6469 Y1.3445 +G01 X-1.6331 Y1.3445 +G01 X-1.5412 Y1.3445 +G01 X-1.5303 Y1.3554 +G00 Z0.1000 +G00 X-1.5535 Y1.6994 +G01 Z-0.0070 F10 +G01 X-1.5535 Y1.7206 F20 +G01 X-1.5454 Y1.7403 +G01 X-1.5345 Y1.7512 +G01 X-1.5345 Y1.8773 +G01 X-1.5475 Y1.8903 +G01 X-1.5475 Y1.9297 +G01 X-1.5197 Y1.9575 +G01 X-1.4803 Y1.9575 +G01 X-1.4525 Y1.9297 +G01 X-1.4525 Y1.8903 +G01 X-1.4655 Y1.8773 +G01 X-1.4655 Y1.7512 +G01 X-1.4546 Y1.7403 +G01 X-1.4465 Y1.7206 +G01 X-1.4465 Y1.7049 +G01 X-1.4451 Y1.7045 +G01 X-0.7769 Y1.7045 +G01 X-0.7700 Y1.7045 +G01 X-0.7532 Y1.7045 +G01 X-0.7221 Y1.6916 +G01 X-0.6984 Y1.6679 +G01 X-0.6855 Y1.6368 +G01 X-0.6855 Y1.6269 +G01 X-0.6855 Y1.5427 +G01 X-0.6725 Y1.5297 +G01 X-0.6725 Y1.4903 +G01 X-0.7003 Y1.4625 +G01 X-0.7397 Y1.4625 +G01 X-0.7675 Y1.4903 +G01 X-0.7675 Y1.5297 +G01 X-0.7545 Y1.5427 +G01 X-0.7545 Y1.6200 +G01 X-0.7548 Y1.6230 +G01 X-0.7571 Y1.6286 +G01 X-0.7614 Y1.6329 +G01 X-0.7670 Y1.6352 +G01 X-0.7700 Y1.6355 +G01 X-0.7769 Y1.6355 +G01 X-1.4481 Y1.6355 +G01 X-1.4620 Y1.6340 +G01 X-1.4924 Y1.6428 +G01 X-1.5096 Y1.6565 +G01 X-1.5106 Y1.6565 +G01 X-1.5303 Y1.6646 +G01 X-1.5454 Y1.6797 +G01 X-1.5535 Y1.6994 +G00 Z0.1000 +G00 X-1.4735 Y0.3294 +G01 Z-0.0070 F10 +G01 X-1.4735 Y0.3506 F20 +G01 X-1.4654 Y0.3703 +G01 X-1.4503 Y0.3854 +G01 X-1.4306 Y0.3935 +G01 X-1.4094 Y0.3935 +G01 X-1.3897 Y0.3854 +G01 X-1.3788 Y0.3745 +G01 X-1.3031 Y0.3745 +G01 X-0.8127 Y0.3745 +G01 X-0.7997 Y0.3875 +G01 X-0.7603 Y0.3875 +G01 X-0.7325 Y0.3597 +G01 X-0.7325 Y0.3203 +G01 X-0.7603 Y0.2925 +G01 X-0.7997 Y0.2925 +G01 X-0.8127 Y0.3055 +G01 X-1.2755 Y0.3055 +G01 X-1.2755 Y0.2227 +G01 X-1.2725 Y0.2197 +G01 X-1.2725 Y0.1803 +G01 X-1.3003 Y0.1525 +G01 X-1.3397 Y0.1525 +G01 X-1.3675 Y0.1803 +G01 X-1.3675 Y0.2197 +G01 X-1.3445 Y0.2427 +G01 X-1.3445 Y0.3055 +G01 X-1.3788 Y0.3055 +G01 X-1.3897 Y0.2946 +G01 X-1.4094 Y0.2865 +G01 X-1.4306 Y0.2865 +G01 X-1.4503 Y0.2946 +G01 X-1.4654 Y0.3097 +G01 X-1.4735 Y0.3294 +G00 Z0.1000 +G00 X-2.0635 Y0.2494 +G01 Z-0.0070 F10 +G01 X-2.0635 Y0.2706 F20 +G01 X-2.0554 Y0.2903 +G01 X-2.0445 Y0.3012 +G01 X-2.0445 Y0.3068 +G01 X-2.0316 Y0.3379 +G01 X-2.0079 Y0.3616 +G01 X-1.9768 Y0.3745 +G01 X-1.9669 Y0.3745 +G01 X-1.8612 Y0.3745 +G01 X-1.8545 Y0.3812 +G01 X-1.8545 Y0.4588 +G01 X-1.8612 Y0.4655 +G01 X-1.8668 Y0.4655 +G01 X-1.8979 Y0.4784 +G01 X-1.9216 Y0.5021 +G01 X-1.9336 Y0.5310 +G01 X-1.9513 Y0.5487 +G01 X-1.9513 Y0.5913 +G01 X-1.9213 Y0.6213 +G01 X-1.8787 Y0.6213 +G01 X-1.8487 Y0.5913 +G01 X-1.8487 Y0.5487 +G01 X-1.8595 Y0.5380 +G01 X-1.8586 Y0.5371 +G01 X-1.8503 Y0.5454 +G01 X-1.8306 Y0.5535 +G01 X-1.8094 Y0.5535 +G01 X-1.7897 Y0.5454 +G01 X-1.7746 Y0.5303 +G01 X-1.7665 Y0.5106 +G01 X-1.7665 Y0.4894 +G01 X-1.7746 Y0.4697 +G01 X-1.7855 Y0.4588 +G01 X-1.7855 Y0.3812 +G01 X-1.7746 Y0.3703 +G01 X-1.7665 Y0.3506 +G01 X-1.7665 Y0.3294 +G01 X-1.7746 Y0.3097 +G01 X-1.7897 Y0.2946 +G01 X-1.8094 Y0.2865 +G01 X-1.8306 Y0.2865 +G01 X-1.8503 Y0.2946 +G01 X-1.8612 Y0.3055 +G01 X-1.9600 Y0.3055 +G01 X-1.9630 Y0.3052 +G01 X-1.9686 Y0.3029 +G01 X-1.9729 Y0.2986 +G01 X-1.9646 Y0.2903 +G01 X-1.9565 Y0.2706 +G01 X-1.9565 Y0.2494 +G01 X-1.9646 Y0.2297 +G01 X-1.9797 Y0.2146 +G01 X-1.9994 Y0.2065 +G01 X-2.0206 Y0.2065 +G01 X-2.0403 Y0.2146 +G01 X-2.0554 Y0.2297 +G01 X-2.0635 Y0.2494 +G00 Z0.1000 +G00 X-3.2075 Y1.5903 +G01 Z-0.0070 F10 +G01 X-3.2075 Y1.6297 F20 +G01 X-3.1945 Y1.6427 +G01 X-3.1945 Y1.6969 +G01 X-3.1945 Y1.7068 +G01 X-3.1816 Y1.7379 +G01 X-3.1579 Y1.7616 +G01 X-3.1268 Y1.7745 +G01 X-3.1169 Y1.7745 +G01 X-2.9969 Y1.7745 +G01 X-2.9900 Y1.7745 +G01 X-2.9889 Y1.7746 +G01 X-2.9869 Y1.7754 +G01 X-2.9854 Y1.7769 +G01 X-2.9846 Y1.7789 +G01 X-2.9845 Y1.7800 +G01 X-2.9845 Y1.8531 +G01 X-2.9845 Y1.8549 +G01 X-2.9845 Y1.8669 +G01 X-2.9845 Y1.8768 +G01 X-2.9716 Y1.9079 +G01 X-2.9479 Y1.9316 +G01 X-2.9168 Y1.9445 +G01 X-2.9069 Y1.9445 +G01 X-2.0969 Y1.9445 +G01 X-2.0831 Y1.9445 +G01 X-2.0327 Y1.9445 +G01 X-2.0197 Y1.9575 +G01 X-1.9803 Y1.9575 +G01 X-1.9673 Y1.9445 +G01 X-1.7700 Y1.9445 +G01 X-1.7670 Y1.9448 +G01 X-1.7614 Y1.9471 +G01 X-1.7571 Y1.9514 +G01 X-1.7548 Y1.9570 +G01 X-1.7545 Y1.9600 +G01 X-1.7545 Y1.9654 +G01 X-1.7545 Y1.9669 +G01 X-1.7545 Y2.0669 +G01 X-1.7545 Y2.0768 +G01 X-1.7416 Y2.1079 +G01 X-1.7179 Y2.1316 +G01 X-1.6868 Y2.1445 +G01 X-1.6700 Y2.1445 +G01 X-1.6631 Y2.1445 +G01 X-1.2531 Y2.1445 +G01 X-1.2432 Y2.1445 +G01 X-1.2121 Y2.1316 +G01 X-1.1884 Y2.1079 +G01 X-1.1755 Y2.0768 +G01 X-1.1755 Y2.0600 +G01 X-1.1755 Y2.0531 +G01 X-1.1755 Y1.9169 +G01 X-1.1755 Y1.9100 +G01 X-1.1752 Y1.9070 +G01 X-1.1729 Y1.9014 +G01 X-1.1686 Y1.8971 +G01 X-1.1630 Y1.8948 +G01 X-1.1600 Y1.8945 +G01 X-1.1559 Y1.8945 +G01 X-1.1531 Y1.8945 +G01 X-0.7990 Y1.8945 +G01 X-0.7895 Y1.9041 +G01 X-0.7703 Y1.9120 +G01 X-0.7497 Y1.9120 +G01 X-0.7305 Y1.9041 +G01 X-0.7210 Y1.8945 +G01 X-0.2647 Y1.8945 +G01 X-0.2548 Y1.8945 +G01 X-0.2228 Y1.8841 +G01 X-0.1956 Y1.8644 +G01 X-0.1804 Y1.8434 +G01 X-0.1208 Y1.8434 +G01 X-0.1006 Y1.8350 +G01 X-0.0851 Y1.8196 +G01 X-0.0768 Y1.7994 +G01 X-0.0768 Y1.7775 +G01 X-0.0851 Y1.7573 +G01 X-0.1006 Y1.7418 +G01 X-0.1208 Y1.7334 +G01 X-0.2792 Y1.7334 +G01 X-0.2994 Y1.7418 +G01 X-0.3149 Y1.7573 +G01 X-0.3232 Y1.7775 +G01 X-0.3232 Y1.7994 +G01 X-0.3149 Y1.8196 +G01 X-0.3089 Y1.8255 +G01 X-0.7210 Y1.8255 +G01 X-0.7305 Y1.8159 +G01 X-0.7497 Y1.8080 +G01 X-0.7703 Y1.8080 +G01 X-0.7895 Y1.8159 +G01 X-0.7990 Y1.8255 +G01 X-1.1531 Y1.8255 +G01 X-1.1559 Y1.8255 +G01 X-1.1669 Y1.8255 +G01 X-1.1768 Y1.8255 +G01 X-1.2079 Y1.8384 +G01 X-1.2316 Y1.8621 +G01 X-1.2445 Y1.8932 +G01 X-1.2445 Y1.9100 +G01 X-1.2445 Y1.9169 +G01 X-1.2445 Y2.0531 +G01 X-1.2445 Y2.0600 +G01 X-1.2448 Y2.0630 +G01 X-1.2471 Y2.0686 +G01 X-1.2514 Y2.0729 +G01 X-1.2570 Y2.0752 +G01 X-1.2600 Y2.0755 +G01 X-1.6631 Y2.0755 +G01 X-1.6700 Y2.0755 +G01 X-1.6730 Y2.0752 +G01 X-1.6786 Y2.0729 +G01 X-1.6829 Y2.0686 +G01 X-1.6852 Y2.0630 +G01 X-1.6855 Y2.0600 +G01 X-1.6855 Y1.9669 +G01 X-1.6855 Y1.9654 +G01 X-1.6855 Y1.9531 +G01 X-1.6855 Y1.9432 +G01 X-1.6984 Y1.9121 +G01 X-1.7221 Y1.8884 +G01 X-1.7532 Y1.8755 +G01 X-1.7631 Y1.8755 +G01 X-1.9673 Y1.8755 +G01 X-1.9803 Y1.8625 +G01 X-2.0197 Y1.8625 +G01 X-2.0327 Y1.8755 +G01 X-2.0555 Y1.8755 +G01 X-2.0555 Y1.7500 +G01 X-2.0552 Y1.7470 +G01 X-2.0529 Y1.7414 +G01 X-2.0486 Y1.7371 +G01 X-2.0430 Y1.7348 +G01 X-2.0400 Y1.7345 +G01 X-2.0343 Y1.7345 +G01 X-2.0331 Y1.7345 +G01 X-1.8027 Y1.7345 +G01 X-1.7897 Y1.7475 +G01 X-1.7503 Y1.7475 +G01 X-1.7373 Y1.7345 +G01 X-1.7331 Y1.7345 +G01 X-1.7272 Y1.7345 +G01 X-1.7035 Y1.7247 +G01 X-1.6853 Y1.7065 +G01 X-1.6755 Y1.6828 +G01 X-1.6755 Y1.6769 +G01 X-1.6755 Y1.5100 +G01 X-1.6752 Y1.5070 +G01 X-1.6729 Y1.5014 +G01 X-1.6686 Y1.4971 +G01 X-1.6630 Y1.4948 +G01 X-1.6600 Y1.4945 +G01 X-1.6573 Y1.4945 +G01 X-1.6531 Y1.4945 +G01 X-1.4669 Y1.4945 +G01 X-1.4600 Y1.4945 +G01 X-1.4432 Y1.4945 +G01 X-1.4121 Y1.4816 +G01 X-1.3884 Y1.4579 +G01 X-1.3819 Y1.4424 +G01 X-1.3768 Y1.4445 +G01 X-1.3669 Y1.4445 +G01 X-1.3595 Y1.4445 +G01 X-1.3531 Y1.4445 +G01 X-1.3397 Y1.4445 +G01 X-1.3339 Y1.4503 +G01 X-1.3164 Y1.4575 +G01 X-1.1835 Y1.4575 +G01 X-1.1661 Y1.4503 +G01 X-1.1527 Y1.4369 +G01 X-1.1455 Y1.4194 +G01 X-1.1455 Y1.4005 +G01 X-1.1527 Y1.3831 +G01 X-1.1661 Y1.3697 +G01 X-1.1835 Y1.3625 +G01 X-1.3164 Y1.3625 +G01 X-1.3339 Y1.3697 +G01 X-1.3397 Y1.3755 +G01 X-1.3531 Y1.3755 +G01 X-1.3595 Y1.3755 +G01 X-1.3600 Y1.3755 +G01 X-1.3630 Y1.3752 +G01 X-1.3686 Y1.3729 +G01 X-1.3729 Y1.3686 +G01 X-1.3752 Y1.3630 +G01 X-1.3755 Y1.3600 +G01 X-1.3755 Y1.2531 +G01 X-1.3755 Y1.2438 +G01 X-1.3755 Y1.2339 +G01 X-1.3825 Y1.2170 +G01 X-1.3825 Y1.1903 +G01 X-1.4103 Y1.1625 +G01 X-1.4497 Y1.1625 +G01 X-1.4775 Y1.1903 +G01 X-1.4775 Y1.2297 +G01 X-1.4497 Y1.2575 +G01 X-1.4445 Y1.2575 +G01 X-1.4445 Y1.4100 +G01 X-1.4448 Y1.4130 +G01 X-1.4471 Y1.4186 +G01 X-1.4514 Y1.4229 +G01 X-1.4570 Y1.4252 +G01 X-1.4600 Y1.4255 +G01 X-1.4669 Y1.4255 +G01 X-1.6531 Y1.4255 +G01 X-1.6573 Y1.4255 +G01 X-1.6669 Y1.4255 +G01 X-1.6768 Y1.4255 +G01 X-1.7079 Y1.4384 +G01 X-1.7316 Y1.4621 +G01 X-1.7445 Y1.4932 +G01 X-1.7445 Y1.5031 +G01 X-1.7445 Y1.6583 +G01 X-1.7503 Y1.6525 +G01 X-1.7897 Y1.6525 +G01 X-1.8027 Y1.6655 +G01 X-2.0331 Y1.6655 +G01 X-2.0344 Y1.6655 +G01 X-2.0469 Y1.6655 +G01 X-2.0568 Y1.6655 +G01 X-2.0879 Y1.6784 +G01 X-2.1116 Y1.7021 +G01 X-2.1245 Y1.7332 +G01 X-2.1245 Y1.7431 +G01 X-2.1245 Y1.8755 +G01 X-2.9000 Y1.8755 +G01 X-2.9030 Y1.8752 +G01 X-2.9086 Y1.8729 +G01 X-2.9129 Y1.8686 +G01 X-2.9152 Y1.8630 +G01 X-2.9155 Y1.8600 +G01 X-2.9155 Y1.8548 +G01 X-2.9155 Y1.8531 +G01 X-2.9155 Y1.7731 +G01 X-2.9155 Y1.7652 +G01 X-2.9268 Y1.7378 +G01 X-2.9478 Y1.7168 +G01 X-2.9752 Y1.7055 +G01 X-2.9831 Y1.7055 +G01 X-2.9897 Y1.7055 +G01 X-2.9900 Y1.7055 +G01 X-2.9969 Y1.7055 +G01 X-3.1100 Y1.7055 +G01 X-3.1130 Y1.7052 +G01 X-3.1186 Y1.7029 +G01 X-3.1229 Y1.6986 +G01 X-3.1252 Y1.6930 +G01 X-3.1255 Y1.6900 +G01 X-3.1255 Y1.6427 +G01 X-3.1125 Y1.6297 +G01 X-3.1125 Y1.5903 +G01 X-3.1255 Y1.5773 +G01 X-3.1255 Y0.9600 +G01 X-3.1252 Y0.9570 +G01 X-3.1229 Y0.9514 +G01 X-3.1186 Y0.9471 +G01 X-3.1130 Y0.9448 +G01 X-3.1100 Y0.9445 +G01 X-3.1047 Y0.9445 +G01 X-3.1031 Y0.9445 +G01 X-2.5481 Y0.9445 +G01 X-2.5313 Y0.9613 +G01 X-2.4887 Y0.9613 +G01 X-2.4719 Y0.9445 +G01 X-2.1669 Y0.9445 +G01 X-2.1600 Y0.9445 +G01 X-2.1570 Y0.9448 +G01 X-2.1514 Y0.9471 +G01 X-2.1471 Y0.9514 +G01 X-2.1448 Y0.9570 +G01 X-2.1445 Y0.9600 +G01 X-2.1445 Y1.0669 +G01 X-2.1445 Y1.2755 +G01 X-2.1703 Y1.2755 +G01 X-2.1761 Y1.2697 +G01 X-2.1935 Y1.2625 +G01 X-2.3264 Y1.2625 +G01 X-2.3439 Y1.2697 +G01 X-2.3573 Y1.2831 +G01 X-2.3645 Y1.3005 +G01 X-2.3645 Y1.3194 +G01 X-2.3573 Y1.3369 +G01 X-2.3439 Y1.3503 +G01 X-2.3264 Y1.3575 +G01 X-2.1935 Y1.3575 +G01 X-2.1761 Y1.3503 +G01 X-2.1703 Y1.3445 +G01 X-2.1231 Y1.3445 +G01 X-2.1192 Y1.3445 +G01 X-2.0991 Y1.3362 +G01 X-2.0838 Y1.3209 +G01 X-2.0755 Y1.3008 +G01 X-2.0755 Y1.2969 +G01 X-2.0755 Y1.2831 +G01 X-2.0755 Y1.0669 +G01 X-2.0755 Y1.0543 +G01 X-2.0657 Y1.0445 +G01 X-2.0497 Y1.0445 +G01 X-2.0439 Y1.0503 +G01 X-2.0264 Y1.0575 +G01 X-1.8935 Y1.0575 +G01 X-1.8761 Y1.0503 +G01 X-1.8627 Y1.0369 +G01 X-1.8555 Y1.0194 +G01 X-1.8555 Y1.0005 +G01 X-1.8627 Y0.9831 +G01 X-1.8761 Y0.9697 +G01 X-1.8935 Y0.9625 +G01 X-2.0264 Y0.9625 +G01 X-2.0439 Y0.9697 +G01 X-2.0497 Y0.9755 +G01 X-2.0731 Y0.9755 +G01 X-2.0755 Y0.9755 +G01 X-2.0755 Y0.9531 +G01 X-2.0755 Y0.9432 +G01 X-2.0884 Y0.9121 +G01 X-2.1121 Y0.8884 +G01 X-2.1432 Y0.8755 +G01 X-2.1600 Y0.8755 +G01 X-2.1669 Y0.8755 +G01 X-2.4719 Y0.8755 +G01 X-2.4887 Y0.8587 +G01 X-2.5313 Y0.8587 +G01 X-2.5481 Y0.8755 +G01 X-3.1031 Y0.8755 +G01 X-3.1047 Y0.8755 +G01 X-3.1169 Y0.8755 +G01 X-3.1268 Y0.8755 +G01 X-3.1579 Y0.8884 +G01 X-3.1816 Y0.9121 +G01 X-3.1945 Y0.9432 +G01 X-3.1945 Y0.9531 +G01 X-3.1945 Y1.5773 +G01 X-3.2075 Y1.5903 +G00 Z0.1000 +G00 X-1.3164 Y0.8575 +G01 Z-0.0070 F10 +G01 X-1.1835 Y0.8575 F20 +G01 X-1.1661 Y0.8503 +G01 X-1.1527 Y0.8369 +G01 X-1.1455 Y0.8194 +G01 X-1.1455 Y0.8005 +G01 X-1.1527 Y0.7831 +G01 X-1.1661 Y0.7697 +G01 X-1.1835 Y0.7625 +G01 X-1.3164 Y0.7625 +G01 X-1.3339 Y0.7697 +G01 X-1.3397 Y0.7755 +G01 X-1.5000 Y0.7755 +G01 X-1.5030 Y0.7752 +G01 X-1.5086 Y0.7729 +G01 X-1.5129 Y0.7686 +G01 X-1.5152 Y0.7630 +G01 X-1.5155 Y0.7600 +G01 X-1.5155 Y0.7544 +G01 X-1.5155 Y0.7531 +G01 X-1.5155 Y0.6927 +G01 X-1.5025 Y0.6797 +G01 X-1.5025 Y0.6403 +G01 X-1.5303 Y0.6125 +G01 X-1.5697 Y0.6125 +G01 X-1.5975 Y0.6403 +G01 X-1.5975 Y0.6797 +G01 X-1.5845 Y0.6927 +G01 X-1.5845 Y0.7531 +G01 X-1.5845 Y0.7544 +G01 X-1.5845 Y0.7669 +G01 X-1.5845 Y0.7768 +G01 X-1.5716 Y0.8079 +G01 X-1.5479 Y0.8316 +G01 X-1.5168 Y0.8445 +G01 X-1.5069 Y0.8445 +G01 X-1.3397 Y0.8445 +G01 X-1.3339 Y0.8503 +G01 X-1.3164 Y0.8575 +G00 Z0.1000 +G00 X-1.0164 Y1.2575 +G01 Z-0.0070 F10 +G01 X-0.8835 Y1.2575 F20 +G01 X-0.8661 Y1.2503 +G01 X-0.8603 Y1.2445 +G01 X-0.4469 Y1.2445 +G01 X-0.4400 Y1.2445 +G01 X-0.4367 Y1.2445 +G01 X-0.4331 Y1.2445 +G01 X-0.4252 Y1.2445 +G01 X-0.3978 Y1.2332 +G01 X-0.3768 Y1.2122 +G01 X-0.3655 Y1.1848 +G01 X-0.3655 Y1.1769 +G01 X-0.3655 Y1.1616 +G01 X-0.3652 Y1.1586 +G01 X-0.3629 Y1.1530 +G01 X-0.3586 Y1.1487 +G01 X-0.3530 Y1.1464 +G01 X-0.3500 Y1.1461 +G01 X-0.3443 Y1.1461 +G01 X-0.3431 Y1.1461 +G01 X-0.3115 Y1.1461 +G01 X-0.2994 Y1.1582 +G01 X-0.2792 Y1.1666 +G01 X-0.1208 Y1.1666 +G01 X-0.1006 Y1.1582 +G01 X-0.0851 Y1.1427 +G01 X-0.0768 Y1.1225 +G01 X-0.0768 Y1.1006 +G01 X-0.0851 Y1.0804 +G01 X-0.1006 Y1.0649 +G01 X-0.1208 Y1.0566 +G01 X-0.2792 Y1.0566 +G01 X-0.2994 Y1.0649 +G01 X-0.3115 Y1.0771 +G01 X-0.3431 Y1.0771 +G01 X-0.3444 Y1.0771 +G01 X-0.3569 Y1.0771 +G01 X-0.3668 Y1.0771 +G01 X-0.3979 Y1.0899 +G01 X-0.4216 Y1.1137 +G01 X-0.4345 Y1.1448 +G01 X-0.4345 Y1.1547 +G01 X-0.4345 Y1.1700 +G01 X-0.4346 Y1.1711 +G01 X-0.4354 Y1.1731 +G01 X-0.4369 Y1.1746 +G01 X-0.4389 Y1.1754 +G01 X-0.4400 Y1.1755 +G01 X-0.4469 Y1.1755 +G01 X-0.8603 Y1.1755 +G01 X-0.8661 Y1.1697 +G01 X-0.8835 Y1.1625 +G01 X-1.0164 Y1.1625 +G01 X-1.0339 Y1.1697 +G01 X-1.0473 Y1.1831 +G01 X-1.0545 Y1.2005 +G01 X-1.0545 Y1.2194 +G01 X-1.0473 Y1.2369 +G01 X-1.0339 Y1.2503 +G01 X-1.0164 Y1.2575 +G00 Z0.1000 +G00 X-1.0164 Y1.1575 +G01 Z-0.0070 F10 +G01 X-0.8835 Y1.1575 F20 +G01 X-0.8661 Y1.1503 +G01 X-0.8603 Y1.1445 +G01 X-0.5927 Y1.1445 +G01 X-0.5797 Y1.1575 +G01 X-0.5403 Y1.1575 +G01 X-0.5125 Y1.1297 +G01 X-0.5125 Y1.0903 +G01 X-0.5403 Y1.0625 +G01 X-0.5797 Y1.0625 +G01 X-0.5927 Y1.0755 +G01 X-0.8603 Y1.0755 +G01 X-0.8661 Y1.0697 +G01 X-0.8835 Y1.0625 +G01 X-1.0164 Y1.0625 +G01 X-1.0339 Y1.0697 +G01 X-1.0473 Y1.0831 +G01 X-1.0545 Y1.1005 +G01 X-1.0545 Y1.1194 +G01 X-1.0473 Y1.1369 +G01 X-1.0339 Y1.1503 +G01 X-1.0164 Y1.1575 +G00 Z0.1000 +G00 X-1.0164 Y1.0575 +G01 Z-0.0070 F10 +G01 X-0.8835 Y1.0575 F20 +G01 X-0.8661 Y1.0503 +G01 X-0.8603 Y1.0445 +G01 X-0.4869 Y1.0445 +G01 X-0.4809 Y1.0445 +G01 X-0.4800 Y1.0445 +G01 X-0.4632 Y1.0445 +G01 X-0.4321 Y1.0316 +G01 X-0.4084 Y1.0079 +G01 X-0.3955 Y0.9768 +G01 X-0.3955 Y0.9669 +G01 X-0.3955 Y0.9569 +G01 X-0.3955 Y0.9500 +G01 X-0.3954 Y0.9489 +G01 X-0.3946 Y0.9469 +G01 X-0.3931 Y0.9454 +G01 X-0.3911 Y0.9446 +G01 X-0.3900 Y0.9445 +G01 X-0.3100 Y0.9445 +G01 X-0.2994 Y0.9550 +G01 X-0.2792 Y0.9634 +G01 X-0.1208 Y0.9634 +G01 X-0.1006 Y0.9550 +G01 X-0.0851 Y0.9396 +G01 X-0.0768 Y0.9194 +G01 X-0.0768 Y0.8975 +G01 X-0.0851 Y0.8773 +G01 X-0.1006 Y0.8618 +G01 X-0.1208 Y0.8534 +G01 X-0.2792 Y0.8534 +G01 X-0.2994 Y0.8618 +G01 X-0.3131 Y0.8755 +G01 X-0.3969 Y0.8755 +G01 X-0.4048 Y0.8755 +G01 X-0.4322 Y0.8868 +G01 X-0.4532 Y0.9078 +G01 X-0.4645 Y0.9352 +G01 X-0.4645 Y0.9431 +G01 X-0.4645 Y0.9497 +G01 X-0.4645 Y0.9500 +G01 X-0.4645 Y0.9569 +G01 X-0.4645 Y0.9600 +G01 X-0.4648 Y0.9630 +G01 X-0.4671 Y0.9686 +G01 X-0.4714 Y0.9729 +G01 X-0.4770 Y0.9752 +G01 X-0.4800 Y0.9755 +G01 X-0.4810 Y0.9755 +G01 X-0.4869 Y0.9755 +G01 X-0.8603 Y0.9755 +G01 X-0.8661 Y0.9697 +G01 X-0.8835 Y0.9625 +G01 X-1.0164 Y0.9625 +G01 X-1.0339 Y0.9697 +G01 X-1.0473 Y0.9831 +G01 X-1.0545 Y1.0005 +G01 X-1.0545 Y1.0194 +G01 X-1.0473 Y1.0369 +G01 X-1.0339 Y1.0503 +G01 X-1.0164 Y1.0575 +G00 Z0.1000 +G00 X-1.3164 Y1.2575 +G01 Z-0.0070 F10 +G01 X-1.1835 Y1.2575 F20 +G01 X-1.1661 Y1.2503 +G01 X-1.1527 Y1.2369 +G01 X-1.1455 Y1.2194 +G01 X-1.1455 Y1.2005 +G01 X-1.1527 Y1.1831 +G01 X-1.1661 Y1.1697 +G01 X-1.1835 Y1.1625 +G01 X-1.3164 Y1.1625 +G01 X-1.3339 Y1.1697 +G01 X-1.3473 Y1.1831 +G01 X-1.3545 Y1.2005 +G01 X-1.3545 Y1.2194 +G01 X-1.3473 Y1.2369 +G01 X-1.3339 Y1.2503 +G01 X-1.3164 Y1.2575 +G00 Z0.1000 +G00 X-1.3164 Y1.3575 +G01 Z-0.0070 F10 +G01 X-1.1835 Y1.3575 F20 +G01 X-1.1661 Y1.3503 +G01 X-1.1527 Y1.3369 +G01 X-1.1455 Y1.3194 +G01 X-1.1455 Y1.3005 +G01 X-1.1527 Y1.2831 +G01 X-1.1661 Y1.2697 +G01 X-1.1835 Y1.2625 +G01 X-1.3164 Y1.2625 +G01 X-1.3339 Y1.2697 +G01 X-1.3473 Y1.2831 +G01 X-1.3545 Y1.3005 +G01 X-1.3545 Y1.3194 +G01 X-1.3473 Y1.3369 +G01 X-1.3339 Y1.3503 +G01 X-1.3164 Y1.3575 +G00 Z0.1000 +G00 X-0.7397 Y1.3575 +G01 Z-0.0070 F10 +G01 X-0.7003 Y1.3575 F20 +G01 X-0.6725 Y1.3297 +G01 X-0.6725 Y1.2903 +G01 X-0.7003 Y1.2625 +G01 X-0.7397 Y1.2625 +G01 X-0.7527 Y1.2755 +G01 X-0.8603 Y1.2755 +G01 X-0.8661 Y1.2697 +G01 X-0.8835 Y1.2625 +G01 X-1.0164 Y1.2625 +G01 X-1.0339 Y1.2697 +G01 X-1.0473 Y1.2831 +G01 X-1.0545 Y1.3005 +G01 X-1.0545 Y1.3194 +G01 X-1.0473 Y1.3369 +G01 X-1.0339 Y1.3503 +G01 X-1.0164 Y1.3575 +G01 X-0.8835 Y1.3575 +G01 X-0.8661 Y1.3503 +G01 X-0.8603 Y1.3445 +G01 X-0.7527 Y1.3445 +G01 X-0.7397 Y1.3575 +G00 Z0.1000 +G00 X-0.8275 Y0.5203 +G01 Z-0.0070 F10 +G01 X-0.8275 Y0.5597 F20 +G01 X-0.8145 Y0.5727 +G01 X-0.8145 Y0.8600 +G01 X-0.8148 Y0.8630 +G01 X-0.8171 Y0.8686 +G01 X-0.8214 Y0.8729 +G01 X-0.8270 Y0.8752 +G01 X-0.8300 Y0.8755 +G01 X-0.8348 Y0.8755 +G01 X-0.8369 Y0.8755 +G01 X-0.8603 Y0.8755 +G01 X-0.8661 Y0.8697 +G01 X-0.8835 Y0.8625 +G01 X-1.0164 Y0.8625 +G01 X-1.0339 Y0.8697 +G01 X-1.0473 Y0.8831 +G01 X-1.0545 Y0.9005 +G01 X-1.0545 Y0.9194 +G01 X-1.0473 Y0.9369 +G01 X-1.0339 Y0.9503 +G01 X-1.0164 Y0.9575 +G01 X-0.8835 Y0.9575 +G01 X-0.8661 Y0.9503 +G01 X-0.8603 Y0.9445 +G01 X-0.8369 Y0.9445 +G01 X-0.8348 Y0.9445 +G01 X-0.8231 Y0.9445 +G01 X-0.8132 Y0.9445 +G01 X-0.7821 Y0.9316 +G01 X-0.7584 Y0.9079 +G01 X-0.7455 Y0.8768 +G01 X-0.7455 Y0.8669 +G01 X-0.7455 Y0.5727 +G01 X-0.7325 Y0.5597 +G01 X-0.7325 Y0.5203 +G01 X-0.7603 Y0.4925 +G01 X-0.7997 Y0.4925 +G01 X-0.8275 Y0.5203 +G00 Z0.1000 +G00 X-0.5868 Y1.5655 +G01 Z-0.0070 F10 +G01 X-0.5868 Y1.5655 F20 +G01 X-0.6179 Y1.5784 +G01 X-0.6416 Y1.6021 +G01 X-0.6545 Y1.6332 +G01 X-0.6545 Y1.6431 +G01 X-0.6545 Y1.6500 +G01 X-0.6545 Y1.6569 +G01 X-0.6545 Y1.7200 +G01 X-0.6546 Y1.7211 +G01 X-0.6554 Y1.7231 +G01 X-0.6569 Y1.7246 +G01 X-0.6589 Y1.7254 +G01 X-0.6600 Y1.7255 +G01 X-1.3031 Y1.7255 +G01 X-1.3045 Y1.7255 +G01 X-1.3169 Y1.7255 +G01 X-1.3268 Y1.7255 +G01 X-1.3579 Y1.7384 +G01 X-1.3816 Y1.7621 +G01 X-1.3945 Y1.7932 +G01 X-1.3945 Y1.8031 +G01 X-1.3945 Y1.8210 +G01 X-1.4120 Y1.8385 +G01 X-1.4120 Y1.8815 +G01 X-1.3945 Y1.8990 +G01 X-1.3945 Y1.9531 +G01 X-1.3945 Y1.9588 +G01 X-1.3945 Y1.9600 +G01 X-1.3948 Y1.9630 +G01 X-1.3971 Y1.9686 +G01 X-1.4014 Y1.9729 +G01 X-1.4070 Y1.9752 +G01 X-1.4100 Y1.9755 +G01 X-1.4169 Y1.9755 +G01 X-1.5631 Y1.9755 +G01 X-1.5700 Y1.9755 +G01 X-1.5730 Y1.9752 +G01 X-1.5786 Y1.9729 +G01 X-1.5829 Y1.9686 +G01 X-1.5852 Y1.9630 +G01 X-1.5855 Y1.9600 +G01 X-1.5855 Y1.7969 +G01 X-1.5855 Y1.7731 +G01 X-1.5855 Y1.6369 +G01 X-1.5855 Y1.6300 +G01 X-1.5852 Y1.6270 +G01 X-1.5829 Y1.6214 +G01 X-1.5786 Y1.6171 +G01 X-1.5730 Y1.6148 +G01 X-1.5700 Y1.6145 +G01 X-1.5692 Y1.6145 +G01 X-1.5631 Y1.6145 +G01 X-1.1431 Y1.6145 +G01 X-1.1332 Y1.6145 +G01 X-1.1021 Y1.6016 +G01 X-1.0784 Y1.5779 +G01 X-1.0655 Y1.5468 +G01 X-1.0655 Y1.5300 +G01 X-1.0655 Y1.5231 +G01 X-1.0655 Y0.8600 +G01 X-1.0652 Y0.8570 +G01 X-1.0629 Y0.8514 +G01 X-1.0586 Y0.8471 +G01 X-1.0530 Y0.8448 +G01 X-1.0500 Y0.8445 +G01 X-1.0439 Y0.8445 +G01 X-1.0431 Y0.8445 +G01 X-1.0397 Y0.8445 +G01 X-1.0339 Y0.8503 +G01 X-1.0164 Y0.8575 +G01 X-0.8835 Y0.8575 +G01 X-0.8661 Y0.8503 +G01 X-0.8527 Y0.8369 +G01 X-0.8455 Y0.8194 +G01 X-0.8455 Y0.8005 +G01 X-0.8527 Y0.7831 +G01 X-0.8661 Y0.7697 +G01 X-0.8835 Y0.7625 +G01 X-1.0164 Y0.7625 +G01 X-1.0339 Y0.7697 +G01 X-1.0397 Y0.7755 +G01 X-1.0431 Y0.7755 +G01 X-1.0439 Y0.7755 +G01 X-1.0569 Y0.7755 +G01 X-1.0668 Y0.7755 +G01 X-1.0979 Y0.7884 +G01 X-1.1216 Y0.8121 +G01 X-1.1345 Y0.8432 +G01 X-1.1345 Y0.8531 +G01 X-1.1345 Y1.5231 +G01 X-1.1345 Y1.5300 +G01 X-1.1348 Y1.5330 +G01 X-1.1371 Y1.5386 +G01 X-1.1414 Y1.5429 +G01 X-1.1470 Y1.5452 +G01 X-1.1500 Y1.5455 +G01 X-1.5631 Y1.5455 +G01 X-1.5693 Y1.5455 +G01 X-1.5769 Y1.5455 +G01 X-1.5868 Y1.5455 +G01 X-1.6179 Y1.5584 +G01 X-1.6416 Y1.5821 +G01 X-1.6545 Y1.6132 +G01 X-1.6545 Y1.6231 +G01 X-1.6545 Y1.6271 +G01 X-1.6545 Y1.6300 +G01 X-1.6545 Y1.6369 +G01 X-1.6545 Y1.7555 +G01 X-1.9319 Y1.7555 +G01 X-1.9487 Y1.7387 +G01 X-1.9913 Y1.7387 +G01 X-2.0213 Y1.7687 +G01 X-2.0213 Y1.8113 +G01 X-1.9913 Y1.8413 +G01 X-1.9487 Y1.8413 +G01 X-1.9319 Y1.8245 +G01 X-1.6545 Y1.8245 +G01 X-1.6545 Y1.9669 +G01 X-1.6545 Y1.9768 +G01 X-1.6416 Y2.0079 +G01 X-1.6179 Y2.0316 +G01 X-1.5868 Y2.0445 +G01 X-1.5700 Y2.0445 +G01 X-1.5631 Y2.0445 +G01 X-1.4169 Y2.0445 +G01 X-1.4100 Y2.0445 +G01 X-1.3932 Y2.0445 +G01 X-1.3621 Y2.0316 +G01 X-1.3384 Y2.0079 +G01 X-1.3255 Y1.9768 +G01 X-1.3255 Y1.9669 +G01 X-1.3255 Y1.9588 +G01 X-1.3255 Y1.9531 +G01 X-1.3255 Y1.8990 +G01 X-1.3080 Y1.8815 +G01 X-1.3080 Y1.8385 +G01 X-1.3255 Y1.8210 +G01 X-1.3255 Y1.8100 +G01 X-1.3252 Y1.8070 +G01 X-1.3229 Y1.8014 +G01 X-1.3186 Y1.7971 +G01 X-1.3130 Y1.7948 +G01 X-1.3100 Y1.7945 +G01 X-1.3045 Y1.7945 +G01 X-1.3031 Y1.7945 +G01 X-0.6531 Y1.7945 +G01 X-0.6452 Y1.7945 +G01 X-0.6178 Y1.7832 +G01 X-0.5968 Y1.7622 +G01 X-0.5855 Y1.7348 +G01 X-0.5855 Y1.7269 +G01 X-0.5855 Y1.6569 +G01 X-0.5855 Y1.6500 +G01 X-0.5852 Y1.6470 +G01 X-0.5829 Y1.6414 +G01 X-0.5786 Y1.6371 +G01 X-0.5730 Y1.6348 +G01 X-0.5700 Y1.6345 +G01 X-0.3031 Y1.6345 +G01 X-0.2994 Y1.6382 +G01 X-0.2792 Y1.6466 +G01 X-0.1208 Y1.6466 +G01 X-0.1006 Y1.6382 +G01 X-0.0851 Y1.6227 +G01 X-0.0768 Y1.6025 +G01 X-0.0768 Y1.5806 +G01 X-0.0851 Y1.5604 +G01 X-0.1006 Y1.5449 +G01 X-0.1208 Y1.5366 +G01 X-0.2792 Y1.5366 +G01 X-0.2994 Y1.5449 +G01 X-0.3149 Y1.5604 +G01 X-0.3170 Y1.5655 +G01 X-0.5769 Y1.5655 +G01 X-0.5868 Y1.5655 +G00 Z0.1000 +G00 X-0.5255 Y0.4732 +G01 Z-0.0070 F10 +G01 X-0.5255 Y0.4732 F20 +G01 X-0.5384 Y0.4421 +G01 X-0.5621 Y0.4184 +G01 X-0.5932 Y0.4055 +G01 X-0.6031 Y0.4055 +G01 X-0.6100 Y0.4055 +G01 X-0.6169 Y0.4055 +G01 X-1.3769 Y0.4055 +G01 X-1.3868 Y0.4055 +G01 X-1.4179 Y0.4184 +G01 X-1.4416 Y0.4421 +G01 X-1.4461 Y0.4529 +G01 X-1.4503 Y0.4546 +G01 X-1.4654 Y0.4697 +G01 X-1.4735 Y0.4894 +G01 X-1.4735 Y0.5106 +G01 X-1.4654 Y0.5303 +G01 X-1.4645 Y0.5312 +G01 X-1.4645 Y0.6773 +G01 X-1.4775 Y0.6903 +G01 X-1.4775 Y0.7297 +G01 X-1.4497 Y0.7575 +G01 X-1.4103 Y0.7575 +G01 X-1.3825 Y0.7297 +G01 X-1.3825 Y0.6903 +G01 X-1.3955 Y0.6773 +G01 X-1.3955 Y0.5478 +G01 X-1.3897 Y0.5454 +G01 X-1.3746 Y0.5303 +G01 X-1.3665 Y0.5106 +G01 X-1.3665 Y0.4894 +G01 X-1.3726 Y0.4747 +G01 X-1.3700 Y0.4745 +G01 X-0.6169 Y0.4745 +G01 X-0.6100 Y0.4745 +G01 X-0.6070 Y0.4748 +G01 X-0.6014 Y0.4771 +G01 X-0.5971 Y0.4814 +G01 X-0.5948 Y0.4870 +G01 X-0.5945 Y0.4900 +G01 X-0.5945 Y0.8773 +G01 X-0.6075 Y0.8903 +G01 X-0.6075 Y0.9297 +G01 X-0.5797 Y0.9575 +G01 X-0.5403 Y0.9575 +G01 X-0.5125 Y0.9297 +G01 X-0.5125 Y0.8903 +G01 X-0.5255 Y0.8773 +G01 X-0.5255 Y0.4831 +G01 X-0.5255 Y0.4732 +G00 Z0.1000 +G00 X-2.3645 Y0.7968 +G01 Z-0.0070 F10 +G01 X-2.3645 Y0.7968 F20 +G01 X-2.3516 Y0.8279 +G01 X-2.3279 Y0.8516 +G01 X-2.2968 Y0.8645 +G01 X-2.2800 Y0.8645 +G01 X-2.2731 Y0.8645 +G01 X-1.8669 Y0.8645 +G01 X-1.8600 Y0.8645 +G01 X-1.8570 Y0.8648 +G01 X-1.8514 Y0.8671 +G01 X-1.8471 Y0.8714 +G01 X-1.8448 Y0.8770 +G01 X-1.8445 Y0.8800 +G01 X-1.8445 Y0.8869 +G01 X-1.8445 Y1.0755 +G01 X-1.8703 Y1.0755 +G01 X-1.8761 Y1.0697 +G01 X-1.8935 Y1.0625 +G01 X-2.0264 Y1.0625 +G01 X-2.0439 Y1.0697 +G01 X-2.0573 Y1.0831 +G01 X-2.0645 Y1.1005 +G01 X-2.0645 Y1.1194 +G01 X-2.0573 Y1.1369 +G01 X-2.0439 Y1.1503 +G01 X-2.0264 Y1.1575 +G01 X-1.8935 Y1.1575 +G01 X-1.8761 Y1.1503 +G01 X-1.8703 Y1.1445 +G01 X-1.8031 Y1.1445 +G01 X-1.3397 Y1.1445 +G01 X-1.3339 Y1.1503 +G01 X-1.3164 Y1.1575 +G01 X-1.1835 Y1.1575 +G01 X-1.1661 Y1.1503 +G01 X-1.1527 Y1.1369 +G01 X-1.1455 Y1.1194 +G01 X-1.1455 Y1.1005 +G01 X-1.1527 Y1.0831 +G01 X-1.1661 Y1.0697 +G01 X-1.1835 Y1.0625 +G01 X-1.3164 Y1.0625 +G01 X-1.3339 Y1.0697 +G01 X-1.3397 Y1.0755 +G01 X-1.7755 Y1.0755 +G01 X-1.7755 Y0.8869 +G01 X-1.7755 Y0.8800 +G01 X-1.7755 Y0.8632 +G01 X-1.7884 Y0.8321 +G01 X-1.8121 Y0.8084 +G01 X-1.8432 Y0.7955 +G01 X-1.8600 Y0.7955 +G01 X-1.8669 Y0.7955 +G01 X-2.2731 Y0.7955 +G01 X-2.2800 Y0.7955 +G01 X-2.2830 Y0.7952 +G01 X-2.2886 Y0.7929 +G01 X-2.2929 Y0.7886 +G01 X-2.2952 Y0.7830 +G01 X-2.2955 Y0.7800 +G01 X-2.2955 Y0.7531 +G01 X-2.2955 Y0.7492 +G01 X-2.3038 Y0.7291 +G01 X-2.3191 Y0.7138 +G01 X-2.3392 Y0.7055 +G01 X-2.3500 Y0.7055 +G01 X-2.3569 Y0.7055 +G01 X-2.6473 Y0.7055 +G01 X-2.6503 Y0.7025 +G01 X-2.6897 Y0.7025 +G01 X-2.7027 Y0.7155 +G01 X-2.8069 Y0.7155 +G01 X-2.8206 Y0.7018 +G01 X-2.8408 Y0.6934 +G01 X-2.9992 Y0.6934 +G01 X-3.0194 Y0.7018 +G01 X-3.0349 Y0.7173 +G01 X-3.0432 Y0.7375 +G01 X-3.0432 Y0.7594 +G01 X-3.0349 Y0.7796 +G01 X-3.0194 Y0.7950 +G01 X-2.9992 Y0.8034 +G01 X-2.8408 Y0.8034 +G01 X-2.8206 Y0.7950 +G01 X-2.8100 Y0.7845 +G01 X-2.7027 Y0.7845 +G01 X-2.6897 Y0.7975 +G01 X-2.6503 Y0.7975 +G01 X-2.6273 Y0.7745 +G01 X-2.3645 Y0.7745 +G01 X-2.3645 Y0.7869 +G01 X-2.3645 Y0.7968 +G00 Z0.1000 +G00 X-2.3869 Y1.7155 +G01 Z-0.0070 F10 +G01 X-2.3900 Y1.7186 F20 +G01 X-2.3931 Y1.7155 +G01 X-2.3869 Y1.7155 +G00 Z0.1000 +G00 X-1.7195 Y1.2209 +G01 Z-0.0070 F10 +G01 X-1.7195 Y1.1791 F20 +G01 X-1.7491 Y1.1495 +G01 X-1.7909 Y1.1495 +G01 X-1.8039 Y1.1625 +G01 X-1.8857 Y1.1625 +G01 X-1.8918 Y1.1600 +G01 X-1.8744 Y1.1528 +G01 X-1.8691 Y1.1475 +G01 X-1.8175 Y1.1475 +G01 X-1.8025 Y1.1475 +G01 X-1.3409 Y1.1475 +G01 X-1.3356 Y1.1528 +G01 X-1.3182 Y1.1600 +G01 X-1.3356 Y1.1672 +G01 X-1.3498 Y1.1814 +G01 X-1.3575 Y1.2000 +G01 X-1.3575 Y1.2200 +G01 X-1.3498 Y1.2386 +G01 X-1.3356 Y1.2528 +G01 X-1.3182 Y1.2600 +G01 X-1.3356 Y1.2672 +G01 X-1.3498 Y1.2814 +G01 X-1.3575 Y1.3000 +G01 X-1.3575 Y1.3200 +G01 X-1.3498 Y1.3386 +G01 X-1.3356 Y1.3528 +G01 X-1.3182 Y1.3600 +G01 X-1.3356 Y1.3672 +G01 X-1.3409 Y1.3725 +G01 X-1.3525 Y1.3725 +G01 X-1.3595 Y1.3725 +G01 X-1.3600 Y1.3725 +G01 X-1.3624 Y1.3723 +G01 X-1.3669 Y1.3704 +G01 X-1.3704 Y1.3669 +G01 X-1.3723 Y1.3624 +G01 X-1.3725 Y1.3600 +G01 X-1.3725 Y1.2525 +G01 X-1.3725 Y1.2433 +G01 X-1.3725 Y1.2333 +G01 X-1.3795 Y1.2164 +G01 X-1.3795 Y1.1891 +G01 X-1.4091 Y1.1595 +G01 X-1.4509 Y1.1595 +G01 X-1.4805 Y1.1891 +G01 X-1.4805 Y1.2309 +G01 X-1.4509 Y1.2605 +G01 X-1.4475 Y1.2605 +G01 X-1.4475 Y1.2891 +G01 X-1.4521 Y1.2780 +G01 X-1.4680 Y1.2621 +G01 X-1.4888 Y1.2535 +G01 X-1.5112 Y1.2535 +G01 X-1.5320 Y1.2621 +G01 X-1.5424 Y1.2725 +G01 X-1.5857 Y1.2725 +G01 X-1.5857 Y1.2475 +G01 X-1.6175 Y1.2157 +G01 X-1.6625 Y1.2157 +G01 X-1.6943 Y1.2475 +G01 X-1.6943 Y1.2725 +G01 X-1.7325 Y1.2725 +G01 X-1.7325 Y1.2339 +G01 X-1.7195 Y1.2209 +G00 Z0.1000 +G00 X-1.8175 Y1.2725 +G01 Z-0.0070 F10 +G01 X-1.8312 Y1.2782 F20 +G01 X-1.8418 Y1.2888 +G01 X-1.8475 Y1.3025 +G01 X-1.8475 Y1.5325 +G01 X-1.8475 Y1.5400 +G01 X-1.8475 Y1.5405 +G01 X-1.8479 Y1.5414 +G01 X-1.8486 Y1.5421 +G01 X-1.8495 Y1.5425 +G01 X-1.8500 Y1.5425 +G01 X-2.3325 Y1.5425 +G01 X-2.3343 Y1.5425 +G01 X-2.3475 Y1.5425 +G01 X-2.3574 Y1.5425 +G01 X-2.3896 Y1.5558 +G01 X-2.4142 Y1.5804 +G01 X-2.4275 Y1.6126 +G01 X-2.4275 Y1.6225 +G01 X-2.4275 Y1.6311 +G01 X-2.4405 Y1.6441 +G01 X-2.4405 Y1.6859 +G01 X-2.4369 Y1.6895 +G01 X-2.4609 Y1.6895 +G01 X-2.4625 Y1.6911 +G01 X-2.4625 Y1.6025 +G01 X-2.4682 Y1.5888 +G01 X-2.4788 Y1.5782 +G01 X-2.4825 Y1.5767 +G01 X-2.4825 Y1.4475 +G01 X-2.4825 Y1.4325 +G01 X-2.4825 Y1.2600 +G01 X-2.4823 Y1.2576 +G01 X-2.4804 Y1.2531 +G01 X-2.4769 Y1.2496 +G01 X-2.4724 Y1.2477 +G01 X-2.4700 Y1.2475 +G01 X-2.4643 Y1.2475 +G01 X-2.4625 Y1.2475 +G01 X-2.3509 Y1.2475 +G01 X-2.3456 Y1.2528 +G01 X-2.3282 Y1.2600 +G01 X-2.3456 Y1.2672 +G01 X-2.3598 Y1.2814 +G01 X-2.3675 Y1.3000 +G01 X-2.3675 Y1.3200 +G01 X-2.3598 Y1.3386 +G01 X-2.3456 Y1.3528 +G01 X-2.3270 Y1.3605 +G01 X-2.1930 Y1.3605 +G01 X-2.1744 Y1.3528 +G01 X-2.1691 Y1.3475 +G01 X-2.1225 Y1.3475 +G01 X-2.1186 Y1.3475 +G01 X-2.0974 Y1.3387 +G01 X-2.0813 Y1.3226 +G01 X-2.0725 Y1.3014 +G01 X-2.0725 Y1.2975 +G01 X-2.0725 Y1.2825 +G01 X-2.0725 Y1.0675 +G01 X-2.0725 Y1.0555 +G01 X-2.0645 Y1.0475 +G01 X-2.0509 Y1.0475 +G01 X-2.0456 Y1.0528 +G01 X-2.0282 Y1.0600 +G01 X-2.0456 Y1.0672 +G01 X-2.0598 Y1.0814 +G01 X-2.0675 Y1.1000 +G01 X-2.0675 Y1.1200 +G01 X-2.0598 Y1.1386 +G01 X-2.0456 Y1.1528 +G01 X-2.0282 Y1.1600 +G01 X-2.0456 Y1.1672 +G01 X-2.0598 Y1.1814 +G01 X-2.0675 Y1.2000 +G01 X-2.0675 Y1.2200 +G01 X-2.0598 Y1.2386 +G01 X-2.0456 Y1.2528 +G01 X-2.0282 Y1.2600 +G01 X-2.0456 Y1.2672 +G01 X-2.0598 Y1.2814 +G01 X-2.0675 Y1.3000 +G01 X-2.0675 Y1.3200 +G01 X-2.0598 Y1.3386 +G01 X-2.0456 Y1.3528 +G01 X-2.0270 Y1.3605 +G01 X-1.9975 Y1.3605 +G01 X-1.9975 Y1.4200 +G01 X-1.9976 Y1.4208 +G01 X-2.0092 Y1.4324 +G01 X-2.0100 Y1.4325 +G01 X-2.1707 Y1.4325 +G01 X-2.1875 Y1.4157 +G01 X-2.2325 Y1.4157 +G01 X-2.2380 Y1.4212 +G01 X-2.2450 Y1.4188 +G01 X-2.2450 Y1.4172 +G01 X-2.2772 Y1.3850 +G01 X-2.3228 Y1.3850 +G01 X-2.3550 Y1.4172 +G01 X-2.3550 Y1.4628 +G01 X-2.3228 Y1.4950 +G01 X-2.2772 Y1.4950 +G01 X-2.2713 Y1.4891 +G01 X-2.2643 Y1.4914 +G01 X-2.2643 Y1.4925 +G01 X-2.2325 Y1.5243 +G01 X-2.1875 Y1.5243 +G01 X-2.1707 Y1.5075 +G01 X-2.0093 Y1.5075 +G01 X-1.9925 Y1.5243 +G01 X-1.9475 Y1.5243 +G01 X-1.9157 Y1.4925 +G01 X-1.9157 Y1.4475 +G01 X-1.9235 Y1.4397 +G01 X-1.9225 Y1.4374 +G01 X-1.9225 Y1.4275 +G01 X-1.9225 Y1.3605 +G01 X-1.8930 Y1.3605 +G01 X-1.8744 Y1.3528 +G01 X-1.8602 Y1.3386 +G01 X-1.8525 Y1.3200 +G01 X-1.8525 Y1.3000 +G01 X-1.8602 Y1.2814 +G01 X-1.8744 Y1.2672 +G01 X-1.8918 Y1.2600 +G01 X-1.8744 Y1.2528 +G01 X-1.8602 Y1.2386 +G01 X-1.8597 Y1.2375 +G01 X-1.8075 Y1.2375 +G01 X-1.8075 Y1.2725 +G01 X-1.8175 Y1.2725 +G00 Z0.1000 +G00 X-2.4775 Y1.7775 +G01 Z-0.0070 F10 +G01 X-2.4739 Y1.7775 F20 +G01 X-2.4609 Y1.7905 +G01 X-2.4191 Y1.7905 +G01 X-2.3900 Y1.7614 +G01 X-2.3775 Y1.7739 +G01 X-2.3775 Y1.7800 +G01 X-2.3777 Y1.7824 +G01 X-2.3796 Y1.7869 +G01 X-2.3831 Y1.7904 +G01 X-2.3876 Y1.7923 +G01 X-2.3900 Y1.7925 +G01 X-2.5300 Y1.7925 +G01 X-2.5324 Y1.7923 +G01 X-2.5369 Y1.7904 +G01 X-2.5404 Y1.7869 +G01 X-2.5423 Y1.7824 +G01 X-2.5425 Y1.7800 +G01 X-2.5425 Y1.7775 +G01 X-2.5425 Y1.7739 +G01 X-2.5425 Y1.7625 +G01 X-2.5425 Y1.7526 +G01 X-2.5558 Y1.7204 +G01 X-2.5804 Y1.6958 +G01 X-2.6126 Y1.6825 +G01 X-2.6225 Y1.6825 +G01 X-2.6361 Y1.6825 +G01 X-2.6491 Y1.6695 +G01 X-2.6909 Y1.6695 +G01 X-2.7039 Y1.6825 +G01 X-2.7300 Y1.6825 +G01 X-2.7324 Y1.6823 +G01 X-2.7369 Y1.6804 +G01 X-2.7404 Y1.6769 +G01 X-2.7423 Y1.6724 +G01 X-2.7425 Y1.6700 +G01 X-2.7425 Y1.6642 +G01 X-2.7425 Y1.6625 +G01 X-2.7425 Y1.5925 +G01 X-2.7425 Y1.5846 +G01 X-2.7543 Y1.5561 +G01 X-2.7761 Y1.5343 +G01 X-2.8046 Y1.5225 +G01 X-2.8125 Y1.5225 +G01 X-2.8197 Y1.5225 +G01 X-2.8200 Y1.5225 +G01 X-2.8275 Y1.5225 +G01 X-2.9525 Y1.5225 +G01 X-2.9525 Y1.4570 +G01 X-2.9466 Y1.4712 +G01 X-2.9312 Y1.4866 +G01 X-2.9109 Y1.4950 +G01 X-2.8891 Y1.4950 +G01 X-2.8688 Y1.4866 +G01 X-2.8597 Y1.4775 +G01 X-2.5575 Y1.4775 +G01 X-2.5575 Y1.5725 +G01 X-2.6261 Y1.5725 +G01 X-2.6391 Y1.5595 +G01 X-2.6809 Y1.5595 +G01 X-2.7105 Y1.5891 +G01 X-2.7105 Y1.6309 +G01 X-2.6809 Y1.6605 +G01 X-2.6391 Y1.6605 +G01 X-2.6261 Y1.6475 +G01 X-2.5375 Y1.6475 +G01 X-2.5375 Y1.7025 +G01 X-2.5375 Y1.7035 +G01 X-2.5375 Y1.7175 +G01 X-2.5375 Y1.7234 +G01 X-2.5272 Y1.7482 +G01 X-2.5082 Y1.7672 +G01 X-2.4834 Y1.7775 +G01 X-2.4775 Y1.7775 +G00 Z0.1000 +G00 X-2.8688 Y1.3934 +G01 Z-0.0070 F10 +G01 X-2.8891 Y1.3850 F20 +G01 X-2.9109 Y1.3850 +G01 X-2.9312 Y1.3934 +G01 X-2.9466 Y1.4088 +G01 X-2.9525 Y1.4230 +G01 X-2.9525 Y1.3805 +G01 X-2.9291 Y1.3805 +G01 X-2.8995 Y1.3509 +G01 X-2.8995 Y1.3091 +G01 X-2.9291 Y1.2795 +G01 X-2.9709 Y1.2795 +G01 X-3.0005 Y1.3091 +G01 X-3.0005 Y1.3109 +G01 X-3.0157 Y1.3261 +G01 X-3.0275 Y1.3546 +G01 X-3.0275 Y1.3625 +G01 X-3.0275 Y1.3661 +G01 X-3.0275 Y1.3700 +G01 X-3.0275 Y1.5225 +G01 X-3.0275 Y1.5300 +G01 X-3.0275 Y1.5301 +G01 X-3.0275 Y1.5375 +G01 X-3.0275 Y1.5434 +G01 X-3.0172 Y1.5682 +G01 X-2.9982 Y1.5872 +G01 X-2.9734 Y1.5975 +G01 X-2.9675 Y1.5975 +G01 X-2.8275 Y1.5975 +G01 X-2.8200 Y1.5975 +G01 X-2.8195 Y1.5975 +G01 X-2.8186 Y1.5979 +G01 X-2.8179 Y1.5986 +G01 X-2.8175 Y1.5995 +G01 X-2.8175 Y1.6000 +G01 X-2.8175 Y1.6625 +G01 X-2.8175 Y1.6642 +G01 X-2.8175 Y1.6775 +G01 X-2.8175 Y1.6874 +G01 X-2.8042 Y1.7196 +G01 X-2.7796 Y1.7442 +G01 X-2.7474 Y1.7575 +G01 X-2.7375 Y1.7575 +G01 X-2.7039 Y1.7575 +G01 X-2.6914 Y1.7700 +G01 X-2.7039 Y1.7825 +G01 X-2.8125 Y1.7825 +G01 X-2.8200 Y1.7825 +G01 X-2.8224 Y1.7823 +G01 X-2.8269 Y1.7804 +G01 X-2.8304 Y1.7769 +G01 X-2.8323 Y1.7724 +G01 X-2.8325 Y1.7700 +G01 X-2.8325 Y1.6875 +G01 X-2.8325 Y1.6859 +G01 X-2.8325 Y1.6725 +G01 X-2.8325 Y1.6666 +G01 X-2.8428 Y1.6418 +G01 X-2.8618 Y1.6228 +G01 X-2.8866 Y1.6125 +G01 X-2.8925 Y1.6125 +G01 X-3.0125 Y1.6125 +G01 X-3.0191 Y1.6125 +G01 X-3.0200 Y1.6125 +G01 X-3.0224 Y1.6123 +G01 X-3.0269 Y1.6104 +G01 X-3.0304 Y1.6069 +G01 X-3.0323 Y1.6024 +G01 X-3.0325 Y1.6000 +G01 X-3.0325 Y1.2900 +G01 X-3.0323 Y1.2876 +G01 X-3.0304 Y1.2831 +G01 X-3.0269 Y1.2796 +G01 X-3.0224 Y1.2777 +G01 X-3.0200 Y1.2775 +G01 X-3.0125 Y1.2775 +G01 X-2.7237 Y1.2775 +G01 X-2.7200 Y1.2782 +G01 X-2.7163 Y1.2775 +G01 X-2.7139 Y1.2775 +G01 X-2.6909 Y1.3005 +G01 X-2.6491 Y1.3005 +G01 X-2.6195 Y1.2709 +G01 X-2.6195 Y1.2291 +G01 X-2.6491 Y1.1995 +G01 X-2.6774 Y1.1995 +G01 X-2.6999 Y1.1950 +G01 X-2.7286 Y1.2007 +G01 X-2.7314 Y1.2025 +G01 X-3.0125 Y1.2025 +G01 X-3.0200 Y1.2025 +G01 X-3.0374 Y1.2025 +G01 X-3.0696 Y1.2158 +G01 X-3.0942 Y1.2404 +G01 X-3.1075 Y1.2726 +G01 X-3.1075 Y1.2825 +G01 X-3.1075 Y1.6075 +G01 X-3.1075 Y1.6174 +G01 X-3.0942 Y1.6496 +G01 X-3.0696 Y1.6742 +G01 X-3.0374 Y1.6875 +G01 X-3.0275 Y1.6875 +G01 X-3.0190 Y1.6875 +G01 X-3.0125 Y1.6875 +G01 X-2.9075 Y1.6875 +G01 X-2.9075 Y1.7775 +G01 X-2.9075 Y1.7874 +G01 X-2.8942 Y1.8196 +G01 X-2.8696 Y1.8442 +G01 X-2.8374 Y1.8575 +G01 X-2.8200 Y1.8575 +G01 X-2.8125 Y1.8575 +G01 X-2.7039 Y1.8575 +G01 X-2.6909 Y1.8705 +G01 X-2.6491 Y1.8705 +G01 X-2.6195 Y1.8409 +G01 X-2.6195 Y1.7991 +G01 X-2.6486 Y1.7700 +G01 X-2.6361 Y1.7575 +G01 X-2.6300 Y1.7575 +G01 X-2.6276 Y1.7577 +G01 X-2.6231 Y1.7596 +G01 X-2.6196 Y1.7631 +G01 X-2.6177 Y1.7676 +G01 X-2.6175 Y1.7700 +G01 X-2.6175 Y1.7739 +G01 X-2.6175 Y1.7775 +G01 X-2.6175 Y1.7875 +G01 X-2.6175 Y1.7974 +G01 X-2.6042 Y1.8296 +G01 X-2.5796 Y1.8542 +G01 X-2.5474 Y1.8675 +G01 X-2.5375 Y1.8675 +G01 X-2.3825 Y1.8675 +G01 X-2.3726 Y1.8675 +G01 X-2.3404 Y1.8542 +G01 X-2.3158 Y1.8296 +G01 X-2.3025 Y1.7974 +G01 X-2.3025 Y1.7875 +G01 X-2.3025 Y1.7775 +G01 X-2.2493 Y1.7775 +G01 X-2.2325 Y1.7943 +G01 X-2.1875 Y1.7943 +G01 X-2.1557 Y1.7625 +G01 X-2.1557 Y1.7175 +G01 X-2.1875 Y1.6857 +G01 X-2.2325 Y1.6857 +G01 X-2.2493 Y1.7025 +G01 X-2.3061 Y1.7025 +G01 X-2.3191 Y1.6895 +G01 X-2.3431 Y1.6895 +G01 X-2.3395 Y1.6859 +G01 X-2.3395 Y1.6441 +G01 X-2.3525 Y1.6311 +G01 X-2.3525 Y1.6300 +G01 X-2.3523 Y1.6276 +G01 X-2.3504 Y1.6231 +G01 X-2.3469 Y1.6196 +G01 X-2.3424 Y1.6177 +G01 X-2.3400 Y1.6175 +G01 X-2.3343 Y1.6175 +G01 X-2.3325 Y1.6175 +G01 X-1.8425 Y1.6175 +G01 X-1.8346 Y1.6175 +G01 X-1.8061 Y1.6057 +G01 X-1.7843 Y1.5839 +G01 X-1.7725 Y1.5554 +G01 X-1.7725 Y1.5475 +G01 X-1.7725 Y1.5400 +G01 X-1.7725 Y1.5325 +G01 X-1.7725 Y1.3475 +G01 X-1.7625 Y1.3475 +G01 X-1.6475 Y1.3475 +G01 X-1.6325 Y1.3475 +G01 X-1.5424 Y1.3475 +G01 X-1.5320 Y1.3579 +G01 X-1.5112 Y1.3665 +G01 X-1.4888 Y1.3665 +G01 X-1.4680 Y1.3579 +G01 X-1.4521 Y1.3420 +G01 X-1.4475 Y1.3309 +G01 X-1.4475 Y1.4100 +G01 X-1.4477 Y1.4124 +G01 X-1.4496 Y1.4169 +G01 X-1.4531 Y1.4204 +G01 X-1.4576 Y1.4223 +G01 X-1.4600 Y1.4225 +G01 X-1.4675 Y1.4225 +G01 X-1.6525 Y1.4225 +G01 X-1.6571 Y1.4225 +G01 X-1.6675 Y1.4225 +G01 X-1.6774 Y1.4225 +G01 X-1.7096 Y1.4358 +G01 X-1.7342 Y1.4604 +G01 X-1.7475 Y1.4926 +G01 X-1.7475 Y1.5025 +G01 X-1.7475 Y1.6511 +G01 X-1.7491 Y1.6495 +G01 X-1.7909 Y1.6495 +G01 X-1.8039 Y1.6625 +G01 X-2.0325 Y1.6625 +G01 X-2.0338 Y1.6625 +G01 X-2.0475 Y1.6625 +G01 X-2.0574 Y1.6625 +G01 X-2.0896 Y1.6758 +G01 X-2.1142 Y1.7004 +G01 X-2.1275 Y1.7326 +G01 X-2.1275 Y1.7425 +G01 X-2.1275 Y1.8725 +G01 X-2.9000 Y1.8725 +G01 X-2.9024 Y1.8723 +G01 X-2.9069 Y1.8704 +G01 X-2.9104 Y1.8669 +G01 X-2.9123 Y1.8624 +G01 X-2.9125 Y1.8600 +G01 X-2.9125 Y1.8543 +G01 X-2.9125 Y1.8525 +G01 X-2.9125 Y1.7725 +G01 X-2.9125 Y1.7646 +G01 X-2.9243 Y1.7361 +G01 X-2.9461 Y1.7143 +G01 X-2.9746 Y1.7025 +G01 X-2.9825 Y1.7025 +G01 X-2.9897 Y1.7025 +G01 X-2.9900 Y1.7025 +G01 X-2.9975 Y1.7025 +G01 X-3.1100 Y1.7025 +G01 X-3.1124 Y1.7023 +G01 X-3.1169 Y1.7004 +G01 X-3.1204 Y1.6969 +G01 X-3.1223 Y1.6924 +G01 X-3.1225 Y1.6900 +G01 X-3.1225 Y1.6825 +G01 X-3.1225 Y1.6439 +G01 X-3.1095 Y1.6309 +G01 X-3.1095 Y1.5891 +G01 X-3.1225 Y1.5761 +G01 X-3.1225 Y0.9600 +G01 X-3.1223 Y0.9576 +G01 X-3.1204 Y0.9531 +G01 X-3.1169 Y0.9496 +G01 X-3.1124 Y0.9477 +G01 X-3.1100 Y0.9475 +G01 X-3.1041 Y0.9475 +G01 X-3.1025 Y0.9475 +G01 X-2.5493 Y0.9475 +G01 X-2.5325 Y0.9643 +G01 X-2.4875 Y0.9643 +G01 X-2.4707 Y0.9475 +G01 X-2.1675 Y0.9475 +G01 X-2.1600 Y0.9475 +G01 X-2.1576 Y0.9477 +G01 X-2.1531 Y0.9496 +G01 X-2.1496 Y0.9531 +G01 X-2.1477 Y0.9576 +G01 X-2.1475 Y0.9600 +G01 X-2.1475 Y1.0675 +G01 X-2.1475 Y1.2725 +G01 X-2.1691 Y1.2725 +G01 X-2.1744 Y1.2672 +G01 X-2.1918 Y1.2600 +G01 X-2.1744 Y1.2528 +G01 X-2.1602 Y1.2386 +G01 X-2.1525 Y1.2200 +G01 X-2.1525 Y1.2000 +G01 X-2.1602 Y1.1814 +G01 X-2.1744 Y1.1672 +G01 X-2.1918 Y1.1600 +G01 X-2.1744 Y1.1528 +G01 X-2.1602 Y1.1386 +G01 X-2.1525 Y1.1200 +G01 X-2.1525 Y1.1000 +G01 X-2.1602 Y1.0814 +G01 X-2.1744 Y1.0672 +G01 X-2.1918 Y1.0600 +G01 X-2.1744 Y1.0528 +G01 X-2.1602 Y1.0386 +G01 X-2.1525 Y1.0200 +G01 X-2.1525 Y1.0000 +G01 X-2.1602 Y0.9814 +G01 X-2.1744 Y0.9672 +G01 X-2.1930 Y0.9595 +G01 X-2.3270 Y0.9595 +G01 X-2.3456 Y0.9672 +G01 X-2.3509 Y0.9725 +G01 X-2.9075 Y0.9725 +G01 X-2.9174 Y0.9725 +G01 X-2.9496 Y0.9858 +G01 X-2.9742 Y1.0104 +G01 X-2.9875 Y1.0426 +G01 X-2.9875 Y1.0525 +G01 X-2.9875 Y1.0961 +G01 X-3.0005 Y1.1091 +G01 X-3.0005 Y1.1509 +G01 X-2.9709 Y1.1805 +G01 X-2.9291 Y1.1805 +G01 X-2.8995 Y1.1509 +G01 X-2.8995 Y1.1091 +G01 X-2.9125 Y1.0961 +G01 X-2.9125 Y1.0600 +G01 X-2.9123 Y1.0576 +G01 X-2.9104 Y1.0531 +G01 X-2.9069 Y1.0496 +G01 X-2.9024 Y1.0477 +G01 X-2.9000 Y1.0475 +G01 X-2.3509 Y1.0475 +G01 X-2.3456 Y1.0528 +G01 X-2.3282 Y1.0600 +G01 X-2.3456 Y1.0672 +G01 X-2.3598 Y1.0814 +G01 X-2.3675 Y1.1000 +G01 X-2.3675 Y1.1200 +G01 X-2.3598 Y1.1386 +G01 X-2.3456 Y1.1528 +G01 X-2.3282 Y1.1600 +G01 X-2.3456 Y1.1672 +G01 X-2.3509 Y1.1725 +G01 X-2.4625 Y1.1725 +G01 X-2.4643 Y1.1725 +G01 X-2.4775 Y1.1725 +G01 X-2.4874 Y1.1725 +G01 X-2.5196 Y1.1858 +G01 X-2.5442 Y1.2104 +G01 X-2.5575 Y1.2426 +G01 X-2.5575 Y1.2525 +G01 X-2.5575 Y1.4025 +G01 X-2.8597 Y1.4025 +G01 X-2.8688 Y1.3934 +G00 Z0.1000 +G00 X-0.4225 Y0.2826 +G01 Z-0.0070 F10 +G01 X-0.4225 Y0.2826 F20 +G01 X-0.4358 Y0.2504 +G01 X-0.4604 Y0.2258 +G01 X-0.4926 Y0.2125 +G01 X-0.5025 Y0.2125 +G01 X-0.5100 Y0.2125 +G01 X-0.5175 Y0.2125 +G01 X-1.0400 Y0.2125 +G01 X-1.0424 Y0.2123 +G01 X-1.0469 Y0.2104 +G01 X-1.0504 Y0.2069 +G01 X-1.0523 Y0.2024 +G01 X-1.0525 Y0.2000 +G01 X-1.0525 Y0.1947 +G01 X-1.0525 Y0.1925 +G01 X-1.0525 Y0.1425 +G01 X-1.0525 Y0.1326 +G01 X-1.0658 Y0.1004 +G01 X-1.0904 Y0.0758 +G01 X-1.1226 Y0.0625 +G01 X-1.1400 Y0.0625 +G01 X-1.1475 Y0.0625 +G01 X-1.5925 Y0.0625 +G01 X-1.6000 Y0.0625 +G01 X-1.6174 Y0.0625 +G01 X-1.6496 Y0.0758 +G01 X-1.6742 Y0.1004 +G01 X-1.6875 Y0.1326 +G01 X-1.6875 Y0.1425 +G01 X-1.6875 Y0.8675 +G01 X-1.6875 Y0.8774 +G01 X-1.6742 Y0.9096 +G01 X-1.6496 Y0.9342 +G01 X-1.6174 Y0.9475 +G01 X-1.6075 Y0.9475 +G01 X-1.5992 Y0.9475 +G01 X-1.5925 Y0.9475 +G01 X-1.3409 Y0.9475 +G01 X-1.3356 Y0.9528 +G01 X-1.3182 Y0.9600 +G01 X-1.3356 Y0.9672 +G01 X-1.3409 Y0.9725 +G01 X-1.6825 Y0.9725 +G01 X-1.6900 Y0.9725 +G01 X-1.6905 Y0.9725 +G01 X-1.6914 Y0.9721 +G01 X-1.6921 Y0.9714 +G01 X-1.6925 Y0.9705 +G01 X-1.6925 Y0.9700 +G01 X-1.6925 Y0.9625 +G01 X-1.6925 Y0.8075 +G01 X-1.6925 Y0.8000 +G01 X-1.6925 Y0.7826 +G01 X-1.7058 Y0.7504 +G01 X-1.7304 Y0.7258 +G01 X-1.7626 Y0.7125 +G01 X-1.7800 Y0.7125 +G01 X-1.7875 Y0.7125 +G01 X-1.9891 Y0.7125 +G01 X-1.9780 Y0.7079 +G01 X-1.9676 Y0.6975 +G01 X-1.7839 Y0.6975 +G01 X-1.7709 Y0.7105 +G01 X-1.7291 Y0.7105 +G01 X-1.6995 Y0.6809 +G01 X-1.6995 Y0.6391 +G01 X-1.7291 Y0.6095 +G01 X-1.7709 Y0.6095 +G01 X-1.7839 Y0.6225 +G01 X-1.8757 Y0.6225 +G01 X-1.8457 Y0.5925 +G01 X-1.8457 Y0.5505 +G01 X-1.8312 Y0.5565 +G01 X-1.8088 Y0.5565 +G01 X-1.7880 Y0.5479 +G01 X-1.7721 Y0.5320 +G01 X-1.7635 Y0.5112 +G01 X-1.7635 Y0.4888 +G01 X-1.7721 Y0.4680 +G01 X-1.7825 Y0.4576 +G01 X-1.7825 Y0.3824 +G01 X-1.7721 Y0.3720 +G01 X-1.7635 Y0.3512 +G01 X-1.7635 Y0.3288 +G01 X-1.7721 Y0.3080 +G01 X-1.7880 Y0.2921 +G01 X-1.8088 Y0.2835 +G01 X-1.8312 Y0.2835 +G01 X-1.8520 Y0.2921 +G01 X-1.8624 Y0.3025 +G01 X-1.9600 Y0.3025 +G01 X-1.9624 Y0.3023 +G01 X-1.9669 Y0.3004 +G01 X-1.9687 Y0.2986 +G01 X-1.9621 Y0.2920 +G01 X-1.9535 Y0.2712 +G01 X-1.9535 Y0.2488 +G01 X-1.9621 Y0.2280 +G01 X-1.9780 Y0.2121 +G01 X-1.9988 Y0.2035 +G01 X-2.0212 Y0.2035 +G01 X-2.0420 Y0.2121 +G01 X-2.0579 Y0.2280 +G01 X-2.0665 Y0.2488 +G01 X-2.0665 Y0.2712 +G01 X-2.0579 Y0.2920 +G01 X-2.0475 Y0.3024 +G01 X-2.0475 Y0.3074 +G01 X-2.0342 Y0.3396 +G01 X-2.0096 Y0.3642 +G01 X-1.9774 Y0.3775 +G01 X-1.9675 Y0.3775 +G01 X-1.8624 Y0.3775 +G01 X-1.8575 Y0.3824 +G01 X-1.8575 Y0.4576 +G01 X-1.8624 Y0.4625 +G01 X-1.8674 Y0.4625 +G01 X-1.8996 Y0.4758 +G01 X-1.9242 Y0.5004 +G01 X-1.9362 Y0.5294 +G01 X-1.9543 Y0.5475 +G01 X-1.9543 Y0.5925 +G01 X-1.9243 Y0.6225 +G01 X-1.9676 Y0.6225 +G01 X-1.9780 Y0.6121 +G01 X-1.9988 Y0.6035 +G01 X-2.0212 Y0.6035 +G01 X-2.0420 Y0.6121 +G01 X-2.0524 Y0.6225 +G01 X-2.0825 Y0.6225 +G01 X-2.0891 Y0.6225 +G01 X-2.0900 Y0.6225 +G01 X-2.0924 Y0.6223 +G01 X-2.0969 Y0.6204 +G01 X-2.1004 Y0.6169 +G01 X-2.1023 Y0.6124 +G01 X-2.1025 Y0.6100 +G01 X-2.1025 Y0.2939 +G01 X-2.0895 Y0.2809 +G01 X-2.0895 Y0.2391 +G01 X-2.1191 Y0.2095 +G01 X-2.1609 Y0.2095 +G01 X-2.1905 Y0.2391 +G01 X-2.1905 Y0.2809 +G01 X-2.1775 Y0.2939 +G01 X-2.1775 Y0.6175 +G01 X-2.1775 Y0.6274 +G01 X-2.1642 Y0.6596 +G01 X-2.1396 Y0.6842 +G01 X-2.1074 Y0.6975 +G01 X-2.0975 Y0.6975 +G01 X-2.0890 Y0.6975 +G01 X-2.0825 Y0.6975 +G01 X-2.0524 Y0.6975 +G01 X-2.0420 Y0.7079 +G01 X-2.0309 Y0.7125 +G01 X-2.1825 Y0.7125 +G01 X-2.1900 Y0.7125 +G01 X-2.1905 Y0.7125 +G01 X-2.1914 Y0.7121 +G01 X-2.1921 Y0.7114 +G01 X-2.1925 Y0.7105 +G01 X-2.1925 Y0.7100 +G01 X-2.1925 Y0.5975 +G01 X-2.1925 Y0.5955 +G01 X-2.1925 Y0.5825 +G01 X-2.1925 Y0.5746 +G01 X-2.2043 Y0.5461 +G01 X-2.2261 Y0.5243 +G01 X-2.2546 Y0.5125 +G01 X-2.2625 Y0.5125 +G01 X-2.2690 Y0.5125 +G01 X-2.2700 Y0.5125 +G01 X-2.2775 Y0.5125 +G01 X-2.4857 Y0.5125 +G01 X-2.4557 Y0.4825 +G01 X-2.4557 Y0.4375 +G01 X-2.4625 Y0.4307 +G01 X-2.4625 Y0.2694 +G01 X-2.4625 Y0.1900 +G01 X-2.4625 Y0.1896 +G01 X-2.4622 Y0.1889 +G01 X-2.4618 Y0.1882 +G01 X-2.4611 Y0.1878 +G01 X-2.4604 Y0.1875 +G01 X-2.4600 Y0.1875 +G01 X-2.4517 Y0.1875 +G01 X-2.4505 Y0.1875 +G01 X-1.8705 Y0.1875 +G01 X-1.8705 Y0.2209 +G01 X-1.8409 Y0.2505 +G01 X-1.7991 Y0.2505 +G01 X-1.7695 Y0.2209 +G01 X-1.7695 Y0.1791 +G01 X-1.7725 Y0.1761 +G01 X-1.7725 Y0.1746 +G01 X-1.7820 Y0.1452 +G01 X-1.8002 Y0.1202 +G01 X-1.8252 Y0.1020 +G01 X-1.8546 Y0.0925 +G01 X-1.8605 Y0.0925 +G01 X-2.4505 Y0.0925 +G01 X-2.4517 Y0.0925 +G01 X-2.4694 Y0.0925 +G01 X-2.4754 Y0.0925 +G01 X-2.5048 Y0.1020 +G01 X-2.5298 Y0.1202 +G01 X-2.5479 Y0.1452 +G01 X-2.5575 Y0.1746 +G01 X-2.5575 Y0.1805 +G01 X-2.5575 Y0.2225 +G01 X-2.6061 Y0.2225 +G01 X-2.6191 Y0.2095 +G01 X-2.6609 Y0.2095 +G01 X-2.6905 Y0.2391 +G01 X-2.6905 Y0.2809 +G01 X-2.6609 Y0.3105 +G01 X-2.6191 Y0.3105 +G01 X-2.6061 Y0.2975 +G01 X-2.5575 Y0.2975 +G01 X-2.5575 Y0.4307 +G01 X-2.5643 Y0.4375 +G01 X-2.5643 Y0.4825 +G01 X-2.5343 Y0.5125 +G01 X-2.8088 Y0.5125 +G01 X-2.8189 Y0.5024 +G01 X-2.8402 Y0.4936 +G01 X-2.9998 Y0.4936 +G01 X-3.0211 Y0.5024 +G01 X-3.0374 Y0.5187 +G01 X-3.0462 Y0.5400 +G01 X-3.0462 Y0.5631 +G01 X-3.0374 Y0.5844 +G01 X-3.0211 Y0.6007 +G01 X-2.9998 Y0.6096 +G01 X-2.8402 Y0.6096 +G01 X-2.8189 Y0.6007 +G01 X-2.8057 Y0.5875 +G01 X-2.2775 Y0.5875 +G01 X-2.2700 Y0.5875 +G01 X-2.2695 Y0.5875 +G01 X-2.2686 Y0.5879 +G01 X-2.2679 Y0.5886 +G01 X-2.2675 Y0.5895 +G01 X-2.2675 Y0.5900 +G01 X-2.2675 Y0.5955 +G01 X-2.2675 Y0.5975 +G01 X-2.2675 Y0.7175 +G01 X-2.2675 Y0.7254 +G01 X-2.2557 Y0.7539 +G01 X-2.2339 Y0.7757 +G01 X-2.2054 Y0.7875 +G01 X-2.1975 Y0.7875 +G01 X-2.1904 Y0.7875 +G01 X-2.1900 Y0.7875 +G01 X-2.1825 Y0.7875 +G01 X-1.7875 Y0.7875 +G01 X-1.7800 Y0.7875 +G01 X-1.7776 Y0.7877 +G01 X-1.7731 Y0.7896 +G01 X-1.7696 Y0.7931 +G01 X-1.7677 Y0.7976 +G01 X-1.7675 Y0.8000 +G01 X-1.7675 Y0.8075 +G01 X-1.7675 Y0.9625 +G01 X-1.7675 Y0.9700 +G01 X-1.7675 Y0.9702 +G01 X-1.7675 Y0.9775 +G01 X-1.7675 Y0.9854 +G01 X-1.7557 Y1.0139 +G01 X-1.7339 Y1.0357 +G01 X-1.7054 Y1.0475 +G01 X-1.6975 Y1.0475 +G01 X-1.6900 Y1.0475 +G01 X-1.6825 Y1.0475 +G01 X-1.3409 Y1.0475 +G01 X-1.3356 Y1.0528 +G01 X-1.3182 Y1.0600 +G01 X-1.3356 Y1.0672 +G01 X-1.3409 Y1.0725 +G01 X-1.7725 Y1.0725 +G01 X-1.7725 Y0.8875 +G01 X-1.7725 Y0.8800 +G01 X-1.7725 Y0.8626 +G01 X-1.7858 Y0.8304 +G01 X-1.8104 Y0.8058 +G01 X-1.8426 Y0.7925 +G01 X-1.8525 Y0.7925 +G01 X-2.2725 Y0.7925 +G01 X-2.2800 Y0.7925 +G01 X-2.2824 Y0.7923 +G01 X-2.2869 Y0.7904 +G01 X-2.2904 Y0.7869 +G01 X-2.2923 Y0.7824 +G01 X-2.2925 Y0.7800 +G01 X-2.2925 Y0.7525 +G01 X-2.2925 Y0.7486 +G01 X-2.3013 Y0.7274 +G01 X-2.3174 Y0.7113 +G01 X-2.3386 Y0.7025 +G01 X-2.3500 Y0.7025 +G01 X-2.3575 Y0.7025 +G01 X-2.6461 Y0.7025 +G01 X-2.6491 Y0.6995 +G01 X-2.6909 Y0.6995 +G01 X-2.7039 Y0.7125 +G01 X-2.8057 Y0.7125 +G01 X-2.8189 Y0.6993 +G01 X-2.8402 Y0.6904 +G01 X-2.9998 Y0.6904 +G01 X-3.0211 Y0.6993 +G01 X-3.0374 Y0.7156 +G01 X-3.0462 Y0.7369 +G01 X-3.0462 Y0.7600 +G01 X-3.0374 Y0.7813 +G01 X-3.0211 Y0.7976 +G01 X-2.9998 Y0.8064 +G01 X-2.8402 Y0.8064 +G01 X-2.8189 Y0.7976 +G01 X-2.8088 Y0.7875 +G01 X-2.7039 Y0.7875 +G01 X-2.6909 Y0.8005 +G01 X-2.6491 Y0.8005 +G01 X-2.6261 Y0.7775 +G01 X-2.3675 Y0.7775 +G01 X-2.3675 Y0.7875 +G01 X-2.3675 Y0.7974 +G01 X-2.3542 Y0.8296 +G01 X-2.3296 Y0.8542 +G01 X-2.2974 Y0.8675 +G01 X-2.2800 Y0.8675 +G01 X-2.2725 Y0.8675 +G01 X-1.8600 Y0.8675 +G01 X-1.8576 Y0.8677 +G01 X-1.8531 Y0.8696 +G01 X-1.8496 Y0.8731 +G01 X-1.8477 Y0.8776 +G01 X-1.8475 Y0.8800 +G01 X-1.8475 Y0.8875 +G01 X-1.8475 Y1.0725 +G01 X-1.8691 Y1.0725 +G01 X-1.8744 Y1.0672 +G01 X-1.8918 Y1.0600 +G01 X-1.8744 Y1.0528 +G01 X-1.8602 Y1.0386 +G01 X-1.8525 Y1.0200 +G01 X-1.8525 Y1.0000 +G01 X-1.8602 Y0.9814 +G01 X-1.8744 Y0.9672 +G01 X-1.8930 Y0.9595 +G01 X-2.0270 Y0.9595 +G01 X-2.0456 Y0.9672 +G01 X-2.0509 Y0.9725 +G01 X-2.0725 Y0.9725 +G01 X-2.0725 Y0.9525 +G01 X-2.0725 Y0.9426 +G01 X-2.0858 Y0.9104 +G01 X-2.1104 Y0.8858 +G01 X-2.1426 Y0.8725 +G01 X-2.1600 Y0.8725 +G01 X-2.1675 Y0.8725 +G01 X-2.4707 Y0.8725 +G01 X-2.4875 Y0.8557 +G01 X-2.5325 Y0.8557 +G01 X-2.5493 Y0.8725 +G01 X-3.1025 Y0.8725 +G01 X-3.1041 Y0.8725 +G01 X-3.1175 Y0.8725 +G01 X-3.1274 Y0.8725 +G01 X-3.1596 Y0.8858 +G01 X-3.1842 Y0.9104 +G01 X-3.1975 Y0.9426 +G01 X-3.1975 Y0.9525 +G01 X-3.1975 Y1.5761 +G01 X-3.2105 Y1.5891 +G01 X-3.2105 Y1.6309 +G01 X-3.1975 Y1.6439 +G01 X-3.1975 Y1.6825 +G01 X-3.1975 Y1.6900 +G01 X-3.1975 Y1.7074 +G01 X-3.1842 Y1.7396 +G01 X-3.1596 Y1.7642 +G01 X-3.1274 Y1.7775 +G01 X-3.1175 Y1.7775 +G01 X-2.9975 Y1.7775 +G01 X-2.9900 Y1.7775 +G01 X-2.9895 Y1.7775 +G01 X-2.9886 Y1.7779 +G01 X-2.9879 Y1.7786 +G01 X-2.9875 Y1.7795 +G01 X-2.9875 Y1.7800 +G01 X-2.9875 Y1.8525 +G01 X-2.9875 Y1.8543 +G01 X-2.9875 Y1.8675 +G01 X-2.9875 Y1.8774 +G01 X-2.9742 Y1.9096 +G01 X-2.9496 Y1.9342 +G01 X-2.9174 Y1.9475 +G01 X-2.9075 Y1.9475 +G01 X-2.0975 Y1.9475 +G01 X-2.0825 Y1.9475 +G01 X-2.0339 Y1.9475 +G01 X-2.0209 Y1.9605 +G01 X-1.9791 Y1.9605 +G01 X-1.9661 Y1.9475 +G01 X-1.7700 Y1.9475 +G01 X-1.7676 Y1.9477 +G01 X-1.7631 Y1.9496 +G01 X-1.7596 Y1.9531 +G01 X-1.7577 Y1.9576 +G01 X-1.7575 Y1.9600 +G01 X-1.7575 Y1.9660 +G01 X-1.7575 Y1.9675 +G01 X-1.7575 Y2.0675 +G01 X-1.7575 Y2.0774 +G01 X-1.7442 Y2.1096 +G01 X-1.7196 Y2.1342 +G01 X-1.6874 Y2.1475 +G01 X-1.6700 Y2.1475 +G01 X-1.6625 Y2.1475 +G01 X-1.2525 Y2.1475 +G01 X-1.2426 Y2.1475 +G01 X-1.2104 Y2.1342 +G01 X-1.1858 Y2.1096 +G01 X-1.1725 Y2.0774 +G01 X-1.1725 Y2.0600 +G01 X-1.1725 Y2.0525 +G01 X-1.1725 Y1.9100 +G01 X-1.1723 Y1.9076 +G01 X-1.1704 Y1.9031 +G01 X-1.1669 Y1.8996 +G01 X-1.1624 Y1.8977 +G01 X-1.1600 Y1.8975 +G01 X-1.1554 Y1.8975 +G01 X-1.1525 Y1.8975 +G01 X-0.8003 Y1.8975 +G01 X-0.7912 Y1.9066 +G01 X-0.7709 Y1.9150 +G01 X-0.7491 Y1.9150 +G01 X-0.7288 Y1.9066 +G01 X-0.7197 Y1.8975 +G01 X-0.2641 Y1.8975 +G01 X-0.2543 Y1.8975 +G01 X-0.2214 Y1.8868 +G01 X-0.1935 Y1.8665 +G01 X-0.1789 Y1.8464 +G01 X-0.1202 Y1.8464 +G01 X-0.0989 Y1.8376 +G01 X-0.0826 Y1.8213 +G01 X-0.0738 Y1.8000 +G01 X-0.0738 Y1.7769 +G01 X-0.0826 Y1.7556 +G01 X-0.0989 Y1.7393 +G01 X-0.1202 Y1.7304 +G01 X-0.2798 Y1.7304 +G01 X-0.3011 Y1.7393 +G01 X-0.3174 Y1.7556 +G01 X-0.3262 Y1.7769 +G01 X-0.3262 Y1.8000 +G01 X-0.3174 Y1.8213 +G01 X-0.3162 Y1.8225 +G01 X-0.7197 Y1.8225 +G01 X-0.7288 Y1.8134 +G01 X-0.7491 Y1.8050 +G01 X-0.7709 Y1.8050 +G01 X-0.7912 Y1.8134 +G01 X-0.8003 Y1.8225 +G01 X-1.1525 Y1.8225 +G01 X-1.1554 Y1.8225 +G01 X-1.1675 Y1.8225 +G01 X-1.1774 Y1.8225 +G01 X-1.2096 Y1.8358 +G01 X-1.2342 Y1.8604 +G01 X-1.2475 Y1.8926 +G01 X-1.2475 Y1.9100 +G01 X-1.2475 Y2.0525 +G01 X-1.2475 Y2.0600 +G01 X-1.2477 Y2.0624 +G01 X-1.2496 Y2.0669 +G01 X-1.2531 Y2.0704 +G01 X-1.2576 Y2.0723 +G01 X-1.2600 Y2.0725 +G01 X-1.6625 Y2.0725 +G01 X-1.6700 Y2.0725 +G01 X-1.6724 Y2.0723 +G01 X-1.6769 Y2.0704 +G01 X-1.6804 Y2.0669 +G01 X-1.6823 Y2.0624 +G01 X-1.6825 Y2.0600 +G01 X-1.6825 Y1.9675 +G01 X-1.6825 Y1.9659 +G01 X-1.6825 Y1.9525 +G01 X-1.6825 Y1.9426 +G01 X-1.6958 Y1.9104 +G01 X-1.7204 Y1.8858 +G01 X-1.7526 Y1.8725 +G01 X-1.7625 Y1.8725 +G01 X-1.9661 Y1.8725 +G01 X-1.9791 Y1.8595 +G01 X-2.0209 Y1.8595 +G01 X-2.0339 Y1.8725 +G01 X-2.0525 Y1.8725 +G01 X-2.0525 Y1.7500 +G01 X-2.0523 Y1.7476 +G01 X-2.0504 Y1.7431 +G01 X-2.0469 Y1.7396 +G01 X-2.0424 Y1.7377 +G01 X-2.0400 Y1.7375 +G01 X-2.0338 Y1.7375 +G01 X-2.0325 Y1.7375 +G01 X-1.9943 Y1.7375 +G01 X-2.0243 Y1.7675 +G01 X-2.0243 Y1.8125 +G01 X-1.9925 Y1.8443 +G01 X-1.9475 Y1.8443 +G01 X-1.9307 Y1.8275 +G01 X-1.6575 Y1.8275 +G01 X-1.6575 Y1.9675 +G01 X-1.6575 Y1.9774 +G01 X-1.6442 Y2.0096 +G01 X-1.6196 Y2.0342 +G01 X-1.5874 Y2.0475 +G01 X-1.5700 Y2.0475 +G01 X-1.5625 Y2.0475 +G01 X-1.4175 Y2.0475 +G01 X-1.4100 Y2.0475 +G01 X-1.3926 Y2.0475 +G01 X-1.3604 Y2.0342 +G01 X-1.3358 Y2.0096 +G01 X-1.3225 Y1.9774 +G01 X-1.3225 Y1.9675 +G01 X-1.3225 Y1.9587 +G01 X-1.3225 Y1.9525 +G01 X-1.3225 Y1.9003 +G01 X-1.3050 Y1.8828 +G01 X-1.3050 Y1.8372 +G01 X-1.3225 Y1.8197 +G01 X-1.3225 Y1.8100 +G01 X-1.3223 Y1.8076 +G01 X-1.3204 Y1.8031 +G01 X-1.3169 Y1.7996 +G01 X-1.3124 Y1.7977 +G01 X-1.3100 Y1.7975 +G01 X-1.3040 Y1.7975 +G01 X-1.3025 Y1.7975 +G01 X-0.6525 Y1.7975 +G01 X-0.6446 Y1.7975 +G01 X-0.6161 Y1.7857 +G01 X-0.5943 Y1.7639 +G01 X-0.5825 Y1.7354 +G01 X-0.5825 Y1.7275 +G01 X-0.5825 Y1.6575 +G01 X-0.5825 Y1.6500 +G01 X-0.5823 Y1.6476 +G01 X-0.5804 Y1.6431 +G01 X-0.5769 Y1.6396 +G01 X-0.5724 Y1.6377 +G01 X-0.5700 Y1.6375 +G01 X-0.3043 Y1.6375 +G01 X-0.3011 Y1.6407 +G01 X-0.2798 Y1.6496 +G01 X-0.1202 Y1.6496 +G01 X-0.0989 Y1.6407 +G01 X-0.0826 Y1.6244 +G01 X-0.0738 Y1.6031 +G01 X-0.0738 Y1.5800 +G01 X-0.0826 Y1.5587 +G01 X-0.0989 Y1.5424 +G01 X-0.1202 Y1.5336 +G01 X-0.2798 Y1.5336 +G01 X-0.3011 Y1.5424 +G01 X-0.3174 Y1.5587 +G01 X-0.3190 Y1.5625 +G01 X-0.5775 Y1.5625 +G01 X-0.5874 Y1.5625 +G01 X-0.6196 Y1.5758 +G01 X-0.6442 Y1.6004 +G01 X-0.6575 Y1.6326 +G01 X-0.6575 Y1.6425 +G01 X-0.6575 Y1.6500 +G01 X-0.6575 Y1.6575 +G01 X-0.6575 Y1.7200 +G01 X-0.6575 Y1.7205 +G01 X-0.6579 Y1.7214 +G01 X-0.6586 Y1.7221 +G01 X-0.6595 Y1.7225 +G01 X-0.6600 Y1.7225 +G01 X-1.3025 Y1.7225 +G01 X-1.3041 Y1.7225 +G01 X-1.3175 Y1.7225 +G01 X-1.3274 Y1.7225 +G01 X-1.3596 Y1.7358 +G01 X-1.3842 Y1.7604 +G01 X-1.3975 Y1.7926 +G01 X-1.3975 Y1.8025 +G01 X-1.3975 Y1.8197 +G01 X-1.4150 Y1.8372 +G01 X-1.4150 Y1.8828 +G01 X-1.3975 Y1.9003 +G01 X-1.3975 Y1.9525 +G01 X-1.3975 Y1.9587 +G01 X-1.3975 Y1.9600 +G01 X-1.3977 Y1.9624 +G01 X-1.3996 Y1.9669 +G01 X-1.4031 Y1.9704 +G01 X-1.4076 Y1.9723 +G01 X-1.4100 Y1.9725 +G01 X-1.4175 Y1.9725 +G01 X-1.5625 Y1.9725 +G01 X-1.5700 Y1.9725 +G01 X-1.5724 Y1.9723 +G01 X-1.5769 Y1.9704 +G01 X-1.5804 Y1.9669 +G01 X-1.5823 Y1.9624 +G01 X-1.5825 Y1.9600 +G01 X-1.5825 Y1.7975 +G01 X-1.5825 Y1.7725 +G01 X-1.5825 Y1.6375 +G01 X-1.5825 Y1.6300 +G01 X-1.5823 Y1.6276 +G01 X-1.5804 Y1.6231 +G01 X-1.5769 Y1.6196 +G01 X-1.5724 Y1.6177 +G01 X-1.5700 Y1.6175 +G01 X-1.5692 Y1.6175 +G01 X-1.5625 Y1.6175 +G01 X-1.1425 Y1.6175 +G01 X-1.1326 Y1.6175 +G01 X-1.1004 Y1.6042 +G01 X-1.0758 Y1.5796 +G01 X-1.0625 Y1.5474 +G01 X-1.0625 Y1.5300 +G01 X-1.0625 Y1.5225 +G01 X-1.0625 Y0.8600 +G01 X-1.0623 Y0.8576 +G01 X-1.0604 Y0.8531 +G01 X-1.0569 Y0.8496 +G01 X-1.0524 Y0.8477 +G01 X-1.0500 Y0.8475 +G01 X-1.0434 Y0.8475 +G01 X-1.0425 Y0.8475 +G01 X-1.0409 Y0.8475 +G01 X-1.0356 Y0.8528 +G01 X-1.0182 Y0.8600 +G01 X-1.0356 Y0.8672 +G01 X-1.0498 Y0.8814 +G01 X-1.0575 Y0.9000 +G01 X-1.0575 Y0.9200 +G01 X-1.0498 Y0.9386 +G01 X-1.0356 Y0.9528 +G01 X-1.0182 Y0.9600 +G01 X-1.0356 Y0.9672 +G01 X-1.0498 Y0.9814 +G01 X-1.0575 Y1.0000 +G01 X-1.0575 Y1.0200 +G01 X-1.0498 Y1.0386 +G01 X-1.0356 Y1.0528 +G01 X-1.0182 Y1.0600 +G01 X-1.0356 Y1.0672 +G01 X-1.0498 Y1.0814 +G01 X-1.0575 Y1.1000 +G01 X-1.0575 Y1.1200 +G01 X-1.0498 Y1.1386 +G01 X-1.0356 Y1.1528 +G01 X-1.0182 Y1.1600 +G01 X-1.0356 Y1.1672 +G01 X-1.0498 Y1.1814 +G01 X-1.0575 Y1.2000 +G01 X-1.0575 Y1.2200 +G01 X-1.0498 Y1.2386 +G01 X-1.0356 Y1.2528 +G01 X-1.0182 Y1.2600 +G01 X-1.0356 Y1.2672 +G01 X-1.0498 Y1.2814 +G01 X-1.0575 Y1.3000 +G01 X-1.0575 Y1.3200 +G01 X-1.0498 Y1.3386 +G01 X-1.0356 Y1.3528 +G01 X-1.0182 Y1.3600 +G01 X-1.0356 Y1.3672 +G01 X-1.0498 Y1.3814 +G01 X-1.0575 Y1.4000 +G01 X-1.0575 Y1.4200 +G01 X-1.0498 Y1.4386 +G01 X-1.0356 Y1.4528 +G01 X-1.0170 Y1.4605 +G01 X-0.8830 Y1.4605 +G01 X-0.8644 Y1.4528 +G01 X-0.8591 Y1.4475 +G01 X-0.5825 Y1.4475 +G01 X-0.5726 Y1.4475 +G01 X-0.5404 Y1.4342 +G01 X-0.5158 Y1.4096 +G01 X-0.5025 Y1.3774 +G01 X-0.5025 Y1.3675 +G01 X-0.5025 Y1.3600 +G01 X-0.5025 Y1.3584 +G01 X-0.5023 Y1.3560 +G01 X-0.5004 Y1.3515 +G01 X-0.4969 Y1.3480 +G01 X-0.4924 Y1.3462 +G01 X-0.4900 Y1.3459 +G01 X-0.4854 Y1.3459 +G01 X-0.4825 Y1.3459 +G01 X-0.3128 Y1.3459 +G01 X-0.3011 Y1.3576 +G01 X-0.2798 Y1.3664 +G01 X-0.1202 Y1.3664 +G01 X-0.0989 Y1.3576 +G01 X-0.0826 Y1.3413 +G01 X-0.0738 Y1.3200 +G01 X-0.0738 Y1.2969 +G01 X-0.0826 Y1.2756 +G01 X-0.0989 Y1.2593 +G01 X-0.1202 Y1.2504 +G01 X-0.2798 Y1.2504 +G01 X-0.3011 Y1.2593 +G01 X-0.3128 Y1.2709 +G01 X-0.4825 Y1.2709 +G01 X-0.4854 Y1.2709 +G01 X-0.4975 Y1.2709 +G01 X-0.5074 Y1.2709 +G01 X-0.5396 Y1.2842 +G01 X-0.5642 Y1.3089 +G01 X-0.5775 Y1.3410 +G01 X-0.5775 Y1.3510 +G01 X-0.5775 Y1.3525 +G01 X-0.5775 Y1.3600 +G01 X-0.5777 Y1.3624 +G01 X-0.5796 Y1.3669 +G01 X-0.5831 Y1.3704 +G01 X-0.5876 Y1.3723 +G01 X-0.5900 Y1.3725 +G01 X-0.8591 Y1.3725 +G01 X-0.8644 Y1.3672 +G01 X-0.8818 Y1.3600 +G01 X-0.8644 Y1.3528 +G01 X-0.8591 Y1.3475 +G01 X-0.7539 Y1.3475 +G01 X-0.7409 Y1.3605 +G01 X-0.6991 Y1.3605 +G01 X-0.6695 Y1.3309 +G01 X-0.6695 Y1.2891 +G01 X-0.6991 Y1.2595 +G01 X-0.7409 Y1.2595 +G01 X-0.7539 Y1.2725 +G01 X-0.8591 Y1.2725 +G01 X-0.8644 Y1.2672 +G01 X-0.8818 Y1.2600 +G01 X-0.8644 Y1.2528 +G01 X-0.8591 Y1.2475 +G01 X-0.4475 Y1.2475 +G01 X-0.4400 Y1.2475 +G01 X-0.4325 Y1.2475 +G01 X-0.4246 Y1.2475 +G01 X-0.3961 Y1.2357 +G01 X-0.3743 Y1.2139 +G01 X-0.3625 Y1.1854 +G01 X-0.3625 Y1.1775 +G01 X-0.3625 Y1.1616 +G01 X-0.3623 Y1.1591 +G01 X-0.3604 Y1.1546 +G01 X-0.3569 Y1.1512 +G01 X-0.3524 Y1.1493 +G01 X-0.3500 Y1.1491 +G01 X-0.3437 Y1.1491 +G01 X-0.3425 Y1.1491 +G01 X-0.3128 Y1.1491 +G01 X-0.3011 Y1.1607 +G01 X-0.2798 Y1.1696 +G01 X-0.1202 Y1.1696 +G01 X-0.0989 Y1.1607 +G01 X-0.0826 Y1.1444 +G01 X-0.0738 Y1.1231 +G01 X-0.0738 Y1.1000 +G01 X-0.0826 Y1.0787 +G01 X-0.0989 Y1.0624 +G01 X-0.1202 Y1.0536 +G01 X-0.2798 Y1.0536 +G01 X-0.3011 Y1.0624 +G01 X-0.3128 Y1.0741 +G01 X-0.3425 Y1.0741 +G01 X-0.3437 Y1.0741 +G01 X-0.3575 Y1.0741 +G01 X-0.3674 Y1.0741 +G01 X-0.3996 Y1.0874 +G01 X-0.4242 Y1.1120 +G01 X-0.4375 Y1.1442 +G01 X-0.4375 Y1.1541 +G01 X-0.4375 Y1.1700 +G01 X-0.4375 Y1.1705 +G01 X-0.4379 Y1.1714 +G01 X-0.4386 Y1.1721 +G01 X-0.4395 Y1.1725 +G01 X-0.4400 Y1.1725 +G01 X-0.4475 Y1.1725 +G01 X-0.8591 Y1.1725 +G01 X-0.8644 Y1.1672 +G01 X-0.8818 Y1.1600 +G01 X-0.8644 Y1.1528 +G01 X-0.8591 Y1.1475 +G01 X-0.5939 Y1.1475 +G01 X-0.5809 Y1.1605 +G01 X-0.5391 Y1.1605 +G01 X-0.5095 Y1.1309 +G01 X-0.5095 Y1.0891 +G01 X-0.5391 Y1.0595 +G01 X-0.5809 Y1.0595 +G01 X-0.5939 Y1.0725 +G01 X-0.8591 Y1.0725 +G01 X-0.8644 Y1.0672 +G01 X-0.8818 Y1.0600 +G01 X-0.8644 Y1.0528 +G01 X-0.8591 Y1.0475 +G01 X-0.4875 Y1.0475 +G01 X-0.4839 Y1.0475 +G01 X-0.4725 Y1.0475 +G01 X-0.4626 Y1.0475 +G01 X-0.4304 Y1.0342 +G01 X-0.4058 Y1.0096 +G01 X-0.3925 Y0.9774 +G01 X-0.3925 Y0.9675 +G01 X-0.3925 Y0.9575 +G01 X-0.3925 Y0.9500 +G01 X-0.3925 Y0.9495 +G01 X-0.3921 Y0.9486 +G01 X-0.3914 Y0.9479 +G01 X-0.3905 Y0.9475 +G01 X-0.3900 Y0.9475 +G01 X-0.3112 Y0.9475 +G01 X-0.3011 Y0.9576 +G01 X-0.2798 Y0.9664 +G01 X-0.1202 Y0.9664 +G01 X-0.0989 Y0.9576 +G01 X-0.0826 Y0.9413 +G01 X-0.0738 Y0.9200 +G01 X-0.0738 Y0.8969 +G01 X-0.0826 Y0.8756 +G01 X-0.0989 Y0.8593 +G01 X-0.1202 Y0.8504 +G01 X-0.2798 Y0.8504 +G01 X-0.3011 Y0.8593 +G01 X-0.3143 Y0.8725 +G01 X-0.3975 Y0.8725 +G01 X-0.4054 Y0.8725 +G01 X-0.4339 Y0.8843 +G01 X-0.4557 Y0.9061 +G01 X-0.4675 Y0.9346 +G01 X-0.4675 Y0.9425 +G01 X-0.4675 Y0.9499 +G01 X-0.4675 Y0.9575 +G01 X-0.4675 Y0.9600 +G01 X-0.4677 Y0.9624 +G01 X-0.4696 Y0.9669 +G01 X-0.4731 Y0.9704 +G01 X-0.4776 Y0.9723 +G01 X-0.4800 Y0.9725 +G01 X-0.4839 Y0.9725 +G01 X-0.4875 Y0.9725 +G01 X-0.8591 Y0.9725 +G01 X-0.8644 Y0.9672 +G01 X-0.8818 Y0.9600 +G01 X-0.8644 Y0.9528 +G01 X-0.8591 Y0.9475 +G01 X-0.8375 Y0.9475 +G01 X-0.8353 Y0.9475 +G01 X-0.8225 Y0.9475 +G01 X-0.8126 Y0.9475 +G01 X-0.7804 Y0.9342 +G01 X-0.7558 Y0.9096 +G01 X-0.7425 Y0.8774 +G01 X-0.7425 Y0.8675 +G01 X-0.7425 Y0.5739 +G01 X-0.7295 Y0.5609 +G01 X-0.7295 Y0.5191 +G01 X-0.7591 Y0.4895 +G01 X-0.8009 Y0.4895 +G01 X-0.8305 Y0.5191 +G01 X-0.8305 Y0.5609 +G01 X-0.8175 Y0.5739 +G01 X-0.8175 Y0.8600 +G01 X-0.8177 Y0.8624 +G01 X-0.8196 Y0.8669 +G01 X-0.8231 Y0.8704 +G01 X-0.8276 Y0.8723 +G01 X-0.8300 Y0.8725 +G01 X-0.8353 Y0.8725 +G01 X-0.8375 Y0.8725 +G01 X-0.8591 Y0.8725 +G01 X-0.8644 Y0.8672 +G01 X-0.8818 Y0.8600 +G01 X-0.8644 Y0.8528 +G01 X-0.8502 Y0.8386 +G01 X-0.8425 Y0.8200 +G01 X-0.8425 Y0.8000 +G01 X-0.8502 Y0.7814 +G01 X-0.8644 Y0.7672 +G01 X-0.8830 Y0.7595 +G01 X-1.0170 Y0.7595 +G01 X-1.0356 Y0.7672 +G01 X-1.0409 Y0.7725 +G01 X-1.0425 Y0.7725 +G01 X-1.0434 Y0.7725 +G01 X-1.0575 Y0.7725 +G01 X-1.0674 Y0.7725 +G01 X-1.0996 Y0.7858 +G01 X-1.1242 Y0.8104 +G01 X-1.1375 Y0.8426 +G01 X-1.1375 Y0.8525 +G01 X-1.1375 Y1.5225 +G01 X-1.1375 Y1.5300 +G01 X-1.1377 Y1.5324 +G01 X-1.1396 Y1.5369 +G01 X-1.1431 Y1.5404 +G01 X-1.1476 Y1.5423 +G01 X-1.1500 Y1.5425 +G01 X-1.5625 Y1.5425 +G01 X-1.5692 Y1.5425 +G01 X-1.5775 Y1.5425 +G01 X-1.5874 Y1.5425 +G01 X-1.6196 Y1.5558 +G01 X-1.6442 Y1.5804 +G01 X-1.6575 Y1.6126 +G01 X-1.6575 Y1.6225 +G01 X-1.6575 Y1.6270 +G01 X-1.6575 Y1.6300 +G01 X-1.6575 Y1.6375 +G01 X-1.6575 Y1.7525 +G01 X-1.9307 Y1.7525 +G01 X-1.9457 Y1.7375 +G01 X-1.8039 Y1.7375 +G01 X-1.7909 Y1.7505 +G01 X-1.7491 Y1.7505 +G01 X-1.7361 Y1.7375 +G01 X-1.7325 Y1.7375 +G01 X-1.7266 Y1.7375 +G01 X-1.7018 Y1.7272 +G01 X-1.6828 Y1.7082 +G01 X-1.6725 Y1.6834 +G01 X-1.6725 Y1.6775 +G01 X-1.6725 Y1.6646 +G01 X-1.6725 Y1.6625 +G01 X-1.6725 Y1.5100 +G01 X-1.6723 Y1.5076 +G01 X-1.6704 Y1.5031 +G01 X-1.6669 Y1.4996 +G01 X-1.6624 Y1.4977 +G01 X-1.6600 Y1.4975 +G01 X-1.6571 Y1.4975 +G01 X-1.6525 Y1.4975 +G01 X-1.4675 Y1.4975 +G01 X-1.4600 Y1.4975 +G01 X-1.4426 Y1.4975 +G01 X-1.4104 Y1.4842 +G01 X-1.3858 Y1.4596 +G01 X-1.3803 Y1.4463 +G01 X-1.3774 Y1.4475 +G01 X-1.3675 Y1.4475 +G01 X-1.3594 Y1.4475 +G01 X-1.3525 Y1.4475 +G01 X-1.3409 Y1.4475 +G01 X-1.3356 Y1.4528 +G01 X-1.3170 Y1.4605 +G01 X-1.1830 Y1.4605 +G01 X-1.1644 Y1.4528 +G01 X-1.1502 Y1.4386 +G01 X-1.1425 Y1.4200 +G01 X-1.1425 Y1.4000 +G01 X-1.1502 Y1.3814 +G01 X-1.1644 Y1.3672 +G01 X-1.1818 Y1.3600 +G01 X-1.1644 Y1.3528 +G01 X-1.1502 Y1.3386 +G01 X-1.1425 Y1.3200 +G01 X-1.1425 Y1.3000 +G01 X-1.1502 Y1.2814 +G01 X-1.1644 Y1.2672 +G01 X-1.1818 Y1.2600 +G01 X-1.1644 Y1.2528 +G01 X-1.1502 Y1.2386 +G01 X-1.1425 Y1.2200 +G01 X-1.1425 Y1.2000 +G01 X-1.1502 Y1.1814 +G01 X-1.1644 Y1.1672 +G01 X-1.1818 Y1.1600 +G01 X-1.1644 Y1.1528 +G01 X-1.1502 Y1.1386 +G01 X-1.1425 Y1.1200 +G01 X-1.1425 Y1.1000 +G01 X-1.1502 Y1.0814 +G01 X-1.1644 Y1.0672 +G01 X-1.1818 Y1.0600 +G01 X-1.1644 Y1.0528 +G01 X-1.1502 Y1.0386 +G01 X-1.1425 Y1.0200 +G01 X-1.1425 Y1.0000 +G01 X-1.1502 Y0.9814 +G01 X-1.1644 Y0.9672 +G01 X-1.1818 Y0.9600 +G01 X-1.1644 Y0.9528 +G01 X-1.1502 Y0.9386 +G01 X-1.1425 Y0.9200 +G01 X-1.1425 Y0.9000 +G01 X-1.1502 Y0.8814 +G01 X-1.1644 Y0.8672 +G01 X-1.1818 Y0.8600 +G01 X-1.1644 Y0.8528 +G01 X-1.1502 Y0.8386 +G01 X-1.1425 Y0.8200 +G01 X-1.1425 Y0.8000 +G01 X-1.1502 Y0.7814 +G01 X-1.1644 Y0.7672 +G01 X-1.1830 Y0.7595 +G01 X-1.3170 Y0.7595 +G01 X-1.3356 Y0.7672 +G01 X-1.3409 Y0.7725 +G01 X-1.5000 Y0.7725 +G01 X-1.5024 Y0.7723 +G01 X-1.5069 Y0.7704 +G01 X-1.5104 Y0.7669 +G01 X-1.5123 Y0.7624 +G01 X-1.5125 Y0.7600 +G01 X-1.5125 Y0.7539 +G01 X-1.5125 Y0.7525 +G01 X-1.5125 Y0.6939 +G01 X-1.4995 Y0.6809 +G01 X-1.4995 Y0.6391 +G01 X-1.5291 Y0.6095 +G01 X-1.5709 Y0.6095 +G01 X-1.6005 Y0.6391 +G01 X-1.6005 Y0.6809 +G01 X-1.5875 Y0.6939 +G01 X-1.5875 Y0.7525 +G01 X-1.5875 Y0.7539 +G01 X-1.5875 Y0.7675 +G01 X-1.5875 Y0.7774 +G01 X-1.5742 Y0.8096 +G01 X-1.5496 Y0.8342 +G01 X-1.5174 Y0.8475 +G01 X-1.5075 Y0.8475 +G01 X-1.3409 Y0.8475 +G01 X-1.3356 Y0.8528 +G01 X-1.3182 Y0.8600 +G01 X-1.3356 Y0.8672 +G01 X-1.3409 Y0.8725 +G01 X-1.5925 Y0.8725 +G01 X-1.5993 Y0.8725 +G01 X-1.6000 Y0.8725 +G01 X-1.6024 Y0.8723 +G01 X-1.6069 Y0.8704 +G01 X-1.6104 Y0.8669 +G01 X-1.6123 Y0.8624 +G01 X-1.6125 Y0.8600 +G01 X-1.6125 Y0.1500 +G01 X-1.6123 Y0.1476 +G01 X-1.6104 Y0.1431 +G01 X-1.6069 Y0.1396 +G01 X-1.6024 Y0.1377 +G01 X-1.6000 Y0.1375 +G01 X-1.5925 Y0.1375 +G01 X-1.1475 Y0.1375 +G01 X-1.1400 Y0.1375 +G01 X-1.1376 Y0.1377 +G01 X-1.1331 Y0.1396 +G01 X-1.1296 Y0.1431 +G01 X-1.1277 Y0.1476 +G01 X-1.1275 Y0.1500 +G01 X-1.1275 Y0.1925 +G01 X-1.1275 Y0.1947 +G01 X-1.1275 Y0.2075 +G01 X-1.1275 Y0.2174 +G01 X-1.1142 Y0.2496 +G01 X-1.0896 Y0.2742 +G01 X-1.0574 Y0.2875 +G01 X-1.0475 Y0.2875 +G01 X-0.5175 Y0.2875 +G01 X-0.5100 Y0.2875 +G01 X-0.5076 Y0.2877 +G01 X-0.5031 Y0.2896 +G01 X-0.4996 Y0.2931 +G01 X-0.4977 Y0.2976 +G01 X-0.4975 Y0.3000 +G01 X-0.4975 Y0.6525 +G01 X-0.4975 Y0.6536 +G01 X-0.4975 Y0.6675 +G01 X-0.4975 Y0.6774 +G01 X-0.4842 Y0.7096 +G01 X-0.4596 Y0.7342 +G01 X-0.4274 Y0.7475 +G01 X-0.4100 Y0.7475 +G01 X-0.3143 Y0.7475 +G01 X-0.3011 Y0.7607 +G01 X-0.2798 Y0.7696 +G01 X-0.1202 Y0.7696 +G01 X-0.0989 Y0.7607 +G01 X-0.0826 Y0.7444 +G01 X-0.0738 Y0.7231 +G01 X-0.0738 Y0.7000 +G01 X-0.0826 Y0.6787 +G01 X-0.0989 Y0.6624 +G01 X-0.1202 Y0.6536 +G01 X-0.2798 Y0.6536 +G01 X-0.3011 Y0.6624 +G01 X-0.3112 Y0.6725 +G01 X-0.4100 Y0.6725 +G01 X-0.4124 Y0.6723 +G01 X-0.4169 Y0.6704 +G01 X-0.4204 Y0.6669 +G01 X-0.4223 Y0.6624 +G01 X-0.4225 Y0.6600 +G01 X-0.4225 Y0.6536 +G01 X-0.4225 Y0.6525 +G01 X-0.4225 Y0.2925 +G01 X-0.4225 Y0.2826 +G00 Z0.1000 +G00 X-0.5225 Y0.4726 +G01 Z-0.0070 F10 +G01 X-0.5225 Y0.4726 F20 +G01 X-0.5358 Y0.4404 +G01 X-0.5604 Y0.4158 +G01 X-0.5926 Y0.4025 +G01 X-0.6025 Y0.4025 +G01 X-0.6108 Y0.4025 +G01 X-0.6175 Y0.4025 +G01 X-1.3775 Y0.4025 +G01 X-1.3874 Y0.4025 +G01 X-1.4196 Y0.4158 +G01 X-1.4442 Y0.4404 +G01 X-1.4484 Y0.4506 +G01 X-1.4520 Y0.4521 +G01 X-1.4679 Y0.4680 +G01 X-1.4765 Y0.4888 +G01 X-1.4765 Y0.5112 +G01 X-1.4679 Y0.5320 +G01 X-1.4675 Y0.5324 +G01 X-1.4675 Y0.6761 +G01 X-1.4805 Y0.6891 +G01 X-1.4805 Y0.7309 +G01 X-1.4509 Y0.7605 +G01 X-1.4091 Y0.7605 +G01 X-1.3795 Y0.7309 +G01 X-1.3795 Y0.6891 +G01 X-1.3925 Y0.6761 +G01 X-1.3925 Y0.5498 +G01 X-1.3880 Y0.5479 +G01 X-1.3721 Y0.5320 +G01 X-1.3635 Y0.5112 +G01 X-1.3635 Y0.4888 +G01 X-1.3682 Y0.4775 +G01 X-0.6175 Y0.4775 +G01 X-0.6107 Y0.4775 +G01 X-0.6100 Y0.4775 +G01 X-0.6076 Y0.4777 +G01 X-0.6031 Y0.4796 +G01 X-0.5996 Y0.4831 +G01 X-0.5977 Y0.4876 +G01 X-0.5975 Y0.4900 +G01 X-0.5975 Y0.8761 +G01 X-0.6105 Y0.8891 +G01 X-0.6105 Y0.9309 +G01 X-0.5809 Y0.9605 +G01 X-0.5391 Y0.9605 +G01 X-0.5095 Y0.9309 +G01 X-0.5095 Y0.8891 +G01 X-0.5225 Y0.8761 +G01 X-0.5225 Y0.4825 +G01 X-0.5225 Y0.4726 +G00 Z0.1000 +G00 X-1.5565 Y1.6988 +G01 Z-0.0070 F10 +G01 X-1.5565 Y1.7212 F20 +G01 X-1.5479 Y1.7420 +G01 X-1.5375 Y1.7524 +G01 X-1.5375 Y1.8761 +G01 X-1.5505 Y1.8891 +G01 X-1.5505 Y1.9309 +G01 X-1.5209 Y1.9605 +G01 X-1.4791 Y1.9605 +G01 X-1.4495 Y1.9309 +G01 X-1.4495 Y1.8891 +G01 X-1.4625 Y1.8761 +G01 X-1.4625 Y1.7524 +G01 X-1.4521 Y1.7420 +G01 X-1.4435 Y1.7212 +G01 X-1.4435 Y1.7075 +G01 X-0.7625 Y1.7075 +G01 X-0.7526 Y1.7075 +G01 X-0.7204 Y1.6942 +G01 X-0.6958 Y1.6696 +G01 X-0.6825 Y1.6374 +G01 X-0.6825 Y1.6275 +G01 X-0.6825 Y1.5439 +G01 X-0.6695 Y1.5309 +G01 X-0.6695 Y1.4891 +G01 X-0.6991 Y1.4595 +G01 X-0.7409 Y1.4595 +G01 X-0.7705 Y1.4891 +G01 X-0.7705 Y1.5309 +G01 X-0.7575 Y1.5439 +G01 X-0.7575 Y1.6200 +G01 X-0.7577 Y1.6224 +G01 X-0.7596 Y1.6269 +G01 X-0.7631 Y1.6304 +G01 X-0.7676 Y1.6323 +G01 X-0.7700 Y1.6325 +G01 X-1.4480 Y1.6325 +G01 X-1.4622 Y1.6309 +G01 X-1.4938 Y1.6401 +G01 X-1.5106 Y1.6535 +G01 X-1.5112 Y1.6535 +G01 X-1.5320 Y1.6621 +G01 X-1.5479 Y1.6780 +G01 X-1.5565 Y1.6988 +G00 Z0.1000 +G00 X-1.3705 Y0.1791 +G01 Z-0.0070 F10 +G01 X-1.3705 Y0.2209 F20 +G01 X-1.3475 Y0.2439 +G01 X-1.3475 Y0.3025 +G01 X-1.3776 Y0.3025 +G01 X-1.3880 Y0.2921 +G01 X-1.4088 Y0.2835 +G01 X-1.4312 Y0.2835 +G01 X-1.4520 Y0.2921 +G01 X-1.4679 Y0.3080 +G01 X-1.4765 Y0.3288 +G01 X-1.4765 Y0.3512 +G01 X-1.4679 Y0.3720 +G01 X-1.4520 Y0.3879 +G01 X-1.4312 Y0.3965 +G01 X-1.4088 Y0.3965 +G01 X-1.3880 Y0.3879 +G01 X-1.3776 Y0.3775 +G01 X-1.3175 Y0.3775 +G01 X-0.8139 Y0.3775 +G01 X-0.8009 Y0.3905 +G01 X-0.7591 Y0.3905 +G01 X-0.7295 Y0.3609 +G01 X-0.7295 Y0.3191 +G01 X-0.7591 Y0.2895 +G01 X-0.8009 Y0.2895 +G01 X-0.8139 Y0.3025 +G01 X-1.2725 Y0.3025 +G01 X-1.2725 Y0.2239 +G01 X-1.2695 Y0.2209 +G01 X-1.2695 Y0.1791 +G01 X-1.2991 Y0.1495 +G01 X-1.3409 Y0.1495 +G01 X-1.3705 Y0.1791 +G00 Z0.1000 +G00 X-1.9664 Y0.7005 +G01 Z-0.0070 F10 +G01 X-1.7852 Y0.7005 F20 +G01 X-1.7761 Y0.7095 +G01 X-1.9754 Y0.7095 +G01 X-1.9664 Y0.7005 +G00 Z0.1000 +G00 X-1.4457 Y1.5005 +G01 Z-0.0070 F10 +G01 X-1.4457 Y1.5005 F20 +G01 X-1.4184 Y1.4916 +G01 X-1.3952 Y1.4748 +G01 X-1.3784 Y1.4516 +G01 X-1.3776 Y1.4494 +G01 X-1.3743 Y1.4505 +G01 X-1.3681 Y1.4505 +G01 X-1.3607 Y1.4505 +G01 X-1.3600 Y1.4505 +G01 X-1.3519 Y1.4505 +G01 X-1.3422 Y1.4505 +G01 X-1.3373 Y1.4554 +G01 X-1.3176 Y1.4635 +G01 X-1.1824 Y1.4635 +G01 X-1.1627 Y1.4554 +G01 X-1.1476 Y1.4403 +G01 X-1.1405 Y1.4230 +G01 X-1.1405 Y1.5219 +G01 X-1.1405 Y1.5300 +G01 X-1.1406 Y1.5315 +G01 X-1.1415 Y1.5343 +G01 X-1.1433 Y1.5367 +G01 X-1.1457 Y1.5385 +G01 X-1.1485 Y1.5394 +G01 X-1.1500 Y1.5395 +G01 X-1.5619 Y1.5395 +G01 X-1.5685 Y1.5395 +G01 X-1.5781 Y1.5395 +G01 X-1.5843 Y1.5395 +G01 X-1.6116 Y1.5484 +G01 X-1.6348 Y1.5652 +G01 X-1.6516 Y1.5884 +G01 X-1.6605 Y1.6157 +G01 X-1.6605 Y1.6219 +G01 X-1.6605 Y1.6299 +G01 X-1.6605 Y1.6381 +G01 X-1.6605 Y1.7495 +G01 X-1.7438 Y1.7495 +G01 X-1.7348 Y1.7405 +G01 X-1.7319 Y1.7405 +G01 X-1.7260 Y1.7405 +G01 X-1.7001 Y1.7298 +G01 X-1.6802 Y1.7099 +G01 X-1.6695 Y1.6840 +G01 X-1.6695 Y1.6781 +G01 X-1.6695 Y1.6658 +G01 X-1.6695 Y1.6619 +G01 X-1.6695 Y1.5100 +G01 X-1.6694 Y1.5085 +G01 X-1.6685 Y1.5057 +G01 X-1.6667 Y1.5033 +G01 X-1.6643 Y1.5015 +G01 X-1.6615 Y1.5006 +G01 X-1.6600 Y1.5005 +G01 X-1.6534 Y1.5005 +G01 X-1.6519 Y1.5005 +G01 X-1.4519 Y1.5005 +G01 X-1.4457 Y1.5005 +G00 Z0.1000 +G00 X-1.7961 Y1.7495 +G01 Z-0.0070 F10 +G01 X-1.9294 Y1.7495 F20 +G01 X-1.9385 Y1.7405 +G01 X-1.8052 Y1.7405 +G01 X-1.7961 Y1.7495 +G00 Z0.1000 +G00 X-2.6165 Y1.8422 +G01 Z-0.0070 F10 +G01 X-2.6165 Y1.8066 F20 +G01 X-2.6116 Y1.8216 +G01 X-2.5948 Y1.8448 +G01 X-2.5716 Y1.8616 +G01 X-2.5474 Y1.8695 +G01 X-2.6438 Y1.8695 +G01 X-2.6165 Y1.8422 +G00 Z0.1000 +G00 X-2.6205 Y1.7939 +G01 Z-0.0070 F10 +G01 X-2.6443 Y1.7700 F20 +G01 X-2.6348 Y1.7605 +G01 X-2.6300 Y1.7605 +G01 X-2.6285 Y1.7606 +G01 X-2.6257 Y1.7615 +G01 X-2.6233 Y1.7633 +G01 X-2.6215 Y1.7657 +G01 X-2.6206 Y1.7685 +G01 X-2.6205 Y1.7700 +G01 X-2.6205 Y1.7765 +G01 X-2.6205 Y1.7781 +G01 X-2.6205 Y1.7881 +G01 X-2.6205 Y1.7939 +G00 Z0.1000 +G00 X-2.1576 Y1.0797 +G01 Z-0.0070 F10 +G01 X-2.1727 Y1.0646 F20 +G01 X-2.1839 Y1.0600 +G01 X-2.1727 Y1.0554 +G01 X-2.1576 Y1.0403 +G01 X-2.1505 Y1.0230 +G01 X-2.1505 Y1.0970 +G01 X-2.1576 Y1.0797 +G00 Z0.1000 +G00 X-2.1727 Y1.2646 +G01 Z-0.0070 F10 +G01 X-2.1839 Y1.2600 F20 +G01 X-2.1727 Y1.2554 +G01 X-2.1576 Y1.2403 +G01 X-2.1505 Y1.2230 +G01 X-2.1505 Y1.2695 +G01 X-2.1678 Y1.2695 +G01 X-2.1727 Y1.2646 +G00 Z0.1000 +G00 X-2.1576 Y1.1797 +G01 Z-0.0070 F10 +G01 X-2.1727 Y1.1646 F20 +G01 X-2.1839 Y1.1600 +G01 X-2.1727 Y1.1554 +G01 X-2.1576 Y1.1403 +G01 X-2.1505 Y1.1230 +G01 X-2.1505 Y1.1970 +G01 X-2.1576 Y1.1797 +G00 Z0.1000 +G00 X-2.0632 Y1.0505 +G01 Z-0.0070 F10 +G01 X-2.0522 Y1.0505 F20 +G01 X-2.0473 Y1.0554 +G01 X-2.0361 Y1.0600 +G01 X-2.0473 Y1.0646 +G01 X-2.0624 Y1.0797 +G01 X-2.0695 Y1.0970 +G01 X-2.0695 Y1.0568 +G01 X-2.0632 Y1.0505 +G00 Z0.1000 +G00 X-2.0624 Y1.1403 +G01 Z-0.0070 F10 +G01 X-2.0473 Y1.1554 F20 +G01 X-2.0361 Y1.1600 +G01 X-2.0473 Y1.1646 +G01 X-2.0624 Y1.1797 +G01 X-2.0695 Y1.1970 +G01 X-2.0695 Y1.1230 +G01 X-2.0624 Y1.1403 +G00 Z0.1000 +G00 X-2.0624 Y1.2403 +G01 Z-0.0070 F10 +G01 X-2.0473 Y1.2554 F20 +G01 X-2.0361 Y1.2600 +G01 X-2.0473 Y1.2646 +G01 X-2.0624 Y1.2797 +G01 X-2.0695 Y1.2970 +G01 X-2.0695 Y1.2819 +G01 X-2.0695 Y1.2230 +G01 X-2.0624 Y1.2403 +G00 Z0.1000 +G00 X-1.8181 Y1.2695 +G01 Z-0.0070 F10 +G01 X-1.8329 Y1.2757 F20 +G01 X-1.8443 Y1.2871 +G01 X-1.8495 Y1.2995 +G01 X-1.8495 Y1.2994 +G01 X-1.8576 Y1.2797 +G01 X-1.8727 Y1.2646 +G01 X-1.8839 Y1.2600 +G01 X-1.8727 Y1.2554 +G01 X-1.8578 Y1.2405 +G01 X-1.8105 Y1.2405 +G01 X-1.8105 Y1.2695 +G01 X-1.8181 Y1.2695 +G00 Z0.1000 +G00 X-1.8576 Y0.9797 +G01 Z-0.0070 F10 +G01 X-1.8727 Y0.9646 F20 +G01 X-1.8924 Y0.9565 +G01 X-2.0276 Y0.9565 +G01 X-2.0473 Y0.9646 +G01 X-2.0522 Y0.9695 +G01 X-2.0695 Y0.9695 +G01 X-2.0695 Y0.9519 +G01 X-2.0695 Y0.9457 +G01 X-2.0784 Y0.9184 +G01 X-2.0952 Y0.8952 +G01 X-2.1184 Y0.8784 +G01 X-2.1426 Y0.8705 +G01 X-1.8600 Y0.8705 +G01 X-1.8585 Y0.8706 +G01 X-1.8557 Y0.8715 +G01 X-1.8533 Y0.8733 +G01 X-1.8515 Y0.8757 +G01 X-1.8506 Y0.8785 +G01 X-1.8505 Y0.8800 +G01 X-1.8505 Y0.9970 +G01 X-1.8576 Y0.9797 +G00 Z0.1000 +G00 X-1.8727 Y1.0646 +G01 Z-0.0070 F10 +G01 X-1.8839 Y1.0600 F20 +G01 X-1.8727 Y1.0554 +G01 X-1.8576 Y1.0403 +G01 X-1.8505 Y1.0230 +G01 X-1.8505 Y1.0695 +G01 X-1.8678 Y1.0695 +G01 X-1.8727 Y1.0646 +G00 Z0.1000 +G00 X-1.8052 Y1.1595 +G01 Z-0.0070 F10 +G01 X-1.8827 Y1.1595 F20 +G01 X-1.8727 Y1.1554 +G01 X-1.8678 Y1.1505 +G01 X-1.8181 Y1.1505 +G01 X-1.8019 Y1.1505 +G01 X-1.7961 Y1.1505 +G01 X-1.8052 Y1.1595 +G00 Z0.1000 +G00 X-1.7165 Y1.2222 +G01 Z-0.0070 F10 +G01 X-1.7165 Y1.1778 F20 +G01 X-1.7438 Y1.1505 +G01 X-1.3422 Y1.1505 +G01 X-1.3373 Y1.1554 +G01 X-1.3261 Y1.1600 +G01 X-1.3373 Y1.1646 +G01 X-1.3524 Y1.1797 +G01 X-1.3605 Y1.1994 +G01 X-1.3605 Y1.2206 +G01 X-1.3524 Y1.2403 +G01 X-1.3373 Y1.2554 +G01 X-1.3261 Y1.2600 +G01 X-1.3373 Y1.2646 +G01 X-1.3524 Y1.2797 +G01 X-1.3605 Y1.2994 +G01 X-1.3605 Y1.3206 +G01 X-1.3524 Y1.3403 +G01 X-1.3373 Y1.3554 +G01 X-1.3261 Y1.3600 +G01 X-1.3373 Y1.3646 +G01 X-1.3422 Y1.3695 +G01 X-1.3519 Y1.3695 +G01 X-1.3600 Y1.3695 +G01 X-1.3615 Y1.3694 +G01 X-1.3643 Y1.3685 +G01 X-1.3667 Y1.3667 +G01 X-1.3685 Y1.3643 +G01 X-1.3694 Y1.3615 +G01 X-1.3695 Y1.3600 +G01 X-1.3695 Y1.2681 +G01 X-1.3695 Y1.2588 +G01 X-1.3695 Y1.2577 +G01 X-1.3695 Y1.2427 +G01 X-1.3695 Y1.2388 +G01 X-1.3757 Y1.2158 +G01 X-1.3765 Y1.2143 +G01 X-1.3765 Y1.1878 +G01 X-1.4078 Y1.1565 +G01 X-1.4522 Y1.1565 +G01 X-1.4835 Y1.1878 +G01 X-1.4835 Y1.2322 +G01 X-1.4522 Y1.2635 +G01 X-1.4505 Y1.2635 +G01 X-1.4505 Y1.2681 +G01 X-1.4505 Y1.2754 +G01 X-1.4663 Y1.2596 +G01 X-1.4882 Y1.2505 +G01 X-1.5118 Y1.2505 +G01 X-1.5337 Y1.2596 +G01 X-1.5436 Y1.2695 +G01 X-1.5827 Y1.2695 +G01 X-1.5827 Y1.2463 +G01 X-1.6163 Y1.2127 +G01 X-1.6637 Y1.2127 +G01 X-1.6973 Y1.2463 +G01 X-1.6973 Y1.2695 +G01 X-1.7295 Y1.2695 +G01 X-1.7295 Y1.2352 +G01 X-1.7165 Y1.2222 +G00 Z0.1000 +G00 X-2.4795 Y1.4481 +G01 Z-0.0070 F10 +G01 X-2.4795 Y1.4319 F20 +G01 X-2.4795 Y1.2600 +G01 X-2.4794 Y1.2585 +G01 X-2.4785 Y1.2557 +G01 X-2.4767 Y1.2533 +G01 X-2.4743 Y1.2515 +G01 X-2.4715 Y1.2506 +G01 X-2.4700 Y1.2505 +G01 X-2.4633 Y1.2505 +G01 X-2.4619 Y1.2505 +G01 X-2.3522 Y1.2505 +G01 X-2.3473 Y1.2554 +G01 X-2.3361 Y1.2600 +G01 X-2.3473 Y1.2646 +G01 X-2.3624 Y1.2797 +G01 X-2.3705 Y1.2994 +G01 X-2.3705 Y1.3206 +G01 X-2.3624 Y1.3403 +G01 X-2.3473 Y1.3554 +G01 X-2.3276 Y1.3635 +G01 X-2.1924 Y1.3635 +G01 X-2.1727 Y1.3554 +G01 X-2.1678 Y1.3505 +G01 X-2.1381 Y1.3505 +G01 X-2.1219 Y1.3505 +G01 X-2.1180 Y1.3505 +G01 X-2.0957 Y1.3413 +G01 X-2.0787 Y1.3243 +G01 X-2.0705 Y1.3044 +G01 X-2.0705 Y1.3206 +G01 X-2.0624 Y1.3403 +G01 X-2.0473 Y1.3554 +G01 X-2.0276 Y1.3635 +G01 X-2.0005 Y1.3635 +G01 X-2.0005 Y1.4119 +G01 X-2.0005 Y1.4195 +G01 X-2.0105 Y1.4295 +G01 X-2.0181 Y1.4295 +G01 X-2.1694 Y1.4295 +G01 X-2.1863 Y1.4127 +G01 X-2.2337 Y1.4127 +G01 X-2.2388 Y1.4177 +G01 X-2.2420 Y1.4166 +G01 X-2.2420 Y1.4160 +G01 X-2.2760 Y1.3820 +G01 X-2.3240 Y1.3820 +G01 X-2.3580 Y1.4160 +G01 X-2.3580 Y1.4640 +G01 X-2.3240 Y1.4980 +G01 X-2.2760 Y1.4980 +G01 X-2.2705 Y1.4925 +G01 X-2.2673 Y1.4936 +G01 X-2.2673 Y1.4937 +G01 X-2.2337 Y1.5273 +G01 X-2.1863 Y1.5273 +G01 X-2.1694 Y1.5105 +G01 X-2.0181 Y1.5105 +G01 X-2.0105 Y1.5105 +G01 X-1.9937 Y1.5273 +G01 X-1.9463 Y1.5273 +G01 X-1.9127 Y1.4937 +G01 X-1.9127 Y1.4463 +G01 X-1.9208 Y1.4382 +G01 X-1.9195 Y1.4343 +G01 X-1.9195 Y1.4281 +G01 X-1.9195 Y1.4237 +G01 X-1.9195 Y1.4200 +G01 X-1.9195 Y1.4119 +G01 X-1.9195 Y1.3635 +G01 X-1.8924 Y1.3635 +G01 X-1.8727 Y1.3554 +G01 X-1.8576 Y1.3403 +G01 X-1.8505 Y1.3230 +G01 X-1.8505 Y1.5319 +G01 X-1.8505 Y1.5395 +G01 X-2.3319 Y1.5395 +G01 X-2.3337 Y1.5395 +G01 X-2.3481 Y1.5395 +G01 X-2.3543 Y1.5395 +G01 X-2.3816 Y1.5484 +G01 X-2.4048 Y1.5652 +G01 X-2.4216 Y1.5884 +G01 X-2.4305 Y1.6157 +G01 X-2.4305 Y1.6219 +G01 X-2.4305 Y1.6298 +G01 X-2.4435 Y1.6428 +G01 X-2.4435 Y1.6865 +G01 X-2.4595 Y1.6865 +G01 X-2.4595 Y1.6019 +G01 X-2.4657 Y1.5871 +G01 X-2.4771 Y1.5757 +G01 X-2.4795 Y1.5747 +G01 X-2.4795 Y1.4481 +G00 Z0.1000 +G00 X-2.7135 Y1.5878 +G01 Z-0.0070 F10 +G01 X-2.7135 Y1.6322 F20 +G01 X-2.6822 Y1.6635 +G01 X-2.6378 Y1.6635 +G01 X-2.6248 Y1.6505 +G01 X-2.5405 Y1.6505 +G01 X-2.5405 Y1.7019 +G01 X-2.5405 Y1.7100 +G01 X-2.5405 Y1.7181 +G01 X-2.5405 Y1.7240 +G01 X-2.5298 Y1.7499 +G01 X-2.5099 Y1.7698 +G01 X-2.4840 Y1.7805 +G01 X-2.4781 Y1.7805 +G01 X-2.4752 Y1.7805 +G01 X-2.4661 Y1.7895 +G01 X-2.5219 Y1.7895 +G01 X-2.5300 Y1.7895 +G01 X-2.5315 Y1.7894 +G01 X-2.5343 Y1.7885 +G01 X-2.5367 Y1.7867 +G01 X-2.5385 Y1.7843 +G01 X-2.5394 Y1.7815 +G01 X-2.5395 Y1.7800 +G01 X-2.5395 Y1.7781 +G01 X-2.5395 Y1.7765 +G01 X-2.5395 Y1.7619 +G01 X-2.5395 Y1.7557 +G01 X-2.5484 Y1.7284 +G01 X-2.5652 Y1.7052 +G01 X-2.5884 Y1.6884 +G01 X-2.6157 Y1.6795 +G01 X-2.6219 Y1.6795 +G01 X-2.6348 Y1.6795 +G01 X-2.6478 Y1.6665 +G01 X-2.6922 Y1.6665 +G01 X-2.7052 Y1.6795 +G01 X-2.7219 Y1.6795 +G01 X-2.7300 Y1.6795 +G01 X-2.7315 Y1.6794 +G01 X-2.7343 Y1.6785 +G01 X-2.7367 Y1.6767 +G01 X-2.7385 Y1.6743 +G01 X-2.7394 Y1.6715 +G01 X-2.7395 Y1.6700 +G01 X-2.7395 Y1.6631 +G01 X-2.7395 Y1.6619 +G01 X-2.7395 Y1.5919 +G01 X-2.7395 Y1.5840 +G01 X-2.7518 Y1.5544 +G01 X-2.7744 Y1.5318 +G01 X-2.8040 Y1.5195 +G01 X-2.8119 Y1.5195 +G01 X-2.8200 Y1.5195 +G01 X-2.8281 Y1.5195 +G01 X-2.9495 Y1.5195 +G01 X-2.9495 Y1.4720 +G01 X-2.9492 Y1.4729 +G01 X-2.9329 Y1.4892 +G01 X-2.9115 Y1.4980 +G01 X-2.8885 Y1.4980 +G01 X-2.8671 Y1.4892 +G01 X-2.8585 Y1.4805 +G01 X-2.5605 Y1.4805 +G01 X-2.5605 Y1.5695 +G01 X-2.6248 Y1.5695 +G01 X-2.6378 Y1.5565 +G01 X-2.6822 Y1.5565 +G01 X-2.7135 Y1.5878 +G00 Z0.1000 +G00 X-1.1476 Y0.9797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y0.9646 F20 +G01 X-1.1739 Y0.9600 +G01 X-1.1627 Y0.9554 +G01 X-1.1476 Y0.9403 +G01 X-1.1405 Y0.9230 +G01 X-1.1405 Y0.9970 +G01 X-1.1476 Y0.9797 +G00 Z0.1000 +G00 X-1.1476 Y1.0797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y1.0646 F20 +G01 X-1.1739 Y1.0600 +G01 X-1.1627 Y1.0554 +G01 X-1.1476 Y1.0403 +G01 X-1.1405 Y1.0230 +G01 X-1.1405 Y1.0970 +G01 X-1.1476 Y1.0797 +G00 Z0.1000 +G00 X-1.1476 Y1.1797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y1.1646 F20 +G01 X-1.1739 Y1.1600 +G01 X-1.1627 Y1.1554 +G01 X-1.1476 Y1.1403 +G01 X-1.1405 Y1.1230 +G01 X-1.1405 Y1.1970 +G01 X-1.1476 Y1.1797 +G00 Z0.1000 +G00 X-1.1476 Y1.2797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y1.2646 F20 +G01 X-1.1739 Y1.2600 +G01 X-1.1627 Y1.2554 +G01 X-1.1476 Y1.2403 +G01 X-1.1405 Y1.2230 +G01 X-1.1405 Y1.2970 +G01 X-1.1476 Y1.2797 +G00 Z0.1000 +G00 X-1.1476 Y1.3797 +G01 Z-0.0070 F10 +G01 X-1.1627 Y1.3646 F20 +G01 X-1.1739 Y1.3600 +G01 X-1.1627 Y1.3554 +G01 X-1.1476 Y1.3403 +G01 X-1.1405 Y1.3230 +G01 X-1.1405 Y1.3970 +G01 X-1.1476 Y1.3797 +G00 Z0.1000 +G00 X-1.0524 Y1.3403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y1.3554 F20 +G01 X-1.0261 Y1.3600 +G01 X-1.0373 Y1.3646 +G01 X-1.0524 Y1.3797 +G01 X-1.0595 Y1.3970 +G01 X-1.0595 Y1.3230 +G01 X-1.0524 Y1.3403 +G00 Z0.1000 +G00 X-1.0524 Y1.2403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y1.2554 F20 +G01 X-1.0261 Y1.2600 +G01 X-1.0373 Y1.2646 +G01 X-1.0524 Y1.2797 +G01 X-1.0595 Y1.2970 +G01 X-1.0595 Y1.2230 +G01 X-1.0524 Y1.2403 +G00 Z0.1000 +G00 X-1.0524 Y1.1403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y1.1554 F20 +G01 X-1.0261 Y1.1600 +G01 X-1.0373 Y1.1646 +G01 X-1.0524 Y1.1797 +G01 X-1.0595 Y1.1970 +G01 X-1.0595 Y1.1230 +G01 X-1.0524 Y1.1403 +G00 Z0.1000 +G00 X-1.0524 Y1.0403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y1.0554 F20 +G01 X-1.0261 Y1.0600 +G01 X-1.0373 Y1.0646 +G01 X-1.0524 Y1.0797 +G01 X-1.0595 Y1.0970 +G01 X-1.0595 Y1.0230 +G01 X-1.0524 Y1.0403 +G00 Z0.1000 +G00 X-1.0524 Y0.9403 +G01 Z-0.0070 F10 +G01 X-1.0373 Y0.9554 F20 +G01 X-1.0261 Y0.9600 +G01 X-1.0373 Y0.9646 +G01 X-1.0524 Y0.9797 +G01 X-1.0595 Y0.9970 +G01 X-1.0595 Y0.9230 +G01 X-1.0524 Y0.9403 +G00 Z0.1000 +G00 X-1.0594 Y0.8585 +G01 Z-0.0070 F10 +G01 X-1.0585 Y0.8557 F20 +G01 X-1.0567 Y0.8533 +G01 X-1.0543 Y0.8515 +G01 X-1.0515 Y0.8506 +G01 X-1.0500 Y0.8505 +G01 X-1.0429 Y0.8505 +G01 X-1.0422 Y0.8505 +G01 X-1.0373 Y0.8554 +G01 X-1.0261 Y0.8600 +G01 X-1.0373 Y0.8646 +G01 X-1.0524 Y0.8797 +G01 X-1.0595 Y0.8970 +G01 X-1.0595 Y0.8600 +G01 X-1.0594 Y0.8585 +G00 Z0.1000 +G00 X-3.0281 Y1.6905 +G01 Z-0.0070 F10 +G01 X-3.0200 Y1.6905 F20 +G01 X-3.0119 Y1.6905 +G01 X-2.9105 Y1.6905 +G01 X-2.9105 Y1.7616 +G01 X-2.9218 Y1.7344 +G01 X-2.9444 Y1.7118 +G01 X-2.9740 Y1.6995 +G01 X-2.9819 Y1.6995 +G01 X-2.9893 Y1.6995 +G01 X-2.9900 Y1.6995 +G01 X-2.9981 Y1.6995 +G01 X-3.1100 Y1.6995 +G01 X-3.1115 Y1.6994 +G01 X-3.1143 Y1.6985 +G01 X-3.1167 Y1.6967 +G01 X-3.1185 Y1.6943 +G01 X-3.1194 Y1.6915 +G01 X-3.1195 Y1.6900 +G01 X-3.1195 Y1.6831 +G01 X-3.1195 Y1.6819 +G01 X-3.1195 Y1.6452 +G01 X-3.1065 Y1.6322 +G01 X-3.1065 Y1.6266 +G01 X-3.1016 Y1.6416 +G01 X-3.0848 Y1.6648 +G01 X-3.0616 Y1.6816 +G01 X-3.0343 Y1.6905 +G01 X-3.0281 Y1.6905 +G00 Z0.1000 +G00 X-2.3443 Y1.6215 +G01 Z-0.0070 F10 +G01 X-2.3415 Y1.6206 F20 +G01 X-2.3400 Y1.6205 +G01 X-2.3336 Y1.6205 +G01 X-2.3319 Y1.6205 +G01 X-1.8419 Y1.6205 +G01 X-1.8340 Y1.6205 +G01 X-1.8044 Y1.6082 +G01 X-1.7818 Y1.5856 +G01 X-1.7695 Y1.5560 +G01 X-1.7695 Y1.5481 +G01 X-1.7695 Y1.5400 +G01 X-1.7695 Y1.5319 +G01 X-1.7695 Y1.3505 +G01 X-1.7619 Y1.3505 +G01 X-1.6481 Y1.3505 +G01 X-1.6319 Y1.3505 +G01 X-1.5436 Y1.3505 +G01 X-1.5337 Y1.3604 +G01 X-1.5118 Y1.3695 +G01 X-1.4882 Y1.3695 +G01 X-1.4663 Y1.3604 +G01 X-1.4505 Y1.3446 +G01 X-1.4505 Y1.4019 +G01 X-1.4505 Y1.4100 +G01 X-1.4506 Y1.4115 +G01 X-1.4515 Y1.4143 +G01 X-1.4533 Y1.4167 +G01 X-1.4557 Y1.4185 +G01 X-1.4585 Y1.4194 +G01 X-1.4600 Y1.4195 +G01 X-1.6519 Y1.4195 +G01 X-1.6534 Y1.4195 +G01 X-1.6681 Y1.4195 +G01 X-1.6743 Y1.4195 +G01 X-1.7016 Y1.4284 +G01 X-1.7248 Y1.4452 +G01 X-1.7416 Y1.4684 +G01 X-1.7505 Y1.4957 +G01 X-1.7505 Y1.5019 +G01 X-1.7505 Y1.6465 +G01 X-1.7922 Y1.6465 +G01 X-1.8052 Y1.6595 +G01 X-2.0319 Y1.6595 +G01 X-2.0400 Y1.6595 +G01 X-2.0412 Y1.6595 +G01 X-2.0481 Y1.6595 +G01 X-2.0543 Y1.6595 +G01 X-2.0816 Y1.6684 +G01 X-2.1048 Y1.6852 +G01 X-2.1216 Y1.7084 +G01 X-2.1305 Y1.7357 +G01 X-2.1305 Y1.7419 +G01 X-2.1305 Y1.7496 +G01 X-2.1305 Y1.7500 +G01 X-2.1305 Y1.7581 +G01 X-2.1305 Y1.8695 +G01 X-2.3726 Y1.8695 +G01 X-2.3484 Y1.8616 +G01 X-2.3252 Y1.8448 +G01 X-2.3084 Y1.8216 +G01 X-2.2995 Y1.7943 +G01 X-2.2995 Y1.7881 +G01 X-2.2995 Y1.7805 +G01 X-2.2505 Y1.7805 +G01 X-2.2337 Y1.7973 +G01 X-2.1863 Y1.7973 +G01 X-2.1527 Y1.7637 +G01 X-2.1527 Y1.7163 +G01 X-2.1863 Y1.6827 +G01 X-2.2337 Y1.6827 +G01 X-2.2505 Y1.6995 +G01 X-2.3048 Y1.6995 +G01 X-2.3178 Y1.6865 +G01 X-2.3365 Y1.6865 +G01 X-2.3365 Y1.6428 +G01 X-2.3495 Y1.6299 +G01 X-2.3494 Y1.6285 +G01 X-2.3485 Y1.6257 +G01 X-2.3467 Y1.6233 +G01 X-2.3443 Y1.6215 +G00 Z0.1000 +G00 X-2.6922 Y1.3035 +G01 Z-0.0070 F10 +G01 X-2.6478 Y1.3035 F20 +G01 X-2.6165 Y1.2722 +G01 X-2.6165 Y1.2278 +G01 X-2.6478 Y1.1965 +G01 X-2.6772 Y1.1965 +G01 X-2.6999 Y1.1919 +G01 X-2.7298 Y1.1979 +G01 X-2.7323 Y1.1995 +G01 X-3.0119 Y1.1995 +G01 X-3.0129 Y1.1995 +G01 X-3.0281 Y1.1995 +G01 X-3.0343 Y1.1995 +G01 X-3.0616 Y1.2084 +G01 X-3.0848 Y1.2252 +G01 X-3.1016 Y1.2484 +G01 X-3.1105 Y1.2757 +G01 X-3.1105 Y1.2819 +G01 X-3.1105 Y1.5838 +G01 X-3.1195 Y1.5748 +G01 X-3.1195 Y0.9600 +G01 X-3.1194 Y0.9585 +G01 X-3.1185 Y0.9557 +G01 X-3.1167 Y0.9533 +G01 X-3.1143 Y0.9515 +G01 X-3.1115 Y0.9506 +G01 X-3.1100 Y0.9505 +G01 X-3.1050 Y0.9505 +G01 X-3.1019 Y0.9505 +G01 X-2.5505 Y0.9505 +G01 X-2.5337 Y0.9673 +G01 X-2.4863 Y0.9673 +G01 X-2.4694 Y0.9505 +G01 X-2.1681 Y0.9505 +G01 X-2.1600 Y0.9505 +G01 X-2.1585 Y0.9506 +G01 X-2.1557 Y0.9515 +G01 X-2.1533 Y0.9533 +G01 X-2.1515 Y0.9557 +G01 X-2.1506 Y0.9585 +G01 X-2.1505 Y0.9600 +G01 X-2.1505 Y0.9970 +G01 X-2.1576 Y0.9797 +G01 X-2.1727 Y0.9646 +G01 X-2.1924 Y0.9565 +G01 X-2.3276 Y0.9565 +G01 X-2.3473 Y0.9646 +G01 X-2.3522 Y0.9695 +G01 X-2.8919 Y0.9695 +G01 X-2.8929 Y0.9695 +G01 X-2.9081 Y0.9695 +G01 X-2.9143 Y0.9695 +G01 X-2.9416 Y0.9784 +G01 X-2.9648 Y0.9952 +G01 X-2.9816 Y1.0184 +G01 X-2.9905 Y1.0457 +G01 X-2.9905 Y1.0519 +G01 X-2.9905 Y1.0948 +G01 X-3.0035 Y1.1078 +G01 X-3.0035 Y1.1522 +G01 X-2.9722 Y1.1835 +G01 X-2.9278 Y1.1835 +G01 X-2.8965 Y1.1522 +G01 X-2.8965 Y1.1078 +G01 X-2.9095 Y1.0948 +G01 X-2.9095 Y1.0600 +G01 X-2.9094 Y1.0585 +G01 X-2.9085 Y1.0557 +G01 X-2.9067 Y1.0533 +G01 X-2.9043 Y1.0515 +G01 X-2.9015 Y1.0506 +G01 X-2.9000 Y1.0505 +G01 X-2.8929 Y1.0505 +G01 X-2.8919 Y1.0505 +G01 X-2.3522 Y1.0505 +G01 X-2.3473 Y1.0554 +G01 X-2.3361 Y1.0600 +G01 X-2.3473 Y1.0646 +G01 X-2.3624 Y1.0797 +G01 X-2.3705 Y1.0994 +G01 X-2.3705 Y1.1206 +G01 X-2.3624 Y1.1403 +G01 X-2.3473 Y1.1554 +G01 X-2.3361 Y1.1600 +G01 X-2.3473 Y1.1646 +G01 X-2.3522 Y1.1695 +G01 X-2.4619 Y1.1695 +G01 X-2.4633 Y1.1695 +G01 X-2.4781 Y1.1695 +G01 X-2.4843 Y1.1695 +G01 X-2.5116 Y1.1784 +G01 X-2.5348 Y1.1952 +G01 X-2.5516 Y1.2184 +G01 X-2.5605 Y1.2457 +G01 X-2.5605 Y1.2519 +G01 X-2.5605 Y1.3995 +G01 X-2.8585 Y1.3995 +G01 X-2.8671 Y1.3908 +G01 X-2.8885 Y1.3820 +G01 X-2.9115 Y1.3820 +G01 X-2.9329 Y1.3908 +G01 X-2.9492 Y1.4071 +G01 X-2.9495 Y1.4080 +G01 X-2.9495 Y1.3835 +G01 X-2.9278 Y1.3835 +G01 X-2.8965 Y1.3522 +G01 X-2.8965 Y1.3078 +G01 X-2.9238 Y1.2805 +G01 X-2.7240 Y1.2805 +G01 X-2.7200 Y1.2813 +G01 X-2.7160 Y1.2805 +G01 X-2.7152 Y1.2805 +G01 X-2.6922 Y1.3035 +G00 Z0.1000 +G00 X-3.0294 Y1.2885 +G01 Z-0.0070 F10 +G01 X-3.0285 Y1.2857 F20 +G01 X-3.0267 Y1.2833 +G01 X-3.0243 Y1.2815 +G01 X-3.0215 Y1.2806 +G01 X-3.0200 Y1.2805 +G01 X-3.0129 Y1.2805 +G01 X-3.0119 Y1.2805 +G01 X-2.9761 Y1.2805 +G01 X-3.0035 Y1.3078 +G01 X-3.0035 Y1.3097 +G01 X-3.0182 Y1.3244 +G01 X-3.0295 Y1.3516 +G01 X-3.0295 Y1.2900 +G01 X-3.0294 Y1.2885 +G00 Z0.1000 +G00 X-3.0198 Y1.5699 +G01 Z-0.0070 F10 +G01 X-3.0198 Y1.5699 F20 +G01 X-2.9999 Y1.5898 +G01 X-2.9740 Y1.6005 +G01 X-2.9681 Y1.6005 +G01 X-2.8281 Y1.6005 +G01 X-2.8205 Y1.6005 +G01 X-2.8205 Y1.6619 +G01 X-2.8205 Y1.6631 +G01 X-2.8205 Y1.6781 +G01 X-2.8205 Y1.6843 +G01 X-2.8116 Y1.7116 +G01 X-2.7948 Y1.7348 +G01 X-2.7716 Y1.7516 +G01 X-2.7443 Y1.7605 +G01 X-2.7381 Y1.7605 +G01 X-2.7337 Y1.7605 +G01 X-2.7300 Y1.7605 +G01 X-2.7219 Y1.7605 +G01 X-2.7052 Y1.7605 +G01 X-2.6957 Y1.7700 +G01 X-2.7052 Y1.7795 +G01 X-2.8119 Y1.7795 +G01 X-2.8200 Y1.7795 +G01 X-2.8215 Y1.7794 +G01 X-2.8243 Y1.7785 +G01 X-2.8267 Y1.7767 +G01 X-2.8285 Y1.7743 +G01 X-2.8294 Y1.7715 +G01 X-2.8295 Y1.7700 +G01 X-2.8295 Y1.6881 +G01 X-2.8295 Y1.6861 +G01 X-2.8295 Y1.6719 +G01 X-2.8295 Y1.6660 +G01 X-2.8402 Y1.6401 +G01 X-2.8601 Y1.6202 +G01 X-2.8860 Y1.6095 +G01 X-2.8919 Y1.6095 +G01 X-3.0119 Y1.6095 +G01 X-3.0200 Y1.6095 +G01 X-3.0215 Y1.6094 +G01 X-3.0243 Y1.6085 +G01 X-3.0267 Y1.6067 +G01 X-3.0285 Y1.6043 +G01 X-3.0294 Y1.6015 +G01 X-3.0295 Y1.6000 +G01 X-3.0295 Y1.5464 +G01 X-3.0198 Y1.5699 +G00 Z0.1000 +G00 X-2.8281 Y1.8605 +G01 Z-0.0070 F10 +G01 X-2.8204 Y1.8605 F20 +G01 X-2.8200 Y1.8605 +G01 X-2.8119 Y1.8605 +G01 X-2.7052 Y1.8605 +G01 X-2.6961 Y1.8695 +G01 X-2.9000 Y1.8695 +G01 X-2.9015 Y1.8694 +G01 X-2.9043 Y1.8685 +G01 X-2.9067 Y1.8667 +G01 X-2.9085 Y1.8643 +G01 X-2.9094 Y1.8615 +G01 X-2.9095 Y1.8600 +G01 X-2.9095 Y1.8550 +G01 X-2.9095 Y1.8519 +G01 X-2.9095 Y1.7874 +G01 X-2.9016 Y1.8116 +G01 X-2.8848 Y1.8348 +G01 X-2.8616 Y1.8516 +G01 X-2.8343 Y1.8605 +G01 X-2.8281 Y1.8605 +G00 Z0.1000 +G00 X-2.3900 Y1.7657 +G01 Z-0.0070 F10 +G01 X-2.3805 Y1.7752 F20 +G01 X-2.3805 Y1.7800 +G01 X-2.3806 Y1.7815 +G01 X-2.3815 Y1.7843 +G01 X-2.3833 Y1.7867 +G01 X-2.3857 Y1.7885 +G01 X-2.3885 Y1.7894 +G01 X-2.3900 Y1.7895 +G01 X-2.4138 Y1.7895 +G01 X-2.3900 Y1.7657 +G00 Z0.1000 +G00 X-1.7784 Y0.8384 +G01 Z-0.0070 F10 +G01 X-1.7784 Y0.8384 F20 +G01 X-1.7952 Y0.8152 +G01 X-1.8184 Y0.7984 +G01 X-1.8426 Y0.7905 +G01 X-1.7800 Y0.7905 +G01 X-1.7785 Y0.7906 +G01 X-1.7757 Y0.7915 +G01 X-1.7733 Y0.7933 +G01 X-1.7715 Y0.7957 +G01 X-1.7706 Y0.7985 +G01 X-1.7705 Y0.8000 +G01 X-1.7705 Y0.8626 +G01 X-1.7784 Y0.8384 +G00 Z0.1000 +G00 X-1.6981 Y1.0505 +G01 Z-0.0070 F10 +G01 X-1.6873 Y1.0505 F20 +G01 X-1.6819 Y1.0505 +G01 X-1.3422 Y1.0505 +G01 X-1.3373 Y1.0554 +G01 X-1.3261 Y1.0600 +G01 X-1.3373 Y1.0646 +G01 X-1.3422 Y1.0695 +G01 X-1.7695 Y1.0695 +G01 X-1.7695 Y0.9884 +G01 X-1.7582 Y1.0156 +G01 X-1.7356 Y1.0382 +G01 X-1.7060 Y1.0505 +G01 X-1.6981 Y1.0505 +G00 Z0.1000 +G00 X-1.6081 Y0.9505 +G01 Z-0.0070 F10 +G01 X-1.6006 Y0.9505 F20 +G01 X-1.6000 Y0.9505 +G01 X-1.5919 Y0.9505 +G01 X-1.3422 Y0.9505 +G01 X-1.3373 Y0.9554 +G01 X-1.3261 Y0.9600 +G01 X-1.3373 Y0.9646 +G01 X-1.3422 Y0.9695 +G01 X-1.6819 Y0.9695 +G01 X-1.6874 Y0.9695 +G01 X-1.6895 Y0.9695 +G01 X-1.6895 Y0.9646 +G01 X-1.6895 Y0.9619 +G01 X-1.6895 Y0.8774 +G01 X-1.6816 Y0.9016 +G01 X-1.6648 Y0.9248 +G01 X-1.6416 Y0.9416 +G01 X-1.6143 Y0.9505 +G01 X-1.6081 Y0.9505 +G00 Z0.1000 +G00 X-0.4195 Y0.2857 +G01 Z-0.0070 F10 +G01 X-0.4195 Y0.2857 F20 +G01 X-0.4284 Y0.2584 +G01 X-0.4452 Y0.2352 +G01 X-0.4684 Y0.2184 +G01 X-0.4957 Y0.2095 +G01 X-0.5019 Y0.2095 +G01 X-0.5094 Y0.2095 +G01 X-0.5100 Y0.2095 +G01 X-0.5181 Y0.2095 +G01 X-1.0400 Y0.2095 +G01 X-1.0415 Y0.2094 +G01 X-1.0443 Y0.2085 +G01 X-1.0467 Y0.2067 +G01 X-1.0485 Y0.2043 +G01 X-1.0494 Y0.2015 +G01 X-1.0495 Y0.2000 +G01 X-1.0495 Y0.1930 +G01 X-1.0495 Y0.1919 +G01 X-1.0495 Y0.1419 +G01 X-1.0495 Y0.1357 +G01 X-1.0584 Y0.1084 +G01 X-1.0752 Y0.0852 +G01 X-1.0984 Y0.0684 +G01 X-1.1257 Y0.0595 +G01 X-1.1319 Y0.0595 +G01 X-1.1400 Y0.0595 +G01 X-1.1481 Y0.0595 +G01 X-1.6081 Y0.0595 +G01 X-1.6143 Y0.0595 +G01 X-1.6416 Y0.0684 +G01 X-1.6648 Y0.0852 +G01 X-1.6816 Y0.1084 +G01 X-1.6905 Y0.1357 +G01 X-1.6905 Y0.1419 +G01 X-1.6905 Y0.1498 +G01 X-1.6905 Y0.1500 +G01 X-1.6905 Y0.1581 +G01 X-1.6905 Y0.7826 +G01 X-1.6984 Y0.7584 +G01 X-1.7152 Y0.7352 +G01 X-1.7384 Y0.7184 +G01 X-1.7534 Y0.7135 +G01 X-1.7278 Y0.7135 +G01 X-1.6965 Y0.6822 +G01 X-1.6965 Y0.6378 +G01 X-1.7278 Y0.6065 +G01 X-1.7722 Y0.6065 +G01 X-1.7852 Y0.6195 +G01 X-1.8685 Y0.6195 +G01 X-1.8427 Y0.5937 +G01 X-1.8427 Y0.5550 +G01 X-1.8318 Y0.5595 +G01 X-1.8082 Y0.5595 +G01 X-1.7863 Y0.5504 +G01 X-1.7696 Y0.5337 +G01 X-1.7605 Y0.5118 +G01 X-1.7605 Y0.4882 +G01 X-1.7696 Y0.4663 +G01 X-1.7795 Y0.4564 +G01 X-1.7795 Y0.3836 +G01 X-1.7696 Y0.3737 +G01 X-1.7605 Y0.3518 +G01 X-1.7605 Y0.3282 +G01 X-1.7696 Y0.3063 +G01 X-1.7863 Y0.2896 +G01 X-1.8082 Y0.2805 +G01 X-1.8318 Y0.2805 +G01 X-1.8537 Y0.2896 +G01 X-1.8636 Y0.2995 +G01 X-1.9600 Y0.2995 +G01 X-1.9615 Y0.2994 +G01 X-1.9643 Y0.2985 +G01 X-1.9596 Y0.2937 +G01 X-1.9505 Y0.2718 +G01 X-1.9505 Y0.2482 +G01 X-1.9596 Y0.2263 +G01 X-1.9763 Y0.2096 +G01 X-1.9982 Y0.2005 +G01 X-2.0218 Y0.2005 +G01 X-2.0437 Y0.2096 +G01 X-2.0604 Y0.2263 +G01 X-2.0695 Y0.2482 +G01 X-2.0695 Y0.2718 +G01 X-2.0604 Y0.2937 +G01 X-2.0505 Y0.3036 +G01 X-2.0505 Y0.3043 +G01 X-2.0416 Y0.3316 +G01 X-2.0248 Y0.3548 +G01 X-2.0016 Y0.3716 +G01 X-1.9743 Y0.3805 +G01 X-1.9681 Y0.3805 +G01 X-1.8636 Y0.3805 +G01 X-1.8605 Y0.3836 +G01 X-1.8605 Y0.4564 +G01 X-1.8636 Y0.4595 +G01 X-1.8643 Y0.4595 +G01 X-1.8916 Y0.4684 +G01 X-1.9148 Y0.4852 +G01 X-1.9316 Y0.5084 +G01 X-1.9375 Y0.5265 +G01 X-1.9573 Y0.5463 +G01 X-1.9573 Y0.5937 +G01 X-1.9315 Y0.6195 +G01 X-1.9664 Y0.6195 +G01 X-1.9763 Y0.6096 +G01 X-1.9982 Y0.6005 +G01 X-2.0218 Y0.6005 +G01 X-2.0437 Y0.6096 +G01 X-2.0536 Y0.6195 +G01 X-2.0900 Y0.6195 +G01 X-2.0915 Y0.6194 +G01 X-2.0943 Y0.6185 +G01 X-2.0967 Y0.6167 +G01 X-2.0985 Y0.6143 +G01 X-2.0994 Y0.6115 +G01 X-2.0995 Y0.6100 +G01 X-2.0995 Y0.6019 +G01 X-2.0995 Y0.2952 +G01 X-2.0865 Y0.2822 +G01 X-2.0865 Y0.2378 +G01 X-2.1178 Y0.2065 +G01 X-2.1622 Y0.2065 +G01 X-2.1935 Y0.2378 +G01 X-2.1935 Y0.2822 +G01 X-2.1805 Y0.2952 +G01 X-2.1805 Y0.6019 +G01 X-2.1805 Y0.6100 +G01 X-2.1805 Y0.6131 +G01 X-2.1805 Y0.6181 +G01 X-2.1805 Y0.6243 +G01 X-2.1716 Y0.6516 +G01 X-2.1548 Y0.6748 +G01 X-2.1316 Y0.6916 +G01 X-2.1043 Y0.7005 +G01 X-2.0981 Y0.7005 +G01 X-2.0536 Y0.7005 +G01 X-2.0446 Y0.7095 +G01 X-2.1819 Y0.7095 +G01 X-2.1895 Y0.7095 +G01 X-2.1895 Y0.5981 +G01 X-2.1895 Y0.5967 +G01 X-2.1895 Y0.5819 +G01 X-2.1895 Y0.5740 +G01 X-2.2018 Y0.5444 +G01 X-2.2244 Y0.5218 +G01 X-2.2540 Y0.5095 +G01 X-2.2619 Y0.5095 +G01 X-2.2696 Y0.5095 +G01 X-2.2700 Y0.5095 +G01 X-2.2781 Y0.5095 +G01 X-2.4785 Y0.5095 +G01 X-2.4527 Y0.4837 +G01 X-2.4527 Y0.4363 +G01 X-2.4595 Y0.4294 +G01 X-2.4595 Y0.2700 +G01 X-2.4595 Y0.1905 +G01 X-2.4514 Y0.1905 +G01 X-2.4500 Y0.1905 +G01 X-1.8735 Y0.1905 +G01 X-1.8735 Y0.2222 +G01 X-1.8422 Y0.2535 +G01 X-1.7978 Y0.2535 +G01 X-1.7665 Y0.2222 +G01 X-1.7665 Y0.1778 +G01 X-1.7695 Y0.1748 +G01 X-1.7695 Y0.1741 +G01 X-1.7793 Y0.1438 +G01 X-1.7981 Y0.1181 +G01 X-1.8238 Y0.0993 +G01 X-1.8541 Y0.0895 +G01 X-1.8600 Y0.0895 +G01 X-2.4500 Y0.0895 +G01 X-2.4514 Y0.0895 +G01 X-2.4700 Y0.0895 +G01 X-2.4759 Y0.0895 +G01 X-2.5062 Y0.0993 +G01 X-2.5319 Y0.1181 +G01 X-2.5507 Y0.1438 +G01 X-2.5605 Y0.1741 +G01 X-2.5605 Y0.1900 +G01 X-2.5605 Y0.2195 +G01 X-2.6048 Y0.2195 +G01 X-2.6178 Y0.2065 +G01 X-2.6622 Y0.2065 +G01 X-2.6935 Y0.2378 +G01 X-2.6935 Y0.2822 +G01 X-2.6622 Y0.3135 +G01 X-2.6178 Y0.3135 +G01 X-2.6048 Y0.3005 +G01 X-2.5605 Y0.3005 +G01 X-2.5605 Y0.4294 +G01 X-2.5673 Y0.4363 +G01 X-2.5673 Y0.4837 +G01 X-2.5415 Y0.5095 +G01 X-2.8076 Y0.5095 +G01 X-2.8172 Y0.4999 +G01 X-2.8396 Y0.4906 +G01 X-3.0004 Y0.4906 +G01 X-3.0228 Y0.4999 +G01 X-3.0400 Y0.5170 +G01 X-3.0492 Y0.5394 +G01 X-3.0492 Y0.5637 +G01 X-3.0400 Y0.5861 +G01 X-3.0228 Y0.6033 +G01 X-3.0004 Y0.6126 +G01 X-2.8396 Y0.6126 +G01 X-2.8172 Y0.6033 +G01 X-2.8044 Y0.5905 +G01 X-2.2781 Y0.5905 +G01 X-2.2705 Y0.5905 +G01 X-2.2705 Y0.5967 +G01 X-2.2705 Y0.5981 +G01 X-2.2705 Y0.7181 +G01 X-2.2705 Y0.7260 +G01 X-2.2582 Y0.7556 +G01 X-2.2356 Y0.7782 +G01 X-2.2084 Y0.7895 +G01 X-2.2719 Y0.7895 +G01 X-2.2800 Y0.7895 +G01 X-2.2815 Y0.7894 +G01 X-2.2843 Y0.7885 +G01 X-2.2867 Y0.7867 +G01 X-2.2885 Y0.7843 +G01 X-2.2894 Y0.7815 +G01 X-2.2895 Y0.7800 +G01 X-2.2895 Y0.7519 +G01 X-2.2895 Y0.7480 +G01 X-2.2987 Y0.7257 +G01 X-2.3157 Y0.7087 +G01 X-2.3380 Y0.6995 +G01 X-2.3419 Y0.6995 +G01 X-2.3500 Y0.6995 +G01 X-2.3581 Y0.6995 +G01 X-2.6448 Y0.6995 +G01 X-2.6478 Y0.6965 +G01 X-2.6922 Y0.6965 +G01 X-2.7052 Y0.7095 +G01 X-2.8044 Y0.7095 +G01 X-2.8172 Y0.6967 +G01 X-2.8396 Y0.6874 +G01 X-3.0004 Y0.6874 +G01 X-3.0228 Y0.6967 +G01 X-3.0400 Y0.7139 +G01 X-3.0492 Y0.7363 +G01 X-3.0492 Y0.7606 +G01 X-3.0400 Y0.7830 +G01 X-3.0228 Y0.8001 +G01 X-3.0004 Y0.8094 +G01 X-2.8396 Y0.8094 +G01 X-2.8172 Y0.8001 +G01 X-2.8076 Y0.7905 +G01 X-2.7052 Y0.7905 +G01 X-2.6922 Y0.8035 +G01 X-2.6478 Y0.8035 +G01 X-2.6248 Y0.7805 +G01 X-2.3705 Y0.7805 +G01 X-2.3705 Y0.7881 +G01 X-2.3705 Y0.7943 +G01 X-2.3616 Y0.8216 +G01 X-2.3448 Y0.8448 +G01 X-2.3216 Y0.8616 +G01 X-2.2974 Y0.8695 +G01 X-2.4694 Y0.8695 +G01 X-2.4863 Y0.8527 +G01 X-2.5337 Y0.8527 +G01 X-2.5505 Y0.8695 +G01 X-3.1019 Y0.8695 +G01 X-3.1051 Y0.8695 +G01 X-3.1181 Y0.8695 +G01 X-3.1243 Y0.8695 +G01 X-3.1516 Y0.8784 +G01 X-3.1748 Y0.8952 +G01 X-3.1916 Y0.9184 +G01 X-3.2005 Y0.9457 +G01 X-3.2005 Y0.9519 +G01 X-3.2005 Y1.5748 +G01 X-3.2135 Y1.5878 +G01 X-3.2135 Y1.6322 +G01 X-3.2005 Y1.6452 +G01 X-3.2005 Y1.6819 +G01 X-3.2005 Y1.6831 +G01 X-3.2005 Y1.6981 +G01 X-3.2005 Y1.7043 +G01 X-3.1916 Y1.7316 +G01 X-3.1748 Y1.7548 +G01 X-3.1516 Y1.7716 +G01 X-3.1243 Y1.7805 +G01 X-3.1181 Y1.7805 +G01 X-3.1137 Y1.7805 +G01 X-3.1100 Y1.7805 +G01 X-2.9981 Y1.7805 +G01 X-2.9905 Y1.7805 +G01 X-2.9905 Y1.8519 +G01 X-2.9905 Y1.8551 +G01 X-2.9905 Y1.8681 +G01 X-2.9905 Y1.8743 +G01 X-2.9816 Y1.9016 +G01 X-2.9648 Y1.9248 +G01 X-2.9416 Y1.9416 +G01 X-2.9143 Y1.9505 +G01 X-2.9081 Y1.9505 +G01 X-2.0819 Y1.9505 +G01 X-2.0352 Y1.9505 +G01 X-2.0222 Y1.9635 +G01 X-1.9778 Y1.9635 +G01 X-1.9648 Y1.9505 +G01 X-1.7700 Y1.9505 +G01 X-1.7685 Y1.9506 +G01 X-1.7657 Y1.9515 +G01 X-1.7633 Y1.9533 +G01 X-1.7615 Y1.9557 +G01 X-1.7606 Y1.9585 +G01 X-1.7605 Y1.9600 +G01 X-1.7605 Y1.9643 +G01 X-1.7605 Y1.9681 +G01 X-1.7605 Y2.0519 +G01 X-1.7605 Y2.0600 +G01 X-1.7605 Y2.0681 +G01 X-1.7605 Y2.0743 +G01 X-1.7516 Y2.1016 +G01 X-1.7348 Y2.1248 +G01 X-1.7116 Y2.1416 +G01 X-1.6843 Y2.1505 +G01 X-1.6781 Y2.1505 +G01 X-1.2519 Y2.1505 +G01 X-1.2457 Y2.1505 +G01 X-1.2184 Y2.1416 +G01 X-1.1952 Y2.1248 +G01 X-1.1784 Y2.1016 +G01 X-1.1695 Y2.0743 +G01 X-1.1695 Y2.0681 +G01 X-1.1695 Y2.0600 +G01 X-1.1695 Y2.0519 +G01 X-1.1695 Y1.9100 +G01 X-1.1694 Y1.9085 +G01 X-1.1685 Y1.9057 +G01 X-1.1667 Y1.9033 +G01 X-1.1643 Y1.9015 +G01 X-1.1615 Y1.9006 +G01 X-1.1600 Y1.9005 +G01 X-1.1519 Y1.9005 +G01 X-0.8015 Y1.9005 +G01 X-0.7929 Y1.9092 +G01 X-0.7715 Y1.9180 +G01 X-0.7485 Y1.9180 +G01 X-0.7271 Y1.9092 +G01 X-0.7185 Y1.9005 +G01 X-0.2635 Y1.9005 +G01 X-0.2538 Y1.9005 +G01 X-0.2201 Y1.8895 +G01 X-0.1913 Y1.8687 +G01 X-0.1774 Y1.8494 +G01 X-0.1196 Y1.8494 +G01 X-0.0972 Y1.8401 +G01 X-0.0800 Y1.8230 +G01 X-0.0708 Y1.8006 +G01 X-0.0708 Y1.7763 +G01 X-0.0800 Y1.7539 +G01 X-0.0972 Y1.7367 +G01 X-0.1196 Y1.7274 +G01 X-0.2804 Y1.7274 +G01 X-0.3028 Y1.7367 +G01 X-0.3200 Y1.7539 +G01 X-0.3292 Y1.7763 +G01 X-0.3292 Y1.8006 +G01 X-0.3214 Y1.8195 +G01 X-0.7185 Y1.8195 +G01 X-0.7271 Y1.8108 +G01 X-0.7485 Y1.8020 +G01 X-0.7715 Y1.8020 +G01 X-0.7929 Y1.8108 +G01 X-0.8015 Y1.8195 +G01 X-1.1519 Y1.8195 +G01 X-1.1600 Y1.8195 +G01 X-1.1603 Y1.8195 +G01 X-1.1681 Y1.8195 +G01 X-1.1743 Y1.8195 +G01 X-1.2016 Y1.8284 +G01 X-1.2248 Y1.8452 +G01 X-1.2416 Y1.8684 +G01 X-1.2505 Y1.8957 +G01 X-1.2505 Y1.9019 +G01 X-1.2505 Y2.0519 +G01 X-1.2505 Y2.0600 +G01 X-1.2506 Y2.0615 +G01 X-1.2515 Y2.0643 +G01 X-1.2533 Y2.0667 +G01 X-1.2557 Y2.0685 +G01 X-1.2585 Y2.0694 +G01 X-1.2600 Y2.0695 +G01 X-1.6700 Y2.0695 +G01 X-1.6715 Y2.0694 +G01 X-1.6743 Y2.0685 +G01 X-1.6767 Y2.0667 +G01 X-1.6785 Y2.0643 +G01 X-1.6794 Y2.0615 +G01 X-1.6795 Y2.0600 +G01 X-1.6795 Y2.0519 +G01 X-1.6795 Y1.9681 +G01 X-1.6795 Y1.9642 +G01 X-1.6795 Y1.9519 +G01 X-1.6795 Y1.9457 +G01 X-1.6884 Y1.9184 +G01 X-1.7052 Y1.8952 +G01 X-1.7284 Y1.8784 +G01 X-1.7557 Y1.8695 +G01 X-1.7619 Y1.8695 +G01 X-1.9648 Y1.8695 +G01 X-1.9778 Y1.8565 +G01 X-2.0222 Y1.8565 +G01 X-2.0352 Y1.8695 +G01 X-2.0495 Y1.8695 +G01 X-2.0495 Y1.7581 +G01 X-2.0495 Y1.7500 +G01 X-2.0494 Y1.7485 +G01 X-2.0485 Y1.7457 +G01 X-2.0467 Y1.7433 +G01 X-2.0443 Y1.7415 +G01 X-2.0415 Y1.7406 +G01 X-2.0400 Y1.7405 +G01 X-2.0319 Y1.7405 +G01 X-2.0015 Y1.7405 +G01 X-2.0273 Y1.7663 +G01 X-2.0273 Y1.8137 +G01 X-1.9937 Y1.8473 +G01 X-1.9463 Y1.8473 +G01 X-1.9294 Y1.8305 +G01 X-1.6605 Y1.8305 +G01 X-1.6605 Y1.9681 +G01 X-1.6605 Y1.9743 +G01 X-1.6516 Y2.0016 +G01 X-1.6348 Y2.0248 +G01 X-1.6116 Y2.0416 +G01 X-1.5843 Y2.0505 +G01 X-1.5781 Y2.0505 +G01 X-1.5704 Y2.0505 +G01 X-1.5700 Y2.0505 +G01 X-1.5619 Y2.0505 +G01 X-1.4181 Y2.0505 +G01 X-1.4100 Y2.0505 +G01 X-1.4019 Y2.0505 +G01 X-1.3957 Y2.0505 +G01 X-1.3684 Y2.0416 +G01 X-1.3452 Y2.0248 +G01 X-1.3284 Y2.0016 +G01 X-1.3195 Y1.9743 +G01 X-1.3195 Y1.9681 +G01 X-1.3195 Y1.9015 +G01 X-1.3020 Y1.8840 +G01 X-1.3020 Y1.8360 +G01 X-1.3195 Y1.8185 +G01 X-1.3195 Y1.8100 +G01 X-1.3194 Y1.8085 +G01 X-1.3185 Y1.8057 +G01 X-1.3167 Y1.8033 +G01 X-1.3143 Y1.8015 +G01 X-1.3115 Y1.8006 +G01 X-1.3100 Y1.8005 +G01 X-1.3033 Y1.8005 +G01 X-1.3019 Y1.8005 +G01 X-0.6519 Y1.8005 +G01 X-0.6440 Y1.8005 +G01 X-0.6144 Y1.7882 +G01 X-0.5918 Y1.7656 +G01 X-0.5795 Y1.7360 +G01 X-0.5795 Y1.7281 +G01 X-0.5795 Y1.6500 +G01 X-0.5794 Y1.6485 +G01 X-0.5785 Y1.6457 +G01 X-0.5767 Y1.6433 +G01 X-0.5743 Y1.6415 +G01 X-0.5715 Y1.6406 +G01 X-0.5700 Y1.6405 +G01 X-0.5619 Y1.6405 +G01 X-0.3056 Y1.6405 +G01 X-0.3028 Y1.6433 +G01 X-0.2804 Y1.6526 +G01 X-0.1196 Y1.6526 +G01 X-0.0972 Y1.6433 +G01 X-0.0800 Y1.6261 +G01 X-0.0708 Y1.6037 +G01 X-0.0708 Y1.5794 +G01 X-0.0800 Y1.5570 +G01 X-0.0972 Y1.5399 +G01 X-0.1196 Y1.5306 +G01 X-0.2804 Y1.5306 +G01 X-0.3028 Y1.5399 +G01 X-0.3200 Y1.5570 +G01 X-0.3210 Y1.5595 +G01 X-0.5619 Y1.5595 +G01 X-0.5700 Y1.5595 +G01 X-0.5730 Y1.5595 +G01 X-0.5781 Y1.5595 +G01 X-0.5843 Y1.5595 +G01 X-0.6116 Y1.5684 +G01 X-0.6348 Y1.5852 +G01 X-0.6516 Y1.6084 +G01 X-0.6605 Y1.6357 +G01 X-0.6605 Y1.6419 +G01 X-0.6605 Y1.7195 +G01 X-1.3019 Y1.7195 +G01 X-1.3033 Y1.7195 +G01 X-1.3181 Y1.7195 +G01 X-1.3243 Y1.7195 +G01 X-1.3516 Y1.7284 +G01 X-1.3748 Y1.7452 +G01 X-1.3916 Y1.7684 +G01 X-1.4005 Y1.7957 +G01 X-1.4005 Y1.8019 +G01 X-1.4005 Y1.8185 +G01 X-1.4180 Y1.8360 +G01 X-1.4180 Y1.8840 +G01 X-1.4005 Y1.9015 +G01 X-1.4005 Y1.9600 +G01 X-1.4006 Y1.9615 +G01 X-1.4015 Y1.9643 +G01 X-1.4033 Y1.9667 +G01 X-1.4057 Y1.9685 +G01 X-1.4085 Y1.9694 +G01 X-1.4100 Y1.9695 +G01 X-1.4181 Y1.9695 +G01 X-1.5619 Y1.9695 +G01 X-1.5700 Y1.9695 +G01 X-1.5715 Y1.9694 +G01 X-1.5743 Y1.9685 +G01 X-1.5767 Y1.9667 +G01 X-1.5785 Y1.9643 +G01 X-1.5794 Y1.9615 +G01 X-1.5795 Y1.9600 +G01 X-1.5795 Y1.7981 +G01 X-1.5795 Y1.7719 +G01 X-1.5795 Y1.6381 +G01 X-1.5795 Y1.6300 +G01 X-1.5794 Y1.6285 +G01 X-1.5785 Y1.6257 +G01 X-1.5767 Y1.6233 +G01 X-1.5743 Y1.6215 +G01 X-1.5715 Y1.6206 +G01 X-1.5700 Y1.6205 +G01 X-1.5684 Y1.6205 +G01 X-1.5619 Y1.6205 +G01 X-1.1419 Y1.6205 +G01 X-1.1357 Y1.6205 +G01 X-1.1084 Y1.6116 +G01 X-1.0852 Y1.5948 +G01 X-1.0684 Y1.5716 +G01 X-1.0595 Y1.5443 +G01 X-1.0595 Y1.5381 +G01 X-1.0595 Y1.5304 +G01 X-1.0595 Y1.5300 +G01 X-1.0595 Y1.5219 +G01 X-1.0595 Y1.4230 +G01 X-1.0524 Y1.4403 +G01 X-1.0373 Y1.4554 +G01 X-1.0176 Y1.4635 +G01 X-0.8824 Y1.4635 +G01 X-0.8627 Y1.4554 +G01 X-0.8578 Y1.4505 +G01 X-0.5981 Y1.4505 +G01 X-0.5900 Y1.4505 +G01 X-0.5869 Y1.4505 +G01 X-0.5819 Y1.4505 +G01 X-0.5757 Y1.4505 +G01 X-0.5484 Y1.4416 +G01 X-0.5252 Y1.4248 +G01 X-0.5084 Y1.4016 +G01 X-0.4995 Y1.3743 +G01 X-0.4995 Y1.3681 +G01 X-0.4995 Y1.3584 +G01 X-0.4994 Y1.3569 +G01 X-0.4985 Y1.3541 +G01 X-0.4967 Y1.3517 +G01 X-0.4943 Y1.3500 +G01 X-0.4915 Y1.3490 +G01 X-0.4900 Y1.3489 +G01 X-0.4835 Y1.3489 +G01 X-0.4819 Y1.3489 +G01 X-0.3140 Y1.3489 +G01 X-0.3028 Y1.3601 +G01 X-0.2804 Y1.3694 +G01 X-0.1196 Y1.3694 +G01 X-0.0972 Y1.3601 +G01 X-0.0800 Y1.3430 +G01 X-0.0708 Y1.3206 +G01 X-0.0708 Y1.2963 +G01 X-0.0800 Y1.2739 +G01 X-0.0972 Y1.2567 +G01 X-0.1196 Y1.2474 +G01 X-0.2804 Y1.2474 +G01 X-0.3028 Y1.2567 +G01 X-0.3140 Y1.2679 +G01 X-0.4819 Y1.2679 +G01 X-0.4835 Y1.2679 +G01 X-0.4981 Y1.2679 +G01 X-0.5043 Y1.2679 +G01 X-0.5316 Y1.2768 +G01 X-0.5548 Y1.2936 +G01 X-0.5716 Y1.3168 +G01 X-0.5805 Y1.3441 +G01 X-0.5805 Y1.3504 +G01 X-0.5805 Y1.3600 +G01 X-0.5806 Y1.3615 +G01 X-0.5815 Y1.3643 +G01 X-0.5833 Y1.3667 +G01 X-0.5857 Y1.3685 +G01 X-0.5885 Y1.3694 +G01 X-0.5900 Y1.3695 +G01 X-0.5981 Y1.3695 +G01 X-0.8578 Y1.3695 +G01 X-0.8627 Y1.3646 +G01 X-0.8739 Y1.3600 +G01 X-0.8627 Y1.3554 +G01 X-0.8578 Y1.3505 +G01 X-0.7552 Y1.3505 +G01 X-0.7422 Y1.3635 +G01 X-0.6978 Y1.3635 +G01 X-0.6665 Y1.3322 +G01 X-0.6665 Y1.2878 +G01 X-0.6978 Y1.2565 +G01 X-0.7422 Y1.2565 +G01 X-0.7552 Y1.2695 +G01 X-0.8578 Y1.2695 +G01 X-0.8627 Y1.2646 +G01 X-0.8739 Y1.2600 +G01 X-0.8627 Y1.2554 +G01 X-0.8578 Y1.2505 +G01 X-0.4319 Y1.2505 +G01 X-0.4240 Y1.2505 +G01 X-0.3944 Y1.2382 +G01 X-0.3718 Y1.2156 +G01 X-0.3595 Y1.1860 +G01 X-0.3595 Y1.1781 +G01 X-0.3595 Y1.1701 +G01 X-0.3595 Y1.1700 +G01 X-0.3595 Y1.1619 +G01 X-0.3595 Y1.1616 +G01 X-0.3594 Y1.1601 +G01 X-0.3585 Y1.1573 +G01 X-0.3567 Y1.1549 +G01 X-0.3543 Y1.1531 +G01 X-0.3515 Y1.1522 +G01 X-0.3500 Y1.1521 +G01 X-0.3489 Y1.1521 +G01 X-0.3419 Y1.1521 +G01 X-0.3140 Y1.1521 +G01 X-0.3028 Y1.1633 +G01 X-0.2804 Y1.1726 +G01 X-0.1196 Y1.1726 +G01 X-0.0972 Y1.1633 +G01 X-0.0800 Y1.1461 +G01 X-0.0708 Y1.1237 +G01 X-0.0708 Y1.0994 +G01 X-0.0800 Y1.0770 +G01 X-0.0972 Y1.0599 +G01 X-0.1196 Y1.0506 +G01 X-0.2804 Y1.0506 +G01 X-0.3028 Y1.0599 +G01 X-0.3140 Y1.0711 +G01 X-0.3419 Y1.0711 +G01 X-0.3489 Y1.0711 +G01 X-0.3500 Y1.0711 +G01 X-0.3581 Y1.0711 +G01 X-0.3643 Y1.0711 +G01 X-0.3916 Y1.0799 +G01 X-0.4148 Y1.0968 +G01 X-0.4316 Y1.1200 +G01 X-0.4405 Y1.1472 +G01 X-0.4405 Y1.1535 +G01 X-0.4405 Y1.1619 +G01 X-0.4405 Y1.1695 +G01 X-0.8578 Y1.1695 +G01 X-0.8627 Y1.1646 +G01 X-0.8739 Y1.1600 +G01 X-0.8627 Y1.1554 +G01 X-0.8578 Y1.1505 +G01 X-0.5952 Y1.1505 +G01 X-0.5822 Y1.1635 +G01 X-0.5378 Y1.1635 +G01 X-0.5065 Y1.1322 +G01 X-0.5065 Y1.0878 +G01 X-0.5378 Y1.0565 +G01 X-0.5822 Y1.0565 +G01 X-0.5952 Y1.0695 +G01 X-0.8578 Y1.0695 +G01 X-0.8627 Y1.0646 +G01 X-0.8739 Y1.0600 +G01 X-0.8627 Y1.0554 +G01 X-0.8578 Y1.0505 +G01 X-0.4881 Y1.0505 +G01 X-0.4866 Y1.0505 +G01 X-0.4719 Y1.0505 +G01 X-0.4657 Y1.0505 +G01 X-0.4384 Y1.0416 +G01 X-0.4152 Y1.0248 +G01 X-0.3984 Y1.0016 +G01 X-0.3895 Y0.9743 +G01 X-0.3895 Y0.9681 +G01 X-0.3895 Y0.9505 +G01 X-0.3819 Y0.9505 +G01 X-0.3124 Y0.9505 +G01 X-0.3028 Y0.9601 +G01 X-0.2804 Y0.9694 +G01 X-0.1196 Y0.9694 +G01 X-0.0972 Y0.9601 +G01 X-0.0800 Y0.9430 +G01 X-0.0708 Y0.9206 +G01 X-0.0708 Y0.8963 +G01 X-0.0800 Y0.8739 +G01 X-0.0972 Y0.8567 +G01 X-0.1196 Y0.8474 +G01 X-0.2804 Y0.8474 +G01 X-0.3028 Y0.8567 +G01 X-0.3156 Y0.8695 +G01 X-0.3819 Y0.8695 +G01 X-0.3900 Y0.8695 +G01 X-0.3935 Y0.8695 +G01 X-0.3981 Y0.8695 +G01 X-0.4060 Y0.8695 +G01 X-0.4356 Y0.8818 +G01 X-0.4582 Y0.9044 +G01 X-0.4705 Y0.9340 +G01 X-0.4705 Y0.9419 +G01 X-0.4705 Y0.9600 +G01 X-0.4706 Y0.9615 +G01 X-0.4715 Y0.9643 +G01 X-0.4733 Y0.9667 +G01 X-0.4757 Y0.9685 +G01 X-0.4785 Y0.9694 +G01 X-0.4800 Y0.9695 +G01 X-0.4866 Y0.9695 +G01 X-0.4881 Y0.9695 +G01 X-0.8578 Y0.9695 +G01 X-0.8627 Y0.9646 +G01 X-0.8739 Y0.9600 +G01 X-0.8627 Y0.9554 +G01 X-0.8578 Y0.9505 +G01 X-0.8381 Y0.9505 +G01 X-0.8342 Y0.9505 +G01 X-0.8219 Y0.9505 +G01 X-0.8157 Y0.9505 +G01 X-0.7884 Y0.9416 +G01 X-0.7652 Y0.9248 +G01 X-0.7484 Y0.9016 +G01 X-0.7395 Y0.8743 +G01 X-0.7395 Y0.8681 +G01 X-0.7395 Y0.5752 +G01 X-0.7265 Y0.5622 +G01 X-0.7265 Y0.5178 +G01 X-0.7578 Y0.4865 +G01 X-0.8022 Y0.4865 +G01 X-0.8335 Y0.5178 +G01 X-0.8335 Y0.5622 +G01 X-0.8205 Y0.5752 +G01 X-0.8205 Y0.8600 +G01 X-0.8206 Y0.8615 +G01 X-0.8215 Y0.8643 +G01 X-0.8233 Y0.8667 +G01 X-0.8257 Y0.8685 +G01 X-0.8285 Y0.8694 +G01 X-0.8300 Y0.8695 +G01 X-0.8343 Y0.8695 +G01 X-0.8381 Y0.8695 +G01 X-0.8578 Y0.8695 +G01 X-0.8627 Y0.8646 +G01 X-0.8739 Y0.8600 +G01 X-0.8627 Y0.8554 +G01 X-0.8476 Y0.8403 +G01 X-0.8395 Y0.8206 +G01 X-0.8395 Y0.7994 +G01 X-0.8476 Y0.7797 +G01 X-0.8627 Y0.7646 +G01 X-0.8824 Y0.7565 +G01 X-1.0176 Y0.7565 +G01 X-1.0373 Y0.7646 +G01 X-1.0422 Y0.7695 +G01 X-1.0429 Y0.7695 +G01 X-1.0581 Y0.7695 +G01 X-1.0643 Y0.7695 +G01 X-1.0916 Y0.7784 +G01 X-1.1148 Y0.7952 +G01 X-1.1316 Y0.8184 +G01 X-1.1405 Y0.8457 +G01 X-1.1405 Y0.8519 +G01 X-1.1405 Y0.8970 +G01 X-1.1476 Y0.8797 +G01 X-1.1627 Y0.8646 +G01 X-1.1739 Y0.8600 +G01 X-1.1627 Y0.8554 +G01 X-1.1476 Y0.8403 +G01 X-1.1395 Y0.8206 +G01 X-1.1395 Y0.7994 +G01 X-1.1476 Y0.7797 +G01 X-1.1627 Y0.7646 +G01 X-1.1824 Y0.7565 +G01 X-1.3176 Y0.7565 +G01 X-1.3373 Y0.7646 +G01 X-1.3422 Y0.7695 +G01 X-1.5000 Y0.7695 +G01 X-1.5015 Y0.7694 +G01 X-1.5043 Y0.7685 +G01 X-1.5067 Y0.7667 +G01 X-1.5085 Y0.7643 +G01 X-1.5094 Y0.7615 +G01 X-1.5095 Y0.7600 +G01 X-1.5095 Y0.7537 +G01 X-1.5095 Y0.7519 +G01 X-1.5095 Y0.6952 +G01 X-1.4965 Y0.6822 +G01 X-1.4965 Y0.6378 +G01 X-1.5278 Y0.6065 +G01 X-1.5722 Y0.6065 +G01 X-1.6035 Y0.6378 +G01 X-1.6035 Y0.6822 +G01 X-1.5905 Y0.6952 +G01 X-1.5905 Y0.7519 +G01 X-1.5905 Y0.7538 +G01 X-1.5905 Y0.7681 +G01 X-1.5905 Y0.7743 +G01 X-1.5816 Y0.8016 +G01 X-1.5648 Y0.8248 +G01 X-1.5416 Y0.8416 +G01 X-1.5143 Y0.8505 +G01 X-1.5081 Y0.8505 +G01 X-1.3422 Y0.8505 +G01 X-1.3373 Y0.8554 +G01 X-1.3261 Y0.8600 +G01 X-1.3373 Y0.8646 +G01 X-1.3422 Y0.8695 +G01 X-1.5919 Y0.8695 +G01 X-1.6000 Y0.8695 +G01 X-1.6015 Y0.8694 +G01 X-1.6043 Y0.8685 +G01 X-1.6067 Y0.8667 +G01 X-1.6085 Y0.8643 +G01 X-1.6094 Y0.8615 +G01 X-1.6095 Y0.8600 +G01 X-1.6095 Y0.1581 +G01 X-1.6095 Y0.1500 +G01 X-1.6094 Y0.1485 +G01 X-1.6085 Y0.1457 +G01 X-1.6067 Y0.1433 +G01 X-1.6043 Y0.1415 +G01 X-1.6015 Y0.1406 +G01 X-1.6000 Y0.1405 +G01 X-1.1481 Y0.1405 +G01 X-1.1400 Y0.1405 +G01 X-1.1385 Y0.1406 +G01 X-1.1357 Y0.1415 +G01 X-1.1333 Y0.1433 +G01 X-1.1315 Y0.1457 +G01 X-1.1306 Y0.1485 +G01 X-1.1305 Y0.1500 +G01 X-1.1305 Y0.1919 +G01 X-1.1305 Y0.1930 +G01 X-1.1305 Y0.2081 +G01 X-1.1305 Y0.2143 +G01 X-1.1216 Y0.2416 +G01 X-1.1048 Y0.2648 +G01 X-1.0816 Y0.2816 +G01 X-1.0543 Y0.2905 +G01 X-1.0481 Y0.2905 +G01 X-0.8061 Y0.2905 +G01 X-0.8152 Y0.2995 +G01 X-1.2695 Y0.2995 +G01 X-1.2695 Y0.2252 +G01 X-1.2665 Y0.2222 +G01 X-1.2665 Y0.1778 +G01 X-1.2978 Y0.1465 +G01 X-1.3422 Y0.1465 +G01 X-1.3735 Y0.1778 +G01 X-1.3735 Y0.2222 +G01 X-1.3505 Y0.2452 +G01 X-1.3505 Y0.2995 +G01 X-1.3764 Y0.2995 +G01 X-1.3863 Y0.2896 +G01 X-1.4082 Y0.2805 +G01 X-1.4318 Y0.2805 +G01 X-1.4537 Y0.2896 +G01 X-1.4704 Y0.3063 +G01 X-1.4795 Y0.3282 +G01 X-1.4795 Y0.3518 +G01 X-1.4704 Y0.3737 +G01 X-1.4537 Y0.3904 +G01 X-1.4318 Y0.3995 +G01 X-1.4082 Y0.3995 +G01 X-1.3863 Y0.3904 +G01 X-1.3764 Y0.3805 +G01 X-1.3181 Y0.3805 +G01 X-1.3019 Y0.3805 +G01 X-0.8152 Y0.3805 +G01 X-0.8022 Y0.3935 +G01 X-0.7578 Y0.3935 +G01 X-0.7265 Y0.3622 +G01 X-0.7265 Y0.3178 +G01 X-0.7538 Y0.2905 +G01 X-0.5181 Y0.2905 +G01 X-0.5100 Y0.2905 +G01 X-0.5085 Y0.2906 +G01 X-0.5057 Y0.2915 +G01 X-0.5033 Y0.2933 +G01 X-0.5015 Y0.2957 +G01 X-0.5006 Y0.2985 +G01 X-0.5005 Y0.3000 +G01 X-0.5005 Y0.6519 +G01 X-0.5005 Y0.6542 +G01 X-0.5005 Y0.6681 +G01 X-0.5005 Y0.6743 +G01 X-0.4916 Y0.7016 +G01 X-0.4748 Y0.7248 +G01 X-0.4516 Y0.7416 +G01 X-0.4243 Y0.7505 +G01 X-0.4181 Y0.7505 +G01 X-0.3156 Y0.7505 +G01 X-0.3028 Y0.7633 +G01 X-0.2804 Y0.7726 +G01 X-0.1196 Y0.7726 +G01 X-0.0972 Y0.7633 +G01 X-0.0800 Y0.7461 +G01 X-0.0708 Y0.7237 +G01 X-0.0708 Y0.6994 +G01 X-0.0800 Y0.6770 +G01 X-0.0972 Y0.6599 +G01 X-0.1196 Y0.6506 +G01 X-0.2804 Y0.6506 +G01 X-0.3028 Y0.6599 +G01 X-0.3124 Y0.6695 +G01 X-0.4100 Y0.6695 +G01 X-0.4115 Y0.6694 +G01 X-0.4143 Y0.6685 +G01 X-0.4167 Y0.6667 +G01 X-0.4185 Y0.6643 +G01 X-0.4194 Y0.6615 +G01 X-0.4195 Y0.6600 +G01 X-0.4195 Y0.6542 +G01 X-0.4195 Y0.6519 +G01 X-0.4195 Y0.2919 +G01 X-0.4195 Y0.2857 +G00 Z0.1000 +G00 X-0.5195 Y0.4981 +G01 Z-0.0070 F10 +G01 X-0.5195 Y0.4900 F20 +G01 X-0.5195 Y0.4870 +G01 X-0.5195 Y0.4819 +G01 X-0.5195 Y0.4757 +G01 X-0.5284 Y0.4484 +G01 X-0.5452 Y0.4252 +G01 X-0.5684 Y0.4084 +G01 X-0.5957 Y0.3995 +G01 X-0.6019 Y0.3995 +G01 X-1.3781 Y0.3995 +G01 X-1.3843 Y0.3995 +G01 X-1.4116 Y0.4084 +G01 X-1.4348 Y0.4252 +G01 X-1.4516 Y0.4484 +G01 X-1.4517 Y0.4488 +G01 X-1.4537 Y0.4496 +G01 X-1.4704 Y0.4663 +G01 X-1.4795 Y0.4882 +G01 X-1.4795 Y0.5118 +G01 X-1.4705 Y0.5336 +G01 X-1.4705 Y0.6748 +G01 X-1.4835 Y0.6878 +G01 X-1.4835 Y0.7322 +G01 X-1.4522 Y0.7635 +G01 X-1.4078 Y0.7635 +G01 X-1.3765 Y0.7322 +G01 X-1.3765 Y0.6878 +G01 X-1.3895 Y0.6748 +G01 X-1.3895 Y0.5518 +G01 X-1.3863 Y0.5504 +G01 X-1.3696 Y0.5337 +G01 X-1.3605 Y0.5118 +G01 X-1.3605 Y0.4882 +G01 X-1.3637 Y0.4805 +G01 X-0.6100 Y0.4805 +G01 X-0.6085 Y0.4806 +G01 X-0.6057 Y0.4815 +G01 X-0.6033 Y0.4833 +G01 X-0.6015 Y0.4857 +G01 X-0.6006 Y0.4885 +G01 X-0.6005 Y0.4900 +G01 X-0.6005 Y0.4981 +G01 X-0.6005 Y0.8748 +G01 X-0.6135 Y0.8878 +G01 X-0.6135 Y0.9322 +G01 X-0.5822 Y0.9635 +G01 X-0.5378 Y0.9635 +G01 X-0.5065 Y0.9322 +G01 X-0.5065 Y0.8878 +G01 X-0.5195 Y0.8748 +G01 X-0.5195 Y0.4981 +G00 Z0.1000 +G00 X-1.5535 Y1.8878 +G01 Z-0.0070 F10 +G01 X-1.5535 Y1.9322 F20 +G01 X-1.5222 Y1.9635 +G01 X-1.4778 Y1.9635 +G01 X-1.4465 Y1.9322 +G01 X-1.4465 Y1.8878 +G01 X-1.4595 Y1.8748 +G01 X-1.4595 Y1.7536 +G01 X-1.4496 Y1.7437 +G01 X-1.4405 Y1.7218 +G01 X-1.4405 Y1.7105 +G01 X-0.7619 Y1.7105 +G01 X-0.7557 Y1.7105 +G01 X-0.7284 Y1.7016 +G01 X-0.7052 Y1.6848 +G01 X-0.6884 Y1.6616 +G01 X-0.6795 Y1.6343 +G01 X-0.6795 Y1.6281 +G01 X-0.6795 Y1.6205 +G01 X-0.6795 Y1.6200 +G01 X-0.6795 Y1.6119 +G01 X-0.6795 Y1.5452 +G01 X-0.6665 Y1.5322 +G01 X-0.6665 Y1.4878 +G01 X-0.6978 Y1.4565 +G01 X-0.7422 Y1.4565 +G01 X-0.7735 Y1.4878 +G01 X-0.7735 Y1.5322 +G01 X-0.7605 Y1.5452 +G01 X-0.7605 Y1.6119 +G01 X-0.7605 Y1.6200 +G01 X-0.7606 Y1.6215 +G01 X-0.7615 Y1.6243 +G01 X-0.7633 Y1.6267 +G01 X-0.7657 Y1.6285 +G01 X-0.7685 Y1.6294 +G01 X-0.7700 Y1.6295 +G01 X-1.4478 Y1.6295 +G01 X-1.4625 Y1.6279 +G01 X-1.4953 Y1.6374 +G01 X-1.5117 Y1.6505 +G01 X-1.5118 Y1.6505 +G01 X-1.5337 Y1.6596 +G01 X-1.5504 Y1.6763 +G01 X-1.5595 Y1.6982 +G01 X-1.5595 Y1.7218 +G01 X-1.5504 Y1.7437 +G01 X-1.5405 Y1.7536 +G01 X-1.5405 Y1.8748 +G01 X-1.5535 Y1.8878 +G00 Z0.1000 +G00 X-1.6987 Y1.0535 +G01 Z-0.0070 F10 +G01 X-1.6866 Y1.0535 F20 +G01 X-1.6813 Y1.0535 +G01 X-1.3434 Y1.0535 +G01 X-1.3390 Y1.0579 +G01 X-1.3339 Y1.0600 +G01 X-1.3390 Y1.0621 +G01 X-1.3434 Y1.0665 +G01 X-1.7665 Y1.0665 +G01 X-1.7665 Y1.0035 +G01 X-1.7608 Y1.0173 +G01 X-1.7373 Y1.0408 +G01 X-1.7066 Y1.0535 +G01 X-1.6987 Y1.0535 +G00 Z0.1000 +G00 X-1.7757 Y0.8370 +G01 Z-0.0070 F10 +G01 X-1.7757 Y0.8370 F20 +G01 X-1.7931 Y0.8131 +G01 X-1.8170 Y0.7957 +G01 X-1.8237 Y0.7935 +G01 X-1.7800 Y0.7935 +G01 X-1.7790 Y0.7936 +G01 X-1.7770 Y0.7942 +G01 X-1.7754 Y0.7954 +G01 X-1.7742 Y0.7970 +G01 X-1.7736 Y0.7990 +G01 X-1.7735 Y0.8000 +G01 X-1.7735 Y0.8437 +G01 X-1.7757 Y0.8370 +G00 Z0.1000 +G00 X-1.4452 Y1.5035 +G01 Z-0.0070 F10 +G01 X-1.4452 Y1.5035 F20 +G01 X-1.4170 Y1.4943 +G01 X-1.3931 Y1.4769 +G01 X-1.3758 Y1.4532 +G01 X-1.3748 Y1.4535 +G01 X-1.3600 Y1.4535 +G01 X-1.3513 Y1.4535 +G01 X-1.3434 Y1.4535 +G01 X-1.3390 Y1.4579 +G01 X-1.3182 Y1.4665 +G01 X-1.1818 Y1.4665 +G01 X-1.1610 Y1.4579 +G01 X-1.1451 Y1.4420 +G01 X-1.1435 Y1.4381 +G01 X-1.1435 Y1.5213 +G01 X-1.1435 Y1.5300 +G01 X-1.1436 Y1.5310 +G01 X-1.1442 Y1.5329 +G01 X-1.1454 Y1.5346 +G01 X-1.1470 Y1.5358 +G01 X-1.1490 Y1.5364 +G01 X-1.1500 Y1.5365 +G01 X-1.5613 Y1.5365 +G01 X-1.5684 Y1.5365 +G01 X-1.5787 Y1.5365 +G01 X-1.5848 Y1.5365 +G01 X-1.6130 Y1.5457 +G01 X-1.6369 Y1.5631 +G01 X-1.6543 Y1.5870 +G01 X-1.6635 Y1.6152 +G01 X-1.6635 Y1.6213 +G01 X-1.6635 Y1.6256 +G01 X-1.6635 Y1.6300 +G01 X-1.6635 Y1.6387 +G01 X-1.6635 Y1.7465 +G01 X-1.7366 Y1.7465 +G01 X-1.7336 Y1.7435 +G01 X-1.7313 Y1.7435 +G01 X-1.7254 Y1.7435 +G01 X-1.6984 Y1.7323 +G01 X-1.6777 Y1.7116 +G01 X-1.6665 Y1.6846 +G01 X-1.6665 Y1.6787 +G01 X-1.6665 Y1.6654 +G01 X-1.6665 Y1.6613 +G01 X-1.6665 Y1.5100 +G01 X-1.6664 Y1.5090 +G01 X-1.6658 Y1.5070 +G01 X-1.6646 Y1.5054 +G01 X-1.6629 Y1.5042 +G01 X-1.6610 Y1.5036 +G01 X-1.6600 Y1.5035 +G01 X-1.6529 Y1.5035 +G01 X-1.6513 Y1.5035 +G01 X-1.4513 Y1.5035 +G01 X-1.4452 Y1.5035 +G00 Z0.1000 +G00 X-1.8034 Y1.7465 +G01 Z-0.0070 F10 +G01 X-1.9282 Y1.7465 F20 +G01 X-1.9312 Y1.7435 +G01 X-1.8064 Y1.7435 +G01 X-1.8034 Y1.7465 +G00 Z0.1000 +G00 X-2.6135 Y1.8434 +G01 Z-0.0070 F10 +G01 X-2.6135 Y1.8241 F20 +G01 X-2.5969 Y1.8469 +G01 X-2.5730 Y1.8643 +G01 X-2.5663 Y1.8665 +G01 X-2.6366 Y1.8665 +G01 X-2.6135 Y1.8434 +G00 Z0.1000 +G00 X-2.6401 Y1.7700 +G01 Z-0.0070 F10 +G01 X-2.6336 Y1.7635 F20 +G01 X-2.6300 Y1.7635 +G01 X-2.6290 Y1.7636 +G01 X-2.6270 Y1.7642 +G01 X-2.6254 Y1.7654 +G01 X-2.6242 Y1.7670 +G01 X-2.6236 Y1.7690 +G01 X-2.6235 Y1.7700 +G01 X-2.6235 Y1.7771 +G01 X-2.6235 Y1.7787 +G01 X-2.6235 Y1.7866 +G01 X-2.6401 Y1.7700 +G00 Z0.1000 +G00 X-2.1710 Y1.2621 +G01 Z-0.0070 F10 +G01 X-2.1761 Y1.2600 F20 +G01 X-2.1710 Y1.2579 +G01 X-2.1551 Y1.2420 +G01 X-2.1535 Y1.2381 +G01 X-2.1535 Y1.2665 +G01 X-2.1666 Y1.2665 +G01 X-2.1710 Y1.2621 +G00 Z0.1000 +G00 X-2.1551 Y1.1780 +G01 Z-0.0070 F10 +G01 X-2.1710 Y1.1621 F20 +G01 X-2.1761 Y1.1600 +G01 X-2.1710 Y1.1579 +G01 X-2.1551 Y1.1420 +G01 X-2.1535 Y1.1381 +G01 X-2.1535 Y1.1819 +G01 X-2.1551 Y1.1780 +G00 Z0.1000 +G00 X-2.1551 Y1.0780 +G01 Z-0.0070 F10 +G01 X-2.1710 Y1.0621 F20 +G01 X-2.1761 Y1.0600 +G01 X-2.1710 Y1.0579 +G01 X-2.1551 Y1.0420 +G01 X-2.1535 Y1.0381 +G01 X-2.1535 Y1.0513 +G01 X-2.1535 Y1.0819 +G01 X-2.1551 Y1.0780 +G00 Z0.1000 +G00 X-2.0620 Y1.0535 +G01 Z-0.0070 F10 +G01 X-2.0534 Y1.0535 F20 +G01 X-2.0490 Y1.0579 +G01 X-2.0439 Y1.0600 +G01 X-2.0490 Y1.0621 +G01 X-2.0649 Y1.0780 +G01 X-2.0665 Y1.0819 +G01 X-2.0665 Y1.0580 +G01 X-2.0620 Y1.0535 +G00 Z0.1000 +G00 X-2.0649 Y1.1420 +G01 Z-0.0070 F10 +G01 X-2.0490 Y1.1579 F20 +G01 X-2.0439 Y1.1600 +G01 X-2.0490 Y1.1621 +G01 X-2.0649 Y1.1780 +G01 X-2.0665 Y1.1819 +G01 X-2.0665 Y1.1381 +G01 X-2.0649 Y1.1420 +G00 Z0.1000 +G00 X-2.0649 Y1.2420 +G01 Z-0.0070 F10 +G01 X-2.0490 Y1.2579 F20 +G01 X-2.0439 Y1.2600 +G01 X-2.0490 Y1.2621 +G01 X-2.0649 Y1.2780 +G01 X-2.0665 Y1.2819 +G01 X-2.0665 Y1.2381 +G01 X-2.0649 Y1.2420 +G00 Z0.1000 +G00 X-2.9302 Y1.3865 +G01 Z-0.0070 F10 +G01 X-2.9346 Y1.3883 F20 +G01 X-2.9465 Y1.4002 +G01 X-2.9465 Y1.3865 +G01 X-2.9302 Y1.3865 +G00 Z0.1000 +G00 X-1.1451 Y0.9780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y0.9621 F20 +G01 X-1.1661 Y0.9600 +G01 X-1.1610 Y0.9579 +G01 X-1.1451 Y0.9420 +G01 X-1.1435 Y0.9381 +G01 X-1.1435 Y0.9819 +G01 X-1.1451 Y0.9780 +G00 Z0.1000 +G00 X-1.1451 Y1.0780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y1.0621 F20 +G01 X-1.1661 Y1.0600 +G01 X-1.1610 Y1.0579 +G01 X-1.1451 Y1.0420 +G01 X-1.1435 Y1.0381 +G01 X-1.1435 Y1.0819 +G01 X-1.1451 Y1.0780 +G00 Z0.1000 +G00 X-1.1451 Y1.1780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y1.1621 F20 +G01 X-1.1661 Y1.1600 +G01 X-1.1610 Y1.1579 +G01 X-1.1451 Y1.1420 +G01 X-1.1435 Y1.1381 +G01 X-1.1435 Y1.1819 +G01 X-1.1451 Y1.1780 +G00 Z0.1000 +G00 X-1.1451 Y1.2780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y1.2621 F20 +G01 X-1.1661 Y1.2600 +G01 X-1.1610 Y1.2579 +G01 X-1.1451 Y1.2420 +G01 X-1.1435 Y1.2381 +G01 X-1.1435 Y1.2819 +G01 X-1.1451 Y1.2780 +G00 Z0.1000 +G00 X-1.1451 Y1.3780 +G01 Z-0.0070 F10 +G01 X-1.1610 Y1.3621 F20 +G01 X-1.1661 Y1.3600 +G01 X-1.1610 Y1.3579 +G01 X-1.1451 Y1.3420 +G01 X-1.1435 Y1.3381 +G01 X-1.1435 Y1.3819 +G01 X-1.1451 Y1.3780 +G00 Z0.1000 +G00 X-1.0549 Y1.3420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y1.3579 F20 +G01 X-1.0339 Y1.3600 +G01 X-1.0390 Y1.3621 +G01 X-1.0549 Y1.3780 +G01 X-1.0565 Y1.3819 +G01 X-1.0565 Y1.3381 +G01 X-1.0549 Y1.3420 +G00 Z0.1000 +G00 X-1.0549 Y1.2420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y1.2579 F20 +G01 X-1.0339 Y1.2600 +G01 X-1.0390 Y1.2621 +G01 X-1.0549 Y1.2780 +G01 X-1.0565 Y1.2819 +G01 X-1.0565 Y1.2381 +G01 X-1.0549 Y1.2420 +G00 Z0.1000 +G00 X-1.0549 Y1.1420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y1.1579 F20 +G01 X-1.0339 Y1.1600 +G01 X-1.0390 Y1.1621 +G01 X-1.0549 Y1.1780 +G01 X-1.0565 Y1.1819 +G01 X-1.0565 Y1.1381 +G01 X-1.0549 Y1.1420 +G00 Z0.1000 +G00 X-1.0549 Y1.0420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y1.0579 F20 +G01 X-1.0339 Y1.0600 +G01 X-1.0390 Y1.0621 +G01 X-1.0549 Y1.0780 +G01 X-1.0565 Y1.0819 +G01 X-1.0565 Y1.0381 +G01 X-1.0549 Y1.0420 +G00 Z0.1000 +G00 X-1.0549 Y0.9420 +G01 Z-0.0070 F10 +G01 X-1.0390 Y0.9579 F20 +G01 X-1.0339 Y0.9600 +G01 X-1.0390 Y0.9621 +G01 X-1.0549 Y0.9780 +G01 X-1.0565 Y0.9819 +G01 X-1.0565 Y0.9381 +G01 X-1.0549 Y0.9420 +G00 Z0.1000 +G00 X-1.0564 Y0.8590 +G01 Z-0.0070 F10 +G01 X-1.0558 Y0.8570 F20 +G01 X-1.0546 Y0.8554 +G01 X-1.0529 Y0.8542 +G01 X-1.0510 Y0.8536 +G01 X-1.0500 Y0.8535 +G01 X-1.0434 Y0.8535 +G01 X-1.0390 Y0.8579 +G01 X-1.0339 Y0.8600 +G01 X-1.0390 Y0.8621 +G01 X-1.0549 Y0.8780 +G01 X-1.0565 Y0.8819 +G01 X-1.0565 Y0.8600 +G01 X-1.0564 Y0.8590 +G00 Z0.1000 +G00 X-1.9651 Y0.7035 +G01 Z-0.0070 F10 +G01 X-1.7864 Y0.7035 F20 +G01 X-1.7834 Y0.7065 +G01 X-1.9681 Y0.7065 +G01 X-1.9651 Y0.7035 +G00 Z0.1000 +G00 X-2.7064 Y1.8635 +G01 Z-0.0070 F10 +G01 X-2.7034 Y1.8665 F20 +G01 X-2.9000 Y1.8665 +G01 X-2.9010 Y1.8664 +G01 X-2.9029 Y1.8658 +G01 X-2.9046 Y1.8646 +G01 X-2.9058 Y1.8629 +G01 X-2.9064 Y1.8610 +G01 X-2.9065 Y1.8600 +G01 X-2.9065 Y1.8544 +G01 X-2.9065 Y1.8513 +G01 X-2.9065 Y1.8063 +G01 X-2.9043 Y1.8130 +G01 X-2.8869 Y1.8369 +G01 X-2.8630 Y1.8543 +G01 X-2.8348 Y1.8635 +G01 X-2.8200 Y1.8635 +G01 X-2.8113 Y1.8635 +G01 X-2.7064 Y1.8635 +G00 Z0.1000 +G00 X-3.0223 Y1.5716 +G01 Z-0.0070 F10 +G01 X-3.0223 Y1.5716 F20 +G01 X-3.0016 Y1.5923 +G01 X-2.9746 Y1.6035 +G01 X-2.9687 Y1.6035 +G01 X-2.8287 Y1.6035 +G01 X-2.8235 Y1.6035 +G01 X-2.8235 Y1.6613 +G01 X-2.8235 Y1.6626 +G01 X-2.8235 Y1.6787 +G01 X-2.8235 Y1.6848 +G01 X-2.8143 Y1.7130 +G01 X-2.7969 Y1.7369 +G01 X-2.7730 Y1.7543 +G01 X-2.7448 Y1.7635 +G01 X-2.7300 Y1.7635 +G01 X-2.7064 Y1.7635 +G01 X-2.6999 Y1.7700 +G01 X-2.7064 Y1.7765 +G01 X-2.8113 Y1.7765 +G01 X-2.8200 Y1.7765 +G01 X-2.8210 Y1.7764 +G01 X-2.8229 Y1.7758 +G01 X-2.8246 Y1.7746 +G01 X-2.8258 Y1.7729 +G01 X-2.8264 Y1.7710 +G01 X-2.8265 Y1.7700 +G01 X-2.8265 Y1.6887 +G01 X-2.8265 Y1.6867 +G01 X-2.8265 Y1.6713 +G01 X-2.8265 Y1.6654 +G01 X-2.8377 Y1.6384 +G01 X-2.8584 Y1.6177 +G01 X-2.8854 Y1.6065 +G01 X-2.8913 Y1.6065 +G01 X-3.0113 Y1.6065 +G01 X-3.0200 Y1.6065 +G01 X-3.0210 Y1.6064 +G01 X-3.0229 Y1.6058 +G01 X-3.0246 Y1.6046 +G01 X-3.0258 Y1.6029 +G01 X-3.0264 Y1.6010 +G01 X-3.0265 Y1.6000 +G01 X-3.0265 Y1.5615 +G01 X-3.0223 Y1.5716 +G00 Z0.1000 +G00 X-3.0264 Y1.2890 +G01 Z-0.0070 F10 +G01 X-3.0258 Y1.2870 F20 +G01 X-3.0246 Y1.2854 +G01 X-3.0229 Y1.2842 +G01 X-3.0210 Y1.2836 +G01 X-3.0200 Y1.2835 +G01 X-2.9834 Y1.2835 +G01 X-3.0065 Y1.3066 +G01 X-3.0065 Y1.3084 +G01 X-3.0208 Y1.3227 +G01 X-3.0265 Y1.3365 +G01 X-3.0265 Y1.2900 +G01 X-3.0264 Y1.2890 +G00 Z0.1000 +G00 X-1.8334 Y1.6235 +G01 Z-0.0070 F10 +G01 X-1.8334 Y1.6235 F20 +G01 X-1.8027 Y1.6108 +G01 X-1.7792 Y1.5873 +G01 X-1.7665 Y1.5566 +G01 X-1.7665 Y1.5487 +G01 X-1.7665 Y1.5400 +G01 X-1.7665 Y1.5314 +G01 X-1.7665 Y1.3535 +G01 X-1.7613 Y1.3535 +G01 X-1.6487 Y1.3535 +G01 X-1.6313 Y1.3535 +G01 X-1.5449 Y1.3535 +G01 X-1.5354 Y1.3630 +G01 X-1.5124 Y1.3725 +G01 X-1.4876 Y1.3725 +G01 X-1.4646 Y1.3630 +G01 X-1.4535 Y1.3519 +G01 X-1.4535 Y1.4013 +G01 X-1.4535 Y1.4100 +G01 X-1.4536 Y1.4110 +G01 X-1.4542 Y1.4129 +G01 X-1.4554 Y1.4146 +G01 X-1.4570 Y1.4158 +G01 X-1.4590 Y1.4164 +G01 X-1.4600 Y1.4165 +G01 X-1.6513 Y1.4165 +G01 X-1.6529 Y1.4165 +G01 X-1.6687 Y1.4165 +G01 X-1.6748 Y1.4165 +G01 X-1.7030 Y1.4257 +G01 X-1.7269 Y1.4431 +G01 X-1.7443 Y1.4670 +G01 X-1.7535 Y1.4952 +G01 X-1.7535 Y1.5013 +G01 X-1.7535 Y1.6435 +G01 X-1.7934 Y1.6435 +G01 X-1.8064 Y1.6565 +G01 X-2.0313 Y1.6565 +G01 X-2.0400 Y1.6565 +G01 X-2.0548 Y1.6565 +G01 X-2.0830 Y1.6657 +G01 X-2.1069 Y1.6831 +G01 X-2.1243 Y1.7070 +G01 X-2.1335 Y1.7352 +G01 X-2.1335 Y1.7500 +G01 X-2.1335 Y1.7587 +G01 X-2.1335 Y1.8665 +G01 X-2.3537 Y1.8665 +G01 X-2.3470 Y1.8643 +G01 X-2.3231 Y1.8469 +G01 X-2.3057 Y1.8230 +G01 X-2.2965 Y1.7948 +G01 X-2.2965 Y1.7887 +G01 X-2.2965 Y1.7835 +G01 X-2.2518 Y1.7835 +G01 X-2.2350 Y1.8003 +G01 X-2.1850 Y1.8003 +G01 X-2.1497 Y1.7650 +G01 X-2.1497 Y1.7150 +G01 X-2.1850 Y1.6797 +G01 X-2.2350 Y1.6797 +G01 X-2.2518 Y1.6965 +G01 X-2.3036 Y1.6965 +G01 X-2.3166 Y1.6835 +G01 X-2.3335 Y1.6835 +G01 X-2.3335 Y1.6416 +G01 X-2.3463 Y1.6288 +G01 X-2.3458 Y1.6270 +G01 X-2.3446 Y1.6254 +G01 X-2.3429 Y1.6242 +G01 X-2.3410 Y1.6236 +G01 X-2.3400 Y1.6235 +G01 X-2.3331 Y1.6235 +G01 X-2.3313 Y1.6235 +G01 X-1.8413 Y1.6235 +G01 X-1.8334 Y1.6235 +G00 Z0.1000 +G00 X-2.4787 Y1.7835 +G01 Z-0.0070 F10 +G01 X-2.4764 Y1.7835 F20 +G01 X-2.4734 Y1.7865 +G01 X-2.5213 Y1.7865 +G01 X-2.5300 Y1.7865 +G01 X-2.5310 Y1.7864 +G01 X-2.5329 Y1.7858 +G01 X-2.5346 Y1.7846 +G01 X-2.5358 Y1.7829 +G01 X-2.5364 Y1.7810 +G01 X-2.5365 Y1.7800 +G01 X-2.5365 Y1.7787 +G01 X-2.5365 Y1.7770 +G01 X-2.5365 Y1.7613 +G01 X-2.5365 Y1.7552 +G01 X-2.5457 Y1.7270 +G01 X-2.5631 Y1.7031 +G01 X-2.5870 Y1.6857 +G01 X-2.6152 Y1.6765 +G01 X-2.6213 Y1.6765 +G01 X-2.6336 Y1.6765 +G01 X-2.6436 Y1.6665 +G01 X-2.6366 Y1.6665 +G01 X-2.6236 Y1.6535 +G01 X-2.5435 Y1.6535 +G01 X-2.5435 Y1.7013 +G01 X-2.5435 Y1.7076 +G01 X-2.5435 Y1.7100 +G01 X-2.5435 Y1.7187 +G01 X-2.5435 Y1.7246 +G01 X-2.5323 Y1.7516 +G01 X-2.5116 Y1.7723 +G01 X-2.4846 Y1.7835 +G01 X-2.4787 Y1.7835 +G00 Z0.1000 +G00 X-2.4765 Y1.4313 +G01 Z-0.0070 F10 +G01 X-2.4765 Y1.2600 F20 +G01 X-2.4764 Y1.2590 +G01 X-2.4758 Y1.2570 +G01 X-2.4746 Y1.2554 +G01 X-2.4729 Y1.2542 +G01 X-2.4710 Y1.2536 +G01 X-2.4700 Y1.2535 +G01 X-2.4627 Y1.2535 +G01 X-2.4613 Y1.2535 +G01 X-2.3534 Y1.2535 +G01 X-2.3490 Y1.2579 +G01 X-2.3439 Y1.2600 +G01 X-2.3490 Y1.2621 +G01 X-2.3649 Y1.2780 +G01 X-2.3735 Y1.2988 +G01 X-2.3735 Y1.3212 +G01 X-2.3649 Y1.3420 +G01 X-2.3490 Y1.3579 +G01 X-2.3282 Y1.3665 +G01 X-2.1918 Y1.3665 +G01 X-2.1710 Y1.3579 +G01 X-2.1666 Y1.3535 +G01 X-2.1387 Y1.3535 +G01 X-2.1300 Y1.3535 +G01 X-2.1274 Y1.3535 +G01 X-2.1213 Y1.3535 +G01 X-2.1174 Y1.3535 +G01 X-2.0940 Y1.3438 +G01 X-2.0762 Y1.3260 +G01 X-2.0735 Y1.3195 +G01 X-2.0735 Y1.3212 +G01 X-2.0649 Y1.3420 +G01 X-2.0490 Y1.3579 +G01 X-2.0282 Y1.3665 +G01 X-2.0035 Y1.3665 +G01 X-2.0035 Y1.4113 +G01 X-2.0035 Y1.4182 +G01 X-2.0118 Y1.4265 +G01 X-2.0187 Y1.4265 +G01 X-2.1682 Y1.4265 +G01 X-2.1850 Y1.4097 +G01 X-2.2350 Y1.4097 +G01 X-2.2395 Y1.4142 +G01 X-2.2747 Y1.3790 +G01 X-2.3253 Y1.3790 +G01 X-2.3610 Y1.4147 +G01 X-2.3610 Y1.4653 +G01 X-2.3253 Y1.5010 +G01 X-2.2747 Y1.5010 +G01 X-2.2697 Y1.4959 +G01 X-2.2691 Y1.4961 +G01 X-2.2350 Y1.5303 +G01 X-2.1850 Y1.5303 +G01 X-2.1682 Y1.5135 +G01 X-2.0187 Y1.5135 +G01 X-2.0118 Y1.5135 +G01 X-1.9950 Y1.5303 +G01 X-1.9450 Y1.5303 +G01 X-1.9097 Y1.4950 +G01 X-1.9097 Y1.4450 +G01 X-1.9173 Y1.4374 +G01 X-1.9165 Y1.4348 +G01 X-1.9165 Y1.4200 +G01 X-1.9165 Y1.4113 +G01 X-1.9165 Y1.3665 +G01 X-1.8918 Y1.3665 +G01 X-1.8710 Y1.3579 +G01 X-1.8551 Y1.3420 +G01 X-1.8535 Y1.3381 +G01 X-1.8535 Y1.5313 +G01 X-1.8535 Y1.5365 +G01 X-2.3313 Y1.5365 +G01 X-2.3331 Y1.5365 +G01 X-2.3487 Y1.5365 +G01 X-2.3548 Y1.5365 +G01 X-2.3830 Y1.5457 +G01 X-2.4069 Y1.5631 +G01 X-2.4243 Y1.5870 +G01 X-2.4335 Y1.6152 +G01 X-2.4335 Y1.6213 +G01 X-2.4335 Y1.6286 +G01 X-2.4465 Y1.6416 +G01 X-2.4465 Y1.6835 +G01 X-2.4565 Y1.6835 +G01 X-2.4565 Y1.6013 +G01 X-2.4631 Y1.5854 +G01 X-2.4754 Y1.5731 +G01 X-2.4765 Y1.5726 +G01 X-2.4765 Y1.4313 +G00 Z0.1000 +G00 X-2.6366 Y1.5535 +G01 Z-0.0070 F10 +G01 X-2.6834 Y1.5535 F20 +G01 X-2.7165 Y1.5866 +G01 X-2.7165 Y1.6334 +G01 X-2.6864 Y1.6635 +G01 X-2.6934 Y1.6635 +G01 X-2.7064 Y1.6765 +G01 X-2.7300 Y1.6765 +G01 X-2.7310 Y1.6764 +G01 X-2.7329 Y1.6758 +G01 X-2.7346 Y1.6746 +G01 X-2.7358 Y1.6729 +G01 X-2.7364 Y1.6710 +G01 X-2.7365 Y1.6700 +G01 X-2.7365 Y1.6626 +G01 X-2.7365 Y1.6613 +G01 X-2.7365 Y1.5913 +G01 X-2.7365 Y1.5834 +G01 X-2.7492 Y1.5527 +G01 X-2.7727 Y1.5292 +G01 X-2.8034 Y1.5165 +G01 X-2.8113 Y1.5165 +G01 X-2.8200 Y1.5165 +G01 X-2.8287 Y1.5165 +G01 X-2.9465 Y1.5165 +G01 X-2.9465 Y1.4798 +G01 X-2.9346 Y1.4917 +G01 X-2.9121 Y1.5010 +G01 X-2.8879 Y1.5010 +G01 X-2.8654 Y1.4917 +G01 X-2.8572 Y1.4835 +G01 X-2.5635 Y1.4835 +G01 X-2.5635 Y1.5665 +G01 X-2.6236 Y1.5665 +G01 X-2.6366 Y1.5535 +G00 Z0.1000 +G00 X-2.6934 Y1.3065 +G01 Z-0.0070 F10 +G01 X-2.6466 Y1.3065 F20 +G01 X-2.6135 Y1.2734 +G01 X-2.6135 Y1.2266 +G01 X-2.6466 Y1.1935 +G01 X-2.6769 Y1.1935 +G01 X-2.6999 Y1.1889 +G01 X-2.7310 Y1.1950 +G01 X-2.7332 Y1.1965 +G01 X-3.0287 Y1.1965 +G01 X-3.0348 Y1.1965 +G01 X-3.0630 Y1.2057 +G01 X-3.0869 Y1.2231 +G01 X-3.1043 Y1.2470 +G01 X-3.1135 Y1.2752 +G01 X-3.1135 Y1.2813 +G01 X-3.1135 Y1.5766 +G01 X-3.1165 Y1.5736 +G01 X-3.1165 Y0.9600 +G01 X-3.1164 Y0.9590 +G01 X-3.1158 Y0.9570 +G01 X-3.1146 Y0.9554 +G01 X-3.1129 Y0.9542 +G01 X-3.1110 Y0.9536 +G01 X-3.1100 Y0.9535 +G01 X-3.1044 Y0.9535 +G01 X-3.1013 Y0.9535 +G01 X-2.5518 Y0.9535 +G01 X-2.5388 Y0.9665 +G01 X-2.9087 Y0.9665 +G01 X-2.9148 Y0.9665 +G01 X-2.9430 Y0.9757 +G01 X-2.9669 Y0.9931 +G01 X-2.9843 Y1.0170 +G01 X-2.9935 Y1.0452 +G01 X-2.9935 Y1.0513 +G01 X-2.9935 Y1.0936 +G01 X-3.0065 Y1.1066 +G01 X-3.0065 Y1.1534 +G01 X-2.9734 Y1.1865 +G01 X-2.9266 Y1.1865 +G01 X-2.8935 Y1.1534 +G01 X-2.8935 Y1.1066 +G01 X-2.9065 Y1.0936 +G01 X-2.9065 Y1.0600 +G01 X-2.9064 Y1.0590 +G01 X-2.9058 Y1.0570 +G01 X-2.9046 Y1.0554 +G01 X-2.9029 Y1.0542 +G01 X-2.9010 Y1.0536 +G01 X-2.9000 Y1.0535 +G01 X-2.3534 Y1.0535 +G01 X-2.3490 Y1.0579 +G01 X-2.3439 Y1.0600 +G01 X-2.3490 Y1.0621 +G01 X-2.3649 Y1.0780 +G01 X-2.3735 Y1.0988 +G01 X-2.3735 Y1.1212 +G01 X-2.3649 Y1.1420 +G01 X-2.3490 Y1.1579 +G01 X-2.3439 Y1.1600 +G01 X-2.3490 Y1.1621 +G01 X-2.3534 Y1.1665 +G01 X-2.4613 Y1.1665 +G01 X-2.4627 Y1.1665 +G01 X-2.4787 Y1.1665 +G01 X-2.4848 Y1.1665 +G01 X-2.5130 Y1.1757 +G01 X-2.5369 Y1.1931 +G01 X-2.5543 Y1.2170 +G01 X-2.5635 Y1.2452 +G01 X-2.5635 Y1.2513 +G01 X-2.5635 Y1.3965 +G01 X-2.8572 Y1.3965 +G01 X-2.8654 Y1.3883 +G01 X-2.8879 Y1.3790 +G01 X-2.9121 Y1.3790 +G01 X-2.9240 Y1.3839 +G01 X-2.8935 Y1.3534 +G01 X-2.8935 Y1.3066 +G01 X-2.9166 Y1.2835 +G01 X-2.7243 Y1.2835 +G01 X-2.7200 Y1.2843 +G01 X-2.7163 Y1.2836 +G01 X-2.6934 Y1.3065 +G00 Z0.1000 +G00 X-1.8551 Y1.2780 +G01 Z-0.0070 F10 +G01 X-1.8710 Y1.2621 F20 +G01 X-1.8761 Y1.2600 +G01 X-1.8710 Y1.2579 +G01 X-1.8566 Y1.2435 +G01 X-1.8135 Y1.2435 +G01 X-1.8135 Y1.2665 +G01 X-1.8187 Y1.2665 +G01 X-1.8346 Y1.2731 +G01 X-1.8469 Y1.2854 +G01 X-1.8495 Y1.2916 +G01 X-1.8551 Y1.2780 +G00 Z0.1000 +G00 X-1.8551 Y0.9780 +G01 Z-0.0070 F10 +G01 X-1.8710 Y0.9621 F20 +G01 X-1.8918 Y0.9535 +G01 X-2.0282 Y0.9535 +G01 X-2.0490 Y0.9621 +G01 X-2.0534 Y0.9665 +G01 X-2.0665 Y0.9665 +G01 X-2.0665 Y0.9513 +G01 X-2.0665 Y0.9452 +G01 X-2.0757 Y0.9170 +G01 X-2.0931 Y0.8931 +G01 X-2.1170 Y0.8757 +G01 X-2.1237 Y0.8735 +G01 X-1.8600 Y0.8735 +G01 X-1.8590 Y0.8736 +G01 X-1.8570 Y0.8742 +G01 X-1.8554 Y0.8754 +G01 X-1.8542 Y0.8770 +G01 X-1.8536 Y0.8790 +G01 X-1.8535 Y0.8800 +G01 X-1.8535 Y0.9819 +G01 X-1.8551 Y0.9780 +G00 Z0.1000 +G00 X-1.8710 Y1.0621 +G01 Z-0.0070 F10 +G01 X-1.8761 Y1.0600 F20 +G01 X-1.8710 Y1.0579 +G01 X-1.8551 Y1.0420 +G01 X-1.8535 Y1.0381 +G01 X-1.8535 Y1.0665 +G01 X-1.8666 Y1.0665 +G01 X-1.8710 Y1.0621 +G00 Z0.1000 +G00 X-1.8064 Y1.1565 +G01 Z-0.0070 F10 +G01 X-1.8696 Y1.1565 F20 +G01 X-1.8666 Y1.1535 +G01 X-1.8187 Y1.1535 +G01 X-1.8034 Y1.1535 +G01 X-1.8064 Y1.1565 +G00 Z0.1000 +G00 X-1.7135 Y1.2234 +G01 Z-0.0070 F10 +G01 X-1.7135 Y1.1766 F20 +G01 X-1.7366 Y1.1535 +G01 X-1.3434 Y1.1535 +G01 X-1.3390 Y1.1579 +G01 X-1.3339 Y1.1600 +G01 X-1.3390 Y1.1621 +G01 X-1.3549 Y1.1780 +G01 X-1.3635 Y1.1988 +G01 X-1.3635 Y1.2212 +G01 X-1.3549 Y1.2420 +G01 X-1.3390 Y1.2579 +G01 X-1.3339 Y1.2600 +G01 X-1.3390 Y1.2621 +G01 X-1.3549 Y1.2780 +G01 X-1.3635 Y1.2988 +G01 X-1.3635 Y1.3212 +G01 X-1.3549 Y1.3420 +G01 X-1.3390 Y1.3579 +G01 X-1.3339 Y1.3600 +G01 X-1.3390 Y1.3621 +G01 X-1.3434 Y1.3665 +G01 X-1.3513 Y1.3665 +G01 X-1.3600 Y1.3665 +G01 X-1.3610 Y1.3664 +G01 X-1.3629 Y1.3658 +G01 X-1.3646 Y1.3646 +G01 X-1.3658 Y1.3629 +G01 X-1.3664 Y1.3610 +G01 X-1.3665 Y1.3600 +G01 X-1.3665 Y1.2687 +G01 X-1.3665 Y1.2594 +G01 X-1.3665 Y1.2583 +G01 X-1.3665 Y1.2421 +G01 X-1.3665 Y1.2384 +G01 X-1.3729 Y1.2146 +G01 X-1.3735 Y1.2135 +G01 X-1.3735 Y1.1866 +G01 X-1.4066 Y1.1535 +G01 X-1.4534 Y1.1535 +G01 X-1.4865 Y1.1866 +G01 X-1.4865 Y1.2334 +G01 X-1.4535 Y1.2664 +G01 X-1.4535 Y1.2681 +G01 X-1.4646 Y1.2570 +G01 X-1.4876 Y1.2475 +G01 X-1.5124 Y1.2475 +G01 X-1.5354 Y1.2570 +G01 X-1.5449 Y1.2665 +G01 X-1.5797 Y1.2665 +G01 X-1.5797 Y1.2450 +G01 X-1.6150 Y1.2097 +G01 X-1.6650 Y1.2097 +G01 X-1.7003 Y1.2450 +G01 X-1.7003 Y1.2665 +G01 X-1.7265 Y1.2665 +G01 X-1.7265 Y1.2364 +G01 X-1.7135 Y1.2234 +G00 Z0.1000 +G00 X-2.4682 Y0.9535 +G01 Z-0.0070 F10 +G01 X-2.1687 Y0.9535 F20 +G01 X-2.1600 Y0.9535 +G01 X-2.1590 Y0.9536 +G01 X-2.1570 Y0.9542 +G01 X-2.1554 Y0.9554 +G01 X-2.1542 Y0.9570 +G01 X-2.1536 Y0.9590 +G01 X-2.1535 Y0.9600 +G01 X-2.1535 Y0.9819 +G01 X-2.1551 Y0.9780 +G01 X-2.1710 Y0.9621 +G01 X-2.1918 Y0.9535 +G01 X-2.3282 Y0.9535 +G01 X-2.3490 Y0.9621 +G01 X-2.3534 Y0.9665 +G01 X-2.4812 Y0.9665 +G01 X-2.4682 Y0.9535 +G00 Z0.1000 +G00 X-3.0287 Y1.6935 +G01 Z-0.0070 F10 +G01 X-3.0200 Y1.6935 F20 +G01 X-3.0113 Y1.6935 +G01 X-2.9135 Y1.6935 +G01 X-2.9135 Y1.7465 +G01 X-2.9192 Y1.7327 +G01 X-2.9427 Y1.7092 +G01 X-2.9734 Y1.6965 +G01 X-2.9900 Y1.6965 +G01 X-2.9987 Y1.6965 +G01 X-3.1100 Y1.6965 +G01 X-3.1110 Y1.6964 +G01 X-3.1129 Y1.6958 +G01 X-3.1146 Y1.6946 +G01 X-3.1158 Y1.6929 +G01 X-3.1164 Y1.6910 +G01 X-3.1165 Y1.6900 +G01 X-3.1165 Y1.6825 +G01 X-3.1165 Y1.6813 +G01 X-3.1165 Y1.6464 +G01 X-3.1065 Y1.6364 +G01 X-3.1043 Y1.6430 +G01 X-3.0869 Y1.6669 +G01 X-3.0630 Y1.6843 +G01 X-3.0348 Y1.6935 +G01 X-3.0287 Y1.6935 +G00 Z0.1000 +G00 X-1.3434 Y0.9535 +G01 Z-0.0070 F10 +G01 X-1.3390 Y0.9579 F20 +G01 X-1.3339 Y0.9600 +G01 X-1.3390 Y0.9621 +G01 X-1.3434 Y0.9665 +G01 X-1.6813 Y0.9665 +G01 X-1.6865 Y0.9665 +G01 X-1.6865 Y0.9638 +G01 X-1.6865 Y0.9613 +G01 X-1.6865 Y0.8963 +G01 X-1.6843 Y0.9030 +G01 X-1.6669 Y0.9269 +G01 X-1.6430 Y0.9443 +G01 X-1.6148 Y0.9535 +G01 X-1.6000 Y0.9535 +G01 X-1.5913 Y0.9535 +G01 X-1.3434 Y0.9535 +G00 Z0.1000 +G00 X-2.3870 Y1.7858 +G01 Z-0.0070 F10 +G01 X-2.3890 Y1.7864 F20 +G01 X-2.3900 Y1.7865 +G01 X-2.4066 Y1.7865 +G01 X-2.3900 Y1.7699 +G01 X-2.3835 Y1.7764 +G01 X-2.3835 Y1.7800 +G01 X-2.3836 Y1.7810 +G01 X-2.3842 Y1.7829 +G01 X-2.3854 Y1.7846 +G01 X-2.3870 Y1.7858 +G00 Z0.1000 +G00 X-1.9766 Y1.8535 +G01 Z-0.0070 F10 +G01 X-2.0234 Y1.8535 F20 +G01 X-2.0364 Y1.8665 +G01 X-2.0465 Y1.8665 +G01 X-2.0465 Y1.7587 +G01 X-2.0465 Y1.7500 +G01 X-2.0464 Y1.7490 +G01 X-2.0458 Y1.7470 +G01 X-2.0446 Y1.7454 +G01 X-2.0429 Y1.7442 +G01 X-2.0410 Y1.7436 +G01 X-2.0400 Y1.7435 +G01 X-2.0313 Y1.7435 +G01 X-2.0088 Y1.7435 +G01 X-2.0303 Y1.7650 +G01 X-2.0303 Y1.8150 +G01 X-1.9950 Y1.8503 +G01 X-1.9450 Y1.8503 +G01 X-1.9282 Y1.8335 +G01 X-1.6635 Y1.8335 +G01 X-1.6635 Y1.9687 +G01 X-1.6635 Y1.9748 +G01 X-1.6543 Y2.0030 +G01 X-1.6369 Y2.0269 +G01 X-1.6130 Y2.0443 +G01 X-1.5848 Y2.0535 +G01 X-1.5700 Y2.0535 +G01 X-1.5613 Y2.0535 +G01 X-1.4187 Y2.0535 +G01 X-1.4100 Y2.0535 +G01 X-1.4013 Y2.0535 +G01 X-1.3952 Y2.0535 +G01 X-1.3670 Y2.0443 +G01 X-1.3431 Y2.0269 +G01 X-1.3257 Y2.0030 +G01 X-1.3165 Y1.9748 +G01 X-1.3165 Y1.9687 +G01 X-1.3165 Y1.9028 +G01 X-1.2990 Y1.8853 +G01 X-1.2990 Y1.8347 +G01 X-1.3165 Y1.8172 +G01 X-1.3165 Y1.8100 +G01 X-1.3164 Y1.8090 +G01 X-1.3158 Y1.8070 +G01 X-1.3146 Y1.8054 +G01 X-1.3129 Y1.8042 +G01 X-1.3110 Y1.8036 +G01 X-1.3100 Y1.8035 +G01 X-1.3028 Y1.8035 +G01 X-1.3013 Y1.8035 +G01 X-0.7830 Y1.8035 +G01 X-0.7946 Y1.8083 +G01 X-0.8028 Y1.8165 +G01 X-1.1513 Y1.8165 +G01 X-1.1600 Y1.8165 +G01 X-1.1748 Y1.8165 +G01 X-1.2030 Y1.8257 +G01 X-1.2269 Y1.8431 +G01 X-1.2443 Y1.8670 +G01 X-1.2535 Y1.8952 +G01 X-1.2535 Y1.9013 +G01 X-1.2535 Y2.0513 +G01 X-1.2535 Y2.0598 +G01 X-1.2535 Y2.0600 +G01 X-1.2536 Y2.0610 +G01 X-1.2542 Y2.0629 +G01 X-1.2554 Y2.0646 +G01 X-1.2570 Y2.0658 +G01 X-1.2590 Y2.0664 +G01 X-1.2600 Y2.0665 +G01 X-1.6700 Y2.0665 +G01 X-1.6710 Y2.0664 +G01 X-1.6730 Y2.0658 +G01 X-1.6746 Y2.0646 +G01 X-1.6758 Y2.0629 +G01 X-1.6764 Y2.0610 +G01 X-1.6765 Y2.0600 +G01 X-1.6765 Y1.9687 +G01 X-1.6765 Y1.9649 +G01 X-1.6765 Y1.9513 +G01 X-1.6765 Y1.9452 +G01 X-1.6857 Y1.9170 +G01 X-1.7031 Y1.8931 +G01 X-1.7270 Y1.8757 +G01 X-1.7552 Y1.8665 +G01 X-1.7613 Y1.8665 +G01 X-1.9636 Y1.8665 +G01 X-1.9766 Y1.8535 +G00 Z0.1000 +G00 X-0.4165 Y0.2852 +G01 Z-0.0070 F10 +G01 X-0.4165 Y0.2852 F20 +G01 X-0.4257 Y0.2570 +G01 X-0.4431 Y0.2331 +G01 X-0.4670 Y0.2157 +G01 X-0.4952 Y0.2065 +G01 X-0.5100 Y0.2065 +G01 X-0.5187 Y0.2065 +G01 X-1.0400 Y0.2065 +G01 X-1.0410 Y0.2064 +G01 X-1.0430 Y0.2058 +G01 X-1.0446 Y0.2046 +G01 X-1.0458 Y0.2029 +G01 X-1.0464 Y0.2010 +G01 X-1.0465 Y0.2000 +G01 X-1.0465 Y0.1924 +G01 X-1.0465 Y0.1913 +G01 X-1.0465 Y0.1413 +G01 X-1.0465 Y0.1352 +G01 X-1.0557 Y0.1070 +G01 X-1.0731 Y0.0831 +G01 X-1.0970 Y0.0657 +G01 X-1.1252 Y0.0565 +G01 X-1.1313 Y0.0565 +G01 X-1.1400 Y0.0565 +G01 X-1.1487 Y0.0565 +G01 X-1.6087 Y0.0565 +G01 X-1.6148 Y0.0565 +G01 X-1.6430 Y0.0657 +G01 X-1.6669 Y0.0831 +G01 X-1.6843 Y0.1070 +G01 X-1.6935 Y0.1352 +G01 X-1.6935 Y0.1413 +G01 X-1.6935 Y0.1434 +G01 X-1.6935 Y0.1500 +G01 X-1.6935 Y0.1587 +G01 X-1.6935 Y0.7637 +G01 X-1.6957 Y0.7570 +G01 X-1.7131 Y0.7331 +G01 X-1.7359 Y0.7165 +G01 X-1.7266 Y0.7165 +G01 X-1.6935 Y0.6834 +G01 X-1.6935 Y0.6366 +G01 X-1.7266 Y0.6035 +G01 X-1.7734 Y0.6035 +G01 X-1.7864 Y0.6165 +G01 X-1.8612 Y0.6165 +G01 X-1.8397 Y0.5950 +G01 X-1.8397 Y0.5595 +G01 X-1.8324 Y0.5625 +G01 X-1.8076 Y0.5625 +G01 X-1.7846 Y0.5530 +G01 X-1.7670 Y0.5354 +G01 X-1.7575 Y0.5124 +G01 X-1.7575 Y0.4876 +G01 X-1.7670 Y0.4646 +G01 X-1.7765 Y0.4551 +G01 X-1.7765 Y0.3849 +G01 X-1.7670 Y0.3754 +G01 X-1.7575 Y0.3524 +G01 X-1.7575 Y0.3276 +G01 X-1.7670 Y0.3046 +G01 X-1.7846 Y0.2870 +G01 X-1.8076 Y0.2775 +G01 X-1.8324 Y0.2775 +G01 X-1.8554 Y0.2870 +G01 X-1.8649 Y0.2965 +G01 X-1.9513 Y0.2965 +G01 X-1.9581 Y0.2965 +G01 X-1.9570 Y0.2954 +G01 X-1.9475 Y0.2724 +G01 X-1.9475 Y0.2476 +G01 X-1.9570 Y0.2246 +G01 X-1.9746 Y0.2070 +G01 X-1.9976 Y0.1975 +G01 X-2.0224 Y0.1975 +G01 X-2.0454 Y0.2070 +G01 X-2.0630 Y0.2246 +G01 X-2.0725 Y0.2476 +G01 X-2.0725 Y0.2724 +G01 X-2.0630 Y0.2954 +G01 X-2.0535 Y0.3049 +G01 X-2.0443 Y0.3330 +G01 X-2.0269 Y0.3569 +G01 X-2.0030 Y0.3743 +G01 X-1.9748 Y0.3835 +G01 X-1.9600 Y0.3835 +G01 X-1.9513 Y0.3835 +G01 X-1.8649 Y0.3835 +G01 X-1.8635 Y0.3849 +G01 X-1.8635 Y0.4551 +G01 X-1.8649 Y0.4565 +G01 X-1.8930 Y0.4657 +G01 X-1.9169 Y0.4831 +G01 X-1.9343 Y0.5070 +G01 X-1.9401 Y0.5249 +G01 X-1.9603 Y0.5450 +G01 X-1.9603 Y0.5950 +G01 X-1.9388 Y0.6165 +G01 X-1.9651 Y0.6165 +G01 X-1.9746 Y0.6070 +G01 X-1.9976 Y0.5975 +G01 X-2.0224 Y0.5975 +G01 X-2.0454 Y0.6070 +G01 X-2.0549 Y0.6165 +G01 X-2.0900 Y0.6165 +G01 X-2.0910 Y0.6164 +G01 X-2.0929 Y0.6158 +G01 X-2.0946 Y0.6146 +G01 X-2.0958 Y0.6129 +G01 X-2.0964 Y0.6110 +G01 X-2.0965 Y0.6100 +G01 X-2.0965 Y0.6013 +G01 X-2.0965 Y0.2964 +G01 X-2.0835 Y0.2834 +G01 X-2.0835 Y0.2366 +G01 X-2.1166 Y0.2035 +G01 X-2.1634 Y0.2035 +G01 X-2.1965 Y0.2366 +G01 X-2.1965 Y0.2834 +G01 X-2.1835 Y0.2964 +G01 X-2.1835 Y0.6013 +G01 X-2.1835 Y0.6100 +G01 X-2.1835 Y0.6248 +G01 X-2.1743 Y0.6530 +G01 X-2.1569 Y0.6769 +G01 X-2.1330 Y0.6943 +G01 X-2.1048 Y0.7035 +G01 X-2.0987 Y0.7035 +G01 X-2.0549 Y0.7035 +G01 X-2.0519 Y0.7065 +G01 X-2.1813 Y0.7065 +G01 X-2.1865 Y0.7065 +G01 X-2.1865 Y0.5987 +G01 X-2.1865 Y0.5973 +G01 X-2.1865 Y0.5813 +G01 X-2.1865 Y0.5734 +G01 X-2.1992 Y0.5427 +G01 X-2.2227 Y0.5192 +G01 X-2.2534 Y0.5065 +G01 X-2.2700 Y0.5065 +G01 X-2.2787 Y0.5065 +G01 X-2.4712 Y0.5065 +G01 X-2.4497 Y0.4850 +G01 X-2.4497 Y0.4350 +G01 X-2.4565 Y0.4282 +G01 X-2.4565 Y0.2706 +G01 X-2.4565 Y0.1935 +G01 X-2.4508 Y0.1935 +G01 X-2.4494 Y0.1935 +G01 X-1.8765 Y0.1935 +G01 X-1.8765 Y0.2234 +G01 X-1.8434 Y0.2565 +G01 X-1.7966 Y0.2565 +G01 X-1.7635 Y0.2234 +G01 X-1.7635 Y0.1766 +G01 X-1.7665 Y0.1736 +G01 X-1.7766 Y0.1424 +G01 X-1.7959 Y0.1159 +G01 X-1.8224 Y0.0966 +G01 X-1.8536 Y0.0865 +G01 X-1.8594 Y0.0865 +G01 X-2.4494 Y0.0865 +G01 X-2.4508 Y0.0865 +G01 X-2.4706 Y0.0865 +G01 X-2.4764 Y0.0865 +G01 X-2.5076 Y0.0966 +G01 X-2.5341 Y0.1159 +G01 X-2.5534 Y0.1424 +G01 X-2.5635 Y0.1736 +G01 X-2.5635 Y0.1794 +G01 X-2.5635 Y0.2165 +G01 X-2.6036 Y0.2165 +G01 X-2.6166 Y0.2035 +G01 X-2.6634 Y0.2035 +G01 X-2.6965 Y0.2366 +G01 X-2.6965 Y0.2834 +G01 X-2.6634 Y0.3165 +G01 X-2.6166 Y0.3165 +G01 X-2.6036 Y0.3035 +G01 X-2.5635 Y0.3035 +G01 X-2.5635 Y0.4282 +G01 X-2.5703 Y0.4350 +G01 X-2.5703 Y0.4850 +G01 X-2.5488 Y0.5065 +G01 X-2.8063 Y0.5065 +G01 X-2.8155 Y0.4973 +G01 X-2.8390 Y0.4876 +G01 X-3.0010 Y0.4876 +G01 X-3.0245 Y0.4973 +G01 X-3.0425 Y0.5153 +G01 X-3.0522 Y0.5388 +G01 X-3.0522 Y0.5643 +G01 X-3.0425 Y0.5878 +G01 X-3.0245 Y0.6058 +G01 X-3.0010 Y0.6156 +G01 X-2.8390 Y0.6156 +G01 X-2.8155 Y0.6058 +G01 X-2.8032 Y0.5935 +G01 X-2.2787 Y0.5935 +G01 X-2.2735 Y0.5935 +G01 X-2.2735 Y0.5973 +G01 X-2.2735 Y0.5987 +G01 X-2.2735 Y0.7187 +G01 X-2.2735 Y0.7266 +G01 X-2.2608 Y0.7573 +G01 X-2.2373 Y0.7808 +G01 X-2.2235 Y0.7865 +G01 X-2.2713 Y0.7865 +G01 X-2.2800 Y0.7865 +G01 X-2.2810 Y0.7864 +G01 X-2.2829 Y0.7858 +G01 X-2.2846 Y0.7846 +G01 X-2.2858 Y0.7829 +G01 X-2.2864 Y0.7810 +G01 X-2.2865 Y0.7800 +G01 X-2.2865 Y0.7513 +G01 X-2.2865 Y0.7474 +G01 X-2.2962 Y0.7240 +G01 X-2.3140 Y0.7062 +G01 X-2.3374 Y0.6965 +G01 X-2.3413 Y0.6965 +G01 X-2.3500 Y0.6965 +G01 X-2.3587 Y0.6965 +G01 X-2.6436 Y0.6965 +G01 X-2.6466 Y0.6935 +G01 X-2.6934 Y0.6935 +G01 X-2.7064 Y0.7065 +G01 X-2.8032 Y0.7065 +G01 X-2.8155 Y0.6942 +G01 X-2.8390 Y0.6844 +G01 X-3.0010 Y0.6844 +G01 X-3.0245 Y0.6942 +G01 X-3.0425 Y0.7122 +G01 X-3.0522 Y0.7357 +G01 X-3.0522 Y0.7612 +G01 X-3.0425 Y0.7847 +G01 X-3.0245 Y0.8027 +G01 X-3.0010 Y0.8124 +G01 X-2.8390 Y0.8124 +G01 X-2.8155 Y0.8027 +G01 X-2.8063 Y0.7935 +G01 X-2.7064 Y0.7935 +G01 X-2.6934 Y0.8065 +G01 X-2.6466 Y0.8065 +G01 X-2.6236 Y0.7835 +G01 X-2.3735 Y0.7835 +G01 X-2.3735 Y0.7887 +G01 X-2.3735 Y0.7948 +G01 X-2.3643 Y0.8230 +G01 X-2.3469 Y0.8469 +G01 X-2.3230 Y0.8643 +G01 X-2.3163 Y0.8665 +G01 X-2.4682 Y0.8665 +G01 X-2.4850 Y0.8497 +G01 X-2.5350 Y0.8497 +G01 X-2.5518 Y0.8665 +G01 X-3.1013 Y0.8665 +G01 X-3.1044 Y0.8665 +G01 X-3.1187 Y0.8665 +G01 X-3.1248 Y0.8665 +G01 X-3.1530 Y0.8757 +G01 X-3.1769 Y0.8931 +G01 X-3.1943 Y0.9170 +G01 X-3.2035 Y0.9452 +G01 X-3.2035 Y0.9513 +G01 X-3.2035 Y1.5736 +G01 X-3.2165 Y1.5866 +G01 X-3.2165 Y1.6334 +G01 X-3.2035 Y1.6464 +G01 X-3.2035 Y1.6813 +G01 X-3.2035 Y1.6825 +G01 X-3.2035 Y1.6987 +G01 X-3.2035 Y1.7048 +G01 X-3.1943 Y1.7330 +G01 X-3.1769 Y1.7569 +G01 X-3.1530 Y1.7743 +G01 X-3.1248 Y1.7835 +G01 X-3.1187 Y1.7835 +G01 X-2.9987 Y1.7835 +G01 X-2.9935 Y1.7835 +G01 X-2.9935 Y1.8513 +G01 X-2.9935 Y1.8544 +G01 X-2.9935 Y1.8687 +G01 X-2.9935 Y1.8748 +G01 X-2.9843 Y1.9030 +G01 X-2.9669 Y1.9269 +G01 X-2.9430 Y1.9443 +G01 X-2.9148 Y1.9535 +G01 X-2.9087 Y1.9535 +G01 X-2.0813 Y1.9535 +G01 X-2.0364 Y1.9535 +G01 X-2.0234 Y1.9665 +G01 X-1.9766 Y1.9665 +G01 X-1.9636 Y1.9535 +G01 X-1.7700 Y1.9535 +G01 X-1.7690 Y1.9536 +G01 X-1.7670 Y1.9542 +G01 X-1.7654 Y1.9554 +G01 X-1.7642 Y1.9570 +G01 X-1.7636 Y1.9590 +G01 X-1.7635 Y1.9600 +G01 X-1.7635 Y1.9650 +G01 X-1.7635 Y1.9687 +G01 X-1.7635 Y2.0687 +G01 X-1.7635 Y2.0748 +G01 X-1.7543 Y2.1030 +G01 X-1.7369 Y2.1269 +G01 X-1.7130 Y2.1443 +G01 X-1.6848 Y2.1535 +G01 X-1.6787 Y2.1535 +G01 X-1.2513 Y2.1535 +G01 X-1.2452 Y2.1535 +G01 X-1.2170 Y2.1443 +G01 X-1.1931 Y2.1269 +G01 X-1.1757 Y2.1030 +G01 X-1.1665 Y2.0748 +G01 X-1.1665 Y2.0687 +G01 X-1.1665 Y2.0597 +G01 X-1.1665 Y2.0513 +G01 X-1.1665 Y1.9100 +G01 X-1.1664 Y1.9090 +G01 X-1.1658 Y1.9070 +G01 X-1.1646 Y1.9054 +G01 X-1.1629 Y1.9042 +G01 X-1.1610 Y1.9036 +G01 X-1.1600 Y1.9035 +G01 X-1.1513 Y1.9035 +G01 X-0.8028 Y1.9035 +G01 X-0.7946 Y1.9117 +G01 X-0.7721 Y1.9210 +G01 X-0.7479 Y1.9210 +G01 X-0.7254 Y1.9117 +G01 X-0.7172 Y1.9035 +G01 X-0.2629 Y1.9035 +G01 X-0.2533 Y1.9035 +G01 X-0.2187 Y1.8922 +G01 X-0.1892 Y1.8708 +G01 X-0.1758 Y1.8524 +G01 X-0.1190 Y1.8524 +G01 X-0.0955 Y1.8427 +G01 X-0.0775 Y1.8247 +G01 X-0.0678 Y1.8012 +G01 X-0.0678 Y1.7757 +G01 X-0.0775 Y1.7522 +G01 X-0.0955 Y1.7342 +G01 X-0.1190 Y1.7244 +G01 X-0.2810 Y1.7244 +G01 X-0.3045 Y1.7342 +G01 X-0.3225 Y1.7522 +G01 X-0.3322 Y1.7757 +G01 X-0.3322 Y1.8012 +G01 X-0.3259 Y1.8165 +G01 X-0.7172 Y1.8165 +G01 X-0.7254 Y1.8083 +G01 X-0.7370 Y1.8035 +G01 X-0.6513 Y1.8035 +G01 X-0.6434 Y1.8035 +G01 X-0.6127 Y1.7908 +G01 X-0.5892 Y1.7673 +G01 X-0.5765 Y1.7366 +G01 X-0.5765 Y1.7287 +G01 X-0.5765 Y1.6500 +G01 X-0.5764 Y1.6490 +G01 X-0.5758 Y1.6470 +G01 X-0.5746 Y1.6454 +G01 X-0.5729 Y1.6442 +G01 X-0.5710 Y1.6436 +G01 X-0.5700 Y1.6435 +G01 X-0.5613 Y1.6435 +G01 X-0.3068 Y1.6435 +G01 X-0.3045 Y1.6458 +G01 X-0.2810 Y1.6556 +G01 X-0.1190 Y1.6556 +G01 X-0.0955 Y1.6458 +G01 X-0.0775 Y1.6278 +G01 X-0.0678 Y1.6043 +G01 X-0.0678 Y1.5788 +G01 X-0.0775 Y1.5553 +G01 X-0.0955 Y1.5373 +G01 X-0.1190 Y1.5276 +G01 X-0.2810 Y1.5276 +G01 X-0.3045 Y1.5373 +G01 X-0.3225 Y1.5553 +G01 X-0.3230 Y1.5565 +G01 X-0.5613 Y1.5565 +G01 X-0.5700 Y1.5565 +G01 X-0.5848 Y1.5565 +G01 X-0.6130 Y1.5657 +G01 X-0.6369 Y1.5831 +G01 X-0.6543 Y1.6070 +G01 X-0.6635 Y1.6352 +G01 X-0.6635 Y1.6413 +G01 X-0.6635 Y1.7165 +G01 X-1.3013 Y1.7165 +G01 X-1.3028 Y1.7165 +G01 X-1.3187 Y1.7165 +G01 X-1.3248 Y1.7165 +G01 X-1.3530 Y1.7257 +G01 X-1.3769 Y1.7431 +G01 X-1.3943 Y1.7670 +G01 X-1.4035 Y1.7952 +G01 X-1.4035 Y1.8013 +G01 X-1.4035 Y1.8172 +G01 X-1.4210 Y1.8347 +G01 X-1.4210 Y1.8853 +G01 X-1.4035 Y1.9028 +G01 X-1.4035 Y1.9600 +G01 X-1.4036 Y1.9610 +G01 X-1.4042 Y1.9630 +G01 X-1.4054 Y1.9646 +G01 X-1.4070 Y1.9658 +G01 X-1.4090 Y1.9664 +G01 X-1.4100 Y1.9665 +G01 X-1.4187 Y1.9665 +G01 X-1.5613 Y1.9665 +G01 X-1.5700 Y1.9665 +G01 X-1.5710 Y1.9664 +G01 X-1.5729 Y1.9658 +G01 X-1.5746 Y1.9646 +G01 X-1.5758 Y1.9629 +G01 X-1.5764 Y1.9610 +G01 X-1.5765 Y1.9600 +G01 X-1.5765 Y1.7987 +G01 X-1.5765 Y1.7713 +G01 X-1.5765 Y1.6387 +G01 X-1.5765 Y1.6300 +G01 X-1.5764 Y1.6290 +G01 X-1.5758 Y1.6270 +G01 X-1.5746 Y1.6254 +G01 X-1.5729 Y1.6242 +G01 X-1.5710 Y1.6236 +G01 X-1.5700 Y1.6235 +G01 X-1.5683 Y1.6235 +G01 X-1.5613 Y1.6235 +G01 X-1.1413 Y1.6235 +G01 X-1.1352 Y1.6235 +G01 X-1.1070 Y1.6143 +G01 X-1.0831 Y1.5969 +G01 X-1.0657 Y1.5730 +G01 X-1.0565 Y1.5448 +G01 X-1.0565 Y1.5300 +G01 X-1.0565 Y1.5213 +G01 X-1.0565 Y1.4381 +G01 X-1.0549 Y1.4420 +G01 X-1.0390 Y1.4579 +G01 X-1.0182 Y1.4665 +G01 X-0.8818 Y1.4665 +G01 X-0.8610 Y1.4579 +G01 X-0.8566 Y1.4535 +G01 X-0.5987 Y1.4535 +G01 X-0.5900 Y1.4535 +G01 X-0.5752 Y1.4535 +G01 X-0.5470 Y1.4443 +G01 X-0.5231 Y1.4269 +G01 X-0.5057 Y1.4030 +G01 X-0.4965 Y1.3748 +G01 X-0.4965 Y1.3687 +G01 X-0.4965 Y1.3584 +G01 X-0.4964 Y1.3574 +G01 X-0.4958 Y1.3555 +G01 X-0.4946 Y1.3538 +G01 X-0.4929 Y1.3526 +G01 X-0.4910 Y1.3520 +G01 X-0.4900 Y1.3519 +G01 X-0.4829 Y1.3519 +G01 X-0.4813 Y1.3519 +G01 X-0.3153 Y1.3519 +G01 X-0.3045 Y1.3627 +G01 X-0.2810 Y1.3724 +G01 X-0.1190 Y1.3724 +G01 X-0.0955 Y1.3627 +G01 X-0.0775 Y1.3447 +G01 X-0.0678 Y1.3212 +G01 X-0.0678 Y1.2957 +G01 X-0.0775 Y1.2722 +G01 X-0.0955 Y1.2542 +G01 X-0.1190 Y1.2444 +G01 X-0.2810 Y1.2444 +G01 X-0.3045 Y1.2542 +G01 X-0.3153 Y1.2649 +G01 X-0.4813 Y1.2649 +G01 X-0.4829 Y1.2649 +G01 X-0.4987 Y1.2649 +G01 X-0.5048 Y1.2649 +G01 X-0.5330 Y1.2741 +G01 X-0.5569 Y1.2915 +G01 X-0.5743 Y1.3154 +G01 X-0.5835 Y1.3436 +G01 X-0.5835 Y1.3498 +G01 X-0.5835 Y1.3600 +G01 X-0.5836 Y1.3610 +G01 X-0.5842 Y1.3630 +G01 X-0.5854 Y1.3646 +G01 X-0.5870 Y1.3658 +G01 X-0.5890 Y1.3664 +G01 X-0.5900 Y1.3665 +G01 X-0.5987 Y1.3665 +G01 X-0.8566 Y1.3665 +G01 X-0.8610 Y1.3621 +G01 X-0.8661 Y1.3600 +G01 X-0.8610 Y1.3579 +G01 X-0.8566 Y1.3535 +G01 X-0.7564 Y1.3535 +G01 X-0.7434 Y1.3665 +G01 X-0.6966 Y1.3665 +G01 X-0.6635 Y1.3334 +G01 X-0.6635 Y1.2866 +G01 X-0.6966 Y1.2535 +G01 X-0.7434 Y1.2535 +G01 X-0.7564 Y1.2665 +G01 X-0.8566 Y1.2665 +G01 X-0.8610 Y1.2621 +G01 X-0.8661 Y1.2600 +G01 X-0.8610 Y1.2579 +G01 X-0.8566 Y1.2535 +G01 X-0.4313 Y1.2535 +G01 X-0.4234 Y1.2535 +G01 X-0.3927 Y1.2408 +G01 X-0.3692 Y1.2173 +G01 X-0.3565 Y1.1866 +G01 X-0.3565 Y1.1787 +G01 X-0.3565 Y1.1717 +G01 X-0.3565 Y1.1700 +G01 X-0.3565 Y1.1616 +G01 X-0.3564 Y1.1606 +G01 X-0.3558 Y1.1586 +G01 X-0.3546 Y1.1570 +G01 X-0.3529 Y1.1558 +G01 X-0.3510 Y1.1551 +G01 X-0.3500 Y1.1551 +G01 X-0.3466 Y1.1551 +G01 X-0.3413 Y1.1551 +G01 X-0.3153 Y1.1551 +G01 X-0.3045 Y1.1658 +G01 X-0.2810 Y1.1756 +G01 X-0.1190 Y1.1756 +G01 X-0.0955 Y1.1658 +G01 X-0.0775 Y1.1478 +G01 X-0.0678 Y1.1243 +G01 X-0.0678 Y1.0988 +G01 X-0.0775 Y1.0753 +G01 X-0.0955 Y1.0573 +G01 X-0.1190 Y1.0476 +G01 X-0.2810 Y1.0476 +G01 X-0.3045 Y1.0573 +G01 X-0.3153 Y1.0681 +G01 X-0.3413 Y1.0681 +G01 X-0.3467 Y1.0681 +G01 X-0.3587 Y1.0681 +G01 X-0.3648 Y1.0681 +G01 X-0.3930 Y1.0772 +G01 X-0.4169 Y1.0946 +G01 X-0.4343 Y1.1186 +G01 X-0.4435 Y1.1468 +G01 X-0.4435 Y1.1529 +G01 X-0.4435 Y1.1613 +G01 X-0.4435 Y1.1665 +G01 X-0.8566 Y1.1665 +G01 X-0.8610 Y1.1621 +G01 X-0.8661 Y1.1600 +G01 X-0.8610 Y1.1579 +G01 X-0.8566 Y1.1535 +G01 X-0.5964 Y1.1535 +G01 X-0.5834 Y1.1665 +G01 X-0.5366 Y1.1665 +G01 X-0.5035 Y1.1334 +G01 X-0.5035 Y1.0866 +G01 X-0.5366 Y1.0535 +G01 X-0.5834 Y1.0535 +G01 X-0.5964 Y1.0665 +G01 X-0.8566 Y1.0665 +G01 X-0.8610 Y1.0621 +G01 X-0.8661 Y1.0600 +G01 X-0.8610 Y1.0579 +G01 X-0.8566 Y1.0535 +G01 X-0.4887 Y1.0535 +G01 X-0.4872 Y1.0535 +G01 X-0.4713 Y1.0535 +G01 X-0.4652 Y1.0535 +G01 X-0.4370 Y1.0443 +G01 X-0.4131 Y1.0269 +G01 X-0.3957 Y1.0030 +G01 X-0.3865 Y0.9748 +G01 X-0.3865 Y0.9687 +G01 X-0.3865 Y0.9535 +G01 X-0.3813 Y0.9535 +G01 X-0.3137 Y0.9535 +G01 X-0.3045 Y0.9627 +G01 X-0.2810 Y0.9724 +G01 X-0.1190 Y0.9724 +G01 X-0.0955 Y0.9627 +G01 X-0.0775 Y0.9447 +G01 X-0.0678 Y0.9212 +G01 X-0.0678 Y0.8957 +G01 X-0.0775 Y0.8722 +G01 X-0.0955 Y0.8542 +G01 X-0.1190 Y0.8444 +G01 X-0.2810 Y0.8444 +G01 X-0.3045 Y0.8542 +G01 X-0.3168 Y0.8665 +G01 X-0.3813 Y0.8665 +G01 X-0.3900 Y0.8665 +G01 X-0.4066 Y0.8665 +G01 X-0.4373 Y0.8792 +G01 X-0.4608 Y0.9027 +G01 X-0.4735 Y0.9334 +G01 X-0.4735 Y0.9413 +G01 X-0.4735 Y0.9600 +G01 X-0.4736 Y0.9610 +G01 X-0.4742 Y0.9629 +G01 X-0.4754 Y0.9646 +G01 X-0.4770 Y0.9658 +G01 X-0.4790 Y0.9664 +G01 X-0.4800 Y0.9665 +G01 X-0.4872 Y0.9665 +G01 X-0.4887 Y0.9665 +G01 X-0.8566 Y0.9665 +G01 X-0.8610 Y0.9621 +G01 X-0.8661 Y0.9600 +G01 X-0.8610 Y0.9579 +G01 X-0.8566 Y0.9535 +G01 X-0.8387 Y0.9535 +G01 X-0.8349 Y0.9535 +G01 X-0.8213 Y0.9535 +G01 X-0.8152 Y0.9535 +G01 X-0.7870 Y0.9443 +G01 X-0.7631 Y0.9269 +G01 X-0.7457 Y0.9030 +G01 X-0.7365 Y0.8748 +G01 X-0.7365 Y0.8687 +G01 X-0.7365 Y0.5764 +G01 X-0.7235 Y0.5634 +G01 X-0.7235 Y0.5166 +G01 X-0.7566 Y0.4835 +G01 X-0.8034 Y0.4835 +G01 X-0.8365 Y0.5166 +G01 X-0.8365 Y0.5634 +G01 X-0.8235 Y0.5764 +G01 X-0.8235 Y0.8600 +G01 X-0.8236 Y0.8610 +G01 X-0.8242 Y0.8629 +G01 X-0.8254 Y0.8646 +G01 X-0.8270 Y0.8658 +G01 X-0.8290 Y0.8664 +G01 X-0.8300 Y0.8665 +G01 X-0.8350 Y0.8665 +G01 X-0.8387 Y0.8665 +G01 X-0.8566 Y0.8665 +G01 X-0.8610 Y0.8621 +G01 X-0.8661 Y0.8600 +G01 X-0.8610 Y0.8579 +G01 X-0.8451 Y0.8420 +G01 X-0.8365 Y0.8212 +G01 X-0.8365 Y0.7988 +G01 X-0.8451 Y0.7780 +G01 X-0.8610 Y0.7621 +G01 X-0.8818 Y0.7535 +G01 X-1.0182 Y0.7535 +G01 X-1.0390 Y0.7621 +G01 X-1.0434 Y0.7665 +G01 X-1.0587 Y0.7665 +G01 X-1.0648 Y0.7665 +G01 X-1.0930 Y0.7757 +G01 X-1.1169 Y0.7931 +G01 X-1.1343 Y0.8170 +G01 X-1.1435 Y0.8452 +G01 X-1.1435 Y0.8513 +G01 X-1.1435 Y0.8819 +G01 X-1.1451 Y0.8780 +G01 X-1.1610 Y0.8621 +G01 X-1.1661 Y0.8600 +G01 X-1.1610 Y0.8579 +G01 X-1.1451 Y0.8420 +G01 X-1.1365 Y0.8212 +G01 X-1.1365 Y0.7988 +G01 X-1.1451 Y0.7780 +G01 X-1.1610 Y0.7621 +G01 X-1.1818 Y0.7535 +G01 X-1.3182 Y0.7535 +G01 X-1.3390 Y0.7621 +G01 X-1.3434 Y0.7665 +G01 X-1.5000 Y0.7665 +G01 X-1.5010 Y0.7664 +G01 X-1.5029 Y0.7658 +G01 X-1.5046 Y0.7646 +G01 X-1.5058 Y0.7629 +G01 X-1.5064 Y0.7610 +G01 X-1.5065 Y0.7600 +G01 X-1.5065 Y0.7532 +G01 X-1.5065 Y0.7513 +G01 X-1.5065 Y0.6964 +G01 X-1.4935 Y0.6834 +G01 X-1.4935 Y0.6366 +G01 X-1.5266 Y0.6035 +G01 X-1.5734 Y0.6035 +G01 X-1.6065 Y0.6366 +G01 X-1.6065 Y0.6834 +G01 X-1.5935 Y0.6964 +G01 X-1.5935 Y0.7513 +G01 X-1.5935 Y0.7532 +G01 X-1.5935 Y0.7687 +G01 X-1.5935 Y0.7748 +G01 X-1.5843 Y0.8030 +G01 X-1.5669 Y0.8269 +G01 X-1.5430 Y0.8443 +G01 X-1.5148 Y0.8535 +G01 X-1.5087 Y0.8535 +G01 X-1.3434 Y0.8535 +G01 X-1.3390 Y0.8579 +G01 X-1.3339 Y0.8600 +G01 X-1.3390 Y0.8621 +G01 X-1.3434 Y0.8665 +G01 X-1.5913 Y0.8665 +G01 X-1.6000 Y0.8665 +G01 X-1.6010 Y0.8664 +G01 X-1.6029 Y0.8658 +G01 X-1.6046 Y0.8646 +G01 X-1.6058 Y0.8629 +G01 X-1.6064 Y0.8610 +G01 X-1.6065 Y0.8600 +G01 X-1.6065 Y0.1587 +G01 X-1.6065 Y0.1500 +G01 X-1.6064 Y0.1490 +G01 X-1.6058 Y0.1470 +G01 X-1.6046 Y0.1454 +G01 X-1.6029 Y0.1442 +G01 X-1.6010 Y0.1436 +G01 X-1.6000 Y0.1435 +G01 X-1.1487 Y0.1435 +G01 X-1.1400 Y0.1435 +G01 X-1.1390 Y0.1436 +G01 X-1.1370 Y0.1442 +G01 X-1.1354 Y0.1454 +G01 X-1.1342 Y0.1470 +G01 X-1.1336 Y0.1490 +G01 X-1.1335 Y0.1500 +G01 X-1.1335 Y0.1913 +G01 X-1.1335 Y0.1924 +G01 X-1.1335 Y0.2087 +G01 X-1.1335 Y0.2148 +G01 X-1.1243 Y0.2430 +G01 X-1.1069 Y0.2669 +G01 X-1.0830 Y0.2843 +G01 X-1.0548 Y0.2935 +G01 X-1.0487 Y0.2935 +G01 X-0.8134 Y0.2935 +G01 X-0.8164 Y0.2965 +G01 X-1.2665 Y0.2965 +G01 X-1.2665 Y0.2264 +G01 X-1.2635 Y0.2234 +G01 X-1.2635 Y0.1766 +G01 X-1.2966 Y0.1435 +G01 X-1.3434 Y0.1435 +G01 X-1.3765 Y0.1766 +G01 X-1.3765 Y0.2234 +G01 X-1.3535 Y0.2464 +G01 X-1.3535 Y0.2965 +G01 X-1.3751 Y0.2965 +G01 X-1.3846 Y0.2870 +G01 X-1.4076 Y0.2775 +G01 X-1.4324 Y0.2775 +G01 X-1.4554 Y0.2870 +G01 X-1.4730 Y0.3046 +G01 X-1.4825 Y0.3276 +G01 X-1.4825 Y0.3524 +G01 X-1.4730 Y0.3754 +G01 X-1.4554 Y0.3930 +G01 X-1.4324 Y0.4025 +G01 X-1.4076 Y0.4025 +G01 X-1.3846 Y0.3930 +G01 X-1.3751 Y0.3835 +G01 X-1.3187 Y0.3835 +G01 X-1.3013 Y0.3835 +G01 X-0.8164 Y0.3835 +G01 X-0.8034 Y0.3965 +G01 X-0.7566 Y0.3965 +G01 X-0.7235 Y0.3634 +G01 X-0.7235 Y0.3166 +G01 X-0.7466 Y0.2935 +G01 X-0.5187 Y0.2935 +G01 X-0.5100 Y0.2935 +G01 X-0.5090 Y0.2936 +G01 X-0.5070 Y0.2942 +G01 X-0.5054 Y0.2954 +G01 X-0.5042 Y0.2970 +G01 X-0.5036 Y0.2990 +G01 X-0.5035 Y0.3000 +G01 X-0.5035 Y0.6513 +G01 X-0.5035 Y0.6535 +G01 X-0.5035 Y0.6687 +G01 X-0.5035 Y0.6748 +G01 X-0.4943 Y0.7030 +G01 X-0.4769 Y0.7269 +G01 X-0.4530 Y0.7443 +G01 X-0.4248 Y0.7535 +G01 X-0.4187 Y0.7535 +G01 X-0.3168 Y0.7535 +G01 X-0.3045 Y0.7658 +G01 X-0.2810 Y0.7756 +G01 X-0.1190 Y0.7756 +G01 X-0.0955 Y0.7658 +G01 X-0.0775 Y0.7478 +G01 X-0.0678 Y0.7243 +G01 X-0.0678 Y0.6988 +G01 X-0.0775 Y0.6753 +G01 X-0.0955 Y0.6573 +G01 X-0.1190 Y0.6476 +G01 X-0.2810 Y0.6476 +G01 X-0.3045 Y0.6573 +G01 X-0.3137 Y0.6665 +G01 X-0.4100 Y0.6665 +G01 X-0.4110 Y0.6664 +G01 X-0.4129 Y0.6658 +G01 X-0.4146 Y0.6646 +G01 X-0.4158 Y0.6629 +G01 X-0.4164 Y0.6610 +G01 X-0.4165 Y0.6600 +G01 X-0.4165 Y0.6535 +G01 X-0.4165 Y0.6513 +G01 X-0.4165 Y0.2913 +G01 X-0.4165 Y0.2852 +G00 Z0.1000 +G00 X-1.5625 Y1.6976 +G01 Z-0.0070 F10 +G01 X-1.5625 Y1.7224 F20 +G01 X-1.5530 Y1.7454 +G01 X-1.5435 Y1.7549 +G01 X-1.5435 Y1.8736 +G01 X-1.5565 Y1.8866 +G01 X-1.5565 Y1.9334 +G01 X-1.5234 Y1.9665 +G01 X-1.4766 Y1.9665 +G01 X-1.4435 Y1.9334 +G01 X-1.4435 Y1.8866 +G01 X-1.4565 Y1.8736 +G01 X-1.4565 Y1.7549 +G01 X-1.4470 Y1.7454 +G01 X-1.4375 Y1.7224 +G01 X-1.4375 Y1.7135 +G01 X-0.7613 Y1.7135 +G01 X-0.7552 Y1.7135 +G01 X-0.7270 Y1.7043 +G01 X-0.7031 Y1.6869 +G01 X-0.6857 Y1.6630 +G01 X-0.6765 Y1.6348 +G01 X-0.6765 Y1.6200 +G01 X-0.6765 Y1.6113 +G01 X-0.6765 Y1.5464 +G01 X-0.6635 Y1.5334 +G01 X-0.6635 Y1.4866 +G01 X-0.6966 Y1.4535 +G01 X-0.7434 Y1.4535 +G01 X-0.7765 Y1.4866 +G01 X-0.7765 Y1.5334 +G01 X-0.7635 Y1.5464 +G01 X-0.7635 Y1.6113 +G01 X-0.7635 Y1.6200 +G01 X-0.7636 Y1.6210 +G01 X-0.7642 Y1.6229 +G01 X-0.7654 Y1.6246 +G01 X-0.7670 Y1.6258 +G01 X-0.7690 Y1.6264 +G01 X-0.7700 Y1.6265 +G01 X-1.4476 Y1.6265 +G01 X-1.4592 Y1.6252 +G01 X-1.4867 Y1.6309 +G01 X-1.5111 Y1.6448 +G01 X-1.5143 Y1.6483 +G01 X-1.5354 Y1.6570 +G01 X-1.5530 Y1.6746 +G01 X-1.5625 Y1.6976 +G00 Z0.1000 +G00 X-0.5165 Y0.4987 +G01 Z-0.0070 F10 +G01 X-0.5165 Y0.4900 F20 +G01 X-0.5165 Y0.4752 +G01 X-0.5257 Y0.4470 +G01 X-0.5431 Y0.4231 +G01 X-0.5670 Y0.4057 +G01 X-0.5952 Y0.3965 +G01 X-0.6013 Y0.3965 +G01 X-1.3787 Y0.3965 +G01 X-1.3848 Y0.3965 +G01 X-1.4130 Y0.4057 +G01 X-1.4369 Y0.4231 +G01 X-1.4539 Y0.4464 +G01 X-1.4554 Y0.4470 +G01 X-1.4730 Y0.4646 +G01 X-1.4825 Y0.4876 +G01 X-1.4825 Y0.5124 +G01 X-1.4735 Y0.5342 +G01 X-1.4735 Y0.6736 +G01 X-1.4865 Y0.6866 +G01 X-1.4865 Y0.7334 +G01 X-1.4534 Y0.7665 +G01 X-1.4066 Y0.7665 +G01 X-1.3735 Y0.7334 +G01 X-1.3735 Y0.6866 +G01 X-1.3865 Y0.6736 +G01 X-1.3865 Y0.5538 +G01 X-1.3846 Y0.5530 +G01 X-1.3670 Y0.5354 +G01 X-1.3575 Y0.5124 +G01 X-1.3575 Y0.4876 +G01 X-1.3592 Y0.4835 +G01 X-0.6100 Y0.4835 +G01 X-0.6090 Y0.4836 +G01 X-0.6070 Y0.4842 +G01 X-0.6054 Y0.4854 +G01 X-0.6042 Y0.4870 +G01 X-0.6036 Y0.4890 +G01 X-0.6035 Y0.4900 +G01 X-0.6035 Y0.4987 +G01 X-0.6035 Y0.8736 +G01 X-0.6165 Y0.8866 +G01 X-0.6165 Y0.9334 +G01 X-0.5834 Y0.9665 +G01 X-0.5366 Y0.9665 +G01 X-0.5035 Y0.9334 +G01 X-0.5035 Y0.8866 +G01 X-0.5165 Y0.8736 +G01 X-0.5165 Y0.4987 +G00 Z0.1000 +G00 X-2.6105 Y1.8446 +G01 Z-0.0070 F10 +G01 X-2.6105 Y1.8334 F20 +G01 X-2.5991 Y1.8491 +G01 X-2.5792 Y1.8635 +G01 X-2.6294 Y1.8635 +G01 X-2.6105 Y1.8446 +G00 Z0.1000 +G00 X-2.6359 Y1.7700 +G01 Z-0.0070 F10 +G01 X-2.6324 Y1.7665 F20 +G01 X-2.6300 Y1.7665 +G01 X-2.6295 Y1.7665 +G01 X-2.6284 Y1.7669 +G01 X-2.6275 Y1.7675 +G01 X-2.6269 Y1.7684 +G01 X-2.6265 Y1.7695 +G01 X-2.6265 Y1.7700 +G01 X-2.6265 Y1.7775 +G01 X-2.6265 Y1.7792 +G01 X-2.6265 Y1.7794 +G01 X-2.6359 Y1.7700 +G00 Z0.1000 +G00 X-2.3884 Y1.7831 +G01 Z-0.0070 F10 +G01 X-2.3895 Y1.7835 F20 +G01 X-2.3900 Y1.7835 +G01 X-2.3994 Y1.7835 +G01 X-2.3900 Y1.7741 +G01 X-2.3865 Y1.7776 +G01 X-2.3865 Y1.7800 +G01 X-2.3865 Y1.7805 +G01 X-2.3869 Y1.7816 +G01 X-2.3875 Y1.7825 +G01 X-2.3884 Y1.7831 +G00 Z0.1000 +G00 X-2.4670 Y0.9565 +G01 Z-0.0070 F10 +G01 X-2.3433 Y0.9565 F20 +G01 X-2.3507 Y0.9596 +G01 X-2.3546 Y0.9635 +G01 X-2.4740 Y0.9635 +G01 X-2.4670 Y0.9565 +G00 Z0.1000 +G00 X-1.5461 Y1.3565 +G01 Z-0.0070 F10 +G01 X-1.5371 Y1.3655 F20 +G01 X-1.5130 Y1.3755 +G01 X-1.4870 Y1.3755 +G01 X-1.4629 Y1.3655 +G01 X-1.4565 Y1.3591 +G01 X-1.4565 Y1.4007 +G01 X-1.4565 Y1.4100 +G01 X-1.4565 Y1.4105 +G01 X-1.4569 Y1.4116 +G01 X-1.4575 Y1.4125 +G01 X-1.4584 Y1.4131 +G01 X-1.4595 Y1.4135 +G01 X-1.4600 Y1.4135 +G01 X-1.6507 Y1.4135 +G01 X-1.6524 Y1.4135 +G01 X-1.6692 Y1.4135 +G01 X-1.6753 Y1.4135 +G01 X-1.7044 Y1.4229 +G01 X-1.7291 Y1.4409 +G01 X-1.7470 Y1.4656 +G01 X-1.7565 Y1.4947 +G01 X-1.7565 Y1.5007 +G01 X-1.7565 Y1.6405 +G01 X-1.7946 Y1.6405 +G01 X-1.8076 Y1.6535 +G01 X-2.0307 Y1.6535 +G01 X-2.0400 Y1.6535 +G01 X-2.0412 Y1.6535 +G01 X-2.0492 Y1.6535 +G01 X-2.0553 Y1.6535 +G01 X-2.0844 Y1.6629 +G01 X-2.1091 Y1.6809 +G01 X-2.1270 Y1.7056 +G01 X-2.1365 Y1.7347 +G01 X-2.1365 Y1.7407 +G01 X-2.1365 Y1.7496 +G01 X-2.1365 Y1.7500 +G01 X-2.1365 Y1.7592 +G01 X-2.1365 Y1.8635 +G01 X-2.3408 Y1.8635 +G01 X-2.3209 Y1.8491 +G01 X-2.3029 Y1.8244 +G01 X-2.2935 Y1.7953 +G01 X-2.2935 Y1.7893 +G01 X-2.2935 Y1.7865 +G01 X-2.2530 Y1.7865 +G01 X-2.2362 Y1.8033 +G01 X-2.1838 Y1.8033 +G01 X-2.1467 Y1.7662 +G01 X-2.1467 Y1.7138 +G01 X-2.1838 Y1.6767 +G01 X-2.2362 Y1.6767 +G01 X-2.2530 Y1.6935 +G01 X-2.3024 Y1.6935 +G01 X-2.3154 Y1.6805 +G01 X-2.3305 Y1.6805 +G01 X-2.3305 Y1.6404 +G01 X-2.3428 Y1.6280 +G01 X-2.3425 Y1.6275 +G01 X-2.3416 Y1.6269 +G01 X-2.3405 Y1.6265 +G01 X-2.3400 Y1.6265 +G01 X-2.3326 Y1.6265 +G01 X-2.3307 Y1.6265 +G01 X-1.8407 Y1.6265 +G01 X-1.8328 Y1.6265 +G01 X-1.8010 Y1.6133 +G01 X-1.7767 Y1.5890 +G01 X-1.7635 Y1.5572 +G01 X-1.7635 Y1.5493 +G01 X-1.7635 Y1.5400 +G01 X-1.7635 Y1.5308 +G01 X-1.7635 Y1.3565 +G01 X-1.7607 Y1.3565 +G01 X-1.6492 Y1.3565 +G01 X-1.6307 Y1.3565 +G01 X-1.5461 Y1.3565 +G00 Z0.1000 +G00 X-2.8637 Y1.3857 +G01 Z-0.0070 F10 +G01 X-2.8873 Y1.3760 F20 +G01 X-2.9119 Y1.3760 +G01 X-2.8905 Y1.3546 +G01 X-2.8905 Y1.3054 +G01 X-2.9094 Y1.2865 +G01 X-2.7246 Y1.2865 +G01 X-2.7201 Y1.2874 +G01 X-2.7173 Y1.2869 +G01 X-2.6946 Y1.3095 +G01 X-2.6454 Y1.3095 +G01 X-2.6105 Y1.2746 +G01 X-2.6105 Y1.2254 +G01 X-2.6454 Y1.1905 +G01 X-2.6766 Y1.1905 +G01 X-2.6999 Y1.1858 +G01 X-2.7321 Y1.1922 +G01 X-2.7341 Y1.1935 +G01 X-3.0292 Y1.1935 +G01 X-3.0353 Y1.1935 +G01 X-3.0644 Y1.2029 +G01 X-3.0891 Y1.2209 +G01 X-3.1070 Y1.2456 +G01 X-3.1135 Y1.2655 +G01 X-3.1135 Y0.9600 +G01 X-3.1135 Y0.9595 +G01 X-3.1131 Y0.9584 +G01 X-3.1125 Y0.9575 +G01 X-3.1116 Y0.9569 +G01 X-3.1105 Y0.9565 +G01 X-3.1100 Y0.9565 +G01 X-3.1040 Y0.9565 +G01 X-3.1007 Y0.9565 +G01 X-2.5530 Y0.9565 +G01 X-2.5460 Y0.9635 +G01 X-2.9092 Y0.9635 +G01 X-2.9153 Y0.9635 +G01 X-2.9444 Y0.9729 +G01 X-2.9691 Y0.9909 +G01 X-2.9870 Y1.0156 +G01 X-2.9965 Y1.0447 +G01 X-2.9965 Y1.0507 +G01 X-2.9965 Y1.0924 +G01 X-3.0095 Y1.1054 +G01 X-3.0095 Y1.1546 +G01 X-2.9746 Y1.1895 +G01 X-2.9254 Y1.1895 +G01 X-2.8905 Y1.1546 +G01 X-2.8905 Y1.1054 +G01 X-2.9035 Y1.0924 +G01 X-2.9035 Y1.0600 +G01 X-2.9035 Y1.0594 +G01 X-2.9031 Y1.0584 +G01 X-2.9025 Y1.0575 +G01 X-2.9016 Y1.0569 +G01 X-2.9005 Y1.0565 +G01 X-2.9000 Y1.0565 +G01 X-2.3546 Y1.0565 +G01 X-2.3511 Y1.0600 +G01 X-2.3674 Y1.0763 +G01 X-2.3765 Y1.0982 +G01 X-2.3765 Y1.1218 +G01 X-2.3674 Y1.1437 +G01 X-2.3511 Y1.1600 +G01 X-2.3546 Y1.1635 +G01 X-2.4607 Y1.1635 +G01 X-2.4622 Y1.1635 +G01 X-2.4792 Y1.1635 +G01 X-2.4853 Y1.1635 +G01 X-2.5144 Y1.1729 +G01 X-2.5391 Y1.1909 +G01 X-2.5570 Y1.2156 +G01 X-2.5665 Y1.2447 +G01 X-2.5665 Y1.2507 +G01 X-2.5665 Y1.3935 +G01 X-2.8560 Y1.3935 +G01 X-2.8637 Y1.3857 +G00 Z0.1000 +G00 X-2.5609 Y1.7009 +G01 Z-0.0070 F10 +G01 X-2.5609 Y1.7009 F20 +G01 X-2.5856 Y1.6829 +G01 X-2.6147 Y1.6735 +G01 X-2.6207 Y1.6735 +G01 X-2.6324 Y1.6735 +G01 X-2.6364 Y1.6695 +G01 X-2.6354 Y1.6695 +G01 X-2.6224 Y1.6565 +G01 X-2.5465 Y1.6565 +G01 X-2.5465 Y1.7007 +G01 X-2.5465 Y1.7074 +G01 X-2.5465 Y1.7100 +G01 X-2.5465 Y1.7192 +G01 X-2.5465 Y1.7208 +G01 X-2.5609 Y1.7009 +G00 Z0.1000 +G00 X-2.5207 Y1.7835 +G01 Z-0.0070 F10 +G01 X-2.5300 Y1.7835 F20 +G01 X-2.5305 Y1.7835 +G01 X-2.5316 Y1.7831 +G01 X-2.5325 Y1.7825 +G01 X-2.5331 Y1.7816 +G01 X-2.5335 Y1.7805 +G01 X-2.5335 Y1.7800 +G01 X-2.5335 Y1.7792 +G01 X-2.5335 Y1.7775 +G01 X-2.5335 Y1.7607 +G01 X-2.5335 Y1.7547 +G01 X-2.5133 Y1.7748 +G01 X-2.4924 Y1.7835 +G01 X-2.5207 Y1.7835 +G00 Z0.1000 +G00 X-2.4495 Y1.6404 +G01 Z-0.0070 F10 +G01 X-2.4495 Y1.6805 F20 +G01 X-2.4535 Y1.6805 +G01 X-2.4535 Y1.6007 +G01 X-2.4606 Y1.5837 +G01 X-2.4735 Y1.5707 +G01 X-2.4735 Y1.4307 +G01 X-2.4735 Y1.2600 +G01 X-2.4735 Y1.2595 +G01 X-2.4731 Y1.2584 +G01 X-2.4725 Y1.2575 +G01 X-2.4716 Y1.2569 +G01 X-2.4705 Y1.2565 +G01 X-2.4700 Y1.2565 +G01 X-2.4622 Y1.2565 +G01 X-2.4607 Y1.2565 +G01 X-2.3546 Y1.2565 +G01 X-2.3511 Y1.2600 +G01 X-2.3674 Y1.2763 +G01 X-2.3765 Y1.2982 +G01 X-2.3765 Y1.3218 +G01 X-2.3674 Y1.3437 +G01 X-2.3507 Y1.3604 +G01 X-2.3288 Y1.3695 +G01 X-2.1912 Y1.3695 +G01 X-2.1693 Y1.3604 +G01 X-2.1654 Y1.3565 +G01 X-2.1392 Y1.3565 +G01 X-2.1300 Y1.3565 +G01 X-2.1273 Y1.3565 +G01 X-2.1207 Y1.3565 +G01 X-2.1168 Y1.3565 +G01 X-2.0923 Y1.3464 +G01 X-2.0739 Y1.3280 +G01 X-2.0674 Y1.3437 +G01 X-2.0507 Y1.3604 +G01 X-2.0288 Y1.3695 +G01 X-2.0065 Y1.3695 +G01 X-2.0065 Y1.4107 +G01 X-2.0065 Y1.4170 +G01 X-2.0130 Y1.4235 +G01 X-2.0192 Y1.4235 +G01 X-2.1670 Y1.4235 +G01 X-2.1838 Y1.4067 +G01 X-2.2362 Y1.4067 +G01 X-2.2395 Y1.4100 +G01 X-2.2735 Y1.3760 +G01 X-2.3265 Y1.3760 +G01 X-2.3640 Y1.4135 +G01 X-2.3640 Y1.4665 +G01 X-2.3265 Y1.5040 +G01 X-2.2735 Y1.5040 +G01 X-2.2695 Y1.5000 +G01 X-2.2362 Y1.5333 +G01 X-2.1838 Y1.5333 +G01 X-2.1670 Y1.5165 +G01 X-2.0192 Y1.5165 +G01 X-2.0130 Y1.5165 +G01 X-1.9962 Y1.5333 +G01 X-1.9438 Y1.5333 +G01 X-1.9067 Y1.4962 +G01 X-1.9067 Y1.4438 +G01 X-1.9139 Y1.4366 +G01 X-1.9135 Y1.4353 +G01 X-1.9135 Y1.4292 +G01 X-1.9135 Y1.4239 +G01 X-1.9135 Y1.4200 +G01 X-1.9135 Y1.4107 +G01 X-1.9135 Y1.3695 +G01 X-1.8912 Y1.3695 +G01 X-1.8693 Y1.3604 +G01 X-1.8565 Y1.3476 +G01 X-1.8565 Y1.5307 +G01 X-1.8565 Y1.5335 +G01 X-2.3307 Y1.5335 +G01 X-2.3326 Y1.5335 +G01 X-2.3492 Y1.5335 +G01 X-2.3553 Y1.5335 +G01 X-2.3844 Y1.5429 +G01 X-2.4091 Y1.5609 +G01 X-2.4270 Y1.5856 +G01 X-2.4365 Y1.6147 +G01 X-2.4365 Y1.6207 +G01 X-2.4365 Y1.6274 +G01 X-2.4495 Y1.6404 +G00 Z0.1000 +G00 X-2.6354 Y1.5505 +G01 Z-0.0070 F10 +G01 X-2.6846 Y1.5505 F20 +G01 X-2.7195 Y1.5854 +G01 X-2.7195 Y1.6346 +G01 X-2.6936 Y1.6605 +G01 X-2.6946 Y1.6605 +G01 X-2.7076 Y1.6735 +G01 X-2.7300 Y1.6735 +G01 X-2.7305 Y1.6735 +G01 X-2.7316 Y1.6731 +G01 X-2.7325 Y1.6725 +G01 X-2.7331 Y1.6716 +G01 X-2.7335 Y1.6705 +G01 X-2.7335 Y1.6700 +G01 X-2.7335 Y1.6621 +G01 X-2.7335 Y1.6607 +G01 X-2.7335 Y1.5907 +G01 X-2.7335 Y1.5828 +G01 X-2.7467 Y1.5510 +G01 X-2.7710 Y1.5267 +G01 X-2.8028 Y1.5135 +G01 X-2.8107 Y1.5135 +G01 X-2.8200 Y1.5135 +G01 X-2.8292 Y1.5135 +G01 X-2.9435 Y1.5135 +G01 X-2.9435 Y1.4870 +G01 X-2.9363 Y1.4943 +G01 X-2.9127 Y1.5040 +G01 X-2.8873 Y1.5040 +G01 X-2.8637 Y1.4943 +G01 X-2.8560 Y1.4865 +G01 X-2.5665 Y1.4865 +G01 X-2.5665 Y1.5635 +G01 X-2.6224 Y1.5635 +G01 X-2.6354 Y1.5505 +G00 Z0.1000 +G00 X-1.8192 Y1.2635 +G01 Z-0.0070 F10 +G01 X-1.8363 Y1.2706 F20 +G01 X-1.8494 Y1.2837 +G01 X-1.8495 Y1.2838 +G01 X-1.8526 Y1.2763 +G01 X-1.8689 Y1.2600 +G01 X-1.8554 Y1.2465 +G01 X-1.8165 Y1.2465 +G01 X-1.8165 Y1.2635 +G01 X-1.8192 Y1.2635 +G00 Z0.1000 +G00 X-2.9165 Y1.7314 +G01 Z-0.0070 F10 +G01 X-2.9167 Y1.7310 F20 +G01 X-2.9167 Y1.7310 +G01 X-2.9410 Y1.7067 +G01 X-2.9656 Y1.6965 +G01 X-2.9165 Y1.6965 +G01 X-2.9165 Y1.7314 +G00 Z0.1000 +G00 X-3.0225 Y1.2875 +G01 Z-0.0070 F10 +G01 X-3.0216 Y1.2869 F20 +G01 X-3.0205 Y1.2865 +G01 X-3.0200 Y1.2865 +G01 X-2.9906 Y1.2865 +G01 X-3.0095 Y1.3054 +G01 X-3.0095 Y1.3072 +G01 X-3.0233 Y1.3210 +G01 X-3.0235 Y1.3214 +G01 X-3.0235 Y1.2900 +G01 X-3.0235 Y1.2894 +G01 X-3.0231 Y1.2884 +G01 X-3.0225 Y1.2875 +G00 Z0.1000 +G00 X-3.0033 Y1.5948 +G01 Z-0.0070 F10 +G01 X-3.0033 Y1.5948 F20 +G01 X-2.9824 Y1.6035 +G01 X-3.0107 Y1.6035 +G01 X-3.0200 Y1.6035 +G01 X-3.0205 Y1.6035 +G01 X-3.0216 Y1.6031 +G01 X-3.0225 Y1.6025 +G01 X-3.0231 Y1.6016 +G01 X-3.0235 Y1.6005 +G01 X-3.0235 Y1.6000 +G01 X-3.0235 Y1.5747 +G01 X-3.0033 Y1.5948 +G00 Z0.1000 +G00 X-3.1100 Y1.6935 +G01 Z-0.0070 F10 +G01 X-3.1105 Y1.6935 F20 +G01 X-3.1105 Y1.6935 +G01 X-3.1116 Y1.6931 +G01 X-3.1125 Y1.6925 +G01 X-3.1131 Y1.6916 +G01 X-3.1135 Y1.6905 +G01 X-3.1135 Y1.6900 +G01 X-3.1135 Y1.6820 +G01 X-3.1135 Y1.6807 +G01 X-3.1135 Y1.6476 +G01 X-3.1078 Y1.6420 +G01 X-3.1070 Y1.6444 +G01 X-3.0891 Y1.6691 +G01 X-3.0644 Y1.6870 +G01 X-3.0445 Y1.6935 +G01 X-3.1100 Y1.6935 +G00 Z0.1000 +G00 X-2.8292 Y1.6065 +G01 Z-0.0070 F10 +G01 X-2.8265 Y1.6065 F20 +G01 X-2.8265 Y1.6576 +G01 X-2.8351 Y1.6367 +G01 X-2.8567 Y1.6151 +G01 X-2.8776 Y1.6065 +G01 X-2.8292 Y1.6065 +G00 Z0.1000 +G00 X-2.8170 Y1.7144 +G01 Z-0.0070 F10 +G01 X-2.8170 Y1.7144 F20 +G01 X-2.7991 Y1.7391 +G01 X-2.7744 Y1.7570 +G01 X-2.7453 Y1.7665 +G01 X-2.7392 Y1.7665 +G01 X-2.7339 Y1.7665 +G01 X-2.7300 Y1.7665 +G01 X-2.7076 Y1.7665 +G01 X-2.7041 Y1.7700 +G01 X-2.7076 Y1.7735 +G01 X-2.8107 Y1.7735 +G01 X-2.8200 Y1.7735 +G01 X-2.8205 Y1.7735 +G01 X-2.8216 Y1.7731 +G01 X-2.8225 Y1.7725 +G01 X-2.8231 Y1.7716 +G01 X-2.8235 Y1.7705 +G01 X-2.8235 Y1.7700 +G01 X-2.8235 Y1.6945 +G01 X-2.8170 Y1.7144 +G00 Z0.1000 +G00 X-2.9000 Y1.8635 +G01 Z-0.0070 F10 +G01 X-2.9005 Y1.8635 F20 +G01 X-2.9016 Y1.8631 +G01 X-2.9025 Y1.8625 +G01 X-2.9031 Y1.8616 +G01 X-2.9035 Y1.8605 +G01 X-2.9035 Y1.8600 +G01 X-2.9035 Y1.8540 +G01 X-2.9035 Y1.8507 +G01 X-2.9035 Y1.8192 +G01 X-2.8891 Y1.8391 +G01 X-2.8644 Y1.8570 +G01 X-2.8445 Y1.8635 +G01 X-2.9000 Y1.8635 +G00 Z0.1000 +G00 X-2.4467 Y0.4862 +G01 Z-0.0070 F10 +G01 X-2.4467 Y0.4338 F20 +G01 X-2.4535 Y0.4270 +G01 X-2.4535 Y0.2712 +G01 X-2.4535 Y0.1965 +G01 X-2.4503 Y0.1965 +G01 X-2.4488 Y0.1965 +G01 X-2.0278 Y0.1965 +G01 X-2.0471 Y0.2045 +G01 X-2.0655 Y0.2229 +G01 X-2.0755 Y0.2470 +G01 X-2.0755 Y0.2730 +G01 X-2.0655 Y0.2971 +G01 X-2.0561 Y0.3065 +G01 X-2.0470 Y0.3344 +G01 X-2.0291 Y0.3591 +G01 X-2.0044 Y0.3770 +G01 X-1.9753 Y0.3865 +G01 X-1.9693 Y0.3865 +G01 X-1.9608 Y0.3865 +G01 X-1.9600 Y0.3865 +G01 X-1.9507 Y0.3865 +G01 X-1.8665 Y0.3865 +G01 X-1.8665 Y0.4539 +G01 X-1.8944 Y0.4629 +G01 X-1.9191 Y0.4809 +G01 X-1.9370 Y0.5056 +G01 X-1.9428 Y0.5232 +G01 X-1.9633 Y0.5438 +G01 X-1.9633 Y0.5962 +G01 X-1.9460 Y0.6135 +G01 X-1.9639 Y0.6135 +G01 X-1.9729 Y0.6045 +G01 X-1.9970 Y0.5945 +G01 X-2.0230 Y0.5945 +G01 X-2.0471 Y0.6045 +G01 X-2.0561 Y0.6135 +G01 X-2.0900 Y0.6135 +G01 X-2.0905 Y0.6135 +G01 X-2.0916 Y0.6131 +G01 X-2.0925 Y0.6125 +G01 X-2.0931 Y0.6116 +G01 X-2.0935 Y0.6105 +G01 X-2.0935 Y0.6100 +G01 X-2.0935 Y0.6007 +G01 X-2.0935 Y0.2976 +G01 X-2.0805 Y0.2846 +G01 X-2.0805 Y0.2354 +G01 X-2.1154 Y0.2005 +G01 X-2.1646 Y0.2005 +G01 X-2.1995 Y0.2354 +G01 X-2.1995 Y0.2846 +G01 X-2.1865 Y0.2976 +G01 X-2.1865 Y0.5656 +G01 X-2.1967 Y0.5410 +G01 X-2.2210 Y0.5167 +G01 X-2.2528 Y0.5035 +G01 X-2.2607 Y0.5035 +G01 X-2.2663 Y0.5035 +G01 X-2.2700 Y0.5035 +G01 X-2.2792 Y0.5035 +G01 X-2.4640 Y0.5035 +G01 X-2.4467 Y0.4862 +G00 Z0.1000 +G00 X-0.8589 Y1.3600 +G01 Z-0.0070 F10 +G01 X-0.8554 Y1.3565 F20 +G01 X-0.7576 Y1.3565 +G01 X-0.7506 Y1.3635 +G01 X-0.8554 Y1.3635 +G01 X-0.8589 Y1.3600 +G00 Z0.1000 +G00 X-0.7795 Y1.4854 +G01 Z-0.0070 F10 +G01 X-0.7795 Y1.5346 F20 +G01 X-0.7665 Y1.5476 +G01 X-0.7665 Y1.6107 +G01 X-0.7665 Y1.6200 +G01 X-0.7665 Y1.6205 +G01 X-0.7669 Y1.6216 +G01 X-0.7675 Y1.6225 +G01 X-0.7684 Y1.6231 +G01 X-0.7695 Y1.6235 +G01 X-0.7700 Y1.6235 +G01 X-1.1255 Y1.6235 +G01 X-1.1056 Y1.6170 +G01 X-1.0809 Y1.5991 +G01 X-1.0629 Y1.5744 +G01 X-1.0535 Y1.5453 +G01 X-1.0535 Y1.5393 +G01 X-1.0535 Y1.5305 +G01 X-1.0535 Y1.5300 +G01 X-1.0535 Y1.5207 +G01 X-1.0535 Y1.4476 +G01 X-1.0407 Y1.4604 +G01 X-1.0188 Y1.4695 +G01 X-0.8812 Y1.4695 +G01 X-0.8593 Y1.4604 +G01 X-0.8554 Y1.4565 +G01 X-0.7506 Y1.4565 +G01 X-0.7795 Y1.4854 +G00 Z0.1000 +G00 X-0.8589 Y1.1600 +G01 Z-0.0070 F10 +G01 X-0.8554 Y1.1565 F20 +G01 X-0.5976 Y1.1565 +G01 X-0.5906 Y1.1635 +G01 X-0.8554 Y1.1635 +G01 X-0.8589 Y1.1600 +G00 Z0.1000 +G00 X-0.7576 Y1.2635 +G01 Z-0.0070 F10 +G01 X-0.8554 Y1.2635 F20 +G01 X-0.8589 Y1.2600 +G01 X-0.8554 Y1.2565 +G01 X-0.7506 Y1.2565 +G01 X-0.7576 Y1.2635 +G00 Z0.1000 +G00 X-1.6092 Y0.9565 +G01 Z-0.0070 F10 +G01 X-1.6004 Y0.9565 F20 +G01 X-1.6000 Y0.9565 +G01 X-1.5907 Y0.9565 +G01 X-1.3446 Y0.9565 +G01 X-1.3411 Y0.9600 +G01 X-1.3446 Y0.9635 +G01 X-1.6807 Y0.9635 +G01 X-1.6835 Y0.9635 +G01 X-1.6835 Y0.9631 +G01 X-1.6835 Y0.9607 +G01 X-1.6835 Y0.9092 +G01 X-1.6691 Y0.9291 +G01 X-1.6444 Y0.9470 +G01 X-1.6153 Y0.9565 +G01 X-1.6093 Y0.9565 +G00 Z0.1000 +G00 X-1.7109 Y0.7309 +G01 Z-0.0070 F10 +G01 X-1.7109 Y0.7309 F20 +G01 X-1.7266 Y0.7195 +G01 X-1.7254 Y0.7195 +G01 X-1.6965 Y0.6906 +G01 X-1.6965 Y0.7508 +G01 X-1.7109 Y0.7309 +G00 Z0.1000 +G00 X-1.5965 Y0.6976 +G01 Z-0.0070 F10 +G01 X-1.5965 Y0.7507 F20 +G01 X-1.5965 Y0.7527 +G01 X-1.5965 Y0.7692 +G01 X-1.5965 Y0.7753 +G01 X-1.5870 Y0.8044 +G01 X-1.5691 Y0.8291 +G01 X-1.5444 Y0.8470 +G01 X-1.5153 Y0.8565 +G01 X-1.5093 Y0.8565 +G01 X-1.3446 Y0.8565 +G01 X-1.3411 Y0.8600 +G01 X-1.3446 Y0.8635 +G01 X-1.5907 Y0.8635 +G01 X-1.6000 Y0.8635 +G01 X-1.6005 Y0.8635 +G01 X-1.6016 Y0.8631 +G01 X-1.6025 Y0.8625 +G01 X-1.6031 Y0.8616 +G01 X-1.6035 Y0.8605 +G01 X-1.6035 Y0.8600 +G01 X-1.6035 Y0.6906 +G01 X-1.5965 Y0.6976 +G00 Z0.1000 +G00 X-1.2635 Y0.2935 +G01 Z-0.0070 F10 +G01 X-1.2635 Y0.2276 F20 +G01 X-1.2605 Y0.2246 +G01 X-1.2605 Y0.1754 +G01 X-1.2894 Y0.1465 +G01 X-1.1492 Y0.1465 +G01 X-1.1402 Y0.1465 +G01 X-1.1400 Y0.1465 +G01 X-1.1395 Y0.1465 +G01 X-1.1384 Y0.1469 +G01 X-1.1375 Y0.1475 +G01 X-1.1369 Y0.1484 +G01 X-1.1365 Y0.1495 +G01 X-1.1365 Y0.1500 +G01 X-1.1365 Y0.2092 +G01 X-1.1365 Y0.2153 +G01 X-1.1270 Y0.2444 +G01 X-1.1091 Y0.2691 +G01 X-1.0844 Y0.2870 +G01 X-1.0645 Y0.2935 +G01 X-1.2635 Y0.2935 +G00 Z0.1000 +G00 X-1.3795 Y0.1754 +G01 Z-0.0070 F10 +G01 X-1.3795 Y0.2246 F20 +G01 X-1.3565 Y0.2476 +G01 X-1.3565 Y0.2935 +G01 X-1.3739 Y0.2935 +G01 X-1.3829 Y0.2845 +G01 X-1.4070 Y0.2745 +G01 X-1.4330 Y0.2745 +G01 X-1.4571 Y0.2845 +G01 X-1.4755 Y0.3029 +G01 X-1.4855 Y0.3270 +G01 X-1.4855 Y0.3530 +G01 X-1.4755 Y0.3771 +G01 X-1.4571 Y0.3955 +G01 X-1.4330 Y0.4055 +G01 X-1.4179 Y0.4055 +G01 X-1.4391 Y0.4209 +G01 X-1.4558 Y0.4439 +G01 X-1.4571 Y0.4445 +G01 X-1.4755 Y0.4629 +G01 X-1.4855 Y0.4870 +G01 X-1.4855 Y0.5130 +G01 X-1.4765 Y0.5348 +G01 X-1.4765 Y0.6724 +G01 X-1.4895 Y0.6854 +G01 X-1.4895 Y0.7346 +G01 X-1.4606 Y0.7635 +G01 X-1.5000 Y0.7635 +G01 X-1.5005 Y0.7635 +G01 X-1.5016 Y0.7631 +G01 X-1.5025 Y0.7625 +G01 X-1.5031 Y0.7616 +G01 X-1.5035 Y0.7605 +G01 X-1.5035 Y0.7600 +G01 X-1.5035 Y0.7527 +G01 X-1.5035 Y0.7507 +G01 X-1.5035 Y0.6976 +G01 X-1.4905 Y0.6846 +G01 X-1.4905 Y0.6354 +G01 X-1.5254 Y0.6005 +G01 X-1.5746 Y0.6005 +G01 X-1.6035 Y0.6294 +G01 X-1.6035 Y0.1592 +G01 X-1.6035 Y0.1500 +G01 X-1.6035 Y0.1495 +G01 X-1.6031 Y0.1484 +G01 X-1.6025 Y0.1475 +G01 X-1.6016 Y0.1469 +G01 X-1.6005 Y0.1465 +G01 X-1.6000 Y0.1465 +G01 X-1.3506 Y0.1465 +G01 X-1.3795 Y0.1754 +G00 Z0.1000 +G00 X-0.5976 Y1.0635 +G01 Z-0.0070 F10 +G01 X-0.8554 Y1.0635 F20 +G01 X-0.8589 Y1.0600 +G01 X-0.8554 Y1.0565 +G01 X-0.5906 Y1.0565 +G01 X-0.5976 Y1.0635 +G00 Z0.1000 +G00 X-0.8589 Y0.9600 +G01 Z-0.0070 F10 +G01 X-0.8554 Y0.9565 F20 +G01 X-0.8392 Y0.9565 +G01 X-0.8353 Y0.9565 +G01 X-0.8207 Y0.9565 +G01 X-0.8147 Y0.9565 +G01 X-0.7856 Y0.9470 +G01 X-0.7609 Y0.9291 +G01 X-0.7429 Y0.9044 +G01 X-0.7335 Y0.8753 +G01 X-0.7335 Y0.8693 +G01 X-0.7335 Y0.5776 +G01 X-0.7205 Y0.5646 +G01 X-0.7205 Y0.5154 +G01 X-0.7494 Y0.4865 +G01 X-0.6100 Y0.4865 +G01 X-0.6094 Y0.4865 +G01 X-0.6084 Y0.4869 +G01 X-0.6075 Y0.4875 +G01 X-0.6069 Y0.4884 +G01 X-0.6065 Y0.4895 +G01 X-0.6065 Y0.4900 +G01 X-0.6065 Y0.4992 +G01 X-0.6065 Y0.8724 +G01 X-0.6195 Y0.8854 +G01 X-0.6195 Y0.9346 +G01 X-0.5906 Y0.9635 +G01 X-0.8554 Y0.9635 +G01 X-0.8589 Y0.9600 +G00 Z0.1000 +G00 X-1.1589 Y0.8600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y0.8476 F20 +G01 X-1.1465 Y0.8507 +G01 X-1.1465 Y0.8724 +G01 X-1.1589 Y0.8600 +G00 Z0.1000 +G00 X-1.0411 Y0.9600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y0.9724 F20 +G01 X-1.0535 Y0.9476 +G01 X-1.0411 Y0.9600 +G00 Z0.1000 +G00 X-1.0411 Y1.0600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y1.0724 F20 +G01 X-1.0535 Y1.0476 +G01 X-1.0411 Y1.0600 +G00 Z0.1000 +G00 X-1.0411 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y1.1724 F20 +G01 X-1.0535 Y1.1476 +G01 X-1.0411 Y1.1600 +G00 Z0.1000 +G00 X-1.0411 Y1.2600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y1.2724 F20 +G01 X-1.0535 Y1.2476 +G01 X-1.0411 Y1.2600 +G00 Z0.1000 +G00 X-1.0411 Y1.3600 +G01 Z-0.0070 F10 +G01 X-1.0535 Y1.3724 F20 +G01 X-1.0535 Y1.3476 +G01 X-1.0411 Y1.3600 +G00 Z0.1000 +G00 X-1.1589 Y1.3600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y1.3476 F20 +G01 X-1.1465 Y1.3724 +G01 X-1.1589 Y1.3600 +G00 Z0.1000 +G00 X-1.1589 Y1.2600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y1.2476 F20 +G01 X-1.1465 Y1.2724 +G01 X-1.1589 Y1.2600 +G00 Z0.1000 +G00 X-1.1589 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y1.1476 F20 +G01 X-1.1465 Y1.1724 +G01 X-1.1589 Y1.1600 +G00 Z0.1000 +G00 X-1.1589 Y1.0600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y1.0476 F20 +G01 X-1.1465 Y1.0724 +G01 X-1.1589 Y1.0600 +G00 Z0.1000 +G00 X-1.1589 Y0.9600 +G01 Z-0.0070 F10 +G01 X-1.1465 Y0.9476 F20 +G01 X-1.1465 Y0.9724 +G01 X-1.1589 Y0.9600 +G00 Z0.1000 +G00 X-1.0525 Y0.8575 +G01 Z-0.0070 F10 +G01 X-1.0516 Y0.8569 F20 +G01 X-1.0505 Y0.8565 +G01 X-1.0500 Y0.8565 +G01 X-1.0446 Y0.8565 +G01 X-1.0411 Y0.8600 +G01 X-1.0535 Y0.8724 +G01 X-1.0535 Y0.8600 +G01 X-1.0535 Y0.8594 +G01 X-1.0531 Y0.8584 +G01 X-1.0525 Y0.8575 +G00 Z0.1000 +G00 X-2.0511 Y1.2600 +G01 Z-0.0070 F10 +G01 X-2.0635 Y1.2724 F20 +G01 X-2.0635 Y1.2476 +G01 X-2.0511 Y1.2600 +G00 Z0.1000 +G00 X-2.0511 Y1.1600 +G01 Z-0.0070 F10 +G01 X-2.0635 Y1.1724 F20 +G01 X-2.0635 Y1.1476 +G01 X-2.0511 Y1.1600 +G00 Z0.1000 +G00 X-2.1689 Y1.1600 +G01 Z-0.0070 F10 +G01 X-2.1565 Y1.1476 F20 +G01 X-2.1565 Y1.1724 +G01 X-2.1689 Y1.1600 +G00 Z0.1000 +G00 X-2.1689 Y1.2600 +G01 Z-0.0070 F10 +G01 X-2.1565 Y1.2476 F20 +G01 X-2.1565 Y1.2635 +G01 X-2.1654 Y1.2635 +G01 X-2.1689 Y1.2600 +G00 Z0.1000 +G00 X-2.1692 Y0.9565 +G01 Z-0.0070 F10 +G01 X-2.1600 Y0.9565 F20 +G01 X-2.1595 Y0.9565 +G01 X-2.1584 Y0.9569 +G01 X-2.1575 Y0.9575 +G01 X-2.1569 Y0.9584 +G01 X-2.1565 Y0.9595 +G01 X-2.1565 Y0.9600 +G01 X-2.1565 Y0.9724 +G01 X-2.1693 Y0.9596 +G01 X-2.1767 Y0.9565 +G01 X-2.1692 Y0.9565 +G00 Z0.1000 +G00 X-2.1689 Y1.0600 +G01 Z-0.0070 F10 +G01 X-2.1565 Y1.0476 F20 +G01 X-2.1565 Y1.0507 +G01 X-2.1565 Y1.0724 +G01 X-2.1689 Y1.0600 +G00 Z0.1000 +G00 X-2.0607 Y1.0565 +G01 Z-0.0070 F10 +G01 X-2.0546 Y1.0565 F20 +G01 X-2.0511 Y1.0600 +G01 X-2.0635 Y1.0724 +G01 X-2.0635 Y1.0593 +G01 X-2.0607 Y1.0565 +G00 Z0.1000 +G00 X-1.3574 Y1.3437 +G01 Z-0.0070 F10 +G01 X-1.3411 Y1.3600 F20 +G01 X-1.3446 Y1.3635 +G01 X-1.3507 Y1.3635 +G01 X-1.3600 Y1.3635 +G01 X-1.3605 Y1.3635 +G01 X-1.3616 Y1.3631 +G01 X-1.3625 Y1.3625 +G01 X-1.3631 Y1.3616 +G01 X-1.3635 Y1.3605 +G01 X-1.3635 Y1.3600 +G01 X-1.3635 Y1.3291 +G01 X-1.3574 Y1.3437 +G00 Z0.1000 +G00 X-2.0435 Y1.7592 +G01 Z-0.0070 F10 +G01 X-2.0435 Y1.7500 F20 +G01 X-2.0435 Y1.7495 +G01 X-2.0431 Y1.7484 +G01 X-2.0425 Y1.7475 +G01 X-2.0416 Y1.7469 +G01 X-2.0405 Y1.7465 +G01 X-2.0400 Y1.7465 +G01 X-2.0307 Y1.7465 +G01 X-2.0160 Y1.7465 +G01 X-2.0333 Y1.7638 +G01 X-2.0333 Y1.8162 +G01 X-1.9990 Y1.8505 +G01 X-2.0246 Y1.8505 +G01 X-2.0376 Y1.8635 +G01 X-2.0435 Y1.8635 +G01 X-2.0435 Y1.7592 +G00 Z0.1000 +G00 X-1.9726 Y1.8533 +G01 Z-0.0070 F10 +G01 X-1.9438 Y1.8533 F20 +G01 X-1.9270 Y1.8365 +G01 X-1.6665 Y1.8365 +G01 X-1.6665 Y1.9692 +G01 X-1.6665 Y1.9753 +G01 X-1.6570 Y2.0044 +G01 X-1.6391 Y2.0291 +G01 X-1.6144 Y2.0470 +G01 X-1.5853 Y2.0565 +G01 X-1.5793 Y2.0565 +G01 X-1.5705 Y2.0565 +G01 X-1.5700 Y2.0565 +G01 X-1.5607 Y2.0565 +G01 X-1.4192 Y2.0565 +G01 X-1.4100 Y2.0565 +G01 X-1.4007 Y2.0565 +G01 X-1.3947 Y2.0565 +G01 X-1.3656 Y2.0470 +G01 X-1.3409 Y2.0291 +G01 X-1.3229 Y2.0044 +G01 X-1.3135 Y1.9753 +G01 X-1.3135 Y1.9693 +G01 X-1.3135 Y1.9040 +G01 X-1.2960 Y1.8865 +G01 X-1.2960 Y1.8335 +G01 X-1.3135 Y1.8160 +G01 X-1.3135 Y1.8100 +G01 X-1.3135 Y1.8095 +G01 X-1.3131 Y1.8084 +G01 X-1.3125 Y1.8075 +G01 X-1.3116 Y1.8069 +G01 X-1.3105 Y1.8065 +G01 X-1.3100 Y1.8065 +G01 X-1.3023 Y1.8065 +G01 X-1.3007 Y1.8065 +G01 X-0.7970 Y1.8065 +G01 X-0.8040 Y1.8135 +G01 X-1.1507 Y1.8135 +G01 X-1.1600 Y1.8135 +G01 X-1.1602 Y1.8135 +G01 X-1.1692 Y1.8135 +G01 X-1.1753 Y1.8135 +G01 X-1.2044 Y1.8229 +G01 X-1.2291 Y1.8409 +G01 X-1.2470 Y1.8656 +G01 X-1.2565 Y1.8947 +G01 X-1.2565 Y1.9007 +G01 X-1.2565 Y2.0507 +G01 X-1.2565 Y2.0598 +G01 X-1.2565 Y2.0600 +G01 X-1.2565 Y2.0605 +G01 X-1.2569 Y2.0616 +G01 X-1.2575 Y2.0625 +G01 X-1.2584 Y2.0631 +G01 X-1.2595 Y2.0635 +G01 X-1.2600 Y2.0635 +G01 X-1.6700 Y2.0635 +G01 X-1.6705 Y2.0635 +G01 X-1.6716 Y2.0631 +G01 X-1.6725 Y2.0625 +G01 X-1.6731 Y2.0616 +G01 X-1.6735 Y2.0605 +G01 X-1.6735 Y2.0600 +G01 X-1.6735 Y1.9692 +G01 X-1.6735 Y1.9653 +G01 X-1.6735 Y1.9507 +G01 X-1.6735 Y1.9447 +G01 X-1.6829 Y1.9156 +G01 X-1.7009 Y1.8909 +G01 X-1.7256 Y1.8729 +G01 X-1.7547 Y1.8635 +G01 X-1.7607 Y1.8635 +G01 X-1.9624 Y1.8635 +G01 X-1.9726 Y1.8533 +G00 Z0.1000 +G00 X-1.6635 Y1.5095 +G01 Z-0.0070 F10 +G01 X-1.6631 Y1.5084 F20 +G01 X-1.6625 Y1.5075 +G01 X-1.6616 Y1.5069 +G01 X-1.6605 Y1.5065 +G01 X-1.6600 Y1.5065 +G01 X-1.6524 Y1.5065 +G01 X-1.6507 Y1.5065 +G01 X-1.4507 Y1.5065 +G01 X-1.4447 Y1.5065 +G01 X-1.4156 Y1.4970 +G01 X-1.3909 Y1.4791 +G01 X-1.3745 Y1.4565 +G01 X-1.3693 Y1.4565 +G01 X-1.3606 Y1.4565 +G01 X-1.3600 Y1.4565 +G01 X-1.3507 Y1.4565 +G01 X-1.3446 Y1.4565 +G01 X-1.3407 Y1.4604 +G01 X-1.3188 Y1.4695 +G01 X-1.1812 Y1.4695 +G01 X-1.1593 Y1.4604 +G01 X-1.1465 Y1.4476 +G01 X-1.1465 Y1.5207 +G01 X-1.1465 Y1.5300 +G01 X-1.1465 Y1.5305 +G01 X-1.1469 Y1.5316 +G01 X-1.1475 Y1.5325 +G01 X-1.1484 Y1.5331 +G01 X-1.1495 Y1.5335 +G01 X-1.1500 Y1.5335 +G01 X-1.5607 Y1.5335 +G01 X-1.5683 Y1.5335 +G01 X-1.5792 Y1.5335 +G01 X-1.5853 Y1.5335 +G01 X-1.6144 Y1.5429 +G01 X-1.6391 Y1.5609 +G01 X-1.6570 Y1.5856 +G01 X-1.6635 Y1.6055 +G01 X-1.6635 Y1.5100 +G01 X-1.6635 Y1.5095 +G00 Z0.1000 +G00 X-1.6665 Y1.7435 +G01 Z-0.0070 F10 +G01 X-1.7176 Y1.7435 F20 +G01 X-1.6967 Y1.7348 +G01 X-1.6751 Y1.7133 +G01 X-1.6665 Y1.6924 +G01 X-1.6665 Y1.7435 +G00 Z0.1000 +G00 X-1.3544 Y1.7229 +G01 Z-0.0070 F10 +G01 X-1.3544 Y1.7229 F20 +G01 X-1.3791 Y1.7409 +G01 X-1.3970 Y1.7656 +G01 X-1.4065 Y1.7947 +G01 X-1.4065 Y1.8007 +G01 X-1.4065 Y1.8160 +G01 X-1.4240 Y1.8335 +G01 X-1.4240 Y1.8865 +G01 X-1.4065 Y1.9040 +G01 X-1.4065 Y1.9600 +G01 X-1.4065 Y1.9605 +G01 X-1.4069 Y1.9616 +G01 X-1.4075 Y1.9625 +G01 X-1.4084 Y1.9631 +G01 X-1.4095 Y1.9635 +G01 X-1.4100 Y1.9635 +G01 X-1.4192 Y1.9635 +G01 X-1.4694 Y1.9635 +G01 X-1.4405 Y1.9346 +G01 X-1.4405 Y1.8854 +G01 X-1.4535 Y1.8724 +G01 X-1.4535 Y1.7561 +G01 X-1.4445 Y1.7471 +G01 X-1.4345 Y1.7230 +G01 X-1.4345 Y1.7165 +G01 X-1.3345 Y1.7165 +G01 X-1.3544 Y1.7229 +G00 Z0.1000 +G00 X-1.4895 Y1.1854 +G01 Z-0.0070 F10 +G01 X-1.4895 Y1.2346 F20 +G01 X-1.4744 Y1.2497 +G01 X-1.4870 Y1.2445 +G01 X-1.5130 Y1.2445 +G01 X-1.5371 Y1.2545 +G01 X-1.5461 Y1.2635 +G01 X-1.5767 Y1.2635 +G01 X-1.5767 Y1.2438 +G01 X-1.6138 Y1.2067 +G01 X-1.6662 Y1.2067 +G01 X-1.7033 Y1.2438 +G01 X-1.7033 Y1.2635 +G01 X-1.7235 Y1.2635 +G01 X-1.7235 Y1.2376 +G01 X-1.7105 Y1.2246 +G01 X-1.7105 Y1.1754 +G01 X-1.7294 Y1.1565 +G01 X-1.4606 Y1.1565 +G01 X-1.4895 Y1.1854 +G00 Z0.1000 +G00 X-1.3411 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.3574 Y1.1763 F20 +G01 X-1.3665 Y1.1982 +G01 X-1.3665 Y1.2218 +G01 X-1.3574 Y1.2437 +G01 X-1.3411 Y1.2600 +G01 X-1.3574 Y1.2763 +G01 X-1.3635 Y1.2909 +G01 X-1.3635 Y1.2692 +G01 X-1.3635 Y1.2600 +G01 X-1.3635 Y1.2588 +G01 X-1.3635 Y1.2415 +G01 X-1.3635 Y1.2380 +G01 X-1.3701 Y1.2135 +G01 X-1.3705 Y1.2127 +G01 X-1.3705 Y1.1854 +G01 X-1.3994 Y1.1565 +G01 X-1.3446 Y1.1565 +G01 X-1.3411 Y1.1600 +G00 Z0.1000 +G00 X-1.8654 Y1.0635 +G01 Z-0.0070 F10 +G01 X-1.8689 Y1.0600 F20 +G01 X-1.8565 Y1.0476 +G01 X-1.8565 Y1.0635 +G01 X-1.8654 Y1.0635 +G00 Z0.1000 +G00 X-1.7909 Y0.8109 +G01 Z-0.0070 F10 +G01 X-1.7909 Y0.8109 F20 +G01 X-1.8108 Y0.7965 +G01 X-1.7800 Y0.7965 +G01 X-1.7795 Y0.7965 +G01 X-1.7784 Y0.7969 +G01 X-1.7775 Y0.7975 +G01 X-1.7769 Y0.7984 +G01 X-1.7765 Y0.7995 +G01 X-1.7765 Y0.8000 +G01 X-1.7765 Y0.8308 +G01 X-1.7909 Y0.8109 +G00 Z0.1000 +G00 X-1.6992 Y1.0565 +G01 Z-0.0070 F10 +G01 X-1.6876 Y1.0565 F20 +G01 X-1.6807 Y1.0565 +G01 X-1.3446 Y1.0565 +G01 X-1.3411 Y1.0600 +G01 X-1.3446 Y1.0635 +G01 X-1.7635 Y1.0635 +G01 X-1.7635 Y1.0186 +G01 X-1.7633 Y1.0190 +G01 X-1.7390 Y1.0433 +G01 X-1.7072 Y1.0565 +G01 X-1.6992 Y1.0565 +G00 Z0.1000 +G00 X-2.1770 Y0.6544 +G01 Z-0.0070 F10 +G01 X-2.1770 Y0.6544 F20 +G01 X-2.1591 Y0.6791 +G01 X-2.1344 Y0.6970 +G01 X-2.1145 Y0.7035 +G01 X-2.1807 Y0.7035 +G01 X-2.1835 Y0.7035 +G01 X-2.1835 Y0.6345 +G01 X-2.1770 Y0.6544 +G00 Z0.1000 +G00 X-1.8565 Y0.9724 +G01 Z-0.0070 F10 +G01 X-1.8693 Y0.9596 F20 +G01 X-1.8912 Y0.9505 +G01 X-2.0288 Y0.9505 +G01 X-2.0507 Y0.9596 +G01 X-2.0546 Y0.9635 +G01 X-2.0635 Y0.9635 +G01 X-2.0635 Y0.9507 +G01 X-2.0635 Y0.9447 +G01 X-2.0729 Y0.9156 +G01 X-2.0909 Y0.8909 +G01 X-2.1108 Y0.8765 +G01 X-1.8600 Y0.8765 +G01 X-1.8595 Y0.8765 +G01 X-1.8584 Y0.8769 +G01 X-1.8575 Y0.8775 +G01 X-1.8569 Y0.8784 +G01 X-1.8565 Y0.8795 +G01 X-1.8565 Y0.8800 +G01 X-1.8565 Y0.9724 +G00 Z0.1000 +G00 X-1.5655 Y1.6970 +G01 Z-0.0070 F10 +G01 X-1.5655 Y1.7230 F20 +G01 X-1.5555 Y1.7471 +G01 X-1.5465 Y1.7561 +G01 X-1.5465 Y1.8724 +G01 X-1.5595 Y1.8854 +G01 X-1.5595 Y1.9346 +G01 X-1.5306 Y1.9635 +G01 X-1.5607 Y1.9635 +G01 X-1.5700 Y1.9635 +G01 X-1.5705 Y1.9635 +G01 X-1.5716 Y1.9631 +G01 X-1.5725 Y1.9625 +G01 X-1.5731 Y1.9616 +G01 X-1.5735 Y1.9605 +G01 X-1.5735 Y1.9600 +G01 X-1.5735 Y1.7992 +G01 X-1.5735 Y1.7707 +G01 X-1.5735 Y1.6392 +G01 X-1.5735 Y1.6300 +G01 X-1.5735 Y1.6295 +G01 X-1.5731 Y1.6284 +G01 X-1.5725 Y1.6275 +G01 X-1.5716 Y1.6269 +G01 X-1.5705 Y1.6265 +G01 X-1.5700 Y1.6265 +G01 X-1.5682 Y1.6265 +G01 X-1.5607 Y1.6265 +G01 X-1.4802 Y1.6265 +G01 X-1.4878 Y1.6281 +G01 X-1.5130 Y1.6424 +G01 X-1.5161 Y1.6458 +G01 X-1.5371 Y1.6545 +G01 X-1.5555 Y1.6729 +G01 X-1.5655 Y1.6970 +G00 Z0.1000 +G00 X-0.8395 Y0.5154 +G01 Z-0.0070 F10 +G01 X-0.8395 Y0.5646 F20 +G01 X-0.8265 Y0.5776 +G01 X-0.8265 Y0.8600 +G01 X-0.8265 Y0.8605 +G01 X-0.8269 Y0.8616 +G01 X-0.8275 Y0.8625 +G01 X-0.8284 Y0.8631 +G01 X-0.8295 Y0.8635 +G01 X-0.8300 Y0.8635 +G01 X-0.8353 Y0.8635 +G01 X-0.8392 Y0.8635 +G01 X-0.8554 Y0.8635 +G01 X-0.8589 Y0.8600 +G01 X-0.8426 Y0.8437 +G01 X-0.8335 Y0.8218 +G01 X-0.8335 Y0.7982 +G01 X-0.8426 Y0.7763 +G01 X-0.8593 Y0.7596 +G01 X-0.8812 Y0.7505 +G01 X-1.0188 Y0.7505 +G01 X-1.0407 Y0.7596 +G01 X-1.0446 Y0.7635 +G01 X-1.0592 Y0.7635 +G01 X-1.0653 Y0.7635 +G01 X-1.0944 Y0.7729 +G01 X-1.1191 Y0.7909 +G01 X-1.1335 Y0.8108 +G01 X-1.1335 Y0.7982 +G01 X-1.1426 Y0.7763 +G01 X-1.1593 Y0.7596 +G01 X-1.1812 Y0.7505 +G01 X-1.3188 Y0.7505 +G01 X-1.3407 Y0.7596 +G01 X-1.3446 Y0.7635 +G01 X-1.3994 Y0.7635 +G01 X-1.3705 Y0.7346 +G01 X-1.3705 Y0.6854 +G01 X-1.3835 Y0.6724 +G01 X-1.3835 Y0.5558 +G01 X-1.3829 Y0.5555 +G01 X-1.3645 Y0.5371 +G01 X-1.3545 Y0.5130 +G01 X-1.3545 Y0.4870 +G01 X-1.3547 Y0.4865 +G01 X-0.8106 Y0.4865 +G01 X-0.8395 Y0.5154 +G00 Z0.1000 +G00 X-1.3809 Y0.3935 +G01 Z-0.0070 F10 +G01 X-1.3739 Y0.3865 F20 +G01 X-1.3192 Y0.3865 +G01 X-1.3007 Y0.3865 +G01 X-0.8176 Y0.3865 +G01 X-0.8106 Y0.3935 +G01 X-1.3792 Y0.3935 +G01 X-1.3809 Y0.3935 +G00 Z0.1000 +G00 X-2.9400 Y1.3895 +G01 Z-0.0070 F10 +G01 X-2.9435 Y1.3930 F20 +G01 X-2.9435 Y1.3895 +G01 X-2.9400 Y1.3895 +G00 Z0.1000 +G00 X-0.2816 Y1.3754 +G01 Z-0.0070 F10 +G01 X-0.1184 Y1.3754 F20 +G01 X-0.0938 Y1.3652 +G01 X-0.0750 Y1.3464 +G01 X-0.0648 Y1.3218 +G01 X-0.0648 Y1.2951 +G01 X-0.0750 Y1.2705 +G01 X-0.0938 Y1.2516 +G01 X-0.1184 Y1.2414 +G01 X-0.2816 Y1.2414 +G01 X-0.3062 Y1.2516 +G01 X-0.3165 Y1.2619 +G01 X-0.4807 Y1.2619 +G01 X-0.4823 Y1.2619 +G01 X-0.4992 Y1.2619 +G01 X-0.5053 Y1.2619 +G01 X-0.5344 Y1.2714 +G01 X-0.5591 Y1.2893 +G01 X-0.5770 Y1.3141 +G01 X-0.5865 Y1.3431 +G01 X-0.5865 Y1.3492 +G01 X-0.5865 Y1.3600 +G01 X-0.5865 Y1.3605 +G01 X-0.5869 Y1.3616 +G01 X-0.5875 Y1.3625 +G01 X-0.5884 Y1.3631 +G01 X-0.5894 Y1.3635 +G01 X-0.5900 Y1.3635 +G01 X-0.5992 Y1.3635 +G01 X-0.6894 Y1.3635 +G01 X-0.6605 Y1.3346 +G01 X-0.6605 Y1.2854 +G01 X-0.6894 Y1.2565 +G01 X-0.4307 Y1.2565 +G01 X-0.4228 Y1.2565 +G01 X-0.3910 Y1.2433 +G01 X-0.3667 Y1.2190 +G01 X-0.3535 Y1.1872 +G01 X-0.3535 Y1.1792 +G01 X-0.3535 Y1.1700 +G01 X-0.3535 Y1.1616 +G01 X-0.3535 Y1.1610 +G01 X-0.3531 Y1.1600 +G01 X-0.3525 Y1.1591 +G01 X-0.3516 Y1.1585 +G01 X-0.3505 Y1.1581 +G01 X-0.3500 Y1.1581 +G01 X-0.3451 Y1.1581 +G01 X-0.3407 Y1.1581 +G01 X-0.3165 Y1.1581 +G01 X-0.3062 Y1.1684 +G01 X-0.2816 Y1.1786 +G01 X-0.1184 Y1.1786 +G01 X-0.0938 Y1.1684 +G01 X-0.0750 Y1.1495 +G01 X-0.0648 Y1.1249 +G01 X-0.0648 Y1.0982 +G01 X-0.0750 Y1.0736 +G01 X-0.0938 Y1.0548 +G01 X-0.1184 Y1.0446 +G01 X-0.2816 Y1.0446 +G01 X-0.3062 Y1.0548 +G01 X-0.3165 Y1.0651 +G01 X-0.3407 Y1.0651 +G01 X-0.3452 Y1.0651 +G01 X-0.3592 Y1.0651 +G01 X-0.3653 Y1.0651 +G01 X-0.3944 Y1.0745 +G01 X-0.4191 Y1.0925 +G01 X-0.4370 Y1.1172 +G01 X-0.4465 Y1.1463 +G01 X-0.4465 Y1.1523 +G01 X-0.4465 Y1.1607 +G01 X-0.4465 Y1.1635 +G01 X-0.5294 Y1.1635 +G01 X-0.5005 Y1.1346 +G01 X-0.5005 Y1.0854 +G01 X-0.5294 Y1.0565 +G01 X-0.4892 Y1.0565 +G01 X-0.4878 Y1.0565 +G01 X-0.4707 Y1.0565 +G01 X-0.4647 Y1.0565 +G01 X-0.4356 Y1.0470 +G01 X-0.4109 Y1.0291 +G01 X-0.3929 Y1.0044 +G01 X-0.3835 Y0.9753 +G01 X-0.3835 Y0.9693 +G01 X-0.3835 Y0.9565 +G01 X-0.3149 Y0.9565 +G01 X-0.3062 Y0.9652 +G01 X-0.2816 Y0.9754 +G01 X-0.1184 Y0.9754 +G01 X-0.0938 Y0.9652 +G01 X-0.0750 Y0.9464 +G01 X-0.0648 Y0.9218 +G01 X-0.0648 Y0.8951 +G01 X-0.0750 Y0.8705 +G01 X-0.0938 Y0.8516 +G01 X-0.1184 Y0.8414 +G01 X-0.2816 Y0.8414 +G01 X-0.3062 Y0.8516 +G01 X-0.3181 Y0.8635 +G01 X-0.3992 Y0.8635 +G01 X-0.4072 Y0.8635 +G01 X-0.4390 Y0.8767 +G01 X-0.4633 Y0.9010 +G01 X-0.4765 Y0.9328 +G01 X-0.4765 Y0.9407 +G01 X-0.4765 Y0.9600 +G01 X-0.4765 Y0.9605 +G01 X-0.4769 Y0.9616 +G01 X-0.4775 Y0.9625 +G01 X-0.4784 Y0.9631 +G01 X-0.4795 Y0.9635 +G01 X-0.4800 Y0.9635 +G01 X-0.4878 Y0.9635 +G01 X-0.4892 Y0.9635 +G01 X-0.5294 Y0.9635 +G01 X-0.5005 Y0.9346 +G01 X-0.5005 Y0.8854 +G01 X-0.5135 Y0.8724 +G01 X-0.5135 Y0.4992 +G01 X-0.5135 Y0.4900 +G01 X-0.5135 Y0.4868 +G01 X-0.5135 Y0.4807 +G01 X-0.5135 Y0.4747 +G01 X-0.5229 Y0.4456 +G01 X-0.5409 Y0.4209 +G01 X-0.5656 Y0.4030 +G01 X-0.5947 Y0.3935 +G01 X-0.6007 Y0.3935 +G01 X-0.7494 Y0.3935 +G01 X-0.7205 Y0.3646 +G01 X-0.7205 Y0.3154 +G01 X-0.7394 Y0.2965 +G01 X-0.5192 Y0.2965 +G01 X-0.5100 Y0.2965 +G01 X-0.5095 Y0.2965 +G01 X-0.5084 Y0.2969 +G01 X-0.5075 Y0.2975 +G01 X-0.5069 Y0.2984 +G01 X-0.5065 Y0.2995 +G01 X-0.5065 Y0.3000 +G01 X-0.5065 Y0.6507 +G01 X-0.5065 Y0.6528 +G01 X-0.5065 Y0.6692 +G01 X-0.5065 Y0.6753 +G01 X-0.4970 Y0.7044 +G01 X-0.4791 Y0.7291 +G01 X-0.4544 Y0.7470 +G01 X-0.4253 Y0.7565 +G01 X-0.4193 Y0.7565 +G01 X-0.3181 Y0.7565 +G01 X-0.3062 Y0.7684 +G01 X-0.2816 Y0.7786 +G01 X-0.1184 Y0.7786 +G01 X-0.0938 Y0.7684 +G01 X-0.0750 Y0.7495 +G01 X-0.0648 Y0.7249 +G01 X-0.0648 Y0.6982 +G01 X-0.0750 Y0.6736 +G01 X-0.0938 Y0.6548 +G01 X-0.1184 Y0.6446 +G01 X-0.2816 Y0.6446 +G01 X-0.3062 Y0.6548 +G01 X-0.3149 Y0.6635 +G01 X-0.4100 Y0.6635 +G01 X-0.4105 Y0.6635 +G01 X-0.4116 Y0.6631 +G01 X-0.4125 Y0.6625 +G01 X-0.4131 Y0.6616 +G01 X-0.4135 Y0.6605 +G01 X-0.4135 Y0.6600 +G01 X-0.4135 Y0.6528 +G01 X-0.4135 Y0.6507 +G01 X-0.4135 Y0.2907 +G01 X-0.4135 Y0.2847 +G01 X-0.4229 Y0.2556 +G01 X-0.4409 Y0.2309 +G01 X-0.4656 Y0.2129 +G01 X-0.4947 Y0.2035 +G01 X-0.5007 Y0.2035 +G01 X-0.5096 Y0.2035 +G01 X-0.5100 Y0.2035 +G01 X-0.5192 Y0.2035 +G01 X-1.0400 Y0.2035 +G01 X-1.0405 Y0.2035 +G01 X-1.0416 Y0.2031 +G01 X-1.0425 Y0.2025 +G01 X-1.0431 Y0.2016 +G01 X-1.0435 Y0.2005 +G01 X-1.0435 Y0.2000 +G01 X-1.0435 Y0.1407 +G01 X-1.0435 Y0.1347 +G01 X-1.0529 Y0.1056 +G01 X-1.0709 Y0.0809 +G01 X-1.0956 Y0.0629 +G01 X-1.1247 Y0.0535 +G01 X-1.1307 Y0.0535 +G01 X-1.1403 Y0.0535 +G01 X-1.1492 Y0.0535 +G01 X-1.6092 Y0.0535 +G01 X-1.6153 Y0.0535 +G01 X-1.6444 Y0.0629 +G01 X-1.6691 Y0.0809 +G01 X-1.6870 Y0.1056 +G01 X-1.6965 Y0.1347 +G01 X-1.6965 Y0.1407 +G01 X-1.6965 Y0.1500 +G01 X-1.6965 Y0.1592 +G01 X-1.6965 Y0.6294 +G01 X-1.7254 Y0.6005 +G01 X-1.7746 Y0.6005 +G01 X-1.7876 Y0.6135 +G01 X-1.8540 Y0.6135 +G01 X-1.8367 Y0.5962 +G01 X-1.8367 Y0.5640 +G01 X-1.8330 Y0.5655 +G01 X-1.8070 Y0.5655 +G01 X-1.7829 Y0.5555 +G01 X-1.7645 Y0.5371 +G01 X-1.7545 Y0.5130 +G01 X-1.7545 Y0.4870 +G01 X-1.7645 Y0.4629 +G01 X-1.7735 Y0.4539 +G01 X-1.7735 Y0.3861 +G01 X-1.7645 Y0.3771 +G01 X-1.7545 Y0.3530 +G01 X-1.7545 Y0.3270 +G01 X-1.7645 Y0.3029 +G01 X-1.7829 Y0.2845 +G01 X-1.8070 Y0.2745 +G01 X-1.8330 Y0.2745 +G01 X-1.8571 Y0.2845 +G01 X-1.8661 Y0.2935 +G01 X-1.9507 Y0.2935 +G01 X-1.9530 Y0.2935 +G01 X-1.9445 Y0.2730 +G01 X-1.9445 Y0.2470 +G01 X-1.9545 Y0.2229 +G01 X-1.9729 Y0.2045 +G01 X-1.9922 Y0.1965 +G01 X-1.8795 Y0.1965 +G01 X-1.8795 Y0.2246 +G01 X-1.8446 Y0.2595 +G01 X-1.7954 Y0.2595 +G01 X-1.7605 Y0.2246 +G01 X-1.7605 Y0.1754 +G01 X-1.7639 Y0.1720 +G01 X-1.7739 Y0.1411 +G01 X-1.7938 Y0.1138 +G01 X-1.8210 Y0.0939 +G01 X-1.8531 Y0.0835 +G01 X-1.8588 Y0.0835 +G01 X-2.4488 Y0.0835 +G01 X-2.4503 Y0.0835 +G01 X-2.4712 Y0.0835 +G01 X-2.4769 Y0.0835 +G01 X-2.5089 Y0.0939 +G01 X-2.5362 Y0.1138 +G01 X-2.5561 Y0.1410 +G01 X-2.5665 Y0.1731 +G01 X-2.5665 Y0.1788 +G01 X-2.5665 Y0.2135 +G01 X-2.6024 Y0.2135 +G01 X-2.6154 Y0.2005 +G01 X-2.6646 Y0.2005 +G01 X-2.6995 Y0.2354 +G01 X-2.6995 Y0.2846 +G01 X-2.6646 Y0.3195 +G01 X-2.6154 Y0.3195 +G01 X-2.6024 Y0.3065 +G01 X-2.5665 Y0.3065 +G01 X-2.5665 Y0.4270 +G01 X-2.5733 Y0.4338 +G01 X-2.5733 Y0.4862 +G01 X-2.5560 Y0.5035 +G01 X-2.8051 Y0.5035 +G01 X-2.8138 Y0.4948 +G01 X-2.8384 Y0.4846 +G01 X-3.0016 Y0.4846 +G01 X-3.0262 Y0.4948 +G01 X-3.0450 Y0.5136 +G01 X-3.0552 Y0.5382 +G01 X-3.0552 Y0.5649 +G01 X-3.0450 Y0.5895 +G01 X-3.0262 Y0.6084 +G01 X-3.0016 Y0.6186 +G01 X-2.8384 Y0.6186 +G01 X-2.8138 Y0.6084 +G01 X-2.8019 Y0.5965 +G01 X-2.2792 Y0.5965 +G01 X-2.2765 Y0.5965 +G01 X-2.2765 Y0.5979 +G01 X-2.2765 Y0.5992 +G01 X-2.2765 Y0.7192 +G01 X-2.2765 Y0.7272 +G01 X-2.2633 Y0.7590 +G01 X-2.2390 Y0.7833 +G01 X-2.2386 Y0.7835 +G01 X-2.2707 Y0.7835 +G01 X-2.2800 Y0.7835 +G01 X-2.2805 Y0.7835 +G01 X-2.2816 Y0.7831 +G01 X-2.2825 Y0.7825 +G01 X-2.2831 Y0.7816 +G01 X-2.2835 Y0.7805 +G01 X-2.2835 Y0.7800 +G01 X-2.2835 Y0.7507 +G01 X-2.2835 Y0.7468 +G01 X-2.2936 Y0.7223 +G01 X-2.3123 Y0.7036 +G01 X-2.3368 Y0.6935 +G01 X-2.3407 Y0.6935 +G01 X-2.3500 Y0.6935 +G01 X-2.3592 Y0.6935 +G01 X-2.6424 Y0.6935 +G01 X-2.6454 Y0.6905 +G01 X-2.6946 Y0.6905 +G01 X-2.7076 Y0.7035 +G01 X-2.8019 Y0.7035 +G01 X-2.8138 Y0.6916 +G01 X-2.8384 Y0.6814 +G01 X-3.0016 Y0.6814 +G01 X-3.0262 Y0.6916 +G01 X-3.0450 Y0.7105 +G01 X-3.0552 Y0.7351 +G01 X-3.0552 Y0.7618 +G01 X-3.0450 Y0.7864 +G01 X-3.0262 Y0.8052 +G01 X-3.0016 Y0.8154 +G01 X-2.8384 Y0.8154 +G01 X-2.8138 Y0.8052 +G01 X-2.8051 Y0.7965 +G01 X-2.7076 Y0.7965 +G01 X-2.6946 Y0.8095 +G01 X-2.6454 Y0.8095 +G01 X-2.6224 Y0.7865 +G01 X-2.3765 Y0.7865 +G01 X-2.3765 Y0.7892 +G01 X-2.3765 Y0.7953 +G01 X-2.3670 Y0.8244 +G01 X-2.3491 Y0.8491 +G01 X-2.3292 Y0.8635 +G01 X-2.4670 Y0.8635 +G01 X-2.4838 Y0.8467 +G01 X-2.5362 Y0.8467 +G01 X-2.5530 Y0.8635 +G01 X-3.1007 Y0.8635 +G01 X-3.1040 Y0.8635 +G01 X-3.1192 Y0.8635 +G01 X-3.1253 Y0.8635 +G01 X-3.1544 Y0.8729 +G01 X-3.1791 Y0.8909 +G01 X-3.1970 Y0.9156 +G01 X-3.2065 Y0.9447 +G01 X-3.2065 Y0.9507 +G01 X-3.2065 Y1.5724 +G01 X-3.2195 Y1.5854 +G01 X-3.2195 Y1.6346 +G01 X-3.2065 Y1.6476 +G01 X-3.2065 Y1.6807 +G01 X-3.2065 Y1.6820 +G01 X-3.2065 Y1.6992 +G01 X-3.2065 Y1.7053 +G01 X-3.1970 Y1.7344 +G01 X-3.1791 Y1.7591 +G01 X-3.1544 Y1.7770 +G01 X-3.1253 Y1.7865 +G01 X-3.1193 Y1.7865 +G01 X-2.9992 Y1.7865 +G01 X-2.9965 Y1.7865 +G01 X-2.9965 Y1.8507 +G01 X-2.9965 Y1.8540 +G01 X-2.9965 Y1.8692 +G01 X-2.9965 Y1.8753 +G01 X-2.9870 Y1.9044 +G01 X-2.9691 Y1.9291 +G01 X-2.9444 Y1.9470 +G01 X-2.9153 Y1.9565 +G01 X-2.9093 Y1.9565 +G01 X-2.0807 Y1.9565 +G01 X-2.0376 Y1.9565 +G01 X-2.0246 Y1.9695 +G01 X-1.9754 Y1.9695 +G01 X-1.9624 Y1.9565 +G01 X-1.7700 Y1.9565 +G01 X-1.7695 Y1.9565 +G01 X-1.7684 Y1.9569 +G01 X-1.7675 Y1.9575 +G01 X-1.7669 Y1.9584 +G01 X-1.7665 Y1.9595 +G01 X-1.7665 Y1.9600 +G01 X-1.7665 Y1.9653 +G01 X-1.7665 Y1.9692 +G01 X-1.7665 Y2.0692 +G01 X-1.7665 Y2.0753 +G01 X-1.7570 Y2.1044 +G01 X-1.7391 Y2.1291 +G01 X-1.7144 Y2.1470 +G01 X-1.6853 Y2.1565 +G01 X-1.6793 Y2.1565 +G01 X-1.2507 Y2.1565 +G01 X-1.2447 Y2.1565 +G01 X-1.2156 Y2.1470 +G01 X-1.1909 Y2.1291 +G01 X-1.1729 Y2.1044 +G01 X-1.1635 Y2.0753 +G01 X-1.1635 Y2.0693 +G01 X-1.1635 Y2.0597 +G01 X-1.1635 Y2.0507 +G01 X-1.1635 Y1.9100 +G01 X-1.1635 Y1.9095 +G01 X-1.1631 Y1.9084 +G01 X-1.1625 Y1.9075 +G01 X-1.1616 Y1.9069 +G01 X-1.1605 Y1.9065 +G01 X-1.1600 Y1.9065 +G01 X-1.1507 Y1.9065 +G01 X-0.8040 Y1.9065 +G01 X-0.7963 Y1.9143 +G01 X-0.7727 Y1.9240 +G01 X-0.7473 Y1.9240 +G01 X-0.7237 Y1.9143 +G01 X-0.7160 Y1.9065 +G01 X-0.2623 Y1.9065 +G01 X-0.2529 Y1.9065 +G01 X-0.2173 Y1.8949 +G01 X-0.1870 Y1.8730 +G01 X-0.1743 Y1.8554 +G01 X-0.1184 Y1.8554 +G01 X-0.0938 Y1.8452 +G01 X-0.0750 Y1.8264 +G01 X-0.0648 Y1.8018 +G01 X-0.0648 Y1.7751 +G01 X-0.0750 Y1.7505 +G01 X-0.0938 Y1.7316 +G01 X-0.1184 Y1.7214 +G01 X-0.2816 Y1.7214 +G01 X-0.3062 Y1.7316 +G01 X-0.3250 Y1.7505 +G01 X-0.3352 Y1.7751 +G01 X-0.3352 Y1.8018 +G01 X-0.3304 Y1.8135 +G01 X-0.7160 Y1.8135 +G01 X-0.7230 Y1.8065 +G01 X-0.6507 Y1.8065 +G01 X-0.6428 Y1.8065 +G01 X-0.6110 Y1.7933 +G01 X-0.5867 Y1.7690 +G01 X-0.5735 Y1.7372 +G01 X-0.5735 Y1.7292 +G01 X-0.5735 Y1.6500 +G01 X-0.5735 Y1.6494 +G01 X-0.5731 Y1.6484 +G01 X-0.5725 Y1.6475 +G01 X-0.5716 Y1.6469 +G01 X-0.5705 Y1.6465 +G01 X-0.5700 Y1.6465 +G01 X-0.5607 Y1.6465 +G01 X-0.3081 Y1.6465 +G01 X-0.3062 Y1.6484 +G01 X-0.2816 Y1.6586 +G01 X-0.1184 Y1.6586 +G01 X-0.0938 Y1.6484 +G01 X-0.0750 Y1.6295 +G01 X-0.0648 Y1.6049 +G01 X-0.0648 Y1.5782 +G01 X-0.0750 Y1.5536 +G01 X-0.0938 Y1.5348 +G01 X-0.1184 Y1.5246 +G01 X-0.2816 Y1.5246 +G01 X-0.3062 Y1.5348 +G01 X-0.3249 Y1.5535 +G01 X-0.5607 Y1.5535 +G01 X-0.5700 Y1.5535 +G01 X-0.5732 Y1.5535 +G01 X-0.5792 Y1.5535 +G01 X-0.5853 Y1.5535 +G01 X-0.6144 Y1.5629 +G01 X-0.6391 Y1.5809 +G01 X-0.6570 Y1.6056 +G01 X-0.6665 Y1.6347 +G01 X-0.6665 Y1.6407 +G01 X-0.6665 Y1.7135 +G01 X-0.7455 Y1.7135 +G01 X-0.7256 Y1.7070 +G01 X-0.7009 Y1.6891 +G01 X-0.6829 Y1.6644 +G01 X-0.6735 Y1.6353 +G01 X-0.6735 Y1.6293 +G01 X-0.6735 Y1.6205 +G01 X-0.6735 Y1.6200 +G01 X-0.6735 Y1.6107 +G01 X-0.6735 Y1.5476 +G01 X-0.6605 Y1.5346 +G01 X-0.6605 Y1.4854 +G01 X-0.6894 Y1.4565 +G01 X-0.5992 Y1.4565 +G01 X-0.5900 Y1.4565 +G01 X-0.5869 Y1.4565 +G01 X-0.5807 Y1.4565 +G01 X-0.5747 Y1.4565 +G01 X-0.5456 Y1.4470 +G01 X-0.5209 Y1.4291 +G01 X-0.5029 Y1.4044 +G01 X-0.4935 Y1.3753 +G01 X-0.4935 Y1.3693 +G01 X-0.4935 Y1.3584 +G01 X-0.4935 Y1.3579 +G01 X-0.4931 Y1.3568 +G01 X-0.4925 Y1.3559 +G01 X-0.4916 Y1.3553 +G01 X-0.4905 Y1.3550 +G01 X-0.4900 Y1.3549 +G01 X-0.4823 Y1.3549 +G01 X-0.4807 Y1.3549 +G01 X-0.3165 Y1.3549 +G01 X-0.3062 Y1.3652 +G01 X-0.2816 Y1.3754 +G00 Z0.1000 +G00 X-2.3898 Y1.7804 +G01 Z-0.0070 F10 +G01 X-2.3899 Y1.7805 F20 +G01 X-2.3900 Y1.7805 +G01 X-2.3921 Y1.7805 +G01 X-2.3900 Y1.7784 +G01 X-2.3895 Y1.7789 +G01 X-2.3895 Y1.7800 +G01 X-2.3896 Y1.7802 +G01 X-2.3896 Y1.7804 +G01 X-2.3898 Y1.7804 +G00 Z0.1000 +G00 X-1.8500 Y1.2746 +G01 Z-0.0070 F10 +G01 X-1.8646 Y1.2600 F20 +G01 X-1.8541 Y1.2495 +G01 X-1.8195 Y1.2495 +G01 X-1.8195 Y1.2605 +G01 X-1.8198 Y1.2605 +G01 X-1.8380 Y1.2680 +G01 X-1.8484 Y1.2784 +G01 X-1.8500 Y1.2746 +G00 Z0.1000 +G00 X-1.3726 Y0.3895 +G01 Z-0.0070 F10 +G01 X-1.3198 Y0.3895 F20 +G01 X-1.3001 Y0.3895 +G01 X-0.8189 Y0.3895 +G01 X-0.8179 Y0.3905 +G01 X-1.3736 Y0.3905 +G01 X-1.3726 Y0.3895 +G00 Z0.1000 +G00 X-0.8425 Y0.5141 +G01 Z-0.0070 F10 +G01 X-0.8425 Y0.5659 F20 +G01 X-0.8295 Y0.5789 +G01 X-0.8295 Y0.8600 +G01 X-0.8296 Y0.8602 +G01 X-0.8296 Y0.8604 +G01 X-0.8298 Y0.8604 +G01 X-0.8299 Y0.8605 +G01 X-0.8369 Y0.8605 +G01 X-0.8398 Y0.8605 +G01 X-0.8541 Y0.8605 +G01 X-0.8546 Y0.8600 +G01 X-0.8400 Y0.8454 +G01 X-0.8305 Y0.8224 +G01 X-0.8305 Y0.7976 +G01 X-0.8400 Y0.7746 +G01 X-0.8576 Y0.7570 +G01 X-0.8806 Y0.7475 +G01 X-1.0194 Y0.7475 +G01 X-1.0424 Y0.7570 +G01 X-1.0459 Y0.7605 +G01 X-1.0598 Y0.7605 +G01 X-1.0658 Y0.7605 +G01 X-1.0957 Y0.7702 +G01 X-1.1212 Y0.7888 +G01 X-1.1305 Y0.8015 +G01 X-1.1305 Y0.7976 +G01 X-1.1400 Y0.7746 +G01 X-1.1576 Y0.7570 +G01 X-1.1806 Y0.7475 +G01 X-1.3194 Y0.7475 +G01 X-1.3424 Y0.7570 +G01 X-1.3459 Y0.7605 +G01 X-1.3921 Y0.7605 +G01 X-1.3675 Y0.7359 +G01 X-1.3675 Y0.6841 +G01 X-1.3805 Y0.6711 +G01 X-1.3805 Y0.5574 +G01 X-1.3619 Y0.5388 +G01 X-1.3515 Y0.5136 +G01 X-1.3515 Y0.4895 +G01 X-0.8179 Y0.4895 +G01 X-0.8425 Y0.5141 +G00 Z0.1000 +G00 X-2.6959 Y1.3125 +G01 Z-0.0070 F10 +G01 X-2.6441 Y1.3125 F20 +G01 X-2.6075 Y1.2759 +G01 X-2.6075 Y1.2241 +G01 X-2.6441 Y1.1875 +G01 X-2.6763 Y1.1875 +G01 X-2.6999 Y1.1828 +G01 X-2.7333 Y1.1894 +G01 X-2.7350 Y1.1905 +G01 X-2.9221 Y1.1905 +G01 X-2.8875 Y1.1559 +G01 X-2.8875 Y1.1041 +G01 X-2.9005 Y1.0911 +G01 X-2.9005 Y1.0600 +G01 X-2.9004 Y1.0598 +G01 X-2.9004 Y1.0596 +G01 X-2.9002 Y1.0596 +G01 X-2.9001 Y1.0595 +G01 X-2.8986 Y1.0595 +G01 X-2.8901 Y1.0595 +G01 X-2.3559 Y1.0595 +G01 X-2.3554 Y1.0600 +G01 X-2.3700 Y1.0746 +G01 X-2.3795 Y1.0976 +G01 X-2.3795 Y1.1224 +G01 X-2.3700 Y1.1454 +G01 X-2.3554 Y1.1600 +G01 X-2.3559 Y1.1605 +G01 X-2.4601 Y1.1605 +G01 X-2.4615 Y1.1605 +G01 X-2.4798 Y1.1605 +G01 X-2.4858 Y1.1605 +G01 X-2.5157 Y1.1702 +G01 X-2.5412 Y1.1888 +G01 X-2.5598 Y1.2143 +G01 X-2.5695 Y1.2442 +G01 X-2.5695 Y1.2501 +G01 X-2.5695 Y1.3905 +G01 X-2.8547 Y1.3905 +G01 X-2.8620 Y1.3832 +G01 X-2.8867 Y1.3730 +G01 X-2.9046 Y1.3730 +G01 X-2.8875 Y1.3559 +G01 X-2.8875 Y1.3041 +G01 X-2.9021 Y1.2895 +G01 X-2.7249 Y1.2895 +G01 X-2.7201 Y1.2905 +G01 X-2.7183 Y1.2901 +G01 X-2.6959 Y1.3125 +G00 Z0.1000 +G00 X-2.6341 Y1.5475 +G01 Z-0.0070 F10 +G01 X-2.6859 Y1.5475 F20 +G01 X-2.7225 Y1.5841 +G01 X-2.7225 Y1.6359 +G01 X-2.6984 Y1.6600 +G01 X-2.7089 Y1.6705 +G01 X-2.7300 Y1.6705 +G01 X-2.7302 Y1.6704 +G01 X-2.7304 Y1.6704 +G01 X-2.7304 Y1.6702 +G01 X-2.7305 Y1.6701 +G01 X-2.7305 Y1.6614 +G01 X-2.7305 Y1.6601 +G01 X-2.7305 Y1.5901 +G01 X-2.7305 Y1.5858 +G01 X-2.7393 Y1.5589 +G01 X-2.7559 Y1.5359 +G01 X-2.7789 Y1.5193 +G01 X-2.8058 Y1.5105 +G01 X-2.8101 Y1.5105 +G01 X-2.8200 Y1.5105 +G01 X-2.8298 Y1.5105 +G01 X-2.9405 Y1.5105 +G01 X-2.9405 Y1.4942 +G01 X-2.9379 Y1.4968 +G01 X-2.9133 Y1.5070 +G01 X-2.8867 Y1.5070 +G01 X-2.8620 Y1.4968 +G01 X-2.8547 Y1.4895 +G01 X-2.5695 Y1.4895 +G01 X-2.5695 Y1.5605 +G01 X-2.6211 Y1.5605 +G01 X-2.6341 Y1.5475 +G00 Z0.1000 +G00 X-2.4705 Y1.4498 +G01 Z-0.0070 F10 +G01 X-2.4705 Y1.4301 F20 +G01 X-2.4705 Y1.2600 +G01 X-2.4704 Y1.2598 +G01 X-2.4704 Y1.2596 +G01 X-2.4702 Y1.2596 +G01 X-2.4701 Y1.2595 +G01 X-2.4615 Y1.2595 +G01 X-2.4601 Y1.2595 +G01 X-2.3559 Y1.2595 +G01 X-2.3554 Y1.2600 +G01 X-2.3700 Y1.2746 +G01 X-2.3795 Y1.2976 +G01 X-2.3795 Y1.3224 +G01 X-2.3700 Y1.3454 +G01 X-2.3524 Y1.3630 +G01 X-2.3294 Y1.3725 +G01 X-2.1906 Y1.3725 +G01 X-2.1676 Y1.3630 +G01 X-2.1641 Y1.3595 +G01 X-2.1398 Y1.3595 +G01 X-2.1300 Y1.3595 +G01 X-2.1273 Y1.3595 +G01 X-2.1201 Y1.3595 +G01 X-2.1162 Y1.3595 +G01 X-2.0906 Y1.3489 +G01 X-2.0750 Y1.3333 +G01 X-2.0700 Y1.3454 +G01 X-2.0524 Y1.3630 +G01 X-2.0294 Y1.3725 +G01 X-2.0095 Y1.3725 +G01 X-2.0095 Y1.4101 +G01 X-2.0095 Y1.4157 +G01 X-2.0143 Y1.4205 +G01 X-2.0198 Y1.4205 +G01 X-2.1657 Y1.4205 +G01 X-2.1825 Y1.4037 +G01 X-2.2375 Y1.4037 +G01 X-2.2395 Y1.4057 +G01 X-2.2722 Y1.3730 +G01 X-2.3277 Y1.3730 +G01 X-2.3670 Y1.4122 +G01 X-2.3670 Y1.4677 +G01 X-2.3277 Y1.5070 +G01 X-2.2722 Y1.5070 +G01 X-2.2695 Y1.5043 +G01 X-2.2433 Y1.5305 +G01 X-2.3301 Y1.5305 +G01 X-2.3318 Y1.5305 +G01 X-2.3498 Y1.5305 +G01 X-2.3558 Y1.5305 +G01 X-2.3857 Y1.5402 +G01 X-2.4112 Y1.5588 +G01 X-2.4298 Y1.5843 +G01 X-2.4395 Y1.6142 +G01 X-2.4395 Y1.6201 +G01 X-2.4395 Y1.6261 +G01 X-2.4505 Y1.6371 +G01 X-2.4505 Y1.6001 +G01 X-2.4580 Y1.5820 +G01 X-2.4705 Y1.5695 +G01 X-2.4705 Y1.4498 +G00 Z0.1000 +G00 X-2.5201 Y1.7805 +G01 Z-0.0070 F10 +G01 X-2.5300 Y1.7805 F20 +G01 X-2.5301 Y1.7805 +G01 X-2.5302 Y1.7804 +G01 X-2.5304 Y1.7804 +G01 X-2.5304 Y1.7802 +G01 X-2.5305 Y1.7801 +G01 X-2.5305 Y1.7798 +G01 X-2.5305 Y1.7782 +G01 X-2.5305 Y1.7619 +G01 X-2.5150 Y1.7774 +G01 X-2.5075 Y1.7805 +G01 X-2.5201 Y1.7805 +G00 Z0.1000 +G00 X-2.5588 Y1.6988 +G01 Z-0.0070 F10 +G01 X-2.5588 Y1.6988 F20 +G01 X-2.5843 Y1.6802 +G01 X-2.6142 Y1.6705 +G01 X-2.6201 Y1.6705 +G01 X-2.6311 Y1.6705 +G01 X-2.6316 Y1.6700 +G01 X-2.6211 Y1.6595 +G01 X-2.5495 Y1.6595 +G01 X-2.5495 Y1.7001 +G01 X-2.5495 Y1.7044 +G01 X-2.5495 Y1.7115 +G01 X-2.5588 Y1.6988 +G00 Z0.1000 +G00 X-2.1657 Y1.5195 +G01 Z-0.0070 F10 +G01 X-2.0198 Y1.5195 F20 +G01 X-2.0143 Y1.5195 +G01 X-2.0033 Y1.5305 +G01 X-2.1767 Y1.5305 +G01 X-2.1657 Y1.5195 +G00 Z0.1000 +G00 X-1.9037 Y1.4975 +G01 Z-0.0070 F10 +G01 X-1.9037 Y1.4425 F20 +G01 X-1.9105 Y1.4357 +G01 X-1.9105 Y1.4200 +G01 X-1.9105 Y1.4101 +G01 X-1.9105 Y1.3725 +G01 X-1.8906 Y1.3725 +G01 X-1.8676 Y1.3630 +G01 X-1.8595 Y1.3549 +G01 X-1.8595 Y1.5301 +G01 X-1.8595 Y1.5305 +G01 X-1.9367 Y1.5305 +G01 X-1.9037 Y1.4975 +G00 Z0.1000 +G00 X-1.8322 Y1.6295 +G01 Z-0.0070 F10 +G01 X-1.8322 Y1.6295 F20 +G01 X-1.7993 Y1.6159 +G01 X-1.7741 Y1.5907 +G01 X-1.7605 Y1.5578 +G01 X-1.7605 Y1.5499 +G01 X-1.7605 Y1.5400 +G01 X-1.7605 Y1.5302 +G01 X-1.7605 Y1.3595 +G01 X-1.7601 Y1.3595 +G01 X-1.6498 Y1.3595 +G01 X-1.6301 Y1.3595 +G01 X-1.5474 Y1.3595 +G01 X-1.5388 Y1.3681 +G01 X-1.5136 Y1.3785 +G01 X-1.4864 Y1.3785 +G01 X-1.4612 Y1.3681 +G01 X-1.4595 Y1.3664 +G01 X-1.4595 Y1.4001 +G01 X-1.4595 Y1.4100 +G01 X-1.4596 Y1.4102 +G01 X-1.4596 Y1.4104 +G01 X-1.4598 Y1.4104 +G01 X-1.4599 Y1.4105 +G01 X-1.6501 Y1.4105 +G01 X-1.6517 Y1.4105 +G01 X-1.6698 Y1.4105 +G01 X-1.6758 Y1.4105 +G01 X-1.7057 Y1.4202 +G01 X-1.7312 Y1.4388 +G01 X-1.7498 Y1.4643 +G01 X-1.7595 Y1.4942 +G01 X-1.7595 Y1.5001 +G01 X-1.7595 Y1.6375 +G01 X-1.7959 Y1.6375 +G01 X-1.8089 Y1.6505 +G01 X-2.0301 Y1.6505 +G01 X-2.0400 Y1.6505 +G01 X-2.0558 Y1.6505 +G01 X-2.0857 Y1.6602 +G01 X-2.1112 Y1.6788 +G01 X-2.1298 Y1.7043 +G01 X-2.1395 Y1.7342 +G01 X-2.1395 Y1.7500 +G01 X-2.1395 Y1.7598 +G01 X-2.1395 Y1.8605 +G01 X-2.3315 Y1.8605 +G01 X-2.3188 Y1.8512 +G01 X-2.3002 Y1.8257 +G01 X-2.2905 Y1.7958 +G01 X-2.2905 Y1.7898 +G01 X-2.2905 Y1.7895 +G01 X-2.2543 Y1.7895 +G01 X-2.2375 Y1.8063 +G01 X-2.1825 Y1.8063 +G01 X-2.1437 Y1.7675 +G01 X-2.1437 Y1.7125 +G01 X-2.1825 Y1.6737 +G01 X-2.2375 Y1.6737 +G01 X-2.2543 Y1.6905 +G01 X-2.3011 Y1.6905 +G01 X-2.3141 Y1.6775 +G01 X-2.3275 Y1.6775 +G01 X-2.3275 Y1.6391 +G01 X-2.3371 Y1.6295 +G01 X-2.3318 Y1.6295 +G01 X-2.3301 Y1.6295 +G01 X-1.8401 Y1.6295 +G01 X-1.8322 Y1.6295 +G00 Z0.1000 +G00 X-3.0125 Y1.1041 +G01 Z-0.0070 F10 +G01 X-3.0125 Y1.1559 F20 +G01 X-2.9779 Y1.1905 +G01 X-3.0101 Y1.1905 +G01 X-3.0186 Y1.1905 +G01 X-3.0200 Y1.1905 +G01 X-3.0358 Y1.1905 +G01 X-3.0657 Y1.2002 +G01 X-3.0912 Y1.2188 +G01 X-3.1098 Y1.2443 +G01 X-3.1105 Y1.2466 +G01 X-3.1105 Y0.9600 +G01 X-3.1104 Y0.9598 +G01 X-3.1104 Y0.9596 +G01 X-3.1102 Y0.9596 +G01 X-3.1101 Y0.9595 +G01 X-3.1029 Y0.9595 +G01 X-3.1001 Y0.9595 +G01 X-2.5543 Y0.9595 +G01 X-2.5533 Y0.9605 +G01 X-2.8901 Y0.9605 +G01 X-2.8986 Y0.9605 +G01 X-2.9000 Y0.9605 +G01 X-2.9158 Y0.9605 +G01 X-2.9457 Y0.9702 +G01 X-2.9712 Y0.9888 +G01 X-2.9898 Y1.0143 +G01 X-2.9995 Y1.0442 +G01 X-2.9995 Y1.0501 +G01 X-2.9995 Y1.0911 +G01 X-3.0125 Y1.1041 +G00 Z0.1000 +G00 X-2.4657 Y0.9595 +G01 Z-0.0070 F10 +G01 X-2.3549 Y0.9595 F20 +G01 X-2.3559 Y0.9605 +G01 X-2.4667 Y0.9605 +G01 X-2.4657 Y0.9595 +G00 Z0.1000 +G00 X-2.9195 Y1.7248 +G01 Z-0.0070 F10 +G01 X-2.9259 Y1.7159 F20 +G01 X-2.9259 Y1.7159 +G01 X-2.9485 Y1.6995 +G01 X-2.9195 Y1.6995 +G01 X-2.9195 Y1.7248 +G00 Z0.1000 +G00 X-3.0204 Y1.2898 +G01 Z-0.0070 F10 +G01 X-3.0204 Y1.2896 F20 +G01 X-3.0202 Y1.2896 +G01 X-3.0201 Y1.2895 +G01 X-3.0186 Y1.2895 +G01 X-3.0101 Y1.2895 +G01 X-2.9979 Y1.2895 +G01 X-3.0125 Y1.3041 +G01 X-3.0125 Y1.3048 +G01 X-3.0141 Y1.3059 +G01 X-3.0205 Y1.3148 +G01 X-3.0205 Y1.2998 +G01 X-3.0205 Y1.2900 +G01 X-3.0204 Y1.2898 +G00 Z0.1000 +G00 X-3.0050 Y1.5974 +G01 Z-0.0070 F10 +G01 X-3.0050 Y1.5974 F20 +G01 X-2.9975 Y1.6005 +G01 X-3.0200 Y1.6005 +G01 X-3.0202 Y1.6004 +G01 X-3.0204 Y1.6004 +G01 X-3.0204 Y1.6002 +G01 X-3.0205 Y1.6001 +G01 X-3.0205 Y1.5901 +G01 X-3.0205 Y1.5819 +G01 X-3.0050 Y1.5974 +G00 Z0.1000 +G00 X-3.1100 Y1.6905 +G01 Z-0.0070 F10 +G01 X-3.1101 Y1.6905 F20 +G01 X-3.1102 Y1.6904 +G01 X-3.1104 Y1.6904 +G01 X-3.1104 Y1.6902 +G01 X-3.1105 Y1.6901 +G01 X-3.1105 Y1.6814 +G01 X-3.1105 Y1.6801 +G01 X-3.1105 Y1.6489 +G01 X-3.1087 Y1.6471 +G01 X-3.0912 Y1.6712 +G01 X-3.0657 Y1.6898 +G01 X-3.0634 Y1.6905 +G01 X-3.1100 Y1.6905 +G00 Z0.1000 +G00 X-2.8298 Y1.6095 +G01 Z-0.0070 F10 +G01 X-2.8295 Y1.6095 F20 +G01 X-2.8295 Y1.6425 +G01 X-2.8326 Y1.6350 +G01 X-2.8550 Y1.6126 +G01 X-2.8625 Y1.6095 +G01 X-2.8298 Y1.6095 +G00 Z0.1000 +G00 X-2.8198 Y1.7157 +G01 Z-0.0070 F10 +G01 X-2.8198 Y1.7157 F20 +G01 X-2.8012 Y1.7412 +G01 X-2.7757 Y1.7598 +G01 X-2.7458 Y1.7695 +G01 X-2.7398 Y1.7695 +G01 X-2.7089 Y1.7695 +G01 X-2.7084 Y1.7700 +G01 X-2.7089 Y1.7705 +G01 X-2.8101 Y1.7705 +G01 X-2.8200 Y1.7705 +G01 X-2.8202 Y1.7704 +G01 X-2.8204 Y1.7704 +G01 X-2.8204 Y1.7702 +G01 X-2.8205 Y1.7701 +G01 X-2.8205 Y1.7134 +G01 X-2.8198 Y1.7157 +G00 Z0.1000 +G00 X-2.9000 Y1.8605 +G01 Z-0.0070 F10 +G01 X-2.9001 Y1.8605 F20 +G01 X-2.9002 Y1.8604 +G01 X-2.9004 Y1.8604 +G01 X-2.9004 Y1.8602 +G01 X-2.9005 Y1.8601 +G01 X-2.9005 Y1.8528 +G01 X-2.9005 Y1.8501 +G01 X-2.9005 Y1.8285 +G01 X-2.8912 Y1.8412 +G01 X-2.8657 Y1.8598 +G01 X-2.8634 Y1.8605 +G01 X-2.9000 Y1.8605 +G00 Z0.1000 +G00 X-2.0775 Y0.2859 +G01 Z-0.0070 F10 +G01 X-2.0775 Y0.2760 F20 +G01 X-2.0681 Y0.2988 +G01 X-2.0587 Y0.3081 +G01 X-2.0498 Y0.3357 +G01 X-2.0312 Y0.3612 +G01 X-2.0057 Y0.3798 +G01 X-1.9758 Y0.3895 +G01 X-1.9600 Y0.3895 +G01 X-1.9501 Y0.3895 +G01 X-1.8695 Y0.3895 +G01 X-1.8695 Y0.4517 +G01 X-1.8957 Y0.4602 +G01 X-1.9212 Y0.4788 +G01 X-1.9398 Y0.5043 +G01 X-1.9454 Y0.5216 +G01 X-1.9663 Y0.5425 +G01 X-1.9663 Y0.5975 +G01 X-1.9533 Y0.6105 +G01 X-1.9626 Y0.6105 +G01 X-1.9712 Y0.6019 +G01 X-1.9964 Y0.5915 +G01 X-2.0236 Y0.5915 +G01 X-2.0488 Y0.6019 +G01 X-2.0574 Y0.6105 +G01 X-2.0900 Y0.6105 +G01 X-2.0902 Y0.6104 +G01 X-2.0904 Y0.6104 +G01 X-2.0904 Y0.6102 +G01 X-2.0905 Y0.6101 +G01 X-2.0905 Y0.6001 +G01 X-2.0905 Y0.2989 +G01 X-2.0775 Y0.2859 +G00 Z0.1000 +G00 X-2.1798 Y0.6557 +G01 Z-0.0070 F10 +G01 X-2.1612 Y0.6812 F20 +G01 X-2.1612 Y0.6812 +G01 X-2.1357 Y0.6998 +G01 X-2.1334 Y0.7005 +G01 X-2.1801 Y0.7005 +G01 X-2.1805 Y0.7005 +G01 X-2.1805 Y0.6534 +G01 X-2.1798 Y0.6557 +G00 Z0.1000 +G00 X-2.4437 Y0.4875 +G01 Z-0.0070 F10 +G01 X-2.4437 Y0.4325 F20 +G01 X-2.4505 Y0.4257 +G01 X-2.4505 Y0.2718 +G01 X-2.4505 Y0.1995 +G01 X-2.4496 Y0.1995 +G01 X-2.4482 Y0.1995 +G01 X-2.1679 Y0.1995 +G01 X-2.2025 Y0.2341 +G01 X-2.2025 Y0.2859 +G01 X-2.1895 Y0.2989 +G01 X-2.1895 Y0.5485 +G01 X-2.2059 Y0.5259 +G01 X-2.2289 Y0.5093 +G01 X-2.2558 Y0.5005 +G01 X-2.2601 Y0.5005 +G01 X-2.4567 Y0.5005 +G01 X-2.4437 Y0.4875 +G00 Z0.1000 +G00 X-1.6998 Y1.0595 +G01 Z-0.0070 F10 +G01 X-1.6899 Y1.0595 F20 +G01 X-1.6801 Y1.0595 +G01 X-1.3459 Y1.0595 +G01 X-1.3454 Y1.0600 +G01 X-1.3459 Y1.0605 +G01 X-1.7605 Y1.0605 +G01 X-1.7605 Y1.0252 +G01 X-1.7541 Y1.0341 +G01 X-1.7311 Y1.0507 +G01 X-1.7042 Y1.0595 +G01 X-1.6998 Y1.0595 +G00 Z0.1000 +G00 X-1.7888 Y0.8088 +G01 Z-0.0070 F10 +G01 X-1.7888 Y0.8088 F20 +G01 X-1.8015 Y0.7995 +G01 X-1.7800 Y0.7995 +G01 X-1.7798 Y0.7996 +G01 X-1.7796 Y0.7996 +G01 X-1.7796 Y0.7998 +G01 X-1.7795 Y0.7999 +G01 X-1.7795 Y0.8215 +G01 X-1.7888 Y0.8088 +G00 Z0.1000 +G00 X-1.5001 Y0.7605 +G01 Z-0.0070 F10 +G01 X-1.5002 Y0.7604 F20 +G01 X-1.5004 Y0.7604 +G01 X-1.5004 Y0.7602 +G01 X-1.5005 Y0.7601 +G01 X-1.5005 Y0.7519 +G01 X-1.5005 Y0.7501 +G01 X-1.5005 Y0.6989 +G01 X-1.4925 Y0.6909 +G01 X-1.4925 Y0.7359 +G01 X-1.4679 Y0.7605 +G01 X-1.5000 Y0.7605 +G00 Z0.1000 +G00 X-1.4925 Y1.1841 +G01 Z-0.0070 F10 +G01 X-1.4925 Y1.2359 F20 +G01 X-1.4869 Y1.2415 +G01 X-1.5136 Y1.2415 +G01 X-1.5388 Y1.2519 +G01 X-1.5474 Y1.2605 +G01 X-1.5737 Y1.2605 +G01 X-1.5737 Y1.2425 +G01 X-1.6125 Y1.2037 +G01 X-1.6675 Y1.2037 +G01 X-1.7063 Y1.2425 +G01 X-1.7063 Y1.2605 +G01 X-1.7205 Y1.2605 +G01 X-1.7205 Y1.2389 +G01 X-1.7075 Y1.2259 +G01 X-1.7075 Y1.1741 +G01 X-1.7221 Y1.1595 +G01 X-1.4679 Y1.1595 +G01 X-1.4925 Y1.1841 +G00 Z0.1000 +G00 X-1.3454 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.3600 Y1.1746 F20 +G01 X-1.3675 Y1.1928 +G01 X-1.3675 Y1.1841 +G01 X-1.3921 Y1.1595 +G01 X-1.3459 Y1.1595 +G01 X-1.3454 Y1.1600 +G00 Z0.1000 +G00 X-1.8641 Y1.0605 +G01 Z-0.0070 F10 +G01 X-1.8646 Y1.0600 F20 +G01 X-1.8595 Y1.0549 +G01 X-1.8595 Y1.0605 +G01 X-1.8641 Y1.0605 +G00 Z0.1000 +G00 X-1.8595 Y0.9651 +G01 Z-0.0070 F10 +G01 X-1.8676 Y0.9570 F20 +G01 X-1.8906 Y0.9475 +G01 X-2.0294 Y0.9475 +G01 X-2.0524 Y0.9570 +G01 X-2.0559 Y0.9605 +G01 X-2.0605 Y0.9605 +G01 X-2.0605 Y0.9501 +G01 X-2.0605 Y0.9442 +G01 X-2.0702 Y0.9143 +G01 X-2.0888 Y0.8888 +G01 X-2.1015 Y0.8795 +G01 X-1.8600 Y0.8795 +G01 X-1.8598 Y0.8796 +G01 X-1.8596 Y0.8796 +G01 X-1.8596 Y0.8798 +G01 X-1.8595 Y0.8799 +G01 X-1.8595 Y0.9651 +G00 Z0.1000 +G00 X-1.3557 Y1.7202 +G01 Z-0.0070 F10 +G01 X-1.3557 Y1.7202 F20 +G01 X-1.3812 Y1.7388 +G01 X-1.3998 Y1.7643 +G01 X-1.4095 Y1.7942 +G01 X-1.4095 Y1.8001 +G01 X-1.4095 Y1.8147 +G01 X-1.4270 Y1.8322 +G01 X-1.4270 Y1.8877 +G01 X-1.4095 Y1.9052 +G01 X-1.4095 Y1.9600 +G01 X-1.4096 Y1.9602 +G01 X-1.4096 Y1.9604 +G01 X-1.4098 Y1.9604 +G01 X-1.4099 Y1.9605 +G01 X-1.4621 Y1.9605 +G01 X-1.4375 Y1.9359 +G01 X-1.4375 Y1.8841 +G01 X-1.4505 Y1.8711 +G01 X-1.4505 Y1.7574 +G01 X-1.4419 Y1.7488 +G01 X-1.4315 Y1.7236 +G01 X-1.4315 Y1.7195 +G01 X-1.3534 Y1.7195 +G01 X-1.3557 Y1.7202 +G00 Z0.1000 +G00 X-1.5388 Y1.6519 +G01 Z-0.0070 F10 +G01 X-1.5581 Y1.6712 F20 +G01 X-1.5685 Y1.6964 +G01 X-1.5685 Y1.7236 +G01 X-1.5581 Y1.7488 +G01 X-1.5495 Y1.7574 +G01 X-1.5495 Y1.8711 +G01 X-1.5625 Y1.8841 +G01 X-1.5625 Y1.9359 +G01 X-1.5379 Y1.9605 +G01 X-1.5601 Y1.9605 +G01 X-1.5700 Y1.9605 +G01 X-1.5702 Y1.9604 +G01 X-1.5704 Y1.9604 +G01 X-1.5704 Y1.9602 +G01 X-1.5705 Y1.9601 +G01 X-1.5705 Y1.7998 +G01 X-1.5705 Y1.7701 +G01 X-1.5705 Y1.6398 +G01 X-1.5705 Y1.6300 +G01 X-1.5704 Y1.6298 +G01 X-1.5704 Y1.6296 +G01 X-1.5702 Y1.6296 +G01 X-1.5701 Y1.6295 +G01 X-1.5681 Y1.6295 +G01 X-1.5601 Y1.6295 +G01 X-1.4964 Y1.6295 +G01 X-1.5149 Y1.6401 +G01 X-1.5178 Y1.6432 +G01 X-1.5388 Y1.6519 +G00 Z0.1000 +G00 X-0.8546 Y0.9600 +G01 Z-0.0070 F10 +G01 X-0.8541 Y0.9595 F20 +G01 X-0.8398 Y0.9595 +G01 X-0.8368 Y0.9595 +G01 X-0.8201 Y0.9595 +G01 X-0.8142 Y0.9595 +G01 X-0.7843 Y0.9498 +G01 X-0.7588 Y0.9312 +G01 X-0.7402 Y0.9057 +G01 X-0.7305 Y0.8758 +G01 X-0.7305 Y0.8698 +G01 X-0.7305 Y0.5789 +G01 X-0.7175 Y0.5659 +G01 X-0.7175 Y0.5141 +G01 X-0.7421 Y0.4895 +G01 X-0.6100 Y0.4895 +G01 X-0.6098 Y0.4896 +G01 X-0.6096 Y0.4896 +G01 X-0.6096 Y0.4898 +G01 X-0.6095 Y0.4899 +G01 X-0.6095 Y0.8711 +G01 X-0.6225 Y0.8841 +G01 X-0.6225 Y0.9359 +G01 X-0.5979 Y0.9605 +G01 X-0.8541 Y0.9605 +G01 X-0.8546 Y0.9600 +G00 Z0.1000 +G00 X-0.5989 Y1.0605 +G01 Z-0.0070 F10 +G01 X-0.8541 Y1.0605 F20 +G01 X-0.8546 Y1.0600 +G01 X-0.8541 Y1.0595 +G01 X-0.5979 Y1.0595 +G01 X-0.5989 Y1.0605 +G00 Z0.1000 +G00 X-1.6098 Y0.9595 +G01 Z-0.0070 F10 +G01 X-1.6005 Y0.9595 F20 +G01 X-1.6000 Y0.9595 +G01 X-1.5901 Y0.9595 +G01 X-1.3459 Y0.9595 +G01 X-1.3454 Y0.9600 +G01 X-1.3459 Y0.9605 +G01 X-1.6801 Y0.9605 +G01 X-1.6805 Y0.9605 +G01 X-1.6805 Y0.9601 +G01 X-1.6805 Y0.9185 +G01 X-1.6712 Y0.9312 +G01 X-1.6457 Y0.9498 +G01 X-1.6158 Y0.9595 +G01 X-1.6098 Y0.9595 +G00 Z0.1000 +G00 X-1.7088 Y0.7288 +G01 Z-0.0070 F10 +G01 X-1.7088 Y0.7288 F20 +G01 X-1.7213 Y0.7197 +G01 X-1.6995 Y0.6979 +G01 X-1.6995 Y0.7415 +G01 X-1.7088 Y0.7288 +G00 Z0.1000 +G00 X-1.5995 Y0.6989 +G01 Z-0.0070 F10 +G01 X-1.5995 Y0.7501 F20 +G01 X-1.5995 Y0.7519 +G01 X-1.5995 Y0.7698 +G01 X-1.5995 Y0.7758 +G01 X-1.5898 Y0.8057 +G01 X-1.5712 Y0.8312 +G01 X-1.5457 Y0.8498 +G01 X-1.5158 Y0.8595 +G01 X-1.5098 Y0.8595 +G01 X-1.3459 Y0.8595 +G01 X-1.3454 Y0.8600 +G01 X-1.3459 Y0.8605 +G01 X-1.5901 Y0.8605 +G01 X-1.6000 Y0.8605 +G01 X-1.6002 Y0.8604 +G01 X-1.6004 Y0.8604 +G01 X-1.6004 Y0.8602 +G01 X-1.6005 Y0.8601 +G01 X-1.6005 Y0.6979 +G01 X-1.5995 Y0.6989 +G00 Z0.1000 +G00 X-1.2605 Y0.2905 +G01 Z-0.0070 F10 +G01 X-1.2605 Y0.2289 F20 +G01 X-1.2575 Y0.2259 +G01 X-1.2575 Y0.1741 +G01 X-1.2821 Y0.1495 +G01 X-1.1400 Y0.1495 +G01 X-1.1398 Y0.1496 +G01 X-1.1396 Y0.1496 +G01 X-1.1396 Y0.1498 +G01 X-1.1395 Y0.1499 +G01 X-1.1395 Y0.1901 +G01 X-1.1395 Y0.1944 +G01 X-1.1395 Y0.2098 +G01 X-1.1395 Y0.2158 +G01 X-1.1298 Y0.2457 +G01 X-1.1112 Y0.2712 +G01 X-1.0857 Y0.2898 +G01 X-1.0834 Y0.2905 +G01 X-1.2605 Y0.2905 +G00 Z0.1000 +G00 X-1.3825 Y0.1741 +G01 Z-0.0070 F10 +G01 X-1.3825 Y0.2259 F20 +G01 X-1.3595 Y0.2489 +G01 X-1.3595 Y0.2905 +G01 X-1.3726 Y0.2905 +G01 X-1.3812 Y0.2819 +G01 X-1.4064 Y0.2715 +G01 X-1.4336 Y0.2715 +G01 X-1.4588 Y0.2819 +G01 X-1.4781 Y0.3012 +G01 X-1.4885 Y0.3264 +G01 X-1.4885 Y0.3536 +G01 X-1.4781 Y0.3788 +G01 X-1.4588 Y0.3981 +G01 X-1.4336 Y0.4085 +G01 X-1.4271 Y0.4085 +G01 X-1.4412 Y0.4188 +G01 X-1.4577 Y0.4415 +G01 X-1.4588 Y0.4419 +G01 X-1.4781 Y0.4612 +G01 X-1.4885 Y0.4864 +G01 X-1.4885 Y0.5136 +G01 X-1.4795 Y0.5353 +G01 X-1.4795 Y0.6711 +G01 X-1.4875 Y0.6791 +G01 X-1.4875 Y0.6341 +G01 X-1.5241 Y0.5975 +G01 X-1.5759 Y0.5975 +G01 X-1.6005 Y0.6221 +G01 X-1.6005 Y0.1598 +G01 X-1.6005 Y0.1502 +G01 X-1.6005 Y0.1500 +G01 X-1.6004 Y0.1498 +G01 X-1.6004 Y0.1496 +G01 X-1.6002 Y0.1496 +G01 X-1.6001 Y0.1495 +G01 X-1.3579 Y0.1495 +G01 X-1.3825 Y0.1741 +G00 Z0.1000 +G00 X-0.5357 Y1.2687 +G01 Z-0.0070 F10 +G01 X-0.5357 Y1.2687 F20 +G01 X-0.5612 Y1.2872 +G01 X-0.5798 Y1.3127 +G01 X-0.5895 Y1.3427 +G01 X-0.5895 Y1.3486 +G01 X-0.5895 Y1.3501 +G01 X-0.5895 Y1.3600 +G01 X-0.5896 Y1.3602 +G01 X-0.5896 Y1.3604 +G01 X-0.5898 Y1.3604 +G01 X-0.5899 Y1.3605 +G01 X-0.6821 Y1.3605 +G01 X-0.6575 Y1.3359 +G01 X-0.6575 Y1.2841 +G01 X-0.6821 Y1.2595 +G01 X-0.5075 Y1.2595 +G01 X-0.5357 Y1.2687 +G00 Z0.1000 +G00 X-0.7589 Y1.2605 +G01 Z-0.0070 F10 +G01 X-0.8541 Y1.2605 F20 +G01 X-0.8546 Y1.2600 +G01 X-0.8541 Y1.2595 +G01 X-0.7579 Y1.2595 +G01 X-0.7589 Y1.2605 +G00 Z0.1000 +G00 X-0.8546 Y1.1600 +G01 Z-0.0070 F10 +G01 X-0.8541 Y1.1595 F20 +G01 X-0.5989 Y1.1595 +G01 X-0.5979 Y1.1605 +G01 X-0.8541 Y1.1605 +G01 X-0.8546 Y1.1600 +G00 Z0.1000 +G00 X-0.8546 Y1.3600 +G01 Z-0.0070 F10 +G01 X-0.8541 Y1.3595 F20 +G01 X-0.7589 Y1.3595 +G01 X-0.7579 Y1.3605 +G01 X-0.8541 Y1.3605 +G01 X-0.8546 Y1.3600 +G00 Z0.1000 +G00 X-0.7825 Y1.4841 +G01 Z-0.0070 F10 +G01 X-0.7825 Y1.5359 F20 +G01 X-0.7695 Y1.5489 +G01 X-0.7695 Y1.6101 +G01 X-0.7695 Y1.6200 +G01 X-0.7696 Y1.6202 +G01 X-0.7696 Y1.6204 +G01 X-0.7698 Y1.6204 +G01 X-0.7699 Y1.6205 +G01 X-1.1066 Y1.6205 +G01 X-1.1043 Y1.6198 +G01 X-1.0788 Y1.6012 +G01 X-1.0602 Y1.5757 +G01 X-1.0505 Y1.5458 +G01 X-1.0505 Y1.5300 +G01 X-1.0505 Y1.5201 +G01 X-1.0505 Y1.4549 +G01 X-1.0424 Y1.4630 +G01 X-1.0194 Y1.4725 +G01 X-0.8806 Y1.4725 +G01 X-0.8576 Y1.4630 +G01 X-0.8541 Y1.4595 +G01 X-0.7579 Y1.4595 +G01 X-0.7825 Y1.4841 +G00 Z0.1000 +G00 X-2.0595 Y1.0595 +G01 Z-0.0070 F10 +G01 X-2.0559 Y1.0595 F20 +G01 X-2.0554 Y1.0600 +G01 X-2.0605 Y1.0651 +G01 X-2.0605 Y1.0605 +G01 X-2.0595 Y1.0595 +G00 Z0.1000 +G00 X-2.1646 Y1.0600 +G01 Z-0.0070 F10 +G01 X-2.1595 Y1.0549 F20 +G01 X-2.1595 Y1.0651 +G01 X-2.1646 Y1.0600 +G00 Z0.1000 +G00 X-2.1646 Y1.1600 +G01 Z-0.0070 F10 +G01 X-2.1595 Y1.1549 F20 +G01 X-2.1595 Y1.1651 +G01 X-2.1646 Y1.1600 +G00 Z0.1000 +G00 X-2.0554 Y1.1600 +G01 Z-0.0070 F10 +G01 X-2.0605 Y1.1651 F20 +G01 X-2.0605 Y1.1549 +G01 X-2.0554 Y1.1600 +G00 Z0.1000 +G00 X-2.0554 Y1.2600 +G01 Z-0.0070 F10 +G01 X-2.0605 Y1.2651 F20 +G01 X-2.0605 Y1.2549 +G01 X-2.0554 Y1.2600 +G00 Z0.1000 +G00 X-2.1599 Y0.9595 +G01 Z-0.0070 F10 +G01 X-2.1598 Y0.9596 F20 +G01 X-2.1596 Y0.9596 +G01 X-2.1596 Y0.9598 +G01 X-2.1595 Y0.9599 +G01 X-2.1595 Y0.9651 +G01 X-2.1651 Y0.9595 +G01 X-2.1600 Y0.9595 +G00 Z0.1000 +G00 X-2.1646 Y1.2600 +G01 Z-0.0070 F10 +G01 X-2.1595 Y1.2549 F20 +G01 X-2.1595 Y1.2605 +G01 X-2.1641 Y1.2605 +G01 X-2.1646 Y1.2600 +G00 Z0.1000 +G00 X-1.0505 Y0.8599 +G01 Z-0.0070 F10 +G01 X-1.0504 Y0.8598 F20 +G01 X-1.0504 Y0.8596 +G01 X-1.0502 Y0.8596 +G01 X-1.0501 Y0.8595 +G01 X-1.0459 Y0.8595 +G01 X-1.0454 Y0.8600 +G01 X-1.0505 Y0.8651 +G01 X-1.0505 Y0.8600 +G00 Z0.1000 +G00 X-1.1546 Y0.8600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y0.8549 F20 +G01 X-1.1495 Y0.8651 +G01 X-1.1546 Y0.8600 +G00 Z0.1000 +G00 X-1.1546 Y1.3600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y1.3549 F20 +G01 X-1.1495 Y1.3651 +G01 X-1.1546 Y1.3600 +G00 Z0.1000 +G00 X-1.1546 Y1.2600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y1.2549 F20 +G01 X-1.1495 Y1.2651 +G01 X-1.1546 Y1.2600 +G00 Z0.1000 +G00 X-1.1546 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y1.1549 F20 +G01 X-1.1495 Y1.1651 +G01 X-1.1546 Y1.1600 +G00 Z0.1000 +G00 X-1.1546 Y1.0600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y1.0549 F20 +G01 X-1.1495 Y1.0651 +G01 X-1.1546 Y1.0600 +G00 Z0.1000 +G00 X-1.1546 Y0.9600 +G01 Z-0.0070 F10 +G01 X-1.1495 Y0.9549 F20 +G01 X-1.1495 Y0.9651 +G01 X-1.1546 Y0.9600 +G00 Z0.1000 +G00 X-1.0454 Y0.9600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y0.9651 F20 +G01 X-1.0505 Y0.9549 +G01 X-1.0454 Y0.9600 +G00 Z0.1000 +G00 X-1.0454 Y1.0600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y1.0651 F20 +G01 X-1.0505 Y1.0549 +G01 X-1.0454 Y1.0600 +G00 Z0.1000 +G00 X-1.0454 Y1.1600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y1.1651 F20 +G01 X-1.0505 Y1.1549 +G01 X-1.0454 Y1.1600 +G00 Z0.1000 +G00 X-1.0454 Y1.2600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y1.2651 F20 +G01 X-1.0505 Y1.2549 +G01 X-1.0454 Y1.2600 +G00 Z0.1000 +G00 X-1.0454 Y1.3600 +G01 Z-0.0070 F10 +G01 X-1.0505 Y1.3651 F20 +G01 X-1.0505 Y1.3549 +G01 X-1.0454 Y1.3600 +G00 Z0.1000 +G00 X-2.6316 Y1.7700 +G01 Z-0.0070 F10 +G01 X-2.6311 Y1.7695 F20 +G01 X-2.6300 Y1.7695 +G01 X-2.6298 Y1.7696 +G01 X-2.6296 Y1.7696 +G01 X-2.6296 Y1.7698 +G01 X-2.6295 Y1.7699 +G01 X-2.6295 Y1.7721 +G01 X-2.6316 Y1.7700 +G00 Z0.1000 +G00 X-1.6695 Y1.7405 +G01 Z-0.0070 F10 +G01 X-1.7025 Y1.7405 F20 +G01 X-1.6950 Y1.7374 +G01 X-1.6726 Y1.7150 +G01 X-1.6695 Y1.7075 +G01 X-1.6695 Y1.7405 +G00 Z0.1000 +G00 X-1.6605 Y1.5099 +G01 Z-0.0070 F10 +G01 X-1.6604 Y1.5098 F20 +G01 X-1.6604 Y1.5096 +G01 X-1.6602 Y1.5096 +G01 X-1.6601 Y1.5095 +G01 X-1.6517 Y1.5095 +G01 X-1.6501 Y1.5095 +G01 X-1.4501 Y1.5095 +G01 X-1.4442 Y1.5095 +G01 X-1.4143 Y1.4998 +G01 X-1.3888 Y1.4812 +G01 X-1.3730 Y1.4595 +G01 X-1.3600 Y1.4595 +G01 X-1.3501 Y1.4595 +G01 X-1.3459 Y1.4595 +G01 X-1.3424 Y1.4630 +G01 X-1.3194 Y1.4725 +G01 X-1.1806 Y1.4725 +G01 X-1.1576 Y1.4630 +G01 X-1.1495 Y1.4549 +G01 X-1.1495 Y1.5201 +G01 X-1.1495 Y1.5300 +G01 X-1.1496 Y1.5302 +G01 X-1.1496 Y1.5304 +G01 X-1.1498 Y1.5304 +G01 X-1.1499 Y1.5305 +G01 X-1.5601 Y1.5305 +G01 X-1.5681 Y1.5305 +G01 X-1.5798 Y1.5305 +G01 X-1.5858 Y1.5305 +G01 X-1.6157 Y1.5402 +G01 X-1.6412 Y1.5588 +G01 X-1.6598 Y1.5843 +G01 X-1.6605 Y1.5866 +G01 X-1.6605 Y1.5100 +G00 Z0.1000 +G00 X-1.9653 Y1.8563 +G01 Z-0.0070 F10 +G01 X-1.9425 Y1.8563 F20 +G01 X-1.9257 Y1.8395 +G01 X-1.6695 Y1.8395 +G01 X-1.6695 Y1.9698 +G01 X-1.6695 Y1.9758 +G01 X-1.6598 Y2.0057 +G01 X-1.6412 Y2.0312 +G01 X-1.6157 Y2.0498 +G01 X-1.5858 Y2.0595 +G01 X-1.5700 Y2.0595 +G01 X-1.5601 Y2.0595 +G01 X-1.4001 Y2.0595 +G01 X-1.3942 Y2.0595 +G01 X-1.3643 Y2.0498 +G01 X-1.3388 Y2.0312 +G01 X-1.3202 Y2.0057 +G01 X-1.3105 Y1.9758 +G01 X-1.3105 Y1.9698 +G01 X-1.3105 Y1.9052 +G01 X-1.2930 Y1.8877 +G01 X-1.2930 Y1.8322 +G01 X-1.3105 Y1.8147 +G01 X-1.3105 Y1.8100 +G01 X-1.3104 Y1.8098 +G01 X-1.3104 Y1.8096 +G01 X-1.3102 Y1.8096 +G01 X-1.3101 Y1.8095 +G01 X-1.3017 Y1.8095 +G01 X-1.3001 Y1.8095 +G01 X-0.8042 Y1.8095 +G01 X-0.8052 Y1.8105 +G01 X-1.1501 Y1.8105 +G01 X-1.1600 Y1.8105 +G01 X-1.1669 Y1.8105 +G01 X-1.1698 Y1.8105 +G01 X-1.1758 Y1.8105 +G01 X-1.2057 Y1.8202 +G01 X-1.2312 Y1.8388 +G01 X-1.2498 Y1.8643 +G01 X-1.2595 Y1.8942 +G01 X-1.2595 Y1.9001 +G01 X-1.2595 Y2.0600 +G01 X-1.2596 Y2.0602 +G01 X-1.2596 Y2.0604 +G01 X-1.2598 Y2.0604 +G01 X-1.2599 Y2.0605 +G01 X-1.2698 Y2.0605 +G01 X-1.6601 Y2.0605 +G01 X-1.6700 Y2.0605 +G01 X-1.6702 Y2.0604 +G01 X-1.6704 Y2.0604 +G01 X-1.6704 Y2.0602 +G01 X-1.6705 Y2.0601 +G01 X-1.6705 Y1.9698 +G01 X-1.6705 Y1.9666 +G01 X-1.6705 Y1.9501 +G01 X-1.6705 Y1.9442 +G01 X-1.6802 Y1.9143 +G01 X-1.6988 Y1.8888 +G01 X-1.7243 Y1.8702 +G01 X-1.7542 Y1.8605 +G01 X-1.7601 Y1.8605 +G01 X-1.9611 Y1.8605 +G01 X-1.9653 Y1.8563 +G00 Z0.1000 +G00 X-2.0405 Y1.7598 +G01 Z-0.0070 F10 +G01 X-2.0405 Y1.7500 F20 +G01 X-2.0405 Y1.7499 +G01 X-2.0404 Y1.7498 +G01 X-2.0404 Y1.7496 +G01 X-2.0402 Y1.7496 +G01 X-2.0401 Y1.7495 +G01 X-2.0301 Y1.7495 +G01 X-2.0233 Y1.7495 +G01 X-2.0363 Y1.7625 +G01 X-2.0363 Y1.8175 +G01 X-2.0063 Y1.8475 +G01 X-2.0259 Y1.8475 +G01 X-2.0389 Y1.8605 +G01 X-2.0405 Y1.8605 +G01 X-2.0405 Y1.7598 +G00 Z0.1000 +G00 X-1.3600 Y1.2454 +G01 Z-0.0070 F10 +G01 X-1.3454 Y1.2600 F20 +G01 X-1.3600 Y1.2746 +G01 X-1.3605 Y1.2759 +G01 X-1.3605 Y1.2698 +G01 X-1.3605 Y1.2441 +G01 X-1.3600 Y1.2454 +G00 Z0.1000 +G00 X-1.3600 Y1.3454 +G01 Z-0.0070 F10 +G01 X-1.3454 Y1.3600 F20 +G01 X-1.3459 Y1.3605 +G01 X-1.3501 Y1.3605 +G01 X-1.3600 Y1.3605 +G01 X-1.3602 Y1.3604 +G01 X-1.3604 Y1.3604 +G01 X-1.3604 Y1.3602 +G01 X-1.3605 Y1.3601 +G01 X-1.3605 Y1.3441 +G01 X-1.3600 Y1.3454 +G00 Z0.1000 +G00 X-2.0488 Y0.2019 +G01 Z-0.0070 F10 +G01 X-2.0681 Y0.2212 F20 +G01 X-2.0775 Y0.2440 +G01 X-2.0775 Y0.2341 +G01 X-2.1121 Y0.1995 +G01 X-2.0429 Y0.1995 +G01 X-2.0488 Y0.2019 +G00 Z0.1000 +G00 X-2.6075 Y1.8459 +G01 Z-0.0070 F10 +G01 X-2.6075 Y1.8426 F20 +G01 X-2.6012 Y1.8512 +G01 X-2.5885 Y1.8605 +G01 X-2.6221 Y1.8605 +G01 X-2.6075 Y1.8459 +G00 Z0.1000 +G00 X-0.2822 Y1.1816 +G01 Z-0.0070 F10 +G01 X-0.1178 Y1.1816 F20 +G01 X-0.0921 Y1.1709 +G01 X-0.0724 Y1.1512 +G01 X-0.0618 Y1.1255 +G01 X-0.0618 Y1.0976 +G01 X-0.0724 Y1.0719 +G01 X-0.0921 Y1.0522 +G01 X-0.1178 Y1.0416 +G01 X-0.2822 Y1.0416 +G01 X-0.3079 Y1.0522 +G01 X-0.3177 Y1.0621 +G01 X-0.3401 Y1.0621 +G01 X-0.3428 Y1.0621 +G01 X-0.3598 Y1.0621 +G01 X-0.3658 Y1.0621 +G01 X-0.3957 Y1.0718 +G01 X-0.4212 Y1.0903 +G01 X-0.4398 Y1.1158 +G01 X-0.4495 Y1.1458 +G01 X-0.4495 Y1.1517 +G01 X-0.4495 Y1.1601 +G01 X-0.4495 Y1.1605 +G01 X-0.5221 Y1.1605 +G01 X-0.4975 Y1.1359 +G01 X-0.4975 Y1.0841 +G01 X-0.5221 Y1.0595 +G01 X-0.4898 Y1.0595 +G01 X-0.4886 Y1.0595 +G01 X-0.4701 Y1.0595 +G01 X-0.4642 Y1.0595 +G01 X-0.4343 Y1.0498 +G01 X-0.4088 Y1.0312 +G01 X-0.3902 Y1.0057 +G01 X-0.3805 Y0.9758 +G01 X-0.3805 Y0.9698 +G01 X-0.3805 Y0.9598 +G01 X-0.3805 Y0.9595 +G01 X-0.3162 Y0.9595 +G01 X-0.3079 Y0.9678 +G01 X-0.2822 Y0.9784 +G01 X-0.1178 Y0.9784 +G01 X-0.0921 Y0.9678 +G01 X-0.0724 Y0.9481 +G01 X-0.0618 Y0.9223 +G01 X-0.0618 Y0.8945 +G01 X-0.0724 Y0.8688 +G01 X-0.0921 Y0.8491 +G01 X-0.1178 Y0.8384 +G01 X-0.2822 Y0.8384 +G01 X-0.3079 Y0.8491 +G01 X-0.3193 Y0.8605 +G01 X-0.3998 Y0.8605 +G01 X-0.4042 Y0.8605 +G01 X-0.4311 Y0.8693 +G01 X-0.4541 Y0.8859 +G01 X-0.4707 Y0.9089 +G01 X-0.4795 Y0.9358 +G01 X-0.4795 Y0.9500 +G01 X-0.4795 Y0.9598 +G01 X-0.4795 Y0.9600 +G01 X-0.4796 Y0.9602 +G01 X-0.4796 Y0.9604 +G01 X-0.4798 Y0.9604 +G01 X-0.4799 Y0.9605 +G01 X-0.4887 Y0.9605 +G01 X-0.4898 Y0.9605 +G01 X-0.5221 Y0.9605 +G01 X-0.4975 Y0.9359 +G01 X-0.4975 Y0.8841 +G01 X-0.5105 Y0.8711 +G01 X-0.5105 Y0.4801 +G01 X-0.5105 Y0.4742 +G01 X-0.5202 Y0.4443 +G01 X-0.5388 Y0.4188 +G01 X-0.5643 Y0.4002 +G01 X-0.5942 Y0.3905 +G01 X-0.6001 Y0.3905 +G01 X-0.7421 Y0.3905 +G01 X-0.7175 Y0.3659 +G01 X-0.7175 Y0.3141 +G01 X-0.7321 Y0.2995 +G01 X-0.5198 Y0.2995 +G01 X-0.5100 Y0.2995 +G01 X-0.5098 Y0.2996 +G01 X-0.5096 Y0.2996 +G01 X-0.5096 Y0.2998 +G01 X-0.5095 Y0.2999 +G01 X-0.5095 Y0.6501 +G01 X-0.5095 Y0.6517 +G01 X-0.5095 Y0.6698 +G01 X-0.5095 Y0.6758 +G01 X-0.4998 Y0.7057 +G01 X-0.4812 Y0.7312 +G01 X-0.4557 Y0.7498 +G01 X-0.4258 Y0.7595 +G01 X-0.4100 Y0.7595 +G01 X-0.4001 Y0.7595 +G01 X-0.3193 Y0.7595 +G01 X-0.3079 Y0.7709 +G01 X-0.2822 Y0.7816 +G01 X-0.1178 Y0.7816 +G01 X-0.0921 Y0.7709 +G01 X-0.0724 Y0.7512 +G01 X-0.0618 Y0.7255 +G01 X-0.0618 Y0.6976 +G01 X-0.0724 Y0.6719 +G01 X-0.0921 Y0.6522 +G01 X-0.1178 Y0.6416 +G01 X-0.2822 Y0.6416 +G01 X-0.3079 Y0.6522 +G01 X-0.3162 Y0.6605 +G01 X-0.4001 Y0.6605 +G01 X-0.4100 Y0.6605 +G01 X-0.4102 Y0.6604 +G01 X-0.4104 Y0.6604 +G01 X-0.4104 Y0.6602 +G01 X-0.4105 Y0.6601 +G01 X-0.4105 Y0.6516 +G01 X-0.4105 Y0.6501 +G01 X-0.4105 Y0.2901 +G01 X-0.4105 Y0.2842 +G01 X-0.4202 Y0.2543 +G01 X-0.4388 Y0.2288 +G01 X-0.4643 Y0.2102 +G01 X-0.4942 Y0.2005 +G01 X-0.5001 Y0.2005 +G01 X-0.5095 Y0.2005 +G01 X-0.5100 Y0.2005 +G01 X-0.5198 Y0.2005 +G01 X-1.0400 Y0.2005 +G01 X-1.0402 Y0.2004 +G01 X-1.0404 Y0.2004 +G01 X-1.0404 Y0.2002 +G01 X-1.0405 Y0.2001 +G01 X-1.0405 Y0.1943 +G01 X-1.0405 Y0.1901 +G01 X-1.0405 Y0.1401 +G01 X-1.0405 Y0.1342 +G01 X-1.0502 Y0.1043 +G01 X-1.0688 Y0.0788 +G01 X-1.0943 Y0.0602 +G01 X-1.1242 Y0.0505 +G01 X-1.1301 Y0.0505 +G01 X-1.6098 Y0.0505 +G01 X-1.6158 Y0.0505 +G01 X-1.6457 Y0.0602 +G01 X-1.6712 Y0.0788 +G01 X-1.6898 Y0.1043 +G01 X-1.6995 Y0.1342 +G01 X-1.6995 Y0.1401 +G01 X-1.6995 Y0.1503 +G01 X-1.6995 Y0.1598 +G01 X-1.6995 Y0.6221 +G01 X-1.7241 Y0.5975 +G01 X-1.7759 Y0.5975 +G01 X-1.7889 Y0.6105 +G01 X-1.8467 Y0.6105 +G01 X-1.8337 Y0.5975 +G01 X-1.8337 Y0.5685 +G01 X-1.8064 Y0.5685 +G01 X-1.7812 Y0.5581 +G01 X-1.7619 Y0.5388 +G01 X-1.7515 Y0.5136 +G01 X-1.7515 Y0.4864 +G01 X-1.7619 Y0.4612 +G01 X-1.7705 Y0.4526 +G01 X-1.7705 Y0.3874 +G01 X-1.7619 Y0.3788 +G01 X-1.7515 Y0.3536 +G01 X-1.7515 Y0.3264 +G01 X-1.7619 Y0.3012 +G01 X-1.7812 Y0.2819 +G01 X-1.8064 Y0.2715 +G01 X-1.8336 Y0.2715 +G01 X-1.8588 Y0.2819 +G01 X-1.8674 Y0.2905 +G01 X-1.9485 Y0.2905 +G01 X-1.9415 Y0.2736 +G01 X-1.9415 Y0.2464 +G01 X-1.9519 Y0.2212 +G01 X-1.9712 Y0.2019 +G01 X-1.9771 Y0.1995 +G01 X-1.8825 Y0.1995 +G01 X-1.8825 Y0.2259 +G01 X-1.8459 Y0.2625 +G01 X-1.7941 Y0.2625 +G01 X-1.7575 Y0.2259 +G01 X-1.7575 Y0.1741 +G01 X-1.7612 Y0.1704 +G01 X-1.7712 Y0.1397 +G01 X-1.7916 Y0.1116 +G01 X-1.8197 Y0.0912 +G01 X-1.8527 Y0.0805 +G01 X-1.8582 Y0.0805 +G01 X-2.4482 Y0.0805 +G01 X-2.4496 Y0.0805 +G01 X-2.4718 Y0.0805 +G01 X-2.4773 Y0.0805 +G01 X-2.5103 Y0.0912 +G01 X-2.5384 Y0.1116 +G01 X-2.5588 Y0.1397 +G01 X-2.5695 Y0.1727 +G01 X-2.5695 Y0.1782 +G01 X-2.5695 Y0.2105 +G01 X-2.6011 Y0.2105 +G01 X-2.6141 Y0.1975 +G01 X-2.6659 Y0.1975 +G01 X-2.7025 Y0.2341 +G01 X-2.7025 Y0.2859 +G01 X-2.6659 Y0.3225 +G01 X-2.6141 Y0.3225 +G01 X-2.6011 Y0.3095 +G01 X-2.5695 Y0.3095 +G01 X-2.5695 Y0.4257 +G01 X-2.5763 Y0.4325 +G01 X-2.5763 Y0.4875 +G01 X-2.5633 Y0.5005 +G01 X-2.8038 Y0.5005 +G01 X-2.8121 Y0.4922 +G01 X-2.8378 Y0.4816 +G01 X-3.0022 Y0.4816 +G01 X-3.0279 Y0.4922 +G01 X-3.0476 Y0.5119 +G01 X-3.0582 Y0.5376 +G01 X-3.0582 Y0.5655 +G01 X-3.0476 Y0.5912 +G01 X-3.0279 Y0.6109 +G01 X-3.0022 Y0.6216 +G01 X-2.8378 Y0.6216 +G01 X-2.8121 Y0.6109 +G01 X-2.8007 Y0.5995 +G01 X-2.2795 Y0.5995 +G01 X-2.2795 Y0.5998 +G01 X-2.2795 Y0.7198 +G01 X-2.2795 Y0.7242 +G01 X-2.2707 Y0.7511 +G01 X-2.2541 Y0.7741 +G01 X-2.2452 Y0.7805 +G01 X-2.2701 Y0.7805 +G01 X-2.2800 Y0.7805 +G01 X-2.2802 Y0.7804 +G01 X-2.2804 Y0.7804 +G01 X-2.2804 Y0.7802 +G01 X-2.2805 Y0.7801 +G01 X-2.2805 Y0.7701 +G01 X-2.2805 Y0.7698 +G01 X-2.2805 Y0.7600 +G01 X-2.2805 Y0.7569 +G01 X-2.2805 Y0.7501 +G01 X-2.2805 Y0.7462 +G01 X-2.2911 Y0.7206 +G01 X-2.3106 Y0.7011 +G01 X-2.3362 Y0.6905 +G01 X-2.3401 Y0.6905 +G01 X-2.6411 Y0.6905 +G01 X-2.6441 Y0.6875 +G01 X-2.6959 Y0.6875 +G01 X-2.7089 Y0.7005 +G01 X-2.8007 Y0.7005 +G01 X-2.8121 Y0.6891 +G01 X-2.8378 Y0.6784 +G01 X-3.0022 Y0.6784 +G01 X-3.0279 Y0.6891 +G01 X-3.0476 Y0.7088 +G01 X-3.0582 Y0.7345 +G01 X-3.0582 Y0.7623 +G01 X-3.0476 Y0.7881 +G01 X-3.0279 Y0.8078 +G01 X-3.0022 Y0.8184 +G01 X-2.8378 Y0.8184 +G01 X-2.8121 Y0.8078 +G01 X-2.8038 Y0.7995 +G01 X-2.7089 Y0.7995 +G01 X-2.6959 Y0.8125 +G01 X-2.6441 Y0.8125 +G01 X-2.6211 Y0.7895 +G01 X-2.3795 Y0.7895 +G01 X-2.3795 Y0.7958 +G01 X-2.3698 Y0.8257 +G01 X-2.3512 Y0.8512 +G01 X-2.3385 Y0.8605 +G01 X-2.4657 Y0.8605 +G01 X-2.4825 Y0.8437 +G01 X-2.5375 Y0.8437 +G01 X-2.5543 Y0.8605 +G01 X-3.1001 Y0.8605 +G01 X-3.1030 Y0.8605 +G01 X-3.1198 Y0.8605 +G01 X-3.1258 Y0.8605 +G01 X-3.1557 Y0.8702 +G01 X-3.1812 Y0.8888 +G01 X-3.1998 Y0.9143 +G01 X-3.2095 Y0.9442 +G01 X-3.2095 Y0.9501 +G01 X-3.2095 Y1.5711 +G01 X-3.2225 Y1.5841 +G01 X-3.2225 Y1.6359 +G01 X-3.2095 Y1.6489 +G01 X-3.2095 Y1.6801 +G01 X-3.2095 Y1.6814 +G01 X-3.2095 Y1.6998 +G01 X-3.2095 Y1.7058 +G01 X-3.1998 Y1.7357 +G01 X-3.1812 Y1.7612 +G01 X-3.1557 Y1.7798 +G01 X-3.1258 Y1.7895 +G01 X-3.1198 Y1.7895 +G01 X-2.9998 Y1.7895 +G01 X-2.9995 Y1.7895 +G01 X-2.9995 Y1.8501 +G01 X-2.9995 Y1.8528 +G01 X-2.9995 Y1.8698 +G01 X-2.9995 Y1.8758 +G01 X-2.9898 Y1.9057 +G01 X-2.9712 Y1.9312 +G01 X-2.9457 Y1.9498 +G01 X-2.9158 Y1.9595 +G01 X-2.9098 Y1.9595 +G01 X-2.0801 Y1.9595 +G01 X-2.0389 Y1.9595 +G01 X-2.0259 Y1.9725 +G01 X-1.9741 Y1.9725 +G01 X-1.9611 Y1.9595 +G01 X-1.7700 Y1.9595 +G01 X-1.7698 Y1.9596 +G01 X-1.7696 Y1.9596 +G01 X-1.7696 Y1.9598 +G01 X-1.7695 Y1.9599 +G01 X-1.7695 Y1.9666 +G01 X-1.7695 Y1.9698 +G01 X-1.7695 Y2.0698 +G01 X-1.7695 Y2.0758 +G01 X-1.7598 Y2.1057 +G01 X-1.7412 Y2.1312 +G01 X-1.7157 Y2.1498 +G01 X-1.6858 Y2.1595 +G01 X-1.6700 Y2.1595 +G01 X-1.6601 Y2.1595 +G01 X-1.2698 Y2.1595 +G01 X-1.2600 Y2.1595 +G01 X-1.2442 Y2.1595 +G01 X-1.2143 Y2.1498 +G01 X-1.1888 Y2.1312 +G01 X-1.1702 Y2.1057 +G01 X-1.1605 Y2.0758 +G01 X-1.1605 Y2.0698 +G01 X-1.1605 Y1.9100 +G01 X-1.1604 Y1.9098 +G01 X-1.1604 Y1.9096 +G01 X-1.1602 Y1.9096 +G01 X-1.1601 Y1.9095 +G01 X-1.1501 Y1.9095 +G01 X-0.8052 Y1.9095 +G01 X-0.7979 Y1.9168 +G01 X-0.7733 Y1.9270 +G01 X-0.7467 Y1.9270 +G01 X-0.7220 Y1.9168 +G01 X-0.7147 Y1.9095 +G01 X-0.2617 Y1.9095 +G01 X-0.2524 Y1.9095 +G01 X-0.2159 Y1.8976 +G01 X-0.1849 Y1.8751 +G01 X-0.1728 Y1.8584 +G01 X-0.1178 Y1.8584 +G01 X-0.0921 Y1.8478 +G01 X-0.0724 Y1.8281 +G01 X-0.0618 Y1.8023 +G01 X-0.0618 Y1.7745 +G01 X-0.0724 Y1.7488 +G01 X-0.0921 Y1.7291 +G01 X-0.1178 Y1.7184 +G01 X-0.2822 Y1.7184 +G01 X-0.3079 Y1.7291 +G01 X-0.3276 Y1.7488 +G01 X-0.3382 Y1.7745 +G01 X-0.3382 Y1.8023 +G01 X-0.3349 Y1.8105 +G01 X-0.7147 Y1.8105 +G01 X-0.7158 Y1.8095 +G01 X-0.6501 Y1.8095 +G01 X-0.6458 Y1.8095 +G01 X-0.6189 Y1.8007 +G01 X-0.5959 Y1.7841 +G01 X-0.5793 Y1.7611 +G01 X-0.5705 Y1.7342 +G01 X-0.5705 Y1.7298 +G01 X-0.5705 Y1.6500 +G01 X-0.5704 Y1.6498 +G01 X-0.5704 Y1.6496 +G01 X-0.5702 Y1.6496 +G01 X-0.5701 Y1.6495 +G01 X-0.5601 Y1.6495 +G01 X-0.3093 Y1.6495 +G01 X-0.3079 Y1.6509 +G01 X-0.2822 Y1.6616 +G01 X-0.1178 Y1.6616 +G01 X-0.0921 Y1.6509 +G01 X-0.0724 Y1.6312 +G01 X-0.0618 Y1.6055 +G01 X-0.0618 Y1.5776 +G01 X-0.0724 Y1.5519 +G01 X-0.0921 Y1.5322 +G01 X-0.1178 Y1.5216 +G01 X-0.2822 Y1.5216 +G01 X-0.3079 Y1.5322 +G01 X-0.3262 Y1.5505 +G01 X-0.5601 Y1.5505 +G01 X-0.5700 Y1.5505 +G01 X-0.5858 Y1.5505 +G01 X-0.6157 Y1.5602 +G01 X-0.6412 Y1.5788 +G01 X-0.6598 Y1.6043 +G01 X-0.6695 Y1.6342 +G01 X-0.6695 Y1.6401 +G01 X-0.6695 Y1.7105 +G01 X-0.7266 Y1.7105 +G01 X-0.7243 Y1.7098 +G01 X-0.6988 Y1.6912 +G01 X-0.6802 Y1.6657 +G01 X-0.6705 Y1.6358 +G01 X-0.6705 Y1.6200 +G01 X-0.6705 Y1.6101 +G01 X-0.6705 Y1.5489 +G01 X-0.6575 Y1.5359 +G01 X-0.6575 Y1.4841 +G01 X-0.6821 Y1.4595 +G01 X-0.5801 Y1.4595 +G01 X-0.5742 Y1.4595 +G01 X-0.5443 Y1.4498 +G01 X-0.5188 Y1.4312 +G01 X-0.5002 Y1.4057 +G01 X-0.4905 Y1.3758 +G01 X-0.4905 Y1.3600 +G01 X-0.4905 Y1.3584 +G01 X-0.4904 Y1.3582 +G01 X-0.4904 Y1.3581 +G01 X-0.4902 Y1.3580 +G01 X-0.4901 Y1.3579 +G01 X-0.4814 Y1.3579 +G01 X-0.4801 Y1.3579 +G01 X-0.3177 Y1.3579 +G01 X-0.3079 Y1.3678 +G01 X-0.2822 Y1.3784 +G01 X-0.1178 Y1.3784 +G01 X-0.0921 Y1.3678 +G01 X-0.0724 Y1.3481 +G01 X-0.0618 Y1.3223 +G01 X-0.0618 Y1.2945 +G01 X-0.0724 Y1.2688 +G01 X-0.0921 Y1.2491 +G01 X-0.1178 Y1.2384 +G01 X-0.2822 Y1.2384 +G01 X-0.3079 Y1.2491 +G01 X-0.3177 Y1.2589 +G01 X-0.4241 Y1.2589 +G01 X-0.3989 Y1.2507 +G01 X-0.3759 Y1.2341 +G01 X-0.3593 Y1.2111 +G01 X-0.3505 Y1.1842 +G01 X-0.3505 Y1.1798 +G01 X-0.3505 Y1.1700 +G01 X-0.3505 Y1.1616 +G01 X-0.3504 Y1.1613 +G01 X-0.3504 Y1.1612 +G01 X-0.3502 Y1.1611 +G01 X-0.3501 Y1.1611 +G01 X-0.3428 Y1.1611 +G01 X-0.3401 Y1.1611 +G01 X-0.3177 Y1.1611 +G01 X-0.3079 Y1.1709 +G01 X-0.2822 Y1.1816 +G00 Z0.1000 +G82 X-0.2200 Y0.1800 Z-0.0110 F10 R0.1000 P1.000000 +G82 X-0.2300 Y2.0300 +G82 X-3.0700 Y2.0100 +G82 X-3.0700 Y0.1900 +G82 X-2.2100 Y1.4700 +G82 X-2.2100 Y1.7400 +G82 X-1.9700 Y1.4700 +G82 X-1.9700 Y1.7900 +G82 X-1.9000 Y0.5700 +G82 X-1.6400 Y1.2700 +G82 X-2.5100 Y0.9100 +G82 X-2.5100 Y0.4600 +G82 X-2.9000 Y1.4400 +G82 X-2.3000 Y1.4400 +G82 X-0.7200 Y1.3100 +G82 X-0.7200 Y1.5100 +G82 X-0.5600 Y1.1100 +G82 X-0.5600 Y0.9100 +G82 X-0.7800 Y0.5400 +G82 X-0.7800 Y0.3400 +G82 X-1.5500 Y0.6600 +G82 X-1.7500 Y0.6600 +G82 X-2.9500 Y1.1300 +G82 X-2.9500 Y1.3300 +G82 X-0.7600 Y1.8600 +G82 X-1.3600 Y1.8600 +G82 X-1.5000 Y1.3100 +G82 X-1.5000 Y1.7100 +G82 X-1.8200 Y0.5000 +G82 X-1.4200 Y0.5000 +G82 X-1.8200 Y0.3400 +G82 X-1.4200 Y0.3400 +G82 X-2.0100 Y0.2600 +G82 X-2.0100 Y0.6600 +G82 X-2.9200 Y0.5516 +G82 X-2.9200 Y0.7484 +G82 X-1.9600 Y1.3100 +G82 X-1.9600 Y1.2100 +G82 X-1.9600 Y1.1100 +G82 X-1.9600 Y1.0100 +G82 X-2.2600 Y1.0100 +G82 X-2.2600 Y1.1100 +G82 X-2.2600 Y1.2100 +G82 X-2.2600 Y1.3100 +G82 X-0.9500 Y1.4100 +G82 X-0.9500 Y1.3100 +G82 X-0.9500 Y1.2100 +G82 X-0.9500 Y1.1100 +G82 X-0.9500 Y1.0100 +G82 X-0.9500 Y0.9100 +G82 X-0.9500 Y0.8100 +G82 X-1.2500 Y0.8100 +G82 X-1.2500 Y0.9100 +G82 X-1.2500 Y1.0100 +G82 X-1.2500 Y1.1100 +G82 X-1.2500 Y1.2100 +G82 X-1.2500 Y1.3100 +G82 X-1.2500 Y1.4100 +G82 X-2.6700 Y1.8200 +G82 X-2.6700 Y1.7200 +G82 X-0.2000 Y1.7884 +G82 X-0.2000 Y1.5916 +G82 X-2.3400 Y1.7400 +G82 X-2.3900 Y1.6650 +G82 X-2.4400 Y1.7400 +G82 X-3.1600 Y1.6100 +G82 X-2.6600 Y1.6100 +G82 X-2.6700 Y0.7500 +G82 X-2.6700 Y1.2500 +G82 X-1.7700 Y1.2000 +G82 X-1.7700 Y1.7000 +G82 X-2.0000 Y1.9100 +G82 X-1.5000 Y1.9100 +G82 X-1.4300 Y1.2100 +G82 X-1.4300 Y0.7100 +G82 X-1.8200 Y0.2000 +G82 X-1.3200 Y0.2000 +G82 X-2.6400 Y0.2600 +G82 X-2.1400 Y0.2600 +G82 X-0.2000 Y1.3084 +G82 X-0.2000 Y1.1116 +G82 X-0.2000 Y0.9084 +G82 X-0.2000 Y0.7116 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.mill.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.mill.tap new file mode 100644 index 00000000..b4c4d899 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.mill.tap @@ -0,0 +1,53 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0100 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-0.9700 Y0.6300 +G01 Z-0.0100 F10.00 +G01 X-1.1100 Y0.6300 F20.00 +G01 X-1.1900 Y0.7100 +G01 X-1.2600 Y0.7100 +G01 X-1.2600 Y0.5000 +G01 X-1.1900 Y0.5000 +G01 X-1.1900 Y0.5100 +G01 X-1.1200 Y0.5800 +G01 X-0.9700 Y0.5800 +G01 X-0.9700 Y0.6300 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.text.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.text.tap new file mode 100644 index 00000000..0a22deae --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.bot.text.tap @@ -0,0 +1,388 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0050 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X-3.0670 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-3.0670 Y2.1357 F20.00 +G01 X-3.0350 Y2.1357 +G01 X-3.0243 Y2.1250 +G01 X-3.0243 Y2.1037 +G01 X-3.0350 Y2.0930 +G01 X-3.0670 Y2.0930 +G00 Z0.1000 +G00 X-2.9598 Y2.1357 +G01 Z-0.0050 F10.00 +G01 X-2.9919 Y2.1357 F20.00 +G01 X-3.0025 Y2.1250 +G01 X-3.0025 Y2.1037 +G01 X-2.9919 Y2.0930 +G01 X-2.9598 Y2.0930 +G00 Z0.1000 +G00 X-2.9381 Y2.1571 +G01 Z-0.0050 F10.00 +G01 X-2.9381 Y2.0930 F20.00 +G01 X-2.9061 Y2.0930 +G01 X-2.8954 Y2.1037 +G01 X-2.8954 Y2.1250 +G01 X-2.9061 Y2.1357 +G01 X-2.9381 Y2.1357 +G00 Z0.1000 +G00 X-2.8523 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-2.8416 Y2.0716 F20.00 +G01 X-2.8309 Y2.0823 +G01 X-2.8309 Y2.1357 +G01 X-2.8630 Y2.1357 +G01 X-2.8736 Y2.1250 +G01 X-2.8736 Y2.1037 +G01 X-2.8630 Y2.0930 +G01 X-2.8309 Y2.0930 +G00 Z0.1000 +G00 X-2.7665 Y2.1357 +G01 Z-0.0050 F10.00 +G01 X-2.7985 Y2.1357 F20.00 +G01 X-2.8092 Y2.1250 +G01 X-2.8092 Y2.1037 +G01 X-2.7985 Y2.0930 +G01 X-2.7665 Y2.0930 +G00 Z0.1000 +G00 X-2.7341 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-2.7127 Y2.0930 F20.00 +G01 X-2.7020 Y2.1037 +G01 X-2.7020 Y2.1250 +G01 X-2.7127 Y2.1357 +G01 X-2.7341 Y2.1357 +G01 X-2.7447 Y2.1250 +G01 X-2.7447 Y2.1037 +G01 X-2.7341 Y2.0930 +G00 Z0.1000 +G00 X-2.6376 Y2.1571 +G01 Z-0.0050 F10.00 +G01 X-2.6376 Y2.0930 F20.00 +G01 X-2.6696 Y2.0930 +G01 X-2.6803 Y2.1037 +G01 X-2.6803 Y2.1250 +G01 X-2.6696 Y2.1357 +G01 X-2.6376 Y2.1357 +G00 Z0.1000 +G00 X-2.5838 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-2.6052 Y2.0930 F20.00 +G01 X-2.6158 Y2.1037 +G01 X-2.6158 Y2.1250 +G01 X-2.6052 Y2.1357 +G01 X-2.5838 Y2.1357 +G01 X-2.5731 Y2.1250 +G01 X-2.5731 Y2.1144 +G01 X-2.6158 Y2.1144 +G00 Z0.1000 +G00 X-2.5087 Y2.1037 +G01 Z-0.0050 F10.00 +G01 X-2.5194 Y2.0930 F20.00 +G01 X-2.5407 Y2.0930 +G01 X-2.5514 Y2.1037 +G01 X-2.5514 Y2.1464 +G01 X-2.5407 Y2.1571 +G01 X-2.5194 Y2.1571 +G01 X-2.5087 Y2.1464 +G01 X-2.5087 Y2.1250 +G01 X-2.5194 Y2.1144 +G01 X-2.5407 Y2.1144 +G01 X-2.5407 Y2.1357 +G01 X-2.5194 Y2.1357 +G01 X-2.5194 Y2.1144 +G00 Z0.1000 +G00 X-2.4869 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-2.4869 Y2.1357 F20.00 +G01 X-2.4549 Y2.1357 +G01 X-2.4442 Y2.1250 +G01 X-2.4442 Y2.1037 +G01 X-2.4549 Y2.0930 +G01 X-2.4869 Y2.0930 +G00 Z0.1000 +G00 X-2.3798 Y2.1357 +G01 Z-0.0050 F10.00 +G01 X-2.4118 Y2.1357 F20.00 +G01 X-2.4225 Y2.1250 +G01 X-2.4225 Y2.1037 +G01 X-2.4118 Y2.0930 +G01 X-2.3798 Y2.0930 +G00 Z0.1000 +G00 X-2.3580 Y2.1571 +G01 Z-0.0050 F10.00 +G01 X-2.3580 Y2.0930 F20.00 +G01 X-2.3260 Y2.0930 +G01 X-2.3153 Y2.1037 +G01 X-2.3153 Y2.1250 +G01 X-2.3260 Y2.1357 +G01 X-2.3580 Y2.1357 +G00 Z0.1000 +G00 X-2.2722 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-2.2615 Y2.0716 F20.00 +G01 X-2.2509 Y2.0823 +G01 X-2.2509 Y2.1357 +G01 X-2.2829 Y2.1357 +G01 X-2.2936 Y2.1250 +G01 X-2.2936 Y2.1037 +G01 X-2.2829 Y2.0930 +G01 X-2.2509 Y2.0930 +G00 Z0.1000 +G00 X-2.1864 Y2.1357 +G01 Z-0.0050 F10.00 +G01 X-2.2184 Y2.1357 F20.00 +G01 X-2.2291 Y2.1250 +G01 X-2.2291 Y2.1037 +G01 X-2.2184 Y2.0930 +G01 X-2.1864 Y2.0930 +G00 Z0.1000 +G00 X-2.1540 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-2.1326 Y2.0930 F20.00 +G01 X-2.1220 Y2.1037 +G01 X-2.1220 Y2.1250 +G01 X-2.1326 Y2.1357 +G01 X-2.1540 Y2.1357 +G01 X-2.1647 Y2.1250 +G01 X-2.1647 Y2.1037 +G01 X-2.1540 Y2.0930 +G00 Z0.1000 +G00 X-2.0575 Y2.1571 +G01 Z-0.0050 F10.00 +G01 X-2.0575 Y2.0930 F20.00 +G01 X-2.0895 Y2.0930 +G01 X-2.1002 Y2.1037 +G01 X-2.1002 Y2.1250 +G01 X-2.0895 Y2.1357 +G01 X-2.0575 Y2.1357 +G00 Z0.1000 +G00 X-2.0037 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-2.0251 Y2.0930 F20.00 +G01 X-2.0358 Y2.1037 +G01 X-2.0358 Y2.1250 +G01 X-2.0251 Y2.1357 +G01 X-2.0037 Y2.1357 +G01 X-1.9931 Y2.1250 +G01 X-1.9931 Y2.1144 +G01 X-2.0358 Y2.1144 +G00 Z0.1000 +G00 X-1.9713 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-1.9713 Y2.1037 F20.00 +G01 X-1.9606 Y2.1037 +G01 X-1.9606 Y2.0930 +G01 X-1.9713 Y2.0930 +G00 Z0.1000 +G00 X-1.9284 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-1.9071 Y2.0930 F20.00 +G01 X-1.8964 Y2.1037 +G01 X-1.8964 Y2.1250 +G01 X-1.9071 Y2.1357 +G01 X-1.9284 Y2.1357 +G01 X-1.9391 Y2.1250 +G01 X-1.9391 Y2.1037 +G01 X-1.9284 Y2.0930 +G00 Z0.1000 +G00 X-1.8746 Y2.0930 +G01 Z-0.0050 F10.00 +G01 X-1.8746 Y2.1357 F20.00 +G00 Z0.1000 +G00 X-1.8746 Y2.1144 +G01 Z-0.0050 F10.00 +G01 X-1.8533 Y2.1357 F20.00 +G01 X-1.8426 Y2.1357 +G00 Z0.1000 +G00 X-1.7996 Y2.0716 +G01 Z-0.0050 F10.00 +G01 X-1.7889 Y2.0716 F20.00 +G01 X-1.7782 Y2.0823 +G01 X-1.7782 Y2.1357 +G01 X-1.8102 Y2.1357 +G01 X-1.8209 Y2.1250 +G01 X-1.8209 Y2.1037 +G01 X-1.8102 Y2.0930 +G01 X-1.7782 Y2.0930 +G00 Z0.1000 +G00 X-2.8443 Y2.0464 +G01 Z-0.0050 F10.00 +G01 X-2.8550 Y2.0571 F20.00 +G01 X-2.8763 Y2.0571 +G01 X-2.8870 Y2.0464 +G01 X-2.8870 Y2.0037 +G01 X-2.8763 Y1.9930 +G01 X-2.8550 Y1.9930 +G01 X-2.8443 Y2.0037 +G00 Z0.1000 +G00 X-2.8119 Y1.9930 +G01 Z-0.0050 F10.00 +G01 X-2.7905 Y1.9930 F20.00 +G01 X-2.7798 Y2.0037 +G01 X-2.7798 Y2.0250 +G01 X-2.7905 Y2.0357 +G01 X-2.8119 Y2.0357 +G01 X-2.8225 Y2.0250 +G01 X-2.8225 Y2.0037 +G01 X-2.8119 Y1.9930 +G00 Z0.1000 +G00 X-2.7581 Y1.9716 +G01 Z-0.0050 F10.00 +G01 X-2.7581 Y2.0357 F20.00 +G01 X-2.7261 Y2.0357 +G01 X-2.7154 Y2.0250 +G01 X-2.7154 Y2.0037 +G01 X-2.7261 Y1.9930 +G01 X-2.7581 Y1.9930 +G00 Z0.1000 +G00 X-2.6936 Y2.0357 +G01 Z-0.0050 F10.00 +G01 X-2.6936 Y2.0037 F20.00 +G01 X-2.6830 Y1.9930 +G01 X-2.6509 Y1.9930 +G00 Z0.1000 +G00 X-2.6509 Y2.0357 +G01 Z-0.0050 F10.00 +G01 X-2.6509 Y1.9823 F20.00 +G01 X-2.6616 Y1.9716 +G01 X-2.6723 Y1.9716 +G00 Z0.1000 +G00 X-2.6292 Y1.9930 +G01 Z-0.0050 F10.00 +G01 X-2.6292 Y2.0357 F20.00 +G00 Z0.1000 +G00 X-2.6292 Y2.0144 +G01 Z-0.0050 F10.00 +G01 X-2.6078 Y2.0357 F20.00 +G01 X-2.5972 Y2.0357 +G00 Z0.1000 +G00 X-2.5755 Y2.0357 +G01 Z-0.0050 F10.00 +G01 X-2.5648 Y2.0357 F20.00 +G01 X-2.5648 Y1.9930 +G00 Z0.1000 +G00 X-2.5755 Y1.9930 +G01 Z-0.0050 F10.00 +G01 X-2.5541 Y1.9930 F20.00 +G00 Z0.1000 +G00 X-2.5648 Y2.0677 +G01 Z-0.0050 F10.00 +G01 X-2.5648 Y2.0571 F20.00 +G00 Z0.1000 +G00 X-2.5112 Y1.9716 +G01 Z-0.0050 F10.00 +G01 X-2.5005 Y1.9716 F20.00 +G01 X-2.4898 Y1.9823 +G01 X-2.4898 Y2.0357 +G01 X-2.5218 Y2.0357 +G01 X-2.5325 Y2.0250 +G01 X-2.5325 Y2.0037 +G01 X-2.5218 Y1.9930 +G01 X-2.4898 Y1.9930 +G00 Z0.1000 +G00 X-2.4681 Y2.0571 +G01 Z-0.0050 F10.00 +G01 X-2.4681 Y1.9930 F20.00 +G00 Z0.1000 +G00 X-2.4681 Y2.0250 +G01 Z-0.0050 F10.00 +G01 X-2.4574 Y2.0357 F20.00 +G01 X-2.4360 Y2.0357 +G01 X-2.4254 Y2.0250 +G01 X-2.4254 Y1.9930 +G00 Z0.1000 +G00 X-2.3929 Y2.0464 +G01 Z-0.0050 F10.00 +G01 X-2.3929 Y2.0037 F20.00 +G01 X-2.3823 Y1.9930 +G00 Z0.1000 +G00 X-2.4036 Y2.0357 +G01 Z-0.0050 F10.00 +G01 X-2.3823 Y2.0357 F20.00 +G00 Z0.1000 +G00 X-2.2535 Y1.9930 +G01 Z-0.0050 F10.00 +G01 X-2.2962 Y1.9930 F20.00 +G01 X-2.2535 Y2.0357 +G01 X-2.2535 Y2.0464 +G01 X-2.2642 Y2.0571 +G01 X-2.2855 Y2.0571 +G01 X-2.2962 Y2.0464 +G00 Z0.1000 +G00 X-2.2317 Y2.0037 +G01 Z-0.0050 F10.00 +G01 X-2.2317 Y2.0464 F20.00 +G01 X-2.2211 Y2.0571 +G01 X-2.1997 Y2.0571 +G01 X-2.1890 Y2.0464 +G01 X-2.1890 Y2.0037 +G01 X-2.1997 Y1.9930 +G01 X-2.2211 Y1.9930 +G01 X-2.2317 Y2.0037 +G01 X-2.1890 Y2.0464 +G00 Z0.1000 +G00 X-2.1673 Y2.0037 +G01 Z-0.0050 F10.00 +G01 X-2.1673 Y2.0464 F20.00 +G01 X-2.1566 Y2.0571 +G01 X-2.1353 Y2.0571 +G01 X-2.1246 Y2.0464 +G01 X-2.1246 Y2.0037 +G01 X-2.1353 Y1.9930 +G01 X-2.1566 Y1.9930 +G01 X-2.1673 Y2.0037 +G01 X-2.1246 Y2.0464 +G00 Z0.1000 +G00 X-2.1028 Y2.0037 +G01 Z-0.0050 F10.00 +G01 X-2.0922 Y1.9930 F20.00 +G01 X-2.0708 Y1.9930 +G01 X-2.0601 Y2.0037 +G01 X-2.0601 Y2.0464 +G01 X-2.0708 Y2.0571 +G01 X-2.0922 Y2.0571 +G01 X-2.1028 Y2.0464 +G01 X-2.1028 Y2.0357 +G01 X-2.0922 Y2.0250 +G01 X-2.0601 Y2.0250 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.brd b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.brd new file mode 100644 index 00000000..1c22253c Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.brd differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.drl.txt b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.drl.txt new file mode 100644 index 00000000..74fbfbd2 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.drl.txt @@ -0,0 +1,26 @@ +# +# Sample drill rack file for the enabtmr board. +# +# Drill is the size of the drill bit. +# Min is the smallest hole the bit will be used for. +# Max is the largest hole the bit will be used for. +# +# Each value can have a "unit of measure" added to it, +# such as 0.500mm . If you do not provide the unit of measure, +# values over 0.250 are considered millimeters, and +# values under 0.250 are considered inches. For example: +# 0.400 would be considered 0.400 mm. +# 0.125 would be considered 0.125 inches. +# +# Please note that you must use a TAB character +# between each setting on a line. +# +# Tip: Set the TAB size of your editor to 12 characters. +# +tool drill_size minimum maximum length +T01 0.500mm 0.000in 0.025in 1.5in +T02 0.032in 0.025in 0.035in 1.5in +T03 0.040in 0.035in 0.045in 1.5in +T04 0.050in 0.045in 0.055in 1.5in +T05 0.062in 0.055in 0.070in 1.5in +T06 0.125in 0.100in 0.125in 1.5in diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.sch b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.sch new file mode 100644 index 00000000..99a7e027 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.sch differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.drill.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.drill.tap new file mode 100644 index 00000000..3e5e1dbf --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.drill.tap @@ -0,0 +1,1461 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +( Tool| Size | Min Sub | Max Sub | Count ) +( T01 0.500mm 0.0197in 0.0197in 0.0236in ) +( T02 0.813mm 0.0320in 0.0320in 0.0320in ) +( T03 1.016mm 0.0400in 0.0400in 0.0440in ) +( T04 1.270mm 0.0500in 0.0470in 0.0500in ) +( T06 3.175mm 0.1250in 0.0000in 0.0000in ) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T01 ; 0.0197 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.6400 Y1.2700 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X1.9000 Y0.5700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9000 Y0.5700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9000 Y0.5700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9000 Y0.5700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.7900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.7900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.7900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9700 Y1.7900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.4700 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2100 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.4600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.4600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.4600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.4600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.5100 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T02 ; 0.0320 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.5600 Y0.9100 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X0.5600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.5600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.5600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.5600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.5100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.5100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.5100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7200 Y1.5100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.5400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.5400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.5400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.7800 Y0.5400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.9500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.8100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y0.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.2500 Y1.4100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.3600 Y1.8600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y0.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y0.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y0.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y0.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4300 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7500 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.7000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.7000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.7000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.7700 Y1.7000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.2000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.9600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0000 Y1.9100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.1400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.1400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.1400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.1400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.1100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.2100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.2600 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3900 Y1.6650 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3900 Y1.6650 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3900 Y1.6650 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.3900 Y1.6650 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.4400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.4400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.4400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.4400 Y1.7400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6400 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y0.7500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y0.7500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y0.7500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y0.7500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.2500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.2500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.2500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.2500 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.7200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.7200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.7200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.7200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.8200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.8200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.8200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.6700 Y1.8200 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9000 Y1.4400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.1300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.1300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.1300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.1300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.3300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.3300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.3300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9500 Y1.3300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.1600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.1600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.1600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.1600 Y1.6100 +G01 Z-0.032000 +G01 Z0.100000 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T03 ; 0.0400 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X1.4200 Y0.3400 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X1.4200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.4200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.3100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.5000 Y1.7100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.3400 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X1.8200 Y0.5000 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.2600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.0100 Y0.6600 +G01 Z-0.032000 +G01 Z0.100000 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T04 ; 0.0500 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2000 Y0.7116 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X0.2000 Y0.9084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y0.9084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y0.9084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y0.9084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.1116 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.1116 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.1116 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.1116 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.3084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.3084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.3084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.3084 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.5916 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.5916 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.5916 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.5916 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.7884 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.7884 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.7884 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2000 Y1.7884 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.5516 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.5516 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.5516 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.5516 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.7484 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.7484 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.7484 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X2.9200 Y0.7484 +G01 Z-0.032000 +G01 Z0.100000 +M05 +G00 Z0.0000 +G00 X0.0000 Y0.0000 +M06 T06 ; 0.1250 +G00 Z0.1000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +G00 Z0.100000 +G00 X0.2200 Y0.1800 +G01 Z-0.0320 F10.00 +G01 Z0.100000 +(R0.1000 P1.000000) +(G00 Z0.100000) +G00 X0.2300 Y2.0300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2300 Y2.0300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2300 Y2.0300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X0.2300 Y2.0300 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y0.1900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y0.1900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y0.1900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y0.1900 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y2.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y2.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y2.0100 +G01 Z-0.032000 +G01 Z0.100000 +(G00 Z0.100000) +G00 X3.0700 Y2.0100 +G01 Z-0.032000 +G01 Z0.100000 +T01 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.etch.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.etch.tap new file mode 100644 index 00000000..0a4154f8 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.etch.tap @@ -0,0 +1,1494 @@ +(.../pcb-gcode-3.5.2.11/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcb-gcode-3.5.2.11/docs/examples/enabtmr.brd) +(Current profile is .../pcb-gcode-3.5.2.11/profiles/emc.pp ) +(This file generated 5/16/11 11:25 PM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0030 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.5000 0.6000 1.5000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0002) +(isolate step = 0.0050) +(Generated top outlines, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X2.4305 Y1.6482 +G01 Z-0.0070 F10.00 +G01 X2.4305 Y1.6818 F20.00 +G01 X2.4068 Y1.7055 +G01 X2.3732 Y1.7055 +G01 X2.3495 Y1.6818 +G01 X2.3495 Y1.6482 +G01 X2.3732 Y1.6245 +G01 X2.4068 Y1.6245 +G01 X2.4305 Y1.6482 +G00 Z0.1000 +G00 X2.0251 Y1.3505 +G01 Z-0.0070 F10.00 +G01 X1.8949 Y1.3505 F20.00 +G01 X1.8801 Y1.3443 +G01 X1.8687 Y1.3329 +G01 X1.8625 Y1.3181 +G01 X1.8625 Y1.3019 +G01 X1.8687 Y1.2871 +G01 X1.8801 Y1.2757 +G01 X1.8949 Y1.2695 +G01 X2.0251 Y1.2695 +G01 X2.0399 Y1.2757 +G01 X2.0513 Y1.2871 +G01 X2.0575 Y1.3019 +G01 X2.0575 Y1.3181 +G01 X2.0513 Y1.3329 +G01 X2.0399 Y1.3443 +G01 X2.0251 Y1.3505 +G00 Z0.1000 +G00 X2.0251 Y1.2505 +G01 Z-0.0070 F10.00 +G01 X1.8949 Y1.2505 F20.00 +G01 X1.8801 Y1.2443 +G01 X1.8687 Y1.2329 +G01 X1.8625 Y1.2181 +G01 X1.8625 Y1.2019 +G01 X1.8687 Y1.1871 +G01 X1.8801 Y1.1757 +G01 X1.8949 Y1.1695 +G01 X2.0251 Y1.1695 +G01 X2.0399 Y1.1757 +G01 X2.0513 Y1.1871 +G01 X2.0575 Y1.2019 +G01 X2.0575 Y1.2181 +G01 X2.0513 Y1.2329 +G01 X2.0399 Y1.2443 +G01 X2.0251 Y1.2505 +G00 Z0.1000 +G00 X2.3251 Y1.2505 +G01 Z-0.0070 F10.00 +G01 X2.1949 Y1.2505 F20.00 +G01 X2.1801 Y1.2443 +G01 X2.1687 Y1.2329 +G01 X2.1625 Y1.2181 +G01 X2.1625 Y1.2019 +G01 X2.1687 Y1.1871 +G01 X2.1801 Y1.1757 +G01 X2.1949 Y1.1695 +G01 X2.3251 Y1.1695 +G01 X2.3399 Y1.1757 +G01 X2.3513 Y1.1871 +G01 X2.3575 Y1.2019 +G01 X2.3575 Y1.2181 +G01 X2.3513 Y1.2329 +G01 X2.3399 Y1.2443 +G01 X2.3251 Y1.2505 +G00 Z0.1000 +G00 X2.3251 Y1.3505 +G01 Z-0.0070 F10.00 +G01 X2.1949 Y1.3505 F20.00 +G01 X2.1801 Y1.3443 +G01 X2.1687 Y1.3329 +G01 X2.1625 Y1.3181 +G01 X2.1625 Y1.3019 +G01 X2.1687 Y1.2871 +G01 X2.1801 Y1.2757 +G01 X2.1949 Y1.2695 +G01 X2.3251 Y1.2695 +G01 X2.3399 Y1.2757 +G01 X2.3513 Y1.2871 +G01 X2.3575 Y1.3019 +G01 X2.3575 Y1.3181 +G01 X2.3513 Y1.3329 +G01 X2.3399 Y1.3443 +G01 X2.3251 Y1.3505 +G00 Z0.1000 +G00 X2.0251 Y1.1505 +G01 Z-0.0070 F10.00 +G01 X1.8949 Y1.1505 F20.00 +G01 X1.8801 Y1.1443 +G01 X1.8687 Y1.1329 +G01 X1.8625 Y1.1181 +G01 X1.8625 Y1.1019 +G01 X1.8687 Y1.0871 +G01 X1.8801 Y1.0757 +G01 X1.8949 Y1.0695 +G01 X2.0251 Y1.0695 +G01 X2.0399 Y1.0757 +G01 X2.0513 Y1.0871 +G01 X2.0575 Y1.1019 +G01 X2.0575 Y1.1181 +G01 X2.0513 Y1.1329 +G01 X2.0399 Y1.1443 +G01 X2.0251 Y1.1505 +G00 Z0.1000 +G00 X2.0251 Y1.0505 +G01 Z-0.0070 F10.00 +G01 X1.8949 Y1.0505 F20.00 +G01 X1.8801 Y1.0443 +G01 X1.8687 Y1.0329 +G01 X1.8625 Y1.0181 +G01 X1.8625 Y1.0019 +G01 X1.8687 Y0.9871 +G01 X1.8801 Y0.9757 +G01 X1.8949 Y0.9695 +G01 X2.0251 Y0.9695 +G01 X2.0399 Y0.9757 +G01 X2.0513 Y0.9871 +G01 X2.0575 Y1.0019 +G01 X2.0575 Y1.0181 +G01 X2.0513 Y1.0329 +G01 X2.0399 Y1.0443 +G01 X2.0251 Y1.0505 +G00 Z0.1000 +G00 X2.3251 Y1.1505 +G01 Z-0.0070 F10.00 +G01 X2.1949 Y1.1505 F20.00 +G01 X2.1801 Y1.1443 +G01 X2.1687 Y1.1329 +G01 X2.1625 Y1.1181 +G01 X2.1625 Y1.1019 +G01 X2.1687 Y1.0871 +G01 X2.1801 Y1.0757 +G01 X2.1949 Y1.0695 +G01 X2.3251 Y1.0695 +G01 X2.3399 Y1.0757 +G01 X2.3513 Y1.0871 +G01 X2.3575 Y1.1019 +G01 X2.3575 Y1.1181 +G01 X2.3513 Y1.1329 +G01 X2.3399 Y1.1443 +G01 X2.3251 Y1.1505 +G00 Z0.1000 +G00 X2.3251 Y1.0505 +G01 Z-0.0070 F10.00 +G01 X2.1949 Y1.0505 F20.00 +G01 X2.1801 Y1.0443 +G01 X2.1687 Y1.0329 +G01 X2.1625 Y1.0181 +G01 X2.1625 Y1.0019 +G01 X2.1687 Y0.9871 +G01 X2.1801 Y0.9757 +G01 X2.1949 Y0.9695 +G01 X2.3251 Y0.9695 +G01 X2.3399 Y0.9757 +G01 X2.3513 Y0.9871 +G01 X2.3575 Y1.0019 +G01 X2.3575 Y1.0181 +G01 X2.3513 Y1.0329 +G01 X2.3399 Y1.0443 +G01 X2.3251 Y1.0505 +G00 Z0.1000 +G00 X1.5465 Y1.3007 +G01 Z-0.0070 F10.00 +G01 X1.5465 Y1.3192 F20.00 +G01 X1.5394 Y1.3363 +G01 X1.5263 Y1.3494 +G01 X1.5092 Y1.3565 +G01 X1.4907 Y1.3565 +G01 X1.4737 Y1.3494 +G01 X1.4606 Y1.3363 +G01 X1.4535 Y1.3192 +G01 X1.4535 Y1.3007 +G01 X1.4606 Y1.2837 +G01 X1.4737 Y1.2706 +G01 X1.4907 Y1.2635 +G01 X1.5092 Y1.2635 +G01 X1.5263 Y1.2706 +G01 X1.5394 Y1.2837 +G01 X1.5465 Y1.3007 +G00 Z0.1000 +G00 X1.5465 Y1.7007 +G01 Z-0.0070 F10.00 +G01 X1.5465 Y1.7192 F20.00 +G01 X1.5394 Y1.7363 +G01 X1.5263 Y1.7494 +G01 X1.5092 Y1.7565 +G01 X1.4907 Y1.7565 +G01 X1.4737 Y1.7494 +G01 X1.4606 Y1.7363 +G01 X1.4535 Y1.7192 +G01 X1.4535 Y1.7007 +G01 X1.4606 Y1.6837 +G01 X1.4737 Y1.6706 +G01 X1.4907 Y1.6635 +G01 X1.5092 Y1.6635 +G01 X1.5263 Y1.6706 +G01 X1.5394 Y1.6837 +G01 X1.5465 Y1.7007 +G00 Z0.1000 +G00 X1.8665 Y0.4907 +G01 Z-0.0070 F10.00 +G01 X1.8665 Y0.5092 F20.00 +G01 X1.8594 Y0.5263 +G01 X1.8463 Y0.5394 +G01 X1.8292 Y0.5465 +G01 X1.8107 Y0.5465 +G01 X1.7937 Y0.5394 +G01 X1.7806 Y0.5263 +G01 X1.7735 Y0.5092 +G01 X1.7735 Y0.4907 +G01 X1.7806 Y0.4737 +G01 X1.7937 Y0.4606 +G01 X1.8107 Y0.4535 +G01 X1.8292 Y0.4535 +G01 X1.8463 Y0.4606 +G01 X1.8594 Y0.4737 +G01 X1.8665 Y0.4907 +G00 Z0.1000 +G00 X1.4665 Y0.4907 +G01 Z-0.0070 F10.00 +G01 X1.4665 Y0.5092 F20.00 +G01 X1.4594 Y0.5263 +G01 X1.4463 Y0.5394 +G01 X1.4292 Y0.5465 +G01 X1.4107 Y0.5465 +G01 X1.3937 Y0.5394 +G01 X1.3806 Y0.5263 +G01 X1.3735 Y0.5092 +G01 X1.3735 Y0.4907 +G01 X1.3806 Y0.4737 +G01 X1.3937 Y0.4606 +G01 X1.4107 Y0.4535 +G01 X1.4292 Y0.4535 +G01 X1.4463 Y0.4606 +G01 X1.4594 Y0.4737 +G01 X1.4665 Y0.4907 +G00 Z0.1000 +G00 X1.8665 Y0.3307 +G01 Z-0.0070 F10.00 +G01 X1.8665 Y0.3492 F20.00 +G01 X1.8594 Y0.3663 +G01 X1.8463 Y0.3794 +G01 X1.8292 Y0.3865 +G01 X1.8107 Y0.3865 +G01 X1.7937 Y0.3794 +G01 X1.7806 Y0.3663 +G01 X1.7735 Y0.3492 +G01 X1.7735 Y0.3307 +G01 X1.7806 Y0.3137 +G01 X1.7937 Y0.3006 +G01 X1.8107 Y0.2935 +G01 X1.8292 Y0.2935 +G01 X1.8463 Y0.3006 +G01 X1.8594 Y0.3137 +G01 X1.8665 Y0.3307 +G00 Z0.1000 +G00 X1.4665 Y0.3307 +G01 Z-0.0070 F10.00 +G01 X1.4665 Y0.3492 F20.00 +G01 X1.4594 Y0.3663 +G01 X1.4463 Y0.3794 +G01 X1.4292 Y0.3865 +G01 X1.4107 Y0.3865 +G01 X1.3937 Y0.3794 +G01 X1.3806 Y0.3663 +G01 X1.3735 Y0.3492 +G01 X1.3735 Y0.3307 +G01 X1.3806 Y0.3137 +G01 X1.3937 Y0.3006 +G01 X1.4107 Y0.2935 +G01 X1.4292 Y0.2935 +G01 X1.4463 Y0.3006 +G01 X1.4594 Y0.3137 +G01 X1.4665 Y0.3307 +G00 Z0.1000 +G00 X2.0565 Y0.2507 +G01 Z-0.0070 F10.00 +G01 X2.0565 Y0.2692 F20.00 +G01 X2.0494 Y0.2863 +G01 X2.0363 Y0.2994 +G01 X2.0192 Y0.3065 +G01 X2.0007 Y0.3065 +G01 X1.9837 Y0.2994 +G01 X1.9706 Y0.2863 +G01 X1.9635 Y0.2692 +G01 X1.9635 Y0.2507 +G01 X1.9706 Y0.2337 +G01 X1.9837 Y0.2206 +G01 X2.0007 Y0.2135 +G01 X2.0192 Y0.2135 +G01 X2.0363 Y0.2206 +G01 X2.0494 Y0.2337 +G01 X2.0565 Y0.2507 +G00 Z0.1000 +G00 X2.0565 Y0.6507 +G01 Z-0.0070 F10.00 +G01 X2.0565 Y0.6692 F20.00 +G01 X2.0494 Y0.6863 +G01 X2.0363 Y0.6994 +G01 X2.0192 Y0.7065 +G01 X2.0007 Y0.7065 +G01 X1.9837 Y0.6994 +G01 X1.9706 Y0.6863 +G01 X1.9635 Y0.6692 +G01 X1.9635 Y0.6507 +G01 X1.9706 Y0.6337 +G01 X1.9837 Y0.6206 +G01 X2.0007 Y0.6135 +G01 X2.0192 Y0.6135 +G01 X2.0363 Y0.6206 +G01 X2.0494 Y0.6337 +G01 X2.0565 Y0.6507 +G00 Z0.1000 +G00 X3.2005 Y1.5932 +G01 Z-0.0070 F10.00 +G01 X3.2005 Y1.6268 F20.00 +G01 X3.1768 Y1.6505 +G01 X3.1432 Y1.6505 +G01 X3.1195 Y1.6268 +G01 X3.1195 Y1.5932 +G01 X3.1432 Y1.5695 +G01 X3.1768 Y1.5695 +G01 X3.2005 Y1.5932 +G00 Z0.1000 +G00 X2.7005 Y1.5932 +G01 Z-0.0070 F10.00 +G01 X2.7005 Y1.6268 F20.00 +G01 X2.6768 Y1.6505 +G01 X2.6432 Y1.6505 +G01 X2.6195 Y1.6268 +G01 X2.6195 Y1.5932 +G01 X2.6432 Y1.5695 +G01 X2.6768 Y1.5695 +G01 X2.7005 Y1.5932 +G00 Z0.1000 +G00 X1.0151 Y1.4505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.4505 F20.00 +G01 X0.8701 Y1.4443 +G01 X0.8587 Y1.4329 +G01 X0.8525 Y1.4181 +G01 X0.8525 Y1.4019 +G01 X0.8587 Y1.3871 +G01 X0.8701 Y1.3757 +G01 X0.8849 Y1.3695 +G01 X1.0151 Y1.3695 +G01 X1.0299 Y1.3757 +G01 X1.0413 Y1.3871 +G01 X1.0475 Y1.4019 +G01 X1.0475 Y1.4181 +G01 X1.0413 Y1.4329 +G01 X1.0299 Y1.4443 +G01 X1.0151 Y1.4505 +G00 Z0.1000 +G00 X1.0151 Y1.3505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.3505 F20.00 +G01 X0.8701 Y1.3443 +G01 X0.8587 Y1.3329 +G01 X0.8525 Y1.3181 +G01 X0.8525 Y1.3019 +G01 X0.8587 Y1.2871 +G01 X0.8701 Y1.2757 +G01 X0.8849 Y1.2695 +G01 X1.0151 Y1.2695 +G01 X1.0299 Y1.2757 +G01 X1.0413 Y1.2871 +G01 X1.0475 Y1.3019 +G01 X1.0475 Y1.3181 +G01 X1.0413 Y1.3329 +G01 X1.0299 Y1.3443 +G01 X1.0151 Y1.3505 +G00 Z0.1000 +G00 X1.0151 Y0.8505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y0.8505 F20.00 +G01 X0.8701 Y0.8443 +G01 X0.8587 Y0.8329 +G01 X0.8525 Y0.8181 +G01 X0.8525 Y0.8019 +G01 X0.8587 Y0.7871 +G01 X0.8701 Y0.7757 +G01 X0.8849 Y0.7695 +G01 X1.0151 Y0.7695 +G01 X1.0299 Y0.7757 +G01 X1.0413 Y0.7871 +G01 X1.0475 Y0.8019 +G01 X1.0475 Y0.8181 +G01 X1.0413 Y0.8329 +G01 X1.0299 Y0.8443 +G01 X1.0151 Y0.8505 +G00 Z0.1000 +G00 X1.3151 Y0.8505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y0.8505 F20.00 +G01 X1.1701 Y0.8443 +G01 X1.1587 Y0.8329 +G01 X1.1525 Y0.8181 +G01 X1.1525 Y0.8019 +G01 X1.1587 Y0.7871 +G01 X1.1701 Y0.7757 +G01 X1.1849 Y0.7695 +G01 X1.3151 Y0.7695 +G01 X1.3299 Y0.7757 +G01 X1.3413 Y0.7871 +G01 X1.3475 Y0.8019 +G01 X1.3475 Y0.8181 +G01 X1.3413 Y0.8329 +G01 X1.3299 Y0.8443 +G01 X1.3151 Y0.8505 +G00 Z0.1000 +G00 X1.0151 Y1.2505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.2505 F20.00 +G01 X0.8701 Y1.2443 +G01 X0.8587 Y1.2329 +G01 X0.8525 Y1.2181 +G01 X0.8525 Y1.2019 +G01 X0.8587 Y1.1871 +G01 X0.8701 Y1.1757 +G01 X0.8849 Y1.1695 +G01 X1.0151 Y1.1695 +G01 X1.0299 Y1.1757 +G01 X1.0413 Y1.1871 +G01 X1.0475 Y1.2019 +G01 X1.0475 Y1.2181 +G01 X1.0413 Y1.2329 +G01 X1.0299 Y1.2443 +G01 X1.0151 Y1.2505 +G00 Z0.1000 +G00 X1.0151 Y1.1505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.1505 F20.00 +G01 X0.8701 Y1.1443 +G01 X0.8587 Y1.1329 +G01 X0.8525 Y1.1181 +G01 X0.8525 Y1.1019 +G01 X0.8587 Y1.0871 +G01 X0.8701 Y1.0757 +G01 X0.8849 Y1.0695 +G01 X1.0151 Y1.0695 +G01 X1.0299 Y1.0757 +G01 X1.0413 Y1.0871 +G01 X1.0475 Y1.1019 +G01 X1.0475 Y1.1181 +G01 X1.0413 Y1.1329 +G01 X1.0299 Y1.1443 +G01 X1.0151 Y1.1505 +G00 Z0.1000 +G00 X1.0151 Y0.9505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y0.9505 F20.00 +G01 X0.8701 Y0.9443 +G01 X0.8587 Y0.9329 +G01 X0.8525 Y0.9181 +G01 X0.8525 Y0.9019 +G01 X0.8587 Y0.8871 +G01 X0.8701 Y0.8757 +G01 X0.8849 Y0.8695 +G01 X1.0151 Y0.8695 +G01 X1.0299 Y0.8757 +G01 X1.0413 Y0.8871 +G01 X1.0475 Y0.9019 +G01 X1.0475 Y0.9181 +G01 X1.0413 Y0.9329 +G01 X1.0299 Y0.9443 +G01 X1.0151 Y0.9505 +G00 Z0.1000 +G00 X1.0151 Y1.0505 +G01 Z-0.0070 F10.00 +G01 X0.8849 Y1.0505 F20.00 +G01 X0.8701 Y1.0443 +G01 X0.8587 Y1.0329 +G01 X0.8525 Y1.0181 +G01 X0.8525 Y1.0019 +G01 X0.8587 Y0.9871 +G01 X0.8701 Y0.9757 +G01 X0.8849 Y0.9695 +G01 X1.0151 Y0.9695 +G01 X1.0299 Y0.9757 +G01 X1.0413 Y0.9871 +G01 X1.0475 Y1.0019 +G01 X1.0475 Y1.0181 +G01 X1.0413 Y1.0329 +G01 X1.0299 Y1.0443 +G01 X1.0151 Y1.0505 +G00 Z0.1000 +G00 X1.3151 Y0.9505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y0.9505 F20.00 +G01 X1.1701 Y0.9443 +G01 X1.1587 Y0.9329 +G01 X1.1525 Y0.9181 +G01 X1.1525 Y0.9019 +G01 X1.1587 Y0.8871 +G01 X1.1701 Y0.8757 +G01 X1.1849 Y0.8695 +G01 X1.3151 Y0.8695 +G01 X1.3299 Y0.8757 +G01 X1.3413 Y0.8871 +G01 X1.3475 Y0.9019 +G01 X1.3475 Y0.9181 +G01 X1.3413 Y0.9329 +G01 X1.3299 Y0.9443 +G01 X1.3151 Y0.9505 +G00 Z0.1000 +G00 X1.3151 Y1.0505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.0505 F20.00 +G01 X1.1701 Y1.0443 +G01 X1.1587 Y1.0329 +G01 X1.1525 Y1.0181 +G01 X1.1525 Y1.0019 +G01 X1.1587 Y0.9871 +G01 X1.1701 Y0.9757 +G01 X1.1849 Y0.9695 +G01 X1.3151 Y0.9695 +G01 X1.3299 Y0.9757 +G01 X1.3413 Y0.9871 +G01 X1.3475 Y1.0019 +G01 X1.3475 Y1.0181 +G01 X1.3413 Y1.0329 +G01 X1.3299 Y1.0443 +G01 X1.3151 Y1.0505 +G00 Z0.1000 +G00 X1.3151 Y1.1505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.1505 F20.00 +G01 X1.1701 Y1.1443 +G01 X1.1587 Y1.1329 +G01 X1.1525 Y1.1181 +G01 X1.1525 Y1.1019 +G01 X1.1587 Y1.0871 +G01 X1.1701 Y1.0757 +G01 X1.1849 Y1.0695 +G01 X1.3151 Y1.0695 +G01 X1.3299 Y1.0757 +G01 X1.3413 Y1.0871 +G01 X1.3475 Y1.1019 +G01 X1.3475 Y1.1181 +G01 X1.3413 Y1.1329 +G01 X1.3299 Y1.1443 +G01 X1.3151 Y1.1505 +G00 Z0.1000 +G00 X1.3151 Y1.2505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.2505 F20.00 +G01 X1.1701 Y1.2443 +G01 X1.1587 Y1.2329 +G01 X1.1525 Y1.2181 +G01 X1.1525 Y1.2019 +G01 X1.1587 Y1.1871 +G01 X1.1701 Y1.1757 +G01 X1.1849 Y1.1695 +G01 X1.3151 Y1.1695 +G01 X1.3299 Y1.1757 +G01 X1.3413 Y1.1871 +G01 X1.3475 Y1.2019 +G01 X1.3475 Y1.2181 +G01 X1.3413 Y1.2329 +G01 X1.3299 Y1.2443 +G01 X1.3151 Y1.2505 +G00 Z0.1000 +G00 X1.3151 Y1.3505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.3505 F20.00 +G01 X1.1701 Y1.3443 +G01 X1.1587 Y1.3329 +G01 X1.1525 Y1.3181 +G01 X1.1525 Y1.3019 +G01 X1.1587 Y1.2871 +G01 X1.1701 Y1.2757 +G01 X1.1849 Y1.2695 +G01 X1.3151 Y1.2695 +G01 X1.3299 Y1.2757 +G01 X1.3413 Y1.2871 +G01 X1.3475 Y1.3019 +G01 X1.3475 Y1.3181 +G01 X1.3413 Y1.3329 +G01 X1.3299 Y1.3443 +G01 X1.3151 Y1.3505 +G00 Z0.1000 +G00 X1.3151 Y1.4505 +G01 Z-0.0070 F10.00 +G01 X1.1849 Y1.4505 F20.00 +G01 X1.1701 Y1.4443 +G01 X1.1587 Y1.4329 +G01 X1.1525 Y1.4181 +G01 X1.1525 Y1.4019 +G01 X1.1587 Y1.3871 +G01 X1.1701 Y1.3757 +G01 X1.1849 Y1.3695 +G01 X1.3151 Y1.3695 +G01 X1.3299 Y1.3757 +G01 X1.3413 Y1.3871 +G01 X1.3475 Y1.4019 +G01 X1.3475 Y1.4181 +G01 X1.3413 Y1.4329 +G01 X1.3299 Y1.4443 +G01 X1.3151 Y1.4505 +G00 Z0.1000 +G00 X0.2778 Y1.3564 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y1.3564 F20.00 +G01 X0.1046 Y1.3491 +G01 X0.0911 Y1.3356 +G01 X0.0838 Y1.3180 +G01 X0.0838 Y1.2989 +G01 X0.0911 Y1.2812 +G01 X0.1046 Y1.2677 +G01 X0.1222 Y1.2604 +G01 X0.2778 Y1.2604 +G01 X0.2954 Y1.2677 +G01 X0.3089 Y1.2812 +G01 X0.3162 Y1.2989 +G01 X0.3162 Y1.3180 +G01 X0.3089 Y1.3356 +G01 X0.2954 Y1.3491 +G01 X0.2778 Y1.3564 +G00 Z0.1000 +G00 X0.2778 Y1.1596 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y1.1596 F20.00 +G01 X0.1046 Y1.1523 +G01 X0.0911 Y1.1388 +G01 X0.0838 Y1.1211 +G01 X0.0838 Y1.1020 +G01 X0.0911 Y1.0844 +G01 X0.1046 Y1.0709 +G01 X0.1222 Y1.0636 +G01 X0.2778 Y1.0636 +G01 X0.2954 Y1.0709 +G01 X0.3089 Y1.0844 +G01 X0.3162 Y1.1020 +G01 X0.3162 Y1.1211 +G01 X0.3089 Y1.1388 +G01 X0.2954 Y1.1523 +G01 X0.2778 Y1.1596 +G00 Z0.1000 +G00 X0.2778 Y0.9564 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y0.9564 F20.00 +G01 X0.1046 Y0.9491 +G01 X0.0911 Y0.9356 +G01 X0.0838 Y0.9180 +G01 X0.0838 Y0.8989 +G01 X0.0911 Y0.8812 +G01 X0.1046 Y0.8677 +G01 X0.1222 Y0.8604 +G01 X0.2778 Y0.8604 +G01 X0.2954 Y0.8677 +G01 X0.3089 Y0.8812 +G01 X0.3162 Y0.8989 +G01 X0.3162 Y0.9180 +G01 X0.3089 Y0.9356 +G01 X0.2954 Y0.9491 +G01 X0.2778 Y0.9564 +G00 Z0.1000 +G00 X0.2778 Y0.7596 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y0.7596 F20.00 +G01 X0.1046 Y0.7523 +G01 X0.0911 Y0.7388 +G01 X0.0838 Y0.7211 +G01 X0.0838 Y0.7020 +G01 X0.0911 Y0.6844 +G01 X0.1046 Y0.6709 +G01 X0.1222 Y0.6636 +G01 X0.2778 Y0.6636 +G01 X0.2954 Y0.6709 +G01 X0.3089 Y0.6844 +G01 X0.3162 Y0.7020 +G01 X0.3162 Y0.7211 +G01 X0.3089 Y0.7388 +G01 X0.2954 Y0.7523 +G01 X0.2778 Y0.7596 +G00 Z0.1000 +G00 X2.8422 Y0.5036 +G01 Z-0.0070 F10.00 +G01 X2.9978 Y0.5036 F20.00 +G01 X3.0154 Y0.5109 +G01 X3.0289 Y0.5244 +G01 X3.0362 Y0.5420 +G01 X3.0362 Y0.5611 +G01 X3.0289 Y0.5788 +G01 X3.0154 Y0.5923 +G01 X2.9978 Y0.5996 +G01 X2.8422 Y0.5996 +G01 X2.8246 Y0.5923 +G01 X2.8111 Y0.5788 +G01 X2.8038 Y0.5611 +G01 X2.8038 Y0.5420 +G01 X2.8111 Y0.5244 +G01 X2.8246 Y0.5109 +G01 X2.8422 Y0.5036 +G00 Z0.1000 +G00 X2.8422 Y0.7004 +G01 Z-0.0070 F10.00 +G01 X2.9978 Y0.7004 F20.00 +G01 X3.0154 Y0.7077 +G01 X3.0289 Y0.7212 +G01 X3.0362 Y0.7389 +G01 X3.0362 Y0.7580 +G01 X3.0289 Y0.7756 +G01 X3.0154 Y0.7891 +G01 X2.9978 Y0.7964 +G01 X2.8422 Y0.7964 +G01 X2.8246 Y0.7891 +G01 X2.8111 Y0.7756 +G01 X2.8038 Y0.7580 +G01 X2.8038 Y0.7389 +G01 X2.8111 Y0.7212 +G01 X2.8246 Y0.7077 +G01 X2.8422 Y0.7004 +G00 Z0.1000 +G00 X0.2778 Y1.8364 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y1.8364 F20.00 +G01 X0.1046 Y1.8291 +G01 X0.0911 Y1.8156 +G01 X0.0838 Y1.7980 +G01 X0.0838 Y1.7789 +G01 X0.0911 Y1.7612 +G01 X0.1046 Y1.7477 +G01 X0.1222 Y1.7404 +G01 X0.2778 Y1.7404 +G01 X0.2954 Y1.7477 +G01 X0.3089 Y1.7612 +G01 X0.3162 Y1.7789 +G01 X0.3162 Y1.7980 +G01 X0.3089 Y1.8156 +G01 X0.2954 Y1.8291 +G01 X0.2778 Y1.8364 +G00 Z0.1000 +G00 X0.2778 Y1.6396 +G01 Z-0.0070 F10.00 +G01 X0.1222 Y1.6396 F20.00 +G01 X0.1046 Y1.6323 +G01 X0.0911 Y1.6188 +G01 X0.0838 Y1.6011 +G01 X0.0838 Y1.5820 +G01 X0.0911 Y1.5644 +G01 X0.1046 Y1.5509 +G01 X0.1222 Y1.5436 +G01 X0.2778 Y1.5436 +G01 X0.2954 Y1.5509 +G01 X0.3089 Y1.5644 +G01 X0.3162 Y1.5820 +G01 X0.3162 Y1.6011 +G01 X0.3089 Y1.6188 +G01 X0.2954 Y1.6323 +G01 X0.2778 Y1.6396 +G00 Z0.1000 +G00 X0.7605 Y1.2932 +G01 Z-0.0070 F10.00 +G01 X0.7605 Y1.3268 F20.00 +G01 X0.7368 Y1.3505 +G01 X0.7032 Y1.3505 +G01 X0.6795 Y1.3268 +G01 X0.6795 Y1.2932 +G01 X0.7032 Y1.2695 +G01 X0.7368 Y1.2695 +G01 X0.7605 Y1.2932 +G00 Z0.1000 +G00 X0.7605 Y1.4932 +G01 Z-0.0070 F10.00 +G01 X0.7605 Y1.5268 F20.00 +G01 X0.7368 Y1.5505 +G01 X0.7032 Y1.5505 +G01 X0.6795 Y1.5268 +G01 X0.6795 Y1.4932 +G01 X0.7032 Y1.4695 +G01 X0.7368 Y1.4695 +G01 X0.7605 Y1.4932 +G00 Z0.1000 +G00 X0.6005 Y1.0932 +G01 Z-0.0070 F10.00 +G01 X0.6005 Y1.1268 F20.00 +G01 X0.5768 Y1.1505 +G01 X0.5432 Y1.1505 +G01 X0.5195 Y1.1268 +G01 X0.5195 Y1.0932 +G01 X0.5432 Y1.0695 +G01 X0.5768 Y1.0695 +G01 X0.6005 Y1.0932 +G00 Z0.1000 +G00 X0.6005 Y0.8932 +G01 Z-0.0070 F10.00 +G01 X0.6005 Y0.9268 F20.00 +G01 X0.5768 Y0.9505 +G01 X0.5432 Y0.9505 +G01 X0.5195 Y0.9268 +G01 X0.5195 Y0.8932 +G01 X0.5432 Y0.8695 +G01 X0.5768 Y0.8695 +G01 X0.6005 Y0.8932 +G00 Z0.1000 +G00 X0.8205 Y0.5232 +G01 Z-0.0070 F10.00 +G01 X0.8205 Y0.5568 F20.00 +G01 X0.7968 Y0.5805 +G01 X0.7632 Y0.5805 +G01 X0.7395 Y0.5568 +G01 X0.7395 Y0.5232 +G01 X0.7632 Y0.4995 +G01 X0.7968 Y0.4995 +G01 X0.8205 Y0.5232 +G00 Z0.1000 +G00 X0.8205 Y0.3232 +G01 Z-0.0070 F10.00 +G01 X0.8205 Y0.3568 F20.00 +G01 X0.7968 Y0.3805 +G01 X0.7632 Y0.3805 +G01 X0.7395 Y0.3568 +G01 X0.7395 Y0.3232 +G01 X0.7632 Y0.2995 +G01 X0.7968 Y0.2995 +G01 X0.8205 Y0.3232 +G00 Z0.1000 +G00 X1.5905 Y0.6432 +G01 Z-0.0070 F10.00 +G01 X1.5905 Y0.6768 F20.00 +G01 X1.5668 Y0.7005 +G01 X1.5332 Y0.7005 +G01 X1.5095 Y0.6768 +G01 X1.5095 Y0.6432 +G01 X1.5332 Y0.6195 +G01 X1.5668 Y0.6195 +G01 X1.5905 Y0.6432 +G00 Z0.1000 +G00 X1.7905 Y0.6432 +G01 Z-0.0070 F10.00 +G01 X1.7905 Y0.6768 F20.00 +G01 X1.7668 Y0.7005 +G01 X1.7332 Y0.7005 +G01 X1.7095 Y0.6768 +G01 X1.7095 Y0.6432 +G01 X1.7332 Y0.6195 +G01 X1.7668 Y0.6195 +G01 X1.7905 Y0.6432 +G00 Z0.1000 +G00 X2.7105 Y0.7332 +G01 Z-0.0070 F10.00 +G01 X2.7105 Y0.7668 F20.00 +G01 X2.6868 Y0.7905 +G01 X2.6532 Y0.7905 +G01 X2.6295 Y0.7668 +G01 X2.6295 Y0.7332 +G01 X2.6532 Y0.7095 +G01 X2.6868 Y0.7095 +G01 X2.7105 Y0.7332 +G00 Z0.1000 +G00 X2.7105 Y1.2332 +G01 Z-0.0070 F10.00 +G01 X2.7105 Y1.2668 F20.00 +G01 X2.6868 Y1.2905 +G01 X2.6532 Y1.2905 +G01 X2.6295 Y1.2668 +G01 X2.6295 Y1.2332 +G01 X2.6532 Y1.2095 +G01 X2.6868 Y1.2095 +G01 X2.7105 Y1.2332 +G00 Z0.1000 +G00 X2.7105 Y1.8032 +G01 Z-0.0070 F10.00 +G01 X2.7105 Y1.8368 F20.00 +G01 X2.6868 Y1.8605 +G01 X2.6532 Y1.8605 +G01 X2.6295 Y1.8368 +G01 X2.6295 Y1.8032 +G01 X2.6532 Y1.7795 +G01 X2.6868 Y1.7795 +G01 X2.7105 Y1.8032 +G00 Z0.1000 +G00 X2.7105 Y1.7032 +G01 Z-0.0070 F10.00 +G01 X2.7105 Y1.7368 F20.00 +G01 X2.6868 Y1.7605 +G01 X2.6532 Y1.7605 +G01 X2.6295 Y1.7368 +G01 X2.6295 Y1.7032 +G01 X2.6532 Y1.6795 +G01 X2.6868 Y1.6795 +G01 X2.7105 Y1.7032 +G00 Z0.1000 +G00 X2.9905 Y1.1132 +G01 Z-0.0070 F10.00 +G01 X2.9905 Y1.1468 F20.00 +G01 X2.9668 Y1.1705 +G01 X2.9332 Y1.1705 +G01 X2.9095 Y1.1468 +G01 X2.9095 Y1.1132 +G01 X2.9332 Y1.0895 +G01 X2.9668 Y1.0895 +G01 X2.9905 Y1.1132 +G00 Z0.1000 +G00 X2.9905 Y1.3132 +G01 Z-0.0070 F10.00 +G01 X2.9905 Y1.3468 F20.00 +G01 X2.9668 Y1.3705 +G01 X2.9332 Y1.3705 +G01 X2.9095 Y1.3468 +G01 X2.9095 Y1.3132 +G01 X2.9332 Y1.2895 +G01 X2.9668 Y1.2895 +G01 X2.9905 Y1.3132 +G00 Z0.1000 +G00 X1.8105 Y1.1832 +G01 Z-0.0070 F10.00 +G01 X1.8105 Y1.2168 F20.00 +G01 X1.7868 Y1.2405 +G01 X1.7532 Y1.2405 +G01 X1.7295 Y1.2168 +G01 X1.7295 Y1.1832 +G01 X1.7532 Y1.1595 +G01 X1.7868 Y1.1595 +G01 X1.8105 Y1.1832 +G00 Z0.1000 +G00 X1.8105 Y1.6832 +G01 Z-0.0070 F10.00 +G01 X1.8105 Y1.7168 F20.00 +G01 X1.7868 Y1.7405 +G01 X1.7532 Y1.7405 +G01 X1.7295 Y1.7168 +G01 X1.7295 Y1.6832 +G01 X1.7532 Y1.6595 +G01 X1.7868 Y1.6595 +G01 X1.8105 Y1.6832 +G00 Z0.1000 +G00 X2.0405 Y1.8932 +G01 Z-0.0070 F10.00 +G01 X2.0405 Y1.9268 F20.00 +G01 X2.0168 Y1.9505 +G01 X1.9832 Y1.9505 +G01 X1.9595 Y1.9268 +G01 X1.9595 Y1.8932 +G01 X1.9832 Y1.8695 +G01 X2.0168 Y1.8695 +G01 X2.0405 Y1.8932 +G00 Z0.1000 +G00 X1.5405 Y1.8932 +G01 Z-0.0070 F10.00 +G01 X1.5405 Y1.9268 F20.00 +G01 X1.5168 Y1.9505 +G01 X1.4832 Y1.9505 +G01 X1.4595 Y1.9268 +G01 X1.4595 Y1.8932 +G01 X1.4832 Y1.8695 +G01 X1.5168 Y1.8695 +G01 X1.5405 Y1.8932 +G00 Z0.1000 +G00 X1.4705 Y1.1932 +G01 Z-0.0070 F10.00 +G01 X1.4705 Y1.2268 F20.00 +G01 X1.4468 Y1.2505 +G01 X1.4132 Y1.2505 +G01 X1.3895 Y1.2268 +G01 X1.3895 Y1.1932 +G01 X1.4132 Y1.1695 +G01 X1.4468 Y1.1695 +G01 X1.4705 Y1.1932 +G00 Z0.1000 +G00 X1.4705 Y0.6932 +G01 Z-0.0070 F10.00 +G01 X1.4705 Y0.7268 F20.00 +G01 X1.4468 Y0.7505 +G01 X1.4132 Y0.7505 +G01 X1.3895 Y0.7268 +G01 X1.3895 Y0.6932 +G01 X1.4132 Y0.6695 +G01 X1.4468 Y0.6695 +G01 X1.4705 Y0.6932 +G00 Z0.1000 +G00 X1.8605 Y0.1832 +G01 Z-0.0070 F10.00 +G01 X1.8605 Y0.2168 F20.00 +G01 X1.8368 Y0.2405 +G01 X1.8032 Y0.2405 +G01 X1.7795 Y0.2168 +G01 X1.7795 Y0.1832 +G01 X1.8032 Y0.1595 +G01 X1.8368 Y0.1595 +G01 X1.8605 Y0.1832 +G00 Z0.1000 +G00 X1.3605 Y0.1832 +G01 Z-0.0070 F10.00 +G01 X1.3605 Y0.2168 F20.00 +G01 X1.3368 Y0.2405 +G01 X1.3032 Y0.2405 +G01 X1.2795 Y0.2168 +G01 X1.2795 Y0.1832 +G01 X1.3032 Y0.1595 +G01 X1.3368 Y0.1595 +G01 X1.3605 Y0.1832 +G00 Z0.1000 +G00 X2.6805 Y0.2432 +G01 Z-0.0070 F10.00 +G01 X2.6805 Y0.2768 F20.00 +G01 X2.6568 Y0.3005 +G01 X2.6232 Y0.3005 +G01 X2.5995 Y0.2768 +G01 X2.5995 Y0.2432 +G01 X2.6232 Y0.2195 +G01 X2.6568 Y0.2195 +G01 X2.6805 Y0.2432 +G00 Z0.1000 +G00 X2.1805 Y0.2432 +G01 Z-0.0070 F10.00 +G01 X2.1805 Y0.2768 F20.00 +G01 X2.1568 Y0.3005 +G01 X2.1232 Y0.3005 +G01 X2.0995 Y0.2768 +G01 X2.0995 Y0.2432 +G01 X2.1232 Y0.2195 +G01 X2.1568 Y0.2195 +G01 X2.1805 Y0.2432 +G00 Z0.1000 +G00 X2.3805 Y1.7232 +G01 Z-0.0070 F10.00 +G01 X2.3805 Y1.7568 F20.00 +G01 X2.3568 Y1.7805 +G01 X2.3232 Y1.7805 +G01 X2.2995 Y1.7568 +G01 X2.2995 Y1.7232 +G01 X2.3232 Y1.6995 +G01 X2.3568 Y1.6995 +G01 X2.3805 Y1.7232 +G00 Z0.1000 +G00 X2.4805 Y1.7232 +G01 Z-0.0070 F10.00 +G01 X2.4805 Y1.7568 F20.00 +G01 X2.4568 Y1.7805 +G01 X2.4232 Y1.7805 +G01 X2.3995 Y1.7568 +G01 X2.3995 Y1.7232 +G01 X2.4232 Y1.6995 +G01 X2.4568 Y1.6995 +G01 X2.4805 Y1.7232 +G00 Z0.1000 +G00 X2.9450 Y1.4310 +G01 Z-0.0070 F10.00 +G01 X2.9450 Y1.4489 F20.00 +G01 X2.9381 Y1.4655 +G01 X2.9255 Y1.4781 +G01 X2.9089 Y1.4850 +G01 X2.8910 Y1.4850 +G01 X2.8745 Y1.4781 +G01 X2.8619 Y1.4655 +G01 X2.8550 Y1.4489 +G01 X2.8550 Y1.4310 +G01 X2.8619 Y1.4145 +G01 X2.8745 Y1.4019 +G01 X2.8910 Y1.3950 +G01 X2.9089 Y1.3950 +G01 X2.9255 Y1.4019 +G01 X2.9381 Y1.4145 +G01 X2.9450 Y1.4310 +G00 Z0.1000 +G00 X2.3450 Y1.4214 +G01 Z-0.0070 F10.00 +G01 X2.3450 Y1.4586 F20.00 +G01 X2.3186 Y1.4850 +G01 X2.2814 Y1.4850 +G01 X2.2550 Y1.4586 +G01 X2.2550 Y1.4214 +G01 X2.2814 Y1.3950 +G01 X2.3186 Y1.3950 +G01 X2.3450 Y1.4214 +G00 Z0.1000 +G00 X0.8050 Y1.8510 +G01 Z-0.0070 F10.00 +G01 X0.8050 Y1.8689 F20.00 +G01 X0.7981 Y1.8855 +G01 X0.7855 Y1.8981 +G01 X0.7689 Y1.9050 +G01 X0.7510 Y1.9050 +G01 X0.7345 Y1.8981 +G01 X0.7219 Y1.8855 +G01 X0.7150 Y1.8689 +G01 X0.7150 Y1.8510 +G01 X0.7219 Y1.8345 +G01 X0.7345 Y1.8219 +G01 X0.7510 Y1.8150 +G01 X0.7689 Y1.8150 +G01 X0.7855 Y1.8219 +G01 X0.7981 Y1.8345 +G01 X0.8050 Y1.8510 +G00 Z0.1000 +G00 X1.4050 Y1.8414 +G01 Z-0.0070 F10.00 +G01 X1.4050 Y1.8786 F20.00 +G01 X1.3786 Y1.9050 +G01 X1.3414 Y1.9050 +G01 X1.3150 Y1.8786 +G01 X1.3150 Y1.8414 +G01 X1.3414 Y1.8150 +G01 X1.3786 Y1.8150 +G01 X1.4050 Y1.8414 +G00 Z0.1000 +G00 X2.2543 Y1.4516 +G01 Z-0.0070 F10.00 +G01 X2.2543 Y1.4884 F20.00 +G01 X2.2375 Y1.5052 +G01 X2.2375 Y1.7048 +G01 X2.2543 Y1.7216 +G01 X2.2543 Y1.7584 +G01 X2.2284 Y1.7843 +G01 X2.1916 Y1.7843 +G01 X2.1657 Y1.7584 +G01 X2.1657 Y1.7216 +G01 X2.1825 Y1.7048 +G01 X2.1825 Y1.5052 +G01 X2.1657 Y1.4884 +G01 X2.1657 Y1.4516 +G01 X2.1916 Y1.4257 +G01 X2.2284 Y1.4257 +G01 X2.2543 Y1.4516 +G00 Z0.1000 +G00 X2.0143 Y1.4516 +G01 Z-0.0070 F10.00 +G01 X2.0143 Y1.4884 F20.00 +G01 X1.9975 Y1.5052 +G01 X1.9975 Y1.7548 +G01 X2.0143 Y1.7716 +G01 X2.0143 Y1.8084 +G01 X1.9884 Y1.8343 +G01 X1.9516 Y1.8343 +G01 X1.9257 Y1.8084 +G01 X1.9257 Y1.7716 +G01 X1.9425 Y1.7548 +G01 X1.9425 Y1.5052 +G01 X1.9257 Y1.4884 +G01 X1.9257 Y1.4516 +G01 X1.9516 Y1.4257 +G01 X1.9884 Y1.4257 +G01 X2.0143 Y1.4516 +G00 Z0.1000 +G00 X2.5543 Y0.8916 +G01 Z-0.0070 F10.00 +G01 X2.5543 Y0.9284 F20.00 +G01 X2.5284 Y0.9543 +G01 X2.4916 Y0.9543 +G01 X2.4657 Y0.9284 +G01 X2.4657 Y0.8916 +G01 X2.4825 Y0.8748 +G01 X2.4825 Y0.4952 +G01 X2.4657 Y0.4784 +G01 X2.4657 Y0.4416 +G01 X2.4916 Y0.4157 +G01 X2.5284 Y0.4157 +G01 X2.5543 Y0.4416 +G01 X2.5543 Y0.4784 +G01 X2.5375 Y0.4952 +G01 X2.5375 Y0.8748 +G01 X2.5543 Y0.8916 +G00 Z0.1000 +G00 X1.6125 Y0.9246 +G01 Z-0.0070 F10.00 +G01 X1.6125 Y0.9246 F20.00 +G01 X1.6243 Y0.8961 +G01 X1.6461 Y0.8743 +G01 X1.6746 Y0.8625 +G01 X1.6845 Y0.8625 +G01 X1.6900 Y0.8625 +G01 X1.6955 Y0.8625 +G01 X1.8500 Y0.8625 +G01 X1.8544 Y0.8621 +G01 X1.8625 Y0.8587 +G01 X1.8687 Y0.8525 +G01 X1.8721 Y0.8444 +G01 X1.8725 Y0.8400 +G01 X1.8725 Y0.8368 +G01 X1.8725 Y0.8345 +G01 X1.8725 Y0.6052 +G01 X1.8557 Y0.5884 +G01 X1.8557 Y0.5516 +G01 X1.8816 Y0.5257 +G01 X1.9184 Y0.5257 +G01 X1.9443 Y0.5516 +G01 X1.9443 Y0.5884 +G01 X1.9275 Y0.6052 +G01 X1.9275 Y0.8345 +G01 X1.9275 Y0.8369 +G01 X1.9275 Y0.8455 +G01 X1.9275 Y0.8554 +G01 X1.9157 Y0.8839 +G01 X1.8939 Y0.9057 +G01 X1.8654 Y0.9175 +G01 X1.8555 Y0.9175 +G01 X1.6955 Y0.9175 +G01 X1.6900 Y0.9175 +G01 X1.6856 Y0.9179 +G01 X1.6775 Y0.9213 +G01 X1.6713 Y0.9275 +G01 X1.6679 Y0.9356 +G01 X1.6675 Y0.9400 +G01 X1.6675 Y1.2348 +G01 X1.6843 Y1.2516 +G01 X1.6843 Y1.2884 +G01 X1.6584 Y1.3143 +G01 X1.6216 Y1.3143 +G01 X1.5957 Y1.2884 +G01 X1.5957 Y1.2516 +G01 X1.6125 Y1.2348 +G01 X1.6125 Y0.9345 +G01 X1.6125 Y0.9246 +G00 Z0.1000 +G00 X0.2200 Y0.1800 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2300 Y2.0300 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X3.0700 Y2.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X3.0700 Y0.1900 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2100 Y1.4700 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2100 Y1.7400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9700 Y1.4700 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9700 Y1.7900 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9000 Y0.5700 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.6400 Y1.2700 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.5100 Y0.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.5100 Y0.4600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9000 Y1.4400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.3000 Y1.4400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7200 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7200 Y1.5100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.5600 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.5600 Y0.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7800 Y0.5400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7800 Y0.3400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.5500 Y0.6600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.7500 Y0.6600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9500 Y1.1300 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9500 Y1.3300 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.7600 Y1.8600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.3600 Y1.8600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.5000 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.5000 Y1.7100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.8200 Y0.5000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.4200 Y0.5000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.8200 Y0.3400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.4200 Y0.3400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.0100 Y0.2600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.0100 Y0.6600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9200 Y0.5516 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.9200 Y0.7484 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9600 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9600 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9600 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.9600 Y1.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2600 Y1.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2600 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2600 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.2600 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.4100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y1.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y0.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.9500 Y0.8100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y0.8100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y0.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.0100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.1100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.3100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.2500 Y1.4100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6700 Y1.8200 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6700 Y1.7200 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y1.7884 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y1.5916 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.3400 Y1.7400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.3900 Y1.6650 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.4400 Y1.7400 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X3.1600 Y1.6100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6600 Y1.6100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6700 Y0.7500 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6700 Y1.2500 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.7700 Y1.2000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.7700 Y1.7000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.0000 Y1.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.5000 Y1.9100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.4300 Y1.2100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.4300 Y0.7100 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.8200 Y0.2000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X1.3200 Y0.2000 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.6400 Y0.2600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X2.1400 Y0.2600 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y1.3084 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y1.1116 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y0.9084 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 X0.2000 Y0.7116 +G01 Z-0.0110 F10.00 +G00 Z0.1000 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.mill.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.mill.tap new file mode 100644 index 00000000..c22a0891 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.mill.tap @@ -0,0 +1,53 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0070 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X0.9700 Y0.6300 +G01 Z-0.0100 F10.00 +G01 X1.1100 Y0.6300 F20.00 +G01 X1.1900 Y0.7100 +G01 X1.2600 Y0.7100 +G01 X1.2600 Y0.5000 +G01 X1.1900 Y0.5000 +G01 X1.1900 Y0.5100 +G01 X1.1200 Y0.5800 +G01 X0.9700 Y0.5800 +G01 X0.9700 Y0.6300 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.text.tap b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.text.tap new file mode 100644 index 00000000..8bde108c --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/examples/enabtmr.top.text.tap @@ -0,0 +1,151 @@ +(.../Documents/src/pcbgcode/pcb-gcode.ulp) +(Copyright 2005 - 2009 by John Johnson) +(See readme.txt for licensing terms.) +(This file generated from the board:) +(.../pcbgcode/docs/examples/enabtmr.brd) +(Current profile is .../pcbgcode/profiles/generic.pp ) +(This file generated 2/7/09 10:26 AM) +(Settings from pcb-machine.h) +( Tool Size) +(0.0100 ) +(Z Axis Settings) +( High Up Down Drill) +(0.5000 0.1000 -0.0070 -0.0320 ) +(spindle on time = 3.0000) +(milling depth = -0.0100) +(text depth = -0.0050) +(tool change at 0.0000 0.0000 0.0000 ) +(feed rate xy = F20.00 ) +(feed rate z = F10.00 ) +(Settings from pcb-defaults.h) +(Isolate min = 0.0010) +(isolate max = 0.0200) +(isolate step = 0.0050) +(Generated top outlines, top drill, bottom outlines, bottom drill, ) +(Unit of measure: inch) +(Inch Mode) +G20 +(Inch Mode) +G20 +(Absolute Coordinates) +G90 +(Absolute Coordinates) +G90 +G00 X0.0000 Y0.0000 +M03 +G04 P3.000000 +M03 +G04 P3.000000 +G00 Z0.1000 +G00 X0.4457 Y2.1371 +G01 Z-0.0050 F10.00 +G01 X0.4030 Y2.1371 F20.00 +G01 X0.4030 Y2.0730 +G01 X0.4457 Y2.0730 +G00 Z0.1000 +G00 X0.4030 Y2.1050 +G01 Z-0.0050 F10.00 +G01 X0.4244 Y2.1050 F20.00 +G00 Z0.1000 +G00 X0.4675 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.4675 Y2.1157 F20.00 +G01 X0.4995 Y2.1157 +G01 X0.5102 Y2.1050 +G01 X0.5102 Y2.0730 +G00 Z0.1000 +G00 X0.5426 Y2.1157 +G01 Z-0.0050 F10.00 +G01 X0.5639 Y2.1157 F20.00 +G01 X0.5746 Y2.1050 +G01 X0.5746 Y2.0730 +G01 X0.5426 Y2.0730 +G01 X0.5319 Y2.0837 +G01 X0.5426 Y2.0944 +G01 X0.5746 Y2.0944 +G00 Z0.1000 +G00 X0.5964 Y2.1371 +G01 Z-0.0050 F10.00 +G01 X0.5964 Y2.0730 F20.00 +G01 X0.6284 Y2.0730 +G01 X0.6391 Y2.0837 +G01 X0.6391 Y2.1050 +G01 X0.6284 Y2.1157 +G01 X0.5964 Y2.1157 +G00 Z0.1000 +G00 X0.6608 Y2.1371 +G01 Z-0.0050 F10.00 +G01 X0.6715 Y2.1371 F20.00 +G01 X0.6715 Y2.0730 +G00 Z0.1000 +G00 X0.6608 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.6822 Y2.0730 F20.00 +G00 Z0.1000 +G00 X0.7358 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.7145 Y2.0730 F20.00 +G01 X0.7038 Y2.0837 +G01 X0.7038 Y2.1050 +G01 X0.7145 Y2.1157 +G01 X0.7358 Y2.1157 +G01 X0.7465 Y2.1050 +G01 X0.7465 Y2.0944 +G01 X0.7038 Y2.0944 +G00 Z0.1000 +G00 X0.8540 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.8540 Y2.1371 F20.00 +G00 Z0.1000 +G00 X0.8327 Y2.1371 +G01 Z-0.0050 F10.00 +G01 X0.8754 Y2.1371 F20.00 +G00 Z0.1000 +G00 X0.8971 Y2.1157 +G01 Z-0.0050 F10.00 +G01 X0.9078 Y2.1157 F20.00 +G01 X0.9078 Y2.0730 +G00 Z0.1000 +G00 X0.8971 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.9185 Y2.0730 F20.00 +G00 Z0.1000 +G00 X0.9078 Y2.1477 +G01 Z-0.0050 F10.00 +G01 X0.9078 Y2.1371 F20.00 +G00 Z0.1000 +G00 X0.9401 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X0.9401 Y2.1157 F20.00 +G01 X0.9508 Y2.1157 +G01 X0.9615 Y2.1050 +G01 X0.9615 Y2.0730 +G00 Z0.1000 +G00 X0.9615 Y2.1050 +G01 Z-0.0050 F10.00 +G01 X0.9721 Y2.1157 F20.00 +G01 X0.9828 Y2.1050 +G01 X0.9828 Y2.0730 +G00 Z0.1000 +G00 X1.0366 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X1.0152 Y2.0730 F20.00 +G01 X1.0046 Y2.0837 +G01 X1.0046 Y2.1050 +G01 X1.0152 Y2.1157 +G01 X1.0366 Y2.1157 +G01 X1.0473 Y2.1050 +G01 X1.0473 Y2.0944 +G01 X1.0046 Y2.0944 +G00 Z0.1000 +G00 X1.0690 Y2.0730 +G01 Z-0.0050 F10.00 +G01 X1.0690 Y2.1157 F20.00 +G00 Z0.1000 +G00 X1.0690 Y2.0944 +G01 Z-0.0050 F10.00 +G01 X1.0904 Y2.1157 F20.00 +G01 X1.1010 Y2.1157 +G00 Z0.5000 +M05 +M02 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/homepage.jpg b/trunk/ulp/pcb-gcode-3.6.0.4/docs/homepage.jpg new file mode 100644 index 00000000..f69a69bc Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/docs/homepage.jpg differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/isolation_settings_300.gif b/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/isolation_settings_300.gif new file mode 100644 index 00000000..9b8e6507 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/isolation_settings_300.gif differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/pcbgcode-600.gif b/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/pcbgcode-600.gif new file mode 100644 index 00000000..f8d8e8cc Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/pcbgcode-600.gif differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/z_axis.gif b/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/z_axis.gif new file mode 100644 index 00000000..7697e86b Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/z_axis.gif differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/z_axis.svg b/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/z_axis.svg new file mode 100644 index 00000000..58e76004 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/images/z_axis.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + Up + + + High + + Down + + Drill Depth + + + + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/lstlang0.sty b/trunk/ulp/pcb-gcode-3.6.0.4/docs/lstlang0.sty new file mode 100644 index 00000000..84299746 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/lstlang0.sty @@ -0,0 +1,42 @@ +\lst@definelanguage{eagle}[]{C}% + {morekeywords={ + usage, + EAGLE_VERSION, EAGLE_REVISION, REAL_EPSILON, REAL_MAX, REAL_MIN, + INT_MAX, INT_MIN, PI, + board, deviceset, library, output, package, schematic, sheet, + symbol, + real, string, + abs, acos, asin, atan, ceil, cos, exit, exp, + filedir, fileerror, fileext, fileglob, filename, + fileread, filesetext, filesize, filetime, + floor, frac, ingroup, isalnum, isalpha, iscntrl, + isdigit, isgraph, islower, isprint, ispunct, isspace, + isupper, isxdigit, log, log10, lookup, max, min, + palette, pow, printf, round, sin, sort, sprintf, + sqrt, status, strchr, strjoin, strlen, strlwr, strrchr, + strrstr, strsplit, strstr, strsub, strtod, strtol, + strupr, system, t2day, t2dayofweek, t2hour, t2minute, + t2month, t2second, t2string, t2year, tan, time, + tolower, toupper, trunc, u2inch, u2mic, u2mil, u2mm, + UL_LIBRARY, UL_GRID, UL_LAYER, UL_DEVICESET, UL_DEVICE, UL_GATE, + UL_PACKAGE, UL_CONTACT, UL_PAD, UL_SMD, UL_CIRCLE, UL_HOLE, + UL_RECTANGLE, UL_FRAME, UL_TEXT, UL_WIRE, UL_POLYGON, + UL_SYMBOL, UL_PIN, UL_SCHEMATIC, UL_PART, UL_INSTANCE, + UL_ATTRIBUTE, UL_BUS, UL_SEGMENT, UL_LABEL, UL_NET, + UL_JUNCTION, UL_PINREF, UL_BOARD, UL_ELEMENT, UL_SIGNAL, + UL_CONTACTREF, UL_VIA, + SET, DISPLAY, GRID, SET, WINDOW, WIRE, + CLOSE, EDIT, EXPORT, OPEN, QUIT, REMOVE, SCRIPT, + USE, WRITE, ADD, ARC, ATTRIBUTE, CIRCLE, CLASS, + COPY, CUT, DELETE, DESCRIPTION, GROUP, HOLE, LAYER, + MIRROR, MITER, MOVE, NAME, PASTE, POLYGON, RECT, ROTATE, + SMASH, SPLIT, TEXT, VALUE, WIRE, DRC, ERRORS, + LOCK, RATSNEST, REPLACE, RIPUP, ROUTE, SIGNAL, VIA, + BOARD, BUS, ERC, GATESWAP, INVOKE, JUNCTION, + LABEL, NET, PINSWAP, CONNECT, PACKAGE, PAD, PIN, + PREFIX, REMOVE, SMD, TECHNOLOGY, VALUE, + ASSIGN, CHANGE, MENU, AUTO, HELP, INFO, MARK, + OPTIMIZE, PRINT, REDO, RUN, SHOW, UNDO, UPDATE + }, + sensitive=true + } diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/pcbgcode.pdf b/trunk/ulp/pcb-gcode-3.6.0.4/docs/pcbgcode.pdf new file mode 100644 index 00000000..f6e20204 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/docs/pcbgcode.pdf differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/docs/pcbgcode.tex b/trunk/ulp/pcb-gcode-3.6.0.4/docs/pcbgcode.tex new file mode 100644 index 00000000..66a97470 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/docs/pcbgcode.tex @@ -0,0 +1,1074 @@ +\documentclass[11pt]{book} + +%\usepackage{setspace} +%\usepackage{fullpage} +%\usepackage{relsize} +\usepackage{graphicx} +\usepackage{geometry} + +\usepackage[sc]{mathpazo} % Use the Palatino font +\usepackage[T1]{fontenc} % Use 8-bit encoding that has 256 glyphs +%\linespread{1.05} % Line spacing - Palatino needs more space between lines +\usepackage{microtype} % Slightly tweak font spacing for aesthetics + +%\usepackage[hmarginratio=1:1,top=32mm,columnsep=20pt]{geometry} % Document margins + +\usepackage[ + pdfauthor={John T. Johnson},% + pdftitle={The PCB-GCODE User's Manual},% + pdfsubject={pcb-gcode mechanically etching printed circuit boards},% + pdfkeywords={pcb-gcode}{g-code}{pcb}{cnc}{etching},% + colorlinks=true,% + linkcolor=gray,% + urlcolor=gray% +]{hyperref} % For hyperlinks in the PDF + +\usepackage[hang, small,labelfont=bf,up,textfont=it,up]{caption} % Custom captions under/above floats in tables or figures +\usepackage{booktabs} % Horizontal rules in tables + +\usepackage{paralist} % Used for the compactitem environment which makes bullet points with less space between them + +\usepackage{fancyhdr} % Headers and footers +%\pagestyle{fancy} % All pages have headers and footers +\fancyhead{} % Blank out the default header +\fancyfoot{} % Blank out the default footer +%\fancyhead[C]{SED1 $\bullet$ December 5, 2012 $\bullet$ Unpublished} % Custom header text +\fancyfoot[RO,LE]{\thepage} % Custom footer text + +\usepackage{varioref} + +%\usepackage{lmodern} + +\usepackage{listings} + +\usepackage{textcomp} + +\usepackage{float} + +\usepackage[section]{placeins} + +%\usepackage{draftwatermark} + +\usepackage{makeidx} +\makeindex +%\usepackage{showidx} % shows index items in margins, doesn't gen index page + +%---------------------------------------------------------------------------------------- +% TITLE SECTION +%---------------------------------------------------------------------------------------- + +\title{\vspace{-15mm}\fontsize{24pt}{10pt}\selectfont\textbf{The PCB-GCODE User's Manual}\\[1em] +\fontsize{18pt}{10pt}\textsc{Version 3.6.0.4}\\[1em] +} + +\author{ +\large +Copyright \copyright\ 2013\\[1em] +\textsc{John T. Johnson}\\[2mm] %\thanks{A thank you or further information}\\[2mm] % Your name +\normalsize \href{mailto:pcbgcode@pcbgcode.org}{\texttt{pcbgcode@pcbgcode.org}} % Your email address +\vspace{-5mm} +} +%\date{} % empty date, since it is shown in the header + +%\makeglossary + +% Adobe bug workoround +\pdfminorversion=4 + +%====================================================================== +%====================================================================== +\begin{document} +%====================================================================== +%====================================================================== + +%\newcommand{\marginnote}[1]{% +% \marginpar{\colorbox{yellow}{\parbox{\marginparwidth}{% +% %\setstretch{0.5} +% \textcolor{red}{\scriptsize{#1}}}}}} + +\newcommand{\warning}[1]{ + \marginpar{ + \vspace{0.1in} + \includegraphics{/Users/john/Dropbox/Docs/warning.pdf} + \centering + #1 + } +} + +\newcommand{\information}[1]{ + \marginpar{ + \vspace{0.1in} + \includegraphics{/Users/john/Dropbox/Docs/information.pdf} + \centering + #1 + } +} + +\newcommand{\howitworks}[1]{ + \marginpar{ + \vspace{0.1in} + \includegraphics{/Users/john/Dropbox/Docs/gears.pdf} + \centering + #1 + } +} + + + +\setlength{\marginparwidth}{1.0in} +\setlength{\marginparsep}{2em} + + +\newcommand{\code}[1]{\texttt{#1}} + +\definecolor{gray}{rgb}{0.5,0.5,0.5} + +\lstset{language=eagle, + basicstyle=\ttfamily\small, + numberstyle=\small\color{gray}, + numbers=left, + showstringspaces=false, + stepnumber=1, +% frame=shadowbox, + breaklines=true} + +\frontmatter + +\maketitle + +% +%--------------------------------------------------------------------- +% +\section*{About this book} + +This book is typeset with \href{http://en.wikipedia.org/wiki/LaTeX}{\LaTeX{}} using the Computer Modern and Palatino fonts. +\vspace{1ex} + +\noindent The \LaTeX{} distribution used is \href{http://tug.org/mactex/}{MacTeX}. The editor is \href{http://texpadapp.com}{Texpad} for \href{http://www.apple.com/osx/}{Mac OS X} and \href{http://www.apple.com/ios/}{iOS}. When doing academic writing, I use \href{http://bibdesk.sourceforge.net}{BibDesk} on Mac OS X and \href{https://itunes.apple.com/us/app/pocketbib-for-bibtex-bibdesk/id524521749?mt=8}{PocketBib} on iOS. +\vspace{1ex} + +\noindent Some words, such as MacTeX in the previous paragraph, are links to websites. In this manual, all links are colored gray. The reader will note that other words are links to figures, tables, or sections in this manual. These are also colored gray. The reader may click these links to jump to the linked item. +\vspace{1ex} + +\noindent Throughout this book there are icons in the margins that will help the reader navigate the book and find material at an appropriate skill level. These icons are shown below. +\vspace{5ex} + +\howitworks{} \noindent Sections marked with this icon provide background on the operation of pcb-gcode. This information is for curious users and can safely be skipped. +\vspace{10ex} + +%\information{} \noindent Information. +%\vspace{10ex} + +\warning{} \noindent Some parts of the manual are for intermediate or advanced users. This icon alerts the reader to this fact. + +\tableofcontents + +\listoffigures + +\listoftables + +\mainmatter + +%====================================================================== +% +\chapter{Introduction}\label{chp:Introduction} +% +%====================================================================== + +% +%--------------------------------------------------------------------- +% +\section{Purpose}\label{sec:Purpose} + +Pcb-gcode is a User Language Program (ULP) for EAGLE PCB design software produced by \href{http://cadsoftusa.com}{CadSoft}. Pcb-gcode allows one to make printed circuit boards by using a CNC router or milling machine to cut the traces out of the copper on the board. It also produces files for drilling holes. Two-sided boards are supported. By "mechanically etching" the boards, no toxic chemicals are needed -- making the process more environmentally friendly. Turn-around times and costs are much reduced from ordering a prototype from a board house. + +% +%--------------------------------------------------------------------- +% +\section{Features}\label{sec:Features} + +Though no program can be all things to all people, pcb-gcode has a lot of features to help make it useful. + +\begin{description} + \item[One or two sided boards] There are checkboxes for selecting whether to generate files for the top and/or bottom sides of the boards. + \item[Outlines] Generate gcode for cutting around the tracks of the PCB. Multiple passes are possible, which helps eliminate the small slivers that may be left behind. There is also an option to make only one outline pass. + \item[Drills] Generate gcode for drilling component and mounting holes. Tool changes are supported, as well as a drill rack file. + \item[Preview] A preview for outlines is available. + \item[Milling] Milling code can be generated for any wires drawn on the Milling (46) layer. + \item[Text] Generates gcode to engrave any vector text that is on the Milling (46) layer. + \item[Spot drill holes] Holes can be spot drilled with the outlines tool to help the drill bits to start straight when drilling holes. + \item[Tool change position] Where the machine should go so that the tool can be changed. + \item[Drill rack files] Allows using one drill bit for a range of hole sizes in the board. + \item[Profile] Starting settings for particular styles of gcode, for example, Mach3 or EMC, among others. + \item[Embedding comments] Comments documenting the settings a file was created with can be inserted into the gcode. + \item[User gcode] For users that need to generate gcode for unusual situations. + \item[File naming] Several options exist for naming files according to the conventions of the user's controller, and their local language. + \item[Plugins] Allow for future expansion. +\end{description} + +% +%--------------------------------------------------------------------- +% +\section{How it Works}\label{sec:HowItWorks} +\subsection{Overview} +After designing your board in Eagle's board editor, the ULP pcb-gcode-setup is run and options are set (See \figurename \vref{fig:SetupGenerationOptions}). Pcb-gcode will generate a set of files that will cut out the tracks, pads, pours and vias (hereinafter called tracks) for the top and/or bottom of the board. Pcb-gcode can also generate files to drill holes from the top and/or bottom of the board. Since the holes usually go all the way through, they only need to be drilled from one side, although some users have drilled slightly more than half way from both sides for a cleaner finish. The user may also choose to create milling wires on the milling layer of the board. This can be used to cut out sections of the board, or cut the perimeter of the board out. There is also an option for engraving vector text that the user places on the milling layer. + +After the files are generated, they are transferred to the control software for the CNC router or milling machine. The PCB is mounted on the machine. The origin is set to the lower left for the top side of the board and the top files are run. The board is then flipped in the \code{X} axis (i.e. around the \code{Y} axis), the origin is set at the lower right, and the bottom files are run. After minimal inspection and cleanup, the board is ready to be loaded with components. + +\subsection{Isolation} +Pcb-gcode has the ability to generate g-code that cuts out tracks with increasing amounts of isolation. This is helpful because it can help eliminate small slivers of copper left behind by the cutting process. + +The isolation begins at a minimum amount and is increased by a step size until a maximum amount is reached. The builtin previewer can be used to see how this isolation works. See \figurename \vref{fig:MultipassBoard}. From the zoomed view shown in \figurename \vref{fig:MultipassBoardZoom} you can see that the passes start out close to the track, then move out by a step size. The colors of the preview tracks follow the standard resistor color codes, so brown is the first pass, red is the second, orange the third, etc. + +\howitworks{} +For the curious reader, the isolation is calculated as shown in Equation \vref{egn:IsolationCalculation}. You do not need to know this to use pcb-gcode. Note that this formula is erroneous and that the $EtchingToolSize$ should be divided by 2 to yield the offset. Changing this now would break many user's setups, so it will be left as is. Most users arrive at the setting for the etching tool size by trial and error, so it is likely a moot point. + +\begin{equation} +isolation = EtchingToolSize+MinimumIsolation+PassNumber*StepSize +\label{egn:IsolationCalculation} +\end{equation} + + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Multipass-Board.png} + } + \caption{Preview showing color-coded multiple passes.} + \label{fig:MultipassBoard} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Multipass-Board-Zoom.png} + } + \caption{Preview showing a zoomed version of the color-coded multiple passes. Brown is the first pass, red the second, orange the third, etc.} + \label{fig:MultipassBoardZoom} +\end{figure} + +\subsection{Drilling} +Compared to the isolation passes and files, drill file creation is relatively straight forward. Each hole in the board is sorted according to size and then position. Optionally a rack file can be used. Rack files contain a list of drills the user has available and the size holes they can be used for. For more information on rack files, see Section \vref{sec:DrillRackFiles}. G-code is created to position and drill each hole. Tool changes can be included in the file so that the user or an automated tool changer can change the bit. + +%====================================================================== +% +\chapter{Setup}\label{chp:Setup} +% +%====================================================================== + +% +%--------------------------------------------------------------------- +% +\section{EAGLE compatibility}\label{sec:EAGLECompatibility}\index{eagle!compatibility} + +Pcb-gcode is compatible with EAGLE versions 5 and 6\footnote{CadSoft changed the way numbers were represented internally with their release of version 6. This effectively broke parts of pcb-gcode. Version 3.6 incorporates changes for compatibility with version 5 or 6.}. For versions of EAGLE before version 5, pcb-gcode version 3.3.3 is still available \href{http://groups.yahoo.com/group/pcb-gcode/files/\%21\%20Software/pcb-gcode-3.3.3.zip}{in the Yahoo! group}. This manual does not apply to version 3.3.3. Please see the documentation included with version 3.3.3. + +% +%--------------------------------------------------------------------- +% +\section{Installation}\label{sec:Installation}\index{installation} + +\subsection{Downloading and unarchiving} +Pcb-gcode can be downloaded from the Yahoo! group's \href{http://groups.yahoo.com/group/pcb-gcode/files/\%21\%20Software}{software folder}. \index{download site} Unzip the archive into a place where the operating system will allow files to be saved. For Windows, this should be somewhere inside your Documents folder. For Mac OS X, it could be, for instance, \code{\textasciitilde/Documents/Eagle/pcbgcode}, and for Linux, somewhere off your home folder. Be sure to preserve the directory structure in the archive. See \figurename \vref{fig:folderstructure}. + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Folder-Structure.png} + } + \caption{The proper directory structure after uncompressing the archive.} + \label{fig:folderstructure} +\end{figure} + +\subsection{Configuring EAGLE} +Now that pcb-gcode is uncompressed, Eagle must know where it is located. In Eagle's \code{Control Panel}, click \code{Options $|$ Directories}, then put the path to pcb-gcode in the \code{User Language Programs} field. See \figurename \vref{fig:EagleOptionsDirectories}. + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Eagle-Options-Directories.png} + } + \caption{Add the path to pcb-gcode to the User Language Programs option.} + \label{fig:EagleOptionsDirectories} +\end{figure} + +\subsection{Selecting g-code style}\label{sub:SelectingGCodeStyle}\index{g-code style} +To complete the setup, pcb-gcode must be told which type of g-code it should generate. Open a board in Eagle, then click \code{File $|$ Run...}. Locate the folder where pcb-gcode is and select pcb-gcode-setup.ulp. You will see the screen in \figurename \vref{fig:SelectGcodeStyle}. Select the style g-code that most closely matches your controller. + +You will receive the warning shown in \figurename \vref{fig:GcodeDefaultsWarning}. If this is the first time pcb-gcode has been run, just click Yes and skip the rest of this paragraph. If this is an existing installation of pcb-gcode and gcode-defaults.h has been modified, make note of the modifications before clicking Yes, then make those modifications as needed to the new gcode-defaults.h file. + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Select-Gcode-Style.png} + } + \caption{Select the style g-code pcb-gcode should produce.} + \label{fig:SelectGcodeStyle} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Gcode-Defaults-Warning.png} + } + \caption{Overwrite warning for gcode-defaults.h.} + \label{fig:GcodeDefaultsWarning} +\end{figure} + +After clicking Yes, \code{pcb-gcode-setup} will be run again, and you will see the screen shown in \figurename \vref{fig:SetupGenerationOptions}. + +% +%--------------------------------------------------------------------- +% +\section{Machine Setup}\label{sec:MachineSetup} + +\begin{figure} + \center{ + \includegraphics[width=14cm]{figs/Setup-Machine.png} + } + \caption{Machine options.} + \label{fig:SetupMachine} +\end{figure} + +Click the \code{Machine} tab to view the machine options as shown in \figurename \vref{fig:SetupMachine}. First select the preferred unit of measure by selecting it under \code{Units}. \index{unit of measure} + +Now set the settings for the Z axis. \code{Z High} should be high enough to clear any clamps or fixtures that hold the PCB down.\index{Z High} Set \code{Z Up} high enough to clear the board when moving from location to location.\index{Z Up} Set \code{Z Down} to the depth into the board that the tool should cut.\index{Z Down} \code{Drill Depth} should be set deep enough to drill through the PCB.\index{Drill Depth} \code{Drill Dwell} is the time, in seconds, that the drill should pause at the bottom of the hole.\index{Drill Dwell} + +The \code{Tool Change} options are the position where the tool should be moved for changing the tool.\index{Tool Change} + +The \code{Spin Up Time} in the \code{Spindle} box should be set to the length of time in seconds that it takes the spindle to come up to speed. If the spindle is manually controlled, this can be set to \code{1}.\index{Spin Up Time} + +The \code{Feed Rates} should be set for \code{X Y} moves as well as \code{Z} moves. Rates here will usually be quite low unless the machine has a very fast spindle. See a machinist's reference on how to calculate the optimal feed rate, use trial and error, or post to the Yahoo! group email list for advice. + +\code{Epsilon} is the minimum move that will be written to the g-code file. For instance, if \code{Epsilon} is set to $0.0001''$ and the g-code file will not contain movements less than $0.0001''$. This option will rarely need to be changed. + +The \code{Default Drill Rack File} option allows for the selection of a rack file to be used if one has not been setup for a particular board. In most cases this can be left blank to start with. See Section \vref{sec:DrillRackFiles} for more information about setting up rack files. + +% +%--------------------------------------------------------------------- +% +\section{Generation Options}\label{sec:GenerationOptions} + +\begin{figure} + \center{ + \includegraphics[width=14cm]{figs/Setup-Generation-Options.png} + } + \caption{Options available when generating a board.} + \label{fig:SetupGenerationOptions} +\end{figure} + +Now that reasonable values have been set for the machine, click the \code{Generation Options} tab (See \figurename \vref{fig:SetupGenerationOptions}). This is where the various files produced by pcb-gcode can be selected, and common options can be set. A description of the options follows: + +\begin{description} + \item[Top Side] Options having to do with the tracks on the top of the board, and drill holes made from the top side of the board. + \begin{description} + \item[Generate top outlines] Generate g-code to cut out the tracks, pads, pours and vias on the top side of the board. + \item[Generate top drills] Generate g-code to drill holes from the top side of the board. + \end{description} + \item[Bottom Side] Options having to do with the tracks on the bottom of the board, and drill holes made from the bottom side of the board. + \begin{description} + \item[Generate bottom outlines] Generate g-code to cut out the tracks, pads, pours and vias on the bottom side of the board. + \item[Generate bottom drills] Generate g-code to drill holes from the bottom side of the board. + \item[Mirror] X coordinates for the bottom of the board are usually negative. This makes setting the origin for a two-sided board easier. Turning this option on causes the X coordinates to be positive, however, the bottom tracks will be a mirror image of what they should be. So in general, leave this option off. + \end{description} + \item[Board] Options that apply to the board in general. + \begin{description} + \item[Show preview] Use the previewer in pcb-gcode to preview the g-code generated. + \item[Generate milling] Generate g-code for any wires the user has drawn on the \code{Milling} (46) layer. \code{Depth} sets the milling depth. + \item[Generate text] Generate g-code to engrave any vector text the user may have placed on the \code{Milling} layer. \code{Depth} sets the engraving depth. Not that text on the top or bottom layers will be outlined just as the tracks are, whereas text on the milling layer is engraved. That is, the tool along the center of the lines that make up the letter. + \item[Spot drill holes] Spot drilling helps the drill bits center themselves and helps prevent "walking." Depth sets the spot drill depth. + \item[Isolation] The cutting tool can make several passes around the tracks at an increasing distance each time. This helps eliminate slivers of copper that remain. + \begin{description} + \item[Single pass] When turned on, only a single pass will be made around the tracks on the board. + \item[Minimum] The minimum distance the cutting tool will be away from tracks. That is, the starting isolation amount. + \item[Maximum] The maximum distance the cutting tool will be away from tracks. The maximum isolation amount. + \item[Step size] The amount the isolation increases with each pass. + \end{description} + \item[Etching Tool Size] The size of the cutter used to cut around tracks on the board. + \end{description} +\end{description} + +% +%--------------------------------------------------------------------- +% +\section{GCode Options}\label{sec:GCodeOptions} + +\begin{figure} + \center{ + \includegraphics[width=14cm]{figs/Setup-GCode-Options.png} + } + \caption{Options for generating g-code files.} + \label{fig:GCodeOptions} +\end{figure} + +The options under the GCode Options tab allows the customization of some of the g-code file's content, as well as how the files are named. + +\begin{description} + \item[NC File Comments] Comments added to the g-code file. + \begin{description} + \item[NC File Comment from Board] adds a comment with the name of the board file. + \item[NC File Comment Date] adds the date the g-code file is created. + \item[NC File Comment Machine Settings] adds settings related to the machine. Tool size, Z axis settings, spindle on time, milling depth, text depth, tool change position, XY feed rate, Z feed rate. + \item[NC File Comment PCB Defaults Settings] adds comments with the isolation settings: min, max, and step size, which files were selected to be produced, and the unit of measure. + \end{description} + + \item[Other Options] Options affecting how the g-code is generated. + \begin{description} + \item[Use user gcode (from user-gcode.h)] inserts user g-code into the generated file. See Section \vref{sec:UserGCode} for more details. + \item[Debug Flag] sets the global debug flag. Used for development and troubleshooting. + \item[Do tool change with zero step] after moving to the tool change position and pausing for the operator to change the bit, the Z axis will move to Z0.000 and pause. This allows the operator to adjust the bit length to touch the surface of the PCB. Note that the tool should initially be set high into the spindle so that it won't dig into the PCB when it moves to Z0. + \item[Flip board in Y instead of X] changes the code generated so that after one side of the board is cut, the board should be flipped in the Y axis to complete cutting on the other side. The default is for the board to be flipped in the X axis. + \item[Compact gcode] eliminates some redundant commands in the g-code file, such as having G01 on every line. + \item[Use line numbers?] inserts line numbers into the g-code file. The format shown \code{\%05d} will insert 5 digit numbers with leading zeroes. + \item[Use simple drill code] uses XYZ movements to create drill holes. Usually \code{DRILL\_{}FIRST\_{}HOLE} and \code{DRILL\_{}HOLE} are used, but some controllers don't understand the command (typically \code{G82}). + \end{description} + + \item[File naming] every option one could want for naming files. + \begin{description} + \item[Macros] the following can be used in the file name to create the final file name. Note that paths do not include a \code{/} at the end. Also note that \code{/} is always the path delimiter, even on Windows. Eagle handles the conversion automatically. + \begin{description} + \item[\$PROJECT\_{}PATH{[}n{]}] Project paths as set in the Eagle Control Panel. n begins at zero for the first entry. + \item[\$ULP\_{}PATH{[}n{]}] ULP paths as set in the Control Panel. + \item[\$CAM\_{}PATH{[}n{]}] CAM paths as set in the Control Panel. + \item[\$BOARD\_{}PATH] path to the board file. + \item[\$BOARD\_{}NAME] the file name of the board file with the extension removed. + \item[\$SIDE] the side of the board being generated. Defaults are 'bot' and 'top'. + \item[\$FILE] the file being generated. Defaults are 'etch', 'drill', 'mill' and 'text'. + \item[\$EXT] the extension set in \code{Extension} on this screen. + \end{description} + \item[Test Filenames] click the button to see how the file names will look. + \item[Help] gives a list of the macros defined above and tips on creating file names. + \end{description} +\end{description} + +Using the options shown in \ref{fig:GCodeOptions}, here is how the filename for the top etching file will be created: +\begin{itemize} +\item The board path and board name will be used. (\code{Filename Base}) +\item The word for 'top' will be substituted for \code{\$SIDE}. (See \code{Etching} under \code{Top (Component) Side Files}. +\item The word for 'etch' will be substituted for \code{\$FILE}. +\item The \code{Extension} will be substituted for \code{\$EXT}. +\end{itemize} +Using examples for the board path and name, the final file name would be:\\ +\lstinline!/Users/john/Documents/pcbcode/examples/enabtmr.top.etch.tap! + +%====================================================================== +% +\chapter{Using pcb-gcode} +% +%====================================================================== + +% +%--------------------------------------------------------------------- +% +\section{Running pcb-gcode}\index{pcb-gcode!running}\label{sec:running} + +Run pcb-gcode by selecting File $|$ Run... from EAGLE's board editor. Find the file \code{pcb-gcode-setup.ulp} and click the Open button. The setup screen will be shown where options can be changed (See \figurename~\ref{fig:SetupGenerationOptions}). When the options are correct, click the \code{Accept and make my board} button. To save the options without generating files for the board, click the \code{Accept} button. + +Pcb-gcode is actually two programs. The first, pcb-gcode-setup, allows for setting options and changing the way NC files are created. The second program is pcb-gcode, which actually creates the files. Most people run pcb-gcode-setup, check their settings, then click the \code{Accept and make my board} button to generate files. If settings don't need to be changed, pcb-gcode can be run directly and all the file selections and options from the last time pcb-gcode-setup was run will be used. + +To make it easier to run pcb-gcode and pcb-gcode-setup, use EAGLE's Assign function to assign a shortcut key to \code{run pcb-gcode} and \code{run pcb-gcode-setup} (See \figurename~\vref{fig:EagleOptionsAssign}). + +\begin{figure} + \center{ + \includegraphics[width=5cm]{figs/EAGLE-Options-Assign.png} + } + \caption{EAGLE shortcut key assignments.} + \label{fig:EagleOptionsAssign} +\end{figure} + +% +%--------------------------------------------------------------------- +% +\section{Using EAGLE's DRC}\index{eagle!DRC}\label{sec:EagleDRC} + +When creating files to etch a board, it is usually the case that the tracks should be made wide to allow for easier machining and to account for tolerances in the machine such as backlash and spindle runout. EAGLE's Design Rule Check (DRC) can be used to help ensure that all tracks on the board will be cut out, and no bridges will be left. + +A bridge is formed when two parts (tracks, pads, vias) on the board are too close together for the etching tool to pass between them. An example is shown in \figurename~\vref{fig:TwoComponents}. For this example, Single Pass isolation is selected, minimum isolation is set to $0.010''$, and the etching tool size is set to $0.005''$. These setting are shown in \figurename~\vref{fig:DRCExampleSettings}. + +\begin{figure} + \center{ + \includegraphics[width=5cm]{figs/Two-Components.png} + } + \caption{Two components in the board layout editor.} + \label{fig:TwoComponents} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=5cm]{figs/DRC-Example-Settings.png} + } + \caption{Pcb-gcode settings for the DRC example.} + \label{fig:DRCExampleSettings} +\end{figure} + +If the pads for the leads for the resistors that are close together are more than $0.010'' + 0.010'' + 0.005'' = 0.025''$ inches apart, the pads will be properly isolated as shown in \figurename~\vref{fig:GoodClearance}. However, if the two pads are less than $0.025''$ apart, they cannot be isolated, and a bridge will be formed as shown in \figurename~\vref{fig:TooClose}. + +\begin{figure} + \center{ + \includegraphics[width=7cm]{figs/Good-Clearance.png} + } + \caption{The pads are far enough apart to allow them to be isolated.} + \label{fig:GoodClearance} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=7cm]{figs/Too-Close.png} + } + \caption{The two pads are too close together and cannot be isolated. A bridge is formed.} + \label{fig:TooClose} +\end{figure} + +To help ensure that this does not happen, EAGLE's DRC can be used. From the board editor in EAGLE, click the Tools menu, then click DRC. Click the Clearance tab and set all clearances to 25mil. (A mil is $0.001''$, so this equals $0.025''$.) When the Check button is clicked, any distances less than 0.025" will be marked with a red mark, and a list of errors will be shown as in \figurename~\vref{fig:DRCError}. + +\begin{figure} + \center{ + \includegraphics[width=7cm]{figs/DRC-Error.png} + } + \caption{EAGLE's DRC indicating the two pads are too close together.} + \label{fig:DRCError} +\end{figure} + +Once the DRC clearances are set up, it is a simple matter to click the DRC button or run a DRC check from the Tools menu before running pcb-gcode to generate files for the board. This provides a good way to help ensure that components on the board are far enough apart to be properly isolated. + +% +%--------------------------------------------------------------------- +% +\section{Previewer}\index{previewer}\label{sec:Previewer} + +The previewer included in pcb-gcode shows a quick preview of the tool movements that are sent to the NC file. The lines are color coded using the standard resistor color codes. The first pass of the tool is drawn in brown, the second is red, the third is orange, etc. + +The preview is enabled by turning on the \code{Show preview} option under the \code{Generation Options} tab (See \figurename \vref{fig:SetupGenerationOptions}). After pcb-gcode creates the isolation or milling for the current layer, a preview of the results will be shown in the previewer. Several keys can be used to change the view, See Table \vref{tbl:PreviewerKeys}. If you wonder about some of the unusual keys, such as why \code{e} can be used to pan right, it is because of the Dvorak keyboard layout that some use, including the author. + +\begin{table}[h]\caption{Keys available in previewer}\label{tbl:PreviewerKeys}\index{previewer!keys}\index{keys!previewer} +\centering +\begin{tabular}{ll} + \toprule + Key & Function\\ + \midrule + 1 & Set zoom to 1x (no zoom)\\ + 2 & Set zoom to 2x\\ + + = & Zoom in\\ + - \_{} & Zoom out\\ + a $\leftarrow$ & Pan left\\ + d e $\rightarrow$ & Pan right\\ + w , $\uparrow$ & Pan up\\ + s o $\downarrow$ & Pan down\\ + c & Color on / off\\ + q x & Quit preview \\ \bottomrule +\end{tabular} +\end{table} + +The previewer does not read and interpret the NC files directly, but uses an internal representation of the tool movements. This gives an accurate representation of the tool's movements and size, without the overhead of interpreting several different styles of g-code. + +\begin{figure} + \center{ + \includegraphics[width=14cm]{figs/Previewer-Screen-Shot.png} + } + \caption{The previewer showing a multi-pass file for the bottom side of an example PCB included with pcb-gcode.} + \label{fig:PreviewerScreenShot} +\end{figure} + +As can be seen in \figurename~\vref{fig:PreviewerScreenShot}, additional information is provided by the preview. In the upper-left corner is the name of the board file that was processed to produce this preview. At the upper-right, the viewer version number can be found. Just to the left of that is the etching tool size set in pcb-gcode-setup. Just below the version number is the number of passes generated. Back on the left-hand side near the top is an overview of the keys available. + +The four extents of the board are marked with red corners. At the upper right corner, the X and Y coordinates are given. The X and Y coordinates are also given at the lower-left corner. Note that in the figure, the X coordinate is negative because this is the bottom of the board. In the lower right corner, a circle and crosshairs mark the origin point for the board. + +If the milling and text options are turned on, the previewer will show any files generated for the top and bottom milling and text. Since the Milling (46) layer is not a top or bottom layer (it can be thought of as going through the board), NC files are generated to mill any lines drawn on it from either the top or bottom side. So in other words, if \code{Generate milling} is selected, both top and bottom milling files will be generated. The same for text placed on the Milling layer. If \code{Generate text} is selected, both top and bottom text engraving files will be generated. There is one caveat: if the text is mirrored, it will be output in the bottom milling file. If the text is not mirrored, it will be output in the top milling file. This is similar to the way text placed on the \code{Top} and \code{Bottom} layers looks. The following example will help clarify this. + +The example board \code{docs/examples/04151\_lcdi2c.brd} shown in \figurename~\vref{fig:014151Board} includes wires (shown in blue) drawn on the Milling layer, as well as mirrored vector text (also shown in blue) placed on the Milling layer. A prewiew of the bottom milling file is shown in \figurename~\vref{fig:BottomMilling}. A preview of the bottom text engraving file is shown in \figurename~\vref{fig:BottomText}. You can see that the text is oriented properly for engraving on the bottom side of the board. The object info for the text is shown in \figurename~\vref{fig:MirroredTextInfo}. + +The top milling file preview looks just like the bottom preview, and is not shown. The top text engraving file was empty since there is no non-mirrored text on the Milling layer, so its preview has also been omitted. + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/04151_lcdi2c.png} + } + \caption{The sample board \code{docs/examples/04151\_lcdi2c.brd} with wires and mirrored text on the Milling layer.} + \label{fig:014151Board} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Bottom-Milling.png} + } + \caption{Milling generated for milling from the bottom side of \code{docs/examples/04151\_lcdi2c.brd}.} + \label{fig:BottomMilling} +\end{figure} + +\begin{figure} + \center{ + \includegraphics[width=10cm]{figs/Bottom-Text.png} + } + \caption{Text engraving generated for cutting on the bottom side of \code{docs/examples/04151\_lcdi2c.brd}.} + \label{fig:BottomText} +\end{figure} + +\clearpage + +\begin{figure} + \center{ + \includegraphics[width=8cm]{figs/Mirrored-Text-Info.png} + } + \caption{The object info for the mirrored text on the Milling layer. Note that the Mirror checkbox is on. This indicates to pcb-gcode that the text should be engraved on the bottom side of the board.} + \label{fig:MirroredTextInfo} +\end{figure} + + +\howitworks{} +For the curious reader, the previewer is written using a language called \href{http://processing.org}{Processing}, which is somewhat Java-like. Three versions of the previewer are included in pcb-gcode, one for each operating system supported: Mac OS X, Linux, and Windows. When the previewer is enabled, pcb-gcode detects which operating system it is running on, and runs the appropriate viewer. + +%====================================================================== +% +\chapter{Customizing} +% +%====================================================================== + +% +%--------------------------------------------------------------------- +% +\section{G-Code}\index{g-code!customizing}\label{sec:CustomizingGCode} + +\warning{Intermediate} +When the g-code style is initially selected at installation as discussed in Section \vref{sub:SelectingGCodeStyle}, the profile (\code{.pp}) file selected is copied from the \code{profiles} folder to the \code{settings} folder and to the file \code{gcode-defaults.h}. This is the file that pcb-gcode uses when generating g-code files. + +The listing found in Appendix \vref{chp:SampleProfile} can alse be used as a reference for editing \code{gcode-defaults.h}. If there is a need to change the g-code generated by pcb-gcode, the gcode-defaults.h file can be edited. + +The definitions in the file are flexible in some aspects, and restricted in others. The main restriction is that a definition that expects a certain number of parameters must be given that number of parameters. Unused parameters can be passed as comments in the g-code. + +For example, if the controller does not understand the DWELL command, it can be changed to a comment. In the listing, DWELL is defined to be: + +\begin{lstlisting}[firstnumber=46] +string DWELL = "G04 " + PARAM + "%f" + EOL; +\end{lstlisting} + +This can be made into a comment the controller will ignore by surrounding it with COMMENT\_{}BEGIN and COMMENT\_{}END: + +\begin{lstlisting}[firstnumber=46] +string DWELL = COMMENT_BEGIN + "G04 " + PARAM + "%f" + COMMENT_END + EOL; +\end{lstlisting} + +The \lstinline!%f! that pcb-gcode needs is still there, but the command is now just a comment as far as the controller is concerned. + +\marginpar{\scriptsize This is only an example. EAGLE handles line endings automatically depending on the operating system it is running on. If line endings in generated NC files need to be changed, a conversion program should be used.} + +The definitions use previous definitions as much as possible. This helps make the files more readable, and makes future changes easier as well. For instance, \code{EOL} is defined in line 22 to be \code{"\textbackslash{}n"}. Changing the line ending of all generated code would be a simple matter of changing the single definition of \code{EOL}, rather than editing every line. + +The first option on line 11, \code{FILENAMES\_8\_CHARACTERS}, tells pcb-gcode whether it should limit filenames to 8 characters. This is used for DOS control software such as TurboCNC. + +\begin{description}\index{gcode-defaults.h!definitions of commands}\index{profiles!definitions of commands} +\item[Misc defines] Comments and line ending +\begin{description} + \item[COMMENT\_{}BEGIN, COMMENT\_{}END] If your controller doesn't understand beginning and ending characters for comments, as on lines 16-17, just make \code{COMMENT\_{}END} empty. + + \item[EOL] is the character added to the end of every line. +\end{description} + +\item[Formats] Parameter formats. +\begin{description} + \item[PARAM] different controllers use different characters to introduce a parameter. Mach3 uses \code{P}, while others use \code{\#}. + + \item[FORMAT] is the floating point format used for coordinates. The default value \code{\%-7.4f} means a leading negative sign will be output for negative coordinates (very important), the number will be 7 digits long, and 4 digits will be to the right of the decimal point. The \code{f} indicates it is a floating point (real) number. + + \item[FR\_{}FORMAT] is the format used to insert feedrate parameters into the g-code. In the example, the leading \code{F} indicates this is a feedrate parameter. The rest of the format is similar to \code{FORMAT} --- leading negative sign possible, 5 digits wide, no digits to the right of the decimal point. + + \item[IJ\_{}FORMAT] is used to output \code{I J} coordinates to the g-code file. You can see by the definition on line 26 that this format reuses the \code{FORMAT} definition defined earlier. +\end{description} + +\item[Modes] Inch, metric, etc. modes +\begin{description} + \item[INCH\_{}MODE] used to set the controller to inch mode. + + \item[INCH\_{}MODE\_{}COMMENT] a comment inserted in the g-code indicating that inch mode is being set. + + \item[METRIC\_{}MODE] used to set the controller to Metric mode. + + \item[METRIC|\_{}MODE\_{}COMMENT] a comment inserted in the g-code indicating that metric mode is being set. + + \item[MIL\_{}MODE] used to set the controller to mil mode. Currently undefined in all profiles. + + \item[MICRON\_{}MODE] used to set the controller to micron mode. Currently undefined in all profiles. + + \item[ABSOLUTE\_{}MODE] would be used to set the controller to absolute coordinates mode. Currently just a comment. +\end{description} + +\item[G Codes] Basic g-code defines for movements. +\begin{description} + \item[RAPID] for rapid moves with the cutting tool out of the material. + \item[FEED] for movements with the cutting tool in the material. + \item[ARC\_{}CW] for cutting an arc clockwise. + \item[ARC\_{}CCW] for cutting an arc counter-clockwise. + \item[DWELL] pause for a number of seconds. Number of seconds (a float) is passed. +\end{description} + +\item[M Codes] M-code definitions. +\begin{description} + \item[SPINDLE\_{}ON] turns the spindle on. Takes \code{DWELL} as a parameter. + \item[SPINDLE\_{}OFF] turns the spindle off. + \item[END\_{}PROGRAM] signals the end of the gcode program. + \item[OPERATOR\_{}PAUSE] pauses for the operator to do something, like change the tool. +\end{description} + +\item[Coordinates] Definitions for coordinate parameters. +\begin{description} + \item[MOVE\_{}X] X axis movement. Passed an \code{X} coordinate as a parameter. + \item[MOVE\_{}Y] Y axis movement. Passed a \code{Y} coordinate as a parameter. + \item[MOVE\_{}XY] XY axis movement. Passed an \code{X} and \code{Y} coordinate as parameters. + \item[MOVE\_{}Z] Z axis movement. Passed a \code{Z} coordinate as a parameter. + \item[MOVE\_{}XYZ] XYZ axis movement. Passed \code{X Y Z} coordinates as parameters. +\end{description} + +\item[Rapids] Combinations of \code{RAPID} and the above coordinates. +\begin{description} + \item[RAPID\_{}MOVE\_{}X] rapid X axis movement. Passed an \code{X} coordinate as a parameter. + \item[RAPID\_{}MOVE\_{}Y] rapid Y axis movement. Passed a \code{Y} coordinate as a parameter. + \item[RAPID\_{}MOVE\_{}XY] rapid XY axis movement. Passed \code{X Y} coordinates as parameters. + \item[RAPID\_{}MOVE\_{}XY\_{}HOME] rapid XY axis movement to \code{X0 Y0}. + \item[RAPID\_{}MOVE\_{}Z] rapid Z axis movement. Passed a \code{Z} coordinate as a parameter. + \item[RAPID\_{}MOVE\_{}XYZ] rapid XYZ axis movement. Passed \code{X Y Z} coordinates as parameters. +\end{description} + +\item[Feeds] Movements at cutting speed, uses \code{FEED} and the coordinate definitions above. +\begin{description} + \item[FEED\_{}MOVE\_{}X] feed X axis movement. Passed an \code{X} coordinate as a parameter. + \item[FEED\_{}MOVE\_{}Y] feed Y axis movement. Passed a \code{Y} coordinate as a parameter. + \item[FEED\_{}MOVE\_{}XY] feed XY axis movement. Passed \code{X Y} coordinates as parameters. + \item[FEED\_{}MOVE\_{}XY\_{}WITH\_{}RATE] feed XY axis movement. Passed \code{X Y} coordinates and the feed rate. + \item[FEED\_{}MOVE\_{}Z] feed Z axis movement. Passed a \code{Z} coordinate as a parameter. + \item[FEED\_{}MOVE\_{}Z\_{}WITH\_{}RATE] feed Z axis movement. Passed \code{Z} coordinate and a feed rate as parameters. + \item[FEED\_{}MOVE\_{}XYZ] feed XYZ axis movement. Passed an \code{X Y Z} coordinates as parameters. +\end{description} + +\item[Drilling holes] Definitions for drilling holes. +\begin{description} + \item[DRILL\_{}CODE] the gcode instruction to drill a hole. + \item[RELEASE\_{}PLANE] the Z position to move the drill to after drilling. Takes a \code{Z} coordinate as a parameter. + \item[DWELL\_{}TIME] the time to dwell in the bottom of the hole. Takes a floating point (real) argument. + \item[DRILL\_{}FIRST\_{}HOLE] generated to drill the first hole. Takes \code{X Y Z}, feed rate, release \code{Z} plane and dwell time as parameters. + \item[DRILL\_{}HOLE] generated for subsequent holes. Takes \code{X Y} as parameters. +\end{description} + +\item[Tool change] Definitions for changing tools. +\begin{description} + \item[TOOL\_{}CODE] the tool selection code. Passed the tool number (an integer) as a parameter. + \item[TOOL\_{}MM\_{}FORMAT] a tool size formatted for millimeters. Passed a tool size (float). + \item[TOOL\_{}INCH\_{}FORMAT] a tool size formatted for inches. Passed a tool size (float). + \item[TOOL\_{}CHANGE] the command issued when a tool is to be changed. Takes tool number and tool size as arguments. + \item[TOOL\_{}CHANGE\_{}TABLE\_{}HEADER] the tool table header comment inserted in the g-code. + \item[TOOL\_{}CHANGE\_{}TABLE\_{}FORMAT] generates an entry for the tool table. Note that this is a function. +\end{description} + +\item[Circles / Arcs] Arc and circle commands. +\begin{description} + \item[CIRCLE\_{}TOP] a clockwise circle on the top of the board. Takes \code{X Y I J} as parameters. + \item[CIRCLE\_{}BOTTOM] a counter-clockwise circle on the bottom of the board. Takes \code{X Y I J} as parameters. +\end{description} +\end{description} + +% +%--------------------------------------------------------------------- +% +\section{Profiles}\index{profiles}\label{sec:Profiles} + +\warning{Advanced} +Profiles, which are found in the \code{profiles} folder, control the format that pcb-gcode uses when writing g-code. The files ending in \code{.pp} are the list of files shown when pcb-gcode is initially set up (See Section \vref{sec:Installation}), and also in the list of profiles in the \code{GCode Styles} tab. When a profile is selected, it is copied to \code{settings/gcode-defaults.h}. A sample profile is shown in Appendix \vref{chp:SampleProfile}. + +To create a custom profile, such as for a controller that is not already supported, begin with a profile that most closely matches the g-code the controller supports. Select this profile in \code{GCode Styles} and \code{Accept} the change. This will copy the profile to \code{settings/gcode-defaults.h}. Generate code for a test board and open the generated files in an editor. Find commands that the controller does not support, and edit \code{gcode-defaults.h} to generate the proper code. When testing is complete, copy \code{settings/gcode-defaults.h} into the \code{profiles} folder, renaming it with a descriptive name and the extension \code{.pp}. Edit the file and change the author and description fields. And of course, save a backup somewhere outside the pcb-gcode folder heirarchy. To share this profile with other users of this controller, upload the profile file to the \href{http://groups.yahoo.com/group/pcb-gcode/files/%21%20Software/Profiles/}{Profiles folder} on the Yahoo! group. + +For information on editing \code{gcode-defaults.h}, See Section \vref{sec:CustomizingGCode}. + + +% +%--------------------------------------------------------------------- +% +\section{Drill Rack Files}\index{rack files}\index{drill files}\label{sec:DrillRackFiles} + +Rack files allow the substitution of one drill size for a range of sizes that may be found in the board. For instance, a $0.031''$ drill might be used for hole sizes $0.025''$ -- $0.032''$. This cuts down on the number of drills that must be kept on hand, and the number of tool changes needed to drill a board. An example drill rack file is shown in Listing \ref{lst:SampleRackFile}. \textbf{Please heed the warning about using a tab character} between entries on a line. Otherwise, your rack file will not work. + +As can be seen, drills with different units of measure are supported. This includes inches, millimeters, mils, or wire gage sizes. See Listing \ref{lst:SampleEntries} for examples that work. The algorithm tries to be intelligent and assumes, for example, that 0.1 is in inches, whereas 0.6 is in millimeters. To be safe, add the unit of measure after the number. + +Looking at Listing \ref{lst:SampleRackFile}, the meaning of the fields are as follows: + +\begin{description} + \item[tool] The tool number to use. This is somewhat arbitrary unless the machine has a tool changer. Just be sure to start with 1 and increment by 1. + \item[drill\_size] The size of the actual drill. These should be in ascending order from smallest to largest. + \item[minimum] The smallest hole size this drill should be used for. + \item[maximum] The largest hole this drill should be used for. + \item[length] Currently not used. Leave set to 1.5in. +\end{description} + +Taking tool \code{T01} as an example. It is a 0.500mm drill, and it will be used for all holes from \code{0.000in} up to \code{0.025in}. Meaning, if there is a $0.015''$ hole in the board, it will be drilled with this bit. If there is a $0.045''$ hole, it will not be drilled with drill \code{T01}, but another drill will be used, if a good match is available. + +Looking at the table, it can be seen that all hole sizes from 0.000in up to 0.125in have been accounted for. If, say, a $0.130''$ hole is in the board, an error message will be given saying a drill is not available for that size hole. + +Rack file are selected by the following method: first, if there is a rack file with the same name as the board, but with the extension \code{.drl}, it will be used. Next, a default rack file will be used if it has been set in \code{pcb-gcode-setup} (See \figurename \vref{fig:SetupMachine}). Finally, if neither of those is available, the rack file \code{settings/default.drl} will be used from the \code{pcb-gcode} directory. If all these attempts fail and no rack file can be found, a table of drill sizes will be written to the drill file. In most cases this works well, but sometimes it can result in, for instance, drilling ten holes with a $0.031''$, then stopping and asking for a $0.032''$ bit. Obviously, the same bit could have been used for both sets of holes. That is why rack files exist. + + +\begin{lstlisting}[caption={Sample Rack File},label={lst:SampleRackFile}] +# +# Please note that you must use a TAB character +# between each setting on a line. +# +# Tip: Set the TAB size of your editor to 12 characters. +# +tool drill_size minimum maximum length +T01 0.500mm 0.000in 0.025in 1.5in +T02 0.032in 0.025in 0.035in 1.5in +T03 0.040in 0.035in 0.045in 1.5in +T04 0.050in 0.045in 0.055in 1.5in +T05 0.062in 0.055in 0.070in 1.5in +T06 0.085in 0.070in 0.125in 1.5in +\end{lstlisting} + +\begin{lstlisting}[caption={Sample entries for rack files},label={lst:SampleEntries}] +0.032in 0.032 inches +62ml 62 mils, 0.062 inches +0.43mm 0.43 millimeters +1500mc 1500 microns, 1.500 millimeters +60# 60 wire gage drill (0.040'' or 1.016mm) +0.12 0.12 inches +0.60 0.60 millimeters +43 43 wire gage drill +\end{lstlisting} + + + +% +%--------------------------------------------------------------------- +% +\section{User GCode}\index{user gcode}\label{sec:UserGCode} + +\warning{Advanced} +The pcb−gcode ULP allows you to customize the g−code created for your boards to a great degree. If you don't see an option in the profile that suits your needs, you can add your code to the \code{user-gcode.h} file. To enable user g-code, run \code{pcb-gcode-setup}, click the \code{GCode Options} tab, then turn the \code{Use user gcode...} option on. Generate a set of NC files for a board. Let's say, for example, that after you change the tool when you're drilling from the bottom of the board, you want the tool to move to X5 Y5 Z5, turn the spindle off, then turn it back on. Since this has to do with drilling the bottom of the board, we should look at the ...bot.drill.tap (bottom drill) file. An excerpt from a file is shown in Listing \vref{lst:BottomDrillBeforeGCode}. + +\begin{lstlisting}[caption={Bottom drill file before adding user g-code.},label={lst:BottomDrillBeforeGCode}] +G90 +(Tool Change Begin) +(Bottom Tool Change Begin) +M05 +G00 X0.0000 Y0.0000 Z2.0000 +M06 T01 ; 0.0236 +(Bottom Tool changed) +(Tool changed) +G00 Z0.0200 +M03 +G04 P3.000000 +(Bottom Tool Change End) +(Tool Change End) +G82 X−1.6200 Y1.2900 Z−0.1000 F9.80 R0.0200 P0.250000 +G82 X−1.8800 Y0.5900 +G82 X−1.9500 Y1.4900 +G82 X−1.9500 Y1.8100 +\end{lstlisting} + +We want to add our commands after the tool is changed when drilling the bottom of the board. Looking at the sample above, you will find this line: +\begin{lstlisting}[firstnumber=12] +(Bottom Tool Change End) +\end{lstlisting} + +That's where we want our code to go. Now you can open user-gcode.h in your favorite editor, and use the Search or Find feature to find the line with Bottom Tool Change End. Here's an excerpt from the user−gcode.h file: + +\begin{lstlisting} +TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n"; +TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n"; +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; +TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n"; +\end{lstlisting} +The 3$^{rd}$ line is the one we're interested in: +\begin{lstlisting}[firstnumber=3] +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; +\end{lstlisting} +Change the line so that it looks like this: +\begin{lstlisting}[firstnumber=3] +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n" + "G00 X5 Y5 Z5\n" + "M05 (spindle off)\n" + "G04 P3.000000 (wait 3 seconds)\n" + "M03 (spindle on)\n"; + "G04 P3.000000 (wait 3 more seconds\n"; +\end{lstlisting} + +Notice that all the lines have a \lstinline!\n! before the last \lstinline!"! and that the last line is the only one that ends with a semi−colon \lstinline!;!. +Generate the files again. Open the bottom drill file in the editor and have a look. Here's how the sample looks now: +\begin{lstlisting} +G90 +(Tool Change Begin) +(Bottom Tool Change Begin) +M05 +G00 X0.0000 Y0.0000 Z2.0000 +M06 T01 ; 0.0236 +(Bottom Tool changed) +(Tool changed) +G00 Z0.0200 +M03 +G04 P3.000000 +(Bottom Tool Change End) +G00 X5 Y5 Z5 +M05 (spindle off) +G04 P3.000000 (wait 3 seconds) +M03 (spindle on) +G04 P3.000000 (wait 3 more seconds) +(Tool Change End) +G82 X−1.6200 Y1.2900 Z−0.1000 F9.80 R0.0200 P0.250000 +G82 X−1.8800 Y0.5900 +G82 X−1.9500 Y1.4900 +G82 X−1.9500 Y1.8100 +\end{lstlisting} +Note that the lines added to the user-gcode.h file are now in the generated g-code from lines 13-17. + +Since we put our code in the \lstinline!TOOL_CHANGE_END[BOTTOM]! definition, it will only be put in files for the bottom side of the board. So the code will be in the bot.drill file. If we only wanted our code in files for the top side, we would have put the code in \lstinline!TOOL_CHANGE_END[TOP]!. You can probably guess that if we wanted the code in both the top and bottom files, we would have put the code in \lstinline!TOOL_CHANGE_END[TOOL_CHANGE_END[ALL]!. +To conclude, the steps to follow are: +\begin{enumerate} + +\item Generate a set of files. +\item Find the file that you want the code to be put in (bot, top, etc.). +\item Find the location in the file that you want the code. +\item Find the comment near that location. +\item Find the comment in the user−gcode.h file. +\item Insert your code after the comment. +\item Generate the files again and check to be sure it is correct. +\end{enumerate} + +% +%--------------------------------------------------------------------- +% +%\section{About the Author} +% +%Users have asked about my background in the past. I am currently a full-time college student studying Cell Biology / Biotechnology. My goal is to be accepted into a PhD program where I can design a direct-to-nerve interface to provide haptic (touch) and proprioceptive (position) feedback from prosthetics worn by amputees. By providing at least touch feedback, the wearer will incorporate the prosthetic into their body image. It will become part of their \textit{self} rather than just a machine attached to their body. + +\appendix +\chapter{Sample Mach3 Profile}\label{chp:SampleProfile} + +\begin{lstlisting}[numbers=left, + breaklines=true, + numberstyle=\tiny\color{gray}, + basicstyle=\ttfamily\tiny +] +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. + +// +// author=John Johnson +// description=Mach3 - EMC for Windows +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +string FORMAT = "%-7.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.0f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; + +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; + +\end{lstlisting} + + +\backmatter + +\printindex + +\end{document} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/pcb-gcode-setup.ulp b/trunk/ulp/pcb-gcode-3.6.0.4/pcb-gcode-setup.ulp new file mode 100644 index 00000000..116a451c --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/pcb-gcode-setup.ulp @@ -0,0 +1,872 @@ +// +// Generate g-code for milling PC boards. +// +// Copyright 2004-2013 by John Johnson Software, LLC. +// See readme.html for copyright information. +// + +#include "source/pcb-gcode.h" +#include "settings/pcb-defaults.h" +#include "settings/pcb-machine.h" +#include "settings/gcode-defaults.h" +#include "settings/pcb-gcode-options.h" +#include "source/filecopy.h" +#include "source/math.h" +#include "source/filename_subs.h" +#include "plugin_headers.h" + +int m_current_units = OUTPUT_UNITS; +string m_uom_suffix = "unknown"; +string M_UOM_SUFFIXES[] = { + "mc", // microns + "mm", // millimeters + "ml", // mils + "in" // inches +}; + +int m_setup_was_changed = NO; +string m_cmd; + +string FILENAME_TOP_ETCH_FILE_SAMPLE; +string FILENAME_TOP_DRILL_FILE_SAMPLE; +string FILENAME_TOP_MILL_FILE_SAMPLE; +string FILENAME_TOP_TEXT_FILE_SAMPLE; +string FILENAME_TOP_FILL_FILE_SAMPLE; +string FILENAME_BOT_ETCH_FILE_SAMPLE; +string FILENAME_BOT_DRILL_FILE_SAMPLE; +string FILENAME_BOT_MILL_FILE_SAMPLE; +string FILENAME_BOT_TEXT_FILE_SAMPLE; +string FILENAME_BOT_FILL_FILE_SAMPLE; + +string temp_str; + +void set_uom_suffix(int n) +{ + m_uom_suffix = M_UOM_SUFFIXES[n]; +} + +string get_uom_suffix() +{ + return m_uom_suffix; +} + +void write_bool_param(string name, int value) +{ + printf("int %s = %s;\n", name, (value) ? "YES" : "NO"); +} + +void write_int_param(string name, int value) +{ + printf("int %s = %d;\n", name, value); +} + +void write_int_defined(string name, string value) +{ + printf("int %s = %s;\n", name, value); +} + +void write_real_param(string name, real value) +{ + printf("real %s = %f;\n", name, value); +} + +void write_string_param(string name, string value) +{ + printf("string %s = \"%s\";\n", name, value); +} + +// UNIT CONVERSION BEGIN TAG DO NOT REMOVE + +void convert_units(int new_units) +{ + MILLING_DEPTH = convert(MILLING_DEPTH, m_current_units, new_units); + TEXT_DEPTH = convert(TEXT_DEPTH, m_current_units, new_units); + SPOT_DRILL_DEPTH = convert(SPOT_DRILL_DEPTH, m_current_units, new_units); + ISO_MIN = convert(ISO_MIN, m_current_units, new_units); + ISO_MAX = convert(ISO_MAX, m_current_units, new_units); + ISO_STEP = convert(ISO_STEP, m_current_units, new_units); + DEFAULT_WIDTH = convert(DEFAULT_WIDTH, m_current_units, new_units); + DEFAULT_Z_HIGH = convert(DEFAULT_Z_HIGH, m_current_units, new_units); + DEFAULT_Z_UP = convert(DEFAULT_Z_UP, m_current_units, new_units); + DEFAULT_Z_DOWN = convert(DEFAULT_Z_DOWN, m_current_units, new_units); + DRILL_DEPTH = convert(DRILL_DEPTH, m_current_units, new_units); + TOOL_CHANGE_POS_X = convert(TOOL_CHANGE_POS_X, m_current_units, new_units); + TOOL_CHANGE_POS_Y = convert(TOOL_CHANGE_POS_Y, m_current_units, new_units); + TOOL_CHANGE_POS_Z = convert(TOOL_CHANGE_POS_Z, m_current_units, new_units); + FEED_RATE = convert(FEED_RATE, m_current_units, new_units); + FEED_RATE_Z = convert(FEED_RATE_Z, m_current_units, new_units); + EPSILON = convert(EPSILON, m_current_units, new_units); + + set_uom_suffix(OUTPUT_UNITS); + dlgRedisplay(); + m_current_units = new_units; +} + +// UNIT CONVERSION END TAG DO NOT REMOVE + +// Copy the *.release.h files to *.h, thereby restoring +// their default contents. +void restore_file_defaults() +{ + string restore_files[]; + string file_name; + int num_files; + int i; + int release_start; + + num_files = fileglob(restore_files, + g_path + "/safe_options/" + "*.release.h"); + if (num_files == 0) { + dlgMessageBox("There aren't any .release.h files," + " perhaps you should reinstall the program?"); + exit(0); + } + + for (i=0; i < num_files; i++) { + release_start = strrstr(restore_files[i], ".release.h"); + file_name = strsub(restore_files[i], 0, release_start) + ".h"; + filecopy(restore_files[i], file_name); + } + + filecopy(g_path + "/profiles/generic.pp", + g_path + "/settings/gcode-defaults.h"); +} + +int pp_selection = -1; +string pp_files[]; +string pp_auth_desc[]; +int num_pp_files; + +num_pp_files = fileglob(pp_files, g_path + "/profiles/*.pp"); + +for(int i=0; i < num_pp_files; i++) { + string lines[]; + + pp_auth_desc[i] = pp_files[i]; + + int num_lines = fileread(lines, pp_files[i]); + for(int j=0; j < num_lines; j++) { + string fields[]; + + int num_fields = strsplit(fields, lines[j], '='); + for(int k=0; k < num_fields; k++) { + + if(strlwr(fields[k]) == "// author") { + pp_auth_desc[i] = pp_auth_desc[i] + " \t" + fields[k + 1]; + } + else if(strlwr(fields[k]) == "// description") { + pp_auth_desc[i] = pp_auth_desc[i] + " \t" + fields[k + 1]; + } + } + } +} + +string m_maximum_label = "Maximum"; +string m_step_size_label = "Step size"; +if (SINGLE_PASS) { + m_maximum_label = "not used"; + m_step_size_label = "not used"; +} + +string m_eagle_compatibility = ""; +string m_compatibility = ""; +if (EAGLE_VERSION < 5) { + m_compatibility = "NOT COMPATIBLE"; +} +else if (EAGLE_VERSION == 5) { + m_compatibility = "verified compatible"; +} +else if (EAGLE_VERSION == 6) { + if (EAGLE_RELEASE <= 3) { + m_compatibility = "verified compatible"; + } + else { + m_compatibility = "probably compatible"; + } +} +sprintf(m_eagle_compatibility, "%d.%d (%s)", EAGLE_VERSION, EAGLE_RELEASE, m_compatibility); + +int Result = dlgDialog("pcb-gcode Setup") { + + set_uom_suffix(OUTPUT_UNITS); + + dlgVBoxLayout { + dlgLabel( + "" + "" + "" + "" + "" + "" + "
    " + "" + "" + "" + "
    Copyright 2004-2013 by" + " John Johnson Software, LLC.
    " + "
    All Rights Reserved
    " + "
    Version 3.6.0.4
    You have EAGLE version " + m_eagle_compatibility + "
    "); + if (program_is_setup()) { + dlgLabel("
    Your current profile is based on the " + + CURRENT_PROFILE[DESCRIPTION] + " profile.

    "); + dlgLabel("
    Please use the settings under the tabs to" + " customize the gcode that is generated for you.
    "); + } + else { + dlgLabel("

    Welcome!

    " + "

    Since this is the first time you have run this setup" + " program, please select the profile that best suits your machine." + " Click the Accept button to save your changes.
    "); + } +// dlgLabel(""); + } + + + dlgTabWidget { + + /*************************************************************** + * + * G E N E R A T I O N O P T I O N S + * + ***************************************************************/ + + if (program_is_setup()) dlgTabPage("Generation Options") { + dlgHBoxLayout { + dlgStretch(20); + dlgVBoxLayout { + dlgGroup("Top Side") { + dlgCheckBox("Generate top outlines", GENERATE_TOP_OUTLINES); + dlgCheckBox("Generate top drills ", GENERATE_TOP_DRILL); + } + dlgStretch(1); + } + dlgVBoxLayout { + dlgGroup("Bottom Side") { + dlgCheckBox("Generate bottom outlines", + GENERATE_BOTTOM_OUTLINES); + dlgCheckBox("Generate bottom drills ", + GENERATE_BOTTOM_DRILL); + dlgCheckBox("Mirror ", + MIRROR_BOTTOM); + } + dlgStretch(1); + dlgLabel(""); + dlgStretch(3); + } + dlgVBoxLayout { + dlgGroup("Board") { + dlgVBoxLayout { + dlgCheckBox("Show preview ", SHOW_PREVIEW); + dlgGridLayout { + dlgCell(0, 0) dlgCheckBox("Generate milling", GENERATE_MILLING); + dlgCell(0, 1) dlgLabel("Depth "); + dlgCell(0, 2) { dlgRealEdit(MILLING_DEPTH); dlgLabel(m_uom_suffix, YES); } + + dlgCell(1, 0) dlgCheckBox("Generate text", GENERATE_TEXT); + dlgCell(1, 1) dlgLabel("Depth "); + dlgCell(1, 2) { dlgRealEdit(TEXT_DEPTH); dlgLabel(m_uom_suffix, YES); } + dlgCell(2, 0) dlgCheckBox("Spot drill holes", SPOT_DRILL); + dlgCell(2, 1) dlgLabel("Depth"); + dlgCell(2, 2) { dlgRealEdit(SPOT_DRILL_DEPTH); dlgLabel(m_uom_suffix, YES); } + } + dlgGridLayout { + dlgCell(0, 0, 0, 1) dlgLabel("Isolation"); + dlgCell(0, 1) { + dlgCheckBox("Single pass", SINGLE_PASS) { + if (SINGLE_PASS) { +/* dlgMessageBox("You have selected the single pass option.\n" + + "The next time you run pcb-gcode-setup, the Maximum and Step Size " + + "options will be hidden. Only Minimum will be shown.\n" + + "To change back, just turn Single pass off, " + + "click Accept, and run pcb-gcode-setup again.\n" + + "The minimum, maximum, and step size options will be available again."); + */ + m_maximum_label = "not used"; + m_step_size_label = "not used"; + } + else { + m_maximum_label = "Maximum"; + m_step_size_label = "Step size"; + } + } + } + dlgCell(1, 0) dlgLabel("Minimum"); + dlgCell(1, 1) { dlgRealEdit(ISO_MIN); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(3, 0) dlgLabel(m_maximum_label, YES); + dlgCell(3, 1) { dlgRealEdit(ISO_MAX); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(4, 0) dlgLabel(m_step_size_label, YES); + dlgCell(4, 1) { dlgRealEdit(ISO_STEP); + dlgLabel(m_uom_suffix, YES); + } + } + dlgSpacing(10); + dlgVBoxLayout { + dlgLabel("Etching Tool Size "); + dlgHBoxLayout { dlgRealEdit(DEFAULT_WIDTH); + dlgLabel(m_uom_suffix, YES); + } + } + } + } + dlgStretch(1); + } + dlgStretch(20); + } + dlgHBoxLayout { + } + } + + /*************************************************************** + * + * M A C H I N E + * + ***************************************************************/ + if (program_is_setup()) dlgTabPage("Machine") { + dlgHBoxLayout { + dlgStretch(20); + dlgLabel(""); + dlgGroup("Z Axis") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Z High "); + dlgCell(1, 1) { + dlgRealEdit(DEFAULT_Z_HIGH); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(2, 0) dlgLabel("Z Up "); + dlgCell(2, 1) { + dlgRealEdit(DEFAULT_Z_UP); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(3, 0) dlgLabel("Z Down "); + dlgCell(3, 1) { + dlgRealEdit(DEFAULT_Z_DOWN); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(4, 0) dlgLabel("Drill Depth "); + dlgCell(4, 1) { + dlgRealEdit(DRILL_DEPTH); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(5, 0) dlgLabel("Drill Dwell "); + dlgCell(5, 1) dlgRealEdit(DRILL_DWELL, 0); // DO NOT CONVERT + } + } + dlgGroup("Tool Change") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Position X "); + dlgCell(1, 1) { dlgRealEdit(TOOL_CHANGE_POS_X); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(2, 0) dlgLabel("Position Y "); + dlgCell(2, 1) { dlgRealEdit(TOOL_CHANGE_POS_Y); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(3, 0) dlgLabel("Position Z "); + dlgCell(3, 1) { dlgRealEdit(TOOL_CHANGE_POS_Z); + dlgLabel(m_uom_suffix, YES); + } + } + } + dlgStretch(20); + } + dlgHBoxLayout { + dlgStretch(20); + dlgGroup("Units") { + dlgRadioButton("Microns", OUTPUT_UNITS) { + convert_units(U_MICRONS); + } + dlgRadioButton("Millimeters", OUTPUT_UNITS) { + convert_units(U_MILLIMETERS); + } + dlgRadioButton("Mils", OUTPUT_UNITS) { + convert_units(U_MILS); + } + dlgRadioButton("Inches", OUTPUT_UNITS) { + convert_units(U_INCHES); + } + } + dlgGroup("Spindle") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Spin Up Time "); + dlgCell(1, 1) dlgRealEdit(SPINDLE_ON_TIME); // DO NOT CONVERT + } + } + dlgGroup("Feed Rates") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("X Y "); + dlgCell(1, 1) { dlgRealEdit(FEED_RATE); + dlgLabel(m_uom_suffix, YES); dlgLabel("/min"); + } + dlgCell(2, 0) dlgLabel("Z "); + dlgCell(2, 1) { dlgRealEdit(FEED_RATE_Z); + dlgLabel(m_uom_suffix, YES); dlgLabel("/min"); + } + } + } + dlgGroup("Misc") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Epsilon"); + dlgCell(1, 1) { dlgRealEdit(EPSILON); + dlgLabel(m_uom_suffix, YES); + dlgPushButton("?") { + dlgMessageBox("If an X or Y move is less than this amount, do not " + "put a move in the g-code file. For instance, if one point is " + "only 0.00001\" away from another point, there is no need to " + "write the move to the g-code file, since the machine will not " + "move anyway. This helps make the g-code file smaller, and run faster."); + } + } + dlgCell(2, 0) dlgLabel("Default Drill Rack File"); + dlgCell(2, 1) dlgStringEdit(DEFAULT_DRILL_FILE); + dlgCell(2, 2) { + dlgPushButton("...") { + DEFAULT_DRILL_FILE = dlgFileOpen("Find default drill rack file", + g_path + "/settings", + "Drill files (*.drl);;All files (*.*)"); + } + dlgPushButton("?") { + dlgMessageBox( + "Please see docs/readme.html for full details.
    " + "pcb-gcode will look for (in order):
    " + "board.drl
    " + "The file you select here.
    " + "path_to_pcbgcode/settings/default.drl
    " + "If this setting is blank, and it does not find a file, " + "it will assume you do not want to use a rack file.
    " + "If this setting is not blank, and it cannot find one of the " + "files listed above, it will give you an error message." + ); + } + } + } + } + dlgStretch(20); + } + } + + /*************************************************************** + * + * G C O D E S T Y L E + * + ***************************************************************/ + dlgTabPage("GCode Style") { + dlgLabel("Please select your style of gcode below."); + dlgLabel("If you make changes to gcode-defaults.h to " + "work with your machine,"); + dlgLabel( + "Please email the file to " + "pcbgcode@pcbgcode.org for possible inclusion " + "in the next release."); + dlgListView("File\tAuthor\tDescription", + pp_auth_desc, pp_selection); + } + + /*************************************************************** + * + * G C O D E O P T I O N S + * + ***************************************************************/ + if (program_is_setup()) dlgTabPage("GCode Options") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgGroup("NC File Comments") { + dlgCheckBox("NC File Comment from Board", + NC_FILE_COMMENT_FROM_BOARD); + dlgCheckBox("Nc File Comment Date", + NC_FILE_COMMENT_DATE); + dlgCheckBox("Nc File Comment Machine Settings", + NC_FILE_COMMENT_MACHINE_SETTINGS); + dlgCheckBox("Nc File Comment Pcb Defaults Settings", + NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS); + } +// dlgStretch(1); + } + dlgGroup("Other Options") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgCheckBox("Use user gcode (from user-gcode.h)", USER_GCODE); + dlgCheckBox("Debug Flag", g_debug_flag); + dlgCheckBox("Do tool change with zero step", DO_TOOL_CHANGE_WITH_ZERO_STEP); + dlgCheckBox("Flip board in Y instead of X", FLIP_BOARD_IN_Y); + } + dlgVBoxLayout { + dlgCheckBox("Compact gcode", COMPACT_GCODE); + dlgHBoxLayout { + dlgCheckBox("Use line numbers?", USE_LINE_NUMBERS); + dlgLabel(" Format "); dlgStringEdit(LINE_NUMBER_FORMAT); + } + dlgCheckBox("Use simple drill code ", + SIMPLE_DRILL_CODE); + } + } + // dlgStretch(1); + } + } + dlgHBoxLayout { + dlgGroup("File Naming") { + dlgGridLayout { + dlgCell(0, 0, 0, 1) { + dlgLabel("Filename Base "); dlgStringEdit(FILENAME_BASE); + } + dlgCell(0, 2) { + dlgLabel("Extension "); dlgStringEdit(DEFAULT_EXTENSION); + dlgStretch(1); + } + dlgCell(2, 0) { dlgLabel("Word for 'etch'"); + dlgStringEdit(ETCH_FILE_NAME); + } + dlgCell(2, 1) { dlgLabel("Word for 'drill'"); + dlgStringEdit(DRILL_FILE_NAME); + } + dlgCell(2, 2) { dlgLabel("Word for 'mill'"); + dlgStringEdit(MILL_FILE_NAME); + } + dlgCell(2, 3) { dlgLabel("Word for 'text'"); + dlgStringEdit(TEXT_FILE_NAME); dlgStretch(1); + } + dlgCell(3, 0) { dlgLabel("Word for 'top'"); + dlgStringEdit(TOP_FILE_NAME); + } + dlgCell(3, 1) { dlgLabel("Word for 'bottom'"); + dlgStringEdit(BOT_FILE_NAME); + } + } + dlgHBoxLayout { + dlgGroup("Top (Component) Side Files") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Etching "); + dlgCell(1, 1) { dlgStringEdit(FILENAME_TOP_ETCH_FILE); } + dlgCell(2, 0) dlgLabel("Drill "); + dlgCell(2, 1) { dlgStringEdit(FILENAME_TOP_DRILL_FILE); } + dlgCell(3, 0) dlgLabel("Mill "); + dlgCell(3, 1) { dlgStringEdit(FILENAME_TOP_MILL_FILE); } + dlgCell(4, 0) dlgLabel("Text "); + dlgCell(4, 1) { dlgStringEdit(FILENAME_TOP_TEXT_FILE); } + } + } + dlgGroup("Bottom (Solder) Side Files") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Etching "); + dlgCell(1, 1) dlgStringEdit(FILENAME_BOT_ETCH_FILE); + dlgCell(2, 0) dlgLabel("Drill "); + dlgCell(2, 1) dlgStringEdit(FILENAME_BOT_DRILL_FILE); + dlgCell(3, 0) dlgLabel("Mill "); + dlgCell(3, 1) dlgStringEdit(FILENAME_BOT_MILL_FILE); + dlgCell(4, 0) dlgLabel("Text "); + dlgCell(4, 1) dlgStringEdit(FILENAME_BOT_TEXT_FILE); + } + } +// dlgStretch(1); + dlgVBoxLayout { + dlgPushButton("Test Filenames") { + FILENAME_TOP_ETCH_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_TOP_ETCH_FILE, + TOP, PH_TOP_OUT_WRITE); + FILENAME_TOP_DRILL_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_TOP_DRILL_FILE, + TOP, PH_TOP_DRILL); + FILENAME_TOP_MILL_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_TOP_MILL_FILE, + TOP, PH_MILL); + FILENAME_TOP_TEXT_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_TOP_TEXT_FILE, + TOP, PH_TEXT); + FILENAME_BOT_ETCH_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_BOT_ETCH_FILE, + BOTTOM, PH_BOTTOM_OUT_WRITE); + FILENAME_BOT_DRILL_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_BOT_DRILL_FILE, + BOTTOM, PH_BOTTOM_DRILL); + FILENAME_BOT_MILL_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_BOT_MILL_FILE, + BOTTOM, PH_MILL); + FILENAME_BOT_TEXT_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_BOT_TEXT_FILE, + BOTTOM, PH_TEXT); + FILENAME_TOP_ETCH_FILE_SAMPLE = substitute( + FILENAME_TOP_ETCH_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_TOP_DRILL_FILE_SAMPLE = substitute( + FILENAME_TOP_DRILL_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_TOP_MILL_FILE_SAMPLE = substitute( + FILENAME_TOP_MILL_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_TOP_TEXT_FILE_SAMPLE = substitute( + FILENAME_TOP_TEXT_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_BOT_ETCH_FILE_SAMPLE = substitute( + FILENAME_BOT_ETCH_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_BOT_DRILL_FILE_SAMPLE = substitute( + FILENAME_BOT_DRILL_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_BOT_MILL_FILE_SAMPLE = substitute( + FILENAME_BOT_MILL_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_BOT_TEXT_FILE_SAMPLE = substitute( + FILENAME_BOT_TEXT_FILE_SAMPLE, + key_value_record(" ", "_")); + temp_str = ";Test Filenames\n" + "Spaces in file paths have been " + "replaced with underscores _ to keep " + "the lines from wrapping.\n" + "Top:\n" + "Etch:\t" + FILENAME_TOP_ETCH_FILE_SAMPLE + "\n" + + "Drill:\t" + FILENAME_TOP_DRILL_FILE_SAMPLE + "\n" + + "Mill:\t" + FILENAME_TOP_MILL_FILE_SAMPLE + "\n" + + "Text:\t" + FILENAME_TOP_TEXT_FILE_SAMPLE + "\n" + + "\nBottom:\n" + "Etch:\t" + FILENAME_BOT_ETCH_FILE_SAMPLE + "\n" + + "Drill:\t" + FILENAME_BOT_DRILL_FILE_SAMPLE + "\n" + + "Mill:\t" + FILENAME_BOT_MILL_FILE_SAMPLE + "\n" + + "Text:\t" + FILENAME_BOT_TEXT_FILE_SAMPLE + "\n"; + dlgMessageBox(temp_str); + } + dlgPushButton("Help") { + dlgMessageBox(filename_subs_help()); + } +// dlgStretch(1); + } + } + } + } + + } + if (program_is_setup()) dlgTabPage("Plugins") { + #include "plugins/plugin_loader.h" + } + + /*************************************************************** + * + * O T H E R + * + ***************************************************************/ + if (program_is_setup()) dlgTabPage("Other") { + dlgHBoxLayout { + dlgStretch(1); + dlgVBoxLayout { + dlgStretch(1); + dlgGroup("Miscellaneous") { + dlgGridLayout { + dlgCell(0, 0, 0, 5) { + dlgLabel("All misc. options are deprecated."); + } + } + } + dlgPushButton("Reset to Factory Defaults") { + if (dlgMessageBox( + "This is going to change the following files" + " back to their default contents, erasing any changes" + " you may have made to them:

    " + "" + "" + "" + "
    pcb-defaults.hpcb-gcode-options.h
    pcb-machine.huser-gcode.h

    " + "Is that something you want to do?

    " + "If you aren't sure, click No.", + "-Yes", "+No") == 0 /*Yes*/) { + restore_file_defaults(); + exit("run pcb-gcode-setup"); + } + } + dlgStretch(1); + } + dlgStretch(1); + } + } + } + + dlgHBoxLayout { + dlgStretch(5); + dlgPushButton("+&Accept") dlgAccept(); + if (program_is_setup()) { + dlgPushButton("Accept and make my &board") dlgAccept(2); + } + dlgPushButton("-Cancel") { + if (dlgMessageBox("Cancel your changes.

    " + "Are you sure?", "Yes", "No") == 0) dlgReject(); + } + } +}; + +// Accept Accept and make board +if (Result == 1 || Result == 2) { + + fileerror(); + output(g_path + "/settings/pcb-defaults.h", "wt") { + + int now = time(); + + printf( + "//\n// Default values for generating gcode from a PCB.\n//\n"); + printf("// These settings were last changed with " + "pcb-gcode-setup: %s\n//\n", t2string(now)); + printf("//\n// Changes you make in this file will be overwritten " + "if you use pcb-gcode-setup.\n//\n\n"); + + write_bool_param("SINGLE_PASS", SINGLE_PASS); + write_real_param("ISO_MIN", ISO_MIN); + write_real_param("ISO_MAX", ISO_MAX); + write_real_param("ISO_STEP", ISO_STEP); + printf("\n"); + + write_bool_param("GENERATE_TOP_OUTLINES", GENERATE_TOP_OUTLINES); + write_bool_param("GENERATE_TOP_DRILL", GENERATE_TOP_DRILL); + write_bool_param("GENERATE_TOP_FILL", GENERATE_TOP_FILL); + printf("\n"); + + write_bool_param("GENERATE_BOTTOM_OUTLINES", + GENERATE_BOTTOM_OUTLINES); + write_bool_param("GENERATE_BOTTOM_DRILL", GENERATE_BOTTOM_DRILL); + write_bool_param("GENERATE_BOTTOM_FILL", GENERATE_BOTTOM_FILL); + write_bool_param("MIRROR_BOTTOM", + MIRROR_BOTTOM); + write_bool_param("SIMPLE_DRILL_CODE", SIMPLE_DRILL_CODE); + + printf("\n"); + + write_bool_param("GENERATE_MILLING", GENERATE_MILLING); + printf("\n"); + + write_bool_param("GENERATE_TEXT", GENERATE_TEXT); + printf("\n"); + + write_bool_param("SPOT_DRILL", SPOT_DRILL); + write_real_param("SPOT_DRILL_DEPTH", SPOT_DRILL_DEPTH); + printf("\n"); + + write_bool_param("DO_TOOL_CHANGE_WITH_ZERO_STEP", + DO_TOOL_CHANGE_WITH_ZERO_STEP); + printf("\n"); + + write_bool_param("FLIP_BOARD_IN_Y", FLIP_BOARD_IN_Y); + printf("\n"); + + // Place a // in front of units not being used + if (OUTPUT_UNITS != U_MICRONS) printf("//"); + write_int_defined("OUTPUT_UNITS", "U_MICRONS"); + if (OUTPUT_UNITS != U_MILLIMETERS) printf("//"); + write_int_defined("OUTPUT_UNITS", "U_MILLIMETERS"); + if (OUTPUT_UNITS != U_MILS) printf("//"); + write_int_defined("OUTPUT_UNITS", "U_MILS"); + if (OUTPUT_UNITS != U_INCHES) printf("//"); + write_int_defined("OUTPUT_UNITS", "U_INCHES"); + } + if(fileerror()) + exit(1); + + if(pp_selection > -1) { + if (dlgMessageBox( + "If you have made manual changes to gcode-defaults.h, they" + " will be overwritten by your new gcode style selection.

    " + "(Click Yes if you aren't sure.)

    " + "Save your selection?", "Yes", "No") == 0) { + + filecopy(pp_files[pp_selection], + g_path + "/settings/gcode-defaults.h"); + + fileerror(); + set_current_profile(pp_auth_desc[pp_selection]); + if(fileerror()) + exit(1); + + m_setup_was_changed = YES; + } + } + + output(g_path + "/settings/pcb-gcode-options.h") { + printf("//\n"); + printf("// General Options "); + printf("// Your edits to this file will be overwritten" + " by the setup program.\n"); + printf("//\n"); + write_bool_param("SHOW_PROGRESS", SHOW_PROGRESS); + write_string_param("RESTORE_MENU_FILE", RESTORE_MENU_FILE); + write_bool_param("NC_FILE_COMMENT_FROM_BOARD", + NC_FILE_COMMENT_FROM_BOARD); + write_bool_param("NC_FILE_COMMENT_DATE", NC_FILE_COMMENT_DATE); + write_bool_param("NC_FILE_COMMENT_MACHINE_SETTINGS", + NC_FILE_COMMENT_MACHINE_SETTINGS); + write_bool_param("NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS", + NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS); + write_bool_param("USER_GCODE", USER_GCODE); + write_bool_param("g_debug_flag", g_debug_flag); + write_bool_param("COMPACT_GCODE", COMPACT_GCODE); + write_bool_param("USE_LINE_NUMBERS", USE_LINE_NUMBERS); + write_string_param("LINE_NUMBER_FORMAT", LINE_NUMBER_FORMAT); + write_bool_param("SHOW_PREVIEW", SHOW_PREVIEW); + + write_string_param("FILENAME_BASE", FILENAME_BASE); + write_string_param("FILENAME_TOP_ETCH_FILE", FILENAME_TOP_ETCH_FILE); + write_string_param("FILENAME_TOP_DRILL_FILE", FILENAME_TOP_DRILL_FILE); + write_string_param("FILENAME_TOP_MILL_FILE", FILENAME_TOP_MILL_FILE); + write_string_param("FILENAME_TOP_TEXT_FILE", FILENAME_TOP_TEXT_FILE); + write_string_param("FILENAME_TOP_FILL_FILE", FILENAME_TOP_FILL_FILE); + + write_string_param("FILENAME_BOT_ETCH_FILE", FILENAME_BOT_ETCH_FILE); + write_string_param("FILENAME_BOT_DRILL_FILE", FILENAME_BOT_DRILL_FILE); + write_string_param("FILENAME_BOT_MILL_FILE", FILENAME_BOT_MILL_FILE); + write_string_param("FILENAME_BOT_TEXT_FILE", FILENAME_BOT_TEXT_FILE); + write_string_param("FILENAME_BOT_FILL_FILE", FILENAME_BOT_FILL_FILE); + write_string_param("ETCH_FILE_NAME", ETCH_FILE_NAME); + write_string_param("DRILL_FILE_NAME", DRILL_FILE_NAME); + write_string_param("MILL_FILE_NAME", MILL_FILE_NAME); + write_string_param("TEXT_FILE_NAME", TEXT_FILE_NAME); + write_string_param("TOP_FILE_NAME", TOP_FILE_NAME); + write_string_param("BOT_FILE_NAME", BOT_FILE_NAME); + write_string_param("DEFAULT_EXTENSION", DEFAULT_EXTENSION); + + write_string_param("DEFAULT_DRILL_FILE", DEFAULT_DRILL_FILE); + } + + output(g_path + "/settings/pcb-machine.h") { + printf("//\n"); + printf("// For ease of use, and to avoid overwritting your settings,\n"); + printf("// use pcb-gcode-setup to make changes to these settings.\n"); + printf("//\n\n"); + write_real_param("DEFAULT_Z_HIGH", DEFAULT_Z_HIGH); + write_real_param("DEFAULT_Z_UP", DEFAULT_Z_UP); + write_real_param("DEFAULT_Z_DOWN", DEFAULT_Z_DOWN); + write_real_param("DRILL_DEPTH", DRILL_DEPTH); + write_real_param("DRILL_DWELL", DRILL_DWELL); + write_real_param("SPINDLE_ON_TIME", SPINDLE_ON_TIME); + write_real_param("MILLING_DEPTH", MILLING_DEPTH); + write_real_param("TEXT_DEPTH", TEXT_DEPTH); + write_real_param("TOOL_CHANGE_POS_X", TOOL_CHANGE_POS_X); + write_real_param("TOOL_CHANGE_POS_Y", TOOL_CHANGE_POS_Y); + write_real_param("TOOL_CHANGE_POS_Z", TOOL_CHANGE_POS_Z); + write_real_param("FEED_RATE", FEED_RATE); + write_real_param("FEED_RATE_Z", FEED_RATE_Z); + write_real_param("DEFAULT_WIDTH", DEFAULT_WIDTH); + write_real_param("X_OFFSET", X_OFFSET); + write_real_param("Y_OFFSET",Y_OFFSET); + write_real_param("X_HOME", X_HOME); + write_real_param("Y_HOME",Y_HOME); + write_real_param("EPSILON", EPSILON); + } + +} + +m_cmd = ""; +switch (Result) { + // Accept + case 1: + if (m_setup_was_changed) + m_cmd = "run pcb-gcode-setup;\n"; + break; + // Accept and make board + case 2: +// dlgMessageBox("g_path = \"" + g_path + "\""); + m_cmd = "run pcb-gcode;\n"; + break; +} + +if (SHOW_PROGRESS && RESTORE_MENU_FILE != "") { + m_cmd = "script " + RESTORE_MENU_FILE + ";\n" + m_cmd; +} +exit(m_cmd); diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/pcb-gcode.ulp b/trunk/ulp/pcb-gcode-3.6.0.4/pcb-gcode.ulp new file mode 100644 index 00000000..446e2ad7 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/pcb-gcode.ulp @@ -0,0 +1,1115 @@ +// +// Generate g-code for milling PC boards. +// +// Copyright 2004-2013 by John Johnson Software, LLC. +// See readme.html for copyright information. +// +// See pcb-defaults.h, gcode-defaults.h and pcb-machine.h for options. +// + +#include "source/pcb-gcode.h" +#include "source/pcb-gcode-stack.h" +#include "settings/pcb-defaults.h" +#include "settings/pcb-machine.h" +#include "settings/gcode-defaults.h" +#include "settings/pcb-gcode-options.h" +#include "settings/user-gcode.h" +#include "source/math.h" +#include "source/drill.h" +#include "source/library.h" +#include "source/pcb-file-utils.h" +#include "source/filename_subs.h" + +#usage "

    pcb-gcode™ Gcode Generation Utility
    " + " Version 3.6.0.4

    " + "Copyright© 2004 - 2013 by John Johnson Software, LLC
    " + "All Rights Reserved

    " + "

    " + "Join the Yahoo! pcb-gcode group " + "http://groups.yahoo.com/group/pcb-gcode" + "
    or contact the author at pcbgcode@pcbgcode.org" + "
    " + "


    " + "This program generates g-code for 'mechanically etching' PC boards. " + "Using a CNC router or milling machine, you can make PC boards without using etching chemicals.

    " + "It will create files for the outlines of tracks, drilling holes, and milling cutouts in the board." + "
    See the readme.html file for more info.

    " + "There are many options in the setup program.
    " + "To setup which files are generated, and how, use the following command:
    " + "run pcb-gcode --setup

    " + "

    " + "If you want to produce a set of files without changing options, you can run pcb-gcode directly." + "Usage is as follows:
    " + "run pcb-gcode [option] [file]
    " + "Where:\n" + "" + "" + "" + "" + "" + "" + "
    OptionFunction
    --helpShow this help screen
    --setupRun the setup / configuration program
    fileIs the optional root filename.\n
    If not given, the board name is used as the root filename.
    " + "" + "" + "


    " + +g_width = DEFAULT_WIDTH; + +// Filename to output to. +string m_file_name = ""; + +// Which side we're currently working on. +g_side = TOP; + +// Tool currently being used. +int m_current_tool = 0; + +// Amount to isolate traces. +real m_isolate = 0.0; + +// Used to pass the pass info to the next pass of the program. +int m_pass_num; + +// The layer being worked on. +int m_layer; + +// Used to create command strings. +string g_cmd; +string g_cmd_temp; + +// Save the maximum and minimum coordinates. +real m_max_x; +real m_max_y; +real m_min_x; +real m_min_y; +void save_extents(real x, real y) +{ + m_max_x = max(m_max_x, x); + m_max_y = max(m_max_y, y); + m_min_x = min(m_min_x, x); + m_min_y = min(m_min_y, y); +} + +void preview() +{ + if (SHOW_PREVIEW) { + switch(get_os()) { + case OS_MACOSX: + system(g_path + "/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub"); + break; + case OS_LINUX: + system(g_path + "/source/viewer.linux.sh"); + break; + case OS_WINDOWS: + system(g_path + "/viewer/application.windows/viewer.exe"); + dlgMessageBox("Close this window when you have finished with the preview"); + break; + default: + Fatal("Oops!", "Can't figure out which OS you have."); + } + } +} +// +// Determine the next phase, and set g_phase accordingly. +// +// Params: none +// Return: none +// +void next_phase(void) +{ + if (g_phase == PH_TOP_OUT_GEN && GENERATE_TOP_OUTLINES != YES) { + g_phase += 2; + return; + } + if (g_phase == PH_BOTTOM_OUT_GEN && GENERATE_BOTTOM_OUTLINES != YES) { + g_phase += 2; + return; + } + + if (g_phase == PH_TOP_OUT_WRITE || g_phase == PH_BOTTOM_OUT_WRITE) { + if (m_isolate < ISO_MAX && !SINGLE_PASS) { + m_isolate += ISO_STEP; + m_pass_num++; + g_phase--; + } + else { + m_isolate = ISO_MIN; + m_pass_num = 0; + g_phase++; + + preview(); + } + } + else { + g_phase++; + } +} + +////////////////////////////////////////////////// +// +// Hole drilling routines. +// +////////////////////////////////////////////////// + +// +// Add a hole drilling command to the command string. +// +// Params: +// Size Drill size. +// x x coordinate. +// y y coordinate. +// Returns: +// none +// Changes: +// the stack +// +void add_hole(int req_size, int x, int y) +{ + string tempstr; + int drill_size; + + drill_size = get_drill_for(req_size); + + sprintf(tempstr, "%06d\t%06d\t%06d", drill_size, x, y); + stack_push(tempstr); +} + +/* + * Create a drill file for the desired side. + * + * Params: + * which_side Side to produce the file for. + * suffix Suffix to use for the file name (i.e. bd). + * Returns: + * none + * Changes: + * side +*/ +void drill(int which_side, string suffix) +{ + int num_lines; + int i; + real last_size; + string drill_args[]; + m_current_tool = 0; + real drill_size_mm; + real drill_size_inch; + real drill_size; + real drill_x; + real drill_y; + int drill_tool_num; + + g_side = which_side; + + // + // Build a stack with all the holes. + // + board(B) { + B.holes(H) add_hole(H.drill, H.x, H.y); + B.signals(S) S.vias(V) add_hole(V.drill, V.x, V.y); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + add_hole(C.pad.drill, C.pad.x, C.pad.y); + } + } + E.package.holes(H) add_hole(H.drill, H.x, H.y); + } + // B.elements + + // Sorts the drills by size, x and y. + stack_sort(); + + // + // Create the drill g-code file. + // + last_size = -1; + output(get_filename(), "wt") { + output_file_preamble(); + + // + // Create a tool table at the beginning of the file. + // + out(TOOL_CHANGE_TABLE_HEADER); + for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { + if (i==END_OF_STACK) break; + strsplit(drill_args, stack_elem(i), '\t'); + drill_size_inch = u2inch(my_strtol(drill_args[DRILL_SIZE])); + drill_size_mm = u2mm(my_strtol(drill_args[DRILL_SIZE])); + drill_size = my_strtol(drill_args[DRILL_SIZE]); + + if (drill_size != last_size) { + ++m_current_tool; + drill_tool_num = get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool); + out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num, + drill_size_mm, drill_size_inch, + g_mins[drill_tool_num], g_maxs[drill_tool_num], + g_drill_sub_cnt[drill_tool_num])); + } + last_size = drill_size; + } + // for + + // Set the mode for the user's UOM. + out(get_mode()); + out(ABSOLUTE_MODE); + + // + // Generate drill code. + // + m_current_tool = 0; + for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { + strsplit(drill_args, stack_elem(i), '\t'); + drill_size = units(my_strtol(drill_args[DRILL_SIZE])); + drill_x = scale_x(my_strtol(drill_args[DRILL_X])); + drill_y = scale_y(my_strtol(drill_args[DRILL_Y])); + save_extents(drill_x, drill_y); + + if (drill_size == last_size) { + output_drill_hole(drill_x, drill_y, DRILL_DEPTH); + } + else { + m_current_tool++; + // Tool change routine + output_tool_change_begin(); + out(SPINDLE_OFF); + rz(TOOL_CHANGE_POS_Z); + rxy(TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y); + out(fir(TOOL_CHANGE, get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool), drill_size)); + output_tool_changed(); + + if (DO_TOOL_CHANGE_WITH_ZERO_STEP == YES) { + output_tool_zero_begin(); + fzr(0.000, FEED_RATE_Z); + // fixme: wondering about the following line + out(fir(TOOL_CHANGE, m_current_tool, drill_size)); + output_tool_zero_end(); + } + + rz(DEFAULT_Z_UP); + out(fr(SPINDLE_ON, SPINDLE_ON_TIME)); + output_tool_change_end(); + + output_drill_first_hole(drill_x, drill_y, DRILL_DEPTH); + last_size = drill_size; + } + // if drill_size != last_size + } + // for + + output_file_postamble(); + + // End of file + // change back to tool 1 + out(fi(TOOL_CODE + EOL, 1)); + end_gcode(); + } + // output + } + // Board +} +// drill + +int m_first_spot_drill = YES; +void spot_drill_hole(int x, int y) +{ + real drill_x; + real drill_y; + + drill_x = scale_x(x); + drill_y = scale_y(y); + save_extents(drill_x, drill_y); + + if (m_first_spot_drill) { + output_drill_first_hole(drill_x, drill_y, SPOT_DRILL_DEPTH); + m_first_spot_drill = NO; + } + else { + output_drill_hole(drill_x, drill_y, SPOT_DRILL_DEPTH); + } +} + +void spot_drill(UL_BOARD B) +{ + if (SPOT_DRILL == NO) { return; } + + B.holes(H) spot_drill_hole(H.x, H.y); + B.signals(S) S.vias(V) spot_drill_hole(V.x, V.y); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + spot_drill_hole(C.pad.x, C.pad.y); + } + } + E.package.holes(H) spot_drill_hole(H.x, H.y); + } + // B.elements +} + +string m_lines; +string LINE_SEP = "\n"; +string COORD_SEP = ","; +string COORD_FMT = "%8.5f"; + +string coords(real x1, real y1, real x2, real y2) +{ + return frrrr(COORD_FMT + COORD_SEP + COORD_FMT + COORD_SEP + + COORD_FMT + COORD_SEP + COORD_FMT + LINE_SEP, x1, y1, x2, y2); +} + +// +// "Draw" on the output device, i.e. the gcode file. +// +// Params: +// x1,y1 Start of the line. +// x2,y2 End of the line. +// state +// z_down +// Returns: +// none +// +real m_arc_begin_x; +real m_arc_begin_y; +int pair_count = 0; +int MAX_COORDS_PER_LINE = 4; +void device_draw(int x1, int y1, int x2, int y2, int state, real z_down) +{ + real rx1, ry1, rx2, ry2; + + rx1 = scale_x(x1); + ry1 = scale_y(y1); + rx2 = scale_x(x2); + ry2 = scale_y(y2); + save_extents(rx1, ry1); + save_extents(rx2, ry2); + + // Output g-code based on the current state. + switch(state) { + + // Start of a new line. + case ST_START_LINE: + user_track_begin(rx1, ry1, rx2, ry2); + + m_lines += coords(rx1, ry1, rx2, ry2); + + rz(DEFAULT_Z_UP); + rxy(rx1, ry1); + fzr(z_down, FEED_RATE_Z); + fxyr(rx2, ry2, FEED_RATE); + pair_count = 0; + break; + + // A fill line. + case ST_FILL: + Fatal("Programmer Error", "The Fill functions are no longer supported."); + break; + + // Continue a line. + // End a line. + case ST_CONTINUE_LINE: + user_track_continue(rx1, ry1, rx2, ry2); + + m_lines += coords(rx1, ry1, rx2, ry2); + + if (COMPACT_GCODE == YES) { + if (pair_count == 0) { + fxy(rx2, ry2); + } + else { + xy(rx2, ry2); + } + pair_count++; + } + else { + fxy(rx2, ry2); + } + break; + + case ST_END_LINE: + user_track_end(rx1, ry1, rx2, ry2); + + m_lines += coords(rx1, ry1, rx2, ry2); + + + if (COMPACT_GCODE == YES) { + xy(rx2, ry2); + pair_count = 0; + } + else { + fxy(rx2, ry2); + } + break; + + // Drill a hole. + // todo is this valid? + case ST_DRILL: + printf("cause an error if used %d"); + // printf("drill (%f, %f)\n", rx2, ry2); + break; + + // Create an arc. + case ST_ARC_BEGIN: + user_arc_begin(rx1, ry1, rx2, ry2); + m_arc_begin_x = rx1; + m_arc_begin_y = ry1; + break; + + // Finish an arc. + case ST_ARC_END: + user_arc_end(rx1, ry1, rx2, ry2); + real cx = rx2; + real cy = ry2; + real end_x = rx1; + real end_y = ry1; + + if (1 /* USE_IJ_RELATIVE */) { + cx = rx2 - rx1; + cy = ry2 - ry1; + } + + rz(DEFAULT_Z_UP); + rxy(end_x, end_y); + fzr(z_down, FEED_RATE_Z); + if (g_side == TOP || MIRROR_BOTTOM == YES) { + out(frrrr(CIRCLE_TOP, m_arc_begin_x, m_arc_begin_y, cx, cy)); + } + else { + out(frrrr(CIRCLE_BOTTOM, m_arc_begin_x, m_arc_begin_y, cx, cy)); + } + break; + + } + // switch(state) +} +// device_draw + + +// +// Generate polygons for outline or fill. +// This creates a series of commands for Eagle and puts them +// in g_cmd to be passed when we exit from this phase of pcb-gcode. +// +// Params: +// which_side The side to operate on. +// Return: +// none +// +void generate_outlines(int which_side) +{ + string cmd_temp = ""; + + g_cmd = ""; + + if (which_side == TOP) + m_layer = TOP_LAYER; + else + m_layer = BOTTOM_LAYER; + + board(B) { + real f = BORDER_SIZE; + real x1 = units(B.area.x1) - f; + real y1 = units(B.area.y1) - f; + real x2 = units(B.area.x2) + f; + real y2 = units(B.area.y2) + f; + + B.signals(S) { + if (S.name == OUTLINES_SIGNAL_NAME) { + sprintf(cmd_temp, "delete (%f %f) (%f %f);\n", + x1, y1, x2, y2); + g_cmd = g_cmd + cmd_temp; + } + } + + sprintf(cmd_temp, "grid %s;\n" + "change isolate %f;\n" + "change rank 6;\n" + "change pour solid;\n" + "change width %f;\n" + "change orphans on;\n" + "layer %d;\n" + "polygon %s %f (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n" + "ratsnest;\n" + , + UNIT_OF_MEASURE, + m_isolate, + g_width, + m_layer, + OUTLINES_SIGNAL_NAME, g_width, + x1, y1, x2, y1, x2, y2, x1, y2, x1, y1 + ); + g_cmd = g_cmd + cmd_temp; + return; + } + // board(B) +} +// generate_outlines + +void out_lines(string path, string mode) +{ + output(path, mode) { + if (m_pass_num == 0) { + printf("# board=%s\n", elided_path(get_filename(), 30)); + printf("# tool size=%f\n", g_width); + } + printf("# pass=%d\n", m_pass_num + 1); + printf(m_lines); + } +} + +// +// Write text from the Milling layer to a text engraving file. +// +// Params: +// file_name Output filename. +// Return: +// none +// +void output_text_code(string file_name) +{ + int state; + int old_x, old_y; + + board(B) { + output(get_filename(), "wt") { + user_file_opened(get_filename(), "wt"); + + output_file_preamble(); + + // Initialize the device (i.e. the output file). + begin_gcode(); + + // Process all the wires. + B.texts(T) T.wires(W) { + if ((T.mirror && g_side == BOTTOM) || (! T.mirror && g_side == TOP)) { + // If this is a text layer, check if we should continue + // a line, or start a new one. + if (W.layer == TEXT_LAYER) { + if (W.x1 == old_x && W.y1 == old_y) { + state = ST_CONTINUE_LINE; + } + else { + state = ST_START_LINE; + } + + // if this is an arc, it is treated specially. + if (W.arc) { + device_draw( W.arc.x1, W.arc.y1, W.arc.x2, W.arc.y2, ST_ARC_BEGIN, TEXT_DEPTH); + device_draw( W.arc.x2, W.arc.y2, W.arc.xc, W.arc.yc, ST_ARC_END, TEXT_DEPTH); + save_extents(W.x1, W.y1); + save_extents(W.x2, W.y2); + state = ST_START_LINE; + } + else { + // Draw the line (i.e. output the gcode for the line). + device_draw(W.x1, W.y1, W.x2, W.y2, state, TEXT_DEPTH); + old_x = W.x2; + old_y = W.y2; + save_extents(W.x1, W.y1); + save_extents(W.x2, W.y2); + } + // if (W.arc) + } + // if (W.layer == TEXT_LAYER) + } + // if (top and bottom check) + } + // T.wires + output_file_postamble(); + end_gcode(); + user_file_closing(); + } + // output + user_file_closed(get_filename(), "wt"); + } + // board + g_width = abs(TEXT_DEPTH); + out_lines(g_path + "/viewer/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt"); + + preview(); + + m_lines = ""; +} +// output_text_code + + +// +// Write layer data to mill files. +// +// Params: +// file_name Output filename. +// Return: +// none +// +void output_mill_code(string file_name) +{ + int state; + int old_x, old_y; + + board(B) { + output(get_filename(), "wt") { + user_file_opened(get_filename(), "wt"); + + output_file_preamble(); + + // Initialize the device (i.e. the output file). + begin_gcode(); + + // Process all the wires. + B.wires(W) W.pieces(P) { + // If this is a mill layer, check if we should continue + // a line, or start a new one. + if (P.layer == MILL_LAYER) { + if (P.x1 == old_x && P.y1 == old_y) { + state = ST_CONTINUE_LINE; + } + else { + state = ST_START_LINE; + } + + // if this is an arc, it is treated specially. + if (P.arc) { + device_draw( P.arc.x1, P.arc.y1, P.arc.x2, P.arc.y2, ST_ARC_BEGIN, MILLING_DEPTH); + device_draw( P.arc.x2, P.arc.y2, P.arc.xc, P.arc.yc, ST_ARC_END, MILLING_DEPTH); + save_extents(P.x1, P.y1); + save_extents(P.x2, P.y2); + state = ST_START_LINE; + } + else { + // Draw the line (i.e. output the gcode for the line). + device_draw(P.x1, P.y1, P.x2, P.y2, state, MILLING_DEPTH); + old_x = P.x2; + old_y = P.y2; + save_extents(P.x1, P.y1); + save_extents(P.x2, P.y2); + } + // if (P.arc) + } + // if (P.layer == MILL_LAYER) + } + // pieces + output_file_postamble(); + end_gcode(); + user_file_closing(); + } + // output + user_file_closed(get_filename(), "wt"); + } + // board + + g_width = abs(MILLING_DEPTH); + out_lines(g_path + "/viewer/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt"); + + preview(); + + m_lines = ""; +} +// output_mill_code + + +// +// Write polygon lines to the file. +// +// Params: +// which_side Side of the board to work on. +// suffix Suffix of the file. +// task +// Return: +// none +// +void write_outlines(int which_side, string suffix, int task) +{ + string mode; + int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN; + int x0, y0; + int first = 1; + int frame_wire; + int state; + + if (m_pass_num == 0) { + mode = "wt"; + } + else { + mode = "at"; + } + g_side = which_side; + switch (which_side) { + case TOP: + m_layer = TOP_LAYER; + break; + case BOTTOM: + m_layer = BOTTOM_LAYER; + break; + case MILL: + m_layer = MILL_LAYER; + break; + case TEXT: + m_layer = TEXT_LAYER; + break; + default: + sprintf(g_debug, "Illegal which_side %d in write_outlines", which_side); + Fatal("Sorry...", g_debug); + } + + if (m_layer == MILL_LAYER || m_layer == TEXT_LAYER) { + if (which_side == MILL) { + g_side = TOP; + output_mill_code(m_file_name + "mt" + DEFAULT_EXTENSION); + g_side = BOTTOM; + output_mill_code(m_file_name + "mb" + DEFAULT_EXTENSION); + return; + } + else { + g_side = TOP; + output_text_code(m_file_name + "tt" + DEFAULT_EXTENSION); + g_side = BOTTOM; + output_text_code(m_file_name + "tb" + DEFAULT_EXTENSION); + return; + } + } + // if m_layer == MILL_LAYER + + output(get_filename(), mode) { + board(B) { + user_file_opened(get_filename(), mode); + + int rubout_layer = -1; + B.layers(L) { + if (strstr(strlwr(L.name), "rubout") != -1) { + if (strstr(strlwr(L.name), "top") != -1 && which_side == TOP) { + rubout_layer = L.number; + } + else if (strstr(strlwr(L.name), "bot") != -1 && which_side == BOTTOM) { + rubout_layer = L.number; + } + } + } + + if (rubout_layer != -1) { + B.wires(W) { + if (W.layer == rubout_layer) { + device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN); + device_draw(W.x1, W.y1, W.x2, W.y2, ST_END_LINE, DEFAULT_Z_DOWN); // fixme needed? + } + } + } + + B.signals(S) { + if (S.name == OUTLINES_SIGNAL_NAME) { + S.polygons(P) { + P.wires(W) { + x1 = min(x1, W.x1); + x2 = max(x2, W.x1); + y1 = min(y1, W.y1); + y2 = max(y2, W.y1); + } + if (m_pass_num == 0) { + output_file_preamble(); + begin_gcode(); + } + else { + output_between_outline_passes(); + } + + switch (task) { + case TASK_OUTLINES: + // P.contours jtj + P.contours(W) { + if (first) { + x0 = W.x1; + y0 = W.y1; + frame_wire = (x0 == x1 || x0 == x2) && (y0 == y1 || y0 == y2); + state = ST_START_LINE; + first = 0; + } + else if (W.x2 == x0 && W.y2 == y0) { + state = ST_END_LINE; + first = 1; + } + else { + state = ST_CONTINUE_LINE; + } + + if (!frame_wire) { + device_draw(W.x1, W.y1, W.x2, W.y2, state, DEFAULT_Z_DOWN); + } + } + // P.contours(W) + break; + + case TASK_FILL: + P.fillings(W) { + device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN); + } + break; + } + // switch(task) + + if (m_isolate >= ISO_MAX || SINGLE_PASS || task == TASK_FILL) { + output_file_postamble(); + rz(DEFAULT_Z_UP); + spot_drill(B); + end_gcode(); + } + + sprintf(g_cmd, "delete (%f %f) (%f %f);\n", + units(x1), units(y1), units(x2), units(y2) + ); + } + // polygons + } + // if(S.name == OUTLINES_SIGNAL_NAME) + } + // signals + } + // board + user_file_closing(); + } + // output + user_file_closed(get_filename(), mode); + out_lines(g_path + "/viewer/data/optimize_me.txt", mode); + out_lines(g_path + "/viewer/applet/data/optimize_me.txt", mode); + out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", mode); + out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", mode); + out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", mode); + +} +// write_outlines + +/* string get_phase_name(int phase) +{ + return PHASE_NAME[phase]; +} + */ +void gen_progress_menu(int phase) +{ + output(path_scr[0] + '/' + "source/pcb-gcode-prg.scr") { + printf("MENU \\\n"); + for(int i = 1; i < PH_LAST_PHASE; i++) { + if (i == phase) { + printf("--%s-- \\\n", get_phase_name(i)); + // " (for TextMate) + } + else { + printf(" %s \\\n", get_phase_name(i)); + } + } + printf(";\n"); + } +} + +// Make sure a board is available to work on. +// todo move towards bottom +if (!board) { + Fatal("No board!", "Please run this program from the board editor"); +} + +// +// Process command line arguments. +// +switch (OUTPUT_UNITS) { + case U_MICRONS: + UNIT_OF_MEASURE = "mic"; + break; + case U_MILLIMETERS: + UNIT_OF_MEASURE = "mm"; + break; + case U_MILS: + UNIT_OF_MEASURE = "mil"; + break; + case U_INCHES: + UNIT_OF_MEASURE = "inch"; + break; +} + +if (argv[FILENAME_ARG] == "--setup") { + exit("run pcb-gcode-setup"); +} + +if (argv[FILENAME_ARG] == "--attr") { + string attrs; + board(B) { + B.attributes(A) { + attrs = attrs + A.name + "\t" + A.value + "\n"; + } + } + dlgMessageBox(attrs); + exit(0); +} + +if (argv[FILENAME_ARG] == "--help") { + int choice = dlgMessageBox(usage, "+Return to Eagle", "Run Setup Now"); + switch (choice) { + + // return to eagle + case 0: + exit(0); + break; + + // Run setup now + case 1: + exit("run pcb-gcode-setup"); + break; + } + exit(0); +} + +// Be sure a filename is specified. +if (argv[FILENAME_ARG]) { + m_file_name = argv[FILENAME_ARG]; + if (filedir(m_file_name) == "") { + board(B) m_file_name = filedir(B.name) + m_file_name; + } +} +else { + board(B) m_file_name = filesetext(B.name, ""); +} + +if (FILENAMES_8_CHARACTERS) { + m_file_name = filedir(m_file_name) + strsub(filename(m_file_name), 0, 5); +} + +// Use a default width if one is not given. +if (argv[WIDTH_ARG]) { + g_width = strtod(argv[WIDTH_ARG]); +} +else { + g_width = DEFAULT_WIDTH; +} + +// Get the isolate parameter or use the default. +if (argv[ISO_ARG]) { + m_isolate = strtod(argv[ISO_ARG]); +} +else { + m_isolate = ISO_MIN; +} + +// Get the pass number, or default to first pass (0). +if (argv[PASS_ARG]) { + m_pass_num = strtol(argv[PASS_ARG]); +} +else { + m_pass_num = 0; +} + +// Get the phase we are processing, or default to the first one. +if (argv[PHASE_ARG]) { + g_phase = strtol(argv[PHASE_ARG]); +} +else { + g_phase = PH_TOP_OUT_GEN; +} + +get_current_profile(); +if (g_phase == PH_TOP_OUT_GEN && m_pass_num == 0 && program_is_setup() == NO) +{ + exit("run pcb-gcode-setup"); +} + +// +// Do what we need to for this phase. +// +switch (g_phase) { + case PH_TOP_OUT_GEN: + if (GENERATE_TOP_OUTLINES == YES) + generate_outlines(TOP); + break; + case PH_TOP_OUT_WRITE: + if (GENERATE_TOP_OUTLINES == YES) + write_outlines(TOP, "top", OUTLINES); + break; + + case PH_TOP_FILL_GEN: + if (GENERATE_TOP_FILL == YES) + generate_outlines(TOP); + break; + case PH_TOP_FILL_WRITE: + if (GENERATE_TOP_FILL == YES) + write_outlines(TOP, "tf", FILL); + break; + + case PH_BOTTOM_OUT_GEN: + if (GENERATE_BOTTOM_OUTLINES == YES) + generate_outlines(BOTTOM); + break; + case PH_BOTTOM_OUT_WRITE: + if (GENERATE_BOTTOM_OUTLINES == YES) + write_outlines(BOTTOM, "bot", OUTLINES); + break; + + case PH_BOTTOM_FILL_GEN: + if (GENERATE_BOTTOM_FILL == YES) + generate_outlines(BOTTOM); + break; + case PH_BOTTOM_FILL_WRITE: + if (GENERATE_BOTTOM_FILL == YES) + write_outlines(BOTTOM, "bf", FILL); + break; + + case PH_TOP_DRILL: + if (GENERATE_TOP_DRILL == YES) + drill(TOP, "td"); + break; + case PH_BOTTOM_DRILL: + if (GENERATE_BOTTOM_DRILL == YES) + drill(BOTTOM, "bd"); + break; + + case PH_MILL: + if (GENERATE_MILLING == YES) + write_outlines(MILL, "mil", MILL_BOARD); + break; + + case PH_TEXT: + if (GENERATE_TEXT == YES) + write_outlines(TEXT, "txt", MILL_TEXT); + break; + + default: + sprintf(g_debug, "Illegal phase %d in main routine", g_phase); + Fatal("Sorry...", g_debug); +} + +// Set things up for the next phase. +next_phase(); + +if (SHOW_PROGRESS == YES) { + gen_progress_menu(g_phase); +} + +// If this is not the last phase, exit with a command line for +// Eagle to process. The command includes running this program again. +if (g_phase < PH_LAST_PHASE) { + sprintf(g_cmd, + "%s" + "window fit;\n" + "%s" + "run '%s' '%s' '%f' '%f' '%d' '%d';\n", + g_cmd, + (SHOW_PROGRESS) ? "script pcb-gcode-prg.scr;\n" : "", + argv[PROGRAM_NAME_ARG], m_file_name, g_width, m_isolate, + m_pass_num, g_phase + ); + exit(g_cmd); +} +else { + g_cmd = "window fit;\n"; + if (SHOW_PROGRESS) { + if (RESTORE_MENU_FILE != "") { + g_cmd = g_cmd + "script " + RESTORE_MENU_FILE + ";\n"; + } + else { + g_cmd = g_cmd + "menu;\n"; + } + } + + exit(g_cmd); +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/pcbgcode.tmproj b/trunk/ulp/pcb-gcode-3.6.0.4/pcbgcode.tmproj new file mode 100644 index 00000000..7ff8c204 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/pcbgcode.tmproj @@ -0,0 +1,264 @@ + + + + + currentDocument + rakefile.rb + documents + + + expanded + + name + docs + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + docs + + + filename + pcb_gcode_is_setup + lastUsed + 2012-12-16T21:32:53Z + + + filename + pcb-gcode-setup.ulp + lastUsed + 2013-01-17T03:04:58Z + + + filename + pcb-gcode.ulp + lastUsed + 2013-01-17T03:05:09Z + + + filename + pcbgcode.tmproj + lastUsed + 2009-02-07T14:49:48Z + + + filename + plugin_headers.h + lastUsed + 2012-12-16T18:55:27Z + + + name + plugins + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + plugins + + + name + profiles + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + profiles + + + name + safe_options + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + safe_options + + + name + settings + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + settings + + + expanded + + name + source + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + source + + + filename + storage.nv + lastUsed + 2009-01-03T00:27:28Z + + + name + viewer + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + viewer + + + expanded + + name + make + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + make + + + filename + rakefile.rb + lastUsed + 2013-01-17T03:13:04Z + selected + + + + filename + README + lastUsed + 2013-01-02T22:44:23Z + + + fileHierarchyDrawerWidth + 296 + metaData + + README + + caret + + column + 28 + line + 0 + + firstVisibleColumn + 0 + firstVisibleLine + 0 + + docs/changelog.txt + + caret + + column + 65 + line + 3 + + firstVisibleColumn + 0 + firstVisibleLine + 0 + + make/write_convert_units.rb + + caret + + column + 32 + line + 87 + + firstVisibleColumn + 0 + firstVisibleLine + 46 + + pcb-gcode-setup.ulp + + caret + + column + 31 + line + 204 + + firstVisibleColumn + 0 + firstVisibleLine + 183 + + pcb-gcode.ulp + + caret + + column + 21 + line + 23 + + firstVisibleColumn + 0 + firstVisibleLine + 2 + + rakefile.rb + + caret + + column + 76 + line + 43 + + firstVisibleColumn + 0 + firstVisibleLine + 41 + + source/pcb-gcode.h + + caret + + column + 0 + line + 190 + + columnSelection + + firstVisibleColumn + 0 + firstVisibleLine + 181 + selectFrom + + column + 23 + line + 190 + + selectTo + + column + 0 + line + 190 + + + + openDocuments + + pcb-gcode-setup.ulp + pcb-gcode.ulp + docs/changelog.txt + rakefile.rb + source/pcb-gcode.h + README + make/write_convert_units.rb + + showFileHierarchyDrawer + + windowFrame + {{339, 83}, {957, 795}} + + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugin_headers.h b/trunk/ulp/pcb-gcode-3.6.0.4/plugin_headers.h new file mode 100644 index 00000000..87474841 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugin_headers.h @@ -0,0 +1,4 @@ +#include "source/nonvolatile.h" + +#include "plugins/calculator.plugin.h" + \ No newline at end of file diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin new file mode 100644 index 00000000..3d0645a5 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin @@ -0,0 +1,75 @@ +dlgGroup("Calculator (RPN)") { + dlgGridLayout { + int row; + dlgCell(row, 0) { dlgLabel("Result"); } + dlgCell(row, 1, row, 3) { + dlgGroup("") { dlgLabel(m_result, 1); } + } + dlgCell(row, 4) dlgLabel(g_angle_mode_str, 1); + dlgCell(++row, 0) { dlgLabel("Entry"); } + dlgCell(row, 1, row, 3) dlgGroup("") { dlgLabel(m_entry, 1); } + dlgCell(++row, 0) dlgPushButton("7") calc_enter("7"); + dlgCell(row, 1) dlgPushButton("8") calc_enter("8"); + dlgCell(row, 2) dlgPushButton("9") calc_enter("9"); + dlgCell(row, 3) dlgPushButton("/") calc(m_entry, OP_DIVIDE); + dlgCell(row, 4) dlgPushButton("M+") calc(m_entry, OP_MEMORY_PLUS); + dlgCell(row, 5) dlgPushButton("deg") calc(m_entry, OP_DEGREE); + dlgCell(row, 6) dlgPushButton("rad") calc(m_entry, OP_RADIAN); + + dlgCell(++row, 0) dlgPushButton("4") calc_enter("4"); + dlgCell(row, 1) dlgPushButton("5") calc_enter("5"); + dlgCell(row, 2) dlgPushButton("6") calc_enter("6"); + dlgCell(row, 3) dlgPushButton("*") calc(m_entry, OP_MULTIPLY); + dlgCell(row, 4) dlgPushButton("->M") calc(m_entry, OP_MEMORY_STORE); + dlgCell(row, 5) dlgPushButton("sin") calc(m_entry, OP_SINE); + dlgCell(row, 6) dlgPushButton("arc sin") calc(m_entry, OP_ARC_SINE); + + dlgCell(++row, 0) dlgPushButton("1") calc_enter("1"); + dlgCell(row, 1) dlgPushButton("2") calc_enter("2"); + dlgCell(row, 2) dlgPushButton("3") calc_enter("3"); + dlgCell(row, 3) dlgPushButton("--") calc(m_entry, OP_SUBTRACT); + dlgCell(row, 4) dlgPushButton("<-M") calc(m_entry, OP_MEMORY_RECALL); + dlgCell(row, 5) dlgPushButton("cos") calc(m_entry, OP_COSINE); + dlgCell(row, 6) dlgPushButton("arc cos") calc(m_entry, OP_ARC_COSINE); + + dlgCell(++row, 0) dlgPushButton(".") calc_enter("."); + dlgCell(row, 1) dlgPushButton("0") calc_enter("0"); + dlgCell(row, 2) dlgPushButton("C") calc(m_entry, OP_CLEAR); + dlgCell(row, 3) dlgPushButton("++") calc(m_entry, OP_ADD); + dlgCell(row, 4) dlgPushButton("0->M") calc(m_entry, OP_MEMORY_CLEAR); + dlgCell(row, 5) dlgPushButton("tan") calc(m_entry, OP_TANGENT); + dlgCell(row, 6) dlgPushButton("arc tan") calc(m_entry, OP_ARC_TANGENT); + + dlgCell(++row, 2, row, 4) dlgPushButton("ENTER") { + set_accum(m_entry); + m_result = m_entry; + m_entry = ""; + dlgRedisplay(); + } + + dlgCell(row, 6) dlgPushButton("Help") { + dlgMessageBox("

    Help for the RPN Calculator

    " + "RPN stands for Reverse Polish Notation.
    " + "The calculator has a number in the Result line.
    " + "You enter a number in the Entry line, then select an operation, " + "like add, subtract, etc. The answer of that operation will be " + "put into the Result line, ready for a new operation.

    " + "Here is an example:" + "Let's say you have a part and you want to drill a hole on a circle " + "with a 5" radius, 37° counter-clockwise " + "from the center at X=1.2, Y=2.4.
    " + "Enter the following:
    " + "37 [sin]
    " + "5 [*]
    " + "1.2 [+]
    " + "The answer is 4.209. That is the Y coordinate
    " + "37 [cos]
    " + "5 [*]
    " + "2.4 [+]
    " + "The answer is 6.393, that is the X coordinate

    " + "I guess that is a complex example :-)" + ); + } + + } +} \ No newline at end of file diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin.h b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin.h new file mode 100644 index 00000000..4f690d1b --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/calculator.plugin.h @@ -0,0 +1,297 @@ +/********************************************************** + * + * A basic calculator. + * + * Plugin Definitions + * NAME = calculator + * DESC = Basic calculator + * AUTHOR = John Johnson + * TAB_NAME = Plugins + **********************************************************/ + +int UNARY_BEGIN = 0x80; +int ANGLE_IN = 0x40; +int ANGLE_OUT = 0x20; + +enum { + OP_INVALID, + OP_CLEAR, + OP_ENTER, + OP_ADD, + OP_SUBTRACT, + OP_DIVIDE, + OP_MULTIPLY, + OP_RADIAN, + OP_DEGREE +}; + +enum { + OP_MEMORY_PLUS = 0x80 /* UNARY_BEGIN */, + OP_MEMORY_STORE, + OP_MEMORY_RECALL, + OP_MEMORY_CLEAR +}; + +enum { + OP_SINE = 0xC0 /* UNARY_BEGIN + ANGLE_IN */, + OP_COSINE, + OP_TANGENT, + OP_ARC_SINE, + OP_ARC_COSINE, + OP_ARC_TANGENT +}; + +enum { + OP_INV_SINE = 0xA0 /* UNARY_BEGIN + ANGLE_OUT */, + OP_INV_COSINE, + OP_INV_TANGENT +}; + +enum { + ANG_INVALID, + ANG_RADIAN, + ANG_DEGREE + /* ANG_GRADIANS - sorry */ +}; + +int m_angle_mode; +string g_angle_mode_str; +int g_memory; + +real accum; +real depth; +int passes; +string nc_file; +int unit_metric; +real length; +string result; + +string m_result = "0"; +string m_entry = "0"; + +string format_number(real n) +{ + string tmp; + + sprintf(tmp, "%f", n); + return tmp; + +} + +real set_accum(string s) +{ + accum = strtod(s); + return accum; +} + +string set_result(real r) +{ + m_result = format_number(r); +// set_nv_param("calc_result", m_result); + return m_result; +} + +real set_angle_mode(int mode) +{ + real result; + string num; + int used_entry; + + result = strtod(m_result); + + if (m_entry != "") { + num = m_entry; + used_entry = 1; + } + else if (m_result != "") { + num = m_result; + } + else { + num = m_result; + } + + if (m_angle_mode == ANG_DEGREE && mode == ANG_RADIAN) { + result = strtod(num) / 180 * PI; + } + else if (m_angle_mode == ANG_RADIAN && mode == ANG_DEGREE) { + result = strtod(num) / PI * 180; + } + m_angle_mode = mode; + + switch (m_angle_mode) { + case ANG_RADIAN: + g_angle_mode_str = "rad"; + break; + case ANG_DEGREE: + g_angle_mode_str = "deg"; + break; + } + +// set_nv_param("calc_angle_mode", g_angle_mode_str); + +// if (used_entry) { + m_entry = format_number(result); +// } +// else { + set_result(result); +// }*/ + return result; +} + +string get_mode_str() +{ + return (m_angle_mode == ANG_RADIAN) ? "rad" : "deg"; +} + +real rad(real n) +{ + return (m_angle_mode == ANG_RADIAN) ? n : n / 180 * PI; +} + +real unrad(real n) +{ + return (m_angle_mode == ANG_RADIAN) ? n : n / PI * 180; +} + +int is_unary(int op) +{ + return (op & UNARY_BEGIN) ? 1 : 0; +} + +void set_memory(real n) +{ + string tmp; + + g_memory = n; +// set_nv_param("calc_memory", format_number(n)); +} + +real get_memory() +{ + return g_memory; +} + +void clear_memory() +{ + g_memory = 0; +} + +int m_entering; +void calc_enter(string n) +{ + if (!m_entering) { + m_entry = n; + m_entering = 1; + } + else { + m_entry += n; + } +} + +real calc(string a, int OPERATION) +{ + real ra; + int no_clear; + + m_entering = 0; + + ra = strtod(a); + if (m_entry == "" && m_result != "" && is_unary(OPERATION)) + ra = strtod(m_result); + + if (OPERATION & ANGLE_IN) { + ra = rad(ra); + } + + switch(OPERATION) { + case OP_ENTER: + accum = ra; + set_result(accum); + break; + case OP_ADD: + accum = accum + ra; + break; + case OP_SUBTRACT: + accum = accum - ra; + break; + case OP_DIVIDE: + accum = accum / ra; + break; + case OP_MULTIPLY: + accum = accum * ra; + break; + case OP_DEGREE: + accum = set_angle_mode(ANG_DEGREE); + break; + case OP_RADIAN: + accum = set_angle_mode(ANG_RADIAN); + break; + + case OP_MEMORY_PLUS: + set_memory(ra + get_memory()); + accum = ra; + break; + case OP_MEMORY_STORE: + set_memory(ra); + accum = ra; + break; + case OP_MEMORY_RECALL: + m_entry = format_number(get_memory()); + no_clear = 1; + accum = ra; + break; + case OP_MEMORY_CLEAR: + clear_memory(); + accum = ra; + break; + + case OP_COSINE: + accum = cos(ra); + break; + case OP_SINE: + accum = sin(ra); + break; + case OP_TANGENT: + accum = tan(ra); + break; + + case OP_ARC_COSINE: + accum = acos(ra); + break; + case OP_ARC_SINE: + accum = asin(ra); + break; + case OP_ARC_TANGENT: + accum = atan(ra); + break; + + case OP_CLEAR: + accum = 0; + break; + default: + dlgMessageBox("Invalid OPERATION"); + } + + if (OPERATION & ANGLE_OUT) { + accum = unrad(accum); + } + + set_result(accum); + if (!no_clear) m_entry = ""; + return accum; +} + +/********************************** + * Initialization. + **********************************/ + +set_angle_mode(ANG_DEGREE); + + +//~ set_memory(strtod(get_nv_param("calc_memory", "0.0", 0 /* don't abort */))); +//~ if (get_nv_param("calc_angle_mode", "deg", 0 /* don't abort */) == "deg") +//~ set_angle_mode(ANG_DEGREE); +//~ else +//~ set_angle_mode(ANG_RADIAN); +//~ set_result(strtod(get_nv_param("calc_result", "0.0", 0 /* don't abort */))); + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/filenames.plugin b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/filenames.plugin new file mode 100644 index 00000000..db5ce481 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/filenames.plugin @@ -0,0 +1,32 @@ +dlgGroup("File Naming") { + dlgHBoxLayout { + dlgLabel("Filename Base "); dlgStringEdit(FILENAME_BASE); + } + dlgGroup("Top (Component) Side Files") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Etching "); + dlgCell(1, 1) dlgStringEdit(FILENAME_TOP_ETCH_FILE); + dlgCell(2, 0) dlgLabel("Drill "); + dlgCell(2, 1) dlgStringEdit(FILENAME_TOP_DRILL_FILE); + dlgCell(3, 0) dlgLabel("Mill "); + dlgCell(3, 1) dlgStringEdit(FILENAME_TOP_MILL_FILE); + dlgCell(4, 0) dlgLabel("Fill "); + dlgCell(4, 1) dlgStringEdit(FILENAME_TOP_FILL_FILE); + } + } + dlgGroup("Bottom (Solder) Side Files") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Etching "); + dlgCell(1, 1) dlgStringEdit(FILENAME_BOT_ETCH_FILE); + dlgCell(2, 0) dlgLabel("Drill "); + dlgCell(2, 1) dlgStringEdit(FILENAME_BOT_DRILL_FILE); + dlgCell(3, 0) dlgLabel("Mill "); + dlgCell(3, 1) dlgStringEdit(FILENAME_BOT_MILL_FILE); + dlgCell(4, 0) dlgLabel("Fill "); + dlgCell(4, 1) dlgStringEdit(FILENAME_BOT_FILL_FILE); + } + } + dlgPushButton("Test Filenames") { + dlgMessageBox("Test"); + } +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_headers.h b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_headers.h new file mode 100644 index 00000000..3cc01ef2 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_headers.h @@ -0,0 +1,4 @@ +#include "nonvolatile.h" + +#include "plugins/calculator.plugin.h" + \ No newline at end of file diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_loader.h b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_loader.h new file mode 100644 index 00000000..b668c2ea --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/plugin_loader.h @@ -0,0 +1,40 @@ +/* + * Generate g-code for milling PC boards. + * + * Copyright 2004-2009 by John Johnson Software, LLC. + * See readme.html for copyright information. + * + */ + +// BEGIN_PLUGIN_INCLUDES +dlgVBoxLayout { + dlgHBoxLayout { +/* dlgVBoxLayout { + dlgGroup("Square X and Y (doesn't do anything)") { + #include "square_x_and_y.plugin" + } + dlgStretch(1); + } + dlgVBoxLayout { + dlgGroup("Square Z") { + #include "square_z.plugin" + } + dlgStretch(1); + } + dlgVBoxLayout { + dlgGroup("Filenames") { + #include "filenames.plugin" + } + dlgStretch(1); + }*/ + } + dlgHBoxLayout { + dlgStretch(1); + dlgVBoxLayout { + #include "calculator.plugin" + } + dlgStretch(1); + } + dlgStretch(1); +} +// END_PLUGIN_INCLUDES diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_x_and_y.plugin b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_x_and_y.plugin new file mode 100644 index 00000000..a06135d5 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_x_and_y.plugin @@ -0,0 +1,37 @@ +//Square X Y/Helps you square the X and Y axes of your machine./john + +/********************************************************** + * + * Diagnostic to help people square their machines in + * the X and Y axes. + * + * Plugin Definitions + * NAME = square X and Y + * DESC = Helps a user square their machine. + * AUTHOR = John Johnson + * TAB_NAME = Plugins + **********************************************************/ +real depth; +int passes; +string nc_file; +int unit_metric; +real length; +string result; + +dlgGridLayout { + dlgCell(0, 0, 0, 3) { + dlgCheckBox("Use Metric", unit_metric) { dlgRedisplay(); } + } + dlgCell(1, 0) { dlgLabel("Length"); dlgRealEdit(length); } + dlgCell(2, 0) { dlgLabel("Passes"); dlgIntEdit(passes); } + dlgCell(3, 0) { dlgLabel("Depth"); dlgRealEdit(depth); } + dlgCell(4, 0) { dlgLabel("NC File"); dlgStringEdit(nc_file); + dlgPushButton("...") { + nc_file = dlgFileSave("Save gcode as..."); + } + } + dlgCell(1,1) { + sprintf(result, "tan(45) = %f", tan(PI / 4)); + dlgLabel(result, 1); + } +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_z.plugin b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_z.plugin new file mode 100644 index 00000000..7bacb7a6 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/plugins/square_z.plugin @@ -0,0 +1,15 @@ +//Square X Y/Helps you square the X and Y axes of your machine./john + +/********************************************************** + * + * Diagnostic to help people square their machines in + * the X and Y axes. + * + * Plugin Definitions + * NAME = square X and Y + * DESC = Helps a user square their machine. + * AUTHOR = John Johnson + * TAB_NAME = Plugins + **********************************************************/ + +dlgLabel("Nice layout here"); diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/emc.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/emc.pp new file mode 100644 index 00000000..15156481 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/emc.pp @@ -0,0 +1,125 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. +// +// author=John Johnson +// description=EMC +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string FORMAT = "%-6.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.2f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + COMMENT_BEGIN + FORMAT + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/generic.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/generic.pp new file mode 100644 index 00000000..5982cb04 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/generic.pp @@ -0,0 +1,130 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. +// +// author=John Johnson +// description=Tries to be very compatible +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string FORMAT = "%-6.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.2f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// Not using G82 so it will be very generic. +// +string DRILL_CODE = ";( G82 not used )"; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; + +string DRILL_FIRST_HOLE = RAPID + "Z" + real_to_string(DEFAULT_Z_UP) + EOL + + RAPID + MOVE_XY + EOL + + FEED + MOVE_Z + FR_FORMAT + EOL + + FEED + "Z" + real_to_string(DEFAULT_Z_UP) + EOL + + COMMENT_BEGIN + RELEASE_PLANE + " " + DWELL_TIME + COMMENT_END + EOL; + +string DRILL_HOLE = COMMENT_BEGIN + RAPID + "Z" + real_to_string(DEFAULT_Z_UP) + COMMENT_END + EOL + + RAPID + MOVE_XY + EOL + + FEED + "Z" + real_to_string(DRILL_DEPTH) + EOL + + FEED + "Z" + real_to_string(DEFAULT_Z_UP) + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + TOOL_CODE + " " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " " + TOOL_INCH_FORMAT + " " + TOOL_INCH_FORMAT + " " + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/isel.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/isel.pp new file mode 100644 index 00000000..44f6ec94 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/isel.pp @@ -0,0 +1,124 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. +// +// author=John Johnson +// description=iSel +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string FORMAT = "%-6.0f "; /* coordinate format */ +string FR_FORMAT = "F%-5.0f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; +string EOL = "\n"; /* standard line ending */ +string PARAM = "#"; /* some use P, some # for parameters */ +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "FASTABS "; +string FEED = "MOVEABS "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "SPINDLE ON" + EOL + DWELL; +string SPINDLE_OFF = "SPINDLE OFF" + EOL; +string END_PROGRAM = "PROGEND" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/mach.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/mach.pp new file mode 100644 index 00000000..fdef4222 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/mach.pp @@ -0,0 +1,126 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. + +// +// author=John Johnson +// description=Mach3 - EMC for Windows +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +string FORMAT = "%-7.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.0f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; + +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/profiles/turbocnc.pp b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/turbocnc.pp new file mode 100644 index 00000000..b18e69dc --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/profiles/turbocnc.pp @@ -0,0 +1,126 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. + +// +// author=Art Eckstein +// description=TurboCNC +// + +int FILENAMES_8_CHARACTERS = YES; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string FORMAT = "%-6.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.2f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/rakefile.rb b/trunk/ulp/pcb-gcode-3.6.0.4/rakefile.rb new file mode 100644 index 00000000..4d88ca6b --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/rakefile.rb @@ -0,0 +1,82 @@ +# _*_ Mode: Ruby -*- +# +# Rakefile for pcb-gcode. +# +require 'pp' +require 'rake/clean' + +# this will be improved later +PCB_GCODE_VERSION = "3.6.0.4" + +RELEASE_FILE = "~/Documents/pcb-gcode-#{PCB_GCODE_VERSION}.zip" + +ignore_files = ['pcb_gcode_is_setup', '*.old', 'storage.nv', + 'make/*', 'make', 'make/', + '*.b#*', '*.s#*', '*.l#*', + '*.DS_Store', 'optomize_me.txt', + '*.svn*', + 'docs/pcbgcode.aux', 'docs/pcbgcode.glo', 'docs/pcbgcode.gls', 'docs/pcbgcode.idx', + 'docs/pcbgcode.ilg', 'docs/pcbgcode.ind', 'docs/pcbgcode.lof', 'docs/pcbgcode.log', + 'docs/pcbgcode.lot', 'docs/pcbgcode.out', 'docs/pcbgcode.toc', + 'docs/figs/*' +] + +desc "Build the docs/pcbgcode.pdf file." +file 'docs/pcbgcode.pdf' => 'docs/pcbgcode.tex' do |t| + system "cd docs && pdflatex pcbgcode" + system "cd docs && makeindex pcbgcode" + system "cd docs && pdflatex pcbgcode" + system "cd docs && pdflatex pcbgcode" +end + +desc "Create the .zip file to be released." +task :release_file do + zip_cmd = "rm ../pcb-gcode-#{PCB_GCODE_VERSION}.zip" + system(zip_cmd) + zip_cmd = "zip -r ../pcb-gcode-#{PCB_GCODE_VERSION}.zip *" + zip_cmd += ' -x ' + zip_cmd += ignore_files.join(' -x ') + system(zip_cmd) + zip_cmd = "unzip ../pcb-gcode-#{PCB_GCODE_VERSION} -d ../pcb-gcode-#{PCB_GCODE_VERSION}" + system(zip_cmd) + zip_cmd = "rm ~/Documents/pcb-gcode-#{PCB_GCODE_VERSION}.zip" + system(zip_cmd) + zip_cmd = "cd .. && zip -r ~/Documents/pcb-gcode-#{PCB_GCODE_VERSION}.zip pcb-gcode-#{PCB_GCODE_VERSION}" + system(zip_cmd) +end + +desc "Copy current settings/* files to the safe_options folder." +task :safe_options do + SAFE_OPTIONS = ['pcb-defaults', 'pcb-machine', 'pcb-gcode-options', 'user-gcode'] + SAFE_OPTIONS.each do |name| + cp 'settings/' + name + '.h', 'safe_options/' + name + '.release.h' + end +end + +desc "Recreate data folders for viewers. Usually after re-exporting from Processing." +task :fix_viewers do + system("cp -R viewer/data viewer/applet") + system("cp -R viewer/data viewer/application.linux/") + system("cp -R viewer/data viewer/application.macosx/") + system("cp -R viewer/data viewer/application.windows/") +end + +desc "Write the convert units function in pcb-gcode-setup.ulp." +task :write_convert_units do + system("make/write_convert_units.rb") +end + +desc "Be sure the build isn't happening from a working svn directory." +task :check_svn do + if File.exist?('.svn') + abort("Cannot build with .svn files present.") + end +end + +CLOBBER.include('docs/pcbgcode.aux', 'docs/pcbgcode.glo', 'docs/pcbgcode.gls', 'docs/pcbgcode.idx', + 'docs/pcbgcode.ilg', 'docs/pcbgcode.ind', 'docs/pcbgcode.lof', 'docs/pcbgcode.log', + 'docs/pcbgcode.lot', 'docs/pcbgcode.out', 'docs/pcbgcode.toc' +) + +task :default => [:check_svn, 'docs/pcbgcode.pdf', :fix_viewers, :safe_options, :write_convert_units, :release_file] do +end diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.h new file mode 100644 index 00000000..f532f869 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.h @@ -0,0 +1,38 @@ +// +// Default values for generating gcode from a PCB. +// +// These settings were last changed with pcb-gcode-setup: 2/8/09 5:28 PM +// +// +// Changes you make in this file will be overwritten if you use pcb-gcode-setup. +// + +real ISO_MIN = 0.001000; +real ISO_MAX = 0.020000; +real ISO_STEP = 0.005000; + +int GENERATE_TOP_OUTLINES = NO; +int GENERATE_TOP_DRILL = NO; +int GENERATE_TOP_FILL = NO; + +int GENERATE_BOTTOM_OUTLINES = YES; +int GENERATE_BOTTOM_DRILL = YES; +int GENERATE_BOTTOM_FILL = NO; +int MIRROR_BOTTOM = NO; +int SIMPLE_DRILL_CODE = YES; + +int GENERATE_MILLING = NO; + +int GENERATE_TEXT = NO; + +int SPOT_DRILL = YES; +real SPOT_DRILL_DEPTH = -0.011000; + +int DO_TOOL_CHANGE_WITH_ZERO_STEP = NO; + +int FLIP_BOARD_IN_Y = NO; + +//int OUTPUT_UNITS = U_MICRONS; +//int OUTPUT_UNITS = U_MILLIMETERS; +//int OUTPUT_UNITS = U_MILS; +int OUTPUT_UNITS = U_INCHES; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.release.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.release.h new file mode 100644 index 00000000..80fcc9e1 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-defaults.release.h @@ -0,0 +1,39 @@ +// +// Default values for generating gcode from a PCB. +// +// These settings were last changed with pcb-gcode-setup: 12/28/12 11:21 PM +// +// +// Changes you make in this file will be overwritten if you use pcb-gcode-setup. +// + +int SINGLE_PASS = NO; +real ISO_MIN = 0.001000; +real ISO_MAX = 0.020000; +real ISO_STEP = 0.005000; + +int GENERATE_TOP_OUTLINES = NO; +int GENERATE_TOP_DRILL = NO; +int GENERATE_TOP_FILL = NO; + +int GENERATE_BOTTOM_OUTLINES = YES; +int GENERATE_BOTTOM_DRILL = YES; +int GENERATE_BOTTOM_FILL = NO; +int MIRROR_BOTTOM = NO; +int SIMPLE_DRILL_CODE = NO; + +int GENERATE_MILLING = NO; + +int GENERATE_TEXT = NO; + +int SPOT_DRILL = YES; +real SPOT_DRILL_DEPTH = -0.011000; + +int DO_TOOL_CHANGE_WITH_ZERO_STEP = YES; + +int FLIP_BOARD_IN_Y = NO; + +//int OUTPUT_UNITS = U_MICRONS; +//int OUTPUT_UNITS = U_MILLIMETERS; +//int OUTPUT_UNITS = U_MILS; +int OUTPUT_UNITS = U_INCHES; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.h new file mode 100644 index 00000000..e07e6cb5 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.h @@ -0,0 +1,34 @@ +// +// General Options // Your edits to this file will be overwritten by the setup program. +// +int SHOW_PROGRESS = NO; +string RESTORE_MENU_FILE = "pcb-gcode-menu.scr"; +int NC_FILE_COMMENT_FROM_BOARD = YES; +int NC_FILE_COMMENT_DATE = YES; +int NC_FILE_COMMENT_MACHINE_SETTINGS = NO; +int NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS = NO; +int USER_GCODE = NO; +int g_debug_flag = NO; +int COMPACT_GCODE = NO; +int USE_LINE_NUMBERS = NO; +string LINE_NUMBER_FORMAT = "N%05d "; +int SHOW_PREVIEW = YES; +string FILENAME_BASE = "$BOARD_PATH/$BOARD_NAME"; +string FILENAME_TOP_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_FILL_FILE = ""; +string FILENAME_BOT_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_FILL_FILE = ""; +string ETCH_FILE_NAME = "etch"; +string DRILL_FILE_NAME = "drill"; +string MILL_FILE_NAME = "mill"; +string TEXT_FILE_NAME = "text"; +string TOP_FILE_NAME = "top"; +string BOT_FILE_NAME = "bot"; +string DEFAULT_EXTENSION = "tap"; +string DEFAULT_DRILL_FILE = ""; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.release.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.release.h new file mode 100644 index 00000000..a173fe4c --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-gcode-options.release.h @@ -0,0 +1,34 @@ +// +// General Options // Your edits to this file will be overwritten by the setup program. +// +int SHOW_PROGRESS = NO; +string RESTORE_MENU_FILE = "pcb-gcode-menu.scr"; +int NC_FILE_COMMENT_FROM_BOARD = YES; +int NC_FILE_COMMENT_DATE = YES; +int NC_FILE_COMMENT_MACHINE_SETTINGS = YES; +int NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS = YES; +int USER_GCODE = NO; +int g_debug_flag = YES; +int COMPACT_GCODE = NO; +int USE_LINE_NUMBERS = NO; +string LINE_NUMBER_FORMAT = "N%05d "; +int SHOW_PREVIEW = YES; +string FILENAME_BASE = "$BOARD_PATH/$BOARD_NAME"; +string FILENAME_TOP_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_FILL_FILE = ""; +string FILENAME_BOT_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_FILL_FILE = ""; +string ETCH_FILE_NAME = "etch"; +string DRILL_FILE_NAME = "drill"; +string MILL_FILE_NAME = "mill"; +string TEXT_FILE_NAME = "text"; +string TOP_FILE_NAME = "top"; +string BOT_FILE_NAME = "bot"; +string DEFAULT_EXTENSION = "tap"; +string DEFAULT_DRILL_FILE = ""; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.h new file mode 100644 index 00000000..e8b8e040 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.h @@ -0,0 +1,24 @@ +// +// For ease of use, and to avoid overwritting your settings, +// use pcb-gcode-setup to make changes to these settings. +// + +real DEFAULT_Z_HIGH = 0.500000; +real DEFAULT_Z_UP = 0.100000; +real DEFAULT_Z_DOWN = -0.007000; +real DRILL_DEPTH = -0.032000; +real DRILL_DWELL = 1.000000; +real SPINDLE_ON_TIME = 3.000000; +real MILLING_DEPTH = -0.010000; +real TEXT_DEPTH = -0.005000; +real TOOL_CHANGE_POS_X = 0.000000; +real TOOL_CHANGE_POS_Y = 0.000000; +real TOOL_CHANGE_POS_Z = 0.000000; +real FEED_RATE = 20.000000; +real FEED_RATE_Z = 10.000000; +real DEFAULT_WIDTH = 0.007000; +real X_OFFSET = 0.000000; +real Y_OFFSET = 0.000000; +real X_HOME = 0.000000; +real Y_HOME = 0.000000; +real EPSILON = 0.000100; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.release.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.release.h new file mode 100644 index 00000000..309340e2 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/pcb-machine.release.h @@ -0,0 +1,24 @@ +// +// For ease of use, and to avoid overwritting your settings, +// use pcb-gcode-setup to make changes to these settings. +// + +real DEFAULT_Z_HIGH = 0.500000; +real DEFAULT_Z_UP = 0.100000; +real DEFAULT_Z_DOWN = -0.007000; +real DRILL_DEPTH = -0.032000; +real DRILL_DWELL = 1.000000; +real SPINDLE_ON_TIME = 3.000000; +real MILLING_DEPTH = -0.010000; +real TEXT_DEPTH = -0.005000; +real TOOL_CHANGE_POS_X = 0.500000; +real TOOL_CHANGE_POS_Y = 0.600000; +real TOOL_CHANGE_POS_Z = 1.000000; +real FEED_RATE = 20.000000; +real FEED_RATE_Z = 10.000000; +real DEFAULT_WIDTH = 0.007000; +real X_OFFSET = 0.000000; +real Y_OFFSET = 0.000000; +real X_HOME = 0.000000; +real Y_HOME = 0.000000; +real EPSILON = 0.000100; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.h new file mode 100644 index 00000000..564cfe5c --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.h @@ -0,0 +1,236 @@ +// +// Define your own gcode sequences in this file. +// +// The settings are listed from most general, to most specific. The settings +// at the top of this file go into every file created, while the settings +// at the end of this file have to do with tool changes only. +// +// Note that each line ends with \n this is Geek Speak for newline. +// In other words, it's like hitting the Enter key at the end of a line. +// Notice also that the lines have a ; at the end. +// +// See the bottom of this file for an example of using multiple lines. +// + +// Inserted into bottom, top or all files. +string FILE_BEGIN[] = { "", "", "", "" }; +string FILE_END[] = { "", "", "", "" }; + +FILE_BEGIN[ALL] = "(Beginning of every file)\n"; +FILE_END[ALL] = "(End of every file)\n"; + +FILE_BEGIN[BOTTOM] = "(Beginning of every bottom file)\n"; +FILE_END[BOTTOM] = "(End of every bottom file)\n"; + +FILE_BEGIN[TOP] = "(Beginning of every top file)\n"; +FILE_END[TOP] = "(End of every top file)\n"; + +// Inserted into outline files (track milling). +string OUTLINE_BEGIN[] = { "", "", "", "" }; +string OUTLINE_BETWEEN[] = { "", "", "", "" }; +string OUTLINE_END[] = { "", "", "", "" }; + +OUTLINE_BEGIN[ALL] = "(Outline Begin)\n"; +OUTLINE_BETWEEN[ALL] = "(Between Passes)\n"; +OUTLINE_END[ALL] = "(Outline End)\n"; + +OUTLINE_BEGIN[BOTTOM] = "(Bottom outline Begin)\n"; +OUTLINE_BETWEEN[BOTTOM] = "(Bottom between passes)\n"; +OUTLINE_END[BOTTOM] = "(Bottom outline End)\n"; + +OUTLINE_BEGIN[TOP] = "(Top outline Begin)\n"; +OUTLINE_BETWEEN[TOP] = "(Top between passes)\n"; +OUTLINE_END[TOP] = "(Top outline End)\n"; + +// Inserted into drill files. +string DRILL_BEGIN[] = { "", "", "", "" }; +string DRILL_END[] = { "", "", "", "" }; + +DRILL_BEGIN[ALL] = "(Beginning of All Drill files)\n"; +DRILL_END[ALL] = "(End of all Drill Files)\n"; + +DRILL_BEGIN[BOTTOM] = "(Bottom Drill Begin)\n"; +DRILL_END[BOTTOM] = "(Bottom Drill End)\n"; + +DRILL_BEGIN[TOP] = "(Top Drill Begin)\n"; +DRILL_END[TOP] = "(Top Drill End)\n"; + +// Inserted into fill files. +string FILL_BEGIN[] = { "", "", "", "" }; +string FILL_END[] = { "", "", "", "" }; + +FILL_BEGIN[ALL] = "(Fill Begin)\n"; +FILL_END[ALL] = "(Fill End)\n"; + +FILL_BEGIN[BOTTOM] = "(Bottom Fill Begin)\n"; +FILL_END[BOTTOM] = "(Bottom Fill End)\n"; + +FILL_BEGIN[TOP] = "(Top Fill Begin)\n"; +FILL_END[TOP] = "(Top Fill End)\n"; + +// Inserted into milling files. +string MILL_BEGIN[] = { "", "", "", "" }; +string MILL_END[] = { "", "", "", "" }; + +MILL_BEGIN[ALL] = "(MILL Begin)\n"; +MILL_END[ALL] = "(MILL End)\n"; + +MILL_BEGIN[BOTTOM] = "(Bottom MILL Begin)\n"; +MILL_END[BOTTOM] = "(Bottom MILL End)\n"; + +MILL_BEGIN[TOP] = "(Top MILL Begin)\n"; +MILL_END[TOP] = "(Top MILL End)\n"; + +// Tool change code. +string TOOL_CHANGE_BEGIN[] = { "", "", "", "" }; +string TOOL_CHANGED[] = { "", "", "", "" }; +string TOOL_ZERO_BEGIN[] = { "", "", "", "" }; +string TOOL_ZERO_END[] = { "", "", "", "" }; +string TOOL_CHANGE_END[] = { "", "", "", "" }; + +TOOL_CHANGE_BEGIN[ALL] = "(Tool Change Begin)\n"; +TOOL_CHANGED[ALL] = "(Tool changed)\n"; +TOOL_ZERO_BEGIN[ALL] = "(Tool zero begin)\n"; +TOOL_ZERO_END[ALL] = "(Tool zero end)\n"; +TOOL_CHANGE_END[ALL] = "(Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[BOTTOM] = "(Bottom Tool Change Begin)\n"; +TOOL_CHANGED[BOTTOM] = "(Bottom Tool changed)\n"; +TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n"; +TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n"; +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n"; +TOOL_CHANGED[TOP] = "(Top Tool changed)\n"; +TOOL_ZERO_BEGIN[TOP] = "(Top Tool zero begin)\n"; +TOOL_ZERO_END[TOP] = "(Top Tool zero end)\n"; +TOOL_CHANGE_END[TOP] = "(Top Tool Changed End)\n"; + +// +// An example of using more than one line of gcode. +// Note that only the last line has a ; at the end. +// +string THIS_ISNT_USED[] = { "", "", "", "" }; // Don't change lines like this +THIS_ISNT_USED[BOTTOM] = "G20\n" + "G90\n" + "G01 Z0\n" + "G00 X0 Y0\n" + "M06 T2 ; 0.060\n" + "G04 P5\n"; + +/* + * The functions below should make it easier for folks outputing their own code, etc. + * + */ + +/* + * Called after the gcode file has been opened. + * Mode can be + * "wt" (write a text file) when the file is first opened. + * "at" (append a text file) if the file is added to. + * + * You might want to check g_side to see which "side" you are working on. + * g_side can be TOP, BOTTOM or MILL. + * + */ +void user_file_opened(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just before the gcode file is closed. + * + */ +void user_file_closing() +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just after the gcode file is closed. + * See user_file_opened for information on the mode parameter. + * + */ +void user_file_closed(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of the outline of a track. + * + */ +void user_track_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * An intermediate point on the outline of a track. + * + */ +int user_coord_cnt; +void user_track_continue(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of the outline of a track. + * + */ +void user_track_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of an arc. + * + */ +void user_arc_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of an arc. + * + */ +void user_arc_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.release.h b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.release.h new file mode 100644 index 00000000..564cfe5c --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/safe_options/user-gcode.release.h @@ -0,0 +1,236 @@ +// +// Define your own gcode sequences in this file. +// +// The settings are listed from most general, to most specific. The settings +// at the top of this file go into every file created, while the settings +// at the end of this file have to do with tool changes only. +// +// Note that each line ends with \n this is Geek Speak for newline. +// In other words, it's like hitting the Enter key at the end of a line. +// Notice also that the lines have a ; at the end. +// +// See the bottom of this file for an example of using multiple lines. +// + +// Inserted into bottom, top or all files. +string FILE_BEGIN[] = { "", "", "", "" }; +string FILE_END[] = { "", "", "", "" }; + +FILE_BEGIN[ALL] = "(Beginning of every file)\n"; +FILE_END[ALL] = "(End of every file)\n"; + +FILE_BEGIN[BOTTOM] = "(Beginning of every bottom file)\n"; +FILE_END[BOTTOM] = "(End of every bottom file)\n"; + +FILE_BEGIN[TOP] = "(Beginning of every top file)\n"; +FILE_END[TOP] = "(End of every top file)\n"; + +// Inserted into outline files (track milling). +string OUTLINE_BEGIN[] = { "", "", "", "" }; +string OUTLINE_BETWEEN[] = { "", "", "", "" }; +string OUTLINE_END[] = { "", "", "", "" }; + +OUTLINE_BEGIN[ALL] = "(Outline Begin)\n"; +OUTLINE_BETWEEN[ALL] = "(Between Passes)\n"; +OUTLINE_END[ALL] = "(Outline End)\n"; + +OUTLINE_BEGIN[BOTTOM] = "(Bottom outline Begin)\n"; +OUTLINE_BETWEEN[BOTTOM] = "(Bottom between passes)\n"; +OUTLINE_END[BOTTOM] = "(Bottom outline End)\n"; + +OUTLINE_BEGIN[TOP] = "(Top outline Begin)\n"; +OUTLINE_BETWEEN[TOP] = "(Top between passes)\n"; +OUTLINE_END[TOP] = "(Top outline End)\n"; + +// Inserted into drill files. +string DRILL_BEGIN[] = { "", "", "", "" }; +string DRILL_END[] = { "", "", "", "" }; + +DRILL_BEGIN[ALL] = "(Beginning of All Drill files)\n"; +DRILL_END[ALL] = "(End of all Drill Files)\n"; + +DRILL_BEGIN[BOTTOM] = "(Bottom Drill Begin)\n"; +DRILL_END[BOTTOM] = "(Bottom Drill End)\n"; + +DRILL_BEGIN[TOP] = "(Top Drill Begin)\n"; +DRILL_END[TOP] = "(Top Drill End)\n"; + +// Inserted into fill files. +string FILL_BEGIN[] = { "", "", "", "" }; +string FILL_END[] = { "", "", "", "" }; + +FILL_BEGIN[ALL] = "(Fill Begin)\n"; +FILL_END[ALL] = "(Fill End)\n"; + +FILL_BEGIN[BOTTOM] = "(Bottom Fill Begin)\n"; +FILL_END[BOTTOM] = "(Bottom Fill End)\n"; + +FILL_BEGIN[TOP] = "(Top Fill Begin)\n"; +FILL_END[TOP] = "(Top Fill End)\n"; + +// Inserted into milling files. +string MILL_BEGIN[] = { "", "", "", "" }; +string MILL_END[] = { "", "", "", "" }; + +MILL_BEGIN[ALL] = "(MILL Begin)\n"; +MILL_END[ALL] = "(MILL End)\n"; + +MILL_BEGIN[BOTTOM] = "(Bottom MILL Begin)\n"; +MILL_END[BOTTOM] = "(Bottom MILL End)\n"; + +MILL_BEGIN[TOP] = "(Top MILL Begin)\n"; +MILL_END[TOP] = "(Top MILL End)\n"; + +// Tool change code. +string TOOL_CHANGE_BEGIN[] = { "", "", "", "" }; +string TOOL_CHANGED[] = { "", "", "", "" }; +string TOOL_ZERO_BEGIN[] = { "", "", "", "" }; +string TOOL_ZERO_END[] = { "", "", "", "" }; +string TOOL_CHANGE_END[] = { "", "", "", "" }; + +TOOL_CHANGE_BEGIN[ALL] = "(Tool Change Begin)\n"; +TOOL_CHANGED[ALL] = "(Tool changed)\n"; +TOOL_ZERO_BEGIN[ALL] = "(Tool zero begin)\n"; +TOOL_ZERO_END[ALL] = "(Tool zero end)\n"; +TOOL_CHANGE_END[ALL] = "(Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[BOTTOM] = "(Bottom Tool Change Begin)\n"; +TOOL_CHANGED[BOTTOM] = "(Bottom Tool changed)\n"; +TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n"; +TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n"; +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n"; +TOOL_CHANGED[TOP] = "(Top Tool changed)\n"; +TOOL_ZERO_BEGIN[TOP] = "(Top Tool zero begin)\n"; +TOOL_ZERO_END[TOP] = "(Top Tool zero end)\n"; +TOOL_CHANGE_END[TOP] = "(Top Tool Changed End)\n"; + +// +// An example of using more than one line of gcode. +// Note that only the last line has a ; at the end. +// +string THIS_ISNT_USED[] = { "", "", "", "" }; // Don't change lines like this +THIS_ISNT_USED[BOTTOM] = "G20\n" + "G90\n" + "G01 Z0\n" + "G00 X0 Y0\n" + "M06 T2 ; 0.060\n" + "G04 P5\n"; + +/* + * The functions below should make it easier for folks outputing their own code, etc. + * + */ + +/* + * Called after the gcode file has been opened. + * Mode can be + * "wt" (write a text file) when the file is first opened. + * "at" (append a text file) if the file is added to. + * + * You might want to check g_side to see which "side" you are working on. + * g_side can be TOP, BOTTOM or MILL. + * + */ +void user_file_opened(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just before the gcode file is closed. + * + */ +void user_file_closing() +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just after the gcode file is closed. + * See user_file_opened for information on the mode parameter. + * + */ +void user_file_closed(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of the outline of a track. + * + */ +void user_track_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * An intermediate point on the outline of a track. + * + */ +int user_coord_cnt; +void user_track_continue(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of the outline of a track. + * + */ +void user_track_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of an arc. + * + */ +void user_arc_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of an arc. + * + */ +void user_arc_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/default.drl.txt b/trunk/ulp/pcb-gcode-3.6.0.4/settings/default.drl.txt new file mode 100644 index 00000000..537f1f02 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/default.drl.txt @@ -0,0 +1,27 @@ +# -*- Mode: Eagle -*- +# +# Sample drill rack file. +# +# drill_size is the size of the drill bit. +# minimum is the smallest hole the bit will be used for. +# maximum is the largest hole the bit will be used for. +# +# Each value can have a "unit of measure" added to it, +# such as 0.500mm . If you do not provide the unit of measure, +# values over 0.250 are considered millimeters, and +# values under 0.250 are considered inches. For example: +# 0.400 would be considered 0.400 mm. +# 0.125 would be considered 0.125 inches. +# +# Please note that you must use a TAB character +# between each setting on a line. +# +# Tip: Set the TAB size of your editor to 12 characters. +# +tool drill_size minimum maximum length +T01 0.500mm 0.000in 0.025in 1.5in +T02 0.032in 0.025in 0.035in 1.5in +T03 0.040in 0.035in 0.039in 1.5in +T04 0.050in 0.045in 0.055in 1.5in +T05 0.062in 0.055in 0.070in 1.5in +T06 0.125in 0.100in 0.125in 1.5in diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/gcode-defaults.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/gcode-defaults.h new file mode 100644 index 00000000..fdef4222 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/gcode-defaults.h @@ -0,0 +1,126 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. + +// +// author=John Johnson +// description=Mach3 - EMC for Windows +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +string FORMAT = "%-7.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.0f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; + +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-defaults.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-defaults.h new file mode 100644 index 00000000..80fcc9e1 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-defaults.h @@ -0,0 +1,39 @@ +// +// Default values for generating gcode from a PCB. +// +// These settings were last changed with pcb-gcode-setup: 12/28/12 11:21 PM +// +// +// Changes you make in this file will be overwritten if you use pcb-gcode-setup. +// + +int SINGLE_PASS = NO; +real ISO_MIN = 0.001000; +real ISO_MAX = 0.020000; +real ISO_STEP = 0.005000; + +int GENERATE_TOP_OUTLINES = NO; +int GENERATE_TOP_DRILL = NO; +int GENERATE_TOP_FILL = NO; + +int GENERATE_BOTTOM_OUTLINES = YES; +int GENERATE_BOTTOM_DRILL = YES; +int GENERATE_BOTTOM_FILL = NO; +int MIRROR_BOTTOM = NO; +int SIMPLE_DRILL_CODE = NO; + +int GENERATE_MILLING = NO; + +int GENERATE_TEXT = NO; + +int SPOT_DRILL = YES; +real SPOT_DRILL_DEPTH = -0.011000; + +int DO_TOOL_CHANGE_WITH_ZERO_STEP = YES; + +int FLIP_BOARD_IN_Y = NO; + +//int OUTPUT_UNITS = U_MICRONS; +//int OUTPUT_UNITS = U_MILLIMETERS; +//int OUTPUT_UNITS = U_MILS; +int OUTPUT_UNITS = U_INCHES; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-gcode-options.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-gcode-options.h new file mode 100644 index 00000000..a173fe4c --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-gcode-options.h @@ -0,0 +1,34 @@ +// +// General Options // Your edits to this file will be overwritten by the setup program. +// +int SHOW_PROGRESS = NO; +string RESTORE_MENU_FILE = "pcb-gcode-menu.scr"; +int NC_FILE_COMMENT_FROM_BOARD = YES; +int NC_FILE_COMMENT_DATE = YES; +int NC_FILE_COMMENT_MACHINE_SETTINGS = YES; +int NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS = YES; +int USER_GCODE = NO; +int g_debug_flag = YES; +int COMPACT_GCODE = NO; +int USE_LINE_NUMBERS = NO; +string LINE_NUMBER_FORMAT = "N%05d "; +int SHOW_PREVIEW = YES; +string FILENAME_BASE = "$BOARD_PATH/$BOARD_NAME"; +string FILENAME_TOP_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_FILL_FILE = ""; +string FILENAME_BOT_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_FILL_FILE = ""; +string ETCH_FILE_NAME = "etch"; +string DRILL_FILE_NAME = "drill"; +string MILL_FILE_NAME = "mill"; +string TEXT_FILE_NAME = "text"; +string TOP_FILE_NAME = "top"; +string BOT_FILE_NAME = "bot"; +string DEFAULT_EXTENSION = "tap"; +string DEFAULT_DRILL_FILE = ""; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-machine.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-machine.h new file mode 100644 index 00000000..309340e2 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/pcb-machine.h @@ -0,0 +1,24 @@ +// +// For ease of use, and to avoid overwritting your settings, +// use pcb-gcode-setup to make changes to these settings. +// + +real DEFAULT_Z_HIGH = 0.500000; +real DEFAULT_Z_UP = 0.100000; +real DEFAULT_Z_DOWN = -0.007000; +real DRILL_DEPTH = -0.032000; +real DRILL_DWELL = 1.000000; +real SPINDLE_ON_TIME = 3.000000; +real MILLING_DEPTH = -0.010000; +real TEXT_DEPTH = -0.005000; +real TOOL_CHANGE_POS_X = 0.500000; +real TOOL_CHANGE_POS_Y = 0.600000; +real TOOL_CHANGE_POS_Z = 1.000000; +real FEED_RATE = 20.000000; +real FEED_RATE_Z = 10.000000; +real DEFAULT_WIDTH = 0.007000; +real X_OFFSET = 0.000000; +real Y_OFFSET = 0.000000; +real X_HOME = 0.000000; +real Y_HOME = 0.000000; +real EPSILON = 0.000100; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/settings/user-gcode.h b/trunk/ulp/pcb-gcode-3.6.0.4/settings/user-gcode.h new file mode 100644 index 00000000..564cfe5c --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/settings/user-gcode.h @@ -0,0 +1,236 @@ +// +// Define your own gcode sequences in this file. +// +// The settings are listed from most general, to most specific. The settings +// at the top of this file go into every file created, while the settings +// at the end of this file have to do with tool changes only. +// +// Note that each line ends with \n this is Geek Speak for newline. +// In other words, it's like hitting the Enter key at the end of a line. +// Notice also that the lines have a ; at the end. +// +// See the bottom of this file for an example of using multiple lines. +// + +// Inserted into bottom, top or all files. +string FILE_BEGIN[] = { "", "", "", "" }; +string FILE_END[] = { "", "", "", "" }; + +FILE_BEGIN[ALL] = "(Beginning of every file)\n"; +FILE_END[ALL] = "(End of every file)\n"; + +FILE_BEGIN[BOTTOM] = "(Beginning of every bottom file)\n"; +FILE_END[BOTTOM] = "(End of every bottom file)\n"; + +FILE_BEGIN[TOP] = "(Beginning of every top file)\n"; +FILE_END[TOP] = "(End of every top file)\n"; + +// Inserted into outline files (track milling). +string OUTLINE_BEGIN[] = { "", "", "", "" }; +string OUTLINE_BETWEEN[] = { "", "", "", "" }; +string OUTLINE_END[] = { "", "", "", "" }; + +OUTLINE_BEGIN[ALL] = "(Outline Begin)\n"; +OUTLINE_BETWEEN[ALL] = "(Between Passes)\n"; +OUTLINE_END[ALL] = "(Outline End)\n"; + +OUTLINE_BEGIN[BOTTOM] = "(Bottom outline Begin)\n"; +OUTLINE_BETWEEN[BOTTOM] = "(Bottom between passes)\n"; +OUTLINE_END[BOTTOM] = "(Bottom outline End)\n"; + +OUTLINE_BEGIN[TOP] = "(Top outline Begin)\n"; +OUTLINE_BETWEEN[TOP] = "(Top between passes)\n"; +OUTLINE_END[TOP] = "(Top outline End)\n"; + +// Inserted into drill files. +string DRILL_BEGIN[] = { "", "", "", "" }; +string DRILL_END[] = { "", "", "", "" }; + +DRILL_BEGIN[ALL] = "(Beginning of All Drill files)\n"; +DRILL_END[ALL] = "(End of all Drill Files)\n"; + +DRILL_BEGIN[BOTTOM] = "(Bottom Drill Begin)\n"; +DRILL_END[BOTTOM] = "(Bottom Drill End)\n"; + +DRILL_BEGIN[TOP] = "(Top Drill Begin)\n"; +DRILL_END[TOP] = "(Top Drill End)\n"; + +// Inserted into fill files. +string FILL_BEGIN[] = { "", "", "", "" }; +string FILL_END[] = { "", "", "", "" }; + +FILL_BEGIN[ALL] = "(Fill Begin)\n"; +FILL_END[ALL] = "(Fill End)\n"; + +FILL_BEGIN[BOTTOM] = "(Bottom Fill Begin)\n"; +FILL_END[BOTTOM] = "(Bottom Fill End)\n"; + +FILL_BEGIN[TOP] = "(Top Fill Begin)\n"; +FILL_END[TOP] = "(Top Fill End)\n"; + +// Inserted into milling files. +string MILL_BEGIN[] = { "", "", "", "" }; +string MILL_END[] = { "", "", "", "" }; + +MILL_BEGIN[ALL] = "(MILL Begin)\n"; +MILL_END[ALL] = "(MILL End)\n"; + +MILL_BEGIN[BOTTOM] = "(Bottom MILL Begin)\n"; +MILL_END[BOTTOM] = "(Bottom MILL End)\n"; + +MILL_BEGIN[TOP] = "(Top MILL Begin)\n"; +MILL_END[TOP] = "(Top MILL End)\n"; + +// Tool change code. +string TOOL_CHANGE_BEGIN[] = { "", "", "", "" }; +string TOOL_CHANGED[] = { "", "", "", "" }; +string TOOL_ZERO_BEGIN[] = { "", "", "", "" }; +string TOOL_ZERO_END[] = { "", "", "", "" }; +string TOOL_CHANGE_END[] = { "", "", "", "" }; + +TOOL_CHANGE_BEGIN[ALL] = "(Tool Change Begin)\n"; +TOOL_CHANGED[ALL] = "(Tool changed)\n"; +TOOL_ZERO_BEGIN[ALL] = "(Tool zero begin)\n"; +TOOL_ZERO_END[ALL] = "(Tool zero end)\n"; +TOOL_CHANGE_END[ALL] = "(Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[BOTTOM] = "(Bottom Tool Change Begin)\n"; +TOOL_CHANGED[BOTTOM] = "(Bottom Tool changed)\n"; +TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n"; +TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n"; +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n"; +TOOL_CHANGED[TOP] = "(Top Tool changed)\n"; +TOOL_ZERO_BEGIN[TOP] = "(Top Tool zero begin)\n"; +TOOL_ZERO_END[TOP] = "(Top Tool zero end)\n"; +TOOL_CHANGE_END[TOP] = "(Top Tool Changed End)\n"; + +// +// An example of using more than one line of gcode. +// Note that only the last line has a ; at the end. +// +string THIS_ISNT_USED[] = { "", "", "", "" }; // Don't change lines like this +THIS_ISNT_USED[BOTTOM] = "G20\n" + "G90\n" + "G01 Z0\n" + "G00 X0 Y0\n" + "M06 T2 ; 0.060\n" + "G04 P5\n"; + +/* + * The functions below should make it easier for folks outputing their own code, etc. + * + */ + +/* + * Called after the gcode file has been opened. + * Mode can be + * "wt" (write a text file) when the file is first opened. + * "at" (append a text file) if the file is added to. + * + * You might want to check g_side to see which "side" you are working on. + * g_side can be TOP, BOTTOM or MILL. + * + */ +void user_file_opened(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just before the gcode file is closed. + * + */ +void user_file_closing() +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just after the gcode file is closed. + * See user_file_opened for information on the mode parameter. + * + */ +void user_file_closed(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of the outline of a track. + * + */ +void user_track_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * An intermediate point on the outline of a track. + * + */ +int user_coord_cnt; +void user_track_continue(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of the outline of a track. + * + */ +void user_track_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of an arc. + * + */ +void user_arc_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of an arc. + * + */ +void user_arc_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/drill.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/drill.h new file mode 100644 index 00000000..9d31bb0f --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/drill.h @@ -0,0 +1,193 @@ +// -*- Mode: Eagle -*- +// +// Drill routines. +// + +#include "nonvolatile.h" + +string TOOL_FLD = "tool"; +string DRILL_FLD = "drill_size"; +string MIN_FLD = "minimum"; +string MAX_FLD = "maximum"; +string LENGTH_FLD = "length"; +char DRILL_SEP = '\t'; +string g_rack[]; +int g_num_drills; +int g_drill_sub_cnt[]; +real g_mins[]; +real g_maxs[]; + +int m_shut_up; +int m_last_match; +int m_have_rack = false; +string m_rack_file_name = "?"; + +if (get_nv_param("drill_shut_up", "NO", NO) == "YES") { + m_shut_up = YES; +} +else { + m_shut_up = NO; +} + +void message(string msg) +{ + if(m_shut_up) + return; + + msg = "Rack file: " + elided_path(m_rack_file_name, 30) + ":\n" + msg; + + switch(dlgMessageBox(msg, "Ok", "Shut up already", "Never ask again")) { + case 1: + m_shut_up = 1; + break; + case 2: + m_shut_up = 1; + set_nv_param("drill_shut_up", "YES"); + break; + } +} + +void read_rack_file(string drill_file) +{ + string VALID_DRILL_CHARS = "#+-.0123456789imntT\t"; + + string drill_raw[]; + int num_raw_drills; + string key; + string temp; + string drill_text; + int i; + + /* + * Remove comment lines from the rack file. + * + */ + g_num_drills = 0; + num_raw_drills = fileread(drill_raw, drill_file); + string first_char; + for (i=0; i 0 && DRILL_SIZES_INCHES[i] > inches) { + i--; + } + return i; +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/filecopy.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/filecopy.h new file mode 100644 index 00000000..7fe5b47b --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/filecopy.h @@ -0,0 +1,26 @@ +// -*- Mode: Eagle -*- +void filecopy(string from_name, string to_name) +{ + string contents[]; + int num_lines; + + fileerror(); + num_lines = fileread(contents, from_name); + + if(fileerror()) { + dlgMessageBox("Error: Could not open " + from_name + + " for copying to " + to_name); + exit(1); + } + + output(to_name) { + for (int i=0; i < num_lines; i++) { + printf("%s\n", contents[i]); + } + } + if(fileerror()) { + dlgMessageBox("Error: Could not write the contents of " + + from_name + " to " + to_name); + exit(1); + } +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/filename_subs.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/filename_subs.h new file mode 100644 index 00000000..5e3906f1 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/filename_subs.h @@ -0,0 +1,161 @@ +// -*- Mode: Eagle -*- + +string FILENAME_SUBS; + +// +// Values to substitute in file names. +// +string setup_subs_side_phase(int l_side, int l_phase) +{ + string side; + string file; + string tmp; + int i; + + side = (l_side == TOP) ? TOP_FILE_NAME : BOT_FILE_NAME; + switch (l_phase) { + case PH_TOP_OUT_GEN: + case PH_TOP_OUT_WRITE: + case PH_BOTTOM_OUT_GEN: + case PH_BOTTOM_OUT_WRITE: + file = ETCH_FILE_NAME; + break; + case PH_TOP_DRILL: + case PH_BOTTOM_DRILL: + file = DRILL_FILE_NAME; + break; + case PH_MILL: + file = MILL_FILE_NAME; + break; + case PH_TEXT: + file = TEXT_FILE_NAME; + break; + default: + file = "invalid"; + } +// dlgMessageBox("file = " + ETCH_FILE_NAME); +// file = PHASE_NAME[l_phase]; + FILENAME_SUBS = ""; + i = 0; + while (path_epf[i] != "") { + sprintf(tmp, "$PROJECT_PATH[%d]", i); + FILENAME_SUBS += key_value_record(tmp, remove_last_slash(path_epf[i])); + sprintf(tmp, "$ULP_PATH[%d]", i); + FILENAME_SUBS += key_value_record(tmp, remove_last_slash(path_ulp[i])); + sprintf(tmp, "$CAM_PATH[%d]", i); + FILENAME_SUBS += key_value_record(tmp, remove_last_slash(path_cam[i])); + i++; + } + FILENAME_SUBS += key_value_record("$PATH", remove_last_slash(g_path)) + + key_value_record("$BOARD_PATH", remove_last_slash(filedir(BOARD_NAME))) + + key_value_record("$BOARD_NAME", filesetext(filename(BOARD_NAME), "")) + + key_value_record("$BOARD_FILE_PATH", filesetext(BOARD_NAME, "")) + + key_value_record("$SIDE", side) + + key_value_record("$FILE", file) + + key_value_record("$EXT", DEFAULT_EXTENSION) + ; + return FILENAME_SUBS; +} + +string filename_subs_help() +{ + return "

    Filename Variables

    " + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
    $PROJECT_PATH[n]Project paths as set in the Control Panel. " + "n begins at zero for the first entry.
    $ULP_PATH[n]As above, but for User Language Program paths.
    $CAM_PATH[n]As above, but for CAM Jobs paths.
    $BOARD_PATHPath to the board file.
    $BOARD_NAMEThe file name of the board with the extension (.brd) removed.
    $BOARD_FILE_PATHPath and name of the board with the extension (.brd) removed.
    $SIDESide of the board being generated. By default 'bot' or 'top'.
    $FILEFile of the board being generated. By default 'etch', 'drill' and 'mill' or 'text'.
    $EXTThe extension you set under the GCode Options tab.
    " + "Paths do not end with a /.
    " + "Example:
    " + "Assume the board we are working on is:
    " + "/home/john/eagle/my_stuff/enabtmr.brd
    " + "and we use these settings:
    " + "Filename Base: $BOARD_PATH/$BOARD_NAME
    " + "Top (Component) Side Files" + "" + "" + "" + "" + "" + "
    Etching: .$SIDE.$FILE.$EXT
    Drill: .$SIDE.$FILE.$EXT
    Mill: /mill_jobs/$BOARD_NAME.$SIDE.$FILE.tap
    Text: $SIDE.$FILE.tap
    " + "Would create the following filenames:
    " + "" + "" + "" + "" + "" + "
    Etching: /home/john/eagle/my_stuff/enabtmr.top.etch.nc
    Drill: /home/john/eagle/my_stuff/enabtmr.top.drill.nc
    Mill: /home/john/eagle/my_stuff/enabtmr/mill_jobs/enabtmr.top.mill.tap
    Drill: /home/john/eagle/my_stuff/enabtmr.top.text.nc
    " + ; +} + +string setup_subs() +{ + return setup_subs_side_phase(g_side, g_phase); +} + +string sub_side_phase(string s, int side, int phase) +{ + if (phase == 0) dlgMessageBox("phase == 0"); + setup_subs_side_phase(side, phase); + return substitute(s, FILENAME_SUBS); +} + +string get_filename() +{ + string name; + + setup_subs(); + + if (g_side == TOP) { + switch(g_phase) { + case PH_TOP_OUT_GEN: + case PH_TOP_OUT_WRITE: + name = FILENAME_TOP_ETCH_FILE; + break; + case PH_TOP_DRILL: + name = FILENAME_TOP_DRILL_FILE; + break; + case PH_MILL: + name = FILENAME_TOP_MILL_FILE; + break; + case PH_TEXT: + name = FILENAME_TOP_TEXT_FILE; + break; + } + } + else { + switch(g_phase) { + case PH_BOTTOM_OUT_GEN: + case PH_BOTTOM_OUT_WRITE: + name = FILENAME_BOT_ETCH_FILE; + break; + case PH_BOTTOM_DRILL: + name = FILENAME_BOT_DRILL_FILE; + break; + case PH_MILL: + name = FILENAME_BOT_MILL_FILE; + break; + case PH_TEXT: + name = FILENAME_BOT_TEXT_FILE; + break; + } + } + return substitute(FILENAME_BASE + name, FILENAME_SUBS); +} + +setup_subs(); + +string sub_path(string name) +{ + return substitute(name, FILENAME_SUBS); +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/library.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/library.h new file mode 100644 index 00000000..9d720103 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/library.h @@ -0,0 +1,210 @@ +// -*- Mode: Eagle -*- +// +// Convert n, an Eagle internal measure, to the user's selected +// unit of measure. +// +// Params: +// n An Eagle internal number. +// Return: +// n converted to the user's unit of measure. +// + +//real X_OFFSET = 1.0; +//real Y_OFFSET = 1.0; + +real units(int n) +{ + switch (OUTPUT_UNITS) { + case U_MICRONS: + return u2mic(n); + break; + case U_MILLIMETERS: + return u2mm(n); + break; + case U_MILS: + return u2mil(n); + break; + case U_INCHES: + return u2inch(n); + break; + } + + return u2inch(n); +} + +// +// Returns the mode command (i.e. G20) to set the machine to +// the user's selected unit of measure. +// +// Params: +// none +// Return: +// A string containing the mode command. +// +string get_mode() { + string mode; + + switch (OUTPUT_UNITS) { + case U_MICRONS: + mode= MICRON_MODE; + break; + case U_MILLIMETERS: + if (NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS) { + mode = METRIC_MODE_COMMENT; + } + mode += METRIC_MODE; + break; + case U_MILS: + mode = MIL_MODE; + break; + case U_INCHES: + if (NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS) { + mode = INCH_MODE_COMMENT; + } + mode += INCH_MODE; + break; + default: + mode = "M02 (Unknown mode in get_mode)"; + } + + return mode; +} + +// +// Scale X to positive or negative depending on the side +// of the board. Negative for bottom, positive for top. +// +// Params: +// x X coordinate. +// Return: +// x scaled for top (+) or bottom (-). +// +real scale_x(int x) +{ + real scaled; + + scaled = units(x) + X_OFFSET; + if (g_side == BOTTOM) { + if (FLIP_BOARD_IN_Y == NO && MIRROR_BOTTOM == NO) { + scaled = scaled * -1; + } + } + return scaled; +} + +// +// Return y converted to user's units. +// +// Params: +// y Y coordinate. +// Return: +// Y converted to user's units. +// +real scale_y(int y) +{ + real scaled; + + scaled = units(y) + Y_OFFSET; + if (g_side == BOTTOM) { + if (FLIP_BOARD_IN_Y == YES && MIRROR_BOTTOM == NO) { + scaled = scaled * -1; + } + } + return scaled; +} + +// +// Converts string to long, ignoring leading 0s. +// +// Params: +// s A numeric string. +// Returns: +// s converted to a long. +// +int my_strtol(string s) +{ + string result; + int i; + + i=0; + while (s[i] == '0') + i++; + result = strsub(s, i); + return strtol(result); +} + + + +// +// Show a dialog with a message and details. +// +// Params: +// Message General message. +// Details Details of the message. +// Return: none +// +void Message(string msg) +{ + dlgMessageBox(msg); +} + +// +// Show a dialog with an error message and details. +// +// Params: +// Message General error message. +// Details Details of the error. +// Return: none +// +void Error(string msg, string details) +{ + Message(usage + "
    Error: " + msg + "

    " + details); +} + +// +// Show a dialog with an error message and details, +// then exit the program. +// +// Params: +// Message General error message. +// Details Details of the error. +// Return: none +// +void Fatal(string msg, string details) +{ + // todo change to call Error + Error(msg, details); + exit(1); +} + + +int file_exists(string file) +{ + string files[]; + int num_files = fileglob(files, file); + +/* string s; + + for (int i=0; i < num_files; i++) + s +=files[i] + "\n"; + Message(s); +*/ + return (num_files > 0); +} + +enum { + OS_INVALID = 0, + OS_UNKNOWN, + OS_MACOSX, + OS_LINUX, + OS_WINDOWS +} + +int get_os() +{ + if (file_exists("/Applications/*")) + return OS_MACOSX; + if (file_exists("/home/*")) + return OS_LINUX; + return OS_WINDOWS; +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/library.ulp b/trunk/ulp/pcb-gcode-3.6.0.4/source/library.ulp new file mode 100644 index 00000000..46ffb9d1 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/library.ulp @@ -0,0 +1,36 @@ +// +// Tests for library.h . +// + +#include "math.h" +#include "pcb-defaults.h" +#include "library.h" + +int test_units[] = { + U_INCHES, + U_MICRONS, + U_MILLIMETERS, + U_MILS +}; + +int in_nums[] = { + 5000, + 125, + 9950, + 505 +}; + +real out_nums[] = { +}; + +int i; + +string msg; + +for (i=0; i < 3; i++) { + OUTPUT_UNITS = test_units[i]; + if (conv(in_nums[i]) != out_nums[i]) { + sprintf(msg, "Units %d in: %6d out: %7.4f", OUTPUT_UNITS, in_nums[i], out_nums[i]); + Error("test failed", msg); + } +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/math.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/math.h new file mode 100644 index 00000000..a2344fc6 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/math.h @@ -0,0 +1,179 @@ +// -*- Mode: Eagle -*- +/* + * + * Math utilities. + * + * Copyright 2007 - 2013 by John Johnson Software, LLC. + * All Rights Reserved. + * + */ + +//#include "source/drill_sizes.h" +#include "drill_sizes.h" + +real MM_PER_INCH = 25.4; +int MICRONS_PER_MM = 1000; +int MILS_PER_INCH = 1000; + +// +// Thanks EAGLE! No one expects an internal units change. :-) +// +int INTERNAL_SCALAR = 10000; +if (EAGLE_VERSION >= 6) { + INTERNAL_SCALAR = 320000; +} + +int INTERNALS_PER_MICRON = (INTERNAL_SCALAR / 1000); +int INTERNALS_PER_MM = INTERNAL_SCALAR; +int INTERNALS_PER_MIL = MM_PER_INCH * (INTERNAL_SCALAR / 1000); +int INTERNALS_PER_INCH = MM_PER_INCH * INTERNAL_SCALAR; + +/* + * Return the suffix unit of measure from a string. + */ +string get_units(string s) +{ + int len; + string units; + + len = strlen(s); + units = strsub(s, len - 2, 2); + // special handling for wire size drill numbers + if (strsub(units, 1, 1) == "#") + units = "#"; + return units; +} + +//enum { U_INVALID, U_MICRONS, U_MILLIMETERS, U_MILS, U_INCHES }; + +real convert(real value, int old_units, int new_units) +{ + real temp; + real result; + + // Convert current value to 10ths of microns. + switch(old_units) { + case U_MICRONS: + temp = value * INTERNALS_PER_MICRON; + break; + case U_MILLIMETERS: + temp = value * INTERNALS_PER_MM; + break; + case U_MILS: + temp = value * INTERNALS_PER_MIL; + break; + case U_INCHES: + temp = value * INTERNALS_PER_INCH; + break; + case U_INTERNALS: + temp = value; + break; + default: + dlgMessageBox(":Invalid value for old_units in convert()"); + exit(0); + } + + // Convert temp value to the new unit of measure. + switch(new_units) { + case U_MICRONS: + result = temp / INTERNALS_PER_MICRON; + break; + case U_MILLIMETERS: + result = temp / INTERNALS_PER_MM; + break; + case U_MILS: + result = temp / INTERNALS_PER_MIL; + break; + case U_INCHES: + result = temp / INTERNALS_PER_INCH; + break; + case U_INTERNALS: + result = temp; + break; + default: + dlgMessageBox(":Invalid value for new_units (" + int_to_string(new_units) + ") in convert()"); + exit(0); + } + + return result; +} + + +/* + * Convert a string with a number and a unit-of-measure suffix into + * Eagle internal units (microns). + * + * 0.032in 0.032 inches + * 62ml 62 mils, 0.062 inches + * 0.43mm 0.43 millimeters + * 1500mc 1500 microns, 1.500 millimeters + * 60# 60 wire gage drill (0.040" or 1.016mm) + * 0.12 0.12 inches + * 0.60 0.60 millimeters + * 43 43 wire gage drill + * + */ +int conv_to_units(string s) +{ + int val; + string units; + real num; + real mm; + string str; + + s = strlwr(s); + + units = get_units(s); + num = strtod(s); + + if(units == "mm") + val = convert(num, U_MILLIMETERS, U_INTERNALS); + else if (units == "in") + val = convert(num, U_INCHES, U_INTERNALS); + else if (units == "ml") + val = convert(num, U_MILS, U_INTERNALS); + else if (units == "mc") + val = num; + else if (units == "#") { + val = convert(get_drill_size_inches(num), U_INCHES, U_INTERNALS); + } + else { + if (num <= 0.25) + val = convert(num, U_INCHES, U_INTERNALS); + else if (num <= 6) + val = convert(num, U_MILLIMETERS, U_INTERNALS); + else + val = convert(get_drill_size_inches(num), U_INCHES, U_INTERNALS); + } + + return val; +} + +/* + * Determine if an integer value is within a range (inclusive). + */ +int in_range_int(int val, int min_val, int max_val) +{ + return((val >= min_val) && (val <= max_val)); +} + +int close(real val_a, real val_b) +{ + return(abs(val_a - val_b) < EPSILON); +} + +int close2(real xa, real xb, real ya, real yb) +{ + if (close(xa, xb) && close(ya, yb)) { + return true; + } + return false; +} + +int close3(real xa, real xb, real ya, real yb, real za, real zb) +{ + if (close(xa, xb) && close(ya, yb) && close(za, zb)) { + return true; + } + return false; +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/math.ulp b/trunk/ulp/pcb-gcode-3.6.0.4/source/math.ulp new file mode 100644 index 00000000..d2b20656 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/math.ulp @@ -0,0 +1,86 @@ +/* + * math.h tester. + */ + +#include "pcb-gcode.h" +#include "settings/pcb-machine.h" +#include "math.h" + +string test_strings[] = { + "0.100in", + "0.5mm", + "30#", + ".05", + ".7", + "5#", + "" +}; + +int answers_mu[] = { + 25400, + 5000, +// if you get far enough away, you'll be on your way home. Tom Waits + 32766, + 12700, + 7000, + 52324 +}; + +int i; +string str; +int val; +int failed = 0; + +for (i = 0; test_strings[i] != ""; i++) { + val = conv_to_units(test_strings[i]); + if ( val != answers_mu[i]) { + sprintf(str, "!Incorrect! String: '%s' converted to %dmu", test_strings[i], val); + dlgMessageBox(str); + failed = 1; + } +} + +real r_val; + +r_val = convert(0.100, U_INCHES, U_MILLIMETERS); +if (r_val != 2.54) { + sprintf(str, "!Incorrect! 0.1inches converted to %fmm", r_val); + dlgMessageBox(str); + failed = 1; +} + +r_val = convert(2.54, U_MILLIMETERS, U_INCHES); +if (r_val != 0.100) { + sprintf(str, "!Incorrect! 2.54mm converted to %fin", r_val); + dlgMessageBox(str); + failed = 1; +} +r_val = convert(0.100, U_INCHES, U_MICRONS); +if (r_val != 2540) { + sprintf(str, "!Incorrect! 0.1inches converted to %fmicrons", r_val); + dlgMessageBox(str); + failed = 1; +} +r_val = convert(16510, U_MICRONS, U_INCHES); +if (r_val != 0.65) { + sprintf(str, "!Incorrect! 16510microns converted to %finches", r_val); + dlgMessageBox(str); + failed = 1; +} +r_val = convert(0.735, U_INCHES, U_MILS); +if (r_val != 735) { + sprintf(str, "!Incorrect! 0.1inches converted to %fmils", r_val); + dlgMessageBox(str); + failed = 1; +} +r_val = convert(987, U_MILS, U_INCHES); +if (r_val != 0.987) { + sprintf(str, "!Incorrect! 987mils converted to %finches", r_val); + dlgMessageBox(str); + failed = 1; +} + + +if (failed == 0) { + dlgMessageBox("Passed"); +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/nonvolatile.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/nonvolatile.h new file mode 100644 index 00000000..0e93336e --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/nonvolatile.h @@ -0,0 +1,102 @@ +// -*- Mode: Eagle -*- +/* nonvolatile.h + * Copyright 2004-2009 by John Johnson Software, LLC. + * See readme.html for copyright information. + */ + +string STORAGE_NAME = g_path + "/storage.nv"; +int NAME_FIELD = 0; +int VALUE_FIELD = 1; +char SEPARATOR = '='; +string m_params[]; +string empty[]; + +if (filetime(STORAGE_NAME) == 0) { + output(STORAGE_NAME, "wt") { + printf("created%c%s\s", SEPARATOR, t2string(time())); + } +} + +void empty_m_params() +{ + int i; + + while (m_params[i] != "") + m_params[i++] = ""; +} + +int read_nv_file(int can_abort) +{ + int num_params; + + empty_m_params(); + fileerror(); + num_params = fileread(m_params, STORAGE_NAME); + if(fileerror()) { + if(can_abort) { + exit(1); + } + else { + return 0; + } + } +/* string t; + sprintf(t, "there are %d params", num_params); + dlgMessageBox(t); + */ return num_params; +} + +string get_nv_param(string name, string def, int can_abort) +{ + string value; + + read_nv_file(can_abort); + + value = lookup(m_params, name, VALUE_FIELD, SEPARATOR); + if (value == "") { + return def; + } + return value; +} + +void set_nv_param(string name, string value) +{ + int num_params; + int i; + string record[]; + + num_params = read_nv_file(0); + if (lookup(m_params, name, VALUE_FIELD, SEPARATOR) == "") { + m_params[num_params] = name + SEPARATOR + value; + num_params++; + } + else { + for (i=0; i < num_params; i++) { + strsplit(record, m_params[i], SEPARATOR); + if (record[NAME_FIELD] == name) { + record[VALUE_FIELD] = value; + m_params[i] = record[NAME_FIELD] + SEPARATOR + record[VALUE_FIELD]; + break; + } + } + } + output(STORAGE_NAME, "wt") { + for (i = 0; i < num_params; i++) { + printf("%s\n", m_params[i]); + } + } +} + +void set_real_nv_param(string name, real value) +{ + string str; + sprintf(str, "%f", value); + set_nv_param(name, str); +} + +real get_real_nv_param(string name) +{ + string str; + str = get_nv_param(name, "0.000", YES); + return strtod(str); +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-file-utils.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-file-utils.h new file mode 100644 index 00000000..c3a66c22 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-file-utils.h @@ -0,0 +1,463 @@ +// -*- Mode: Eagle -*- + +int m_line_number; +int LINE_NUMBER_INCREMENT = 10; +string g_preview; + +void eol() +{ + printf(EOL); + m_line_number += LINE_NUMBER_INCREMENT; +} + +int out(string s) +{ + int old_line_num; + string lines[]; + int num; + int i; + string line; + + old_line_num = m_line_number; + + num = strsplit(lines, s, '\n'); + for (i = 0; i < num; i++) { + line = lines[i]; + if (strlen(line) > 0 && line != "\n" && line != "EOL") { + if (USE_LINE_NUMBERS) { + printf(LINE_NUMBER_FORMAT, m_line_number); + } + printf(line); + if (i < num - 1 || rightstr(s,1) == "\n") { + printf(EOL); + } + m_line_number = m_line_number + LINE_NUMBER_INCREMENT; + } + } + return old_line_num; +} + +// +// Variables used to track the machine's current position and eliminate +// moves to the same coordinates. +// +real cur_x = -999.999; +real cur_y = -999.999; +real cur_z = -999.999; + +void xy(real x, real y) +{ + if (close(x, cur_x) && close(y, cur_y)) { + return; + } + + if (COMPACT_GCODE == YES) { + if (! close(x, cur_x) && ! close(y, cur_y)) { + out(frr(MOVE_XY, x, y) + EOL); + cur_x = x; + cur_y = y; + return; + } + if (! close(x, cur_x)) { + out(fr(MOVE_X, x) + EOL); + cur_x = x; + cur_y = y; + return; + } + if (! close(y, cur_y)) { + out(fr(MOVE_Y, y) + EOL); + cur_y = y; + return; + } + } + if (! close(x, cur_x) || ! close(y, cur_y)) { + out(frr(MOVE_XY, x, y) + EOL); + cur_x = x; + cur_y = y; + } +} + +// +// Output Feed commands. +// +void rate(real f) +{ + out(fr(FR_FORMAT, f)); +} + +void fx(real x) +{ + if (! close(x, cur_x)) { + out(fr(FEED_MOVE_X, x) + EOL); + cur_x = x; + } +} + +void fy(real y) +{ + if (! close(y, cur_y)) { + out(fr(FEED_MOVE_Y, y) + EOL); + cur_y = y; + } +} + +void fz(real z) +{ + if (! close(z, cur_z)) { + out(fr(FEED_MOVE_Z, z) + EOL); + cur_z = z; + } +} + +// Since the next move may depend on the Z rate having been set +// in this routine, it just outputs the move as usual. +void fzr(real z, real f) +{ + out( frr(FEED_MOVE_Z_WITH_RATE, z, f) + EOL); + cur_z = z; +} + +void fxy(real x, real y) +{ + if (! close(x, cur_x) || ! close(y, cur_y)) { + out( frr(FEED_MOVE_XY, x, y) + EOL); + cur_x = x; + cur_y = y; + } +} + +// Since the next move may depend on the XY rate having been set +// in this routine, it just outputs the move as usual. +void fxyr(real x, real y, real f) +{ + out( frrr(FEED_MOVE_XY_WITH_RATE, x, y, f) + EOL); +} + +void fxyz(real x, real y, real z) +{ + if (! close(x, cur_x) || ! close(y, cur_y) || ! close(z, cur_z)) { + out(frrr(FEED_MOVE_XYZ, x, y, z) + EOL); + cur_x = x; + cur_y = y; + cur_z = z; + } +} + +// +// Output Rapid commands. +// +void rx(real x) +{ + if (! close(x, cur_x)) { + out(fr(RAPID_MOVE_X, x) + EOL); + cur_x = x; + } +} + +void ry(real y) +{ + if (! close(y, cur_y)) { + out(fr(RAPID_MOVE_Y, y) + EOL); + cur_y = y; + } +} + +void rz(real z) +{ + if (! close(z, cur_z)) { + out(fr(RAPID_MOVE_Z, z) + EOL); + cur_z = z; + } +} + +void rxy(real x, real y) +{ + if (! close(x, cur_x) || ! close(y, cur_y)) { + out( frr(RAPID_MOVE_XY, x, y) + EOL); + cur_x = x; + cur_y = y; + } +} + +void rxyz(real x, real y, real z) +{ + if (! close(x, cur_x) || ! close(y, cur_y) || ! close(z, cur_z)) { + out(frrr(RAPID_MOVE_XYZ, x, y, z) + EOL); + cur_x = x; + cur_y = y; + cur_z = z; + } +} + +void comm(string str) +{ + if (strlen(str) > 0) { + out(COMMENT_BEGIN + str + COMMENT_END + EOL); + } +} + +void output_file_heading() +{ + if (NC_FILE_COMMENT_FROM_BOARD) { + comm(elided_path(argv[PROGRAM_NAME_ARG], 30)); + comm("Copyright 2005 - 2012 by John Johnson"); + comm("See readme.txt for licensing terms."); + + board(B) { + comm("This file generated from the board:"); + comm(elided_path(B.name, 30)); + } + } + + if (NC_FILE_COMMENT_FROM_BOARD || NC_FILE_COMMENT_DATE || + NC_FILE_COMMENT_MACHINE_SETTINGS || NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS || + g_debug_flag) { + comm("Current profile is " + elided_path(CURRENT_PROFILE[FILE_NAME], 30)); + } + if (NC_FILE_COMMENT_DATE) { + comm("This file generated " + t2string(time())); + } + + if (NC_FILE_COMMENT_MACHINE_SETTINGS) { + comm("Settings from pcb-machine.h"); + comm(" Tool Size"); + comm(fr(FORMAT, g_width)); + comm("Z Axis Settings"); + comm(" High Up Down Drill"); + comm(fr(FORMAT, DEFAULT_Z_HIGH) + "\t" + + fr(FORMAT, DEFAULT_Z_UP) + "\t" + + fr(FORMAT, DEFAULT_Z_DOWN) + "\t" + + fr(FORMAT, DRILL_DEPTH)); + comm(fr("spindle on time = %6.4f", SPINDLE_ON_TIME)); + comm(fr("milling depth = %6.4f", MILLING_DEPTH)); + comm(fr("text depth = %6.4f", TEXT_DEPTH)); + comm(frrr("tool change at " + FORMAT + FORMAT + FORMAT, + TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y, TOOL_CHANGE_POS_Z)); + comm("feed rate xy = " + fr(FR_FORMAT, FEED_RATE)); + comm("feed rate z = " + fr(FR_FORMAT, FEED_RATE_Z)); + } + + if (NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS) { + comm("Settings from pcb-defaults.h"); + comm(fr("isolate min = %6.4f", ISO_MIN)); + comm(fr("isolate max = %6.4f", ISO_MAX)); + comm(fr("isolate step = %6.4f", ISO_STEP)); + string tt; + sprintf(tt, "Generated %s%s%s%s%s%s", + (GENERATE_TOP_OUTLINES) ? "top outlines, " : "", + (GENERATE_TOP_DRILL) ? "top drill, " : "", + (GENERATE_TOP_FILL) ? "top fill, " : "", + (GENERATE_BOTTOM_OUTLINES) ? "bottom outlines, " : "", + (GENERATE_BOTTOM_DRILL) ? "bottom drill, " : "", + (GENERATE_BOTTOM_FILL) ? "bottom fill" : "" + ); + comm(tt); + comm("Unit of measure: " + UNIT_OF_MEASURE); + } +} + +// +// Writes the header for the output file. +// +// Params: +// none +// Returns: +// none +// +void begin_gcode(void) +{ + out(get_mode()); + + out(ABSOLUTE_MODE); + rxy(X_HOME, Y_HOME); + out(fr(SPINDLE_ON, SPINDLE_ON_TIME)); +} + +// +// Write end of file commands. +// +// Params: +// none +// Return: +// none +// +void end_gcode(void) +{ + rz(DEFAULT_Z_HIGH); + out(SPINDLE_OFF); + out(END_PROGRAM); +} + +// Kinds (outline, drill, etc.) +void output_kind_begin() +{ + if (USER_GCODE == NO) + return; + + switch (g_phase) { + case PH_TOP_OUT_WRITE: + case PH_BOTTOM_OUT_WRITE: + out(OUTLINE_BEGIN[ALL]); + out(OUTLINE_BEGIN[g_side]); + break; + + case PH_TOP_DRILL: + case PH_BOTTOM_DRILL: + out(DRILL_BEGIN[ALL]); + out(DRILL_BEGIN[g_side]); + break; + + case PH_TOP_FILL_WRITE: + case PH_BOTTOM_FILL_WRITE: + out(FILL_BEGIN[ALL]); + out(FILL_BEGIN[g_side]); + break; + + case PH_MILL: + out(MILL_BEGIN[ALL]); + out(MILL_BEGIN[g_side]); + break; + default: + dlgMessageBox("!Unknown g_phase " + int_to_string(g_phase) + + " in output_kind_begin()"); + } +} + +void output_between_outline_passes() +{ + if (USER_GCODE) { + out(OUTLINE_BETWEEN[ALL]); + out(OUTLINE_BETWEEN[g_side]); + } +} + +void output_kind_end() +{ + if (USER_GCODE == NO) + return; + + switch (g_phase) { + case PH_TOP_OUT_WRITE: + case PH_BOTTOM_OUT_WRITE: + out(OUTLINE_END[g_side]); + out(OUTLINE_END[ALL]); + break; + + case PH_TOP_DRILL: + case PH_BOTTOM_DRILL: + out(DRILL_END[g_side]); + out(DRILL_END[ALL]); + break; + + case PH_TOP_FILL_WRITE: + case PH_BOTTOM_FILL_WRITE: + out(FILL_END[g_side]); + out(FILL_END[ALL]); + break; + + case PH_MILL: + out(MILL_END[g_side]); + out(MILL_END[ALL]); + break; + default: + dlgMessageBox("!Unknown g_phase " + int_to_string(g_phase) + + " in output_kind_end()"); + } +} + +// Tool changing +void output_tool_change_begin() +{ + if (USER_GCODE) { + out(TOOL_CHANGE_BEGIN[ALL]); + out(TOOL_CHANGE_BEGIN[g_side]); + } +} + +void output_tool_changed() +{ + if (USER_GCODE) { + out(TOOL_CHANGED[g_side]); + out(TOOL_CHANGED[ALL]); + } +} + +void output_tool_zero_begin() +{ + if (USER_GCODE) { + out(TOOL_ZERO_BEGIN[ALL]); + out(TOOL_ZERO_BEGIN[g_side]); + } +} + +void output_tool_zero_end() +{ + if (USER_GCODE) { + out(TOOL_ZERO_END[g_side]); + out(TOOL_ZERO_END[ALL]); + } +} + +void output_tool_change_end() +{ + if (USER_GCODE) { + out(TOOL_CHANGE_END[g_side]); + out(TOOL_CHANGE_END[ALL]); + } +} + +// +// Print file beginning headers and user-codes. +// +void output_file_preamble() +{ + output_file_heading(); + + if (USER_GCODE) { + out(FILE_BEGIN[ALL]); + out(FILE_BEGIN[g_side]); + output_kind_begin(); + } +} + +// +// Print file closing text and user-codes. +// +void output_file_postamble() +{ + if (USER_GCODE) { + output_kind_end(); + out(FILE_END[g_side]); + out(FILE_END[ALL]); + } +} + +void output_drill_first_hole(real drill_x, real drill_y, real depth) +{ + string tt; + + if (SIMPLE_DRILL_CODE) { + rxy(drill_x, drill_y); + fzr(depth, FEED_RATE_Z); + rz(DEFAULT_Z_UP); + } + else { + //"G82 X%fY%f Z%f F10.0 R0.1 #250\n", + sprintf(tt, DRILL_FIRST_HOLE, drill_x, drill_y, + depth, FEED_RATE_Z, DEFAULT_Z_UP, + DRILL_DWELL); + out(tt); + } +} + +void output_drill_hole(real drill_x, real drill_y, real depth) +{ + if (SIMPLE_DRILL_CODE) { + rxy(drill_x, drill_y); + fzr(depth, FEED_RATE_Z); + rz(DEFAULT_Z_UP); + } + else { + out(frr(DRILL_HOLE, drill_x, drill_y)); + } +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode-menu.scr b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode-menu.scr new file mode 100644 index 00000000..a50f6d46 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode-menu.scr @@ -0,0 +1,34 @@ +# Command Menu Setup +# +# This is based on menu.scr that comes with Eagle. +# To display the command menu in the editor windows you have to +# activate the option 'Command texts' in the 'Options/User Interface' menu. +# + +MENU 'PCB-GCode : run pcb-gcode;' \ + 'PCB-GCode Setup : run pcb-gcode-setup;' \ + '---' \ + 'Grid {\ + Metric {\ + Fine : Grid mm 0.1; |\ + Coarse : Grid mm 1;\ + } | \ + Imperial {\ + Fine : Grid inch 0.001; |\ + Coarse : Grid inch 0.1;\ + } | \ + On : Grid On; | \ + Off : Grid Off;\ + }'\ + 'Display {\ + Top : Display None Top Pads Vias Dimension; |\ + Bottom : Display None Bottom Pads Vias Dimension; |\ + Placeplan {\ + Top : Display None tPlace Dimension; |\ + Bottom : Display None bPlace Dimension;\ + }\ + }'\ + '---'\ + 'Fit : Window Fit;'\ + 'Add' 'Delete' 'Move' ';' 'Edit' 'Quit'\ + ; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode-prg.scr b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode-prg.scr new file mode 100644 index 00000000..0a299227 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode-prg.scr @@ -0,0 +1,13 @@ +MENU \ + Gen_Top_Outlines \ +<> \ + Gen_Top_Fill \ + Write_Top_Fill \ + Gen_Bottom_Outlines \ + Write_Bottom_Outlines \ + Gen_Bottom_Fill \ + Write_Bottom_Fill \ + Top_Drills \ + Bottom_Drills \ + Milling \ +; diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode-stack.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode-stack.h new file mode 100644 index 00000000..20fac8fd --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode-stack.h @@ -0,0 +1,66 @@ +// -*- Mode: Eagle -*- +// +// Routines to implement a stack made from a string array. +// + +// +// Constants +// +int END_OF_STACK = -1; + +// +// Global variables +// +string g_stack[]; +int g_stack_ndx = 0; +int g_fwd_iter = 0; +int g_rev_iter = 0; + +// +// Module variables +// + +// +// Functions +// +void stack_init() { + g_stack_ndx = 0; +} + +string stack_pop() { + if (g_stack_ndx > 0) { + return g_stack[--g_stack_ndx]; + } + return "EMPTY-STACK"; +} + +void stack_push(string astring) { + g_stack[g_stack_ndx++] = astring; +} + +string stack_elem(int n) { + return g_stack[n]; +} + +int stack_count() { + return g_stack_ndx; +} + +void stack_sort() { + sort(stack_count(), g_stack); +} + +int stack_fwd_iter() { + g_fwd_iter = 0; + return g_fwd_iter; +} + +int stack_fwd_next() { + if (g_fwd_iter == END_OF_STACK) + return END_OF_STACK; + if (g_fwd_iter < (g_stack_ndx - 1)) { + return ++g_fwd_iter; + } + g_fwd_iter = END_OF_STACK; + return END_OF_STACK; +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode.h new file mode 100644 index 00000000..0b1828d7 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/pcb-gcode.h @@ -0,0 +1,246 @@ +// -*- Mode: Eagle -*- +// +// Constants and enums for pcb-gcode.ulp. +// +// (Actually, they should be consts and typedefs, +// but Eagle doesn't support that.) +// + +// +// No users options here. +// + +#include "string.h" + +string RELEASE = "NOT SET"; +string REVISION = "000"; + +string g_path = "."; + +string BOARD_NAME; +board(B) { BOARD_NAME = B.name; } + +enum { + U_MICRONS = 0, + U_MILLIMETERS = 1, + U_MILS = 2, + U_INCHES = 3, + U_INTERNALS = 4 +}; + +enum { + OUTPUT_MICRONS = 0, + OUTPUT_MILLIMETERS = 1, + OUTPUT_MILS = 2, + OUTPUT_INCHES = 3, + OUTPUT_INTERNALS = 4 +}; + +enum { NO = 0, YES = 1 }; +enum { false = 0, true = 1 }; + +enum { TASK_INVALID, TASK_OUTLINES, TASK_FILL }; + +enum { ST_INVALID, + ST_START_LINE, ST_CONTINUE_LINE, ST_END_LINE, + ST_DRILL, + ST_FILL, + ST_ARC_BEGIN, + ST_ARC_END}; + +enum { TOP = 0, BOTTOM = 1, MILL = 2, TEXT = 3, ALL = 4 }; + +int PROGRAM_NAME_ARG = 0; +int FILENAME_ARG = 1; +int WIDTH_ARG = 2; +int ISO_ARG = 3; +int PASS_ARG = 4; +int PHASE_ARG = 5; + +real COORD_TOLERANCE = 0.0001; + +string OUTLINES_SIGNAL_NAME = "_OUTLINES_"; + +int TOP_LAYER = 1; +int BOTTOM_LAYER = 16; +int MILL_LAYER = 46; +int TEXT_LAYER = 46; // same as MILL_LAYER + +int OUTLINES = 1; +int FILL = 2; +int MILL_BOARD = 3; +int MILL_TEXT = 4; + +enum { + PH_INVALID = 0, + PH_TOP_OUT_GEN = 1, + PH_TOP_OUT_WRITE = 2, + PH_TOP_FILL_GEN = 3, + PH_TOP_FILL_WRITE = 4, + PH_BOTTOM_OUT_GEN = 5, + PH_BOTTOM_OUT_WRITE = 6, + PH_BOTTOM_FILL_GEN = 7, + PH_BOTTOM_FILL_WRITE = 8, + PH_TOP_DRILL = 9, + PH_BOTTOM_DRILL = 10, + PH_MILL = 11, + PH_TEXT = 12, + + PH_LAST_PHASE = 13 +}; + +string PHASE_NAME[] = { + "invalid", + "Gen_Top_Outlines", "Write_Top_Outlines", + "Gen_Top_Fill", "Write_Top_Fill", + "Gen_Bottom_Outlines", "Write_Bottom_Outlines", + "Gen_Bottom_Fill", "Write_Bottom_Fill", + "Top_Drills", "Bottom_Drills", + "Milling", + "Text", + "Finished!" +}; + +string get_phase_name(int phase) +{ + return PHASE_NAME[phase]; +} + +// Used to convert a numeric state into a text name for that state. +string state_text[] = { + "ST_START_LINE", + "ST_CONTINUE_LINE", + "ST_END_LINE", + "ST_DRILL", + "ST_FILL" +}; + +real ROUND_FACTOR = 1000; + +real BORDER_SIZE = 0.001; + +int DRILL_SIZE = 0; +int DRILL_X = 1; +int DRILL_Y = 2; + +string UNIT_OF_MEASURE = "not set"; + +real g_width = 0.01; +int g_side = TOP; + +// Which phase of the process we're working on. +int g_phase; + +string IS_SETUP_FILE_NAME = "pcb_gcode_is_setup"; + +// Current profile array and indices for it. +string CURRENT_PROFILE[]; +enum { + FILE_NAME = 0, + AUTHOR = 1, + DESCRIPTION = 2 + } + +string get_current_profile() +{ + string files[]; + int num_files = fileglob(files, g_path + "/" + IS_SETUP_FILE_NAME); + if (num_files > 0) { + fileread(CURRENT_PROFILE, g_path + "/" + IS_SETUP_FILE_NAME); + } + else { + CURRENT_PROFILE[FILE_NAME] = "NONE"; + CURRENT_PROFILE[AUTHOR] = "NONE"; + CURRENT_PROFILE[DESCRIPTION] = "NONE"; + return "NONE"; + } + + return CURRENT_PROFILE[DESCRIPTION]; +} + +void set_current_profile(string profile_fields) +{ + strsplit(CURRENT_PROFILE, profile_fields, '\t'); + output(g_path + "/" + IS_SETUP_FILE_NAME) { + printf("%s\n", CURRENT_PROFILE[FILE_NAME]); + printf("%s\n", CURRENT_PROFILE[AUTHOR]); + printf("%s\n", CURRENT_PROFILE[DESCRIPTION]); + } +} + +int program_is_setup() +{ + if (get_current_profile() == "NONE") + return NO; + + return YES; +} + + +// Find the path where all our files are located. It must be one of the directories in the +// Options | Directories | User Language Programs settings. + + +void get_path() +{ + int index = 0; + string last_g_path; + + board(B) g_path = filedir(B.name); + + last_g_path = g_path; + while (g_path > "") { + g_path = remove_last_dir(g_path); + if (filetime(g_path + "/source/pcb-gcode.h")) { + return; + } + if (last_g_path == g_path) { + break; + } + last_g_path = g_path; + } + + while (path_ulp[index] != "" && index < 10) { + if(filetime(path_ulp[index] + "/source/pcb-gcode.h")) { + g_path = path_ulp[index]; + return; + } + index++; + } +} + +get_path(); + +if (g_path == "") { + dlgMessageBox("There is a problem with your installation of pcb-gcode.\n" + + "You probably need to add the path to pcb-gcode's folder in " + + "EAGLE's Control Panel | Options | Directories | User Language Programs.\n" + "Please see docs/readme.html"); + exit(-1); +} +else { +// dlgMessageBox("g_path = " + g_path); +} + +// This reads the current profile into CURRENT_PROFILE, if available. +get_current_profile(); + +// I know, I know. No way around it that I see right now. +string g_real_to_string_string = ""; +string real_to_string(real n) +{ + sprintf(g_real_to_string_string, "%f", n); + return g_real_to_string_string; +} + +string g_int_to_string_string = ""; +string int_to_string(int n) +{ + sprintf(g_int_to_string_string, "%d", n); + return g_int_to_string_string; +} + + +// Used to show debugging information. +string g_debug; + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/stack.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/stack.h new file mode 100644 index 00000000..d7b3111a --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/stack.h @@ -0,0 +1,71 @@ +// -*- Mode: Eagle -*- +/* +* A stack. +* +*/ + +string m_ary[]; +char FIELD_SEP = '\t'; +char RECORD_SEP = '\n'; + +string push(string stack, string entry) +{ + return stack + entry + RECORD_SEP; +} + +string top(string stack) +{ + int num = strsplit(m_ary, stack, RECORD_SEP); + return m_ary[num - 1]; +} + +string pop(string stack) +{ + string str; + int num = strsplit(m_ary, stack, RECORD_SEP); + m_ary[num - 1] = ""; + str = strjoin(m_ary, RECORD_SEP); + int off = strrchr(str, RECORD_SEP); + return strsub(str, off - 1); +} + +string bottom(string stack) +{ + return ""; +} + +string shift(string stack) +{ + return ""; +} + +string unshift(string stack, string entry) +{ + return ""; +} + +string t; +t = push(t, "aaa"); +t = push(t, "bbb"); +t = push(t, "ccc"); + + +string msg; +string qqq; +sprintf(msg, "stack:\n%s", t); +qqq = qqq + msg; +string s; +s = top(t); +sprintf(msg, "top:\n%s", s); +qqq = qqq + msg; +t = pop(t); +s = top(t); +sprintf(msg, "top:\n%s", s); +qqq = qqq + msg; + +t = push(t, "ddd"); + +sprintf(msg, "stack:\n%s", t); +qqq = qqq + msg; + +dlgMessageBox(qqq); diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/stack.ulp b/trunk/ulp/pcb-gcode-3.6.0.4/source/stack.ulp new file mode 100644 index 00000000..df24136d --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/stack.ulp @@ -0,0 +1,66 @@ +/* +* A stack. +* +*/ + +string m_ary[]; +char FIELD_SEP = '\t'; +char RECORD_SEP = '\n'; + +string push(string stack, string entry) +{ + return stack + entry + RECORD_SEP; +} + +string top(string stack) +{ + int num = strsplit(m_ary, stack, RECORD_SEP); + return m_ary[num - 1]; +} + +string pop(string stack) +{ + int off = strrchr(stack, RECORD_SEP, -2); + return strsub(stack, off); +} + +string bottom(string stack) +{ + return ""; +} + +string shift(string stack) +{ + return ""; +} + +string unshift(string stack, string entry) +{ + return ""; +} + +string t; +t = push(t, "aaa"); +t = push(t, "bbb"); +t = push(t, "ccc"); + + +string msg; +string qqq; +sprintf(msg, "stack:\n%s", t); +qqq = qqq + msg; +string s; +s = top(t); +sprintf(msg, "top:\n%s", s); +qqq = qqq + msg; +t = pop(t); +s = top(t); +sprintf(msg, "top:\n%s", s); +qqq = qqq + msg; + +t = push(t, "ddd"); + +sprintf(msg, "stack:\n%s", t); +qqq = qqq + msg; + +dlgMessageBox(qqq); diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/string.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/string.h new file mode 100644 index 00000000..f7be3943 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/string.h @@ -0,0 +1,306 @@ +// -*- Mode: Eagle -*- +/* + * + * String utilities. + * + * Copyright 2007 - 2009 by John Johnson Software, LLC. + * All Rights Reserved. + * + */ + + + +int STR_NOT_FOUND = -1; +char REC_SEP = '\v'; +char FIELD_SEP = '\t'; + +string leftstr(string s, int n) +{ + return strsub(s, 0, n); +} + +string rightstr(string s, int n) +{ + return strsub(s, strlen(s) - n); +} + +string ltrim(string s) +{ + while (leftstr(s, 1) == " ") { + s = strsub(s, 1); + } + return s; +} + +string rtrim(string s) +{ + while (strsub(s, strlen(s) - 1, 1) == " ") { + s = strsub(s, 0, strlen(s) - 1); + } + return s; +} + +string trim(string s) +{ + return ltrim(rtrim(s)); +} + +string remove_last_slash(string s) +{ + if (rightstr(s, 1) == "/") { + s = leftstr(s, strlen(s) - 1); + } + return s; +} + +string remove_last_dir(string s) +{ + int pos; + + pos = strrstr(s, "/"); + return leftstr(s, pos); +} + +string key_value_record(string a, string b) +{ + return a + FIELD_SEP + b + REC_SEP; +} + +/* + * Replace text in a string with other text. + * + */ +string substitute(string s, string replacements) +{ + int pos; + string keys[]; + string values[]; + string records[]; + string fields[]; + int num_keys; + int num_fields; + int i; + string temp; + int last_match; + + num_keys = strsplit(records, replacements, REC_SEP); + num_keys--; + for (i=0; i width) { break; } + pos = pos - strlen(path) - 1; + } + if (keep_pos <= 0) { return path; } + return "..." + strsub(path, keep_pos); +} + + +string fi(string f, int i) { + string str; + if (strcnt(f, '%') < 1) { + return ""; + } + else { + sprintf(str, f, i); + } + return str; +} + +string fir(string f, int i, real r) { + string str; + if (strcnt(f, '%') < 1) { + return fi(f, i); + } + else { + sprintf(str, f, i, r); + } + return str; +} + +string fr(string f, real r) { + string str; + if (strcnt(f, '%') < 1) { + return ""; + } + else { + sprintf(str, f, r); + } + return str; +} + +string frr(string f, real r1, real r2) { + string str; + if (strcnt(f, '%') < 2) { + return fr(f, r1); + } + else { + sprintf(str, f, r1, r2); + } + return str; +} + +string frrr(string f, real r1, real r2, real r3) { + string str; + if (strcnt(f, '%') < 3) { + return frr(f, r1, r2); + } + else { + sprintf(str, f, r1, r2, r3); + } + return str; +} + +string frrrr(string f, real r1, real r2, real r3, real r4) { + string str; + if (strcnt(f, '%') < 4) { + return frrr(f, r1, r2, r3); + } + else { + sprintf(str, f, r1, r2, r3, r4); + } + return str; +} + +string fs(string f, string s) { + string str; + if (strcnt(f, '%') < 1) { + return ""; + } + else { + sprintf(str, f, s); + } + return str; +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/string.ulp b/trunk/ulp/pcb-gcode-3.6.0.4/source/string.ulp new file mode 100644 index 00000000..946e4b8c --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/string.ulp @@ -0,0 +1,39 @@ +/* + * + * String utilities. + * + * Copyright 2007 - 2009 by John Johnson Software, LLC. + * All Rights Reserved. + * + */ + +#include "string.h" + +if (leftstr("test string", 3) != "tes") exit(12); +if (rightstr("test string", 3) != "ing") exit(13); +if (ltrim(" test string") != "test string") exit(14); +if (rtrim("test string ") != "test string") exit(15); +if (trim(" test string ") != "test string") exit(16); +if (remove_last_dir("c:/dir/thet/ssot/") != "c:/dir/thet") exit(17); + +string replacements; +string original_string; +string new_string; +string board_filepath; +int t = time(); + +board(b) board_filepath = b.name; +replacements = + key_value_record("%P", filedir(board_filepath)) + + key_value_record("%F", filename(board_filepath)) + + key_value_record("%B", filesetext(filename(board_filepath), "")) + + key_value_record("%D", t2string(t)) + + key_value_record("%S", "top") + + key_value_record("%T", "drill"); + +original_string = "Path = %P,\n Filename = %F,\n" + + "Board Name = %B, Now is %D\n" + + "Side is %S, and this is the %T file."; + +new_string = substitute(original_string, replacements); +dlgMessageBox(new_string); diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/test_nonvolatile.h b/trunk/ulp/pcb-gcode-3.6.0.4/source/test_nonvolatile.h new file mode 100644 index 00000000..6edae9c5 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/test_nonvolatile.h @@ -0,0 +1,51 @@ +// -*- Mode: Eagle -*- +/* test nonvolatile.h */ + +#include "nonvolatile.h" + +set_nv_param("first_name", "Jamile"); +set_nv_param("last_name", "Johnson"); +set_nv_param("email", "jamile@nowhere.com"); + +m_params[0] = "" +m_params[1] = "" +m_params[2] = "" + +if (get_nv_param("first_name", "ERROR", NO) == "ERROR") + exit("first_name failed"); +if (get_nv_param("last_name", "ERROR", NO) == "ERROR") + exit("last_name failed"); +if (get_nv_param("email", "ERROR", NO) == "ERROR") + exit("email failed"); + +if (get_nv_param("first_name", "ERROR", NO) != "Jamile") + exit("first_name failed"); +if (get_nv_param("last_name", "ERROR", NO) != "Johnson") + exit("last_name failed"); +if (get_nv_param("email", "ERROR", NO) != "jamile@nowhere.com") + exit("email failed"); + + +set_nv_param("first_name", "John"); +set_nv_param("last_name", "Johnson"); +set_nv_param("email", "pcbgcode@pcbgcode.org"); + +m_params[0] = "" +m_params[1] = "" +m_params[2] = "" + +if (get_nv_param("first_name", "ERROR", NO) == "ERROR") + exit("first_name failed"); +if (get_nv_param("last_name", "ERROR", NO) == "ERROR") + exit("last_name failed"); +if (get_nv_param("email", "ERROR", NO) == "ERROR") + exit("email failed"); + +if (get_nv_param("first_name", "ERROR", NO) != "John") + exit("first_name failed"); +if (get_nv_param("last_name", "ERROR", NO) != "Johnson") + exit("last_name failed"); +if (get_nv_param("email", "ERROR", NO) != "pcbgcode@pcbgcode.org") + exit("email failed"); + + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/test_nonvolatile.ulp b/trunk/ulp/pcb-gcode-3.6.0.4/source/test_nonvolatile.ulp new file mode 100644 index 00000000..8a4929b1 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/test_nonvolatile.ulp @@ -0,0 +1,83 @@ +/* test nonvolatile.h */ + +#include "nonvolatile.h" + +set_nv_param("first_name", "Jamile"); +set_nv_param("last_name", "Johnson"); +set_nv_param("email", "jamile@nowhere.com"); + +m_params[0] = ""; +m_params[1] = ""; +m_params[2] = ""; + +if (get_nv_param("first_name", "ERROR", 0) == "ERROR") +{ dlgMessageBox("14 first_name failed"); + exit(1); +} +if (get_nv_param("last_name", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("last_name failed"); + exit(1); +} +if (get_nv_param("email", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("email failed"); + exit(1); +} + +if (get_nv_param("first_name", "ERROR", 0) != "Jamile") +{ + dlgMessageBox("first_name failed"); + exit(1); +} +if (get_nv_param("last_name", "ERROR", 0) != "Johnson") +{ + dlgMessageBox("last_name failed"); + exit(1); +} +if (get_nv_param("email", "ERROR", 0) != "jamile@nowhere.com") +{ + dlgMessageBox("email failed"); + exit(1); +} + + +set_nv_param("first_name", "John"); +set_nv_param("last_name", "Johnson"); +set_nv_param("email", "pcbgcode@pcbgcode.org"); + +m_params[0] = ""; +m_params[1] = ""; +m_params[2] = ""; + +if (get_nv_param("first_name", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("55 first_name failed"); + int t=1/0; +} +if (get_nv_param("last_name", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("60 last_name failed"); + int t=1/0; +} +if (get_nv_param("email", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("65 email failed"); + int t=1/0; +} + +if (get_nv_param("first_name", "ERROR", 0) != "John") +{ + dlgMessageBox("71 first_name failed"); + int t=1/0; +} +if (get_nv_param("last_name", "ERROR", 0) != "Johnson") +{ + dlgMessageBox("76 last_name failed"); + int t=1/0; +} +if (get_nv_param("email", "ERROR", 0) != "pcbgcode@pcbgcode.org") +{ + dlgMessageBox("81 email failed"); + int t=1/0; +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/source/viewer.linux.sh b/trunk/ulp/pcb-gcode-3.6.0.4/source/viewer.linux.sh new file mode 100644 index 00000000..9a3e928a --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/source/viewer.linux.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +PATH=/usr/local/jdk/bin:$PATH + +cd "`dirname $0`/../viewer/application.linux" +./viewer >viewer.log 2>&1 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/data/BankGothic-Light-14.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/data/BankGothic-Light-24.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/data/optimize_me.txt b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/data/optimize_me.txt new file mode 100644 index 00000000..fefb850a --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/data/optimize_me.txt @@ -0,0 +1,35 @@ +# board=.../examples/04151_lcdi2c.bot.text.tap +# tool size=0.005000 +# pass=1 +-2.58002, 0.14068,-2.67009, 0.14068 +-2.67009, 0.14068,-2.69261, 0.16319 +-2.69261, 0.16319,-2.69261, 0.20823 +-2.69261, 0.20823,-2.67009, 0.23075 +-2.67009, 0.23075,-2.58002, 0.23075 +-2.58002, 0.23075,-2.55750, 0.20823 +-2.55750, 0.20823,-2.55750, 0.16319 +-2.55750, 0.16319,-2.58002, 0.14068 +-2.58002, 0.14068,-2.67009, 0.23075 +-2.55750, 0.34635,-2.69261, 0.34635 +-2.69261, 0.34635,-2.62506, 0.27879 +-2.62506, 0.27879,-2.62506, 0.36887 +-2.64757, 0.41691,-2.69261, 0.46194 +-2.69261, 0.46194,-2.55750, 0.46194 +-2.55750, 0.41691,-2.55750, 0.50698 +-2.69261, 0.64509,-2.69261, 0.55502 +-2.69261, 0.55502,-2.62506, 0.55502 +-2.62506, 0.55502,-2.64757, 0.60006 +-2.64757, 0.60006,-2.64757, 0.62257 +-2.64757, 0.62257,-2.62506, 0.64509 +-2.62506, 0.64509,-2.58002, 0.64509 +-2.58002, 0.64509,-2.55750, 0.62257 +-2.55750, 0.62257,-2.55750, 0.57754 +-2.55750, 0.57754,-2.58002, 0.55502 +-2.64757, 0.69313,-2.69261, 0.73817 +-2.69261, 0.73817,-2.55750, 0.73817 +-2.55750, 0.69313,-2.55750, 0.78321 +-2.55750, 0.96936,-2.64757, 0.96936 +-2.64757, 0.96936,-2.69261, 1.01440 +-2.69261, 1.01440,-2.64757, 1.05944 +-2.64757, 1.05944,-2.55750, 1.05944 +-2.62506, 0.96936,-2.62506, 1.05944 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/index.html b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/index.html new file mode 100644 index 00000000..a2958ebd --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/index.html @@ -0,0 +1,108 @@ + + + + + + + viewer : Built with Processing + + + + + +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

    + + This browser does not have a Java Plug-in. +
    + + Get the latest Java Plug-in here. + +
    +

    + +
    + + +
    + + +
    + +

    + viewer + +Load line coordinates from a file and draw them. + + +

    + +

    + Source code: viewer +

    + +

    + Built with Processing +

    +
    + + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/loading.gif b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/loading.gif new file mode 100644 index 00000000..1ddae508 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/loading.gif differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/viewer.jar b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/viewer.jar new file mode 100644 index 00000000..7345b613 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/viewer.jar differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/viewer.java b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/viewer.java new file mode 100644 index 00000000..0b5bb3ac --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/viewer.java @@ -0,0 +1,449 @@ +import processing.core.*; +import processing.xml.*; + +import java.applet.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; +import java.text.*; +import java.util.*; +import java.util.zip.*; +import java.util.regex.*; + +public class viewer extends PApplet { + +/** + * viewer + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +int[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +int bg_color = 0xff000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001f; + +int m_pass; +boolean m_monochrome = true; + +/* + * Parse Strings and produce Lines. + * + */ +public void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = PApplet.parseFloat(pieces[0]); + float y1 = PApplet.parseFloat(pieces[1]); + float x2 = PApplet.parseFloat(pieces[2]); + float y2 = PApplet.parseFloat(pieces[3]); + int m_pass = PApplet.parseInt(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +public void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +public void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +public void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = PApplet.parseFloat(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = PApplet.parseInt(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +public void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +public float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +public float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +public void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0f; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +public void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +public void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2f; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5f) { + m_scale -= 0.2f; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + + + static public void main(String args[]) { + PApplet.main(new String[] { "--bgcolor=#ffffff", "viewer" }); + } +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/viewer.pde b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/viewer.pde new file mode 100644 index 00000000..fd38c78d --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/applet/viewer.pde @@ -0,0 +1,428 @@ +/** + * viewer + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = true; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/data/BankGothic-Light-14.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/data/BankGothic-Light-24.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/data/optimize_me.txt b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/data/optimize_me.txt new file mode 100644 index 00000000..fefb850a --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/data/optimize_me.txt @@ -0,0 +1,35 @@ +# board=.../examples/04151_lcdi2c.bot.text.tap +# tool size=0.005000 +# pass=1 +-2.58002, 0.14068,-2.67009, 0.14068 +-2.67009, 0.14068,-2.69261, 0.16319 +-2.69261, 0.16319,-2.69261, 0.20823 +-2.69261, 0.20823,-2.67009, 0.23075 +-2.67009, 0.23075,-2.58002, 0.23075 +-2.58002, 0.23075,-2.55750, 0.20823 +-2.55750, 0.20823,-2.55750, 0.16319 +-2.55750, 0.16319,-2.58002, 0.14068 +-2.58002, 0.14068,-2.67009, 0.23075 +-2.55750, 0.34635,-2.69261, 0.34635 +-2.69261, 0.34635,-2.62506, 0.27879 +-2.62506, 0.27879,-2.62506, 0.36887 +-2.64757, 0.41691,-2.69261, 0.46194 +-2.69261, 0.46194,-2.55750, 0.46194 +-2.55750, 0.41691,-2.55750, 0.50698 +-2.69261, 0.64509,-2.69261, 0.55502 +-2.69261, 0.55502,-2.62506, 0.55502 +-2.62506, 0.55502,-2.64757, 0.60006 +-2.64757, 0.60006,-2.64757, 0.62257 +-2.64757, 0.62257,-2.62506, 0.64509 +-2.62506, 0.64509,-2.58002, 0.64509 +-2.58002, 0.64509,-2.55750, 0.62257 +-2.55750, 0.62257,-2.55750, 0.57754 +-2.55750, 0.57754,-2.58002, 0.55502 +-2.64757, 0.69313,-2.69261, 0.73817 +-2.69261, 0.73817,-2.55750, 0.73817 +-2.55750, 0.69313,-2.55750, 0.78321 +-2.55750, 0.96936,-2.64757, 0.96936 +-2.64757, 0.96936,-2.69261, 1.01440 +-2.69261, 1.01440,-2.64757, 1.05944 +-2.64757, 1.05944,-2.55750, 1.05944 +-2.62506, 0.96936,-2.62506, 1.05944 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/lib/core.jar b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/lib/core.jar new file mode 100644 index 00000000..29375ea3 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/lib/core.jar differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/lib/viewer.jar b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/lib/viewer.jar new file mode 100644 index 00000000..b28e7714 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/lib/viewer.jar differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/source/viewer.java b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/source/viewer.java new file mode 100644 index 00000000..7165d14f --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/source/viewer.java @@ -0,0 +1,452 @@ +import processing.core.*; +import processing.xml.*; + +import java.applet.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; +import java.text.*; +import java.util.*; +import java.util.zip.*; +import java.util.regex.*; + +public class viewer extends PApplet { + +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +int[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +int bg_color = 0xff000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001f; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +public void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = PApplet.parseFloat(pieces[0]); + float y1 = PApplet.parseFloat(pieces[1]); + float x2 = PApplet.parseFloat(pieces[2]); + float y2 = PApplet.parseFloat(pieces[3]); + int m_pass = PApplet.parseInt(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +public void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +public void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +public void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = PApplet.parseFloat(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = PApplet.parseInt(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +public void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +public float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +public float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +public void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0f; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +public void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +public void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2f; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5f) { + m_scale -= 0.2f; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + + + static public void main(String args[]) { + PApplet.main(new String[] { "--bgcolor=#ffffff", "viewer" }); + } +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/source/viewer.pde b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/source/viewer.pde new file mode 100644 index 00000000..1659cedc --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/source/viewer.pde @@ -0,0 +1,431 @@ +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/viewer b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/viewer new file mode 100644 index 00000000..74d932bd --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.linux/viewer @@ -0,0 +1,4 @@ +#!/bin/sh + +APPDIR=$(dirname "$0") +java -Djava.library.path="$APPDIR" -cp "$APPDIR/lib/viewer.jar:$APPDIR/lib/core.jar" viewer diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/data/BankGothic-Light-14.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/data/BankGothic-Light-24.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/data/optimize_me.txt b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/data/optimize_me.txt new file mode 100644 index 00000000..fefb850a --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/data/optimize_me.txt @@ -0,0 +1,35 @@ +# board=.../examples/04151_lcdi2c.bot.text.tap +# tool size=0.005000 +# pass=1 +-2.58002, 0.14068,-2.67009, 0.14068 +-2.67009, 0.14068,-2.69261, 0.16319 +-2.69261, 0.16319,-2.69261, 0.20823 +-2.69261, 0.20823,-2.67009, 0.23075 +-2.67009, 0.23075,-2.58002, 0.23075 +-2.58002, 0.23075,-2.55750, 0.20823 +-2.55750, 0.20823,-2.55750, 0.16319 +-2.55750, 0.16319,-2.58002, 0.14068 +-2.58002, 0.14068,-2.67009, 0.23075 +-2.55750, 0.34635,-2.69261, 0.34635 +-2.69261, 0.34635,-2.62506, 0.27879 +-2.62506, 0.27879,-2.62506, 0.36887 +-2.64757, 0.41691,-2.69261, 0.46194 +-2.69261, 0.46194,-2.55750, 0.46194 +-2.55750, 0.41691,-2.55750, 0.50698 +-2.69261, 0.64509,-2.69261, 0.55502 +-2.69261, 0.55502,-2.62506, 0.55502 +-2.62506, 0.55502,-2.64757, 0.60006 +-2.64757, 0.60006,-2.64757, 0.62257 +-2.64757, 0.62257,-2.62506, 0.64509 +-2.62506, 0.64509,-2.58002, 0.64509 +-2.58002, 0.64509,-2.55750, 0.62257 +-2.55750, 0.62257,-2.55750, 0.57754 +-2.55750, 0.57754,-2.58002, 0.55502 +-2.64757, 0.69313,-2.69261, 0.73817 +-2.69261, 0.73817,-2.55750, 0.73817 +-2.55750, 0.69313,-2.55750, 0.78321 +-2.55750, 0.96936,-2.64757, 0.96936 +-2.64757, 0.96936,-2.69261, 1.01440 +-2.69261, 1.01440,-2.64757, 1.05944 +-2.64757, 1.05944,-2.55750, 1.05944 +-2.62506, 0.96936,-2.62506, 1.05944 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/source/viewer.java b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/source/viewer.java new file mode 100644 index 00000000..7165d14f --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/source/viewer.java @@ -0,0 +1,452 @@ +import processing.core.*; +import processing.xml.*; + +import java.applet.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; +import java.text.*; +import java.util.*; +import java.util.zip.*; +import java.util.regex.*; + +public class viewer extends PApplet { + +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +int[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +int bg_color = 0xff000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001f; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +public void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = PApplet.parseFloat(pieces[0]); + float y1 = PApplet.parseFloat(pieces[1]); + float x2 = PApplet.parseFloat(pieces[2]); + float y2 = PApplet.parseFloat(pieces[3]); + int m_pass = PApplet.parseInt(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +public void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +public void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +public void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = PApplet.parseFloat(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = PApplet.parseInt(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +public void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +public float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +public float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +public void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0f; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +public void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +public void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2f; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5f) { + m_scale -= 0.2f; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + + + static public void main(String args[]) { + PApplet.main(new String[] { "--bgcolor=#ffffff", "viewer" }); + } +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/source/viewer.pde b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/source/viewer.pde new file mode 100644 index 00000000..1659cedc --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/source/viewer.pde @@ -0,0 +1,431 @@ +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Info.plist b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Info.plist new file mode 100644 index 00000000..bd3489b8 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Info.plist @@ -0,0 +1,59 @@ + + + + + CFBundleName + viewer + CFBundleVersion + 10.2 + CFBundleAllowMixedLocalizations + true + CFBundleExecutable + JavaApplicationStub + CFBundleDevelopmentRegion + English + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleInfoDictionaryVersion + 6.0 + CFBundleIconFile + sketch.icns + CFBundleIdentifier + viewer + + LSUIPresentationMode + 0 + Java + + VMOptions + -Xms64m -Xmx256m + MainClass + viewer + JVMVersion + 1.5* + ClassPath + $JAVAROOT/viewer.jar:$JAVAROOT/core.jar + + Properties + + + apple.laf.useScreenMenuBar + true + apple.awt.showGrowBox + false + com.apple.smallTabs + true + apple.awt.Antialiasing + false + apple.awt.TextAntialiasing + true + com.apple.hwaccel + true + apple.awt.use-file-dialog-packages + false + + + + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub new file mode 100644 index 00000000..eeb8b561 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/PkgInfo b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/PkgInfo new file mode 100644 index 00000000..bd04210f --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Resources/Java/core.jar b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Resources/Java/core.jar new file mode 100644 index 00000000..29375ea3 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Resources/Java/core.jar differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Resources/Java/viewer.jar b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Resources/Java/viewer.jar new file mode 100644 index 00000000..b28e7714 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Resources/Java/viewer.jar differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Resources/sketch.icns b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Resources/sketch.icns new file mode 100644 index 00000000..8ffb8d7d Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.macosx/viewer.app/Contents/Resources/sketch.icns differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/data/BankGothic-Light-14.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/data/BankGothic-Light-24.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/data/optimize_me.txt b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/data/optimize_me.txt new file mode 100644 index 00000000..fefb850a --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/data/optimize_me.txt @@ -0,0 +1,35 @@ +# board=.../examples/04151_lcdi2c.bot.text.tap +# tool size=0.005000 +# pass=1 +-2.58002, 0.14068,-2.67009, 0.14068 +-2.67009, 0.14068,-2.69261, 0.16319 +-2.69261, 0.16319,-2.69261, 0.20823 +-2.69261, 0.20823,-2.67009, 0.23075 +-2.67009, 0.23075,-2.58002, 0.23075 +-2.58002, 0.23075,-2.55750, 0.20823 +-2.55750, 0.20823,-2.55750, 0.16319 +-2.55750, 0.16319,-2.58002, 0.14068 +-2.58002, 0.14068,-2.67009, 0.23075 +-2.55750, 0.34635,-2.69261, 0.34635 +-2.69261, 0.34635,-2.62506, 0.27879 +-2.62506, 0.27879,-2.62506, 0.36887 +-2.64757, 0.41691,-2.69261, 0.46194 +-2.69261, 0.46194,-2.55750, 0.46194 +-2.55750, 0.41691,-2.55750, 0.50698 +-2.69261, 0.64509,-2.69261, 0.55502 +-2.69261, 0.55502,-2.62506, 0.55502 +-2.62506, 0.55502,-2.64757, 0.60006 +-2.64757, 0.60006,-2.64757, 0.62257 +-2.64757, 0.62257,-2.62506, 0.64509 +-2.62506, 0.64509,-2.58002, 0.64509 +-2.58002, 0.64509,-2.55750, 0.62257 +-2.55750, 0.62257,-2.55750, 0.57754 +-2.55750, 0.57754,-2.58002, 0.55502 +-2.64757, 0.69313,-2.69261, 0.73817 +-2.69261, 0.73817,-2.55750, 0.73817 +-2.55750, 0.69313,-2.55750, 0.78321 +-2.55750, 0.96936,-2.64757, 0.96936 +-2.64757, 0.96936,-2.69261, 1.01440 +-2.69261, 1.01440,-2.64757, 1.05944 +-2.64757, 1.05944,-2.55750, 1.05944 +-2.62506, 0.96936,-2.62506, 1.05944 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/lib/args.txt b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/lib/args.txt new file mode 100644 index 00000000..0e23ea1c --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/lib/args.txt @@ -0,0 +1,3 @@ + -Xms64m -Xmx256m +viewer +viewer.jar,core.jar diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/lib/core.jar b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/lib/core.jar new file mode 100644 index 00000000..29375ea3 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/lib/core.jar differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/lib/viewer.jar b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/lib/viewer.jar new file mode 100644 index 00000000..b28e7714 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/lib/viewer.jar differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/source/viewer.java b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/source/viewer.java new file mode 100644 index 00000000..7165d14f --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/source/viewer.java @@ -0,0 +1,452 @@ +import processing.core.*; +import processing.xml.*; + +import java.applet.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; +import java.text.*; +import java.util.*; +import java.util.zip.*; +import java.util.regex.*; + +public class viewer extends PApplet { + +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +int[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +int bg_color = 0xff000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001f; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +public void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = PApplet.parseFloat(pieces[0]); + float y1 = PApplet.parseFloat(pieces[1]); + float x2 = PApplet.parseFloat(pieces[2]); + float y2 = PApplet.parseFloat(pieces[3]); + int m_pass = PApplet.parseInt(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +public void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +public void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +public void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = PApplet.parseFloat(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = PApplet.parseInt(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +public void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +public float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +public float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +public void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0f; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +public void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +public void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2f; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5f) { + m_scale -= 0.2f; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + + + static public void main(String args[]) { + PApplet.main(new String[] { "--bgcolor=#ffffff", "viewer" }); + } +} diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/source/viewer.pde b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/source/viewer.pde new file mode 100644 index 00000000..1659cedc --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/source/viewer.pde @@ -0,0 +1,431 @@ +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/viewer.exe b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/viewer.exe new file mode 100644 index 00000000..ea70a3a2 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/application.windows/viewer.exe differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/data/BankGothic-Light-14.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/data/BankGothic-Light-24.vlw b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/data/optimize_me.txt b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/data/optimize_me.txt new file mode 100644 index 00000000..fefb850a --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/data/optimize_me.txt @@ -0,0 +1,35 @@ +# board=.../examples/04151_lcdi2c.bot.text.tap +# tool size=0.005000 +# pass=1 +-2.58002, 0.14068,-2.67009, 0.14068 +-2.67009, 0.14068,-2.69261, 0.16319 +-2.69261, 0.16319,-2.69261, 0.20823 +-2.69261, 0.20823,-2.67009, 0.23075 +-2.67009, 0.23075,-2.58002, 0.23075 +-2.58002, 0.23075,-2.55750, 0.20823 +-2.55750, 0.20823,-2.55750, 0.16319 +-2.55750, 0.16319,-2.58002, 0.14068 +-2.58002, 0.14068,-2.67009, 0.23075 +-2.55750, 0.34635,-2.69261, 0.34635 +-2.69261, 0.34635,-2.62506, 0.27879 +-2.62506, 0.27879,-2.62506, 0.36887 +-2.64757, 0.41691,-2.69261, 0.46194 +-2.69261, 0.46194,-2.55750, 0.46194 +-2.55750, 0.41691,-2.55750, 0.50698 +-2.69261, 0.64509,-2.69261, 0.55502 +-2.69261, 0.55502,-2.62506, 0.55502 +-2.62506, 0.55502,-2.64757, 0.60006 +-2.64757, 0.60006,-2.64757, 0.62257 +-2.64757, 0.62257,-2.62506, 0.64509 +-2.62506, 0.64509,-2.58002, 0.64509 +-2.58002, 0.64509,-2.55750, 0.62257 +-2.55750, 0.62257,-2.55750, 0.57754 +-2.55750, 0.57754,-2.58002, 0.55502 +-2.64757, 0.69313,-2.69261, 0.73817 +-2.69261, 0.73817,-2.55750, 0.73817 +-2.55750, 0.69313,-2.55750, 0.78321 +-2.55750, 0.96936,-2.64757, 0.96936 +-2.64757, 0.96936,-2.69261, 1.01440 +-2.69261, 1.01440,-2.64757, 1.05944 +-2.64757, 1.05944,-2.55750, 1.05944 +-2.62506, 0.96936,-2.62506, 1.05944 diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/viewer.pde b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/viewer.pde new file mode 100644 index 00000000..1659cedc --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/viewer.pde @@ -0,0 +1,431 @@ +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/pcb-gcode-3.6.0.4/viewer/viewer.tmproj b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/viewer.tmproj new file mode 100644 index 00000000..a928b6f5 --- /dev/null +++ b/trunk/ulp/pcb-gcode-3.6.0.4/viewer/viewer.tmproj @@ -0,0 +1,66 @@ + + + + + currentDocument + viewer.pde + documents + + + filename + optimize_me.txt + lastUsed + 2008-07-06T14:34:24Z + + + filename + viewer.pde + lastUsed + 2008-07-06T17:47:22Z + selected + + + + fileHierarchyDrawerWidth + 200 + metaData + + optimize_me.txt + + caret + + column + 0 + line + 0 + + firstVisibleColumn + 0 + firstVisibleLine + 0 + + viewer.pde + + caret + + column + 0 + line + 0 + + firstVisibleColumn + 0 + firstVisibleLine + 0 + + + openDocuments + + viewer.pde + + showFileHierarchyDrawer + + windowFrame + {{547, 8}, {849, 870}} + + diff --git a/trunk/ulp/pcb-gcode-setup.ulp b/trunk/ulp/pcb-gcode-setup.ulp new file mode 100644 index 00000000..116a451c --- /dev/null +++ b/trunk/ulp/pcb-gcode-setup.ulp @@ -0,0 +1,872 @@ +// +// Generate g-code for milling PC boards. +// +// Copyright 2004-2013 by John Johnson Software, LLC. +// See readme.html for copyright information. +// + +#include "source/pcb-gcode.h" +#include "settings/pcb-defaults.h" +#include "settings/pcb-machine.h" +#include "settings/gcode-defaults.h" +#include "settings/pcb-gcode-options.h" +#include "source/filecopy.h" +#include "source/math.h" +#include "source/filename_subs.h" +#include "plugin_headers.h" + +int m_current_units = OUTPUT_UNITS; +string m_uom_suffix = "unknown"; +string M_UOM_SUFFIXES[] = { + "mc", // microns + "mm", // millimeters + "ml", // mils + "in" // inches +}; + +int m_setup_was_changed = NO; +string m_cmd; + +string FILENAME_TOP_ETCH_FILE_SAMPLE; +string FILENAME_TOP_DRILL_FILE_SAMPLE; +string FILENAME_TOP_MILL_FILE_SAMPLE; +string FILENAME_TOP_TEXT_FILE_SAMPLE; +string FILENAME_TOP_FILL_FILE_SAMPLE; +string FILENAME_BOT_ETCH_FILE_SAMPLE; +string FILENAME_BOT_DRILL_FILE_SAMPLE; +string FILENAME_BOT_MILL_FILE_SAMPLE; +string FILENAME_BOT_TEXT_FILE_SAMPLE; +string FILENAME_BOT_FILL_FILE_SAMPLE; + +string temp_str; + +void set_uom_suffix(int n) +{ + m_uom_suffix = M_UOM_SUFFIXES[n]; +} + +string get_uom_suffix() +{ + return m_uom_suffix; +} + +void write_bool_param(string name, int value) +{ + printf("int %s = %s;\n", name, (value) ? "YES" : "NO"); +} + +void write_int_param(string name, int value) +{ + printf("int %s = %d;\n", name, value); +} + +void write_int_defined(string name, string value) +{ + printf("int %s = %s;\n", name, value); +} + +void write_real_param(string name, real value) +{ + printf("real %s = %f;\n", name, value); +} + +void write_string_param(string name, string value) +{ + printf("string %s = \"%s\";\n", name, value); +} + +// UNIT CONVERSION BEGIN TAG DO NOT REMOVE + +void convert_units(int new_units) +{ + MILLING_DEPTH = convert(MILLING_DEPTH, m_current_units, new_units); + TEXT_DEPTH = convert(TEXT_DEPTH, m_current_units, new_units); + SPOT_DRILL_DEPTH = convert(SPOT_DRILL_DEPTH, m_current_units, new_units); + ISO_MIN = convert(ISO_MIN, m_current_units, new_units); + ISO_MAX = convert(ISO_MAX, m_current_units, new_units); + ISO_STEP = convert(ISO_STEP, m_current_units, new_units); + DEFAULT_WIDTH = convert(DEFAULT_WIDTH, m_current_units, new_units); + DEFAULT_Z_HIGH = convert(DEFAULT_Z_HIGH, m_current_units, new_units); + DEFAULT_Z_UP = convert(DEFAULT_Z_UP, m_current_units, new_units); + DEFAULT_Z_DOWN = convert(DEFAULT_Z_DOWN, m_current_units, new_units); + DRILL_DEPTH = convert(DRILL_DEPTH, m_current_units, new_units); + TOOL_CHANGE_POS_X = convert(TOOL_CHANGE_POS_X, m_current_units, new_units); + TOOL_CHANGE_POS_Y = convert(TOOL_CHANGE_POS_Y, m_current_units, new_units); + TOOL_CHANGE_POS_Z = convert(TOOL_CHANGE_POS_Z, m_current_units, new_units); + FEED_RATE = convert(FEED_RATE, m_current_units, new_units); + FEED_RATE_Z = convert(FEED_RATE_Z, m_current_units, new_units); + EPSILON = convert(EPSILON, m_current_units, new_units); + + set_uom_suffix(OUTPUT_UNITS); + dlgRedisplay(); + m_current_units = new_units; +} + +// UNIT CONVERSION END TAG DO NOT REMOVE + +// Copy the *.release.h files to *.h, thereby restoring +// their default contents. +void restore_file_defaults() +{ + string restore_files[]; + string file_name; + int num_files; + int i; + int release_start; + + num_files = fileglob(restore_files, + g_path + "/safe_options/" + "*.release.h"); + if (num_files == 0) { + dlgMessageBox("There aren't any .release.h files," + " perhaps you should reinstall the program?"); + exit(0); + } + + for (i=0; i < num_files; i++) { + release_start = strrstr(restore_files[i], ".release.h"); + file_name = strsub(restore_files[i], 0, release_start) + ".h"; + filecopy(restore_files[i], file_name); + } + + filecopy(g_path + "/profiles/generic.pp", + g_path + "/settings/gcode-defaults.h"); +} + +int pp_selection = -1; +string pp_files[]; +string pp_auth_desc[]; +int num_pp_files; + +num_pp_files = fileglob(pp_files, g_path + "/profiles/*.pp"); + +for(int i=0; i < num_pp_files; i++) { + string lines[]; + + pp_auth_desc[i] = pp_files[i]; + + int num_lines = fileread(lines, pp_files[i]); + for(int j=0; j < num_lines; j++) { + string fields[]; + + int num_fields = strsplit(fields, lines[j], '='); + for(int k=0; k < num_fields; k++) { + + if(strlwr(fields[k]) == "// author") { + pp_auth_desc[i] = pp_auth_desc[i] + " \t" + fields[k + 1]; + } + else if(strlwr(fields[k]) == "// description") { + pp_auth_desc[i] = pp_auth_desc[i] + " \t" + fields[k + 1]; + } + } + } +} + +string m_maximum_label = "Maximum"; +string m_step_size_label = "Step size"; +if (SINGLE_PASS) { + m_maximum_label = "not used"; + m_step_size_label = "not used"; +} + +string m_eagle_compatibility = ""; +string m_compatibility = ""; +if (EAGLE_VERSION < 5) { + m_compatibility = "NOT COMPATIBLE"; +} +else if (EAGLE_VERSION == 5) { + m_compatibility = "verified compatible"; +} +else if (EAGLE_VERSION == 6) { + if (EAGLE_RELEASE <= 3) { + m_compatibility = "verified compatible"; + } + else { + m_compatibility = "probably compatible"; + } +} +sprintf(m_eagle_compatibility, "%d.%d (%s)", EAGLE_VERSION, EAGLE_RELEASE, m_compatibility); + +int Result = dlgDialog("pcb-gcode Setup") { + + set_uom_suffix(OUTPUT_UNITS); + + dlgVBoxLayout { + dlgLabel( + "" + "" + "" + "" + "" + "" + "
    " + "" + "" + "" + "
    Copyright 2004-2013 by" + " John Johnson Software, LLC.
    " + "
    All Rights Reserved
    " + "
    Version 3.6.0.4
    You have EAGLE version " + m_eagle_compatibility + "
    "); + if (program_is_setup()) { + dlgLabel("
    Your current profile is based on the " + + CURRENT_PROFILE[DESCRIPTION] + " profile.

    "); + dlgLabel("
    Please use the settings under the tabs to" + " customize the gcode that is generated for you.
    "); + } + else { + dlgLabel("

    Welcome!

    " + "

    Since this is the first time you have run this setup" + " program, please select the profile that best suits your machine." + " Click the Accept button to save your changes.
    "); + } +// dlgLabel(""); + } + + + dlgTabWidget { + + /*************************************************************** + * + * G E N E R A T I O N O P T I O N S + * + ***************************************************************/ + + if (program_is_setup()) dlgTabPage("Generation Options") { + dlgHBoxLayout { + dlgStretch(20); + dlgVBoxLayout { + dlgGroup("Top Side") { + dlgCheckBox("Generate top outlines", GENERATE_TOP_OUTLINES); + dlgCheckBox("Generate top drills ", GENERATE_TOP_DRILL); + } + dlgStretch(1); + } + dlgVBoxLayout { + dlgGroup("Bottom Side") { + dlgCheckBox("Generate bottom outlines", + GENERATE_BOTTOM_OUTLINES); + dlgCheckBox("Generate bottom drills ", + GENERATE_BOTTOM_DRILL); + dlgCheckBox("Mirror ", + MIRROR_BOTTOM); + } + dlgStretch(1); + dlgLabel(""); + dlgStretch(3); + } + dlgVBoxLayout { + dlgGroup("Board") { + dlgVBoxLayout { + dlgCheckBox("Show preview ", SHOW_PREVIEW); + dlgGridLayout { + dlgCell(0, 0) dlgCheckBox("Generate milling", GENERATE_MILLING); + dlgCell(0, 1) dlgLabel("Depth "); + dlgCell(0, 2) { dlgRealEdit(MILLING_DEPTH); dlgLabel(m_uom_suffix, YES); } + + dlgCell(1, 0) dlgCheckBox("Generate text", GENERATE_TEXT); + dlgCell(1, 1) dlgLabel("Depth "); + dlgCell(1, 2) { dlgRealEdit(TEXT_DEPTH); dlgLabel(m_uom_suffix, YES); } + dlgCell(2, 0) dlgCheckBox("Spot drill holes", SPOT_DRILL); + dlgCell(2, 1) dlgLabel("Depth"); + dlgCell(2, 2) { dlgRealEdit(SPOT_DRILL_DEPTH); dlgLabel(m_uom_suffix, YES); } + } + dlgGridLayout { + dlgCell(0, 0, 0, 1) dlgLabel("Isolation"); + dlgCell(0, 1) { + dlgCheckBox("Single pass", SINGLE_PASS) { + if (SINGLE_PASS) { +/* dlgMessageBox("You have selected the single pass option.\n" + + "The next time you run pcb-gcode-setup, the Maximum and Step Size " + + "options will be hidden. Only Minimum will be shown.\n" + + "To change back, just turn Single pass off, " + + "click Accept, and run pcb-gcode-setup again.\n" + + "The minimum, maximum, and step size options will be available again."); + */ + m_maximum_label = "not used"; + m_step_size_label = "not used"; + } + else { + m_maximum_label = "Maximum"; + m_step_size_label = "Step size"; + } + } + } + dlgCell(1, 0) dlgLabel("Minimum"); + dlgCell(1, 1) { dlgRealEdit(ISO_MIN); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(3, 0) dlgLabel(m_maximum_label, YES); + dlgCell(3, 1) { dlgRealEdit(ISO_MAX); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(4, 0) dlgLabel(m_step_size_label, YES); + dlgCell(4, 1) { dlgRealEdit(ISO_STEP); + dlgLabel(m_uom_suffix, YES); + } + } + dlgSpacing(10); + dlgVBoxLayout { + dlgLabel("Etching Tool Size "); + dlgHBoxLayout { dlgRealEdit(DEFAULT_WIDTH); + dlgLabel(m_uom_suffix, YES); + } + } + } + } + dlgStretch(1); + } + dlgStretch(20); + } + dlgHBoxLayout { + } + } + + /*************************************************************** + * + * M A C H I N E + * + ***************************************************************/ + if (program_is_setup()) dlgTabPage("Machine") { + dlgHBoxLayout { + dlgStretch(20); + dlgLabel(""); + dlgGroup("Z Axis") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Z High "); + dlgCell(1, 1) { + dlgRealEdit(DEFAULT_Z_HIGH); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(2, 0) dlgLabel("Z Up "); + dlgCell(2, 1) { + dlgRealEdit(DEFAULT_Z_UP); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(3, 0) dlgLabel("Z Down "); + dlgCell(3, 1) { + dlgRealEdit(DEFAULT_Z_DOWN); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(4, 0) dlgLabel("Drill Depth "); + dlgCell(4, 1) { + dlgRealEdit(DRILL_DEPTH); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(5, 0) dlgLabel("Drill Dwell "); + dlgCell(5, 1) dlgRealEdit(DRILL_DWELL, 0); // DO NOT CONVERT + } + } + dlgGroup("Tool Change") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Position X "); + dlgCell(1, 1) { dlgRealEdit(TOOL_CHANGE_POS_X); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(2, 0) dlgLabel("Position Y "); + dlgCell(2, 1) { dlgRealEdit(TOOL_CHANGE_POS_Y); + dlgLabel(m_uom_suffix, YES); + } + dlgCell(3, 0) dlgLabel("Position Z "); + dlgCell(3, 1) { dlgRealEdit(TOOL_CHANGE_POS_Z); + dlgLabel(m_uom_suffix, YES); + } + } + } + dlgStretch(20); + } + dlgHBoxLayout { + dlgStretch(20); + dlgGroup("Units") { + dlgRadioButton("Microns", OUTPUT_UNITS) { + convert_units(U_MICRONS); + } + dlgRadioButton("Millimeters", OUTPUT_UNITS) { + convert_units(U_MILLIMETERS); + } + dlgRadioButton("Mils", OUTPUT_UNITS) { + convert_units(U_MILS); + } + dlgRadioButton("Inches", OUTPUT_UNITS) { + convert_units(U_INCHES); + } + } + dlgGroup("Spindle") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Spin Up Time "); + dlgCell(1, 1) dlgRealEdit(SPINDLE_ON_TIME); // DO NOT CONVERT + } + } + dlgGroup("Feed Rates") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("X Y "); + dlgCell(1, 1) { dlgRealEdit(FEED_RATE); + dlgLabel(m_uom_suffix, YES); dlgLabel("/min"); + } + dlgCell(2, 0) dlgLabel("Z "); + dlgCell(2, 1) { dlgRealEdit(FEED_RATE_Z); + dlgLabel(m_uom_suffix, YES); dlgLabel("/min"); + } + } + } + dlgGroup("Misc") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Epsilon"); + dlgCell(1, 1) { dlgRealEdit(EPSILON); + dlgLabel(m_uom_suffix, YES); + dlgPushButton("?") { + dlgMessageBox("If an X or Y move is less than this amount, do not " + "put a move in the g-code file. For instance, if one point is " + "only 0.00001\" away from another point, there is no need to " + "write the move to the g-code file, since the machine will not " + "move anyway. This helps make the g-code file smaller, and run faster."); + } + } + dlgCell(2, 0) dlgLabel("Default Drill Rack File"); + dlgCell(2, 1) dlgStringEdit(DEFAULT_DRILL_FILE); + dlgCell(2, 2) { + dlgPushButton("...") { + DEFAULT_DRILL_FILE = dlgFileOpen("Find default drill rack file", + g_path + "/settings", + "Drill files (*.drl);;All files (*.*)"); + } + dlgPushButton("?") { + dlgMessageBox( + "Please see docs/readme.html for full details.
    " + "pcb-gcode will look for (in order):
    " + "board.drl
    " + "The file you select here.
    " + "path_to_pcbgcode/settings/default.drl
    " + "If this setting is blank, and it does not find a file, " + "it will assume you do not want to use a rack file.
    " + "If this setting is not blank, and it cannot find one of the " + "files listed above, it will give you an error message." + ); + } + } + } + } + dlgStretch(20); + } + } + + /*************************************************************** + * + * G C O D E S T Y L E + * + ***************************************************************/ + dlgTabPage("GCode Style") { + dlgLabel("Please select your style of gcode below."); + dlgLabel("If you make changes to gcode-defaults.h to " + "work with your machine,"); + dlgLabel( + "Please email the file to " + "pcbgcode@pcbgcode.org for possible inclusion " + "in the next release."); + dlgListView("File\tAuthor\tDescription", + pp_auth_desc, pp_selection); + } + + /*************************************************************** + * + * G C O D E O P T I O N S + * + ***************************************************************/ + if (program_is_setup()) dlgTabPage("GCode Options") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgGroup("NC File Comments") { + dlgCheckBox("NC File Comment from Board", + NC_FILE_COMMENT_FROM_BOARD); + dlgCheckBox("Nc File Comment Date", + NC_FILE_COMMENT_DATE); + dlgCheckBox("Nc File Comment Machine Settings", + NC_FILE_COMMENT_MACHINE_SETTINGS); + dlgCheckBox("Nc File Comment Pcb Defaults Settings", + NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS); + } +// dlgStretch(1); + } + dlgGroup("Other Options") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgCheckBox("Use user gcode (from user-gcode.h)", USER_GCODE); + dlgCheckBox("Debug Flag", g_debug_flag); + dlgCheckBox("Do tool change with zero step", DO_TOOL_CHANGE_WITH_ZERO_STEP); + dlgCheckBox("Flip board in Y instead of X", FLIP_BOARD_IN_Y); + } + dlgVBoxLayout { + dlgCheckBox("Compact gcode", COMPACT_GCODE); + dlgHBoxLayout { + dlgCheckBox("Use line numbers?", USE_LINE_NUMBERS); + dlgLabel(" Format "); dlgStringEdit(LINE_NUMBER_FORMAT); + } + dlgCheckBox("Use simple drill code ", + SIMPLE_DRILL_CODE); + } + } + // dlgStretch(1); + } + } + dlgHBoxLayout { + dlgGroup("File Naming") { + dlgGridLayout { + dlgCell(0, 0, 0, 1) { + dlgLabel("Filename Base "); dlgStringEdit(FILENAME_BASE); + } + dlgCell(0, 2) { + dlgLabel("Extension "); dlgStringEdit(DEFAULT_EXTENSION); + dlgStretch(1); + } + dlgCell(2, 0) { dlgLabel("Word for 'etch'"); + dlgStringEdit(ETCH_FILE_NAME); + } + dlgCell(2, 1) { dlgLabel("Word for 'drill'"); + dlgStringEdit(DRILL_FILE_NAME); + } + dlgCell(2, 2) { dlgLabel("Word for 'mill'"); + dlgStringEdit(MILL_FILE_NAME); + } + dlgCell(2, 3) { dlgLabel("Word for 'text'"); + dlgStringEdit(TEXT_FILE_NAME); dlgStretch(1); + } + dlgCell(3, 0) { dlgLabel("Word for 'top'"); + dlgStringEdit(TOP_FILE_NAME); + } + dlgCell(3, 1) { dlgLabel("Word for 'bottom'"); + dlgStringEdit(BOT_FILE_NAME); + } + } + dlgHBoxLayout { + dlgGroup("Top (Component) Side Files") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Etching "); + dlgCell(1, 1) { dlgStringEdit(FILENAME_TOP_ETCH_FILE); } + dlgCell(2, 0) dlgLabel("Drill "); + dlgCell(2, 1) { dlgStringEdit(FILENAME_TOP_DRILL_FILE); } + dlgCell(3, 0) dlgLabel("Mill "); + dlgCell(3, 1) { dlgStringEdit(FILENAME_TOP_MILL_FILE); } + dlgCell(4, 0) dlgLabel("Text "); + dlgCell(4, 1) { dlgStringEdit(FILENAME_TOP_TEXT_FILE); } + } + } + dlgGroup("Bottom (Solder) Side Files") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Etching "); + dlgCell(1, 1) dlgStringEdit(FILENAME_BOT_ETCH_FILE); + dlgCell(2, 0) dlgLabel("Drill "); + dlgCell(2, 1) dlgStringEdit(FILENAME_BOT_DRILL_FILE); + dlgCell(3, 0) dlgLabel("Mill "); + dlgCell(3, 1) dlgStringEdit(FILENAME_BOT_MILL_FILE); + dlgCell(4, 0) dlgLabel("Text "); + dlgCell(4, 1) dlgStringEdit(FILENAME_BOT_TEXT_FILE); + } + } +// dlgStretch(1); + dlgVBoxLayout { + dlgPushButton("Test Filenames") { + FILENAME_TOP_ETCH_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_TOP_ETCH_FILE, + TOP, PH_TOP_OUT_WRITE); + FILENAME_TOP_DRILL_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_TOP_DRILL_FILE, + TOP, PH_TOP_DRILL); + FILENAME_TOP_MILL_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_TOP_MILL_FILE, + TOP, PH_MILL); + FILENAME_TOP_TEXT_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_TOP_TEXT_FILE, + TOP, PH_TEXT); + FILENAME_BOT_ETCH_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_BOT_ETCH_FILE, + BOTTOM, PH_BOTTOM_OUT_WRITE); + FILENAME_BOT_DRILL_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_BOT_DRILL_FILE, + BOTTOM, PH_BOTTOM_DRILL); + FILENAME_BOT_MILL_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_BOT_MILL_FILE, + BOTTOM, PH_MILL); + FILENAME_BOT_TEXT_FILE_SAMPLE = sub_side_phase( + FILENAME_BASE + FILENAME_BOT_TEXT_FILE, + BOTTOM, PH_TEXT); + FILENAME_TOP_ETCH_FILE_SAMPLE = substitute( + FILENAME_TOP_ETCH_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_TOP_DRILL_FILE_SAMPLE = substitute( + FILENAME_TOP_DRILL_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_TOP_MILL_FILE_SAMPLE = substitute( + FILENAME_TOP_MILL_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_TOP_TEXT_FILE_SAMPLE = substitute( + FILENAME_TOP_TEXT_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_BOT_ETCH_FILE_SAMPLE = substitute( + FILENAME_BOT_ETCH_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_BOT_DRILL_FILE_SAMPLE = substitute( + FILENAME_BOT_DRILL_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_BOT_MILL_FILE_SAMPLE = substitute( + FILENAME_BOT_MILL_FILE_SAMPLE, + key_value_record(" ", "_")); + FILENAME_BOT_TEXT_FILE_SAMPLE = substitute( + FILENAME_BOT_TEXT_FILE_SAMPLE, + key_value_record(" ", "_")); + temp_str = ";Test Filenames\n" + "Spaces in file paths have been " + "replaced with underscores _ to keep " + "the lines from wrapping.\n" + "Top:\n" + "Etch:\t" + FILENAME_TOP_ETCH_FILE_SAMPLE + "\n" + + "Drill:\t" + FILENAME_TOP_DRILL_FILE_SAMPLE + "\n" + + "Mill:\t" + FILENAME_TOP_MILL_FILE_SAMPLE + "\n" + + "Text:\t" + FILENAME_TOP_TEXT_FILE_SAMPLE + "\n" + + "\nBottom:\n" + "Etch:\t" + FILENAME_BOT_ETCH_FILE_SAMPLE + "\n" + + "Drill:\t" + FILENAME_BOT_DRILL_FILE_SAMPLE + "\n" + + "Mill:\t" + FILENAME_BOT_MILL_FILE_SAMPLE + "\n" + + "Text:\t" + FILENAME_BOT_TEXT_FILE_SAMPLE + "\n"; + dlgMessageBox(temp_str); + } + dlgPushButton("Help") { + dlgMessageBox(filename_subs_help()); + } +// dlgStretch(1); + } + } + } + } + + } + if (program_is_setup()) dlgTabPage("Plugins") { + #include "plugins/plugin_loader.h" + } + + /*************************************************************** + * + * O T H E R + * + ***************************************************************/ + if (program_is_setup()) dlgTabPage("Other") { + dlgHBoxLayout { + dlgStretch(1); + dlgVBoxLayout { + dlgStretch(1); + dlgGroup("Miscellaneous") { + dlgGridLayout { + dlgCell(0, 0, 0, 5) { + dlgLabel("All misc. options are deprecated."); + } + } + } + dlgPushButton("Reset to Factory Defaults") { + if (dlgMessageBox( + "This is going to change the following files" + " back to their default contents, erasing any changes" + " you may have made to them:

    " + "" + "" + "" + "
    pcb-defaults.hpcb-gcode-options.h
    pcb-machine.huser-gcode.h

    " + "Is that something you want to do?

    " + "If you aren't sure, click No.", + "-Yes", "+No") == 0 /*Yes*/) { + restore_file_defaults(); + exit("run pcb-gcode-setup"); + } + } + dlgStretch(1); + } + dlgStretch(1); + } + } + } + + dlgHBoxLayout { + dlgStretch(5); + dlgPushButton("+&Accept") dlgAccept(); + if (program_is_setup()) { + dlgPushButton("Accept and make my &board") dlgAccept(2); + } + dlgPushButton("-Cancel") { + if (dlgMessageBox("Cancel your changes.

    " + "Are you sure?", "Yes", "No") == 0) dlgReject(); + } + } +}; + +// Accept Accept and make board +if (Result == 1 || Result == 2) { + + fileerror(); + output(g_path + "/settings/pcb-defaults.h", "wt") { + + int now = time(); + + printf( + "//\n// Default values for generating gcode from a PCB.\n//\n"); + printf("// These settings were last changed with " + "pcb-gcode-setup: %s\n//\n", t2string(now)); + printf("//\n// Changes you make in this file will be overwritten " + "if you use pcb-gcode-setup.\n//\n\n"); + + write_bool_param("SINGLE_PASS", SINGLE_PASS); + write_real_param("ISO_MIN", ISO_MIN); + write_real_param("ISO_MAX", ISO_MAX); + write_real_param("ISO_STEP", ISO_STEP); + printf("\n"); + + write_bool_param("GENERATE_TOP_OUTLINES", GENERATE_TOP_OUTLINES); + write_bool_param("GENERATE_TOP_DRILL", GENERATE_TOP_DRILL); + write_bool_param("GENERATE_TOP_FILL", GENERATE_TOP_FILL); + printf("\n"); + + write_bool_param("GENERATE_BOTTOM_OUTLINES", + GENERATE_BOTTOM_OUTLINES); + write_bool_param("GENERATE_BOTTOM_DRILL", GENERATE_BOTTOM_DRILL); + write_bool_param("GENERATE_BOTTOM_FILL", GENERATE_BOTTOM_FILL); + write_bool_param("MIRROR_BOTTOM", + MIRROR_BOTTOM); + write_bool_param("SIMPLE_DRILL_CODE", SIMPLE_DRILL_CODE); + + printf("\n"); + + write_bool_param("GENERATE_MILLING", GENERATE_MILLING); + printf("\n"); + + write_bool_param("GENERATE_TEXT", GENERATE_TEXT); + printf("\n"); + + write_bool_param("SPOT_DRILL", SPOT_DRILL); + write_real_param("SPOT_DRILL_DEPTH", SPOT_DRILL_DEPTH); + printf("\n"); + + write_bool_param("DO_TOOL_CHANGE_WITH_ZERO_STEP", + DO_TOOL_CHANGE_WITH_ZERO_STEP); + printf("\n"); + + write_bool_param("FLIP_BOARD_IN_Y", FLIP_BOARD_IN_Y); + printf("\n"); + + // Place a // in front of units not being used + if (OUTPUT_UNITS != U_MICRONS) printf("//"); + write_int_defined("OUTPUT_UNITS", "U_MICRONS"); + if (OUTPUT_UNITS != U_MILLIMETERS) printf("//"); + write_int_defined("OUTPUT_UNITS", "U_MILLIMETERS"); + if (OUTPUT_UNITS != U_MILS) printf("//"); + write_int_defined("OUTPUT_UNITS", "U_MILS"); + if (OUTPUT_UNITS != U_INCHES) printf("//"); + write_int_defined("OUTPUT_UNITS", "U_INCHES"); + } + if(fileerror()) + exit(1); + + if(pp_selection > -1) { + if (dlgMessageBox( + "If you have made manual changes to gcode-defaults.h, they" + " will be overwritten by your new gcode style selection.

    " + "(Click Yes if you aren't sure.)

    " + "Save your selection?", "Yes", "No") == 0) { + + filecopy(pp_files[pp_selection], + g_path + "/settings/gcode-defaults.h"); + + fileerror(); + set_current_profile(pp_auth_desc[pp_selection]); + if(fileerror()) + exit(1); + + m_setup_was_changed = YES; + } + } + + output(g_path + "/settings/pcb-gcode-options.h") { + printf("//\n"); + printf("// General Options "); + printf("// Your edits to this file will be overwritten" + " by the setup program.\n"); + printf("//\n"); + write_bool_param("SHOW_PROGRESS", SHOW_PROGRESS); + write_string_param("RESTORE_MENU_FILE", RESTORE_MENU_FILE); + write_bool_param("NC_FILE_COMMENT_FROM_BOARD", + NC_FILE_COMMENT_FROM_BOARD); + write_bool_param("NC_FILE_COMMENT_DATE", NC_FILE_COMMENT_DATE); + write_bool_param("NC_FILE_COMMENT_MACHINE_SETTINGS", + NC_FILE_COMMENT_MACHINE_SETTINGS); + write_bool_param("NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS", + NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS); + write_bool_param("USER_GCODE", USER_GCODE); + write_bool_param("g_debug_flag", g_debug_flag); + write_bool_param("COMPACT_GCODE", COMPACT_GCODE); + write_bool_param("USE_LINE_NUMBERS", USE_LINE_NUMBERS); + write_string_param("LINE_NUMBER_FORMAT", LINE_NUMBER_FORMAT); + write_bool_param("SHOW_PREVIEW", SHOW_PREVIEW); + + write_string_param("FILENAME_BASE", FILENAME_BASE); + write_string_param("FILENAME_TOP_ETCH_FILE", FILENAME_TOP_ETCH_FILE); + write_string_param("FILENAME_TOP_DRILL_FILE", FILENAME_TOP_DRILL_FILE); + write_string_param("FILENAME_TOP_MILL_FILE", FILENAME_TOP_MILL_FILE); + write_string_param("FILENAME_TOP_TEXT_FILE", FILENAME_TOP_TEXT_FILE); + write_string_param("FILENAME_TOP_FILL_FILE", FILENAME_TOP_FILL_FILE); + + write_string_param("FILENAME_BOT_ETCH_FILE", FILENAME_BOT_ETCH_FILE); + write_string_param("FILENAME_BOT_DRILL_FILE", FILENAME_BOT_DRILL_FILE); + write_string_param("FILENAME_BOT_MILL_FILE", FILENAME_BOT_MILL_FILE); + write_string_param("FILENAME_BOT_TEXT_FILE", FILENAME_BOT_TEXT_FILE); + write_string_param("FILENAME_BOT_FILL_FILE", FILENAME_BOT_FILL_FILE); + write_string_param("ETCH_FILE_NAME", ETCH_FILE_NAME); + write_string_param("DRILL_FILE_NAME", DRILL_FILE_NAME); + write_string_param("MILL_FILE_NAME", MILL_FILE_NAME); + write_string_param("TEXT_FILE_NAME", TEXT_FILE_NAME); + write_string_param("TOP_FILE_NAME", TOP_FILE_NAME); + write_string_param("BOT_FILE_NAME", BOT_FILE_NAME); + write_string_param("DEFAULT_EXTENSION", DEFAULT_EXTENSION); + + write_string_param("DEFAULT_DRILL_FILE", DEFAULT_DRILL_FILE); + } + + output(g_path + "/settings/pcb-machine.h") { + printf("//\n"); + printf("// For ease of use, and to avoid overwritting your settings,\n"); + printf("// use pcb-gcode-setup to make changes to these settings.\n"); + printf("//\n\n"); + write_real_param("DEFAULT_Z_HIGH", DEFAULT_Z_HIGH); + write_real_param("DEFAULT_Z_UP", DEFAULT_Z_UP); + write_real_param("DEFAULT_Z_DOWN", DEFAULT_Z_DOWN); + write_real_param("DRILL_DEPTH", DRILL_DEPTH); + write_real_param("DRILL_DWELL", DRILL_DWELL); + write_real_param("SPINDLE_ON_TIME", SPINDLE_ON_TIME); + write_real_param("MILLING_DEPTH", MILLING_DEPTH); + write_real_param("TEXT_DEPTH", TEXT_DEPTH); + write_real_param("TOOL_CHANGE_POS_X", TOOL_CHANGE_POS_X); + write_real_param("TOOL_CHANGE_POS_Y", TOOL_CHANGE_POS_Y); + write_real_param("TOOL_CHANGE_POS_Z", TOOL_CHANGE_POS_Z); + write_real_param("FEED_RATE", FEED_RATE); + write_real_param("FEED_RATE_Z", FEED_RATE_Z); + write_real_param("DEFAULT_WIDTH", DEFAULT_WIDTH); + write_real_param("X_OFFSET", X_OFFSET); + write_real_param("Y_OFFSET",Y_OFFSET); + write_real_param("X_HOME", X_HOME); + write_real_param("Y_HOME",Y_HOME); + write_real_param("EPSILON", EPSILON); + } + +} + +m_cmd = ""; +switch (Result) { + // Accept + case 1: + if (m_setup_was_changed) + m_cmd = "run pcb-gcode-setup;\n"; + break; + // Accept and make board + case 2: +// dlgMessageBox("g_path = \"" + g_path + "\""); + m_cmd = "run pcb-gcode;\n"; + break; +} + +if (SHOW_PROGRESS && RESTORE_MENU_FILE != "") { + m_cmd = "script " + RESTORE_MENU_FILE + ";\n" + m_cmd; +} +exit(m_cmd); diff --git a/trunk/ulp/pcb-gcode.ulp b/trunk/ulp/pcb-gcode.ulp new file mode 100644 index 00000000..446e2ad7 --- /dev/null +++ b/trunk/ulp/pcb-gcode.ulp @@ -0,0 +1,1115 @@ +// +// Generate g-code for milling PC boards. +// +// Copyright 2004-2013 by John Johnson Software, LLC. +// See readme.html for copyright information. +// +// See pcb-defaults.h, gcode-defaults.h and pcb-machine.h for options. +// + +#include "source/pcb-gcode.h" +#include "source/pcb-gcode-stack.h" +#include "settings/pcb-defaults.h" +#include "settings/pcb-machine.h" +#include "settings/gcode-defaults.h" +#include "settings/pcb-gcode-options.h" +#include "settings/user-gcode.h" +#include "source/math.h" +#include "source/drill.h" +#include "source/library.h" +#include "source/pcb-file-utils.h" +#include "source/filename_subs.h" + +#usage "

    pcb-gcode™ Gcode Generation Utility
    " + " Version 3.6.0.4

    " + "Copyright© 2004 - 2013 by John Johnson Software, LLC
    " + "All Rights Reserved

    " + "

    " + "Join the Yahoo! pcb-gcode group " + "http://groups.yahoo.com/group/pcb-gcode" + "
    or contact the author at pcbgcode@pcbgcode.org" + "
    " + "


    " + "This program generates g-code for 'mechanically etching' PC boards. " + "Using a CNC router or milling machine, you can make PC boards without using etching chemicals.

    " + "It will create files for the outlines of tracks, drilling holes, and milling cutouts in the board." + "
    See the readme.html file for more info.

    " + "There are many options in the setup program.
    " + "To setup which files are generated, and how, use the following command:
    " + "run pcb-gcode --setup

    " + "

    " + "If you want to produce a set of files without changing options, you can run pcb-gcode directly." + "Usage is as follows:
    " + "run pcb-gcode [option] [file]
    " + "Where:\n" + "" + "" + "" + "" + "" + "" + "
    OptionFunction
    --helpShow this help screen
    --setupRun the setup / configuration program
    fileIs the optional root filename.\n
    If not given, the board name is used as the root filename.
    " + "" + "" + "


    " + +g_width = DEFAULT_WIDTH; + +// Filename to output to. +string m_file_name = ""; + +// Which side we're currently working on. +g_side = TOP; + +// Tool currently being used. +int m_current_tool = 0; + +// Amount to isolate traces. +real m_isolate = 0.0; + +// Used to pass the pass info to the next pass of the program. +int m_pass_num; + +// The layer being worked on. +int m_layer; + +// Used to create command strings. +string g_cmd; +string g_cmd_temp; + +// Save the maximum and minimum coordinates. +real m_max_x; +real m_max_y; +real m_min_x; +real m_min_y; +void save_extents(real x, real y) +{ + m_max_x = max(m_max_x, x); + m_max_y = max(m_max_y, y); + m_min_x = min(m_min_x, x); + m_min_y = min(m_min_y, y); +} + +void preview() +{ + if (SHOW_PREVIEW) { + switch(get_os()) { + case OS_MACOSX: + system(g_path + "/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub"); + break; + case OS_LINUX: + system(g_path + "/source/viewer.linux.sh"); + break; + case OS_WINDOWS: + system(g_path + "/viewer/application.windows/viewer.exe"); + dlgMessageBox("Close this window when you have finished with the preview"); + break; + default: + Fatal("Oops!", "Can't figure out which OS you have."); + } + } +} +// +// Determine the next phase, and set g_phase accordingly. +// +// Params: none +// Return: none +// +void next_phase(void) +{ + if (g_phase == PH_TOP_OUT_GEN && GENERATE_TOP_OUTLINES != YES) { + g_phase += 2; + return; + } + if (g_phase == PH_BOTTOM_OUT_GEN && GENERATE_BOTTOM_OUTLINES != YES) { + g_phase += 2; + return; + } + + if (g_phase == PH_TOP_OUT_WRITE || g_phase == PH_BOTTOM_OUT_WRITE) { + if (m_isolate < ISO_MAX && !SINGLE_PASS) { + m_isolate += ISO_STEP; + m_pass_num++; + g_phase--; + } + else { + m_isolate = ISO_MIN; + m_pass_num = 0; + g_phase++; + + preview(); + } + } + else { + g_phase++; + } +} + +////////////////////////////////////////////////// +// +// Hole drilling routines. +// +////////////////////////////////////////////////// + +// +// Add a hole drilling command to the command string. +// +// Params: +// Size Drill size. +// x x coordinate. +// y y coordinate. +// Returns: +// none +// Changes: +// the stack +// +void add_hole(int req_size, int x, int y) +{ + string tempstr; + int drill_size; + + drill_size = get_drill_for(req_size); + + sprintf(tempstr, "%06d\t%06d\t%06d", drill_size, x, y); + stack_push(tempstr); +} + +/* + * Create a drill file for the desired side. + * + * Params: + * which_side Side to produce the file for. + * suffix Suffix to use for the file name (i.e. bd). + * Returns: + * none + * Changes: + * side +*/ +void drill(int which_side, string suffix) +{ + int num_lines; + int i; + real last_size; + string drill_args[]; + m_current_tool = 0; + real drill_size_mm; + real drill_size_inch; + real drill_size; + real drill_x; + real drill_y; + int drill_tool_num; + + g_side = which_side; + + // + // Build a stack with all the holes. + // + board(B) { + B.holes(H) add_hole(H.drill, H.x, H.y); + B.signals(S) S.vias(V) add_hole(V.drill, V.x, V.y); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + add_hole(C.pad.drill, C.pad.x, C.pad.y); + } + } + E.package.holes(H) add_hole(H.drill, H.x, H.y); + } + // B.elements + + // Sorts the drills by size, x and y. + stack_sort(); + + // + // Create the drill g-code file. + // + last_size = -1; + output(get_filename(), "wt") { + output_file_preamble(); + + // + // Create a tool table at the beginning of the file. + // + out(TOOL_CHANGE_TABLE_HEADER); + for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { + if (i==END_OF_STACK) break; + strsplit(drill_args, stack_elem(i), '\t'); + drill_size_inch = u2inch(my_strtol(drill_args[DRILL_SIZE])); + drill_size_mm = u2mm(my_strtol(drill_args[DRILL_SIZE])); + drill_size = my_strtol(drill_args[DRILL_SIZE]); + + if (drill_size != last_size) { + ++m_current_tool; + drill_tool_num = get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool); + out(TOOL_CHANGE_TABLE_FORMAT(drill_tool_num, + drill_size_mm, drill_size_inch, + g_mins[drill_tool_num], g_maxs[drill_tool_num], + g_drill_sub_cnt[drill_tool_num])); + } + last_size = drill_size; + } + // for + + // Set the mode for the user's UOM. + out(get_mode()); + out(ABSOLUTE_MODE); + + // + // Generate drill code. + // + m_current_tool = 0; + for (i=stack_fwd_iter(); i != END_OF_STACK; i=stack_fwd_next()) { + strsplit(drill_args, stack_elem(i), '\t'); + drill_size = units(my_strtol(drill_args[DRILL_SIZE])); + drill_x = scale_x(my_strtol(drill_args[DRILL_X])); + drill_y = scale_y(my_strtol(drill_args[DRILL_Y])); + save_extents(drill_x, drill_y); + + if (drill_size == last_size) { + output_drill_hole(drill_x, drill_y, DRILL_DEPTH); + } + else { + m_current_tool++; + // Tool change routine + output_tool_change_begin(); + out(SPINDLE_OFF); + rz(TOOL_CHANGE_POS_Z); + rxy(TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y); + out(fir(TOOL_CHANGE, get_tool_num_for(my_strtol(drill_args[DRILL_SIZE]), m_current_tool), drill_size)); + output_tool_changed(); + + if (DO_TOOL_CHANGE_WITH_ZERO_STEP == YES) { + output_tool_zero_begin(); + fzr(0.000, FEED_RATE_Z); + // fixme: wondering about the following line + out(fir(TOOL_CHANGE, m_current_tool, drill_size)); + output_tool_zero_end(); + } + + rz(DEFAULT_Z_UP); + out(fr(SPINDLE_ON, SPINDLE_ON_TIME)); + output_tool_change_end(); + + output_drill_first_hole(drill_x, drill_y, DRILL_DEPTH); + last_size = drill_size; + } + // if drill_size != last_size + } + // for + + output_file_postamble(); + + // End of file + // change back to tool 1 + out(fi(TOOL_CODE + EOL, 1)); + end_gcode(); + } + // output + } + // Board +} +// drill + +int m_first_spot_drill = YES; +void spot_drill_hole(int x, int y) +{ + real drill_x; + real drill_y; + + drill_x = scale_x(x); + drill_y = scale_y(y); + save_extents(drill_x, drill_y); + + if (m_first_spot_drill) { + output_drill_first_hole(drill_x, drill_y, SPOT_DRILL_DEPTH); + m_first_spot_drill = NO; + } + else { + output_drill_hole(drill_x, drill_y, SPOT_DRILL_DEPTH); + } +} + +void spot_drill(UL_BOARD B) +{ + if (SPOT_DRILL == NO) { return; } + + B.holes(H) spot_drill_hole(H.x, H.y); + B.signals(S) S.vias(V) spot_drill_hole(V.x, V.y); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) { + spot_drill_hole(C.pad.x, C.pad.y); + } + } + E.package.holes(H) spot_drill_hole(H.x, H.y); + } + // B.elements +} + +string m_lines; +string LINE_SEP = "\n"; +string COORD_SEP = ","; +string COORD_FMT = "%8.5f"; + +string coords(real x1, real y1, real x2, real y2) +{ + return frrrr(COORD_FMT + COORD_SEP + COORD_FMT + COORD_SEP + + COORD_FMT + COORD_SEP + COORD_FMT + LINE_SEP, x1, y1, x2, y2); +} + +// +// "Draw" on the output device, i.e. the gcode file. +// +// Params: +// x1,y1 Start of the line. +// x2,y2 End of the line. +// state +// z_down +// Returns: +// none +// +real m_arc_begin_x; +real m_arc_begin_y; +int pair_count = 0; +int MAX_COORDS_PER_LINE = 4; +void device_draw(int x1, int y1, int x2, int y2, int state, real z_down) +{ + real rx1, ry1, rx2, ry2; + + rx1 = scale_x(x1); + ry1 = scale_y(y1); + rx2 = scale_x(x2); + ry2 = scale_y(y2); + save_extents(rx1, ry1); + save_extents(rx2, ry2); + + // Output g-code based on the current state. + switch(state) { + + // Start of a new line. + case ST_START_LINE: + user_track_begin(rx1, ry1, rx2, ry2); + + m_lines += coords(rx1, ry1, rx2, ry2); + + rz(DEFAULT_Z_UP); + rxy(rx1, ry1); + fzr(z_down, FEED_RATE_Z); + fxyr(rx2, ry2, FEED_RATE); + pair_count = 0; + break; + + // A fill line. + case ST_FILL: + Fatal("Programmer Error", "The Fill functions are no longer supported."); + break; + + // Continue a line. + // End a line. + case ST_CONTINUE_LINE: + user_track_continue(rx1, ry1, rx2, ry2); + + m_lines += coords(rx1, ry1, rx2, ry2); + + if (COMPACT_GCODE == YES) { + if (pair_count == 0) { + fxy(rx2, ry2); + } + else { + xy(rx2, ry2); + } + pair_count++; + } + else { + fxy(rx2, ry2); + } + break; + + case ST_END_LINE: + user_track_end(rx1, ry1, rx2, ry2); + + m_lines += coords(rx1, ry1, rx2, ry2); + + + if (COMPACT_GCODE == YES) { + xy(rx2, ry2); + pair_count = 0; + } + else { + fxy(rx2, ry2); + } + break; + + // Drill a hole. + // todo is this valid? + case ST_DRILL: + printf("cause an error if used %d"); + // printf("drill (%f, %f)\n", rx2, ry2); + break; + + // Create an arc. + case ST_ARC_BEGIN: + user_arc_begin(rx1, ry1, rx2, ry2); + m_arc_begin_x = rx1; + m_arc_begin_y = ry1; + break; + + // Finish an arc. + case ST_ARC_END: + user_arc_end(rx1, ry1, rx2, ry2); + real cx = rx2; + real cy = ry2; + real end_x = rx1; + real end_y = ry1; + + if (1 /* USE_IJ_RELATIVE */) { + cx = rx2 - rx1; + cy = ry2 - ry1; + } + + rz(DEFAULT_Z_UP); + rxy(end_x, end_y); + fzr(z_down, FEED_RATE_Z); + if (g_side == TOP || MIRROR_BOTTOM == YES) { + out(frrrr(CIRCLE_TOP, m_arc_begin_x, m_arc_begin_y, cx, cy)); + } + else { + out(frrrr(CIRCLE_BOTTOM, m_arc_begin_x, m_arc_begin_y, cx, cy)); + } + break; + + } + // switch(state) +} +// device_draw + + +// +// Generate polygons for outline or fill. +// This creates a series of commands for Eagle and puts them +// in g_cmd to be passed when we exit from this phase of pcb-gcode. +// +// Params: +// which_side The side to operate on. +// Return: +// none +// +void generate_outlines(int which_side) +{ + string cmd_temp = ""; + + g_cmd = ""; + + if (which_side == TOP) + m_layer = TOP_LAYER; + else + m_layer = BOTTOM_LAYER; + + board(B) { + real f = BORDER_SIZE; + real x1 = units(B.area.x1) - f; + real y1 = units(B.area.y1) - f; + real x2 = units(B.area.x2) + f; + real y2 = units(B.area.y2) + f; + + B.signals(S) { + if (S.name == OUTLINES_SIGNAL_NAME) { + sprintf(cmd_temp, "delete (%f %f) (%f %f);\n", + x1, y1, x2, y2); + g_cmd = g_cmd + cmd_temp; + } + } + + sprintf(cmd_temp, "grid %s;\n" + "change isolate %f;\n" + "change rank 6;\n" + "change pour solid;\n" + "change width %f;\n" + "change orphans on;\n" + "layer %d;\n" + "polygon %s %f (%f %f) (%f %f) (%f %f) (%f %f) (%f %f);\n" + "ratsnest;\n" + , + UNIT_OF_MEASURE, + m_isolate, + g_width, + m_layer, + OUTLINES_SIGNAL_NAME, g_width, + x1, y1, x2, y1, x2, y2, x1, y2, x1, y1 + ); + g_cmd = g_cmd + cmd_temp; + return; + } + // board(B) +} +// generate_outlines + +void out_lines(string path, string mode) +{ + output(path, mode) { + if (m_pass_num == 0) { + printf("# board=%s\n", elided_path(get_filename(), 30)); + printf("# tool size=%f\n", g_width); + } + printf("# pass=%d\n", m_pass_num + 1); + printf(m_lines); + } +} + +// +// Write text from the Milling layer to a text engraving file. +// +// Params: +// file_name Output filename. +// Return: +// none +// +void output_text_code(string file_name) +{ + int state; + int old_x, old_y; + + board(B) { + output(get_filename(), "wt") { + user_file_opened(get_filename(), "wt"); + + output_file_preamble(); + + // Initialize the device (i.e. the output file). + begin_gcode(); + + // Process all the wires. + B.texts(T) T.wires(W) { + if ((T.mirror && g_side == BOTTOM) || (! T.mirror && g_side == TOP)) { + // If this is a text layer, check if we should continue + // a line, or start a new one. + if (W.layer == TEXT_LAYER) { + if (W.x1 == old_x && W.y1 == old_y) { + state = ST_CONTINUE_LINE; + } + else { + state = ST_START_LINE; + } + + // if this is an arc, it is treated specially. + if (W.arc) { + device_draw( W.arc.x1, W.arc.y1, W.arc.x2, W.arc.y2, ST_ARC_BEGIN, TEXT_DEPTH); + device_draw( W.arc.x2, W.arc.y2, W.arc.xc, W.arc.yc, ST_ARC_END, TEXT_DEPTH); + save_extents(W.x1, W.y1); + save_extents(W.x2, W.y2); + state = ST_START_LINE; + } + else { + // Draw the line (i.e. output the gcode for the line). + device_draw(W.x1, W.y1, W.x2, W.y2, state, TEXT_DEPTH); + old_x = W.x2; + old_y = W.y2; + save_extents(W.x1, W.y1); + save_extents(W.x2, W.y2); + } + // if (W.arc) + } + // if (W.layer == TEXT_LAYER) + } + // if (top and bottom check) + } + // T.wires + output_file_postamble(); + end_gcode(); + user_file_closing(); + } + // output + user_file_closed(get_filename(), "wt"); + } + // board + g_width = abs(TEXT_DEPTH); + out_lines(g_path + "/viewer/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt"); + + preview(); + + m_lines = ""; +} +// output_text_code + + +// +// Write layer data to mill files. +// +// Params: +// file_name Output filename. +// Return: +// none +// +void output_mill_code(string file_name) +{ + int state; + int old_x, old_y; + + board(B) { + output(get_filename(), "wt") { + user_file_opened(get_filename(), "wt"); + + output_file_preamble(); + + // Initialize the device (i.e. the output file). + begin_gcode(); + + // Process all the wires. + B.wires(W) W.pieces(P) { + // If this is a mill layer, check if we should continue + // a line, or start a new one. + if (P.layer == MILL_LAYER) { + if (P.x1 == old_x && P.y1 == old_y) { + state = ST_CONTINUE_LINE; + } + else { + state = ST_START_LINE; + } + + // if this is an arc, it is treated specially. + if (P.arc) { + device_draw( P.arc.x1, P.arc.y1, P.arc.x2, P.arc.y2, ST_ARC_BEGIN, MILLING_DEPTH); + device_draw( P.arc.x2, P.arc.y2, P.arc.xc, P.arc.yc, ST_ARC_END, MILLING_DEPTH); + save_extents(P.x1, P.y1); + save_extents(P.x2, P.y2); + state = ST_START_LINE; + } + else { + // Draw the line (i.e. output the gcode for the line). + device_draw(P.x1, P.y1, P.x2, P.y2, state, MILLING_DEPTH); + old_x = P.x2; + old_y = P.y2; + save_extents(P.x1, P.y1); + save_extents(P.x2, P.y2); + } + // if (P.arc) + } + // if (P.layer == MILL_LAYER) + } + // pieces + output_file_postamble(); + end_gcode(); + user_file_closing(); + } + // output + user_file_closed(get_filename(), "wt"); + } + // board + + g_width = abs(MILLING_DEPTH); + out_lines(g_path + "/viewer/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/applet/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", "wt"); + out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", "wt"); + + preview(); + + m_lines = ""; +} +// output_mill_code + + +// +// Write polygon lines to the file. +// +// Params: +// which_side Side of the board to work on. +// suffix Suffix of the file. +// task +// Return: +// none +// +void write_outlines(int which_side, string suffix, int task) +{ + string mode; + int x1 = INT_MAX, y1 = INT_MAX, x2 = INT_MIN, y2 = INT_MIN; + int x0, y0; + int first = 1; + int frame_wire; + int state; + + if (m_pass_num == 0) { + mode = "wt"; + } + else { + mode = "at"; + } + g_side = which_side; + switch (which_side) { + case TOP: + m_layer = TOP_LAYER; + break; + case BOTTOM: + m_layer = BOTTOM_LAYER; + break; + case MILL: + m_layer = MILL_LAYER; + break; + case TEXT: + m_layer = TEXT_LAYER; + break; + default: + sprintf(g_debug, "Illegal which_side %d in write_outlines", which_side); + Fatal("Sorry...", g_debug); + } + + if (m_layer == MILL_LAYER || m_layer == TEXT_LAYER) { + if (which_side == MILL) { + g_side = TOP; + output_mill_code(m_file_name + "mt" + DEFAULT_EXTENSION); + g_side = BOTTOM; + output_mill_code(m_file_name + "mb" + DEFAULT_EXTENSION); + return; + } + else { + g_side = TOP; + output_text_code(m_file_name + "tt" + DEFAULT_EXTENSION); + g_side = BOTTOM; + output_text_code(m_file_name + "tb" + DEFAULT_EXTENSION); + return; + } + } + // if m_layer == MILL_LAYER + + output(get_filename(), mode) { + board(B) { + user_file_opened(get_filename(), mode); + + int rubout_layer = -1; + B.layers(L) { + if (strstr(strlwr(L.name), "rubout") != -1) { + if (strstr(strlwr(L.name), "top") != -1 && which_side == TOP) { + rubout_layer = L.number; + } + else if (strstr(strlwr(L.name), "bot") != -1 && which_side == BOTTOM) { + rubout_layer = L.number; + } + } + } + + if (rubout_layer != -1) { + B.wires(W) { + if (W.layer == rubout_layer) { + device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN); + device_draw(W.x1, W.y1, W.x2, W.y2, ST_END_LINE, DEFAULT_Z_DOWN); // fixme needed? + } + } + } + + B.signals(S) { + if (S.name == OUTLINES_SIGNAL_NAME) { + S.polygons(P) { + P.wires(W) { + x1 = min(x1, W.x1); + x2 = max(x2, W.x1); + y1 = min(y1, W.y1); + y2 = max(y2, W.y1); + } + if (m_pass_num == 0) { + output_file_preamble(); + begin_gcode(); + } + else { + output_between_outline_passes(); + } + + switch (task) { + case TASK_OUTLINES: + // P.contours jtj + P.contours(W) { + if (first) { + x0 = W.x1; + y0 = W.y1; + frame_wire = (x0 == x1 || x0 == x2) && (y0 == y1 || y0 == y2); + state = ST_START_LINE; + first = 0; + } + else if (W.x2 == x0 && W.y2 == y0) { + state = ST_END_LINE; + first = 1; + } + else { + state = ST_CONTINUE_LINE; + } + + if (!frame_wire) { + device_draw(W.x1, W.y1, W.x2, W.y2, state, DEFAULT_Z_DOWN); + } + } + // P.contours(W) + break; + + case TASK_FILL: + P.fillings(W) { + device_draw(W.x1, W.y1, W.x2, W.y2, ST_START_LINE, DEFAULT_Z_DOWN); + } + break; + } + // switch(task) + + if (m_isolate >= ISO_MAX || SINGLE_PASS || task == TASK_FILL) { + output_file_postamble(); + rz(DEFAULT_Z_UP); + spot_drill(B); + end_gcode(); + } + + sprintf(g_cmd, "delete (%f %f) (%f %f);\n", + units(x1), units(y1), units(x2), units(y2) + ); + } + // polygons + } + // if(S.name == OUTLINES_SIGNAL_NAME) + } + // signals + } + // board + user_file_closing(); + } + // output + user_file_closed(get_filename(), mode); + out_lines(g_path + "/viewer/data/optimize_me.txt", mode); + out_lines(g_path + "/viewer/applet/data/optimize_me.txt", mode); + out_lines(g_path + "/viewer/application.macosx/data/optimize_me.txt", mode); + out_lines(g_path + "/viewer/application.linux/data/optimize_me.txt", mode); + out_lines(g_path + "/viewer/application.windows/data/optimize_me.txt", mode); + +} +// write_outlines + +/* string get_phase_name(int phase) +{ + return PHASE_NAME[phase]; +} + */ +void gen_progress_menu(int phase) +{ + output(path_scr[0] + '/' + "source/pcb-gcode-prg.scr") { + printf("MENU \\\n"); + for(int i = 1; i < PH_LAST_PHASE; i++) { + if (i == phase) { + printf("--%s-- \\\n", get_phase_name(i)); + // " (for TextMate) + } + else { + printf(" %s \\\n", get_phase_name(i)); + } + } + printf(";\n"); + } +} + +// Make sure a board is available to work on. +// todo move towards bottom +if (!board) { + Fatal("No board!", "Please run this program from the board editor"); +} + +// +// Process command line arguments. +// +switch (OUTPUT_UNITS) { + case U_MICRONS: + UNIT_OF_MEASURE = "mic"; + break; + case U_MILLIMETERS: + UNIT_OF_MEASURE = "mm"; + break; + case U_MILS: + UNIT_OF_MEASURE = "mil"; + break; + case U_INCHES: + UNIT_OF_MEASURE = "inch"; + break; +} + +if (argv[FILENAME_ARG] == "--setup") { + exit("run pcb-gcode-setup"); +} + +if (argv[FILENAME_ARG] == "--attr") { + string attrs; + board(B) { + B.attributes(A) { + attrs = attrs + A.name + "\t" + A.value + "\n"; + } + } + dlgMessageBox(attrs); + exit(0); +} + +if (argv[FILENAME_ARG] == "--help") { + int choice = dlgMessageBox(usage, "+Return to Eagle", "Run Setup Now"); + switch (choice) { + + // return to eagle + case 0: + exit(0); + break; + + // Run setup now + case 1: + exit("run pcb-gcode-setup"); + break; + } + exit(0); +} + +// Be sure a filename is specified. +if (argv[FILENAME_ARG]) { + m_file_name = argv[FILENAME_ARG]; + if (filedir(m_file_name) == "") { + board(B) m_file_name = filedir(B.name) + m_file_name; + } +} +else { + board(B) m_file_name = filesetext(B.name, ""); +} + +if (FILENAMES_8_CHARACTERS) { + m_file_name = filedir(m_file_name) + strsub(filename(m_file_name), 0, 5); +} + +// Use a default width if one is not given. +if (argv[WIDTH_ARG]) { + g_width = strtod(argv[WIDTH_ARG]); +} +else { + g_width = DEFAULT_WIDTH; +} + +// Get the isolate parameter or use the default. +if (argv[ISO_ARG]) { + m_isolate = strtod(argv[ISO_ARG]); +} +else { + m_isolate = ISO_MIN; +} + +// Get the pass number, or default to first pass (0). +if (argv[PASS_ARG]) { + m_pass_num = strtol(argv[PASS_ARG]); +} +else { + m_pass_num = 0; +} + +// Get the phase we are processing, or default to the first one. +if (argv[PHASE_ARG]) { + g_phase = strtol(argv[PHASE_ARG]); +} +else { + g_phase = PH_TOP_OUT_GEN; +} + +get_current_profile(); +if (g_phase == PH_TOP_OUT_GEN && m_pass_num == 0 && program_is_setup() == NO) +{ + exit("run pcb-gcode-setup"); +} + +// +// Do what we need to for this phase. +// +switch (g_phase) { + case PH_TOP_OUT_GEN: + if (GENERATE_TOP_OUTLINES == YES) + generate_outlines(TOP); + break; + case PH_TOP_OUT_WRITE: + if (GENERATE_TOP_OUTLINES == YES) + write_outlines(TOP, "top", OUTLINES); + break; + + case PH_TOP_FILL_GEN: + if (GENERATE_TOP_FILL == YES) + generate_outlines(TOP); + break; + case PH_TOP_FILL_WRITE: + if (GENERATE_TOP_FILL == YES) + write_outlines(TOP, "tf", FILL); + break; + + case PH_BOTTOM_OUT_GEN: + if (GENERATE_BOTTOM_OUTLINES == YES) + generate_outlines(BOTTOM); + break; + case PH_BOTTOM_OUT_WRITE: + if (GENERATE_BOTTOM_OUTLINES == YES) + write_outlines(BOTTOM, "bot", OUTLINES); + break; + + case PH_BOTTOM_FILL_GEN: + if (GENERATE_BOTTOM_FILL == YES) + generate_outlines(BOTTOM); + break; + case PH_BOTTOM_FILL_WRITE: + if (GENERATE_BOTTOM_FILL == YES) + write_outlines(BOTTOM, "bf", FILL); + break; + + case PH_TOP_DRILL: + if (GENERATE_TOP_DRILL == YES) + drill(TOP, "td"); + break; + case PH_BOTTOM_DRILL: + if (GENERATE_BOTTOM_DRILL == YES) + drill(BOTTOM, "bd"); + break; + + case PH_MILL: + if (GENERATE_MILLING == YES) + write_outlines(MILL, "mil", MILL_BOARD); + break; + + case PH_TEXT: + if (GENERATE_TEXT == YES) + write_outlines(TEXT, "txt", MILL_TEXT); + break; + + default: + sprintf(g_debug, "Illegal phase %d in main routine", g_phase); + Fatal("Sorry...", g_debug); +} + +// Set things up for the next phase. +next_phase(); + +if (SHOW_PROGRESS == YES) { + gen_progress_menu(g_phase); +} + +// If this is not the last phase, exit with a command line for +// Eagle to process. The command includes running this program again. +if (g_phase < PH_LAST_PHASE) { + sprintf(g_cmd, + "%s" + "window fit;\n" + "%s" + "run '%s' '%s' '%f' '%f' '%d' '%d';\n", + g_cmd, + (SHOW_PROGRESS) ? "script pcb-gcode-prg.scr;\n" : "", + argv[PROGRAM_NAME_ARG], m_file_name, g_width, m_isolate, + m_pass_num, g_phase + ); + exit(g_cmd); +} +else { + g_cmd = "window fit;\n"; + if (SHOW_PROGRESS) { + if (RESTORE_MENU_FILE != "") { + g_cmd = g_cmd + "script " + RESTORE_MENU_FILE + ";\n"; + } + else { + g_cmd = g_cmd + "menu;\n"; + } + } + + exit(g_cmd); +} diff --git a/trunk/ulp/pcb-service.ulp b/trunk/ulp/pcb-service.ulp new file mode 100644 index 00000000..afef1d3a --- /dev/null +++ b/trunk/ulp/pcb-service.ulp @@ -0,0 +1,660 @@ +#usage "en: PCB Quote Service" + "

    " + "Get a quote for manufacturing your PCB.
    ", + "de: PCB-Angebots-Service\n" + "

    " + "Hiermit gelangen Sie zu einem Angebot zur Fertigung Ihres Boards.

    " + "Autor: support@cadsoft.de

    " + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#require 5.1000 +int Version = 25; // Refer to versioning system. Needed because ULP version independent from EAGLE version + +enum { false = 0, true = 1 }; + +// Debug stuff +int Dbg = 0; +string DbgFile; +string DbgMsg; + +// Messages +string Warnings; +int Useless; // When a quote doesn't make sense (e.g empty board or such) + +// Design rules +int Export = 1; +string DruFile; + +// Units / scaling: Handling change of internal units V5 -> V6: +int UFactor = (EAGLE_VERSION < 6 && EAGLE_RELEASE < 12) ? 1 : 32; +int PrefUnit; // Preferred unit (representation in dialog) + +// Fabrication parameters +string BoardName; +int NrLayers; +int CopperThicknessOutside = INT_MAX; +int CopperThicknessInside = INT_MAX; +int MaterialThickness; +int MinTraceWidth = INT_MAX; +int MinHoleSize = INT_MAX; +string SolderSides; +string SilkScreenSides; +int NrBlindBuriedTypes; +int MinPitch = INT_MAX; +int NrSmdPadsTop; +int NrSmdPadsBottom; + +// Assembly parameters +int NrPackages; +int NrThruHoles; +int NrBGAs; +int NrQFNs; +int NrFinePitchs; +int NrOtherSMDs; +int HasSMDBothSides; + +// For computing width and height +real XMin = REAL_MAX, XMax = -REAL_MAX, YMin = REAL_MAX, YMax = -REAL_MAX; + +// Language support for dialogs: German/English +// Please keep to alphabetic sorting for better maintainability ! +string Dictionary[] = { + "en\v" + "de\v", + "Assembly Parameters:\v" + "Bestückungs-Parameter:\v", + "Board length (dimension Y):\v" + "Boardlänge (Y-Richtung):\v", + "Board name:\v" + "Boardname:\v", + "Board thickness:\v" + "Boarddicke:\v", + "Board width (dimension X):\v" + "Boardbreite (X-Richtung):\v", + "Board width and length could not be determined from dimension layer. \v" + "Boardbreite und -länge konnten nicht bestimmt werden anhand des Dimension-Layers. \v", + "Both Sides\v" + "beidseitig\v", + "Bottom Side\v" + "unten\v", + "Please use the dimension layer to design the board outline.\v" + "Bitte benutzen Sie den Dimension-Layer, um die Boardumrisse festzulegen.\v", + "Calculating quote parameters...\v" + "Berechne Angebots-Parameter...\v", + "Change Country:\v" + "Land wechseln:\v", + "Close\v" + "Schliessen\v", + "+Continue...\v" + "+Weiter...\v", + "Copper thickness outer layers:\v" + "Kupferstärke aussen:\v", + "Copper thickness inner layers:\v" + "Kupferstärke innen:\v", + "Estimate based on outer layers failed. \v" + "Schätzung basierend auf Aussen-Layer fehlgeschlagen. \v", + "Estimation based on outer layers. \v" + "Schätzung basierend auf Aussen-Layer. \v", + "Fabrication Parameters:\v" + "Fertigungs-Parameter:\v", + "Get PCB Quote\v" + "Zum PCB-Angebot\v", + "A quote for this board doesn't make sense yet !\v" + "Ein Angebot für dieses Board macht noch keinen Sinn !\v", + "If you want to get a quote anyway, please follow the link.\v" + "Wenn Sie dennoch ein Angebot erhalten wollen, folgen Sie bitte dem Link.\v", + "Information:\v" + "Hinweise:\v", + "Minimum hole size:\v" + "Kleinster Bohrdurchmesser:\v", + "Minimum SMD pitch:\v" + "Kleinster SMD-Abstand:\v", + "Minimum trace width (track width):\v" + "Kleinste Bahnbreite:\v", + "Minimum trace width could not be determined.\v" + "Minimale Bahnbreite konnte nicht bestimmt werden.\v", + "No copper found in the signal layers. \v" + "Kein Kupfer in den Signal-Layern vorhanden. \v", + "No\v" + "Nein\v", + "None\v" + "keine\v", + "Number of\v" + "Anzahl von\v", + "Number of blind or buried hole types:\v" + "Anzahl von Blind- oder Buried-Bohrungsarten:\v", + "Number of different packages:\v" + "Anzahl verschiedener Packages:\v", + "Number of fine pitch packages:\v" + "Anzahl von Fine-Pitch-Packages:\v", + "Number of other SMDs:\v" + "Anzahl sonstiger SMDs:\v", + "Number of SMD pads on bottom:\v" + "Anzahl von SMD-Pads unten:\v", + "Number of SMD pads on top:\v" + "Anzahl von SMD-Pads oben:\v", + "Number of thru hole packages: \v" + "Anzahl von durchkontaktierten Packages: \v", + "Number of layers:\v" + "Anzahl Layer:\v", + "Wire(s) and/or polygon(s) with zero width found on signal layer(s). \v" + "Bahnen und/oder Polygone mit Breite 0 in Signal-Layer(n) gefunden. \v", + "None of the signal layers are used.\v" + "Keines der Signal-Layer wird verwendet.\v", + "Parameters:\v" + "Parameter:\v", + "PCB Quote Service\v" + "PCB-Angebots-Service\v", + "Please start from Layout editor !\v" + "Bitte starten Sie vom Layout-Editor aus !\v", + "Silkscreen sides:\v" + "Bestückungsdruck-Seiten:\v", + "SMDs on both sides:\v" + "SMDs beidseitig:\v", + "Solder sides:\v" + "Lötseiten:\v", + "There are still airwires left.\v" + "Es sind noch Luftlinien vorhanden.\v", + "Top Side\v" + "oben\v", + "undefined\v" + "unbestimmt\v", + "Warnings:\v" + "Warnungen:\v", + "Yes\v" + "Ja\v", + "Your board layout is incomplete:\v" + "Ihr Board-Layout ist unvollständig:\v" +}; + +string DlgLang = language(); +if (DlgLang != "de") DlgLang = "en"; +int LangIdx = strstr(Dictionary[0], DlgLang) / 3; + +// Translate, based on dictionary +string tr(string s) { + string t = lookup(Dictionary, s, LangIdx, '\v'); + return t ? t : s; +} + +string Unknown = tr("undefined"); + +//- Auxiliary functions ------------------------------------------------------- + +string GetTargetURL() { + return "http://www.element14.com/community/community/knode/pcb_services"; +} + +// String handling +string I2Str(int i) { string str; sprintf(str, "%d", i); return str; } +string B2Str(int b) { return b ? "true" : "false"; } + +// HTML stuff +string LItem(string txt) { return "

  • " + txt + "
  • "; } +string Bold(string txt) { return "" + txt + ""; } + +// Unit handling +string U2MmStr(int i) { string str; sprintf(str, "%f", u2mm(i)); return str; } +string U2InStr(int i) { string str; sprintf(str, "%f", u2inch(i)); return str; } +string U2OzStr(int i) { string str; sprintf(str, "%f", i/(350.0 * UFactor)); return str; }// Todo: Check this ! +// Unit to preferred unit as String with extension ! +string U2PrefUStrExt(int i) { return (PrefUnit == GRID_UNIT_MM) ? U2MmStr(i) + " mm" : U2InStr(i) + " in"; } + +int Str2U(string s) { + if (strstr(s, "mm") > 0) return int(strtod(s) * 10000 * UFactor); + if (strstr(s, "mil") > 0) return int(strtod(s) * 10 * UFactor * 25.4); + if (strstr(s, "in") > 0) return int(strtod(s) * 10000 * UFactor * 25.4); + if (strstr(s, "mic") > 0) return int(strtod(s) * 10 * UFactor); + dlgMessageBox("Unknown unit in design rules !"); exit(EXIT_FAILURE); + return 0; +} + +//------------------------------------------------------- +// Get PCB parameters +//------------------------------------------------------- + +// Means really within, not at the borders +int Within(int val, int l, int u) { return (val > l) && (val < u); } + +int ValidBBox() { + return (XMin < REAL_MAX) && (XMax > -REAL_MAX) && + (YMin < REAL_MAX) && (YMax > -REAL_MAX) && + (XMax - XMin > 1000) && (YMax - YMin > 1000); // Could make this much bigger, but that's not crucial (currently 0.1 mm) +} + +/* +int CheckIfBGA(UL_PACKAGE LBRPAC) { +// board(B) B.libraries(L) L.packages(PAC) +// if (PAC.name == pacName) { + int i; + LBRPAC.contacts(C) { + LbrPacConXs[i] = C.x; + LbrPacConYs[i++] = C.y; + // Get grid dimensions + ConXMin = min(ConXMin, C.x); + conXMax = max(conXMax, C.x); + ConYMin = min(ConYMin, C.y); + conYMax = max(conYMax, C.y); + if (Dbg) { sprintf(DbgMsg, "LbrPac: (%f %f)\n", u2mm(LbrPacConXs[i-1]), u2mm(LbrPacConYs[i-1])); DbgTxt += DbgMsg; } + if (C.smd) { + ConDiam = C.smd.dx; + // All dx/dy must be equal + conDiamMin = min(conDiamMin, C.smd.dx); + conDiamMin = min(conDiamMin, C.smd.dy); + conDiamMax = max(conDiamMax, C.smd.dx); + conDiamMax = max(conDiamMax, C.smd.dy); + if (C.smd.roundness - 100 > roundTol) errRound = true; + } + else { + errType = true; + break; + } + } + } +}*/ + +// Update bounding box with another box +void UpdateBBoxBox(int xmin, int ymin, int xmax, int ymax) { + XMin = min(XMin, xmin); + XMax = max(XMax, xmax); + YMin = min(YMin, ymin); + YMax = max(YMax, ymax); +} + +void UpdateBBoxWire(UL_WIRE W, int layer) { + if (W.layer == layer) { + real w2 = W.width/2; + real xmin = min(W.x1 - w2, W.x2 - w2), ymin = min(W.y1 - w2, W.y2 - w2); + real xmax = max(W.x1 + w2, W.x2 + w2), ymax = max(W.y1 + w2, W.y2 + w2); + if (W.arc) { + if (W.arc.angle2 > 360) + xmax = W.arc.xc + W.arc.radius + w2; + if (((W.arc.angle1 < 90) && (W.arc.angle2 > 90)) || (W.arc.angle2 > 450)) + ymax = W.arc.yc + W.arc.radius + w2; + if (((W.arc.angle1 < 180) && (W.arc.angle2 > 180)) || (W.arc.angle2 > 540)) + xmin = W.arc.xc - W.arc.radius - w2; + if (((W.arc.angle1 < 270) && (W.arc.angle2 > 270)) || (W.arc.angle2 > 630)) + ymin = W.arc.yc - W.arc.radius - w2; + } + UpdateBBoxBox(xmin, ymin, xmax, ymax); + } +} + +void UpdateBBoxCircle(UL_CIRCLE C, int layer) { + if (C.layer == layer) { + real w2 = C.width / 2; + UpdateBBoxBox(C.x - C.radius - w2, C.y - C.radius - w2, C.x + C.radius + w2, C.y + C.radius + w2); + } +} + +void UpdateBBox(int layer, int el_origin) { + board(B) { + B.wires(W) UpdateBBoxWire(W, layer); + B.circles(C) UpdateBBoxCircle(C, layer); + B.elements(E) { + if (el_origin) UpdateBBoxBox(E.x, E.y, E.x, E.y); // Elements are always on signal layers. + E.package.wires(W) UpdateBBoxWire(W, layer); + E.package.circles(C) UpdateBBoxCircle(C, layer); + } + } +} + +void GetDruParams() { + string lines[]; + int nrlines = fileread(lines, DruFile); + if (nrlines == 0) dlgMessageBox("Error reading design rules !"); + int layer_used[], nrlayers, bottom_idx; + + for (int i = 0; i < nrlines; ++i) { + string words[]; + int nrwords = strsplit(words, lines[i], ' '); + if (nrwords < 3) continue; // Empty line or some other stuff + string keyword = words[0]; + if (keyword == "layerSetup") + for (int k = 1; k <= 16; ++k) { + string nr_pattern; + sprintf(nr_pattern, "[\\D]%d[\\D]", k); // Number, surrounded by 'no number character' + if (strxstr(words[2], nr_pattern) != -1) { + layer_used[k - 1] = true; + ++NrLayers; + bottom_idx = k - 1; + } + } + else if (keyword == "mtCopper") { + if (nrwords != 18) dlgMessageBox("Unexpected design rules !"); + int top_thickness = -1, bot_thickness; + for (int k = 2; k < nrwords; ++k) { + if (layer_used[k - 2]) { + int thickness = Str2U(words[k]); + if (top_thickness == -1) + top_thickness = thickness; + else if (k - 2 == bottom_idx) + bot_thickness = thickness; + else + CopperThicknessInside = min(thickness, CopperThicknessInside); + MaterialThickness += thickness; + } + } + CopperThicknessOutside = min(top_thickness, bot_thickness); + } + else if (keyword == "mtIsolate") { + if (nrwords != 17) dlgMessageBox("Unexpected design rules !"); + // n used layers => n-1 isolate layers. If only 1 layer, also 1 isolate layer. + for (int k = 2; k < nrwords; ++k) + if (layer_used[k - 2]) + MaterialThickness += Str2U(words[k]); + } + else if (keyword == "mdSmdSmd") + MinPitch = Str2U(words[2]); + } +} + +void CalcMinTraceWidth() { + board(B) { + B.wires(W) if (W.layer <= 16) MinTraceWidth = min(W.width, MinTraceWidth); + B.signals(S) { + S.polygons(P) if (P.layer <= 16) MinTraceWidth = min(P.width, MinTraceWidth); + S.wires(W) if (W.layer <= 16) MinTraceWidth = min(W.width, MinTraceWidth); + } + } +} + +void CheckHoles() { + int idx[], start[], end[], k; + board(B) { + B.holes(H) MinHoleSize = min(MinHoleSize, H.drill); + B.signals(S) S.vias(V) { + MinHoleSize = min(MinHoleSize, V.drill); + // Collect blind/buried holes ! + if ((V.start > 1) || (V.end < 16)) { + start[k] = V.start; + end[k] = V.end; + ++k; + } + } + B.elements(E) { + E.package.contacts(C) if (C.pad) + MinHoleSize = min(MinHoleSize, C.pad.drill); + E.package.holes(H) MinHoleSize = min(MinHoleSize, H.drill); + } + } + // NrBlindBuriedTypes: Find out how many different ones exist ! + sort(k, idx, start, end); + for (int l = 0, cur_s = 0, cur_e = 0; l < k; ++l) + if ((start[idx[l]] != cur_s) || (end[idx[l]] != cur_e)) { + ++NrBlindBuriedTypes; + cur_s = start[idx[l]]; + cur_e = end[idx[l]]; + } +} + +void GetPCBParams() { + // Check out layers: + int smask_top, smask_bottom, silk_top, silk_bottom; + int nr_used_layers; + board(B) { + BoardName = filename(B.name); + B.layers(L) if (L.used) + if (L.number <= 16) ++nr_used_layers; + else if (L.number == LAYER_TSTOP) smask_top = 1; + else if (L.number == LAYER_BSTOP) smask_bottom = 1; + else if (L.number == LAYER_TPLACE) silk_top = 1; // Could also take TNAMES/TVALUES. Leave the criterium less strict + else if (L.number == LAYER_BPLACE) silk_bottom = 1; // Could also take BNAMES/BVALUES. Leave the criterium less strict + } + SolderSides = smask_top ? (smask_bottom ? "Both Sides" : "Top Side") : + (smask_bottom ? "Bottom Side" : "None"); + SilkScreenSides = (silk_top) ? (silk_bottom ? "Both Sides" : "Top Side") : + (silk_bottom ? "Bottom Side" : "None"); + if (nr_used_layers == 0) { + Warnings += LItem(tr("None of the signal layers are used.")); + Useless = 1; + } + + // Board outlines: + UpdateBBox(LAYER_DIMENSION, 0); + if (!ValidBBox()) { + Warnings += "
  • " + tr("Board width and length could not be determined from dimension layer. "); + UpdateBBox(LAYER_TOP, 1); + UpdateBBox(LAYER_BOTTOM, 1); + if (!ValidBBox()) + Warnings += tr("Estimate based on outer layers failed. ") + + tr("Please use the dimension layer to design the board outline.") + "
  • "; + else + Warnings += tr("Estimation based on outer layers. ") + ""; + } + + CalcMinTraceWidth(); + if (MinTraceWidth == INT_MAX) + Warnings += LItem(tr("No copper found in the signal layers. ") + + tr("Minimum trace width could not be determined.")); + if (MinTraceWidth == 0) + Warnings += LItem(tr("Wire(s) and/or polygon(s) with zero width found on signal layer(s). ") + + tr("Minimum trace width could not be determined.")); + GetDruParams(); + CheckHoles(); + int air_wires = 0; + { // Check if there are still airwires: + board(B) { + B.wires(W) if (W.layer == LAYER_UNROUTED) air_wires = 1; + B.signals(S) { + S.polygons(P) if (P.layer == LAYER_UNROUTED) air_wires = 1; + S.wires(W) if (W.layer == LAYER_UNROUTED) air_wires = 1; + } + } + } + if (air_wires) + Warnings += LItem(tr("There are still airwires left.")); + + // Analysis of elements + // Alternative idea for performance optimization: + // Run SMD analysis over all library packages to avoid multiple runs + // Keep results in Arrays + string keyBGA = "BGA", keyQFN = "QFN"; + real sqLimitFinePitch = 0.5 * 0.5; // Square of the threshold for Fine Pitch (in mm) + board(B) B.elements(E) { + int isThruHole, isSMD; + E.package.contacts(C) + if (C.smd) { + isSMD = true; + if (C.smd.layer == LAYER_TOP) ++NrSmdPadsTop; + else ++NrSmdPadsBottom; + } + else + isThruHole = true; // Assuming there are no mixed versions + if (isThruHole) ++NrThruHoles; + else if (isSMD) { // There might also be the case of NO contacts ! + // Collect contacts in untransformed state to make geometrical checks ! + real conXs[], conYs[]; + int nrCons; + B.libraries(L) + if (L.name == E.package.library) L.packages(P) + if (P.name == E.package.name) P.contacts(C) { + conXs[nrCons] = u2mm(C.x); + conYs[nrCons++] = u2mm(C.y); + } + if (strstr(E.name, keyBGA) >= 0 || + strstr(E.package.name, keyBGA) >= 0 || + strstr(E.package.description, keyBGA) >= 0) { + // Plausibility check + ++NrBGAs; + } + else if (strstr(E.name, keyQFN) >= 0 || + strstr(E.package.name, keyQFN) >= 0 || + strstr(E.package.description, keyQFN) >= 0) { + // Plausibility check + ++NrQFNs; + } + else { + // if there's a contact pair with distance <= fine pitch limit it's a FINE Pitch, else it's an other SMD + for (int isFP = false, i = 0; i < nrCons && !isFP; ++i) + for (int j = i + 1; j < nrCons && !isFP; ++j) + if ((conXs[j] - conXs[i]) * (conXs[j] - conXs[i]) + + (conYs[j] - conYs[i]) * (conYs[j] - conYs[i]) <= sqLimitFinePitch) + isFP = true; + if (isFP) + ++NrFinePitchs; + else + ++NrOtherSMDs; + } + } + } + HasSMDBothSides = NrSmdPadsTop * NrSmdPadsBottom > 0; + + // Packages (number of unique elements) + // Only those with contacts ! + board(B) B.libraries(L) L.packages(P) P.contacts(C) { + ++NrPackages; + break; + } +} + +string MakeParamSendString() { + // Fab parameters: + // - Parameters that always can be determined: + string send = "?source=SBPCAD" + + "&boardName=" + BoardName + + "&numLayers=" + I2Str(NrLayers) + + "&materialThicknessMm=" + U2MmStr(MaterialThickness) + + "&materialThicknessIn=" + U2InStr(MaterialThickness) + + "&copperThicknessOutsideMm=" + U2MmStr(CopperThicknessOutside) + + "&copperThicknessOutsideOz=" + U2OzStr(CopperThicknessOutside) + + "&solderSides=" + SolderSides + + "&silkScreenSides=" + SilkScreenSides + + "&blindBuriedHoles=" + I2Str(NrBlindBuriedTypes) + + "&numPadsTop=" + I2Str(NrSmdPadsTop) + + "&numPadsBottom=" + I2Str(NrSmdPadsBottom); + // - Parameters that might miss: + if (ValidBBox()) + send += "&boardWidthMm=" + U2MmStr(XMax - XMin) + + "&boardWidthIn=" + U2InStr(XMax - XMin) + + "&boardLengthMm=" + U2MmStr(YMax - YMin) + + "&boardLengthIn=" + U2InStr(YMax - YMin); + if (Within(CopperThicknessInside, 0, INT_MAX)) + send += "&copperThicknessInsideMm=" + U2MmStr(CopperThicknessInside) + + "&copperThicknessInsideOz=" + U2OzStr(CopperThicknessInside); + if (Within(MinTraceWidth, 0, INT_MAX)) + send += "&minTraceWidthMm=" + U2MmStr(MinTraceWidth) + + "&minTraceWidthIn=" + U2InStr(MinTraceWidth); + if (MinPitch < INT_MAX) + send += "&minPitchMm=" + U2MmStr(MinPitch) + + "&minPitchIn=" + U2InStr(MinPitch); + if (MinHoleSize < INT_MAX) + send += "&minHoleSizeMm=" + U2MmStr(MinHoleSize) + + "&minHoleSizeIn=" + U2InStr(MinHoleSize); + // Assy parameters: + send += "&numPackages=" + I2Str(NrPackages) + + "&numBGAs=" + I2Str(NrBGAs) + + "&numQFNs=" + I2Str(NrQFNs) + + "&numFinePitch=" + I2Str(NrFinePitchs) + + "&numOtherSMDs=" + I2Str(NrOtherSMDs) + + "&numThruHoles=" + I2Str(NrThruHoles) + + "&hasSMDBothSides=" + B2Str(HasSMDBothSides); + + if (Dbg) output(DbgFile, "wba") printf("%s\n%s\n", GetTargetURL(), send); + return send; +} + +int Dialog() { + string Info[] = { + "Based on your board layout and the design rules, key parameters for manufacturing " + "your board like board size, minimum hole size etc. are determined. Your design " + "should be complete and have passed a DRC successfully.
    " + "By following the link below you get to the PCB quote site on Element14 where these " + "parameters are transferred. This way with a few steps you get a quote for manufacturing " + "your board." + , + "Basierend auf Ihr Board-Layout und den Designregeln werden wichtige Parameter zur Fertigung " + "des Boards ermittelt wie zum Beispiel Boardgrösse, kleinster Bohrdurchmesser usw. " + "Ihr Design sollte möglichst vollständig und ein erfolgreicher DRC durchgeführt worden sein.
    " + "Durch Klicken des Links unten gelangen Sie zur PCB-Angebotsseite auf Element14, wo diese " + "Parameter übernommen werden. Mit wenigen Schritten erhalten Sie so ein Angebot zur Fertigung " + "Ihres Boards." + }; + string url = ""; + return dlgDialog(tr("PCB Quote Service (Version " + I2Str(Version) + ")")) { + dlgHBoxLayout dlgSpacing(470); + dlgGroup(tr("Information:")) + dlgLabel(Info[LangIdx], 1); + if (Warnings) + dlgHBoxLayout + dlgGroup(tr("Warnings:")) + dlgLabel(Warnings); + if (!Useless) { + dlgGroup(tr("Fabrication Parameters:")) + dlgGridLayout { + int Row; + dlgCell(Row, 0) dlgLabel(tr("Number of layers:")); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrLayers))); + dlgCell(Row, 0) dlgLabel(tr("Board name:")); dlgCell(Row++, 1) dlgLabel(Bold(BoardName)); + dlgCell(Row, 0) dlgLabel(tr("Board width (dimension X):")); dlgCell(Row++, 1) dlgLabel(Bold(ValidBBox() ? U2PrefUStrExt(XMax - XMin) : Unknown)); + dlgCell(Row, 0) dlgLabel(tr("Board length (dimension Y):")); dlgCell(Row++, 1) dlgLabel(Bold(ValidBBox() ? U2PrefUStrExt(YMax - YMin) : Unknown)); + dlgCell(Row, 0) dlgLabel(tr("Board thickness:")); dlgCell(Row++, 1) dlgLabel(Bold(U2PrefUStrExt(MaterialThickness))); + dlgCell(Row, 0) dlgLabel(tr("Copper thickness outer layers:")); dlgCell(Row++, 1) dlgLabel(Bold(U2PrefUStrExt(CopperThicknessOutside))); + dlgCell(Row, 0) dlgLabel(tr("Copper thickness inner layers:")); dlgCell(Row++, 1) dlgLabel(Bold(Within(CopperThicknessInside, 0, INT_MAX) ? U2PrefUStrExt(CopperThicknessInside) : Unknown)); + dlgCell(Row, 0) dlgLabel(tr("Solder sides:")); dlgCell(Row++, 1) dlgLabel(Bold(tr(SolderSides))); + dlgCell(Row, 0) dlgLabel(tr("Silkscreen sides:")); dlgCell(Row++, 1) dlgLabel(Bold(tr(SilkScreenSides))); + dlgCell(Row, 0) dlgLabel(tr("Number of SMD pads on top:")); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrSmdPadsTop))); + dlgCell(Row, 0) dlgLabel(tr("Number of SMD pads on bottom:")); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrSmdPadsBottom))); + dlgCell(Row, 0) dlgLabel(tr("Number of blind or buried hole types:")); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrBlindBuriedTypes))); + dlgCell(Row, 0) dlgLabel(tr("Minimum trace width (track width):")); dlgCell(Row++, 1) dlgLabel(Bold(Within(MinTraceWidth, 0, INT_MAX) ? U2PrefUStrExt(MinTraceWidth) : Unknown)); + dlgCell(Row, 0) dlgLabel(tr("Minimum SMD pitch:")); dlgCell(Row++, 1) dlgLabel(Bold(MinPitch < INT_MAX ? U2PrefUStrExt(MinPitch) : Unknown)); + dlgCell(Row, 0) dlgLabel(tr("Minimum hole size:")); dlgCell(Row++, 1) dlgLabel(Bold(MinHoleSize < INT_MAX ? U2PrefUStrExt(MinHoleSize) : Unknown)); + } + dlgGroup(tr("Assembly Parameters:")) + dlgGridLayout { + int Row; + dlgCell(Row, 0) dlgLabel(tr("Number of different packages:")); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrPackages))); + dlgCell(Row, 0) dlgLabel(tr("Number of") + " BGAs:"); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrBGAs))); + dlgCell(Row, 0) dlgLabel(tr("Number of") + " QFNs:"); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrQFNs))); + dlgCell(Row, 0) dlgLabel(tr("Number of fine pitch packages:")); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrFinePitchs))); + dlgCell(Row, 0) dlgLabel(tr("Number of other SMDs:")); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrOtherSMDs))); + dlgCell(Row, 0) dlgLabel(tr("Number of thru hole packages: ")); dlgCell(Row++, 1) dlgLabel(Bold(I2Str(NrThruHoles))); + dlgCell(Row, 0) dlgLabel(tr("SMDs on both sides:")); dlgCell(Row++, 1) dlgLabel(Bold(HasSMDBothSides ? tr("Yes") : tr("No"))); + } + } + dlgHBoxLayout { + dlgStretch(1); + if (!Useless) + dlgLabel("" + url + tr("Get PCB Quote") + "", 1); + dlgStretch(1); + dlgPushButton(tr("Close")) dlgReject(); + } + }; +} + +//----------------------------------------------------------------------------- +// main section +//----------------------------------------------------------------------------- + +// Parse arguments +for (int i = 1; i <= argc; ++i) { + if (argv[i] == "-noexp") Export = 0; +} + +if (board) { + string dir = filedir(argv[0]); + board(B) DruFile = dir + "dl-" + filename(filesetext(B.name, ".dru")); + if (Export) + exit("DRC SAVE '" + DruFile + "';\nRUN '" + argv[0] + "' -noexp;"); + if (Dbg) board(B) { + DbgFile = filedir(B.name) + "/dbg-pcb-service.txt"; + output(DbgFile, "wba") printf("\nBoard: %s\n", filename(B.name)); + } + status(tr("Calculating quote parameters...")); + GetPCBParams(); + if (Warnings) { + string tmp = tr("Your board layout is incomplete:") + "
      " + Warnings + "
    "; + if (Useless) tmp += tr("A quote for this board doesn't make sense yet !"); + else tmp += tr("If you want to get a quote anyway, please follow the link."); + Warnings = tmp; + } + if (Dbg && Warnings) output(DbgFile, "wba") printf("Warnings: \n%s\n", Warnings); + board(B) { + int grU = B.grid.unit; + PrefUnit = (grU == GRID_UNIT_MM || grU == GRID_UNIT_MIC) ? GRID_UNIT_MM : GRID_UNIT_INCH; + } + while (Dialog() == 1); + exit(EXIT_SUCCESS); +} +else + dlgMessageBox(tr("Please start from board editor !")); diff --git a/trunk/ulp/pcb_gcode_is_setup b/trunk/ulp/pcb_gcode_is_setup new file mode 100644 index 00000000..2fb82301 --- /dev/null +++ b/trunk/ulp/pcb_gcode_is_setup @@ -0,0 +1,3 @@ +C:/ProgramPaolo/EAGLE-7.3.0/ulp/profiles/generic.pp +John Johnson +Tries to be very compatible diff --git a/trunk/ulp/pcbgcode.tmproj b/trunk/ulp/pcbgcode.tmproj new file mode 100644 index 00000000..7ff8c204 --- /dev/null +++ b/trunk/ulp/pcbgcode.tmproj @@ -0,0 +1,264 @@ + + + + + currentDocument + rakefile.rb + documents + + + expanded + + name + docs + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + docs + + + filename + pcb_gcode_is_setup + lastUsed + 2012-12-16T21:32:53Z + + + filename + pcb-gcode-setup.ulp + lastUsed + 2013-01-17T03:04:58Z + + + filename + pcb-gcode.ulp + lastUsed + 2013-01-17T03:05:09Z + + + filename + pcbgcode.tmproj + lastUsed + 2009-02-07T14:49:48Z + + + filename + plugin_headers.h + lastUsed + 2012-12-16T18:55:27Z + + + name + plugins + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + plugins + + + name + profiles + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + profiles + + + name + safe_options + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + safe_options + + + name + settings + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + settings + + + expanded + + name + source + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + source + + + filename + storage.nv + lastUsed + 2009-01-03T00:27:28Z + + + name + viewer + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + viewer + + + expanded + + name + make + regexFolderFilter + !.*/(\.[^/]*|CVS|_darcs|_MTN|\{arch\}|blib|.*~\.nib|.*\.(framework|app|pbproj|pbxproj|xcode(proj)?|bundle))$ + sourceDirectory + make + + + filename + rakefile.rb + lastUsed + 2013-01-17T03:13:04Z + selected + + + + filename + README + lastUsed + 2013-01-02T22:44:23Z + + + fileHierarchyDrawerWidth + 296 + metaData + + README + + caret + + column + 28 + line + 0 + + firstVisibleColumn + 0 + firstVisibleLine + 0 + + docs/changelog.txt + + caret + + column + 65 + line + 3 + + firstVisibleColumn + 0 + firstVisibleLine + 0 + + make/write_convert_units.rb + + caret + + column + 32 + line + 87 + + firstVisibleColumn + 0 + firstVisibleLine + 46 + + pcb-gcode-setup.ulp + + caret + + column + 31 + line + 204 + + firstVisibleColumn + 0 + firstVisibleLine + 183 + + pcb-gcode.ulp + + caret + + column + 21 + line + 23 + + firstVisibleColumn + 0 + firstVisibleLine + 2 + + rakefile.rb + + caret + + column + 76 + line + 43 + + firstVisibleColumn + 0 + firstVisibleLine + 41 + + source/pcb-gcode.h + + caret + + column + 0 + line + 190 + + columnSelection + + firstVisibleColumn + 0 + firstVisibleLine + 181 + selectFrom + + column + 23 + line + 190 + + selectTo + + column + 0 + line + 190 + + + + openDocuments + + pcb-gcode-setup.ulp + pcb-gcode.ulp + docs/changelog.txt + rakefile.rb + source/pcb-gcode.h + README + make/write_convert_units.rb + + showFileHierarchyDrawer + + windowFrame + {{339, 83}, {957, 795}} + + diff --git a/trunk/ulp/plugin_headers.h b/trunk/ulp/plugin_headers.h new file mode 100644 index 00000000..87474841 --- /dev/null +++ b/trunk/ulp/plugin_headers.h @@ -0,0 +1,4 @@ +#include "source/nonvolatile.h" + +#include "plugins/calculator.plugin.h" + \ No newline at end of file diff --git a/trunk/ulp/plugins/calculator.plugin b/trunk/ulp/plugins/calculator.plugin new file mode 100644 index 00000000..3d0645a5 --- /dev/null +++ b/trunk/ulp/plugins/calculator.plugin @@ -0,0 +1,75 @@ +dlgGroup("Calculator (RPN)") { + dlgGridLayout { + int row; + dlgCell(row, 0) { dlgLabel("Result"); } + dlgCell(row, 1, row, 3) { + dlgGroup("") { dlgLabel(m_result, 1); } + } + dlgCell(row, 4) dlgLabel(g_angle_mode_str, 1); + dlgCell(++row, 0) { dlgLabel("Entry"); } + dlgCell(row, 1, row, 3) dlgGroup("") { dlgLabel(m_entry, 1); } + dlgCell(++row, 0) dlgPushButton("7") calc_enter("7"); + dlgCell(row, 1) dlgPushButton("8") calc_enter("8"); + dlgCell(row, 2) dlgPushButton("9") calc_enter("9"); + dlgCell(row, 3) dlgPushButton("/") calc(m_entry, OP_DIVIDE); + dlgCell(row, 4) dlgPushButton("M+") calc(m_entry, OP_MEMORY_PLUS); + dlgCell(row, 5) dlgPushButton("deg") calc(m_entry, OP_DEGREE); + dlgCell(row, 6) dlgPushButton("rad") calc(m_entry, OP_RADIAN); + + dlgCell(++row, 0) dlgPushButton("4") calc_enter("4"); + dlgCell(row, 1) dlgPushButton("5") calc_enter("5"); + dlgCell(row, 2) dlgPushButton("6") calc_enter("6"); + dlgCell(row, 3) dlgPushButton("*") calc(m_entry, OP_MULTIPLY); + dlgCell(row, 4) dlgPushButton("->M") calc(m_entry, OP_MEMORY_STORE); + dlgCell(row, 5) dlgPushButton("sin") calc(m_entry, OP_SINE); + dlgCell(row, 6) dlgPushButton("arc sin") calc(m_entry, OP_ARC_SINE); + + dlgCell(++row, 0) dlgPushButton("1") calc_enter("1"); + dlgCell(row, 1) dlgPushButton("2") calc_enter("2"); + dlgCell(row, 2) dlgPushButton("3") calc_enter("3"); + dlgCell(row, 3) dlgPushButton("--") calc(m_entry, OP_SUBTRACT); + dlgCell(row, 4) dlgPushButton("<-M") calc(m_entry, OP_MEMORY_RECALL); + dlgCell(row, 5) dlgPushButton("cos") calc(m_entry, OP_COSINE); + dlgCell(row, 6) dlgPushButton("arc cos") calc(m_entry, OP_ARC_COSINE); + + dlgCell(++row, 0) dlgPushButton(".") calc_enter("."); + dlgCell(row, 1) dlgPushButton("0") calc_enter("0"); + dlgCell(row, 2) dlgPushButton("C") calc(m_entry, OP_CLEAR); + dlgCell(row, 3) dlgPushButton("++") calc(m_entry, OP_ADD); + dlgCell(row, 4) dlgPushButton("0->M") calc(m_entry, OP_MEMORY_CLEAR); + dlgCell(row, 5) dlgPushButton("tan") calc(m_entry, OP_TANGENT); + dlgCell(row, 6) dlgPushButton("arc tan") calc(m_entry, OP_ARC_TANGENT); + + dlgCell(++row, 2, row, 4) dlgPushButton("ENTER") { + set_accum(m_entry); + m_result = m_entry; + m_entry = ""; + dlgRedisplay(); + } + + dlgCell(row, 6) dlgPushButton("Help") { + dlgMessageBox("

    Help for the RPN Calculator

    " + "RPN stands for Reverse Polish Notation.
    " + "The calculator has a number in the Result line.
    " + "You enter a number in the Entry line, then select an operation, " + "like add, subtract, etc. The answer of that operation will be " + "put into the Result line, ready for a new operation.

    " + "Here is an example:" + "Let's say you have a part and you want to drill a hole on a circle " + "with a 5" radius, 37° counter-clockwise " + "from the center at X=1.2, Y=2.4.
    " + "Enter the following:
    " + "37 [sin]
    " + "5 [*]
    " + "1.2 [+]
    " + "The answer is 4.209. That is the Y coordinate
    " + "37 [cos]
    " + "5 [*]
    " + "2.4 [+]
    " + "The answer is 6.393, that is the X coordinate

    " + "I guess that is a complex example :-)" + ); + } + + } +} \ No newline at end of file diff --git a/trunk/ulp/plugins/calculator.plugin.h b/trunk/ulp/plugins/calculator.plugin.h new file mode 100644 index 00000000..4f690d1b --- /dev/null +++ b/trunk/ulp/plugins/calculator.plugin.h @@ -0,0 +1,297 @@ +/********************************************************** + * + * A basic calculator. + * + * Plugin Definitions + * NAME = calculator + * DESC = Basic calculator + * AUTHOR = John Johnson + * TAB_NAME = Plugins + **********************************************************/ + +int UNARY_BEGIN = 0x80; +int ANGLE_IN = 0x40; +int ANGLE_OUT = 0x20; + +enum { + OP_INVALID, + OP_CLEAR, + OP_ENTER, + OP_ADD, + OP_SUBTRACT, + OP_DIVIDE, + OP_MULTIPLY, + OP_RADIAN, + OP_DEGREE +}; + +enum { + OP_MEMORY_PLUS = 0x80 /* UNARY_BEGIN */, + OP_MEMORY_STORE, + OP_MEMORY_RECALL, + OP_MEMORY_CLEAR +}; + +enum { + OP_SINE = 0xC0 /* UNARY_BEGIN + ANGLE_IN */, + OP_COSINE, + OP_TANGENT, + OP_ARC_SINE, + OP_ARC_COSINE, + OP_ARC_TANGENT +}; + +enum { + OP_INV_SINE = 0xA0 /* UNARY_BEGIN + ANGLE_OUT */, + OP_INV_COSINE, + OP_INV_TANGENT +}; + +enum { + ANG_INVALID, + ANG_RADIAN, + ANG_DEGREE + /* ANG_GRADIANS - sorry */ +}; + +int m_angle_mode; +string g_angle_mode_str; +int g_memory; + +real accum; +real depth; +int passes; +string nc_file; +int unit_metric; +real length; +string result; + +string m_result = "0"; +string m_entry = "0"; + +string format_number(real n) +{ + string tmp; + + sprintf(tmp, "%f", n); + return tmp; + +} + +real set_accum(string s) +{ + accum = strtod(s); + return accum; +} + +string set_result(real r) +{ + m_result = format_number(r); +// set_nv_param("calc_result", m_result); + return m_result; +} + +real set_angle_mode(int mode) +{ + real result; + string num; + int used_entry; + + result = strtod(m_result); + + if (m_entry != "") { + num = m_entry; + used_entry = 1; + } + else if (m_result != "") { + num = m_result; + } + else { + num = m_result; + } + + if (m_angle_mode == ANG_DEGREE && mode == ANG_RADIAN) { + result = strtod(num) / 180 * PI; + } + else if (m_angle_mode == ANG_RADIAN && mode == ANG_DEGREE) { + result = strtod(num) / PI * 180; + } + m_angle_mode = mode; + + switch (m_angle_mode) { + case ANG_RADIAN: + g_angle_mode_str = "rad"; + break; + case ANG_DEGREE: + g_angle_mode_str = "deg"; + break; + } + +// set_nv_param("calc_angle_mode", g_angle_mode_str); + +// if (used_entry) { + m_entry = format_number(result); +// } +// else { + set_result(result); +// }*/ + return result; +} + +string get_mode_str() +{ + return (m_angle_mode == ANG_RADIAN) ? "rad" : "deg"; +} + +real rad(real n) +{ + return (m_angle_mode == ANG_RADIAN) ? n : n / 180 * PI; +} + +real unrad(real n) +{ + return (m_angle_mode == ANG_RADIAN) ? n : n / PI * 180; +} + +int is_unary(int op) +{ + return (op & UNARY_BEGIN) ? 1 : 0; +} + +void set_memory(real n) +{ + string tmp; + + g_memory = n; +// set_nv_param("calc_memory", format_number(n)); +} + +real get_memory() +{ + return g_memory; +} + +void clear_memory() +{ + g_memory = 0; +} + +int m_entering; +void calc_enter(string n) +{ + if (!m_entering) { + m_entry = n; + m_entering = 1; + } + else { + m_entry += n; + } +} + +real calc(string a, int OPERATION) +{ + real ra; + int no_clear; + + m_entering = 0; + + ra = strtod(a); + if (m_entry == "" && m_result != "" && is_unary(OPERATION)) + ra = strtod(m_result); + + if (OPERATION & ANGLE_IN) { + ra = rad(ra); + } + + switch(OPERATION) { + case OP_ENTER: + accum = ra; + set_result(accum); + break; + case OP_ADD: + accum = accum + ra; + break; + case OP_SUBTRACT: + accum = accum - ra; + break; + case OP_DIVIDE: + accum = accum / ra; + break; + case OP_MULTIPLY: + accum = accum * ra; + break; + case OP_DEGREE: + accum = set_angle_mode(ANG_DEGREE); + break; + case OP_RADIAN: + accum = set_angle_mode(ANG_RADIAN); + break; + + case OP_MEMORY_PLUS: + set_memory(ra + get_memory()); + accum = ra; + break; + case OP_MEMORY_STORE: + set_memory(ra); + accum = ra; + break; + case OP_MEMORY_RECALL: + m_entry = format_number(get_memory()); + no_clear = 1; + accum = ra; + break; + case OP_MEMORY_CLEAR: + clear_memory(); + accum = ra; + break; + + case OP_COSINE: + accum = cos(ra); + break; + case OP_SINE: + accum = sin(ra); + break; + case OP_TANGENT: + accum = tan(ra); + break; + + case OP_ARC_COSINE: + accum = acos(ra); + break; + case OP_ARC_SINE: + accum = asin(ra); + break; + case OP_ARC_TANGENT: + accum = atan(ra); + break; + + case OP_CLEAR: + accum = 0; + break; + default: + dlgMessageBox("Invalid OPERATION"); + } + + if (OPERATION & ANGLE_OUT) { + accum = unrad(accum); + } + + set_result(accum); + if (!no_clear) m_entry = ""; + return accum; +} + +/********************************** + * Initialization. + **********************************/ + +set_angle_mode(ANG_DEGREE); + + +//~ set_memory(strtod(get_nv_param("calc_memory", "0.0", 0 /* don't abort */))); +//~ if (get_nv_param("calc_angle_mode", "deg", 0 /* don't abort */) == "deg") +//~ set_angle_mode(ANG_DEGREE); +//~ else +//~ set_angle_mode(ANG_RADIAN); +//~ set_result(strtod(get_nv_param("calc_result", "0.0", 0 /* don't abort */))); + diff --git a/trunk/ulp/plugins/filenames.plugin b/trunk/ulp/plugins/filenames.plugin new file mode 100644 index 00000000..db5ce481 --- /dev/null +++ b/trunk/ulp/plugins/filenames.plugin @@ -0,0 +1,32 @@ +dlgGroup("File Naming") { + dlgHBoxLayout { + dlgLabel("Filename Base "); dlgStringEdit(FILENAME_BASE); + } + dlgGroup("Top (Component) Side Files") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Etching "); + dlgCell(1, 1) dlgStringEdit(FILENAME_TOP_ETCH_FILE); + dlgCell(2, 0) dlgLabel("Drill "); + dlgCell(2, 1) dlgStringEdit(FILENAME_TOP_DRILL_FILE); + dlgCell(3, 0) dlgLabel("Mill "); + dlgCell(3, 1) dlgStringEdit(FILENAME_TOP_MILL_FILE); + dlgCell(4, 0) dlgLabel("Fill "); + dlgCell(4, 1) dlgStringEdit(FILENAME_TOP_FILL_FILE); + } + } + dlgGroup("Bottom (Solder) Side Files") { + dlgGridLayout { + dlgCell(1, 0) dlgLabel("Etching "); + dlgCell(1, 1) dlgStringEdit(FILENAME_BOT_ETCH_FILE); + dlgCell(2, 0) dlgLabel("Drill "); + dlgCell(2, 1) dlgStringEdit(FILENAME_BOT_DRILL_FILE); + dlgCell(3, 0) dlgLabel("Mill "); + dlgCell(3, 1) dlgStringEdit(FILENAME_BOT_MILL_FILE); + dlgCell(4, 0) dlgLabel("Fill "); + dlgCell(4, 1) dlgStringEdit(FILENAME_BOT_FILL_FILE); + } + } + dlgPushButton("Test Filenames") { + dlgMessageBox("Test"); + } +} diff --git a/trunk/ulp/plugins/plugin_headers.h b/trunk/ulp/plugins/plugin_headers.h new file mode 100644 index 00000000..3cc01ef2 --- /dev/null +++ b/trunk/ulp/plugins/plugin_headers.h @@ -0,0 +1,4 @@ +#include "nonvolatile.h" + +#include "plugins/calculator.plugin.h" + \ No newline at end of file diff --git a/trunk/ulp/plugins/plugin_loader.h b/trunk/ulp/plugins/plugin_loader.h new file mode 100644 index 00000000..b668c2ea --- /dev/null +++ b/trunk/ulp/plugins/plugin_loader.h @@ -0,0 +1,40 @@ +/* + * Generate g-code for milling PC boards. + * + * Copyright 2004-2009 by John Johnson Software, LLC. + * See readme.html for copyright information. + * + */ + +// BEGIN_PLUGIN_INCLUDES +dlgVBoxLayout { + dlgHBoxLayout { +/* dlgVBoxLayout { + dlgGroup("Square X and Y (doesn't do anything)") { + #include "square_x_and_y.plugin" + } + dlgStretch(1); + } + dlgVBoxLayout { + dlgGroup("Square Z") { + #include "square_z.plugin" + } + dlgStretch(1); + } + dlgVBoxLayout { + dlgGroup("Filenames") { + #include "filenames.plugin" + } + dlgStretch(1); + }*/ + } + dlgHBoxLayout { + dlgStretch(1); + dlgVBoxLayout { + #include "calculator.plugin" + } + dlgStretch(1); + } + dlgStretch(1); +} +// END_PLUGIN_INCLUDES diff --git a/trunk/ulp/plugins/square_x_and_y.plugin b/trunk/ulp/plugins/square_x_and_y.plugin new file mode 100644 index 00000000..a06135d5 --- /dev/null +++ b/trunk/ulp/plugins/square_x_and_y.plugin @@ -0,0 +1,37 @@ +//Square X Y/Helps you square the X and Y axes of your machine./john + +/********************************************************** + * + * Diagnostic to help people square their machines in + * the X and Y axes. + * + * Plugin Definitions + * NAME = square X and Y + * DESC = Helps a user square their machine. + * AUTHOR = John Johnson + * TAB_NAME = Plugins + **********************************************************/ +real depth; +int passes; +string nc_file; +int unit_metric; +real length; +string result; + +dlgGridLayout { + dlgCell(0, 0, 0, 3) { + dlgCheckBox("Use Metric", unit_metric) { dlgRedisplay(); } + } + dlgCell(1, 0) { dlgLabel("Length"); dlgRealEdit(length); } + dlgCell(2, 0) { dlgLabel("Passes"); dlgIntEdit(passes); } + dlgCell(3, 0) { dlgLabel("Depth"); dlgRealEdit(depth); } + dlgCell(4, 0) { dlgLabel("NC File"); dlgStringEdit(nc_file); + dlgPushButton("...") { + nc_file = dlgFileSave("Save gcode as..."); + } + } + dlgCell(1,1) { + sprintf(result, "tan(45) = %f", tan(PI / 4)); + dlgLabel(result, 1); + } +} diff --git a/trunk/ulp/plugins/square_z.plugin b/trunk/ulp/plugins/square_z.plugin new file mode 100644 index 00000000..7bacb7a6 --- /dev/null +++ b/trunk/ulp/plugins/square_z.plugin @@ -0,0 +1,15 @@ +//Square X Y/Helps you square the X and Y axes of your machine./john + +/********************************************************** + * + * Diagnostic to help people square their machines in + * the X and Y axes. + * + * Plugin Definitions + * NAME = square X and Y + * DESC = Helps a user square their machine. + * AUTHOR = John Johnson + * TAB_NAME = Plugins + **********************************************************/ + +dlgLabel("Nice layout here"); diff --git a/trunk/ulp/prevdevdescript.ulp b/trunk/ulp/prevdevdescript.ulp new file mode 100644 index 00000000..9bfca6d5 --- /dev/null +++ b/trunk/ulp/prevdevdescript.ulp @@ -0,0 +1,42 @@ +#usage "Edit previous device description\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string dev[]; +string edit = ""; +int count = 0; +int n = 0; + +if (library) library(L) { + L.devicesets(D) { + count++; + dev[count] = D.name; + cmd += D.name + "\n"; + } + } + +if (deviceset) deviceset(D) { + edit = D.name; + } + +for (n = 1; n < count; n++) { + if (edit == dev[n]) { + break; + } + } + +if (n > 1) { + cmd = "EDIT " + dev[n - 1] + ".dev; DESCRIPT\n" ; + // ************************************************** + // a ";" must not follow DESCRIPT + // otherwise the description is overwritten + // with an empty string + // ************************************************** + } +else + cmd = "EDIT " + dev[1] + ".dev; DESCRIPT\n" ; + +exit(cmd); diff --git a/trunk/ulp/prevpacdescript.ulp b/trunk/ulp/prevpacdescript.ulp new file mode 100644 index 00000000..b7648c45 --- /dev/null +++ b/trunk/ulp/prevpacdescript.ulp @@ -0,0 +1,43 @@ +#usage "Edit previous package description\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string pac[]; +string edit = ""; +int count = 0; +int n = 0; + +if (library) library(L) { + L.packages(P) { + count++; + pac[count] = P.name; + cmd += P.name + "\n"; + } + } + +if (package) package(P) { + edit = P.name; + } + +for (n = 1; n < count; n++) { + if (edit == pac[n]) { + break; + } + } + +if (n > 1) { + cmd = "EDIT " + pac[n - 1] + ".pac;\n DESCRIPT\n" ; + // ************************************************** + // a ";" must not follow DESCRIPT + // otherwise the description is overwritten + // with an empty string + // ************************************************** + } + +else + cmd = "EDIT " + pac[0] + ".pac;\n DESCRIPT\n" ; + +exit(cmd); diff --git a/trunk/ulp/print-inductor-ulp.bmp b/trunk/ulp/print-inductor-ulp.bmp new file mode 100644 index 00000000..16d5e9fd Binary files /dev/null and b/trunk/ulp/print-inductor-ulp.bmp differ diff --git a/trunk/ulp/print-inductor.ulp b/trunk/ulp/print-inductor.ulp new file mode 100644 index 00000000..cf78839d --- /dev/null +++ b/trunk/ulp/print-inductor.ulp @@ -0,0 +1,587 @@ +#usage "This ULP calculates and place a coil with and with out ferrit kernel.

    " + "Depending from where you are starting the ULP, places pads (library) or vias (board).

    " + "The calculation of coils or inductivities depends on a lot of " + "different factors, like
    " + " -- basic material of the board
    " + " -- thickness of the board
    " + " -- number of layers
    " + " -- thickness of the layers
    " + " -- distances between elements
    " + " -- tracks
    " + " -- copper areas / ground plains
    " + " -- thickness of the copper layers
    " + " -- track width
    " + " -- distances between tracks
    " + " -- surface of tracks (tin?)
    " + " -- the signal's frequency
    " + " -- ...
    " + "All these factors should be taken into consideration for the formula !
    " + "used below to calculate an exact value for a coil. Nevertheless it !
    " + "is necessary to check the result by a practical measurement. It is !
    " + "very difficult to generate coils with exact values this way.
    " + "Generally one can say that printed coils can be used in the MHz range only.
    " + "Author: support@cadsoft.de,
    "; + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, +// EXPRESSED OR IMPLIED. + + +// **************----- german description -------------*************** +string deHelp = + "Dieses ULP berechnet eine Spiralspule mit oder ohne Ferritkern.

    " + + "Dieses ULP kann in der Libary ebenso wie im Board benutzt werden.
    " + + "Je nachdem ob Sie es von einer Library oder von einem Borad aus " + "starten, werden Pads bzw. Vias plaziert.
    " + + "
    " + + "Die Berechnung der Windungen bzw. der Induktivität hängt von vielen Faktoren ab, wie z.B.:
    " + + " - Basismaterial
    " + + " - Stärke der Leiterplatte
    " + + " - Anzahl der Lagen
    " + + " - Dicke der Lagen
    " + + " - Abstand zu benachbarten Bauteilen, Leitungen, Kupferflächen, Masseflächen etc.
    " + + " - Dicke der Kupferbeschichtung
    " + + " - Breite der Leiterbahn (unterätzen)
    " + + " - Abstand zwischen den Leiterbahnen (Spiralkreise / Ätzgenauigkeit)
    " + + " - Oberfläche der Leiterbahn (Verzinnt)
    " + + " - Signal-Frequenz
    " + + " - ...
    " + + "Um daraus einen einigermassen genauen Wert zu berechnen, müßten alle oben genannten Faktoren
    " + + "als Korrekturwerte in die Formel einfliessen.
    " + + "Was aber in jedem Fall durch entspechende Messungen nachgeprüft werden müßte.
    " + + "In der Praxis sind Printspulen mit genau definierten Werten und in engen Toleranzen " + + "nur sehr schwer herzustellen.
    " + + "Im Allgemeinen kann man davon ausgehen, dass Printspulen nur im MHz Bereich " + + "einigermassen Nutzbar sind.
    " + + "Author: support@cadsoft.de,
    "; + +string Help = usage; + +if (language() == "de") Help = deHelp; + +// 05.06.2002 alf@cadsoft.de +// 24.01.2005 alf@cadsoft.de + +// *** all Parameter generated in MM *** +// parameter section + +real n = 9.0; // turns +real wireWidth_mm = 0.2; // track width +real wireDistance_mm = 0.3; // min. distance between tracks +real distance_e = 0.3; // distance first wound to Ferrit +real PVdiameter = 0.5; // pad/via diameter +real PVdrill = 0.4; // drill diameter +real ferrit_length_L = 5.5; +real ferrit_length_K = 2.0; +real ferrit_length_K1 = 2.0; +real distance_h = 5.3; +real offx = 0.0; +real offy = 0.0; +int Layer = 1; +string Shape = "ROUND"; // Pad/Via shape do not change !!! +string solderpoint = ""; +string dimlayer = ";\nChange Layer 20;\n"; + +int undo_off_on = 1; +string file; + +real ferrit_old_L = ferrit_length_L; +real ferrit_old_K = ferrit_length_K; +real ferrit_old_K1 = ferrit_length_K1; // with of outher ferrit kernel + +int arcresolution = 10; // Arc resolution +real turn_degree = 90; +int degree_resol = turn_degree / arcresolution; // *** Degree resolution + +string Spiral_H = ""; +string cmd = ""; +string s; +int cflag = 0; +int fullturn = 0; // Flag + +// ********* functions ******************************* +void show(string s) { + dlgDialog("Show CMD") { + dlgHBoxLayout dlgSpacing(300); + dlgHBoxLayout { + dlgVBoxLayout { + dlgSpacing(500); + } + dlgTextEdit(s); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") { dlgReject(); exit(0); } + dlgStretch(1); + } + }; + return; +} + +// *** calculate arc coordinate *** +string xyArc(real angle, real radiusx, real radiusy, real offsetx, real offsety) { + string tmp; + real rad = PI / 180 * angle; + sprintf(tmp, "(%.4f %.4f)\n", + cos(rad) * radiusx + offsetx, + sin(rad) * radiusy + offsety ); + return tmp; +} + +// *** interpolate arc coodinates from startarc to endarc *** +string spiral(real sRadius, real eRadius, real startArc, real endArc, real aresolution, real ox, real oy ) { + string e = ""; + if (startArc > endArc) { dlgMessageBox("Start ARC > End ARC", "OK"); return ""; } + real stepangle = aresolution; // (endArc - startArc) / aresolution; + real ellips = 0; + if (aresolution) ellips = (eRadius - sRadius) / ((endArc - startArc) / aresolution); + int step = 0; + for (real angle = startArc; angle <= endArc; angle += stepangle) { + e += xyArc(angle, sRadius + ellips * step, sRadius + ellips * step, ox, oy); + step++; + } + if (angle != endArc) { + step--; + e += xyArc(endArc, sRadius + ellips * step, sRadius + ellips * step, ox, oy); + } + return e + "\n"; +} + + + // place a Pad (Via) on startpoint +string PadViaS(string command, real x1, real y1, real angle, real g, real ox, real oy) { + real p = x1 + (wireWidth_mm / 2) - (PVdiameter / 2); // + sprintf( s, "%s %s", command, xyArc(angle, p, 0.0, ox, oy) ); + return s; +} + + + // place a Pad (Via) on endpoint +string PadViaE(string command, real x1, real y1, real angle, real g, real ox, real oy) { + real pRadius = y1 + ((x1 - y1) / 180 * g) + (PVdiameter / 2) - (wireWidth_mm / 2) ; + sprintf( s, "%s %s", solderpoint, xyArc(angle, pRadius, pRadius, ox, oy) ); + return s; +} + + + +void doit(void) { + real Ndist = (wireDistance_mm + wireWidth_mm ) ; // distance ARC to ARC + int fullwind = trunc(n); // count of full turns + real lastwind = n - fullwind; // reminder Turn + real startarc = 0; + real endarc = 360; + real startRadius = distance_e + Ndist; + real endRadius = startRadius + Ndist; + real sArc; + real eArc; + // script header + if (!undo_off_on) cmd += "SET UNDO_LOG OFF;\n"; + sprintf( s, "GRID mm;\n"); + cmd += s; + sprintf( s, "Change dia %.4f;\n", PVdiameter); + cmd += s; + sprintf( s, "Change shape %s;\n", Shape); + cmd += s; + sprintf( s, "Change drill %.4f;\n", PVdrill); + cmd += s; + sprintf( s, "change width %.4f;\n", wireWidth_mm); + cmd += s; + sprintf( s, "Change layer %d;\n", Layer); + cmd += s; + cmd += "SET WIRE_BEND 2;\n"; + + // **** Long coil with Ferrit kernel ********** + if (PVdiameter < wireWidth_mm) PVdiameter = wireWidth_mm; + real startradius = distance_e + wireWidth_mm/2; + real radius = startradius; + real ky = ferrit_length_K/2; + real kx1 = ferrit_length_L/2 + (distance_e + PVdiameter - wireWidth_mm/2 - startradius); + real kx2 = -ferrit_length_L/2; + + if (ferrit_length_L || ferrit_length_K) { + // *** place PAD/VIA *************************** + cmd += PadViaS( solderpoint, kx1 + radius, 0.0, kx1 + radius, ky, offx, offy); + cmd += PadViaS( ";WIRE ", kx1 + radius, 0.0, kx1 + radius, ky, offx, offy); + sprintf( s, " (%.4f %.4f) (%.4f %.4f)\n", + kx1 + radius + offx, 0.0 + offy, kx1 + radius + offx, ky + offy); // rechts anfang + cmd += s; + + for (int q = 1; q <= fullwind; q++) { + sprintf( s, ";WIRE (%.4f %.4f) (%.4f %.4f)\n", // right start + kx1 + radius + offx, 0.0 + offy, kx1 + radius + offx, ky + offy); + cmd += s; + cmd += ";\nWIRE " + spiral(radius, radius, 0.0, 90.0, degree_resol, kx1 + offx, ky + offy ); + sprintf( s, ";WIRE (%.4f %.4f) (%.4f %.4f)\n", // top + kx1 + offx, ky + radius + offy, kx2 + offx, ky + radius + offy); + cmd += s; + cmd += ";\nWIRE " + spiral(radius, radius, 90.0, 180.0, degree_resol, kx2 + offx, ky + offy ); + sprintf( s, ";WIRE (%.4f %.4f) (%.4f %.4f)\n", // left + kx2 - radius + offx, ky + offy, kx2 - radius + offx, -ky + offy); + cmd += s; + cmd += ";\nWIRE " + spiral(radius, radius, 180.0, 270.0, degree_resol, kx2 + offx, -ky + offy ); + sprintf( s, ";WIRE (%.4f %.4f) (%.4f %.4f)\n", // bottom + kx2 + offx, -ky - radius + offy, kx1 + Ndist + offx, -ky - radius + offy); + cmd += s; + cmd += ";\nWIRE " + spiral(radius, radius, 270.0, 360.0, degree_resol, kx1 + Ndist + offx, -ky + offy ); + sprintf( s, ";WIRE (%.4f %.4f) (%.4f %.4f)\n", // right end + kx1 + radius + Ndist + offx, -ky + offy, kx1 + radius + Ndist + offx, 0.0 + offy ); + cmd += s; + radius += Ndist; + } + // **************************************** + // **** if last wound < 360 degree ******** + eArc = 360 * lastwind; + real lastStartArc = 0;; + real lastEndArc = 90.0; + real lastPadViaX = kx1; + real lastPadViaY = ky; + if (eArc) { + // *** 0 - 90 degree ******************************************************** + if (eArc < 90) { + lastEndArc = eArc; + } + sprintf( s, ";\nWIRE (%.4f %.4f) (%.4f %.4f)\n", + kx1 + radius + offx, 0.0 + offy, kx1 + radius + offx, ky + offy); // rechts anfang + cmd += s; + cmd += ";\nWIRE " + spiral(radius, radius, lastStartArc, lastEndArc, degree_resol, kx1 + offx, ky + offy ); + // *** 90 - 180 degree ******************************************************** + if (eArc > 90 ) { + lastStartArc = 90;; + lastEndArc = 180; + lastPadViaX = kx2; + lastPadViaY = ky; + if (eArc < 180) { + lastEndArc = eArc; + } + sprintf( s, ";\nWIRE (%.4f %.4f) (%.4f %.4f)\n", + kx1 + offx, ky + radius + offy, kx2 + offx, ky + radius + offy); // oben + cmd += s; + cmd += ";\nWIRE " + spiral(radius, radius, lastStartArc, lastEndArc, degree_resol, kx2 + offx, ky + offy ); + } + // *** 180 - 270 degree ******************************************************** + if (eArc > 180) { + lastStartArc = 180;; + lastEndArc = 270; + lastPadViaX = kx2; + lastPadViaY = -ky; + sprintf( s, ";\nWIRE (%.4f %.4f) (%.4f %.4f)\n", + kx2 - radius + offx, ky + offy, kx2 - radius + offx, -ky + offy); // links + cmd += s; + cmd += ";\nWIRE " + spiral(radius, radius, lastStartArc, lastEndArc, degree_resol, kx2 + offx, -ky + offy ); + } + sprintf( s, ";\nWIRE (%.4f %.4f) (%.4f %.4f)\n", + kx2 + offx, -ky - radius + offy, kx1 + Ndist + offx, -ky - radius + offy); // unten + + // *** 270 - 359.9 degree ******************************************************** + if (eArc > 270) { + lastStartArc = 270; + lastEndArc = eArc; + lastPadViaX = kx1 + Ndist; + lastPadViaY = -ky; + cmd += s; + cmd += ";\nWIRE " + spiral(radius, radius, lastStartArc, lastEndArc, degree_resol, kx1 + Ndist + offx, -ky + offy ); + } + // *** set PAD/VIA to end of coil *** + cmd += xyArc(lastEndArc, radius + PVdiameter / 2 - wireWidth_mm / 2, radius + PVdiameter / 2 - wireWidth_mm / 2, lastPadViaX + offx, lastPadViaY + offy); + cmd += solderpoint + xyArc(lastEndArc, radius + PVdiameter / 2 - wireWidth_mm / 2, radius + PVdiameter / 2 - wireWidth_mm / 2, lastPadViaX + offx, lastPadViaY + offy); + } + // *********************************************** + // *** place PAD/VIA to end of full turn coil **** + else { + sprintf( s, "\n(%.4f %.4f)\n", + kx1 + radius + PVdiameter / 2 - wireWidth_mm / 2 + offx, 0.0 + offy ); // rechts ende + cmd += s; + sprintf( s, ";\n%s (%.4f %.4f)\n", solderpoint, + kx1 + radius + PVdiameter / 2 - wireWidth_mm / 2 + offx, 0.0 + offy ); // rechts ende + cmd += s; + + } + // **** Ferrit kernel dimesion **** + cmd += dimlayer; + cmd += "SET WIRE_BEND 0;\n"; + sprintf( s, "WIRE 0 (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + -ferrit_length_L/2 + offx, -ferrit_length_K/2 + offy, + ferrit_length_L/2 + offx, -ferrit_length_K/2 + offy, + ferrit_length_L/2 + offx, ferrit_length_K/2 + offy, + -ferrit_length_L/2 + offx, ferrit_length_K/2 + offy, + -ferrit_length_L/2 + offx, -ferrit_length_K/2 + offy ); + cmd += s; + sprintf( s, "WIRE (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + -ferrit_length_L/2 + offx, -ferrit_length_K/2 - distance_h + offy, + ferrit_length_L/2 + offx, -ferrit_length_K/2 - distance_h + offy - ferrit_length_K1, + -ferrit_length_L/2 + offx, -ferrit_length_K/2 - distance_h + offy ); + cmd += s; + sprintf( s, "WIRE (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\n", + ferrit_length_L/2 + offx, ferrit_length_K/2 + distance_h + offy, + -ferrit_length_L/2 + offx, ferrit_length_K/2 + distance_h + offy + ferrit_length_K1, + ferrit_length_L/2 + offx, ferrit_length_K/2 + distance_h + offy ); + + cmd += s; + cmd += "WINDOW FIT;\n"; + } + // ************************************** + // **** Rounded coil without Ferrit **** + else { + cmd += PadViaS( solderpoint, distance_e + Ndist, Ndist, 0, 0, offx, offy); + if (wireWidth_mm < PVdiameter) { + cmd += PadViaS( ";WIRE ", distance_e + Ndist, Ndist, 0, 0, offx, offy); + } + else cmd += ";WIRE "; + // *** full turns *** + sArc = startarc; + eArc = endarc; + degree_resol = 90 / arcresolution ; // *** angle-resolution + for (int x = 1; x <= fullwind; x++) { + cmd += spiral( startRadius, endRadius, sArc, eArc, degree_resol, offx, offy ) + ";WIRE "; + startRadius = endRadius; + endRadius = startRadius + Ndist; + } + // *** last turn < 360 degtee *** + eArc = 360 * lastwind; + if (eArc) { + endRadius = startRadius + Ndist * lastwind; + cmd += spiral( startRadius, endRadius, sArc, eArc, degree_resol, offx, offy ); + } + if (!lastwind) endRadius -= Ndist; + cmd += ";WIRE " + xyArc(eArc, endRadius, endRadius, offx, offy); + cmd += xyArc(eArc, endRadius + PVdiameter / 2 - wireWidth_mm / 2, endRadius + PVdiameter / 2 - wireWidth_mm / 2, offx, offy); + cmd += solderpoint + xyArc(eArc, endRadius + PVdiameter / 2 - wireWidth_mm / 2, endRadius + PVdiameter / 2 - wireWidth_mm / 2, offx, offy); + } + sprintf( s, ";\nWIN (%.3f %.3f);\n", offx, offy); + cmd += s; + output(file, "wtD") printf("%s", cmd); + sprintf(cmd, "SCRIPT '%s';", file); + exit (cmd); +} + +// *** calculate turns *** +real calcturn(int sw) { + real turn = (distance_h - 2*distance_e - wireWidth_mm) / (wireWidth_mm + wireDistance_mm) + 1; + real full = trunc(turn); + real partial = turn - full; + if(sw) { + if (partial > 0.0001) { + turn = full + 1; + } + } + return turn; +} + + +// **** calculatings *********************** +void calculates(int cf) { + switch (cf) { + case 0 : n = calcturn(fullturn); + break; + + case 1 : wireWidth_mm = (distance_h - 2 * distance_e - wireDistance_mm * (n-1)) / n; + break; + + case 2 : wireDistance_mm = (distance_h - 2 * distance_e - wireWidth_mm * n) / (n-1); + break; + + case 3 : distance_h = 2 * distance_e + wireWidth_mm + ((wireWidth_mm + wireDistance_mm) * (n-1)); + break; + } + return; +} + +real check_calculates(int cf) { + real cw; + switch (cf) { + case 0 : cw = calcturn(fullturn); + break; + + case 1 : cw = (distance_h - 2 * distance_e - wireDistance_mm * (n-1)) / n; + break; + + case 2 : cw = (distance_h - 2 * distance_e - wireWidth_mm * n) / (n-1); + break; + + case 3 : cw = 2 * distance_e + wireWidth_mm + ((wireWidth_mm + wireDistance_mm) * (n-1)); + break; + } + return cw; +} + +void set_spiral(void) { + ferrit_old_L = ferrit_length_L; + ferrit_old_K = ferrit_length_K; + ferrit_old_K1 = ferrit_length_K1; + ferrit_length_K1 = ferrit_length_K = ferrit_length_L = 0; + Spiral_H = ""; + return; +} + +void set_inductor(void) { + ferrit_length_L = ferrit_old_L; + ferrit_length_K = ferrit_old_K; + ferrit_length_K1 = ferrit_old_K1; + Spiral_H = ""; + return; +} + + +// *** main *** +if (board) { + board(B) file = filesetext(B.name, ".scr"); + solderpoint = ";\nVIA "; +} +else if (package) { + library(L) file = filesetext(L.name, ".scr"); + solderpoint = ";\nPAD "; +} +else { + dlgMessageBox("Start this ULP in a Board- or Package-Editor!", "OK"); + exit(0); +} + +if (!ferrit_length_K && !ferrit_length_L) set_spiral(); + +// ************ DIALOG ******************************** +dlgDialog(filename(argv[0])) { + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel(" All measures in mm "); + dlgLabel(Spiral_H, 1); + dlgHBoxLayout { + dlgPushButton("with Fe&rrit") set_inductor(); + dlgPushButton("only S&piral") set_spiral(); + dlgSpacing(12); + dlgGroup("UNDO Buffer") { + dlgHBoxLayout { + dlgRadioButton(" Off", undo_off_on); // UNDO Buffer off/on + dlgRadioButton(" On", undo_off_on); // UNDO Buffer off/on + } + } + dlgStretch(1); + } + dlgStretch(1); + } + dlgVBoxLayout { + dlgGridLayout { + dlgCell(1, 2) dlgLabel("Arc resolution"); + dlgCell(2, 1) dlgLabel("Steps at &90"); // Step at 90 Degree + dlgCell(2, 2) dlgIntEdit(arcresolution, 1, 90); + + dlgCell(3, 1) dlgSpacing(10); + + dlgCell(4, 1) dlgLabel("Tur&ns"); // number of turns (Wound) + dlgCell(4, 2) dlgRealEdit(n, 1.0, 100.0); + + dlgCell(5, 1) dlgLabel("Width '&w'"); // track width + dlgCell(5, 2) dlgRealEdit(wireWidth_mm, 0.01, 25.0); + + dlgCell(6, 1) dlgLabel("Distance '&d'"); // track distance + dlgCell(6, 2) dlgRealEdit(wireDistance_mm, 0.0, 25.0); + + dlgCell(7, 1) dlgSpacing(10); + + dlgCell(8, 1) dlgLabel("Distance '&e'"); // distance between ferrit kernel an wound + dlgCell(8, 2) dlgRealEdit(distance_e, 0.0, 25.0); + + dlgCell(9, 1) dlgLabel("Via/Pad Dia&meter"); // pad/via diameter + dlgCell(9, 2) dlgRealEdit(PVdiameter, 0.01, 10.0); + dlgCell(10, 1) dlgLabel("&Via/Pad Drill"); // drill diameter + dlgCell(10, 2) dlgRealEdit(PVdrill, 0.05, 10.0); + dlgCell(11, 1) dlgLabel("L&ayer"); // Layer number + dlgCell(11, 2) dlgIntEdit(Layer, 1, 255); + + dlgCell(13, 1) dlgSpacing(8); + + dlgCell(14, 2) dlgLabel("Ferrit"); + + dlgCell(15, 1) dlgLabel("Distance '&h'"); // distance between ferrit kernel + dlgCell(15, 2) dlgRealEdit(distance_h, 0.0, 25.0); + + dlgCell(16, 1) dlgLabel("Length '&L'"); // Ferrit lenth + dlgCell(16, 2) dlgRealEdit(ferrit_length_L, 0.0, 200.0); + + dlgCell(17, 1) dlgLabel("Width '&K'"); // Ferrit width + dlgCell(17, 2) dlgRealEdit(ferrit_length_K, 0.0, 200.0); + + dlgCell(18, 1) dlgLabel("Width 'K&1'"); // Ferrit width + dlgCell(18, 2) dlgRealEdit(ferrit_length_K1, 0.0, 200.0); + + dlgCell(19, 2) dlgLabel("Center/offset"); + + dlgCell(20, 1) dlgLabel("&X"); // place with offset X + dlgCell(20, 2) dlgRealEdit( offx, -800.0, 800.0 ); + dlgCell(21, 1) dlgLabel("&Y"); // place with offset Y + dlgCell(21, 2) dlgRealEdit( offy, -800.0, 800.0 ); + + } + dlgStretch(1); + } + dlgSpacing(8); + dlgVBoxLayout { + dlgSpacing(10); + dlgGroup("Calculate") { + // dlgSpacing(2); + dlgCheckBox("&Full turns", fullturn); // calculate full turns + // dlgSpacing(2); + dlgRadioButton("T&urns", cflag); + dlgSpacing(4); + dlgRadioButton("W&idth", cflag); + dlgSpacing(4); + dlgRadioButton("Di&st. d", cflag); + dlgSpacing(130); + dlgRadioButton("Dis&t. h", cflag); + dlgSpacing(16); + dlgPushButton("&Calculate") calculates(cflag); + } + + dlgStretch(1); + } + } + dlgHBoxLayout { + dlgPushButton("OK") { + int ok = 1; + if (PVdiameter > wireWidth_mm + wireDistance_mm + distance_e) { + sprintf(s, "Invalid Parameter:

    Pad/Via-Diameter %.f mm > Distance 'e' + 'w' + 'd' %.f mm", + PVdiameter, wireWidth_mm + wireDistance_mm + distance_e); + dlgMessageBox(s, "OK"); + ok = 0; + } + if (PVdrill > wireWidth_mm + wireDistance_mm + distance_e) { + sprintf(s, "Invalid Parameter:

    Pad/Via-Drill %.f mm > Distance 'e' + 'w' + 'd' %.f mm", + PVdrill, wireWidth_mm + wireDistance_mm + distance_e); + dlgMessageBox(s, "OK"); + ok = 0; + } + + if (ferrit_length_L && ferrit_length_K) { + ok = 0; + if (distance_h) { + real check_h = (distance_e * 2 + wireWidth_mm * calcturn(1) + wireDistance_mm * (calcturn(1)-1) ); + real check_diff = distance_h - check_h; + if (check_diff < -0.0001) { + sprintf(s, " Invalid Parameter:


    %.4f mm 'e' + ('d'+'w'*n)
    %.4f mm distance 'h'

    %.4f mm difference at %.f full turns (%.1f turns)", + check_h, distance_h, check_diff, calcturn(1), n ); + if (dlgMessageBox(s, "Cancel", "Accept" ) == 0); + else ok = 1; + } + else { + ok = 1; + } + } + if (distance_h < check_calculates(3)) { + sprintf(s, "Invalid Parameter:

    More turns as distance h, (check Calculate)/qt>"); + dlgMessageBox(s, "OK"); + ok = 0; + } + } + + if (ok) { + if (!ferrit_length_L || !ferrit_length_K) ferrit_length_L = ferrit_length_K = 0; + dlgAccept(); + degree_resol = turn_degree / arcresolution; + doit(); + } + } + dlgStretch(0); + dlgPushButton("-Cancel") { dlgReject(); exit(0); } + dlgStretch(1); + dlgPushButton("Inf&o") dlgMessageBox(Help, "Ok"); + } +}; diff --git a/trunk/ulp/print-spiral.bmp b/trunk/ulp/print-spiral.bmp new file mode 100644 index 00000000..9f1cd64f Binary files /dev/null and b/trunk/ulp/print-spiral.bmp differ diff --git a/trunk/ulp/print-transparent-brd.ulp b/trunk/ulp/print-transparent-brd.ulp new file mode 100644 index 00000000..90e62a41 --- /dev/null +++ b/trunk/ulp/print-transparent-brd.ulp @@ -0,0 +1,345 @@ +#usage "de:Das Board transparent ausdrucken.

    " + "Nur die Option IMAGE kann wirklich transparent ausdrucken.

    " + "RUN print-transparent-brd [Options]
    " + "
    Es werden für die Layer 1 16 17 18 20 21 22 25 26 27 28 51 und 52 die " + "entsprechenden Farb-Codes gesetzt,
    " + "und falls mit DISPLAY aktiviert, ausgedruckt. Alle anderen Layer werden abgeschaltet.

    " + "Die Hintergrundfarbe wird auf " + "weiss umgestellt, die Farben der Kupferlayer " + "werden entsprechend abgeschwächt, die Farben des Place, Docu, Name, und " + "Value-Layer werden auf schwarz eingestellt, so dass die Leiterbahnen " + "nur schwach unter dem kräftigen Bestückungsdruck " + "zu erkennen sind.

    " + "Alle PRINT-Option werden ausgeführt. Lesen Sie bitte dazu unter HELP PRINT.

    " + "RUN print-transparent-brd IMAGE @ DPI [Options]

    " + "Die Option IMAGE erzeugt ein Bitmap-Bild des Fensters anstatt eines Ausdrucks.
    " + "Die Option @ nach IMAGE wird durch den Dateinamen inkl. Pfad und die Dateierweiterung .png ersetzt.
    " + "Alternativ kann/muß man den Pfad/Dateinamen, in Hochkommas (Apostroph) eingeschlossen angeben, wenn " + "im Pfad oder Dateinamen ein Leerzeichen (Space) vorkommt.
    " + "DPI ist die Auflösung (dots per inch), z.B. 360
    " + "RUN print-transparent-brd IMAGE 'Laufwerk:/Pfad/Dateiname' 360

    " + "Author: alf@cadsoft.de" + , + "en:Print Board in a transparent style.

    " + "Only the option IMAGE print real transparent.

    " + "RUN print-transparent-brd [options]
    " + "The ULP changes the color settings for layers 1 16 17 18 20 21 22 25 26 27 28 51 and 52
    " + "and prints them, if activated. All the other layers will be switched off.

    " + "The background color will be set to " + "white , the colors of the copper layers " + "will be changed into a less bright mode. The colors of layers Place, Docu, Name, and " + "value will be set to black , so that the traces " + "are faintly visible under the strong silk screen layers.

    " + "All given PRINT options will be executed. Please read HELP PRINT for details.

    " + "RUN print-transparent-brd IMAGE @ DPI

    " + "The IMAGE option generates a bitmap of the editor window instead of the print-out.
    " + "The parameter @ following the IMAGE option will be replaced by path + file name + extension .png.
    " + "As an alterantive you can add your own path/file name which has to be included into single quotes.
    " + "DPI stands for the resolution, for example, 360
    " + "RUN print-transparent-brd IMAGE 'drive:/path/file name' 360

    " + "Author: alf@cadsoft.de" + +#require 5.1200 +string Version = "1.0.2"; // 2010-11-11 alf@cadsoft.de + // 2010-11-30 Alle Print-Optionen durchreichen. + // Layer die nicht gedruckt werden sollen, werden mit -nummer ab, + // und nach dem drucken wieder eingeschaltet. + // Die Option IMAGE kann die Ansicht als Bild abspeichern. + // 2011-09-01 Bestückungsvarianten ausdruck. Der Layer 101 bis 106 bleiben erhalten + // wie sie sind. + // 2013-07-03 bei Palette schwarz und weiss wird die Frabe 0 nicht behandelt + // Wenn Pad bzw. Via-Layer keine eigene Farbe besitzt, wird die Farbe nicht verändert. + + + + +string Ptype[] = { "BLACK", "WHITE", "COLORED" }; +enum { BLACK, WHITE, COLORED }; // Paletten Definition + +//int Fa[], Fr[], Fg[], Fb[]; // Farbcodes der Palette, Alpha, Rot, Grün, Blau +int Actual_Palette = -1; +string s, Scmd, Spalette, OrgLayColor; + +string Fname = ""; // Board-Dateiname +string Fscript = ""; // Script-Dateiname + +// Die Farben (Nummerzuweisung) zum Transparant drucken mit weissen Hintergrund. +enum { WeissNT, + HellGrau, + Hellblau, + Hellgruen, + Hellcyan, + Hellrot, + Hellmagenta, + Hellgelb, + Hellgrau2, + Schwarz, + Blau, + Gruen, + Cyan, + Rot, + Magenta, + Gelb, + Grid, + Null + }; + +// Die Farbdefinitionen +string PrintColor[]; +PrintColor[WeissNT] = "0xFFFFFFFF"; // weiss, nicht transparent +PrintColor[HellGrau] = "0xFFC8C8C8"; +PrintColor[Hellblau] = "0x8FC3CEFF"; +PrintColor[Hellgruen] = "0x4F004000"; +PrintColor[Hellcyan] = "0x8FA4FCFF"; +PrintColor[Hellrot] = "0x8FFFB9B9"; +PrintColor[Hellmagenta] = "0x8FE9C8FF"; +PrintColor[Hellgelb] = "0x8FFDFFB9"; +PrintColor[Hellgrau2] = "0xFFDEDEDE"; +PrintColor[Schwarz] = "0xFF000000"; +PrintColor[Blau] = "0x8F4C49FF"; +PrintColor[Gruen] = "0x8F00FF00"; +PrintColor[Cyan] = "0x8F00D7FD"; +PrintColor[Rot] = "0x8FFF3737"; +PrintColor[Magenta] = "0x8FFF0AF3"; +PrintColor[Gelb] = "0x8FFCFF13"; +PrintColor[Grid] = "0x3213F3F3"; +PrintColor[Null] = "0x00FFFFFF"; // weiss transparent + +int PrintBackground = WHITE; // weisser Hintergrund zum drucken +string SetPrintColor = ""; +string ReDisplayLAyer = ""; // zum wieder herstellen der Layer (Display) + +int test = 0; // test flag + +if (argv[1] == "-T") test = 1; + +// ### Funktionen ### +void readPalette(int t) { + for (int n = 0; n < PALETTE_ENTRIES; n++) { + if ((t == 0 || t == 1) && n == 0) { + ; // Farbe 0 (Hintergrund) in weißer und schwarzer Palette kann nicht gändert werden. + } + else { + sprintf(s, "Set PALETTE %d 0x%08X;\n", n, palette(n, t)); + Spalette+=s; + } + } + return; +} + + +string getColor(int color, int type) { + string s; + if (color || type > 1 ) { + sprintf(s, "SEt PALETTE % 3d 0x%08X\n", color, palette(color, type) ); + } + return s; +} + + +void save(string Fname, string script) { + output(Fname, "wtD") { + printf("%s", script); + } + return; +} + + +for (int t = 0; t < PALETTE_TYPES; t++) { // *** Anzahl der Paletten *** + sprintf(s, "SET PALETTE %s;\n", Ptype[t]); + Spalette+=s; + readPalette(t); +} + +Actual_Palette = palette(-1); // die Palette des aktuellen Fenster wählen +Spalette+="# Die aktuelle Palette\n"; +sprintf(s, "sET PALETTE %s;\n", Ptype[Actual_Palette]); +Spalette+=s; +/* +Die verwendeten Farben für die Layer +1. Hintergrund weiss +2. Top hell rot +3. Bottom hell blau +4. tPlace schwarz +5. bPlace schwarz +6. tNamens schwarz +7. bNamens schwarz +8. tValues schwarz +9. bValues schwarz +*/ + +if (board) board(BRD) { + if (argc < 2) { + dlgDialog("Print transparant HELP") { + dlgHBoxLayout dlgSpacing(550); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(300); + dlgTextView(usage); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + dlgPushButton("-CANCEL") { dlgReject(); exit(0); } + } + }; + } + + Fname = BRD.name; + sprintf(Fscript, "%s", filesetext(Fname, "~print~transparent.scr")); + string restore_org_palette = filesetext(Fname, "~restore-palette.scr"); + Scmd+="# "+Fname+"\n"; + sprintf(s, "# Generated with ULP %s Version %s;\n# 1st to restore original palette\nSET PALETTE %s;\n", // weisser Hintergrund + filename(argv[0]), Version, Ptype[PrintBackground] + ); + Scmd += "SET PAD_NAMES OFF;\n"; + OrgLayColor+=s; + SetPrintColor+= "seT PALETTE "+Ptype[PrintBackground]+";\n"; + BRD.layers(L) { + if (L.visible) { + OrgLayColor+=getColor(L.color, PrintBackground); + switch(L.number) { + // Top + case 1 : sprintf(s, "SET PALETTE %d %s; # %d hellrot\n", L.color, PrintColor[Hellrot], L.number); + SetPrintColor += s; + break; + // Bottom + case 16 : sprintf(s, "SET PALETTE %d %s; # %d hellblau\n", L.color, PrintColor[Hellblau], L.number); + SetPrintColor += s; + break; + // Pads + case 17 : if (L.color) { // nur wenn PAD-Layer eine eigene Farbe besitzt + sprintf(s, "SET PALETTE %d %s; # %d hellgruen\n", L.color, PrintColor[Hellgruen], L.number); + SetPrintColor += s; + } + break; + // Vias + case 18 : if (L.color) { // nur wenn VIA-Layer eine eigene Farbe besitzt + sprintf(s, "SET PALETTE %d %s; # %d hellgruen\n", L.color, PrintColor[Hellgruen], L.number); + SetPrintColor += s; + } + break; + // Dimension + case 20 : sprintf(s, "SET PALETTE %d %s; # %d dunkelgrau\n", L.color, PrintColor[Hellgrau2], L.number); + SetPrintColor += s; + break; + // tPlace + case 21 : sprintf(s, "SET PALETTE %d %s; # %d schwarz\n", L.color, PrintColor[Schwarz], L.number); + SetPrintColor += s; + break; + // bPlace + case 22 : sprintf(s, "SET PALETTE %d %s; # %d schwarz\n", L.color, PrintColor[Schwarz], L.number); + SetPrintColor += s; + break; + // tName + case 25 : sprintf(s, "SET PALETTE %d %s; # %d schwarz\n", L.color, PrintColor[Schwarz], L.number); + SetPrintColor += s; + break; + // bName + case 26 : sprintf(s, "SET PALETTE %d %s; # %d schwarz\n", L.color, PrintColor[Schwarz], L.number); + SetPrintColor += s; + break; + // tValue + case 27 : sprintf(s, "SET PALETTE %d %s; # %d schwarz\n", L.color, PrintColor[Schwarz], L.number); + SetPrintColor += s; + break; + // bValue + case 28 : sprintf(s, "SET PALETTE %d %s; # %d schwarz\n", L.color, PrintColor[Schwarz], L.number); + SetPrintColor += s; + break; + // tDocu + case 51 : sprintf(s, "SET PALETTE %d %s; # %d schwarz\n", L.color, PrintColor[Schwarz], L.number); + SetPrintColor += s; + break; + // bDocu + case 52 : sprintf(s, "SET PALETTE %d %s; # %d schwarz\n", L.color, PrintColor[Schwarz], L.number); + SetPrintColor += s; + break; + case 101 : + break; + case 102 : + break; + case 103 : + break; + case 104 : + break; + case 105 : + break; + // alle anderen + default : // Layer abschalten die nicht gedruckt werden sollen. + sprintf(s, "DISPLAY -%d;\n", L.number); // Layer abschalten die nicht gedruckt werden sollen + SetPrintColor += s; + sprintf(s, "DISPLAY %d;\n", L.number); // Layer wieder einschalten + ReDisplayLAyer += s; + } + } + } + sprintf(s, "%s WIN;\n", SetPrintColor); + Scmd += s; + if (test) Scmd += "RUN ulpmessage 'blasse Farben?';\n"; // + else { + int n1 = 1; + if (strupr(argv[1]) == "IMAGE") { + sprintf(s, "EXPORT "); + Scmd += s; + if (argv[2] == "@") { // wird ersetzt durch den Dateinamen und die Extension ".png", dammit man sich nicht die Finger wund tippen muß. + n1 = 3; + sprintf(s, "IMAGE '%s' ", filesetext(Fname, ".png")); + Scmd += s; + } + } + else { + sprintf(s, "PRINT "); + Scmd += s; + } + for (int n = n1; n < argc; n++) { // 2010-11-29 alle Optionen wie in der Kommandozeile angegeben weiterreichen. + sprintf(s, " %s", argv[n]); + Scmd += s; + } + } + sprintf(s, ";\nSCRIPT '%s'", restore_org_palette); + Scmd += s; + + sprintf(s, "# 2nd to reset the used palette\nSET PALETTE %s;\n", Ptype[palette(-1)]); // aktueller Hintergrund + OrgLayColor+=s; + OrgLayColor += "SET PAD_NAMES ON;"; + save(restore_org_palette, OrgLayColor); +} + +else { + dlgMessageBox("Start this ULP in a BRD!", "OK"); + exit(-1); +} + +if (test) { + int Result = dlgDialog("Farbpalette für aktuellen Ausdruck") { + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(350); + dlgTextEdit(Scmd); + } + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(300); + dlgTextEdit(OrgLayColor); + } + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(100); + dlgTextEdit(Spalette); + } + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-ESC") dlgReject(); + dlgStretch(1); + } + }; + + if (!Result) exit(-1); +} + +output(Fscript, "wtD") { + printf("%s\n%s", Scmd, ReDisplayLAyer); +} +exit("SCRIPT '"+Fscript+"'"); + + diff --git a/trunk/ulp/profiles/emc.pp b/trunk/ulp/profiles/emc.pp new file mode 100644 index 00000000..15156481 --- /dev/null +++ b/trunk/ulp/profiles/emc.pp @@ -0,0 +1,125 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. +// +// author=John Johnson +// description=EMC +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string FORMAT = "%-6.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.2f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + COMMENT_BEGIN + FORMAT + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; + diff --git a/trunk/ulp/profiles/generic.pp b/trunk/ulp/profiles/generic.pp new file mode 100644 index 00000000..5982cb04 --- /dev/null +++ b/trunk/ulp/profiles/generic.pp @@ -0,0 +1,130 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. +// +// author=John Johnson +// description=Tries to be very compatible +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string FORMAT = "%-6.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.2f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// Not using G82 so it will be very generic. +// +string DRILL_CODE = ";( G82 not used )"; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; + +string DRILL_FIRST_HOLE = RAPID + "Z" + real_to_string(DEFAULT_Z_UP) + EOL + + RAPID + MOVE_XY + EOL + + FEED + MOVE_Z + FR_FORMAT + EOL + + FEED + "Z" + real_to_string(DEFAULT_Z_UP) + EOL + + COMMENT_BEGIN + RELEASE_PLANE + " " + DWELL_TIME + COMMENT_END + EOL; + +string DRILL_HOLE = COMMENT_BEGIN + RAPID + "Z" + real_to_string(DEFAULT_Z_UP) + COMMENT_END + EOL + + RAPID + MOVE_XY + EOL + + FEED + "Z" + real_to_string(DRILL_DEPTH) + EOL + + FEED + "Z" + real_to_string(DEFAULT_Z_UP) + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + TOOL_CODE + " " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " " + TOOL_INCH_FORMAT + " " + TOOL_INCH_FORMAT + " " + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; + diff --git a/trunk/ulp/profiles/isel.pp b/trunk/ulp/profiles/isel.pp new file mode 100644 index 00000000..44f6ec94 --- /dev/null +++ b/trunk/ulp/profiles/isel.pp @@ -0,0 +1,124 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. +// +// author=John Johnson +// description=iSel +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string FORMAT = "%-6.0f "; /* coordinate format */ +string FR_FORMAT = "F%-5.0f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; +string EOL = "\n"; /* standard line ending */ +string PARAM = "#"; /* some use P, some # for parameters */ +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "FASTABS "; +string FEED = "MOVEABS "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "SPINDLE ON" + EOL + DWELL; +string SPINDLE_OFF = "SPINDLE OFF" + EOL; +string END_PROGRAM = "PROGEND" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; diff --git a/trunk/ulp/profiles/mach.pp b/trunk/ulp/profiles/mach.pp new file mode 100644 index 00000000..fdef4222 --- /dev/null +++ b/trunk/ulp/profiles/mach.pp @@ -0,0 +1,126 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. + +// +// author=John Johnson +// description=Mach3 - EMC for Windows +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +string FORMAT = "%-7.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.0f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; + +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; diff --git a/trunk/ulp/profiles/turbocnc.pp b/trunk/ulp/profiles/turbocnc.pp new file mode 100644 index 00000000..b18e69dc --- /dev/null +++ b/trunk/ulp/profiles/turbocnc.pp @@ -0,0 +1,126 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. + +// +// author=Art Eckstein +// description=TurboCNC +// + +int FILENAMES_8_CHARACTERS = YES; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string FORMAT = "%-6.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.2f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// G82 Xx.xxx Yy.yyy Z.zzz Fff.f Rr.rrr #dwell +// +string DRILL_CODE = "G82 "; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; +string DRILL_FIRST_HOLE = DRILL_CODE + MOVE_XYZ + FR_FORMAT + RELEASE_PLANE + DWELL_TIME + EOL; +string DRILL_HOLE = DRILL_CODE + MOVE_XY + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + + TOOL_CODE + "| " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " | " + TOOL_INCH_FORMAT + " | " + + TOOL_INCH_FORMAT + " | " + + " %4d" + " " + + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill, count); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; + diff --git a/trunk/ulp/rakefile.rb b/trunk/ulp/rakefile.rb new file mode 100644 index 00000000..4d88ca6b --- /dev/null +++ b/trunk/ulp/rakefile.rb @@ -0,0 +1,82 @@ +# _*_ Mode: Ruby -*- +# +# Rakefile for pcb-gcode. +# +require 'pp' +require 'rake/clean' + +# this will be improved later +PCB_GCODE_VERSION = "3.6.0.4" + +RELEASE_FILE = "~/Documents/pcb-gcode-#{PCB_GCODE_VERSION}.zip" + +ignore_files = ['pcb_gcode_is_setup', '*.old', 'storage.nv', + 'make/*', 'make', 'make/', + '*.b#*', '*.s#*', '*.l#*', + '*.DS_Store', 'optomize_me.txt', + '*.svn*', + 'docs/pcbgcode.aux', 'docs/pcbgcode.glo', 'docs/pcbgcode.gls', 'docs/pcbgcode.idx', + 'docs/pcbgcode.ilg', 'docs/pcbgcode.ind', 'docs/pcbgcode.lof', 'docs/pcbgcode.log', + 'docs/pcbgcode.lot', 'docs/pcbgcode.out', 'docs/pcbgcode.toc', + 'docs/figs/*' +] + +desc "Build the docs/pcbgcode.pdf file." +file 'docs/pcbgcode.pdf' => 'docs/pcbgcode.tex' do |t| + system "cd docs && pdflatex pcbgcode" + system "cd docs && makeindex pcbgcode" + system "cd docs && pdflatex pcbgcode" + system "cd docs && pdflatex pcbgcode" +end + +desc "Create the .zip file to be released." +task :release_file do + zip_cmd = "rm ../pcb-gcode-#{PCB_GCODE_VERSION}.zip" + system(zip_cmd) + zip_cmd = "zip -r ../pcb-gcode-#{PCB_GCODE_VERSION}.zip *" + zip_cmd += ' -x ' + zip_cmd += ignore_files.join(' -x ') + system(zip_cmd) + zip_cmd = "unzip ../pcb-gcode-#{PCB_GCODE_VERSION} -d ../pcb-gcode-#{PCB_GCODE_VERSION}" + system(zip_cmd) + zip_cmd = "rm ~/Documents/pcb-gcode-#{PCB_GCODE_VERSION}.zip" + system(zip_cmd) + zip_cmd = "cd .. && zip -r ~/Documents/pcb-gcode-#{PCB_GCODE_VERSION}.zip pcb-gcode-#{PCB_GCODE_VERSION}" + system(zip_cmd) +end + +desc "Copy current settings/* files to the safe_options folder." +task :safe_options do + SAFE_OPTIONS = ['pcb-defaults', 'pcb-machine', 'pcb-gcode-options', 'user-gcode'] + SAFE_OPTIONS.each do |name| + cp 'settings/' + name + '.h', 'safe_options/' + name + '.release.h' + end +end + +desc "Recreate data folders for viewers. Usually after re-exporting from Processing." +task :fix_viewers do + system("cp -R viewer/data viewer/applet") + system("cp -R viewer/data viewer/application.linux/") + system("cp -R viewer/data viewer/application.macosx/") + system("cp -R viewer/data viewer/application.windows/") +end + +desc "Write the convert units function in pcb-gcode-setup.ulp." +task :write_convert_units do + system("make/write_convert_units.rb") +end + +desc "Be sure the build isn't happening from a working svn directory." +task :check_svn do + if File.exist?('.svn') + abort("Cannot build with .svn files present.") + end +end + +CLOBBER.include('docs/pcbgcode.aux', 'docs/pcbgcode.glo', 'docs/pcbgcode.gls', 'docs/pcbgcode.idx', + 'docs/pcbgcode.ilg', 'docs/pcbgcode.ind', 'docs/pcbgcode.lof', 'docs/pcbgcode.log', + 'docs/pcbgcode.lot', 'docs/pcbgcode.out', 'docs/pcbgcode.toc' +) + +task :default => [:check_svn, 'docs/pcbgcode.pdf', :fix_viewers, :safe_options, :write_convert_units, :release_file] do +end diff --git a/trunk/ulp/remove-dev-sym-pac.ulp b/trunk/ulp/remove-dev-sym-pac.ulp new file mode 100644 index 00000000..ad76bfe7 --- /dev/null +++ b/trunk/ulp/remove-dev-sym-pac.ulp @@ -0,0 +1,92 @@ +#usage "Remove actual device/symbol/package and edit next\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd = ""; +string dev[]; +string sym[]; +string pac[]; +string edit = ""; +int scount = 0; +int dcount = 0; +int pcount = 0; +int n = 0; + +if (library) library(L) { + L.devicesets(D) { + dcount++; + dev[dcount] = D.name; + } + L.symbols(S) { + scount++; + sym[scount] = S.name; + } + L.packages(P) { + pcount++; + pac[pcount] = P.name; + } + + if (deviceset) deviceset(D) { + edit = D.name; + cmd = "REMOVE " + D.name + ";\n" ; + + for (n = 1; n < dcount; n++) { + if (edit == dev[n]) { + break; + } + } + + if (n < dcount) { + cmd += "EDIT " + dev[n + 1] + ".dev;\n" ; + } + else { + if (dcount > 0) { + cmd += "EDIT " + dev[n - 1] + ".dev;\n" ; + } + else exit (0); + } + } + if (symbol) symbol(S) { + edit = S.name; + cmd = "REMOVE " + S.name + ";\n" ; + + for (n = 1; n < scount; n++) { + if (edit == sym[n]) { + break; + } + } + + if (n < scount) { + cmd += "EDIT " + sym[n + 1] + ".sym;\n" ; + } + else { + if (scount > 0) { + cmd += "EDIT " + sym[n - 1] + ".sym;\n" ; + } + else exit (0); + } + } + if (package) package(P) { + edit = P.name; + cmd = "REMOVE " + P.name + ";\n" ; + + for (n = 1; n < pcount; n++) { + if (edit == pac[n]) { + break; + } + } + + if (n < dcount) { + cmd += "EDIT " + pac[n + 1] + ".pac;\n" ; + } + else { + if (pcount > 0) { + cmd += "EDIT " + pac[n - 1] + ".pac;\n" ; + } + else exit (0); + } + } + exit(cmd); + } diff --git a/trunk/ulp/remove-unused-packages.ulp b/trunk/ulp/remove-unused-packages.ulp new file mode 100644 index 00000000..13c4b99d --- /dev/null +++ b/trunk/ulp/remove-unused-packages.ulp @@ -0,0 +1,161 @@ +#usage "en:This ULP deletes unused package variants in the referring library of a device you placed " + "in the schematic and finally executes the UPDATE command.

    " + "Attention: Copy the library into a separate directory and adjust the library path setting in " + "Options - Directories before.
    " + "Otherwise the original libraries will be modified.
    " + "Example:
    " + "RUN remove-unused-package [Prefix | Partname]" + "

    " + "Author: alf@cadsoft.de" + , + "de:Nicht benutzte Packagevarianten eines benutzen Device im Schaltplan werden in der " + "Bibliothek gelöscht
    und anschliesend ein UPDATE durchgeführt.

    " + "ACHTUNG: Kopieren Sie evtl. die Bibliothek in einen entsprechenden Ordner, " + "setzen Sie den Pfad unter Optionen - Bibliotheken auf diesen Ordner, da sonst die original Bibliothek " + "entsprechend bearbeitet wird.

    " + "Beispiel:
    " + "RUN remove-unused-package [Prefix | Bauteilname]" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string Version = "1.0.0"; // 2011-05-25 alf@cadsoft.de + +string Removename = filesetext(argv[0], "~remove_unused_pac.lst"); + + +string DeviceName = ""; +string DevicePackage = ""; + +string DevSetList[]; +string DevList[]; +string PacList[]; +string LbrList[]; +int Cnt = 0; +string Lines[]; + +string Use_in; + +string Object = strupr(argv[1]); // use in schematic (Device) or board (Element) +int Olen = strlen(Object); + +if (!Object) { + dlgMessageBox(usage, "OK"); + exit(0); +} + + +void splitlist(void) { + string s[]; + for (int n = 0; Lines[n]; n++) { + strsplit(s, Lines[n], '\t'); + LbrList[n] = s[0]; // devicesetlibrary; + DevSetList[n] = s[1]; // devicesetname; + DevList[n] = s[2]; // devicename; + PacList[n] = s[3]; // devicepackagename; + } + return; +} + + +void addlist(string devicesetlibrary, string devicesetname, string devicename, string devicepackagename, string tech, string ename) { + for (int n = 0; n < Cnt; n++) { + if (LbrList[n] == devicesetlibrary && DevSetList[n] == devicesetname && DevList[n] == devicename && PacList[n] == devicepackagename) { + return; + } + } + LbrList[Cnt] = devicesetlibrary; + DevSetList[Cnt] = devicesetname; + DevList[Cnt] = devicename; + PacList[Cnt] = devicepackagename; + sprintf(Lines[Cnt], "%s\t%s\t%s\t%s", LbrList[Cnt], DevSetList[Cnt], DevList[Cnt], PacList[Cnt]); + Cnt++; + return; +} + +if (schematic) { + schematic(SCH) { + SCH.sheets(S) { + S.parts(PA) { + string pname = PA.name; + if (strstr(PA.name, Object) == 0 && isdigit(pname[Olen]) || PA.name == Object) { + addlist(PA.deviceset.library, PA.deviceset.name, PA.device.name, PA.device.package.name, PA.device.technologies, PA.name); + } + } + } + int index[]; + sort(Cnt, Lines); + output(Removename, "wtD") for (int n = 0; Lines[n]; n++) printf("%s\n", Lines[n]); + exit("OPEN '" + LbrList[0] + "' ;\n RUN '"+ argv[0] + "' '" + Removename + "' '" + SCH.name + "'"); + } +} + + +else if (library) { + if (argv[1] == Removename) { + int Cnt = fileread(Lines, Removename); + splitlist(); + string lname[]; + string devsetname[]; + string devname[]; + string pacname[]; + string variant[]; + int checkdevset[]; // mark checked deviseset + int usedpac[]; // mark used package variant + library(L) { + int cnt = 0; + int doit = 0; + L.devicesets(DEV) { + DEV.devices(D) { + lname[cnt] = filename(L.name); + devsetname[cnt] = DEV.name; + devname[cnt] = D.name; + pacname[cnt] = D.package.name; + cnt++; + } + } + // check used package variants + for (int n = 0; Lines[n]; n++) { + for (int n1 = 0; n1 < cnt; n1++) { + if (filename(LbrList[n]) == filesetext(lname[n1], "")) { + if ( DevSetList[n] == devsetname[n1]) { + checkdevset[n1] = 1; // mark checked + if (PacList[n] == pacname[n1] ) { // wenn die Packagevariante benutzt ist, wird sie markiert + usedpac[n1] = 1; + //break; + } + } + } + } + } + for (int u = 0; u < cnt; u++) { + if (checkdevset[u]) { + if (usedpac[u]) { + // package is used + sprintf(variant[u], "# %s %s PAC %s %s ; used in sch.", lname[u], devsetname[u], devname[u], pacname[u]); // Kommentar benutzte Variante. + } + else { + sprintf(variant[u], "EDIT %s.DEV; PAC -%s # %s;", devsetname[u], devname[u], pacname[u]); // Delete unbenutzte Variante. + } + } + else { + sprintf(variant[u], "# %s nicht im SCH %s %s %s", lname[u], devsetname[u], devname[u], pacname[u]); // nicht benutztes Device im SCH + } + } + string fscript = filesetext(L.name, "~del-variants.scr"); + output(fscript, "wtD") { + for (int n = 0; n < cnt; n++) { + printf("SET CONFIRM YES;\n"); + printf("%s\n", variant[n]); + printf("SET CONFIRM OFF;\n"); + } + printf("WRITE;\nEDIT '%s';\n UPDATE '%s';\n", argv[2], L.name); + } + exit("SCRIPT '" + fscript + "'"); + } + } +} + +dlgMessageBox("!Start this ULP in a schematic.", "OK"); +exit(0); \ No newline at end of file diff --git a/trunk/ulp/rename-signal.ulp b/trunk/ulp/rename-signal.ulp new file mode 100644 index 00000000..89ac1524 --- /dev/null +++ b/trunk/ulp/rename-signal.ulp @@ -0,0 +1,43 @@ +#usage "Rename SIGNALSs in a board with Suffix

    " + "RUN rename-signals [suffix]
    " + "Author: support@cadsoft.de"; + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, +// EXPRESSED OR IMPLIED. + + +string Version = "Version 1.1"; // check if schematic editor window open + +string fileName; + +string suffix = argv[1]; + +// ### Functions ### + + +if (project.schematic) { + dlgMessageBox(argv[0]+ "\n" + Version + "\nFirst close the schematic editor!", "OK"); + exit(-1); +} + +// ** MAIN ** +if (board) { + board(B) { + fileName = filesetext(B.name, "rename-signal-suffix~~~.scr"); + int cntsig = 0; + output(fileName, "wtD") { + printf("# 'This file is generated by %s, exported from;\n", Version); + printf("# '%s at %s;\n", fileName, t2string(time())); + printf("# '%s;\n\n", EAGLE_SIGNATURE); + B.signals(S) { + S.contactrefs(C) { + printf("SIGNAL 'S$S_0%d%s' %s %s;\n", cntsig, suffix, C.element.name, C.contact.name); + cntsig++; + break; + } + } + } + exit ("SCRIPT '" + fileName + "';"); + } +} +else dlgMessageBox("Start this ULP in Board!", "OK"); diff --git a/trunk/ulp/renamnet-suffix.ulp b/trunk/ulp/renamnet-suffix.ulp new file mode 100644 index 00000000..c2aef360 --- /dev/null +++ b/trunk/ulp/renamnet-suffix.ulp @@ -0,0 +1,122 @@ +#usage "Rename NETs in a schematic with NET name suffix

    " + "Author: support@cadsoft.de"; + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, +// EXPRESSED OR IMPLIED. + +string Help = + "Wird ein Netz umbenannt, dass aus mehreren Segmenten besteht,\n" + + "bzw. auf mehrere Sheets verteilt ist, muss die Abfrage:\n" + + " Change Name of:\n" + + " This Segment\n" + + " Every Segment on this Sheet\n" + + " All Segments on all Sheets\n\n" + + "immer mit 'Every Segment on this Sheet' bzw.\n" + + "'All Segments on all Sheets' beantwortet werden.\n\n"; + + + +string Version = "Version 1.0"; + + // ********************************************* +string Suffix = ""; // **** Anhang an den Netznamen, **** + // **** kann nach belieben geändert werden. **** + // ********************************************* + +real Grid = 100; // in 100 Mil + + +int index[]; +int s = 0, pg = 0; + +numeric string n[]; // P.name; + int is[]; // I.sheet; + int ix[]; + int iy[]; + +string fileName; + +// ### Functions ### +void setgridmil (void) { + printf("GRID mil 100;\n"); + return; +} + +void editsheet(int i) { + if (s != is[i]) { // Sheet wechseln + s = is[i]; + printf("EDIT .S%d;\n",s); + } + return; +} + +void namescript(void) { + for (int i = 0; i < pg; i++) { + editsheet(i); // ** Change Sheet + printf("NAME '%s%s' (%.2f %.2f);\n", n[i], Suffix, u2mil(ix[i]), u2mil(iy[i])); + } + return; +} + +int found (string f) +{ + for (int i = 0; i < pg; i++) { + if (n[i] == f) return i; + } + return -1; +} + +// ** MAIN ** +if (schematic) { + schematic(SCH) { + fileName = filesetext(SCH.name, "renamenet-suffix~~~.scr"); + + int Result = dlgDialog("Rename NET in Schematic") { + dlgLabel(Help); + dlgHBoxLayout { + dlgLabel("Net &suffix"); + dlgStringEdit(Suffix); + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + }; + if (!Result) exit(0); + + output(fileName, "wtD") { + + printf("# 'This file is generated by %s, exported from;\n", Version); + printf("# '%s at %s;\n", SCH.name, t2string(time())); + printf("# '%s;\n\n", EAGLE_SIGNATURE); + setgridmil(); + printf("DISPLAY NONE 91;\n"); + + // collect all Nets + SCH.sheets(SH) { + SH.nets(N) { + N.segments(SEG) { + SEG.wires(W) { + n[pg] = N.name; + ix[pg] = W.x1; + iy[pg] = W.y1; + is[pg] = SH.number; + if (found(n[pg]) == -1) pg++; + break; + } + break; + } + } + } + namescript(); + + printf("GRID INCH;\n"); + printf("GRID 0.1;\n"); + printf("DISPLAY ALL -93;\n"); + } + exit ("SCRIPT '" + fileName + "';"); + } +} +else dlgMessageBox("Start this ULP in Schematic!", "OK"); diff --git a/trunk/ulp/renumber-sheet.ulp b/trunk/ulp/renumber-sheet.ulp new file mode 100644 index 00000000..dca7b6da --- /dev/null +++ b/trunk/ulp/renumber-sheet.ulp @@ -0,0 +1,733 @@ +#usage "Renumber the parts of a schematic

    " + "1 step:
    This version checks of empty prefix in deviceset, and check if the deviceset prefix even used prefix.
    " + "2 step:
    If not set a prefix in used deviceset, you can select a device to open the device of library to correct the prefix.
    " + "3 step:
    Option to update the library
    " + "4 step:
    Renumber
    " + "Please follow the instructions.

    " + "This version use the defined prefix of deviceset to renumber parts.
    " + "This version renumbers devices with and without packages (no supply) " + "sorted by sheets and coordinates (vertical/descending, horizontal/ascending).
    " + "Optional: The starting point for the numeration of parts on the first sheet " + "defines an offset value for the following pages.
    " + "Example:
    " + " - 0 = R1 ... Rn
    " + " - 100 sheet 1: R101..R199 sheet 2: R201..R299 ...
    " + " - 500 sheet 1: R501..R999 sheet 2: R1001..R1499 ...
    " + " - 1000 sheet 1: R1001..R1999 sheet 2: R2001..R2999 ...
    " + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED +#require 6.0500 + +string Version = "ULP Version 5.0.1"; // 2006.08.23 alf@cadsoft.de + // correct counter if crossing page by same prefix + // 2008.01.30 alf@cadsoft.de + // renumber only the current sheet by start sheet-number * numerical_order + // 2012-06-21 - corrected sort by Weighting of emphasis in Y-direction + // alf@cadsoft.de + // 2013-03-19 - do not use devicesets without prefix od parts with prefix "U$" + // 1. check PREFIX of Parts in used deviceset + // 2. update librarie + // 3. flag for renumber also symbol without package + // 2013-08-19 - Rename by old-name new-name, if more gates on same origin + // 2013-09-09 - now more Prefixes allowed for "do not renumber with prefix", separated by ";" + +string Info = "ATTENTION

    " + + "Please verify that the corresponding layout file (if already existing) " + + "has been loaded with the schematic file.

    " + + "Otherwise back-/forward-annotation will not work afterwards."; + +string Infoplus = + " You can change the following sorting parameters:

    " + + " descx = 0 (X ascending [left >> right])
    " + + " descx = 1 (X descending [right >> left])
    " + + " descy = 0 (Y ascending [bottom >> top])
    " + + " descy = 1 (Y descending [top >> bottom])
    "; + + +int descy = 1; // set to 0 sorting ascending +int descx = 0; // set to 1 sorting descending +int numerical_order = 0; // sort from sheet 1, or sort by start counter for sheet +int emphases = 0; // weighting of emphases first X second Y or first Y second X + +int actual_sheet = 0; // 2008.01.30 +int only_actual_sheet = 0; // 2008.01.30 +string sheet_info = ""; + +numeric string OldNames[], NewNames[], Prefix[]; +int x[], y[], Index[], Sheet[]; +int nrNames = 0; + +numeric string SymNames[]; // Device-Name of Symbol +int symsh[]; +int SymX[], SymY[]; +int Snr = 0; +int Dnr = 0; + +string Error = ""; +string SymPrefix[]; +string DevPrefix[]; +string DevName[]; +string SymDevName[]; + +int RenumWithoutPackage = 1; // 2013-03-19 +string NoPrefixRenumber = "TP"; // Prefix do not renumber Testpoints + +int ckx[], cky[], cksh[]; +string ckname[]; + +string Cmd; +string c; + +real Grid = 100; // in 100 Mil +string lbr[], dev[], sym[]; + +/* first check PREFIX 2013-03-19 **/ +string UndefinedPrefix = "U$"; // all parts without prefix in deviceset, get a name U$ by ADD +numeric string RealPartName[], RealRrefix[]; +int CntRN = 0; + +string PartName[], PartDeviceSet[], PartLib[], PartPrefix[]; +int PartSheet[]; +int PartX[], PartY[], X, Y; +int CntP = 0; +string List[]; + +string PrefixError[]; +int CntNoDevPrefix = 0; +int CntNoPartPrefix = 0; + +/* first check PREFIX 2013-03-19 */ + + +/****************** Functions **********************/ +/******** first check PREFIX 2013-03-19 ************/ +int getnum(string name, string prefix) { + int len = strlen(prefix); + return strtol(strsub(name, len)); +} + +int getlastnum(string prefix) { + int foundstart = 0; + int foundlast = 0; + for (int n = 0; n < CntRN; n++){ + if (RealRrefix[Index[n]] == prefix) { + foundstart = n; + } + else { + if (foundstart) { + foundlast = foundstart; + } + else { + if (foundlast) { + return getnum(RealPartName[Index[foundstart]], RealRrefix[Index[foundstart]]); + } + } + } + } + return 0; +} + +int checksheet(UL_PART P) { + P.instances(I) { + if (I.sheet) { + X = I.x; + Y = I.y; + return I.sheet; + } + } + dlgMessageBox("!Das darf nicht vorkommen, Instance auf keinem Sheet.", "OK"); + exit(-99); +} + +void opendev(int sel) { + string s[]; + int cnt = strsplit(s, PrefixError[sel], '\t'); + string cmd; + sprintf(cmd, "OPEN '%s';EDIT '%s.DEV';PREFIX", s[1], s[2]); + exit(cmd); +} + +void updatedev(int sel) { + string s[]; + int cnt = strsplit(s, PrefixError[sel], '\t'); + string cmd; + sprintf(cmd, "UPDATE '%s'; RUN '%s'", s[1],argv[0]); + exit(cmd); +} +/******** first check PREFIX 2013-03-19 ************/ + + +int GetNumberIndex(string Name) { + // Returns the index of the first digit of the numeric part of Name + // -1 indicates there is no numeric part in Name + int l = strlen(Name) - 1; + for (int Index = l; Index >= 0; --Index) { + if (!isdigit(Name[Index])) + return Index < l ? Index + 1 : -1; + } + return 0; +} + +string GetPrefix(string name) { // Prefix of Device + int num = GetNumberIndex(name); + if (num < 1) return name; + else { + string pfx = name; + pfx[num] = 0; + return pfx; + } +} + +void DescendingY(void) { + for (int ny = 0; ny < nrNames ; ny++) { + y[ny] = 0 - y[ny]; + } + return; +} + +void DescendingX(void) { + for (int nx = 0; nx < nrNames ; nx++) { + x[nx] = 0 - x[nx]; + } + return; +} + +void SortElements(void) { + // Sorts the elements according to their location, first by ascending + // x coordinates, then by ascending y coordinates. + // If you prefer a different kind of sorting, you can implement this here. + // As a result, the integer array Index[] must contain the new sequence + // in which to renumber the elements. + + // 2008-07-24 alf, weighting of emphases first X second Y or first Y second X + + if (descy) DescendingY(); + if (descx) DescendingX(); + + if(!numerical_order) { + if (!emphases) sort(nrNames, Index, NewNames, Sheet, x, y); + else sort(nrNames, Index, NewNames, Sheet, y, x); + } + else { + if (!emphases) sort(nrNames, Index, Sheet, NewNames, x, y); + if (emphases) sort(nrNames, Index, Sheet, NewNames, y, x); // 2012-06-21 correct sort on emphases + } + if (descy) DescendingY(); + if (descx) DescendingX(); + return; +} + +/********** in V6 not more used while new option NAME Oldname Newname 2013-08-19 +void CheckSameOrigin(int chk) { // eagle can not rename an element + // if another element is on the same coordinate + int index[]; + string checklist, h; + sort(chk, index, cksh, ckx, cky); + for (int n = 0; n < nrNames; n++) { + if(ckx[index[n]] == ckx[index[n+1]] && cky[index[n]] == cky[index[n+1]] && cksh[index[n]] == cksh[index[n+1]]) { + sprintf(h, "%s & %s on same coordinate (%d %d) mil in sheet %d\n", + ckname[index[n]], ckname[index[n+1]], + ckx[index[n]], + cky[index[n]], + cksh[index[n]]); + checklist += h; + } + } + if (checklist) { + dlgDialog("Check coordinates") { + dlgLabel("Eagle can not rename elements that are placed at the same position!"); + dlgHBoxLayout { + dlgSpacing(300); + } + dlgTextView(checklist); + dlgHBoxLayout { + dlgPushButton("Break") dlgAccept(); + dlgStretch(1); + } + }; + exit(0); + } + return; +} +********/ + +void GenerateNames(void) { + string memprefix = ""; + int mem_sh = 0; + if(!numerical_order) { + // Generates new numeric parts to the element names in NewNames + int k; + for (int n = 0; n <= nrNames - 1; ++n) { + if (memprefix != NewNames[Index[n]]) { + memprefix = NewNames[Index[n]]; + k = 0; + } + sprintf(NewNames[Index[n]], "%s%d", NewNames[Index[n]], ++k); + } + } + else { // renumber sheets by 100.. 200.. 300.. + string h; + int newdevnr; + for(int n = 0; n < nrNames ; ++n) { + if (memprefix != NewNames[Index[n]]) { + memprefix = NewNames[Index[n]]; + newdevnr = numerical_order * Sheet[Index[n]] +1; + } + if (mem_sh != Sheet[Index[n]]) { // a new Sheet is starting by old prefix *** 2006.08.23 alf@cadsoft.de + mem_sh = Sheet[Index[n]]; + newdevnr = numerical_order * Sheet[Index[n]] +1; + } + sprintf(NewNames[Index[n]], "%s%d", NewNames[Index[n]], newdevnr); + newdevnr++; + if (newdevnr-(Sheet[Index[n]]*numerical_order) >= numerical_order) { + sprintf(h, "More parts with prefix '%s' than starting point %d on sheet %d
    Start the ulp with numerical order >= %d
    ", + memprefix, numerical_order, Sheet[Index[n]], numerical_order*10); + dlgMessageBox(h, "Break"); + exit(0); + } + } + } + return; +} + +void Rename(int x, int y, string Old, string New) { + // Generates the EAGLE command necessary to change element name Old to New + //sprintf(c, "Name '%s' (%d %d);#297\n", New, x, y); + sprintf(c, "NAME '%s' '%s';#298\n", Old, New); // 2013-08-19 + Cmd += c; + return; +} + +void GenerateScript(void) { + // Generates an EAGLE script file that does the whole renumbering. + // The tricky part here is that we cannot rename an element to a name + // that already exists in the schematic (which, e.g. might be necessary if + // we had to swap the names of two elements). Therefore we have to + // use a ScratchName wherever this is necessary. + + // If there is nothing to do, the resulting script file will be empty. + + string ScratchName[]; + int sch = 0; + int n; + int t = time(); + for ( n = 0; n < nrNames; ++n) { + if (Sheet[Index[n]] != sch) { + sch = Sheet[Index[n]]; // *** change sheet + sprintf(c, "Edit .s%d;\n", sch); + Cmd += c; + } + sprintf( ScratchName[Index[n]], "$%d_%d_$_%s", sch, n, t2string(t, "Uyyyy-MM-dd_hh-mm-ss")); // 2013-03-19 verhindert Problem für temporäre umbenenung falls früherer Durchlauf abgebrochen + Rename(x[Index[n]],y[Index[n]], OldNames[Index[n]], ScratchName[Index[n]]); + } + for ( n = 0; n < nrNames; ++n) { + if (Sheet[Index[n]] != sch) { + sch = Sheet[Index[n]]; // *** change sheet + sprintf(c, "Edit .s%d;\n", sch); + Cmd += c; + } + Rename(x[Index[n]],y[Index[n]], ScratchName[Index[n]], NewNames[Index[n]]); + } + return; +} + +// *** check collision before rename *** +string CheckNames(void) { + string new_name = ";"; + string h; + + for (int Dn = 0; Dn < Dnr; Dn++ ) { + for (int Sn = 0; Sn < Snr; Sn++) { + if (DevPrefix[Dn] == SymPrefix[Sn]) { + sprintf(h, "# Do not use Prefix %s on Device with Package (%s) and Device without Package (%s)\n", + SymPrefix[Sn], DevName[Dn], SymDevName[Sn]); + Error += h; + break; + } + } + } + for (int n = 0; n < nrNames - 1; ++n) { // make a long string + new_name += NewNames[n] + ";"; + } + + for (int xx = 0; xx < Snr - 1; xx++) { + string sd = SymNames[xx]; + if(sd[0] == '$') { // if first character is a $ on Symbolname + Error += "# Do not use $ character at first position in device names\n"; + sprintf(h, "# RENAME %s at (%.4f %.4f) - sheet %d before running this ULP again' (%.4f %.4f)\n", + SymNames[xx], SymX[xx] / 1000.0, SymY[xx] / 1000.0, symsh[xx], SymX[xx] / 1000.0, SymY[xx] / 1000.0); + Error += h; + } + int s; + int pos = strrstr(new_name, ";" + SymNames[xx] + ";"); + if (pos > 0 ) { + for (s = 0; s < nrNames - 1; s++) { + if(NewNames[s] == SymNames[xx]) { + break; + } + } + Error += "# Collision of symbol name and device name (eg. Frames, Supply ...)\n"; + sprintf(h, "# Rename PREFIX of Device %s at (%.4f %.4f) - sheet %d before renaming %s at (%.4f %.4f) - sheet %d';\n", + SymNames[xx], SymX[xx] / 1000.0, SymY[xx] / 1000.0, symsh[xx], + OldNames[s], x[s] / 1000.0, y[s] / 1000.0, Sheet[s] ); + Error += h; + } + } + return Error; +} + +void setgridmil (void) { + sprintf(c, "GRID MIL 100 OFF;\n"); + Cmd += c; + // ## only display layer 94 (symbol) if placed a text + // ## at symbol origin. 15.06.2004 alf@cadsoft.de + //sprintf(c, "DISPLAY NONE 94 -95 -96;\n"); + //Cmd += c; + return; +} + +void visible(UL_SCHEMATIC S) { + sprintf(c, "DISP NONE "); + Cmd += c; + S.layers(L) { + if (L.visible) { + sprintf(c, "%d ", L.number); + Cmd += c; + } + } + Cmd += ";\n"; + return; +} + +void menue(void) { + int Result = dlgDialog("Renumber Schematic") { + dlgLabel("" + Info + ""); + dlgHBoxLayout { + dlgGroup("Sort X") { + dlgRadioButton("&Ascending", descx); + dlgRadioButton("&Descending", descx); + } + dlgGroup("Sort Y") { + dlgRadioButton("A&scending", descy); + dlgRadioButton("D&escending", descy); + } + dlgGroup("Weighting of emphases") { + dlgRadioButton("X-direction", emphases); + dlgRadioButton("Y-direction", emphases); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgLabel("Do not renumber parts with &Prefixes (separated by ';')"); + dlgStringEdit(NoPrefixRenumber); + dlgStretch(1); + } + + dlgHBoxLayout { + dlgCheckBox("Renumber parts without package ", RenumWithoutPackage); // 2013-03-19 + dlgStretch(1); + } + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(180); + dlgGroup("Sheet") { + dlgLabel("Start numbering for sheet at:"); + dlgLabel(" - 0 numeration R1...Rn"); + dlgLabel(" - 100 sheet 1: R101..R199, sheet 2: R201..R299, ..."); + dlgLabel(" - 1000 sheet 1: R1001..R1999, sheet 2: R2001..R2999, ..."); + dlgSpacing(10); + dlgHBoxLayout { + dlgLabel("&Numerical order "); + dlgIntEdit(numerical_order, 0, 10000); + dlgStretch(1); + } + dlgVBoxLayout dlgSpacing(10); + dlgCheckBox("Sort in numerical order on the ¤t sheet only", only_actual_sheet) { + if (only_actual_sheet) { + if (numerical_order) { + sprintf(sheet_info, "The starting number of current sheet is %d", actual_sheet * numerical_order); + } + else { + sprintf(sheet_info, "Please check the numerical order!"); + } + } + else { + if (!numerical_order) sprintf(sheet_info, "The starting number is 1"); + else sprintf(sheet_info, "The starting number on sheet is X * %d", numerical_order); + + } + } + dlgVBoxLayout dlgSpacing(10); + dlgLabel(sheet_info, 1); + dlgStretch(1); + } + } + dlgHBoxLayout { + dlgPushButton("+&OK") { + if (only_actual_sheet && !numerical_order) { + sprintf(sheet_info, "Please check the numerical order!"); + dlgMessageBox(sheet_info, "OK"); + } + else dlgAccept(); + } + dlgSpacing(15); + dlgPushButton("-Cancel") dlgReject(); + dlgSpacing(15); + dlgLabel(Version); + dlgStretch(1); + dlgPushButton("&Help") dlgMessageBox(usage, "OK"); + } + }; + if (!Result) exit (0); + return ; +} + +if (schematic) { + /******** 1 step: check empty and uneven prefix 2013-03-19 ************/ + schematic(SCH) { + SCH.parts(P) { + if (!P.deviceset.prefix || strstr(P.name, UndefinedPrefix) == 0 || strstr(P.name, "$") == 0 || strstr(P.name, P.deviceset.prefix) < 0 ) { + PartName[CntP] = P.name; + PartDeviceSet[CntP] = P.deviceset.name; + PartLib[CntP] = P.deviceset.library ; + PartPrefix[CntP] = P.deviceset.prefix; + PartSheet[CntP] = checksheet(P); + PartX[CntP] = X; + PartY[CntP] = Y; + sprintf(List[CntP], "%s\t%s\t%s\t%s\t%d", + PartName[CntP], + PartLib[CntP], + PartDeviceSet[CntP], + PartPrefix[CntP], + PartSheet[CntP] + ); + if (!PartPrefix[CntP] || PartPrefix[CntP] == UndefinedPrefix ) { + PrefixError[CntNoDevPrefix] = List[CntP]; + CntNoDevPrefix++; + } + if (strstr(PartName[CntP], UndefinedPrefix) == 0 || strstr(PartName[CntP], "$") == 0 || strstr(P.name, P.deviceset.prefix) < 0) { + RealPartName[CntRN] = P.deviceset.prefix; + RealRrefix[CntRN] = P.name; + CntRN++; + } + CntP++; + } + } + } + /******** 1 step: check device prefix (library) ********/ + int sel = -1; + if (CntNoDevPrefix) { + string Status; + sprintf(Status, "Step 1: Found %d PARTS without PREFIX in deviceset", CntNoDevPrefix+1); + dlgDialog("Prefix check") { + dlgLabel(Status); + dlgHBoxLayout dlgSpacing(550); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgListView("Name\tLib\tDevideset\tPrefix\tSheet", PrefixError, sel) opendev(sel); + } + dlgLabel("Do not use empty PREFIX in deviceset or 'U$' as part prefix!"); + dlgLabel("First check and set PREFIX in library (deviceset) and then UPDATE library."); + dlgHBoxLayout { + dlgPushButton("OK") { + if (sel < 0) { + dlgMessageBox("First select a part, to set prefix in library.", "OK"); + } + else opendev(sel); + } + dlgPushButton("UPDATE") { + if (sel < 0) { + dlgMessageBox("First select a part, to UPDATE this library.", "OK"); + } + else updatedev(sel); + } + dlgPushButton("UPDATE ALL") { dlgReject(); exit("UPDATE; RUN '"+argv[0]+"'"); } + dlgPushButton("CANCEL") { dlgReject(); exit(-2); } + } + }; + exit("UPDATE"); + } + /******** 2 step: rename uneven part prefix by deviceset prefix ********/ + sort(CntRN, Index, RealPartName); + int i[]; + sort(CntP, i, PartPrefix); // nach dem Prefix der LBR sortiert + string actprefix = ""; + int cntnumber; + string s, cmd; + for (int n; n < CntRN; n++) { + if (actprefix != PartPrefix[i[n]]) { + cntnumber = getlastnum(PartPrefix[i[n]]); + actprefix = PartPrefix[i[n]]; + sprintf(s, "EDIT .s%d; NAME '%s%d' (%.6fmil %.6fmil);\n", + PartSheet[i[n]], + PartPrefix[i[n]], ++cntnumber, + u2mil(PartX[i[n]]), u2mil(PartY[i[n]]) + ); + cmd+=s; + } + else { + sprintf(s, "EDIT .s%d; NAME '%s%d' (%.6fmil %.6fmil);\n", + PartSheet[i[n]], + PartPrefix[i[n]], ++cntnumber, + u2mil(PartX[i[n]]), u2mil(PartY[i[n]]) + ); + cmd+=s; + } + } + /* + if (CntRN) { + dlgDialog("Step 2: Rename Part by Device-PREFIX") { + dlgHBoxLayout dlgSpacing(450); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(450); + dlgTextEdit(cmd); + } + dlgHBoxLayout { // wenn der Origin des Symbol auf einem Kontaktpunkt liegt, wird das NET umbenannt, nicht das PART! + dlgPushButton("RUN SCRIPT") { + dlgAccept(); + exit("DISPLAY NONE 94;" + cmd + "DISPLAY LAST; RUN '"+argv[0]+"'"); + } + dlgStretch(1); + dlgPushButton("CANCEL") { dlgReject(); exit(-2); } + } + }; + } + */ + /******** end check PREFIX 2013-03-19 ************/ + + /******** 4 step: renumber ********/ + if (sheet) { + sheet(S) actual_sheet = S.number; + sprintf(sheet_info, "The current sheet is %d", actual_sheet); + } + schematic(S) { + menue(); + int l = 1; + int chk; + string NoRenumPrefixes[]; // 2013-09-09 + int nPrefixes = strsplit(NoRenumPrefixes,NoPrefixRenumber,';'); + S.sheets(SH) { + if (only_actual_sheet) { + ; // do not change the actual sheet number + } + else { + actual_sheet = SH.number; // set the numer to actuel sheet number + } + if (actual_sheet == SH.number) { // 2008.01.30 + SH.parts(P) { + // 2013-03-19 int n = GetNumberIndex(P.name); + // 2013-03-19if (n > 0) { + + if (P.device.package || RenumWithoutPackage) { // **** only Devices with Packages + // **** without Supply symbol Frames ect... + // **** DO NOT RENUMBER Elements with this PREFIXES + // 2013-03-19 if (GetPrefix(P.name) == NoPrefixRenumber); old verison + //if (P.deviceset.prefix == NoPrefixRenumber); + + int skipRenumber = 0; // 2013-09-09 + for (int i = 0; i < nPrefixes && !skipRenumber; ++i) { + if (GetPrefix(P.name) == NoRenumPrefixes[i]) + skipRenumber = 1; + } + if (skipRenumber || GetPrefix(P.name) == NoPrefixRenumber); + else { + // 2013-03-19 DevPrefix[Dnr] = GetPrefix(P.name); old version + DevPrefix[Dnr] = P.deviceset.prefix; + DevName[Dnr] = P.name; + ++Dnr; + P.instances(I) { + int found = -1; + for (int fn = 0; fn < nrNames; fn++) { + if (OldNames[fn] == P.name) { + found = fn; + break; + } + } + if (found < 0) { + x[nrNames] = u2mil(I.x); // cannot use E.x/y directly because of + y[nrNames] = u2mil(I.y); // sort() problem with integers > 32767 + OldNames[nrNames] = P.name; // in version 3.50 + NewNames[nrNames] = P.deviceset.prefix;; // 2013-03-19 strsub(P.name, 0, n); + Sheet[nrNames] = I.sheet; + Prefix[nrNames] = P.deviceset.prefix; // 2013-03-19 GetPrefix(P.name); + ++nrNames; + } + + else { + if (Sheet[fn] == I.sheet) { + if ( u2mil(I.x) < x[fn] || u2mil(I.y) > y[fn] ) { + // tausche wenn x kleiner oder y groesser + x[fn] > u2mil(I.x); + y[fn] > u2mil(I.y); + } + } + } + } + } + } + // Only Symbol (Supply, Port, Frame...) + else { // *** check PartName on Symbols Supply, Port, Frame ... *** + SymPrefix[Snr] = GetPrefix(P.name); + SymDevName[Snr] = P.name; + P.instances(I) { + SymNames[Snr] = P.name; // Device-Name of Symbol + SymX[Snr] = u2mil(I.x); // cannot use E.x/y directly because of + SymY[Snr] = u2mil(I.y); // sort() problem with integers > 32767 + symsh[Snr] = I.sheet; + ++Snr; + break; + } + } + // 2013-03-19 } + P.instances(I) { + ckx[chk] = u2mil(I.x); // cannot use E.x/y directly because of + cky[chk] = u2mil(I.y); // sort() problem with integers > 32767 + ckname[chk] = I.name; + cksh[chk] = I.sheet; + chk++; + } + } + } // 2008.01.30 + } + + //CheckSameOrigin(chk); 2013-08-19 + SortElements(); + GenerateNames(); + setgridmil (); + GenerateScript(); + + if (CheckNames()) { + int select; + dlgDialog("Symbol ref Device Names") { + dlgVBoxLayout { + dlgLabel("Warnings for renumber!"); + dlgTextView(Error); + } + dlgHBoxLayout { + dlgSpacing(450); + } + dlgHBoxLayout { + dlgPushButton("+&OK") dlgAccept(); + dlgStretch(1); + } + }; + exit (-1); + } + + sprintf(c, "GRID INCH 0.1;\n"); + Cmd += c; + sprintf(c, "EDIT .S%d;\n", actual_sheet); + Cmd += c; + visible(S); + + string fname = filesetext(S.name, "~renumsch.scr"); + output(fname, "wtD") printf("%s", Cmd); + exit ("SCRIPT '" + fname + "';"); + } +} + +else { + dlgMessageBox("\nStart this ULP in a Schematic\n"); + exit (0); +} diff --git a/trunk/ulp/route-bga.ulp b/trunk/ulp/route-bga.ulp new file mode 100644 index 00000000..018fb21d --- /dev/null +++ b/trunk/ulp/route-bga.ulp @@ -0,0 +1,1185 @@ +#usage "en: BGA Escape Routing " + "

    " + "Usage: run route-bga element" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#require 6.0000 + +string Version = "1.0"; + +//====================================================================================== +// Include +enum { false = 0, true = 1 }; + +// Debug stuff + +int Dbg = 0; +string DbgMsg, DbgTxt, DbgFile; + +void DbgInit() { + if (Dbg) { + output(DbgFile, "wt") printf(""); + DbgTxt = ""; + } +} + +void DbgDump() { + if (Dbg) { + output(DbgFile, "wba") printf(DbgTxt); + DbgTxt = ""; + } +} + +// General utilities +int Sgn(int i) { + return (i > 0) ? 1 : (i < 0) ? -1 : 0; +} + +string I2Str(int i) { + string str; + sprintf(str, "%d", i); + return str; +} + +// nrDigits: number of digits after dot/comma +string R2Str(real r, int nrDigits) { + string str; + sprintf(str, "%." + I2Str(nrDigits) + "f", r); + return str; +} + +int Str2U(string s) { + if (strstr(s, "mm") > 0) return int(strtod(s) * 10000 * 32); + if (strstr(s, "mil") > 0) return int(strtod(s) * 10 * 32 * 25.4); + if (strstr(s, "in") > 0) return int(strtod(s) * 10000 * 32 * 25.4); + if (strstr(s, "mic") > 0) return int(strtod(s) * 10 * 32); + dlgMessageBox("Unknown unit ! Cannot convert."); + return 0; +} + +// Language support for dialogs: German/English +// Please keep to alphabetic sorting for better maintainability ! + +string Dictionary[] = { + "en\v" + "de\v", + "All contacts\v" + "Alle Kontakte\v", + "BGA analysis for \v" + "BGA-Analyse von \v", + "Cancel\v" + "Beenden\v", + "Contact diameter: \v" + "Kontakt-Durchmesser: \v", + "Contact distance: \v" + "Kontakt-Abstand: \v", + "Contacts not completely circular (Roundness < 99%) !\v" + "Kontakte nicht vollständig kreisförmig (Rundheit < 99%) !\v", + "Contacts with signals\v" + "Kontakte mit Signalen\v", + "Coverage\v" + "Abdeckung\v", + "Deviation of SMD dimensions\v" + "Unterschiedliche SMD-Grössen !\v", + "Element contains non SMD contacts !\v" + "Element enthält Nicht-SMD-Kontakte !\v", + "Escape distance: \v" + "Escape-Distanz: \v", + "Help\v" + "Hilfe\v", + "Make bones\v" + "Knochentechnik\v", + "Maximum via drill for bone technique: \v" + "Maximaler Via-Durchmesser für die Knochentechnik: \v", + "Maximum wire width for one wire between contacts: \v" + "Maximale Wire-Breite für eine Bahn zwischen den Kontakten: \v", + "Micro via drill size:\v" + "Micro-Via-Durchmesser:\v", + "Not enough space for vias between contacts. \v" + "Nicht ausreichend Platz für Vias zwischen den Kontakten. \v", + "Not enough space for wires between contacts. \v" + "Nicht ausreichend Platz für Wires zwischen den Kontakten. \v", + "not found\v" + "nicht gefunden\v", + "Number of contacts: \v" + "Anzahl von Kontakten: \v", + "Please start from Layout editor !\v" + "Bitte starten Sie vom Layout-Editor aus !\v", + "Processing %d of %d contacts\v" + "Bearbeite %d von %d Kontakten\v", + "Stacked micro vias:\v" + "Stacked Micro-Vias:\v", + "Stacked micro vias recommended !\v" + "Empfehlung von Stacked Micro-Vias !\v", + "Use net classes\v" + "Netzklassen verwenden\v", + "Use specific sizes:\v" + "Spezifische Grössen verwenden:\v", + "with signals\v" + "mit Signalen\v", + "Via drill size:\v" + "Via-Durchmesser:\v", + "Via strategy\v" + "Via-Strategie\v", + "Wire and via sizes:\v" + "Wire- und Via-Grössen:\v", + "Wire width:\v" + "Wire-Breite:\v" +}; + +string DlgLang = language(); +if (DlgLang != "de") DlgLang = "en"; +int LangIdx = strstr(Dictionary[0], DlgLang) / 3; + +// Translate, based on dictionary +string tr(string s) { + string t = lookup(Dictionary, s, LangIdx, '\v'); + return (t != "") ? t : s; +} +// End include +//============================================================================== + +//============================================================================== +// Globals +//============================================================================== + +// Constants +//---------- + +// States of grid points +enum { NEAR_WIRE = 1, + NEAR_VIA = 2, + WIRE = 3, + VIA = 4, + CON = 1 << 3, + VISITED = 1 << 4 + + }; +enum { ROUTE_MASK = 0x7 }; + +// Dimensions +enum { DIM_X, DIM_Y }; + +enum { INVALID_POS = -1 }; + +// Via strategies +enum { BONES = 0, STACKED_VIAS = 1 }; +// Route modes +enum { ESCAPE, INTERNAL }; + +// Variables +//---------- + +// DRU stuff +int ExpDRUs = true; +string DruFile; +// Not adjusted +int MinWireWire, MinWirePad, MinWireVia, MinPadVia, MinViaVia; +// Used as minimums +int MinWireWidth; +int MinViaDrill, MinMicroViaDrill; +// Restring stuff +real RestFacVia, RestFacMicroVia; +int RestMinVia, RestMaxVia, RestMinMicroVia, RestMaxMicroVia; +int NrLayers, Layers[]; + +int EscapeDist = 5 * 10000 * 32; // 5 mm + +int Dialog = true; +string ScrFile; +int ExtUnit; +string ExtUnitName; +string ElemNames[]; +int NrElems; + +real Lbr2BrdRot[] = { 1, 0, + 0, 1 }; +int ElemX, ElemY; + +int WireWidth; +int ViaDrill, ViaDiam; +int MicroViaDrill, MicroViaDiam; + +// Net classes +int UseNetClasses = false; +int MaxNetClassId; +int ClassAdjWidths[], ClassAdjDrills[], ClassClearances[]; + +// BGA specific +//------------- +// Element as whole +string ElemName; +real ElemAngle; +int ElemMirror; +int NrNewSig; +int ElemViaStrat = BONES; //STACKED_VIAS; +int ElemRouteAll = false; + +// Contacts +int ConXMin, ConYMin; +int NrCons, NrConsX, NrConsY, NrConsWithSig; +string ConSigNames[]; +int ConXs[], ConYs[], ConClassIds[], ConIdxs[]; +// Corresponding coords of lbr package +int LbrPacConXs[], LbrPacConYs[]; +int ConDist, ConDiam; + +int MaxWireWidth1, MaxViaDrill; + +// Grid Matrix +int NrGrid, NrGridX, NrGridY, GridStates[]; +int GridOriginX, GridOriginY; +int GridDist; +int GridMultiple = 1; +// Only calculated and relevant if more than one wire between contacts: +// - Distance from contact middle to next possible wire middle. +int GridConMWireM; +// - Distance from wire middle to neighboring wire middle +real GridWireMWireM; + +// Matrix of allowed transitions +// - Number of states relevant for routing through/beside them +int NrOccStates = 6; +int Allowed[] = { true, true, true, true, true, true, // NEAR_VIA + true, true, true, true, true, true, // NEAR_WIRE + true, false, false, false, false, false, // WIRE + true, false, true, false, false, false };// VIA +// The index position for contact in the Allowed-Matrix. +int AllowedIdxCon = 5; + +// Current states while traversing grid +int CurTraverse; +int CurGridX, CurGridY; +//int CurRouteDir; +int CurIncX, CurIncY; +int CurEscaped; + +int PrevTryIncI, PrevTryIncJ; // PrevStepMode ? +int CurRouteMode; +int CurDeltaI, CurDeltaJ; +int CurTryIncI[], CurTryIncJ[], CurNrTries; // Optimize with CurStepModes[3] ? +int CurTakeBone; +int CurBoneX, CurBoneY; + +// Escape trials +int TryI, TryJ; + +//============================================================================== +// Functions +//============================================================================== + +int ExtU2U(real x) { + return (ExtUnit == GRID_UNIT_MM) ? mm2u(x) : + (ExtUnit == GRID_UNIT_INCH) ? inch2u(x) : + (ExtUnit == GRID_UNIT_MIC) ? mic2u(x) : mil2u(x); +} + +real U2ExtU(int x) { + return (ExtUnit == GRID_UNIT_MM) ? u2mm(x) : + (ExtUnit == GRID_UNIT_INCH) ? u2inch(x) : + (ExtUnit == GRID_UNIT_MIC) ? u2mic(x) : u2mil(x); +} + +string U2ExtUStr(int u) { + return R2Str(U2ExtU(u), 3) + ExtUnitName; +} + +int GetViaDiam(int drill) { + return drill + min(max(RestFacVia * drill, RestMinVia), RestMaxVia) * 2; +} + +void GetDesignParams() { + // Read relevant design rule parameters: + string lines[], laySetupStr; + int nrLines = fileread(lines, DruFile); + if (nrLines == 0) { + dlgMessageBox("Error reading design rules !"); + exit(EXIT_FAILURE); + } + for (int i = 0; i < nrLines; ++i) { + string words[]; + int nrWords = strsplit(words, lines[i], ' '); + if (nrWords < 3) continue; // Empty line or some other stuff + string keyword = words[0]; + if (keyword == "mdWireWire") MinWireWire = Str2U(words[2]); + else if (keyword == "mdWirePad") MinWirePad = Str2U(words[2]); + else if (keyword == "mdWireVia") MinWireVia = Str2U(words[2]); + else if (keyword == "mdPadVia") MinPadVia = Str2U(words[2]); + else if (keyword == "mdViaVia") MinViaVia = Str2U(words[2]); + else if (keyword == "msWidth") MinWireWidth = Str2U(words[2]); + else if (keyword == "layerSetup") laySetupStr = words[2]; + else if (keyword == "msDrill") MinViaDrill = Str2U(words[2]); + else if (keyword == "rvViaOuter") RestFacVia = strtod(words[2]); + else if (keyword == "rlMinViaOuter") RestMinVia = Str2U(words[2]); + else if (keyword == "rlMaxViaOuter") RestMaxVia = Str2U(words[2]); + else if (keyword == "msMicroVia") MinMicroViaDrill = Str2U(words[2]); + else if (keyword == "rvMicroViaOuter") RestFacMicroVia = strtod(words[2]); + else if (keyword == "rlMinMicroViaOuter") RestMinMicroVia = Str2U(words[2]); + else if (keyword == "rlMaxMicroViaOuter") RestMaxMicroVia = Str2U(words[2]); + } + // Evaluate LayerSetup-String: + for (int j = 1; j <= 16; ++j) { + string layStr; + sprintf(layStr, "[\\D]%d[\\D]", j); + if (strxstr(laySetupStr, layStr) != -1) { + Layers[NrLayers++] = j; + if (Dbg) { sprintf(DbgMsg, "Layer %d\n", Layers[NrLayers -1]); DbgTxt += DbgMsg; } + } + } + WireWidth = MinWireWidth; + ViaDrill = MinViaDrill; + MicroViaDrill = min(MinMicroViaDrill, MinViaDrill); + if (Dbg) { + sprintf(DbgMsg, "DRU Params: MinWireWire %f MinWirePad %f MinWireVia %f MinPadVia %f MinViaVia %f\n", + u2mm(MinWireWire), u2mm(MinWirePad), u2mm(MinWireVia), u2mm(MinPadVia), u2mm(MinViaVia)); + DbgTxt += DbgMsg; + } +} + +int GridState(int lay, int i, int j) { + return (i >= 0 && i < NrGridX && j >= 0 && j < NrGridY) ? GridStates[lay * NrGrid + i * NrGridY + j]: 0; +} + +int GridHasState(int lay, int i, int j, int state) { + return GridStates[lay * NrGrid + i * NrGridY + j] & state; +} + +// Not valid for route states ! +void SetGridState(int lay, int i, int j, int state) { + GridStates[lay * NrGrid + i * NrGridY + j] |= state; +} + +void SetGridRouteState(int lay, int i, int j, int state) { + if (i >= 0 && i < NrGridX && j >= 0 && j < NrGridY) + GridStates[lay * NrGrid + i * NrGridY + j] = (GridStates[lay * NrGrid + i * NrGridY + j] & ~ROUTE_MASK) | state; +} + +int GridCoord(int k, int dim) { + if (GridMultiple <= 2) + return (dim == DIM_X ? GridOriginX : GridOriginY) + k * GridDist; + // If more than 1 trace fits between it's not so obvious... + int r = k % GridMultiple - 1; + int between = (r > -1) ? GridConMWireM + r * GridWireMWireM : 0; + return (dim == DIM_X ? GridOriginX : GridOriginY) + k / GridMultiple * ConDist + between; +} + +int LbrGrid2BrdCoord(int i, int j, int dim) { + int elemCoord = (dim == DIM_X) ? ElemX : ElemY; + int rowOffs = (dim == DIM_X) ? 0 : 2; // LbrPacX = LbrPac = 0 + return round(Lbr2BrdRot[rowOffs] * GridCoord(i, DIM_X) + Lbr2BrdRot[rowOffs + 1] * GridCoord(j, DIM_Y)) + elemCoord; +} + +void SetupElement(string elemName) { + int err = false, errRound = false, errType = false, errSize = false; + int found = false; + int roundTol = 1; // Perhaps check this out more detailed ! + int conXMax = INT_MIN, conYMax = INT_MIN; + int conDiamMin = INT_MAX, conDiamMax = INT_MIN; // Checking radius deviations + int conDistMin = INT_MAX, conDistMax = INT_MIN; // Checking distance deviations + + ElemName = elemName; + NrNewSig = 0; + NrCons = 0; + ConDist = INT_MAX; + ConXMin = INT_MAX, ConYMin = INT_MAX; + if (Dbg) DbgTxt += "SetupElement:\n"; + + // Find element and package of according library + board(B) { + string lbrName, pacName; + B.elements(E) + if (E.name == elemName) { + found = true; + lbrName = E.package.library; + pacName = E.package.name; + // Params for xform + ElemX = E.x; + ElemY = E.y; + ElemMirror = E.mirror; + ElemAngle = E.angle / 180 * PI; // Bogenmass ! + Lbr2BrdRot[0] = cos(ElemAngle); + Lbr2BrdRot[1] =-sin(ElemAngle); + Lbr2BrdRot[2] = sin(ElemAngle); + Lbr2BrdRot[3] = cos(ElemAngle); + if (Dbg) { + sprintf(DbgMsg, "angle, Rot: %f, (%f %f %f %f)\n", E.angle, Lbr2BrdRot[0], Lbr2BrdRot[1] ,Lbr2BrdRot[2] ,Lbr2BrdRot[3]); + DbgTxt += DbgMsg; + } + E.package.contacts(C) { + ConXs[NrCons] = C.x; + ConYs[NrCons] = C.y; + ConSigNames[NrCons] = C.signal; + if (C.signal != "") ++NrConsWithSig; + if (Dbg) { sprintf(DbgMsg, "Elem: (%f %f)\n", u2mm(ConXs[NrCons]), u2mm(ConYs[NrCons])); DbgTxt += DbgMsg; } + ++NrCons; + } + break; + } + if (!found) { + dlgMessageBox("Element " + elemName + " " + tr("not found") + "!"); + exit(EXIT_FAILURE); + } + found = false; + B.libraries(L) if (!found && L.name == lbrName) + L.packages(PAC) if (PAC.name == pacName) { + found = true; + int i; + PAC.contacts(C) { + LbrPacConXs[i] = C.x; + LbrPacConYs[i++] = C.y; + // Get grid dimensions + ConXMin = min(ConXMin, C.x); + conXMax = max(conXMax, C.x); + ConYMin = min(ConYMin, C.y); + conYMax = max(conYMax, C.y); + if (Dbg) { sprintf(DbgMsg, "LbrPac: (%f %f)\n", u2mm(LbrPacConXs[i-1]), u2mm(LbrPacConYs[i-1])); DbgTxt += DbgMsg; } + if (C.smd) { + ConDiam = C.smd.dx; + if (C.smd.dx != C.smd.dy || 100 - C.smd.roundness > roundTol) + errRound = true; + conDiamMin = min(conDiamMin, C.smd.dx); + conDiamMax = max(conDiamMax, C.smd.dx); + if (conDiamMin != conDiamMax) + errSize = true; + } + else { + errType = true; + break; + } + } + break; + } + } + + // Error conditions: + if (errSize) dlgMessageBox(tr("Deviation of SMD sizes ") + " ! " + "Minimum = " + + U2ExtUStr(conDiamMin) + ", Maximum = " + U2ExtUStr(conDiamMax)); + if (errType) dlgMessageBox(tr("Element contains non SMD contacts !")); + if (errRound) dlgMessageBox(tr("Contacts not completely circular !")); + if (errSize || errType || errRound) + exit(EXIT_FAILURE); + + ConDiam = (conDiamMin + conDiamMax) / 2; // Tolerant approach. Tolerances tbd. + sort(NrCons, ConIdxs, LbrPacConXs, LbrPacConYs); + // Calc contact distance. + for (int i = 1, curX = LbrPacConXs[ConIdxs[0]]; i < NrCons; ++i) { + if (LbrPacConXs[ConIdxs[i]] == curX) + ConDist = min(ConDist, LbrPacConYs[ConIdxs[i]] - LbrPacConYs[ConIdxs[i - 1]]); + else { + ConDist = min(ConDist, LbrPacConXs[ConIdxs[i]] - curX); + curX = LbrPacConXs[ConIdxs[i]]; + } + } + if (Dbg) DbgDump(); + + real rNrConsX = real(conXMax - ConXMin) / ConDist + 1; + real rNrConsY = real(conYMax - ConYMin) / ConDist + 1; + NrConsX = round(rNrConsX); + NrConsY = round(rNrConsY); + if (Dbg) { + real dbgEpsX = abs(rNrConsX - NrConsX); + real dbgEpsY = abs(rNrConsY - NrConsY); + sprintf(DbgMsg, "Deviation NrConsX/Y: %.7f %.7f\n", dbgEpsX, dbgEpsY); DbgTxt += DbgMsg; + DbgDump(); + } + MaxWireWidth1 = max(ConDist - ConDiam - 2 * MinWirePad, 0); + int viaDiam = sqrt(2) * ConDist - ConDiam - 2 * MinPadVia; + MaxViaDrill = max(max(min(viaDiam / (1 + 2 * RestFacVia), viaDiam - 2 * RestMinVia), viaDiam - 2 * RestMaxVia), 0); +} + +void IncludeClasses() { + string sigNames[]; + int sigClassIds[], nrSigs; + board(B) { + int maxNetClassId; + B.classes(C) if (C.name != "") { + // Adjustment: + ClassAdjWidths[C.number] = max(C.width, MinWireWidth); + ClassAdjDrills[C.number] = max(C.drill, MinViaDrill); // CalcViaDiam + ClassClearances[C.number] = C.clearance; + if (Dbg) { + sprintf(DbgMsg, "C.number %d C.width %f C.drill %f C.clearance %f\n", + C.number, u2mm(C.width), u2mm(C.drill), u2mm(C.clearance)); + DbgTxt += DbgMsg; + } + maxNetClassId = max(maxNetClassId, C.number); + } + // Incorporate class widths, drills etc. in design parameters. + ViaDiam = GetViaDiam(MinViaDrill); + for (int i = 0; i < maxNetClassId; ++i) { + WireWidth = max(WireWidth, ClassAdjWidths[i]); + ViaDiam = max(ViaDiam, GetViaDiam(ClassAdjDrills[i])); + MinWireWire = max(MinWireWire, ClassClearances[i]); + MinWirePad = max(MinWirePad, ClassClearances[i]); + MinWireVia = max(MinWireVia, ClassClearances[i]); + MinViaVia = max(MinViaVia, ClassClearances[i]); + MinPadVia = max(MinPadVia, ClassClearances[i]); + } + // Collect BGA's signals and classes + B.signals(S) + S.contactrefs(CR) + if (CR.element.name == ElemName) { + sigNames[nrSigs] = S.name; + sigClassIds[nrSigs++] = S.class.number; + if (Dbg) { + sprintf(DbgMsg, "BGA-Signal: %s %d\n", sigNames[nrSigs - 1], sigClassIds[nrSigs - 1]); + DbgTxt += DbgMsg; + } + break; + } + } + for (int i = 0; i < NrCons; ++i) + if (ConSigNames[i] != "") + for (int j = 0; j < nrSigs; ++j) + if (sigNames[j] == ConSigNames[i]) { + ConClassIds[i] = sigClassIds[j]; + if (Dbg) { + sprintf(DbgMsg, "Con->ClassId: %d %d\n", i, ConClassIds[i]); + DbgTxt += DbgMsg; + } + break; + } + DbgDump(); +} + +void InitGrid() { + if (Dbg) { + sprintf(DbgMsg, "InitGrid: ViaDiam %f MicroViaDiam %f WireWidth %f \n" + "MinWireWire %f MinWirePad %f MinWireVia %f MinViaVia %f MinPadVia %f\n", + u2mm(ViaDiam), u2mm(MicroViaDiam), u2mm(WireWidth), u2mm(MinWireWire), + u2mm(MinWirePad), u2mm(MinWireVia), u2mm(MinViaVia), u2mm(MinPadVia)); + DbgTxt += DbgMsg; + } + // Nr traces between contacts: + int freeWidth = ConDist - ConDiam - 2 * MinWirePad - WireWidth; + if (freeWidth >= 0) { + GridMultiple = 2; + // In this case we support more than 1 trace between ! + if (ElemViaStrat == STACKED_VIAS) + GridMultiple += freeWidth / (WireWidth + MinWireWire); + } + if (GridMultiple <= 2) GridDist = ConDist / GridMultiple; + else { + GridConMWireM = ConDiam / 2 + MinWirePad + WireWidth / 2; + GridWireMWireM = real(freeWidth) / (GridMultiple - 2); + } + NrGridX = (NrConsX - 1) * GridMultiple + 1; + NrGridY = (NrConsY - 1) * GridMultiple + 1; + NrGrid = NrGridX * NrGridY; + GridOriginX = ConXMin; + GridOriginY = ConYMin; + + if (Dbg) { + sprintf(DbgMsg, "GridMultiple %d GridDist %f NrGridX %d NrGridY %d \nGridOriginX %f GridOriginY %f\n", + GridMultiple, u2mm(GridDist), NrGridX, NrGridY, u2mm(GridOriginX), u2mm(GridOriginY)); + DbgTxt += DbgMsg; DbgDump(); + } + + int nrTotal = NrGrid * NrLayers; + for (int i = nrTotal - 1; i >= 0; --i) GridStates[i] = 0; // Faster initialisation this way... + for (int k = 0; k < NrCons; ++k) { + int i = round(real(LbrPacConXs[k] - GridOriginX) / ConDist * GridMultiple); + int j = round(real(LbrPacConYs[k] - GridOriginY) / ConDist * GridMultiple); + SetGridState(0, i, j, CON); + } + Allowed[NrOccStates * (NEAR_WIRE - 1) + AllowedIdxCon] = (GridDist * sqrt(2) >= ConDiam + MinWirePad * 2 + WireWidth); + Allowed[NrOccStates * (VIA - 1) + NEAR_VIA] = (GridDist >= ViaDiam + MinViaVia); + Allowed[NrOccStates * (NEAR_VIA - 1) + VIA] = Allowed[NrOccStates * (VIA - 1) + NEAR_VIA]; + Allowed[NrOccStates * (NEAR_VIA - 1) + AllowedIdxCon] = (GridDist >= ViaDiam / 2 + ConDiam / 2 + MinPadVia); + Allowed[NrOccStates * (NEAR_VIA - 1) + WIRE] = (GridDist >= ViaDiam / 2 + WireWidth / 2 + MinWireVia); + // Leads to diagonal problem ! + //Allowed[NrOccStates * (WIRE - 1) + NEAR_VIA] = Allowed[NrOccStates * (NEAR_VIA - 1) + WIRE]; + if (Dbg) { + sprintf(DbgMsg,"NEAR_WIRE -> CON: GridDist * sqrt(2) %f <-> %f\n", + u2mm(int(GridDist * sqrt(2))), u2mm(ConDiam + MinWirePad * 2 + WireWidth)); DbgTxt += DbgMsg; + sprintf(DbgMsg,"NEAR_VIA -> CON: ViaDiam / 2 + ConDiam / 2 + MinPadVia: %f\n", + u2mm(ViaDiam / 2 + ConDiam / 2 + MinPadVia)); DbgTxt += DbgMsg; + sprintf(DbgMsg,"WIRE -> NEAR_VIA: ViaDiam / 2 + WireWidth / 2 + MinWireVia: %f\n", + u2mm(ViaDiam / 2 + WireWidth / 2 + MinWireVia)); DbgTxt += DbgMsg; + + sprintf(DbgMsg,"Allowed-Matrix:\n"); DbgTxt += DbgMsg; + for (int i = 0; i<4; ++i) { + sprintf(DbgMsg,"%d %d %d %d %d %d\n", Allowed[NrOccStates * i], Allowed[NrOccStates * i + 1], + Allowed[NrOccStates * i + 2], Allowed[NrOccStates * i + 3], + Allowed[NrOccStates * i + 4], Allowed[NrOccStates * i + 5]); + DbgTxt += DbgMsg; + } + DbgDump(); + } +} + +int AllowedTransition(int curState, int newRouteState) { + int allowed = (curState & CON) ? Allowed[NrOccStates * (newRouteState - 1) + AllowedIdxCon] : true; + if (allowed) { + int routeState = curState & ROUTE_MASK; // 3 bit ! + if (routeState != 0) + allowed = Allowed[NrOccStates * (newRouteState - 1) + routeState]; + } + if (Dbg) { sprintf(DbgMsg, "AllowedTransition: %d -> %d: %d\n", curState, newRouteState, allowed); DbgTxt += DbgMsg; } + return allowed; +} + +int Layer(int i) { + return ElemMirror ? Layers[NrLayers - 1 - i] : Layers[i]; +} + +int ConIdx(int i, int j) { + if (Dbg) { sprintf(DbgMsg, "ConIdx: i %d j %d\n", i, j); DbgTxt += DbgMsg; } + if ((i % GridMultiple != 0) || (j % GridMultiple != 0)) return -1; + int x = GridOriginX + round(ConDist * i / GridMultiple); // ! oder ConXs/Y - Arrays ersetzen ! + int y = GridOriginY + round(ConDist * j / GridMultiple); + for (int k = 0; k < NrCons; ++k) + if ((LbrPacConXs[ConIdxs[k]] == x) && (LbrPacConYs[ConIdxs[k]] == y)) { + if (Dbg) { sprintf(DbgMsg, "ConIdx return: %d\n", ConIdxs[k]); DbgTxt += DbgMsg; } + return ConIdxs[k]; + } + else if (LbrPacConXs[ConIdxs[k]] > x) { + if (Dbg) DbgTxt += "LbrPacConXs[ConIdxs[k]] > x !"; + return -1; + } + return -1; +} + +string NewSigName() { + string newSigName; + sprintf(newSigName, "%s-%d", ElemName, ++NrNewSig); //IC2-34. Alternative: IC2-i-j, i,j Kontaktpos. + return newSigName; +} + +int BorderDist(int i, int j) { + return min(min(i, NrGridX - 1 - i), min(j, NrGridY - 1 - j)); +} + +void TurnLeft() { + if (Dbg) { sprintf(DbgMsg, "TurnLeft: before: (%d %d) (%d %d)\n", CurDeltaI, CurDeltaJ, CurIncX, CurIncY); DbgTxt += DbgMsg; } + int oldDeltaI = CurDeltaI, oldIncX = CurIncX; + CurDeltaI = -CurDeltaJ; + CurDeltaJ = oldDeltaI; + CurIncX = -CurIncY; + CurIncY = oldIncX; + if (Dbg) { sprintf(DbgMsg, "TurnLeft: after: (%d %d) (%d %d)\n", CurDeltaI, CurDeltaJ, CurIncX, CurIncY); DbgTxt += DbgMsg; } +} + +int SetNextPos() { + if (Dbg) { sprintf(DbgMsg, "SetNextPos: before: %d %d\n", CurGridX, CurGridY); DbgTxt += DbgMsg; DbgDump(); } + if (!CurTraverse) { + CurGridX = 0; + CurGridY = NrGridY - 1; + // Route to left, traverse down + CurDeltaI = -1; + CurDeltaJ = 0; + CurIncX = 0; + CurIncY = -1; + SetGridState(0, CurGridX, CurGridY, VISITED); + CurTraverse = true; + return true; + } + int turn1 = false; + if (GridHasState(0, CurGridX + CurIncX, CurGridY + CurIncY, VISITED)) { + TurnLeft(); + turn1 = true; + } + CurGridX += CurIncX; + CurGridY += CurIncY; + if (!turn1 && min(CurGridX, NrGridX - 1 - CurGridX) == min(CurGridY, NrGridY - 1 - CurGridY)) + TurnLeft(); + if (GridHasState(0, CurGridX, CurGridY, VISITED)) + CurGridX = CurGridY = INVALID_POS; + else + SetGridState(0, CurGridX, CurGridY, VISITED); + if (Dbg) { sprintf(DbgMsg, "SetNextPos: after: %d %d\n", CurGridX, CurGridY); DbgTxt += DbgMsg; DbgDump(); } + return (CurGridX != INVALID_POS); +} + +int SetNextConPos() { + while (SetNextPos() && !(GridHasState(0, CurGridX, CurGridY, CON) && + (ElemRouteAll || ConSigNames[ConIdx(CurGridX, CurGridY)] != ""))); + CurEscaped = false; + CurTakeBone = false; + CurRouteMode = ESCAPE; + return (CurGridX != INVALID_POS); +} + +int IsBorder(int i, int j) { + return (i == 0) || (i == NrGridX - 1) || (j == 0) || (j == NrGridY - 1); +} + +int TryRoute(int lay, int i, int j, int incX, int incY, int routeType, int singleStep) { + if (Dbg) { + sprintf(DbgMsg, "Try start: i %d j %d incX %d inc Y %d type %d\n", i,j,incX,incY,routeType); + DbgTxt += DbgMsg; DbgDump(); + } + TryI = i; + TryJ = j; + while (true) { + if (IsBorder(TryI, TryJ) || !AllowedTransition(GridState(lay, TryI + incX, TryJ + incY), routeType)) break; + if (routeType == VIA) { + if (incX == 0) { + if (!(AllowedTransition(GridState(lay, TryI - 1, TryJ + incY), NEAR_VIA) && + AllowedTransition(GridState(lay, TryI + 1, TryJ + incY), NEAR_VIA) && + AllowedTransition(GridState(lay, TryI, TryJ + 2 * incY), NEAR_VIA))) break; + } + else if (incY == 0) { + if (!(AllowedTransition(GridState(lay, TryI + incX, TryJ - 1), NEAR_VIA) && + AllowedTransition(GridState(lay, TryI + incX, TryJ + 1), NEAR_VIA) && + AllowedTransition(GridState(lay, TryI + 2 * incX, TryJ), NEAR_VIA))) break; + } + else if (!(AllowedTransition(GridState(lay, TryI + incX - 1, TryJ + incY ), NEAR_VIA) && + AllowedTransition(GridState(lay, TryI + incX , TryJ + incY - 1), NEAR_VIA) && + AllowedTransition(GridState(lay, TryI + incX + 1, TryJ + incY ), NEAR_VIA) && + AllowedTransition(GridState(lay, TryI + incX , TryJ + incY + 1), NEAR_VIA))) break; + } + else if ((incX * incY != 0) && + !(AllowedTransition(GridState(lay, TryI , TryJ + incY), NEAR_WIRE) && + AllowedTransition(GridState(lay, TryI + incX, TryJ ), NEAR_WIRE))) break; + TryI += incX; + TryJ += incY; + if (singleStep) break; + } + CurEscaped = IsBorder(TryI, TryJ); + if (Dbg) { sprintf(DbgMsg, "Try end: TriI %d TryJ %d\n", TryI, TryJ); DbgTxt += DbgMsg; DbgDump(); } + return CurEscaped || (TryI != i) || (TryJ != j); +} + +void SetNextSteps() { + if (CurRouteMode == ESCAPE) { + int prevI = (PrevTryIncI == 0 && PrevTryIncJ == 0) ? Sgn(CurDeltaI) : PrevTryIncI; + int prevJ = (PrevTryIncI == 0 && PrevTryIncJ == 0) ? Sgn(CurDeltaJ) : PrevTryIncJ; + int incI[] = { prevI, Sgn( prevI + prevJ), Sgn(prevI - prevJ) }; + int incJ[] = { prevJ, Sgn(-prevI + prevJ), Sgn(prevI + prevJ) }; + int idx[] = { 0, 1, 2 }; + CurNrTries = 3; + if (Dbg) { + sprintf(DbgMsg, "SetNextSteps before: CurNrTries %d\n", CurNrTries); DbgTxt += DbgMsg; + for (int k = 0; k < CurNrTries; ++k) { + sprintf(DbgMsg, "%d %d,", incI[k], incJ[k]); DbgTxt += DbgMsg; + } + DbgTxt += "\n"; + } + // Assumption: Only one direction can be opposite of escape direction + if (incI[1] * CurDeltaI < 0 || incJ[1] * CurDeltaJ < 0) { + incI[1] = incI[2]; + incJ[1] = incJ[2]; + --CurNrTries; + } + else if (incI[2] * CurDeltaI < 0 || incJ[2] * CurDeltaJ < 0) + --CurNrTries; + // If direction exactly matches to escape direction take this one first ! + for (int k = 1; k < CurNrTries; ++k) + if (Sgn(incI[k]) == Sgn(CurDeltaI) && Sgn(incJ[k]) == Sgn(CurDeltaJ)) { // Sgn would be obsolete if all normed + idx[0] = k; + idx[k] = 0; + break; + } + // If direction is orthogonal (only one) make it the last one ! + for (k = 0; k < CurNrTries; ++k) + if (incI[idx[k]] * CurDeltaI + incJ[idx[k]] * CurDeltaJ == 0) { + int t = idx[k]; + idx[k] = idx[CurNrTries - 1]; + idx[CurNrTries - 1] = t; + } + for (k = 0; k < CurNrTries; ++k) { + CurTryIncI[k] = incI[idx[k]]; + CurTryIncJ[k] = incJ[idx[k]]; + } + } + if (Dbg) { + sprintf(DbgMsg, "SetNextSteps: CurNrTries %d\n", CurNrTries); DbgTxt += DbgMsg; + for (int k = 0; k < CurNrTries; ++k) { + sprintf(DbgMsg, "%d %d,", CurTryIncI[k], CurTryIncJ[k]); DbgTxt += DbgMsg; + } + DbgTxt += "\n"; + } +} + +// Important: (i,j) must be a BORDER POINT ! +int EscapeVec(int i, int j, int dim) { + int k, l; + if (i == 0 && j > 0) k = -EscapeDist; + else if (i < NrGridX - 1 && j == 0) l = -EscapeDist; + else if (i == NrGridX - 1 && j < NrGridY - 1) k = EscapeDist; + else l = EscapeDist; + int rowOffs = (dim == DIM_X) ? 0 : 2; + if (Dbg) { + int tr = round(Lbr2BrdRot[rowOffs] * k + Lbr2BrdRot[rowOffs + 1] * l); + sprintf(DbgMsg, "EscapeVec: i,j,k,l,dim: tr: (%d %d) (%f %f) %d: %f)\n",i, j, u2mm(k), u2mm(l), dim, u2mm(tr)); DbgTxt += DbgMsg; + } + return round(Lbr2BrdRot[rowOffs] * k + Lbr2BrdRot[rowOffs + 1] * l); +} + +void Execute() { + output(ScrFile, "wt") + for (int i = 0; i < NrElems; ++i) { + board(B) B.elements(E) + if (E.name == ElemNames[i]) { + ViaDiam = GetViaDiam(ViaDrill); + MicroViaDiam = MicroViaDrill + min(max(RestFacMicroVia * MicroViaDrill, RestMinMicroVia), RestMaxMicroVia) * 2; // same like GetViaDiam + if (UseNetClasses) IncludeClasses(); + InitGrid(); + printf("CHANGE SHAPE round;\n"); + printf("SET WIRE_BEND 2;\n"); // 2 necessary for rotations != k * 45 + int conCnt = 0; + for (CurTraverse = false, SetNextConPos(); CurGridX != INVALID_POS; SetNextConPos()) { // Achte auf i ! + string statMsg; + sprintf(statMsg, "Processing %d of %d contacts...", ++conCnt, ElemRouteAll ? NrCons : NrConsWithSig); + status(statMsg); + if (Dbg) { DbgTxt += statMsg; DbgDump(); } + for (int lay = 0, noRoute = false; lay < NrLayers && !CurEscaped && !noRoute; ++lay) { + int curTryI = (CurTakeBone) ? CurBoneX : CurGridX, curTryJ = (CurTakeBone) ? CurBoneY : CurGridY; + int tryI[] = { curTryI }, tryJ[] = { curTryJ }; + int nrTryPts = 1, trapped = false; + int viaTrial = false, routeType = WIRE; + if (Dbg) { + sprintf(DbgMsg, "%s: Contact (%d %d), Layer %d", ElemNames[i], CurGridX, CurGridY, lay); + DbgTxt += DbgMsg + "\n"; DbgDump(); + } + PrevTryIncI = PrevTryIncJ = 0; + if (lay == 0) + CurEscaped = (BorderDist(CurGridX, CurGridY) == 0); + while (!(trapped || CurEscaped)) { + if (!viaTrial) SetNextSteps(); + int tryIncI, tryIncJ; + if ((TryRoute(lay, curTryI, curTryJ, tryIncI = CurTryIncI[0], tryIncJ = CurTryIncJ[0], routeType, true) > 0) || + (CurNrTries > 1 && + (TryRoute(lay, curTryI, curTryJ, tryIncI = CurTryIncI[1], tryIncJ = CurTryIncJ[1], routeType, true) > 0)) || + (CurNrTries > 2 && + (TryRoute(lay, curTryI, curTryJ, tryIncI = CurTryIncI[2], tryIncJ = CurTryIncJ[2], routeType, true) > 0))) { + tryI[nrTryPts] = TryI; + tryJ[nrTryPts++] = TryJ; + curTryI = TryI; + curTryJ = TryJ; + PrevTryIncI = tryIncI; + PrevTryIncJ = tryIncJ; + routeType = WIRE; // In any case continue with WIRE ! + if (Dbg) DbgDump(); + } + else if (ElemViaStrat == BONES && lay == 0 && nrTryPts >= 2 && !viaTrial) { + routeType = VIA; + nrTryPts = 1; + curTryI = CurGridX; + curTryJ = CurGridY; + tryI[0] = curTryI; + tryJ[0] = curTryJ; + PrevTryIncI = PrevTryIncJ = 0; + CurTryIncI[0] = CurDeltaI; + CurTryIncJ[0] = CurDeltaJ; + CurTryIncI[1] = Sgn( CurDeltaI + CurDeltaJ); + CurTryIncJ[1] = Sgn(-CurDeltaI + CurDeltaJ); + CurNrTries = 2; + viaTrial = true; + } + else + trapped = true; + } + if (CurEscaped || (lay == 0 && ElemViaStrat == BONES)) { + int cIdx = ConIdx(CurGridX, CurGridY); + real firstX = U2ExtU(CurTakeBone ? LbrGrid2BrdCoord(CurBoneX, CurBoneY, DIM_X) : ConXs[cIdx]); + real firstY = U2ExtU(CurTakeBone ? LbrGrid2BrdCoord(CurBoneX, CurBoneY, DIM_Y) : ConYs[cIdx]); + real outWireWidth = U2ExtU(UseNetClasses ? ClassAdjWidths[ConClassIds[cIdx]] : WireWidth) ; + real outViaDrill = U2ExtU(ElemViaStrat == STACKED_VIAS ? MicroViaDrill : + UseNetClasses ? ClassAdjDrills[ConClassIds[cIdx]] : ViaDrill); + if (Dbg) { + sprintf(DbgMsg, "Output: cIdx %d \n", cIdx); DbgTxt += DbgMsg; + if (UseNetClasses) { + sprintf(DbgMsg, "ConClassIds[cIdx] %d ClassWidths[ConClassIds[cIdx]] %f " + "ClassDrills[ConClassIds[cIdx]] %f\n", ConClassIds[cIdx], + u2mm(ClassAdjWidths[ConClassIds[cIdx]]), u2mm(ClassAdjDrills[ConClassIds[cIdx]])); + DbgTxt += DbgMsg; + } + DbgDump(); + } + string sig = ConSigNames[cIdx]; + if (sig == "") sig = NewSigName(); + if (Dbg) { sprintf(DbgMsg, "Escaped, after NewSigName\n"); DbgTxt += DbgMsg; DbgDump(); } + + if (CurEscaped) { + printf("LAYER %d;\n", Layer(lay)); // Evtl. nach vias + if (lay > 0) { + printf("CHANGE DRILL %f;\n", outViaDrill); + printf("VIA '%s'", sig); + if (ElemViaStrat == STACKED_VIAS) { + for (int l = 1; l <= lay; ++l) + printf(" %d-%d (%f %f)", Layer(l - 1), Layer(l), firstX, firstY); + printf(";\n"); + } + else { + for (int l = 1; l <= lay; ++l) { + SetGridRouteState(l, CurBoneX, CurBoneY, VIA); + SetGridRouteState(l, CurBoneX - 1, CurBoneY , NEAR_VIA); + SetGridRouteState(l, CurBoneX + 1, CurBoneY , NEAR_VIA); + SetGridRouteState(l, CurBoneX , CurBoneY - 1, NEAR_VIA); + SetGridRouteState(l, CurBoneX , CurBoneY + 1, NEAR_VIA); + } + printf(" %d-%d (%f %f);\n", Layer(0), Layer(lay), // Durchkontaktierung ? + U2ExtU(LbrGrid2BrdCoord(CurBoneX, CurBoneY, DIM_X)), + U2ExtU(LbrGrid2BrdCoord(CurBoneX, CurBoneY, DIM_Y))); + } + } + if (Dbg) { sprintf(DbgMsg, "Escaped, wire\n"); DbgTxt += DbgMsg; DbgDump(); } + printf("WIRE '%s' %f (%f %f)", sig, outWireWidth, firstX, firstY); + SetGridRouteState(lay, tryI[0], tryJ[0], WIRE); // Is VIA getting overridden ? + for (int i = 1; i < nrTryPts; ++i) { + // Mark wire + int incI = Sgn(tryI[i] - tryI[i - 1]), incJ = Sgn(tryJ[i] - tryJ[i - 1]); + // Put this together if no performance reasons against it ! + if (abs(tryI[i] - tryI[i - 1]) > 1 || abs(tryJ[i] - tryJ[i - 1]) > 1) { + for (int k = tryI[i - 1] + incI, l = tryJ[i - 1] + incJ; + (tryI[i] - k) * incI >= 0 && (tryJ[i] - l) * incJ >= 0; k += incI, l += incJ) { + if (Dbg) { sprintf(DbgMsg, "k %d l %d ", k, l); DbgTxt += DbgMsg; DbgDump(); } + SetGridRouteState(lay, k, l, WIRE); + if (incI * incJ != 0) { + SetGridRouteState(lay, k - incI, l, NEAR_WIRE); + SetGridRouteState(lay, k , l - incJ, NEAR_WIRE); + } + } + } + else { + SetGridRouteState(lay, tryI[i], tryJ[i], WIRE); + if (incI * incJ != 0) { + SetGridRouteState(lay, tryI[i - 1] + incI, tryJ[i - 1], NEAR_WIRE); + SetGridRouteState(lay, tryI[i - 1], tryJ[i - 1] + incJ, NEAR_WIRE); + } + } + printf(" (%f %f)", U2ExtU(LbrGrid2BrdCoord(tryI[i], tryJ[i], DIM_X)), + U2ExtU(LbrGrid2BrdCoord(tryI[i], tryJ[i], DIM_Y))); + } + // The escape wire ! + if (Dbg) { sprintf(DbgMsg, "Escaped, wire outside\n"); DbgTxt += DbgMsg; DbgDump(); } + int lastI = tryI[nrTryPts - 1], lastJ = tryJ[nrTryPts - 1]; + printf(" (%f %f);\n", U2ExtU(LbrGrid2BrdCoord(lastI, lastJ, DIM_X) + EscapeVec(lastI, lastJ, DIM_X)), + U2ExtU(LbrGrid2BrdCoord(lastI, lastJ, DIM_Y) + EscapeVec(lastI, lastJ, DIM_Y))); + } + else if (nrTryPts >= 2) { + if (Dbg) { sprintf(DbgMsg, "Bone-Stuff start\n"); DbgTxt += DbgMsg; DbgDump(); } + int incI = tryI[1] - tryI[0], incJ = tryJ[1] - tryJ[0]; + printf("LAYER %d;\n", Layer(0)); + printf("WIRE '%s' %f (%f %f) (%f %f);\n", sig, outWireWidth, firstX, firstY, + U2ExtU(LbrGrid2BrdCoord(tryI[1], tryJ[1], DIM_X)), + U2ExtU(LbrGrid2BrdCoord(tryI[1], tryJ[1], DIM_Y))); + // Assume this is a single diagonal step ! + SetGridRouteState(lay, tryI[1], tryJ[1], WIRE); + if (incI * incJ != 0) { // Incs not necessary here ! + SetGridRouteState(lay, tryI[1], tryJ[0], NEAR_WIRE); + SetGridRouteState(lay, tryI[0], tryJ[1], NEAR_WIRE); + } + CurBoneX = tryI[1]; + CurBoneY = tryJ[1]; + CurTakeBone = true; + ConSigNames[cIdx] = sig; + if (Dbg) { sprintf(DbgMsg, "Bone-Stuff end\n"); DbgTxt += DbgMsg; DbgDump(); } + } + else + noRoute = true; + } + } + } + printf("SET WIRE_BEND 3;\n"); // Limit to k * 45 again. + } + } + DbgDump(); + if (Dbg) dlgMessageBox("Calculation done !"); + exit("SCRIPT '" + ScrFile + "';"); +} + +//============================================================================== +// Main +//============================================================================== +/* +*/ + +void main() { + string help[] = { + "

    BGA Escape Routing

    " + "Based on design rules an attempt is made to route all signals out of a BGA.
    " + "The package must follow a BGA design, meaning:
      " + "
    • It is an SMD.
    • " + "
    • All contacts have circular shape.
    • " + "
    • All contacts lie on a grid (same distance dx and dy).
    • " + "
    " + "This is checked before start. " + "All signals starting from the BGA should not be routed yet." + "

    " + "BGA analysis
    " + "Before start a feasibility analysis is made that helps you determine appropriate sizes " + "and strategy. It is based on design rule settings, in particular: " + "Minimum wire width, minimum via sizes, via restring settings, clearances between wires, " + "pads and vias. Please make sure your design rules are correct to get accurate results." + "

    " + "Wire and via sizes
    " + "Wire and via sizes can either be taken over from the net classes of the connected signals or " + "specific values may be set. In any case they are limited by the minimum values of the design rules." + "

    " + "Via strategy
    " + "There is the classical bone technique or stacked micro vias. " + "The bone technique requires space for one trace between 2 neighbour contacts." + "The BGA analysis checks this. For stacked micro vias the design rules's layer setup must fit." + "The micro via drill size is independent from net class values." + "

    " + "Coverage
    " + "By default only contacts with signals are routed. If you want all signals, check the " + "radio button in the coverage section." + "

    " + "Finally, the escape distance specifies how far the signals are routed out of the BGA (default 5mm)." + , + "

    BGA Escape Routing

    " + "Unter Berücksichtigung der Design-Regeln wird versucht, alle Signale aus einem BGA herauszuführen.
    " + "Das Package muss einem BGA-Design entsprechen. Das heisst:
      " + "
    • Es ist ein SMD.
    • " + "
    • Alle Anschlüsse sind kreisförmig.
    • " + "
    • Alle Anschlüsse liegen in einem gemeinsamen Raster (gleicher Wert für dx und dy).
    • " + "
    " + "Diese Kriterien werden vor dem Start geprüft. " + "Alle Signale, die am BGA beginnen, sollten noch nicht geroutet sein." + "

    " + "BGA-Analyse
    " + "Zuerst wird eine Machbarkeitsanalyse durchgeführt, die helfen soll, die passenden Größen " + "und die Strategie zu wählen. Diese basiert auf den Werten in den Design-Regeln, insbesondere: " + "Minimum Wire Width, Minimum Via Sizes, Via-Restring-Einstellungen, Mindestabstände zwischen Wires, " + "Pads und Vias. Bitte stellen Sie sicher, dass die Design-Regeln geeignet gewählt sind, um gute Ergebnisse zu erzielen." + "

    " + "Wire- und Via-Größen
    " + "Die Wire- und Via-Größen können entweder von den Netzklassen der angeschlossenen Signale übernommen " + "oder spezifische Werte gesetzt werden. In jedem Fall werden sie von den Minimum-Werten in den Design-Regeln begrenzt." + "

    " + "Via-Strategie
    " + "Es gibt die klassische Knochentechnik oder Stacked Micro-Vias. " + "Die Knochentechnik benötigt genügend Platz für eine Leitung zwischen zwei benachbarten Kontakten. " + "Die BGA-Aanalyse prüft dies. Für Stacked Micro-Vias muss das Layer-Setup in den Design-Regeln stimmen. " + "Der Bohrdurchmesser der Micro-Vias ist ein eigener Wert und hat nichts mit den Netzklassen-Werten zu tun. " + "

    " + "Abdeckung
    " + "Standardmäßig werden nur Kontakte mit Signalen bearbeitet. Wenn alle Kontakte geroutet werden sollen, " + "wählen Sie diese Option unter Abdeckung." + "

    " + "Die Escape-Distanz schliesslich definiert, wie weit die Signale aus dem BGA herausgeführt werden (Default 5mm)." + }; + if (Dbg) DbgFile = filesetext(argv[0], "-dbg.txt"); + DbgInit(); + if (board) { + int i, dummySel, dummySort; + // Prepare step: Export DRUs if necessary + for (i = 1; i <= argc; ++i) + if (argv[i] == "-drus_done") ExpDRUs = false; + board(B) DruFile = filesetext(B.name, ".dru"); + if (ExpDRUs) { + string cmds = "DRC SAVE '" + DruFile + "';\nRUN '" + argv[0] + "' -drus_done"; + for (int i = 1; i <= argc; ++i) + cmds += " " + argv[i]; + exit(cmds + ";"); + } + GetDesignParams(); + // Parse arguments. Design params may get overwritten. + // Note: Only element name is officially supported ! + // Currently other params just for internal use in batch mode. + for (i = 1; i < argc; ++i) { + if (argv[i] == "-drus_done") ExpDRUs = false; + else if (argv[i] == "-nodlg") { Dialog = false; Dbg = false; } + else if (argv[i] == "-stacked") ElemViaStrat = STACKED_VIAS; + else if (argv[i] == "-classes") UseNetClasses = true; + else if (argv[i] == "-all") ElemRouteAll = true; + else if (strstr(argv[i], "-width=") == 0) + WireWidth = Str2U(strsub(argv[i], strlen("-width="))); + else if (strstr(argv[i], "-esc=") == 0) + EscapeDist = Str2U(strsub(argv[i], strlen("-esc="))); + else if (strstr(argv[i], "-drill=") == 0) + ViaDrill = MicroViaDrill = Str2U(strsub(argv[i], strlen("-drill="))); + else ElemNames[NrElems++] = strupr(argv[i]); // Ignore case ! + } + if (ElemNames[0] == "" || NrElems > 1) { // We may allow multiple BGAs in the future. + dlgMessageBox(usage); + exit(-1); + } + board(B) { + ScrFile = filesetext(B.name, "-bga.scr"); + ExtUnit = B.grid.unit; + } + ExtUnitName = (ExtUnit == GRID_UNIT_MM) ? "mm" : + (ExtUnit == GRID_UNIT_INCH) ? "in" : + (ExtUnit == GRID_UNIT_MIC) ? "mic" : "mil"; + SetupElement(ElemNames[0]); + + if (Dialog) int ret = dlgDialog("BGA Escape Routing") { + real dlgWireWidth = U2ExtU(WireWidth); + real dlgEscapeDist = U2ExtU(EscapeDist); + real dlgViaDrill = U2ExtU(ViaDrill); + real dlgMicroViaDrill = U2ExtU(MicroViaDrill); + real dlgMinViaDrill = 0.999 * U2ExtU(MinViaDrill); + real dlgMinMicroViaDrill = 0.999 * U2ExtU(min(MinMicroViaDrill, MinViaDrill)); + if (Dbg) dlgCheckBox("&Debug", Dbg); + dlgGroup(tr("BGA analysis for ") + ElemName +":") { + string analysis = "

      " + "
    • " + tr("Number of contacts: ") + I2Str(NrCons) + " (" + I2Str(NrConsWithSig) + " " + tr("with signals") + ")." + "
    • " + "
    • " + tr("Contact diameter: ") + U2ExtUStr(ConDiam) + "." + "
    • " + "
    • " + tr("Contact distance: ") + U2ExtUStr(ConDist) + "." + "
    • " + "
    • " + tr("Maximum wire width for one wire between contacts: ") + U2ExtUStr(MaxWireWidth1) + "."; + if (MaxWireWidth1 < MinWireWidth) + analysis += "
      " + tr("Not enough space for wires between contacts. ") + tr("Stacked micro vias recommended !"); + analysis += "
    • "; + analysis += "
    • " + tr("Maximum via drill for bone technique: ") + U2ExtUStr(MaxViaDrill) + "."; + if (MaxViaDrill < MinViaDrill) + analysis += "
      " + tr("Not enough space for vias between contacts. ") + tr("Stacked micro vias recommended !"); + analysis += "
    • "; + analysis += "
    "; + dlgLabel(analysis); + } + dlgHBoxLayout { + // Gruppe Wire width: Radiobutton mit RealEdit daneben... + dlgGroup(tr("Wire and via sizes:")) { + dlgHBoxLayout { + dlgRadioButton(tr("Use specific sizes:"), UseNetClasses); + dlgLabel(tr("Wire width:")); + // Upper limit ConDist: Just to have a rough limit. Exact maximum would depend + // on strategy and DRU settings. + dlgRealEdit(dlgWireWidth, U2ExtU(MinWireWidth), U2ExtU(ConDist)); + dlgLabel(ExtUnitName); + dlgLabel(tr("Via drill size:")); + dlgRealEdit(dlgViaDrill, dlgMinViaDrill, U2ExtU(ConDist + ConDiam)); // Upper limit: Just to have a rough limit. See above. + dlgLabel(ExtUnitName); + } + dlgRadioButton(tr("Use net classes"), UseNetClasses); + } + } + dlgGroup(tr("Via strategy")) { + dlgRadioButton(tr("Make bones"), ElemViaStrat); + dlgHBoxLayout { + dlgRadioButton(tr("Stacked micro vias:"), ElemViaStrat); + dlgLabel(tr("Micro via drill size:")); + dlgRealEdit(dlgMicroViaDrill, dlgMinMicroViaDrill, U2ExtU(ConDiam)); // Upper limit: Rough value + dlgLabel(ExtUnitName); + dlgStretch(2); + } + } + dlgGroup(tr("Coverage")) { + dlgRadioButton(tr("Contacts with signals"), ElemRouteAll); + dlgRadioButton(tr("All contacts"), ElemRouteAll); + } + dlgHBoxLayout { + dlgLabel(tr("Escape distance: ")); + dlgRealEdit(dlgEscapeDist, 0, 1000); + dlgLabel(ExtUnitName); + dlgStretch(3); + } + dlgHBoxLayout { + dlgPushButton(tr("Help") + "...") + dlgMessageBox(DlgLang == "de" ? help[1] : help[0]); // Adjust after translation ! + dlgPushButton(tr("Start")) { + EscapeDist = ExtU2U(dlgEscapeDist); + MicroViaDrill = ExtU2U(dlgMicroViaDrill); + if (!UseNetClasses) { + WireWidth = ExtU2U(dlgWireWidth); + ViaDrill = ExtU2U(dlgViaDrill); + } + Execute(); + } + dlgPushButton(tr("Cancel")) dlgReject(); + } + }; // <-- This must be here ! (Ulp-Bug ?) + else + Execute(); + } + else + dlgMessageBox(tr("Please start from Layout editor !")); +} diff --git a/trunk/ulp/run-loop-all-devicesets-script.ulp b/trunk/ulp/run-loop-all-devicesets-script.ulp new file mode 100644 index 00000000..cb76f500 --- /dev/null +++ b/trunk/ulp/run-loop-all-devicesets-script.ulp @@ -0,0 +1,21 @@ +#usage "Run a SCRIPT through all devicesets in a library

    \n" + "RUN run-loop-all-devicesets-script [SCRIPT]
    " + "Author: librarian@cadsoft.de

    " + +string Version = "1.0"; // 2008-08-28 +string ScriptFile = argv[1]; +string cmd, s; + +if (library) { + library(L) { + if (!ScriptFile) ScriptFile = dlgFileOpen("Select a SCRIPT to run in all DEVICESETS", path_scr[0], "*.scr"); + if (!ScriptFile) exit(0); + L.devicesets(DS) { + sprintf(s, "EDIT %s.DEV;\nSCRIPT '%s';\n", DS.name, ScriptFile); + cmd += s; + } + } + exit (cmd); +} + +else dlgMessageBox("Start this ULP from a Library", "OK"); diff --git a/trunk/ulp/run-loop-all-lbr-script.ulp b/trunk/ulp/run-loop-all-lbr-script.ulp new file mode 100644 index 00000000..c9a2b2e2 --- /dev/null +++ b/trunk/ulp/run-loop-all-lbr-script.ulp @@ -0,0 +1,27 @@ +#usage "run a SCRIPT through all libraries in a directory

    \n" + "Load any library from the library directory and execute the SCRIPT.

    " + "Author: librarian@cadsoft.de

    " + +string a[], cmd; + + +//-------- main program -------------------------------------------------- + +if (library) { + library(L) { + string lbr_path = filedir(L.name); + string ScriptFile = dlgFileOpen("Select a SCRIPT to start in all LBRs", "", "*.scr"); + if (!ScriptFile) exit(0); // 2006.02.20 librarian@cadsoft.de + int n = fileglob(a, lbr_path + "*.lbr"); + if (n) { + for (int xl = 0; xl < n; xl++) { + string h; + sprintf(h, "OPEN '" + lbr_path + filename(a[xl]) + "';\nSCRIPT '" + ScriptFile + "';\n"); + cmd += h; + } + } + } + exit (cmd); + } + +else dlgMessageBox("Start this ULP from a Library", "OK"); diff --git a/trunk/ulp/run-loop-all-lbr-ulp.ulp b/trunk/ulp/run-loop-all-lbr-ulp.ulp new file mode 100644 index 00000000..15309fe6 --- /dev/null +++ b/trunk/ulp/run-loop-all-lbr-ulp.ulp @@ -0,0 +1,30 @@ +#usage "run a ULP through all libraries in a directory

    \n" + "This is an example how to loop through all libraries in a directory " + "and counts the devices.

    " + "Load any library from the library directory and execute the ULP.

    " + "Author: support@cadsoft.de

    " + +string a[], cmd; + + +//-------- main program -------------------------------------------------- + + +if (library) { + library(L) { + string lbr_path = filedir(L.name); + string ulpFile = dlgFileOpen("Select a ULP to run in LBRs", "", "*.ulp"); + if (!ulpFile) exit(0); // 2006.02.20 librarian@cadsoft.de + int n = fileglob(a, lbr_path + "*.lbr"); + if (n) { + for (int xl = 0; xl < n; xl++) { + string h; + sprintf(h, "OPEN '" + lbr_path + filename(a[xl]) + "';\nRUN '" + ulpFile + "';\n"); + cmd += h; + } + } + } + exit (cmd); + } + +else dlgMessageBox("Start this ULP from a Library", "OK"); diff --git a/trunk/ulp/run-loop-all-packages-script.ulp b/trunk/ulp/run-loop-all-packages-script.ulp new file mode 100644 index 00000000..8f3ee152 --- /dev/null +++ b/trunk/ulp/run-loop-all-packages-script.ulp @@ -0,0 +1,21 @@ +#usage "Run a SCRIPT through all symbols in a library

    \n" + "RUN run-loop-all-packages-script [SCRIPT]
    " + "Author: librarian@cadsoft.de

    " + +string Version = "1.0"; // 2008-08-28 +string ScriptFile = argv[1]; +string cmd, s; + +if (library) { + library(L) { + if (!ScriptFile) ScriptFile = dlgFileOpen("Select a SCRIPT to run in all PACKAGES", path_scr[0], "*.scr"); + if (!ScriptFile) exit(0); + L.packages(P) { + sprintf(s, "EDIT %s.PAC;\nSCRIPT '%s';\n", P.name, ScriptFile); + cmd += s; + } + } + exit (cmd); +} + +else dlgMessageBox("Start this ULP from a Library", "OK"); diff --git a/trunk/ulp/run-loop-all-schematic-script.ulp b/trunk/ulp/run-loop-all-schematic-script.ulp new file mode 100644 index 00000000..f85751be --- /dev/null +++ b/trunk/ulp/run-loop-all-schematic-script.ulp @@ -0,0 +1,25 @@ +#usage "run a SCRIPT through all schematics in a directory

    \n" + "Load any schematic from the project directory and execute the SCRIPT.

    " + "Author: alf@cadsoft.de

    " + +string a[], cmd; + +//-------- main program -------------------------------------------------- +if (schematic) { + schematic(S) { + string sch_path = filedir(S.name); + string ScriptFile = dlgFileOpen("Select a SCRIPT to start in all Schematics", "", "*.scr"); + if (!ScriptFile) exit(0); + int n = fileglob(a, sch_path + "*.sch"); + if (n) { + for (int xl = 0; xl < n; xl++) { + string h; + sprintf(h, "EDIT '" + sch_path + filename(a[xl]) + "';\nSCRIPT '" + ScriptFile + "';\n"); + cmd += h; + } + } + } + exit (cmd); +} + +else dlgMessageBox("Start this ULP from a Schematic", "OK"); diff --git a/trunk/ulp/run-loop-all-symbols-script.ulp b/trunk/ulp/run-loop-all-symbols-script.ulp new file mode 100644 index 00000000..ceaebdb8 --- /dev/null +++ b/trunk/ulp/run-loop-all-symbols-script.ulp @@ -0,0 +1,21 @@ +#usage "Run a SCRIPT through all symbols in a library

    \n" + "RUN run-loop-all-symbols-script [SCRIPT]
    " + "Author: librarian@cadsoft.de

    " + +string Version = "1.0"; // 2008-08-28 +string ScriptFile = argv[1]; +string cmd, s; + +if (library) { + library(L) { + if (!ScriptFile) ScriptFile = dlgFileOpen("Select a SCRIPT to run in all SYMBOLS", path_scr[0], "*.scr"); + if (!ScriptFile) exit(0); + L.symbols(S) { + sprintf(s, "EDIT %s.SYM;\nSCRIPT '%s';\n", S.name, ScriptFile); + cmd += s; + } + } + exit (cmd); +} + +else dlgMessageBox("Start this ULP from a Library", "OK"); diff --git a/trunk/ulp/safe_options/pcb-defaults.h b/trunk/ulp/safe_options/pcb-defaults.h new file mode 100644 index 00000000..f532f869 --- /dev/null +++ b/trunk/ulp/safe_options/pcb-defaults.h @@ -0,0 +1,38 @@ +// +// Default values for generating gcode from a PCB. +// +// These settings were last changed with pcb-gcode-setup: 2/8/09 5:28 PM +// +// +// Changes you make in this file will be overwritten if you use pcb-gcode-setup. +// + +real ISO_MIN = 0.001000; +real ISO_MAX = 0.020000; +real ISO_STEP = 0.005000; + +int GENERATE_TOP_OUTLINES = NO; +int GENERATE_TOP_DRILL = NO; +int GENERATE_TOP_FILL = NO; + +int GENERATE_BOTTOM_OUTLINES = YES; +int GENERATE_BOTTOM_DRILL = YES; +int GENERATE_BOTTOM_FILL = NO; +int MIRROR_BOTTOM = NO; +int SIMPLE_DRILL_CODE = YES; + +int GENERATE_MILLING = NO; + +int GENERATE_TEXT = NO; + +int SPOT_DRILL = YES; +real SPOT_DRILL_DEPTH = -0.011000; + +int DO_TOOL_CHANGE_WITH_ZERO_STEP = NO; + +int FLIP_BOARD_IN_Y = NO; + +//int OUTPUT_UNITS = U_MICRONS; +//int OUTPUT_UNITS = U_MILLIMETERS; +//int OUTPUT_UNITS = U_MILS; +int OUTPUT_UNITS = U_INCHES; diff --git a/trunk/ulp/safe_options/pcb-defaults.release.h b/trunk/ulp/safe_options/pcb-defaults.release.h new file mode 100644 index 00000000..80fcc9e1 --- /dev/null +++ b/trunk/ulp/safe_options/pcb-defaults.release.h @@ -0,0 +1,39 @@ +// +// Default values for generating gcode from a PCB. +// +// These settings were last changed with pcb-gcode-setup: 12/28/12 11:21 PM +// +// +// Changes you make in this file will be overwritten if you use pcb-gcode-setup. +// + +int SINGLE_PASS = NO; +real ISO_MIN = 0.001000; +real ISO_MAX = 0.020000; +real ISO_STEP = 0.005000; + +int GENERATE_TOP_OUTLINES = NO; +int GENERATE_TOP_DRILL = NO; +int GENERATE_TOP_FILL = NO; + +int GENERATE_BOTTOM_OUTLINES = YES; +int GENERATE_BOTTOM_DRILL = YES; +int GENERATE_BOTTOM_FILL = NO; +int MIRROR_BOTTOM = NO; +int SIMPLE_DRILL_CODE = NO; + +int GENERATE_MILLING = NO; + +int GENERATE_TEXT = NO; + +int SPOT_DRILL = YES; +real SPOT_DRILL_DEPTH = -0.011000; + +int DO_TOOL_CHANGE_WITH_ZERO_STEP = YES; + +int FLIP_BOARD_IN_Y = NO; + +//int OUTPUT_UNITS = U_MICRONS; +//int OUTPUT_UNITS = U_MILLIMETERS; +//int OUTPUT_UNITS = U_MILS; +int OUTPUT_UNITS = U_INCHES; diff --git a/trunk/ulp/safe_options/pcb-gcode-options.h b/trunk/ulp/safe_options/pcb-gcode-options.h new file mode 100644 index 00000000..e07e6cb5 --- /dev/null +++ b/trunk/ulp/safe_options/pcb-gcode-options.h @@ -0,0 +1,34 @@ +// +// General Options // Your edits to this file will be overwritten by the setup program. +// +int SHOW_PROGRESS = NO; +string RESTORE_MENU_FILE = "pcb-gcode-menu.scr"; +int NC_FILE_COMMENT_FROM_BOARD = YES; +int NC_FILE_COMMENT_DATE = YES; +int NC_FILE_COMMENT_MACHINE_SETTINGS = NO; +int NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS = NO; +int USER_GCODE = NO; +int g_debug_flag = NO; +int COMPACT_GCODE = NO; +int USE_LINE_NUMBERS = NO; +string LINE_NUMBER_FORMAT = "N%05d "; +int SHOW_PREVIEW = YES; +string FILENAME_BASE = "$BOARD_PATH/$BOARD_NAME"; +string FILENAME_TOP_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_FILL_FILE = ""; +string FILENAME_BOT_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_FILL_FILE = ""; +string ETCH_FILE_NAME = "etch"; +string DRILL_FILE_NAME = "drill"; +string MILL_FILE_NAME = "mill"; +string TEXT_FILE_NAME = "text"; +string TOP_FILE_NAME = "top"; +string BOT_FILE_NAME = "bot"; +string DEFAULT_EXTENSION = "tap"; +string DEFAULT_DRILL_FILE = ""; diff --git a/trunk/ulp/safe_options/pcb-gcode-options.release.h b/trunk/ulp/safe_options/pcb-gcode-options.release.h new file mode 100644 index 00000000..a173fe4c --- /dev/null +++ b/trunk/ulp/safe_options/pcb-gcode-options.release.h @@ -0,0 +1,34 @@ +// +// General Options // Your edits to this file will be overwritten by the setup program. +// +int SHOW_PROGRESS = NO; +string RESTORE_MENU_FILE = "pcb-gcode-menu.scr"; +int NC_FILE_COMMENT_FROM_BOARD = YES; +int NC_FILE_COMMENT_DATE = YES; +int NC_FILE_COMMENT_MACHINE_SETTINGS = YES; +int NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS = YES; +int USER_GCODE = NO; +int g_debug_flag = YES; +int COMPACT_GCODE = NO; +int USE_LINE_NUMBERS = NO; +string LINE_NUMBER_FORMAT = "N%05d "; +int SHOW_PREVIEW = YES; +string FILENAME_BASE = "$BOARD_PATH/$BOARD_NAME"; +string FILENAME_TOP_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_FILL_FILE = ""; +string FILENAME_BOT_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_FILL_FILE = ""; +string ETCH_FILE_NAME = "etch"; +string DRILL_FILE_NAME = "drill"; +string MILL_FILE_NAME = "mill"; +string TEXT_FILE_NAME = "text"; +string TOP_FILE_NAME = "top"; +string BOT_FILE_NAME = "bot"; +string DEFAULT_EXTENSION = "tap"; +string DEFAULT_DRILL_FILE = ""; diff --git a/trunk/ulp/safe_options/pcb-machine.h b/trunk/ulp/safe_options/pcb-machine.h new file mode 100644 index 00000000..e8b8e040 --- /dev/null +++ b/trunk/ulp/safe_options/pcb-machine.h @@ -0,0 +1,24 @@ +// +// For ease of use, and to avoid overwritting your settings, +// use pcb-gcode-setup to make changes to these settings. +// + +real DEFAULT_Z_HIGH = 0.500000; +real DEFAULT_Z_UP = 0.100000; +real DEFAULT_Z_DOWN = -0.007000; +real DRILL_DEPTH = -0.032000; +real DRILL_DWELL = 1.000000; +real SPINDLE_ON_TIME = 3.000000; +real MILLING_DEPTH = -0.010000; +real TEXT_DEPTH = -0.005000; +real TOOL_CHANGE_POS_X = 0.000000; +real TOOL_CHANGE_POS_Y = 0.000000; +real TOOL_CHANGE_POS_Z = 0.000000; +real FEED_RATE = 20.000000; +real FEED_RATE_Z = 10.000000; +real DEFAULT_WIDTH = 0.007000; +real X_OFFSET = 0.000000; +real Y_OFFSET = 0.000000; +real X_HOME = 0.000000; +real Y_HOME = 0.000000; +real EPSILON = 0.000100; diff --git a/trunk/ulp/safe_options/pcb-machine.release.h b/trunk/ulp/safe_options/pcb-machine.release.h new file mode 100644 index 00000000..309340e2 --- /dev/null +++ b/trunk/ulp/safe_options/pcb-machine.release.h @@ -0,0 +1,24 @@ +// +// For ease of use, and to avoid overwritting your settings, +// use pcb-gcode-setup to make changes to these settings. +// + +real DEFAULT_Z_HIGH = 0.500000; +real DEFAULT_Z_UP = 0.100000; +real DEFAULT_Z_DOWN = -0.007000; +real DRILL_DEPTH = -0.032000; +real DRILL_DWELL = 1.000000; +real SPINDLE_ON_TIME = 3.000000; +real MILLING_DEPTH = -0.010000; +real TEXT_DEPTH = -0.005000; +real TOOL_CHANGE_POS_X = 0.500000; +real TOOL_CHANGE_POS_Y = 0.600000; +real TOOL_CHANGE_POS_Z = 1.000000; +real FEED_RATE = 20.000000; +real FEED_RATE_Z = 10.000000; +real DEFAULT_WIDTH = 0.007000; +real X_OFFSET = 0.000000; +real Y_OFFSET = 0.000000; +real X_HOME = 0.000000; +real Y_HOME = 0.000000; +real EPSILON = 0.000100; diff --git a/trunk/ulp/safe_options/user-gcode.h b/trunk/ulp/safe_options/user-gcode.h new file mode 100644 index 00000000..564cfe5c --- /dev/null +++ b/trunk/ulp/safe_options/user-gcode.h @@ -0,0 +1,236 @@ +// +// Define your own gcode sequences in this file. +// +// The settings are listed from most general, to most specific. The settings +// at the top of this file go into every file created, while the settings +// at the end of this file have to do with tool changes only. +// +// Note that each line ends with \n this is Geek Speak for newline. +// In other words, it's like hitting the Enter key at the end of a line. +// Notice also that the lines have a ; at the end. +// +// See the bottom of this file for an example of using multiple lines. +// + +// Inserted into bottom, top or all files. +string FILE_BEGIN[] = { "", "", "", "" }; +string FILE_END[] = { "", "", "", "" }; + +FILE_BEGIN[ALL] = "(Beginning of every file)\n"; +FILE_END[ALL] = "(End of every file)\n"; + +FILE_BEGIN[BOTTOM] = "(Beginning of every bottom file)\n"; +FILE_END[BOTTOM] = "(End of every bottom file)\n"; + +FILE_BEGIN[TOP] = "(Beginning of every top file)\n"; +FILE_END[TOP] = "(End of every top file)\n"; + +// Inserted into outline files (track milling). +string OUTLINE_BEGIN[] = { "", "", "", "" }; +string OUTLINE_BETWEEN[] = { "", "", "", "" }; +string OUTLINE_END[] = { "", "", "", "" }; + +OUTLINE_BEGIN[ALL] = "(Outline Begin)\n"; +OUTLINE_BETWEEN[ALL] = "(Between Passes)\n"; +OUTLINE_END[ALL] = "(Outline End)\n"; + +OUTLINE_BEGIN[BOTTOM] = "(Bottom outline Begin)\n"; +OUTLINE_BETWEEN[BOTTOM] = "(Bottom between passes)\n"; +OUTLINE_END[BOTTOM] = "(Bottom outline End)\n"; + +OUTLINE_BEGIN[TOP] = "(Top outline Begin)\n"; +OUTLINE_BETWEEN[TOP] = "(Top between passes)\n"; +OUTLINE_END[TOP] = "(Top outline End)\n"; + +// Inserted into drill files. +string DRILL_BEGIN[] = { "", "", "", "" }; +string DRILL_END[] = { "", "", "", "" }; + +DRILL_BEGIN[ALL] = "(Beginning of All Drill files)\n"; +DRILL_END[ALL] = "(End of all Drill Files)\n"; + +DRILL_BEGIN[BOTTOM] = "(Bottom Drill Begin)\n"; +DRILL_END[BOTTOM] = "(Bottom Drill End)\n"; + +DRILL_BEGIN[TOP] = "(Top Drill Begin)\n"; +DRILL_END[TOP] = "(Top Drill End)\n"; + +// Inserted into fill files. +string FILL_BEGIN[] = { "", "", "", "" }; +string FILL_END[] = { "", "", "", "" }; + +FILL_BEGIN[ALL] = "(Fill Begin)\n"; +FILL_END[ALL] = "(Fill End)\n"; + +FILL_BEGIN[BOTTOM] = "(Bottom Fill Begin)\n"; +FILL_END[BOTTOM] = "(Bottom Fill End)\n"; + +FILL_BEGIN[TOP] = "(Top Fill Begin)\n"; +FILL_END[TOP] = "(Top Fill End)\n"; + +// Inserted into milling files. +string MILL_BEGIN[] = { "", "", "", "" }; +string MILL_END[] = { "", "", "", "" }; + +MILL_BEGIN[ALL] = "(MILL Begin)\n"; +MILL_END[ALL] = "(MILL End)\n"; + +MILL_BEGIN[BOTTOM] = "(Bottom MILL Begin)\n"; +MILL_END[BOTTOM] = "(Bottom MILL End)\n"; + +MILL_BEGIN[TOP] = "(Top MILL Begin)\n"; +MILL_END[TOP] = "(Top MILL End)\n"; + +// Tool change code. +string TOOL_CHANGE_BEGIN[] = { "", "", "", "" }; +string TOOL_CHANGED[] = { "", "", "", "" }; +string TOOL_ZERO_BEGIN[] = { "", "", "", "" }; +string TOOL_ZERO_END[] = { "", "", "", "" }; +string TOOL_CHANGE_END[] = { "", "", "", "" }; + +TOOL_CHANGE_BEGIN[ALL] = "(Tool Change Begin)\n"; +TOOL_CHANGED[ALL] = "(Tool changed)\n"; +TOOL_ZERO_BEGIN[ALL] = "(Tool zero begin)\n"; +TOOL_ZERO_END[ALL] = "(Tool zero end)\n"; +TOOL_CHANGE_END[ALL] = "(Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[BOTTOM] = "(Bottom Tool Change Begin)\n"; +TOOL_CHANGED[BOTTOM] = "(Bottom Tool changed)\n"; +TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n"; +TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n"; +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n"; +TOOL_CHANGED[TOP] = "(Top Tool changed)\n"; +TOOL_ZERO_BEGIN[TOP] = "(Top Tool zero begin)\n"; +TOOL_ZERO_END[TOP] = "(Top Tool zero end)\n"; +TOOL_CHANGE_END[TOP] = "(Top Tool Changed End)\n"; + +// +// An example of using more than one line of gcode. +// Note that only the last line has a ; at the end. +// +string THIS_ISNT_USED[] = { "", "", "", "" }; // Don't change lines like this +THIS_ISNT_USED[BOTTOM] = "G20\n" + "G90\n" + "G01 Z0\n" + "G00 X0 Y0\n" + "M06 T2 ; 0.060\n" + "G04 P5\n"; + +/* + * The functions below should make it easier for folks outputing their own code, etc. + * + */ + +/* + * Called after the gcode file has been opened. + * Mode can be + * "wt" (write a text file) when the file is first opened. + * "at" (append a text file) if the file is added to. + * + * You might want to check g_side to see which "side" you are working on. + * g_side can be TOP, BOTTOM or MILL. + * + */ +void user_file_opened(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just before the gcode file is closed. + * + */ +void user_file_closing() +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just after the gcode file is closed. + * See user_file_opened for information on the mode parameter. + * + */ +void user_file_closed(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of the outline of a track. + * + */ +void user_track_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * An intermediate point on the outline of a track. + * + */ +int user_coord_cnt; +void user_track_continue(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of the outline of a track. + * + */ +void user_track_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of an arc. + * + */ +void user_arc_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of an arc. + * + */ +void user_arc_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} diff --git a/trunk/ulp/safe_options/user-gcode.release.h b/trunk/ulp/safe_options/user-gcode.release.h new file mode 100644 index 00000000..564cfe5c --- /dev/null +++ b/trunk/ulp/safe_options/user-gcode.release.h @@ -0,0 +1,236 @@ +// +// Define your own gcode sequences in this file. +// +// The settings are listed from most general, to most specific. The settings +// at the top of this file go into every file created, while the settings +// at the end of this file have to do with tool changes only. +// +// Note that each line ends with \n this is Geek Speak for newline. +// In other words, it's like hitting the Enter key at the end of a line. +// Notice also that the lines have a ; at the end. +// +// See the bottom of this file for an example of using multiple lines. +// + +// Inserted into bottom, top or all files. +string FILE_BEGIN[] = { "", "", "", "" }; +string FILE_END[] = { "", "", "", "" }; + +FILE_BEGIN[ALL] = "(Beginning of every file)\n"; +FILE_END[ALL] = "(End of every file)\n"; + +FILE_BEGIN[BOTTOM] = "(Beginning of every bottom file)\n"; +FILE_END[BOTTOM] = "(End of every bottom file)\n"; + +FILE_BEGIN[TOP] = "(Beginning of every top file)\n"; +FILE_END[TOP] = "(End of every top file)\n"; + +// Inserted into outline files (track milling). +string OUTLINE_BEGIN[] = { "", "", "", "" }; +string OUTLINE_BETWEEN[] = { "", "", "", "" }; +string OUTLINE_END[] = { "", "", "", "" }; + +OUTLINE_BEGIN[ALL] = "(Outline Begin)\n"; +OUTLINE_BETWEEN[ALL] = "(Between Passes)\n"; +OUTLINE_END[ALL] = "(Outline End)\n"; + +OUTLINE_BEGIN[BOTTOM] = "(Bottom outline Begin)\n"; +OUTLINE_BETWEEN[BOTTOM] = "(Bottom between passes)\n"; +OUTLINE_END[BOTTOM] = "(Bottom outline End)\n"; + +OUTLINE_BEGIN[TOP] = "(Top outline Begin)\n"; +OUTLINE_BETWEEN[TOP] = "(Top between passes)\n"; +OUTLINE_END[TOP] = "(Top outline End)\n"; + +// Inserted into drill files. +string DRILL_BEGIN[] = { "", "", "", "" }; +string DRILL_END[] = { "", "", "", "" }; + +DRILL_BEGIN[ALL] = "(Beginning of All Drill files)\n"; +DRILL_END[ALL] = "(End of all Drill Files)\n"; + +DRILL_BEGIN[BOTTOM] = "(Bottom Drill Begin)\n"; +DRILL_END[BOTTOM] = "(Bottom Drill End)\n"; + +DRILL_BEGIN[TOP] = "(Top Drill Begin)\n"; +DRILL_END[TOP] = "(Top Drill End)\n"; + +// Inserted into fill files. +string FILL_BEGIN[] = { "", "", "", "" }; +string FILL_END[] = { "", "", "", "" }; + +FILL_BEGIN[ALL] = "(Fill Begin)\n"; +FILL_END[ALL] = "(Fill End)\n"; + +FILL_BEGIN[BOTTOM] = "(Bottom Fill Begin)\n"; +FILL_END[BOTTOM] = "(Bottom Fill End)\n"; + +FILL_BEGIN[TOP] = "(Top Fill Begin)\n"; +FILL_END[TOP] = "(Top Fill End)\n"; + +// Inserted into milling files. +string MILL_BEGIN[] = { "", "", "", "" }; +string MILL_END[] = { "", "", "", "" }; + +MILL_BEGIN[ALL] = "(MILL Begin)\n"; +MILL_END[ALL] = "(MILL End)\n"; + +MILL_BEGIN[BOTTOM] = "(Bottom MILL Begin)\n"; +MILL_END[BOTTOM] = "(Bottom MILL End)\n"; + +MILL_BEGIN[TOP] = "(Top MILL Begin)\n"; +MILL_END[TOP] = "(Top MILL End)\n"; + +// Tool change code. +string TOOL_CHANGE_BEGIN[] = { "", "", "", "" }; +string TOOL_CHANGED[] = { "", "", "", "" }; +string TOOL_ZERO_BEGIN[] = { "", "", "", "" }; +string TOOL_ZERO_END[] = { "", "", "", "" }; +string TOOL_CHANGE_END[] = { "", "", "", "" }; + +TOOL_CHANGE_BEGIN[ALL] = "(Tool Change Begin)\n"; +TOOL_CHANGED[ALL] = "(Tool changed)\n"; +TOOL_ZERO_BEGIN[ALL] = "(Tool zero begin)\n"; +TOOL_ZERO_END[ALL] = "(Tool zero end)\n"; +TOOL_CHANGE_END[ALL] = "(Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[BOTTOM] = "(Bottom Tool Change Begin)\n"; +TOOL_CHANGED[BOTTOM] = "(Bottom Tool changed)\n"; +TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n"; +TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n"; +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n"; +TOOL_CHANGED[TOP] = "(Top Tool changed)\n"; +TOOL_ZERO_BEGIN[TOP] = "(Top Tool zero begin)\n"; +TOOL_ZERO_END[TOP] = "(Top Tool zero end)\n"; +TOOL_CHANGE_END[TOP] = "(Top Tool Changed End)\n"; + +// +// An example of using more than one line of gcode. +// Note that only the last line has a ; at the end. +// +string THIS_ISNT_USED[] = { "", "", "", "" }; // Don't change lines like this +THIS_ISNT_USED[BOTTOM] = "G20\n" + "G90\n" + "G01 Z0\n" + "G00 X0 Y0\n" + "M06 T2 ; 0.060\n" + "G04 P5\n"; + +/* + * The functions below should make it easier for folks outputing their own code, etc. + * + */ + +/* + * Called after the gcode file has been opened. + * Mode can be + * "wt" (write a text file) when the file is first opened. + * "at" (append a text file) if the file is added to. + * + * You might want to check g_side to see which "side" you are working on. + * g_side can be TOP, BOTTOM or MILL. + * + */ +void user_file_opened(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just before the gcode file is closed. + * + */ +void user_file_closing() +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just after the gcode file is closed. + * See user_file_opened for information on the mode parameter. + * + */ +void user_file_closed(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of the outline of a track. + * + */ +void user_track_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * An intermediate point on the outline of a track. + * + */ +int user_coord_cnt; +void user_track_continue(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of the outline of a track. + * + */ +void user_track_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of an arc. + * + */ +void user_arc_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of an arc. + * + */ +void user_arc_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} diff --git a/trunk/ulp/save-variants4cam.ulp b/trunk/ulp/save-variants4cam.ulp new file mode 100644 index 00000000..38118e47 --- /dev/null +++ b/trunk/ulp/save-variants4cam.ulp @@ -0,0 +1,304 @@ +#usage "Save Variants with extended name bei variant-name

    " + "RUN save-variants4cam.ulp
    " + "Für die automatisierte CAM-Datenausgabe mit einem BATCH-File
    " + "1. Es wird ein SCRIPT (string) erzeugt, daß auf die Varianten umstellt, " + "und das Board mit Namenserweiterung durch die Variantenbezeichnung speichert.
    " + "2. Eine BATCH-Datei (Shell-Script) wird erzeugt, die mit der System()-Funktion " + "gestartet wird, die wiederum den CAM-Prozessor mit entsprechenden Optionen startet und aus " + "dem gespeicherten Bard die CAM-Daten erzeugt." + "

    " + "Unter Linux muß die KDE-Oberfläche (KUBUNTU) verwendet werden, da mit GNOME der CAM-Prozessoraufruf " + "das Board/Control-Panel-Fenster nicht automatisch mit QUIT; schliessen kann." + "

    " + "author alf@cadsoft.de" + + +#require 6.0500; +string Version = "1.0.0"; // 2014-02-06 alf@cadsoft.de + +int Test = 0; // Testflag zum debuggen + +string CurrentVariant = ""; +string Variants[] = { "" }; +int cntVD = 0; +int VDsel = 0; +int UsedLayer[]; + +int IsConsistent = 0; + +string Fname; +string BatchFile; +string BatchFileExt = ".bat"; // die Extension darf für Linux bleiben +string EagleDir = EAGLE_DIR; +string EaglePath = EAGLE_HOME; +string EagleConExe = EAGLE_PATH; // "E:/EG/eg 6/bin/eaglecon.exe/"; + +int OS_Windows = 0; + +if (strstr(OS_SIGNATURE, "Windows") == 0 ) { // Windows Option + EagleConExe = filesetext(EAGLE_PATH, "con.exe"); // unter Windows muß die eaglecon.exe benutzt werden + OS_Windows = 1; +} + +string SystemExit; // das Kommando an das Betriebssystem um das Batch/Shell-Script zu starten + + +// change Eagle slash in path names to backslash for windows +string lash2backslash(string f) { + if (OS_Windows) { // Windows Option + string s[]; + int cnt = strsplit(s, f, '/'); + return strjoin(s, '\\'); + } + return f; +} + +// change backslash in windows path names to Eagle slash +string backslash2lash(string f) { + string s[]; + int cnt = strsplit(s, f, '\\'); + return strjoin(s, '/'); +} + +char checkascii(string s) { + int n = 0; + do { + if (s[n] > 127) return s[n]; + } while(s[n++]); + return 0; +} + +void generatescript(void) { // Das Script (String) für die Speicherung der Varianten und + string cmd, s; // das Batch-File/Shell-Script für den CAM-Processor erzeugen + string batchcommand, b; + string ext = fileext(Fname); + BatchFile = filesetext(Fname, BatchFileExt); + char errcode = checkascii(Fname); + if (errcode) { + string error; + sprintf(error, "Unerlaubtes Zeichen %c (ASCII-Code > 127) in Dateiname

    %s

    gefunden, damit gibt es unter Umständen Probleme im System-Command!", errcode, Fname); + if (dlgMessageBox(error, "Abbruch", "Weiter") != 0) ; + else exit(-80); + } + + if (strlwr(ext) == ".sch") { + sprintf(s, "EDIT .brd;\n"); // zum Board wechseln + cmd+=s; + } + sprintf(s, "SET CONFIRM YES;\n"); // Auto-Antwort auf YES setzen, da nur BRD gespeichert wird kann überschrieben werden. + cmd+=s; + for (int n = 0; n < cntVD; n++) { + string var = Variants[n]; + string camvariantoption = ""; + + if (Variants[n] != "''") { // die Default-Variante darf nicht angegeben werden. + sprintf(camvariantoption, "-A%s ", Variants[n]); // nur echte Varianten benutzen + } + else { + camvariantoption = ""; // "''" darf in Dateiname nicht benutz werden + var = ""; // die leere '' Varianten-Bezeichnung kann hier nicht benutzt werden + } + + string fvarname = filesetext(Fname, "-" + var + ".brd"); + + if (!var ) { + // Gerber Kupfer ... Layer + for (int copperlayer = 1; copperlayer < 17; copperlayer++) { + if (UsedLayer[copperlayer]) { + sprintf(b, "\"%s\" -X %s -dGERBER_RS274X_MM_34 -o\"%s.l%02d\" \"%s\" %d 17 18\n", + lash2backslash(EagleConExe), + camvariantoption, + lash2backslash(fvarname), + copperlayer, + lash2backslash(fvarname), + copperlayer + ); + batchcommand+=b; + } + } + } + // Gerber Bestückungsdruck oben + sprintf(b, "\"%s\" -X %s -dGERBER_RS274X_MM_34 -o\"%s.plc\" \"%s\" 20 21 25\n", + lash2backslash(EagleConExe), + camvariantoption, + lash2backslash(fvarname), + lash2backslash(fvarname) + ); + batchcommand+=b; + // Gerber Bestückungsdruck unten + sprintf(b, "\"%s\" -X %s -dGERBER_RS274X_MM_34 -o\"%s.plc\" \"%s\" 20 22 26\n", + lash2backslash(EagleConExe), + camvariantoption, + lash2backslash(fvarname), + lash2backslash(fvarname) + ); + batchcommand+=b; + // Gerber Boardkontour + sprintf(b, "\"%s\" -X %s -dGERBER_RS274X_MM_34 -o\"%s.dim\" \"%s\" 20\n", + lash2backslash(EagleConExe), + camvariantoption, + lash2backslash(fvarname), + lash2backslash(fvarname) + ); + batchcommand+=b; + // EXCELLON MM 3.3 für GC-Prevue + sprintf(b, "\"%s\" -X %s -dEXCELLON_MM_33_GC-Prevue -o\"%s.drd\" \"%s\" 44 45\n", + lash2backslash(EagleConExe), + camvariantoption, + lash2backslash(fvarname), + lash2backslash(fvarname) + ); + batchcommand+=b; + + // Postscript -r 90 Grad gedreht + sprintf(b, "\"%s\" -X %s -r -dPS -o\"%s.ps\" \"%s\" 20 16\n", // -r für 90 gedreht + lash2backslash(EagleConExe), + camvariantoption, + lash2backslash(fvarname), + lash2backslash(fvarname) + ); + batchcommand+=b; + + /* ***** Ende CAM-Proz. Generierung ***** */ + + /* ***** Umschalten der Variante im Rückgabestring ***** */ + sprintf(s, "VARIANT %s;\nWRITE '%s';\n", Variants[n], fvarname); + cmd+=s; + /* ***** Befehlzeile für den CAM-Proz. im Batch/Shell-Script ***** */ + string f[]; + int fn = fileglob(f, filesetext(fvarname ,".pdf")); + if (fn) { // Existiert das PDF schon, wird es gelösch, um ein aktueles zu schreiben. + sprintf(b, "DEL \"%s\"\n", lash2backslash(f[0])); + batchcommand+=b; + } + sprintf(b, "\"%s\" \"-C PRINT 10.0 -1 -MIRROR -ROTATE -UPSIDEDOWN -CAPTION SOLID WINDOW PAPER 297x210mm FILE .pdf; QUIT;\" \"%s\" \n", + lash2backslash(EagleConExe), + lash2backslash(fvarname) + ); + batchcommand+=b; + } + + if (Test) { + if (OS_Windows) { // Windows Option + batchcommand += "PAUSE\n"; + } + } + sprintf(s, "SET CONFIRM OFF;\n"); + cmd+=s; + sprintf(s, "RUN '%s' '%s'", argv[0], lash2backslash(BatchFile)); // Der Aufruf des ULP für den zweiten Durchlauf, Batch-Ausführung + cmd+=s; + + output(BatchFile, "wtD") printf("%s", lash2backslash(batchcommand)); // das Batch-File/Shell-Script schreiben + + /* ****** nur zur Kontrolle ****** */ + if (!OS_Windows) { // Linux/MAC Option + sprintf(SystemExit, "sh \"%s\"\n", BatchFile); // unter Linux muß man eine Shell aufrufen, die die ausführbare Datei startet + } + else { + sprintf(SystemExit, "CMD.EXE /C \"%s\"", BatchFile); + } + /* ****** nur zur Kontrolle ****** */ + + + if (Test) { + dlgDialog("Check CAM-Batch/Shell scripts") { + dlgGridLayout { + dlgCell(0, 1) dlgHBoxLayout dlgSpacing(1200); + dlgCell(2, 0) dlgVBoxLayout dlgSpacing(100); + dlgCell(4, 0) dlgVBoxLayout dlgSpacing(100); + + dlgCell(1, 1) dlgLabel("Rückgabe-CMD"); + dlgCell(2, 1) dlgTextEdit(cmd); + dlgCell(3, 1) dlgLabel(BatchFile); + dlgCell(4, 1) dlgTextEdit(batchcommand); + } + dlgLabel("Batch/Shell : " + SystemExit); + dlgHBoxLayout { + dlgLabel("EagleConExe : " + EagleConExe); // "Laufwerk:/Pfad/bin/eaglecon.exe/"; + dlgLabel(" | "); + dlgLabel("EagleDir : " + EagleDir); + dlgLabel(" | "); + dlgLabel("EaglePath : " + EaglePath); + dlgLabel(" | "); + dlgLabel("OS_SIGNATURE : " + OS_SIGNATURE); + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); exit(-204); } + dlgStretch(1); + dlgLabel("Version " + Version); + } + }; + } + output(BatchFile, "wtD") printf("%s", batchcommand); + exit(cmd); +} + +if (argv[1]) { // 2. Durchlauf startet das Batch/Shell-Script + string exitcmd; + + if (OS_Windows) { // Windows Option + sprintf(exitcmd, "CMD.EXE /C \"%s\"", argv[1]); // den Aufruf in " " angeben, wegen SPACE im Pfad/Datei-Namen + } + else { + sprintf(exitcmd, "sh \"%s\"\n", argv[1]); // unter Linux muß eine Shell aufgerufen werden + } + system(exitcmd); // rufe das Batch/Shell-Script auf, nachdem die Board-Files erzeugt wurden. + exit("RUN ulpmessage 'CAM-Dateien wurden erzeugt!'"); +} + +if (project.schematic) { + project.schematic(SCH) { + Fname = SCH.name; + IsConsistent++; + CurrentVariant = variant(); + SCH.variantdefs(VD) { + if (CurrentVariant == VD.name) VDsel = cntVD; + sprintf(Variants[cntVD], "%s", VD.name); + cntVD++; + } + } +} + +if (project.board) { + IsConsistent++; + project.board(B) { + B.layers(L) { + UsedLayer[L.number] = L.used; + } + } +} + +if (IsConsistent == 2) { // 2 == Board und Schematic geladen == Konsistent + if (Test) { + string info; + sprintf(info, "%d Variants", cntVD); + int Result = dlgDialog("Save Variants and Generate CAM-Batch/Shell scripts") { + dlgHBoxLayout { + dlgLabel("Current &variant "); + dlgComboBox(Variants, VDsel) { + CurrentVariant = Variants[VDsel]; + setvariant(CurrentVariant); + } + dlgStretch(1); + } + dlgLabel(info); + dlgSpacing(12); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); exit(-265); } + dlgStretch(1); + dlgLabel("Version " + Version); + } + }; + if (Result) { + generatescript(); + } + } + else generatescript(); +} + +else { + dlgMessageBox("!Schematic und Board nicht konsistent!
    Die Erzeugung der Batch/Schell Scripte nicht möglich.", "OK"); +} \ No newline at end of file diff --git a/trunk/ulp/select-sch-group-to-brd-group.ulp b/trunk/ulp/select-sch-group-to-brd-group.ulp new file mode 100644 index 00000000..73ceb048 --- /dev/null +++ b/trunk/ulp/select-sch-group-to-brd-group.ulp @@ -0,0 +1,64 @@ +#usage "en:This ULP defines a GROUP in the layout editor with all those elements that have " + "been previously GROUPed in the schematic editor.

    " + "RUN select-sch-group-to-brd-group

    " + "After running the ULP the MOVE command will be active in the layout. " + "Use Ctrl + right mouse click in order to move the group.
    " + "Author alf@cadsoft.de" + , + "de:Das ULP definiert im Board eine Gruppe mit den Bauteilen, die " + "zuvor im Schaltplan als Gruppe markiert wurden.

    " + "RUN select-sch-group-to-brd-group

    " + "Nach Ausführen des ULPs ist im Layout-Editor der MOVE Befehl aktiv. " + "Mit Strg + rechte Maustaste kann man die Gruppe bewegen.
    " + "Author alf@cadsoft.de" + + +string Version = "1.0.0"; // 2013-06-21 alf@cadsoft.de + +string Name[]; +int cnt = 0; + +int checkEname(string ename) { + for (int n = 0; n < cnt; n++) { + if (Name[n] == ename) return 1; + } + return 0; +} + +void getGroupName(void) { + if (project.schematic) { + project.schematic(SCH) { + SCH.parts(P) { + P.instances(I) { + if (ingroup(I)) { + Name[cnt] = P.name; + cnt++; + } + } + } + } + } + return; +} + +if (board) { + string cmd; + if(!argv[1]) { + sprintf(cmd, "GROUP; RUN '%s' '*'", argv[0]); // lösche evtl. gesetze Gruppe im Board + exit(cmd); + } + getGroupName(); + project.board(B) { + B.elements(E) { + if (checkEname(E.name)) setgroup(E); + } + } + sprintf(cmd, "MOVE "); + exit(cmd); +} +else if (schematic) { + string cmd; + sprintf(cmd, "EDIT .brd;\nGROUP; RUN '%s'", argv[0]); // wechsle zum Board und starte das ULP erneut. + exit(cmd); +} +else dlgMessageBox("Start this ULP in a schematic or board.", "OK"); diff --git a/trunk/ulp/set-all-devices-attribute.ulp b/trunk/ulp/set-all-devices-attribute.ulp new file mode 100644 index 00000000..6e5cc8c7 --- /dev/null +++ b/trunk/ulp/set-all-devices-attribute.ulp @@ -0,0 +1,130 @@ +#usage "en:Run a SCRIPT through all Device Sets (Technology) in a library to define ATTRIBUTEs

    \n" + "RUN set-all-devices-attribute [SCRIPT]
    " + "The script must conform to the following syntax:
    " + "ATTRIBUTE name 'value'
    " + "ATTRIBUTE name DELETE

    " + "The words may be separated by one single space character only.
    " + "In case the value DELETE is used, the attribute will be deleted.

    " + "Value must be included in two single quotes, otherwise special " + "characters, like + - space can cause error messages in the script file.
    " + "If there is no value given or this attribute is already defined in the Device Set " + "the attribute remains unchanged.

    " + "Author: librarian@cadsoft.de

    " + , + "de:Startet ein SCRIPT um in allen Devicesets (Technologien) in einer Bibliothek ATTRIBUTE zu definieren.

    \n" + "RUN set-all-devices-attribute [SCRIPT]
    " + "Das Script muß nach folgenden Regeln erstellt sein:
    " + "ATTRIBUTE Name 'Wert'
    " + "ATTRIBUTE Name DELETE

    " + "Die Wörter dürfen mit nur einem Leerzeichen (Space) getrennt sein.
    " + "Ist der Wert DELETE zugewiesen, wird das Attribute gelöscht

    " + "Der Wert muß in zwei Apostrophen eingeschlossen sein, da es sonst bei " + "Sonderzeichen + - Space etc. im erzeugten Script zu Fehlermeldungen kommen kann.
    " + "Ist kein Wert angegeben und/oder das Attribute im Deviceset schon vorhanden und " + "ein Wert zugewiesen, dann bleibt das Attribute in diesem Deviceset unverändert.

    " + "Author: librarian@cadsoft.de

    " + +string Version = "1.1"; // 2008-09-04 check Variant name + // 1.0 // 2008-06-13 alf@cadsoft.de + +string ScriptFile = argv[1]; +string cmdScript, cmd, s; + +string Lines[], Attribut[], AttValue[]; +int setAtt[]; +int cntl = 0; +int cntAtt = 0; + +if (argv[1] == "?") { + dlgMessageBox(usage, "OK"); +} + +void test(void) { + dlgDialog(filename(argv[0]) + " Script") { + dlgTextView(cmd); + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("Abbruch") { dlgReject(); exit(-2); } + } + }; + return; +} + + +string check_varname(string s) { // 2008-09-04 + if(s == "''") return s; + return "'"+s+"'"; +} + + +void readScript(void) { + cntl = fileread(Lines, ScriptFile); + for (int n = 0; n < cntl; n++) { + if (strstr(Lines[n], "ATTRIBUTE") == 0) { + string a[]; + int cnta = strsplit(a, Lines[n], ' '); + Attribut[cntAtt] = a[1]; + AttValue[cntAtt] = a[2]; + for (int an = 3; an < cnta; an++) { // complete parameter with space + AttValue[cntAtt] += " "+a[an]; + } + cntAtt++; + } + } + return; +} + + +if (library) { + library(L) { + if (ScriptFile) { + string fg[]; + int cntf = fileglob(fg, path_scr[0]+"/"+ScriptFile); + if (!cntf) ScriptFile = ""; + else ScriptFile = fg[0]; + } + if (!ScriptFile) ScriptFile = dlgFileOpen("Select a SCRIPT with ATTRIBUTE commands to run in all DEVICESETS", path_scr[0], "*.scr"); + if (!ScriptFile) exit(0); + readScript(); + cmdScript = filesetext(L.name, "~.scr"); + L.devicesets(DS) { + sprintf(s, "EDIT %s.DEV;\n", DS.name); + cmd += s; + int n; + DS.devices(D) { + string t[]; + int nt = strsplit(t, D.technologies, ' '); + sprintf(s, "PACKAGE %s;\n", check_varname(D.name) ); + cmd += s; + for (int i = 0; i < nt; i++) { + sprintf(s, "TECHNOLOGY %s;\n", t[i]); + cmd += s; + for (n = 0; n < cntAtt; n ++) setAtt[n] = 1; // preset flags + D.attributes(A, t[i]) { + for (n = 0; n < cntAtt; n++) { + status(DS.name+":"+D.name+":"+t[i]); + + if (A.name == Attribut[n]) { + if (A.value || !AttValue[n]) setAtt[n] = 0; // wenn das Attribut schon einen Wert besitzt + // oder im Script kein Wert zugewiesen wird, + // wird das Attribut nicht geändert + } + } + } + for (n = 0; n < cntAtt; n ++) { + if (setAtt[n] || AttValue[n] == "DELETE") { + sprintf(s, "ATTRIBUTE %s %s;\n", Attribut[n], AttValue[n]); + cmd+=s; + s=""; + } + } + } + } + } + } + output(cmdScript, "wtD") printf("%s", cmd); + sprintf(s, "SCRIPT '%s';\n", cmdScript); + exit(s); +} + +else dlgMessageBox("Start this ULP from a Library", "OK"); diff --git a/trunk/ulp/set_name_value.ulp b/trunk/ulp/set_name_value.ulp new file mode 100644 index 00000000..23fa2339 --- /dev/null +++ b/trunk/ulp/set_name_value.ulp @@ -0,0 +1,42 @@ +#usage "place >NAME and >VALUE in Package or Symbol if not placed

    " + "Author alf@cadsoft.de" + +string cmd; + +if (symbol) { + int no_Sname = 1; + int no_Svalue = 1; + symbol(S) { + S.texts(T) { + if (T.value == ">NAME" && T.layer == 95) no_Sname = 0; + if (T.value == ">VALUE" && T.layer == 96) no_Svalue = 0; + if (T.value == ">GATE" && T.layer == 95 || T.value == ">PART" && T.layer == 95) { + no_Sname = 0; + no_Svalue = 0; + } + } + } + if (no_Sname && no_Svalue) { + cmd = "GRID MIL;\nCHANGE SIZE 70;\nCHANGE LAYER 95;\nTEXT >NAME (0 100);\n GRID LAST;"; + cmd += "GRID MIL;\nCHANGE SIZE 70;\nCHANGE LAYER 96;\nTEXT >VALUE (0 0);\n GRID LAST;"; + } +} + +if (package) { + int no_Pname = 1; + int no_Pvalue = 1; + package(P) { + P.texts(T) { + if (T.value == ">NAME" && T.layer == 25) no_Pname = 0; + if (T.value == ">VALUE" && T.layer == 27) no_Pvalue = 0; + } + } + if (no_Pname) { + cmd = "GRID MIL;\nCHANGE SIZE 50;\nCHANGE LAYER 25;\nTEXT >NAME (0 100);\n GRID LAST;"; + } + if (no_Pvalue) { + cmd += "GRID MIL;\nCHANGE SIZE 50;\nCHANGE LAYER 27;\nTEXT >VALUE (0 0);\n GRID LAST;"; + } +} + +exit (cmd); \ No newline at end of file diff --git a/trunk/ulp/settings/default.drl.txt b/trunk/ulp/settings/default.drl.txt new file mode 100644 index 00000000..537f1f02 --- /dev/null +++ b/trunk/ulp/settings/default.drl.txt @@ -0,0 +1,27 @@ +# -*- Mode: Eagle -*- +# +# Sample drill rack file. +# +# drill_size is the size of the drill bit. +# minimum is the smallest hole the bit will be used for. +# maximum is the largest hole the bit will be used for. +# +# Each value can have a "unit of measure" added to it, +# such as 0.500mm . If you do not provide the unit of measure, +# values over 0.250 are considered millimeters, and +# values under 0.250 are considered inches. For example: +# 0.400 would be considered 0.400 mm. +# 0.125 would be considered 0.125 inches. +# +# Please note that you must use a TAB character +# between each setting on a line. +# +# Tip: Set the TAB size of your editor to 12 characters. +# +tool drill_size minimum maximum length +T01 0.500mm 0.000in 0.025in 1.5in +T02 0.032in 0.025in 0.035in 1.5in +T03 0.040in 0.035in 0.039in 1.5in +T04 0.050in 0.045in 0.055in 1.5in +T05 0.062in 0.055in 0.070in 1.5in +T06 0.125in 0.100in 0.125in 1.5in diff --git a/trunk/ulp/settings/gcode-defaults.h b/trunk/ulp/settings/gcode-defaults.h new file mode 100644 index 00000000..fce40fd7 --- /dev/null +++ b/trunk/ulp/settings/gcode-defaults.h @@ -0,0 +1,130 @@ +// +// Options for pcb-gcode.ulp. +// Often used options are at the top of the file. +// Copied to gcode-defaults.h by the setup program. +// +// author=John Johnson +// description=Tries to be very compatible +// + +int FILENAMES_8_CHARACTERS = NO; + +// +// Comments. +// +string COMMENT_BEGIN = "("; +string COMMENT_END = ")"; + +// +// Format strings for coordinates, etc. +// +string FORMAT = "%-6.4f "; /* coordinate format */ +string FR_FORMAT = "F%-5.2f "; /* feedrate format */ +string IJ_FORMAT = "I" + FORMAT + "J" + FORMAT; +string EOL = "\n"; /* standard line ending */ +string PARAM = "P"; /* some use P, some # for parameters */ +// +// Modes +// +string INCH_MODE = "G20" + EOL; +string INCH_MODE_COMMENT = COMMENT_BEGIN + "Inch Mode" + COMMENT_END + EOL; +string METRIC_MODE = "G21" + EOL; +string METRIC_MODE_COMMENT = COMMENT_BEGIN + "Metric Mode" + COMMENT_END + EOL; +string MIL_MODE = "M02 (Please setup MIL_MODE in gcode-defaults.h)" + EOL; +string MICRON_MODE = "M02 (Please setup MICRON_MODE in gcode-defaults.h)" + EOL; +string ABSOLUTE_MODE = COMMENT_BEGIN + "Absolute Coordinates" + COMMENT_END + EOL + "G90" + EOL; + +// +// G codes +// +string RAPID = "G00 "; +string FEED = "G01 "; +string ARC_CW = "G02 "; +string ARC_CCW = "G03 "; +string DWELL = "G04 " + PARAM + "%f" + EOL; + +// +// M codes +// +string SPINDLE_ON = "M03" + EOL + DWELL; +string SPINDLE_OFF = "M05" + EOL; +string END_PROGRAM = "M02" + EOL; +string OPERATOR_PAUSE = "M06 "; + +// +// Coordinates +// +string MOVE_X = "X" + FORMAT; +string MOVE_Y = "Y" + FORMAT; +string MOVE_XY = "X" + FORMAT + "Y" + FORMAT; +string MOVE_Z = "Z" + FORMAT; +string MOVE_XYZ = MOVE_XY + MOVE_Z; + +// +// Rapids +// +string RAPID_MOVE_X = RAPID + MOVE_X; +string RAPID_MOVE_Y = RAPID + MOVE_Y; +string RAPID_MOVE_XY = RAPID + MOVE_XY; +string RAPID_MOVE_XY_HOME = RAPID + "X0 Y0"; +string RAPID_MOVE_Z = RAPID + MOVE_Z; +string RAPID_MOVE_XYZ = RAPID + MOVE_XYZ; + +// +// Feeds +// +string FEED_MOVE_X = FEED + MOVE_X; +string FEED_MOVE_Y = FEED + MOVE_Y; +string FEED_MOVE_XY = FEED + MOVE_XY; +string FEED_MOVE_XY_WITH_RATE = FEED + MOVE_XY + FR_FORMAT; +string FEED_MOVE_Z = FEED + MOVE_Z; +string FEED_MOVE_Z_WITH_RATE = FEED + MOVE_Z + FR_FORMAT; +string FEED_MOVE_XYZ = FEED + MOVE_XYZ; + +// +// Drilling holes +// +// Not using G82 so it will be very generic. +// +string DRILL_CODE = ";( G82 not used )"; +string RELEASE_PLANE = "R" + FORMAT; +string DWELL_TIME = PARAM + "%f"; + +string DRILL_FIRST_HOLE = RAPID + "Z" + real_to_string(DEFAULT_Z_UP) + EOL + + RAPID + MOVE_XY + EOL + + FEED + MOVE_Z + FR_FORMAT + EOL + + FEED + "Z" + real_to_string(DEFAULT_Z_UP) + EOL + + COMMENT_BEGIN + RELEASE_PLANE + " " + DWELL_TIME + COMMENT_END + EOL; + +string DRILL_HOLE = COMMENT_BEGIN + RAPID + "Z" + real_to_string(DEFAULT_Z_UP) + COMMENT_END + EOL + + RAPID + MOVE_XY + EOL + + FEED + "Z" + real_to_string(DRILL_DEPTH) + EOL + + FEED + "Z" + real_to_string(DEFAULT_Z_UP) + EOL; + +// +// Tool change +// +string TOOL_CODE = "T%02d "; +string TOOL_MM_FORMAT = "%1.3fmm"; +string TOOL_INCH_FORMAT = "%1.4fin"; +string TOOL_CHANGE = OPERATOR_PAUSE + TOOL_CODE + " ; " + FORMAT + EOL; + +string TOOL_CHANGE_TABLE_HEADER = COMMENT_BEGIN + + " Tool| Size | Min Sub | Max Sub | Count " + COMMENT_END + EOL; + +string TOOL_CHANGE_TABLE_FORMAT(int tool_number, real size_mm, real size_inch, real min_drill, real max_drill, int count) +{ + string formatted; + + sprintf(formatted, COMMENT_BEGIN + " " + TOOL_CODE + " " + TOOL_MM_FORMAT + " " + + TOOL_INCH_FORMAT + " " + TOOL_INCH_FORMAT + " " + TOOL_INCH_FORMAT + " " + COMMENT_END + EOL, + tool_number, size_mm, size_inch, min_drill, max_drill); + return(formatted); +} + +// +// Circles / Arcs +// +string CIRCLE_TOP = ARC_CW + MOVE_XY + IJ_FORMAT + EOL; +string CIRCLE_BOTTOM = ARC_CCW + MOVE_XY + IJ_FORMAT + EOL; + diff --git a/trunk/ulp/settings/pcb-defaults.h b/trunk/ulp/settings/pcb-defaults.h new file mode 100644 index 00000000..35e73f3c --- /dev/null +++ b/trunk/ulp/settings/pcb-defaults.h @@ -0,0 +1,39 @@ +// +// Default values for generating gcode from a PCB. +// +// These settings were last changed with pcb-gcode-setup: 07/07/20 00:45 +// +// +// Changes you make in this file will be overwritten if you use pcb-gcode-setup. +// + +int SINGLE_PASS = YES; +real ISO_MIN = 1.000000; +real ISO_MAX = 0.508000; +real ISO_STEP = 0.127000; + +int GENERATE_TOP_OUTLINES = YES; +int GENERATE_TOP_DRILL = YES; +int GENERATE_TOP_FILL = NO; + +int GENERATE_BOTTOM_OUTLINES = YES; +int GENERATE_BOTTOM_DRILL = YES; +int GENERATE_BOTTOM_FILL = NO; +int MIRROR_BOTTOM = NO; +int SIMPLE_DRILL_CODE = NO; + +int GENERATE_MILLING = NO; + +int GENERATE_TEXT = NO; + +int SPOT_DRILL = YES; +real SPOT_DRILL_DEPTH = -0.279400; + +int DO_TOOL_CHANGE_WITH_ZERO_STEP = YES; + +int FLIP_BOARD_IN_Y = NO; + +//int OUTPUT_UNITS = U_MICRONS; +int OUTPUT_UNITS = U_MILLIMETERS; +//int OUTPUT_UNITS = U_MILS; +//int OUTPUT_UNITS = U_INCHES; diff --git a/trunk/ulp/settings/pcb-gcode-options.h b/trunk/ulp/settings/pcb-gcode-options.h new file mode 100644 index 00000000..a173fe4c --- /dev/null +++ b/trunk/ulp/settings/pcb-gcode-options.h @@ -0,0 +1,34 @@ +// +// General Options // Your edits to this file will be overwritten by the setup program. +// +int SHOW_PROGRESS = NO; +string RESTORE_MENU_FILE = "pcb-gcode-menu.scr"; +int NC_FILE_COMMENT_FROM_BOARD = YES; +int NC_FILE_COMMENT_DATE = YES; +int NC_FILE_COMMENT_MACHINE_SETTINGS = YES; +int NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS = YES; +int USER_GCODE = NO; +int g_debug_flag = YES; +int COMPACT_GCODE = NO; +int USE_LINE_NUMBERS = NO; +string LINE_NUMBER_FORMAT = "N%05d "; +int SHOW_PREVIEW = YES; +string FILENAME_BASE = "$BOARD_PATH/$BOARD_NAME"; +string FILENAME_TOP_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_TOP_FILL_FILE = ""; +string FILENAME_BOT_ETCH_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_DRILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_MILL_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_TEXT_FILE = ".$SIDE.$FILE.$EXT"; +string FILENAME_BOT_FILL_FILE = ""; +string ETCH_FILE_NAME = "etch"; +string DRILL_FILE_NAME = "drill"; +string MILL_FILE_NAME = "mill"; +string TEXT_FILE_NAME = "text"; +string TOP_FILE_NAME = "top"; +string BOT_FILE_NAME = "bot"; +string DEFAULT_EXTENSION = "tap"; +string DEFAULT_DRILL_FILE = ""; diff --git a/trunk/ulp/settings/pcb-machine.h b/trunk/ulp/settings/pcb-machine.h new file mode 100644 index 00000000..f1564463 --- /dev/null +++ b/trunk/ulp/settings/pcb-machine.h @@ -0,0 +1,24 @@ +// +// For ease of use, and to avoid overwritting your settings, +// use pcb-gcode-setup to make changes to these settings. +// + +real DEFAULT_Z_HIGH = 12.700000; +real DEFAULT_Z_UP = 2.540000; +real DEFAULT_Z_DOWN = -0.177800; +real DRILL_DEPTH = -0.812800; +real DRILL_DWELL = 1.000000; +real SPINDLE_ON_TIME = 3.000000; +real MILLING_DEPTH = -0.254000; +real TEXT_DEPTH = -0.127000; +real TOOL_CHANGE_POS_X = 12.700000; +real TOOL_CHANGE_POS_Y = 15.240000; +real TOOL_CHANGE_POS_Z = 25.400000; +real FEED_RATE = 508.000000; +real FEED_RATE_Z = 254.000000; +real DEFAULT_WIDTH = 1.000000; +real X_OFFSET = 0.000000; +real Y_OFFSET = 0.000000; +real X_HOME = 0.000000; +real Y_HOME = 0.000000; +real EPSILON = 0.002540; diff --git a/trunk/ulp/settings/user-gcode.h b/trunk/ulp/settings/user-gcode.h new file mode 100644 index 00000000..564cfe5c --- /dev/null +++ b/trunk/ulp/settings/user-gcode.h @@ -0,0 +1,236 @@ +// +// Define your own gcode sequences in this file. +// +// The settings are listed from most general, to most specific. The settings +// at the top of this file go into every file created, while the settings +// at the end of this file have to do with tool changes only. +// +// Note that each line ends with \n this is Geek Speak for newline. +// In other words, it's like hitting the Enter key at the end of a line. +// Notice also that the lines have a ; at the end. +// +// See the bottom of this file for an example of using multiple lines. +// + +// Inserted into bottom, top or all files. +string FILE_BEGIN[] = { "", "", "", "" }; +string FILE_END[] = { "", "", "", "" }; + +FILE_BEGIN[ALL] = "(Beginning of every file)\n"; +FILE_END[ALL] = "(End of every file)\n"; + +FILE_BEGIN[BOTTOM] = "(Beginning of every bottom file)\n"; +FILE_END[BOTTOM] = "(End of every bottom file)\n"; + +FILE_BEGIN[TOP] = "(Beginning of every top file)\n"; +FILE_END[TOP] = "(End of every top file)\n"; + +// Inserted into outline files (track milling). +string OUTLINE_BEGIN[] = { "", "", "", "" }; +string OUTLINE_BETWEEN[] = { "", "", "", "" }; +string OUTLINE_END[] = { "", "", "", "" }; + +OUTLINE_BEGIN[ALL] = "(Outline Begin)\n"; +OUTLINE_BETWEEN[ALL] = "(Between Passes)\n"; +OUTLINE_END[ALL] = "(Outline End)\n"; + +OUTLINE_BEGIN[BOTTOM] = "(Bottom outline Begin)\n"; +OUTLINE_BETWEEN[BOTTOM] = "(Bottom between passes)\n"; +OUTLINE_END[BOTTOM] = "(Bottom outline End)\n"; + +OUTLINE_BEGIN[TOP] = "(Top outline Begin)\n"; +OUTLINE_BETWEEN[TOP] = "(Top between passes)\n"; +OUTLINE_END[TOP] = "(Top outline End)\n"; + +// Inserted into drill files. +string DRILL_BEGIN[] = { "", "", "", "" }; +string DRILL_END[] = { "", "", "", "" }; + +DRILL_BEGIN[ALL] = "(Beginning of All Drill files)\n"; +DRILL_END[ALL] = "(End of all Drill Files)\n"; + +DRILL_BEGIN[BOTTOM] = "(Bottom Drill Begin)\n"; +DRILL_END[BOTTOM] = "(Bottom Drill End)\n"; + +DRILL_BEGIN[TOP] = "(Top Drill Begin)\n"; +DRILL_END[TOP] = "(Top Drill End)\n"; + +// Inserted into fill files. +string FILL_BEGIN[] = { "", "", "", "" }; +string FILL_END[] = { "", "", "", "" }; + +FILL_BEGIN[ALL] = "(Fill Begin)\n"; +FILL_END[ALL] = "(Fill End)\n"; + +FILL_BEGIN[BOTTOM] = "(Bottom Fill Begin)\n"; +FILL_END[BOTTOM] = "(Bottom Fill End)\n"; + +FILL_BEGIN[TOP] = "(Top Fill Begin)\n"; +FILL_END[TOP] = "(Top Fill End)\n"; + +// Inserted into milling files. +string MILL_BEGIN[] = { "", "", "", "" }; +string MILL_END[] = { "", "", "", "" }; + +MILL_BEGIN[ALL] = "(MILL Begin)\n"; +MILL_END[ALL] = "(MILL End)\n"; + +MILL_BEGIN[BOTTOM] = "(Bottom MILL Begin)\n"; +MILL_END[BOTTOM] = "(Bottom MILL End)\n"; + +MILL_BEGIN[TOP] = "(Top MILL Begin)\n"; +MILL_END[TOP] = "(Top MILL End)\n"; + +// Tool change code. +string TOOL_CHANGE_BEGIN[] = { "", "", "", "" }; +string TOOL_CHANGED[] = { "", "", "", "" }; +string TOOL_ZERO_BEGIN[] = { "", "", "", "" }; +string TOOL_ZERO_END[] = { "", "", "", "" }; +string TOOL_CHANGE_END[] = { "", "", "", "" }; + +TOOL_CHANGE_BEGIN[ALL] = "(Tool Change Begin)\n"; +TOOL_CHANGED[ALL] = "(Tool changed)\n"; +TOOL_ZERO_BEGIN[ALL] = "(Tool zero begin)\n"; +TOOL_ZERO_END[ALL] = "(Tool zero end)\n"; +TOOL_CHANGE_END[ALL] = "(Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[BOTTOM] = "(Bottom Tool Change Begin)\n"; +TOOL_CHANGED[BOTTOM] = "(Bottom Tool changed)\n"; +TOOL_ZERO_BEGIN[BOTTOM] = "(Bottom Tool zero begin)\n"; +TOOL_ZERO_END[BOTTOM] = "(Bottom Tool zero end)\n"; +TOOL_CHANGE_END[BOTTOM] = "(Bottom Tool Change End)\n"; + +TOOL_CHANGE_BEGIN[TOP] = "(Top Tool Change Begin)\n"; +TOOL_CHANGED[TOP] = "(Top Tool changed)\n"; +TOOL_ZERO_BEGIN[TOP] = "(Top Tool zero begin)\n"; +TOOL_ZERO_END[TOP] = "(Top Tool zero end)\n"; +TOOL_CHANGE_END[TOP] = "(Top Tool Changed End)\n"; + +// +// An example of using more than one line of gcode. +// Note that only the last line has a ; at the end. +// +string THIS_ISNT_USED[] = { "", "", "", "" }; // Don't change lines like this +THIS_ISNT_USED[BOTTOM] = "G20\n" + "G90\n" + "G01 Z0\n" + "G00 X0 Y0\n" + "M06 T2 ; 0.060\n" + "G04 P5\n"; + +/* + * The functions below should make it easier for folks outputing their own code, etc. + * + */ + +/* + * Called after the gcode file has been opened. + * Mode can be + * "wt" (write a text file) when the file is first opened. + * "at" (append a text file) if the file is added to. + * + * You might want to check g_side to see which "side" you are working on. + * g_side can be TOP, BOTTOM or MILL. + * + */ +void user_file_opened(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just before the gcode file is closed. + * + */ +void user_file_closing() +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * Just after the gcode file is closed. + * See user_file_opened for information on the mode parameter. + * + */ +void user_file_closed(string name, string mode) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of the outline of a track. + * + */ +void user_track_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * An intermediate point on the outline of a track. + * + */ +int user_coord_cnt; +void user_track_continue(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of the outline of a track. + * + */ +void user_track_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The beginning of an arc. + * + */ +void user_arc_begin(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} + +/* + * The end of an arc. + * + */ +void user_arc_end(real start_x, real start_y, real end_x, real end_y) +{ + if (USER_GCODE == NO) { + return; + } + + // your code here +} diff --git a/trunk/ulp/show-group.ulp b/trunk/ulp/show-group.ulp new file mode 100644 index 00000000..925b141f --- /dev/null +++ b/trunk/ulp/show-group.ulp @@ -0,0 +1,39 @@ +#usage "Show group from schematic/board in board/schematic

    " + "Author: alf@cadsoft.de" + +string Version = "1.0.0"; // 2012-03-28 + +string Cmd = "SHOW "; +int cnt = 0; + +if (schematic) { + if (project.board) project.board(B) { + B.elements(E) { + if (ingroup(E)) { + Cmd += " " + E.name; + cnt++; + } + } + } +} + +else if (board) { + if (project.schematic) project.schematic(SCH) { + SCH.parts(P) { + P.instances(I) { + if (ingroup(I)) { + Cmd += " " + P.name; + cnt++; + break; + } + } + } + } +} + +else dlgMessageBox("!Start this ULP in a board or schematic.", "OK"); + +if(!cnt) { + dlgMessageBox("!No group selected.", "OK"); +} +exit(Cmd); diff --git a/trunk/ulp/showclass.ulp b/trunk/ulp/showclass.ulp new file mode 100644 index 00000000..61bb66af --- /dev/null +++ b/trunk/ulp/showclass.ulp @@ -0,0 +1,166 @@ +#usage "en:

    Highlights all net with a given CLASS.

    \n" + "This ULPs works from within a board or a schematic.
    " + "

    Author: alf@cadsoft.de", + "de:

    Hebt Signale der angegebenen CLASS hervor.

    \n" + "Dieses ULP arbeitet aus Boards oder Schematics heraus.
    " + "

    Author: alf@cadsoft.de" + +#require 5.0400 +//2013-07-17 JG Now accepts both netclass name and netclass number as valid input +//2013-07-18 AZ select class name by menu, if start without class + +string strTexts[] = { + "en\v" + "de\v" + , + ";This ULP requires a board or a schematic.\v" + ";Dieses Ulp funktioniert nur in Boards und Schematics.\v" + , + "Please select class you want to highlight.\v" + "Wählen Sie die hervorzuhebende CLASS.\v" + , + ";No Signals found with CLASS \"%s\".\v" + ";Es wurden keine Signale der CLASS \"%s\" gefunden.\v" + , + ";No Nets found with CLASS on this page \"%s\".\v" + ";Es wurden keine NETze der CLASS \"%s\" auf dieser Seite gefunden.\v" + +}; + +string strMessage; +string strScript, s; +int nCount; +string strValue; +string ClassName[]; +int Cntcl = 0; + +int Test = 0; + +/*** functions ***/ +string Translate(string src) { + string strLoc = lookup(strTexts, src, strstr(strTexts[0], language()) / 3, '\v'); + return((strLoc != "") ? strLoc : src); +} + +string InputBox() { + int sel = 0; + int nResult = dlgDialog(filename(argv[0])) { + dlgGridLayout { + dlgCell(0, 0) dlgLabel(Translate("Please select class you want to highlight.")); + dlgCell(1, 0) dlgComboBox(ClassName, sel); // 2013-07-18 AZ + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("Cancel") dlgReject(); + } + }; + return(ClassName[sel]); +} + +void test(string Script) { + dlgDialog("test") { + dlgHBoxLayout dlgSpacing(800); + dlgTextEdit(Script); + dlgHBoxLayout { + dlgPushButton("ok") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-99); } + dlgStretch(1); + } + }; + return; +} + +if (argv[1]) { + strValue = argv[1]; +} + +if(board) board(B) { + B.classes(CL) { // 2013-07-18 AZ + if (CL.name) ClassName[Cntcl++] = CL.name; + } + if (!strValue) { + strValue = InputBox(); + } + if(!strValue) exit(EXIT_SUCCESS); + sprintf(strScript, "WINDOW;\n SHOW "); // 2008-11-03 + B.signals(S) { + if(strupr(S.class.name) == strupr(strValue)) { //2013-07-17 JG + sprintf(s, " %s ", S.name); + strScript += s; + ++nCount; + } + else if (strtol(strValue) == 0 && strValue == "0") { + if(strupr(S.class.name) == "DEFAULT") { + sprintf(s, " %s ", S.name); + strScript += s; + ++nCount; + } + } + else if (S.class.number == strtol(strValue) && strupr(S.class.name) != "DEFAULT") { + sprintf(s, " %s ", S.name); + strScript += s; + ++nCount; + } + } + strScript +=" "; + + if(!nCount) { + sprintf(strMessage, Translate(";No Signals found with CLASS \"%s\"."), strValue); + dlgMessageBox(strMessage); + exit(EXIT_FAILURE); + } + else { + if (Test) test(strScript); + exit(strScript); + } +} + +else if(sheet) sheet(S) { + schematic(SCH) SCH.classes(CL) {// 2013-07-18 AZ + if (CL.name) ClassName[Cntcl++] = CL.name; + } + string strName; + schematic(SCH) { + strName = SCH.name; + } + if (!strValue) { + strValue = InputBox(); + } + if(!strValue) exit(EXIT_SUCCESS); + + sprintf(strScript, "WINDOW;\nSHOW "); + S.nets(N) { + if(strupr(N.class.name) == strupr(strValue)) { //2013-08-10 JG + sprintf(s, " %s ", N.name); + strScript += s; + ++nCount; + } + else if (strtol(strValue) == 0 && strValue == "0") { + if(strupr(N.class.name) == "DEFAULT") { + sprintf(s, " %s ", N.name); + strScript += s; + ++nCount; + } + } + else if (N.class.number == strtol(strValue) && strupr(N.class.name) != "DEFAULT") { + sprintf(s, " %s ", N.name); + strScript += s; + ++nCount; + } + } + strScript += " "; + + if(!nCount) { + sprintf(strMessage, Translate(";No Nets found with CLASS on this page \"%s\"."), strValue); + dlgMessageBox(strMessage); + exit(EXIT_FAILURE); + } + else { + if (Test) test(strScript); + exit(strScript); + } +} +else { + dlgMessageBox(Translate(";This ULP requires a board or a schematic.")); +} + diff --git a/trunk/ulp/silk.ulp b/trunk/ulp/silk.ulp new file mode 100644 index 00000000..1c535b9b --- /dev/null +++ b/trunk/ulp/silk.ulp @@ -0,0 +1,172 @@ +#usage "Generate a wider silk screen\n" + "

    " + "Some board manufacturers want to have at least a width of 8mil " + "for silk screen lines in order to guarantee legible results. " + "EAGLE libraries use 5 mil width for silk screen as default. " + "This ULP changes all silk screen elemtents to a minimum " + "with of 8 mil . All elements of layers 21 and 22 " + "are written into new layers 121(_tplace) and 122 (_bplace). " + "Texts are changes as well. The new ratio is 16% (default 8). That " + "means texts with a size of 50 mil get a wire width of 8 mil as well. " + "

    " + "Two new layers will be defined and the new silk screen will be " + "generated. For generating GERBER data be aware that you have to " + "activate layers 121 or 122 instead of the original layers 21 and 22." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + + // Define your own silk screen width here +real Silkwidth = 8.0 ; // in mil +int NewTextRatio = 16 ; // and the new text ratio + +int source, newlay, tplace = 21, + bplace = 22, + offset = 100; + +string TextOrientation; +string cmd = "SET UNDO_LOG OFF;\n"; // advisable for speed reasons +string h; + +void header(void) { + h = "";sprintf(h, "layer %d _tplace;\n", tplace+offset);cmd += h; // here you can change the new + h = "";sprintf(h, "layer %d _bplace;\n", bplace+offset);cmd += h; // layers names + h = "";sprintf(h, "set color_layer %d yellow;\n", tplace+offset);cmd += h; // and + h = "";sprintf(h, "set color_layer %d yellow;\n", bplace+offset);cmd += h; // colors + h = "";sprintf(h, "set wire_bend 2;\n");cmd += h; + h = "";sprintf(h, "\nGRID mil;\n\n");cmd += h; +} + +void searchelements(UL_ELEMENT E) { + newlay = source + offset; + E.package.wires(W) { + if (W.arc) { + if (W.layer == source && u2mil(W.width) <= Silkwidth) { + h = "";sprintf(h, "Layer %d;\n", newlay);cmd += h; + h = "";sprintf(h, "ARC %5.3f ccw (%5.3f %5.3f) (%5.3f %5.3f) (%5.3f %5.3f);\n", + Silkwidth, u2mil(W.arc.x1), u2mil(W.arc.y1), u2mil(2*(W.arc.xc)-W.arc.x1), + u2mil(2*(W.arc.yc) - W.arc.y1), u2mil(W.arc.x2), u2mil(W.arc.y2));cmd += h; + } + if (W.layer == source && u2mil(W.width) > Silkwidth) { + h = "";sprintf(h, "Layer %d;\n", newlay);cmd += h; + h = "";sprintf(h, "ARC %5.3f ccw (%5.3f %5.3f) (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mil(W.arc.width), u2mil(W.arc.x1), u2mil(W.arc.y1), u2mil(2*(W.arc.xc)-W.arc.x1), + u2mil(2*(W.arc.yc) - W.arc.y1), u2mil(W.arc.x2), u2mil(W.arc.y2));cmd += h; + } + } + else { + if (W.layer == source && u2mil(W.width) <= Silkwidth) { + + h = "";sprintf(h, "Layer %d;\n", newlay);cmd += h; + h = "";sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + Silkwidth, u2mil(W.x1), u2mil(W.y1), u2mil(W.x2), u2mil(W.y2));cmd += h; + } + if (W.layer == source && u2mil(W.width) > Silkwidth) { + + h = "";sprintf(h, "Layer %d;\n", newlay);cmd += h; + h = "";sprintf(h, "WIRE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mil(W.width), u2mil(W.x1), u2mil(W.y1), u2mil(W.x2), u2mil(W.y2));cmd += h; + } + } + } + E.package.circles(C) { + if (C.layer == source && u2mil(C.width) <= Silkwidth && u2mil(C.width) != 0) { + + h = "";sprintf(h, "Layer %d;\n", newlay);cmd += h; + h = "";sprintf(h, "CIRCLE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + Silkwidth, u2mil(C.x), u2mil(C.y), u2mil(C.x + C.radius), u2mil(C.y));cmd += h; + } + if (C.layer == source && (u2mil(C.width) > Silkwidth || u2mil(C.width) == 0)) { + + h = "";sprintf(h, "Layer %d;\n", newlay);cmd += h; + h = "";sprintf(h, "CIRCLE %5.3f (%5.3f %5.3f) (%5.3f %5.3f);\n", + u2mil(C.width), u2mil(C.x), u2mil(C.y), u2mil(C.x + C.radius), u2mil(C.y));cmd += h; + } + } + E.package.rectangles(R) { + if (R.layer == source) { + + h = "";sprintf(h, "Layer %d;\n", newlay);cmd += h; + h = "";sprintf(h, "RECT (%5.3f %5.3f) (%5.3f %5.3f);\n", u2mil(R.x1), u2mil(R.y1), + u2mil(R.x2), u2mil(R.y2));cmd += h; + } + } + E.package.polygons(P) { + if (P.layer == source && u2mil(P.width) <= Silkwidth) { + P.wires(WP) { + h = "";sprintf(h, "POLYGON %5.3f (%5.3f %5.3f)\n ",Silkwidth, u2mil(WP.x1), u2mil(WP.y1));cmd += h; + break; + } + P.wires(WP) { + h = "";sprintf(h, " %+f (%5.3f %5.3f)", WP.curve, u2mil(WP.x2), u2mil(WP.y2));cmd += h; + } + h = "";sprintf(h, ";\n");cmd += h; + } + if (P.layer == source && u2mil(P.width) > Silkwidth) { + P.wires(WP) { + h = "";sprintf(h, "POLYGON %5.3f (%5.3f %5.3f)\n ",u2mil(P.width), + u2mil(WP.x1), u2mil(WP.y1));cmd += h; + break; + } + P.wires(WP) { + h = "";sprintf(h, " (%5.3f %5.3f)", u2mil(WP.x2), u2mil(WP.y2));cmd += h; + } + h = "";sprintf(h, ";\n");cmd += h; + } + } + E.package.texts(T) { + if (T.layer == source && T.ratio < NewTextRatio) { + + h = "";sprintf(h, "Layer %d;\n", newlay);cmd += h; + h = "";sprintf(h, "Change Ratio %d;\n", NewTextRatio);cmd += h; + h = "";sprintf(h, "Change Size %5.3f;\n", u2mil(T.size));cmd += h; + h = "";sprintf(h, "TEXT '%s' %s%1.0f (%5.3f %5.3f);\n", + T.value, TextOrientation, T.angle, u2mil(T.x), u2mil(T.y));cmd += h; + } + if (T.layer == source && T.ratio >= NewTextRatio) { + + h = "";sprintf(h, "Layer %d;\n", newlay);cmd += h; + h = "";sprintf(h, "Change Size %5.3f;\n", u2mil(T.size));cmd += h; + h = "";sprintf(h, "TEXT '%s' %s%1.0f (%5.3f %5.3f);\n", + T.value, TextOrientation, T.angle, u2mil(T.x), u2mil(T.y));cmd += h; + } + } +} + +if (board) { + board(B) { + + header(); + + B.elements(E) { + source = tplace; + TextOrientation = "R"; + searchelements(E); + + source = bplace; + TextOrientation = "MR"; + searchelements(E); + } + } + +cmd += "SET UNDO_LOG ON;\n"; + +// Dialog +int Result = dlgDialog("Script to generate the new silk screen") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+Execute") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + } + }; + +if (Result == 0) exit(0); + +exit(cmd); +} + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); +} diff --git a/trunk/ulp/smash-all-sch.ulp b/trunk/ulp/smash-all-sch.ulp new file mode 100644 index 00000000..d847ba0f --- /dev/null +++ b/trunk/ulp/smash-all-sch.ulp @@ -0,0 +1,55 @@ +#usage "Smash all gates of a schematic\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string cmd; +string c; + +void visible(UL_SCHEMATIC S) { + sprintf(c, "DISP NONE;\nDISP "); + cmd += c; + S.layers(L) { + if (L.visible) { + sprintf(c, "%d ", L.number); + cmd += c; + } + } + cmd += ";\n"; + return; +} + +if (schematic) { + schematic(S) { + cmd = "DISPLAY NONE 94;\n"; + cmd += "GRID MIL 1;\n"; + S.sheets(SH) { + sprintf(c, "EDIT .s%d;\n", SH.number); + cmd += c; + SH.parts(P) { + if (P.device.package) { // **** only Devices with Package + // **** without Supply symbol Frames ect... + P.instances(I) { + if (I.sheet != 0) { + sprintf(c, "SMASH (%.2f %.2f);\n", u2mil(I.x), u2mil(I.y) ); + cmd += c; + } + } + } + } + } + + sprintf(c, "GRID INCH 0.1;\n"); + cmd += c; + sprintf(c, "EDIT .S1;\n"); + cmd += c; + visible(S); + exit (cmd); + } +} + +else { + dlgMessageBox("\n Start this ULP in a Schematic \n"); + exit (0); +} diff --git a/trunk/ulp/smd-coordinate.ulp b/trunk/ulp/smd-coordinate.ulp new file mode 100644 index 00000000..08c4dba2 --- /dev/null +++ b/trunk/ulp/smd-coordinate.ulp @@ -0,0 +1,104 @@ +#usage "Print SMD coordinates for Top and Bottom\n" + "

    " + "Generates two files which contain the coordinates of the " + "Smd pads in the layout. Boardname.smt for the Top layer, " + "boardname.smb for Bottom layer. " + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +/* SMD-coordinate.ulp erzeugt eine Datei "boardname.smt" fuer die Koordinaten + der SMD-Pads auf der Bestueckungsseite (TOP)und eine Datei + "boardname.smb" fuer die Koordinaten der SMD-Pads auf der + Loetseite (BOTTOM). + 08.02.2001 alf@cadsoft.de + */ + +int uval = 3; + +string Version = "1.0.1"; + +int smdx[], smdy[]; // size of smd +int x[], y[]; // coordinate of SMD +int tb[]; // top or bottom side +int index[]; +int c = 0; // counter +string Boardname; +string fileTop; +string fileBottom; + +void header(void) { + printf("This file was generated by %s %s, exported from:\n", filename(argv[0]), Version); + printf("%s at %s;\n", Boardname, t2string(time())); + printf("%s;\n\n", EAGLE_SIGNATURE); + printf("%%\n"); +} + + +real value (int v) { + return u2mm(v) ; +} + +void smdxy(int x, int y) { + printf("X%06.3f Y%06.3f mm\n", value(x), value(y) ); + return; +} + +void genfiles(string file) { + sort(c, index, tb, smdx, smdy, x, y); // sortiere top/bottom, groesse, coord. + + for (int n = 0; n < c; n++) { + if (tb[index[n]]) { + smdxy(x[index[n]], y[index[n]]); + } + else { + output(fileTop, "at") { + smdxy(x[index[n]], y[index[n]]); + } + } + } + } + +void trailer(void) { printf("end\n"); } + +// main + +if (board) { + board(B) { + Boardname = B.name; + + fileTop = dlgFileSave("Save SMD coordinate for Top side", filesetext(B.name, ".smt"), "*.smt"); + if (fileTop == "") exit(0); + + fileBottom = dlgFileSave("Save SMD coordinate for Bottom side", filesetext(B.name, ".smb"), "*.smb"); + if (fileBottom == "") exit(0); + + output(fileTop, "wt") { header(); printf("Top\n"); } + output(fileBottom, "wt") { header(); printf("Bottom\n"); + B.elements(E) { + E.package.contacts(C) { + if (C.smd) { + + // collect SMD-Pads + smdx[c] = C.smd.dx; + smdy[c] = C.smd.dy; + x[c] = C.smd.x; + y[c] = C.smd.y; + tb[c] = E.mirror; + c++; + } + } + } + + genfiles(B.name); + trailer(); + output(fileTop, "at") { trailer(); } + } + } +} + +else { + dlgMessageBox("\n Start this ULP in a Board \n"); + exit (0); +} diff --git a/trunk/ulp/snap-on-grid-sch.ulp b/trunk/ulp/snap-on-grid-sch.ulp new file mode 100644 index 00000000..711e7ccc --- /dev/null +++ b/trunk/ulp/snap-on-grid-sch.ulp @@ -0,0 +1,319 @@ +#usage "Snap objects in schematic to default grid\n" + "

    " + "Snaps symbols, junctions, nets and busses to the " + "given grid (default: 0.1 inch)." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +// English Description +string eHelp = "This EAGLE User Language Program can be used to " + "snap the symbols, the nets, and the busses of the current " + "schematic to default grid (0.1 Inch).

    " + "The first run snaps all the devices and all the net lines " + "that are connected to a pin to default grid. " + "The second run snaps the rest of the net lines that are " + "not tied to a pin directly (like bends and junctions)." + "This avoids that elements will be snapped more than once.

    " + " 1. with the device

    " + " 2. with the net lines

    " + " The end of the net tied to the pin can not be moved." + " Thus EAGLE would only move the free end of a net segment" + " again." + "The coordinates will be stored in an array and searched for" + "multiple occurences.

    " + "If devices do not snap to default grid, they are defined" + "offgrid in the libary (symbol) editor. In this case please" + "correct your library definition.

    " + "If it happens that net lines do not snap, they might be" + "connected to a pin (as mentioned above). Or there are" + "superimposed nets at this point. Use the SHOW command to" + "check this closely


    "; + +// * ---------------------------------------------------------- + +// Deutsche Anleitung: +string dHelp = "Dieses EAGLE ULP verschiebt Symbole, " + "Netz-Linien und Bus-Linien im aktuellen Schaltplan auf " + "das Default-Grid (0.1 Inch).

    " + "Der erste Durchlauf snapt die Devices (Symbole). " + "Dabei werden auch alle an Pins angeschlossenen Netzsegmente " + "automatisch gesnapt. Der zweite Durchlauf snapt nur " + "noch die Knickpunkte, Abzweigungen und Kreuzungen der " + "Netze. Andernfalls würden die Netz-Segmente durch die " + "Mehrfachinformation mehrmals verschoben werden.

    " + " 1. mit dem Device.

    " + " 2. mit dem Netz-Segment.

    " + " Das Segment-Ende, das an einem Pin kontaktiert ist, " + " kann nicht verschoben werden. So würde EAGLE nur das " + " freie Segment-Ende ein weiteres Mal verschieben. " + "Die Koordinaten werden zuerst in einer Tabelle gesammelt " + "und nach mehrfachem Vorkommen durchsucht." + "

    " + "Sollten Devices nicht auf das Default Grid gesnapt werden, " + "sind sie in der Library (Symbol) ausserhalb des Grids " + "definiert worden.

    " + "Sollten Netz-Elemente nicht verschoben werden, " + "sind sie - wie oben erwaehnt - an einem Pin angeschlossen, " + "oder an dieser Koordinate doppelt vorhanden. " + "In diesem Fall ueberpruefen Sie mit SHOW, ob es sich um " + "das gleiche Netz handelt.


    "; + + +string Version = "1.0.4"; + +int Grid = strtol(argv[2]); // default 100 Mil + +int pass = strtol(argv[3]) + 1; + +real snap(int n) // returns next grid point +{ + return round(u2mil(n) / Grid) * Grid; +} + +void setgridmil (void) +{ + printf("GRID mil finest;\n"); +} + +real onGrid(int g) +{ + return ((u2mil(g)/Grid) - round(u2mil(g)/Grid)) * Grid; + +} + +void move_w(int x, int y) +{ + printf("MOVE (%.4f %.4f)\n", u2mil(x), u2mil(y)); + printf("(%.4f %.4f);\n", snap(x), snap(y)); +} + +// main +if (!schematic) { + dlgMessageBox("This program can only work in the schematic editor.", "OK"); + exit (0); + } + +if (Grid == 0) { + Grid = 100; + int Result = dlgDialog("SNAP Elements on Grid") { + dlgHBoxLayout { + dlgLabel("&Grid"); + dlgIntEdit(Grid); + dlgLabel("mil"); + } + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("&Help") dlgMessageBox(eHelp, "OK"); + dlgStretch(1); + dlgPushButton("H&ilfe") dlgMessageBox(dHelp, "OK"); + dlgStretch(0); + } + dlgHBoxLayout { + dlgStretch(0); + dlgPushButton("+&OK") dlgAccept(); + dlgStretch(1); + dlgPushButton("-&Cancel") dlgReject(); + dlgStretch(0); + } + }; + if (!Result) exit(-1); + } + +schematic(S) { + string fileName; + fileName = filesetext(S.name, "_snap.scr"); + + int shift = 0; + + output(fileName) { + printf("# This file is generated by %s %s, exported from;\n", filename(argv[0]), Version); + printf("# %s at %s;\n", S.name, t2string(time())); + printf("# %s;\n\n", EAGLE_SIGNATURE); + setgridmil (); // *** switch grid to finest + int snapshift = 0; + + S.sheets(SH) { + printf("EDIT .S%d;\n", SH.number); + printf("Text '#Symbol snap\nDISPLAY NONE 94 -95 -96;\n"); + SH.parts(PA) { + PA.instances(S) { + + // *** check Grid + real xoff = onGrid(S.x); + real yoff = onGrid(S.y); + + if (xoff || yoff) { + move_w(S.x,S.y); + snapshift =1 ; // flag for non Wire-Snap + shift = 1; + } + } + } + + printf("Text '#Junction snap\nDISPLAY NONE 91;\n"); + SH.nets(N) { + N.segments(SEG) { + SEG.junctions(J) { + real xoff = onGrid(J.x); + real yoff = onGrid(J.y); + if (xoff || yoff) { + move_w(J.x,J.y); + snapshift =1 ; // flag for non Wire-Snap + shift = 1; + } + } + } + } + + // * zuerst die Devices und Junctions verschieben * + // * damit werden alle Wire die an Pins angeschlossen * + // * sind, auch gleich mitverschoben. * + // * Jeder weitere Durchlauf verschieb dann nur noch * + // * die Netzsegmente die immer noch nicht auf dem * + // * Default-Grid liegen * + + if (snapshift == 0) { + // *** check Net-Wire on Grid + // 2. snap all Wires + printf("Text '#Net snap\nDISPLAY NONE 91;\n"); + SH.nets(N) { + real x[], y[]; + int countw = 0; + N.segments(SEG) { + SEG.wires(W) { + int notfoundx = 1; + int notfoundy = 1; + int cnt = 0; + // * alle mehrfach vorhandenen Koordinaten ausfiltern + // * mehrere Segmentverbindungen muessen als + // * eine Koordinate behandelt werden, + // * um ein mehrfaches verschieben zu vermeiden + for (cnt = 0; cnt < countw; cnt ++) { + if (W.x1 == x[cnt] && W.y1 == y[cnt] ) { // 1. Segmentende + notfoundx = 0; + break; + } + } + for (cnt = 0; cnt < countw; cnt ++) { + if (W.x2 == x[cnt] && W.y2 == y[cnt] ) { // 2. Segmentende + notfoundy = 0; + break; + } + } + if (notfoundx) { + x[countw] =W.x1; + y[countw]= W.y1; + countw++; + real x1off = onGrid(W.x1); + real y1off = onGrid(W.y1); + + if (x1off || y1off) { + move_w(W.x1,W.y1); + shift = 1; + } + } + if (notfoundy) { + x[countw] =W.x2; + y[countw]= W.y2; + countw++; + real x2off = onGrid(W.x2); + real y2off = onGrid(W.y2); + + if (x2off || y2off) { + move_w(W.x2,W.y2); + shift = 1; + } + } + } + } + } + + // 2. snap all busses + printf("Text '#Bus snap\nDISPLAY NONE 92;\n"); + SH.busses(B) { + real x[], y[]; + int countw = 0; + B.segments(SEG) { + SEG.wires(W) { + int notfoundx = 1; + int notfoundy = 1; + int cnt = 0; + // * alle mehrfach vorhandenen Koordinaten ausfiltern + // * mehrere Segmentverbindungen muessen als + // * eine Koordinate behandelt werden, + // * um ein mehrfaches verschieben zu vermeiden + for (cnt = 0; cnt < countw; cnt ++) { + if (W.x1 == x[cnt] && W.y1 == y[cnt] ) { // 1. Segmentende + notfoundx = 0; + break; + } + } + for (cnt = 0; cnt < countw; cnt ++) { + if (W.x2 == x[cnt] && W.y2 == y[cnt] ) { // 2. Segmentende + notfoundy = 0; + break; + } + } + if (notfoundx) { + x[countw] =W.x1; + y[countw]= W.y1; + countw++; + real x1off = onGrid(W.x1); + real y1off = onGrid(W.y1); + + if (x1off || y1off) { + move_w(W.x1,W.y1); + shift = 1; + } + } + if (notfoundy) { + x[countw] =W.x2; + y[countw]= W.y2; + countw++; + real x2off = onGrid(W.x2); + real y2off = onGrid(W.y2); + + if (x2off || y2off) { + move_w(W.x2,W.y2); + shift = 1; + } + } + } + } + } + } + } + printf("GRID INCH;\n"); + printf("GRID 0.1;\n"); + printf("DISPLAY 91 92 94 95 96 -93;\n"); + } + string h = ""; + if (shift) { + sprintf(h, "run '%s' '%d' '%d' '%d';\n", argv[0], shift, Grid, pass); + + if (pass == 4) { + sprintf(h, "# nach 3 Durchlaeufen muessen alle Elemente gesnapt sein,\n" + "# ueberpruefen Sie den Schaltplan auf doppelt vorkommende,\n" + "# oder sich überlappende Net-Wires, bzw. Junctions\n" + "# in der untenstehenden Liste.\n"); + string text; + int nChars = fileread(text, fileName); + + dlgDialog(fileName) { + dlgTextView(h + text); + dlgHBoxLayout { + dlgPushButton("&OK") dlgAccept(); + dlgSpacing(300); + } + exit (-1); + }; + } + + exit ("script '" + fileName + "';" + h); // do it + } + int Result =(dlgMessageBox("Nothing to do

    " + S.name , "OK")); + if (Result) exit(0); + +} diff --git a/trunk/ulp/snap-pin-in-symbol.ulp b/trunk/ulp/snap-pin-in-symbol.ulp new file mode 100644 index 00000000..638050cb --- /dev/null +++ b/trunk/ulp/snap-pin-in-symbol.ulp @@ -0,0 +1,38 @@ +#usage "snap pins in symbol to grid

    " + "Example: run snap-pin-in-symbol [100]" + "Author: librarian@cadsoft.de" + +string cmd; +real Grid = 100; // default 100 Mil +string s; + +real xoff, yoff; +if (argv[1]) Grid = strtod(argv[1]); + +real snap(int n) { // returns next grid point + return round(u2mil(n) / Grid) * Grid; +} + +int move = 0; +if (library) { + if (symbol) symbol(S) { + string name = S.name; + S.pins(P) { + xoff = snap(P.x) - u2mil(P.x); + yoff = snap(P.y) - u2mil(P.y); + if (xoff || yoff) { + move = 1; + sprintf( s, "MOVE (%.5f %.5f) (%.1f %.1f);\n", u2mil(P.x), u2mil(P.y), snap(P.x), snap(P.y)); + cmd += s; + } + } + if (move) { + if (dlgMessageBox(cmd, "OK", "Cancel") != 0) exit (-1);; + exit("GRID MIL FINEST;\n" + cmd + "GRID MIL 100 1 ON;"); + } + else dlgMessageBox("PINs in " + name + ".SYM on Grid", "OK"); + } + else dlgMessageBox("Start this ULP in a Symbol-Editor", "OK"); +} +else dlgMessageBox("Start this ULP in Library (Symbol)", "OK"); + diff --git a/trunk/ulp/source/drill.h b/trunk/ulp/source/drill.h new file mode 100644 index 00000000..9d31bb0f --- /dev/null +++ b/trunk/ulp/source/drill.h @@ -0,0 +1,193 @@ +// -*- Mode: Eagle -*- +// +// Drill routines. +// + +#include "nonvolatile.h" + +string TOOL_FLD = "tool"; +string DRILL_FLD = "drill_size"; +string MIN_FLD = "minimum"; +string MAX_FLD = "maximum"; +string LENGTH_FLD = "length"; +char DRILL_SEP = '\t'; +string g_rack[]; +int g_num_drills; +int g_drill_sub_cnt[]; +real g_mins[]; +real g_maxs[]; + +int m_shut_up; +int m_last_match; +int m_have_rack = false; +string m_rack_file_name = "?"; + +if (get_nv_param("drill_shut_up", "NO", NO) == "YES") { + m_shut_up = YES; +} +else { + m_shut_up = NO; +} + +void message(string msg) +{ + if(m_shut_up) + return; + + msg = "Rack file: " + elided_path(m_rack_file_name, 30) + ":\n" + msg; + + switch(dlgMessageBox(msg, "Ok", "Shut up already", "Never ask again")) { + case 1: + m_shut_up = 1; + break; + case 2: + m_shut_up = 1; + set_nv_param("drill_shut_up", "YES"); + break; + } +} + +void read_rack_file(string drill_file) +{ + string VALID_DRILL_CHARS = "#+-.0123456789imntT\t"; + + string drill_raw[]; + int num_raw_drills; + string key; + string temp; + string drill_text; + int i; + + /* + * Remove comment lines from the rack file. + * + */ + g_num_drills = 0; + num_raw_drills = fileread(drill_raw, drill_file); + string first_char; + for (i=0; i 0 && DRILL_SIZES_INCHES[i] > inches) { + i--; + } + return i; +} diff --git a/trunk/ulp/source/filecopy.h b/trunk/ulp/source/filecopy.h new file mode 100644 index 00000000..7fe5b47b --- /dev/null +++ b/trunk/ulp/source/filecopy.h @@ -0,0 +1,26 @@ +// -*- Mode: Eagle -*- +void filecopy(string from_name, string to_name) +{ + string contents[]; + int num_lines; + + fileerror(); + num_lines = fileread(contents, from_name); + + if(fileerror()) { + dlgMessageBox("Error: Could not open " + from_name + + " for copying to " + to_name); + exit(1); + } + + output(to_name) { + for (int i=0; i < num_lines; i++) { + printf("%s\n", contents[i]); + } + } + if(fileerror()) { + dlgMessageBox("Error: Could not write the contents of " + + from_name + " to " + to_name); + exit(1); + } +} diff --git a/trunk/ulp/source/filename_subs.h b/trunk/ulp/source/filename_subs.h new file mode 100644 index 00000000..5e3906f1 --- /dev/null +++ b/trunk/ulp/source/filename_subs.h @@ -0,0 +1,161 @@ +// -*- Mode: Eagle -*- + +string FILENAME_SUBS; + +// +// Values to substitute in file names. +// +string setup_subs_side_phase(int l_side, int l_phase) +{ + string side; + string file; + string tmp; + int i; + + side = (l_side == TOP) ? TOP_FILE_NAME : BOT_FILE_NAME; + switch (l_phase) { + case PH_TOP_OUT_GEN: + case PH_TOP_OUT_WRITE: + case PH_BOTTOM_OUT_GEN: + case PH_BOTTOM_OUT_WRITE: + file = ETCH_FILE_NAME; + break; + case PH_TOP_DRILL: + case PH_BOTTOM_DRILL: + file = DRILL_FILE_NAME; + break; + case PH_MILL: + file = MILL_FILE_NAME; + break; + case PH_TEXT: + file = TEXT_FILE_NAME; + break; + default: + file = "invalid"; + } +// dlgMessageBox("file = " + ETCH_FILE_NAME); +// file = PHASE_NAME[l_phase]; + FILENAME_SUBS = ""; + i = 0; + while (path_epf[i] != "") { + sprintf(tmp, "$PROJECT_PATH[%d]", i); + FILENAME_SUBS += key_value_record(tmp, remove_last_slash(path_epf[i])); + sprintf(tmp, "$ULP_PATH[%d]", i); + FILENAME_SUBS += key_value_record(tmp, remove_last_slash(path_ulp[i])); + sprintf(tmp, "$CAM_PATH[%d]", i); + FILENAME_SUBS += key_value_record(tmp, remove_last_slash(path_cam[i])); + i++; + } + FILENAME_SUBS += key_value_record("$PATH", remove_last_slash(g_path)) + + key_value_record("$BOARD_PATH", remove_last_slash(filedir(BOARD_NAME))) + + key_value_record("$BOARD_NAME", filesetext(filename(BOARD_NAME), "")) + + key_value_record("$BOARD_FILE_PATH", filesetext(BOARD_NAME, "")) + + key_value_record("$SIDE", side) + + key_value_record("$FILE", file) + + key_value_record("$EXT", DEFAULT_EXTENSION) + ; + return FILENAME_SUBS; +} + +string filename_subs_help() +{ + return "

    Filename Variables

    " + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
    $PROJECT_PATH[n]Project paths as set in the Control Panel. " + "n begins at zero for the first entry.
    $ULP_PATH[n]As above, but for User Language Program paths.
    $CAM_PATH[n]As above, but for CAM Jobs paths.
    $BOARD_PATHPath to the board file.
    $BOARD_NAMEThe file name of the board with the extension (.brd) removed.
    $BOARD_FILE_PATHPath and name of the board with the extension (.brd) removed.
    $SIDESide of the board being generated. By default 'bot' or 'top'.
    $FILEFile of the board being generated. By default 'etch', 'drill' and 'mill' or 'text'.
    $EXTThe extension you set under the GCode Options tab.
    " + "Paths do not end with a /.
    " + "Example:
    " + "Assume the board we are working on is:
    " + "/home/john/eagle/my_stuff/enabtmr.brd
    " + "and we use these settings:
    " + "Filename Base: $BOARD_PATH/$BOARD_NAME
    " + "Top (Component) Side Files" + "" + "" + "" + "" + "" + "
    Etching: .$SIDE.$FILE.$EXT
    Drill: .$SIDE.$FILE.$EXT
    Mill: /mill_jobs/$BOARD_NAME.$SIDE.$FILE.tap
    Text: $SIDE.$FILE.tap
    " + "Would create the following filenames:
    " + "" + "" + "" + "" + "" + "
    Etching: /home/john/eagle/my_stuff/enabtmr.top.etch.nc
    Drill: /home/john/eagle/my_stuff/enabtmr.top.drill.nc
    Mill: /home/john/eagle/my_stuff/enabtmr/mill_jobs/enabtmr.top.mill.tap
    Drill: /home/john/eagle/my_stuff/enabtmr.top.text.nc
    " + ; +} + +string setup_subs() +{ + return setup_subs_side_phase(g_side, g_phase); +} + +string sub_side_phase(string s, int side, int phase) +{ + if (phase == 0) dlgMessageBox("phase == 0"); + setup_subs_side_phase(side, phase); + return substitute(s, FILENAME_SUBS); +} + +string get_filename() +{ + string name; + + setup_subs(); + + if (g_side == TOP) { + switch(g_phase) { + case PH_TOP_OUT_GEN: + case PH_TOP_OUT_WRITE: + name = FILENAME_TOP_ETCH_FILE; + break; + case PH_TOP_DRILL: + name = FILENAME_TOP_DRILL_FILE; + break; + case PH_MILL: + name = FILENAME_TOP_MILL_FILE; + break; + case PH_TEXT: + name = FILENAME_TOP_TEXT_FILE; + break; + } + } + else { + switch(g_phase) { + case PH_BOTTOM_OUT_GEN: + case PH_BOTTOM_OUT_WRITE: + name = FILENAME_BOT_ETCH_FILE; + break; + case PH_BOTTOM_DRILL: + name = FILENAME_BOT_DRILL_FILE; + break; + case PH_MILL: + name = FILENAME_BOT_MILL_FILE; + break; + case PH_TEXT: + name = FILENAME_BOT_TEXT_FILE; + break; + } + } + return substitute(FILENAME_BASE + name, FILENAME_SUBS); +} + +setup_subs(); + +string sub_path(string name) +{ + return substitute(name, FILENAME_SUBS); +} diff --git a/trunk/ulp/source/library.h b/trunk/ulp/source/library.h new file mode 100644 index 00000000..9d720103 --- /dev/null +++ b/trunk/ulp/source/library.h @@ -0,0 +1,210 @@ +// -*- Mode: Eagle -*- +// +// Convert n, an Eagle internal measure, to the user's selected +// unit of measure. +// +// Params: +// n An Eagle internal number. +// Return: +// n converted to the user's unit of measure. +// + +//real X_OFFSET = 1.0; +//real Y_OFFSET = 1.0; + +real units(int n) +{ + switch (OUTPUT_UNITS) { + case U_MICRONS: + return u2mic(n); + break; + case U_MILLIMETERS: + return u2mm(n); + break; + case U_MILS: + return u2mil(n); + break; + case U_INCHES: + return u2inch(n); + break; + } + + return u2inch(n); +} + +// +// Returns the mode command (i.e. G20) to set the machine to +// the user's selected unit of measure. +// +// Params: +// none +// Return: +// A string containing the mode command. +// +string get_mode() { + string mode; + + switch (OUTPUT_UNITS) { + case U_MICRONS: + mode= MICRON_MODE; + break; + case U_MILLIMETERS: + if (NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS) { + mode = METRIC_MODE_COMMENT; + } + mode += METRIC_MODE; + break; + case U_MILS: + mode = MIL_MODE; + break; + case U_INCHES: + if (NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS) { + mode = INCH_MODE_COMMENT; + } + mode += INCH_MODE; + break; + default: + mode = "M02 (Unknown mode in get_mode)"; + } + + return mode; +} + +// +// Scale X to positive or negative depending on the side +// of the board. Negative for bottom, positive for top. +// +// Params: +// x X coordinate. +// Return: +// x scaled for top (+) or bottom (-). +// +real scale_x(int x) +{ + real scaled; + + scaled = units(x) + X_OFFSET; + if (g_side == BOTTOM) { + if (FLIP_BOARD_IN_Y == NO && MIRROR_BOTTOM == NO) { + scaled = scaled * -1; + } + } + return scaled; +} + +// +// Return y converted to user's units. +// +// Params: +// y Y coordinate. +// Return: +// Y converted to user's units. +// +real scale_y(int y) +{ + real scaled; + + scaled = units(y) + Y_OFFSET; + if (g_side == BOTTOM) { + if (FLIP_BOARD_IN_Y == YES && MIRROR_BOTTOM == NO) { + scaled = scaled * -1; + } + } + return scaled; +} + +// +// Converts string to long, ignoring leading 0s. +// +// Params: +// s A numeric string. +// Returns: +// s converted to a long. +// +int my_strtol(string s) +{ + string result; + int i; + + i=0; + while (s[i] == '0') + i++; + result = strsub(s, i); + return strtol(result); +} + + + +// +// Show a dialog with a message and details. +// +// Params: +// Message General message. +// Details Details of the message. +// Return: none +// +void Message(string msg) +{ + dlgMessageBox(msg); +} + +// +// Show a dialog with an error message and details. +// +// Params: +// Message General error message. +// Details Details of the error. +// Return: none +// +void Error(string msg, string details) +{ + Message(usage + "
    Error: " + msg + "

    " + details); +} + +// +// Show a dialog with an error message and details, +// then exit the program. +// +// Params: +// Message General error message. +// Details Details of the error. +// Return: none +// +void Fatal(string msg, string details) +{ + // todo change to call Error + Error(msg, details); + exit(1); +} + + +int file_exists(string file) +{ + string files[]; + int num_files = fileglob(files, file); + +/* string s; + + for (int i=0; i < num_files; i++) + s +=files[i] + "\n"; + Message(s); +*/ + return (num_files > 0); +} + +enum { + OS_INVALID = 0, + OS_UNKNOWN, + OS_MACOSX, + OS_LINUX, + OS_WINDOWS +} + +int get_os() +{ + if (file_exists("/Applications/*")) + return OS_MACOSX; + if (file_exists("/home/*")) + return OS_LINUX; + return OS_WINDOWS; +} diff --git a/trunk/ulp/source/library.ulp b/trunk/ulp/source/library.ulp new file mode 100644 index 00000000..46ffb9d1 --- /dev/null +++ b/trunk/ulp/source/library.ulp @@ -0,0 +1,36 @@ +// +// Tests for library.h . +// + +#include "math.h" +#include "pcb-defaults.h" +#include "library.h" + +int test_units[] = { + U_INCHES, + U_MICRONS, + U_MILLIMETERS, + U_MILS +}; + +int in_nums[] = { + 5000, + 125, + 9950, + 505 +}; + +real out_nums[] = { +}; + +int i; + +string msg; + +for (i=0; i < 3; i++) { + OUTPUT_UNITS = test_units[i]; + if (conv(in_nums[i]) != out_nums[i]) { + sprintf(msg, "Units %d in: %6d out: %7.4f", OUTPUT_UNITS, in_nums[i], out_nums[i]); + Error("test failed", msg); + } +} diff --git a/trunk/ulp/source/math.h b/trunk/ulp/source/math.h new file mode 100644 index 00000000..a2344fc6 --- /dev/null +++ b/trunk/ulp/source/math.h @@ -0,0 +1,179 @@ +// -*- Mode: Eagle -*- +/* + * + * Math utilities. + * + * Copyright 2007 - 2013 by John Johnson Software, LLC. + * All Rights Reserved. + * + */ + +//#include "source/drill_sizes.h" +#include "drill_sizes.h" + +real MM_PER_INCH = 25.4; +int MICRONS_PER_MM = 1000; +int MILS_PER_INCH = 1000; + +// +// Thanks EAGLE! No one expects an internal units change. :-) +// +int INTERNAL_SCALAR = 10000; +if (EAGLE_VERSION >= 6) { + INTERNAL_SCALAR = 320000; +} + +int INTERNALS_PER_MICRON = (INTERNAL_SCALAR / 1000); +int INTERNALS_PER_MM = INTERNAL_SCALAR; +int INTERNALS_PER_MIL = MM_PER_INCH * (INTERNAL_SCALAR / 1000); +int INTERNALS_PER_INCH = MM_PER_INCH * INTERNAL_SCALAR; + +/* + * Return the suffix unit of measure from a string. + */ +string get_units(string s) +{ + int len; + string units; + + len = strlen(s); + units = strsub(s, len - 2, 2); + // special handling for wire size drill numbers + if (strsub(units, 1, 1) == "#") + units = "#"; + return units; +} + +//enum { U_INVALID, U_MICRONS, U_MILLIMETERS, U_MILS, U_INCHES }; + +real convert(real value, int old_units, int new_units) +{ + real temp; + real result; + + // Convert current value to 10ths of microns. + switch(old_units) { + case U_MICRONS: + temp = value * INTERNALS_PER_MICRON; + break; + case U_MILLIMETERS: + temp = value * INTERNALS_PER_MM; + break; + case U_MILS: + temp = value * INTERNALS_PER_MIL; + break; + case U_INCHES: + temp = value * INTERNALS_PER_INCH; + break; + case U_INTERNALS: + temp = value; + break; + default: + dlgMessageBox(":Invalid value for old_units in convert()"); + exit(0); + } + + // Convert temp value to the new unit of measure. + switch(new_units) { + case U_MICRONS: + result = temp / INTERNALS_PER_MICRON; + break; + case U_MILLIMETERS: + result = temp / INTERNALS_PER_MM; + break; + case U_MILS: + result = temp / INTERNALS_PER_MIL; + break; + case U_INCHES: + result = temp / INTERNALS_PER_INCH; + break; + case U_INTERNALS: + result = temp; + break; + default: + dlgMessageBox(":Invalid value for new_units (" + int_to_string(new_units) + ") in convert()"); + exit(0); + } + + return result; +} + + +/* + * Convert a string with a number and a unit-of-measure suffix into + * Eagle internal units (microns). + * + * 0.032in 0.032 inches + * 62ml 62 mils, 0.062 inches + * 0.43mm 0.43 millimeters + * 1500mc 1500 microns, 1.500 millimeters + * 60# 60 wire gage drill (0.040" or 1.016mm) + * 0.12 0.12 inches + * 0.60 0.60 millimeters + * 43 43 wire gage drill + * + */ +int conv_to_units(string s) +{ + int val; + string units; + real num; + real mm; + string str; + + s = strlwr(s); + + units = get_units(s); + num = strtod(s); + + if(units == "mm") + val = convert(num, U_MILLIMETERS, U_INTERNALS); + else if (units == "in") + val = convert(num, U_INCHES, U_INTERNALS); + else if (units == "ml") + val = convert(num, U_MILS, U_INTERNALS); + else if (units == "mc") + val = num; + else if (units == "#") { + val = convert(get_drill_size_inches(num), U_INCHES, U_INTERNALS); + } + else { + if (num <= 0.25) + val = convert(num, U_INCHES, U_INTERNALS); + else if (num <= 6) + val = convert(num, U_MILLIMETERS, U_INTERNALS); + else + val = convert(get_drill_size_inches(num), U_INCHES, U_INTERNALS); + } + + return val; +} + +/* + * Determine if an integer value is within a range (inclusive). + */ +int in_range_int(int val, int min_val, int max_val) +{ + return((val >= min_val) && (val <= max_val)); +} + +int close(real val_a, real val_b) +{ + return(abs(val_a - val_b) < EPSILON); +} + +int close2(real xa, real xb, real ya, real yb) +{ + if (close(xa, xb) && close(ya, yb)) { + return true; + } + return false; +} + +int close3(real xa, real xb, real ya, real yb, real za, real zb) +{ + if (close(xa, xb) && close(ya, yb) && close(za, zb)) { + return true; + } + return false; +} diff --git a/trunk/ulp/source/math.ulp b/trunk/ulp/source/math.ulp new file mode 100644 index 00000000..d2b20656 --- /dev/null +++ b/trunk/ulp/source/math.ulp @@ -0,0 +1,86 @@ +/* + * math.h tester. + */ + +#include "pcb-gcode.h" +#include "settings/pcb-machine.h" +#include "math.h" + +string test_strings[] = { + "0.100in", + "0.5mm", + "30#", + ".05", + ".7", + "5#", + "" +}; + +int answers_mu[] = { + 25400, + 5000, +// if you get far enough away, you'll be on your way home. Tom Waits + 32766, + 12700, + 7000, + 52324 +}; + +int i; +string str; +int val; +int failed = 0; + +for (i = 0; test_strings[i] != ""; i++) { + val = conv_to_units(test_strings[i]); + if ( val != answers_mu[i]) { + sprintf(str, "!Incorrect! String: '%s' converted to %dmu", test_strings[i], val); + dlgMessageBox(str); + failed = 1; + } +} + +real r_val; + +r_val = convert(0.100, U_INCHES, U_MILLIMETERS); +if (r_val != 2.54) { + sprintf(str, "!Incorrect! 0.1inches converted to %fmm", r_val); + dlgMessageBox(str); + failed = 1; +} + +r_val = convert(2.54, U_MILLIMETERS, U_INCHES); +if (r_val != 0.100) { + sprintf(str, "!Incorrect! 2.54mm converted to %fin", r_val); + dlgMessageBox(str); + failed = 1; +} +r_val = convert(0.100, U_INCHES, U_MICRONS); +if (r_val != 2540) { + sprintf(str, "!Incorrect! 0.1inches converted to %fmicrons", r_val); + dlgMessageBox(str); + failed = 1; +} +r_val = convert(16510, U_MICRONS, U_INCHES); +if (r_val != 0.65) { + sprintf(str, "!Incorrect! 16510microns converted to %finches", r_val); + dlgMessageBox(str); + failed = 1; +} +r_val = convert(0.735, U_INCHES, U_MILS); +if (r_val != 735) { + sprintf(str, "!Incorrect! 0.1inches converted to %fmils", r_val); + dlgMessageBox(str); + failed = 1; +} +r_val = convert(987, U_MILS, U_INCHES); +if (r_val != 0.987) { + sprintf(str, "!Incorrect! 987mils converted to %finches", r_val); + dlgMessageBox(str); + failed = 1; +} + + +if (failed == 0) { + dlgMessageBox("Passed"); +} diff --git a/trunk/ulp/source/nonvolatile.h b/trunk/ulp/source/nonvolatile.h new file mode 100644 index 00000000..0e93336e --- /dev/null +++ b/trunk/ulp/source/nonvolatile.h @@ -0,0 +1,102 @@ +// -*- Mode: Eagle -*- +/* nonvolatile.h + * Copyright 2004-2009 by John Johnson Software, LLC. + * See readme.html for copyright information. + */ + +string STORAGE_NAME = g_path + "/storage.nv"; +int NAME_FIELD = 0; +int VALUE_FIELD = 1; +char SEPARATOR = '='; +string m_params[]; +string empty[]; + +if (filetime(STORAGE_NAME) == 0) { + output(STORAGE_NAME, "wt") { + printf("created%c%s\s", SEPARATOR, t2string(time())); + } +} + +void empty_m_params() +{ + int i; + + while (m_params[i] != "") + m_params[i++] = ""; +} + +int read_nv_file(int can_abort) +{ + int num_params; + + empty_m_params(); + fileerror(); + num_params = fileread(m_params, STORAGE_NAME); + if(fileerror()) { + if(can_abort) { + exit(1); + } + else { + return 0; + } + } +/* string t; + sprintf(t, "there are %d params", num_params); + dlgMessageBox(t); + */ return num_params; +} + +string get_nv_param(string name, string def, int can_abort) +{ + string value; + + read_nv_file(can_abort); + + value = lookup(m_params, name, VALUE_FIELD, SEPARATOR); + if (value == "") { + return def; + } + return value; +} + +void set_nv_param(string name, string value) +{ + int num_params; + int i; + string record[]; + + num_params = read_nv_file(0); + if (lookup(m_params, name, VALUE_FIELD, SEPARATOR) == "") { + m_params[num_params] = name + SEPARATOR + value; + num_params++; + } + else { + for (i=0; i < num_params; i++) { + strsplit(record, m_params[i], SEPARATOR); + if (record[NAME_FIELD] == name) { + record[VALUE_FIELD] = value; + m_params[i] = record[NAME_FIELD] + SEPARATOR + record[VALUE_FIELD]; + break; + } + } + } + output(STORAGE_NAME, "wt") { + for (i = 0; i < num_params; i++) { + printf("%s\n", m_params[i]); + } + } +} + +void set_real_nv_param(string name, real value) +{ + string str; + sprintf(str, "%f", value); + set_nv_param(name, str); +} + +real get_real_nv_param(string name) +{ + string str; + str = get_nv_param(name, "0.000", YES); + return strtod(str); +} diff --git a/trunk/ulp/source/pcb-file-utils.h b/trunk/ulp/source/pcb-file-utils.h new file mode 100644 index 00000000..c3a66c22 --- /dev/null +++ b/trunk/ulp/source/pcb-file-utils.h @@ -0,0 +1,463 @@ +// -*- Mode: Eagle -*- + +int m_line_number; +int LINE_NUMBER_INCREMENT = 10; +string g_preview; + +void eol() +{ + printf(EOL); + m_line_number += LINE_NUMBER_INCREMENT; +} + +int out(string s) +{ + int old_line_num; + string lines[]; + int num; + int i; + string line; + + old_line_num = m_line_number; + + num = strsplit(lines, s, '\n'); + for (i = 0; i < num; i++) { + line = lines[i]; + if (strlen(line) > 0 && line != "\n" && line != "EOL") { + if (USE_LINE_NUMBERS) { + printf(LINE_NUMBER_FORMAT, m_line_number); + } + printf(line); + if (i < num - 1 || rightstr(s,1) == "\n") { + printf(EOL); + } + m_line_number = m_line_number + LINE_NUMBER_INCREMENT; + } + } + return old_line_num; +} + +// +// Variables used to track the machine's current position and eliminate +// moves to the same coordinates. +// +real cur_x = -999.999; +real cur_y = -999.999; +real cur_z = -999.999; + +void xy(real x, real y) +{ + if (close(x, cur_x) && close(y, cur_y)) { + return; + } + + if (COMPACT_GCODE == YES) { + if (! close(x, cur_x) && ! close(y, cur_y)) { + out(frr(MOVE_XY, x, y) + EOL); + cur_x = x; + cur_y = y; + return; + } + if (! close(x, cur_x)) { + out(fr(MOVE_X, x) + EOL); + cur_x = x; + cur_y = y; + return; + } + if (! close(y, cur_y)) { + out(fr(MOVE_Y, y) + EOL); + cur_y = y; + return; + } + } + if (! close(x, cur_x) || ! close(y, cur_y)) { + out(frr(MOVE_XY, x, y) + EOL); + cur_x = x; + cur_y = y; + } +} + +// +// Output Feed commands. +// +void rate(real f) +{ + out(fr(FR_FORMAT, f)); +} + +void fx(real x) +{ + if (! close(x, cur_x)) { + out(fr(FEED_MOVE_X, x) + EOL); + cur_x = x; + } +} + +void fy(real y) +{ + if (! close(y, cur_y)) { + out(fr(FEED_MOVE_Y, y) + EOL); + cur_y = y; + } +} + +void fz(real z) +{ + if (! close(z, cur_z)) { + out(fr(FEED_MOVE_Z, z) + EOL); + cur_z = z; + } +} + +// Since the next move may depend on the Z rate having been set +// in this routine, it just outputs the move as usual. +void fzr(real z, real f) +{ + out( frr(FEED_MOVE_Z_WITH_RATE, z, f) + EOL); + cur_z = z; +} + +void fxy(real x, real y) +{ + if (! close(x, cur_x) || ! close(y, cur_y)) { + out( frr(FEED_MOVE_XY, x, y) + EOL); + cur_x = x; + cur_y = y; + } +} + +// Since the next move may depend on the XY rate having been set +// in this routine, it just outputs the move as usual. +void fxyr(real x, real y, real f) +{ + out( frrr(FEED_MOVE_XY_WITH_RATE, x, y, f) + EOL); +} + +void fxyz(real x, real y, real z) +{ + if (! close(x, cur_x) || ! close(y, cur_y) || ! close(z, cur_z)) { + out(frrr(FEED_MOVE_XYZ, x, y, z) + EOL); + cur_x = x; + cur_y = y; + cur_z = z; + } +} + +// +// Output Rapid commands. +// +void rx(real x) +{ + if (! close(x, cur_x)) { + out(fr(RAPID_MOVE_X, x) + EOL); + cur_x = x; + } +} + +void ry(real y) +{ + if (! close(y, cur_y)) { + out(fr(RAPID_MOVE_Y, y) + EOL); + cur_y = y; + } +} + +void rz(real z) +{ + if (! close(z, cur_z)) { + out(fr(RAPID_MOVE_Z, z) + EOL); + cur_z = z; + } +} + +void rxy(real x, real y) +{ + if (! close(x, cur_x) || ! close(y, cur_y)) { + out( frr(RAPID_MOVE_XY, x, y) + EOL); + cur_x = x; + cur_y = y; + } +} + +void rxyz(real x, real y, real z) +{ + if (! close(x, cur_x) || ! close(y, cur_y) || ! close(z, cur_z)) { + out(frrr(RAPID_MOVE_XYZ, x, y, z) + EOL); + cur_x = x; + cur_y = y; + cur_z = z; + } +} + +void comm(string str) +{ + if (strlen(str) > 0) { + out(COMMENT_BEGIN + str + COMMENT_END + EOL); + } +} + +void output_file_heading() +{ + if (NC_FILE_COMMENT_FROM_BOARD) { + comm(elided_path(argv[PROGRAM_NAME_ARG], 30)); + comm("Copyright 2005 - 2012 by John Johnson"); + comm("See readme.txt for licensing terms."); + + board(B) { + comm("This file generated from the board:"); + comm(elided_path(B.name, 30)); + } + } + + if (NC_FILE_COMMENT_FROM_BOARD || NC_FILE_COMMENT_DATE || + NC_FILE_COMMENT_MACHINE_SETTINGS || NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS || + g_debug_flag) { + comm("Current profile is " + elided_path(CURRENT_PROFILE[FILE_NAME], 30)); + } + if (NC_FILE_COMMENT_DATE) { + comm("This file generated " + t2string(time())); + } + + if (NC_FILE_COMMENT_MACHINE_SETTINGS) { + comm("Settings from pcb-machine.h"); + comm(" Tool Size"); + comm(fr(FORMAT, g_width)); + comm("Z Axis Settings"); + comm(" High Up Down Drill"); + comm(fr(FORMAT, DEFAULT_Z_HIGH) + "\t" + + fr(FORMAT, DEFAULT_Z_UP) + "\t" + + fr(FORMAT, DEFAULT_Z_DOWN) + "\t" + + fr(FORMAT, DRILL_DEPTH)); + comm(fr("spindle on time = %6.4f", SPINDLE_ON_TIME)); + comm(fr("milling depth = %6.4f", MILLING_DEPTH)); + comm(fr("text depth = %6.4f", TEXT_DEPTH)); + comm(frrr("tool change at " + FORMAT + FORMAT + FORMAT, + TOOL_CHANGE_POS_X, TOOL_CHANGE_POS_Y, TOOL_CHANGE_POS_Z)); + comm("feed rate xy = " + fr(FR_FORMAT, FEED_RATE)); + comm("feed rate z = " + fr(FR_FORMAT, FEED_RATE_Z)); + } + + if (NC_FILE_COMMENT_PCB_DEFAULTS_SETTINGS) { + comm("Settings from pcb-defaults.h"); + comm(fr("isolate min = %6.4f", ISO_MIN)); + comm(fr("isolate max = %6.4f", ISO_MAX)); + comm(fr("isolate step = %6.4f", ISO_STEP)); + string tt; + sprintf(tt, "Generated %s%s%s%s%s%s", + (GENERATE_TOP_OUTLINES) ? "top outlines, " : "", + (GENERATE_TOP_DRILL) ? "top drill, " : "", + (GENERATE_TOP_FILL) ? "top fill, " : "", + (GENERATE_BOTTOM_OUTLINES) ? "bottom outlines, " : "", + (GENERATE_BOTTOM_DRILL) ? "bottom drill, " : "", + (GENERATE_BOTTOM_FILL) ? "bottom fill" : "" + ); + comm(tt); + comm("Unit of measure: " + UNIT_OF_MEASURE); + } +} + +// +// Writes the header for the output file. +// +// Params: +// none +// Returns: +// none +// +void begin_gcode(void) +{ + out(get_mode()); + + out(ABSOLUTE_MODE); + rxy(X_HOME, Y_HOME); + out(fr(SPINDLE_ON, SPINDLE_ON_TIME)); +} + +// +// Write end of file commands. +// +// Params: +// none +// Return: +// none +// +void end_gcode(void) +{ + rz(DEFAULT_Z_HIGH); + out(SPINDLE_OFF); + out(END_PROGRAM); +} + +// Kinds (outline, drill, etc.) +void output_kind_begin() +{ + if (USER_GCODE == NO) + return; + + switch (g_phase) { + case PH_TOP_OUT_WRITE: + case PH_BOTTOM_OUT_WRITE: + out(OUTLINE_BEGIN[ALL]); + out(OUTLINE_BEGIN[g_side]); + break; + + case PH_TOP_DRILL: + case PH_BOTTOM_DRILL: + out(DRILL_BEGIN[ALL]); + out(DRILL_BEGIN[g_side]); + break; + + case PH_TOP_FILL_WRITE: + case PH_BOTTOM_FILL_WRITE: + out(FILL_BEGIN[ALL]); + out(FILL_BEGIN[g_side]); + break; + + case PH_MILL: + out(MILL_BEGIN[ALL]); + out(MILL_BEGIN[g_side]); + break; + default: + dlgMessageBox("!Unknown g_phase " + int_to_string(g_phase) + + " in output_kind_begin()"); + } +} + +void output_between_outline_passes() +{ + if (USER_GCODE) { + out(OUTLINE_BETWEEN[ALL]); + out(OUTLINE_BETWEEN[g_side]); + } +} + +void output_kind_end() +{ + if (USER_GCODE == NO) + return; + + switch (g_phase) { + case PH_TOP_OUT_WRITE: + case PH_BOTTOM_OUT_WRITE: + out(OUTLINE_END[g_side]); + out(OUTLINE_END[ALL]); + break; + + case PH_TOP_DRILL: + case PH_BOTTOM_DRILL: + out(DRILL_END[g_side]); + out(DRILL_END[ALL]); + break; + + case PH_TOP_FILL_WRITE: + case PH_BOTTOM_FILL_WRITE: + out(FILL_END[g_side]); + out(FILL_END[ALL]); + break; + + case PH_MILL: + out(MILL_END[g_side]); + out(MILL_END[ALL]); + break; + default: + dlgMessageBox("!Unknown g_phase " + int_to_string(g_phase) + + " in output_kind_end()"); + } +} + +// Tool changing +void output_tool_change_begin() +{ + if (USER_GCODE) { + out(TOOL_CHANGE_BEGIN[ALL]); + out(TOOL_CHANGE_BEGIN[g_side]); + } +} + +void output_tool_changed() +{ + if (USER_GCODE) { + out(TOOL_CHANGED[g_side]); + out(TOOL_CHANGED[ALL]); + } +} + +void output_tool_zero_begin() +{ + if (USER_GCODE) { + out(TOOL_ZERO_BEGIN[ALL]); + out(TOOL_ZERO_BEGIN[g_side]); + } +} + +void output_tool_zero_end() +{ + if (USER_GCODE) { + out(TOOL_ZERO_END[g_side]); + out(TOOL_ZERO_END[ALL]); + } +} + +void output_tool_change_end() +{ + if (USER_GCODE) { + out(TOOL_CHANGE_END[g_side]); + out(TOOL_CHANGE_END[ALL]); + } +} + +// +// Print file beginning headers and user-codes. +// +void output_file_preamble() +{ + output_file_heading(); + + if (USER_GCODE) { + out(FILE_BEGIN[ALL]); + out(FILE_BEGIN[g_side]); + output_kind_begin(); + } +} + +// +// Print file closing text and user-codes. +// +void output_file_postamble() +{ + if (USER_GCODE) { + output_kind_end(); + out(FILE_END[g_side]); + out(FILE_END[ALL]); + } +} + +void output_drill_first_hole(real drill_x, real drill_y, real depth) +{ + string tt; + + if (SIMPLE_DRILL_CODE) { + rxy(drill_x, drill_y); + fzr(depth, FEED_RATE_Z); + rz(DEFAULT_Z_UP); + } + else { + //"G82 X%fY%f Z%f F10.0 R0.1 #250\n", + sprintf(tt, DRILL_FIRST_HOLE, drill_x, drill_y, + depth, FEED_RATE_Z, DEFAULT_Z_UP, + DRILL_DWELL); + out(tt); + } +} + +void output_drill_hole(real drill_x, real drill_y, real depth) +{ + if (SIMPLE_DRILL_CODE) { + rxy(drill_x, drill_y); + fzr(depth, FEED_RATE_Z); + rz(DEFAULT_Z_UP); + } + else { + out(frr(DRILL_HOLE, drill_x, drill_y)); + } +} diff --git a/trunk/ulp/source/pcb-gcode-menu.scr b/trunk/ulp/source/pcb-gcode-menu.scr new file mode 100644 index 00000000..a50f6d46 --- /dev/null +++ b/trunk/ulp/source/pcb-gcode-menu.scr @@ -0,0 +1,34 @@ +# Command Menu Setup +# +# This is based on menu.scr that comes with Eagle. +# To display the command menu in the editor windows you have to +# activate the option 'Command texts' in the 'Options/User Interface' menu. +# + +MENU 'PCB-GCode : run pcb-gcode;' \ + 'PCB-GCode Setup : run pcb-gcode-setup;' \ + '---' \ + 'Grid {\ + Metric {\ + Fine : Grid mm 0.1; |\ + Coarse : Grid mm 1;\ + } | \ + Imperial {\ + Fine : Grid inch 0.001; |\ + Coarse : Grid inch 0.1;\ + } | \ + On : Grid On; | \ + Off : Grid Off;\ + }'\ + 'Display {\ + Top : Display None Top Pads Vias Dimension; |\ + Bottom : Display None Bottom Pads Vias Dimension; |\ + Placeplan {\ + Top : Display None tPlace Dimension; |\ + Bottom : Display None bPlace Dimension;\ + }\ + }'\ + '---'\ + 'Fit : Window Fit;'\ + 'Add' 'Delete' 'Move' ';' 'Edit' 'Quit'\ + ; diff --git a/trunk/ulp/source/pcb-gcode-prg.scr b/trunk/ulp/source/pcb-gcode-prg.scr new file mode 100644 index 00000000..0a299227 --- /dev/null +++ b/trunk/ulp/source/pcb-gcode-prg.scr @@ -0,0 +1,13 @@ +MENU \ + Gen_Top_Outlines \ +<> \ + Gen_Top_Fill \ + Write_Top_Fill \ + Gen_Bottom_Outlines \ + Write_Bottom_Outlines \ + Gen_Bottom_Fill \ + Write_Bottom_Fill \ + Top_Drills \ + Bottom_Drills \ + Milling \ +; diff --git a/trunk/ulp/source/pcb-gcode-stack.h b/trunk/ulp/source/pcb-gcode-stack.h new file mode 100644 index 00000000..20fac8fd --- /dev/null +++ b/trunk/ulp/source/pcb-gcode-stack.h @@ -0,0 +1,66 @@ +// -*- Mode: Eagle -*- +// +// Routines to implement a stack made from a string array. +// + +// +// Constants +// +int END_OF_STACK = -1; + +// +// Global variables +// +string g_stack[]; +int g_stack_ndx = 0; +int g_fwd_iter = 0; +int g_rev_iter = 0; + +// +// Module variables +// + +// +// Functions +// +void stack_init() { + g_stack_ndx = 0; +} + +string stack_pop() { + if (g_stack_ndx > 0) { + return g_stack[--g_stack_ndx]; + } + return "EMPTY-STACK"; +} + +void stack_push(string astring) { + g_stack[g_stack_ndx++] = astring; +} + +string stack_elem(int n) { + return g_stack[n]; +} + +int stack_count() { + return g_stack_ndx; +} + +void stack_sort() { + sort(stack_count(), g_stack); +} + +int stack_fwd_iter() { + g_fwd_iter = 0; + return g_fwd_iter; +} + +int stack_fwd_next() { + if (g_fwd_iter == END_OF_STACK) + return END_OF_STACK; + if (g_fwd_iter < (g_stack_ndx - 1)) { + return ++g_fwd_iter; + } + g_fwd_iter = END_OF_STACK; + return END_OF_STACK; +} diff --git a/trunk/ulp/source/pcb-gcode.h b/trunk/ulp/source/pcb-gcode.h new file mode 100644 index 00000000..0b1828d7 --- /dev/null +++ b/trunk/ulp/source/pcb-gcode.h @@ -0,0 +1,246 @@ +// -*- Mode: Eagle -*- +// +// Constants and enums for pcb-gcode.ulp. +// +// (Actually, they should be consts and typedefs, +// but Eagle doesn't support that.) +// + +// +// No users options here. +// + +#include "string.h" + +string RELEASE = "NOT SET"; +string REVISION = "000"; + +string g_path = "."; + +string BOARD_NAME; +board(B) { BOARD_NAME = B.name; } + +enum { + U_MICRONS = 0, + U_MILLIMETERS = 1, + U_MILS = 2, + U_INCHES = 3, + U_INTERNALS = 4 +}; + +enum { + OUTPUT_MICRONS = 0, + OUTPUT_MILLIMETERS = 1, + OUTPUT_MILS = 2, + OUTPUT_INCHES = 3, + OUTPUT_INTERNALS = 4 +}; + +enum { NO = 0, YES = 1 }; +enum { false = 0, true = 1 }; + +enum { TASK_INVALID, TASK_OUTLINES, TASK_FILL }; + +enum { ST_INVALID, + ST_START_LINE, ST_CONTINUE_LINE, ST_END_LINE, + ST_DRILL, + ST_FILL, + ST_ARC_BEGIN, + ST_ARC_END}; + +enum { TOP = 0, BOTTOM = 1, MILL = 2, TEXT = 3, ALL = 4 }; + +int PROGRAM_NAME_ARG = 0; +int FILENAME_ARG = 1; +int WIDTH_ARG = 2; +int ISO_ARG = 3; +int PASS_ARG = 4; +int PHASE_ARG = 5; + +real COORD_TOLERANCE = 0.0001; + +string OUTLINES_SIGNAL_NAME = "_OUTLINES_"; + +int TOP_LAYER = 1; +int BOTTOM_LAYER = 16; +int MILL_LAYER = 46; +int TEXT_LAYER = 46; // same as MILL_LAYER + +int OUTLINES = 1; +int FILL = 2; +int MILL_BOARD = 3; +int MILL_TEXT = 4; + +enum { + PH_INVALID = 0, + PH_TOP_OUT_GEN = 1, + PH_TOP_OUT_WRITE = 2, + PH_TOP_FILL_GEN = 3, + PH_TOP_FILL_WRITE = 4, + PH_BOTTOM_OUT_GEN = 5, + PH_BOTTOM_OUT_WRITE = 6, + PH_BOTTOM_FILL_GEN = 7, + PH_BOTTOM_FILL_WRITE = 8, + PH_TOP_DRILL = 9, + PH_BOTTOM_DRILL = 10, + PH_MILL = 11, + PH_TEXT = 12, + + PH_LAST_PHASE = 13 +}; + +string PHASE_NAME[] = { + "invalid", + "Gen_Top_Outlines", "Write_Top_Outlines", + "Gen_Top_Fill", "Write_Top_Fill", + "Gen_Bottom_Outlines", "Write_Bottom_Outlines", + "Gen_Bottom_Fill", "Write_Bottom_Fill", + "Top_Drills", "Bottom_Drills", + "Milling", + "Text", + "Finished!" +}; + +string get_phase_name(int phase) +{ + return PHASE_NAME[phase]; +} + +// Used to convert a numeric state into a text name for that state. +string state_text[] = { + "ST_START_LINE", + "ST_CONTINUE_LINE", + "ST_END_LINE", + "ST_DRILL", + "ST_FILL" +}; + +real ROUND_FACTOR = 1000; + +real BORDER_SIZE = 0.001; + +int DRILL_SIZE = 0; +int DRILL_X = 1; +int DRILL_Y = 2; + +string UNIT_OF_MEASURE = "not set"; + +real g_width = 0.01; +int g_side = TOP; + +// Which phase of the process we're working on. +int g_phase; + +string IS_SETUP_FILE_NAME = "pcb_gcode_is_setup"; + +// Current profile array and indices for it. +string CURRENT_PROFILE[]; +enum { + FILE_NAME = 0, + AUTHOR = 1, + DESCRIPTION = 2 + } + +string get_current_profile() +{ + string files[]; + int num_files = fileglob(files, g_path + "/" + IS_SETUP_FILE_NAME); + if (num_files > 0) { + fileread(CURRENT_PROFILE, g_path + "/" + IS_SETUP_FILE_NAME); + } + else { + CURRENT_PROFILE[FILE_NAME] = "NONE"; + CURRENT_PROFILE[AUTHOR] = "NONE"; + CURRENT_PROFILE[DESCRIPTION] = "NONE"; + return "NONE"; + } + + return CURRENT_PROFILE[DESCRIPTION]; +} + +void set_current_profile(string profile_fields) +{ + strsplit(CURRENT_PROFILE, profile_fields, '\t'); + output(g_path + "/" + IS_SETUP_FILE_NAME) { + printf("%s\n", CURRENT_PROFILE[FILE_NAME]); + printf("%s\n", CURRENT_PROFILE[AUTHOR]); + printf("%s\n", CURRENT_PROFILE[DESCRIPTION]); + } +} + +int program_is_setup() +{ + if (get_current_profile() == "NONE") + return NO; + + return YES; +} + + +// Find the path where all our files are located. It must be one of the directories in the +// Options | Directories | User Language Programs settings. + + +void get_path() +{ + int index = 0; + string last_g_path; + + board(B) g_path = filedir(B.name); + + last_g_path = g_path; + while (g_path > "") { + g_path = remove_last_dir(g_path); + if (filetime(g_path + "/source/pcb-gcode.h")) { + return; + } + if (last_g_path == g_path) { + break; + } + last_g_path = g_path; + } + + while (path_ulp[index] != "" && index < 10) { + if(filetime(path_ulp[index] + "/source/pcb-gcode.h")) { + g_path = path_ulp[index]; + return; + } + index++; + } +} + +get_path(); + +if (g_path == "") { + dlgMessageBox("There is a problem with your installation of pcb-gcode.\n" + + "You probably need to add the path to pcb-gcode's folder in " + + "EAGLE's Control Panel | Options | Directories | User Language Programs.\n" + "Please see docs/readme.html"); + exit(-1); +} +else { +// dlgMessageBox("g_path = " + g_path); +} + +// This reads the current profile into CURRENT_PROFILE, if available. +get_current_profile(); + +// I know, I know. No way around it that I see right now. +string g_real_to_string_string = ""; +string real_to_string(real n) +{ + sprintf(g_real_to_string_string, "%f", n); + return g_real_to_string_string; +} + +string g_int_to_string_string = ""; +string int_to_string(int n) +{ + sprintf(g_int_to_string_string, "%d", n); + return g_int_to_string_string; +} + + +// Used to show debugging information. +string g_debug; + diff --git a/trunk/ulp/source/stack.h b/trunk/ulp/source/stack.h new file mode 100644 index 00000000..d7b3111a --- /dev/null +++ b/trunk/ulp/source/stack.h @@ -0,0 +1,71 @@ +// -*- Mode: Eagle -*- +/* +* A stack. +* +*/ + +string m_ary[]; +char FIELD_SEP = '\t'; +char RECORD_SEP = '\n'; + +string push(string stack, string entry) +{ + return stack + entry + RECORD_SEP; +} + +string top(string stack) +{ + int num = strsplit(m_ary, stack, RECORD_SEP); + return m_ary[num - 1]; +} + +string pop(string stack) +{ + string str; + int num = strsplit(m_ary, stack, RECORD_SEP); + m_ary[num - 1] = ""; + str = strjoin(m_ary, RECORD_SEP); + int off = strrchr(str, RECORD_SEP); + return strsub(str, off - 1); +} + +string bottom(string stack) +{ + return ""; +} + +string shift(string stack) +{ + return ""; +} + +string unshift(string stack, string entry) +{ + return ""; +} + +string t; +t = push(t, "aaa"); +t = push(t, "bbb"); +t = push(t, "ccc"); + + +string msg; +string qqq; +sprintf(msg, "stack:\n%s", t); +qqq = qqq + msg; +string s; +s = top(t); +sprintf(msg, "top:\n%s", s); +qqq = qqq + msg; +t = pop(t); +s = top(t); +sprintf(msg, "top:\n%s", s); +qqq = qqq + msg; + +t = push(t, "ddd"); + +sprintf(msg, "stack:\n%s", t); +qqq = qqq + msg; + +dlgMessageBox(qqq); diff --git a/trunk/ulp/source/stack.ulp b/trunk/ulp/source/stack.ulp new file mode 100644 index 00000000..df24136d --- /dev/null +++ b/trunk/ulp/source/stack.ulp @@ -0,0 +1,66 @@ +/* +* A stack. +* +*/ + +string m_ary[]; +char FIELD_SEP = '\t'; +char RECORD_SEP = '\n'; + +string push(string stack, string entry) +{ + return stack + entry + RECORD_SEP; +} + +string top(string stack) +{ + int num = strsplit(m_ary, stack, RECORD_SEP); + return m_ary[num - 1]; +} + +string pop(string stack) +{ + int off = strrchr(stack, RECORD_SEP, -2); + return strsub(stack, off); +} + +string bottom(string stack) +{ + return ""; +} + +string shift(string stack) +{ + return ""; +} + +string unshift(string stack, string entry) +{ + return ""; +} + +string t; +t = push(t, "aaa"); +t = push(t, "bbb"); +t = push(t, "ccc"); + + +string msg; +string qqq; +sprintf(msg, "stack:\n%s", t); +qqq = qqq + msg; +string s; +s = top(t); +sprintf(msg, "top:\n%s", s); +qqq = qqq + msg; +t = pop(t); +s = top(t); +sprintf(msg, "top:\n%s", s); +qqq = qqq + msg; + +t = push(t, "ddd"); + +sprintf(msg, "stack:\n%s", t); +qqq = qqq + msg; + +dlgMessageBox(qqq); diff --git a/trunk/ulp/source/string.h b/trunk/ulp/source/string.h new file mode 100644 index 00000000..f7be3943 --- /dev/null +++ b/trunk/ulp/source/string.h @@ -0,0 +1,306 @@ +// -*- Mode: Eagle -*- +/* + * + * String utilities. + * + * Copyright 2007 - 2009 by John Johnson Software, LLC. + * All Rights Reserved. + * + */ + + + +int STR_NOT_FOUND = -1; +char REC_SEP = '\v'; +char FIELD_SEP = '\t'; + +string leftstr(string s, int n) +{ + return strsub(s, 0, n); +} + +string rightstr(string s, int n) +{ + return strsub(s, strlen(s) - n); +} + +string ltrim(string s) +{ + while (leftstr(s, 1) == " ") { + s = strsub(s, 1); + } + return s; +} + +string rtrim(string s) +{ + while (strsub(s, strlen(s) - 1, 1) == " ") { + s = strsub(s, 0, strlen(s) - 1); + } + return s; +} + +string trim(string s) +{ + return ltrim(rtrim(s)); +} + +string remove_last_slash(string s) +{ + if (rightstr(s, 1) == "/") { + s = leftstr(s, strlen(s) - 1); + } + return s; +} + +string remove_last_dir(string s) +{ + int pos; + + pos = strrstr(s, "/"); + return leftstr(s, pos); +} + +string key_value_record(string a, string b) +{ + return a + FIELD_SEP + b + REC_SEP; +} + +/* + * Replace text in a string with other text. + * + */ +string substitute(string s, string replacements) +{ + int pos; + string keys[]; + string values[]; + string records[]; + string fields[]; + int num_keys; + int num_fields; + int i; + string temp; + int last_match; + + num_keys = strsplit(records, replacements, REC_SEP); + num_keys--; + for (i=0; i width) { break; } + pos = pos - strlen(path) - 1; + } + if (keep_pos <= 0) { return path; } + return "..." + strsub(path, keep_pos); +} + + +string fi(string f, int i) { + string str; + if (strcnt(f, '%') < 1) { + return ""; + } + else { + sprintf(str, f, i); + } + return str; +} + +string fir(string f, int i, real r) { + string str; + if (strcnt(f, '%') < 1) { + return fi(f, i); + } + else { + sprintf(str, f, i, r); + } + return str; +} + +string fr(string f, real r) { + string str; + if (strcnt(f, '%') < 1) { + return ""; + } + else { + sprintf(str, f, r); + } + return str; +} + +string frr(string f, real r1, real r2) { + string str; + if (strcnt(f, '%') < 2) { + return fr(f, r1); + } + else { + sprintf(str, f, r1, r2); + } + return str; +} + +string frrr(string f, real r1, real r2, real r3) { + string str; + if (strcnt(f, '%') < 3) { + return frr(f, r1, r2); + } + else { + sprintf(str, f, r1, r2, r3); + } + return str; +} + +string frrrr(string f, real r1, real r2, real r3, real r4) { + string str; + if (strcnt(f, '%') < 4) { + return frrr(f, r1, r2, r3); + } + else { + sprintf(str, f, r1, r2, r3, r4); + } + return str; +} + +string fs(string f, string s) { + string str; + if (strcnt(f, '%') < 1) { + return ""; + } + else { + sprintf(str, f, s); + } + return str; +} diff --git a/trunk/ulp/source/string.ulp b/trunk/ulp/source/string.ulp new file mode 100644 index 00000000..946e4b8c --- /dev/null +++ b/trunk/ulp/source/string.ulp @@ -0,0 +1,39 @@ +/* + * + * String utilities. + * + * Copyright 2007 - 2009 by John Johnson Software, LLC. + * All Rights Reserved. + * + */ + +#include "string.h" + +if (leftstr("test string", 3) != "tes") exit(12); +if (rightstr("test string", 3) != "ing") exit(13); +if (ltrim(" test string") != "test string") exit(14); +if (rtrim("test string ") != "test string") exit(15); +if (trim(" test string ") != "test string") exit(16); +if (remove_last_dir("c:/dir/thet/ssot/") != "c:/dir/thet") exit(17); + +string replacements; +string original_string; +string new_string; +string board_filepath; +int t = time(); + +board(b) board_filepath = b.name; +replacements = + key_value_record("%P", filedir(board_filepath)) + + key_value_record("%F", filename(board_filepath)) + + key_value_record("%B", filesetext(filename(board_filepath), "")) + + key_value_record("%D", t2string(t)) + + key_value_record("%S", "top") + + key_value_record("%T", "drill"); + +original_string = "Path = %P,\n Filename = %F,\n" + + "Board Name = %B, Now is %D\n" + + "Side is %S, and this is the %T file."; + +new_string = substitute(original_string, replacements); +dlgMessageBox(new_string); diff --git a/trunk/ulp/source/test_nonvolatile.h b/trunk/ulp/source/test_nonvolatile.h new file mode 100644 index 00000000..6edae9c5 --- /dev/null +++ b/trunk/ulp/source/test_nonvolatile.h @@ -0,0 +1,51 @@ +// -*- Mode: Eagle -*- +/* test nonvolatile.h */ + +#include "nonvolatile.h" + +set_nv_param("first_name", "Jamile"); +set_nv_param("last_name", "Johnson"); +set_nv_param("email", "jamile@nowhere.com"); + +m_params[0] = "" +m_params[1] = "" +m_params[2] = "" + +if (get_nv_param("first_name", "ERROR", NO) == "ERROR") + exit("first_name failed"); +if (get_nv_param("last_name", "ERROR", NO) == "ERROR") + exit("last_name failed"); +if (get_nv_param("email", "ERROR", NO) == "ERROR") + exit("email failed"); + +if (get_nv_param("first_name", "ERROR", NO) != "Jamile") + exit("first_name failed"); +if (get_nv_param("last_name", "ERROR", NO) != "Johnson") + exit("last_name failed"); +if (get_nv_param("email", "ERROR", NO) != "jamile@nowhere.com") + exit("email failed"); + + +set_nv_param("first_name", "John"); +set_nv_param("last_name", "Johnson"); +set_nv_param("email", "pcbgcode@pcbgcode.org"); + +m_params[0] = "" +m_params[1] = "" +m_params[2] = "" + +if (get_nv_param("first_name", "ERROR", NO) == "ERROR") + exit("first_name failed"); +if (get_nv_param("last_name", "ERROR", NO) == "ERROR") + exit("last_name failed"); +if (get_nv_param("email", "ERROR", NO) == "ERROR") + exit("email failed"); + +if (get_nv_param("first_name", "ERROR", NO) != "John") + exit("first_name failed"); +if (get_nv_param("last_name", "ERROR", NO) != "Johnson") + exit("last_name failed"); +if (get_nv_param("email", "ERROR", NO) != "pcbgcode@pcbgcode.org") + exit("email failed"); + + diff --git a/trunk/ulp/source/test_nonvolatile.ulp b/trunk/ulp/source/test_nonvolatile.ulp new file mode 100644 index 00000000..8a4929b1 --- /dev/null +++ b/trunk/ulp/source/test_nonvolatile.ulp @@ -0,0 +1,83 @@ +/* test nonvolatile.h */ + +#include "nonvolatile.h" + +set_nv_param("first_name", "Jamile"); +set_nv_param("last_name", "Johnson"); +set_nv_param("email", "jamile@nowhere.com"); + +m_params[0] = ""; +m_params[1] = ""; +m_params[2] = ""; + +if (get_nv_param("first_name", "ERROR", 0) == "ERROR") +{ dlgMessageBox("14 first_name failed"); + exit(1); +} +if (get_nv_param("last_name", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("last_name failed"); + exit(1); +} +if (get_nv_param("email", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("email failed"); + exit(1); +} + +if (get_nv_param("first_name", "ERROR", 0) != "Jamile") +{ + dlgMessageBox("first_name failed"); + exit(1); +} +if (get_nv_param("last_name", "ERROR", 0) != "Johnson") +{ + dlgMessageBox("last_name failed"); + exit(1); +} +if (get_nv_param("email", "ERROR", 0) != "jamile@nowhere.com") +{ + dlgMessageBox("email failed"); + exit(1); +} + + +set_nv_param("first_name", "John"); +set_nv_param("last_name", "Johnson"); +set_nv_param("email", "pcbgcode@pcbgcode.org"); + +m_params[0] = ""; +m_params[1] = ""; +m_params[2] = ""; + +if (get_nv_param("first_name", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("55 first_name failed"); + int t=1/0; +} +if (get_nv_param("last_name", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("60 last_name failed"); + int t=1/0; +} +if (get_nv_param("email", "ERROR", 0) == "ERROR") +{ + dlgMessageBox("65 email failed"); + int t=1/0; +} + +if (get_nv_param("first_name", "ERROR", 0) != "John") +{ + dlgMessageBox("71 first_name failed"); + int t=1/0; +} +if (get_nv_param("last_name", "ERROR", 0) != "Johnson") +{ + dlgMessageBox("76 last_name failed"); + int t=1/0; +} +if (get_nv_param("email", "ERROR", 0) != "pcbgcode@pcbgcode.org") +{ + dlgMessageBox("81 email failed"); + int t=1/0; +} diff --git a/trunk/ulp/source/viewer.linux.sh b/trunk/ulp/source/viewer.linux.sh new file mode 100644 index 00000000..9a3e928a --- /dev/null +++ b/trunk/ulp/source/viewer.linux.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +PATH=/usr/local/jdk/bin:$PATH + +cd "`dirname $0`/../viewer/application.linux" +./viewer >viewer.log 2>&1 diff --git a/trunk/ulp/spiceorder.ulp b/trunk/ulp/spiceorder.ulp new file mode 100644 index 00000000..ff214998 --- /dev/null +++ b/trunk/ulp/spiceorder.ulp @@ -0,0 +1,252 @@ +#usage "en:Place a text Spiceorder xx at all pins in symbol.

    " + "To simulate a schematic in LTspice IV, you can export the schematic and " + "the symbols of a library t a LTspice .asc file format with export-ltspice.ulp.
    " + "To simulate in Spice, the pins must have a SpiceOrder.
    " + "To assigning the spiceorder unique to a pin, you must place the text SiceOrder xx " + "on the coordinate of the pin on the layer 99 SpiceOrder.
    " + "SpiceOrder is a reserved name
    " + "xx ist the number
    " + "You can use this ulp in device- and symbol-editor. If you start the ulp in a device, " + "all used symbols of this device can place the spiceorder, if you start the ulp in a symbol, " + "only this symbol will be edit.Author alf@cadsoft.de" + , + "de:Platziere einen Text SpiceOrder xx an jedem Pin im Symbol

    " + "Um einen Schaltplan in LTspive IV simulieren zu können, kann man mit dem " + "export-ltspice.ulp einen Schaltplan so wie die Symbole der Bibliothek " + "im LTspice .asc Format augeben.
    " + "Zum simulieren in Spice, muß für jeden Pin die SpiceOrder angegeben werden. " + "Um die SpiceOrder eindeutig zuzuordnen, muß man im Symbol an jedem Pin " + "(Koordinate des Pin) im Layer 99 SpiceOrder einen entsprtechenden Text " + "platzieren." + "

    " + "SpiceOrder ist ein reservierter Name.
    " + "xx ist die Nummer." + "

    " + "Dieses ULP kann sowohl im Device-Editor wie im Symbol-Editor gestartet werden. " + "Wird es im Device-Editor gestartet, denn kann man allen Symbolen die im Device " + "benutzt werden die SpiceOrder zuweisen. Im Symbol-Editor gestartet nur dem Symbol " + "das man gerade im Editor geladen hat." + "

    " + "Author alf@cadsoft.de" + +string Version = "1.0.,0"; // 2012-06-28 alf@cadsoft.de + +string SpiceOrder = "SpiceOrder"; + +string PinName[], GateName[], Symbols[], SpiceOrderNum[]; +string List[]; +int PinX[], PinY[]; +int CntPin = 0; + +int OrderExist[]; +int OrderExistCollect = 0; + +int LayerSpiceOrder = 99; // Die Zuordnung der Pins zu der SpiceOrder geschieht über den Text SpiceOrderXX + // und wird als Text in diesem Layer abgelegt! +int ColorViolett = 5; +string DefLayerSpiceLayer = ""; // if not exist this layer + +int test = 0; // test option zum debuggen + +/*** functions ***/ +string checkapostroph(string s) { // da der ganze String in ' eingeschlossen wird, + // müssen die Apostrophen verdoppelt werden. + string t[]; + int cnt; + cnt = strsplit(t, s, '\''); // check Apostroph + if (cnt > 1) { + s = ""; + for (int i = 0; i < cnt; i++) { + if (i == 0) { + if (t[i]) s += t[i]; + } + else if (i) s += "''" + t[i]; + } + } + return s; +} + + +void genLine(int n) { + sprintf(List[n], "%d\t%s\t%s\t%s\t%s\t%.4f\t%.4f", n, Symbols[n], GateName[n], PinName[n], SpiceOrderNum[n], u2mil(PinX[n]), u2mil(PinY[n])); + return; +} + + +void getOrderText(UL_SYMBOL S) { + S.texts(T) { + if (T.layer == LayerSpiceOrder) { + string s[]; + int cnt = strsplit(s, T.value, ' '); + if (s[0] == SpiceOrder) { + S.pins(P) { + int found = 0; + for (int n = 0; n < CntPin; n++) { + if (T.x == PinX[n] && T.y == PinY[n] && S.name == Symbols[n]) { + sprintf(s[2] , "%d %s %.4f %.4f / %.4f %.4f", n, PinName[n], u2mil(P.x), u2mil(P.y), u2mil(PinX[n]), u2mil(PinX[n])); + SpiceOrderNum[n] = s[1]; + genLine(n); + found = 1; + OrderExist[n] = 1; + OrderExistCollect = 1; + break; + } + } + if (found) break; + } + } + } + } + return; +} + + +int checkGsymbolName(string symname) { + int exist = 0; + for (int n = 0; n < CntPin; n++) { + if (Symbols[n] == symname) { + exist = 1; + break; + } + } + return exist; +} + + +int genScript(void) { + string cmd, s; + string gate = ""; + + for (int n = 0; n < CntPin; n++ ) { + if (gate != GateName[n] || symbol) { // || symbol, um aus einem Symbol heraus die SpiceOrder zu definieren + sprintf(s, "Edit '%s.SYM';\nGRID MIL 100 1;\n", checkapostroph(Symbols[n])); + cmd+=s; + sprintf(s, "LAYER %d SpiceOrder;\n", LayerSpiceOrder); + cmd+=s; + sprintf(s, "SET COLOR_LAYER %d %d;\n", LayerSpiceOrder, ColorViolett); // SET COLOR_LAYER layer color; + cmd+=s; + sprintf(s, "DISPLAY NONE %d;\n", LayerSpiceOrder); + cmd+=s; + sprintf(s, "CHANGE Size 16;\nLayer %d;\n", LayerSpiceOrder); + cmd+=s; + sprintf(s, "CHANGE Align Center;\n"); + cmd+=s; + gate = GateName[n]; + } + if (OrderExist[n] ) { + sprintf(s, "DELETE (%.4f %.4f);\n", u2mil(PinX[n]), u2mil(PinY[n]) ); + cmd+=s; + } + if (!SpiceOrderNum[n]) { + dlgMessageBox("First define SpiceOrder!", "OK"); + return 0; + } + sprintf(s, "TEXT 'SpiceOrder %s' R0 (%.4f %.4f);\n", SpiceOrderNum[n], u2mil(PinX[n]), u2mil(PinY[n]) ); + cmd+=s; + } + sprintf(s, "DISPLAY ALL;\n"); + cmd+=s; + if (test) { + dlgDialog("Test") { + dlgHBoxLayout dlgSpacing(600); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(600); + dlgTextEdit(cmd); + } + + dlgHBoxLayout { + dlgPushButton("OK") dlgAccept(); + dlgPushButton("esc") { dlgReject(); exit(-99); } + } + + }; + } + exit(cmd); +} + + +void getSymbolPin(string sname, string gname) { + library(L) { + L.symbols(SYM) { + if (SYM.name == sname) { + SYM.pins(P) { + PinName[CntPin] = P.name; + Symbols[CntPin] = SYM.name; + PinX[CntPin] = P.x; + GateName[CntPin] = gname; + PinY[CntPin] = P.y; + genLine(CntPin); + CntPin++; + } + getOrderText(SYM); + break; + } + } + } + return; +} + + +void getSpiceOrder(int n) { + string neworder = SpiceOrderNum[n]; + dlgDialog("Get Spiceorder") { + dlgGridLayout { + dlgCell(0, 0) dlgHBoxLayout { dlgStretch(1); dlgLabel("Symbol:"); } + dlgCell(0, 1) dlgLabel(Symbols[n]); + dlgCell(1, 0) dlgHBoxLayout { dlgStretch(1); dlgLabel("Gate:"); } + dlgCell(1, 1) dlgLabel(GateName[n]); + dlgCell(2, 0) dlgHBoxLayout { dlgStretch(1); dlgLabel("Pin:"); } + dlgCell(2, 1) dlgLabel(GateName[n]+ "." + PinName[n]); + dlgCell(3, 0) dlgLabel("Spiceorder "); + dlgCell(3, 1) dlgStringEdit(neworder); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-CANCEL") { dlgReject(); return; } + } + }; + SpiceOrderNum[n] = neworder; + genLine(n); + return; +} + + +/*** main ***/ +if (deviceset || symbol) { + if (deviceset) { + deviceset(DV) { + DV.gates(G) { + if (!checkGsymbolName(G.symbol.name)) { + getSymbolPin(G.symbol.name, G.name); + } + } + } + } + if (symbol) { + symbol(S) { + if (!checkGsymbolName(S.name)) { + getSymbolPin(S.name, ""); + } + } + } + int sel; + dlgDialog("Spiceorder") { + dlgHBoxLayout dlgSpacing(500); + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(500); + dlgListView("#\tSymbol\tGate\tPin\tSpiceorder\tX\tY", List, sel) getSpiceOrder(sel); + } + + if (OrderExistCollect) dlgLabel("ATTENTION: SpiceOrder exist!"); + + dlgHBoxLayout { + dlgPushButton("+OK") { if(genScript()) dlgAccept(); } + dlgPushButton("-CANCEL") { dlgReject(); exit(-1); } + dlgStretch(1); + dlgPushButton("&Help") dlgMessageBox(usage, "OK"); + } + }; +} + +else dlgMessageBox("Start this ULP in Deviceset!", "OK"); diff --git a/trunk/ulp/spin-all.ulp b/trunk/ulp/spin-all.ulp new file mode 100644 index 00000000..98411460 --- /dev/null +++ b/trunk/ulp/spin-all.ulp @@ -0,0 +1,126 @@ +#usage "Set spin flag on all (smashed) texts\n" + "

    " + "Generates a command sequence which set spin flag at all texts." + "RUN spin-all [ON | OFF]
    " + "If no option used, the default is ON.
    " + "Option ON OFF are not case sensitive.
    " + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED +#require 5.1200 + +string Version = "1.0"; // 2009-01-15 alf@cadsoft.de +int test = 0; + +int onoff = 0; +if (strupr(argv[1]) == "ON") onoff = 0; +if (strupr(argv[1]) == "OFF") onoff = 1; + +int tx[], ty[], tl[], ts[], index[]; +string tv[]; +int cnttext = 0; +int cnt_unsmashed = 0; +int lVisible[]; +int changed = 0; + +string cmd; +string h; +string scriptfile; + + +/*** Functions ***/ +void header(void) { + sprintf(cmd, "# Exported from %s\n# by %s, %s\n", filesetext(scriptfile, ".brd"), filename(argv[0]), EAGLE_SIGNATURE ); + cmd += "SET UNDO_LOG OFF;\n"; // advisable for speed reasons + cmd += "GRID mm;\n"; +} + + +void addlist(UL_TEXT T) { + tl[cnttext] = T.layer; + tx[cnttext] = T.x; + ty[cnttext] = T.y; + ts[cnttext] = T.spin; + tv[cnttext] = T.value; + cnttext++; + return; +} + + +if (board) board(B) { + B.layers(L) lVisible[L.number] = L.visible; + scriptfile = filesetext(B.name, ".scr"); + header(); + B.texts(T) { // Texts in Board + addlist(T); + } + B.elements(E) { + E.texts(T) { // *** smased texts in elements *** + if (T.value) addlist(T); // only texts with value, + } + E.package.texts(T) { // *** non smased + cnt_unsmashed++; + } + } + sort(cnttext, index, tl); + int actlayer = 0; + for(int n = 0; n < cnttext; n++) { + if (actlayer != tl[index[n]]) { + actlayer = tl[index[n]]; + sprintf(h, "DISPLAY NONE %d;\n", actlayer); + cmd+=h; + } + if (ts[index[n]] == onoff) { + sprintf(h, "ROTATE SR0 (%.4f %.4f);\n", + u2mm(tx[index[n]]), u2mm(ty[index[n]]) ); + cmd += h; + changed++; + } + } + string info; + if (cnt_unsmashed) sprintf(info, "%d unsmached texts found.", cnt_unsmashed); + if (!changed) { + dlgMessageBox("No text found to change the spin flag.\n\n"+info, "OK"); + exit(0); + } + // prepare display mode + cmd += "DISPLAY NONE "; + for(int l = 1; l < 255; l++) { + if (lVisible[l]) { + sprintf(h, " %d", l); + cmd += h; + } + } + cmd += ";\n"; + cmd += "SET UNDO_LOG ON;\n"; + cmd += "GRID LAST;\n"; + // EditBox + if (test) { + int Result = dlgDialog("Spin all texts") { + dlgHBoxLayout { + dlgTextEdit(cmd); + dlgVBoxLayout { + dlgSpacing(300); + } + } + dlgHBoxLayout { + dlgSpacing(500); + } + dlgLabel(info); + dlgHBoxLayout { + dlgPushButton("+&Execute") dlgAccept(); + dlgPushButton("-&Cancel") dlgReject(); + dlgStretch(1); + } + }; + if (Result == 0) exit(0); + } + output(scriptfile, "wtD") printf("%s", cmd); + exit("SCRIPT '" + scriptfile + "';"); +} + +else { + dlgMessageBox("Start this ULP in a board.", "OK"); + exit(-1); +} \ No newline at end of file diff --git a/trunk/ulp/spiral-coil-ulp.bmp b/trunk/ulp/spiral-coil-ulp.bmp new file mode 100644 index 00000000..ed569538 Binary files /dev/null and b/trunk/ulp/spiral-coil-ulp.bmp differ diff --git a/trunk/ulp/spiral-coil.ulp b/trunk/ulp/spiral-coil.ulp new file mode 100644 index 00000000..91288d86 --- /dev/null +++ b/trunk/ulp/spiral-coil.ulp @@ -0,0 +1,373 @@ +#usage "This ULP calculates and place a coil.

    " + "Depending from where you are starting the ULP, places pads (library) or vias (board).

    " + "The calculation of coils or inductivities depends on a lot of " + "different factors, like
    " + " -- basic material of the board
    " + " -- thickness of the board
    " + " -- number of layers
    " + " -- thickness of the layers
    " + " -- distances between elements
    " + " -- tracks
    " + " -- copper areas / ground plains
    " + " -- thickness of the copper layers
    " + " -- track width
    " + " -- distances between tracks
    " + " -- surface of tracks (tin?)
    " + " -- the signal's frequency
    " + " -- ...
    " + "All these factors should be taken into consideration for the formula !
    " + "used below to calculate an exact value for a coil. Nevertheless it !
    " + "is necessary to check the result by a practical measurement. It is !
    " + "very difficult to generate coils with exact values this way.
    " + "Generally one can say that printed coils can be used in the MHz range only.
    " + "Author: support@cadsoft.de,
    "; + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, +// EXPRESSED OR IMPLIED. + +#require 4.1106 + +string Help = usage; + +// **************----- german description -------------*************** +// ---------------------------------------------------------------- +string deHelp = + "Dieses ULP berechnet eine Spiralspule.

    " + + "Dieses ULP kann in der Libary ebenso wie im Board benutzt werden.
    " + + "Je nachdem ob Sie es von einer Library oder von einem Borad aus " + "starten, werden Pads bzw. Vias plaziert.
    " + + "
    " + + "Die Berechnung der Windungen bzw. der Induktivitaet haengt von vielen Faktoren ab, wie z.B.:
    " + + " - Basismaterial
    " + + " - Staerke der Leiterplatte
    " + + " - Anzahl der Lagen
    " + + " - Dicke der Lagen
    " + + " - Abstand zu benachbarten Bauteilen, Leitungen, Kupferflaechen, Masseflaechen etc.
    " + + " - Dicke der Kupferbeschichtung
    " + + " - Breite der Leiterbahn (unteraetzen)
    " + + " - Abstand zwischen den Leiterbahnen (Spiralkreise / Ätzgenauigkeit)
    " + + " - Oberflaeche der Leiterbahn (Verzinnt)
    " + + " - Signal-Frequenz
    " + + " - ...
    " + + "Um daraus einen einigermassen genauen Wert zu berechnen, muessten alle oben genannten Faktoren
    " + + "als Korrekturwerte in die Formael einfliessen.
    " + + "Was aber in jedem Fall durch entspechende Messungen nachgeprueft werden muesste.
    " + + "In der Praxis sind Printspulen mit genau definierten Werten und in engen Toleranzen " + + "nur sehr schwer herzustellen.
    " + + "Im Allgemeinen kann man davon ausgehen, dass Printspulen nur im MHz Bereich " + + "einigermassen Nutzbar sind.
    " + + "Author: support@cadsoft.de,
    "; + +if (language() == "de") Help = deHelp; + +// 05.06.2002 alf@cadsoft.de +// 24.01.2005 alf@cadsoft.de + +// ****************************************************************** + +// Parameterliste -- parameter section + +real n = 4.0; // number of turns +real Wirewidth_mm = 0.2; // track width +real Wiredistance_mm = 0.2; // min. distance between tracks +real Diameter = 0.6; // pad/via diameter +real Drill = 0.4; // drill diameter +real offx = 0.0; +real offy = 0.0; + +real UserArc; +int windn; +int wind1; // count of total turns +real windlast; // reminder Turn +real Ndist; // distance between turns + +string Shape = "ROUND"; // Pad/Via-Form nicht veraendern +string direction = "CCW"; // *** Drehrichtung der Spirale nicht veraendern *** + // *** Direction do not change *** +string solderpoint; + +string cmd = ""; +string s; +int Layer = 1; + + + /* calculate X coordinate by Radius */ + +real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserArc) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real NewArc; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + { + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + NewArc = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + NewArc = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + NewArc = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * cos(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + NewArc = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + NewArc = (Xalt - Xorigin) + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + NewArc = (Xalt - Xorigin + 90) + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + NewArc = (Xalt - Xorigin + 270)+ UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * cos(rad)); + } + } +} + + + /* calculate Y coordinate by Radius */ + +real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserArc) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real NewArc; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + { + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + NewArc = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + NewArc = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + NewArc = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * sin(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + NewArc = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + NewArc = (Xalt - Xorigin) + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + NewArc = (Xalt - Xorigin + 90) + UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + NewArc = (Xalt - Xorigin + 270)+ UserArc; + real rad = PI / 180 * NewArc; + return (RADIUS * sin(rad)); + } + } +} + + + /* place a Pad (Via) on startpoint */ +void PadViaS(real x1, real x2, real w, real g) { + real p = x1 + (Wirewidth_mm / 2) - (Diameter / 2); // + sprintf( s, "%s (%4.2f %4.2f);\n", solderpoint , p + offx , 0.0 + offy); + cmd += s; + } + + + /* place a Pad (Via) on endpoint */ +void PadViaE(real x1, real x2, real w, real g) { + real pRadius = x2 + ((x1 - x2) / 180 * g) + (Diameter / 2) - (Wirewidth_mm / 2) ; + real px = Xneu(pRadius, 0, 0, 0, w); + real py = Yneu(pRadius, 0, 0, 0, w); + sprintf( s, "%s (%4.2f %4.2f);\n", solderpoint, px + offx, py + offy); + cmd += s; + } + +void doit(void) { + Ndist = (Wiredistance_mm + Wirewidth_mm ) ; // distance ARC to ARC + windn = round(n); // liefert x gerundet auf den nächsten Integer-Wert. + wind1 = trunc(n); // liefert den ganzzahligen Teil von n. + windlast = n - wind1; // rest der letzten Windung + UserArc = 360 * windlast; + real startarc = 0; + real endarc = 0; + real end2arc = 0; + real Y = 0; + int x = 0; + real ewx ; + real ewy ; + + sprintf( s, "GRID mm;\n"); + cmd += s; + sprintf( s, "Change dia %4.2f;\n", Diameter); + cmd += s; + sprintf( s, "Change shape %s;\n", Shape); + cmd += s; + sprintf( s, "Change drill %4.2f;\n", Drill); + cmd += s; + PadViaS( Ndist, Ndist, 0, 0); + sprintf( s, "change width %4.3f;\n", Wirewidth_mm); + cmd += s; + sprintf( s, "Change layer %d;\n", Layer); + cmd += s; + + // full turns + for (x = 1; x <= wind1; x++) { + // first ARC -|- erster Halbbogen + startarc = x * Ndist; + endarc = -(x * Ndist + (Ndist / 2)); + sprintf( s, "ARC '%s' (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n", + direction, startarc + offx, Y + offy, endarc + offx, Y + offy, endarc + offx, Y + offy); + cmd += s; + // second ARC -|- zweiter Halbbogen + end2arc = (x + 1) * Ndist; + sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n", + endarc + offx, Y + offy, end2arc + offx, Y + offy, end2arc + offx, Y + offy); + cmd += s; + } + + // last turn + if (UserArc >= 270) { // ***** 270 - 359 + // first ARC -|- erster Halbbogen + startarc = (x ) * Ndist; + endarc = -((x * Ndist) + (Ndist / 2)); + sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n", + startarc + offx, Y + offy, endarc + offx, Y + offy, endarc + offx, Y + offy); + cmd += s; + // finish ARC -|- letzter Halbbogen + end2arc = (x + 1) * Ndist + (Ndist / 8); + ewx = Xneu(end2arc, 0, 0, 0, UserArc); + ewy = Yneu(end2arc, 0, 0, 0, UserArc); + sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n", + endarc + offx, Y + offy, end2arc + offx, Y + offy, ewx + offx, ewy + offy); + cmd += s; + PadViaE( end2arc, -endarc, UserArc, UserArc - 180); + UserArc = 0; + } + + else if (UserArc >= 180) { // ***** 180 - 270 + // finish ARC -|- letzter Halbbogen + startarc = (x ) * Ndist; + endarc = -((x * Ndist) + (Ndist / 2)); + sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n", + startarc + offx, Y + offy, endarc + offx, Y + offy, endarc + offx, Y + offy); + cmd += s; + // finish ARC -|- letzter Halbbogen + end2arc = (x + 1) * Ndist + (Ndist / 2); + ewx = Xneu(end2arc, 0, 0, 0, UserArc); + ewy = Yneu(end2arc, 0, 0, 0, UserArc); + + sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n", + endarc + offx, Y + offy, end2arc + offx, Y + offy, ewx + offx, ewy + offy); + cmd += s; + PadViaE(end2arc, -endarc, UserArc, UserArc - 180); + UserArc = 0; + } + + else if (UserArc >= 90) { // ***** 90 - 180 + // finish ARC -|- letzter Halbbogen + startarc = (x ) * Ndist; + endarc = -((x * Ndist) + (Ndist / 2)); + ewx = Xneu(startarc, 0, 0, 0, UserArc); + ewy = Yneu(startarc, 0, 0, 0, UserArc); + sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n", + startarc + offx, Y + offy, endarc + offx, Y + offy, ewx + offx, ewy + offy); + cmd += s; + PadViaE(-endarc, startarc , UserArc, UserArc); + UserArc = 0; + } + + else if (UserArc > 0) { // ***** 0 - 90 + // finish ARC -|- letzter Halbbogen + startarc = (x ) * Ndist; + endarc = -((x * Ndist) + (Ndist / 2)); + ewx = Xneu(startarc, 0, 0, 0, UserArc); + ewy = Yneu(startarc, 0, 0, 0, UserArc); + sprintf( s, "ARC (%6.3f %6.3f) (%6.3f %6.3f) (%6.3f %6.3f);\n", + startarc + offx, Y + offy, endarc + offx, Y + offy, ewx + offx, ewy + offy); + cmd += s; + PadViaE(-endarc, startarc ,UserArc, UserArc ); + } + + else if (UserArc == 0) { + startarc = (x ) * Ndist; + endarc = -((x * Ndist) + (Ndist / 2)); + PadViaE(-endarc, startarc ,UserArc, UserArc ); + } + + sprintf( s, "Change Layer tPlace;\n"); + + sprintf( s, "window (%6.3f %6.3f);\n", offx, offy); + cmd += s; + exit (cmd); +} + + +// *** main *** + +if (board) board(B) { solderpoint = "VIA"; }; +if (library) library(L) {solderpoint = "PAD"; }; + +string ulp_path = filedir(argv[0]); +string Spiral_H = ""; + +dlgDialog("Copper Spiral") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgHBoxLayout { + dlgLabel("&Turns"); // number of turns (Windungen) + dlgRealEdit( n, 1.0, 100.0); + dlgStretch(1); + } + dlgLabel(Spiral_H); + dlgHBoxLayout { + } + } + dlgVBoxLayout { + dlgGridLayout { + dlgCell(1, 1) dlgLabel("wire &width 'w'"); // track width + dlgCell(1, 2) dlgRealEdit(Wirewidth_mm, 0.01, 25.0); + dlgCell(2, 1) dlgLabel("wire &distance 'd'"); // min. distance between tracks + dlgCell(2, 2) dlgRealEdit(Wiredistance_mm, .01, 25.0); + dlgCell(3, 1) dlgLabel("Via/Pad di&ameter"); // pad/via diameter + dlgCell(3, 2) dlgRealEdit(Diameter, 0.1, 10.0); + dlgCell(4, 1) dlgLabel("Via/Pad d&rill"); // drill diameter + dlgCell(4, 2) dlgRealEdit(Drill, .1, 10.0); + dlgCell(5, 1) dlgLabel("&Layer"); // Layer number + dlgCell(5, 2) dlgIntEdit(Layer, 1, 255); + dlgCell(6, 1) dlgLabel("


    "); + dlgCell(6, 2) dlgLabel("
    "); + dlgCell(7, 1) dlgLabel("offset &X"); // place with offset X + dlgCell(7, 2) dlgRealEdit( offx ); + dlgCell(8, 1) dlgLabel("offset &Y"); // place with offset Y + dlgCell(8, 2) dlgRealEdit( offy ); + + } + dlgStretch(1); + } + } + dlgLabel("All measures in mm"); + dlgHBoxLayout { + dlgPushButton("+&OK") { dlgAccept(); doit(); } + dlgPushButton("-&Cancel") { dlgReject(); exit(0); } + dlgStretch(1); + dlgPushButton("&Help") dlgMessageBox(Help, "Ok"); + } +}; + + diff --git a/trunk/ulp/split-device-symbol.ulp b/trunk/ulp/split-device-symbol.ulp new file mode 100644 index 00000000..c5c3350c --- /dev/null +++ b/trunk/ulp/split-device-symbol.ulp @@ -0,0 +1,215 @@ +#usage "en: This ULP generates the CONNECT list for a new Device, that consists of several Symbols (Gates),
    " + "which have been extracted from one big Symbol by GROUP; CUT; and PASTE.

    " + "Example:
    " + "It is possible to generate a Device with Symbol and Package from a BSDL file or text file (spreadsheet) with " + "the help of RUN make-symbol-device-package-bsdl. In cases where the Symbol becomes too big, due to the " + "number of pins, and it does not fit onto a single schematic sheet, you can divide into several smaller Symbols with " + "the commands GROUP, CUT, EDIT xx.sym, PASTE ...., and adopt the Connect list from the 'original Device'.

    " + "Please note:
    " + "There must not be pins with same names. So it is not possible to use this ULP for Devices that consist of " + "identical Symbols (gates like NAND or OP-AMP..). " + "

    " + "Author alf@cadsoft.de" + , + "de: Dieses ULP erstellt die CONNECT-Liste für ein neues Device, das aus mehreren Symbolen (Gates) besteht,
    " + "die wiederum durch GROUP; CUT; und PASTE aus einem großen Symbol erstellt wurden.

    " + "Beispiel:
    " + "Mit RUN make-symbol-device-package-bsdl kann mit einer BSDL- oder Textdatei (Tabelle) ein Device mit Symbol " + "und Package generiert werden. In den Fällen, in denen das Symbol durch die Anzahl der Pins zu groß wird, " + "um es im Schaltplan auf eine Seite zu platzieren, kann mit GROUP - CUT - EDIT xx.sym - PASTE .... das Symbol in " + "mehrere kleinere Symbole aufgeteilt werden und mit Hilfe dieses ULPs die Connect-Liste vom 'Original-Device' übernommen werden.

    " + "ACHTUNG:
    " + "Es dürfen keine Pin-Namen doppelt vorkommen. So ist es z.B. nicht möglich dieses ULP für ein Device, das aus mehreren gleichen " + "Symbolen (Gates wie NAND oder OP-AMP) besteht, zu benutzen." + "

    " + "Author alf@cadsoft.de" + + + +string Version = "1.0"; // 2006.12.01 alf@cadsoft.de + + +string DeviceVariant, Pin_Name[], Pad_Name[]; +string DeviceSet; +string Device_Sets[]; +string Variant[]; +string Package[]; +string Device_Variant[], Device_Package[]; +int cntD = 0; +int cntConnect = 0; + +string actualpackage = " "; + +string cmd; +string DeviceDescription; + +string replacenewline(string nl) { + string a[]; + int n = strsplit(a, nl, '\n'); + if (n > 0) { + nl = ""; + for (int x = 0; x < n - 1; x++) { + nl += a[x] + "\\n"; + } + nl += a[x]; + } + return "'" + nl + "'"; +} + + +string checkVariant(string s) { + if (s == "''") s = "''''"; + return s; +} + + +void getPackage(int x) { + actualpackage = Device_Package[x]+".PAC"; + return; +} + + +void getVariant(int x) { + string p[], v[]; + int cnt; + cnt = strsplit(p, Package[x], ' '); + cnt = strsplit(v, Variant[x], ' '); + for (int n = 0; n < cnt; n++) { + Device_Variant[n] = v[n]; + Device_Package[n] = p[n]; + } + return; +} + + +string getPadName(string name) { + for (int n = 0; n < cntConnect; n++) { + if (name == Pin_Name[n]) return Pad_Name[n]; + } + return ""; +} + + +if (library) { + string file; + if (deviceset) { + deviceset(DEV) { + DeviceSet = DEV.name; + DEV.devices(D) { + cntConnect = 0; + D.gates(G) { + G.symbol.pins(P) { + cntConnect++; // count all pins + } + } + } + } + if (!cntConnect) { + dlgMessageBox("!This Deviceset use no Symbol(s)", "OK"); + exit(0); + } + + int selD = -1; + int selV = -1; + library(L) { + L.devicesets(DEV) { // collect only devicesets with the same counts of connects as the actual deviceset + int cntC; + if (DEV.name != DeviceSet) { + DEV.devices(D) { + cntC = 0; + D.gates(G) { + G.symbol.pins(P) cntC++; + } + if (cntC == cntConnect) { + Device_Sets[cntD] = DEV.name; + Variant[cntD] += D.name + " "; // Package Variant + Package[cntD] += D.package.name + " "; + } + } + if (cntC == cntConnect) cntD++; + } + } + string use_Device; + int listsel = 0; + do { + int RESULT = dlgDialog(filename(argv[0])) { + dlgHBoxLayout { + dlgLabel(DeviceSet+".DEV"); + //dlgLabel(" Variant:"+DeviceVariant); + } + dlgSpacing(8); + + dlgHBoxLayout { + dlgGridLayout { + dlgCell(0, 1) dlgLabel("Select a &Device\nto get Connect list"); + dlgCell(1, 1) dlgListView("DeviceSet", Device_Sets, selD, listsel) { getVariant(selD); actualpackage = " "; } + dlgCell(0, 2) dlgLabel("Select a Package &Variant") ; + dlgCell(1, 2) dlgListView("Variant", Device_Variant, selV) getPackage(selV); + dlgCell(2, 2) dlgLabel(actualpackage, 1); + } + dlgStretch(1); + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgPushButton("&Help") dlgMessageBox(usage); + } + }; + if (!RESULT) exit(0); + + if (selD < 0) dlgMessageBox("no device selected!", "OK"); + } while (selD < 0); + } + library(L) { + file = filesetext(L.name, "~connect.scr"); + L.devicesets(DEV) { + if (DEV.name == Device_Sets[selD]) { + DEV.devices(D) { + if (D.name == Device_Variant[selV]) { + int n = 0; + D.gates(G) { + G.symbol.pins(P) { + Pin_Name[n] = P.name; + Pad_Name[n] = P.contact.name; + n++; + } + } + } + } + DeviceDescription = DEV.description; + } + } + } + deviceset(DEV) { + int variant_not_used = 1; + DEV.devices(D) { + if (D.name == Device_Variant[selV]) { + variant_not_used = 0; + dlgMessageBox("This Package-Variant are used, select a unused variant!", "OK"); + exit(0); + } + } + if (variant_not_used) { + output(file, "wtD") { + DEV.devices(D) { + printf("PACKAGE %s %s;\n", Device_Package[selV], Device_Variant[selV]); + D.gates(G) { + G.symbol.pins(P) { + string pad = getPadName(P.name); + if (!pad) dlgMessageBox("No PAD found for "+ P.name +"\nCheck Pinname of Symbols", "OK"); + printf("CONNECT %s.%s %s;\n", G.name, P.name, pad); + } + } + string t[]; + printf("DESCRIPTION %s;\n", replacenewline(DeviceDescription+"
    Connect-List generated from "+ Device_Sets[selD] +".DEV Variant "+ checkVariant(Device_Variant[selV]) +" with "+ filename(argv[0])+"")); + } + printf("WIN FIT;\n"); + } + exit("SCRIPT '"+ file + "';\n"); + } + } + } + else dlgMessageBox("Open a Device", "OK"); +} + +else dlgMessageBox("Start this ULP in a LBR (Device)", "OK"); diff --git a/trunk/ulp/statistic-brd-checkmin.val b/trunk/ulp/statistic-brd-checkmin.val new file mode 100644 index 00000000..ab3630d3 --- /dev/null +++ b/trunk/ulp/statistic-brd-checkmin.val @@ -0,0 +1,11 @@ +0.1500 +0.1500 +0.1500 +0.1500 +0.1500 +0.1500 +0.1500 +0.1500 +0.5000 +0.2000 +0.5000 \ No newline at end of file diff --git a/trunk/ulp/statistic-brd.ulp b/trunk/ulp/statistic-brd.ulp new file mode 100644 index 00000000..77f52d68 --- /dev/null +++ b/trunk/ulp/statistic-brd.ulp @@ -0,0 +1,2853 @@ +#usage "Statistic Table of Elements in the Layout

    \n" + "To change the units in the table, please use the variable uval,\n" + "which can be found in the ulp file.

    \n" + "THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, " + "EXPRESSED OR IMPLIED.

    \n" + "Author: alf@cadsoft.de" + +#require 6.0300 + +// 2005-01-12 - Check if layer Top or Bottom used as Power-Plane *** alf@cadsoft.de +// 2005-07-05 - Calculate used area of packages. Use pads, smds and elements in +// Layer 21/51 to calculate the used area of package. +// Rotation of packages are not consider +// 2005-07-19 - Polygon-Rank +// 2005-11-17 - List all defined Layers +// 2005-12-01 - List same Values && Packages && Layer +// 2005-12-08 - List Signals without connection (PAD/SMD) as False-Signals +// 2006-04-28 - Mask Layer +// 2006-09-26 - Circle in Copper-Layer and Text in Place-Layer +// 2006-10-05 - List first Wire coordinate of Flase Signals if exist +// 2007-12-04 - Corrected Class handling to select net-list if classes empty +// 2007-12-19 - Locked & Unlocked Packages +// 2009-02-11 - save also false signals, and rudimentarily signal name in report +// # rudimentary signal names can produced by older eagle version +// 2009-07-15 - Check Polygon in Supply-Layer $name +// 2009-10-15 - separate drill statistic by via stack +// 2009-12-02 - separate packages with and without contacts +// 2010-03-10 - Roundes of SMDs +// 2010-06-09 - Count no Elements with PREFIX TP = TestPoint +// 2010-08-19 - Count RECT in any layer (not copper / can placed by RUN import-bmp.ulp) +// 2010-10-13 - check ARC < 90 for min/max Dimension +// 2011-05-03 - mark Pad in via stack 1-16 as PAD +// 2012-01-11 - correct count circles, new sumcntRECT +// 2012-05-24 - new global via counter +// 2012-11-19 - corrected count different via drills, compare up to 2 decimals +// 2014-11-27 - support of 16 netclasses + +string Version = "Version 1.3.9"; // 2014-11-27 + +int uval = 1; +string unit[] = { "Micron", "mm", "Mil", "Inch" }; +int unitPrec[] = { 0, 1, 1, 3 }, RoundFactor = pow(10, unitPrec[uval]); + +string minvalfile = filesetext(argv[0], "-checkmin.val"); +real checkMinWire = 0.3; +real checkMinArc = checkMinWire; +real checkMinCirc = checkMinWire; +real checkMinPoly = checkMinWire; +real checkMinRestringP = checkMinWire; +real checkMinRestringV = checkMinWire; +real checkMinClearance = 0.3; +real checkMinIsol = checkMinClearance; +real checkMinPadDrill = 0.6; +real checkMinViaDrill = checkMinPadDrill; +real checkMinHoleDrill = checkMinPadDrill; +string checkSupplyLayerPolygon = ""; // 2009-07-15 +string SupplyLayerName[]; +int SupplyLayers[]; +int SupplyLayersUsedPolygons[]; +string showminValWidth; +string showminValOther; + +string LabelcntRECT; +string LabelcntRectANYlayer; +string LabelcntCIRCLE; +string LabelcntTextSize; +string LabelcntTextWidth; +string LabelcntPlaceTextSize; +string LabelcntPlaceTextWidth; + +int maxX = INT_MIN; +int minX = INT_MAX; +int maxY = INT_MIN; +int minY = INT_MAX; + +string wireWidthInternal = " * Wire width are saved in 0.2 micron resolution.\n"; + +int WireWidth[]; +int cWireWidth[]; +int cntWire = 0; + +int ArcWidth[]; +int cArcWidth[]; +int cntArc = 0; + +// ****************************************************************** +// *** WIRE WIDTH wird nur geradzahlig gespeichert, wegen Teilung *** az +// ****************************************************************** +string PolygonLayer[] = { "" , ""}; +int cPolygonL = 0; +int PolygonWidth[]; +int cPolygonWidth[]; +int cntPolyW = 0; + +string PolygonSignalName[]; +int PolygonIsolate[]; +int PolygonRank[]; +int cPolygonIsolate[]; +int cntPolyIso = 0; +int PolyWidthError = 0; +string PolygonError = ""; + +int cntLayer = 0; +string usedLayer; +int cntalllay; +string allLayers[]; +string layerError; +string displayLayerError; +real outlines = 0; +string brdoutline; +string brdmaximum = "max. Board length ?\n(layer 20 empty)"; + +string NetClassName[]; +int NetClassWidth[]; +int NetClassClear[]; +int NetClassDrill[]; +int NetClassNr[]; +int selNetClassNr[]; +int cNetClass[]; + +string SignalName[]; +int SignalClass[]; +string SignalClassList[]; +int SignalClassSelect = 0; +int SignalCnt = 0; +int SignalUnrouted = 0; +string Unrouted = ""; + +string falseSignalList[]; // only signal if connected to pad or smd is a true signal 2005-12-08 alf@cadsoft.de +string FalsWxy[]; // 2006-10-05 coordiante of 1. wire segment if false signal +int falseSignalCnt = 0; +int cntfalseSignalVias[]; +int cntfalseSignalWires[]; // 2009-02-11 +string deleteRudimentalSignalName = ""; // 2009-02-12 + +int cnt_pad_on_signal = 0; + +int SMDx[], SMDy[]; +int cSMD[]; +int rSMD[]; // Roundness 2010-03-10 + +int cntSMDt = 0; +int cntSMDb = 0; +int cntSMD = 0; + +int CirclWidth[]; +int cCirclWidth[]; +int cntCircl = 0; +int sumcntCircl = 0; +int CirclDiam[]; +int cCirclDiam[]; +int cntCirclDiam = 0; + +int RECTx[]; +int RECTy[]; +int cRECT[]; +int cntRECT = 0; +int sumcntRECT = 0; +int cntRectANYlayer[]; +string statisticSumRectANYlayer; + +//int CIRCLEx[]; +//int CIRCLEy[]; +//int cCIRCLE[]; +//int cntCIRCLE = 0; + + +int TextWidth[]; +int cTextWidth[]; +int cntTextWidth = 0; +int TextSize[]; +int cTextSize[]; +int cntTextSize = 0; + +int PlaceTextWidth[]; +int cPlaceTextWidth[]; +int cntPlaceTextWidth = 0; +int PlaceTextSize[]; +int cPlaceTextSize[]; +int cntPlaceTextSize = 0; + + +int PadDrill[]; +int cPadDrill[]; +int cntPDril = 0; + +int PadDiameterTOP[]; +int cPadDiameterTOP[]; +int cntPDiamTOP = 0; +int PadDiameterBOT[]; +int cPadDiameterBOT[]; +int cntPDiamBOT = 0; +int iPadDiameter[]; // inner Layer +int ciPadDiameter[]; +int cntiPDiam = 0; + +int PadRestringTOP[]; +int cPadRestringTOP[]; +int cntPringTOP; +int PadRestringBOT[]; +int cPadRestringBOT[]; +int cntPringBOT; +int PadRestringI[]; +int cPadRestringI[]; +int cntPringI = 0; + +int ViaDrill[]; +int cViaDrill[]; +int cntVDril = 0; +int cntVias = 0; // 2012-05-24 global via counter + +int ViaDiameter[]; +int cViaDiameter[]; +int cntVDiam = 0; + +int ViaDiameterI[]; +int cViaDiameterI[]; +int cntVDiamI = 0; + +int ViaRestringO[], ViaRestringI[]; +int cViaRestringO[], cViaRestringI[]; +int cntVringO = 0, cntVringI = 0; + +int ViaStackCnt[]; +string ViaStack[]; +int cntStack = 0; +string StackDrills[]; // 2009-10-15 +string showStackDrills[]; + +int Hole[]; +int cHole[]; +int cntHole = 0; + +string drillRack[]; +real Drilling[]; +int imax = 0; + +string Lbr[]; +int cLbr[]; +int cntLbr = 0; + +string PacName[]; +int cPacName[]; +int cntPacName = 0; +// --- same Value and Package and Layer --- 2005-12-01 alf@cadsoft.de +int cntEVPL = 0; +string EVALpac[]; +string EvalPAC[]; +int cEVPL[], cEVPL1[], cEVPL16[]; + + +int emptyValue = 0; +string empty = "~/-empty-/~"; + +int cntTPelement = 0; // 2010-06-09 +string statisticTestPoint; + +int cntElement = 0; +string Ename[]; +int ELocked[]; +int cntLocked = 0; +real eUsedArea[]; // calculate over xPlace/xDocu/PAD/SMD 12.05.2005 alf@cadsoft.de +int eUsedLayer[]; +real summary_area = 0; + +string EContact[]; // 2009-12-02 +int cntCont = 0; +string EnoContact[]; +int cntNoCont = 0; + + +int art_selected = 0; +int LBRselected; +int PACselected; +int pac_drill[], cntpac_drill[], cnt_d; +int pac_hole[], cntpac_hole[], cnt_h; +int VALselected; +string Element_info = " \n \n \n"; +string linfo = " Double click in listings
    for detailed info
    "; + +string sum; + int sumSignals = 0; + int sumWires = 0; + int minWires = INT_MAX; + int sumARCw = 0; + int minARCw = INT_MAX; + int sumCIRCw = 0; + int minCIRCw = INT_MAX; + int sumCIRCdiam = 0; + int minCIRCdiam = INT_MAX; + int sumRECT = 0; + int sumAnyRECT = 0; + int minRECTx = INT_MAX; + int minRECTy = INT_MAX; + int minClearance = INT_MAX; + int sumPOLYw = 0; + int minPOLYw = INT_MAX; + int sumISOL = 0; + int minISOL = INT_MAX; + int sumSMD = 0; + int minSMDx = INT_MAX; + int minSMDy = INT_MAX; + int sumPADdril = 0; + int minPADdril = INT_MAX; + int sumPADdia = 0; + int minPADdia = INT_MAX; + int sumPADdiaI = 0; + int minPADdiaI = INT_MAX; + int sumPADrest = 0; + int minPADrest = INT_MAX; + int sumPADrestI = 0; + int minPADrestI = INT_MAX; + int sumVIAdril = 0; + int minVIAdril = INT_MAX; + int sumVIAdiam = 0; + int minVIAdiam = INT_MAX; + int sumVIAdiamI = 0; + int minVIAdiamI = INT_MAX; + int sumVIArest = 0; + int minVIArest = INT_MAX; + int sumVIArestI = 0; + int minVIArestI = INT_MAX; + int sumHOLE = 0; + int minHOLE = INT_MAX; + int sumTEXTw = 0; + int minTEXTw = INT_MAX; + int sumPlaceTEXTw = 0; + int minPlaceTEXTw = INT_MAX; + + + int padlSTOP[]; // Mask in Package 2006-04-28 + int smdlSTOP[]; // Mask in Package + int smdlCREAM[]; // Mask in Package + int lSTOPpac[]; // Mask in Package + int lSTOPbrd[]; // Mask in Board + int lCREAMpac[]; // Mask in Package + int lCREAMbrd[]; // Mask in Board + int msort = 0; + +int indexWire[], + indexPolygonWidth[], + indexPolygonIsolate[], + indexSMD[], + indexPadDrill[], + indexPadDia[], + indexiPadDia[], + indexPadRestring[], + indexPadRestringI[], + indexViaDrill[], + indexViaRestringO[], + indexViaRestringI[], + indexViaDiameter[], + indexViaDiameterI[], + indexHole[], + indexArcW[], + indexCirclW[], + indexTextWidth[], + indexPlaceTextWidth[]; + +numeric string statisticWirew[]; +numeric string statisticPolyw[]; +numeric string statisticPoliso[]; +numeric string statisticCLASS[]; +numeric string statisticFalseSignals[]; +numeric string statisticSMD[]; +numeric string statisticPADdril[]; +numeric string statisticPADdiaTOP[]; +numeric string statisticPADdiaBOT[]; +numeric string statisticPADdiaI[]; +numeric string statisticPADrestTOP[]; +numeric string statisticPADrestBOT[]; +numeric string statisticPADrestI[]; +numeric string statisticVIAdril[]; +numeric string statisticVIAdia[]; +numeric string statisticVIAdiaI[]; +numeric string statisticVIArest[]; +numeric string statisticVIArestI[]; +numeric string statisticVIAstack[]; +numeric string statisticHOLE[]; +numeric string statisticARCw[]; +numeric string statisticCIRw[]; +numeric string statisticCIRdiam[]; +numeric string statisticRECT[]; +numeric string statisticRectANYlayer[]; +numeric string statisticTEXTw[]; +numeric string statisticTEXTsize[]; +numeric string statisticPlaceTEXTw[]; +numeric string statisticPlaceTEXTsize[]; +numeric string statisticLBR[]; +numeric string statisticPAC[]; +//numeric string statisticVALUE[]; 2005.12.02 gecancelt +numeric string statisticValPacLay[]; + +string statisticLocked; +string statisticSTOP_CREAM[]; +string Text; + +string ulp_path; +char bkslash = '/'; +int pos = strrchr(argv[0], bkslash); +if (pos >= 0) ulp_path = strsub(argv[0], 0, pos + 1); + +string attention = ""; + +string brdfile; + + +// Functions + +real u2u(int v) { + switch (uval) { + case GRID_UNIT_MIC : return u2mic(v); + break; + + case GRID_UNIT_MM : return u2mm(v); + break; + + case GRID_UNIT_MIL : return u2mil(v); + break; + + case GRID_UNIT_INCH : return u2inch(v); + break; + } +} + + +string value(int v, string is) { + if (v == INT_MAX) return "not used " + is; + string sv; + switch (uval) { + case GRID_UNIT_INCH : sprintf(sv, "%.6f %s", u2inch(v), is); + break; + + case GRID_UNIT_MIL : sprintf(sv, "%.3f %s", u2mil(v), is); + break; + + case GRID_UNIT_MM : sprintf(sv, "%.4f %s", u2mm(v), is); + break; + + case GRID_UNIT_MIC : sprintf(sv, "%.1f %s", u2mic(v), is); + break; + } + return sv; +} + + +string min_value(int v, real minv) { + string sv = "

    "; + switch (uval) { + case GRID_UNIT_INCH : if(u2inch(v) < minv) { + sprintf(sv, "%s < %.4f

    ", attention, minv ); + } + break; + + case GRID_UNIT_MIL : if(u2mil(v) < minv) { + sprintf(sv, "%s < %.4f

    ", attention, minv ); + } + break; + + case GRID_UNIT_MM : if(u2mm(v) < minv) { + sprintf(sv, "%s < %.4f

    ", attention, minv ); + } + break; + + case GRID_UNIT_MIC : if(u2mic(v) < minv) { + sprintf(sv, "%s < %.4f

    ", attention, minv ); + } + break; + } + return sv; +} + + +string check_min_ValueWidth(void) { + string sh; + sprintf(sh, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + value(minWires, " - Wire width "), + min_value(minWires, checkMinWire), + value(minPOLYw, " - Polygon wire width"), + min_value(minPOLYw, checkMinPoly), + value(minARCw, " - Arc width "), + min_value(minARCw, checkMinArc), + value(minCIRCw, " - Circle width "), + min_value(minCIRCw, checkMinCirc), + value(minPADrest, " - Pad Restring "), + min_value(minPADrest, checkMinRestringP), + value(minVIArest, " - Via Restring "), + min_value(minVIArest, checkMinRestringV), + value(minClearance, " - Clearance "), + min_value(minClearance, checkMinClearance), + value(minISOL, " - Isolate Polygon "), + min_value(minISOL, checkMinIsol) + ); + return sh; +} + +string check_min_ValueOther(void) { + string sh; + sprintf(sh, "%s%s%s%s%s%s%s%s%s%s%s%s%s", + value(minTEXTw, " - Text width ") + "

    ", + value(minSMDx, " - SMD X ") + "

    ", + value(minSMDy, " - SMD Y ") + "

    ", + value(minPADdril, " - Pad drill "), + min_value(minPADdril, checkMinPadDrill), + value(minPADrestI, " - Pad Restring Inner.

    "), + value(minVIAdril, " - Via drill "), + min_value(minVIAdril, checkMinViaDrill), + value(minVIArestI, " - Via Restring Inner.

    "), + value(minHOLE, " - Hole drill "), + min_value(minHOLE, checkMinHoleDrill), + value(minRECTx, " - Rectangle X ") + "

    ", + value(minRECTy, " - Rectangle Y ") + ); + return sh; +} + +void AddDrilling(int Size) { + real x; + switch (uval) { + case GRID_UNIT_MIC : x = round(u2mic(Size) * RoundFactor) / RoundFactor; + break; + case GRID_UNIT_MM : x = round(u2mm(Size) * RoundFactor) / RoundFactor; + break; + case GRID_UNIT_MIL : x = round(u2mil(Size) * RoundFactor) / RoundFactor; + break; + case GRID_UNIT_INCH : x = round(u2inch(Size) * RoundFactor) / RoundFactor; + break; + } + + for (int i = imax; --i >= 0; ) + if (Drilling[i] == x) + return; + Drilling[imax++] = x; + return; +} + +void loadminval(void) { + string line[]; + int lines = fileread(line, minvalfile); + checkMinWire = strtod(line[0]); + checkMinArc = strtod(line[1]); + checkMinCirc = strtod(line[2]); + checkMinPoly = strtod(line[3]); + checkMinRestringP = strtod(line[4]); + checkMinRestringV = strtod(line[5]); + checkMinClearance = strtod(line[6]); + checkMinIsol = strtod(line[7]); + checkMinPadDrill = strtod(line[8]); + checkMinViaDrill = strtod(line[9]); + checkMinHoleDrill = strtod(line[10]); + return; +} + + +void saveminval(void) { + output( minvalfile, "wt") { + printf("%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f\n%.4f", + checkMinWire, + checkMinArc, + checkMinCirc, + checkMinPoly, + checkMinRestringP, + checkMinRestringV, + checkMinClearance, + checkMinIsol, + checkMinPadDrill, + checkMinViaDrill, + checkMinHoleDrill ); + } + return; +} + +void GetCheckValues(void) { + dlgDialog("Checked min values") { + dlgGridLayout { + dlgCell( 0, 0) dlgRealEdit( checkMinWire, 0, 10); + dlgCell( 0, 1) dlgLabel("Check minimum Wire width"); + dlgCell( 1, 0) dlgRealEdit( checkMinArc, 0, 10); + dlgCell( 1, 1) dlgLabel("Check minimum ARC width"); + dlgCell( 2, 0) dlgRealEdit( checkMinCirc, 0, 10); + dlgCell( 2, 1) dlgLabel("Check minimum Circle width"); + dlgCell( 3, 0) dlgRealEdit( checkMinPoly, 0, 10); + dlgCell( 3, 1) dlgLabel("Check minimum Polygon width"); + dlgCell( 4, 0) dlgRealEdit( checkMinRestringP, 0, 10); + dlgCell( 4, 1) dlgLabel("Check minimum Pad Restring width"); + dlgCell( 5, 0) dlgRealEdit( checkMinRestringV, 0, 10); + dlgCell( 5, 1) dlgLabel("Check minimum Via Restring width"); + dlgCell( 6, 0) dlgRealEdit( checkMinClearance, 0, 10); + dlgCell( 6, 1) dlgLabel("Check minimum Clearance"); + dlgCell( 7, 0) dlgRealEdit( checkMinIsol, 0, 10); + dlgCell( 7, 1) dlgLabel("Check minimum Polygon Isolate"); + dlgCell( 8, 0) dlgRealEdit( checkMinPadDrill, 0, 10); + dlgCell( 8, 1) dlgLabel("Check minimum Pad drill"); + dlgCell( 9, 0) dlgRealEdit( checkMinViaDrill, 0, 10); + dlgCell( 9, 1) dlgLabel("Check minimum Via drill"); + dlgCell(10, 0) dlgRealEdit( checkMinHoleDrill, 0, 10); + dlgCell(10, 1) dlgLabel("Check minimum Hole drill"); + } + dlgLabel("All Units = " + unit[uval]); + + dlgHBoxLayout { + dlgPushButton("+OK") { + dlgAccept(); + showminValWidth = check_min_ValueWidth(); + showminValOther = check_min_ValueOther(); + } + dlgPushButton("&Save") saveminval(); + dlgPushButton("&Load") loadminval(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + } + }; + return; +} + +string makestrg(string s) { + string rs; + return rs; +} + +string saveReport(void) { + int t = time(); + int n; + string report = "Data Exported from: "; + report += brdfile + "\n"; + report += "with: " + argv[0] + " " + Version + "\n"; + report += "at: " + t2string(t) + "\n"; + report += EAGLE_SIGNATURE + "\n\n"; + report += "all Values in " + unit[uval] + "\n"; + report += brdmaximum + "\n"; + report += brdoutline + "\n\n"; + report += usedLayer + "_________________________\n"; + if (layerError) report += layerError; + report += "\n"; + report += sum + "\n"; + report += "\n============================\n"; + n=0; + if (Unrouted) report += Unrouted + " Unroutet airwires ***\n"; + report += "\n============================\n"; + n=0; //2010-06-09 + report += statisticLocked+"\n"; + report += statisticTestPoint+"\n"; + report += "\n----------------------------\nLAYER\n"; + n=0; + sort(cntalllay, allLayers); + report += "Nb.\tName\tUsed\n"; + for (n = 0; n < cntalllay; n++) { + report+= allLayers[n] + "\n"; + } + report += "\n----------------------------\nCLASS\n"; + n=0; + while (statisticCLASS[n]) { + report += statisticCLASS[n] + "\n"; + n++; + } + report += "\n----------------------------\nWIDTH\n"; + n=0; + while (statisticWirew[n]) { + report += statisticWirew[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticARCw[n]) { + report += statisticARCw[n] + "\n"; + n++; + } + report += wireWidthInternal; + + report += "\n"; n=0; + while (statisticPolyw[n]) { + report += statisticPolyw[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticPoliso[n]) { + report += statisticPoliso[n] + "\n"; + n++; + } + report += "\nPolygon\n"; n=0; + report += "Type\tName\tLayer\tRank\tWidth\n"; + while (PolygonLayer[n]) { + report += PolygonLayer[n] + "\n"; + n++; + } + if (PolyWidthError) report += PolygonError + "\n"; + + report += wireWidthInternal; + report += "\n----------------------------\n"; + n=0; + while (statisticCIRw[n]) { + report += statisticCIRw[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticCIRdiam[n]) { + report += statisticCIRdiam[n] + "\n"; + n++; + } + report += "\n----------------------------\n"; + n=0; + while (statisticTEXTw[n]) { + report += statisticTEXTw[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticTEXTsize[n]) { + report += statisticTEXTsize[n] + "\n"; + n++; + } + report += "\n----------------------------\n"; + n=0; + while (statisticSMD[n]) { + report += statisticSMD[n] + "\n"; n++; + } + report += "\n"; n=0; + while (statisticPADdiaTOP[n]) { + report += statisticPADdiaTOP[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticPADdiaBOT[n]) { + report += statisticPADdiaBOT[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticPADrestTOP[n]) { + report += statisticPADrestTOP[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticPADrestBOT[n]) { + report += statisticPADrestBOT[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticPADdiaI[n]) { + report += statisticPADdiaI[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticPADrestI[n]) { + report += statisticPADrestI[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticVIAdia[n]) { + report += statisticVIAdia[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticVIArest[n]) { + report += statisticVIArest[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticVIAdiaI[n]) { + report += statisticVIAdiaI[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticVIArestI[n]) { + report += statisticVIArestI[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticVIAdril[n]) { + report += statisticVIAdril[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticVIAstack[n]) { + report += statisticVIAstack[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticPADdril[n]) { + report += statisticPADdril[n] + "\n"; + n++; + } + report += "\n----------------------------\n"; + n=0; + while (statisticHOLE[n]) { + report += statisticHOLE[n] + "\n"; n++; + } + report += "\n"; n=0; + while (drillRack[n]) { + report += drillRack[n] + "\n"; n++; + } + report += "\n----------------------------\n"; + n=0; + while (statisticLBR[n]) { + report += statisticLBR[n] + "\n"; n++; + } + report += "\n"; n=0; + while (statisticPAC[n]) { + report += statisticPAC[n] + "\n"; n++; + } + report += "\n"; n=0; + while (statisticValPacLay[n]) { + report += statisticValPacLay[n] + "\n", n++; + } + report += "\n----------------------------\n"; + n=0; + while (statisticRECT[n]) { + report += statisticRECT[n] + "\n"; n++; + } + report += LabelcntRECT + "\n"; + report += "\n----------------------------\n"; + n=0; + + report += statisticRectANYlayer[0] + "\n"; + + report += "\n----------------------------\n"; + n=0; + while (statisticTEXTsize[n]) { + report += statisticTEXTsize[n] + "\n"; + n++; + } + report += LabelcntTextSize + "\n"; + + report += "\n"; n=0; + while (statisticTEXTw[n]) { + report += statisticTEXTw[n] + "\n"; + n++; + } + report += LabelcntTextWidth + "\n"; + + report += "\n"; n=0; + while (statisticPlaceTEXTsize[n]) { + report += statisticPlaceTEXTsize[n] + "\n"; + n++; + } + report += LabelcntPlaceTextSize + "\n"; + + while (statisticPlaceTEXTw[n]) { + report += statisticPlaceTEXTw[n] + "\n"; + n++; + } + report += LabelcntPlaceTextWidth + "\n"; + + report += "\n"; n=0; + while (statisticCIRdiam[n]) { + report += statisticCIRdiam[n] + "\n"; + n++; + } + report += LabelcntCIRCLE + "\n"; + + report += "\n"; + if (falseSignalCnt) { + report += "False signals:\n"; // 2009-02-11 + for (n = 0; n < falseSignalCnt; n++) { + report += statisticFalseSignals[n]+"\n"; + } + } + if (deleteRudimentalSignalName) { // 2009-02-12 + report += "\n"; + report += "Rudimentarily signal name(s):\n"; + report += deleteRudimentalSignalName; + report += "\n"; + } + report += "End report"; + report += "\n"; + return report; +} + + +void drillStackRack(int rack, real drill) { // 2009-10-15 missing 2cnd dimension for array, realize by string(split) + string drillstr; + sprintf(drillstr, "%.2f", drill); // 2012-11-19 reduce real to 2 decimal to compare + string d[]; + string Drills[]; + int cDrills[]; + int cntDrills = strsplit(d, StackDrills[rack], '\t') / 2; // definition : drill \t count \t drill \t count .... + int found = 0; + int n; + + for (n = 0; n <= cntDrills; n++) { + Drills[n] = d[n*2]; + cDrills[n] = strtol(d[n*2+1]); + if (Drills[n] == drillstr){ + cDrills[n]++; + found = 1; + } + } + if (!found) { + Drills[cntDrills] = drillstr; + cDrills[cntDrills]++; + cntDrills++; + } + string s; + StackDrills[rack] = ""; // clear string to generate new, with new counter + for (n = 0; n < cntDrills; n++) { + sprintf(s, "%s\t%d\t", Drills[n], cDrills[n]); + StackDrills[rack]+=s; + } + return; +} + + +void showLayerRack(int sel) { + string d[]; + int cntDrills = strsplit(d, StackDrills[sel], '\t') / 2; // definition : drill \t count \t drill \t count .... + showStackDrills[0] = ""; + int n; + for (n = 0; n < cntDrills; n++) { + sprintf(showStackDrills[n], "%s\t%s", d[n*2], d[n*2+1]); + } + showStackDrills[n] = ""; // clear last string + return; +} + + +void viaStackRack(int start, int end, string comment, real drill) { // 2009-10-15 new drill + string sstack = ""; + sprintf(sstack, "%02d-%02d%s", start, end, comment); + int notfound = 1; + int stc = 0; + for (stc = 0; stc < cntStack; stc ++) { + if (sstack == ViaStack[stc]) { + drillStackRack(stc, drill); // 2009-10-15 add drill to stack rack + ViaStackCnt[stc]++; + notfound = 0; + break; + } + } + if (notfound) { + ViaStack[cntStack] = sstack; // 2009-10-15 add drill to stack rack + drillStackRack(cntStack, drill); // cound drill + ViaStackCnt[cntStack]++; + cntStack++; + } + return; +} + + +real WireLength(int x1, int x2, int y1, int y2) { + return sqrt( pow(u2u(x2) - u2u(x1), 2) + pow( u2u(y2) - u2u(y1), 2)); +} + + +real WireLengthCircle(real r) { + return u2u(r * 2 * PI) ; +} + + +real WireLengthArc(real startangle, real endangle, int r) { + return u2u(r * 2 * PI) / 360 * (endangle - startangle); +} + + +void checkmaxmin(int x1, int x2, int y1, int y2, int width) { + int w = 0; + if (width) w = width/2; // 2005-07-05 alf + if (x1 > maxX) maxX = x1+w; + if (x2 > maxX) maxX = x2+w; + if (y1 > maxY) maxY = y1+w; + if (y2 > maxY) maxY = y2+w; + if (x1 < minX) minX = x1-w; + if (x2 < minX) minX = x2-w; + if (y1 < minY) minY = y1-w; + if (y2 < minY) minY = y2-w; + return; +} + +void checkHole( int x, int y, int drill ) { + checkmaxmin( x - drill/2, x + drill/2, y - drill/2, y + drill/2 , 0); + return; +} + + +void checkarc( int x1, int x2, int y1, int y2, int xc, int yc, real angle1, real angle2, real radius, int width) { + checkmaxmin( x1, x2, y1, y2, width ); + if ( angle2 > angle1 + 270.0) { + if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, yc - radius, width ); + else if( angle1 < 180 ) checkmaxmin( xc - radius, xc + radius, y1 , yc - radius, width ); + else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, yc + radius, width ); + else if( angle1 < 360 ) checkmaxmin( xc + radius, xc - radius, y1 , yc + radius, width ); + } + else if( angle2 > angle1 + 180.0) { + if ( angle1 < 90 ) checkmaxmin( x1 , xc - radius, yc + radius, y2 , width ); + else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, yc - radius, y2 , width ); + else if( angle1 < 270 ) checkmaxmin( x1 , xc + radius, yc - radius, y2 , width ); + else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, yc + radius, y2 , width ); + } + else if( angle2 > angle1 + 90.0 ) { + if ( angle1 < 90 ) checkmaxmin( x1 , x2 , yc + radius, y2 , width ); + else if( angle1 < 180 ) checkmaxmin( x1 , xc - radius, y1 , y2 , width ); + else if( angle1 < 270 ) checkmaxmin( x1 , x2 , yc - radius, y2 , width ); + else if( angle1 < 360 ) checkmaxmin( x1 , xc + radius, y1 , y2 , width ); + } + else { // 2010-10-13 alf + if ( angle1 < 90 && angle2 > 90 ) checkmaxmin( x1 , x2 , yc + radius, y2 , width ); + else if( angle1 < 180 && angle2 > 180 ) checkmaxmin( x1 , xc - radius, y1 , y2 , width ); + else if( angle1 < 270 && angle2 > 270 ) checkmaxmin( x1 , x2 , yc - radius, y2 , width ); + else if( angle1 < 360 && angle2 > 360 ) checkmaxmin( x1 , xc + radius, y1 , y2 , width ); + } + return; +} + + +void checkpad( int x, int y, int diameter1, int diameter16, int shape1, int shape16, int P_elongation) { + int d = diameter1; + int d2 = diameter1 / 2; + if (shape16 == PAD_SHAPE_LONG) d = diameter1 * (diameter1 * P_elongation / 100); + if (shape16 == PAD_SHAPE_OFFSET) d = diameter1 * (diameter1 * P_elongation / 100) * 1.5; + checkmaxmin( x + d2, x - d2, y + d2, y - d2, 0 ); + return; +} + + +void checksmd( int x, int y, int smddx, int smddy, int Layer) { + int dx2 = smddx / 2; + int dy2 = smddx / 2; + checkmaxmin( x + dx2, x - dx2, y + dy2, y - dy2, 0 ); + return; +} + + +real ArcLength(real ang1, real ang2, real radius) { + return radius * 2 * PI / 360 * (ang2 - ang1); +} + + +string NetClassLabel(string ClassName , int cnt) { + string s; + sprintf(s, "CLASS %s : %d Netze", ClassName , cnt); + return s; +} + + +string isempty(string s) { + if (!s) s = empty; + return s; +} + + +void list_pac_drills(int drill) { + int n; + for ( n = 0; n <= cnt_d; n++) { + if (pac_drill[n] == drill) { + cntpac_drill[n]++; + break; + } + } + if (n > cnt_d) { // a new drill + cnt_d++; + pac_drill[cnt_d] = drill; + cntpac_drill[cnt_d]++; + pac_drill[cnt_d+1] = 0; + } + return; +} + + +void list_pac_holes(int drill) { + int n; + for ( n = 0; n <= cnt_h; n++) { + if (pac_hole[n] == drill) { + cntpac_hole[n]++; + break; + } + } + if (n > cnt_h) { // a new drill + cnt_h++; + pac_hole[cnt_h] = drill; + cntpac_hole[cnt_h]++; + pac_hole[cnt_h+1] = 0; + } + return; +} + + +string infoDril(UL_ELEMENT E) { + string s, h; + cnt_d = -1; + cnt_h = -1; + cntpac_drill[0] = 0; + cntpac_hole[0] = 0; + E.package.holes(H) list_pac_holes(H.drill); + + if (cnt_d > -1) { + s += "Drills:\n"; + for (int n = 0; n <= cnt_d; n++) { + sprintf(h, "%d\t%.4f mm\n", cntpac_drill[n], u2mm(pac_drill[n]) ); + s += h; + } + } + if (cnt_h > -1) { + s += "Holes:\n"; + for (int n = 0; n <= cnt_h; n++) { + sprintf(h, "%d\t%.4f mm\n", cntpac_hole[n], u2mm(pac_hole[n]) ); + s += h; + } + } + if (cnt_d > -1 || cnt_h > -1) s += "------\n"; + return s; +} + +void infoLBR( string val) { + linfo = "Element : Value : Package"; + string s, M; + board(B) { + B.elements(E) { + if (E.package.library == val) { + sprintf(s, "%s %s(%.3f %.3f)\t: %s\t: %s\n", E.name, M, u2u(E.x), u2u(E.y), isempty(E.value), E.package.name); + Element_info += s; + } + } + } + return; +} + +void infoPAC( string val) { + linfo = "Element : Value : Library"; + string s, M; + int getdrill = 0; + board(B) B.elements(E) if (E.package.name == val) { + if (E.mirror) M = "Bot "; + else M = "Top "; + if (!getdrill) { + Element_info += infoDril(E); + getdrill++; + } + sprintf(s, "%s %s(%.3f %.3f)\t: %s\t: %s\n", E.name, M, u2u(E.x), u2u(E.y), isempty(E.value), E.package.library); + Element_info += s; + } + return; +} + + +void infoVAL( string val) { + string s, M; + int pos = strstr(val, empty); + if (pos == 0) { + linfo = "Package : Library"; + val = strsub(val, strlen(empty)); + board(B) B.elements(E) if (E.name == val) { + sprintf(Element_info, "Value empty/leer\n"); + if (E.mirror) M = "Bot "; + else M = "Top "; + sprintf(s, "%s %s(%.3f %.3f) %s\t: %s\n", E.name, M, u2u(E.x), u2u(E.y), E.package.name, E.package.library); + Element_info += s; + } + + } + else { + linfo = "Element : Package : Library"; + board(B) B.elements(E) if (E.value == val) { + if (E.mirror) M = "Bot "; + else M = "Top "; + sprintf(s, "%s %s(%.3f %.3f)\t: %s\t: %s\n\n", E.name, M, u2u(E.x), u2u(E.y), E.package.name, E.package.library); + Element_info += s; + } + } + return; +} + + +void get_Info(int art, string val) { + Element_info = ""; + int pos = strchr(val, '\t', 0); + val = strsub(val, 0, pos); + switch(art) { + case 1 : infoLBR(val); + break; + + case 2 : infoPAC(val); + break; + + case 3 : infoVAL(val); + break; + + default : break; + } + return; +} + + +void resetMaxMin(void) { + maxX = INT_MIN; + minX = INT_MAX; + maxY = INT_MIN; + minY = INT_MAX; + return; +} + + +// *** used area in board to calculate if board area enuff *** + +real used_area(UL_ELEMENT E) { + resetMaxMin(); + E.package.circles(C) { + if (C.layer == 1 || C.layer == 16 || C.layer == 21 || C.layer == 22 || C.layer == 51 || C.layer == 52 ) + checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius, C.width ); + } + E.package.wires(W) { + if (W.layer == 1 || W.layer == 16 || W.layer == 21 || W.layer == 22 || W.layer == 51 || W.layer == 52 ) { + if (W.arc) { + checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius, W.width); + } + else checkmaxmin( W.x1, W.x2, W.y1, W.y2, W.width ); + } + } + E.package.contacts(CON) { + if (CON.pad) checkpad(CON.pad.x, CON.pad.y, CON.pad.diameter[1], CON.pad.diameter[16], CON.pad.shape[1], CON.pad.shape[16], CON.pad.elongation); + else checksmd(CON.smd.x, CON.smd.y, CON.smd.dx[CON.smd.layer], CON.smd.dy[CON.smd.layer], CON.smd.layer); + } + E.package.holes(H) checkHole( H.x, H.y, H.drill ); + E.package.rectangles(R) { + if (R.layer == 1 || R.layer == 16 || R.layer == 21 || R.layer == 22 || R.layer == 51 || R.layer == 52 ) + checkmaxmin( R.x1, R.x2, R.y1, R.y2, 0 ); + } + E.package.texts(T) { + T.wires(W) { + if (W.layer == 1 || W.layer == 16 || W.layer == 21 || W.layer == 22 || W.layer == 51 || W.layer == 52 ) { + if (W.arc) { + checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius, W.width); + } + else checkmaxmin( W.x1, W.x2, W.y1, W.y2, W.width ); + } + } + } + int mx = maxX - minX; + int my = maxY - minY; + return u2u(mx) * u2u(my); +} + + +// main +if (board) { + board(B) { + brdfile = B.name; + int n; + string usedLayers; + string displayUnrouted; + status("Layer"); + B.layers(L) { + string sl; + sprintf(sl, "%3d\t%s\t%d", L.number, L.name, L.used); + allLayers[cntalllay] = sl; + cntalllay++; + string Lnam = L.name; + if (Lnam[0] == '$') { + SupplyLayers[L.number] = 1; // 2009-07-15 check polygon on supply layer + SupplyLayerName[L.number] = L.name; + } + if (L.used && L.number >=1 && L.number <= 16) { + cntLayer++; + sprintf(sl, "%2d %s\n", L.number, L.name); + usedLayers += sl; + if (L.number == 1 || L.number == 16) { + sl = L.name; + if (sl[0] == '$') { + sprintf( sl, "Do not use Layer %.d %s for Powerplane! '$' in Layer Name.", L.number, L.name); + layerError += "\n" + sl; + sprintf( sl, "
    Do not use Layer %.d %s for Powerplane!", L.number, L.name); + displayLayerError += sl; + } + } + } + } + if (layerError) { + layerError += "\n\nUse only inner layer (2 to 15) for Powerplane!\n"; + displayLayerError = "" + displayLayerError + "

    " + + "
    Only use layer 2 - 15 for power planes.
    "; + dlgMessageBox(displayLayerError, "Ok"); + } + sprintf(usedLayer, "used layers %d\n\n%s", cntLayer, usedLayers); + + status("Elements"); + B.elements(E) { + // calculate over xPlace/xDocu/PAD/SMD 12.05.2005 alf@cadsoft.de + if (E.locked) cntLocked++; + if (strstr(E.name, "TP") == 0) cntTPelement++; // 2010-06-09 TP = Testpoint + else { + cntElement++; + Ename[cntElement] = E.name; + ELocked[cntElement] = E.locked; + eUsedLayer[cntElement] = E.mirror; + eUsedArea[cntElement] = used_area(E); // berechne für jedes Element(Package) den benötigten Platz + summary_area += eUsedArea[cntElement]; + } + int cont = 0; // 2009-12-02 package with or without contacts + E.package.contacts(C) { + if (C.pad) list_pac_drills(C.pad.drill); + cont = 1; + } + if (cont) { + EContact[cntCont] = E.name; + cntCont++; + } + else { + sprintf(EnoContact[cntNoCont], "%s\t%s", E.name, E.package.name); + cntNoCont++; + } + } + + resetMaxMin(); + status("Wires"); + B.wires(W) { + if (W.layer == 20) { + if (W.arc) { + outlines += ArcLength(W.arc.angle1, W.arc.angle2, u2u(W.arc.radius)); + checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius, W.width); + } + else { + outlines += WireLength(W.x1, W.x2, W.y1, W.y2); + checkmaxmin( W.x1, W.x2, W.y1, W.y2, W.width ); + } + } + } + status("Circles"); + B.circles(C) { + if (C.layer == 20) { + outlines += WireLengthCircle(C.radius); + checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius, C.width ); + } + } + B.elements(E) { + status("Element:"+E.name); + +/* zombie + if (E.name == "U$1") { + string hh; + sprintf(hh, "%s = %s : %.4f %.4f", E.name, E.value, u2u(E.x), u2u(E.y) ); + if (dlgMessageBox(hh, "OK", "Cancel") != 0) exit(-999); + } +zombie */ + + E.package.wires(W) { + if (W.layer == 20) { // *** Dimension in Packages *** + if (W.arc) { + outlines += ArcLength(W.arc.angle1, W.arc.angle2, u2u(W.arc.radius)); + checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius, W.width); + } + else { + outlines += WireLength(W.x1, W.x2, W.y1, W.y2); + checkmaxmin( W.x1, W.x2, W.y1, W.y2, W.width ); + } + } + } + E.package.circles(C) { + if (C.layer == 20) { + outlines += WireLengthCircle(C.radius); + checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius, C.width ); + } + if (C.layer == 29) lSTOPpac[0]++; // count circle in Stop-Layer 2006-04-28 + if (C.layer == 30) lSTOPpac[1]++; + if (C.layer == 31) lCREAMpac[0]++; // count circle in Cream-Layer + if (C.layer == 32) lCREAMpac[1]++; + } + E.package.polygons(P) { + if (!P.width) PolyWidthError = 1; + P.wires(W) { + if (W.width < 10) { + sprintf(PolygonLayer[cPolygonL], "Package\t%s.PAC \t%d\t%d\t%.4f", E.package.name, W.layer, P.rank, u2mm(P.width)); + cPolygonL++; + } + break; + } + if (P.layer == 29) lSTOPpac[0]++; // count polygon in Stop-Layer 2006-04-28 + if (P.layer == 30) lSTOPpac[1]++; + if (P.layer == 31) lCREAMpac[0]++; // count polygon in Cream-Layer + if (P.layer == 32) lCREAMpac[1]++; + } + E.package.rectangles(R) { + if (R.layer == 29) lSTOPpac[0]++; // count rect in Stop-Layer 2006-04-28 + if (R.layer == 30) lSTOPpac[1]++; + if (R.layer == 31) lCREAMpac[0]++; // count rect in Cream-Layer + if (R.layer == 32) lCREAMpac[1]++; + } + } + + if (outlines) { + sprintf(brdoutline, "Outline contour = %.2f", outlines); + sprintf(brdmaximum, "max. Board length (Layer 20)\nX = %.2f\nY = %.2f", WireLength(minX, maxX, 0,0), WireLength(minY, maxY, 0, 0) ); + } + + B.classes(CL) { + // Net classes ******************** + NetClassNr[CL.number] = CL.number; + NetClassName[CL.number] = CL.name; + NetClassWidth[CL.number] = CL.width; + NetClassClear[CL.number] = CL.clearance; + NetClassDrill[CL.number] = CL.drill; + cNetClass[CL.number] = 0; + } + B.signals(S) { + status("Signal:"+S.name); + int true = 0; // only signal if connected to pad or smd is a true signal 2005-12-08 alf@cadsoft.de + S.contactrefs(C) { + true = 1; + break; + } + if (true) { + cNetClass[S.class.number]++; + sumSignals++; + SignalName[SignalCnt] = S.name; + SignalClass[SignalCnt] = S.class.number; + SignalCnt++; + SignalClassList[S.class.number] += S.name + "\n"; + } + else { + S.vias(V) { + cntfalseSignalVias[falseSignalCnt]++; + sprintf(FalsWxy[falseSignalCnt], "(%.4f %.4f) L %d-%d", u2mm(V.x), u2mm(V.y), V.start, V.end); + + } + S.wires(W) { + cntfalseSignalWires[falseSignalCnt]++; + sprintf(FalsWxy[falseSignalCnt], "(%.4f %.4f) L %d", u2mm(W.x1), u2mm(W.y1), W.layer); + } + if (cntfalseSignalWires[falseSignalCnt] || cntfalseSignalVias[falseSignalCnt]) { // 2009-02-12 + falseSignalList[falseSignalCnt] = S.name; // only signal if connected to pad or smd is a true signal + falseSignalCnt++; + } + else { + string s; + sprintf(s, "WIRE '%s' (%.4f %.4f) (%.4f %.4f);DELETE (%.4f %.4f);\n", + S.name, + u2mm(B.area.x1)-1.0, u2mm(B.area.y1)-1.0, + u2mm(B.area.x1)-2.0, u2mm(B.area.y1)-1.0, + u2mm(B.area.x1)-1.0, u2mm(B.area.y1)-1.0 + ); + deleteRudimentalSignalName+=s; + } + } + + // Wires ******************** + S.wires(W) { + if (W.layer < 19) { + if (W.arc) { + for (int n = 0; n <= cntArc; n++) { + if (ArcWidth[n] == W.arc.width) { + cArcWidth[n]++; + break; + } + } + if (n > cntArc) { + cntArc++; + ArcWidth[cntArc] = W.arc.width; + cArcWidth[cntArc]++; + } + } + else { + for (n = 0; n <= cntWire; n++) { + if (WireWidth[n] == W.width) { + cWireWidth[n]++; + break; + } + } + if (n > cntWire) { + cntWire++; + WireWidth[cntWire] = W.width; + cWireWidth[cntWire]++; + } + } + } + else { + SignalUnrouted++; + } + } + + // Polygone ********************* + S.polygons(P) { + // Polygon Wire width ********* + if (SupplyLayers[P.layer]) { + SupplyLayersUsedPolygons[P.layer]++; + } + if (!P.width) PolyWidthError = 1; + P.wires(W) { + sprintf(PolygonLayer[cPolygonL], "Signal\t%s\t%d\t%d\t%.3f", S.name, P.layer, P.rank, u2mm(W.width) ); + // Polygon Rank 19.07.2005 alf + cPolygonL++; + break; + } + for (n = 0; n <= cntPolyW; n++) { + if (PolygonWidth[n] == P.width) { + cPolygonWidth[n]++; + break; + } + } + if (n > cntPolyW) { + cntPolyW++; + PolygonWidth[cntPolyW] = P.width; + cPolygonWidth[cntPolyW]++; + } + // Polygon isolate ********* + for (n = 0; n <= cntPolyIso; n++) { + if (PolygonIsolate[n] == P.isolate) { + cPolygonIsolate[n]++; + break; + } + } + if (n > cntPolyIso) { + cntPolyIso++; + PolygonIsolate[cntPolyIso] = P.isolate; + cPolygonIsolate[cntPolyIso]++; + } + } + + // Vias ********************* + S.vias(V) { + cntVias ++; // 2012-05-24 + // Vias Drill ********************* + int n; + for (n = 0; n <= cntVDril; n++) { + if (ViaDrill[n] == V.drill) { + cViaDrill[n]++; + break; + } + } //2012-11-19 + if (n > cntVDril) { + cntVDril++; + ViaDrill[cntVDril] = V.drill; + cViaDrill[cntVDril]++; + } + // Vias Diameter TOP ********************* + for (n = 0; n <= cntVDiam; n++) { + if (ViaDiameter[n] == V.diameter[LAYER_BOTTOM]) { + cViaDiameter[n]++; + break; + } + } + if (n > cntVDiam) { + cntVDiam++; + ViaDiameter[cntVDiam] = V.diameter[LAYER_BOTTOM]; + cViaDiameter[cntVDiam]++; + } + + // Vias Diameter Inner Layer ********************* + for (n = 0; n <= cntVDiamI; n++) { + if (ViaDiameterI[n] == V.diameter[2]) { + cViaDiameterI[n]++; + break; + } + } + if (n > cntVDiamI) { + cntVDiamI++; + ViaDiameterI[cntVDiamI] = V.diameter[2]; + cViaDiameterI[cntVDiamI]++; + } + + // Vias Restring Top Bottom ********************* + int VRestringO = (V.diameter[LAYER_BOTTOM] - V.drill ) / 2; + for (n = 0; n <= cntVringO; n++) { + if (ViaRestringO[n] == VRestringO) { + cViaRestringO[n]++; + break; + } + } + if (n > cntVringO) { + cntVringO++; + ViaRestringO[cntVringO] = VRestringO; + cViaRestringO[cntVringO]++; + } + // Vias Restring Inner Layer ********************* + int VRestringI = (V.diameter[2] - V.drill ) / 2; + for (n = 0; n <= cntVringI; n++) { + if (ViaRestringI[n] == VRestringI) { + cViaRestringI[n]++; + break; + } + } + if (n > cntVringI) { + cntVringI++; + ViaRestringI[cntVringI] = VRestringI; + cViaRestringI[cntVringI]++; + } + viaStackRack(V.start, V.end, "", u2mm(V.drill)); + } + S.contactrefs(C) { + cnt_pad_on_signal++; + } + } + + B.holes(H) { + // Holes Board ********************* + for (int n = 0; n <= cntHole; n++) { + if (Hole[n] == H.drill) { + cHole[n]++; + break; + } + } + if (n > cntHole) { + cntHole++; + Hole[cntHole] = H.drill; + cHole[cntHole]++; + } + } + B.circles(C) { + if (C.layer < 19) { + int n; + for (n = 0; n < cntCircl; n++) { // 2012-01-11 + if (CirclWidth[n] == C.width) { + cCirclWidth[n]++; + break; + } + } + if (n == cntCircl ) { // 2012-01-11 + CirclWidth[cntCircl] = C.width; + cCirclWidth[cntCircl]++; + cntCircl++; + } + for (n = 0; n < cntCirclDiam; n++) { // 2012-01-11 + if (CirclDiam[n] == C.radius*2) { + cCirclDiam[n]++; + break; + } + } + if (n == cntCirclDiam ) { // 2012-01-11 + CirclDiam[cntCirclDiam] = C.radius*2; + cCirclDiam[cntCirclDiam]++; // 2012-01-11 + cntCirclDiam++; + } + sumcntCircl++; + } + if (C.layer == 29) lSTOPbrd[0]++; // count circle in Stop-Layer 2006-04-28 + if (C.layer == 30) lSTOPbrd[1]++; + if (C.layer == 31) lCREAMbrd[0]++; // count circle in Cream-Layer + if (C.layer == 32) lCREAMbrd[1]++; + } + + B.rectangles(R) { + if (R.layer < 19) { + int r_x = R.x2 - R.x1; + int r_y = R.y2 - R.y1; + for (int n = 0; n < cntRECT; n++) { + if ( RECTx[n] == r_x && RECTy[n] == r_y ) { + cRECT[n]++; + break; + } + } + if (n == cntRECT ) { + RECTx[cntRECT] = r_x; + RECTy[cntRECT] = r_y; + cRECT[cntRECT]++; + cntRECT++; + } + sumcntRECT++; + } + else if (R.layer == 29) lSTOPbrd[0]++; // count rect in Stop-Layer 2006-04-28 + else if (R.layer == 30) lSTOPbrd[1]++; + else if (R.layer == 31) lCREAMbrd[0]++; // count rect in Cream-Layer + else if (R.layer == 32) lCREAMbrd[1]++; + else cntRectANYlayer[R.layer]++; + } + status("Text"); + B.texts(T) { + if (T.layer < 19) { + for (int n = 0; n <= cntTextSize; n++) { + if (TextSize[n] == T.size) { + cTextSize[n]++; + break; + } + } + if (n > cntTextSize) { + cntTextSize++; + TextSize[cntTextSize] = T.size; + cTextSize[cntTextSize]++; + } + T.wires(W) { + for (int n = 0; n <= cntTextWidth; n++) { + if (TextWidth[n] == W.width) { + cTextWidth[n]++; + break; + } + } + if (n > cntTextWidth) { + cntTextWidth++; + TextWidth[cntTextWidth] = W.width; + cTextWidth[cntTextWidth]++; + } + break; + } + } + if (T.layer >= 21 && T.layer <= 27) { + for (int n = 0; n <= cntPlaceTextSize; n++) { + if (PlaceTextSize[n] == T.size) { + cPlaceTextSize[n]++; + break; + } + } + if (n > cntPlaceTextSize) { + cntPlaceTextSize++; + PlaceTextSize[cntPlaceTextSize] = T.size; + cPlaceTextSize[cntPlaceTextSize]++; + } + T.wires(W) { + for (int n = 0; n <= cntPlaceTextWidth; n++) { + if (PlaceTextWidth[n] == W.width) { + cPlaceTextWidth[n]++; + break; + } + } + if (n > cntPlaceTextWidth) { + cntPlaceTextWidth++; + PlaceTextWidth[cntPlaceTextWidth] = W.width; + cPlaceTextWidth[cntPlaceTextWidth]++; + } + break; + } + } + } + + B.polygons(P) { + if (P.layer == 29) lSTOPbrd[0]++; // count polygon in Stop-Layer 2006-04-28 + if (P.layer == 30) lSTOPbrd[1]++; + if (P.layer == 31) lCREAMbrd[0]++; // count polygon in Cream-Layer + if (P.layer == 32) lCREAMbrd[1]++; + } + + B.elements(E) { + status("Package:"+E.package.name); + E.package.holes(H) { + // Holes Board ********************* + for (int n = 0; n <= cntHole; n++) { + if (Hole[n] == H.drill) { + cHole[n]++; + break; + } + } + if (n > cntHole) { + cntHole++; + Hole[cntHole] = H.drill; + cHole[cntHole]++; + } + } + + E.package.contacts(C) { + if (C.smd) { + if (C.smd.layer == LAYER_TOP) cntSMDt++; + else cntSMDb++; + for (int n = 0; n <= cntSMD; n++) { + if ( (SMDx[n] == C.smd.dx && SMDy[n] == C.smd.dy && rSMD[n] == C.smd.roundness) ) { // 2010-03-10 + cSMD[n]++; + break; + } + } + if (n > cntSMD) { + cntSMD++; + SMDx[cntSMD] = C.smd.dx; + SMDy[cntSMD] = C.smd.dy; + rSMD[cntSMD] = C.smd.roundness; // 2010-03-10 + cSMD[cntSMD]++; + } + } + + if (C.pad) { + // Drills + viaStackRack(1, 16, "-PAD", u2mm(C.pad.drill)); // 2011-05-03 mark stack as pad in layer rack + for ( n = 0; n <= cntPDril; n++) { + if (PadDrill[n] == C.pad.drill) { + cPadDrill[n]++; + break; + } + } + if (n > cntPDril) { // a new drill + cntPDril++; + PadDrill[cntPDril] = C.pad.drill; + cPadDrill[cntPDril]++; + } + // Bottom layer + for ( n = 0; n <= cntPDiamBOT; n++) { + if (PadDiameterBOT[n] == C.pad.diameter[LAYER_BOTTOM]) { + cPadDiameterBOT[n]++; + break; + } + } + if (n > cntPDiamBOT) { + cntPDiamBOT++; + PadDiameterBOT[cntPDiamBOT] = C.pad.diameter[LAYER_BOTTOM]; + cPadDiameterBOT[cntPDiamBOT]++; + } + // Top layer + for (n = 0; n <= cntPDiamTOP; n++) { + if (PadDiameterTOP[n] == C.pad.diameter[LAYER_TOP]) { + cPadDiameterTOP[n]++; + break; + } + } + if (n > cntPDiamTOP) { + cntPDiamTOP++; + PadDiameterTOP[cntPDiamTOP] = C.pad.diameter[LAYER_TOP]; + cPadDiameterTOP[cntPDiamTOP]++; + } + // Inner layer + for ( n = 0; n <= cntiPDiam; n++) { + if (iPadDiameter[n] == C.pad.diameter[2]) { + ciPadDiameter[n]++; + break; + } + } + if (n > cntiPDiam) { + cntiPDiam++; + iPadDiameter[cntiPDiam] = C.pad.diameter[2]; + ciPadDiameter[cntiPDiam]++; + } + // Top-Restring ************************* + int Trestring = (C.pad.diameter[LAYER_TOP] - C.pad.drill) / 2; + for ( n = 0; n <= cntPringTOP; n++) { + if (PadRestringTOP[n] == Trestring) { + cPadRestringTOP[n]++; + break; + } + } + if (n > cntPringTOP) { + cntPringTOP++; + PadRestringTOP[cntPringTOP] = Trestring; + cPadRestringTOP[cntPringTOP]++; + } + + // Bottom-Restring ************************* + int Brestring = (C.pad.diameter[LAYER_BOTTOM] - C.pad.drill) / 2; + for ( n = 0; n <= cntPringBOT; n++) { + if (PadRestringBOT[n] == Brestring) { + cPadRestringBOT[n]++; + break; + } + } + if (n > cntPringBOT) { + cntPringBOT++; + PadRestringBOT[cntPringBOT] = Brestring; + cPadRestringBOT[cntPringBOT]++; + } + + // Inner-Restring ************************* + int Irestring = (C.pad.diameter[2] - C.pad.drill) / 2; + for ( n = 0; n <= cntPringI; n++) { + if (PadRestringI[n] == Irestring) { + cPadRestringI[n]++; + break; + } + } + if (n > cntPringI) { + cntPringI++; + PadRestringI[cntPringI] = Irestring; + cPadRestringI[cntPringI]++; + } + int schape = C.pad.shape[LAYER_TOP]; + schape = C.pad.shape[LAYER_BOTTOM]; + schape = C.pad.shape[2]; + } + } + // Texte in Package [copper] + E.package.texts(T) { + if (T.layer < 19) { + T.wires(W) { + for (int n = 0; n <= cntTextWidth; n++) { + if (TextWidth[n] == W.width) { + cTextWidth[n]++; + break; + } + } + if (n > cntTextWidth) { + cntTextWidth++; + TextWidth[cntTextWidth] = W.width; + cTextWidth[cntTextWidth]++; + } + break; + } + } + if (T.layer >= 21 && T.layer <= 27) { + for (int n = 0; n <= cntPlaceTextSize; n++) { + if (PlaceTextSize[n] == T.size) { + cPlaceTextSize[n]++; + break; + } + } + if (n > cntPlaceTextSize) { + cntPlaceTextSize++; + PlaceTextSize[cntPlaceTextSize] = T.size; + cPlaceTextSize[cntPlaceTextSize]++; + } + T.wires(W) { + for (int n = 0; n <= cntPlaceTextWidth; n++) { + if (PlaceTextWidth[n] == W.width) { + cPlaceTextWidth[n]++; + break; + } + } + if (n > cntPlaceTextWidth) { + cntPlaceTextWidth++; + PlaceTextWidth[cntPlaceTextWidth] = W.width; + cPlaceTextWidth[cntPlaceTextWidth]++; + } + break; + } + } + } + + // Wires in Package [copper] + E.package.wires(W) { + if (W.layer < 19) { + for (n = 0; n <= cntWire; n++) { + if (WireWidth[n] == W.width) { + cWireWidth[n]++; + break; + } + } + if (n > cntWire) { + cntWire++; + WireWidth[cntWire] = W.width; + cWireWidth[cntWire]++; + } + } + } + + // Polygon wires in Package [copper] + E.package.polygons(P) { + if (P.layer < 19) { + for (n = 0; n <= cntPolyW; n++) { + if (PolygonWidth[n] == P.width) { + cPolygonWidth[n]++; + break; + } + } + if (n > cntPolyW) { + cntPolyW++; + PolygonWidth[cntPolyW] = P.width; + cPolygonWidth[cntPolyW]++; + } + // Polygon isolate ********* + for (n = 0; n <= cntPolyIso; n++) { + if (PolygonIsolate[n] == P.isolate) { + cPolygonIsolate[n]++; + break; + } + } + if (n > cntPolyIso) { + cntPolyIso++; + PolygonIsolate[cntPolyIso] = P.isolate; + cPolygonIsolate[cntPolyIso]++; + } + } + } + + // Rectangles in Package [copper] + E.package.rectangles(R) { + if (R.layer < 19) { + int r_x = R.x2 - R.x1; + int r_y = R.y2 - R.y1; + for (int n = 0; n <= cntRECT; n++) { + if ( RECTx[n] == r_x && RECTy[n] == r_y ) { + cRECT[n]++; + break; + } + } + if (n > cntRECT ) { + cntRECT++; + RECTx[cntRECT] = r_x; + RECTy[cntRECT] = r_y; + cRECT[cntRECT]++; + } + } + } + + // Circles in Package [copper] + E.package.circles(C) { + if (C.layer < 19) { + for (int n = 0; n <= cntCircl; n++) { + if (CirclWidth[n] == C.width) { + cCirclWidth[n]++; + break; + } + } + if (n > cntCircl ) { + cntCircl++; + CirclWidth[cntCircl] = C.width; + cCirclWidth[cntCircl]++; + } + for (n = 0; n <= cntCirclDiam; n++) { + if (CirclDiam[n] == C.radius*2) { + cCirclDiam[n]++; + break; + } + } + if (n > cntCirclDiam ) { + cntCirclDiam++; + CirclDiam[cntCircl] = C.radius*2; + cCirclDiam[cntCirclDiam]++; + } + sumcntCircl++; + } + if (C.layer == 29) lSTOPbrd[0]++; // count circle in Stop-Layer 2006-04-28 + if (C.layer == 30) lSTOPbrd[1]++; + if (C.layer == 31) lCREAMbrd[0]++; // count circle in Cream-Layer + if (C.layer == 32) lCREAMbrd[1]++; + } + + // Masks in in Package + E.package.contacts(C) { + if (C.pad) { + if (C.pad.flags && PAD_FLAG_STOP) { + padlSTOP[0]++; // top + padlSTOP[1]++; // bottom + } + } + if (C.smd) { + if (C.smd.flags && SMD_FLAG_STOP) smdlSTOP[E.mirror]++; + if (C.smd.flags && SMD_FLAG_CREAM) smdlCREAM[E.mirror]++; + } + } + + // Element Libraries ********* + for (n = 0; n <= cntLbr; n++) { + if (Lbr[n] == E.package.library) { + cLbr[n]++; + break; + } + } + if (n > cntLbr) { + cntLbr++; + Lbr[cntLbr] = E.package.library; + cLbr[cntLbr]++; + } + // Element Package ********* + for (n = 0; n <= cntPacName; n++) { + if (PacName[n] == E.package.name) { + cPacName[n]++; + break; + } + } + if (n > cntPacName) { + cntPacName++; + PacName[cntPacName] = E.package.name; + cPacName[cntPacName]++; + } + + // Element Value ********* 2005-12-01 alf@cadsoft.de +/* + // -------- List by Value ------------ + for (n = 0; n <= cntEValue; n++) { + if (EValue[n] == Ev) { + cEValue[n]++; + break; + } + } + if (n > cntEValue) { + cntEValue++; + EValue[cntEValue] = Ev; + cEValue[cntEValue]++; + } +*/ + // ----- List by Value/Package/Layer ----------- + string Ev = E.value; + if (Ev == "") { + Ev = empty + E.name; + emptyValue++; + } + for (n = 0; n <= cntEVPL; n++) { + if (EVALpac[n] == Ev && EvalPAC[n] == E.package.name ) { + cEVPL[n]++; + if (E.mirror) cEVPL16[n]++; + else cEVPL1[n]++; + break; + } + } + if (n > cntEVPL) { + cntEVPL++; + EVALpac[cntEVPL] = Ev; + EvalPAC[cntEVPL] = E.package.name; + cEVPL[cntEVPL]++; + if (E.mirror) cEVPL16[cntEVPL]++; + else cEVPL1[cntEVPL]++; + } + } + status("creat list"); + + if (PolyWidthError) PolygonError = "! *** Do not use WIRE WIDTH 0 for Polygon if generate Gerber-Data *** !"; + int x = 0; + // Statistic tabels + // Net Class ******************** 2014-11-27 support of 16 netclasses -ric + statisticCLASS[x] = "# \tName\tmin. Width\tClearance\tmin. Drill\tUsed"; + for (n = 0; n < 16; n++) { + if (NetClassName[n]) { + if(minClearance > NetClassClear[n]) minClearance = NetClassClear[n]; + x++; + sprintf(statisticCLASS[x], "%1d\t%s\t%s\t%s\t%s\t%-4d", + NetClassNr[n], + NetClassName[n], + value(NetClassWidth[n], ""), + value(NetClassClear[n], ""), + value(NetClassDrill[n], ""), + cNetClass[n] + ); + selNetClassNr[x] = NetClassNr[n]; + } + } + + x = 0; + // false Signals ******************** 2005-12-08 alf@cadsoft.de + statisticFalseSignals[x] = "Signal-Name\tVias\tCoordinate Layer"; + for (n = 0; n < falseSignalCnt; n++) { + x++; + sprintf( statisticFalseSignals[x], "%s\t%d\t%s", + falseSignalList[n], // only signal if connected to pad or smd is a true signal 2005-12-08 alf@cadsoft.de + cntfalseSignalVias[n], + FalsWxy[n] + ); + } + + // ************* Wire statistic ***************** + x = 0; + statisticWirew[x] = "WIRE\tQ."; + for (n = 0; n <= cntWire; n++) { + if (cWireWidth[n]) { + sumWires += cWireWidth[n]; + if(minWires > WireWidth[n]) minWires = WireWidth[n]; + x++; + sprintf(statisticWirew[x], "%s\t%-4d", value(WireWidth[n], ""), cWireWidth[n] ); + } + } + + x = 0; + statisticARCw[x] = "ARC\tQ."; + for ( n = 0; n <= cntArc; n++) { + if (cArcWidth[n]) { + sumARCw += cArcWidth[n]; + if(minARCw > ArcWidth[n]) minARCw = ArcWidth[n]; + x++; + sprintf(statisticARCw[x], "%s\t%-4d", value(ArcWidth[n], ""), cArcWidth[n] ); + } + } + + x = 0; + statisticCIRw[x] = "CIRCLE (width)\tQ."; + for ( n = 0; n <= cntCircl; n++) { + if (cCirclWidth[n]) { + sumCIRCw += cCirclWidth[n]; + if(minCIRCw > CirclWidth[n]) minCIRCw = CirclWidth[n]; + x++; + sprintf(statisticCIRw[x], "%s\t%-4d", value(CirclWidth[n], ""), cCirclWidth[n] ); + } + } + + x = 0; + statisticCIRdiam[x] = "CIRCLE diam.\tQ."; + for ( n = 0; n <= cntCirclDiam; n++) { + if (cCirclDiam[n]) { + sumCIRCdiam += cCirclDiam[n]; + if(minCIRCdiam > CirclDiam[n]) minCIRCdiam = CirclDiam[n]; + x++; + sprintf(statisticCIRdiam[x], "%s\t%-4d", value(CirclDiam[n], ""), cCirclDiam[n] ); + } + } + + x = 0; + statisticPolyw[x] = "POLY. width\tQ."; + for ( n = 0; n <= cntPolyW; n++) { + if (cPolygonWidth[n]) { + sumPOLYw += cPolygonWidth[n]; + if(minPOLYw > PolygonWidth[n]) minPOLYw = PolygonWidth[n]; + x++; + sprintf(statisticPolyw[x], "%s\t%-4d", value(PolygonWidth[n], ""), cPolygonWidth[n]); + // ATTENTION : Width saved in .2 Micron + } + } + + x = 0; + statisticPoliso[x] = "POLY. Isol.\tQ."; + for ( n = 0; n <= cntPolyIso; n++) { + if (cPolygonIsolate[n]) { + sumISOL += cPolygonIsolate[n]; + if(minISOL > PolygonIsolate[n]) minISOL = PolygonIsolate[n]; + x++; + sprintf(statisticPoliso[x], "%s\t%-4d", value(PolygonIsolate[n], ""), cPolygonIsolate[n]); + } + } + + x = 0; + statisticRECT[x] = "RECT x\tRECT y\tQ."; + for ( n = 0; n <= cntRECT; n++) { + if (cRECT[n]) { + sumRECT += cRECT[n]; + if(minRECTx > RECTx[n]) minRECTx = RECTx[n]; + if(minRECTy > RECTy[n]) minRECTy = RECTy[n]; + x++; + sprintf(statisticRECT[x], "%s\t%s\t%-4d", value(RECTx[n], ""), value(RECTy[n], ""), cRECT[n]); + } + } + + x = 0; + sprintf(statisticRectANYlayer[0], "RECT Layer\tQ."); + int xr = 1; + for ( n = 1; n < 256; n++) { + if (cntRectANYlayer[n]) { + sumAnyRECT += cntRectANYlayer[n]; + sprintf(statisticRectANYlayer[xr], "%d\t%-4d", n, cntRectANYlayer[n]); + xr++; + } + } + sprintf(statisticSumRectANYlayer, "%d RECT (non copper)", sumAnyRECT); + x = 0; + statisticSMD[x] = "SMD x\tSMD y\tRoundn.\tQ."; + for ( n = 0; n <= cntSMD; n++) { + if (cSMD[n]) { + sumSMD += cSMD[n]; + if(minSMDx > SMDx[n]) minSMDx = SMDx[n]; + if(minSMDy > SMDy[n]) minSMDy = SMDy[n]; + x++; + sprintf(statisticSMD[x], "%s\t%s\t%d%c\t%-4d", value(SMDx[n], ""), value(SMDy[n], ""), rSMD[n], '%', cSMD[n]); // 2010-03-10 + } + } + + x = 0; + statisticPADdril[x] = "PAD drill\tQ."; + for (n = 0; n <= cntPDril; n++) { + if (cPadDrill[n]) { + sumPADdril += cPadDrill[n]; + if(minPADdril > PadDrill[n]) minPADdril = PadDrill[n]; + x++; + sprintf(statisticPADdril[x], "%s\t%-4d", value(PadDrill[n], ""), cPadDrill[n]); + } + } + + x = 0; + statisticPADdiaTOP[x] = "PAD tDiam\tQ."; + for ( n = 0; n <= cntPDiamTOP; n++) { + if (cPadDiameterTOP[n]) { + sumPADdia += cPadDiameterTOP[n]; + if(minPADdia > PadDiameterTOP[n]) minPADdia = PadDiameterTOP[n]; + x++; + sprintf(statisticPADdiaTOP[x], "%s\t%-4d", value(PadDiameterTOP[n], ""), cPadDiameterTOP[n]); + } + } + + x = 0; + statisticPADdiaBOT[x] = "PAD bDiam\tQ."; + for ( n = 0; n <= cntPDiamBOT; n++) { + if (cPadDiameterBOT[n]) { + sumPADdia += cPadDiameterBOT[n]; + if(minPADdia > PadDiameterBOT[n]) minPADdia = PadDiameterBOT[n]; + x++; + sprintf(statisticPADdiaBOT[x], "%s\t%-4d", value(PadDiameterBOT[n], ""), cPadDiameterBOT[n]); + } + } + + x = 0; + statisticPADdiaI[x] = "PAD iDiam\tQ."; + for ( n = 0; n <= cntiPDiam; n++) { + if (ciPadDiameter[n]) { + sumPADdiaI += ciPadDiameter[n]; + if(minPADdiaI > iPadDiameter[n]) minPADdiaI = iPadDiameter[n]; + x++; + sprintf(statisticPADdiaI[x], "%s\t%-4d", value(iPadDiameter[n], ""), ciPadDiameter[n]); + } + } + + x = 0; + statisticPADrestTOP[x] = "PAD tRestring\tQ."; + for ( n = 0; n <= cntPringTOP; n++) { + if (cPadRestringTOP[n]) { + sumPADrest += cPadRestringTOP[n]; + if(minPADrest > PadRestringTOP[n]) minPADrest = PadRestringTOP[n]; + x++; + sprintf(statisticPADrestTOP[x], "%s\t%-4d", value(PadRestringTOP[n], ""), cPadRestringTOP[n]); + } + } + + x = 0; + statisticPADrestBOT[x] = "PAD bRestring\tQ."; + for ( n = 0; n <= cntPringBOT; n++) { + if (cPadRestringBOT[n]) { + sumPADrest += cPadRestringBOT[n]; + if(minPADrest > PadRestringBOT[n]) minPADrest = PadRestringBOT[n]; + x++; + sprintf(statisticPADrestBOT[x], "%s\t%-4d", value(PadRestringBOT[n], ""), cPadRestringBOT[n]); + } + } + + x = 0; + statisticPADrestI[x] = "PAD iRestring\tQ."; + for ( n = 0; n <= cntPringI; n++) { + if (cPadRestringI[n]) { + sumPADrestI += cPadRestringI[n]; + if(minPADrestI > PadRestringI[n]) minPADrestI = PadRestringI[n]; + x++; + sprintf(statisticPADrestI[x], "%s\t%-4d", value(PadRestringI[n], ""), cPadRestringI[n]); + } + } + + x = 0; + statisticVIAdril[x] = "VIA drill\tQ."; + for ( n = 0; n <= cntVDril; n++) { // cntVDril + if (cViaDrill[n]) { + sumVIAdril += cViaDrill[n]; + if(minVIAdril > ViaDrill[n]) minVIAdril = ViaDrill[n]; + x++; + sprintf(statisticVIAdril[x], "%s\t%-4d", value(ViaDrill[n], ""), cViaDrill[n] ); + } + } + + x = 0; + statisticVIAdia[x] = "VIA Outer-Diam\tQ."; + for ( n = 0; n <= cntVDiam; n++) { + if (cViaDiameter[n]) { + sumVIAdiam += cViaDiameter[n]; + if(minVIAdiam > ViaDiameter[n]) minVIAdiam = ViaDiameter[n]; + x++; + sprintf(statisticVIAdia[x], "%s\t%-4d", value(ViaDiameter[n], ""), cViaDiameter[n] ); + } + } + + x = 0; + statisticVIAdiaI[x] = "VIA Inner-Diam.\tQ."; + for ( n = 0; n <= cntVDiamI; n++) { + if (cViaDiameterI[n]) { + sumVIAdiamI += cViaDiameterI[n]; + if(minVIAdiamI > ViaDiameterI[n]) minVIAdiamI = ViaDiameterI[n]; + x++; + sprintf(statisticVIAdiaI[x], "%s\t%-4d", value(ViaDiameterI[n], ""), cViaDiameterI[n] ); + } + } + + x = 0; + statisticVIArest[x] = "VIA Outer-Restring \tQ."; + for ( n = 0; n <= cntVringO; n++) { + if (cViaRestringO[n]) { + sumVIArest += cViaRestringO[n]; + if(minVIArest > ViaRestringO[n]) minVIArest = ViaRestringO[n]; + x++; + sprintf(statisticVIArest[x], "%s\t%-4d", value(ViaRestringO[n], ""), cViaRestringO[n]); + } + } + + x = 0; + statisticVIArestI[x] = "VIA Inner-Restring\tQ."; + for ( n = 0; n <= cntVringI; n++) { + if (cViaRestringI[n]) { + sumVIArestI += cViaRestringI[n]; + if(minVIArestI > ViaRestringI[n]) minVIArestI = ViaRestringI[n]; + x++; + sprintf(statisticVIArestI[x], "%s\t%-4d", value(ViaRestringI[n], ""), cViaRestringI[n]); + } + } + + x = 0; + statisticVIAstack[x] = "VIA Stack\tQ."; + for ( n = 0; n < cntStack; n++) { + x++; + sprintf(statisticVIAstack[x], "%s\t%-4d", ViaStack[n], ViaStackCnt[n]); + } + + x = 0; + statisticHOLE[x] = "HOLE drill\tQ."; + for ( n = 0; n <= cntHole; n++) { + if (cHole[n]) { + sumHOLE += cHole[n]; + if(minHOLE > Hole[n]) minHOLE = Hole[n]; + x++; + sprintf(statisticHOLE[x], "%s\t%-4d", value(Hole[n], ""), cHole[n]); + } + } + + x = 0; + statisticTEXTw[x] = "TEXT (w)\tQ."; + for ( n = 0; n <= cntTextWidth; n++) { + if (cTextWidth[n]) { + sumTEXTw += cTextWidth[n]; + if(minTEXTw > TextWidth[n]) minTEXTw = TextWidth[n]; + x++; + sprintf(statisticTEXTw[x], "%s\t%-4d", value(TextWidth[n], ""),cTextWidth[n] ); + } + } + + x = 0; + statisticTEXTsize[x] = "TEXT (s)\tQ."; + for ( n = 0; n <= cntTextSize; n++) { + if (cTextSize[n]) { + x++; + sprintf(statisticTEXTsize[x], "%s\t%-4d", value(TextSize[n], ""),cTextSize[n] ); + } + } + + x = 0; + statisticPlaceTEXTw[x] = "TEXT \tQ."; + for ( n = 0; n <= cntPlaceTextWidth; n++) { + if (cPlaceTextWidth[n]) { + sumPlaceTEXTw += cPlaceTextWidth[n]; + if(minPlaceTEXTw > PlaceTextWidth[n]) minPlaceTEXTw = PlaceTextWidth[n]; + x++; + sprintf(statisticPlaceTEXTw[x], "%s\t%-4d", value(PlaceTextWidth[n], ""),cPlaceTextWidth[n] ); + } + } + + x = 0; + statisticPlaceTEXTsize[x] = "TEXT \tQ."; + for ( n = 0; n <= cntPlaceTextSize; n++) { + if (cPlaceTextSize[n]) { + x++; + sprintf(statisticPlaceTEXTsize[x], "%s\t%-4d", value(PlaceTextSize[n], ""),cPlaceTextSize[n] ); + } + } + + x = 0; + statisticLBR[x] = "LIBRARY\tQ."; + for ( n = 0; n <= cntLbr; n++) { + if (cLbr[n]) { + x++; + sprintf(statisticLBR[x], "%s\t%-4d", Lbr[n], cLbr[n] ); + } + } + + x = 0; + statisticPAC[x] = "PACKAGE\tQ."; + for ( n = 0; n <= cntPacName; n++) { + if (cPacName[n]) { + x++; + sprintf(statisticPAC[x], "%s\t%-4d", PacName[n], cPacName[n] ); + } + } + + x = 0; + statisticValPacLay[x] = "VALUE\tPAC\tQ.\tTop\tBot"; + for ( n = 0; n <= cntEVPL; n++ ) { + if (cEVPL[n]) { + x++; + sprintf(statisticValPacLay[x], "%s\t%s\t%d\t%d\t%d", + EVALpac[n], EvalPAC[n], cEVPL[n], cEVPL1[n], cEVPL16[n] ); + } + } + sprintf(statisticLocked, "%d Elements: %d locked / %d unlocked", cntElement, cntLocked, cntElement-cntLocked); + sprintf(statisticTestPoint, "%d Testpoints (TP)", cntTPelement); + x = 0; + // Drill Rack statistic + status("Drill/Rack"); + B.holes(H) AddDrilling(H.drill); + B.signals(S) S.vias(V) AddDrilling(V.drill); + B.elements(E) { + E.package.contacts(C) { + if (C.pad) + AddDrilling(C.pad.drill); + } + E.package.holes(H) AddDrilling(H.drill); + } + sort(imax, Drilling); + + drillRack[0] = "RACK"; + for (int i = 0; i < imax; ++i) { + string s; + sprintf(s, "T%02d %5.*f", i + 1, unitPrec[uval], Drilling[i]); + drillRack[i + 1] = s; + } + status("Unroutet"); + if (SignalUnrouted) { + sprintf(displayUnrouted, "%d    unroutet (airwire)", SignalUnrouted ); + sprintf(Unrouted, "%d", SignalUnrouted); + } + status("Generate statistic list"); // 2007-12-19 alf@cadsoft.de + + // Stop/Cream mask statistic 2006-04-28 + sprintf(statisticSTOP_CREAM[0], "%d\t tStop Pad", padlSTOP[0]); + sprintf(statisticSTOP_CREAM[1], "%d\t tStop Smd", smdlSTOP[0]); + sprintf(statisticSTOP_CREAM[2], "%d\t tStop Pac", lSTOPpac[0]); // tMask in Board/Package + sprintf(statisticSTOP_CREAM[3], "%d\t tStop Brd", lSTOPbrd[0]); // tMask in Board/Package + sprintf(statisticSTOP_CREAM[4], "%d\t tStop", padlSTOP[0] + smdlSTOP[0] + lSTOPpac[0] + lSTOPbrd[0]); + + sprintf(statisticSTOP_CREAM[5], "%d\t bStop Pad", padlSTOP[1]); + sprintf(statisticSTOP_CREAM[6], "%d\t bStop Smd", smdlSTOP[1]); + sprintf(statisticSTOP_CREAM[7], "%d\t bStop Pac", lSTOPpac[1]); // tMask in Board/Package + sprintf(statisticSTOP_CREAM[8], "%d\t bStop Brd", lSTOPbrd[1]); // tMask in Board/Package + sprintf(statisticSTOP_CREAM[9], "%d\t bStop", padlSTOP[1] + smdlSTOP[1] + lSTOPpac[1] + lSTOPbrd[1]); + + sprintf(statisticSTOP_CREAM[10], "%d\t tCream Smd", smdlCREAM[0]); + sprintf(statisticSTOP_CREAM[11], "%d\t tCream Pac", lCREAMpac[0]); // tCream in Board/Package + sprintf(statisticSTOP_CREAM[12], "%d\t tCream Brd", lCREAMbrd[0]); // tCream in Board/Package + sprintf(statisticSTOP_CREAM[13], "%d\t tCream", smdlCREAM[0] + lCREAMpac[0] + lCREAMbrd[0]); // tCream in Board/Package + + sprintf(statisticSTOP_CREAM[14], "%d\t bCream Smd", smdlCREAM[1]); + sprintf(statisticSTOP_CREAM[15], "%d\t bCream Pac", lCREAMpac[1]); // bCream in Board/Package + sprintf(statisticSTOP_CREAM[16], "%d\t bCream Brd", lCREAMbrd[1]); // bCream in Board/Package + sprintf(statisticSTOP_CREAM[17], "%d\t bCream", smdlCREAM[1] + lCREAMpac[1] + lCREAMbrd[1]); // bCream in Board/Package + + + // summary ****************** + string Tsummary_area; + sprintf(Tsummary_area, "~ %.2f mm (%.3f dm)", summary_area, summary_area/10000.0); + + sprintf(sum, "%-6d\t Wire(s) incl. Arc(s)\n%-6d\t Polygon(s)\n_________________________\n" + + "%-6d\t SMD(s) top\n%-6d\t SMD(s) bottom\n===================\n%-6d\t SMD(s) total\n\n" + + "%-6d\t PAD(s)\n_________________________\n" + + "%-6d\t Via\n%-6d\t Hole\n===================\n" + + "%-6d\t Drills total\n_________________________\n"+ + "%s\n%s\n_________________________\n" + + "Routing Info: \n%-6d\t Signal(s) \n" + + "%-6d\t PAD/SMD total\n===================\n" + + "%-6d\t PAD/SMD on Signal\n_________________________\n"+ + "Packages used area:\n%s\n_________________________\n", + sumWires + sumARCw, + sumPOLYw, + cntSMDt, + cntSMDb, + sumSMD, + sumPADdril, + cntVias, // 2012-05-24 + sumHOLE, + sumPADdril + cntVias + sumHOLE, // sumVIAdril + statisticSTOP_CREAM[13], // 2006-04-28 + statisticSTOP_CREAM[17], + sumSignals, + sumSMD + sumPADdril, + cnt_pad_on_signal, + Tsummary_area + ); + + sprintf(LabelcntRECT, "%d RECT (copper)", sumcntRECT); + sprintf(LabelcntTextSize, "%d TEXT size (copper)", cntTextSize); + sprintf(LabelcntTextWidth, "%d TEXT wire width (copper)", cntTextWidth); + sprintf(LabelcntPlaceTextSize, "%d TEXT size (place)", cntPlaceTextSize); + sprintf(LabelcntPlaceTextWidth, "%d TEXT wire width (place)", cntPlaceTextWidth); + sprintf(LabelcntCIRCLE, "%d CIRCLE (copper)", sumcntCircl); + sprintf(LabelcntRectANYlayer, "%d RECT (any layer)", sumAnyRECT); + for (int ln = 1; ln < 16; ln++) { + if (SupplyLayersUsedPolygons[ln]) { + string sl; + sprintf(sl, "%d:%s:(%d) ", ln, SupplyLayerName[ln], SupplyLayersUsedPolygons[ln]); + checkSupplyLayerPolygon += sl; + } + } + int Selected = 0; + int StopCreamSelected = 0; + int MCselected = 0; + int ECselected = 0; + // ********************************************************************* + dlgDialog("Statistic of " + B.name) { + showminValWidth = check_min_ValueWidth(); + showminValOther = check_min_ValueOther(); + dlgHBoxLayout dlgSpacing(850); + dlgHBoxLayout { + dlgTabWidget { // *** Board *** + dlgTabPage("&BOARD") { + dlgHBoxLayout { + dlgSpacing(10); + dlgVBoxLayout { + dlgSpacing(10); + dlgLabel(brdmaximum); + dlgSpacing(5); + dlgLabel(brdoutline); + dlgLabel("


    "); + dlgLabel(usedLayer); + dlgLabel(displayLayerError); + dlgStretch(1); + } + dlgSpacing(10); + dlgVBoxLayout { + dlgGroup("Summary") { + dlgLabel(sum); + dlgHBoxLayout { + if (SignalUnrouted) { + dlgLabel(displayUnrouted); + dlgStretch(1); + } + } + } + dlgStretch(1); + } + dlgSpacing(5); + dlgVBoxLayout { + dlgGroup("Minor values") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel(showminValWidth, 1); + dlgHBoxLayout dlgSpacing(200); + } + dlgVBoxLayout { + dlgLabel(showminValOther, 1); + string emptyval = " "; + if (emptyValue) sprintf(emptyval, "%d %s%s Values", emptyValue, empty, attention); + dlgSpacing(6); + dlgLabel(emptyval); + } + } + dlgSpacing(8); + dlgHBoxLayout { + dlgPushButton("&Edit") { + GetCheckValues(); + showminValWidth = check_min_ValueWidth(); + showminValOther = check_min_ValueOther(); + } + dlgStretch(1); + } + } + if (PolyWidthError) dlgLabel("" + PolygonError + "
    Details see Tab POLYGON."); + } + dlgStretch(1); + } + } + dlgTabPage("&LAYER") { // *** all Layer are defined *** + int layselect = 0; + dlgHBoxLayout { + dlgListView("Nb.:\tName\tUsed", allLayers, layselect ); // 2005-11-17 alf@cadsoft.de + dlgStretch(1); + } + } + + dlgTabPage("&CLASS (Signal)") { // *** Class clearance/isolate *** + string classlabel = "Class 0: " + NetClassName[0]; + string ClassNameL = NetClassLabel(NetClassName[SignalClassSelect] , cNetClass[SignalClassSelect]); + string SignalList = SignalClassList[selNetClassNr[SignalClassSelect]]; + dlgHBoxLayout { + dlgVBoxLayout { + dlgListView("", statisticCLASS, SignalClassSelect) { // 2007-12-04 - Corrected Class handling to select net-list if classes empty + SignalList = SignalClassList[selNetClassNr[SignalClassSelect]]; + sprintf(classlabel, "Class %d : %s", + selNetClassNr[SignalClassSelect], + NetClassName[selNetClassNr[SignalClassSelect]]); + } + dlgSpacing(12); + if (falseSignalCnt) { + dlgLabel("False signals (not connected on PAD or SMD)"); + dlgListView("", statisticFalseSignals, SignalClassSelect); + } + /********* 2009-02-12 *********/ + if (deleteRudimentalSignalName) { + dlgLabel(" "); + dlgLabel("Found rudimentarily signal name(s)."); + dlgLabel("You wish to delete this rudimentarily signal names, press button Delete"); + dlgPushButton("&Delete") { + dlgAccept(); + exit("GRID MM;\n"+deleteRudimentalSignalName+"GRID LAST;\nRUN '"+filename(argv[0])+"'"); + } + } + } + dlgSpacing(12); + dlgGroup("Netlist") { + dlgLabel(classlabel, 1); + dlgHBoxLayout { + dlgSpacing(4); + dlgTextView(SignalList); + } + } + dlgStretch(1); + } + } + + dlgTabPage("&WIDTH") { // *** Wire / Text *** + dlgHBoxLayout { + dlgListView("", statisticWirew, Selected); + dlgListView("", statisticARCw, Selected); + dlgSpacing(8); + dlgVBoxLayout { + dlgListView("", statisticTEXTw, Selected); + dlgLabel(LabelcntTextWidth); + } + dlgSpacing(8); + dlgVBoxLayout { + dlgListView("", statisticTEXTsize, Selected); + dlgLabel(LabelcntTextSize); + } + dlgStretch(1); + } + dlgHBoxLayout { + if (SignalUnrouted) { + dlgSpacing(8); + dlgLabel(displayUnrouted); + dlgStretch(1); + } + } + dlgLabel(wireWidthInternal); + } + + dlgTabPage("POL&YGON") { // *** Polygon *** + int selp; + dlgHBoxLayout { + dlgListView("", statisticPolyw, Selected); + dlgListView("", statisticPoliso, Selected); + dlgSpacing(8); + dlgVBoxLayout { + dlgListView("Type\tName\tLayer\tRank\tWidth", PolygonLayer, Selected); + if (PolyWidthError) dlgLabel("" + PolygonError + ""); + dlgLabel(wireWidthInternal); + } + dlgStretch(1); + } + } + + dlgTabPage("&SMD") { // *** Smd *** + dlgHBoxLayout { + dlgListView("", statisticSMD, Selected); + dlgStretch(2); + } + } + + dlgTabPage("&PAD") { // *** Pad *** + dlgHBoxLayout { + dlgVBoxLayout { + dlgListView("", statisticPADdiaTOP, Selected); + dlgListView("", statisticPADdiaBOT, Selected); + } + dlgVBoxLayout { + dlgListView("", statisticPADrestTOP, Selected); + dlgListView("", statisticPADrestBOT, Selected); + } + dlgListView("", statisticPADdiaI, Selected); + dlgListView("", statisticPADrestI, Selected); + dlgStretch(1); + } + } + + dlgTabPage("&VIA") { // *** Via *** + dlgHBoxLayout { + dlgVBoxLayout { + dlgListView("", statisticVIAdia, Selected); + dlgListView("", statisticVIArest, Selected); + } + dlgVBoxLayout { + dlgListView("", statisticVIAdiaI, Selected); + dlgListView("", statisticVIArestI, Selected); + } + dlgListView("", statisticVIAstack, Selected); + dlgStretch(1); + } + } + + dlgTabPage("&DRILL/HOLE") { // *** Drill Hole *** + int plrSelected = -1; + int vlrSelected = -1; + int hlrSelected = -1; + int lrSelected = -1; + int vrSelected = -1; + int shSel = 0; + string StackHead = "select a Layer/Rack"; + dlgHBoxLayout { + dlgListView("", statisticPADdril, plrSelected); + dlgListView("", statisticVIAdril, vlrSelected); + dlgListView("", statisticHOLE, hlrSelected); + dlgListView("", drillRack, lrSelected); + dlgSpacing(12); + dlgListView("Layer/Rack", ViaStack, vrSelected) { + StackHead = "RACK/"+ ViaStack[vrSelected] + "\tQ."; + showLayerRack(vrSelected); // + "\n" + StackDrills[rack] + } + dlgListView(StackHead, showStackDrills, shSel); + //dlgStretch(1); + } + } + + dlgTabPage("&ELEMENT") { // *** Element *** + dlgHBoxLayout { + dlgVBoxLayout { + dlgHBoxLayout { + dlgListView("", statisticLBR, LBRselected) { + art_selected = 1; + get_Info(art_selected, statisticLBR[LBRselected]); + dlgRedisplay(); + } + dlgListView("", statisticPAC, PACselected) { + art_selected = 2; + get_Info(art_selected, statisticPAC[PACselected]); + dlgRedisplay(); + } + } + dlgHBoxLayout { + dlgListView("", statisticValPacLay, VALselected) { + art_selected = 3; + get_Info(art_selected, statisticValPacLay[VALselected]); + dlgRedisplay(); + } + } + } + dlgVBoxLayout { + dlgHBoxLayout dlgSpacing(250); + dlgLabel(linfo ,1); + dlgSpacing(10); + dlgTextView(Element_info); + } + dlgVBoxLayout { + //dlgListView("Electrical", EContact, ECselected); // 2009-12-02 + dlgListView("Mech. Part\tPac.", EnoContact, MCselected); + } + } + dlgSpacing(8); + dlgLabel(statisticLocked); // 2007-12-19 alf@cadsoft.de + if (cntTPelement) dlgLabel(statisticTestPoint); // 2010-06-09 + dlgSpacing(12); + dlgLabel("Packages used area "+Tsummary_area+""); + } + + dlgTabPage("&MASK") { // *** Stop & Cream MASK *** + dlgHBoxLayout { + dlgListView("Count\tLayer", statisticSTOP_CREAM, StopCreamSelected, msort); + dlgStretch(1); + } + } + + dlgTabPage("&RECT CIRCLE") { // *** Rect / Circle *** + dlgHBoxLayout { + dlgVBoxLayout { + dlgListView("", statisticRECT, Selected); + dlgLabel(LabelcntRECT); + } + dlgVBoxLayout { + dlgListView("", statisticRectANYlayer, Selected); + dlgLabel(LabelcntRectANYlayer); + } + dlgSpacing(8); + dlgVBoxLayout { + dlgListView("", statisticCIRw, Selected); + dlgLabel(LabelcntCIRCLE); + } + dlgVBoxLayout { + dlgListView("", statisticCIRdiam, Selected); + dlgLabel(LabelcntCIRCLE); + } + dlgStretch(1); + } + } + + dlgTabPage("&TEXT") { // *** Text *** + dlgHBoxLayout { + dlgVBoxLayout { + dlgListView("", statisticPlaceTEXTw, Selected); + dlgLabel(LabelcntPlaceTextWidth); + } + dlgVBoxLayout { + dlgListView("", statisticPlaceTEXTsize, Selected); + dlgLabel(LabelcntPlaceTextSize); + } + dlgStretch(1); + } + } + } + } + if (checkSupplyLayerPolygon) dlgLabel("Polygon(s) in SUPPLY-LAYER, please check! :
    " + checkSupplyLayerPolygon + ""); + dlgHBoxLayout { + dlgPushButton("-&Quit") dlgAccept(); + dlgPushButton("&Save report") { + string fileName = dlgFileSave("Select a file", filesetext(brdfile,".rep"), "*.rep"); + if (fileName) { + output(fileName, "wt") { + printf("%s", saveReport()); + } + } + } + dlgSpacing(50); + dlgLabel("All Units = " + unit[uval]); + dlgSpacing(50); + dlgStretch(1); + dlgLabel(Version); + } + dlgHBoxLayout { + dlgLabel("Database:"); + dlgLabel(brdfile, 1); + dlgStretch(1); + } + }; + exit (0); + } +} + +else dlgMessageBox("Start this ULP from a Board", "OK"); + diff --git a/trunk/ulp/statistic-copper-plane.ulp b/trunk/ulp/statistic-copper-plane.ulp new file mode 100644 index 00000000..d1725c7b --- /dev/null +++ b/trunk/ulp/statistic-copper-plane.ulp @@ -0,0 +1,532 @@ +#usage "Statisic of copper

    \n" + "Create and evaluate bitmap(s) to calculate the copper area of layers." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string info_en = ";Be sure that there are no elements outside the " + + "board contour which is drawn in layer 20, Dimension.
    " + + "Otherwise it may come to incorrect results.

    " + + "Calculating the board area:
    " + + "Holes and other kinds of openings will not be taken into consideration.
    " + + "Calculating copper areas:
    " + + "Blind and buried vias will not be marked in the reference image as it is " + + "the case with drills and holes.
    This leads to slight inaccuracies in the result."; + + +string info_de = ";
    Bei Benutzung dieses ULPs darf kein Element ausserhalb "+ + "des Platinenumrisses im
    Layer 20 Dimension " + + "gezeichnet sein. Andernfalls kommt es zu fehlerhaften Ergebnissen.

    " + + "Berechnung der Platinenfläche:
    " + + "Bohrungen und Durchbrüche innerhalb der Platine werden nicht berücksichtigt.
    " + + "Berechnung der Kupferfläche:
    "+ + "Bei Verwendung von Blind- und Burried-Vias werden im Referenzbild die Bohrungen
    " + + "nicht wie bei Pads und Holes markiert, wodurch es zu minimalen Ungenauigkeiten
    " + + "im Ergebnis kommen kann."; + + + + +string infotext = info_en; +if (language() == "de") infotext = info_de; + +string MSG_en_de[] = { + "en\v" + "de\v" + , + "Statistics\v" + "Statistik\v" + , + "Delete temporary files (bitmaps)?\v" + "Temporäre Dateien (Bitmaps) löschen?\v" + , + "Layer\tplane (Cu)\t% Cu\v" + "Layer\tFläche (Cu)\t% Cu\v" + , + "Statistics Copper Area:\v" + "Statistik Kupferflächen:\v" + , + "+Ok\v" + "+Ok\v" + , + "-Cancel\v" + "-Abbrechen\v" + , + "+Yes\v" + "+Ja\v" + , + "-No\v" + "-Nein\v" + , + "&Save\v" + "&Speichern\v" + , + "Start this ULP from a Board!\v" + "Starten sie das ULP in einem Board!\v" + , + "Calculate board area\v" + "Berechnen der Platinen-Fläche(n)\n" + , + "Only board area\v" + "Nur Platinenfläche\v" + , + "Also copper layers\v" + "Auch Kupferlayer\v" + , + "Save statistic\v" + "Statistik speichern\v" + "\v" + "\v" + }; + +int Language = strstr(MSG_en_de[0], language()) / 2; +string tr(string s) { + string t = lookup(MSG_en_de, s, Language, '\v'); + return t ? t : s; +} + + +string UlpVersion = "1.0.1"; // 2010-05-04 alf@cadsoft.de - get current background color + +string brdfile; +int cntlayerfiles; + +string fileBitmap; +int resolution = 254; // resolution pixel per inch +real pmm2 = (25.4/resolution) * (25.4/resolution); + +int nBytes = 0; // count bytes of file (fileName) +int ColorBits = 0; // used bits for color +int AdrStart, AdrEnd = 0; // Start & End of BITMAP-Data +int length = 0; // length of bmp-Data +int Byte4Group = 0; // bmp-Data organized as 4-byte groups +char c[]; + +real brd_mm2; +int p2[]; // pixel quadrat pro layer +int BackgroundColor; +int L_dimension[]; // Left dimension of pixel line +int R_dimension[]; // Right dimension of pixel line + +int Y = 0; // count pixels y +int X = 0; // count pixels x + +char copper = 'C'; // reference copper flag +char nonecopper = 'N'; // reference none-copper flag (holes/drills) +char nopcb = copper -1; // reference no printed-circuit-board (outside) +char Bit[] = { nonecopper, copper }; +string planeBit0[]; // byte (character) array for pcb plane +int mBit[]; +string info; + + +string Header; +int nsl = 0; +numeric string plane_statistic[]; + +int fill_drilllayer = 199; +string fill_drill_name = "FillDrill"; +string cmd, h; +string ldisplay; // reset display layers + + +void wait(int w) { + int t = time(); + do { + } while (t+w > time()); + return; +} + +// ** delete temporary circles and layer ** +string remove_layer(int x1, int y1, int x2, int y2) { + string s; + sprintf(s, "DISPLAY NONE %d;\nGROUP (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f) (%.4f %.4f);\nDELETE (>%.4f %.4f);\nLAYER -%d;\nGRID LAST;\n", + fill_drilllayer, + u2mm(x1), u2mm(y1), + u2mm(x2), u2mm(y1), + u2mm(x2), u2mm(y2), + u2mm(x1), u2mm(y2), + u2mm(x1), u2mm(y1), + u2mm(x1)+1, u2mm(y1)+1, fill_drilllayer ); + return s; +} + +string center(int x, int y, int drill) { + string s; + sprintf(s, "circle 0 (%.4f %.4f) (%.4f %.4f) ;\n", + u2mm(x), u2mm(y), u2mm(x) + u2mm(drill)/2, u2mm(y) ); + return s; +} + + +// ** calculate left and right side ** +void PCB_planeColom(int Line) { + int pixel2, z; + BackgroundColor = mBit[0]; + int Copper = 0; + int Dimension = 0; + int copper_cnt; + int zL, zR; + + for(z = 0; z <= X; z++) { + planeBit0[Line][z] = Bit[mBit[z]]; + } + for( zL = 0; zL < X; zL++) { + if(mBit[zL] != BackgroundColor) { + L_dimension[Line] = zL; + break; + } + } + for( zR = X; zR >= 0; zR--) { + if(mBit[zR] != BackgroundColor) { + R_dimension[Line] = zR; + break; + } + } + return; +} + +// ** define outside dimension ** +// ** set flag in pcb array ** +int PCB_planeRow(void) { + status("Mark right and left outline"); + int y, x; + // * mark from left and from right do dimension * + for ( y = 0; y <= Y; y++) { + if (L_dimension[y]) { + for( x = 0; x < X; x++) { + if(planeBit0[y][x] != copper) break; + else planeBit0[y][x]--; // mark pcb outside from left side + } + for( x = X; x > 0; x--) { + if(planeBit0[y][x] != copper) break; + else planeBit0[y][x]--; // mark pcb outside from right side + } + } + } + status("Mark top and bottom outline"); + // * mark from top and from bottom to dimension * + for ( x = 0; x <= X; x++) { + for( y = 0; y < Y; y++) { + if(planeBit0[y][x] != copper) break; + else planeBit0[y][x]--; // mark pcb outside from bottom side + } + for( y = Y; y > 0; y--) { + if(planeBit0[y][x] != copper) break; + else planeBit0[y][x]--; // mark pcb outside from top side + } + } + status("calculate board area"); + int pp2; // count pcb area pixel + for (y = 0; y < Y; y++) { + for (x = L_dimension[y]; x < R_dimension[y]; x++ ) { + if (planeBit0[y][x] != nopcb) pp2++; // komplete pcb plane + } + } + return pp2; +} + + +int calculateLine(int Line, int layer) { + string m; + sprintf(m, "Layer %d: Line %d of %d", layer, Line, Y); + status(m); + int pixel2, x; + BackgroundColor = mBit[1]; + int Copper = 0; + int Dimension = 0; + if (!layer) { + PCB_planeColom(Line); + } + else { + for( x = L_dimension[Line]; x <= R_dimension[Line]; x++) { + if(mBit[x] != BackgroundColor && planeBit0[Line][x] == copper) pixel2++; + } + } + return pixel2; +} + + +void get_pixel_info( int layer) { + int xByte = 4 * Byte4Group; + int bmpBits; + for(int yRead = 0; yRead <= Y; yRead++) { + for(int xRead = 0; xRead < xByte; xRead ++) { + bmpBits = c[AdrStart + yRead * xByte + xRead]; + switch (ColorBits) { + case 1 : for(int bitcnt = 7; bitcnt > -1; bitcnt--) { + mBit[(xRead * 8) + (7 - bitcnt)] = bmpBits; + mBit[(xRead * 8) + (7 - bitcnt)] >>= bitcnt; + mBit[(xRead * 8) + (7 - bitcnt)] &= 0X1; + } + break; + + case 4 : dlgMessageBox("16 colors, not accepted!", "OK"); + exit(-4); + mBit[xRead * 2 ] = bmpBits; + mBit[xRead * 2 + 1] = bmpBits; + mBit[xRead * 2 ] >>= 4; + mBit[xRead * 2 + 1] &= 0x0f; + break; + + case 8 : dlgMessageBox("256 colors, not accepted!", "OK"); + exit(-8); + mBit[xRead] = bmpBits; + break; + } + } + p2[layer] += calculateLine(yRead, layer); + } + // ** calculate array outside outlines ** + if (!layer) { + p2[0] = PCB_planeRow(); // calculate area outside dimension line + } + return; +} + + + +// generate bitmaps and start this ulp again +void genereate_bitmaps(UL_BOARD B) { + status("Generate return script, please wait!"); + + string cmd, l, lfill, h; + string ratsnest = "RATSNEST;\n"; + B.signals(S) { + if (ratsnest) { + S.polygons(P) { + if (ratsnest) { + P.fillings(F) { + ratsnest =""; + break; + } + } + else break; + } + } + else break; + } + cmd += ratsnest; + + int cntlayer = 2; + sprintf(h, "GRID mm;\nLAYER %d %s;\nCHANGE Layer %d;\n", fill_drilllayer, fill_drill_name, fill_drilllayer); + cmd += h; + + // ** temporary fill drills with circle ** + B.holes(L) { + cmd += center(L.x, L.y, L.drill); + } + B.elements(E) { + E.package.holes(H) { + cmd += center(H.x, H.y, H.drill); + } + E.package.contacts(C) { + if (C.pad) { + cmd += center(C.pad.x, C.pad.y, C.pad.drill); + } + } + } + string fvs; + B.signals(S) { + if (cntlayer > 2) break; + S.vias(V) { + fvs += center(V.x, V.y, V.drill); + if (V.start > 1 || V.end < 16) cntlayer ++; + if (cntlayer > 2) break; + } + } + if (cntlayer < 3) { + cmd += fvs; + } + + sprintf(h, "SET FILL_LAYER 17 1;\nSET FILL_LAYER 18 1;\nSET FILL_LAYER 20 1;\nDISPLAY NONE 20 %d;\nEXPORT IMAGE '%s_0.bmp' MONOCHROME %d;\n", + fill_drilllayer, brdfile, resolution); + cmd += h; + + // sprintf(h, "%s_0.bmp", brdfile); + // output( h, "wtD"); // temporary file, delete if eagle closed + + int allcupperlayer = dlgDialog(tr("Statistic")) { + dlgLabel(tr("Calculate board area")); + dlgPushButton( tr("Also copper layers")) dlgAccept(); + dlgPushButton( tr("Only board area")) dlgReject(); + }; + if (allcupperlayer) { + B.layers(L) { + if (L.number >= 1 && L.number <= 16) { + if (L.used) { + sprintf(h, "SET FILL_LAYER %d 1;\nDISPLAY NONE %d 17 18;\nEXPORT IMAGE '%s_%d.bmp' MONOCHROME %d;\n", + L.number, L.number, brdfile, L.number, resolution); + l += h; + sprintf(h, "SET FILL_LAYER %d %d;\n", L.number, L.fill); + lfill += h; + // sprintf(h, "%s_%d.bmp", brdfile, L.number); + // output( h, "wtD"); // temporary file, delete if eagle close + } + } + if (L.number == 17 || L.number == 18) { + sprintf(h, "SET COLOR_LAYER %d %d;\nSET FILL_LAYER %d %d;\n", L.number, L.color, L.number, L.fill); + lfill += h; + } + } + } + if (l) { + cmd += "SET COLOR_LAYER 17 0;\nSET COLOR_LAYER 18 0;\n" + l; // set color Via layer to 0 (black) + } + + ldisplay = "DISPLAY NONE "; + B.layers(L) { + if (L.visible) { + sprintf( h, " %d", L.number); + ldisplay += h; + } + } + + cmd += lfill; // restore layer filling + sprintf(h, "RUN '%s' 1;\n", argv[0]); + cmd += h; + cmd += remove_layer( B.area.x1, B.area.y1, B.area.x2, B.area.y2); + cmd += ldisplay + ";\n"; // restore layer display + status("EXPORT bitmaps, please wait!"); + exit(cmd); +} + + + +// ** read bitmap file ** +void pixel_map(string f) { + nBytes = fileread(c, f); // read file in array + int point = strstr( f, ".bmp"); + int underline = strstr( f, "_", point-4); + int layer = strtol(strsub(f, underline+1, point-underline)); + if (!layer) { + // up to 31 bytes - not all used + if(c[0] != 'B') { + dlgMessageBox(f + ":\nis not a bmp file.\n\nist keine bmp-Datei.", "OK"); + exit(0); + } + if(c[1] != 'M') { + dlgMessageBox(f + ":\nis not a bmp file.\n\nist keine bmp-Datei.", "OK"); + exit(0); + } + if(c[21] > 0) { + dlgMessageBox(f + ":\nToo many pixels in x direction\n" + + "\nAnzahl der Pixel in X zu gross\n", "OK"); + exit (0); + } + if(c[25] > 0) { + dlgMessageBox(f + ":\nToo many pixels y direction\n" + + "\nAnzahl der Pixel in Y zu gross\n", "OK"); + exit (0); + } + ColorBits = c[28]; // counter of ColorBits + if(ColorBits > 1) { + dlgMessageBox("falsche Farbtiefe", "OK"); + exit(0); + } + + AdrEnd = c[2] + c[3] * 256 + c[4] * 256 * 256 + c[5] * 256 * 256 * 256; + AdrStart = c[10]+ c[11] * 256 + c[12] * 256 * 256 + c[13] * 256 * 256 * 256; + X = (c[18] + c[19] * 256 + c[20] * 65536 + c[21] * 256 * 256 * 256) - 1; + Y = (c[22] + c[23] * 256 + c[24] * 65536 + c[25] * 256 * 256 * 256) - 1; + + length = AdrEnd - AdrStart; // bitmap legth + Byte4Group = length / Y / 4; + } + int bitcolor; + bitcolor = c[AdrStart] &= 0X80; // 2010-05-04 alf get background color + if (!bitcolor) { // 2010-05-04 swap color + Bit[0] = copper; + Bit[1] = nonecopper; + } + get_pixel_info(layer); + + if (!layer) { + brd_mm2 = p2[0] * pmm2; + sprintf(plane_statistic[nsl], "0_PCB\t%.2f mm\t --\t%d", brd_mm2, p2[layer] ); + nsl++; + } + else { + real pcbplane_mm2 = p2[0] * pmm2; + real copper_mm2 = p2[layer] * pmm2; + real percent = copper_mm2 / (pcbplane_mm2 / 100); + sprintf(plane_statistic[nsl], "%d\t%.2f mm\t%.1f", layer, copper_mm2, percent); + nsl++; + } + return; +} + + +string save(string file) { + int n; + sort( cntlayerfiles-1, plane_statistic); + string sfile = dlgFileSave(tr("Save statistic"), file, "*.cst"); + if (sfile) { + output(sfile, "wt") { + printf("%s\n%s - Version %s\n%s\n\n%s\n\n%s\n", + EAGLE_SIGNATURE, + filename(argv[0]), + UlpVersion, + t2string(time()), + tr("Statistic Copper Plane:"), + Header ); + do { + printf("%s\n", plane_statistic[n]); + n++; + } while(plane_statistic[n]); + } + } + return sfile; +} + + +// ***************** main **************** +if (board) { + board(B) { + string remove_tempfile; + string file = filesetext(B.name, ""); + brdfile = file + "~~~"; + + if (argc == 1) { + if (dlgMessageBox( infotext, tr("-Ok"), tr("-Cancel")) != 0) exit(0); + genereate_bitmaps(B); + } + fileBitmap = brdfile; + numeric string BMPlayerfiles[]; + cntlayerfiles = fileglob(BMPlayerfiles, fileBitmap + "*.bmp"); + Header = tr("Layer\tplane (Cu)\t% Cu"); + + sort( cntlayerfiles, BMPlayerfiles); + for (int n = 0; n < cntlayerfiles; n++) { + status("Load: " + BMPlayerfiles[n]); + pixel_map(BMPlayerfiles[n]); + sprintf(h, "REMOVE '%s';\n", BMPlayerfiles[n]); + remove_tempfile += h; + } + + status(" "); + wait(1); + file += ".cst"; + int select; + dlgDialog( tr("Statistics")) { + dlgListView(Header, plane_statistic, select); + dlgLabel(file); + dlgHBoxLayout { + dlgPushButton(tr("+OK")) dlgAccept(); + dlgPushButton(tr("&Save")) if (save(file)) dlgAccept(); + dlgStretch(1); + } + }; + cmd += cmd += "GRID LAST;"; + if (dlgMessageBox(tr("Delete temporary files (bitmaps)?"), tr("+Yes"), tr("-No") ) == 0) { + cmd += remove_tempfile; + } + exit(cmd); + } +} + +else { + dlgMessageBox(tr("Start this ULP from a Board!"), "Ok"); + exit(0); +} diff --git a/trunk/ulp/statistic-lbr.ulp b/trunk/ulp/statistic-lbr.ulp new file mode 100644 index 00000000..984c9746 --- /dev/null +++ b/trunk/ulp/statistic-lbr.ulp @@ -0,0 +1,848 @@ +#usage "RUN Library statistics\n" + "

    " + "Author: support@cadsoft.de" + +string Revision = "Version 1.10"; + // 1.02 2005-12-11 alf@cadsoft.de + // 1.03 2006-05-18 Delete unused PAC/SYM + // 1.04 2006-09-25 Check/Delete empty user layer + // Edit selected element + // 1.05 2007-02-07 Check defined User layer also < 100 + // 1.06 2007-02-08 check apostroph in Pac- Sym-Name vor Delete + // 1.07 2007-11-26 correct Text in function del_unused_sym(void) "Delete all unused symbols?" + // 1.08 2009-07-30 info for double click an package statistic + // 1.09 2013-02-21 extend defined User layer > 98 + // 1.10 2015-02-20 save statistic + +string ndev, nvar, ntec, npac, nsym, ndril, cupac, cusym, culay, npref; + +string src_dev[]; +string src_pac[]; +string src_sym[]; +string src_tec[]; +string src_var[]; +string src_pref[]; + +int cnt_variant[]; + +string srt_dev[]; +string srt_pac[]; +string srt_sym[]; +string srt_tec[]; +string srt_var[]; +string srt_pref[]; + + +string srt_drills[]; + +int index_dev[]; +int index_pac[]; +int index_sym[]; +int index_tec[]; +int index_var[]; +int index_pref[]; +int index_dril[]; + +int drills[]; +int cntdril[]; + +int cntdev = 0; +int cntpac = 0; +int cntsym = 0; +int cnttec = 0; +int cntvar = 0; +int cntpref = 0; +int cntdrills = 0; + +int used_pac[]; +int used_sym[]; + +string unUsed_pac[]; +string unUsed_sym[]; + +string usedlabel = " "; +string used[] = { "used in Deviceset\tcnt" }; + +int cntclearused = 0; // Error in dlgListView, + // clear all strings in array befor use dlgListView + // if used a second time less string entry + + +int cntUnUsed_pac = 0; +int cntUnUsed_sym = 0; + +int us, up; +string PackInfo = "Double click on to a package entry\nfor more statistics.\n \n "; +string SymbolInfo = " \n \n"; + +string defined_layers[] = {"" }; +int cnt_deflayer = 0; + +string used_layers[] = {"" }; +int cnt_used_layers = 0; + +string user_layers[] = {"" }; +int cnt_user_layers = 0; + +string usedTechno[]; +int nusedTecno; + +string usedVar[]; +int nusedVar; + +string Empty = "~empty~"; +int nusedPrefix; + +string edittype; + + +// *** --- Functions --- *** + +void checkprefix(string prefix) { + if (!prefix) prefix = Empty; + int f = 0; + for (int n = 0; n <= cntpref; n++) { + if (src_pref[n] == prefix) { + f = 1; + break; + } + } + if (f) return; + src_pref[cntpref] = prefix; + cntpref++; + return; +} + +void checkVariant(string var) { + int f = 0; + for (int n = 0; n <= cntvar; n++) { + if (src_var[n] == var) { + f = 1; + break; + } + } + if (f) return; + src_var[cntvar] = var; + cntvar++; + return; +} + +void checkTechno(string tech) { + string techno[]; + int t = strsplit(techno, tech, ' '); + for (int xt = 0; xt < t; xt++) { + int notf = 1; + for (int n = 0; n <= cnttec; n++) { + if (src_tec[n] == techno[xt]) { + notf = 0; + break; + } + } + if (notf) { + src_tec[cnttec] = techno[xt]; + cnttec++; + } + } + return; +} + + +void TecInfo(string tec) { + library(L) { + usedlabel = "Used Technoligies "; + used[0] = "Deviceset"; + used[1] = ""; + nusedTecno = 1; + L.devicesets(DS) { + DS.devices(D) { + string techno[]; + int cnt = strsplit(techno, D.technologies, ' '); + for (int n = 0; n <= cnt; n++) { + if (techno[n] == tec) { + + sprintf(used[nusedTecno], "%s", DS.name); + nusedTecno++; + used[nusedTecno] = ""; + break; + } + } + } + } + } + return; +} + + +void VarInfo(string var) { + library(L) { + usedlabel = "Used Variants "; + used[0] = "Deviceset"; + used[1] = ""; + nusedVar = 1; + L.devicesets(DS) { + DS.devices(D) { + if (D.name == var) { + sprintf(used[nusedVar], "%s", DS.name); + nusedVar++; + used[nusedVar] = ""; + } + } + } + } + return; +} + +void PrefInfo(string pref) { + if (!pref) pref = Empty; + library(L) { + usedlabel = "Used Prefix " + pref; + used[0] = "Deviceset"; + used[1] = ""; + nusedPrefix = 1; + L.devicesets(DS) { + string pfx = DS.prefix; + if (!pfx) pfx = Empty; + if(pfx == pref) { + sprintf(used[nusedPrefix], "%s", DS.name); + nusedPrefix++; + used[nusedPrefix] = ""; + } + } + } + return; +} + + +void checkUsedPac(string pac) { + int f = 0; + for (int n = 0; n <= cntpac; n++) { + if (src_pac[n] == pac) { + used_pac[n]++; + return; + } + } + dlgMessageBox("Pac not found!", "OK"); +} + + +void checkUsedSym(string sym) { + int f = 0; + for (int n = 0; n <= cntsym; n++) { + if (src_sym[n] == sym) { + used_sym[n]++; + return; + } + } + dlgMessageBox("Sym not found!", "OK"); +} + + +string addApostroph(string s) { + int len = strlen(s); + int pos = strrchr(s, '\''); + string l; + if (pos >= 0) { + l = strsub(s, 0, pos) + "'" + strsub(s, pos, len-pos); + s = l; + } + return s; +} + + +void del_unused_pac(void) { // 2006.05.09 + if (dlgMessageBox("Delete all unused packages?", "YES", "NO") != 0) return; + string cmd, s; + for (int n = 0; n < cntUnUsed_pac; n++) { + sprintf(s, "REMOVE '%s.PAC';\n", addApostroph(unUsed_pac[n])); + cmd += s; + } + sprintf(s, "RUN '%s';\n", argv[0]); + cmd += s; + exit(cmd); +} + + +void del_unused_sym(void) { // 2007.11.26 + if (dlgMessageBox("Delete all unused symbols?", "YES", "NO") != 0) return; + string cmd, s; + for (int n = 0; n < cntUnUsed_sym; n++) { + sprintf(s, "REMOVE '%s.SYM';\n", addApostroph(unUsed_sym[n])); + cmd += s; + } + sprintf(s, "RUN '%s';\n", argv[0]); + cmd += s; + exit(cmd); +} + + +// ** ------------------------ ** +void checkDrill(int drill) { + int nof = 1; + for (int n = 0; n < cntdrills; n++) { + if (drills[n] == drill) { + nof = 0; + cntdril[n]++; + break; + } + } + if (nof) { + drills[cntdrills] = drill; + cntdril[cntdrills]++; + cntdrills++; + } + return; +} + + +int countPAD(UL_PACKAGE P) { + int Pads; + P.contacts(C) { + if (C.pad) { + Pads++; + } + } + return Pads; +} + + +int countSMD(UL_PACKAGE P) { + int Smds; + P.contacts(C) { + if (C.smd) { + Smds++; + } + } + return Smds; +} + +int countHOLE(UL_PACKAGE P) { + int Holes; + P.holes(H) { + Holes++; + } + return Holes; +} + + +int countPIN(UL_SYMBOL S) { + int Pins; + S.pins(P) { + Pins++; + } + return Pins; +} + + +int newUsed(string use_name) { + int new = 1; + int n = 0; + do { + if (used[n] == use_name) { + new = 0; + break; + } + n++; + } while(used[n]); + return new; +} + + +void syminfo(string Name_and_count) { + string symbolname[]; + int n = strsplit(symbolname, Name_and_count, '\t'); + usedlabel = "" + symbolname[0]+".SYM"; + used[0] = "used in Deviceset\tcnt"; + int usedcount = 1; + used[usedcount] = ""; + for (int u = 1; u < cntclearused; u++) used[u] = ""; // while error in dlgListView() + // clear all strings in array 03.05.2005 alf + library(L) { + L.symbols(S) { + if (S.name == symbolname[0]) { + sprintf(SymbolInfo, "%s
    %3d Pin in symbol", S.name, countPIN(S) ); + } + } + L.devicesets(DS) { + int cntinuse; + int new = 0; + DS.gates(G) { + if (G.symbol.name == symbolname[0]) { + if (newUsed(DS.name)) { + used[usedcount] = DS.name; + usedcount++; + used[usedcount] = ""; + new++; + } + cntinuse++; + } + } + if (new) { + string h; + sprintf(h, "\t%d", cntinuse); + used[usedcount-1] += h; + } + } + } + used[usedcount] = ""; + if (cntclearused < usedcount) cntclearused = usedcount; + return; +} + + +void pacinfo(string Name_and_count) { + string packname[]; + int n = strsplit(packname, Name_and_count, '\t'); + usedlabel = "" + packname[0]+".PAC"; + used[0] = "used in Deviceset\tcnt"; + int usedcount = 1; + used[usedcount] = ""; + for (int u = 1; u < cntclearused; u++) used[u] = ""; // while error in dlgListView() + // clear all strings in array 03.05.2005 alf + library(L) { + L.packages(P) { + if (P.name == packname[0]) { + int pac_rect; + int pac_circle; + int pac_wire; + int pac_poly; + int pac_text; + P.rectangles(R) pac_rect++; + P.circles(C) pac_circle++; + P.wires(W) pac_wire++; + P.polygons(P) pac_poly++; + P.texts(T) pac_text++; + sprintf(PackInfo, "Rects = %d\nCircles = %d\nWires = %d\nPolygons = %d\nTexts = %d", pac_rect, pac_circle, pac_wire, pac_poly, pac_text); + dlgMessageBox(PackInfo, "OK"); + sprintf(PackInfo, "%s
    %3d Pad
    %3d Smd
    %3d Hole", P.name, countPAD(P), countSMD(P), countHOLE(P) ); + } + } + L.devicesets(DS) { + int cntinuse; + int new = 0; + DS.devices(D) { + if (D.package) { + if (D.package.name == packname[0]) { + if (newUsed(DS.name)) { + used[usedcount] = DS.name; + usedcount++; + used[usedcount] = ""; + new++; + } + cntinuse++; + } + } + } + if (new) { + string h; + sprintf(h, "\t%d", cntinuse); + used[usedcount-1] += h; + } + } + } + used[usedcount] = ""; + if (cntclearused < usedcount) cntclearused = usedcount; + return; +} + + +void drillinfo(int Drill) { + sprintf(usedlabel, "Drill %.4f mm", u2mm(Drill)); + used[0] = "used in Package\tcnt"; + int usedcount = 1; + used[usedcount] = ""; + for (int u = 1; u < cntclearused; u++) used[u] = ""; // while error in dlgListView() + // clear all strings in array 03.05.2005 alf + library(L) { + L.packages(P) { + int cntinuse; + int new = 0; + P.contacts(C) { + if (C.pad) { + if (C.pad.drill == Drill) { + if (newUsed(P.name)) { + used[usedcount] = P.name; + usedcount++; + used[usedcount] = ""; + new++; + } + cntinuse++; + } + } + } + if (new) { + string h; + sprintf(h, "\t%d", cntinuse); + used[usedcount-1] += h; + } + } + } + used[usedcount] = ""; + if (cntclearused < usedcount) cntclearused = usedcount; + + return; +} + + +void collectLbr(UL_LIBRARY L) { + L.packages(P) { + status(P.name+".PAC"); + src_pac[cntpac] = P.name ; + cntpac++; + src_pac[cntpac] = ""; + P.contacts(C) { + if (C.pad) { + checkDrill(C.pad.drill); + } + } + } + + status(""); + L.symbols(S) { + src_sym[cntsym] = S.name ; + cntsym++; + src_sym[cntsym] = ""; + } + + L.devicesets(DS) { + src_dev[cntdev] = DS.name ; + checkprefix(DS.prefix); + DS.devices(D) { + checkVariant(D.name); + checkTechno(D.technologies); + if (D.package) { + checkUsedPac(D.package.name); + } + cnt_variant[cntdev]++; + } + cntdev++; + src_dev[cntdev] = ""; + DS.gates(G) { + checkUsedSym(G.symbol.name); + } + } + return; +} + +void sort_data(void) { + int n; + string s; + sort (cntdev, index_dev, src_dev, cnt_variant); // 2005.11.15 alf + sort (cntvar, index_var, src_var); + sort (cnttec, index_tec, src_tec); + sort (cntpref, index_pref, src_pref); + sort (cntpac, index_pac, src_pac, used_pac); + sort (cntsym, index_sym, src_sym, used_sym); + sort (cntdrills, index_dril, drills, cntdril); + + for (n = 0; n < cntdev; n++) { + srt_dev[n] = src_dev[index_dev[n]]; + } + for (n = 0; n < cntvar; n++) { + srt_var[n] = src_var[index_var[n]]; + } + for (n = 0; n < cnttec; n++) { + srt_tec[n] = src_tec[index_tec[n]]; + } + for (n = 0; n < cntpref; n++) { + srt_pref[n] = src_pref[index_pref[n]]; + } + for (n = 0; n < cntpac; n++) { + if (used_pac[index_pac[n]]) sprintf(s, "\t%d", used_pac[index_pac[n]]); + else { + s = "\t -"; + unUsed_pac[cntUnUsed_pac] = src_pac[index_pac[n]]; + cntUnUsed_pac++; + } + srt_pac[n] = src_pac[index_pac[n]] + s; + } + for (n = 0; n < cntsym; n++) { + if (used_sym[index_sym[n]]) sprintf(s, "\t%d", used_sym[index_sym[n]]); + else { + s = "\t -"; + unUsed_sym[cntUnUsed_sym] = src_sym[index_sym[n]]; + cntUnUsed_sym++; + } + srt_sym[n] = src_sym[index_sym[n]] + s; + } + for (n = 0; n < cntdrills; n++) { + sprintf(srt_drills[n], "%.4f\t%d", u2mm(drills[index_dril[n]]), cntdril[index_dril[n]]); + } + return; +} + + +// 2006.09.19 check used user layer +string check_userlayer(string ulay) { + string use_user_layer = ""; + int l = strtol(ulay); + library(L) { + L.packages(PAC) { + status(" check "+PAC.name+".PAC"); + int use = 0; + PAC.wires(W) if (W.layer == l) { use++; break; } + PAC.circles(C) if (C.layer == l) { use++; break; } + PAC.rectangles(R) if (R.layer == l) { use++; break; } + PAC.polygons(P) if (P.layer == l) { use++; break; } + PAC.texts(T) if (T.layer == l) { use++; break; } + if (use) use_user_layer += PAC.name + ".PAC\n"; + } + L.symbols(S) { + status(" check "+S.name+".SYM"); + int use = 0; + S.wires(W) if (W.layer == l) { use++; break; } + S.circles(C) if (C.layer == l) { use++; break; } + S.rectangles(R) if (R.layer == l) { use++; break; } + S.polygons(P) if (P.layer == l) { use++; break; } + S.texts(T) if (T.layer == l) { use++; break; } + if (use) use_user_layer += S.name + ".SYM\n"; + } + status(""); + } + return use_user_layer; +} + + +void exit_edit(string text, string ulay) { + string s[], l[]; + int n = strsplit(s, text, '\n'); + int u = strsplit(l, ulay, ' '); + exit("EDIT "+s[0]+";\nLAYER "+l[0]+";"); +} + +void check_used(string ulay) { + string use_user_layer = check_userlayer(ulay); + if (use_user_layer) { + dlgDialog("Statistic") { + dlgLabel("Use layer " + ulay); + dlgTextView(use_user_layer); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("Edit") { dlgAccept(); exit_edit(use_user_layer, ulay); } + dlgStretch(1); + } + }; + } + else if (dlgMessageBox(ulay + "\nthis layer is not used!", "OK", "Delete") != 0) { + string cmd; + sprintf(cmd, "LAYER -%d;\nRUN '%s'\n", strtol(ulay), argv[0]); + exit(cmd); + } + return; +} + + +// 2006.09.19 delete unused user layer +void del_unused_userlayer(void) { + string cmd; + for (int n = 0; n < cnt_user_layers; n++) { + if (!check_userlayer(user_layers[n])) { + string s; + sprintf(s, "LAYER -%d;\n", strtol(user_layers[n]) ); + cmd += s; + } + } + if (cmd) exit(cmd+"RUN '" + argv[0] + "';"); + return; +} + +void save(void) { + string fname; + library(L) fname = L.name; + output(filesetext(fname, ".stat"), "wt") { + printf("%s\nDevices %s\nPAC-Variants %s\nTechnoligies %s\nPackages %s\nSymbols %s\nPrefix %s\nDrills %s\nUnused packages %s\nUnused symbols %s\n", + fname, + ndev, nvar, ntec, npac, nsym, npref, ndril, cupac, cusym + ); + } + return; +} + +void menue_1(void) { + int seldev = 0; + int seltec = 0; + int selvar = 0; + int selpref = 0; + int selsym = -1; + int selpac = -1; + int seldril = -1; + int selused = 0; + + + string usedVariants = " select Device"; + sprintf(ndev, "%3d", cntdev); + sprintf(nvar, "%3d", cntvar); + sprintf(ntec, "%3d", cnttec); + sprintf(npac, "%3d", cntpac); + sprintf(nsym, "%3d", cntsym); + sprintf(npref, "%3d", cntpref); + sprintf(ndril, "%3d", cntdrills); + sprintf(cupac, "%3d", cntUnUsed_pac); + sprintf(cusym, "%3d", cntUnUsed_sym); + sprintf(culay, "%3d", cnt_user_layers); // 2006.09.19 + int listsort = 0; + int sellay, selulay; + + int Result = dlgDialog("Library statistic") { + dlgHBoxLayout { + dlgVBoxLayout dlgSpacing(400); + dlgGridLayout { + dlgCell( 0,1) dlgSpacing(200); + dlgCell( 0,2) dlgSpacing(100); + + dlgCell( 1,0) { dlgLabel(ndev); dlgLabel("&Devices"); } + dlgCell( 1,1) dlgComboBox(srt_dev, seldev) { + sprintf(usedVariants, "%d Variant ", cnt_variant[seldev]); + usedlabel = "Devicesets "; + used[0] = "Deviceset"; + used[1] = srt_dev[seldev]; + used[2] = ""; + edittype = ".DEV"; + } + dlgCell( 1,2) dlgLabel(usedVariants, 1); + + dlgCell( 2,0) { dlgLabel(nvar); dlgLabel("&Variants"); } + dlgCell( 2,1) dlgComboBox(srt_var, selvar) { VarInfo(srt_var[selvar]); edittype = ".DEV"; } + + dlgCell( 3,0) { dlgLabel(ntec); dlgLabel("&Technoligies"); } + dlgCell( 3,1) dlgComboBox(srt_tec, seltec) { TecInfo(srt_tec[seltec]); edittype = ".DEV"; } + + dlgCell( 4,0) { dlgLabel(npref); dlgLabel("&Prefix"); } + dlgCell( 4,1) dlgComboBox(srt_pref, selpref) { PrefInfo(srt_pref[selpref]); edittype = ".DEV"; } + + dlgCell( 5,0) dlgLabel("&Used Layers"); + dlgCell( 5,1) dlgComboBox(used_layers, sellay); + + if (cnt_deflayer) { + dlgCell( 6,1) dlgLabel("+ defined layer"); + dlgCell( 7,0) dlgLabel("&+defined Layers"); + dlgCell( 7,1) dlgComboBox(defined_layers, sellay); + } + + + if (cnt_user_layers) { + dlgCell( 8,1) dlgLabel("Layer user defined"); + dlgCell( 9,1) dlgComboBox(user_layers, selulay) check_used(user_layers[selulay]); + dlgCell( 9,2) if (user_layers[0]) { dlgLabel(culay); dlgPushButton("DELETE") del_unused_userlayer(); } // 2006.09.19 + } + + dlgCell( 10,1) dlgVBoxLayout { + dlgLabel(usedlabel, 1); + dlgListView("", used, selused, listsort); + } + dlgCell( 10,2) dlgVBoxLayout { + dlgSpacing(18); + dlgHBoxLayout { + dlgPushButton("EDIT") { + string e[]; int n = strsplit(e, used[selused], '\t'); + if(selused) { dlgAccept(); exit("EDIT '"+e[0]+edittype+"'"); } + else { + if (!used[1]) dlgMessageBox("!List is empty.\nSelect a Device, Variant, Technology, Symbol or Package.", "OK"); + else if (selused < 1) { + if (edittype == ".DEV") dlgMessageBox("Select a Device", "OK"); + if (edittype == ".PAC") dlgMessageBox("Select a Package", "OK"); + } + } + } + dlgStretch(1); + } + dlgStretch(1); + } + + dlgCell( 11,0) { dlgLabel(cupac); dlgLabel("Unused &Package"); } + dlgCell( 11,1) dlgComboBox(unUsed_pac, up); + dlgCell( 11,2) dlgHBoxLayout { + if (cntUnUsed_pac) { dlgPushButton("DELETE") del_unused_pac(); } // 2006.05.09 + dlgStretch(1); + } + + dlgCell( 12,0) { dlgLabel(cusym); dlgLabel("Unused &Symbol"); } + dlgCell( 12,1) dlgComboBox(unUsed_sym, us); + dlgCell( 12,2) dlgHBoxLayout { + if (cntUnUsed_sym) { dlgPushButton("DELETE") del_unused_sym(); } // 2006.05.09 + dlgStretch(1); + } + } + dlgVBoxLayout { + dlgLabel("S&ymbols " + nsym); + dlgListView("Symbol\tUsed", srt_sym, selsym) { + syminfo(srt_sym[selsym]); + selpac = -1; + seldril = -1; + edittype = ".DEV"; + } + dlgLabel(SymbolInfo, 1); + dlgPushButton("EDIT .sym") { + if(selsym >= 0) { + dlgAccept(); + edittype = ".SYM"; + string e[]; int n = strsplit(e, srt_sym[selsym], '\t'); + exit("EDIT '"+e[0]+edittype+"'"); + } + else dlgMessageBox("First select a Symbol", "OK"); + } + } + dlgVBoxLayout { + dlgLabel("P&ackages " + npac); + dlgListView("Package\tUsed", srt_pac, selpac) { + pacinfo(srt_pac[selpac]); + selsym = -1; + seldril = -1; + edittype = ".DEV"; + } + dlgLabel(PackInfo, 1); + dlgPushButton("EDIT .pac") { + if(selpac >= 0) { + dlgAccept(); + edittype = ".PAC"; + string e[]; int n = strsplit(e, srt_pac[selpac], '\t'); + exit("EDIT '"+e[0]+edittype+"'"); + } + else dlgMessageBox("First select a Package", "OK"); + } + } + dlgVBoxLayout { + dlgLabel("D&rills " + ndril); + dlgListView("Drill mm\tUsed", srt_drills, seldril) { + drillinfo(drills[index_dril[seldril]]); + selsym = -1; + selpac = -1; + edittype = ".PAC"; + } + } + dlgVBoxLayout dlgSpacing(300); + } + + dlgSpacing(12); + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("&Save") save(); + dlgStretch(1); + dlgLabel(Revision); + } + }; + return ; +} + + +// main +if (library) library(L) { + status("Layers"); + L.layers(LAY) { + if (LAY.used) { + sprintf(used_layers[cnt_used_layers], "%d %s", LAY.number, LAY.name); + cnt_used_layers++; + } + if (LAY.number >= 100) { + sprintf(user_layers[cnt_user_layers], "%d %s", LAY.number, LAY.name); + cnt_user_layers++; + } + if (LAY.number == 50 || LAY.number > 52 && LAY.number < 91 || LAY.number > 98 ) { // 2013-02-21 + sprintf(defined_layers[cnt_deflayer], "%d %s", LAY.number, LAY.name); + cnt_deflayer++; + } + } + collectLbr(L); + sort_data(); + menue_1(); +} + diff --git a/trunk/ulp/statistic-sch.ulp b/trunk/ulp/statistic-sch.ulp new file mode 100644 index 00000000..58e2d085 --- /dev/null +++ b/trunk/ulp/statistic-sch.ulp @@ -0,0 +1,770 @@ +#usage "Statistic Table of Parts in the Schematic

    \n" + "To change the units in the table, please use the variable uval,\n" + "which can be found in the ulp file.

    \n" + "THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, " + "EXPRESSED OR IMPLIED.

    \n" + "Author: alf@cadsoft.de" + +#require 4.1106 + + +string Version = "1.0.2"; + +int uval = 1; +string unit[] = { "Micron", "mm", "Mil", "Inch" }; +int unitPrec[] = { 0, 1, 1, 3 }, RoundFactor = pow(10, unitPrec[uval]); + +int maxX = INT_MIN; +int minX = INT_MAX; +int maxY = INT_MIN; +int minY = INT_MAX; + +string wireWidthInternal = " * Wire width are saved in 0.2 micron!\n"; +// ****************************************************************** +// *** WIRE WIDTH wird nur geradzahlig gespeichert, wegen Teilung *** az +// ****************************************************************** + + +int cntLayer = 0; +string usedLayer; +int cntalllay; +string allLayers[]; +string layerError; +string displayLayerError; + +string NetClassName[]; +int NetClassWidth[]; +int NetClassClear[]; +int NetClassDrill[]; +int NetClassNr[]; +int cNetClass[]; +int minClearance = 0; + +int sumNets = 0; +string NetName[]; +int NetClass[]; +string NetClassList[]; +int NetClassSelect = 0; +int NetCnt = 0; + +string falseNetList[]; +string falseNetSheet[]; +int falseNetCnt; + +numeric string statisticWirew[]; +numeric string statisticCLASS[]; +numeric string statisticFalseNets[]; +numeric string statisticLBR[]; +numeric string statisticPAC[]; +numeric string statisticDevice[]; +numeric string statisticVariant[]; + + + + +string onlyNetList[]; // only signal if connected to pad or smd is a true signal 2005.12.08 alf@cadsoft.de +int onlyNetCnt = 0; + +int cnt_Pin_on_net = 0; + + + +string Lbr[]; +int cLbr[]; +int cntLbr = 0; + +string PacName[]; +int cPacName[]; +int cntPacName = 0; + +string Device[]; +int cDevice[]; +int cntDevice = 0; + +string VDevice[]; +string Value[]; +string Variant[]; +string VPart[]; // Partname of same Value +int cVariant[]; +int cntVariant = 0; +int cntNewLine[]; + + +numeric string nPart[] = { "PART" }; +int cntnPart; + +numeric string InstanceGate[]; +int cntGate; +numeric string nGate[]; +int cntnGate; + +string Symbol[]; +int cSymbol[]; +int cntSymbol = 0; + + +// --- same Value and Package and Layer --- 2005.12.01 alf@cadsoft.de +int cntEVPL = 0; +string EVALpac[]; +string EvalPAC[]; +int cEVPL[]; + + +int emptyValue = 0; +string empty = "~/-empty-/~"; + +int cntPart = 0; +string Ename[]; + +int art_selected = 0; +int LBRselected; +int PACselected; +int DEVselected; +int VARselected; +int VALselected; +int NPselect; + +string Part_info = " \n \n \n"; +string linfo = " Double click in listings for detailed info."; +string Val_info = " Double click in listings for detailed info."; + +string sum; +int sumSignals = 0; + +string used_pac[], used_pac_lbr[]; +int cntusedpac = 0; +string unused_pac[], unused_pac_lbr[]; +int cntunusedpac = 0; + +string Text; + +string ulp_path = filedir(argv[0]); + + +string schfile; + + +// Functions + +real u2u(int v) { + switch (uval) { + case GRID_UNIT_MIC : return u2mic(v); + break; + + case GRID_UNIT_MM : return u2mm(v); + break; + + case GRID_UNIT_MIL : return u2mil(v); + break; + + case GRID_UNIT_INCH : return u2inch(v); + break; + } +} + + +string value(int v, string is) { + if (v == INT_MAX) return "not used " + is; + string sv; + switch (uval) { + case GRID_UNIT_INCH : sprintf(sv, "%.6f %s", u2inch(v), is); + break; + + case GRID_UNIT_MIL : sprintf(sv, "%.3f %s", u2mil(v), is); + break; + + case GRID_UNIT_MM : sprintf(sv, "%.4f %s", u2mm(v), is); + break; + + case GRID_UNIT_MIC : sprintf(sv, "%.1f %s", u2mic(v), is); + break; + } + return sv; +} + + + + +string saveReport(void) { + int t = time(); + int n; + string report = "Data Expoted from: "; + report += schfile + "\n"; + report += "with: " + argv[0] + "\n"; + report += "at: " + t2string(t) + "\n"; + report += EAGLE_SIGNATURE + "\n\n"; + report += usedLayer + "_________________________\n\n"; + report += layerError; + report += "\n"; + report += sum + "\n"; + report += "\n============================\n"; n=0; + + report += "\n----------------------------\nLAYER\n"; n=0; + sort(cntalllay, allLayers); + report += "Nb.\tName\tUsed\n"; + for (n = 0; n < cntalllay; n++) { + report+= allLayers[n] + "\n"; + } + report += "\n----------------------------\nCLASS\n"; n=0; + while (statisticCLASS[n]) { + report += statisticCLASS[n] + "\n"; + n++; + } + report += "\n"; n=0; + report += "\n----------------------------\n"; n=0; + while (statisticLBR[n]) { + report += statisticLBR[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticPAC[n]) { + report += statisticPAC[n] + "\n"; + n++; + } + report += "\n"; n=0; + while (statisticDevice[n]) { + report += statisticDevice[n] + "\n"; + n++; + } + + report += "\n"; n=0; + report += "\n----------------------------\n"; n=0; + report += "\n"; + report += "End report"; + return report; +} + + +string NetClassLabel(string ClassName , int cnt) { + string s; + sprintf(s, "CLASS %s : %d Netze", ClassName , cnt); + return s; +} + + +string isempty(string s) { + if (!s) s = empty; + return s; +} + + +void infoLBR( string lbr) { + linfo = " Part : Device : Value : Package "; + string s, M; + schematic(S) { + S.parts(P) { + if (P.device.library == lbr) { + if (P.device.package) { + sprintf(s, "%s \t: %s\t: %s\t: %s\n", P.name, P.device.name, isempty(P.value), P.device.package.name); + Part_info += s; + } + else { + Part_info += P.name + "\t - \tDevice has no Package\n"; + } + } + } + } + return; +} + + +void infoPAC( string pac) { + linfo = " Part : Device : Value : Library "; + string s, M; + int getdrill = 0; + schematic(S) S.parts(P) { + if (P.device.package) { + if (P.device.package.name == pac) { + sprintf(s, "%s \t: %s\t: %s\t:%s\n", P.name, P.device.name, isempty(P.value), P.device.package.library); + Part_info += s; + } + } + } + return; +} + + +void infoDEV( string dev) { + string s; + linfo = " Part : Value : Package : Library "; + schematic(S) S.parts(P) if (P.device.name == dev) { + if (P.device.package) { + sprintf(s, "%s\t: %s\t: %s\t: %s\n", P.name, isempty(P.value), P.device.package.name, P.device.package.library); + Part_info += s; + } + } + return; +} + + +void get_Info(int art, string val) { + Part_info = ""; + int pos = strchr(val, '\t', 0); + val = strsub(val, 0, pos); + switch(art) { + case 1 : infoLBR(val); + break; + + case 2 : infoPAC(val); + break; + + case 3 : infoDEV(val); + break; + + default : break; + } + return; +} + + +string checkNet(string Net) { + string Sheetn = ""; + string separator = ""; + schematic(SCH) { + SCH.sheets(SH) { + SH.nets(N) { + if (Net == N.name) { + string s; + sprintf(s, "%d,", SH.number); + Sheetn += s; + separator = ","; + break; + } + } + } + } + if (!Sheetn) Sheetn = "Layer 0 ?"; + return Sheetn; +} + + +// main +if (schematic) { + int n; + schematic(SCH) { + schfile = SCH.name; + string usedLayers; + status(" Layers"); + SCH.layers(L) { + string sl; + sprintf(sl, "%3d\t%s\t%d", L.number, L.name, L.used); + allLayers[cntalllay] = sl; + cntalllay++; + if (L.used && L.number >=90 && L.number <= 99) { + cntLayer++; + sprintf(sl, "%2d %s\n", L.number, L.name); + usedLayers += sl; + } + } + sprintf(usedLayer, "used layers %d\n\n%s", cntLayer, usedLayers); + + SCH.classes(CL) { + // Net classes ******************** + NetClassNr[CL.number] = CL.number; + NetClassName[CL.number] = CL.name; + NetClassWidth[CL.number] = CL.width; + NetClassClear[CL.number] = CL.clearance; + NetClassDrill[CL.number] = CL.drill; + cNetClass[CL.number] = 0; + } + SCH.nets(N) { + status(" Nets "+N.name); + int true = 0; // only signal if connected to pad or smd is a true signal 2005.12.08 alf@cadsoft.de + N.pinrefs(PR) { + true = 1; + break; + } + if (true) { + cNetClass[N.class.number]++; + sumNets++; + NetName[NetCnt] = N.name; + NetClass[NetCnt] = N.class.number; + NetCnt++; + NetClassList[N.class.number] += N.name + "\n"; + } + else { + falseNetList[falseNetCnt] = N.name; // only signal if connected to pad or smd is a true signal + falseNetSheet[falseNetCnt] = checkNet(N.name); + falseNetCnt++; + } + } + + SCH.parts(P) { + P.instances(I) { + status(" Instance "+I.name); + if (!I.sheet) { + sprintf(nGate[cntnGate], "%s\t%s\t%s\t%s", P.name, I.gate.name, P.value, P.device.library); + cntnGate++; + } + else { + sprintf(InstanceGate[cntGate], "%s\t%s\t%d\t%s", P.name, I.gate.name, I.sheet, P.device.library); + cntGate++; + } + } + + // Part Libraries ********* + for (n = 0; n <= cntLbr; n++) { + if (Lbr[n] == P.device.library) { + cLbr[n]++; + break; + } + } + if (n > cntLbr) { + cntLbr++; + Lbr[cntLbr] = P.device.library; + cLbr[cntLbr]++; + } + + // Part Package ********* + if (P.device.package) { // nur Parts mit Package sonst Symbol wie Frame/Supply etc. + status(" Package "+P.name); + + for (n = 0; n <= cntPacName; n++) { + if (PacName[n] == P.device.package.name) { + cPacName[n]++; + break; + } + } + if (n > cntPacName) { + cntPacName++; + PacName[cntPacName] = P.device.package.name; + cPacName[cntPacName]++; + } + + for (n = 0; n <= cntDevice; n++ ) { + if (Device[n] == P.device.name) { + cDevice[n]++; + break; + }; + } + if (n > cntDevice) { + cntDevice++; + Device[n] = P.device.name; + cDevice[cntDevice]++; + } + + // Value & Variant 2006.03.16 alf + string Pval = P.value; + if (!Pval) Pval = empty; + cntnPart++; + nPart[cntnPart] = P.name; + for (n = 0; n <= cntVariant; n++) { + if (VDevice[n] == P.device.package.name && Value[n] == Pval && Variant[n] == P.device.name) { + VPart[n] += ";"; + cVariant[n]++; + cntNewLine[n]++; + if (cntNewLine[n] == 29) { + cntNewLine[n] = 0; + VPart[n] += "\n"; + } + VPart[n] += P.name; + break; + } + } + if (n > cntVariant) { + cntVariant++; + VDevice[cntVariant] = P.device.package.name; + Value[cntVariant] = Pval; + Variant[cntVariant] = P.device.name; + VPart[n] += P.name; + cVariant[cntVariant]++; + } + } + else { + for (n = 0; n <= cntSymbol; n++ ) { + if (Symbol[n] == P.device.name) { + cSymbol[n]++; + break; + }; + } + if (n > cntSymbol) { + cntSymbol++; + Symbol[n] = P.device.name; + cSymbol[cntSymbol]++; + } + } + + + // Part Value ********* 2005.12.01 alf@cadsoft.de + // ----- List by Value/Package/Layer ----------- + string Pv = P.value; + if (Pv == "") { + Pv = empty + P.name; + emptyValue++; + } + for (n = 0; n <= cntEVPL; n++) { + if (P.device.package) { + if (EVALpac[n] == Pv && EvalPAC[n] == P.device.package.name ) { + cEVPL[n]++; + break; + } + } + } + if (n > cntEVPL) { + cntEVPL++; + EVALpac[cntEVPL] = Pv; + if (P.device.package) { + EvalPAC[cntEVPL] = P.device.package.name; + } + else { + EvalPAC[cntEVPL] = "-- only Symbol --"; + } + cEVPL[cntEVPL]++; + } + } + SCH.libraries(L) { // 2006.05.09 check unused packages + L.devicesets(DS) { + status(" Devicesets "+DS.name); + DS.devices(D) { + if (D.package) { + int n; + for (n = 0; n <= cntPacName; n++) { + if (D.package.name == PacName[n]) { + used_pac[cntusedpac] = D.package.name + "\t" + DS.name + L.name; + cntusedpac++; + break; + } + } + if (n > cntPacName) { + unused_pac[cntunusedpac] = D.package.name + "\t" + DS.name + L.name; + cntunusedpac++; + } + } + else { + ; // only Symbol (Supply) + } + } + } + } + } + + status(" Generate listings"); + int x = 0; + // Statistic tabels + // Net Class ******************** // 2014-11-27 supports 16 netclasses now -ric + statisticCLASS[x] = "# - Name\tmin. Width\tClearance\tmin. Drill\tUsed"; + for (n = 0; n <= 15; n++) { + if (NetClassName[n]) { + if(minClearance > NetClassClear[n]) minClearance = NetClassClear[n]; + x++; + sprintf(statisticCLASS[x], "%1d - %s\t%s\t%s\t%s\t%-4d", + NetClassNr[n], + NetClassName[n], + value(NetClassWidth[n], ""), + value(NetClassClear[n], ""), + value(NetClassDrill[n], ""), + cNetClass[n] + ); + } + } + + + x = 0; + // flase Signals ******************** 2005.12.08 alf@cadsoft.de + statisticFalseNets[x] = "Net-Name\tSheet"; + for (n = 0; n < falseNetCnt; n++) { + x++; + sprintf( statisticFalseNets[x], "%s\t%s", + falseNetList[n], // only net if connected to pin is a true Net + falseNetSheet[n] + ); + } + + + x = 0; + statisticLBR[x] = "LIBRARY\tQuant."; + for ( n = 0; n <= cntLbr; n++) { + if (cLbr[n]) { + x++; + sprintf(statisticLBR[x], "%s\t%-4d", Lbr[n], cLbr[n] ); + } + } + + x = 0; + statisticPAC[x] = "PACKAGE\tQuant."; + for ( n = 0; n <= cntPacName; n++) { + if (cPacName[n]) { + x++; + sprintf(statisticPAC[x], "%s\t%-4d", PacName[n], cPacName[n] ); + } + } + + x = 0; + statisticDevice[x] = "DEVICE\tQuant."; + for ( n = 0; n <= cntDevice; n++) { + if (cDevice[n]) { + x++; + sprintf(statisticDevice[x], "%s\t%-4d", Device[n], cDevice[n] ); + } + } + x = 0; + statisticVariant[0] = "VALUE\tDEVICE\tVARIANT\tQuant."; + for ( n = 0; n <= cntVariant; n++) { + if (cDevice[n]) { + x++; + sprintf(statisticVariant[x], "%s\t%s\t%s\t%-4d", Value[n], VDevice[n], Variant[n], cVariant[n] ); + } + } + + + int Selected = 0; + // ********************************************************************* + dlgDialog("Statistic of " + schfile) { + dlgHBoxLayout { + dlgTabWidget { // *** schematic *** + dlgTabPage("&SCHEMATIC") { + dlgHBoxLayout { + dlgSpacing(10); + dlgVBoxLayout { + dlgSpacing(10); + dlgLabel("


    "); + dlgLabel(usedLayer); + dlgLabel(displayLayerError); + dlgStretch(1); + } + } + dlgStretch(1); + } + + dlgTabPage("&LAYER") { // *** all Layer are defined *** + int layselect = 0; + dlgHBoxLayout { + dlgListView("Nb.:\tName\tUsed", allLayers, layselect ); // 2005.11.17 alf@cadsoft.de + dlgStretch(1); + } + } + + dlgTabPage("&CLASS (Signal)") { // *** Class clearance/isolate *** + string classlabel = "Class : " + NetClassName[0]; + string ClassNameL = NetClassLabel(NetClassName[NetClassSelect] , cNetClass[NetClassSelect]); + string NetList = NetClassList[NetClassSelect]; + dlgHBoxLayout { + dlgVBoxLayout { + dlgListView("", statisticCLASS, NetClassSelect) { NetList = NetClassList[NetClassSelect-1]; classlabel = "Class : " + NetClassName[NetClassSelect-1]; } + dlgSpacing(12); + dlgLabel("False Nets (not connected on a PIN)"); + dlgListView("", statisticFalseNets, NetClassSelect); + } + dlgSpacing(12); + dlgGroup("Netlist") { + dlgLabel(classlabel, 1); + dlgHBoxLayout { + dlgSpacing(4); + dlgTextView(NetList); + } + } + dlgStretch(1); + } + } + + dlgTabPage("&Device") { // *** Device *** + dlgHBoxLayout { + dlgVBoxLayout { + dlgHBoxLayout { + dlgListView("", statisticLBR, LBRselected) { + art_selected = 1; + get_Info(art_selected, statisticLBR[LBRselected]); + dlgRedisplay(); + } + dlgListView("", statisticPAC, PACselected) { + art_selected = 2; + get_Info(art_selected, statisticPAC[PACselected]); + dlgRedisplay(); + } + dlgListView("", statisticDevice, DEVselected) { + art_selected = 3; + get_Info(art_selected, statisticDevice[DEVselected]); + dlgRedisplay(); + } + } + } + dlgVBoxLayout { + dlgHBoxLayout { dlgLabel(linfo ,1); dlgSpacing(200); } + dlgSpacing(10); + dlgTextView(Part_info); + } + } + } + + dlgTabPage("&Part") { // *** Part *** + int Gselect; + dlgHBoxLayout { + dlgVBoxLayout { + dlgLabel(" "); + dlgListView(" Part\tGate\tSheet\tLibrary", InstanceGate, Gselect); + } + dlgSpacing(19); + dlgVBoxLayout { + dlgLabel(" No placed Gates "); + dlgListView(" Part\tGate\tValue\tLibrary", nGate, Gselect); + } + dlgStretch(1); + } + } + + dlgTabPage("&Value") { // *** Value *** + dlgHBoxLayout { + dlgVBoxLayout { + dlgHBoxLayout { + dlgListView("", statisticVariant, VALselected) { + art_selected = 3; + Val_info = VPart[VALselected]; + dlgRedisplay(); + } + dlgStretch(1); + } + } + } + dlgSpacing(8); + dlgHBoxLayout { + dlgSpacing(8); + dlgLabel(Val_info, 1); + } + dlgSpacing(8); + } + + dlgTabPage("P&ackage") { // *** Unused Packages *** + int unusedselected, usedselected; + int lsort = 0; + dlgHBoxLayout { + dlgVBoxLayout { + dlgHBoxLayout { + dlgListView("Used Package-Variant\tLibrary", used_pac, usedselected, lsort); + dlgListView("Unused Package-Variant\tLibrary", unused_pac, unusedselected, lsort); + dlgStretch(1); + } + } + } + } + + } + } + + dlgHBoxLayout { + dlgPushButton("-&Quit") dlgAccept(); + dlgPushButton("&Save report") { + string fileName = dlgFileSave("Select a file", filesetext(schfile,".rep"), "*.rep"); + if (fileName) { + output(fileName, "wt") { + printf("%s", saveReport()); + } + } + } + dlgSpacing(50); + dlgLabel("All Units = " + unit[uval]); + dlgSpacing(50); + dlgStretch(1); + } + dlgHBoxLayout { + dlgLabel("Database:"); + dlgLabel(schfile, 1); + dlgStretch(1); + } + }; + exit (0); +} + + + +else dlgMessageBox("Start this ULP from a Schematic", "OK"); + diff --git a/trunk/ulp/statistic_attention_min_value.bmp b/trunk/ulp/statistic_attention_min_value.bmp new file mode 100644 index 00000000..4b36bb59 Binary files /dev/null and b/trunk/ulp/statistic_attention_min_value.bmp differ diff --git a/trunk/ulp/storage.nv b/trunk/ulp/storage.nv new file mode 100644 index 00000000..9f7b6c43 --- /dev/null +++ b/trunk/ulp/storage.nv @@ -0,0 +1 @@ +created=10.10.2016 14:38s \ No newline at end of file diff --git a/trunk/ulp/teardrops.ulp b/trunk/ulp/teardrops.ulp new file mode 100644 index 00000000..b8e753e0 --- /dev/null +++ b/trunk/ulp/teardrops.ulp @@ -0,0 +1,685 @@ +#usage "Teardrops - v1.05 (02/17/12)\n" + "

    " + "This ULP allows creation of teardrop-shaped connections from a board's vias/pads to their attached wire segments. " + "Making these connections teardrop shaped enhances manufacturability and reduces board failure by ensuring " + "connectivity between the segment and via/pad in cases where the via hole is not accurately drilled and " + "would otherwise sever the segment." + "

    " + "Original Author: Tad Artis (E3Eagle_removethis@E3Switch.com)
    " + "Modifications: Bob Starr (rtzaudio@comcast.net)
    " + "Modification: layer selectable (alf@cadsoft.de)
    " + "
    " + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string HelpText = usage + + "

    Implementation
    " + "This ULP is a variant based on via_teardrops1.ulp by Tad Ardis originally. This version is designed to support pads as well. " + "An attempt has been made to implement teardrops in this ULP while maintaining DRC validity. " + "Teardrops are implemented as 'two' added wire segments attaching from the original signal, at a short radius from the via, to two tangential " + "points at the via's edge. These two attachments form a small triangle and then are further attached to the via's center in order to " + "avoid ratsnest dangling segment errors. The user can specify the radius from the via at which the teardrop begins." + "

    Output
    " + "The output of this program is an .scr script which may be run to add vias to all signals on the board. " + "This .scr file is also properly formatted to allow it to be read into a spreadsheet program as a .csv file which will be found to contain " + "detailed information about the signal and via to which each teardrop is being added. The spreadsheet " + "columns can be sorted and copied back to an .scr to simplify adding teardrops to only certain net classes, via sizes, layers, etc. " + "The spreadsheet format may also allow teardrops to be added to an unused signal layer which would facilitate cutting " + "them from undesired portions of the board and might create a cleaner situation for future board upgrades." + "

    Warnings
    " + "This ULP should be used with forethought or on a copy of your board file just before plotting.
    " + "It may difficult to remove teardrops once added. It may be difficult to run the teardrop ULP a second time on a board which " + "already has teardrops. It may be possible to alleviate these concerns by using the spreadsheet output or a find/replace " + "on the .scr file to send the " + "teardrops to unused signal layers which are then included when the origin signal layer is plotted.
    " + "One should be aware that there are small hexogonal points at the ends of the added teardrop segments which protrude beyond " + "the tangent of the via. In most cases these protrusions are tiny and won't present any design rule violations." + "

    Limitations
    " + "The current software operates using mm units for .scr and only accepts units in mils from the user and in generated spreadsheet values." + "

    Copyright
    " + "Enhancements to the ULP are welcome without the necessity of contacting the author." + "

    " + "This program is provided AS IS and without warranty of any kind, expressed or implied." + "This program may be freely modified and distributed." + "

    " + "


    " + "All text in red shows differences with the previous version of this program." + "
    " +; + +#require 5.1200 + +string Release = "1.06"; +string ReleaseDate = "April 04, 2012"; // alf@cadsoft.de + +string HistoryText1 = + "

    " + "This program was based on the original via_teardrops1.ulp work by Tad Artis (E3Eagle_removethis@E3Switch.com).
    " + "An attempt has been made to add usable support for teardropping pads as well in this adaptation." + "

    " + "The following is a history of this program (most recent first)." + "

    " + "Version 1.0" + "

      " + "
    • Initial version. Released on January 5, 2008.
    • " + "
    " +; + +string HistoryText2 = + "

    " + "The following is a history of this program (most recent first)." + "

    " + "Version History" + "

      " + "
    • v1.00 - Initial release version.
    • " + "

    • v1.01 - Added teardropping of pads support.
    • " + "

    • v1.02 - Improved pad teardrop support.
    • " + "

    • v1.03 - Teardropping of square pad types added support.
    • " + "

    • v1.04 - Added fixes for Eagle v6.0 (Walter Mueller)
    • " //[MUEWA104] + "

    • v1.05 - Modified pad teardrops to fill better
    • " //[RES105] + "

    • v1.06 - Modified selectable layer
    • " //alfcadsoft.de + "

    " +; + +int User_Pads = 0; +int User_Vias = 1; +real User_Tear_Radius = 1.5; +real User_Ignore_Width = 25; +real User_Ignore_sdratio = 1.5; +real uiw_internal; + +int via_count; +int aring; +real radius, radius_sq, tangent_radius; //[MUEWA104] +int in1,in2; +int x_cross, y_cross; +real x1, x2, y1, y2; //[MUEWA104] +real t; //[MUEWA104] +int tstep; //[MUEWA104] +int changes = 0; +real xstep, ystep, xc, yc; +real astart,aend,sin_of_astart,cos_of_astart,wstep,w; +real tearseg_delta_w, tearseg_w, tearseg_len; +int tearseg_xend, tearseg_yend; +string vcount, fname, params; + +numeric string LayerName[]; +int LayerNum[]; +int LayerCount = 0; +int LayerSel = 0; +numeric string TargetLayer[]; // 2012-04-04 +int tCount = 0; +int LayActiv[]; +int IsLayer[]; +int TeardropLayer[]; + +// Output in dual-use .scr and spreadsheet .csv format +void output_hdr(void) { + printf("# SCR Command, Signal Name, Signal Class, Layer, Width, Via Drill, Via Layer Diameter, Via X, Via Y, Ratio segment_width/Via_drill_size\n"); + return; +} + +void output_via_wire(int layer, int width, int x1, int y1, int x2, int y2, UL_VIA V, UL_WIRE W, UL_SIGNAL S) { + if (!LayActiv[layer]) return; // 201-04-04 + int lnum = TeardropLayer[layer]; + printf("LAYER %d; WIRE '%s' %.8f (%.9f %.9f) (%.9f %.9f);\n", // #129, %s, %s, %d, %.1f, %.1f, %.1f, %.3f, %.3f, %.2f\n", // alf@cadsoft.de + lnum, S.name, u2mm(width), u2mm(x1), u2mm(y1), u2mm(x2), u2mm(y2) + //S.name, S.class.name, layer, u2mil(width), u2mil(V.drill), u2mil(V.diameter[layer]), u2mil(V.x), u2mil(V.y), real(width)/V.drill + ); + return; +} + +void output_pad_wire(int layer, int width, int x1, int y1, int x2, int y2, UL_PAD P, UL_WIRE W, UL_SIGNAL S) { + if (!LayActiv[layer]) return; // 201-04-04 + int lnum = TeardropLayer[layer]; + printf("LAYER %d; WIRE '%s' %.8f (%.9f %.9f) (%.9f %.9f);\n", // #139, %s, %s, %d, %.1f, %.1f, %.1f, %.3f, %.3f, %.2f\n", // alf@cadsoft.de + lnum, S.name, u2mm(width), u2mm(x1), u2mm(y1), u2mm(x2), u2mm(y2) + //P.name, P.name, layer, u2mil(width), u2mil(P.drill), u2mil(P.diameter[layer]), u2mil(P.x), u2mil(P.y), real(width)/P.drill + ); + return; +} + +void do_pads(UL_SIGNAL S) { + int shape; + + S.contactrefs(C) { + if (C.contact.pad) { + via_count++; + + sprintf(vcount, "Processing Pad #%d -- Signal %s", via_count, C.contact.pad.name); + status(vcount); + + // find wires starting within teardrop-apex radius of the via and ending outside it. + + //radius = C.contact.pad.drill * (User_Tear_Radius - 0.25); //[RES105] + radius = C.contact.pad.drill * (User_Tear_Radius - 0.5); + radius_sq = radius * radius; + + S.wires(W) { + // quick check first. See if either wire endpoint is within a square of size 2 x radius of the pad. + in1 = 0; + in2 = 0; + + if ((W.width < uiw_internal) && (real(W.width)/C.contact.pad.drill < User_Ignore_sdratio)) { + if (W.layer >= 1 && W.layer <= 16) { + shape = C.contact.pad.shape[W.layer]; + if (shape == PAD_SHAPE_ROUND || shape == PAD_SHAPE_OCTAGON) { + // Passed user specified wires to ignore + if (abs(W.x1-C.contact.pad.x) radius_sq) //[MUEWA104] + in1 = 0; + } + + if (in2) { + if ((real(W.x2-C.contact.pad.x)*(W.x2-C.contact.pad.x)+real(W.y2-C.contact.pad.y)*(W.y2-C.contact.pad.y)) > radius_sq) //[MUEWA104] + in2 = 0; + } + } + } + } + } + + if (in1 ^ in2) { + changes = 1; + // Calculate point where wire crosses radius. Move calculations relative to via's center. + x1 = W.x1-C.contact.pad.x; + x2 = W.x2-C.contact.pad.x; + y1 = W.y1-C.contact.pad.y; + y2 = W.y2-C.contact.pad.y; + // Make x1,y1 always the end closest to via center. + if (in2) { + // Swap start/end + t = x1; + x1 = x2; + x2 = t; + t = y1; + y1 = y2; + y2 = t; + } + // Perhaps the line and arc intersections equations could be solved directly without too much trouble, + // but didn't feel like dealing with it and the special cases. + if (!W.arc) { + // Easiest to represent the line parametrically and step up it. + tstep = max(abs(y2-y1),abs(x2-x1)); + xstep = (x2-x1)/real(tstep); + ystep = (y2-y1)/real(tstep); + tstep = tstep >>1; + + // We're double testing points here, but don't feel like fixing. + for (t = 0; tstep > 0; t = t+tstep) { + xc = x1+xstep*t; + yc = y1+ystep*t; + + if ((xc*xc + yc*yc) > radius_sq) { + // backup a little and increase resolution + t = t-tstep; + tstep = tstep >> 1; + } + } + } + else { + // wire segment is an arc + // Get correct arc starting end angle for x1,y1 + if ((x1+C.contact.pad.x) == W.arc.x1 && (y1+C.contact.pad.y) == W.arc.y1) { + astart = W.arc.angle1; + aend = W.arc.angle2; + } + else { + // Swap start/end + astart = W.arc.angle2; + aend = W.arc.angle1; + } + + // wstep is the change in angle to the next point on the arc to test. + astart = PI/180 * astart; + aend = PI/180 * aend; + wstep = (aend-astart)/2; // make wstep 1/2 the difference + sin_of_astart = W.arc.radius*sin(astart); + cos_of_astart = W.arc.radius*cos(astart); + + // dy = radius*(sin(astart+dw)-sin(astart)) + // dx = radius*(cos(astart+dw)-cos(astart)) + + // w is the current angle on the arc being tested + // We're double testing points here, but don't feel like fixing. + + for (w = astart+wstep; abs(wstep) > .00001; w = w+wstep) { + yc = y1+W.arc.radius*sin(w)-sin_of_astart; + xc = x1+W.arc.radius*cos(w)-cos_of_astart; + + if ((xc*xc + yc*yc) > radius_sq) { + // backup a little and increase resolution + w = w-wstep; + wstep = wstep/2; + } + } + } + + // Determine location of tangents of via back to wire. + // angular offset = sin (viaradius/(seg to via ctr distance)) + + int wmult = 1; + int width = W.width; + int aring = C.contact.pad.diameter[W.layer] - C.contact.pad.drill; + + // printf("# width=%f, drill=%f, diameter=%f, aring=%f\n", u2mil(width), u2mil(C.contact.pad.drill), u2mil(C.contact.pad.diameter[W.layer]), u2mil(aring)); + + // [RES102] - Adjusted tangent divide ratios and added logic to determine + // if wire width is less than 10 mil or the annular ring is less than the wire width, + // double the wire width for better fill. + + if ((u2mil(width) <= 10) || ((u2mil(aring) / 2.0) > u2mil(width))) + wmult = 2; + + width = width * wmult; + + //if (u2mil(C.contact.pad.diameter[W.layer]) >= 100) + // tangent_radius = (C.contact.pad.diameter[W.layer] - (W.width * wmult)) / 4; // [RES102] was 8 + //else + // tangent_radius = (C.contact.pad.diameter[W.layer] - (W.width * wmult)) / 2; // [RES102] was 4 + // [RES105] + tangent_radius = (C.contact.pad.diameter[W.layer] - (W.width * wmult)) / 2; + + if (tangent_radius > 0) { + // don't bother if wire is bigger than via + + tearseg_delta_w = asin(real(tangent_radius)/radius); + tearseg_len = sqrt(radius * radius - tangent_radius * tangent_radius); + + if (xc == 0) { + if (yc < 0) + tearseg_w = PI*.5; + else + tearseg_w = -PI*.5; + } + else { + tearseg_w = atan (real(yc)/(xc)); + } + + // Get the right quadrant + if (xc > 0) tearseg_w = tearseg_w + PI; + + tearseg_xend = C.contact.pad.x+xc + tearseg_len*cos(tearseg_w-tearseg_delta_w); + tearseg_yend = C.contact.pad.y+yc + tearseg_len*sin(tearseg_w-tearseg_delta_w); + + // Suggest a script command. + output_pad_wire(W.layer, width, int(C.contact.pad.x+xc), int(C.contact.pad.y+yc), tearseg_xend, tearseg_yend, C.contact.pad, W, S); + // Now add segment to the center of the via so ratsnest doesn't show up as dangling. + output_pad_wire(W.layer, width, int(C.contact.pad.x), int(C.contact.pad.y), tearseg_xend, tearseg_yend, C.contact.pad, W, S); + + // Now the other side of the tear + tearseg_xend = C.contact.pad.x+xc + tearseg_len*cos(tearseg_w+tearseg_delta_w); + tearseg_yend = C.contact.pad.y+yc + tearseg_len*sin(tearseg_w+tearseg_delta_w); + + // Suggest a script command. + output_pad_wire(W.layer, width, int(C.contact.pad.x+xc), int(C.contact.pad.y+yc), tearseg_xend, tearseg_yend, C.contact.pad, W, S); + // Now add segment to the center of the via so ratsnest doesn't show up as dangling. + output_pad_wire(W.layer, width, int(C.contact.pad.x), int(C.contact.pad.y), tearseg_xend, tearseg_yend, C.contact.pad, W, S); + } + } + } + } + } + return; +} + +void do_vias(UL_SIGNAL S) { + S.vias(V) { + via_count++; + + sprintf (vcount, "Processing Via #%d -- Signal %s", via_count, S.name); + status (vcount); + + // find wires starting within teardrop-apex radius of the via and ending outside it. + radius = V.drill * User_Tear_Radius; + radius_sq = radius * radius; + + S.wires(W) { + // quick check first. See if either wire endpoint is within a square of size 2 x radius of the via. + in1 = 0; + in2 = 0; + + if ((W.width < uiw_internal) && (real(W.width)/V.drill < User_Ignore_sdratio)) { + // Passed user specified wires to ignore + + if (abs(W.x1-V.x)= V.start && W.layer <= V.end) { + if (in1) { + if ((real(W.x1-V.x)*(W.x1-V.x) + real(W.y1-V.y)*(W.y1-V.y)) > radius_sq) //[MUEWA104] + in1 = 0; + } + + if (in2) { + if ((real(W.x2-V.x)*(W.x2-V.x) + real(W.y2-V.y)*(W.y2-V.y)) > radius_sq) //[MUEWA104] + in2 = 0; + } + } + else { + in1 = 0; + in2 = 0; + } + } + } + + if (in1 ^ in2) { + changes = 1; + + // Calculate point where wire crosses radius. Move calculations relative to via's center. + x1 = W.x1-V.x; + x2 = W.x2-V.x; + y1 = W.y1-V.y; + y2 = W.y2-V.y; + + // Make x1,y1 always the end closest to via center. + if (in2) { + // Swap start/end + t = x1; + x1 = x2; + x2 = t; + t = y1; + y1 = y2; + y2 = t; + } + + // Perhaps the line and arc intersections equations could be solved directly without too much trouble, + // but didn't feel like dealing with it and the special cases. + + if (!W.arc) { + // Easiest to represent the line parametrically and step up it. + + tstep = max(abs(y2-y1),abs(x2-x1)); + xstep = (x2-x1)/real(tstep); + ystep = (y2-y1)/real(tstep); + tstep = tstep >>1; + + // We're double testing points here, but don't feel like fixing. + for (t = 0; tstep > 0; t = t+tstep) { + xc = x1+xstep*t; + yc = y1+ystep*t; + + if ((xc*xc + yc*yc) > radius_sq) { + // backup a little and increase resolution + t = t-tstep; + tstep = tstep >> 1; + } + } + } + else { + // wire segment is an arc + // Get correct arc starting end angle for x1,y1 + + if ((x1+V.x) == W.arc.x1 && (y1+V.y) == W.arc.y1) { + astart = W.arc.angle1; + aend = W.arc.angle2; + } + else { + // Swap start/end + astart = W.arc.angle2; + aend = W.arc.angle1; + } + + // wstep is the change in angle to the next point on the arc to test. + astart = PI/180 * astart; + aend = PI/180 * aend; + wstep = (aend-astart)/2; // make wstep 1/2 the difference + sin_of_astart = W.arc.radius*sin(astart); + cos_of_astart = W.arc.radius*cos(astart); + + // dy = radius*(sin(astart+dw)-sin(astart)) + // dx = radius*(cos(astart+dw)-cos(astart)) + + // w is the current angle on the arc being tested + // We're double testing points here, but don't feel like fixing. + + for (w = astart+wstep; abs(wstep) > .00001; w = w+wstep) { + yc = y1+W.arc.radius*sin(w)-sin_of_astart; + xc = x1+W.arc.radius*cos(w)-cos_of_astart; + + if ((xc*xc + yc*yc) > radius_sq) { + // backup a little and increase resolution + w = w-wstep; + wstep = wstep/2; + } + } + } + + // Determine location of tangents of via back to wire. + // angular offset = sin (viaradius/(seg to via ctr distance)) + + tangent_radius = (V.diameter[W.layer] - W.width)/2; + + if (tangent_radius > 0) { + // don't bother if wire is bigger than via + tearseg_delta_w = asin(real(tangent_radius)/radius); + tearseg_len = sqrt (radius * radius - tangent_radius * tangent_radius); + + if (xc == 0) { + if (yc < 0) tearseg_w = PI*.5; + else tearseg_w = -PI*.5; + } + else { + tearseg_w = atan (real(yc)/(xc)); + } + + // Get the right quadrant + if (xc > 0) + tearseg_w = tearseg_w + PI; + + tearseg_xend = V.x+xc + tearseg_len*cos(tearseg_w-tearseg_delta_w); + tearseg_yend = V.y+yc + tearseg_len*sin(tearseg_w-tearseg_delta_w); + + // Suggest a script command. + output_via_wire (W.layer, W.width, int(V.x+xc), int(V.y+yc), tearseg_xend, tearseg_yend, V, W, S); + // Now add segment to the center of the via so ratsnest doesn't show up as dangling. + output_via_wire (W.layer, W.width, int(V.x), int(V.y), tearseg_xend, tearseg_yend, V, W, S); + + // Now the other side of the tear + tearseg_xend = V.x+xc + tearseg_len*cos(tearseg_w+tearseg_delta_w); + tearseg_yend = V.y+yc + tearseg_len*sin(tearseg_w+tearseg_delta_w); + + // Suggest a script command. + output_via_wire (W.layer, W.width, int(V.x+xc), int(V.y+yc), tearseg_xend, tearseg_yend, V, W, S); + // Now add segment to the center of the via so ratsnest doesn't show up as dangling. + output_via_wire (W.layer, W.width, int(V.x), int(V.y), tearseg_xend, tearseg_yend, V, W, S); + } + } + } + } + return; +} + + +void setlayerstatus(void) { // 2012-04-04 set layer status + string s[]; + for (int n = 0; n < LayerCount; n++) { + int cnt = strsplit(s, LayerName[n], '\t'); + int num = strtol(s[0]); + int target = strtol(s[1]); + IsLayer[num] = num; + TeardropLayer[num] = target; + if (s[2] == "yes" ) LayActiv[num] = 1; + else LayActiv[num] = 0; + } + return; +} + + +void generate_tears(void) { + setlayerstatus(); + board(B) { + uiw_internal = User_Ignore_Width/u2mil(1); // Convert user mil units to internal units. + via_count = 0; + fname = filesetext(B.name, "_AddTearDrops.scr"); + + if (!User_Vias && !User_Pads) { + dlgMessageBox("You must check vias and/or pads option."); + return; + } + + output(fname, "wtD") { + printf("# Script generated to add teardrops to board vias.\n"); + printf("# Script generated with '%s', *%s* at %s.\n", filename(argv[0]), EAGLE_SIGNATURE, t2string(time(), "Uyyyy-MM-dd hh:mm:ss")); + printf("# Script values in mm and spreadsheet values in mils:\n"); + printf("# This script generated with the following user parameters:\n"); + printf("# Teardrop Apex Radius Factor: %.2f. Ignoring segments >= %.1f mils. Ignoring segments with width/via_hole ratio >= %.1f. ", + User_Tear_Radius, User_Ignore_Width, User_Ignore_sdratio); + printf("\n"); + output_hdr(); + printf("SET UNDO_LOG OFF;\n"); + printf("SET WIRE_BEND 2;\n"); // straight lines for drawing our teardrop wires. + printf("GRID MM;\n"); + + B.signals(S) { + if (User_Vias) + do_vias(S); + + if (User_Pads) + do_pads(S); + } + + printf("GRID LAST;\n"); + printf("SET UNDO_LOG ON;\n"); + + if (changes) exit ("script '" + fname + "';\n"); + else dlgMessageBox("No teardrops generated with current parameters"); + } + } + return; +} + + +string settarget(string sellayer) { // 2012-04-04 + string no_change = sellayer; + string l[]; + strsplit(l, sellayer, '\t'); + string s[]; + strsplit(s, l[0], '-'); + int activ; + if (l[2] == "yes") activ = 1; + + int sel = strtol(l[1]) -1; + dlgDialog("Target Layer") { + dlgLabel("New layer for " + l[0]); + dlgGroup("Layer activ") { + dlgRadioButton("&no", activ); + dlgRadioButton("&yes", activ); + } + dlgComboBox(TargetLayer, sel) { + sellayer = s[0] + "\t" + TargetLayer[sel]; + if (activ) sellayer += "\t" + "yes"; + else sellayer += "\t" + "no"; + } + dlgHBoxLayout { + dlgPushButton("+OK") { + sellayer = s[0] + "\t" + TargetLayer[sel]; + if (activ) sellayer += "\t" + "yes"; + else sellayer += "\t" + "no"; + dlgAccept(); + } + dlgPushButton("-Cancel") { + dlgReject(); + sellayer = no_change; + } + } + }; + return sellayer; +} + + +//***************************** + +string mainscrtext = + "\nStatus bar will show progress while generating teardrops.\n\n" + "Apex Radius Factor sets the distance from the apex of a teardrop to the associated via's center. " + "The Radius Factor entered is multiplied by the via's drill-hole diameter to arrive at a physical distance." + "For example, with an entered radius factor of 1.5 operating on a via with a drill size of 10mils, the apex begins " + "15 mils from that particular via's center."; + +if (!board) { + dlgMessageBox("You should run this ULP from an open board design."); + exit(0); +} + +dlgDialog("Teardrops for Vias") { + if (!board) { + dlgMessageBox("You should run this ULP from an open board design."); + exit(-1); + } + board(B) { + B.layers(L) { + if (L.number <= 16) { // 2012-04-04 + string lname; + if (L.used) { + sprintf(lname, "%d-%s\t%d-%s\tyes", L.number, L.name, L.number, L.name); + LayerName[LayerCount] = lname; + LayerNum[LayerCount] = L.number; + ++LayerCount; + } + } + sprintf(TargetLayer[tCount], "%d-%s", L.number, L.name); + tCount++; + } + } + + dlgHBoxLayout { + dlgTabWidget { + dlgTabPage("Processing") { + dlgHBoxLayout { + dlgGroup("Parameters") { + dlgSpacing(8); + dlgGridLayout { + dlgCell( 1, 0) dlgLabel("Teardrop Apex Radius Factor "); + dlgCell( 1, 1) dlgRealEdit(User_Tear_Radius, 0.5, 2.5); + + dlgCell( 2, 0) dlgLabel("Ignore all segments >= "); + dlgCell( 2, 1) dlgRealEdit(User_Ignore_Width, 4.0, 400.0); + dlgCell( 2, 2) dlgLabel(" mils"); + + dlgCell( 4, 0) dlgLabel("Ignore all segments/drill ratios >= "); + dlgCell( 4, 1) dlgRealEdit(User_Ignore_sdratio, 0.1, 99.0); + } + dlgVBoxLayout { + dlgGroup("Options") { + dlgCheckBox("&Teardrop Vias", User_Vias); + dlgCheckBox("&Teardrop Pads", User_Pads); + dlgSpacing(8); + dlgLabel("Click on layer to select :"); + dlgListView("Layer Source\tTeardrop Target\tactiv", LayerName, LayerSel) { + LayerName[LayerSel] = settarget(LayerName[LayerSel]); + } + } + dlgStretch(1); + dlgSpacing(10); + dlgHBoxLayout { + dlgPushButton("Teardrop Board") generate_tears(); + dlgPushButton("-Cancel") dlgReject(); + } + } + } + dlgTextView(mainscrtext); + } + } // tab page + + dlgTabPage("Overview") { + dlgTextView(HelpText); + } + + dlgTabPage("History") { + dlgTextView(Release + " " + ReleaseDate + " " + HistoryText2); + } + } + } +}; diff --git a/trunk/ulp/trace-layer.ulp b/trunk/ulp/trace-layer.ulp new file mode 100644 index 00000000..d92b2c05 --- /dev/null +++ b/trunk/ulp/trace-layer.ulp @@ -0,0 +1,123 @@ +#usage "Trace layer, to display layers step by step.

    " + "RUN trace-layer +
    " + "RUN trace-layer -
    " + "Layers 17 Pad, 18 Via, 19 Unrouted, 23 tOrigin and 24 bOrigin are not separated displayed" + "Author alf@cadsoft.de" + +// Version 1.0 - 2007.06.06 alf@cadsoft.de + +int supplyLayer[]; +int usedLayer[]; +int mLayer = 0; +int lastUsed; +string cmd; +string message = ""; + +string layerFile = filesetext(argv[0], ".trl"); +string f[]; +int isFile = fileglob(f, layerFile); + +void checkLayer(void) { + if (argv[1] == "+") { + if (mLayer == 23 || mLayer == 24) mLayer = 25; + if (mLayer == 17 || mLayer == 18 || mLayer == 19) mLayer = 20; + lastUsed = mLayer; + } + if (argv[1] == "-") { + if (mLayer == 23 || mLayer == 24) mLayer = 22; + if (mLayer == 17 || mLayer == 18 || mLayer == 19) mLayer = 16; + lastUsed = mLayer; + } + return; +} + +if (isFile) { + string rLayer; + int n = fileread(rLayer, layerFile); + mLayer = strtol(rLayer); +} + + +if (argv[1] == "-") { + mLayer --; + if (board) { + if (mLayer < 1) { + if (!mLayer) message = "The first layer."; + mLayer = 1; + } + } + else if (schematic) { + if (mLayer < 91) mLayer = 91; + } +} + +if (argv[1] == "+") { + mLayer ++; + if (mLayer >255) { + mLayer = 255; + if (!mLayer) message = "The last layer."; + } +} + + +checkLayer(); +if (board) { + board(B) { + B.layers(L) { + if (L.used) { + usedLayer[L.number] = 1; + } + string ln = L.name; + if (ln[0] == '$') { + usedLayer[L.number] = 1; + supplyLayer[L.number] = 1; + } + } + if (argv[1] == "+") { + if (!usedLayer[mLayer]) { + do { + mLayer++; + if (usedLayer[mLayer]) break; + } while (mLayer < 256); + if (mLayer >= 255) message = "The last Layer."; + } + } + if (argv[1] == "-") { + if (!usedLayer[mLayer]) { + do { + mLayer--; + if (usedLayer[mLayer]) break; + } while (mLayer > 1); + } + } + + checkLayer(); + if (usedLayer[mLayer]) { + if (mLayer < 17) { + if (supplyLayer[mLayer]) { + sprintf(cmd, "DISPLAY NONE %d;\n", mLayer); + message ="ATTENTION this is a Supply layer, do not use this Layer in CAM-Job with Pad- and/or Via-Layer."; + } + else { + sprintf(cmd, "DISPLAY NONE %d 17 18;\n", mLayer); + } + } + else { + sprintf(cmd, "DISPLAY NONE %d;\n", mLayer); + } + lastUsed = mLayer; + } + } +} +checkLayer(); +if (lastUsed) { + output(layerFile, "wtD") { + printf("%d", lastUsed); + } +} +if (message) { + string s; + sprintf(s, "RUN ulpmessage '%s';\n", message); + cmd += s; +} +exit (cmd); \ No newline at end of file diff --git a/trunk/ulp/ulpmessage.ulp b/trunk/ulp/ulpmessage.ulp new file mode 100644 index 00000000..bdb4d617 --- /dev/null +++ b/trunk/ulp/ulpmessage.ulp @@ -0,0 +1,10 @@ +#usage "Display a popup message\n" + "

    " + "Usage: RUN ulpmessage text" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +dlgMessageBox("" + argv[1] + "
    " + argv[2] + "
    ", "OK"); exit(0); + diff --git a/trunk/ulp/unidat.ulp b/trunk/ulp/unidat.ulp new file mode 100644 index 00000000..24593258 --- /dev/null +++ b/trunk/ulp/unidat.ulp @@ -0,0 +1,1035 @@ +#usage "Export UNIDAT format\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +#require 6.0500 +string ULPversion = filename(argv[0]) + " V10.0"; + +/////////////////////////////////////////////////////////////////////////////////////////// +// Revision 10.0: changed to V6 used multi pads on pin (PIN.connects() ) -- alf@cadsoft.de 2014-01-14 +// +// Revision 9.0: corrected u2u(round) function, V6 has 32x higher relolution -- alf@cadsoft.de 2013-03-14 +// +// Revision 8.0: Display status of ULP in any function -- alf@cadsoft.de 31.03.2005 +// Function rot() : correct rotation for any angle +// Pad/Smd-Rotation consider in Eagle 4.1 +// resolution in 1/1000 +// +// Revision 7.0: correct rotation in rot() function 16.02.2005 alf@cadsoft.de +// +// Revision 6.0: exports Fiducial if placed from MAKRS.lbr -- alf@cadsoft.de 30.03.2004 +// Source: unidat.format.91010.doc from +// +// Revision 5.0: exports Polygon of signals -- alf@cadsoft.de +// +// Revision 4.0: for EAGLE Version 4.0 with Dialog -- alf@cadsoft.de +// +// Revision 3.0: include Crossref.ULP with Pin_Name from Sheet -- alf@cadsoft.de +// +// Revision 2.0: shape names again derived from package names (seems to be the only +// solution which makes sense) +// +// Revision 1.3: output of round pads corrected +// Revision 1.2: output limited to elements with package in routine "component" +// Revision 1.1: shape names derived from element names instead of package names (unique!) +// Rudi Hofer, CadSoft, rudi.hofer@cadsoft.de, 9/1999 +/////////////////////////////////////////////////////////////////////////////////////////// +// Since version 2.0 all packages with the same name must be identical (avoid REPLACE!) +/////////////////////////////////////////////////////////////////////////////////////////// +// This ULP generates output for UNICAM software which is able to convert the +// data for automatic mounting and test equipment. The resolution is fixed to 1/100 mm. +// +// To generate the output, load the board and run this ULP. +// +// You can provide properties like "partnumber", "tolerance" etc. in the +// component library: +// +// - define a user layer named UNIDAT +// - add texts in the form "propertyname=value" to this layer, e.g. +// partnumber=12345 +// pos_tolerance=0.05 +// - see array property[] below for predefined property names +// - by changing the array contents you can change the property names +// (do not change the number of array entries!) +// +// OUTPUT OF PROPERTIES IS ONLY POSSIBLE IF FORWARD & BACK ANNOTATION IS USED AND +// IF THE SCHEMATIC AND THE BOARD ARE LOADED! +// THE PROGRAM HAS TO BE EXECUTED FROM THE BOARD WINDOW! +// +// +// Pads of the shape type OCTAGON are changed to round, if the following variable +// is set to 1 (otherwise set to 0) + +int disp_oct_as_round = 1; + +// +/////////////////////////////////////////////////////////////////////////////////////////// + +/* Dieses ULP erzeugt eine Cross-Referenzliste zwischen Pad und Pin *** + * Dabei wird eine Liste generiert, in der die Koordinaten + * der Pads/Netze im Board, in Bezug zu den Pins/Netze im + * Schaltplan(Sheet Nr.) stehen. + * A. Zaffran CadSoft 07.09.1999 + */ + +/* + +%COMPONENT +C1|N$5|sheet2|15.240,8.890|mm| +C1|1|N$5|sheet2|15.240,8.890|mm| +| | | | | | +| | | | X Y +| | | Seite +| | Netzname +| Pad-Name +Bauteil + +%PINS +IC1|IC1A|FILTER|1|I0|sheet1|25.40,22.86|mm| +| | | | | | | | +| | | | | | X Y +| | | | | Seite +| | | | Symbolischer Pin-Name +| | | Numerischer Pin-Name +| | Netzname +| Gate-Name +Bauteil + +*/ + +string _MARKER_ = "marks"; // the library name for fiducials + +int px[], py[], ps[], PinPoints = 0; // Pin: x, y, sheet, counter +string pa[], pg[], pc[], pn[], pnn[]; + // Part-name, gate-name, contact-name, pinname, pin-netname + +int padx[], pady[], pads[], PadPoints = 0; // Pad: x, y, sheet, counter +string padd[], padn[], padnn[]; // devicename, padname, pad-netname + +int sheetload = 0; +string proz = "%"; +string Pad_Pin = ""; + +enum { bottom = 16 }; + +string reffile; +string unifile; + + +//----------------------------------------------------- + +string user_layer_name = "unidat", // layer name for property definitions (lower case!) + jobname, +// jobrevision = "1.0", + layer_name[], + property_assign_char = "=", + property[] = {"partnumber" // propterty[0] is partnumber and so on + ,"parttype" + ,"description" + ,"pos_tolerance" + ,"neg_tolerance" + ,"user1" + ,"user2" + ,"user3" + }, + property_value[], + /* + PAD_SHAPE_SQUARE square + PAD_SHAPE_ROUND round + PAD_SHAPE_OCTAGON octagon + PAD_SHAPE_LONG long + PAD_SHAPE_OFFSET offset + PAD_SHAPE_ANNULUS annulus (only in Supply-Layer) + PAD_SHAPE_THERMAL thermal (only in Supply-Layer) + */ + padshape[] = {"S","R","O","L","T"}, // shapes - square, round, oct, long, offset + padname, + shapename[]; + +real ang2, cx, cy, rx, ry, x, y, x1, x2, y1, y2, r, a1, a2;; + +int i, + padcount, + pad_is_numeric, + max_property = 7, + new, + sx = 0; + +// -------------------------------------------------------------------- + +void test(void) { + string ref; + int nr = fileread(ref, reffile); + string uni; + int nu = fileread(uni, unifile); + dlgDialog("UNIDAT File export") { + dlgLabel("UNIDAT File: " + unifile); + dlgTextView(uni); + dlgLabel("Cross reference file: " + reffile); + dlgTextView(ref); + dlgHBoxLayout { dlgSpacing(400); } + dlgLabel("Fiducial library = '" + _MARKER_ + "'"); + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") dlgAccept(); + dlgStretch(1); + } + }; + return; +} + +void Header(string name) { + printf(";This file is generated by %s from:\n", ULPversion); + printf(";%s';\n", name); +} + +int search_Pad_Pin(string name, string pad) { + for (int pin = 0; pin < PinPoints; pin++) { + if (pa[pin] == name && pc[pin] == pad){ + break; + } + } + if (pin == PinPoints) pin = -2; + return pin; +} + +// -------------------------------------------------------------------- + +real u2u(int x) { // resolution 1/100 mm + return round(u2mm(x) * 100) / 100; // 2013-03-14 do not round with integer! +} + +real u2ang(real x) { + if (x > 360) + x = x -360; + x = round(x * 10) / 10; + return x; +} + +//----------------------------------------------------- +real Xneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * cos(rad)); + } +} + +//----------------------------------------------------- +real Yneu(real Xalt, real Yalt, real Xorigin, real Yorigin, real UserWinkel) { + real RADIUS = sqrt(((Xalt - Xorigin) * (Xalt - Xorigin)) + ((Yalt - Yorigin) * (Yalt - Yorigin))); + real WinkelNeu; /* alter Cosinus Winkel = (Xalt - Xorigin) / RADIUS; */ + + if ((Xalt > Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 1 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt >= Yorigin)) { /* Quadrant 2 */ + WinkelNeu = acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt < Xorigin) && (Yalt < Yorigin)) { /* Quadrant 3 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt > Xorigin) && (Yalt < Yorigin)) { /* Quadrant 4 */ + WinkelNeu = 360 - acos((Xalt - Xorigin) / RADIUS) * 57.29578 + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt == Yorigin)) { /* Ursprung */ + WinkelNeu = (Xalt - Xorigin) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt > Yorigin)) { /* 90 */ + WinkelNeu = (Xalt - Xorigin + 90) + UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } + if ((Xalt == Xorigin) && (Yalt < Yorigin)) { /* 270 */ + WinkelNeu = (Xalt - Xorigin + 270)+ UserWinkel; + real rad = PI / 180 * WinkelNeu; + return (RADIUS * sin(rad)); + } +} + + + + +//----------------------------------------------------- +void rot(real alfa, real xt, real yt) { // change if finer rotation possible + // 30.03.2005 alf@cadsoft.de + if (alfa == 0) { + x = xt; y = yt; + } + else if (alfa == 90) { + x = yt; y = -xt; + } + else if (alfa == 180) { + x = -xt; y = -yt; + } + else if (alfa == 270) { + x = -yt; y = xt; + } + else { + x = Xneu(xt, yt, 0.0, 0.0, 360 - alfa); + y = Yneu(xt, yt, 0.0, 0.0, 360 - alfa); + } + x = round(x * 1000)/1000; + y = round(y * 1000)/1000; // resolution 1/1000 mm + return; +} + +//----------------------------------------------------- +string padtype(UL_CONTACT C) { // name contains shape SROXY or SM for SMD + string s; // diam_drill (in 1/100mm) or smdx_y in (1/100 mm) + real pdi, pdr, sx, sy; // e.g. SR_140_80 or SM_100_120 + if (C.pad) { + pdi = round(u2u(C.pad.diameter[bottom]) * 100); + pdr = round(u2u(C.pad.drill) * 100); // not used + sprintf(s, "P%s_%03.0f", padshape[C.pad.shape[bottom]], pdi); // pdr could be used, too + } + if (C.smd) { + sx = round(u2u(C.smd.dx) * 100); + sy = round(u2u(C.smd.dy) * 100); + sprintf(s, "SM_%03.0f_%03.0f", sx, sy); + } + return s; +} + +//----------------------------------------------------- +real padrotation(UL_CONTACT C) { + if (C.pad) return C.pad.angle; + if (C.smd) return C.smd.angle; +} + +//----------------------------------------------------- +int padelongation(UL_CONTACT C) { + int e = 0; + if (C.pad) e = C.pad.elongation; + return e; +} + +//----------------------------------------------------- +string viatype(UL_VIA V) { + string s; // diam_drill (in 1/100mm) + real pdi, pdr, sx, sy; // e.g. SR_140_80 or SM_100_120 + pdi = round(u2u(V.diameter[bottom]) * 100); + pdr = round(u2u(V.drill) * 100); // not used + sprintf(s, "P%s_%03.0f", padshape[V.shape[bottom]], pdi); // pdr could be used, too + return s; +} +//----------------------------------------------------- +void print_pad_shape(string s, real r, int e) { + real x, y, w, wx, wy, a, b, c, d, elong = e/100; + + string s1; + sprintf(s1, "%s.%s", strsub(s, 3, 1), strsub(s, 4, 2)); + x = strtod(s1); + if (strsub(s, 1, 1) == padshape[0]) { // look for padshape S|R|O|L|T + w = x/2; + printf("L (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g)\n", + w, w, w,-w, -w,-w, -w, w, w, w); + } + if (strsub(s, 1, 1) == padshape[1]) { + printf("C 0,0,%s.%s\n", strsub(s, 3, 1), strsub(s, 4, 2)); + } + if (strsub(s, 1, 1) == padshape[2]) { + if (!disp_oct_as_round) { + x = x/2; + w = x/2; + printf("L (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g)\n", + w, x, x, w, x,-w, w,-x, -w,-x, -x,-w, -x, w, -w, x, w, x); + } + else { + printf("C 0,0,%s.%s\n", strsub(s, 3, 1), strsub(s, 4, 2)); + } + } + if (strsub(s, 1, 1) == padshape[3]) { // long + a = 3*x/8; b = x/2*elong; c = x/8; d = x/4; // dimension ratio x:y = elong + printf("L (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g)\n", + a,d, b,c, b,-c, a,-d, -a,-d, -b,-c, -b,c, -a,d, a,d); + } + if (strsub(s, 1, 1) == padshape[4]) { // offset + a = 3*x/8; b = x/2*elong; c = x/8; d = x/4; // dimension ratio x:y = elong + printf("L (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g)\n", + a,d, b,c, b,-c, a,-d, -a,-d, -b,-c, -b,c, -a,d, a,d); + } + if (strsub(s, 1, 1) == "M") { // look for padshape M = SMD + sprintf(s1, "%s.%s", strsub(s, 7, 1), strsub(s, 8, 2)); + y = strtod(s1); + wx = x/2; wy = y/2; + printf("L (%g,%g) (%g,%g) (%g,%g) (%g,%g) (%g,%g)\n", + wx, wy, wx,-wy, -wx,-wy, -wx, wy, wx, wy); + } + return; +} + +//----------------------------------------------------- +void center(UL_ELEMENT E) { // returns cx, cy + real xmin, xmax, ymin, ymax; + xmin = u2u(E.x); xmax = xmin; + ymin = u2u(E.y); ymax = ymin; + E.package.wires(W){ + if (W.layer == LAYER_TPLACE || W.layer == LAYER_BPLACE) { + xmin = min(u2u(W.x1),xmin); + xmin = min(u2u(W.x2),xmin); + ymin = min(u2u(W.y1),ymin); + ymin = min(u2u(W.y2),ymin); + xmax = max(u2u(W.x1),xmax); + xmax = max(u2u(W.x2),xmax); + ymax = max(u2u(W.y1),ymax); + ymax = max(u2u(W.y2),ymax); + } + } + cx = (xmin+xmax)/2; cy = (ymin+ymax)/2; + return; +} + +//----------------------------------------------------- +string smd_info(UL_ELEMENT E) { + E.package.contacts(C) { + if (C.pad) return "THT"; + else return "SMD"; + } + return "SMD"; // in case it has no electrical connection (e.g. fiducial) +} + +//--------------------------------------------------- +void get_user_parameters(UL_ELEMENT E) { // assign property_values[] + string s, pname, pvalue; + int pos, len; + if (project.schematic) { + project.schematic(S) { + S.parts(P) { + if (P.name == E.name) { + P.instances(I) { + for (i = 0; i <= max_property; i++) { // clear properties + property_value[i] = ""; + } + I.gate.symbol.texts(T) { + if (strlwr(layer_name[T.layer]) == user_layer_name) { + s = T.value; + len = strlen(s); + pos = strstr(s, property_assign_char); + if (pos > 0) { + pname = strsub(s, 0, pos); + pvalue = strsub(s, pos+1, len - pos); + i = 0; + while (i <= max_property) { + if (property[i] == strlwr(pname)) { + property_value[i] = pvalue; + } + i++; + } + } + } + } + } + } + } + } + } + else { // no schematic -> no properties + for (i = 0; i <= max_property; i++) { // clear properties + property_value[i] = ""; + } + } + return; +} + +//--------------------------------------------------- +string signame(string elname, string padname) { + string s = ""; + board(B) { + B.signals(S) { + S.contactrefs(C) { + if (C.element.name == elname) { + if (C.contact.name == padname) { + s = S.name; + } + } + } + } + } + return s; +} + +////////////////////////////////////////////////////// +void create_info() { + status("Info"); + int t = time(); + printf ("%%%%%%INFO\n"); + printf ("DATE=%02d.%02d.%02d %02d:%02d:%02d\n", + t2day(t),t2month(t)+1,t2year(t),t2hour(t),t2minute(t),t2second(t)); + printf ("DELIMITER=|\n"); + printf ("UNITS=MM\n"); + printf ("UNIDAT_VERSION=1.2\n"); // Unidat Software Version + printf ("JOB_NAME=%s\n", jobname); +//printf ("JOB_REVISION=%s\n", jobrevision); // get from somewhere + printf ("NR_OF_PCBOARDS=1\n"); + printf ("TOP_LAYER=1\n"); + printf ("BOTTOM_LAYER=16\n"); + printf ("CADSOFTWARE=EAGLE %d.%d\n", EAGLE_VERSION, EAGLE_RELEASE); + // schematic information could be added here + // e.g. create script file which creates a postscript schematic file + return; +} + +////////////////////////////////////////////////////// +void outline(UL_BOARD B) { + printf ("\n%%%%OUTLINE\n"); + printf ("%%GRAFITEM\n"); + B.wires(W) { + if(W.curve) { + if (W.layer == LAYER_DIMENSION) { + printf("A %g,%g,%g,%.1f,%.1f\n", + u2u(W.arc.xc),u2u(W.arc.yc),u2u(W.arc.radius),u2ang(W.arc.angle1),u2ang(W.arc.angle2 - W.arc.angle1)); + } + } + else { + if (W.layer == LAYER_DIMENSION) { + printf("L (%g,%g) (%g,%g)\n", u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + } + } + B.circles(C) { + if (C.layer == LAYER_DIMENSION) { + printf("C %g,%g,%g\n", u2u(C.x), u2u(C.y), u2u(C.radius)); + } + } + B.elements(E) { + E.package.wires(W) { + if(W.curve) { + if (W.layer == LAYER_DIMENSION) { + printf("A %g,%g,%g,%.1f,%.1f\n", + u2u(W.arc.xc),u2u(W.arc.yc),u2u(W.arc.radius),u2ang(W.arc.angle1),u2ang(W.arc.angle2 - W.arc.angle1)); + } + } + else { + if (W.layer == LAYER_DIMENSION) { + printf("L (%g,%g) (%g,%g)\n", u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + } + } + } + printf ("%%ENDGRAFITEM\n"); + return; +} + +////////////////////////////////////////////////////// +void fiducials(UL_BOARD B) { + printf ("\n%%%%FIDUCIALS\n"); + B.elements(E) { + if (E.package.library == _MARKER_) { + printf("%s|||",E.name); // NAME + printf("%g|%g|",u2u(E.x), u2u(E.y)); // X,Y + printf("%.1f|",u2ang(E.angle)); // ROTATION + if (E.mirror) printf("bottom|"); // ASSEMBLY SIDE + else printf("top|"); + printf("%s|",E.package.name); // SHAPE (e.g. SH_IC1) // special version + printf("\n"); + } + } + return; +} + +////////////////////////////////////////////////////// +void component(UL_BOARD B) { + printf ("\n%%%%COMPONENT\n"); + B.elements(E) { // add exclusion for el. w/o package!!! + if (E.package.library != _MARKER_) { + if (E.package) { + status("Component " + E.name); + get_user_parameters(E); // get user defined prop. from spec. layer + printf("%s|",E.name); // NAME + printf("%s|",property_value[0]); // PARTNUMBER + printf("|"); // PARTCODE not used + printf("%s|",property_value[1]); // PARTTYPE + printf("%s|",property_value[2]); // PARTDESCRIPTION + printf("%s|",E.package.name); // SHAPE (e.g. SH_IC1) // special version + printf("%.1f|",u2ang(E.angle)); // ROTATION + if (E.mirror) printf("bottom|"); // ASSEMBLY SIDE + else printf("top|"); + printf("%g|%g|",u2u(E.x), u2u(E.y)); // X,Y + center(E); + printf("%g|%g|",cx, cy); // X,Y of center point + printf("%s|", smd_info(E)); // SMD or Through-hole + printf("|0|"); // VALUE = 0 + printf("%s|",property_value[3]); // POS TOLERANCE + printf("%s|",property_value[4]); // NEG TOLERANCE + printf("%s|",property_value[5]); // USER1 + printf("%s|",property_value[6]); // USER2 + printf("%s",property_value[7]); // USER3 + printf("\n"); + } + } + } + return; +} + +////////////////////////////////////////////////////// +void other_drillings(UL_BOARD B) { + printf ("\n%%%%OTHER_DRILLINGS\n"); + return; +} + +////////////////////////////////////////////////////// +void component_pin(UL_BOARD B) { + printf ("\n%%%%COMPONENT_PIN\n"); + B.elements(E) { + if (E.package.library != _MARKER_) { + status("Component pin " + E.package.name); + pad_is_numeric = 1; + E.package.contacts(C) { // test if name numeric + padname = C.name; + for (i = 0; padname[i]; ++i) { + if (!isdigit(padname[i])) { + pad_is_numeric = 0; + } + } + } + padcount = 1; + rx = u2u(E.x); ry = u2u(E.y); // origin of package + E.package.contacts(C) { + status("Comp-Pin " + E.package.name); // 29.03.2005 alf@cadsoft.de + printf("%s|",E.name); // COMP. NAME + if (pad_is_numeric) { + printf("%s|", C.name); // PADNR + } + else { + printf("%d|", padcount); + padcount++; + } + int pin = search_Pad_Pin(E.name, C.name); + if (sheetload) { + if (pin < 0) { + printf("|"); // Gate not placed + } + else { + printf("%s|", pn[pin]); // PIN NAME + } + } + else { + printf("no-sheet|"); + } + + printf("%s|", signame(E.name, C.name)); // NET NAME + x1 = u2u(C.x)-rx; y1 = u2u(C.y)-ry; + rot(E.angle, x1, y1); // get x,y + printf("%g|%g|", x, y); // REL. POSITION OF PADS + if (C.pad) { + printf("%s|", padtype(C)); // PADTYPE TOP + printf("%.1f|", u2ang(E.angle)); // PAD ORIENTATION TOP + printf("%s|", padtype(C)); // PADTYPE BOTTOM + printf("%.1f", u2ang(E.angle)); // PAD ORIENTATION BOTTOM + } + if (C.smd) { + if (C.smd.layer == LAYER_TOP) { + printf("%s|", padtype(C)); // PADTYPE TOP + printf("%.1f|", u2ang(E.angle)); // PAD ORIENTATION TOP + printf("|"); // BOTTOM empty + } + else { + printf("||"); // TOP empty + printf("%s|", padtype(C)); // PADTYPE BOTTOM + printf("%.1f", u2ang(E.angle)); // PAD ORIENTATION BOTTOM + } + } + printf("\n"); + } + } + } + return; +} + +////////////////////////////////////////////////////// +void pad(UL_BOARD B) { + string t[]; + int i, j = 0, new; + printf ("\n%%%%PAD\n"); + status("Pads"); + B.elements(E) { + if (E.package.library != _MARKER_) { + E.package.contacts(C) { + new = 1; // padtype not generated yet + for (i = 0; t[i]; i++) { + if (t[i] == padtype(C)) new = 0; // padtype exists + } + if (new) { + t[j] = padtype(C); + j++; + printf("PAD=%s\n", padtype(C)); + printf("%%GRAFITEM\n"); + printf("FC 9,0,0,0\n"); + print_pad_shape(padtype(C), padrotation(C), padelongation(C)); + printf("%%ENDGRAFITEM\n"); + } + } + } + } + B.signals(S) { + status("Vias"); + S.vias(V) { + new = 1; + for (i = 0; t[i]; i++) { + if (t[i] == viatype(V)) new = 0; // padtype exists + } + if (new) { + t[j] = viatype(V); + j++; + printf("PAD=%s\n", viatype(V)); + printf("%%GRAFITEM\n"); + printf("FC 9,0,0,0\n"); + print_pad_shape(viatype(V), 0, 0); + printf("%%ENDGRAFITEM\n"); + } + } + } + return; +} + +////////////////////////////////////////////////////// +void shape(UL_BOARD B) { // what if mirrored? + sx = 0; + printf ("\n%%%%SHAPE\n"); + B.elements(E) { + if (E.package.library != _MARKER_) { + new = 1; // padstacktype not generated yet + for (i = 0; shapename[i]; i++) { + if (shapename[i] == E.package.name) new = 0; // shapename exists + } + if (new) { + status("Shape " + E.package.name); // 29.03.2005 + shapename[sx] = E.package.name; + sx++; + printf ("SHAPE=%s\n", E.package.name); + printf ("%%SHAPEOUTLINE\n"); + printf ("%%GRAFITEM\n"); + rx = u2u(E.x); ry = u2u(E.y); // origin for rot function + E.package.wires(W) { + if (W.curve) { + if (W.arc.layer == LAYER_TPLACE || W.arc.layer == LAYER_BPLACE) { + x1 = u2u(W.arc.xc)-rx; y1 = u2u(W.arc.yc)-ry; + rot(E.angle, x1, y1); // new coord x,y + printf("A %g,%g,%g,%.1f,%.1f\n", + x, y, u2u(W.arc.radius),u2ang(W.arc.angle1 - E.angle),u2ang(W.arc.angle2 - W.arc.angle1)); + } + } + else { + if (W.layer == LAYER_TPLACE || W.layer == LAYER_BPLACE) { + x1 = u2u(W.x1)-rx; y1 = u2u(W.y1)-ry; x2 = u2u(W.x2)-rx; y2 = u2u(W.y2)-ry; + rot(E.angle, x1, y1); x1 = x; y1 = y; + rot(E.angle, x2, y2); x2 = x; y2 = y; + printf("L (%g,%g) (%g,%g)\n", x1, y1, x2, y2); + } + } + } + E.package.circles(C) { + if (C.layer == LAYER_TPLACE || C.layer == LAYER_BPLACE) { + x1 = u2u(C.x)-rx; y1 = u2u(C.y)-ry; + rot(E.angle, x1, y1); + printf("C %g,%g,%g\n", x, y, u2u(C.radius)); + } + } + printf ("%%ENDGRAFITEM\n"); + printf ("%%PACKAGEDIMENSION\n"); + printf ("%%PINLIST\n"); + pad_is_numeric = 1; + E.package.contacts(C) { // test if name numeric + padname = C.name; + for (i = 0; padname[i]; ++i) { + if (!isdigit(padname[i])) { + pad_is_numeric = 0; + } + } + } + padcount = 1; + E.package.contacts(C) { + if (pad_is_numeric) { + printf("%s|", C.name); // PADNR + } + else { + printf("%d|", padcount); + padcount++; + } + x1 = u2u(C.x)-rx; y1 = u2u(C.y)-ry; + rot(E.angle, x1, y1); // get x,y + printf("%g|%g|", x, y); // REL. POSITION OF PADS + if (C.pad) { + printf("%s|", padtype(C)); // PADTYPE TOP + printf("%.1f|", u2ang(E.angle)); // PAD ORIENTATION TOP + printf("%s|", padtype(C)); // PADTYPE BOTTOM + printf("%.1f", u2ang(E.angle)); // PAD ORIENTATION BOTTOM + } + if (C.smd) { + if (C.smd.layer == LAYER_TOP) { + printf("%s|", padtype(C)); // PADTYPE TOP + printf("%.1f|", u2ang(E.angle)); // PAD ORIENTATION TOP + printf("|"); // BOTTOM empty + } + else { + printf("||"); // TOP empty + printf("%s|", padtype(C)); // PADTYPE BOTTOM + printf("%.1f", u2ang(E.angle)); // PAD ORIENTATION BOTTOM + } + } + printf("\n"); + } + } + } + } + return; +} + +////////////////////////////////////////////////////// +void via(UL_BOARD B) { + int i; + printf("\n%%%%VIA\n"); + B.signals(S) { + status("S-Via " + S.name); + S.vias(V) { + i++; + printf("VIA%d|%s|%g|%g|1|16|%s|0|%s|0|Y|Y\n", + i, S.name, u2u(V.x), u2u(V.y), viatype(V), viatype(V)); + } + } + return; +} + +////////////////////////////////////////////////////// +void track(UL_BOARD B) { + printf("\n%%%%TRACK\n"); + B.signals(S) { + status("Track " + S.name); + printf("NET=%s\n", S.name); + printf("%%GRAFITEM\n"); + S.wires(W) { + printf("N %d\n", W.layer); + printf("W %g\n", u2u(W.width)); + printf("FC 0,0,0,0\n"); + printf("L (%g,%g) (%g,%g)\n", u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + S.polygons(POL) { + POL.contours(W) { + printf("N %d\n", W.layer); + printf("W %g\n", u2u(W.width)); + printf("FC 0,0,0,0\n"); + printf("L (%g,%g) (%g,%g)\n", u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + POL.fillings(W) { + printf("N %d\n", W.layer); + printf("W %g\n", u2u(W.width)); + printf("FC 0,0,0,0\n"); + printf("L (%g,%g) (%g,%g)\n", u2u(W.x1), u2u(W.y1), u2u(W.x2), u2u(W.y2)); + } + } + printf("%%ENDGRAFITEM\n"); + } + return; +} + +////////////////////////////////////////////////////// +void create_pcboard_section(UL_BOARD B) { + // printf ("\n%%%%%%PCBOARDIdentifier\n"); + outline(B); + //panelstructure(); + fiducials(B); + component(B); + other_drillings(B); + component_pin(B); + //subcomponent(); + //testpad(); + pad(B); + shape(B); + via(B); + track(B); + //summary(); + return; +} + +////////////////////////////////////////////////////// + +//main +// *** Board coord. *** +if (board) board(B) { + reffile = filesetext(B.name, ".ref"); + output(reffile, "wt") { + Header(B.name); + printf("%sCOMPONENT\n", proz); + + // *** collect all pads *** + B.elements(E) { + if (E.package.library != _MARKER_) { + status("Package " + E.package.name); // 29.03.2005 alf@cadsoft.de + E.package.contacts(C) { + if (C.pad) { + padx[PadPoints] = C.pad.x; + pady[PadPoints] = C.pad.y; + padd[PadPoints] = E.name; + padn[PadPoints] = C.name; + padnn[PadPoints] = "*nc*"; // *** default not connected *** + PadPoints++; + } + } + } + } + B.signals(S) { + // *** if pad connected to net *** + S.contactrefs(C) { + //if (dlgMessageBox(C.element.name, "ok", "esc") != 0) exit(-99); + status("B-Signal " + S.name + "/" + C.element.package.name); // 29.03.2005 alf@cadsoft.de + for (int pad = 0; pad < PadPoints; pad++) { + if (padx[pad] == C.contact.x && pady[pad] == C.contact.y) { + padnn[pad] = S.name; // *** connectad to net-name *** + // default *nc* = not connected + break; + } + } + } + } + + // **** Sheet coord. **** + if (project.schematic) { + sheetload = 1; + project.schematic(S) { + // *** collect all Pins *** + S.sheets(SH) { + SH.parts(PA) { // *** IC1 *** + status("Part " + PA.name); // 29.03.2005 alf@cadsoft.de + int gate = 0; + PA.device.gates(G) { + gate++; + } + int dir = 5; // Dirction PWR + int Pinn = 0; // Pin counter for Gate + PA.instances(IN) { // *** IC1A *** + IN.gate.symbol.pins(P) { + int cntcont = 0; + P.contacts(C) { + cntcont++; + break; + } + if (cntcont) { + P.contacts(C) { // 2014-01-14 new contacts for multipin + if (P.direction != PIN_DIRECTION_PWR) { // only PWR-Pins in Gate ? + dir = P.direction; + } + pc[PinPoints] = C.name; // PAD name von Connect/Pad + px[PinPoints] = C.x; + py[PinPoints] = C.y; + ps[PinPoints] = IN.sheet; // SHEET# + pa[PinPoints] = PA.name; // PART name + pg[PinPoints] = IN.name; // Part+GATE name + pn[PinPoints] = P.name; // PIN name + PinPoints++; + Pinn ++; + } + } + else { + gate = 0; // Reset Gate counter - Supply Symbol has no Gates + // pc[PinPoints] = " no pac."; // kein Pad-Name nur Symbol!! + } + } + } + if (PinPoints > 0) { + switch (gate) { + case 2 : if (dir == 5) { + // Gate-Name wird angezeigt + break; + } + if (dir != 5) { + pg[PinPoints -1] = pa[PinPoints - 1]; // Gatename wird nicht angezeigt + break; + } + case 1 : for (int gp = 0; gp < Pinn; gp++) { + pg[PinPoints - gp -1] = ""; // clear all Pin-Gate-name + } + case 0 : // printf("no Gates (Supply?) =%d\n", gate); + } + } + } + } + } + // *** print all Pad ccord. + for (int pad = 0; pad < PadPoints; pad++) { + for (int p = 0; p < PinPoints; p++) { + if (padd[pad] == pa[p] && padn[pad] == pc[p]) { + pads[pad] = ps[p]; // copy Sheet# to Pad + pnn[p] = padnn[pad]; // Signal name to Pin + } + } + printf("%s|%s|%s|sheet%d|", padd[pad], padn[pad], padnn[pad], pads[pad]); + printf("%.3f,%.3f|mm|\n", u2mm(padx[pad]), u2mm(pady[pad])); + } + // *** %PINS *** + printf("%sPINS\n", proz); + // *** print all Pin sheet/coord. *** + for (int pin = 0; pin < PinPoints; pin++) { + status("Pins " + pa[pin]); // 29.03.2005 alf@cadsoft.de + printf("%s|%s|%s|%s|%s|sheet%d|%.2f,%.2f|mm|\n", + pa[pin], pg[pin], pnn[pin], pc[pin], pn[pin], ps[pin], u2mm(px[pin]), u2mm(py[pin])); + } + } + else { + dlgMessageBox("Please load Schematic first! No data generated!", "OK"); + exit (-1); + } + } +} + +if (board) board(B) { + jobname = filename(B.name); + jobname = strsub(jobname, 0, strlen(jobname) - 4); + unifile = filesetext(B.name, ".uni"); + output(unifile, "wt") { + create_info(); + create_pcboard_section(B); + } + test(); + exit (0); +} + +else { + dlgMessageBox("Start " + ULPversion + " from a Board", "OK"); + exit (-2); +} diff --git a/trunk/ulp/update-packages.ulp b/trunk/ulp/update-packages.ulp new file mode 100644 index 00000000..93f70479 --- /dev/null +++ b/trunk/ulp/update-packages.ulp @@ -0,0 +1,11 @@ +#usage "update current libary with reference package library

    " + "Author alf@cadsoft.de" + +string referencepackage = "plcc-socket.lbr"; +string cmd = ""; + +library(L) { + if (filename(L.name) == referencepackage); + else sprintf(cmd, "UPDATE %s;\nWRITE;\n", referencepackage); +} +exit(cmd); \ No newline at end of file diff --git a/trunk/ulp/useful-routines.ulp b/trunk/ulp/useful-routines.ulp new file mode 100644 index 00000000..85d6e3d4 --- /dev/null +++ b/trunk/ulp/useful-routines.ulp @@ -0,0 +1,67 @@ +#usage "Collection of useful routines\n" + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +// EditBox with Execute/Save filename +int edit_save_execute(string cmd, string f_name) { +int R; + R = dlgDialog("Edit and execute") { + dlgTextEdit(cmd); + dlgHBoxLayout { + dlgPushButton("+&Execute") dlgAccept(); + dlgPushButton("-&Cancel") dlgReject(); + dlgPushButton("+Save") { + string dest = dlgFileSave("Save Script File", f_name+".scr", "*.scr"); + if (dest != "") output(dest, "wt") {printf(cmd);} + } + } + }; +return R; // 1 = Execute, 0 = Cancel +} + +// get ULP program name +string get_ulp_name(void) { + string s = strsub(argv[0], 0, strlen(argv[0])-4); + string p = s; + char c = '/'; + int pos = strrchr(s, c); + if (pos >= 0) { + p = strsub(s, pos + 1); + } + return p; +} + +// get ULP path +string get_ulp_path(void) { + string ulp_path = ""; + char c = '/'; + int pos = strrchr(argv[0], c); + if (pos >= 0) { + ulp_path = strsub(argv[0], 0, pos + 1); + } + return ulp_path; +} + +// get project path, if in board or schematic, otherwise library path +string get_project_path() { +string s = "", p = "";; + if (library) { library(L) s = L.name;} + if (board) { board(B) s = B.name;} + if (schematic){ schematic(S) s = S.name;} + char c = '/'; + int pos = strrchr(s, c); + if (pos >= 0) { + p = strsub(s, 0, pos + 1); + } + return p; +} + +// returns 1 if FileName exists (including path) +int exist_file(string FileName) { +string a[]; + int n = fileglob(a, FileName); + if (n == 0) return 0; + else return 1; +} diff --git a/trunk/ulp/via-mask-one-layer.ulp b/trunk/ulp/via-mask-one-layer.ulp new file mode 100644 index 00000000..536d42bb --- /dev/null +++ b/trunk/ulp/via-mask-one-layer.ulp @@ -0,0 +1,299 @@ +#usage "en:Generate a one-sided stop mask in layer tStop or bStop with a given width beginning at the drill's edge.\n" + "

    " + "In order to delete all mask data objects in the stop layer, which may result from a previous run of this ULP, display none " + "except the Stop layer and use GROUP and DELETE." + "

    " + "Author: support@cadsoft.de" + , + "de:Generiert eine einseitige Lötstop-Maske auf dem Layer tStop oder bStop mit einer angegebenen Breite ab der Bohrlochkante.\n" + "

    " + "Um bereits vorhandene Maskendaten z.B. aus einem vorhergehenden Start des ULPs zu löschen, schalten Sie alle Layer bis auf den " + "gewünschten aus, und löschen sie mit GROUP und DELETE." + "

    " + "Author: support@cadsoft.de" + +// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED + +string DruFile = ""; +string DRUvalues[]; +int DRUlcnt = 0; +int StopLimitLine = 0; +string LayerStack = ""; +real LabmlViaStopLimit = 0.0; + +real MaxViaDrill = 0; +string LayerName[]; +int UsedLayerstack[]; +int CoreLayer = 0; + + +int StopMaskLayer; +string Cmd; + +numeric string ListVDrillsT[]; +int VDrillsT[]; +int CntVdrillsT = 0; +numeric string ListVDrillsB[]; +int VDrillsB[]; +int CntVdrillsB = 0; + +// delete trailing zeros +string delkommanull(string v) { + for (int n = strlen(v)-1; n; n--) { + if(v[n] == '0') v[n] = 0; + else return v; + } + return v; +} + +// get Design Rules +string get_DesignRules(string bfile) { // read boardname.dru + DruFile = filesetext(bfile, ".dru"); + string f[]; + int fcnt = fileglob(f, DruFile); + string h; + if (!argv[1]) { + string cmd; + sprintf(cmd, "DRC SAVE '%s';\nRUN '%s' '%s';", DruFile, argv[0], DruFile); + exit(cmd); + } + DRUlcnt = fileread(DRUvalues, DruFile); // get Design Rules + string s[]; + int n; + int x; + for (int line = 0; line < DRUlcnt; line++) { + n = strsplit(s, DRUvalues[line], ' '); + + if (s[0] == "layerSetup") { + LayerStack = s[2]; + // layerSetup = ([2:1+2*15+16:15]) + string laySetupStr = s[2]; + for (int l = 0; l < strlen(laySetupStr); l++) { + if (!isdigit(laySetupStr[l])) laySetupStr[l] = ' '; + } + string ulayers[]; + int cntl = strsplit(ulayers, laySetupStr, ' '); + int lasttoplayer = 0; + for (int n = 0; n < cntl; n++) { + int lnr = strtol(ulayers[n]); + UsedLayerstack[lnr] = 1; + if (lnr < 9 && lasttoplayer < lnr) lasttoplayer = lnr; + } + CoreLayer = lasttoplayer+1; // der Kern + } + /* mlViaStopLimit = 0.3mm */ + else if (s[0] == "mlViaStopLimit") { + StopLimitLine = line; + real mlViaStopLimit = strtod(s[2]); + if(strstr(s[2], "mil") > 0) { + x = mil2u(mlViaStopLimit); + mlViaStopLimit = u2mm(x); + } + LabmlViaStopLimit = mlViaStopLimit; + } + } + return DruFile; +} + +void savedru(void) { + string s[]; + int n = strsplit(s, DRUvalues[StopLimitLine], ' '); + string v; + sprintf(v, "%f", LabmlViaStopLimit); + sprintf(s[2], "%smm", delkommanull(v)); + DRUvalues[StopLimitLine] = strjoin(s, ' '); + output(DruFile, "wt") { + for (int line = 0; line < DRUlcnt; line++) { + printf("%s\n", DRUvalues[line]); + } + } + string cmd; + sprintf(cmd, "DRC LOAD '%s';\nRUN '%s' '%s';", DruFile, argv[0], DruFile); + exit(cmd); +} + +string changeoversize(string line) { + string s[]; + int n = strsplit(s, line, '\t'); + real oversize = strtod(s[1]); + dlgDialog("Oversize drill") { + dlgLabel("Drill " + s[0]); + dlgHBoxLayout { + dlgLabel("Oversize"); + dlgRealEdit(oversize, 0, 10); + dlgStretch(1); + } + dlgHBoxLayout { + dlgStretch(1); + dlgPushButton("+OK") { + sprintf(s[1], "%f", oversize); + s[1] = delkommanull(s[1]); + line = strjoin(s, '\t'); + dlgAccept(); + } + dlgPushButton("-CANCEL") dlgReject(); + dlgStretch(1); + } + }; + return line; +} + +void getvaluemenu(void) { + string sMaxViaDrill; + string vdrill; + sprintf(vdrill, "%f", MaxViaDrill); + sprintf(sMaxViaDrill, "Found max Via-Drill = %smm", delkommanull(vdrill)); + string vLabmlViaStopLimit; + sprintf(vLabmlViaStopLimit, "%f", LabmlViaStopLimit); + string info = ""; + if (LabmlViaStopLimit < MaxViaDrill) { + sprintf(info, "Max. via drill diameter = %smm
    DRC Parameter for Limit = %smm

    " + + "Set Limit in DRC to %s", + delkommanull(vdrill), delkommanull(vLabmlViaStopLimit), delkommanull(vdrill) + ); + } + int selt = -1; + int selb = -1; + int srt = 1; + int Result = dlgDialog("Generate stop mask for VIA") { + /* + dlgHBoxLayout { + dlgLabel("Layer-Stack"); + dlgLabel(LayerStack); + dlgStretch(1); + } + dlgHBoxLayout { + dlgLabel(sMaxViaDrill); + dlgStretch(1); + } + */ + dlgHBoxLayout { + dlgLabel("Mask Stop-Limit"); + dlgRealEdit(LabmlViaStopLimit); + dlgLabel("mm"); + dlgStretch(1); + } + if (LabmlViaStopLimit < MaxViaDrill) { + dlgGroup("DRC settings") { + dlgHBoxLayout { + dlgLabel(info); + dlgStretch(1); + dlgPushButton("Set, Save and Load DRU") { + LabmlViaStopLimit = MaxViaDrill; + savedru(); + } + } + } + } + dlgGroup("Set stop mask") { + dlgHBoxLayout { + dlgVBoxLayout { + dlgRadioButton("tStop", StopMaskLayer); + dlgListView("Top Drill\toversize", ListVDrillsT, selt, srt) ListVDrillsT[selt] = changeoversize(ListVDrillsT[selt]); + } + dlgVBoxLayout { + dlgRadioButton("bStop", StopMaskLayer); + dlgListView("Bot.Drill\toversize", ListVDrillsB, selb, srt) ListVDrillsB[selb] = changeoversize(ListVDrillsB[selb]); + } + } + } + dlgHBoxLayout { + dlgPushButton("+OK") dlgAccept(); + dlgPushButton("-Cancel") dlgReject(); + dlgStretch(1); + dlgPushButton("Help") dlgMessageBox(usage); + } + }; + if (!Result) exit(0); + return; +} + +real oversize(string line) { + string s[]; + int cnt = strsplit(s, line, '\t'); + return strtod(s[1]); +} + +real getoversize(int drill, int lay) { + int n; + if (lay == 29) { + for (int n = 0; n < CntVdrillsT; n++) { + if (drill == VDrillsT[n]) return oversize(ListVDrillsT[n]); + } + } + else if (lay = 30) { + for (int n = 0; n < CntVdrillsB; n++) { + if (drill == VDrillsB[n]) return oversize(ListVDrillsB[n]); + } + } + dlgMessageBox("Error, no drills found!", "OK"); + exit(-230); +} + +void drawmask(int x, int y, int diameter, int lay) { + real stopmaskoversize = getoversize(diameter, lay); + real radius = u2mm(diameter) / 2 + stopmaskoversize; + string s; + sprintf(s, "CIRCLE 0 (%.4fmm %.4fmm) (%.4fmm %.4fmm) ;\n", + u2mm(x), u2mm(y), u2mm(x) + radius, u2mm(y) ); + Cmd += s; + return; +} + +void adddrill(int drill, int lay) { + if (lay == 1) { + for (int n = 0; n < CntVdrillsT; n++) { + if (drill == VDrillsT[n]) return; + } + VDrillsT[CntVdrillsT++] = drill; + return; + } + else if (lay = 16) { + for (int n = 0; n < CntVdrillsB; n++) { + if (drill == VDrillsB[n]) return; + } + VDrillsB[CntVdrillsB++] = drill; + return; + } + return; +} + +if (board) board(B) { + B.signals(S) { + S.vias(V) { + if(V.start == 1 || V.end == 16 ) { + if (MaxViaDrill < u2mm(V.drill)) MaxViaDrill = u2mm(V.drill); + if (V.start == 1 ) adddrill(V.drill, 1); + else if (V.end == 16) adddrill(V.drill, 16); + } + } + } + int n; + string v; + for (n = 0; n < CntVdrillsT; n++) { + sprintf(v, "%f", u2mm(VDrillsT[n])); + sprintf(ListVDrillsT[n], "%s\t0.0", delkommanull(v)); + } + for (n = 0; n < CntVdrillsB; n++) { + sprintf(v, "%f", u2mm(VDrillsB[n])); + sprintf(ListVDrillsB[n], "%s\t0.0", delkommanull(v)); + } + + string dru_file = get_DesignRules(B.name); // read Designrules + getvaluemenu(); + int masklayer; + if (!StopMaskLayer) masklayer = 29; + else masklayer = 30; + sprintf(Cmd, "Layer %d ;\nchange layer %d;\n", masklayer, masklayer); + B.signals(S) { + S.vias(V) { + if(V.start == 1 && StopMaskLayer == 0 || V.end == 16 && StopMaskLayer == 1) { + drawmask(V.x, V.y, V.drill, masklayer); + } + } + } + exit(Cmd); +} + +else dlgMessageBox("Start this ULP in a Board!", "OK"); +exit(0); diff --git a/trunk/ulp/viewer/applet/data/BankGothic-Light-14.vlw b/trunk/ulp/viewer/applet/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/viewer/applet/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/viewer/applet/data/BankGothic-Light-24.vlw b/trunk/ulp/viewer/applet/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/viewer/applet/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/viewer/applet/data/optimize_me.txt b/trunk/ulp/viewer/applet/data/optimize_me.txt new file mode 100644 index 00000000..3f30631b --- /dev/null +++ b/trunk/ulp/viewer/applet/data/optimize_me.txt @@ -0,0 +1,41 @@ +# board=.../ATTiny13/ATTiny13.bot.etch.tap +# tool size=1.000000 +# pass=1 +-2.81800, 7.28695,-2.81800, 5.41305 +-2.81800, 5.41305,-4.14305, 4.08800 +-4.14305, 4.08800,-6.01695, 4.08800 +-6.01695, 4.08800,-6.17928, 4.25034 +-6.17928, 4.25034,-6.28220, 4.19789 +-6.28220, 4.19789,-6.50675, 4.12493 +-6.50675, 4.12493,-6.73994, 4.08800 +-6.73994, 4.08800,-8.50005, 4.08800 +-8.50005, 4.08800,-8.73325, 4.12493 +-8.73325, 4.12493,-8.95780, 4.19789 +-8.95780, 4.19789,-9.16817, 4.30508 +-9.16817, 4.30508,-9.35918, 4.44386 +-9.35918, 4.44386,-9.52613, 4.61082 +-9.52613, 4.61082,-9.66491, 4.80183 +-9.66491, 4.80183,-9.77210, 5.01220 +-9.77210, 5.01220,-9.84506, 5.23675 +-9.84506, 5.23675,-9.88200, 5.46994 +-9.88200, 5.46994,-9.88200, 7.23005 +-9.88200, 7.23005,-9.84506, 7.46325 +-9.84506, 7.46325,-9.77210, 7.68780 +-9.77210, 7.68780,-9.71966, 7.79072 +-9.71966, 7.79072,-9.88200, 7.95305 +-9.88200, 7.95305,-9.88200, 9.82695 +-9.88200, 9.82695,-9.54894,10.16000 +-9.54894,10.16000,-9.88200,10.49305 +-9.88200,10.49305,-9.88200,12.36695 +-9.88200,12.36695,-8.55695,13.69200 +-8.55695,13.69200,-6.68305,13.69200 +-6.68305,13.69200,-6.35000,13.35894 +-6.35000,13.35894,-6.01695,13.69200 +-6.01695,13.69200,-4.14305,13.69200 +-4.14305,13.69200,-2.81800,12.36695 +-2.81800,12.36695,-2.81800,10.49305 +-2.81800,10.49305,-3.15105,10.16000 +-3.15105,10.16000,-2.81800, 9.82695 +-2.81800, 9.82695,-2.81800, 7.95305 +-2.81800, 7.95305,-3.15105, 7.62000 +-3.15105, 7.62000,-2.81800, 7.28695 diff --git a/trunk/ulp/viewer/applet/index.html b/trunk/ulp/viewer/applet/index.html new file mode 100644 index 00000000..a2958ebd --- /dev/null +++ b/trunk/ulp/viewer/applet/index.html @@ -0,0 +1,108 @@ + + + + + + + viewer : Built with Processing + + + + + +

    + + diff --git a/trunk/ulp/viewer/applet/loading.gif b/trunk/ulp/viewer/applet/loading.gif new file mode 100644 index 00000000..1ddae508 Binary files /dev/null and b/trunk/ulp/viewer/applet/loading.gif differ diff --git a/trunk/ulp/viewer/applet/viewer.jar b/trunk/ulp/viewer/applet/viewer.jar new file mode 100644 index 00000000..7345b613 Binary files /dev/null and b/trunk/ulp/viewer/applet/viewer.jar differ diff --git a/trunk/ulp/viewer/applet/viewer.java b/trunk/ulp/viewer/applet/viewer.java new file mode 100644 index 00000000..0b5bb3ac --- /dev/null +++ b/trunk/ulp/viewer/applet/viewer.java @@ -0,0 +1,449 @@ +import processing.core.*; +import processing.xml.*; + +import java.applet.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; +import java.text.*; +import java.util.*; +import java.util.zip.*; +import java.util.regex.*; + +public class viewer extends PApplet { + +/** + * viewer + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +int[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +int bg_color = 0xff000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001f; + +int m_pass; +boolean m_monochrome = true; + +/* + * Parse Strings and produce Lines. + * + */ +public void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = PApplet.parseFloat(pieces[0]); + float y1 = PApplet.parseFloat(pieces[1]); + float x2 = PApplet.parseFloat(pieces[2]); + float y2 = PApplet.parseFloat(pieces[3]); + int m_pass = PApplet.parseInt(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +public void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +public void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +public void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = PApplet.parseFloat(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = PApplet.parseInt(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +public void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +public float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +public float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +public void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0f; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +public void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +public void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2f; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5f) { + m_scale -= 0.2f; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + + + static public void main(String args[]) { + PApplet.main(new String[] { "--bgcolor=#ffffff", "viewer" }); + } +} diff --git a/trunk/ulp/viewer/applet/viewer.pde b/trunk/ulp/viewer/applet/viewer.pde new file mode 100644 index 00000000..fd38c78d --- /dev/null +++ b/trunk/ulp/viewer/applet/viewer.pde @@ -0,0 +1,428 @@ +/** + * viewer + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = true; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/viewer/application.linux/data/BankGothic-Light-14.vlw b/trunk/ulp/viewer/application.linux/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/viewer/application.linux/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/viewer/application.linux/data/BankGothic-Light-24.vlw b/trunk/ulp/viewer/application.linux/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/viewer/application.linux/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/viewer/application.linux/data/optimize_me.txt b/trunk/ulp/viewer/application.linux/data/optimize_me.txt new file mode 100644 index 00000000..3f30631b --- /dev/null +++ b/trunk/ulp/viewer/application.linux/data/optimize_me.txt @@ -0,0 +1,41 @@ +# board=.../ATTiny13/ATTiny13.bot.etch.tap +# tool size=1.000000 +# pass=1 +-2.81800, 7.28695,-2.81800, 5.41305 +-2.81800, 5.41305,-4.14305, 4.08800 +-4.14305, 4.08800,-6.01695, 4.08800 +-6.01695, 4.08800,-6.17928, 4.25034 +-6.17928, 4.25034,-6.28220, 4.19789 +-6.28220, 4.19789,-6.50675, 4.12493 +-6.50675, 4.12493,-6.73994, 4.08800 +-6.73994, 4.08800,-8.50005, 4.08800 +-8.50005, 4.08800,-8.73325, 4.12493 +-8.73325, 4.12493,-8.95780, 4.19789 +-8.95780, 4.19789,-9.16817, 4.30508 +-9.16817, 4.30508,-9.35918, 4.44386 +-9.35918, 4.44386,-9.52613, 4.61082 +-9.52613, 4.61082,-9.66491, 4.80183 +-9.66491, 4.80183,-9.77210, 5.01220 +-9.77210, 5.01220,-9.84506, 5.23675 +-9.84506, 5.23675,-9.88200, 5.46994 +-9.88200, 5.46994,-9.88200, 7.23005 +-9.88200, 7.23005,-9.84506, 7.46325 +-9.84506, 7.46325,-9.77210, 7.68780 +-9.77210, 7.68780,-9.71966, 7.79072 +-9.71966, 7.79072,-9.88200, 7.95305 +-9.88200, 7.95305,-9.88200, 9.82695 +-9.88200, 9.82695,-9.54894,10.16000 +-9.54894,10.16000,-9.88200,10.49305 +-9.88200,10.49305,-9.88200,12.36695 +-9.88200,12.36695,-8.55695,13.69200 +-8.55695,13.69200,-6.68305,13.69200 +-6.68305,13.69200,-6.35000,13.35894 +-6.35000,13.35894,-6.01695,13.69200 +-6.01695,13.69200,-4.14305,13.69200 +-4.14305,13.69200,-2.81800,12.36695 +-2.81800,12.36695,-2.81800,10.49305 +-2.81800,10.49305,-3.15105,10.16000 +-3.15105,10.16000,-2.81800, 9.82695 +-2.81800, 9.82695,-2.81800, 7.95305 +-2.81800, 7.95305,-3.15105, 7.62000 +-3.15105, 7.62000,-2.81800, 7.28695 diff --git a/trunk/ulp/viewer/application.linux/lib/core.jar b/trunk/ulp/viewer/application.linux/lib/core.jar new file mode 100644 index 00000000..29375ea3 Binary files /dev/null and b/trunk/ulp/viewer/application.linux/lib/core.jar differ diff --git a/trunk/ulp/viewer/application.linux/lib/viewer.jar b/trunk/ulp/viewer/application.linux/lib/viewer.jar new file mode 100644 index 00000000..b28e7714 Binary files /dev/null and b/trunk/ulp/viewer/application.linux/lib/viewer.jar differ diff --git a/trunk/ulp/viewer/application.linux/source/viewer.java b/trunk/ulp/viewer/application.linux/source/viewer.java new file mode 100644 index 00000000..7165d14f --- /dev/null +++ b/trunk/ulp/viewer/application.linux/source/viewer.java @@ -0,0 +1,452 @@ +import processing.core.*; +import processing.xml.*; + +import java.applet.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; +import java.text.*; +import java.util.*; +import java.util.zip.*; +import java.util.regex.*; + +public class viewer extends PApplet { + +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +int[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +int bg_color = 0xff000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001f; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +public void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = PApplet.parseFloat(pieces[0]); + float y1 = PApplet.parseFloat(pieces[1]); + float x2 = PApplet.parseFloat(pieces[2]); + float y2 = PApplet.parseFloat(pieces[3]); + int m_pass = PApplet.parseInt(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +public void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +public void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +public void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = PApplet.parseFloat(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = PApplet.parseInt(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +public void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +public float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +public float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +public void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0f; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +public void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +public void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2f; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5f) { + m_scale -= 0.2f; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + + + static public void main(String args[]) { + PApplet.main(new String[] { "--bgcolor=#ffffff", "viewer" }); + } +} diff --git a/trunk/ulp/viewer/application.linux/source/viewer.pde b/trunk/ulp/viewer/application.linux/source/viewer.pde new file mode 100644 index 00000000..1659cedc --- /dev/null +++ b/trunk/ulp/viewer/application.linux/source/viewer.pde @@ -0,0 +1,431 @@ +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/viewer/application.linux/viewer b/trunk/ulp/viewer/application.linux/viewer new file mode 100644 index 00000000..74d932bd --- /dev/null +++ b/trunk/ulp/viewer/application.linux/viewer @@ -0,0 +1,4 @@ +#!/bin/sh + +APPDIR=$(dirname "$0") +java -Djava.library.path="$APPDIR" -cp "$APPDIR/lib/viewer.jar:$APPDIR/lib/core.jar" viewer diff --git a/trunk/ulp/viewer/application.macosx/data/BankGothic-Light-14.vlw b/trunk/ulp/viewer/application.macosx/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/viewer/application.macosx/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/viewer/application.macosx/data/BankGothic-Light-24.vlw b/trunk/ulp/viewer/application.macosx/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/viewer/application.macosx/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/viewer/application.macosx/data/optimize_me.txt b/trunk/ulp/viewer/application.macosx/data/optimize_me.txt new file mode 100644 index 00000000..3f30631b --- /dev/null +++ b/trunk/ulp/viewer/application.macosx/data/optimize_me.txt @@ -0,0 +1,41 @@ +# board=.../ATTiny13/ATTiny13.bot.etch.tap +# tool size=1.000000 +# pass=1 +-2.81800, 7.28695,-2.81800, 5.41305 +-2.81800, 5.41305,-4.14305, 4.08800 +-4.14305, 4.08800,-6.01695, 4.08800 +-6.01695, 4.08800,-6.17928, 4.25034 +-6.17928, 4.25034,-6.28220, 4.19789 +-6.28220, 4.19789,-6.50675, 4.12493 +-6.50675, 4.12493,-6.73994, 4.08800 +-6.73994, 4.08800,-8.50005, 4.08800 +-8.50005, 4.08800,-8.73325, 4.12493 +-8.73325, 4.12493,-8.95780, 4.19789 +-8.95780, 4.19789,-9.16817, 4.30508 +-9.16817, 4.30508,-9.35918, 4.44386 +-9.35918, 4.44386,-9.52613, 4.61082 +-9.52613, 4.61082,-9.66491, 4.80183 +-9.66491, 4.80183,-9.77210, 5.01220 +-9.77210, 5.01220,-9.84506, 5.23675 +-9.84506, 5.23675,-9.88200, 5.46994 +-9.88200, 5.46994,-9.88200, 7.23005 +-9.88200, 7.23005,-9.84506, 7.46325 +-9.84506, 7.46325,-9.77210, 7.68780 +-9.77210, 7.68780,-9.71966, 7.79072 +-9.71966, 7.79072,-9.88200, 7.95305 +-9.88200, 7.95305,-9.88200, 9.82695 +-9.88200, 9.82695,-9.54894,10.16000 +-9.54894,10.16000,-9.88200,10.49305 +-9.88200,10.49305,-9.88200,12.36695 +-9.88200,12.36695,-8.55695,13.69200 +-8.55695,13.69200,-6.68305,13.69200 +-6.68305,13.69200,-6.35000,13.35894 +-6.35000,13.35894,-6.01695,13.69200 +-6.01695,13.69200,-4.14305,13.69200 +-4.14305,13.69200,-2.81800,12.36695 +-2.81800,12.36695,-2.81800,10.49305 +-2.81800,10.49305,-3.15105,10.16000 +-3.15105,10.16000,-2.81800, 9.82695 +-2.81800, 9.82695,-2.81800, 7.95305 +-2.81800, 7.95305,-3.15105, 7.62000 +-3.15105, 7.62000,-2.81800, 7.28695 diff --git a/trunk/ulp/viewer/application.macosx/source/viewer.java b/trunk/ulp/viewer/application.macosx/source/viewer.java new file mode 100644 index 00000000..7165d14f --- /dev/null +++ b/trunk/ulp/viewer/application.macosx/source/viewer.java @@ -0,0 +1,452 @@ +import processing.core.*; +import processing.xml.*; + +import java.applet.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; +import java.text.*; +import java.util.*; +import java.util.zip.*; +import java.util.regex.*; + +public class viewer extends PApplet { + +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +int[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +int bg_color = 0xff000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001f; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +public void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = PApplet.parseFloat(pieces[0]); + float y1 = PApplet.parseFloat(pieces[1]); + float x2 = PApplet.parseFloat(pieces[2]); + float y2 = PApplet.parseFloat(pieces[3]); + int m_pass = PApplet.parseInt(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +public void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +public void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +public void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = PApplet.parseFloat(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = PApplet.parseInt(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +public void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +public float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +public float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +public void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0f; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +public void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +public void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2f; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5f) { + m_scale -= 0.2f; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + + + static public void main(String args[]) { + PApplet.main(new String[] { "--bgcolor=#ffffff", "viewer" }); + } +} diff --git a/trunk/ulp/viewer/application.macosx/source/viewer.pde b/trunk/ulp/viewer/application.macosx/source/viewer.pde new file mode 100644 index 00000000..1659cedc --- /dev/null +++ b/trunk/ulp/viewer/application.macosx/source/viewer.pde @@ -0,0 +1,431 @@ +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Info.plist b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Info.plist new file mode 100644 index 00000000..bd3489b8 --- /dev/null +++ b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Info.plist @@ -0,0 +1,59 @@ + + + + + CFBundleName + viewer + CFBundleVersion + 10.2 + CFBundleAllowMixedLocalizations + true + CFBundleExecutable + JavaApplicationStub + CFBundleDevelopmentRegion + English + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleInfoDictionaryVersion + 6.0 + CFBundleIconFile + sketch.icns + CFBundleIdentifier + viewer + + LSUIPresentationMode + 0 + Java + + VMOptions + -Xms64m -Xmx256m + MainClass + viewer + JVMVersion + 1.5* + ClassPath + $JAVAROOT/viewer.jar:$JAVAROOT/core.jar + + Properties + + + apple.laf.useScreenMenuBar + true + apple.awt.showGrowBox + false + com.apple.smallTabs + true + apple.awt.Antialiasing + false + apple.awt.TextAntialiasing + true + com.apple.hwaccel + true + apple.awt.use-file-dialog-packages + false + + + + diff --git a/trunk/ulp/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub new file mode 100644 index 00000000..eeb8b561 Binary files /dev/null and b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/MacOS/JavaApplicationStub differ diff --git a/trunk/ulp/viewer/application.macosx/viewer.app/Contents/PkgInfo b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/PkgInfo new file mode 100644 index 00000000..bd04210f --- /dev/null +++ b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/PkgInfo @@ -0,0 +1 @@ +APPL???? \ No newline at end of file diff --git a/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Resources/Java/core.jar b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Resources/Java/core.jar new file mode 100644 index 00000000..29375ea3 Binary files /dev/null and b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Resources/Java/core.jar differ diff --git a/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Resources/Java/viewer.jar b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Resources/Java/viewer.jar new file mode 100644 index 00000000..b28e7714 Binary files /dev/null and b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Resources/Java/viewer.jar differ diff --git a/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Resources/sketch.icns b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Resources/sketch.icns new file mode 100644 index 00000000..8ffb8d7d Binary files /dev/null and b/trunk/ulp/viewer/application.macosx/viewer.app/Contents/Resources/sketch.icns differ diff --git a/trunk/ulp/viewer/application.windows/data/BankGothic-Light-14.vlw b/trunk/ulp/viewer/application.windows/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/viewer/application.windows/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/viewer/application.windows/data/BankGothic-Light-24.vlw b/trunk/ulp/viewer/application.windows/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/viewer/application.windows/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/viewer/application.windows/data/optimize_me.txt b/trunk/ulp/viewer/application.windows/data/optimize_me.txt new file mode 100644 index 00000000..3f30631b --- /dev/null +++ b/trunk/ulp/viewer/application.windows/data/optimize_me.txt @@ -0,0 +1,41 @@ +# board=.../ATTiny13/ATTiny13.bot.etch.tap +# tool size=1.000000 +# pass=1 +-2.81800, 7.28695,-2.81800, 5.41305 +-2.81800, 5.41305,-4.14305, 4.08800 +-4.14305, 4.08800,-6.01695, 4.08800 +-6.01695, 4.08800,-6.17928, 4.25034 +-6.17928, 4.25034,-6.28220, 4.19789 +-6.28220, 4.19789,-6.50675, 4.12493 +-6.50675, 4.12493,-6.73994, 4.08800 +-6.73994, 4.08800,-8.50005, 4.08800 +-8.50005, 4.08800,-8.73325, 4.12493 +-8.73325, 4.12493,-8.95780, 4.19789 +-8.95780, 4.19789,-9.16817, 4.30508 +-9.16817, 4.30508,-9.35918, 4.44386 +-9.35918, 4.44386,-9.52613, 4.61082 +-9.52613, 4.61082,-9.66491, 4.80183 +-9.66491, 4.80183,-9.77210, 5.01220 +-9.77210, 5.01220,-9.84506, 5.23675 +-9.84506, 5.23675,-9.88200, 5.46994 +-9.88200, 5.46994,-9.88200, 7.23005 +-9.88200, 7.23005,-9.84506, 7.46325 +-9.84506, 7.46325,-9.77210, 7.68780 +-9.77210, 7.68780,-9.71966, 7.79072 +-9.71966, 7.79072,-9.88200, 7.95305 +-9.88200, 7.95305,-9.88200, 9.82695 +-9.88200, 9.82695,-9.54894,10.16000 +-9.54894,10.16000,-9.88200,10.49305 +-9.88200,10.49305,-9.88200,12.36695 +-9.88200,12.36695,-8.55695,13.69200 +-8.55695,13.69200,-6.68305,13.69200 +-6.68305,13.69200,-6.35000,13.35894 +-6.35000,13.35894,-6.01695,13.69200 +-6.01695,13.69200,-4.14305,13.69200 +-4.14305,13.69200,-2.81800,12.36695 +-2.81800,12.36695,-2.81800,10.49305 +-2.81800,10.49305,-3.15105,10.16000 +-3.15105,10.16000,-2.81800, 9.82695 +-2.81800, 9.82695,-2.81800, 7.95305 +-2.81800, 7.95305,-3.15105, 7.62000 +-3.15105, 7.62000,-2.81800, 7.28695 diff --git a/trunk/ulp/viewer/application.windows/lib/args.txt b/trunk/ulp/viewer/application.windows/lib/args.txt new file mode 100644 index 00000000..0e23ea1c --- /dev/null +++ b/trunk/ulp/viewer/application.windows/lib/args.txt @@ -0,0 +1,3 @@ + -Xms64m -Xmx256m +viewer +viewer.jar,core.jar diff --git a/trunk/ulp/viewer/application.windows/lib/core.jar b/trunk/ulp/viewer/application.windows/lib/core.jar new file mode 100644 index 00000000..29375ea3 Binary files /dev/null and b/trunk/ulp/viewer/application.windows/lib/core.jar differ diff --git a/trunk/ulp/viewer/application.windows/lib/viewer.jar b/trunk/ulp/viewer/application.windows/lib/viewer.jar new file mode 100644 index 00000000..b28e7714 Binary files /dev/null and b/trunk/ulp/viewer/application.windows/lib/viewer.jar differ diff --git a/trunk/ulp/viewer/application.windows/source/viewer.java b/trunk/ulp/viewer/application.windows/source/viewer.java new file mode 100644 index 00000000..7165d14f --- /dev/null +++ b/trunk/ulp/viewer/application.windows/source/viewer.java @@ -0,0 +1,452 @@ +import processing.core.*; +import processing.xml.*; + +import java.applet.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.event.*; +import java.io.*; +import java.net.*; +import java.text.*; +import java.util.*; +import java.util.zip.*; +import java.util.regex.*; + +public class viewer extends PApplet { + +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +int[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +int bg_color = 0xff000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001f; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +public void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = PApplet.parseFloat(pieces[0]); + float y1 = PApplet.parseFloat(pieces[1]); + float x2 = PApplet.parseFloat(pieces[2]); + float y2 = PApplet.parseFloat(pieces[3]); + int m_pass = PApplet.parseInt(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +public void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +public void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +public void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = PApplet.parseFloat(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = PApplet.parseInt(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +public void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +public float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +public float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +public void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0f; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +public void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +public void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2f; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5f) { + m_scale -= 0.2f; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + + + static public void main(String args[]) { + PApplet.main(new String[] { "--bgcolor=#ffffff", "viewer" }); + } +} diff --git a/trunk/ulp/viewer/application.windows/source/viewer.pde b/trunk/ulp/viewer/application.windows/source/viewer.pde new file mode 100644 index 00000000..1659cedc --- /dev/null +++ b/trunk/ulp/viewer/application.windows/source/viewer.pde @@ -0,0 +1,431 @@ +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/viewer/application.windows/viewer.exe b/trunk/ulp/viewer/application.windows/viewer.exe new file mode 100644 index 00000000..ea70a3a2 Binary files /dev/null and b/trunk/ulp/viewer/application.windows/viewer.exe differ diff --git a/trunk/ulp/viewer/data/BankGothic-Light-14.vlw b/trunk/ulp/viewer/data/BankGothic-Light-14.vlw new file mode 100644 index 00000000..e38bc838 Binary files /dev/null and b/trunk/ulp/viewer/data/BankGothic-Light-14.vlw differ diff --git a/trunk/ulp/viewer/data/BankGothic-Light-24.vlw b/trunk/ulp/viewer/data/BankGothic-Light-24.vlw new file mode 100644 index 00000000..3e84f223 Binary files /dev/null and b/trunk/ulp/viewer/data/BankGothic-Light-24.vlw differ diff --git a/trunk/ulp/viewer/data/optimize_me.txt b/trunk/ulp/viewer/data/optimize_me.txt new file mode 100644 index 00000000..3f30631b --- /dev/null +++ b/trunk/ulp/viewer/data/optimize_me.txt @@ -0,0 +1,41 @@ +# board=.../ATTiny13/ATTiny13.bot.etch.tap +# tool size=1.000000 +# pass=1 +-2.81800, 7.28695,-2.81800, 5.41305 +-2.81800, 5.41305,-4.14305, 4.08800 +-4.14305, 4.08800,-6.01695, 4.08800 +-6.01695, 4.08800,-6.17928, 4.25034 +-6.17928, 4.25034,-6.28220, 4.19789 +-6.28220, 4.19789,-6.50675, 4.12493 +-6.50675, 4.12493,-6.73994, 4.08800 +-6.73994, 4.08800,-8.50005, 4.08800 +-8.50005, 4.08800,-8.73325, 4.12493 +-8.73325, 4.12493,-8.95780, 4.19789 +-8.95780, 4.19789,-9.16817, 4.30508 +-9.16817, 4.30508,-9.35918, 4.44386 +-9.35918, 4.44386,-9.52613, 4.61082 +-9.52613, 4.61082,-9.66491, 4.80183 +-9.66491, 4.80183,-9.77210, 5.01220 +-9.77210, 5.01220,-9.84506, 5.23675 +-9.84506, 5.23675,-9.88200, 5.46994 +-9.88200, 5.46994,-9.88200, 7.23005 +-9.88200, 7.23005,-9.84506, 7.46325 +-9.84506, 7.46325,-9.77210, 7.68780 +-9.77210, 7.68780,-9.71966, 7.79072 +-9.71966, 7.79072,-9.88200, 7.95305 +-9.88200, 7.95305,-9.88200, 9.82695 +-9.88200, 9.82695,-9.54894,10.16000 +-9.54894,10.16000,-9.88200,10.49305 +-9.88200,10.49305,-9.88200,12.36695 +-9.88200,12.36695,-8.55695,13.69200 +-8.55695,13.69200,-6.68305,13.69200 +-6.68305,13.69200,-6.35000,13.35894 +-6.35000,13.35894,-6.01695,13.69200 +-6.01695,13.69200,-4.14305,13.69200 +-4.14305,13.69200,-2.81800,12.36695 +-2.81800,12.36695,-2.81800,10.49305 +-2.81800,10.49305,-3.15105,10.16000 +-3.15105,10.16000,-2.81800, 9.82695 +-2.81800, 9.82695,-2.81800, 7.95305 +-2.81800, 7.95305,-3.15105, 7.62000 +-3.15105, 7.62000,-2.81800, 7.28695 diff --git a/trunk/ulp/viewer/viewer.pde b/trunk/ulp/viewer/viewer.pde new file mode 100644 index 00000000..1659cedc --- /dev/null +++ b/trunk/ulp/viewer/viewer.pde @@ -0,0 +1,431 @@ +/** + * viewer + * + * Copyright 2013 by John Johnson Software, LLC + * All Rights Reserved + * + * Load line coordinates from a file and draw them. + * + */ + +/* + * Representation of a line. + * + */ +class Line { + float sx; + float sy; + float ex; + float ey; + int pass; // What pass this line was created on. + + Line(float x1, float y1, float x2, float y2, int pass_num) { + sx = x1; + sy = y1; + ex = x2; + ey = y2; + pass = pass_num; + } +} + +Line[] plines = new Line[1]; + +/* + * When lines are drawn in color, the colors used follow the + * standard resistor color codes. After 9, the sequence repeats. + * 0 is cyan, rather than black, as that would be a little hard + * to see on the black background. + * Colors are also slightly (204/255) transparent so you can see where + * they overlap. + * + */ +color[] color_table = { + 0xCC3399FF, /* pass 0, cyan */ + 0xCC993300, /* 1 = brown */ + 0xCCFF0000, + 0xCCFF9900, + 0xCCFFFF00, /* yellow */ + 0xCC33FF00, + 0xCC0000FF, + 0xCC660099, /* violet */ + 0xCCCCCCCC, /* gray */ + 0xCCFFFFFF /* white */ +}; + +color bg_color = #000000; + +float x_scale = -200; +float y_scale = -200; +float x_offset = 0; +float y_offset = 300; + +//float minx = 999; +//float miny = 999; +//float maxx = -999; +//float maxy = -999; +float minx = 0; +float miny = 0; +float maxx = 0; +float maxy = 0; + +PFont metaBold; + +String filename = "optimize_me.txt"; + +String comment = ""; +float tool_size = 0.001; + +int m_pass; +boolean m_monochrome = false; + +/* + * Parse Strings and produce Lines. + * + */ +void prepare_lines(String[] lines) { + int i; + + for (i=0; i < lines.length; i++) { + if (lines[i] != null) { + // println(lines[i]); + String[] pieces = split(lines[i], ','); + if (pieces.length == 5) { + float x1 = float(pieces[0]); + float y1 = float(pieces[1]); + float x2 = float(pieces[2]); + float y2 = float(pieces[3]); + int m_pass = int(pieces[4]); + plines[i] = new Line(x1, y1, x2, y2, m_pass); + // println(nfs(plines[i].sx, 1, 5) +", " + nfs(plines[i].sy, 1, 5) + " " + nfs(plines[i].pass, 2)); + minx = min(minx, x1); + miny = min(miny, y1); + maxx = max(maxx, x1); + maxy = max(maxy, y1); + minx = min(minx, x2); + miny = min(miny, y2); + maxx = max(maxx, x2); + maxy = max(maxy, y2); + } + } + } + /* println("prepare_lines exit"); + println("minx = " + nfs(minx, 1, 3)); + println("miny = " + nfs(miny, 1, 3)); + println("maxx = " + nfs(maxx, 1, 3)); + println("maxy = " + nfs(maxy, 1, 3)); + */ +} + +/* + * Calculate scaling based on the extents of the trace coordinates. + * + */ +void set_scaling() { + x_scale = (width - 70) / (maxx - minx); + y_scale = (height - 70) / (maxy - miny); + // println("x_scale = " + nfs(x_scale, 1, 3)); + // println("y_scale = " + nfs(y_scale, 1, 3)); + + y_scale = x_scale = min(x_scale, y_scale); + y_scale = -abs(y_scale); + + if (minx < 0) { + x_offset += abs(minx) * x_scale; + } + x_offset += 20; + y_offset = height - 40; + + /* + println("x_scale = " + nfs(x_scale, 1, 3)); + println("y_scale = " + nfs(y_scale, 1, 3)); + println("x_offset = " + nfs(x_offset, 1, 3)); + println("y_offset = " + nfs(y_offset, 1, 3)); + */ +} + +/* + * Right-justified text. + * + */ +void rtext(String s, float x, float y) { + text(s, x - textWidth(s), y); +} + +/* + * Setup the window. + * Read and parse the file. + * + */ +void setup() { + String matches[]; + size(800, 600); + + String line = null; + String[] lines = new String[1]; + BufferedReader reader = createReader(filename); + do { + try { + line = reader.readLine(); + } + catch (IOException e) { + println("Mama I'm sick"); + } + if (line != null) { + matches = match(line, "^# board=(.+)"); + if (matches != null) { + comment = matches[1]; + } + matches = match(line, "^# tool size=(.+)"); + if (matches != null) { + tool_size = float(matches[1]); + } + matches = match(line, "^# pass=(.+)"); + if (matches != null) { + m_pass = int(matches[1]); + } + matches = match(line, "^#"); + if (matches == null) { + lines = (String[])append(lines, (line + "," + nf(m_pass,2))); + } + } + } while (line != null); + plines = (Line[])expand(plines, lines.length); + prepare_lines(lines); + set_scaling(); + noLoop(); +} + +/* + * Draw a Line. + * + */ +void line(Line l) { + if (l != null) { + if (! m_monochrome) { + stroke(color_table[l.pass % 9]); + } + line(l.sx * x_scale + x_offset, l.sy * y_scale + y_offset, + l.ex * x_scale + x_offset, l.ey * y_scale + y_offset); +// println(nfs(l.sx, 1, 5) +", " + nfs(l.sy, 1, 5)); +// print(nfs(l.sx * x_scale + x_offset, 1, 5) +", " + nfs(l.sy * y_scale + y_offset, 1, 5) + ", "); +// println(nfs(l.ex * x_scale + x_offset, 1, 5) +", " + nfs(l.ey * y_scale + y_offset, 1, 5)); + } + else { + println("null line"); + } +} + +/* + * X scale and offset. + * + */ +float xso(float x) { + return x * x_scale + x_offset; +} + +/* + * Y scale and offset. + * + */ +float yso(float y) { + return y * y_scale + y_offset; +} + +/* + * Text notes around the periphery of the window. + * + */ +void ornaments() { + stroke(255, 0, 0); + fill(255, 0, 0); + strokeWeight(1); + + // lower-left corner + line(xso(minx), yso(miny) - 10, xso(minx), yso(miny)); + line(xso(minx), yso(miny), xso(minx) + 10, yso(miny)); + + text(nfs(minx, 1, 3) + ", " + nfs(miny, 1, 3), xso(minx) + 5, yso(miny) + 12); + + // lower-right + line(xso(maxx), yso(miny) - 10, xso(maxx), yso(miny)); + line(xso(maxx), yso(miny), xso(maxx) - 10, yso(miny)); + + // upper-right + line(xso(maxx) - 10, yso(maxy), xso(maxx), yso(maxy)); + line(xso(maxx), yso(maxy), xso(maxx), yso(maxy) + 10); + rtext(nfs(maxx, 1, 3) + ", " + nfs(maxy, 1, 3), xso(maxx), yso(maxy) - 5); + + // upper-left corner + line(xso(minx) + 10, yso(maxy), xso(minx), yso(maxy)); + line(xso(minx), yso(maxy), xso(minx), yso(maxy) + 10); + + // cross-hoirs at the origin + line(xso(0)-10, yso(0), xso(0)+10, yso(0)); + line(xso(0), yso(0)-10, xso(0), yso(0)+10); + noFill(); + ellipse(xso(0), yso(0), 10, 10); + + // comment from the file + stroke(255); + text(comment, 10, 20); + + // tool size and number of passes + rtext("tool size " + nfs(tool_size, 1, 3), width - 120, 20); + rtext(nfs(m_pass, 1) + " passes", width - 40, 40); + + // brief help + text("Keys: +/- zoom, 1 no zoom, 2 zoom 2x, arrows move, a left, de right, w, up, so down", 10, 40); + text("c toggle color, qx quit", 60, 60); +} + +float m_scale = 1.0; +float m_trans_x = 0; +float m_trans_y = 0; +int draw_cnt = 0; +boolean m_drawing; +void draw() { + m_drawing = true; + background(bg_color); + stroke(127); + fill(bg_color); + strokeWeight(4); + quad(0, 0, width-1, 0, width-1, height-1, 0, height-1); + strokeWeight(1); + + fill(255, 0, 0); + metaBold = loadFont("BankGothic-Light-14.vlw"); + textFont(metaBold); + rtext("Viewer 1.5", width - 20, 20); + + stroke(200); + scale(m_scale); + translate(m_trans_x, m_trans_y); + if (plines != null) { + println("plines.length = " + nf(plines.length, 3)); + strokeWeight(tool_size * x_scale); + for (int i = 0; i < plines.length; i++) { + line(plines[i]); + } + } + else { + text("Didn't open the file", 100, height / 2); + } + + ornaments(); + m_drawing = false; +} + +void keyPressed() { + if (m_drawing) { + return; + } + switch (key) { + + /* + * Toggle colored lines. + * + */ + case 'c': + case 'C': + m_monochrome = ! m_monochrome; + break; + + /* + * Zoom in or out. + * + */ + case '+': + case '=': + if (m_scale < 10) { + m_scale += 0.2; + m_trans_x -= width / m_scale / 20; + m_trans_y -= height / m_scale / 20; + } + break; + case '_': + case '-': + if (m_scale > 0.5) { + m_scale -= 0.2; + m_trans_x += width / m_scale / 20; + m_trans_y += height / m_scale / 20; + } + break; + + /* + * Fixed zoom amounts. + * + */ + case '1': + m_scale = 1; + m_trans_x = 0; + m_trans_y = 0; + break; + case '2': + m_scale = 2; + m_trans_x = -width / 4; + m_trans_y = -height / 4; + break; + + /* + * Exit the program. + * + */ + case 'x': + case 'X': + case 'q': + case 'Q': + exit(); + break; + + /* + * Small movement left, right, up, down. + * + * Use these keys: + * + * QWERTY Dvorak + * w , + * a d a e + * s o + * + */ + case 'a': + m_trans_x += width / 80; + break; + case 'e': + case 'd': + m_trans_x -= width / 80; + break; + case ',': + case 'w': + m_trans_y += width / 80; + break; + case 'o': + case 's': + m_trans_y -= width / 80; + break; + + /* + * Move using the arrow keys. + * + */ + case CODED: + switch (keyCode) { + case LEFT: + m_trans_x += width / 20; + break; + case RIGHT: + m_trans_x -= width / 20; + break; + case UP: + m_trans_y += height / 20; + break; + case DOWN: + m_trans_y -= height / 20; + break; + } + break; + } + background(bg_color); + redraw(); +} + diff --git a/trunk/ulp/viewer/viewer.tmproj b/trunk/ulp/viewer/viewer.tmproj new file mode 100644 index 00000000..a928b6f5 --- /dev/null +++ b/trunk/ulp/viewer/viewer.tmproj @@ -0,0 +1,66 @@ + + + + + currentDocument + viewer.pde + documents + + + filename + optimize_me.txt + lastUsed + 2008-07-06T14:34:24Z + + + filename + viewer.pde + lastUsed + 2008-07-06T17:47:22Z + selected + + + + fileHierarchyDrawerWidth + 200 + metaData + + optimize_me.txt + + caret + + column + 0 + line + 0 + + firstVisibleColumn + 0 + firstVisibleLine + 0 + + viewer.pde + + caret + + column + 0 + line + 0 + + firstVisibleColumn + 0 + firstVisibleLine + 0 + + + openDocuments + + viewer.pde + + showFileHierarchyDrawer + + windowFrame + {{547, 8}, {849, 870}} + + diff --git a/trunk/ulp/warning.bmp b/trunk/ulp/warning.bmp new file mode 100644 index 00000000..a5542144 Binary files /dev/null and b/trunk/ulp/warning.bmp differ