home *** CD-ROM | disk | FTP | other *** search
/ HAM Radio 1 / HamRadio.cdr / tech / pcbsrcs2 / pcbprint.c < prev    next >
C/C++ Source or Header  |  1991-02-07  |  37KB  |  1,410 lines

  1. /*
  2. ** printed circuit board printer, Copyright (C) Randy Nevin 1989, 1990.
  3. **
  4. ** you may give this software to anyone, make as many copies as you like, and
  5. ** post it on public computer bulletin boards and file servers. you may not
  6. ** sell it or charge any fee for distribution (except for media and postage),
  7. ** remove this comment or the copyright notice from the code, or claim that
  8. ** you wrote this code or anything derived from it. you may modify the code as
  9. ** much as you want (please document clearly with comments, and maintain the
  10. ** coding style), but programs which are derived from this one are subject to
  11. ** the conditions stated here. i am providing this code so that people can
  12. ** learn from it, so if you distribute it, please include source code, not
  13. ** just executables. contact me to report bugs or suggest enhancements; i do
  14. ** not guarantee support, but i will make an effort to help you, and i want to
  15. ** act as a central clearing house for future versions. you should contact me
  16. ** before undertaking a significant development effort, to avoid reinventing
  17. ** the wheel. if you come up with an enhancement you consider particularly
  18. ** useful, i would appreciate being informed so that it can be incorporated in
  19. ** future versions. my address is: Randy Nevin, 1731 211th PL NE, Redmond,
  20. ** WA 98053, USA. this code is available directly from the author; just send a
  21. ** 360k floppy and a self-addressed floppy mailer with sufficient postage.
  22. **
  23. ** HISTORY
  24. ** (name        date        description)
  25. ** ----------------------------------------------------
  26. ** randy nevin        3/4/89        initial version
  27. ** randy nevin        3/4/89        released version 1.00
  28. ** randy nevin        4/22/89        implemented /H and /V switches to
  29. **                    distinguish between hp laser jet
  30. **                    commands and vector-oriented commands;
  31. **                    the new vector-oriented commands
  32. **                    should be easy to translate into
  33. **                    postscript or other graphics printer
  34. **                    languages such as hpgl, and are
  35. **                    human-readable
  36. ** randy nevin        4/27/89        released version 1.10
  37. */
  38.  
  39. #include <stdio.h>
  40. #include <stdlib.h>
  41. #include <string.h>
  42. #include "cell.h"
  43.  
  44. /*
  45. ** usage: PCBPRINT [/H] [/V] [/P] [/L] [/Rn] [/Zm] infile
  46. **
  47. ** /P indicates portrait orientation (paper is longer from top to bottom), and
  48. ** /L indicates landscape orientation (paper is longer side-to-side). only one
  49. ** of /P and /L can be present. n is the laser printer resolution (75, 100,
  50. ** 150, or 300) and m is the zoom factor (0, 1, 2, or 3). the defaults are:
  51. ** /P /R150 /Z1. this program creates 6 output files (H, T, B, HT, HB, and
  52. ** HTB). each of these files can be fed to a hewlett-packard laser printer to
  53. ** produce a picture of part or all of the routed printed circuit board. H
  54. ** contains commands to print only the holes and routing holes. T and B
  55. ** contain commands to print only the top-side or bottom-side traces,
  56. ** respectively. HT and HB are the same, but also include the holes, and HTB
  57. ** contains everything (holes, top-side traces, and bottom-side traces).
  58. **
  59. ** /H selects hewlett-packard laser printer commands, and is the default.
  60. ** /V selects vector-oriented commands; if it is selected, none of the other
  61. ** switches are available. when /V is selected, the output files are as above,
  62. ** but consist of the following types of lines:
  63. **    1) DIMENSION(rowmax, colmax)
  64. **    2) LINE(row1, col1, row2, col2)
  65. **    3) CIRCLE(row, col, radius)
  66. ** all parameters are real numbers, and specified in mils (1/1000 of an inch).
  67. ** DIMENSION tells the maximum row and column values that will be encountered.
  68. ** LINE specifies the endpoints of a line. CIRCLE gives a circle center and
  69. ** radius. here is a blow-up of one 50-mil-by-50-mil cell, with certain points
  70. ** of interest labeled by their position relative to the origin (0.0,0.0):
  71. **
  72. **    A---------------B---------------C
  73. **    |                               |
  74. **    |             **D**             | 
  75. **    |           *       *           |
  76. **    |         E           F         |
  77. **    |       *               *       | 
  78. **    G      H        I        J      K
  79. **    |       *               *       | 
  80. **    |         L           M         |
  81. **    |           *       *           |
  82. **    |             **N**             | 
  83. **    |                               |
  84. **    O---------------P---------------Q
  85. **
  86. **    A = ( 50,      0       )
  87. **    B = ( 50,      25      )
  88. **    C = ( 50,      50      )
  89. **    D = ( 37.5,    25      )
  90. **    E = ( 33.8388, 16.1612 )
  91. **    F = ( 33.8388, 33.8388 )
  92. **    G = ( 25,      0       )
  93. **    H = ( 25,      12.5    )
  94. **    I = ( 25,      25      )
  95. **    J = ( 25,      37.5    )
  96. **    K = ( 25,      50      )
  97. **    L = ( 16.1612, 16.1612 )
  98. **    M = ( 16.1612, 33.8388 )
  99. **    N = ( 12.5,    25      )
  100. **    O = ( 0,       0       )
  101. **    P = ( 0,       25      )
  102. **    Q = ( 0,       50      )
  103. */
  104.  
  105. /* markers that hole-related traces have been processed */
  106. #define NOT_NORTH        0x00000200L    /* upward        */
  107. #define NOT_NORTHEAST        0x00000400L    /* upward and right    */
  108. #define NOT_EAST        0x00000800L    /* to the right        */
  109. #define NOT_SOUTHEAST        0x00001000L    /* downward and right    */
  110. #define NOT_SOUTH        0x00002000L    /* downward        */
  111. #define NOT_SOUTHWEST        0x00004000L    /* downward and left    */
  112. #define NOT_WEST        0x00008000L    /* to the left        */
  113. #define NOT_NORTHWEST        0x00010000L    /* upward and left    */
  114. #define NOT_ALL            ( NOT_NORTH \
  115.                 | NOT_NORTHEAST \
  116.                 | NOT_EAST \
  117.                 | NOT_SOUTHEAST \
  118.                 | NOT_SOUTH \
  119.                 | NOT_SOUTHWEST \
  120.                 | NOT_WEST \
  121.                 | NOT_NORTHWEST )
  122.  
  123. #define MAXZOOM    3    /* maximum zoom number; minimum is 0 */
  124.  
  125. #define ZOOM0    3    /* 3x3 dots per cell    */
  126. #define ZOOM1    6    /* 6x6 dots per cell    */
  127. #define ZOOM2    10    /* 10x10 dots per cell    */
  128. #define ZOOM3    18    /* 18x18 dots per cell    */
  129.  
  130. #define HPLASERJET    0    /* hp laser jet commands    */
  131. #define VECTOR        1    /* vector-oriented commands    */
  132.  
  133. static int size[MAXZOOM+1] = { ZOOM0, ZOOM1, ZOOM2, ZOOM3 };
  134.  
  135. #define H    1    /* holes                */
  136. #define T    2    /* top-side traces            */
  137. #define B    4    /* bottom-side traces            */
  138. #define HT    (H+T)    /* holes and top-side traces        */
  139. #define HB    (H+B)    /* holes and bottom-side traces        */
  140. #define HTB    (H+T+B)    /* holes, top- and bottom-side traces    */
  141.  
  142. static int style;    /* 0 = /H, 1 = /V                */
  143. static int currnt;    /* current image type (one of the six above)    */
  144. static int orient;    /* 0=portrait, 1=landscape            */
  145. static int resol;    /* resolution (one of 75,100,150,300)        */
  146. static int zoom;    /* 0=3x3, 1=6x6, 2=10x10, 3=18x18        */
  147. static int nbytes;    /* number of bytes per image row        */
  148.  
  149. int JustBoard = 1; /* only need the board data structure */
  150.  
  151. extern int Nrows, Ncols; /* board dimensions */
  152.  
  153. extern void InitBoard( void );
  154. extern long GetCell( int, int, int );
  155. extern void SetCell( int, int, int, long );
  156.  
  157. void main( int, char *[] );
  158. static void dofile( char *, int );
  159. static void prolog( FILE * );
  160. static void epilog( FILE * );
  161. static void doimage( FILE * );
  162. static void dovector( FILE * );
  163. static void trace( FILE *, int, int, int, int, int, int, int, int );
  164. static void map( long, long, int, FILE * );
  165. static void initbit( void );
  166. static void flushbit( FILE * );
  167. static void outbit( int, FILE * );
  168.  
  169. void main ( argc, argv ) /* input routed board, output laser printer files */
  170.     int argc;
  171.     char *argv[];
  172.     {
  173.     char *self, *p;
  174.     register int r, c;
  175.     int i1, i2, i3, i4, i, j;
  176.     FILE *fp;
  177.     long x;
  178.     char oset, rset, zset;
  179.  
  180.     printf( "Copyright (C) Randy Nevin, 1989, 1990. Version 1.10\n" );
  181.     printf( "See source code for rights granted.\n\n" );
  182.     style = HPLASERJET;
  183.     orient = 0; /* portrait mode */
  184.     resol = 150; /* 150 dots per inch */
  185.     zoom = 1; /* 6x6 cells */
  186.     oset = rset = zset = 0; /* so far, just defaults */
  187.     self = argv[0];
  188.     /* get rid of initial part of path */
  189.     if ((p = strrchr( self, '\\' )) || (p = strrchr( self, ':' )))
  190.         self = ++p;
  191.     /* get rid of extension */
  192.     if ((p = strrchr( self, '.' )) && !stricmp( p, ".EXE" ))
  193.         *p = 0;
  194.     if (argc < 2 || argc > 5) { /* need infile and up to 4 switches */
  195.         fprintf( stderr,
  196.             "usage: %s [/H] [/V] [/P] [/L] [/Rn] [/Zm] infile\n",
  197.             self );
  198.         fprintf( stderr, " H = hp laser jet commands (default)\n" );
  199.         fprintf( stderr, " V = vector-oriented commands\n" );
  200.         fprintf( stderr, " P = portrait orientation\n" );
  201.         fprintf( stderr, " L = landscape orientation\n" );
  202.         fprintf( stderr, " n = resolution (75,100,150,300)\n" );
  203.         fprintf( stderr, " m = zoom (0,1,2,3)\n" );
  204.         exit( -1 );
  205.         }
  206.     for (i = 1; i < argc-1; i++) { /* process switches */
  207.         if (!stricmp( argv[i], "/h" ))
  208.             style = HPLASERJET;
  209.         else if (!stricmp( argv[i], "/v" ))
  210.             style = VECTOR;
  211.         else if (!stricmp( argv[i], "/p" )) {
  212.             if (oset)
  213.                 fprintf( stderr, "duplicate orientation %s\n",
  214.                     argv[i] );
  215.             else {
  216.                 oset = 1;
  217.                 orient = 0;
  218.                 }
  219.             }
  220.         else if (!stricmp( argv[i], "/l" )) {
  221.             if (oset)
  222.                 fprintf( stderr, "duplicate orientation %s\n",
  223.                     argv[i] );
  224.             else {
  225.                 oset = 1;
  226.                 orient = 1;
  227.                 }
  228.             }
  229.         else if (*argv[i] == '/' && (*(argv[i]+1) == 'R'
  230.             || *(argv[i]+1) == 'r')) {
  231.             if (rset)
  232.                 fprintf( stderr, "duplicate resolution %s\n",
  233.                     argv[i] );
  234.             else {
  235.                 rset = 1;
  236.                 resol = atoi( argv[i]+2 );
  237.                 }
  238.             }
  239.         else if (*argv[i] == '/' && (*(argv[i]+1) == 'Z'
  240.             || *(argv[i]+1) == 'z')) {
  241.             if (zset)
  242.                 fprintf( stderr, "duplicate zoom %s\n",
  243.                     argv[i] );
  244.             else {
  245.                 zset = 1;
  246.                 zoom = atoi( argv[i]+2 );
  247.                 }
  248.             }
  249.         else
  250.             fprintf( stderr, "unknown option %s\n", argv[i] );
  251.         }
  252.     if (!(fp = fopen( argv[argc-1], "rb" ))) {
  253.         fprintf( stderr, "can't open %s\n", argv[argc-1] );
  254.         exit( -1 );
  255.         }
  256.     /* fetch the board dimensions */
  257.     if ((i = getc( fp )) == EOF || (j = getc( fp )) == EOF) {
  258.         fprintf( stderr, "premature eof\n" );
  259.         exit( -1 );
  260.         }
  261.     Nrows = (i & 0xFF) | ((j << 8) & 0xFF00);
  262.     if ((i = getc( fp )) == EOF || (j = getc( fp )) == EOF) {
  263.         fprintf( stderr, "premature eof\n" );
  264.         exit( -1 );
  265.         }
  266.     Ncols = (i & 0xFF) | ((j << 8) & 0xFF00);
  267.     InitBoard(); /* allocate memory for data structures */
  268.     for (r = 0; r < Nrows; r++) { /* read in the board, row by column */
  269.         for (c = 0; c < Ncols; c++) {
  270.             /* first do top-side */
  271.             if ((i1 = getc( fp )) == EOF
  272.                 || (i2 = getc( fp )) == EOF
  273.                 || (i3 = getc( fp )) == EOF
  274.                 || (i4 = getc( fp )) == EOF) {
  275.                 fprintf( stderr, "premature eof\n" );
  276.                 exit( -1 );
  277.                 }
  278.             x = (long)i1;
  279.             x |= (((long)i2) << 8);
  280.             x |= (((long)i3) << 16);
  281.             x |= (((long)i4) << 24);
  282.             SetCell( r, c, TOP, x );
  283.             /* then do bottom-side */
  284.             if ((i1 = getc( fp )) == EOF
  285.                 || (i2 = getc( fp )) == EOF
  286.                 || (i3 = getc( fp )) == EOF
  287.                 || (i4 = getc( fp )) == EOF) {
  288.                 fprintf( stderr, "premature eof\n" );
  289.                 exit( -1 );
  290.                 }
  291.             x = (long)i1;
  292.             x |= (((long)i2) << 8);
  293.             x |= (((long)i3) << 16);
  294.             x |= (((long)i4) << 24);
  295.             SetCell( r, c, BOTTOM, x );
  296.             }
  297.         }
  298.     nbytes = (Ncols * size[zoom] + 7) / 8;
  299.     dofile( "H",   H   );
  300.     dofile( "T",   T   );
  301.     dofile( "B",   B   );
  302.     dofile( "HT",  HT  );
  303.     dofile( "HB",  HB  );
  304.     dofile( "HTB", HTB );
  305.     exit( 0 );
  306.     }
  307.  
  308. static void dofile ( p, i ) /* create a board image file */
  309.     char *p;
  310.     int i;
  311.     {
  312.     FILE *fp;
  313.  
  314.     printf( "producing %s image file\n", p );
  315.     currnt = i;
  316.     if (!(fp = fopen( p, "wb" ))) {
  317.         fprintf( stderr, "can't open %s\n", p );
  318.         exit( -1 );
  319.         }
  320.     if (style == HPLASERJET) {
  321.         prolog( fp ); /* initial laser printer commands */    
  322.         doimage( fp ); /* create the board image */
  323.         epilog( fp ); /* final laser printer commands */
  324.         }
  325.     else if (style == VECTOR)
  326.         dovector( fp ); /* create the board image */
  327.     else {
  328.         fprintf( stderr, "internal error\n" );
  329.         exit( -1 );
  330.         }
  331.     if (fclose( fp )) {
  332.         fprintf( stderr, "can't close %s\n", p );
  333.         exit( -1 );
  334.         }
  335.     }
  336.  
  337. static void prolog ( fp ) /* output initial laser printer commands */
  338.     register FILE *fp;
  339.     {
  340.     putc( 0x1B, fp );        /* <esc> */
  341.     putc( 'E', fp );        /* reset */
  342.     putc( 0x1B, fp );        /* <esc> */
  343.     fprintf( fp, "&l%dO", orient );    /* set image orientation */
  344.     putc( 0x1B, fp );        /* <esc> */
  345.     fprintf( fp, "&a10R" );        /* cursor to row 10 */
  346.     putc( 0x1B, fp );        /* <esc> */
  347.     fprintf( fp, "&a10C" );        /* cursor to column 10 */
  348.     putc( 0x1B, fp );        /* <esc> */
  349.     fprintf( fp, "*t%dR", resol );    /* set resolution in dots per inch */
  350.     putc( 0x1B, fp );        /* <esc> */
  351.     fprintf( fp, "*r1A" );        /* start graphics at cursor */
  352.     if (ferror( fp ))
  353.         fprintf( stderr, "output error; disk might be full\n" );
  354.     }
  355.  
  356. static void epilog ( fp ) /* output final laser printer commands */
  357.     register FILE *fp;
  358.     {
  359.     putc( 0x1B, fp );    /* <esc> */
  360.     fprintf( fp, "*rB" );    /* end graphics */
  361.     putc( 0x12, fp );    /* formfeed to eject paper */
  362.     putc( 0x1B, fp );    /* <esc> */
  363.     putc( 'E', fp );    /* reset */
  364.     if (ferror( fp ))
  365.         fprintf( stderr, "output error; disk might be full\n" );
  366.     }
  367.  
  368. static void doimage ( fp ) /* create the board image, row by column */
  369.     FILE *fp;
  370.     {
  371.     register int r, c;
  372.     int ir;
  373.     long x, y;
  374.  
  375.     for (r = Nrows-1; r >= 0; r--) { /* each row */
  376.         for (ir = size[zoom]-1; ir >= 0; ir--) { /* each scan line */
  377.             putc( 0x1B, fp );    /* <esc> */
  378.             fprintf( fp, "*b%dW", nbytes );
  379.             initbit();
  380.             for (c = 0; c < Ncols; c++) {
  381.                 x = GetCell( r, c, TOP );
  382.                 y = GetCell( r, c, BOTTOM );
  383.                 map( x, y, ir, fp );
  384.                 }
  385.             flushbit( fp );
  386.             }
  387.         }
  388.     if (ferror( fp ))
  389.         fprintf( stderr, "output error; disk might be full\n" );
  390.     }
  391.  
  392. /* statement formats */
  393. static char dimstmt[] = "DIMENSION(%d.%d, %d.%d)\r\n";
  394. static char cirstmt[] = "CIRCLE(%d.%d, %d.%d, %d.%d)\r\n";
  395. static char linstmt[] = "LINE(%d.%d, %d.%d, %d.%d, %d.%d)\r\n";
  396.  
  397. static void dovector ( fp ) /* create the board image, row by column */
  398.     FILE *fp;
  399.     {
  400.     register int r, c;
  401.     int r50, c50;
  402.     long x;
  403.  
  404.     fprintf( fp, dimstmt, Nrows*50, 0, Ncols*50, 0 );
  405.     for (r = 0, r50 = 0; r < Nrows; r++, r50 += 50)
  406.         for (c = 0, c50 = 0; c < Ncols; c++, c50 += 50) {
  407.             x = GetCell( r, c, TOP );
  408.             if (x & HOLE) {
  409.                 if (currnt & H)
  410.                     fprintf( fp, cirstmt, r50+25, 0,
  411.                         c50+25, 0, 12, 5 );
  412.                 if (currnt & T) {
  413. /*
  414. ** NOTE: when the trace exits to a corner, we should check which of the
  415. ** 3 adjoining cells it actually goes into. for now, we assume it goes
  416. ** into the diagonal one. if this is a false assumption, the cases
  417. ** below for NORTHEAST, SOUTHEAST, SOUTHWEST, and NORTHWEST will require
  418. ** more checking before the trace() can be started.
  419. */
  420.                     if ((x&(HOLE_NORTH|NOT_NORTH))
  421.                         == HOLE_NORTH)
  422.                         trace( fp, r+1, c,
  423.                             TOP, FROM_SOUTH,
  424.                             r50+37, 5,
  425.                             c50+25, 0 );
  426.                     if ((x&(HOLE_NORTHEAST|NOT_NORTHEAST))
  427.                         == HOLE_NORTHEAST)
  428.                         trace( fp, r+1, c+1,
  429.                             TOP, FROM_SOUTHWEST,
  430.                             r50+33, 8388,
  431.                             c50+33, 8388 );
  432.                     if ((x&(HOLE_EAST|NOT_EAST))
  433.                         == HOLE_EAST)
  434.                         trace( fp, r, c+1,
  435.                             TOP, FROM_WEST,
  436.                             r50+25, 0,
  437.                             c50+37, 5 );
  438.                     if ((x&(HOLE_SOUTHEAST|NOT_SOUTHEAST))
  439.                         == HOLE_SOUTHEAST)
  440.                         trace( fp, r-1, c+1,
  441.                             TOP, FROM_NORTHWEST,
  442.                             r50+16, 1612,
  443.                             c50+33, 8388 );
  444.                     if ((x&(HOLE_SOUTH|NOT_SOUTH))
  445.                         == HOLE_SOUTH)
  446.                         trace( fp, r-1, c,
  447.                             TOP, FROM_NORTH,
  448.                             r50+12, 5,
  449.                             c50+25, 0 );
  450.                     if ((x&(HOLE_SOUTHWEST|NOT_SOUTHWEST))
  451.                         == HOLE_SOUTHWEST)
  452.                         trace( fp, r-1, c-1,
  453.                             TOP, FROM_NORTHEAST,
  454.                             r50+16, 1612,
  455.                             c50+16, 1612 );
  456.                     if ((x&(HOLE_WEST|NOT_WEST))
  457.                         == HOLE_WEST)
  458.                         trace( fp, r, c-1,
  459.                             TOP, FROM_EAST,
  460.                             r50+25, 0,
  461.                             c50+12, 5 );
  462.                     if ((x&(HOLE_NORTHWEST|NOT_NORTHWEST))
  463.                         == HOLE_NORTHWEST)
  464.                         trace( fp, r+1, c-1,
  465.                             TOP, FROM_SOUTHEAST,
  466.                             r50+33, 8388,
  467.                             c50+16, 1612 );
  468.                     }
  469.                 if (currnt & B) {
  470.                     x = GetCell( r, c, BOTTOM );
  471.                     if ((x&(HOLE_NORTH|NOT_NORTH))
  472.                         == HOLE_NORTH)
  473.                         trace( fp, r+1, c,
  474.                             BOTTOM,
  475.                             FROM_SOUTH,
  476.                             r50+37, 5,
  477.                             c50+25, 0 );
  478.                     if ((x&(HOLE_NORTHEAST|NOT_NORTHEAST))
  479.                         == HOLE_NORTHEAST)
  480.                         trace( fp, r+1, c+1,
  481.                             BOTTOM,
  482.                             FROM_SOUTHWEST,
  483.                             r50+33, 8388,
  484.                             c50+33, 8388 );
  485.                     if ((x&(HOLE_EAST|NOT_EAST))
  486.                         == HOLE_EAST)
  487.                         trace( fp, r, c+1,
  488.                             BOTTOM,
  489.                             FROM_WEST,
  490.                             r50+25, 0,
  491.                             c50+37, 5 );
  492.                     if ((x&(HOLE_SOUTHEAST|NOT_SOUTHEAST))
  493.                         == HOLE_SOUTHEAST)
  494.                         trace( fp, r-1, c+1,
  495.                             BOTTOM,
  496.                             FROM_NORTHWEST,
  497.                             r50+16, 1612,
  498.                             c50+33, 8388 );
  499.                     if ((x&(HOLE_SOUTH|NOT_SOUTH))
  500.                         == HOLE_SOUTH)
  501.                         trace( fp, r-1, c,
  502.                             BOTTOM,
  503.                             FROM_NORTH,
  504.                             r50+12, 5,
  505.                             c50+25, 0 );
  506.                     if ((x&(HOLE_SOUTHWEST|NOT_SOUTHWEST))
  507.                         == HOLE_SOUTHWEST)
  508.                         trace( fp, r-1, c-1,
  509.                             BOTTOM,
  510.                             FROM_NORTHEAST,
  511.                             r50+16, 1612,
  512.                             c50+16, 1612 );
  513.                     if ((x&(HOLE_WEST|NOT_WEST))
  514.                         == HOLE_WEST)
  515.                         trace( fp, r, c-1,
  516.                             BOTTOM,
  517.                             FROM_EAST,
  518.                             r50+25, 0,
  519.                             c50+12, 5 );
  520.                     if ((x&(HOLE_NORTHWEST|NOT_NORTHWEST))
  521.                         == HOLE_NORTHWEST)
  522.                         trace( fp, r+1, c-1,
  523.                             BOTTOM,
  524.                             FROM_SOUTHEAST,
  525.                             r50+33, 8388,
  526.                             c50+16, 1612 );
  527.                     }
  528.                 }
  529.             }
  530.     for (r = 0; r < Nrows; r++) /* reset hole-done indicator bits */
  531.         for (c = 0; c < Ncols; c++) {
  532.             x = GetCell( r, c, TOP );
  533.             if (x & HOLE) {
  534.                 SetCell( r, c, TOP, x&(~NOT_ALL) );
  535.                 x = GetCell( r, c, BOTTOM );
  536.                 SetCell( r, c, BOTTOM, x&(~NOT_ALL) );
  537.                 }
  538.             }
  539.     }
  540.  
  541. static void trace ( fp, r, c, s, d, lr, lrf, lc, lcf )
  542.     /* draw a trace with LINE statements */
  543.     FILE *fp;
  544.     register int r, c;
  545.     int s, d, lr, lrf, lc, lcf;
  546.     {
  547.     int r50, c50, a;
  548.     long x;
  549.  
  550.     /*
  551.     ** (r,c,s) gives the current cell; (r50,c50) maintains (r*50,c*50)
  552.     ** so we don't have to keep doing multiplies; d gives the FROM_x
  553.     ** direction we entered this cell from; a gives the FROM_x
  554.     ** direction (angle) of the line currently being built;
  555.     ** (lr.lrf,lc.lcf) gives the mil location (whole and fractional
  556.     ** part, maintained separately so we don't have to do floating
  557.     ** point math) of the last point connected.
  558.     */
  559.  
  560.     r50 = r*50;
  561.     c50 = c*50;
  562.     a = d; /* angle of trace is same as initial direction */
  563.     for (;;) { /* search for the terminating HOLE */
  564.         x = GetCell( r, c, s );
  565.         if (x & HOLE) { /* found it? */
  566. /*
  567. ** NOTE: we should really include a check here that the proper HOLE_x
  568. ** bit is turned on. for now, we assume it is.
  569. */
  570.             switch (d) { /* output the last LINE */
  571.             case FROM_NORTH:
  572.                 if (a != FROM_NORTH) {
  573.                     fprintf( fp, linstmt,
  574.                         lr, lrf, lc, lcf,
  575.                         r50+50, 0, c50+25, 0 );
  576.                     lr = r50+50;
  577.                     lc = c50+25;
  578.                     lrf = lcf = 0;
  579.                     }
  580.                 fprintf( fp, linstmt,
  581.                     lr, lrf, lc, lcf,
  582.                     r50+37, 5, c50+25, 0 );
  583.                 SetCell( r, c, s, x|NOT_NORTH );
  584.                 break;
  585.             case FROM_NORTHEAST:
  586.                 fprintf( fp, linstmt,
  587.                     lr, lrf, lc, lcf,
  588.                     r50+33, 8388, c50+33, 8388 );
  589.                 SetCell( r, c, s, x|NOT_NORTHEAST );
  590.                 break;
  591.             case FROM_EAST:
  592.                 if (a != FROM_EAST) {
  593.                     fprintf( fp, linstmt,
  594.                         lr, lrf, lc, lcf,
  595.                         r50+25, 0, c50+50, 0 );
  596.                     lr = r50+25;
  597.                     lc = c50+50;
  598.                     lrf = lcf = 0;
  599.                     }
  600.                 fprintf( fp, linstmt,
  601.                     lr, lrf, lc, lcf,
  602.                     r50+25, 0, c50+37, 5 );
  603.                 SetCell( r, c, s, x|NOT_EAST );
  604.                 break;
  605.             case FROM_SOUTHEAST:
  606.                 fprintf( fp, linstmt,
  607.                     lr, lrf, lc, lcf,
  608.                     r50+16, 1612, c50+33, 8388 );
  609.                 SetCell( r, c, s, x|NOT_SOUTHEAST );
  610.                 break;
  611.             case FROM_SOUTH:
  612.                 if (a != FROM_SOUTH) {
  613.                     fprintf( fp, linstmt,
  614.                         lr, lrf, lc, lcf,
  615.                         r50, 0, c50+25, 0 );
  616.                     lr = r50;
  617.                     lc = c50+25;
  618.                     lrf = lcf = 0;
  619.                     }
  620.                 fprintf( fp, linstmt,
  621.                     lr, lrf, lc, lcf,
  622.                     r50+12, 5, c50+25, 0 );
  623.                 SetCell( r, c, s, x|NOT_SOUTH );
  624.                 break;
  625.             case FROM_SOUTHWEST:
  626.                 fprintf( fp, linstmt,
  627.                     lr, lrf, lc, lcf,
  628.                     r50+16, 1612, c50+16, 1612 );
  629.                 SetCell( r, c, s, x|NOT_SOUTHWEST );
  630.                 break;
  631.             case FROM_WEST:
  632.                 if (a != FROM_WEST) {
  633.                     fprintf( fp, linstmt,
  634.                         lr, lrf, lc, lcf,
  635.                         r50+25, 0, c50, 0 );
  636.                     lr = r50+25;
  637.                     lc = c50;
  638.                     lrf = lcf = 0;
  639.                     }
  640.                 fprintf( fp, linstmt,
  641.                     lr, lrf, lc, lcf,
  642.                     r50+25, 0, c50+12, 5 );
  643.                 SetCell( r, c, s, x|NOT_WEST );
  644.                 break;
  645.             case FROM_NORTHWEST:
  646.                 fprintf( fp, linstmt,
  647.                     lr, lrf, lc, lcf,
  648.                     r50+33, 8388, c50+16, 1612 );
  649.                 SetCell( r, c, s, x|NOT_NORTHWEST );
  650.                 break;
  651.             default:
  652.                 fprintf( stderr, "internal error\n" );
  653.                 exit( -1 );
  654.                 break;
  655.                 }
  656.             return;
  657.             }
  658.  
  659.         /*
  660.         ** not a HOLE; keep walking along the trace. if the angle is
  661.         ** still right, just move along. otherwise, output a LINE
  662.         ** statement for any turns that are made, reset the last
  663.         ** point connected, and go to the next cell.
  664.         */
  665.  
  666.         switch (d) {
  667.         case FROM_NORTH:
  668.             if (x & LINE_VERTICAL) {
  669.                 if (a != FROM_NORTH) {
  670.                     fprintf( fp, linstmt,
  671.                         lr, lrf, lc, lcf,
  672.                         r50+50, 0, c50+25, 0 );
  673.                     lr = r50+50;
  674.                     lc = c50+25;
  675.                     lrf = lcf = 0;
  676.                     a = FROM_NORTH;
  677.                     }
  678.                 r--;  r50 -= 50;
  679.                 }
  680.             else if (x & CORNER_NORTHEAST) {
  681.                 if (a != FROM_NORTHWEST) {
  682.                     fprintf( fp, linstmt,
  683.                         lr, lrf, lc, lcf,
  684.                         r50+50, 0, c50+25, 0 );
  685.                     lr = r50+50;
  686.                     lc = c50+25;
  687.                     lrf = lcf = 0;
  688.                     a = FROM_NORTHWEST;
  689.                     }
  690.                 c++;  c50 += 50;
  691.                 d = FROM_WEST;
  692.                 }
  693.             else if (x & CORNER_NORTHWEST) {
  694.                 if (a != FROM_NORTHEAST) {
  695.                     fprintf( fp, linstmt,
  696.                         lr, lrf, lc, lcf,
  697.                         r50+50, 0, c50+25, 0 );
  698.                     lr = r50+50;
  699.                     lc = c50+25;
  700.                     lrf = lcf = 0;
  701.                     a = FROM_NORTHEAST;
  702.                     }
  703.                 c--;  c50 -= 50;
  704.                 d = FROM_EAST;
  705.                 }
  706.             else if (x & (BENT_NtoSE | BENT_NtoSW)) {
  707.                 if (a != FROM_NORTH) {
  708.                     fprintf( fp, linstmt,
  709.                         lr, lrf, lc, lcf,
  710.                         r50+50, 0, c50+25, 0 );
  711.                     lr = r50+50;
  712.                     lc = c50+25;
  713.                     lrf = lcf = 0;
  714.                     }
  715.                 fprintf( fp, linstmt,
  716.                     lr, lrf, lc, lcf,
  717.                     r50+25, 0, c50+25, 0 );
  718.                 lr = r50+25;
  719.                 lc = c50+25;
  720.                 lrf = lcf = 0;
  721.                 r--;  r50 -= 50;
  722.                 if (x & BENT_NtoSE) {
  723.                     d = a = FROM_NORTHWEST;
  724.                     c++;  c50 += 50;
  725.                     }
  726.                 else {
  727.                     d = a = FROM_NORTHEAST;
  728.                     c--;  c50 -= 50;
  729.                     }
  730.                 }
  731.             else if (x & (SHARP_NtoNE | SHARP_NtoNW)) {
  732.                 if (a != FROM_NORTH) {
  733.                     fprintf( fp, linstmt,
  734.                         lr, lrf, lc, lcf,
  735.                         r50+50, 0, c50+25, 0 );
  736.                     lr = r50+50;
  737.                     lc = c50+25;
  738.                     lrf = lcf = 0;
  739.                     }
  740.                 fprintf( fp, linstmt,
  741.                     lr, lrf, lc, lcf,
  742.                     r50+25, 0, c50+25, 0 );
  743.                 lr = r50+25;
  744.                 lc = c50+25;
  745.                 lrf = lcf = 0;
  746.                 r++;  r50 += 50;
  747.                 if (x & SHARP_NtoNE) {
  748.                     d = a = FROM_SOUTHWEST;
  749.                     c++;  c50 += 50;
  750.                     }
  751.                 else {
  752.                     d = a = FROM_SOUTHEAST;
  753.                     c--;  c50 -= 50;
  754.                     }
  755.                 }
  756.             else {
  757.                 fprintf( stderr, "internal error\n" );
  758.                 exit( -1 );
  759.                 }
  760.             break;
  761.         case FROM_NORTHEAST:
  762.             if (x & DIAG_NEtoSW) {
  763.                 r--;  r50 -= 50;
  764.                 c--;  c50 -= 50;
  765.                 }
  766.             else if (x & (BENT_StoNE | BENT_WtoNE)) {
  767.                 fprintf( fp, linstmt,
  768.                     lr, lrf, lc, lcf,
  769.                     r50+25, 0, c50+25, 0 );
  770.                 lr = r50+25;
  771.                 lc = c50+25;
  772.                 lrf = lcf = 0;
  773.                 if (x & BENT_StoNE) {
  774.                     d = a = FROM_NORTH;
  775.                     r--;  r50 -= 50;
  776.                     }
  777.                 else {
  778.                     d = a = FROM_EAST;
  779.                     c--;  c50 -= 50;
  780.                     }
  781.                 }
  782.             else if (x & (ANGLE_NEtoSE | ANGLE_NWtoNE)) {
  783.                 fprintf( fp, linstmt,
  784.                     lr, lrf, lc, lcf,
  785.                     r50+25, 0, c50+25, 0 );
  786.                 lr = r50+25;
  787.                 lc = c50+25;
  788.                 lrf = lcf = 0;
  789.                 if (x & ANGLE_NEtoSE) {
  790.                     d = a = FROM_NORTHWEST;
  791.                     r--;  r50 -= 50;
  792.                     c++;  c50 += 50;
  793.                     }
  794.                 else {
  795.                     d = a = FROM_SOUTHEAST;
  796.                     r++;  r50 += 50;
  797.                     c--;  c50 -= 50;
  798.                     }
  799.                 }
  800.             else if (x & (SHARP_NtoNE | SHARP_EtoNE)) {
  801.                 fprintf( fp, linstmt,
  802.                     lr, lrf, lc, lcf,
  803.                     r50+25, 0, c50+25, 0 );
  804.                 lr = r50+25;
  805.                 lc = c50+25;
  806.                 lrf = lcf = 0;
  807.                 if (x & SHARP_NtoNE) {
  808.                     d = a = FROM_SOUTH;
  809.                     r++;  r50 += 50;
  810.                     }
  811.                 else {
  812.                     d = a = FROM_WEST;
  813.                     c++;  c50 += 50;
  814.                     }
  815.                 }
  816.             else {
  817.                 fprintf( stderr, "internal error\n" );
  818.                 exit( -1 );
  819.                 }
  820.             break;
  821.         case FROM_EAST:
  822.             if (x & LINE_HORIZONTAL) {
  823.                 if (a != FROM_EAST) {
  824.                     fprintf( fp, linstmt,
  825.                         lr, lrf, lc, lcf,
  826.                         r50+25, 0, c50+50, 0 );
  827.                     lr = r50+25;
  828.                     lc = c50+50;
  829.                     lrf = lcf = 0;
  830.                     a = FROM_EAST;
  831.                     }
  832.                 c--;  c50 -= 50;
  833.                 }
  834.             else if (x & CORNER_NORTHEAST) {
  835.                 if (a != FROM_SOUTHEAST) {
  836.                     fprintf( fp, linstmt,
  837.                         lr, lrf, lc, lcf,
  838.                         r50+25, 0, c50+50, 0 );
  839.                     lr = r50+25;
  840.                     lc = c50+50;
  841.                     lrf = lcf = 0;
  842.                     a = FROM_SOUTHEAST;
  843.                     }
  844.                 r++;  r50 += 50;
  845.                 d = FROM_SOUTH;
  846.                 }
  847.             else if (x & CORNER_SOUTHEAST) {
  848.                 if (a != FROM_NORTHEAST) {
  849.                     fprintf( fp, linstmt,
  850.                         lr, lrf, lc, lcf,
  851.                         r50+25, 0, c50+50, 0 );
  852.                     lr = r50+25;
  853.                     lc = c50+50;
  854.                     lrf = lcf = 0;
  855.                     a = FROM_NORTHEAST;
  856.                     }
  857.                 r--;  r50 -= 50;
  858.                 d = FROM_NORTH;
  859.                 }
  860.             else if (x & (BENT_EtoSW | BENT_EtoNW)) {
  861.                 if (a != FROM_EAST) {
  862.                     fprintf( fp, linstmt,
  863.                         lr, lrf, lc, lcf,
  864.                         r50+25, 0, c50+50, 0 );
  865.                     lr = r50+25;
  866.                     lc = c50+50;
  867.                     lrf = lcf = 0;
  868.                     }
  869.                 fprintf( fp, linstmt,
  870.                     lr, lrf, lc, lcf,
  871.                     r50+25, 0, c50+25, 0 );
  872.                 lr = r50+25;
  873.                 lc = c50+25;
  874.                 lrf = lcf = 0;
  875.                 c--;  c50 -= 50;
  876.                 if (x & BENT_EtoSW) {
  877.                     d = a = FROM_NORTHEAST;
  878.                     r--;  r50 -= 50;
  879.                     }
  880.                 else {
  881.                     d = a = FROM_SOUTHEAST;
  882.                     r++;  r50 += 50;
  883.                     }
  884.                 }
  885.             else if (x & (SHARP_EtoNE | SHARP_EtoSE)) {
  886.                 if (a != FROM_EAST) {
  887.                     fprintf( fp, linstmt,
  888.                         lr, lrf, lc, lcf,
  889.                         r50+25, 0, c50+50, 0 );
  890.                     lr = r50+25;
  891.                     lc = c50+50;
  892.                     lrf = lcf = 0;
  893.                     }
  894.                 fprintf( fp, linstmt,
  895.                     lr, lrf, lc, lcf,
  896.                     r50+25, 0, c50+25, 0 );
  897.                 lr = r50+25;
  898.                 lc = c50+25;
  899.                 lrf = lcf = 0;
  900.                 c++;  c50 += 50;
  901.                 if (x & SHARP_EtoNE) {
  902.                     d = a = FROM_SOUTHWEST;
  903.                     r++;  r50 += 50;
  904.                     }
  905.                 else {
  906.                     d = a = FROM_NORTHWEST;
  907.                     r--;  r50 -= 50;
  908.                     }
  909.                 }
  910.             else {
  911.                 fprintf( stderr, "internal error\n" );
  912.                 exit( -1 );
  913.                 }
  914.             break;
  915.         case FROM_SOUTHEAST:
  916.             if (x & DIAG_SEtoNW) {
  917.                 r++;  r50 += 50;
  918.                 c--;  c50 -= 50;
  919.                 }
  920.             else if (x & (BENT_NtoSE | BENT_WtoSE)) {
  921.                 fprintf( fp, linstmt,
  922.                     lr, lrf, lc, lcf,
  923.                     r50+25, 0, c50+25, 0 );
  924.                 lr = r50+25;
  925.                 lc = c50+25;
  926.                 lrf = lcf = 0;
  927.                 if (x & BENT_NtoSE) {
  928.                     d = a = FROM_SOUTH;
  929.                     r++;  r50 += 50;
  930.                     }
  931.                 else {
  932.                     d = a = FROM_EAST;
  933.                     c--;  c50 -= 50;
  934.                     }
  935.                 }
  936.             else if (x & (ANGLE_NEtoSE | ANGLE_SEtoSW)) {
  937.                 fprintf( fp, linstmt,
  938.                     lr, lrf, lc, lcf,
  939.                     r50+25, 0, c50+25, 0 );
  940.                 lr = r50+25;
  941.                 lc = c50+25;
  942.                 lrf = lcf = 0;
  943.                 if (x & ANGLE_NEtoSE) {
  944.                     d = a = FROM_SOUTHWEST;
  945.                     r++;  r50 += 50;
  946.                     c++;  c50 += 50;
  947.                     }
  948.                 else {
  949.                     d = a = FROM_NORTHEAST;
  950.                     r--;  r50 -= 50;
  951.                     c--;  c50 -= 50;
  952.                     }
  953.                 }
  954.             else if (x & (SHARP_EtoSE | SHARP_StoSE)) {
  955.                 fprintf( fp, linstmt,
  956.                     lr, lrf, lc, lcf,
  957.                     r50+25, 0, c50+25, 0 );
  958.                 lr = r50+25;
  959.                 lc = c50+25;
  960.                 lrf = lcf = 0;
  961.                 if (x & SHARP_EtoSE) {
  962.                     d = a = FROM_WEST;
  963.                     c++;  c50 += 50;
  964.                     }
  965.                 else {
  966.                     d = a = FROM_NORTH;
  967.                     r--;  r50 -= 50;
  968.                     }
  969.                 }
  970.             else {
  971.                 fprintf( stderr, "internal error\n" );
  972.                 exit( -1 );
  973.                 }
  974.             break;
  975.         case FROM_SOUTH:
  976.             if (x & LINE_VERTICAL) {
  977.                 if (a != FROM_SOUTH) {
  978.                     fprintf( fp, linstmt,
  979.                         lr, lrf, lc, lcf,
  980.                         r50, 0, c50+25, 0 );
  981.                     lr = r50;
  982.                     lc = c50+25;
  983.                     lrf = lcf = 0;
  984.                     a = FROM_SOUTH;
  985.                     }
  986.                 r++;  r50 += 50;
  987.                 }
  988.             else if (x & CORNER_SOUTHEAST) {
  989.                 if (a != FROM_SOUTHWEST) {
  990.                     fprintf( fp, linstmt,
  991.                         lr, lrf, lc, lcf,
  992.                         r50, 0, c50+25, 0 );
  993.                     lr = r50;
  994.                     lc = c50+25;
  995.                     lrf = lcf = 0;
  996.                     a = FROM_SOUTHWEST;
  997.                     }
  998.                 c++;  c50 += 50;
  999.                 d = FROM_WEST;
  1000.                 }
  1001.             else if (x & CORNER_SOUTHWEST) {
  1002.                 if (a != FROM_SOUTHEAST) {
  1003.                     fprintf( fp, linstmt,
  1004.                         lr, lrf, lc, lcf,
  1005.                         r50, 0, c50+25, 0 );
  1006.                     lr = r50;
  1007.                     lc = c50+25;
  1008.                     lrf = lcf = 0;
  1009.                     a = FROM_SOUTHEAST;
  1010.                     }
  1011.                 c--;  c50 -= 50;
  1012.                 d = FROM_EAST;
  1013.                 }
  1014.             else if (x & (BENT_StoNE | BENT_StoNW)) {
  1015.                 if (a != FROM_SOUTH) {
  1016.                     fprintf( fp, linstmt,
  1017.                         lr, lrf, lc, lcf,
  1018.                         r50, 0, c50+25, 0 );
  1019.                     lr = r50;
  1020.                     lc = c50+25;
  1021.                     lrf = lcf = 0;
  1022.                     }
  1023.                 fprintf( fp, linstmt,
  1024.                     lr, lrf, lc, lcf,
  1025.                     r50+25, 0, c50+25, 0 );
  1026.                 lr = r50+25;
  1027.                 lc = c50+25;
  1028.                 lrf = lcf = 0;
  1029.                 r++;  r50 += 50;
  1030.                 if (x & BENT_StoNE) {
  1031.                     d = a = FROM_SOUTHWEST;
  1032.                     c++;  c50 += 50;
  1033.                     }
  1034.                 else {
  1035.                     d = a = FROM_SOUTHEAST;
  1036.                     c--;  c50 -= 50;
  1037.                     }
  1038.                 }
  1039.             else if (x & (SHARP_StoSE | SHARP_StoSW)) {
  1040.                 if (a != FROM_SOUTH) {
  1041.                     fprintf( fp, linstmt,
  1042.                         lr, lrf, lc, lcf,
  1043.                         r50, 0, c50+25, 0 );
  1044.                     lr = r50;
  1045.                     lc = c50+25;
  1046.                     lrf = lcf = 0;
  1047.                     }
  1048.                 fprintf( fp, linstmt,
  1049.                     lr, lrf, lc, lcf,
  1050.                     r50+25, 0, c50+25, 0 );
  1051.                 lr = r50+25;
  1052.                 lc = c50+25;
  1053.                 lrf = lcf = 0;
  1054.                 r--;  r50 -= 50;
  1055.                 if (x & SHARP_StoSE) {
  1056.                     d = a = FROM_NORTHWEST;
  1057.                     c++;  c50 += 50;
  1058.                     }
  1059.                 else {
  1060.                     d = a = FROM_NORTHEAST;
  1061.                     c--;  c50 -= 50;
  1062.                     }
  1063.                 }
  1064.             else {
  1065.                 fprintf( stderr, "internal error\n" );
  1066.                 exit( -1 );
  1067.                 }
  1068.             break;
  1069.         case FROM_SOUTHWEST:
  1070.             if (x & DIAG_NEtoSW) {
  1071.                 r++;  r50 += 50;
  1072.                 c++;  c50 += 50;
  1073.                 }
  1074.             else if (x & (BENT_NtoSW | BENT_EtoSW)) {
  1075.                 fprintf( fp, linstmt,
  1076.                     lr, lrf, lc, lcf,
  1077.                     r50+25, 0, c50+25, 0 );
  1078.                 lr = r50+25;
  1079.                 lc = c50+25;
  1080.                 lrf = lcf = 0;
  1081.                 if (x & BENT_NtoSW) {
  1082.                     d = a = FROM_SOUTH;
  1083.                     r++;  r50 += 50;
  1084.                     }
  1085.                 else {
  1086.                     d = a = FROM_WEST;
  1087.                     c++;  c50 += 50;
  1088.                     }
  1089.                 }
  1090.             else if (x & (ANGLE_SEtoSW | ANGLE_SWtoNW)) {
  1091.                 fprintf( fp, linstmt,
  1092.                     lr, lrf, lc, lcf,
  1093.                     r50+25, 0, c50+25, 0 );
  1094.                 lr = r50+25;
  1095.                 lc = c50+25;
  1096.                 lrf = lcf = 0;
  1097.                 if (x & ANGLE_SEtoSW) {
  1098.                     d = a = FROM_NORTHWEST;
  1099.                     r--;  r50 -= 50;
  1100.                     c++;  c50 += 50;
  1101.                     }
  1102.                 else {
  1103.                     d = a = FROM_SOUTHEAST;
  1104.                     r++;  r50 += 50;
  1105.                     c--;  c50 -= 50;
  1106.                     }
  1107.                 }
  1108.             else if (x & (SHARP_StoSW | SHARP_WtoSW)) {
  1109.                 fprintf( fp, linstmt,
  1110.                     lr, lrf, lc, lcf,
  1111.                     r50+25, 0, c50+25, 0 );
  1112.                 lr = r50+25;
  1113.                 lc = c50+25;
  1114.                 lrf = lcf = 0;
  1115.                 if (x & SHARP_StoSW) {
  1116.                     d = a = FROM_NORTH;
  1117.                     r--;  r50 -= 50;
  1118.                     }
  1119.                 else {
  1120.                     d = a = FROM_EAST;
  1121.                     c--;  c50 -= 50;
  1122.                     }
  1123.                 }
  1124.             else {
  1125.                 fprintf( stderr, "internal error\n" );
  1126.                 exit( -1 );
  1127.                 }
  1128.             break;
  1129.         case FROM_WEST:
  1130.             if (x & LINE_HORIZONTAL) {
  1131.                 if (a != FROM_WEST) {
  1132.                     fprintf( fp, linstmt,
  1133.                         lr, lrf, lc, lcf,
  1134.                         r50+25, 0, c50, 0 );
  1135.                     lr = r50+25;
  1136.                     lc = c50;
  1137.                     lrf = lcf = 0;
  1138.                     a = FROM_WEST;
  1139.                     }
  1140.                 c++;  c50 += 50;
  1141.                 }
  1142.             else if (x & CORNER_NORTHWEST) {
  1143.                 if (a != FROM_SOUTHWEST) {
  1144.                     fprintf( fp, linstmt,
  1145.                         lr, lrf, lc, lcf,
  1146.                         r50+25, 0, c50, 0 );
  1147.                     lr = r50+25;
  1148.                     lc = c50;
  1149.                     lrf = lcf = 0;
  1150.                     a = FROM_SOUTHWEST;
  1151.                     }
  1152.                 r++;  r50 += 50;
  1153.                 d = FROM_SOUTH;
  1154.                 }
  1155.             else if (x & CORNER_SOUTHWEST) {
  1156.                 if (a != FROM_NORTHWEST) {
  1157.                     fprintf( fp, linstmt,
  1158.                         lr, lrf, lc, lcf,
  1159.                         r50+25, 0, c50, 0 );
  1160.                     lr = r50+25;
  1161.                     lc = c50;
  1162.                     lrf = lcf = 0;
  1163.                     a = FROM_NORTHWEST;
  1164.                     }
  1165.                 r--;  r50 -= 50;
  1166.                 d = FROM_NORTH;
  1167.                 }
  1168.             else if (x & (BENT_WtoNE | BENT_WtoSE)) {
  1169.                 if (a != FROM_WEST) {
  1170.                     fprintf( fp, linstmt,
  1171.                         lr, lrf, lc, lcf,
  1172.                         r50+25, 0, c50, 0 );
  1173.                     lr = r50+25;
  1174.                     lc = c50;
  1175.                     lrf = lcf = 0;
  1176.                     }
  1177.                 fprintf( fp, linstmt,
  1178.                     lr, lrf, lc, lcf,
  1179.                     r50+25, 0, c50+25, 0 );
  1180.                 lr = r50+25;
  1181.                 lc = c50+25;
  1182.                 lrf = lcf = 0;
  1183.                 c++;  c50 += 50;
  1184.                 if (x & BENT_WtoNE) {
  1185.                     d = a = FROM_SOUTHWEST;
  1186.                     r++;  r50 += 50;
  1187.                     }
  1188.                 else {
  1189.                     d = a = FROM_NORTHWEST;
  1190.                     r--;  r50 -= 50;
  1191.                     }
  1192.                 }
  1193.             else if (x & (SHARP_WtoNW | SHARP_WtoSW)) {
  1194.                 if (a != FROM_WEST) {
  1195.                     fprintf( fp, linstmt,
  1196.                         lr, lrf, lc, lcf,
  1197.                         r50+25, 0, c50, 0 );
  1198.                     lr = r50+25;
  1199.                     lc = c50;
  1200.                     lrf = lcf = 0;
  1201.                     }
  1202.                 fprintf( fp, linstmt,
  1203.                     lr, lrf, lc, lcf,
  1204.                     r50+25, 0, c50+25, 0 );
  1205.                 lr = r50+25;
  1206.                 lc = c50+25;
  1207.                 lrf = lcf = 0;
  1208.                 c--;  c50 -= 50;
  1209.                 if (x & SHARP_WtoNW) {
  1210.                     d = a = FROM_SOUTHEAST;
  1211.                     r++;  r50 += 50;
  1212.                     }
  1213.                 else {
  1214.                     d = a = FROM_NORTHEAST;
  1215.                     r--;  r50 -= 50;
  1216.                     }
  1217.                 }
  1218.             else {
  1219.                 fprintf( stderr, "internal error\n" );
  1220.                 exit( -1 );
  1221.                 }
  1222.             break;
  1223.         case FROM_NORTHWEST:
  1224.             if (x & DIAG_SEtoNW) {
  1225.                 r--;  r50 -= 50;
  1226.                 c++;  c50 += 50;
  1227.                 }
  1228.             else if (x & (BENT_EtoNW | BENT_StoNW)) {
  1229.                 fprintf( fp, linstmt,
  1230.                     lr, lrf, lc, lcf,
  1231.                     r50+25, 0, c50+25, 0 );
  1232.                 lr = r50+25;
  1233.                 lc = c50+25;
  1234.                 lrf = lcf = 0;
  1235.                 if (x & BENT_EtoNW) {
  1236.                     d = a = FROM_WEST;
  1237.                     c++;  c50 += 50;
  1238.                     }
  1239.                 else {
  1240.                     d = a = FROM_NORTH;
  1241.                     r--;  r50 -= 50;
  1242.                     }
  1243.                 }
  1244.             else if (x & (ANGLE_SWtoNW | ANGLE_NWtoNE)) {
  1245.                 fprintf( fp, linstmt,
  1246.                     lr, lrf, lc, lcf,
  1247.                     r50+25, 0, c50+25, 0 );
  1248.                 lr = r50+25;
  1249.                 lc = c50+25;
  1250.                 lrf = lcf = 0;
  1251.                 if (x & ANGLE_SWtoNW) {
  1252.                     d = a = FROM_NORTHEAST;
  1253.                     r--;  r50 -= 50;
  1254.                     c--;  c50 -= 50;
  1255.                     }
  1256.                 else {
  1257.                     d = a = FROM_SOUTHWEST;
  1258.                     r++;  r50 += 50;
  1259.                     c++;  c50 += 50;
  1260.                     }
  1261.                 }
  1262.             else if (x & (SHARP_WtoNW | SHARP_NtoNW)) {
  1263.                 fprintf( fp, linstmt,
  1264.                     lr, lrf, lc, lcf,
  1265.                     r50+25, 0, c50+25, 0 );
  1266.                 lr = r50+25;
  1267.                 lc = c50+25;
  1268.                 lrf = lcf = 0;
  1269.                 if (x & SHARP_WtoNW) {
  1270.                     d = a = FROM_EAST;
  1271.                     c--;  c50 -= 50;
  1272.                     }
  1273.                 else {
  1274.                     d = a = FROM_SOUTH;
  1275.                     r++;  r50 += 50;
  1276.                     }
  1277.                 }
  1278.             else {
  1279.                 fprintf( stderr, "internal error\n" );
  1280.                 exit( -1 );
  1281.                 }
  1282.             break;
  1283.         default:
  1284.             fprintf( stderr, "internal error\n" );
  1285.             exit( -1 );
  1286.             break;
  1287.             }
  1288.         }
  1289.     }
  1290.  
  1291. struct x { /* group the bit templates for an object */
  1292.     long t;            /* the object type    */
  1293.     char t0[ZOOM0][ZOOM0];    /* tiny zoom template    */
  1294.     char t1[ZOOM1][ZOOM1];    /* small zoom template    */
  1295.     char t2[ZOOM2][ZOOM2];    /* medium zoom template    */
  1296.     char t3[ZOOM3][ZOOM3];    /* large zoom template    */
  1297.     };
  1298.  
  1299. extern struct x y1[]; /* hole templates */
  1300. extern struct x y2[]; /* hole-related templates */
  1301. extern struct x y3[]; /* non-hole-related templates */
  1302.  
  1303. extern int z1; /* number of hole types            */
  1304. extern int z2; /* number of hole-related types        */
  1305. extern int z3; /* number of non-hole-related types    */
  1306.  
  1307. #define domap1(v)    { int i; \
  1308.               for (i = 0; i < z1; i++) { \
  1309.                 if (v & (y1[i].t)) { \
  1310.                     if (zoom == 0) \
  1311.                         bit |= y1[i].t0[ir][ic]; \
  1312.                     else if (zoom == 1) \
  1313.                         bit |= y1[i].t1[ir][ic]; \
  1314.                     else if (zoom == 2) \
  1315.                         bit |= y1[i].t2[ir][ic]; \
  1316.                     else if (zoom == 3) \
  1317.                         bit |= y1[i].t3[ir][ic]; \
  1318.                     } \
  1319.                 if (bit) \
  1320.                     break; \
  1321.                 } }
  1322.  
  1323. #define domap2(v)    { int i; \
  1324.               for (i = 0; i < z2; i++) { \
  1325.                 if (v & (y2[i].t)) { \
  1326.                     if (zoom == 0) \
  1327.                         bit |= y2[i].t0[ir][ic]; \
  1328.                     else if (zoom == 1) \
  1329.                         bit |= y2[i].t1[ir][ic]; \
  1330.                     else if (zoom == 2) \
  1331.                         bit |= y2[i].t2[ir][ic]; \
  1332.                     else if (zoom == 3) \
  1333.                         bit |= y2[i].t3[ir][ic]; \
  1334.                     } \
  1335.                 if (bit) \
  1336.                     break; \
  1337.                 } }
  1338.  
  1339. #define domap3(v)    { int i; \
  1340.               for (i = 0; i < z3; i++) { \
  1341.                 if (v & (y3[i].t)) { \
  1342.                     if (zoom == 0) \
  1343.                         bit |= y3[i].t0[ir][ic]; \
  1344.                     else if (zoom == 1) \
  1345.                         bit |= y3[i].t1[ir][ic]; \
  1346.                     else if (zoom == 2) \
  1347.                         bit |= y3[i].t2[ir][ic]; \
  1348.                     else if (zoom == 3) \
  1349.                         bit |= y3[i].t3[ir][ic]; \
  1350.                     } \
  1351.                 if (bit) \
  1352.                     break; \
  1353.                 } }
  1354.  
  1355. static void map ( v0, v1, ir, fp ) /* map a cell to the image */
  1356.     long v0, v1;
  1357.     int ir;
  1358.     FILE *fp;
  1359.     {
  1360.     register int ic, bit;
  1361.  
  1362.     for (ic = 0; ic < size[zoom]; ic++) { /* do each scan column */
  1363.         bit = 0;
  1364.         if (v0 & HOLE) {
  1365.             if (currnt & H) /* plot holes? */
  1366.                 domap1( v0 );
  1367.             if (!bit && (currnt & T)) /* plot top-side? */
  1368.                 domap2( v0 );
  1369.             if (!bit && (currnt & B)) /* plot bottom-side? */
  1370.                 domap2( v1 );
  1371.             }
  1372.         else {
  1373.             if (v0 && (currnt & T)) /* plot top-side? */
  1374.                 domap3( v0 );
  1375.             if (!bit && v1 && (currnt & B)) /* plot bottom-side? */
  1376.                 domap3( v1 );
  1377.             }
  1378.         outbit( bit, fp );
  1379.         }
  1380.     }
  1381.  
  1382. static int shift; /* how far to shift next bit */
  1383. static char byte; /* the byte buffer */
  1384.  
  1385. static void initbit () { /* initialize bit output */
  1386.     byte = 0;
  1387.     shift = 7;
  1388.     }
  1389.  
  1390. static void flushbit ( fp ) /* flush bit output */
  1391.     FILE *fp;
  1392.     {
  1393.     if (shift != 7) /* buffer empty? */
  1394.         putc( byte, fp ); /* no, output partial byte */
  1395.     }
  1396.  
  1397. static void outbit( bit, fp ) /* output a bit using byte buffering */
  1398.     int bit;
  1399.     FILE *fp;
  1400.     {
  1401.     byte |= ((char)bit << shift);
  1402.     if (!shift) {
  1403.         putc( byte, fp );
  1404.         byte = 0;
  1405.         shift = 7;
  1406.         }
  1407.     else
  1408.         shift--;
  1409.     }
  1410.