home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / os2 / hpgl312.zip / HPGL.C < prev    next >
C/C++ Source or Header  |  1993-04-18  |  39KB  |  1,652 lines

  1. /*
  2.    Copyright (c) 1991 - 1993 Heinz W. Werntges.  All rights reserved.
  3.    Distributed by Free Software Foundation, Inc.
  4.  
  5. This file is part of HP2xx.
  6.  
  7. HP2xx is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  9. to anyone for the consequences of using it or for whether it serves any
  10. particular purpose or works at all, unless he says so in writing.  Refer
  11. to the GNU General Public License, Version 2 or later, for full details.
  12.  
  13. Everyone is granted permission to copy, modify and redistribute
  14. HP2xx, but only under the conditions described in the GNU General Public
  15. License.  A copy of this license is supposed to have been
  16. given to you along with HP2xx so you can know your rights and
  17. responsibilities.  It should be in a file named COPYING.  Among other
  18. things, the copyright notice and this notice must be preserved on all
  19. copies.
  20.  
  21. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  22. */
  23.  
  24. /** HPGL.c: HPGL parser & i/o part of HP2xx (based on D. Donath's "HPtoGF.c")
  25.  **
  26.  ** 91/01/13  V 1.00  HWW  Originating
  27.  ** 91/01/19  V 1.01  HWW  reorganized
  28.  ** 91/01/24  V 1.02  HWW  ESC.-Sequences acknowledged (preliminary!!)
  29.  ** 91/01/29  V 1.03  HWW  Incl. SUN portation
  30.  ** 91/01/31  V 1.04  HWW  Parser: ESC sequences should be skipped now
  31.  ** 91/02/10  V 1.05  HWW  Parser renewed
  32.  ** 91/02/15  V 1.06  HWW  stdlib.h supported
  33.  ** 91/02/19  V 1.07a HWW  parser refined, bugs fixed
  34.  ** 91/06/09  V 1.08  HWW  New options added; some restructuring
  35.  ** 91/06/16  V 1.09  HWW  VGA mode added; some renaming; silent_mode!
  36.  ** 91/06/20  V 1.10  HWW  Rotation added
  37.  ** 91/10/15  V 1.11  HWW  ANSI_C; header files reorganized
  38.  ** 91/10/20  V 1.11a HWW  VAX_C support
  39.  ** 91/10/25  V 1.11b HWW  Support of LT; and LT0; (line type, partial)
  40.  ** 91/11/20  V 1.12  HWW  SPn; support: many changes!
  41.  ** 91/11/21  V 1.12b HWW  First comma in "PA,xxxx,yyyy..." accepted
  42.  ** 91/12/22  V 1.13  HWW  Multiple MOVE compression; "plot_rel", "old_pen"
  43.  ** 92/01/13  V 1.13c HWW  VAX problem with ungetc()/fscanf() fixed; bug fixed
  44.  ** 92/01/15  V 1.13d HWW  "vga" --> "pre"
  45.  ** 92/01/30  V 1.14c HWW  Parser: no need of ';', better portable
  46.  ** 92/02/06  V 1.15a HWW  Parser: AR, AA, CI, read_float() added;
  47.  **               toupper() removed (MACH problems)
  48.  ** 92/02/19  V 1.16c HWW  LB etc. supported
  49.  ** 92/02/23  V 1.17b HWW  LB etc. improved, PG supported
  50.  ** 92/02/25  V 1.17c HWW  Parser improved: SP, LT, multi-mv suppression
  51.  ** 92/03/01  V 1.17d HWW  Char sizes: debugged
  52.  ** 92/03/03  V 1.17e HWW  LB_Mode introduced
  53.  ** 92/04/15  V 1.17f HWW  Width x Height limit assumed
  54.  ** 92/05/21  V 1.18a HWW  Multiple-file usage
  55.  ** 92/05/28  V 1.19a HWW  XT, YT, TL, SM added
  56.  ** 92/10/20  V 1.20c HWW  More line types added (debugged)
  57.  ** 92/11/08  V 1.20d HWW  Interval of active pages
  58.  ** 92/12/13  V 1.20e HWW  truesize option added
  59.  ** 93/02/10  V 1.21a HWW  Arcs & circles now properly closed;
  60.  **               Bug fixed: SC does not interfere with last move
  61.  ** 93/03/10  V 1.21b HWW  Bug fixed in LT scanner part
  62.  ** 93/03/22, V 1.21c HWW  HYPOT() workaround for a weird BCC behavior;
  63.  ** 93/04/02           Line_Generator(): Case *pb==*pa caught
  64.  ** 93/04/13  V 1.22a HWW  UC supported (code by Alois Treindl)
  65.  **/
  66.  
  67. #include <stdio.h>
  68. #include <stdlib.h>
  69. #include <string.h>
  70. #include <ctype.h>
  71. #include <math.h>
  72. #include "bresnham.h"
  73. #include "hp2xx.h"
  74. #include "chardraw.h"
  75.  
  76.  
  77. #define    ETX        '\003'
  78.  
  79. #define P1X_default    603.0    /* DIN A4 defaults    */
  80. #define P1Y_default    521.0
  81. #define P2X_default    10603.0
  82. #define P2Y_default    7721.0
  83.  
  84.  
  85. #ifdef __TURBOC__
  86. #define    HYPOT(x,y)    sqrt((x)*(x)+(y)*(y))
  87. #else
  88. #define    HYPOT(x,y)    hypot(x,y)
  89. #endif
  90.  
  91.  
  92.                 /* Line type selected by HP-GL code    */
  93. LineType    GlobalLineType = LT_default;
  94.                 /* Currently effective line type    */
  95. LineType    CurrentLineType= LT_default;
  96.  
  97.  
  98.  
  99. extern    TextPar    tp;
  100.  
  101. float        xmin, xmax, ymin, ymax, neg_ticklen, pos_ticklen;
  102. double        Diag_P1_P2, glb_pat_len, cur_pat_len, pat_pos;
  103. HPGL_Pt        p_last    = {M_PI, M_PI};    /* Init. to "impossible" values */
  104. HPGL_Pt        HP_pos    = {0};        /* Actual plotter pen position     */
  105. HPGL_Pt        P1    = {P1X_default, P1Y_default}; /* Scaling points    */
  106. HPGL_Pt        P2    = {P2X_default, P2Y_default};
  107.  
  108. static    float    HP_to_xdots, HP_to_ydots;
  109. static    float    rot_cos, rot_sin;
  110.  
  111. static    rotate_flag    = FALSE;    /* Flags tec external to HP-GL    */
  112. static    scale_flag    = FALSE;
  113. static    mv_flag     = FALSE;
  114. #ifdef    ATARI
  115. extern    silent_mode    = FALSE;    /* Don't clobber ATARI preview!    */
  116. #else
  117. static    silent_mode    = FALSE;
  118. #endif
  119. static    record_off    = FALSE;
  120. static    first_page    = 0;
  121. static    last_page    = 0;
  122. static    n_unexpected    = 0;
  123. static    n_unknown    = 0;
  124. static    page_number    = 1;
  125. static    long vec_cntr_r    = 0L;
  126. static    long vec_cntr_w    = 0L;
  127. static    short    pen    = -1;
  128. static    short pens_in_use= 0;
  129. static    pen_down    = FALSE;    /* Internal HP-GL book-keeping:    */
  130. static    plot_rel    = FALSE;
  131. static    char    StrTerm    = ETX;        /* String terminator char    */
  132. static    char    strbuf[MAX_LB_LEN+1] = {0};
  133. static    char    symbol_char = '\0';    /* Char    in Symbol Mode (0=off)    */
  134. static    HPGL_Pt    S1    = {P1X_default, P1Y_default};    /* Scaled     */
  135. static    HPGL_Pt    S2    = {P2X_default, P2Y_default};    /* points    */
  136. static    HPGL_Pt    Q;    /* Delta-P/Delta-S: Initialized with first SC     */
  137.  
  138.  
  139. static    FILE    *td;
  140.  
  141.  
  142.  
  143. /* Known HPGL commands, ASCII-coded as High-byte/low-byte int's    */
  144.  
  145. #define AA    0x4141
  146. #define AF    0x4146
  147. #define AH    0x4148
  148. #define AR    0x4152
  149. #define BL    0x424C
  150. #define CI    0x4349
  151. #define CP    0x4350
  152. #define DF    0x4446
  153. #define DI    0x4449
  154. #define DR    0x4452
  155. #define DT    0x4454
  156. #define ES    0x4553
  157. #define IN    0x494E
  158. #define IP    0x4950
  159. #define LB    0x4C42
  160. #define LO    0x4C4F
  161. #define LT    0x4C54
  162. #define OP    0x4F50
  163. #define PA    0x5041
  164. #define PB    0x5042
  165. #define PD    0x5044
  166. #define PG    0x5047
  167. #define PR    0x5052
  168. #define PU    0x5055
  169. #define SC    0x5343
  170. #define SI    0x5349
  171. #define SL    0x534C
  172. #define SM    0x534D
  173. #define SP    0x5350
  174. #define SR    0x5352
  175. #define TL    0x544C
  176. #define UC    0x5543
  177. #define WD    0x5744
  178. #define XT    0x5854
  179. #define YT    0x5954
  180.  
  181.  
  182.  
  183.  
  184. void    par_err_exit (short code, short cmd)
  185. {
  186. char    *msg;
  187.  
  188.   switch(code)
  189.   {
  190.     case 0:    msg = "Illegal parameters";        break;
  191.     case 1:    msg = "Error in first parameter";    break;
  192.     case 2:    msg = "No second parameter";        break;
  193.     case 3:    msg = "No third parameter";        break;
  194.     case 4:    msg = "No fourth parameter";        break;
  195.     case 98:    msg = "sscanf error: corrupted file?";    break;
  196.     case 99:
  197.     default:    msg = "Internal error";            break;
  198.   }
  199.   fprintf(stderr,"\nError in command %c%c: %s\n", cmd>>8, cmd&0xFF, msg);
  200.   fprintf(stderr," @ Cmd %ld\n", vec_cntr_w);
  201.   exit(ERROR);
  202. }
  203.  
  204.  
  205.  
  206.  
  207. void    HPcoord_to_dotcoord (HPGL_Pt *HP_P, DevPt *DevP)
  208. {
  209.   DevP->x = (int) ((HP_P->x - xmin) * HP_to_xdots);
  210.   DevP->y = (int) ((HP_P->y - ymin) * HP_to_ydots);
  211. }
  212.  
  213.  
  214.  
  215. void    init_HPGL (FILE *tD, PAR *pp)
  216. {
  217. /**
  218.  ** Re-init. global var's for multiple-file applications
  219.  **/
  220.  
  221.   td = tD;
  222.   silent_mode    = pp->quiet;
  223.   xmin        = pp->x0;
  224.   ymin        = pp->y0;
  225.   xmax        = pp->x1;
  226.   ymax        = pp->y1;
  227.  
  228.   pens_in_use    = 0;
  229.  
  230.   /**
  231.    ** Record ON if no page selected (pp->page == 0)!
  232.    **/
  233.   first_page    = pp->first_page;    /* May be 0     */
  234.   last_page    = pp->last_page;    /* May be 0     */
  235.   page_number    = 1;
  236.   record_off    =     (first_page > page_number)
  237.           || ((last_page  < page_number) && (last_page > 0));
  238.  
  239.   rotate_flag    = (pp->rotation != 0.0) ? TRUE : FALSE;
  240.   if (rotate_flag)
  241.   {
  242.     rot_cos = cos (M_PI * pp->rotation / 180.0);
  243.     rot_sin = sin (M_PI * pp->rotation / 180.0);
  244.   }
  245.  
  246.   vec_cntr_r    = 0L;
  247.   vec_cntr_w    = 0L;
  248.  
  249.   reset_HPGL();
  250. }
  251.  
  252.  
  253.  
  254. void    reset_HPGL (void)
  255. {
  256.   p_last.x    = p_last.y = M_PI;
  257.   pen_down     = FALSE;
  258.   plot_rel    = FALSE;
  259.   pen        = -1;
  260.   n_unexpected    = 0;
  261.   n_unknown    = 0;
  262.   mv_flag     = FALSE;
  263.  
  264.   GlobalLineType= CurrentLineType = LT_default;
  265.  
  266.   StrTerm    = ETX;
  267.   strbuf[0]    = '\0';
  268.  
  269.   P1.x        = P1X_default;
  270.   P1.y        = P1Y_default;
  271.   P2.x        = P2X_default;
  272.   P2.y        = P2Y_default;
  273.   Diag_P1_P2    = HYPOT (P2.x - P1.x, P2.y - P1.y);
  274.   glb_pat_len    = cur_pat_len = 0.04 * Diag_P1_P2;
  275.   pat_pos    = 0.0;
  276.   scale_flag    = FALSE;
  277.   S1        = P1;
  278.   S2        = P2;
  279.   Q.x        = Q.y = 1.0;
  280.   HP_pos.x    = HP_pos.y = 0.0;
  281.   neg_ticklen    = 0.005;    /* 0.5 %    */
  282.   pos_ticklen    = 0.005;
  283.   symbol_char    = '\0';
  284.  
  285.   init_text_par();
  286. }
  287.  
  288.  
  289.  
  290. int    read_float (float *pnum, FILE *hd)
  291. /**
  292.  ** Main work-horse for parameter input:
  293.  **
  294.  ** Search for next number, skipping white space but return if mnemonic met.
  295.  ** If found, read in number
  296.  **    returns    0 if valid number
  297.  **        1 if command ended
  298.  **        2 if scanf failed (possibly corrupted file)
  299.  **          EOF if EOF met
  300.  **/
  301. {
  302. int    c;
  303. char    *ptr, numbuf[80];
  304.  
  305.   for ( c=getc(hd); (c!='.')&&(c!='+')&&(c!='-')&&((c<'0')||(c>'9')) ; c=getc(hd) )
  306.   {
  307.     if (c==EOF)        /* Wait for number    */
  308.         return EOF;    /* Should not happen    */
  309.     if (c==';')
  310.         return  1;    /* Terminator reached    */
  311.     if (((c >= 'A') && (c <= 'Z')) ||
  312.         ((c >= 'a') && (c <= 'a')) || (c==ESC))
  313.     {
  314.         ungetc (c, hd);
  315.         return  1;    /* Next Mnemonic reached*/
  316.     }
  317.   }
  318.                 /* Number found: Get it    */
  319.   ptr = numbuf;
  320.   for (*ptr++ = c, c=getc(hd); ((c>='0')&&(c<='9'))||(c=='.'); c=getc(hd) )
  321.     *ptr++ = c;        /* Read number        */
  322.   *ptr='\0';
  323.   if (c!=EOF)
  324.     ungetc (c, hd);
  325.  
  326.   if (sscanf(numbuf,"%f", pnum) != 1)
  327.     return 11;        /* Should never happen    */
  328.   return 0;
  329. }
  330.  
  331.  
  332.  
  333.  
  334. void    read_string (char *buf, FILE *hd)
  335. {
  336. int    c, n;
  337.  
  338.   for (n=0,c = getc(hd); (c!=EOF) && (c!=StrTerm); c = getc(hd))
  339.     if (n++ <MAX_LB_LEN)
  340.         *buf++ = c;
  341.   if (c==StrTerm && c!=ETX)
  342.     *buf++ = c;
  343.   *buf = '\0';
  344. }
  345.  
  346.  
  347.  
  348.  
  349. void    read_symbol_char (FILE *hd)
  350. {
  351. int    c;
  352.  
  353.   for (c = getc(hd); /* ended by switch{} */ ; c = getc(hd))
  354.     switch (c)
  355.     {
  356.       case ' ':
  357.       case _HT:
  358.       case _LF:
  359.         break;        /* Skip white space        */
  360.       case _CR:
  361.       case EOF:
  362.       case ';':        /* CR or "term" end symbol mode    */
  363.         symbol_char = '\0';
  364.         return;
  365.       default:
  366.         if (c < ' ' || c > '~')
  367.             break;    /* Ignore unprintable chars    */
  368.         else
  369.         {
  370.             symbol_char = c;
  371.             return;
  372.         }
  373.     }
  374. }
  375.  
  376.  
  377.  
  378.  
  379. void    evaluate_HPGL (PAR *pp, DevPt *p_maxdot)
  380. {
  381. /**
  382.  ** Set some conversion factors for transformation from HP-GL coordinates
  383.  ** (as given in the temp. file) into mm or pel numbers.
  384.  **
  385.  ** # points (dots) in any direction = range [mm] * 1in/25.4mm * #dots/in
  386.  **/
  387.  
  388. HPGL_Pt    HP_Pt;
  389. double    dot_ratio, Dx, Dy, tmp_w, tmp_h;
  390. char    *dir_str;
  391.  
  392.   Dx = xmax - xmin;
  393.   Dy = ymax - ymin;
  394.   dot_ratio = (double) pp->dpi_y / (double) pp->dpi_x;
  395.  
  396.   /* Width  assuming given height:    */
  397.   tmp_w     = pp->height * Dx / Dy * pp->aspectfactor;
  398.   /* Height assuming given width:    */
  399.   tmp_h     = pp->width  * Dy / Dx / pp->aspectfactor;
  400.  
  401.   /**
  402.    ** EITHER width OR height MUST be the correct limit. The other will
  403.    ** be adapted. Adaptation of both is inconsistent, except in truesize mode.
  404.    **/
  405.  
  406.   if (pp->truesize)
  407.   {
  408.     pp->width    = Dx / 40.0;    /* Ignore -w, take natural HP-GL range    */
  409.     pp->height    = Dy / 40.0;    /* Ignore -h, take natural HP-GL range    */
  410.     HP_to_xdots    = (float) (pp->dpi_x / 1016.0);    /* dots per HP unit    */
  411.     HP_to_ydots    = (float) (pp->dpi_y / 1016.0); /*  (1/40 mm)        */
  412.     dir_str    = "true sizes";
  413.   }
  414.   else
  415.   {
  416.     if (pp->width > tmp_w)
  417.     {
  418.     HP_to_ydots = (float) (pp->dpi_y * pp->height)/ Dy / 25.4;
  419.     HP_to_xdots = HP_to_ydots * pp->aspectfactor  / dot_ratio;
  420.     pp->width   = tmp_w;
  421.     dir_str        = "width adapted";    /* Height fits, adjust width    */
  422.     }
  423.     else
  424.     {
  425.     HP_to_xdots = (float) (pp->dpi_x * pp->width) / Dx / 25.4;
  426.     HP_to_ydots = HP_to_xdots * dot_ratio / pp->aspectfactor;
  427.     pp->height  = tmp_h;
  428.     dir_str        = "height adapted";    /* Width  fits, adjust height    */
  429.     }
  430.   }
  431.  
  432.   if (!pp->quiet)
  433.   {
  434.     fprintf(stderr,"\nWidth  x  height: %5.2f x %5.2f mm, %s\n",
  435.         pp->width, pp->height, dir_str);
  436.     fprintf(stderr,"Coordinate range: (%g, %g) ... (%g, %g)\n",
  437.             xmin, ymin, xmax, ymax);
  438.   }
  439.   HP_Pt.x    = xmax;
  440.   HP_Pt.y    = ymax;
  441.   HPcoord_to_dotcoord (&HP_Pt, p_maxdot);
  442. }
  443.  
  444.  
  445.  
  446. void    read_ESC_cmd (FILE *hd)
  447. /*
  448.  * Read & skip device control commands (ESC.-Commands)
  449.  * Currently known: HP 7550A command set
  450.  */
  451. {
  452. int    c;
  453.  
  454.   if (getc(hd) != '.')
  455.   {
  456.     n_unexpected++;
  457.     return;
  458.   }
  459.  
  460.   switch (getc(hd))
  461.   {
  462.     case EOF:
  463.     n_unexpected++;
  464.     fprintf(stderr,"\nUnexpected EOF!\n");
  465.     return;
  466.     case 'A':
  467.     case 'B':
  468.     case 'E':
  469.     case 'J':
  470.     case 'K':
  471.     case 'L':
  472.     case 'O':
  473.     case 'U':
  474.     case 'Y':
  475.     case '(':
  476.     case ')':
  477.     return;    /* Commands without parameters    */
  478.     case '@':
  479.     case 'H':
  480.     case 'I':
  481.     case 'M':
  482.     case 'N':
  483.     case 'P':
  484.     case 'Q':
  485.     case 'S':
  486.     case 'T':
  487.     do {    /* Search for terminator ':'    */
  488.         c = getc(hd);
  489.     } while ((c!=':')&&(c!=EOF));
  490.     if (c==EOF)
  491.     {
  492.         n_unexpected++;
  493.         fprintf(stderr,"\nUnexpected EOF!\n");
  494.     }
  495.     return;
  496.     default:
  497.     n_unknown++;
  498.     return;
  499.   }
  500. }
  501.  
  502.  
  503.  
  504.  
  505. void    read_HPGL (PAR *p, FILE *hd, FILE *td, DevPt *maxdotcoord)
  506. /**
  507.  ** This routine is the high-level entry for HP-GL processing.
  508.  ** It reads the input stream character-by-character, identifies
  509.  ** ESC. commands (device controls) and HP-GL mnemonics, reads
  510.  ** paramters (if expected), and initiates processing of these
  511.  ** commands. It finally reports on this parsing process.
  512.  **/
  513. {
  514. int    c;
  515.  
  516.   init_HPGL (td, p);
  517.  
  518.   if (!p->quiet)
  519.     fprintf(stderr, "\nReading HPGL file\n");
  520.  
  521.   while ((c = getc(hd)) != EOF)        /* MAIN parser LOOP!!        */
  522.     if (c == ESC)
  523.         read_ESC_cmd (hd);    /* ESC sequence            */
  524.     else
  525.     {
  526.         if ((c<'A') || (c>'z') || ((c>'Z')&&(c<'a')))
  527.             continue;    /* Wait for HPGL mnemonic...    */
  528.         read_HPGL_cmd (c, hd);    /* ... Process it        */
  529.     }
  530.  
  531.   evaluate_HPGL (p, maxdotcoord);
  532.   if (!p->quiet)
  533.   {
  534.     fprintf(stderr,"\nHPGL command(s) ignored: %d\n", n_unknown);
  535.     fprintf(stderr,"Unexpected event(s):  %d\n",  n_unexpected);
  536.     fprintf(stderr,"Internal command(s):  %ld\n", vec_cntr_w);
  537.     fprintf(stderr,"Pens used: ");
  538.     for (c=0; c < 16; c++, pens_in_use >>= 1)
  539.         if (pens_in_use & 1)
  540.             fprintf(stderr,"%d ", c+1);
  541.     putc('\n', stderr);
  542.     fprintf(stderr,"Max. number of pages: %d\n",  page_number);
  543.   }
  544. }
  545.  
  546.  
  547.  
  548.  
  549. static    void    User_to_Plotter_coord (HPGL_Pt *p_usr, HPGL_Pt *p_plot)
  550. /**
  551.  **     Utility: Transformation from (scaled) user coordinates
  552.  **    to plotter coordinates
  553.  **/
  554. {
  555.   p_plot->x = P1.x + (p_usr->x - S1.x) * Q.x;
  556.   p_plot->y = P1.y + (p_usr->y - S1.y) * Q.y;
  557. }
  558.  
  559.  
  560.  
  561. static    void    Plotter_to_User_coord (HPGL_Pt *p_plot, HPGL_Pt *p_usr)
  562. /**
  563.  **     Utility: Transformation from plotter coordinates
  564.  **    to (scaled) user coordinates
  565.  **/
  566. {
  567.   p_usr->x = S1.x + (p_plot->x - P1.x) / Q.x;
  568.   p_usr->y = S1.y + (p_plot->y - P1.y) / Q.y;
  569. }
  570.  
  571.  
  572.  
  573.  
  574.  
  575. /**
  576.  **    Process a single HPGL command
  577.  **/
  578.  
  579. void    read_HPGL_cmd (int c, FILE *hd)
  580. {
  581. short    cmd, old_pen;
  582. HPGL_Pt    p1, p2;
  583. float    ftmp;
  584.  
  585. /**
  586.  ** Each command consists of 2 characters. We unite them here to a single int
  587.  ** to allow for easy processing within a big switch statement:
  588.  **/
  589.   cmd = c<<8;
  590.   if ((c = getc(hd)) == EOF)
  591.     return;
  592.   cmd |= (c & 0xFF);
  593.  
  594.   switch (cmd & 0xDFDF)    /* & forces to upper case    */
  595.   {
  596.   /**
  597.    ** Commands appear in alphabetical order within each topic group
  598.    ** except for command synonyms.
  599.    **/
  600.     case AA:        /* Arc Absolute            */
  601.     arcs (FALSE, hd);
  602.     tp->CR_point = HP_pos;
  603.     break;
  604.     case AR:        /* Arc Relative            */
  605.     arcs (TRUE, hd);
  606.     tp->CR_point = HP_pos;
  607.     break;
  608.     case CI:        /* Circle            */
  609.     circles (hd);
  610.     break;
  611.     case PA:        /* Plot Absolute        */
  612.     lines (plot_rel = FALSE,  hd);
  613.     tp->CR_point = HP_pos;
  614.     break;
  615.     case PD:        /* Pen  Down            */
  616.     pen_down = TRUE;
  617.     lines (plot_rel,  hd);
  618.     tp->CR_point = HP_pos;
  619.     break;
  620.     case PR:        /* Plot Relative        */
  621.     lines (plot_rel = TRUE, hd);
  622.     tp->CR_point = HP_pos;
  623.     break;
  624.     case PU:        /* Pen  Up            */
  625.     pen_down = FALSE;
  626.     lines (plot_rel,  hd);
  627.     tp->CR_point = HP_pos;
  628.     break;
  629.     case TL:        /* Tick Length            */
  630.     if (read_float (&ftmp, hd)) /* No number found    */
  631.     {
  632.         neg_ticklen = pos_ticklen = 0.005;
  633.         return;
  634.     }
  635.     else
  636.         pos_ticklen = ftmp / 100.0;
  637.  
  638.     if (read_float (&ftmp, hd)) /* pos, but not neg    */
  639.     {
  640.         neg_ticklen = 0.0;
  641.         return;
  642.     }
  643.     else
  644.         neg_ticklen = ftmp / 100.0;
  645.     break;
  646.     case XT:        /* X Tick            */
  647.     ax_ticks (0);
  648.     break;
  649.     case YT:        /* Y Tick            */
  650.     ax_ticks (1);
  651.     break;
  652.  
  653.  
  654.     case IP:        /* Input reference Points P1,P2    */
  655.     tp->width  /= (P2.x - P1.x);
  656.     tp->height /= (P2.y - P1.y);
  657.     if (read_float (&p1.x, hd)) /* No number found    */
  658.     {
  659.         P1.x = P1X_default;
  660.         P1.y = P1Y_default;
  661.         P2.x = P2X_default;
  662.         P2.y = P2Y_default;
  663.         goto IP_Exit ;
  664.     }
  665.     if (read_float (&p1.y, hd))    /* x without y! */
  666.         par_err_exit (2,cmd);
  667.  
  668.     if (read_float (&p2.x, hd)) /* No number found    */
  669.     {
  670.         P2.x += p1.x - P1.x;
  671.         P2.y += p1.y - P1.y;
  672.         P1    = p1;
  673.         goto IP_Exit ;
  674.     }
  675.     if (read_float (&p2.y, hd))    /* x without y! */
  676.         par_err_exit (4,cmd);
  677.  
  678.     P1 = p1;
  679.     P2 = p2;
  680.  
  681.     IP_Exit:
  682.     Q.x = (P2.x - P1.x) / (S2.x - S1.x);
  683.     Q.y = (P2.y - P1.y) / (S2.y - S1.y);
  684.     Diag_P1_P2  = HYPOT (P2.x - P1.x, P2.y - P1.y);
  685.     glb_pat_len = cur_pat_len = 0.04 * Diag_P1_P2;
  686.     tp->width  *= (P2.x - P1.x);
  687.     tp->height *= (P2.y - P1.y);
  688.     adjust_text_par();
  689.     return;
  690.  
  691.     case OP:        /* Output reference Points P1,P2*/
  692.     if (!silent_mode)
  693.     {
  694.         fprintf(stderr, "\nP1 = (%g, %g)\n", P1.x, P1.y);
  695.         fprintf(stderr,   "P2 = (%g, %g)\n", P2.x, P2.y);
  696.     }
  697.     break ;
  698.  
  699.     case AF:
  700.     case AH:
  701.     case PG:        /* new PaGe            */
  702.             /* record ON happens only once!    */
  703.     page_number++;
  704.     record_off =     (first_page > page_number)
  705.              || ((last_page  < page_number) && (last_page > 0));
  706.     break ;
  707.  
  708.     case LT:        /* Line Type:             */
  709.     if (read_float (&p1.x, hd))    /* just LT;    */
  710.         GlobalLineType = LT_solid;
  711.     else
  712.     {
  713.         switch ((int) p1.x)
  714.         {
  715.          case 0:    /* Starting dot (LT0;)     */
  716.             GlobalLineType = LT_plot_at;    break;
  717.          case 1:
  718.             GlobalLineType = LT_d_fix;    break;
  719.          case -1:
  720.             GlobalLineType = LT_d_ada;    break;
  721.          case 2:
  722.             GlobalLineType = LT_l_fix;    break;
  723.          case -2:
  724.             GlobalLineType = LT_l_ada;    break;
  725.          case 3:
  726.             GlobalLineType = LT_ls_fix;    break;
  727.          case -3:
  728.             GlobalLineType = LT_ls_ada;    break;
  729.          case 4:
  730.             GlobalLineType = LT_lgd_fix;    break;
  731.          case -4:
  732.             GlobalLineType = LT_lgd_ada;    break;
  733.          case 5:
  734.             GlobalLineType = LT_lgs_fix;    break;
  735.          case -5:
  736.             GlobalLineType = LT_lgs_ada;    break;
  737.          case 6:
  738.             GlobalLineType = LT_lgsgs_fix;    break;
  739.          case -6:
  740.             GlobalLineType = LT_lgsgs_ada;    break;
  741.          default:
  742.             fprintf(stderr,"Illegal line type:\t%d\n", (int) p1.x);
  743.         }
  744.  
  745.         if (!read_float (&p1.y, hd))    /* optional pattern length?    */
  746.         {
  747.             if (p1.y < 0.0)
  748.                 fprintf(stderr,"Illegal pattern length:\t%g\n", p1.y);
  749.             else
  750.                 glb_pat_len = Diag_P1_P2 * p1.y / 100.0;
  751.         }
  752.     }
  753.     CurrentLineType = GlobalLineType;
  754.     cur_pat_len    = glb_pat_len;
  755.     break;
  756.  
  757.     case SC:        /* Input Scale Points S1,S2    */
  758.     User_to_Plotter_coord (&p_last, &p_last);
  759.     if (read_float (&S1.x, hd)) /* No number found    */
  760.     {
  761.         S1.x = P1X_default;
  762.         S1.y = P1Y_default;
  763.         S2.x = P2X_default;
  764.         S2.y = P2Y_default;
  765.         scale_flag = FALSE;
  766.         Q.x = Q.y = 1.0;
  767.         return;
  768.     }
  769.     if (read_float (&S2.x, hd))    /* x without y! */
  770.         par_err_exit (2,cmd);
  771.     if (read_float (&S1.y, hd)) /* No number found    */
  772.         par_err_exit (3,cmd);
  773.     if (read_float (&S2.y, hd))    /* x without y! */
  774.         par_err_exit (4,cmd);
  775.  
  776.     Q.x = (P2.x - P1.x) / (S2.x - S1.x);
  777.     Q.y = (P2.y - P1.y) / (S2.y - S1.y);
  778.     scale_flag = TRUE;
  779.     Plotter_to_User_coord (&p_last, &p_last);
  780.     break;
  781.  
  782.     case SP:        /* Select pen: none/0, or 1...8    */
  783.     old_pen = pen;
  784.     if (read_float (&p1.x, hd))    /* just SP;    */
  785.         pen = 0;
  786.     else
  787.         pen = (int) p1.x;
  788.  
  789.     if (pen < 0 || pen > 8)
  790.     {
  791.         fprintf(stderr,
  792.             "\nIllegal pen number %d: replaced by %d\n", pen, pen % 8);
  793.         n_unexpected++;
  794.         pen = pen % 8;
  795.     }
  796.     if (old_pen != pen)
  797.     {
  798.         if ((fputc (SET_PEN, td) ==  EOF) ||
  799.             (fputc (    pen, td) ==  EOF))
  800.         {
  801.             perror("Writing to temporary file:");
  802.             fprintf(stderr,"Error @ Cmd %ld\n", vec_cntr_w);
  803.             exit (ERROR);
  804.         }
  805.     }
  806.     if (pen)
  807.         pens_in_use |= (1 << (pen-1));
  808.     break;
  809.  
  810.     case DF:        /* Set to default        */
  811.     case IN:
  812.     reset_HPGL();
  813.     tp->CR_point = HP_pos;
  814.     break;
  815.  
  816.     case BL:        /* Buffer label string        */
  817.     read_string (strbuf, hd);
  818.     break;
  819.     case CP:        /* Char Plot (rather: move)    */
  820.     if (read_float (&p1.x, hd)) /* No number found    */
  821.     {
  822.         plot_string("\n\r", LB_direct);
  823.         return;
  824.     }
  825.     else
  826.         if (read_float (&p1.y, hd))
  827.             par_err_exit (2,cmd);
  828.  
  829.     p2.x = p1.x * tp->chardiff.x - p1.y * tp->linediff.x + HP_pos.x;
  830.     p2.y = p1.x * tp->chardiff.y - p1.y * tp->linediff.y + HP_pos.y;
  831.     Pen_action_to_tmpfile (MOVE_TO, &p2, FALSE);
  832.     break;
  833.     case DI:        /* Char plot Dir (absolute)    */
  834.     if (read_float (&p1.x, hd)) /* No number found    */
  835.     {
  836.         tp->dir = 0.0;
  837.         return;
  838.     }
  839.     if (read_float (&p1.y, hd))    /* x, but not y    */
  840.         par_err_exit (2,cmd);
  841.     if ((p1.x==0.0) && (p1.y==0.0))
  842.         par_err_exit (0,cmd);
  843.     tp->dir = atan2(p1.y, p1.x);
  844.     tp->CR_point = HP_pos;
  845.     adjust_text_par();
  846.     break;
  847.     case DR:        /* Char plot Dir (rel P1,P2)    */
  848.     if (read_float (&p1.x, hd)) /* No number found    */
  849.     {
  850.         tp->dir = 0.0;
  851.         return;
  852.     }
  853.     if (read_float (&p1.y, hd))
  854.         par_err_exit (2,cmd);    /* x, but not y    */
  855.     if ((p1.x==0.0) && (p1.y==0.0))
  856.         par_err_exit (0,cmd);
  857.     tp->dir = atan2(p1.y*(P2.y - P1.y), p1.x*(P2.x - P1.x));
  858.     tp->CR_point = HP_pos;
  859.     adjust_text_par();
  860.     break;
  861.     case DT:        /* Define string terminator    */
  862.     StrTerm = getc(hd);
  863.     break;
  864.     case ES:        /* Extra Space            */
  865.     if (read_float (&tp->espace, hd))/* No number found*/
  866.     {
  867.         tp->espace = 0.0;
  868.         tp->eline  = 0.0;
  869.     }
  870.     else
  871.         if (read_float (&tp->eline, hd))
  872.             par_err_exit (2,cmd);
  873.     adjust_text_par();
  874.     break;
  875.     case LB:        /* Label string            */
  876.     read_string (strbuf, hd);
  877.     plot_string (strbuf, LB_direct);
  878.     break;
  879.     case LO:        /* Label Origin            */
  880.     if (read_float (&p1.x, hd))  /* No number found    */
  881.         tp->orig = 1;
  882.     else
  883.     {
  884.         tp->orig = (int) p1.x;
  885.         if (tp->orig < 1 || tp->orig == 10 || tp->orig > 19)
  886.             tp->orig = 1;    /* Error    */
  887.     }
  888.     adjust_text_par();
  889.     break;
  890.     case PB:        /* Plot Buffered label string    */
  891.     plot_string (strbuf, LB_buffered);
  892.     break;
  893.     case SI:        /* Char cell Sizes (absolute)    */
  894.     if (read_float (&tp->width, hd))/* No number found*/
  895.     {
  896.         tp->width  = 0.187;    /* [cm], A4    */
  897.         tp->height = 0.269;    /* [cm], A4    */
  898.     }
  899.     else
  900.     {
  901.         if (read_float (&tp->height, hd))
  902.             par_err_exit (2,cmd);
  903.         if ((tp->width==0.0) || (tp->height==0.0))
  904.             par_err_exit (0,cmd);
  905.     }
  906.     tp->width  *= 400.0; /* [cm] --> [plotter units]    */
  907.     tp->height *= 400.0; /* [cm] --> [plotter units]    */
  908.     adjust_text_par();
  909.     break;
  910.     case SL:        /* Char Slant            */
  911.     if (read_float (&tp->slant, hd)) /* No number found    */
  912.         tp->slant =  0.0;
  913.     adjust_text_par();
  914.     break;
  915.     case SM:        /* Symbol Mode            */
  916.     read_symbol_char (hd);
  917.     break;
  918.     case SR:        /* Character  sizes (Rel P1,P2)    */
  919.     if (read_float (&tp->width, hd)) /* No number found*/
  920.     {
  921.         tp->width  = 0.75; /* % of (P2-P1)_x    */
  922.         tp->height = 1.5;  /* % of (P2-P1)_y    */
  923.     }
  924.     else
  925.     {
  926.         if (read_float (&tp->height, hd))
  927.             par_err_exit (2,cmd);
  928.         if ((tp->width==0.0) || (tp->height==0.0))
  929.             par_err_exit (0,cmd);
  930.     }
  931.     tp->width  *= (P2.x-P1.x)/100.0; /* --> [pl. units]    */
  932.     tp->height *= (P2.y-P1.y)/100.0;
  933.     adjust_text_par();
  934.     break;
  935.  
  936.     case UC:            /* User defined character    */
  937.     plot_user_char (hd);
  938.     break;
  939.  
  940.     case WD:        /* Write string    to display    */
  941.     read_string (strbuf, hd);
  942.     if (!silent_mode)
  943.         fprintf(stderr, "\nLABEL: %s\n", strbuf);
  944.     break;
  945.  
  946.     default :        /* Skip unknown HPGL command: */
  947.     n_unknown++;
  948.     if (!silent_mode)
  949.         fprintf(stderr,"  %c%c: ignored  ",cmd>>8,cmd&0xFF);
  950.     if (c==EOF)
  951.     {
  952.         n_unexpected++;
  953.         if (!silent_mode)
  954.             fprintf(stderr,"\nUnexpected EOF!\t");
  955.     }
  956.     break;
  957.   }
  958. }
  959.  
  960.  
  961. /****************************************************************************/
  962.  
  963.  
  964.  
  965. /**
  966.  **    lines:    Process PA-, PR-, PU-, and  PD- commands
  967.  **/
  968.  
  969.  
  970. void    lines (int relative, FILE *hd)
  971. /**
  972.  ** Examples of anticipated commands:
  973.  **
  974.  **    PA PD0,0,80,50,90,20PU140,30PD150,80;
  975.  **    PU0,0;PD20.53,40.32,30.08,60.2,40,90,;PU100,300;PD120,340...
  976.  **/
  977. {
  978. HPGL_Pt    p;
  979.  
  980.   for ( ; ; )
  981.   {
  982.     if (read_float (&p.x, hd))    /* No number found    */
  983.         return ;
  984.  
  985.     if (read_float (&p.y, hd))    /* x without y invalid! */
  986.         par_err_exit (2,PA);
  987.  
  988.  
  989.     if (relative)            /* Process coordinates    */
  990.     {
  991.         p.x += p_last.x;
  992.         p.y += p_last.y;
  993.     }
  994.  
  995.     if (pen_down)
  996.         Pen_action_to_tmpfile    (DRAW_TO, &p, scale_flag);
  997.     else
  998.         Pen_action_to_tmpfile    (MOVE_TO, &p, scale_flag);
  999.  
  1000.     if (symbol_char)
  1001.     {
  1002.         plot_symbol_char    (symbol_char);
  1003.         Pen_action_to_tmpfile    (MOVE_TO, &p, scale_flag);
  1004.     }
  1005.  
  1006.     p_last = p;
  1007.   }
  1008. }
  1009.  
  1010.  
  1011.  
  1012. /**
  1013.  **    Arcs, circles and alike
  1014.  **/
  1015.  
  1016.  
  1017. static  void    arc_increment (HPGL_Pt *pcenter, double r, double phi)
  1018. {
  1019. HPGL_Pt    p;
  1020.  
  1021.   p.x = pcenter->x + r * cos(phi);
  1022.   p.y = pcenter->y + r * sin(phi);
  1023.  
  1024.   if (pen_down)
  1025.     Pen_action_to_tmpfile (DRAW_TO, &p, scale_flag);
  1026.   else
  1027.     if ((p.x != p_last.x) || (p.y != p_last.y))
  1028.         Pen_action_to_tmpfile (MOVE_TO, &p, scale_flag);
  1029.   p_last = p;
  1030. }
  1031.  
  1032.  
  1033.  
  1034. void    arcs (int relative, FILE *hd)
  1035. {
  1036. HPGL_Pt    p, d, center;
  1037. float    alpha, eps;
  1038. double    phi, phi0, r;
  1039.  
  1040.   if (read_float (&p.x, hd))    /* No number found    */
  1041.     return ;
  1042.  
  1043.   if (read_float (&p.y, hd))    /* x without y invalid! */
  1044.     par_err_exit (2,AA);
  1045.  
  1046.   if (read_float (&alpha, hd))    /* Invalid without angle*/
  1047.     par_err_exit (3,AA);
  1048.   else
  1049.     alpha *= M_PI / 180.0;    /* Deg-to-Rad        */
  1050.  
  1051.   switch (read_float (&eps, hd))
  1052.   {
  1053.     case 0:
  1054.     break;
  1055.     case 1:            /* No resolution option    */
  1056.     eps = 5.0;        /*    so use default!    */
  1057.     break;
  1058.     case 2:                /* Illegal state    */
  1059.     par_err_exit (98,AA);
  1060.     case EOF:
  1061.     return;
  1062.     default:            /* Illegal state    */
  1063.     par_err_exit (99,AA);
  1064.   }
  1065.   eps *= M_PI / 180.0;        /* Deg-to-Rad        */
  1066.  
  1067.  
  1068.   if (relative)            /* Process coordinates    */
  1069.   {
  1070.     d = p;            /* Difference vector    */
  1071.     center.x = d.x + p_last.x;
  1072.     center.y = d.y + p_last.y;
  1073.   }
  1074.   else
  1075.   {
  1076.     d.x = p.x - p_last.x;
  1077.     d.y = p.y - p_last.y;
  1078.     center.x = p.x;
  1079.     center.y = p.y;
  1080.   }
  1081.  
  1082.   if ( ((r = sqrt(d.x*d.x + d.y*d.y)) == 0.0) || (alpha == 0.0) )
  1083.     return;    /* Zero radius or zero arc angle given    */
  1084.  
  1085.   phi0 = atan2(-d.y, -d.x);
  1086.  
  1087.   if ((int) GlobalLineType < 0)    /* Adaptive patterns:    */
  1088.   {
  1089.     p.x = r * cos(eps);    /* A chord segment    */
  1090.     p.y = r * sin(eps);
  1091.     if (scale_flag)
  1092.         User_to_Plotter_coord (&p, &p);
  1093.  
  1094.     /*     Pattern length = chord length        */
  1095.     cur_pat_len = HYPOT (p.x, p.y);
  1096.   }
  1097.  
  1098.   if (alpha > 0.0)
  1099.   {
  1100.     for (phi=phi0+MIN(eps,alpha) ; phi < phi0 + alpha; phi += eps)
  1101.         arc_increment (¢er, r, phi);
  1102.     arc_increment (¢er, r, phi0 + alpha);    /* to endpoint */
  1103.   }
  1104.   else
  1105.   {
  1106.     for (phi=phi0-MIN(eps,-alpha) ; phi > phi0 + alpha; phi -= eps)
  1107.         arc_increment (¢er, r, phi);
  1108.     arc_increment (¢er, r, phi0 + alpha);    /* to endpoint */
  1109.   }
  1110.  
  1111.   cur_pat_len = glb_pat_len;    /* Restore, just in case*/
  1112. }
  1113.  
  1114.  
  1115.  
  1116.  
  1117. void    circles (FILE *hd)
  1118. {
  1119. HPGL_Pt    p, center;
  1120. float    eps, r;
  1121. double    phi;
  1122.  
  1123.   if (read_float (&r, hd))    /* No radius found    */
  1124.     return ;
  1125.  
  1126.   switch (read_float (&eps, hd))
  1127.   {
  1128.     case 0:
  1129.     break;
  1130.     case 1:            /* No resolution option    */
  1131.     eps = 5.0;        /*    so use default!    */
  1132.     break;
  1133.     case 2:                /* Illegal state    */
  1134.     par_err_exit (98,CI);
  1135.     case EOF:
  1136.     return;
  1137.     default:            /* Illegal state    */
  1138.     par_err_exit (99,CI);
  1139.   }
  1140.   eps *= M_PI / 180.0;        /* Deg-to-Rad        */
  1141.  
  1142.  
  1143.   center = p_last;
  1144.  
  1145.   if (r == 0.0)            /* Zero radius given    */
  1146.     return;
  1147.  
  1148.   p.x = center.x + r;
  1149.   p.y = center.y;
  1150.   Pen_action_to_tmpfile (MOVE_TO, &p, scale_flag);
  1151.  
  1152.   if ((int) GlobalLineType < 0)    /* Adaptive patterns    */
  1153.   {
  1154.     p.x = r * cos(eps);    /* A chord segment    */
  1155.     p.y = r * sin(eps);
  1156.     if (scale_flag)
  1157.         User_to_Plotter_coord (&p, &p);
  1158.  
  1159.     /*     Pattern length = chord length        */
  1160.     cur_pat_len = HYPOT (p.x, p.y);
  1161.   }
  1162.  
  1163.   for (phi=eps; phi < 2.0 * M_PI; phi += eps)
  1164.   {
  1165.     p.x = center.x + r * cos(phi);
  1166.     p.y = center.y + r * sin(phi);
  1167.     Pen_action_to_tmpfile (DRAW_TO, &p, scale_flag);
  1168.   }
  1169.   p.x = center.x + r;    /* Close circle at r * (1, 0)    */
  1170.   p.y = center.y;
  1171.   Pen_action_to_tmpfile (DRAW_TO, &p, scale_flag);
  1172.  
  1173.   Pen_action_to_tmpfile (MOVE_TO, ¢er, scale_flag);
  1174.  
  1175.   cur_pat_len = glb_pat_len;    /* Restore, just in case*/
  1176. }
  1177.  
  1178.  
  1179.  
  1180.  
  1181. void    ax_ticks (int mode)
  1182. {
  1183. HPGL_Pt    p0, p1, p2;
  1184.  
  1185.   p0 = p1 = p2 = p_last;
  1186.  
  1187. /**
  1188.  ** According to the HP-GL manual,
  1189.  ** XT & YT are not affected by LT:
  1190.  **/
  1191.   CurrentLineType = LT_solid;
  1192.  
  1193.   if (mode == 0)    /* X tick    */
  1194.   {
  1195.     p1.y -= neg_ticklen * (P2.y - P1.y) / Q.y;
  1196.     p2.y += pos_ticklen * (P2.y - P1.y) / Q.y;
  1197.   }
  1198.   else            /* Y tick    */
  1199.   {
  1200.     p1.x -= neg_ticklen * (P2.x - P1.x) / Q.x;
  1201.     p2.x += pos_ticklen * (P2.x - P1.x) / Q.x;
  1202.   }
  1203.  
  1204.   Pen_action_to_tmpfile (MOVE_TO, &p1, scale_flag);
  1205.   Pen_action_to_tmpfile (DRAW_TO, &p2, scale_flag);
  1206.   Pen_action_to_tmpfile (MOVE_TO, &p0, scale_flag);
  1207.  
  1208.   CurrentLineType = GlobalLineType;
  1209. }
  1210.  
  1211.  
  1212.  
  1213. /**
  1214.  **    Low-level vector generation & file I/O
  1215.  **/
  1216.  
  1217.  
  1218.  
  1219.  
  1220. void    LPattern_Generator (HPGL_Pt    *pa,
  1221.                 double    dx,         double    dy,
  1222.                 double    start_of_pat,    double    end_of_pat)
  1223. /**
  1224.  **    Generator of Line type patterns:
  1225.  **
  1226.  **    pa:        Start point (ptr) of current line segment
  1227.  **    dx, dy:        Components of c * (*pb - *pa), c holding
  1228.  **                dx^2 + dy^2 = pattern_length^2
  1229.  **    start_of_pat:    Fraction of start point within pattern
  1230.  **    end_of_pat:    Fraction of end   point within pattern
  1231.  **            Valid: 0 <= start_of_pat <= end_of_pat <= 1
  1232.  **
  1233.  **    A pattern consists of alternating "line"/"point" and "gap" elements,
  1234.  **    always starting with a line/point. A point is a line of zero length.
  1235.  **    The table below contains the relative lengths of the elements
  1236.  **    of all line types except LT0; and LT; (7), which are treated separately.
  1237.  **    These lengths always add up to 1. A negative value terminates a pattern.
  1238.  **/
  1239. {
  1240. double        length_of_ele, start_of_action, end_of_action;
  1241. static    double    *p_cur_pat,
  1242.         pattern[14][8] = {
  1243.     /*      Line  gap   Line  gap   Line   gap   Line  TERM    */
  1244.     /*-6 */    {0.25, 0.10, 0.10, 0.10, 0.10,  0.10, 0.25, -1},
  1245.     /*-5 */    {0.35, 0.10, 0.10, 0.10, 0.35, -1,   -1     -1},
  1246.     /*-4 */    {0.40, 0.10, 0.00, 0.10, 0.40, -1,   -1,    -1},
  1247.     /*-3 */    {0.35, 0.30, 0.35,-1,   -1,    -1,   -1,    -1},
  1248.     /*-2 */    {0.25, 0.75, 1.00,-1,   -1,    -1,   -1,    -1},
  1249.     /*-1 */    {0.00, 1.00,-1,   -1,   -1,    -1,   -1,    -1},
  1250.     /* 0 */    {0.00, 1.00,-1,   -1,   -1,    -1,   -1,    -1},
  1251.         /* Dummy; should NOT be used    */
  1252.     /* 1 */    {0.00, 1.00,-1,   -1,   -1,    -1,   -1,    -1},
  1253.     /* 2 */    {0.50, 0.50,-1,   -1,   -1,    -1,   -1,    -1},
  1254.     /* 3 */    {0.70, 0.30,-1,   -1,   -1,    -1,   -1,    -1},
  1255.     /* 4 */    {0.80, 0.10, 0.00, 0.10,-1,    -1,   -1,    -1},
  1256.     /* 5 */    {0.70, 0.10, 0.10, 0.10,-1,    -1,   -1,    -1},
  1257.     /* 6 */    {0.50, 0.10, 0.10, 0.10, 0.10,  0.10,-1,    -1},
  1258.     /* 7 */    {1.00,-1,   -1,   -1,   -1,    -1,   -1,    -1}
  1259.         /* Dummy; should NOT be used    */
  1260. };
  1261.  
  1262.   p_cur_pat = pattern[(int)CurrentLineType + 6];
  1263.  
  1264.   if ((int) CurrentLineType < 0)
  1265.     for (;;)
  1266.     {
  1267.         length_of_ele = *p_cur_pat++;    /* Line or point    */
  1268.         if (length_of_ele < 0)
  1269.             return;
  1270.         if (length_of_ele == 0.0)
  1271.             PlotCmd_to_tmpfile (PLOT_AT);
  1272.         else
  1273.             PlotCmd_to_tmpfile (DRAW_TO);
  1274.  
  1275.         pa->x += dx * length_of_ele;
  1276.         pa->y += dy * length_of_ele;
  1277.         HPGL_Pt_to_tmpfile (pa);
  1278.  
  1279.         length_of_ele = *p_cur_pat++;    /* Gap            */
  1280.         if (length_of_ele < 0)
  1281.             return;
  1282.         pa->x += dx * length_of_ele;
  1283.         pa->y += dy * length_of_ele;
  1284.         PlotCmd_to_tmpfile (MOVE_TO);
  1285.         HPGL_Pt_to_tmpfile (pa);
  1286.     }
  1287.   else
  1288.     for (end_of_action=0.0; ; )
  1289.     {
  1290.         /**
  1291.          ** Line or point:
  1292.          **/
  1293.         start_of_action    = end_of_action;
  1294.         length_of_ele    = *p_cur_pat++;
  1295.         if (length_of_ele < 0)
  1296.         return;
  1297.         end_of_action += length_of_ele;
  1298.         if (end_of_action > start_of_pat)    /* If anything to do:    */
  1299.         {
  1300.         if (start_of_pat <= start_of_action)
  1301.         {                /* If start is valid    */
  1302.             if (end_of_action <= end_of_pat)
  1303.             {                /* Draw full element    */
  1304.             pa->x += dx * length_of_ele;
  1305.             pa->y += dy * length_of_ele;
  1306.             if (length_of_ele == 0.0)
  1307.                 PlotCmd_to_tmpfile (PLOT_AT);
  1308.             else
  1309.                 PlotCmd_to_tmpfile (DRAW_TO);
  1310.             HPGL_Pt_to_tmpfile (pa);
  1311.             }
  1312.             else    /* End_of_action beyond End_of_pattern:    */
  1313.             {        /* --> Draw only first part of element:    */
  1314.             pa->x += dx * (end_of_pat - start_of_action);
  1315.             pa->y += dy * (end_of_pat - start_of_action);
  1316.             if (length_of_ele == 0.0)
  1317.                 PlotCmd_to_tmpfile (MOVE_TO);
  1318.             else
  1319.                 PlotCmd_to_tmpfile (DRAW_TO);
  1320.             HPGL_Pt_to_tmpfile (pa);
  1321.             return;
  1322.             }
  1323.         }
  1324.         else    /* Start_of_action before Start_of_pattern:     */
  1325.         {
  1326.             if (end_of_action <= end_of_pat)
  1327.             {        /* Draw remainder of element        */
  1328.             if (length_of_ele == 0.0)
  1329.                 PlotCmd_to_tmpfile (PLOT_AT);
  1330.             else
  1331.                 PlotCmd_to_tmpfile (DRAW_TO);
  1332.             pa->x += dx * (end_of_action - start_of_pat);
  1333.             pa->y += dy * (end_of_action - start_of_pat);
  1334.             HPGL_Pt_to_tmpfile (pa);
  1335.             }
  1336.             else    /* End_of_action beyond End_of_pattern:    */
  1337.                     /* Draw central part of element & leave    */
  1338.             {
  1339.             if (end_of_pat == start_of_pat)
  1340.                 PlotCmd_to_tmpfile (PLOT_AT);
  1341.             else
  1342.                 PlotCmd_to_tmpfile (DRAW_TO);
  1343.             pa->x += dx * (end_of_pat - start_of_pat);
  1344.             pa->y += dy * (end_of_pat - start_of_pat);
  1345.             HPGL_Pt_to_tmpfile (pa);
  1346.             return;
  1347.             }
  1348.         }
  1349.         }
  1350.  
  1351.         /**
  1352.          ** Gap (analogous to line/point):
  1353.          **/
  1354.         start_of_action =  end_of_action;
  1355.         length_of_ele  =  *p_cur_pat++;
  1356.         if (length_of_ele < 0)
  1357.         return;
  1358.         end_of_action += length_of_ele;
  1359.         if (end_of_action > start_of_pat)    /* If anything to do:    */
  1360.         {
  1361.         if (start_of_pat <= start_of_action)
  1362.         {                /* If start is valid    */
  1363.             if (end_of_action <= end_of_pat)
  1364.             {                /* Full gap        */
  1365.             pa->x += dx * length_of_ele;
  1366.             pa->y += dy * length_of_ele;
  1367.             PlotCmd_to_tmpfile (MOVE_TO);
  1368.             HPGL_Pt_to_tmpfile (pa);
  1369.             }
  1370.             else    /* End_of_action beyond End_of_pattern:    */
  1371.             {        /* --> Apply only first part of gap:    */
  1372.             pa->x += dx * (end_of_pat - start_of_action);
  1373.             pa->y += dy * (end_of_pat - start_of_action);
  1374.             PlotCmd_to_tmpfile (MOVE_TO);
  1375.             HPGL_Pt_to_tmpfile (pa);
  1376.             return;
  1377.             }
  1378.         }
  1379.         else    /* Start_of_action before Start_of_pattern:     */
  1380.         {
  1381.             if (end_of_action <= end_of_pat)
  1382.             {        /* Apply remainder of gap        */
  1383.             pa->x += dx * (end_of_action - start_of_pat);
  1384.             pa->y += dy * (end_of_action - start_of_pat);
  1385.             PlotCmd_to_tmpfile (MOVE_TO);
  1386.             HPGL_Pt_to_tmpfile (pa);
  1387.             }
  1388.             else    /* End_of_action beyond End_of_pattern:    */
  1389.                     /* Apply central part of gap & leave    */
  1390.             {
  1391.             if (end_of_pat == start_of_pat)
  1392.                 return;            /* A null move    */
  1393.             pa->x += dx * (end_of_pat - start_of_pat);
  1394.             pa->y += dy * (end_of_pat - start_of_pat);
  1395.             PlotCmd_to_tmpfile (MOVE_TO);
  1396.             HPGL_Pt_to_tmpfile (pa);
  1397.             return;
  1398.             }
  1399.         }
  1400.         }
  1401.     }
  1402. }
  1403.  
  1404.  
  1405.  
  1406.  
  1407. void    Line_Generator (HPGL_Pt *pa, HPGL_Pt *pb, int mv_flag)
  1408. {
  1409. double    seg_len, dx, dy, quot;
  1410. int    n_pat, i;
  1411.  
  1412.   switch (CurrentLineType)
  1413.   {
  1414.     case LT_solid:
  1415.     PlotCmd_to_tmpfile (DRAW_TO);
  1416.     HPGL_Pt_to_tmpfile (pb);
  1417.     return;
  1418.     case LT_plot_at:
  1419.     PlotCmd_to_tmpfile (PLOT_AT);
  1420.     HPGL_Pt_to_tmpfile (pb);
  1421.     return;
  1422.     default:
  1423.     break;
  1424.   }
  1425.  
  1426.   dx = pb->x - pa->x;
  1427.   dy = pb->y - pa->y;
  1428.   seg_len = HYPOT (dx, dy);
  1429.   if (seg_len == 0.0)
  1430.   {
  1431.     if (!silent_mode)
  1432.         fprintf(stderr,"Warning: Zero line segment length -- skipped\n");
  1433.     return;        /* No line to draw ??        */
  1434.   }
  1435.  
  1436.   if ((int) CurrentLineType < 0)    /* Adaptive    */
  1437.   {
  1438.     pat_pos = 0.0;    /* Reset to start-of-pattern    */
  1439.     n_pat    = ceil  (seg_len / cur_pat_len);
  1440.     dx    /= n_pat;
  1441.     dy    /= n_pat;
  1442.             /* Now draw n_pat complete line patterns*/
  1443.     for (i=0; i < n_pat; i++)
  1444.         LPattern_Generator (pa, dx, dy, 0.0, 1.0);
  1445.   }
  1446.   else
  1447.   {
  1448.     if (mv_flag)    /* Last move ends old line pattern    */
  1449.         pat_pos = 0.0;
  1450.     quot    = seg_len / cur_pat_len;
  1451.     dx    /= quot;
  1452.     dy    /= quot;
  1453.     while (quot >= 1.0)
  1454.     {
  1455.         LPattern_Generator (pa, dx, dy, pat_pos, 1.0);
  1456.         quot -= (1.0 - pat_pos);
  1457.         pat_pos = 0.0;
  1458.     }
  1459.     quot += pat_pos;
  1460.     if (quot >= 1.0)
  1461.     {
  1462.         LPattern_Generator (pa, dx, dy, pat_pos, 1.0);
  1463.         quot -= 1.0;
  1464.         pat_pos = 0.0;
  1465.     }
  1466.     LPattern_Generator (pa, dx, dy, pat_pos, quot);
  1467.     pat_pos = quot;
  1468.   }
  1469. }
  1470.  
  1471.  
  1472.  
  1473.  
  1474.  
  1475. void    Pen_action_to_tmpfile (PlotCmd cmd, HPGL_Pt *p, int scaled)
  1476. {
  1477. static    HPGL_Pt    P_last;
  1478. HPGL_Pt        P;
  1479. double        tmp;
  1480.  
  1481.   if (record_off)    /* Wrong page!    */
  1482.     return;
  1483.  
  1484.   if (scaled)        /* Rescaling    */
  1485.     User_to_Plotter_coord (p, &P);
  1486.   else
  1487.     P = *p;        /* Local copy    */
  1488.  
  1489.  
  1490.   HP_pos = P;        /* Actual plotter pos. in plotter coord    */
  1491.  
  1492.   if (rotate_flag)    /* hp2xx-specific global rotation    */
  1493.   {
  1494.     tmp = rot_cos * P.x - rot_sin * P.y;
  1495.     P.y = rot_sin * P.x + rot_cos * P.y;
  1496.     P.x = tmp;
  1497.   }
  1498.  
  1499.  
  1500.   /* Extreme values needed for later scaling:     */
  1501.  
  1502.   switch (cmd)
  1503.   {
  1504.     case MOVE_TO:
  1505.     mv_flag = TRUE;
  1506.     break;
  1507.  
  1508.   /**
  1509.    ** Multiple-move suppression. In addition,
  1510.    ** a move only precedes a draw -- nothing else!
  1511.    **/
  1512.  
  1513.     case DRAW_TO:
  1514.     if (mv_flag)
  1515.     {
  1516.         xmin = MIN (P_last.x, xmin);
  1517.         ymin = MIN (P_last.y, ymin);
  1518.         xmax = MAX (P_last.x, xmax);
  1519.         ymax = MAX (P_last.y, ymax);
  1520.         PlotCmd_to_tmpfile (MOVE_TO);
  1521.         HPGL_Pt_to_tmpfile (&P_last);
  1522.     }
  1523.     /* drop through    */
  1524.     case PLOT_AT:
  1525.     xmin = MIN (P.x, xmin);
  1526.     ymin = MIN (P.y, ymin);
  1527.     xmax = MAX (P.x, xmax);
  1528.     ymax = MAX (P.y, ymax);
  1529.     Line_Generator (&P_last, &P, mv_flag);
  1530.     mv_flag = FALSE;
  1531.     break;
  1532.  
  1533.     default:
  1534.     fprintf(stderr,"Illegal Pen Action: %d\n", cmd);
  1535.     fprintf(stderr,"Error @ Cmd %ld\n", vec_cntr_w);
  1536.     exit (ERROR);
  1537.   }
  1538.   P_last = P;
  1539. }
  1540.  
  1541.  
  1542.  
  1543.  
  1544.  
  1545. void    PlotCmd_to_tmpfile (PlotCmd cmd)
  1546. {
  1547.   if (record_off)    /* Wrong page!    */
  1548.     return;
  1549.  
  1550.   if (!silent_mode) switch (vec_cntr_w++)
  1551.   {
  1552.     case 0:    fprintf(stderr,"Writing Cmd: ");break;
  1553.     case 1:    fprintf(stderr,"1 ");        break;
  1554.     case 2:    fprintf(stderr,"2 ");        break;
  1555.     case 5:    fprintf(stderr,"5 ");        break;
  1556.     case 10:    fprintf(stderr,"10 ");        break;
  1557.     case 20:    fprintf(stderr,"20 ");        break;
  1558.     case 50:    fprintf(stderr,"50 ");        break;
  1559.     case 100:    fprintf(stderr,"100 ");        break;
  1560.     case 200:    fprintf(stderr,"200 ");        break;
  1561.     case 500:    fprintf(stderr,"500 ");        break;
  1562.     case 1000:    fprintf(stderr,"1k ");        break;
  1563.     case 2000:    fprintf(stderr,"2k ");        break;
  1564.     case 5000:    fprintf(stderr,"5k ");        break;
  1565.     case 10000:    fprintf(stderr,"10k ");        break;
  1566.     case 20000:    fprintf(stderr,"20k ");        break;
  1567.     case 50000L:fprintf(stderr,"50k ");        break;
  1568.     case 100000L:fprintf(stderr,"100k ");    break;
  1569.     case 200000L:fprintf(stderr,"200k ");    break;
  1570.     case 500000L:fprintf(stderr,"500k ");    break;
  1571.   }
  1572.  
  1573.   if (fputc ((int) cmd, td) == EOF)
  1574.   {
  1575.     perror("PlotCmd_to_tmpfile");
  1576.     fprintf(stderr,"Error @ Cmd %ld\n", vec_cntr_w);
  1577.     exit (ERROR);
  1578.   }
  1579. }
  1580.  
  1581.  
  1582.  
  1583.  
  1584. void    HPGL_Pt_to_tmpfile (HPGL_Pt *p)
  1585. {
  1586.   if (record_off)    /* Wrong page!    */
  1587.     return;
  1588.  
  1589.   if (fwrite ((VOID *) p, sizeof(*p), 1, td) != 1)
  1590.   {
  1591.     perror("HPGL_Pt_to_tmpfile");
  1592.     fprintf(stderr,"Error @ Cmd %ld\n", vec_cntr_w);
  1593.     exit (ERROR);
  1594.   }
  1595. }
  1596.  
  1597.  
  1598.  
  1599.  
  1600. int    PlotCmd_from_tmpfile (void)
  1601. {
  1602. int    cmd;
  1603.  
  1604.   if (!silent_mode) switch (vec_cntr_r++)
  1605.   {
  1606.     case 0:    fprintf(stderr,"\nProcessing Cmd: ");break;
  1607.     case 1:    fprintf(stderr,"1 ");        break;
  1608.     case 2:    fprintf(stderr,"2 ");        break;
  1609.     case 5:    fprintf(stderr,"5 ");        break;
  1610.     case 10:    fprintf(stderr,"10 ");        break;
  1611.     case 20:    fprintf(stderr,"20 ");        break;
  1612.     case 50:    fprintf(stderr,"50 ");        break;
  1613.     case 100:    fprintf(stderr,"100 ");        break;
  1614.     case 200:    fprintf(stderr,"200 ");        break;
  1615.     case 500:    fprintf(stderr,"500 ");        break;
  1616.     case 1000:    fprintf(stderr,"1k ");        break;
  1617.     case 2000:    fprintf(stderr,"2k ");        break;
  1618.     case 5000:    fprintf(stderr,"5k ");        break;
  1619.     case 10000:    fprintf(stderr,"10k ");        break;
  1620.     case 20000:    fprintf(stderr,"20k ");        break;
  1621.     case 50000L:fprintf(stderr,"50k ");        break;
  1622.     case 100000L:fprintf(stderr,"100k ");    break;
  1623.     case 200000L:fprintf(stderr,"200k ");    break;
  1624.     case 500000L:fprintf(stderr,"500k ");    break;
  1625.   }
  1626.  
  1627.   switch (cmd = fgetc (td))
  1628.   {
  1629.     case NOP:
  1630.     case MOVE_TO:
  1631.     case DRAW_TO:
  1632.     case PLOT_AT:
  1633.     case SET_PEN:
  1634.     return cmd;
  1635. /*  case EOF:    */
  1636.     default:
  1637.     return EOF;
  1638.   }
  1639. }
  1640.  
  1641.  
  1642.  
  1643. void    HPGL_Pt_from_tmpfile (HPGL_Pt *pf)
  1644. {
  1645.   if (fread ((VOID *) pf, sizeof(*pf), 1,td) != 1)
  1646.   {
  1647.     perror("HPGL_Pt_from_tmpfile");
  1648.     fprintf(stderr,"Error @ Cmd %ld\n", vec_cntr_r);
  1649.     exit (ERROR);
  1650.   }
  1651. }
  1652.