#usage "en: <b>Export milling data for a board layout in SCRIPT, HPGL, ISEL, CNC</b>\n"
       "<p>"
       "<author>Author: support@cadsoft.de</author>"
       ,
       "de: <b>Export von Fr&auml;sdaten aus einem Board in SCRIPT, HPGL, ISEL, CNC</b>"
       "<p>"
       "<author>Author: support@cadsoft.de</author>"

#require 6.0400

// ****************** 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.
//
/*** to do :
Scalierung bei HPGL vorwahl 2/5/10
***/

string Version = "Version 6.1.0";   // 2013-04-30 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.<br>" +
                      "<nobr><font color=\"red\">All Clearance ERROR define a not isolated wire track!</font><br></nobr>";

int    Class_used[];
string SClass[];      // 2010-02-02

string INFOpolyClass;
sprintf(INFOpolyClass, "<nobr>If used a filling Polygon on Board, please check Clearance of Design-Rules/Classes if %.8f mm greater <br>" +
                       "as Milling Tool #1, damit bei Leiterbahnen die nicht im 0� 45� oder 90� Winkel also mit beliebigen Winkel<br>" +
                       "verlegt sind, eventuelle F&uuml;llprobleme wegen Rechenungenauigkeit vermieden werden.</nobr>", Inaccurateness);

string SavePar           = "&Save parameter";
string Machine_Menu_Info = "<nobr>Switch On Off the Mashine Menu for Z-Axis mashines!<br>" +
                           "If accept to change this the ULP save the aktual Parameter und restart!</nobr>";
string Z_Machine_Menu    = "Z Axis Menu";

string INFOinside        = "Info Break through";

string INFOinnerContour  = "<nobr>If inside the board one or more breakthruogh you can place a VIA with SIGNAL name<br>" +
                           "'~_REAL_OUTLINEMILL_~' to milling this.</nobr>";
string PlaceVIA      = "place VIA";
string DRCinfo       = "<qt><b>Distance info:</b><br>Distance Copper/Dimension (see <b>DRC</b>) this is the distance between <br>"
                       "the polygon and outline of the board.<br>"
                       "<nobr><font color=\"red\">Do not use value <b>0</b> for <b>Copper/Dimension</b> in Design-Rules-Distance (DRC).<br></font></nobr>";
                       "</qt>";

string Ref_pac       = "_REFERENCE_HOLE_"; // *** special package for mirror milling data ***

string InfoREFERENCE = "<nobr>Generate a special package with<br>" +
                       "REFERENCE circles in Layer 45 Holes.<br>" +
                       "Place it in the layout for milling and <br>" +
                       "mirroring (bottom side) with offset and <br>" +
                       "start this ULP again.<br>" +
                       "The position of the circles are defined<br>" +
                       "in the NC drill data file which comes<br>" +
                       "from the NC machine (eg. Excellon).</nobr><p>";

string InfoREFPack    = "<font color=\"red\">Es ist ein Referenzpackage platziert, um die Fangzapfen der Fräsmaschine zur Berechnung der " +
                        "Spiegelachse heranzuziehen. Daurch darf das ausfräsen aus dem Träger an der Dimension unter umständen nicht " +
                        "eingeschaltet werden!</font><br>Wollen Sie die Platine trotzdem aus dem Träger fräsen, überprüfen Sie die " +
                        "Abstände der Circle zum Layer Dimension!"; // englisch!?

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  = "<font color=blue>After reference package placing start the<br></font><font color=\"#004F00\">";
string PLACErefpac2  = "</font><br><font color=blue>to set the <b>USE</b>ed libraries back.</font>";
string SHOWRackFile  = "Show rack file";
string SAVE_file     = "Save Outlines file";
string REFinfo2      = "<nobr>Press button <b><font color=yellow>Zero reference</font></b> to generate a reference Package from a NC-Drill file<br>" +
                       "to place reference safety grip (circles) on PCB for exact mirroring the bottom side<br>" +
                       "of PCB on milling machine.</nobr>";

string ZeroRef        = "Zero refere&nce";
string No_reftext     = "!No reference file loaded.";

string Script_Used    = "<nobr>SCRIPT used!<br>Return the millings as WIRE to Board-Editor.<br></nobr>";

string OnlyDrillHpgl  = "<nobr>Generate only drill file.</nobr>";
string INFOtext1_on   = "<nobr>Milling top side.</nobr>";
string INFOtext16_on  = "<nobr>Milling bottom side (<font color=red>mirror</font>).</nobr>";
string INFOtext1_off  = "<nobr>Milling top side.</nobr>";
string INFOtext16_off = "<nobr>Milling bottom side (<font color=red>mirror</font>).</nobr>";
string TextInfoPlus   = "<nobr>Plus milling layer (to milling text inverting in a ploygon).</nobr><br>" +
                        "Only can use with Top or Bottom layer.";
string TOOLdiamIso    = "<nobr>Tool diameter for isolate.</nobr><br>";
string OVERlapIso     = "<nobr>Overlap isolate - blow up in percent (%).</nobr>";
string OVERlapRubOut  = "<nobr>Overlap rub-out diameter in percent %.</nobr>";
string TOOLdiamBlow   = "<nobr>Tool diameter for Blow-Up/Rub-Out<br>If value set to <b>0</b>, <b>no</b> Blow-Up (second isolate)<br>and Rub-Out (free milling) is generated.</nobr>";
string TOOLdiamRub    = "<nobr>Rub-Out is off!<br>Tool diameter for sec. isolate<br>If value set, Blow-Up (second isolate) is generated.</nobr>";
string MILLfreeYes    = "<nobr>You must set value to Blow-Up.</nobr>";
string MILLfreeNo     = "<nobr>No blow up and Rub-Out is generated while value is set to 0.</nobr>";
string INFOmirror0    = "<nobr>Layer 16 (Bottom) not mirrored.</nobr>";
string INFOmirror1    = "<nobr>Layer 16 (Bottom) is mirrored.</nobr>";

string GENdrilON      = "<nobr>Generate drill data.</nobr>";
string GENdrilOFF     = "<nobr>Drills (PAD, VIA, HOLE) are disabled.<br>";
string PADdrildiam    = "<nobr>PAD drill diameter</nobr>";
string VIAdrilldiam   = "<nobr>VIA drill diameter.</nobr>";
string HOLEdrildiam   = "<nobr>HOLE drill diameter.</nobr>";
string USErackON      = "<nobr>Use drill rack (1/10mm) see also Tool Assignment.</nobr>";
string USErackOFF     = "<nobr>Use only 3 drills (Pad, Via, Hole).</nobr>";
string DrillLabel     = "<nobr><font color=\"#004f00\">HPGL file include drills</font></nobr>";

string DIMmiltoolOFF  = "<nobr>Mill diameter for cut out.<br>Cut out <b>OFF</b>.</nobr>";
string DIMmiltoolON   = "<nobr>Mill diameter for cut out.<br>Cut out <b>ON</b>.</nobr>";
string INFOspacing    = "This value determins the minimum length of a edge where a spacer will be set.<p>" +
                        "Spacers will be set on vertical & horizontal and in HPGL-Format only.<p>" +
                        "The width of the spacer depends on the diameter of Mill Board/Dim.<br>" +
                        "The value 0 switch off this functioon.";

string INFOresolution = "<nobr>Integer digits, fractional digits.";  // 2011-02-02
string INFOdeep       = "<nobr>Drilling deep value.</nobr>";
string INFOzsafety    = "<nobr>This is the value of lift up the milling tool to change the tool.</nobr>";
string INFOzAxisUp    = "<nobr>This is the value of lift up the milling tool to move fast (safty).</nobr>";
string INFOzAxisDown  = "<nobr>This is the value of push down the milling tool in to the PCB.</nobr>";

string INFOvdrill     = "<nobr>Drilling velocity mm/s.</nobr>";
string INFOvelocity   = "<nobr>Milling velocity mm/s.</nobr>";
string INFOfastVel    = "<nobr>Move velocity (no milling) mm/s.</nobr>";
string INFOrpm        = "<nobr>Spindle rotation per minute.</nobr>";
string INFOmaxdrill   = "<nobr>The maximum used drill diamter.</nobr>";
string DIMdown        = "<nobr>The z parameter for milling Board-Dimension.</nobr>";
string PARKinfo       = "<nobr>The park position of milling tool to mirror the board.</nobr>";
string SaveInfo       = "<nobr>Menu parameter saved!<\nobr>";
string FaultDRCdist1  = "!<qt><nobr>The value for Copper/Dimension is greater than the Mill Board/&Dim diameter.<p>" +
                        "Check/change Distance Copper/Dimension in Design Rules <b>DRC</b><p>" +
                        "or accept a distance of ";

string FaultDRCdist2   = "mm to board dimension.</nobr></qt>";

string Error5          = "<nobr>The CLASS clearance is lower at milling diameter (tool #1)!<br>" +
                         "Befor milling the PCB, start the DRC (Design Rule Check)<br>" +
                         "with the milling diameter (isolate) in CLASS clearance.<br>" +
                         "<font color=\"red\">All Clearance ERROR define a not isolated wire track!</font><br></nobr>"; // 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<br>and placed this package at the<br>left bottom corner, to mark the<br>machine zero.<br>"; // 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, "<b>Bevor Sie die Fr&auml;sdatengenerierung starten, m&uuml;ssen Sie zuerst das Layout mit dem " +
                   "DRC (Design Rule Check) &uuml;berpr&uuml;fen.</b> " +
                   "Stellen Sie die Clearance der benutzten CLASS(en) um mindestens %.3f mm gr&ouml;ßer dem Fr&auml;serdurchmesser ein.<br>" +
                   "<font color=\"red\"><b>Jeder Clearance-ERROR bedeutet eine nicht isolierte Leiterbahn!</b></font><br>", Inaccurateness);

  sprintf(INFOpolyClass, "Ist ein f&uuml;llendes Polygon im Board plaziert, dann muß die Clearance der Design-Rules/Class um %.3f mm gr&ouml;ßer <br>" +
                   "als der Fr&auml;serdurchmesser sein. Damit bei Leiterbahnen die nicht im 0� 45� oder 90� Winkel also mit <br>" +
                   "beliebigen Winkel verlegt sind, eventuelle F&uuml;llprobleme wegen Rechenungenauigkeit vermieden werden.", Inaccurateness);

  SavePar          = "Parameter &sichern";
  Machine_Menu_Info = "<nobr>Ein/Ausschalten der Maschinenparamter f&uuml;r die Z-Achse.<br>Nach &Auml;ndernung des Paramter werden die aktuellen Einstellungen<br>gespeichert und das ULP neu gestartet.</nobr>";

  Z_Machine_Menu   = "Z-Achsen Menü";

  Script_Used      = "<nobr>SCRIPT-Ausgabe!<br>Die Fr&auml;sbahnen (Daten) werden als WIRE in das Board geladen.<br></nobr>";

  INFOinside       = "Info Durchbrüche";
  INFOinnerContour = "<nobr><p>Damit Durchbr&uuml;che innerhalb der Platine ebenfalls ausgefr&auml;st werden,<br>" +
                     "muß in jedem Durchbruch eine VIA mit dem SIGNAL Namen<br>" +
                     "'~_REAL_OUTLINEMILL_~' platziert werden.<br>" +
                     "Ein Durchbruch darf <font color=\"red\">kein HOLE</font> sein, daß bedeutet,bei kreisrunden <br>"
                     "Durchbr&uuml;chen muß ein CIRCLE im Layer Dimension gezeichnet werden.</nobr>"; // 2011-10-04

  DRCinfo         = "<qt><b>Distance info:</b><p>" +                                                      // geändert 2010-08-04
                    "Distance Copper/Dimension (siehe auch <b>DRC</b>) das ist die Distanz <br>" +        // der Wert wird jetz aus den Design-Reglen gelesen,
                    "zwischen dem Polygon (Kupfer) und der Kontur (Layer 20 Dimension) des Board.<p>"+    // daher wird der Hinweiß nicht merh beötigt.
                    "<font color=\"red\"><nobr>" +
                    "<b>Dieser Wert wird aus den Design-Rules gelesen!</b></nobr><br>" +
                    "Benutzen Sie nicht den Wert <b>0</b> f&uuml;r <b>Copper/Dimension</b> <br>" +
                    "in den Design-Rules - Distance.<br></font>" +
                    "</qt>";

  InfoREFERENCE  = "<nobr>Generiert ein spezielles Package mit Referenzkreisen (Circle) im Layer 45 Holes.<br>" +
                   "Platzieren Sie das Package im Layout f&uuml;r fr&auml;sen und spiegeln (Bottom Seite) <br>" +
                   "mit Offset und starten das ULP erneut.<br>" +
                   "Als Dateneingabe f&uuml;r die Koordinaten dieser Kreise kann das NC-Drill-File <br>" +
                   "von der NC-Maschine (Excellon) benutzt werden.<br>" +
                   "Es kann auch jedes Package mit der Bezeichnung &nbsp;&nbsp;<i>" + Ref_pac + " </i><br>" +
                   "als Referenz f&uuml;r den Maschinennullpunkt und die Spiegellinie benutzt werden." +
                   "</nobr><p>" +
                   "<font color=\"red\">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.</font>" +
                   ""; // 2011-02-09

  REFinfo2       = "<nobr>Klicken Sie auf <b><font color=yellow>Masch. Nullpunkt</font></b> zum generieren " +
                   "eines Referenzpackage aus<br>" +
                   "NC-Drill Daten um Referenzfangzapfen (Circle) im Board zu platzieren f&uuml;r <br>" +
                   "die exakte Berechnung der Fr&auml;sdaten bezogen auf den Nullpunkt der<br>" +
                   "NC-Anlage und f&uuml;r die Spiegelung der Unterseite.</nobr>";

  InfoREFPack    = "<font color=\"red\">Es ist ein Referenzpackage platziert, um die Fangzapfen der Fräsmaschine zur berechnung der " +
                   "Spiegelachse heranzuziehen. Daurch darf das ausfräsen aus dem Träger an der Dimension unter umständen nicht " +
                   "eingeschaltet werden!</font><br>Wollen Sie die Platine trotzdem aus dem Träger fräsen, überprüfen Sie die " +
                   "Abstände der Circle zum Layer Dimension!";

  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&auml;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   = "<nobr><font color=blue>Starten Sie nach der Platzierung des Referenzpackage das Script</font><br><font color=\"#004F00\">";
  PLACErefpac2   = "</font><br><font color=blue>um die erzeugte LBR aus der <b>USE</b>-Liste zu l&ouml;schen.</font>";

  SHOWRackFile   = "Bohrer definition";
  SAVE_file      = "Outline Datei sichern";

  DrillLabel     = "<nobr><font color=\"#004f00\">Drills in HPGL Datei enthalten</font></nobr>";

  OnlyDrillHpgl  = "<nobr>Nur Bohrdaten erzeugen!.</nobr>";

  INFOtext1_on   = "<nobr>Top Layer (Oberseite) wird gefr&auml;st.</nobr>";
  INFOtext16_on  = "<nobr>Bottom Layer (Unterseite) wird gefr&auml;st (<font color=red>gespiegelt</font>) </nobr>";
  INFOtext1_off  = "<nobr>Top Layer (Oberseite) AUS.</nobr>";
  INFOtext16_off = "<nobr>Bottom Layer (Unterseite) AUS.</nobr>";
  TextInfoPlus   = "<nobr>Zus&auml;tzlicher Layer zum fr&auml;sen von Texten f&uuml;r Frontplatten.<br>" +
                   "(bzw. Texte in einem Polygon invertiert zu fr&auml;sen.)</nobr>" +
                   "Kann nur in Verbindung mit einem Top- oder Bottom-Layer benutzt werden.";

  TOOLdiamIso    = "<nobr>Werkzeugdurchmesser zum Isolationsfr&auml;sen.</nobr><br>";
  OVERlapIso     = "<nobr>&Uuml;berlappung von 1. Isolation zu 2. Isolation/Freifr&auml;sung in Prozent (%).</nobr>";
  OVERlapRubOut  = "<nobr>&Uuml;berlappung innerhalb der Freifr&auml;sung in Prozent %.</nobr>";
  TOOLdiamBlow   = "<nobr>Werkzeugdurchmesser f&uuml;r erweiterte Isolation und Freifr&auml;sung.<br>" +
                   "Wird der Wert auf <b>0</b> gesetzt wird <b>keine</b> erweiterte Isolation<br>" +
                   "und Freifr&auml;sung generiert.</nobr>";

  TOOLdiamRub    = "<nobr>Freifr&auml;sung (Rub-Out) ist ausgeschaltet!<br>" +
                   "Es werden nur die Fr&auml;swege f&uuml;r eine 2. Isoilation generiert.</nobr><br>" +
                   "Wird der Wert auf <b>0</b> gesetzt wird <b>keine</b> erweiterte Isolation<br>" +
                   "und Freifr&auml;sung generiert.";

  MILLfreeYes    = "<nobr>Es muß ein Wert in Blow-Up (Freifr&auml;sung) gesetzt sein.</nobr>";
  MILLfreeNo     = "<nobr>Es wird kein 2. Isolationsfr&auml;sen plus Freifr&auml;sen generiert,<br>da der Wert auf 0 gesetzt ist.</nobr>";
  INFOmirror0    = "<nobr>Layer 16 (Bottom) wird <b>NICHT</b> gespiegelt.</nobr>";
  INFOmirror1    = "<nobr>Layer 16 (Bottom) wird <b>gespiegelt</b>.</nobr>";

  GENdrilON      = "<nobr>Bohrdaten generierung <b>aktiv</b>.</nobr>";
  GENdrilOFF     = "<nobr>Bohrdaten generierung (PAD, VIA, HOLE) <b>ausgeschaltet</b>.<br>";

  PADdrildiam    = "<nobr>PAD Bohrdurchmesser.<p>" +
                   "Wenn kein Rack benutzt wird, dann werden alle PADs<br>" +
                   "mit diesem Durchmesser gebohrt.<br>" +
                   "Wenn <b>[] Use Rack</b> aktiviert ist, dann werden die PADs<br>" +
                   "in 1/10 mm Abstufung gebohrt.<br>Siehe Tool Assignment.</nobr>";

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

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

  USErackON      = "<nobr>Benutze Bohrertabelle (1/10mm), siehe auch Tool Assignment.<br>" +
                   "Die Bohrungen werden auf 1/10 mm gerundet gebohrt.</nobr>";
  USErackOFF     = "<nobr>Benutze nur 3 Bohrer f&uuml;r Pad, Via, Hole.<p>" +
                   "Alle PADs, VIAs und HOLEs werden mit den im Menu<br>" +
                   "angegeben Werten gebohrt.</nobr>";

  DIMmiltoolOFF  = "<nobr>Fr&auml;serdurchmeser zum ausfr&auml;sen aus dem Tr&auml;ger.<br>Ausfr&auml;sen <b>AUS</b>.</nobr>";
  DIMmiltoolON   = "<nobr>Fr&auml;serdurchmeser zum ausfr&auml;sen aus dem Tr&auml;ger.<br>Ausfr&auml;sen <b>EIN</b>.</nobr>";

  INFOspacing    = "<nobr>Dieser Wert definiert die Mindestkantenl&auml;nge der Platine damit <br>" +
                   "ein Haltesteg (Spacer) erzeugt wird.<br>" +
                   "Haltestege werden nur an horizontalen oder vertikalen Kanten erzeugt.<br>" +
                   "Die Breite der Stege ist abh&auml;ngig vom Durchmesser des Fr&auml;ser<br>" +
                   "(Mill Board/Dim).<br>Der Wert 0 schaltet die Funktion ab.</nobr>";

  INFOresolution = "<nobr>Aufl&ouml;sung, Vor- Nachkommastellen der Koordinaten.</nobr>";  // 2011-02-02
  INFOdeep       = "<nobr>Bohrtiefe in/durch die Platine.</nobr>";
  INFOzsafety    = "<nobr>Der Wert um den der Fr&auml;ser in der Z-Achse &uuml;ber das Werkst&uuml;ck <br>" +
                   "gefahren wird, z.B. f&uuml;r Werkzeugwechsel (Rueckzugsebene).</nobr>";

  INFOzAxisUp    = "<nobr>Der Wert um den der Fr&auml;ser in der Z-Achse &uuml;ber das Werkst&uuml;ck <br>" +
                   "gefahren wird, f&uuml;r Schnellvorschub (Sicherheitsabstand).</nobr>";

  INFOzAxisDown  = "<nobr>Die Fr&auml;stiefe der Z-Achse.</nobr>";

  INFOvdrill     = "<nobr>Bohrgeschwindigkeit mm/s.</nobr>";
  INFOvelocity   = "<nobr>Fr&auml;sgeschwindgkeit mm/sec.</nobr>";
  INFOfastVel    = "<nobr>Schnellvorschub (Geschwindigkeit) mm/s</nobr>";
  INFOrpm        = "<nobr>Spindlumdrehungen pro Minute</nobr>";
  INFOmaxdrill   = "<nobr>Der maximal nutzbare Bohrerdurchmesser.<br>" +
                   "Gr&ouml;ssere Bohrungen werden gefr&auml;st!<br>" +
                   "Siehe auch Tool Assignment.</nobr>";

  DIMdown        = "<nobr>Z-Parameter f&uuml;r ausfr&auml;sen der Boardkontur.</nobr>";
  PARKinfo       = "<nobr>Die Parkposition des Fr&auml;skopf zum umdrehen der Leiterplatte.</nobr>";

  SaveInfo       = "<nobr>Einstellungen gespeichert!<\nobr>";

  FaultDRCdist1  = "!<qt><nobr>Der Wert von Copper/Dimension ist gr&ouml;ßer als der Radius von Mill Board/Dim.<br>" +
                   "&Uuml;berpr&uuml;fen Sie den Wert von Distance Copper/Dimension in den Design Rules (<b>DRC</b>)<br>" +
                   "oder akzeptieren Sie die Distanz von <b>";
  FaultDRCdist2  = " mm zur Boardaussenkannte</b>.</nobr></qt>";

  PlaceVIA       = "platziere VIA";

  Error5         = "<nobr>Die CLASS-Clearance ist kleiner als der F&auml;serdurchmesser von Tool #1!<br>" +
                   "Dadurch kann nicht alles isoliert (gefr&auml;st) werden.<br>" +
                   "Stellen Sie die CLASS-Clearance auf den Fr&auml;serdurchmesser und starten Sie den DRC.<br>" +
                   "<font color=\"red\"><b>Jeder Clearance-Error bedeutet eine nicht isolierte Leiterbahn!</b></font></nobr>";

 sprintf(INFOInaccurat, "Wegen Rechenungenauigkeiten muß f&uuml;r Fr&auml;swege zwischen den Leiterbahnen und " +  // 2006-02-15
                   "einem evtl. vorhandenem F&uuml;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&auml;swegen kommen kann. Also die gefr&auml;ste Isolation nicht " +
                   "komplett geschlossen ist. ",
                   Inaccurateness);

 Mill_mInner_contour = "Auch Innenkonturen fr&auml;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&auml;st wird.<br>" +
                       "Die Ursache ist, daß sich eine Kontur an den Leiterbahnzug anlegt, und eine entgegengesetzt " +
                       "verlaufende Kontur an die berechnete Kontur des (Masse) Polygon.<br>" +
                       "Soll ein evtl. zweifaches Freifr&auml;sen wegen diesem Umstand verhindert werden, so schalten " +
                       "Sie die Option<br><b>Milling [] inner contour</b><br>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  = "<nobr>Erzeugt ein Package mit zwei Kreisen und platziert <br>es an der linken untere Ecke des Board als <br>Manschinen-Nullpunkt.</nobr>"; // 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 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, "~2~.plt");
  }
  return s;
}

// wait in seconds
void wait(int sec) {
  int t = time();
  while(t+sec > time() );
  return;
}

void Warning(string Message, string Details) {
  dlgMessageBox("<b>Warning:&nbsp;" + Message + "</b> " + Details, "OK");
  return;
}

void Fatal(string Message, string Details) {
  dlgMessageBox("<b>ERROR: " + Message + "</b><hr><p>\n" + Details);
  exit(1);
}

int Error(string Message, string Details, string butt_ok, string butt_esc) {
  if (butt_esc) return dlgMessageBox("!<b>ERROR: " + Message + "</b><p>" + Details, butt_ok, butt_esc);
  return dlgMessageBox("!<b>ERROR: " + Message + "</b><p>" + 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, "<nobr>%s</nobr><p>Layer-Setup = %s, muss <b>(1*16)</b> sein.<p>Soll das Layer-Setup ge&auml;ndert werden?<br>",
                        drufile, LayerStack);
          }
          else {
            sprintf(h, "<nobr>%s</nobr><p>Layer Setup = %d, must be </b>(1*16)</b>.<p>Change layer setup now?<br>",
                        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:<br>" +
                 drufile +
                 "<p>M&ouml;chten Sie diese Datei jetzt erzeugen und speichern?<br>";

    else
      message = "No Design Rules file found:<br>" +
                drufile +
                "<p>Do you want to create and save this file now?<br>";

    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:<br>"+
                               "Durchmesser Tool #1 = %.8f mm plus Rechenungenauigkeit = %.3f<br>"+
                               "<nobr>Setze Class Clearance auf <i>%.8f</i> mm oder Fr&auml;serdurchmesser &lt;= kleinster CLASS Clearance - %.3f.</nobr><p>" +
                               "Starten Sie anschließend den DRC und &uuml;berpr&uuml;fen Sie die Abst&auml;nde.",
                          MillToolOutl, Inaccurateness,
                          MillToolOutl + Inaccurateness,
                          Inaccurateness
             );
      sprintf(drc_clearance_wire_wire, "Prüfen Sie auch im <b>DRC</b> Clearance Wire/Wire: %.8f, oder ändern Sie die CLASS(en).", minDistWireWire); // 2011-03-10
    }
    else {
      sprintf(Clearance_check, "Set Clearance of Net Classes:<br>"+
                               "Diameter of tool #1 = %.8f mm plus Inaccurateness = %.8f<br>"+
                               "<nobr>Set Clearance to %.8f mm or use a milling tool &lt;= lowest clearance value - %.3f.</nobr><p>" +
                               "Be sure to start the DRC to have the clearances checked then.",
                          MillToolOutl, Inaccurateness,
                          MillToolOutl + Inaccurateness,
                          Inaccurateness
             );
      sprintf(drc_clearance_wire_wire, "Please sheck also <b>DRC</b> 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(-1347);
  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(-1484);
      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, "#2395 Use rack?\nDrill %.1f > Max. Drill %.1f Tool %d", drilldiam, Max_Drill_Diameter, get_tool(drilldiam));
                             if (dlgMessageBox(dtool, "OK", "Abort milling") != 0) exit(-2393);
                             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#2546 CHANGE DRILL %.2f;# PAD\n", DrillPad); // 2013-02-19
                             break;

        case ViaDrill:
                             printf("\n#2550 CHANGE DRILL %.2f; # VIA\n", DrillVia); // 2013-02-19
                             break;

        case HoleDrill:
                             printf("\n#2554 CHANGE DRILL %.2f; # HOLE\n", DrillHole); // 2013-02-19
                             break;

        case Contour:
                             printf("#2558 DeviceReinit case Contour:\n");
                             printf("ChANGE LAYER %d;\n", Layer + 100);
                             printf("CHANGE wIDTH %.8f;\n", MillToolOutl);
                             break;

        case BlowUp_RubOut:
                             printf("#2564 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("#2571 BlowUp_RubOut or drills\n");           // 2011-10-20
                             printf("\nCHANGE WiDTH %.8f;\nWIRe\n",  MillToolFree);// 2010-10-14
                             break;

        case DimensionLine:
                             printf("\n#2576 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#2589 swap/mirror PCB for other side\n");
                             break;

        case nrMaxDrillDiameter:
                             printf("\n#2593 drill are milling\n");
                             break;
        default:
                             printf("#2596 CHANGE DRILL %.2f;\n", Drill_tools[tool_pass] );
                             break;
      }
      break;

    case devHPGL:     // *** HPGL ***
                      printf("\nSP%d;\nPU;", tool_pass);   // pen select // \n#2602 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(-2759); }
        if (initCode != nrMaxDrillDiameter) {
          initCode = Tcode;
          if (test2) printf("#2776");
          DeviceReInit(Tcode, 45, "2777");  // the Hole layer
        }
      }
    }
    if (Tcode == nrMaxDrillDiameter) { // T-Code 9 ist fräsen

      switch (SelectedDevice) {
         case devScript: if (s) printf("#2784 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("#2925\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("#3017 *** Drills bohren\n");
      switch (SelectedDevice) {
        case devScript:
                        scriptHeader();
                        if (Generatedrills) {
                            DeviceInit(PadDrill, 44);         // 2013-02-19 , OutlineMillSignalLayer);
                            output_drills("#3023 Script-Drills");
                        }
                        break;

        case devHPGL:
                        if (Generatedrills) {
                          DeviceInit(PadDrill, 44);           // 2004-10-05 , OutlineMillSignalLayer);
                          output_drills("#3030 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#3052 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(-3101);

  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 = "<p>";
  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#3346");
        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(-3387);
      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("#3443 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("#3466 Fehler in polycoord1() string:"+polcoord, "OK");
    exit(-3407);
  }
  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#3499 jetzt holes bohren");
              WriteHoles(OutlineMillSignalLayer); // zuerst bohren!
              DeviceReInit(DimensionLine, Layer, "3487"); if (test2) printf("\n#3501 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#3561 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("<nobr><b>No device selected!</b><br>");
                        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 = "<nobr>Erzeugt Fr&auml;swege als Eagle-SCRIPT <br>und liest das Script in das Board ein.<br>" +
                                   "Der Ziel-Layer ist der Layer 101 bzw. 116 f&uuml;r die Isolation.</nobr><br>" +
                                   "Layer 102 / 117 f&uuml;r das Freifr&auml;sen (Pouring).<br>" +
                                   "Layer 103 / 118 f&uuml;r die Aussenkontur (Dimension).<br>" +
                                   "Layer 144 f&uuml;r die Drills (PAD/VIA).<br>"
                                   "Layer 145 f&uuml;r die Holes."; // 2013-02-27
                      }
                      else {
                        Infotext = "<nobr>Generate the milling tracks in to a Eagle SCRIPT <br>"
                                   "and read this script in to the Board.<br>" +
                                   "The target layer is the layer 101 respectively 116.</nobr><br>" +
                                   "Layer 102 / 117 to read copper pouring milling.<br>" +
                                   "Layer 103 / 118 to read real outlines milling (Dimension).<br>"
                                   "Layer 144 to read drills (PAD/VIA).<br>"
                                   "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 = "<font color=\"red\"><b>Not used for SCRIPT</b></font>";
                      break;

    case devHPGL   :  info = Showpic[14];
                      if (language() == "de") {
                        Infotext   = "<nobr>Generiert die Daten (Fr&auml;swege) als HPGL Datei.<br>" +
                                     "PEN #8 ist reserviert zum wechseln der Platine <br>" +
                                     "Vorder - R&uuml;ckseite (spiegeln).</nobr>";
                        DrillLabel = "<nobr><font color=\"#004f00\">Drills in HPGL Datei enthalten</font>";
                      }
                      else {
                        Infotext   = "<nobr>Generate the milling tracks as HPGL file.<br>" +
                                     "PEN #8 is reserved for switch pcb to milling second side.</nobr>";
                        DrillLabel = "<nobr><font color=\"#004f00\">HPGL file include drills</font></nobr>";
                      }
                      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 = "<font color=\"red\"><b>Not used for HPGL</b></font>";
                      break;

    case devISEL   :  info = Showpic[23];
                      if (language() == "de") {
                        Infotext   = "<nobr>Generiert die Daten (Fr&auml;swege) als ISEL Zwischenformat.</nobr>";
                        DrillLabel = "<nobr><font color=\"#004f00\">Drills in ISEL Datei enthalten</font></nobr>";
                      }
                      else {
                        Infotext   = "<nobr>Generate the milling tracks as ISEL intermediate format file.</nobr>";
                        DrillLabel = "<nobr><font color=\"#004f00\">ISEL file include drils</font></nobr>";
                      }
                      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 = "<font color=\"#004f00\"><b>Use for ISEL</b></font>";
                      break;

    case devCNC    :  info = Showpic[24];
                      if (language() == "de") {
                        Infotext    = "<nobr>Generiert die Daten (Fr&auml;swege) als CNC Datei.</nobr>";
                        DrillLabel  = "<nobr><font color=\"#004f00\">Drills in CNC Datei enthalten</font></nobr>";
                      }
                      else {
                        Infotext    = "<nobr>Generate the milling tracks as CNC file.</nobr>";
                        DrillLabel  = "<nobr><font color=\"#004f00\">CNC file include drills</font></nobr>";
                      }
                      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 = "<font color=\"#004f00\"><b>Use for CNC</b></font>";
                      break;

    default        :  info = Showpic[21];
                      Infotext = "<nobr><br><b>No device selected!</b></nobr>";
                      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&auml;lt mehr als 2 Kreise im Layer 45,<br>" +
                              "die Fr&auml;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 + "<p>" + INFOtext16_on;
  }
  else if (!SelectedLayer1 && !SelectedLayer16) {
    info = "<img src=\"mill-outlines-question.bmp\">";
    Infotext = "Kein Layer gew&auml;hlt!";
  }
  else if (SelectedLayer1 && !SelectedLayer16) {
    Infotext = INFOtext1_on + "<p>" + INFOtext16_off;
  }
  else if (!SelectedLayer1 && SelectedLayer16) {
    Infotext = INFOtext1_off + "<p>" + 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(-4051);
    }
  }
}


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&uuml;r das Isolieren (tool #1): " + argv[2], "Der <i>Durchmesser</i> gr&ouml;sser als 0 sein.");
        }
        else {
          Fatal("Illegal diameter for milling tool #1: " + argv[2], "The <i>diameter</i> 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(-4120);
      }

      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 <i>layer(s) </i> 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&uuml;r Pad: " + argv[10], "Der <i>diameter</i> muß gr&ouml;ßer als  0 sein.");
          }
          else {
            Fatal("Illegal diameter for Pad drill tool: " + argv[10], "The <i>diameter</i> must be greater than zero.");
          }
        }
        if (DrillVia <= 0) {
          if (language() == "de") {
            Fatal("Verbotener Bohrdurchmasser f&uuml;r Via: " + argv[11], "Der <i>diameter</i> muß gr&ouml;ßer als  0 sein.");
          }
          else {
            Fatal("Illegal diameter for Via drill tool: " + argv[11], "The <i>diameter</i> must be greater than zero.");
          }
        }
        if (DrillHole <= 0) {
          if (language() == "de") {
            Fatal("Verbotener Bohrdurchmasser f&uuml;r Hole: " + argv[12], "Der <i>diameter</i> muß gr&ouml;ßer als  0 sein.");
          }
          else {
            Fatal("Illegal diameter for Hole drill tool: " + argv[12], "The <i>diameter</i> 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&auml;hlt: " + Device, "W&auml;hlen Sie ein g&uuml;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("<nobr>Es existiert ein Signal " + ReservedOutlineSignalName + " in dem Board!</nobr>",
                    "<nobr>Dieser Signalname ist f&uuml;r das ULP reserviert!<br>Stellen Sie sicher das kein Signal mit diesem Namen im Layout benutzt wird.</nobr>",
                    "OK", "Delete") != 0) exit(del_pol);
          exit(-4233);
        }
        else {
          Fatal("<nobr>There is already a signal named " + ReservedOutlineSignalName + " in this board!</nobr>", "<nobr>Please make sure that there is no such signal in this board.</nobr>");
        }
      }

      // *** 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&uuml;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&uuml;r Distance Copper/Dimension<br>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, "<nobr>" + Clearance_check + "</nobr>", "Change &Tool #1", DRCCHECK);  // [Change &Tool #1]  2012-01-20
        if (fault) exit("CLASS");
      }

      Showpic[0]  = "<img src=\"mill-outlines-eagle.bmp\">";
      Showpic[1]  = "<img src=\"mill-outlines-free.bmp\">";
      Showpic[2]  = "<img src=\"mill-outlines-ovrlpfp.bmp\">";
      Showpic[3]  = "<img src=\"mill-outlines-pour.bmp\">";
      Showpic[4]  = "<img src=\"mill-outlines-ovrlppp.bmp\">";
      Showpic[5]  = "<img src=\"mill-outlines-drill.bmp\">";
      Showpic[6]  = "<img src=\"mill-outlines-via.bmp\">";
      Showpic[7]  = "<img src=\"mill-outlines-hole.bmp\">";
      Showpic[8]  = "<img src=\"mill-outlines-top.bmp\">";
      Showpic[9]  = "<img src=\"mill-outlines-bott.bmp\">";
      Showpic[10] = "<img src=\"mill-outlines-coppdim.bmp\">";
      Showpic[11] = "<img src=\"mill-outlines-nomir.bmp\">";
      Showpic[12] = "<img src=\"mill-outlines-mirror.bmp\">";
      Showpic[13] = "<img src=\"mill-outlines-script.bmp\">";
      Showpic[14] = "<img src=\"mill-outlines-hpgl.bmp\">";
      Showpic[15] = "<img src=\"mill-outlines-spacing.bmp\">";
      Showpic[16] = "<img src=\"mill-outlines-mildimension.bmp\">";
      Showpic[17] = "<img src=\"mill-outlines-null_reference.bmp\">";
      Showpic[18] = "<img src=\"mill-outlines-isol-pour.bmp\">";
      Showpic[19] = "<img src=\"mill-outlines-sec-isol.bmp\">";
      Showpic[20] = "<img src=\"mill-outlines-sec-isolate.bmp\">";
      Showpic[21] = "<img src=\"mill-outlines-question.bmp\">";
      Showpic[22] = "<img src=\"mill-outlines-inside-milling.bmp\">";
      Showpic[23] = "<img src=\"mill-outlines-isel.bmp\">";
      Showpic[24] = "<img src=\"mill-outlines-cnc.bmp\">";
      Showpic[25] = "<img src=\"mill-outlines-cnc-safety.bmp\">";
      Showpic[26] = "<img src=\"mill-outlines-cnc-drill-down.bmp\">";
      Showpic[27] = "<img src=\"mill-outlines-cnc-up.bmp\">";
      Showpic[28] = "<img src=\"mill-outlines-cnc-down.bmp\">";
      Showpic[29] = "<img src=\"mill-outlines-cnc-velocity.bmp\">";
      Showpic[30] = "<img src=\"mill-outlines-cnc-fastvelocity.bmp\">";
      Showpic[31] = "<img src=\"mill-outlines-cnc-rpm.bmp\">";
      Showpic[32] = "<img src=\"mill-outlines-drill-velocity.bmp\">";
      Showpic[33] = "<img src=\"mill-outlines-get_board_zero.bmp\">";           // 2011-02-07 Nullpunkt des Board = Maschinennullpunkt
      Showpic[34] = "<img src=\"mill-outlines-cnc-dim-down.bmp\">";
      Showpic[35] = "<img src=\"mill-outlines-cnc-parkposition.bmp\">";
      Showpic[36] = "<img src=\"mill-outlines-inner-polygon-contour.bmp\">";    // 2010-01-25 inner/outer polygon contour
      Showpic[37] = "<img src=\"mill-outlines-inner-polygon-contour1.bmp\">";
      Showpic[38] = "<img src=\"mill-outlines-resolution.bmp\">";               // 2011-02-02 Auflösung Vor- Nachkommastellen
      Showpic[39] = "<img src=\"mill-outlines-null_reference-drilling.bmp\">";  // 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+"<p>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 = "<img src=\"mill-outlines-mirror-nc-bottom.bmp\">";
                                   layer_info();
                                 }
                                 dlgStretch(1);
                }

                dlgCell( 1, 3) dlgHBoxLayout {
                                 dlgLabel("plus Layer");
                                 dlgComboBox(plus_Text, SelectedPlusLayerTop) {
                                   info = "<img src=\"mill-outlines-plus-text.bmp\">";
                                   Infotext = TextInfoPlus;
                                 }
                                 dlgStretch(1);
                }

                dlgCell( 2, 0) dlgHBoxLayout {
                                 dlgCheckBox("&Mirror ", Mirror_On) {
                                   if (Mirror_On) info = "<img src=\"mill-outlines-mirror-nc-bottom.bmp\">";
                                   else           info = "<img src=\"mill-outlines-mirror-nc-top.bmp\">";
                                   mirror_info();
                                 }
                                 dlgStretch(1);
                }

                dlgCell( 2, 1) dlgHBoxLayout {
                                 dlgLabel("Layer ");
                                 dlgCheckBox("Bottom ", SelectedLayer16) {
                                   info = "<img src=\"mill-outlines-mirror-nc-top.bmp\">";
                                   layer_info();
                                 }
                                 dlgStretch(1);
                }

                dlgCell( 2, 3) dlgHBoxLayout {
                                 dlgLabel("plus Layer");
                                 dlgComboBox(plus_Text, SelectedPlusLayerBot) {
                                   info = "<img src=\"mill-outlines-plus-text.bmp\">";
                                   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 + "<br>" + 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 = "<b><font color=\"blue\">Nur Konturfräsen aus dem Träger.!</font></b><br>" +
                                                "Option <b>Gen. drill</b> wurde abgewählt!";
                                     Holder_Spacing = 0;
                                     Generatedrills = 0;
                                     Dim_on_off = 1;
                                   }
                                   else {
                                     info = Showpic[0];
                                     Infotext = "<b><font color=\"green\">Aktivieren Sie evtl. weitere benötigte Optionen!</font></b>";
                                   }
                                 }
                }

                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("<hr>");
                      dlgCell( 5,  1) dlgLabel("<hr>");
                      dlgCell( 5,  2) dlgLabel("<hr>");
                      dlgCell( 5,  3) dlgLabel("<hr>");

                      dlgCell( 6,  0) dlgLabel("<font color=\"red\">*</font> 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("<font color=\"red\">*</font> 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("<font color=\"red\">*</font> 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("<font color=\"red\">*</font> 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("<font color=\"red\">*</font> 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("<nobr> <font color=\"red\"> * </font>currently not used.</nobr>");

                      dlgCell( 6,  5) dlgLabel("<font color=\"red\">*</font> Park pos. X ");
                      dlgCell( 6,  6) dlgRealEdit(ParkXposition);


                      dlgCell( 6,  8) dlgLabel("<font color=\"red\">*</font> 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!<br>Die Platine wird um %.8f mm ausserhalb der Dimension aus dem Tr&auml;ger gef&auml;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 <i>Isolate diameter</i> must be greater than zero.", NEXT, CANCEL);
                }

                if (!SelectedLayer1 && !SelectedLayer16) {
                  if (!MillOnlyContour) { // 2011-03-10 nur Kontur fräsen
                    fault = Error("<nobr>No layer selected!</nobr>", "<nobr>Select layer 1 or 16 or both.</nobr>", BREAK, CANCEL);
                  }
                }

                if (Clearance_check) {
                  fault = Error(Error5, "<nobr>" + Clearance_check + "</nobr>", "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("", "<nobr>Holder spacing to smal.</nobr>", "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#5193 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(-5168);

    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(-5172);
    exit(Cmd);
  }
}

/******************
*** run passes ****
*******************/
if (InPassDimensionPoly) {  // ## first run calculate the real outline ##
  if (test2) if (dlgMessageBox("#5221 1. Dimension ermitteln", "ok", "esc") != 0) exit(-5181);
  //
  // 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) { // 2008-11-12 get absolut coordiante of via
          // ** delete the temporary Via **
          cntcontvia++;
          sprintf( s, "RIPUP (%.8f %.8f);\n", u2mm(V.x), u2mm(V.y) );
          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, "<qt><b><nobr>%d Konturen im Polygon %s gefunden</nobr></b><p>" +
                      "&Uuml;berpr&uuml;fen Sie die Dimension (Layer 20). " +
                      "Das Layout besteht aus mehreren Outlines. ",
                      cntco, S.name);

          sprintf(i2, "Beispiel:<br>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.<p>" +
                      "<hr>" +
                      "<nobr>Anschliessend an diese Meldung wird nur der Layer Dimension angezeigt!</nobr><br>" +
                      "Schalten Sie entsprechende Layer wieder mit DISPLAY ein.<p>");

          dlgDialog("Contour error") { // 2010-01-20
            dlgLabel(i1);
            dlgLabel("<img src=\"mill-outlines-dimension-contours.bmp\">");
            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(-5237);
    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("#5325 2. Erste Isolation fräsen Pass2\nPolygonstart: " + TrueOutline_coordinate, "ok", "esc") != 0) exit(-5285);
  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("#5350 3. zweites mal Isolation fräsen mit breiteren Fräser und ausräumen!", "ok", "esc") != 0) exit(-5273);
  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("#5388 Breiter Fräser:\n" + s, "ok", "esc") != 0) exit(-5348);
      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(-5413);
    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("#5461 4. Aus dem Träger fräsen!", "ok", "esc") != 0) exit(-5421);
  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("#5488 4.1. Aus dem Träger fräsen!\n" + MillFileName, "ok", "esc") != 0) exit(-5446);
      // *** now milling PCB from holder outside Dimension Line *** 2006-11-07
      if  (SelectedDevice == devScript) printf("\n# milling dimension #5490\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("#5498 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("#5508\n"); WriteHoles(OutlineMillSignalLayer); }
                        break;

        case devCNC:
                        if (Generatedrills) { printf("#5512\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 = "<img src=\"mill-outlines-multi-dimension.bmp\">";
              sprintf(polerror, "<nobr><font color=\"red\"><b>ERROR:</b> %d VIA, %d positive und %d negative Konturen im Polygon </font><b>%s</b></nobr><p>" +
                                "Ü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 <b>nicht</b> Kupferlayer.<br>" +
                                "Entfernen Sie mit DELETE/RIPUP alle Elemente außerhalb der Dimension, bzw. verbinden <br>" +
                                "Sie evtl. mehrfach vorhandene Dimensionen (Konturen) miteinander.<br>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;
            exit(Cmd);
          }
        }
      }
      if (SelectedDevice == devScript) {
        printf("\n#5597 *** 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(-5587);
    sprintf(g, "GRID %s %.f;\nWIN FIT;\n", Gridunit[GridUnitdist], GridDistance);
    Cmd+=g;
    exit(Cmd);
  }
}
