#usage "<qt>nobr><b>Exports the board to HyperLynx Signal-Integrity Transfer Format (.HYP)</b><p>"
       "* HyprLynx.ULP Written by Frank Hoffman of LLOYD I/O INC<br>"
       "* Copyright (c) 1997, All Rights Reserved by LLOYD I/O INC<br>"
       "* 503/222-0702 frankh@lloydio.com www.lloydio.com"
       "<p>"
       "*  1 sided boards use layer 16<br>"
       "*  2 sided boards use layers 1 and 16<br>"
       "*  4 layer boards use layers 1,2 and 15, 16<br>"
       "*  6 layer boards use layers 1,2,3 and 14,15,16<br>"
       "*  8 layer boards use layers 1,2,3,4 and 13,14,15,16<br>"
       "* 10 layer boards use layers 1,2,3,4,5 and 12,13,14,15,16<br>"
       "* 12 layer boards use layers 1,2,3,4,5,6 and 11,12,13,14,15,16<br>"
       "* 14 layer boards use layers 1,2,3,4,5,6,7 and 10,11,12,13,14,15,16<br>"
       "* 16 layer boards use layers 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16<br>"
       "* <br>"
       "* Adapted for Eagle-Version 4.1 <br>"
       "* - Unrouted layer not exported<br>"
       "* - Export also Wire-Arcs<br>"
       "* - SMD shape Roundnes is included<br>"
       "* - PAD shape LONG OFFSET (Oblong) is included<br>"
       "* - PAD accept Top, Bottom and Inner (MDEF) layer<br>"
       "* - VIA generate only used layer in stack<br>"
       "* 02.04.2004 alf@cadsoft.de<br>"
       "* - W.curve correction in C.element.package.wires(W)<br>"
       "* 21.04.2005 alf@cadsoft.de<br>"
       "* - {PADSTACK=...%03d correct number while count from 1<br>"
       "* 17.08.2005 alf@cadsoft.de<br>"
       "* <br>";


// Version 4.11 : W.curve correction in C.element.package.wires(W) 21.04.2005
// Version 4.12 : Correct Padstack number while list from 0 (zerro) 03.05.2005
//                The original ULP counts the PADSTACK-List from 1 (+1),
//                the used Pads counts from 0 ! *** 03.05.2005
// Version 4.13 : Correct Padstack counter in for { loop } *** 11.08.2005
//                Check if a SMD-Pad dx=0 or dy=0 then aborted this ULP RUN.
// Version 4.14 : Correct Padstack counter in all function, count now from 1 to total_pad
//                eliminate correction of 4.12 from 03.05.2005

string Version    = "Version 2.00 9/11/97 -- 4.14 17/08/2005";


string headerline = "* Exports the board to HyperLynx Signal-Integrity Transfer Format (.HYP)";



//***********************************************
// Definitions of yes and no!  Do not modify!
char yes = 1;  // yes must be different from no.
char no  = 0;  // no must be zero (0)
//********************************************************************************************
//********************************************************************************************
//********************************************************************************************
// USER MODIFYABLE DATA

// Generate Files Options:
char GenerateReferenceFile = yes;    // Generate the Reference File  ('yes'/'no')
char GenerateHyperlynxFile = yes;    // Generate the Hyperlynx File  ('yes'/'no')

// Generate Component Types Options:
char UseComponentTypes = yes;        // Devices Q, T, U, IC, C, D, L, R, BD, etc. ('yes'/'no')

// Generate Component Pin Direction Options:
char GeneratePinDirection = no;      // If 'yes', slows down many many times.

// Component Value Change Options:
char TruncateComponentValues = no;   // Truncate ".1uf 50v" to ".1uf" ('yes'/'no')
char ConvertCapValues = yes;         // Convert Capacitor Values. i.e. change ".1" to ".1u" ('yes'/'no')
string ConvertLT1to   = "uF";        // values less than 1 are labeled as this unit
string ConvertGE1to   = "uF";        // convert greater than or equal to 1 are labeled as this unit

// Board Thickness AND Stack Up Options:
char UseBoardStackUp = yes;         // Use board thickness data   ('yes'/'no')
real board_thickness = 0.0625;      // Board Thickness, if 0: use fixed layer sizes else calc layer thicknesses

// Copper Value Options:
real zerooz = 0.0000;               // zero copper thickness
real halfoz = 0.0007;               // 0.5 oz copper thickness
real oneoz  = 0.0014;               // 1.0 oz copper thickness
real twooz  = 0.0028;               // 2.0 oz copper thickness
// Copper Layer Thickness for Each Layer of Copper
real copper_thickness[] = {0.0,  halfoz,halfoz,halfoz,halfoz,halfoz,halfoz,
                                 halfoz,halfoz,halfoz,halfoz,halfoz,halfoz,
                                 halfoz,halfoz,halfoz,halfoz}; // 1st number is not used (no layer 0)
// Copper Layer Plating Thickness for Each Layer of Copper.
// Top and Bottom are used most often.
real copper_plating[]  = {0.0,  halfoz,zerooz,zerooz,zerooz,zerooz,zerooz,
                                zerooz,zerooz,zerooz,zerooz,zerooz,zerooz,
                                zerooz,zerooz,zerooz,halfoz}; // 1st number is not used (no layer 0)

// Dielectric Value Options:
real dicons = 4.8;           // default dielectric constant
real dit1ly = 0.0611;        // dielectric thickness for 1 sided board
real dit2ly = 0.0597;        // dielectric thickness for 2 sided board
real ditmly = 0.0200;        // dielectric thickness for multilayered boards
real dielectric_constant[]  = {  dicons,dicons,dicons,dicons,dicons,dicons,dicons,dicons,dicons};
real dielectric_thickness[] = {  dit1ly,dit2ly,ditmly,ditmly,ditmly,ditmly,ditmly,ditmly,ditmly};

// Special Wire Width Options:
real RectOutlineWireWidth = 0.001;  // Rectangle outline wire width in inches
real HoleOutlineWireWidth = 0.001;  // Holes outline wire width in inches

// Precision of board components to accurately draw and locate.
//  (After the decimal '.' point.)
int precision_of_perimeter = 4;     // board perimeter dimension precision
int precision_of_layers = 5;        // layer thickness precision
int precision_of_pads = 3;          // pad/smd size precision
int precision_of_nets = 4;          // pin/via/segment/width precision


//********************************************************************************************
//********************************************************************************************
//********************************************************************************************
// DO NOT MODIFY ANYTHING BELOW THIS LINE //

int index[];                // sorting index array (indirect)

// pad info
int ISAPAD = 0;                   // through hole pad
int ISASMD = 1;                   // surface mount device pad
int ISAVIA = 18;                  //

// *** HyperLynx pad shapes ***
int OVALROUND  = 0;  // '0' means oval or round (pad_sx=pad_sy if round)
int RECTSQUARE = 1;  // '1' means rectangular or square (pad_sx=pad_sy if square)
int OBLONG     = 2;  // '2' means oblong (oblong shape is a rectangular with rounded corners)

string PadShapes[];               // list of hyp's pad shapes
string HypPadShapes[];            // list of hyp's pad shapes
string EaglePadShapes[];          // list of eagle pad shapes
int    Total_Pads = 0;            // total pads
int    pad_type[];                // pad types (ISAPAD,ISASMD)
int    pad_layer[];               // 0 = Pad, 1 or 16 = SMD, 18 = Via
int    pad_shape_Top_rnds[];      // hyperlynx type OVALROUND, RECTSQUARE, OBLONG
int    pad_shape_Inner[];         // hyperlynx type OVALROUND, RECTSQUARE, OBLONG
int    pad_shape_Bott[];          // hyperlynx type OVALROUND, RECTSQUARE, OBLONG
real   pad_angle_end[];           // Pad rotation or Via End layer (Vias can not rotate!)
int    pad_diameter_Top_or_dx[];
int    pad_diameter_Inner[];
int    pad_diameter_Bott[];
int    pad_dy_elong_start[]; // SMD-dy, Pad-Elongation, Via Stack-Start
int    pad_drill[];

string padStackList = "#\ttype\tlayer\tTop_rnd\tInner\tBott\tang_end\tdx_T\tdx_I\tdx_B\tdy_el\tdril\n";




// copper layer info
string LayerNames[];        // layer names
int copp_lookup[]     = {0, 1,16, 2,15, 3,14, 4,13, 5,12, 6,11, 7,10, 8,9 };
int copp_used_layer[];
int Total_Layers;           // total number of used layers
int layer_counter;          // layer counter
real Total_Board_Thickness; // calculated total board thickness

/* -----  Eagle HELP --------------------------------
PAD_SHAPE_SQUARE       square
PAD_SHAPE_ROUND        round
PAD_SHAPE_OCTAGON      octagon
PAD_SHAPE_LONG         long
PAD_SHAPE_OFFSET       offset
PAD_SHAPE_ANNULUS      annulus (only in Supply-Layer)
PAD_SHAPE_THERMAL      thermal (only in Supply-Layer)
-------------------------------------------------- */

// define the HyperLynx Pad Shapes
PadShapes[ PAD_SHAPE_SQUARE ]       = "1";       // hyp's square and rectangle shape
HypPadShapes[ PAD_SHAPE_SQUARE ]    = "Square";  // HyperLynx's square and rectangle shape
EaglePadShapes[ PAD_SHAPE_SQUARE ]  = "Square";  // Eagle's square and rectangle shape
PadShapes[ PAD_SHAPE_ROUND ]        = "0";       // hyp's round and oval shape
HypPadShapes[ PAD_SHAPE_ROUND ]     = "Round";   // HyperLynx's round and oval shape
EaglePadShapes[ PAD_SHAPE_ROUND ]   = "Round";   // Eagle's round and oval shape
PadShapes[ PAD_SHAPE_OCTAGON ]      = "0";       // hyp's octagon is a round shape
HypPadShapes[ PAD_SHAPE_OCTAGON ]   = "Round";   // HyperLynx's octagon is a round shape
EaglePadShapes[ PAD_SHAPE_OCTAGON ] = "Octagon"; // Eagle's octagon is a round shape
PadShapes[ PAD_SHAPE_LONG ]         = "2";       // hyp's oblong, rectangle with rounded corners
HypPadShapes[ PAD_SHAPE_LONG ]      = "Oblong";  // HyperLynx's oblong, rectangle with rounded corners
EaglePadShapes[ PAD_SHAPE_LONG ]    = "Long";    // Eagle's oblong, rectangle with rounded corners
PadShapes[ PAD_SHAPE_OFFSET ]       = "0";       // hyp's round and oval shape
HypPadShapes[ PAD_SHAPE_OFFSET ]    = "Round";   // HyperLynx's oblong, rectangle with rounded corners
EaglePadShapes[ PAD_SHAPE_OFFSET ]  = "Offset";  // Eagle's (Long) Offset, rectangle with rounded corners



// ***************************************************************************
// layers

// This routine counts visible layers and stores the name in an internal table
// Layer names beginning with '$' have the leading '$' striped.
// This routine is called from a loop
void CountLayers(UL_LAYER L) {
  if ( ( L.number >= 1 ) && ( L.number <= 16  ) ) {
    if ( strchr( L.name, '$' ) == 0 ) {
      LayerNames[L.number] = strsub( L.name, 1 );
    }
    else {
      LayerNames[L.number] = L.name;
    }
    if (L.visible) {
      layer_counter++;
      if (L.used) copp_used_layer[L.number] = 1;
    }
  }
}

// This routine writes out the layer names as signal layers or power planes
// It also writes out the dielectric layer info when needed
// This routine is called from a loop
string layernam; // layer name buffer
void PrintLayer(UL_LAYER L) {
  real diele_thickness;   // calculated dielectric thickness
  real copp_thickness;    // calculated total copper thickness
  int i;                  // loop counter
  if (L.visible) {
    if ( L.number >= 1 && L.number <= 16 ) {
      if ( strchr( L.name, '$' ) == 0 ) { // ** is it a Power plane?
        layernam = strsub( L.name, 1 );
        printf("(PLANE T=%6.*f L=%s)\n",
        precision_of_layers, copper_thickness[L.number], layernam);
      }
      else {
        printf("(SIGNAL T=%6.*f P=%6.*f L=%s)\n",
                 precision_of_layers, copper_thickness[L.number],
                 precision_of_layers, copper_plating[L.number],
                 L.name);
      }
      layer_counter++;
      if (board_thickness) {
        Total_Board_Thickness = board_thickness;
        copp_thickness = 0.0;
        for (int i = 1; i <= Total_Layers; i++ ) {
           copp_thickness += copper_thickness[copp_lookup[i]] + copper_plating[copp_lookup[i]];
        }
        if (Total_Layers <= 2 )  diele_thickness = ( board_thickness - copp_thickness );
        else                     diele_thickness = ( board_thickness - copp_thickness ) / ( real(Total_Layers) - 1.00 );
      }
      else {
        diele_thickness = dielectric_thickness[Total_Layers/2];
        copp_thickness = 0.0;
        for (int i = 1; i <= Total_Layers; i++ ) {
          copp_thickness += copper_thickness[copp_lookup[i]] + copper_plating[copp_lookup[i]];
        }
        if (Total_Layers <= 2 ) Total_Board_Thickness = copp_thickness + diele_thickness;
        else                    Total_Board_Thickness = copp_thickness + (diele_thickness * ( real(Total_Layers) - 1.00 ));
      }
      if (layer_counter < Total_Layers) {
        printf("(DIELECTRIC T=%6.*f C=%4.*f ",
              precision_of_layers,diele_thickness,
              precision_of_layers,dielectric_constant[Total_Layers/2]);
              printf("L=DL%02d)\n",layer_counter);
      }
      if (Total_Layers == 1) {
              printf("(DIELECTRIC T=%6.*f C=%4.*f ",
              precision_of_layers,diele_thickness,
              precision_of_layers,dielectric_constant[Total_Layers/2]);
              printf("L=DL%02d)\n",layer_counter);
      }
    }
  }
}



// ***************************************************************************
// pads

int search_A_Pad( int apad_type, int apad_layer,
                  int apad_shape_Top_rnds, int apad_shape_Inner, int apad_shape_Bott,
                  real apad_angle_end,
                  int apad_dx_Top, int apad_dx_Inner, int apad_dx_Bott,
                  int apad_dy_elong_start,
                  int apad_dril ) {
  int found = 0;
  for ( int i = 1; i <= Total_Pads; i++ ) {
    if ( pad_type[i]                == apad_type &&
         pad_layer[i]               == apad_layer &&
         pad_shape_Top_rnds[i]      == apad_shape_Top_rnds &&
         pad_shape_Inner[i]         == apad_shape_Inner &&
         pad_shape_Bott[i]          == apad_shape_Bott &&
         pad_angle_end[i]           == apad_angle_end &&
         pad_diameter_Top_or_dx[i]  == apad_dx_Top &&
         pad_diameter_Inner[i]      == apad_dx_Inner &&
         pad_diameter_Bott[i]       == apad_dx_Bott &&
         pad_dy_elong_start[i]      == apad_dy_elong_start&&
         pad_drill[i]               == apad_dril )
      {
      found = i;
      break;
    }
  }
 return( found);
}

// This routine inserts a pad of known type and size into the pad table
// The returned value reflects the current number of pads in the table
// If the pad size already exists, the pad is not inserted

void Insert_A_Pad( int apad_type, int apad_layer,
                  int apad_shape_Top_rnds, int apad_shape_Inner, int apad_shape_Bott,
                  real apad_angle_end,
                  int apad_dx_Top, int apad_dx_Inner, int apad_dx_Bott,
                  int apad_dy_elong_start,
                  int apad_dril ) {

  int fnd = search_A_Pad( apad_type, apad_layer, apad_shape_Top_rnds, apad_shape_Inner, apad_shape_Bott, apad_angle_end, apad_dx_Top, apad_dx_Inner, apad_dx_Bott, apad_dy_elong_start, apad_dril);
  if (fnd == 0) {
    Total_Pads++;
    pad_type[Total_Pads]               = apad_type;
    pad_layer[Total_Pads]              = apad_layer;
    pad_shape_Top_rnds[Total_Pads]     = apad_shape_Top_rnds;
    pad_shape_Inner[Total_Pads]        = apad_shape_Inner;
    pad_shape_Bott[Total_Pads]         = apad_shape_Bott;
    pad_angle_end[Total_Pads]          = apad_angle_end;
    pad_diameter_Top_or_dx[Total_Pads] = apad_dx_Top;
    pad_diameter_Inner[Total_Pads]     = apad_dx_Inner;
    pad_diameter_Bott[Total_Pads]      = apad_dx_Bott;
    pad_dy_elong_start[Total_Pads]     = apad_dy_elong_start;
    pad_drill[Total_Pads]              = apad_dril;
  }
  return;
}

// This routine finds a pad of a known type and size and returns the ID
// of the pad (internal number) that is used to identify the pad.

int Find_A_Pad( int apad_type, int apad_layer,
                int apad_shape_Top_rnds, int apad_shape_Inner, int apad_shape_Bott,
                real apad_angle_end,
                int apad_dx_Top, int apad_dx_Inner, int apad_dx_Bott,
                int apad_dy_elong_start,
                int apad_dril ) {
  int fnd = search_A_Pad( apad_type, apad_layer, apad_shape_Top_rnds, apad_shape_Inner, apad_shape_Bott, apad_angle_end, apad_dx_Top, apad_dx_Inner, apad_dx_Bott, apad_dy_elong_start, apad_dril);
  return( fnd );
}

// This routine finds the HyperLynx shape form of eagle shape
int SmdRoundness(int r) {
  if (r == 100) return 0;   // oval or round
  if (r == 0)   return 1;   // rect or square
  return 2;                 // oblong
}


// Insert a pin on in a list of associated connected contacts
int AssPinCount = 0;  // Number of associated Contacts
string AssTabEname[];  // Element Name
string AssTabCname[];  // Contact Name
int AssTabLenEname[];  // Element Name Length
int AssTabLenCname[];  // Contact Name Length
int InsertAssocatedPin( string ename, string cname ) {
  int lenofename,lenofcname;
  lenofename = strlen(ename);
  lenofcname = strlen(cname);
  if ( AssPinCount > 0 ) {
    for ( int i = 0; i < AssPinCount; i++ ) {
      if ( lenofename == AssTabLenEname[i] )
        if ( lenofcname == AssTabLenCname[i] )
          if ( strstr( AssTabEname[i], ename ) != -1 )
            if ( strstr( AssTabCname[i], cname ) != -1 ) return( AssPinCount );
    }
  }
  AssTabEname[AssPinCount] = ename;
  AssTabCname[AssPinCount] = cname;
  AssTabLenEname[AssPinCount] = lenofename;
  AssTabLenCname[AssPinCount] = lenofcname;
  AssPinCount++;
  return( AssPinCount );
}

int FindAssocatedPin( string ename, string cname ) {
  int lenofename,lenofcname;
  lenofename = strlen(ename);
  lenofcname = strlen(cname);
  if ( AssPinCount > 0 ) {
    for ( int i = 0; i < AssPinCount; i++ ) {
      if ( lenofename == AssTabLenEname[i] )
        if ( lenofcname == AssTabLenCname[i] )
          if ( strstr( AssTabEname[i], ename ) != -1 )
            if ( strstr( AssTabCname[i], cname ) != -1 ) return( AssPinCount );
    }
  }
  return( 0 );
}

// write a divider
void printdivider( void ) {
  printf("**********************************************************************\n");
  return;
}

// write a section header with dividers
void printheader(string hs) {
  printdivider();
  printf("* %s\n*\n",hs);
  return;
}

// write translated package types from Eagle to Hyperlynx
int saypackagetype(string pn) {
  if ( strstr( pn,"TSSOP" ) != -1 ) {
    printf(" PKG=TSSOP");
  }
  else if ( strstr( pn,"TQFP" ) != -1 ) {
    printf(" PKG=TQFP");
  }
  else if ( strstr( pn,"SSOP" ) != -1 ) {
    printf(" PKG=SSOP");
  }
  else if ( strstr( pn,"PLCC" ) != -1 ) {
    printf(" PKG=PLCC");
  }
  else if ( strstr( pn,"LCC" ) != -1 ) {
    printf(" PKG=LCC");
  }
  else if ( strstr( pn,"DIP" ) != -1 ) {
    printf(" PKG=DIP");
  }
  else if ( strstr( pn,"QFP" ) != -1 ) {
    printf(" PKG=QFP");
  }
  else if ( strstr( pn,"BGA" ) != -1 ) {
    printf(" PKG=BGA");
  }
  else if ( strstr( pn,"PGA" ) != -1 ) {
    printf(" PKG=PGA");
  }
  else if ( strstr( pn,"DIL" ) != -1 ) {
    printf(" PKG=DIP");
  }
  else if ( strstr( pn,"DIP" ) != -1 ) {
    printf(" PKG=DIP");
  }
  else if ( strstr( pn,"SO" ) != -1 ) {
    printf(" PKG=SO");
  }
  else return( no );  // no package type recognized
  return( yes );      // yes, package recognized
}


// truncate trailing zeros and print value
void TruncateTrailingZeros( real value, int prec ) {
  string num;
  int nlen;
  sprintf( num, "%1.*f", prec, value );
  nlen = strlen( num );
  if ( nlen > 0 ) {
    while ( num[ nlen-1 ] == '0' ) {
      // truncate with a null
      num[ nlen-1 ] = 0;
      // recalc string length
      nlen = strlen( num );
      if ( nlen == 0 )  break;
    }
  }
  printf("%s",num);
  return;
}

// Convert Capacitor Values. i.e. change ".1" to ".1u"
// char ConvertCapValues = yes;
// Cap value conversion rules for values without suffix multipliers
// string ConvertLT1to = "u";    // values less than 1 are "u" or "something else"
// string ConvertGE1to = "u";    // convert greater than or equal to 1 as "u" or "p"
//
void ConvertCapValue( string capvalue ) {
  char cstate;    // state machine
  char clabel;    // unit label
  real cvalue;    // the value of the capacitor
  int lenofcapvalue;  // length of the string for parsing

  if ( ConvertCapValues == yes ) {
    cvalue = strtod( capvalue );
    if ( cvalue != 0.0 ) {
      lenofcapvalue = strlen( capvalue );
      cstate = 1; // set state for searching digits
      for ( int i=0; i<lenofcapvalue; i++ ) {
        clabel = capvalue[ i ];
        if ( isdigit( clabel ) || ( clabel == '.' ) ) {
          cstate = 2; // digits found
        }
        else {
          clabel = toupper( clabel );
          if ( strchr( "FMUPN", clabel ) != -1 ) cstate = 3; // multiplier found
          break;
        }
      }
      // If the value NOT labeled with a multiplier, then label it
      if ( cstate == 1 ) {
        // report error for debugging purposes
        printf("***no digits found***");
      }
      if ( cstate == 2 ) {
        if ( cvalue < 1.0 ) {
          TruncateTrailingZeros( cvalue, 6 );
          printf("%s",ConvertLT1to);
        } else {
          TruncateTrailingZeros( cvalue, 6 );
          printf("%s",ConvertGE1to);
        }
        return;
      }
      if ( cstate == 3 ) {
        if ( clabel == 'M' ) {
          TruncateTrailingZeros( cvalue, 6 );
          printf("uF");
          return;
        }
      }
    }
  }
  printf( "%s", capvalue );
  return;
}

// Search and Translate pin direction information if available and enabled
void SayUPinFunction( string Ptname, string Paname ) {
  int lofs1, lofs2;
  string ipadname;

  // check if search allowed
  if ( GeneratePinDirection == no ) return;

  // part name must begin with either IC or U
  if ( ( strstr( Ptname, "IC" ) == 0 ) || ( strstr( Ptname, "U" ) == 0 ) ) {
    if ( project.schematic ) {
      project.schematic(SCH) {
        SCH.parts(PT) {
          lofs1 = strlen( Ptname );
          lofs2 = strlen( PT.name );
          if ( lofs1 == 0 ) return;
          if ( lofs1 == lofs2 ) {
            if ( strstr( PT.name, Ptname ) == 0 ) {
              PT.instances(I) {
                I.gate.symbol.pins(PIN) {
                  if ( PIN.contact.pad ) ipadname = PIN.contact.pad.name;
                  if ( PIN.contact.smd ) ipadname = PIN.contact.smd.name;
                  lofs1 = strlen( ipadname );
                  lofs2 = strlen( Paname );
                  if ( lofs1 == 0 ) return;
                  if ( lofs1 == lofs2 ) {
                    if ( strstr( ipadname, Paname ) == 0 ) {
                      switch ( PIN.direction ) {
                          case PIN_DIRECTION_OUT:
                          case PIN_DIRECTION_OC:
                          case PIN_DIRECTION_HIZ:
                                      printf(" F=SIM_OUT");
                                      break;
                          case PIN_DIRECTION_IO:
                                      printf(" F=SIM_BOTH");
                                      break;
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  return;
}



// ***************************************************************************
// board
//
// This is the MAIN() function of this ULP

if (board) board(B) {
  if ( GenerateReferenceFile == yes ) {
    output( filesetext( B.name, ".REF" ) ) {
      printdivider();
      printf("%s\n", headerline);   // 03.05.2005 alf@cadsoft.de
      printf("* %s\n*\n", Version);
      printf("* %s\n*\n", EAGLE_SIGNATURE);
      printf("* HyperLynx Board exported from:\n");
      printf("* %s\n", B.name);
      printf("* At %s\n*\n", t2string(time()));
      if (project.schematic) {
        printf("* Schematic is loaded.\n");
      }
      else {
        printf("* Schematic NOT is loaded.\n");
      }
      printf("*\n*\n");

      // Generate the cross references
      printheader("Auto Mapped Reference File for ICs and Us");
      int unknownIC, ICstate, ICvaluelen, ICccnt;
      string ICname, ICvalue, ICpn, ICreflib;
      B.elements(E) {
        unknownIC = yes;  // set component as unknown
        ICname = E.name;  // remember component reference designator
        ICvalue = E.value;  // remember component value name (IC number)
        // parse reference designators ?
        if ( strstr( ICname, "IC" ) == 0 ) {
          if ( isdigit( ICname[2] ) )  unknownIC = no;
        }
        else if ( isdigit( ICname[1] ) ) {
          if ( strchr( ICname, 'U' ) == 0 )  unknownIC = no;
        }
        if ( unknownIC == no ) {
          unknownIC = yes;  // reset component as unknown
          if ( strstr( ICvalue, "74" ) == 0 ) {
            ICstate = 0;
            ICvaluelen = strlen( ICvalue );
            ICccnt = 0;
            for ( int i=2; i<ICvaluelen; i++ ) {
              if ( isalpha( ICvalue[i] ) ) {
                ICccnt++;
              }
            }
            unknownIC = no;
            if ( ICccnt > 0 ) {
              ICreflib = "74" + strsub( ICvalue, 2, ICccnt ) + ".PML";
            }
            else {
              ICreflib = "74TTL.PML";
            }
          } else
          if ( strstr( ICvalue, "40" ) == 0 ) {
            unknownIC = no;
            ICreflib = "74HC.PML";
            ICvalue = "74HC" + ICvalue;
          }
          if ( unknownIC == no ) {
            printf("%s, %s, %s",ICname,ICreflib,ICvalue);
            ICpn =E.package.name;
            if ( strstr( ICpn,"TSSOP" ) != -1 ) {
              printf("_TSSOP");
            }
            else if ( strstr( ICpn,"TQFP" ) != -1 ) {
              printf("_TQFP");
            }
            else if ( strstr( ICpn,"SSOP" ) != -1 ) {
              printf("_SSOP");
            }
            else if ( strstr( ICpn,"PLCC" ) != -1 ) {
              printf("_PLCC");
            }
            else if ( strstr( ICpn,"LCC" ) != -1 ) {
              printf("_LCC");
            }
            else if ( strstr( ICpn,"DIP" ) != -1 ) {
              printf("_DIP");
            }
            else if ( strstr( ICpn,"QFP" ) != -1 ) {
              printf("_QFP");
            }
            else if ( strstr( ICpn,"BGA" ) != -1 ) {
              printf("_BGA");
            }
            else if ( strstr( ICpn,"PGA" ) != -1 ) {
              printf("_PGA");
            }
            else if ( strstr( ICpn,"DIL" ) != -1 ) {
              printf("_DIP");
            }
            else if ( strstr( ICpn,"DIP" ) != -1 ) {
              printf("_DIP");
            }
            else if ( strstr( ICpn,"SO" ) != -1 ) {
              printf("_SSOP");
            }
            printf("\n");
          }
        }
      }
    }
  }

  if ( GenerateHyperlynxFile == no ) {
    exit( EXIT_SUCCESS );
  }
  output( filesetext( B.name, ".HYP" ) ) {
    printdivider();
    printf("%s\n", headerline); // 03.05.2005 alf@cadsoft.de
    printf("* %s\n*\n", Version);
    printf("* %s\n*\n", EAGLE_SIGNATURE);
    printf("* HyperLynx Board exported from:\n");
    printf("* %s\n", B.name);
    printf("* At %s\n*\n", t2string(time()));

    if (project.schematic) {
      printf("* Schematic is loaded.\n");
    }
    else {
      printf("* Schematic NOT is loaded.\n");
    }
    printf("*\n\n");
    printf("{VERSION=2.10}  Compatible with Hyperlynx version 2.10.\n");
    printf("{UNITS=ENGLISH WEIGHT}\n\n");

    // BOARD OVERALL AREA DIMENSIONS
    // Writes the board dimensions found on layer 20
    printheader("Board Dimensions");
    printf("{BOARD\n");
    // wires on the dimension layer
    B.wires(W) {
      if (W.layer == 20 ) {
        if (W.curve) {
          // arcs in the dimension layer
          printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Arcs: Board Outline Arc is CCW\n",
                  precision_of_nets,u2inch(W.arc.x1),precision_of_nets,u2inch(W.arc.y1),
                  precision_of_nets,u2inch(W.arc.x2),precision_of_nets,u2inch(W.arc.y2),
                  precision_of_nets,u2inch(W.arc.xc),precision_of_nets,u2inch(W.arc.yc),
                  precision_of_nets,u2inch(W.arc.radius) );
        }
        else {
          printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Wires: From Board\n",
                  precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1),
                  precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2));
        }
      }
    }
    // rectangles on the dimension layer
    B.rectangles(R) {
      if (R.layer == 20 ) {
        printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Bottom\n",
                precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1),
                precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1) );
        printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Right\n",
                precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1),
                precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2) );
        printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Top\n",
                precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2),
                precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2) );
        printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Board : Left\n",
                precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2),
                precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1) );
      }
    }
    // polygons on the dimension layer
    B.polygons(P) {
      if (P.layer == 20 ) {
        P.wires(W) {
          if (W.layer == 20 ) {
            printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Polygon Wires: From Board\n",
                    precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1),
                    precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2));
          }
        }
      }
    }
    // circles in the dimension layer
    B.circles(C) {
    if (C.layer == 20 ) {
       printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Circles: Board Outline Arc is CCW\n",
                precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
                precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
                precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y),
                precision_of_nets,u2inch(C.radius) );
      }
    }
    // holes in the board
    int halfdrilldiameter;
    B.holes(H) {
      halfdrilldiameter = H.drill / 2;
      printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Holes: Board Outline Arc is CCW\n",
               precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter),
               precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter),
               precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y),
               precision_of_nets,u2inch(halfdrilldiameter) );
    }
    // package wires on the dimension layer
    B.elements(E) {
      E.package.wires(W) {
        if (W.layer == 20 ) {
          if (W.curve) {
            // package arcs in the dimension layer
            printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Arcs: Board Outline Arc is CCW Package %s in %s.LBR\n",
                    precision_of_nets,u2inch(W.arc.x1),precision_of_nets,u2inch(W.arc.y1),
                    precision_of_nets,u2inch(W.arc.x2),precision_of_nets,u2inch(W.arc.y2),
                    precision_of_nets,u2inch(W.arc.xc),precision_of_nets,u2inch(W.arc.yc),
                    precision_of_nets,u2inch(W.arc.radius),
                    E.package.name,E.package.library );
          }
          else {
            printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Wires: From Package %s in %s.LBR\n",
                    precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1),
                    precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2),
                    E.package.name,E.package.library);
          }
        }
      }
      // package rectangles on the dimension layer
      E.package.rectangles(R) {
        if (R.layer == 20 ) {
          printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Bottom\n",
                  precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1),
                  precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1),
                  E.package.name,E.package.library );
          printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Right\n",
                  precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y1),
                  precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2),
                  E.package.name,E.package.library );
          printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Top\n",
                  precision_of_perimeter,u2inch(R.x2),precision_of_perimeter,u2inch(R.y2),
                  precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2),
                  E.package.name,E.package.library );
          printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Rectangles: From Package %s in %s.LBR : Left\n",
                  precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y2),
                  precision_of_perimeter,u2inch(R.x1),precision_of_perimeter,u2inch(R.y1),
                  E.package.name,E.package.library );
        }
      }
      // package polygons on the dimension layer
      E.package.polygons(P) {
        if (P.layer == 20 ) {
          P.wires(W) {
            if (W.layer == 20 ) {
               printf("(PERIMETER_SEGMENT X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f) Polygon Wires: From Package %s in %s.LBR\n",
                        precision_of_perimeter,u2inch(W.x1),precision_of_perimeter,u2inch(W.y1),
                        precision_of_perimeter,u2inch(W.x2),precision_of_perimeter,u2inch(W.y2),
                        E.package.name,E.package.library);
            }
          }
        }
      }
      // package circles in the dimension layer
      E.package.circles(C) {
       if (C.layer == 20 ) {
         printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Circles: Board Outline Arc is CCW Package %s in %s.LBR\n",
                  precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
                  precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
                  precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y),
                  precision_of_nets,u2inch(C.radius),
                  E.package.name,E.package.library );
        }
      }
      // package holes
      int halfdrilldiameter;
      E.package.holes(H) {
        halfdrilldiameter = H.drill / 2;
        printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f) Holes: Board Outline Arc is CCW Package %s in %s.LBR\n",
                 precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter),
                 precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y+halfdrilldiameter),
                 precision_of_nets,u2inch(H.x),precision_of_nets,u2inch(H.y),
                 precision_of_nets,u2inch(halfdrilldiameter),
                 E.package.name,E.package.library );
      }
    }
    printf("}\n\n");

    // LAYER INFORMATION
    printheader("Thickness of Copper and Dielectric Layer Data");
    if ( UseBoardStackUp == yes ) {
      printf("{STACKUP\n");
      layer_counter = 0;
      B.layers(L) CountLayers(L);
      Total_Layers = layer_counter; // remember active layers
      layer_counter = 0;
      B.layers(L) PrintLayer(L);
      printf("}\n");
      // TOTAL BOARD THICKNESS
      printf("* Total Board Thickness %6.4f inch\n\n",Total_Board_Thickness);
    }
    else {
      printf("* No PCB Thickness Data Generated !!! \n*\n\n");
    }

    // PACKAGES ON THE BOARD
    printheader("Components");
    printf("{DEVICES\n");
    int unknowncomponenttype, pincount, componentspace;
    string componentname;
    string componentvalue;
    B.elements(E) {
      // get the number of pins
      pincount = 0;
      E.package.contacts(C) {
        pincount++;
      }
      // set component as unknown
      unknowncomponenttype = yes;
      // remember component reference designator
      componentname = E.name;
      // truncate component values at the first space
      // ? ASK HYPERLYNX : what about something like .1u 50v
      componentvalue = E.value;
      if ( TruncateComponentValues == yes )
        if ( ( componentspace = strchr( componentvalue, ' ' ) ) != -1 )
           componentvalue = strsub( componentvalue, 0, componentspace );
      // parse reference designators ?
      if ( UseComponentTypes == yes ) {
        if ( strstr( componentname, "IC" ) == 0 ) {
          if ( isdigit( componentname[2] ) ) {
            printf("(IC REF=%s NAME=%s L=%s",componentname,componentvalue,
                     E.mirror ? LayerNames[16] : LayerNames[1] );
                     saypackagetype(E.package.name);
            unknowncomponenttype = no;
          }
        }
        else if ( strstr( componentname, "BD" ) == 0 ) {
          if ( isdigit( componentname[2] ) ) {
            printf("(BD REF=%s NAME=%s L=%s",componentname,componentvalue,
                     E.mirror ? LayerNames[16] : LayerNames[1] );
            unknowncomponenttype = no;
          }
        }
        else if ( strstr( componentname, "BEAD" ) == 0 ) {
          if ( isdigit( componentname[4] ) ) {
            printf("(BD REF=%s NAME=%s L=%s",componentname, componentvalue,
                     E.mirror ? LayerNames[16] : LayerNames[1] );
            unknowncomponenttype = no;
          }
        }
        else if ( isdigit( componentname[1] ) ) {
          if ( strchr( componentname, 'U' ) == 0 ) {
            printf("(IC REF=%s NAME=%s L=%s",componentname, componentvalue,
                     E.mirror ? LayerNames[16] : LayerNames[1] );
                     saypackagetype(E.package.name);
            unknowncomponenttype = no;
          }
          else if ( strchr( componentname, 'C' ) == 0 ) {
            printf("(C REF=%s VAL=",componentname);
            ConvertCapValue(componentvalue);
            printf(" L=%s",E.mirror ? LayerNames[16] : LayerNames[1] );
            unknowncomponenttype = no;
          }
          else if ( strchr( componentname, 'R' ) == 0 ) {
            printf("(R REF=%s VAL=%s L=%s",componentname, componentvalue,
                    E.mirror ? LayerNames[16] : LayerNames[1] );
            unknowncomponenttype = no;
          }
          else if ( strchr( componentname, 'L' ) == 0 ) {
            printf("(L REF=%s VAL=%s L=%s",componentname, componentvalue,
                    E.mirror ? LayerNames[16] : LayerNames[1] );
            unknowncomponenttype = no;
          }
          else if ( strchr( componentname, 'D' ) == 0 ) {
            printf("(CR REF=%s NAME=%s L=%s",componentname, componentvalue,
                    E.mirror ? LayerNames[16] : LayerNames[1] );
            unknowncomponenttype = no;
          }
          else if ( strchr( componentname, 'J' ) == 0 ) {
            printf("(J REF=%s NAME=%s L=%s",componentname, componentvalue,
                    E.mirror ? LayerNames[16] : LayerNames[1] );
            unknowncomponenttype = no;
          }
          else if ( strchr( componentname, 'Q' ) == 0 ) {
            printf("(J REF=%s NAME=%s L=%s",componentname, componentvalue,
                    E.mirror ? LayerNames[16] : LayerNames[1] );
            unknowncomponenttype = no;
          }
          else if ( strchr( componentname, 'T' ) == 0 ) {
            printf("(J REF=%s NAME=%s L=%s",componentname, componentvalue,
                    E.mirror ? LayerNames[16] : LayerNames[1] );
            unknowncomponenttype = no;
          }
        }
      }

      // handle unknown component types
      if ( ( unknowncomponenttype == yes ) || ( UseComponentTypes == no ) ) {
        printf("(? REF=%s NAME=%s L=%s",componentname,componentvalue,
                E.mirror ? LayerNames[16] : LayerNames[1] );
        saypackagetype(E.package.name);
      }

      // append comment field
      printf(")  R%03.0f X=%5.*f Y=%5.*f : ",E.angle,precision_of_nets,u2inch(E.x),
              precision_of_nets,u2inch(E.y) );
      printf(" Lib: %s : %s : ", E.package.library, E.package.name);
      printf("Pins %d", pincount);
      printf("\n");
    }
    printf("}\n\n");


    // PADSTACK CREATION OF PADS, SMDS, AND VIAS
    // create list of all the different pads and smds (vias are pads)
    printheader("Pads, Smds, and Via Library");
    // handle all net contacts and vias
    B.signals(S) {
      S.vias(V) {
        Insert_A_Pad( ISAPAD, ISAVIA,
                      V.shape[1], V.shape[2], V.shape[16],
                      V.end,
                      V.diameter[1], V.diameter[2], V.diameter[16],
                      V.start,
                      V.drill );
      }
    }
    // handle all package pins
    B.elements(E) {
      E.package.contacts(C) {
        if (C.pad) {
          Insert_A_Pad( ISAPAD, ISAPAD,
                        C.pad.shape[1], C.pad.shape[2], C.pad.shape[16],
                        C.pad.angle,
                        C.pad.diameter[1], C.pad.diameter[2], C.pad.diameter[16],
                        C.pad.elongation,
                        C.pad.drill );
        }
        else if (C.smd) {
          if ( !C.smd.dx || !C.smd.dy) {
            string h;
            sprintf(h, "!<qt><nobr>Found a SMD-Pad with <b>dx</b> or <b>dy</b> = 0 (Zerro)<br>Pad <b>%s</b>'<br>Layer <b>%d</b><br>Coordinate <b>(%.4f %.4f)</b> mil<br>Package <b>%s.PAC</b><br>Element <b>%s</b><br>Library <b>%s.lbr</b><p><b>ULP aborted.</b></nobr></qt>",
                       C.name,
                       C.smd.layer,
                       u2mil(C.x), u2mil(C.y),
                       E.package.name,
                       E.name,
                       E.package.library
                   );
            dlgMessageBox( h, "OK");
            exit(0);
          }
          else {
            Insert_A_Pad( ISASMD, C.smd.layer,
                        SmdRoundness(C.smd.roundness), 0, 0,
                        C.smd.angle,
                        C.smd.dx, 0, 0,
                        C.smd.dy,
                        0 );
          }
        }
      }
    }

    // write out sorted list of the pads and smds
    if (Total_Pads) {
      /* *** Hyperlynx documentation *************************************
       {PADSTACK=padstack_name, // ** maximum of 32 characters an cannot contain white space
       [drill_size]
       (layer_name,
       pad_shape,    // '0' means oval or round (pad_sx=pad_sy if round)
                     // '1' means rectangular or square (pad_sx=pad_sy if square)
                     // '2' means oblong (oblong shape is a rectangular with rounded corners)
       pad_sx,
       pad_sy,
       pad_angle,    // is the counter-clockwise rotation angle of the pad in degree;
                     // rotation angle can range from 0.0 to +/-359.999;
                     // valid angular resolution is 0.001 degree;
                     // 0 (without a decimal point) is th recommended way of specifying 'no rotation'
       [thermal_clear_shape],
       [thermal_clear_sx],
       [thermal_clear_sy],
       [thermal_clear_angle],
       [pad_type])
      ***************************************************************** */

      string s;
      for (int i = 1; i <= Total_Pads; i++) {  // *** 17.08.2005 count from 1 ***
        if (pad_layer[i] == 0) s = "ISAPAD";
        if (pad_layer[i] == 1 || pad_layer[i] == 16) s = "ISASMD";
        if (pad_layer[i] == 18) s = "ISAVIA";
        if (pad_type[i] == ISASMD) {
          printf("{PADSTACK=SMD%03d\n",i);   // **** 17.08.2005 alf@cadsoft.de ***
          // smds are square, round or oblong

          // * if you wish layer name for layer number remark *
          // * this next 2 lines und mark the second 2 lines  *
          //  printf("(%s,%d,%5.*f,%5.*f,%.1f) Shape was Smd and is now Smd\n",
          //           LayerNames[pad_layer[i]],  // Layer name

          printf("(%d,%d,%5.*f,%5.*f,%.1f) %s Shape was Smd and is now Smd\n",
                   pad_layer[i],           // Layer number
                   pad_shape_Top_rnds[i],
                   precision_of_pads, u2inch(pad_diameter_Top_or_dx[i]),
                   precision_of_pads, u2inch(pad_dy_elong_start[i]),
                   pad_angle_end[i],
                   s );
        }
        else if (pad_type[i] == ISAPAD) {

          /* *** HyperLynx Signal-Integrity Transfer Format ******
          {PADSTACK=padstack_name, [drill_size]
          (layer_name, pad_shape, pad_sx, pad_sy, pad_angle,
          [thermal_clear_shape],
          [thermal_clear_sx],
          [thermal_clear_sy],
          [thermal_clear_angel],
          [pad_type])              [comment]
             ** [pad_type]!M=metal-pad A=anti-pad **
          ******* HyperLynx Signal-Integrity Transfer Format *** */
          printf("{PADSTACK=THR%03d,%5.3f\n", i, u2inch(pad_drill[i]));  // *** 17.08.2005 count from 1 ***
          // pads are on all layers, and have various shapes
          if (pad_layer[i] == ISAPAD) {

            // Pad layer Top
            if (pad_shape_Top_rnds[i] == OBLONG) {
              printf("(1,%s,%5.*f,%5.*f,%.1f) %s Shape was %s and is now %s\n",
                      PadShapes[pad_shape_Top_rnds[i]],
                      precision_of_pads,u2inch(pad_diameter_Top_or_dx[i] * pad_dy_elong_start[i]),
                      precision_of_pads,u2inch(pad_diameter_Top_or_dx[i]),
                      pad_angle_end[i],
                      s,
                      EaglePadShapes[pad_shape_Top_rnds[i]],
                      HypPadShapes[pad_shape_Top_rnds[i]] );
            }
            else {  // OVALROUND or RECTSQUARE
              printf("(1,%s,%5.*f,%5.*f,%.1f) %s Shape was %s and is now %s\n",
                      PadShapes[pad_shape_Top_rnds[i]],
                      precision_of_pads,u2inch(pad_diameter_Top_or_dx[i]),
                      precision_of_pads,u2inch(pad_diameter_Top_or_dx[i]),
                      pad_angle_end[i],
                      s,
                      EaglePadShapes[pad_shape_Top_rnds[i]],
                      HypPadShapes[pad_shape_Top_rnds[i]] );
            }

            // Pad layer Inner
            printf("(MDEF,%s,%5.*f,%5.*f,0) %s\n",
                    PadShapes[pad_shape_Inner[i]],
                    precision_of_pads,u2inch(pad_diameter_Inner[i]),
                    precision_of_pads,u2inch(pad_diameter_Inner[i]),
                    s);

            // Pad layer Bottom
            if (pad_shape_Bott[i] == OBLONG) {
              printf("(16,%s,%5.*f,%5.*f,%.1f) %s Shape was %s and is now %s\n",
                      PadShapes[pad_shape_Bott[i]],
                      precision_of_pads,u2inch(pad_diameter_Bott[i] * pad_dy_elong_start[i]),
                      precision_of_pads,u2inch(pad_diameter_Bott[i]),
                      pad_angle_end[i],
                      s,
                      EaglePadShapes[pad_shape_Bott[i]],
                      HypPadShapes[pad_shape_Bott[i]]);
            }
            else {  // OVALROUND or RECTSQUARE
              printf("(16,%s,%5.*f,%5.*f,%.1f) %s Shape was %s and is now %s\n",
                      PadShapes[pad_shape_Bott[i]],
                      precision_of_pads,u2inch(pad_diameter_Bott[i]),
                      precision_of_pads,u2inch(pad_diameter_Bott[i]),
                      pad_angle_end[i],
                      s,
                      EaglePadShapes[pad_shape_Bott[i]],
                      HypPadShapes[pad_shape_Bott[i]]);
            }
          }

          else if (pad_layer[i] == ISAVIA) {
            // Top - Inner(schleife) - Bottom
            for (int vlay = pad_dy_elong_start[i]; vlay <= pad_angle_end[i]; vlay++) {
              // layer used and allowed?
              if (copp_used_layer[vlay]) {    // layer used for copper an visible
                if (vlay == 1)
                  printf("(1,%s,%5.*f,%5.*f,0) %s Shape was %s and is now %s\n",
                          PadShapes[pad_shape_Top_rnds[i]],
                          precision_of_pads,u2inch(pad_diameter_Top_or_dx[i] * pad_dy_elong_start[i]),
                          precision_of_pads,u2inch(pad_diameter_Top_or_dx[i]),
                          s,
                          EaglePadShapes[pad_shape_Top_rnds[i]],
                          HypPadShapes[pad_shape_Top_rnds[i]] );

                else if (vlay == 16)
                  printf("(16,%s,%5.*f,%5.*f,0f) %s Shape was %s and is now %s\n",
                          PadShapes[pad_shape_Bott[i]],
                          precision_of_pads,u2inch(pad_diameter_Bott[i] * pad_dy_elong_start[i]),
                          precision_of_pads,u2inch(pad_diameter_Bott[i]),
                          s,
                          EaglePadShapes[pad_shape_Top_rnds[i]],
                          HypPadShapes[pad_shape_Top_rnds[i]] );

                else  printf("(%d,0,%5.*f,%5.*f,0) %s always round in inner layer\n",
                        vlay,
                        precision_of_pads,u2inch(pad_diameter_Inner[i]),
                        precision_of_pads,u2inch(pad_diameter_Inner[i]),
                        s );
              }
            }
          }
        }
        printf("}\n\n");
      }
    }

    // SIGNALS
    printheader("Nets");
    int Pad_ID, Xpad, Ypad, EpadX, EpadY, TLaylimit, Blaylimit;
    B.signals(S) {
      printf("{NET=%s\n",S.name);
      S.contactrefs(C) {

        if (C.contact.pad) {
          Pad_ID = Find_A_Pad( ISAPAD, 0,
                              C.contact.pad.shape[1], C.contact.pad.shape[2], C.contact.pad.shape[16],
                              C.contact.pad.angle,
                              C.contact.pad.diameter[1], C.contact.pad.diameter[2], C.contact.pad.diameter[16],
                              C.contact.pad.elongation,
                              C.contact.pad.drill );
          if ( Pad_ID ) { // *** 17.08.2005 Pad count from 1 to total_pad ***
            Xpad = C.contact.pad.x;
            EpadX = Xpad;
            Ypad = C.contact.pad.y;
            EpadY = Ypad;
            TLaylimit = 1;
            Blaylimit = 16;
            printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=THR%03d",
                  precision_of_nets,u2inch(Xpad), precision_of_nets,u2inch(Ypad),
                  C.element.name, C.contact.pad.name, Pad_ID);  // ** correct number while listing count from 1
                                                                // ** 17.08.2005 alf@cadsoft.de ***

            SayUPinFunction( C.element.name, C.contact.pad.name );
            printf(") %s, Pad Diameter: %5.*f  Drill: %5.*f\n",
                  S.name, precision_of_nets, u2inch(C.contact.pad.diameter[16]),
                  precision_of_nets, u2inch(C.contact.pad.drill) );
          }
          else {
            printf("Unregistered Pin Size!\n");
          }
        }
        if (C.contact.smd) {
          Pad_ID = Find_A_Pad( ISASMD, C.contact.smd.layer,
                               SmdRoundness(C.contact.smd.roundness), 0, 0,
                               C.contact.smd.angle,
                               C.contact.smd.dx, 0, 0,
                               C.contact.smd.dy,
                               0 );
          if ( Pad_ID ) {  // *** 17.08.2005 count from 1 ***
            Xpad = C.contact.smd.x;
            EpadX = Xpad;
            Ypad = C.contact.smd.y;
            EpadY = Ypad;
            TLaylimit = C.contact.smd.layer;
            Blaylimit = C.contact.smd.layer;
            printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=SMD%03d",
                     precision_of_nets,u2inch(Xpad), precision_of_nets,u2inch(Ypad),
                     C.element.name, C.contact.smd.name, Pad_ID);  // ** correct number while listing count from 1
                                                                   // ** 17.08.2005 alf@cadsoft.de ***     SayUPinFunction( C.element.name, C.contact.smd.name );
            printf(") %s, Smd Dx: %5.*f  Dy: %5.*f\n",
                    S.name, precision_of_nets, u2inch(C.contact.smd.dx),
                    precision_of_nets, u2inch(C.contact.smd.dy) );
          }
          else {
            printf("Unregistered Smd Size!\n");
          }
        }
        // if a pad/smd was located for this contact
        // and a copper segment starts at this contact's x,y location,
        // then the copper segment is included on this net.
        if ( Pad_ID ) { // *** 17.08.2005 count from 1 ***
          // Package element copper information
          // circles
          C.element.package.circles(A) {
            if ( ( A.layer >= 1 ) && ( A.layer <= 16 ) ) {
                printf("* %s has metal circles or isolation circles\n",C.element.name);
            }
          }
          // polygons
          C.element.package.polygons(P) {
            if ( ( P.layer >= 1 ) && ( P.layer <= 16 ) ) {
               printf("* %s has metal polygons\n",C.element.name);
            }
          }
          // rectangles
          C.element.package.rectangles(R) {
            if ( ( R.layer >= 1 ) && ( R.layer <= 16 ) ) {
              printf("* %s has metal rectangles\n",C.element.name);
            }
          }
          // Find any wires that connect to this pin/pad that are internal to the package
          // 1. build a table of all wires on the accepted layer
          int AnyPackageWiresCount = 0;
          int Wx1[], Wy1[], Wx2[], Wy2[], Wwid[], Wusedflag[],
              Wcurve[], Warcx1[], Warcx2[], Warcxc[], Warcy1[], Warcy2[], Warcyc[], Warcradius[],
              Wlayer ;
          C.element.package.wires(W) {
            // find all wires on the correct layer.
            if ( ( W.layer >= TLaylimit ) && ( W.layer <= Blaylimit ) ) {
              Wx1[AnyPackageWiresCount] = W.x1;
              Wy1[AnyPackageWiresCount] = W.y1;
              Wx2[AnyPackageWiresCount] = W.x2;
              Wy2[AnyPackageWiresCount] = W.y2;
              Wwid[AnyPackageWiresCount] = W.width;
              Wcurve[AnyPackageWiresCount] = W.curve;
              if (W.curve) {                               // 21.04.2005 alf@cadsoft.de
                Warcx1[AnyPackageWiresCount] = W.arc.x1;
                Warcx2[AnyPackageWiresCount] = W.arc.x2;
                Warcxc[AnyPackageWiresCount] = W.arc.xc;
                Warcy1[AnyPackageWiresCount] = W.arc.y1;
                Warcy2[AnyPackageWiresCount] = W.arc.y2;
                Warcyc[AnyPackageWiresCount] = W.arc.yc;
                Warcradius[AnyPackageWiresCount] = W.arc.radius;
              }
              Wusedflag[AnyPackageWiresCount] = no;
              TLaylimit = W.layer;    // fix layer to first found layer on an accepted first layer
              Blaylimit = W.layer;    // fix layer to first found layer on an accepted first layer
              Wlayer = W.layer;       // fix the layer
              AnyPackageWiresCount++; // count one segment
            }
          }
          // 2. search for physically connected copper segments, even if out of order
          if ( AnyPackageWiresCount != 0 ) {
            for ( int woi = 0; woi < AnyPackageWiresCount; woi++ ) {
              if ( Wusedflag[woi] == no ) {
                // check either end of the segment
                if ( ( Wx1[woi] == Xpad ) && ( Wy1[woi] == Ypad ) ) {
                  Xpad = Wx2[woi]; // remember the end of this segment
                  Ypad = Wy2[woi]; // which must be the start of the next segment
                  Wusedflag[woi] = yes;
                  woi = 0; // start searching list from the beginning again
                }
                else if ( ( Wx2[woi] == Xpad ) && ( Wy2[woi] == Ypad ) ) {
                  Xpad = Wx1[woi]; // remember the end of this segment
                  Ypad = Wy1[woi]; // which must be the start of the next segment
                  Wusedflag[woi] = yes;
                  woi = 0; // start searching list from the beginning again
                }
              }
            }
          }
          // 3. write out all segments attached to the contact
          if ( AnyPackageWiresCount != 0 ) {
            for ( int woi = 0; woi < AnyPackageWiresCount; woi++ ) {
              if ( Wusedflag[woi] == yes ) {
                // write the segment
                if ( Wlayer >= 1 && Wlayer <= 16 ) {
                  if (Wcurve[woi]) {
                    printf("(PERIMETER_ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f  W=%5.*f L=%s) Arcs: Board Outline Arc is CCW\n",
                             precision_of_nets,u2inch(Warcx1[woi]), precision_of_nets,u2inch(Warcy1[woi]),
                             precision_of_nets,u2inch(Warcx2[woi]), precision_of_nets,u2inch(Warcy2[woi]),
                             precision_of_nets,u2inch(Warcxc[woi]), precision_of_nets,u2inch(Warcyc[woi]),
                             precision_of_nets,u2inch(Warcradius[woi]),
                             precision_of_nets,u2inch(Wwid[woi]),
                             LayerNames[Wlayer]  );
                  }
                  else {
                    printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) %s Internal Package Wire\n",
                          precision_of_nets,u2inch(Wx1[woi]),
                          precision_of_nets,u2inch(Wy1[woi]),
                          precision_of_nets,u2inch(Wx2[woi]),
                          precision_of_nets,u2inch(Wy2[woi]),
                          precision_of_nets,u2inch(Wwid[woi]),
                          LayerNames[Wlayer],
                          S.name);
                  }
                }
                // write any contact pins or smds
                int OtherPad_ID;
                C.element.package.contacts(Q) {
                  // don't write out contacts at the original element contact location
                  if ( ( Q.x != EpadX ) || ( Q.y != EpadY ) ) {
                    // check if this element contact is at either end of the wire segment
                    if ( ( ( Q.x == Wx1[woi] ) && ( Q.y == Wy1[woi] ) ) ||
                         ( ( Q.x == Wx2[woi] ) && ( Q.y == Wy2[woi] ) ) ) {
                      // if a through hole pad
                      if (Q.pad) {
                        // find a pad on any layer
                        OtherPad_ID = Find_A_Pad( ISAPAD, 0,
                                                  Q.pad.shape[1], Q.pad.shape[2], Q.pad.shape[16],
                                                  Q.pad.angle,
                                                  Q.pad.diameter[1], Q.pad.diameter[2], Q.pad.diameter[16],
                                                  Q.pad.elongation,
                                                  Q.pad.drill );
                        if ( OtherPad_ID ) {  // *** 17.08.2005 count from 1 ***
                          printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=THR%03d",
                                   precision_of_nets, u2inch(Q.pad.x), precision_of_nets, u2inch(Q.pad.y),
                                   C.element.name, Q.pad.name, OtherPad_ID);
                          SayUPinFunction( C.element.name, Q.pad.name );
                          printf(") %s, Internal Package Pad Diameter: %5.*f  Drill: %5.*f\n",
                                   S.name, precision_of_nets,u2inch(Q.pad.diameter[16]),
                                   precision_of_nets, u2inch(Q.pad.drill) );
                          InsertAssocatedPin( C.element.name, Q.pad.name );
                        }
                        else {
                          printf("Unregistered Internal Package Pin Size!\n");
                        }
                      }
                      // if a smd pad
                      if (Q.smd) {
                        // smd pad must be on this layer
                        if ( Q.smd.layer == Wlayer ) {
                          // find a smd that matches
                          OtherPad_ID = Find_A_Pad( ISASMD, Q.smd.layer,
                                                    SmdRoundness(Q.smd.roundness), 0, 0,
                                                    Q.smd.angle,
                                                    Q.smd.dx, 0, 0,
                                                    Q.smd.dy,
                                                    0 );
                          if ( OtherPad_ID ) { // *** 17.08.2005 count from 1 ***
                            printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=SMD%03d",
                                     precision_of_nets,u2inch(Q.smd.x), precision_of_nets,u2inch(Q.smd.y),
                                     C.element.name, Q.smd.name, OtherPad_ID);
                            SayUPinFunction( C.element.name, Q.smd.name );
                            printf(") %s, Smd Dx: %5.*f  Dy: %5.*f\n",
                                     S.name,precision_of_nets,u2inch(Q.smd.dx),
                                     precision_of_nets,u2inch(Q.smd.dy) );
                            InsertAssocatedPin( C.element.name, Q.smd.name );
                          }
                          else {
                            printf("Unregistered Smd Size!\n");
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
      S.vias(V) {
        Pad_ID = Find_A_Pad( ISAPAD, 18,
                             V.shape[1], V.shape[2], V.shape[16],
                             V.end,
                             V.diameter[1], V.diameter[2], V.diameter[16],
                             V.start,
                             V.drill );

        if ( Pad_ID ) { // 17.08.2005 count from 1 ***
          printf("(VIA X=%5.*f Y=%5.*f P=THR%03d) %s\n",
                  precision_of_nets,u2inch(V.x), precision_of_nets, u2inch(V.y),
                  Pad_ID, S.name);   // ** correct number while listing count from 1
                                       // ** 17.08.2005 alf@cadsoft.de ***
        }
        else {
          printf("Unregistered Via Size!\n");
        }
      }
      S.wires(W) {
        if (W.layer >= 1 && W.layer <= 16 ) {
          if (W.curve) {
            printf("(ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f W=%5.*f L=%s)\n",
                    precision_of_nets,u2inch(W.arc.x1), precision_of_nets,u2inch(W.arc.y1),
                    precision_of_nets,u2inch(W.arc.x2), precision_of_nets,u2inch(W.arc.y2),
                    precision_of_nets,u2inch(W.arc.xc), precision_of_nets,u2inch(W.arc.yc),
                    precision_of_nets,u2inch(W.arc.radius),
                    precision_of_nets,u2inch(W.width),
                    LayerNames[W.layer]  );
          }
          else {
            printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) %s\n",
                    precision_of_nets,u2inch(W.x1), precision_of_nets,u2inch(W.y1),
                    precision_of_nets,u2inch(W.x2), precision_of_nets,u2inch(W.y2),
                    precision_of_nets,u2inch(W.width), LayerNames[W.layer], S.name);
          }
        }
      }
      S.polygons(P) {
        printf("* POLYGONS   NOT Allowed in HYP as of BoardSimm 2.2 Build 70.  ");
        printf("Hopefully someday they will!\n");
        printf("* I=Isolate S=Spacing W=Width O=Orphins_On/Off P=Pour_SOLID/HATCH T=Thermals_On/Off L=Layer) Polygon Format\n");
        printf("*(PLG I=%5.*f S=%5.*f W=%5.*f O=%s P=%s T=%s L=%s) Polygon %s Data\n",
                precision_of_nets,u2inch(P.isolate),precision_of_nets,u2inch(P.spacing),
                precision_of_nets,u2inch(P.width),P.orphans ? "On" : "Off",
                P.pour == POLYGON_POUR_SOLID ? "SOLID" : "HATCH",
                P.thermals ? "On" : "Off",LayerNames[P.layer],S.name);
        P.wires(W) {
          printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Polygon %s\n",
                precision_of_nets,u2inch(W.x1),precision_of_nets,u2inch(W.y1),
                precision_of_nets,u2inch(W.x2),precision_of_nets,u2inch(W.y2),
                precision_of_nets,u2inch(W.width),LayerNames[W.layer],S.name);
        }
      }
      printf("}\n\n");
    }

    // Unconnected Component Pins are on their own special net "HYP$xPy"
    // where x=element name and y=pin name

    // handle all unconnected package pins
    B.elements(E) {
      E.package.contacts(C) {
        if ( strlen(C.signal) == 0 ) {
          if (C.pad) {
            Pad_ID = Find_A_Pad( ISAPAD, 0,
                                 C.pad.shape[1], C.pad.shape[2], C.pad.shape[16],
                                 C.pad.angle,
                                 C.pad.diameter[1], C.pad.diameter[2], C.pad.diameter[16],
                                 C.pad.elongation,
                                 C.pad.drill );
            if ( Pad_ID ) { // *** 17.08.2005 count from 1 ***
              if ( FindAssocatedPin( E.name, C.pad.name ) == 0 ) {
                Xpad = C.pad.x;
                Ypad = C.pad.y;
                printf("{NET=HYP$%s.%s\n",E.name,C.pad.name);
                printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=THR%03d",
                       precision_of_nets,u2inch(Xpad), precision_of_nets,u2inch(Ypad),
                       E.name, C.pad.name, Pad_ID);
                printf(") Pad Diameter: %5.*f  Drill: %5.*f\n",
                       precision_of_nets, u2inch(C.pad.diameter[16]),
                       precision_of_nets, u2inch(C.pad.drill) );
                printf("}\n\n");
              }
              else {
                printf("* PIN %s.%s is part of an internal package net.\n",E.name,C.pad.name);
              }
            }
            else {
              printf("* Unregistered Pin Size!\n");
            }
          }
          if (C.smd) {
            Pad_ID = Find_A_Pad( ISASMD, C.smd.layer,
                                 SmdRoundness(C.smd.roundness), 0, 0,
                                 C.smd.angle,
                                 C.smd.dx, 0, 0,
                                 C.smd.dy,
                                 0 );
            if ( Pad_ID ) { // *** 17.08.2005 count from 1 ***
              if ( FindAssocatedPin( E.name, C.smd.name ) == 0 ) {
                Xpad = C.smd.x;
                Ypad = C.smd.y;
                printf("{NET=HYP$%s.%s\n",E.name,C.smd.name);
                printf("(PIN X=%5.*f Y=%5.*f R=%s.%s P=SMD%03d",
                      precision_of_nets,u2inch(Xpad), precision_of_nets,u2inch(Ypad),
                      E.name, C.smd.name, Pad_ID);
                printf(") Smd Dx: %5.*f  Dy: %5.*f\n",
                      precision_of_nets, u2inch(C.smd.dx),
                      precision_of_nets, u2inch(C.smd.dy) );
                printf("}\n\n");
              }
              else {
                printf("* PIN %s.%s is part of an internal package net.\n",E.name,C.smd.name);
              }
            }
            else {
              printf("* Unregistered Smd Size!\n");
            }
          }
        }
      }
    }

    // NETS that aren't signals but are copper are exported as a net named "N$ComNet"
    // Search for any common nets
    int AnyNets = no;
    // B.arcs(A) if ( ( A.layer >= 1 ) && ( A.layer <= 16 ) ) AnyNets = yes;
    B.circles(C) if ( ( C.layer >= 1 ) && ( C.layer <= 16 ) ) AnyNets = yes;
    B.rectangles(R) if ( ( R.layer >= 1 ) && ( R.layer <= 16 ) ) AnyNets = yes;
    B.wires(W) if ( ( W.layer >= 1 ) && ( W.layer <= 16 ) ) AnyNets = yes;

    if ( AnyNets == yes ) {
      printf("{NET=N$ComNet\n");

      // CIRCLES
      B.circles(C) {
        if ( ( C.layer >= 1 ) && ( C.layer <= 16 ) ) {
          printf("(ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f W=%5.*f L=%s) Circle\n",
                   precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
                   precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y+C.radius),
                   precision_of_nets,u2inch(C.x),precision_of_nets,u2inch(C.y),
                   precision_of_nets,u2inch(C.radius),precision_of_nets,u2inch(C.width),
                   LayerNames[C.layer]);
        }
      }

      // RECTANGLES
      B.rectangles(R) {
        if ( ( R.layer >= 1 ) && ( R.layer <= 16 ) ) {
          printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Rectangle Segment Bottom\n",
                   precision_of_nets,u2inch(R.x1),precision_of_nets,u2inch(R.y1),
                   precision_of_nets,u2inch(R.x2),  precision_of_nets,u2inch(R.y1),
                   precision_of_nets,RectOutlineWireWidth,LayerNames[R.layer]);
          printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Rectangle Segment Right\n",
                   precision_of_nets,u2inch(R.x2),precision_of_nets,u2inch(R.y1),
                   precision_of_nets,u2inch(R.x2),precision_of_nets,u2inch(R.y2),
                   precision_of_nets,RectOutlineWireWidth,LayerNames[R.layer]);
          printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Rectangle Segment Top\n",
                   precision_of_nets,u2inch(R.x2),precision_of_nets,u2inch(R.y2),
                   precision_of_nets,u2inch(R.x1),precision_of_nets,u2inch(R.y2),
                   precision_of_nets,RectOutlineWireWidth,LayerNames[R.layer]);
          printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Rectangle Segment Left\n",
                   precision_of_nets,u2inch(R.x1),precision_of_nets,u2inch(R.y2),
                   precision_of_nets,u2inch(R.x1),precision_of_nets,u2inch(R.y1),
                   precision_of_nets,RectOutlineWireWidth,LayerNames[R.layer]);
        }
      }

      // WIRES
      B.wires(W) {
        if ( ( W.layer >= 1 ) && ( W.layer <= 16 ) ) {
          if (W.curve) {
            // ARCS
            printf("(ARC X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f XC=%5.*f YC=%5.*f R=%5.*f W=%5.*f L=%s) Arc is CCW\n",
                    precision_of_nets,u2inch(W.arc.x2),precision_of_nets,u2inch(W.arc.y2),
                    precision_of_nets,u2inch(W.arc.x1),precision_of_nets,u2inch(W.arc.y1),
                    precision_of_nets,u2inch(W.arc.xc),precision_of_nets,u2inch(W.arc.yc),
                    precision_of_nets,u2inch(W.arc.radius),precision_of_nets,u2inch(W.width),
                    LayerNames[W.layer]);
          }
          else {
            printf("(SEG X1=%5.*f Y1=%5.*f X2=%5.*f Y2=%5.*f W=%5.*f L=%s) Wire Segment\n",
                    precision_of_nets,u2inch(W.x1),precision_of_nets,u2inch(W.y1),
                    precision_of_nets,u2inch(W.x2),precision_of_nets,u2inch(W.y2),
                    precision_of_nets,u2inch(W.width),LayerNames[W.layer]);
          }
        }
      }
      printf("}\n\n");
    } // end of copper as common net

    // END OF RUN
    printheader("End of data");
    printf("{END}\n\n");
    printf("{KEY=028-015E-4E5D}\n\n");
  } // end of output() {}

} // end of board() {}


