home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / s / stex2-18.zip / SeeTeX / Iptex / imagen1-specia < prev    next >
Text File  |  1990-09-17  |  25KB  |  939 lines

  1. /*
  2.  * Support drawing routines for Chris Torek's DVI->ImPress program.
  3.  *
  4.  * Requires v1.7 or later ImPress to handle paths.
  5.  * Better if v1.9 or later for arc, circle, and ellipse primitives
  6.  * (define USEGRAPHICS).
  7.  *
  8.  *    Tim Morgan, UC Irvine, 11/17/85
  9.  *
  10.  *
  11.  * At the time these routines are called, the position of the Imagen should
  12.  * have been updated to the upper left corner of the graph (the position
  13.  * the \special appears at in the dvi file).  Then the coordinates in the
  14.  * graphics commands are in terms of a virtual page with axes oriented the
  15.  * same as the Imagen normally has:
  16.  *
  17.  *            0,0
  18.  *             +-----------> +x
  19.  *             |
  20.  *             |
  21.  *             |
  22.  *            \ /
  23.  *             +y
  24.  *
  25.  * Angles are measured in the conventional way, from +x towards +y.
  26.  * Unfortunately, that reverses the meaning of "counterclockwise" from
  27.  * what you see in the output.
  28.  *
  29.  * Unfortunately, some 8/300's don't have an aspect ratio which is 1:1.
  30.  * One of ours appears to be 295 dpi in the horizontal direction and 300dpi
  31.  * vertically.  If ASPECT is defined, then dviimp/imagen1 and draw_imp/special
  32.  * use two different variables for the horizontal and vertical resolution, and
  33.  * otherwise, just one.  Because the drawing routines which are defined
  34.  * in ImPress for circles, arcs, and ellipses in V1.9 and later assume that
  35.  * the output device is 1:1, they can't be used if ASPECT is defined, and
  36.  * because I don't want to hack up imagen1 to understand different horizontal
  37.  * and vertical resolutions, we're currently ignoring this problem, and not
  38.  * defining ASPECT.
  39.  */
  40.  
  41. #ifndef    UNCOMPRESS
  42. #define    UNCOMPRESS    "/usr/ucb/uncompress"
  43. #endif
  44.  
  45. #define    USEGRAPHICS        /* Only if v1.9 or later imPRESS */
  46. #undef    ASPECT
  47.  
  48. #ifdef    ASPECT            /* Can't have both! */
  49. #undef    USEGRAPHICS
  50. #endif
  51.  
  52. #include <stdio.h>
  53. #include <ctype.h>
  54. #include <math.h>
  55. #include "imPcodes.h"
  56.  
  57. extern char *malloc();
  58.  
  59. /*
  60.  *    EXTERNS
  61.  */
  62.  
  63. extern    int NextFamilyNumber;    /* Number of next ImPress family to use */
  64. extern char *ProgName;
  65.  
  66. #ifndef    ASPECT
  67.     extern    int    dviDPI;        /* Resolution of device */
  68. #else
  69.     extern    int    DPIx, DPIy;    /* x,y resolution of device */
  70. #endif
  71.  
  72.  
  73. #define    TRUE    1
  74. #define    FALSE    0
  75.  
  76. #define    TWOPI        (3.14157926536*2.0)
  77. #define    MAXPOINTS    600    /* Most number of points in a path */
  78. #define    SPLINEPOINTS    5000    /* Most points in a spline */
  79. #define    RADTOPXL    2607.435436    /* (16383 / (2pi)).  This
  80.                     converts from radians to the
  81.                     angle units used by ImPress */
  82.  
  83. /* Convert radian angles to 2**-14 angle units used by ImPress */
  84. #define    RadToImpUnits(a)    ((short) ((a)*RADTOPXL + 0.5))
  85.  
  86. /* Graphics operations */
  87. #define    WHITE    0
  88. #define    SHADE    3
  89. #define    OR    7
  90. #define    BLACK    15
  91.  
  92. #ifndef    ASPECT
  93. #define    PixPerInX    dviDPI
  94. #define    PixPerInY    dviDPI
  95. #else
  96. #define    PixPerInX    DPIx
  97. #define    PixPerInY    DPIy
  98. #endif
  99.  
  100. /*
  101.  *    I don' understand the functionality of the GlobalMag & I've wasted
  102.  *    enough tim & paper trying to get this version of conv (from UCI)
  103.  *    to work, so we're sticking with the older one (from Maryland)
  104.  *    until I get the newone to work
  105.  */
  106.  
  107. #ifdef UNDEF
  108. extern    double    GlobalMag;    /* Mag/1000.0, unrounded */
  109. #define    conv(x, f)\
  110.     ((int) ((x) * ((double)(f)/5.0) * (GlobalMag/((double)dviDPI)) + 0.5))
  111. #define    xconv(x)    conv(x, PixPerInX)
  112. #define    yconv(y)    conv(y, PixPerInY)
  113.  
  114. #else
  115.  
  116. #define    xconv(x)    ((int) ((x) * ( ((float) dviDPI) / 1000.0) + 0.5))
  117. #define    yconv(y)    ((int) ((y) * ( ((float) dviDPI) / 1000.0) + 0.5))
  118.  
  119. #endif
  120.  
  121. #define    fnum    NextFamilyNumber
  122.  
  123. #define ImWrt1(x)  putchar(x)
  124. #define putword(w) (putchar ((w) >> 8), putchar (w))
  125. #define ImWrt2(x)  putword(x)
  126.  
  127. static    int xx[MAXPOINTS], yy[MAXPOINTS], pathlen,
  128.     pensize = 2;    /* Size we want Imagen to draw at, default 2 pixels */
  129.  
  130. #define    MAXPENSIZE 20        /* Imagen restriction */
  131.  
  132. static int
  133.     family_defined = FALSE,    /* Have we chosen family yet? */
  134.     texture_defined = FALSE,/* Have we done a set_texture yet? */
  135.     whiten_next = FALSE,    /* Should next object be whitened? */
  136.     blacken_next = FALSE,    /* Should next object be blackened? */
  137.     shade_next = FALSE;    /* Should next object be shaded? */
  138.  
  139. double shading = -1.0;        /* How should next object be shaded? */
  140.  
  141. /* Predefined shading (texture) glyph */
  142. /* First, define size of glyph */
  143. #define    THEIGHT    32        /* bits high */
  144. #define    TWIDTH    4        /* bytes wide */
  145. /* Next, declare the bit map for the glyph */
  146. static char stexture[THEIGHT][TWIDTH]={
  147.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  148.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  149.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  150.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  151.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  152.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  153.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  154.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  155.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  156.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  157.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  158.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  159.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  160.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  161.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  162.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}};
  163.  
  164. /*
  165.  * Copy a default texture into the stexture array
  166.  */
  167. static void glyph_init()
  168. {
  169.     static char btexture[THEIGHT][TWIDTH]={
  170.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  171.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  172.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  173.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  174.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  175.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  176.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  177.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  178.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  179.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  180.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  181.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  182.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  183.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00},
  184.     {0xcc, 0xcc, 0xcc, 0xcc}, {0x00, 0x00, 0x00, 0x00},
  185.     {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00}};
  186.  
  187.     int i;
  188.     for (i=0; i<THEIGHT; i++)
  189.         bcopy(btexture[i],stexture[i],TWIDTH);
  190.  
  191. }
  192.  
  193.  
  194. /*
  195.  * Push the state of the Imagen and set up a new virtual coord system
  196.  */
  197. static void push_location()
  198. {
  199.     ImWrt1(imP_PUSH);
  200.     ImWrt1(imP_SET_HV_SYSTEM);
  201.     ImWrt1(0140);
  202. }
  203.  
  204.  
  205. /*
  206.  * Create the pushed virtual page, and pop the state of the printer
  207.  */
  208. static void pop_location()
  209. {
  210.     ImWrt1(imP_POP);
  211. }
  212.  
  213.  
  214. /*
  215.  * Set the pen size
  216.  * Called as \special{pn size}
  217.  *     eg: \special{pn 8}
  218.  * The size is the number of milli-inches for the diameter of the pen.
  219.  * This routine converts that value to device-dependent pixels, and makes
  220.  * sure that the resulting value is within legal bounds.
  221.  */
  222. static void im_pensize(cp)
  223. char *cp;
  224. {
  225.     int size;
  226.     
  227.     if (sscanf(cp, " %d ", &size) != 1) return;
  228.     pensize = yconv(size);
  229.     if (pensize < 1) pensize = 1;
  230.     else if (pensize > MAXPENSIZE) pensize = MAXPENSIZE;
  231. }
  232.  
  233.  
  234. /*
  235.  * Make sure the pen size is set.  Since we push and pop the state,
  236.  * this has to be sent for each different object (I think).
  237.  */
  238. static void set_pen_size()
  239. {
  240.     ImWrt1(imP_SET_PEN);
  241.     ImWrt1(pensize);
  242. }
  243.  
  244.  
  245. /*
  246.  * Actually apply the attributes (shade, whiten, or blacken) to the currently
  247.  * defined path/figure.
  248.  */
  249. static void do_attributes()
  250. {
  251.     static int family;        /* Family of downloaded texture glyph */
  252.     static int member;        /* Member of family */
  253.     int i,j;            /* Loop through glyph array */
  254.  
  255.     if (shading >= 0.4 && shading <= 0.6) {
  256.     if (!family_defined) {
  257.         family_defined = TRUE;
  258.         family = fnum++;
  259.         member = -1;
  260.     }
  261.     if (!texture_defined) {
  262.         texture_defined = TRUE;
  263.         member++;
  264.         ImWrt1(imP_BGLY);
  265.         ImWrt1((family & 0x7e) >> 1);
  266.         ImWrt1((family & 0x01) << 7 | (member & 0x7f));
  267.         /*ImWrt2(0); */        /* Advance width */
  268.         ImWrt2(32);
  269.         ImWrt2(TWIDTH*8);    /* pixel width (8 x number of bytes) */
  270.         /*ImWrt2(0); */        /* left offset */
  271.         ImWrt2(32);
  272.         ImWrt2(THEIGHT);    /* and height of glyph */
  273.         /*ImWrt2(0); */        /* top offset */
  274.         ImWrt2(32);
  275.         for (i=0; i<THEIGHT; i++)/* Do rows */
  276.         for (j=0; j<TWIDTH; j++) ImWrt1(stexture[i][j]);
  277.     }
  278.     ImWrt1(imP_SET_TEXTURE);
  279.     ImWrt1((family & 0x7e) >> 1);
  280.     ImWrt1((family & 0x01) << 7 | (member & 0x7f));
  281.     ImWrt1(imP_FILL_PATH);
  282.     ImWrt1(SHADE);
  283.     glyph_init(); /* reinitialize the array */
  284.     }
  285.     else if (shading >= 0.0 && shading < 0.4) {
  286.     ImWrt1(imP_FILL_PATH);
  287.     ImWrt1(WHITE);
  288.     }
  289.     else if (shading > 0.6) {
  290.     ImWrt1(imP_FILL_PATH);
  291.     ImWrt1(BLACK);
  292.     }
  293.     shading = -1.0;
  294. }
  295.  
  296.  
  297. /*
  298.  * Flush the path that we've built up with im_drawto(), but don't draw it.
  299.  * Called as \special{ip}.
  300.  */
  301. static void im_invispath()
  302. {
  303.     register int i;
  304.  
  305.     push_location();
  306.     if (pathlen <= 0) return;
  307.     ImWrt1(imP_CREATE_PATH);
  308.     ImWrt2(pathlen);
  309.     for (i=1; i<=pathlen; i++) {
  310.     ImWrt2(xx[i]);
  311.     ImWrt2(yy[i]);
  312.     }
  313.     pathlen = 0;
  314.     do_attributes();
  315.     pop_location();
  316. }
  317.  
  318.  
  319. /*
  320.  * Flush the path that we've built up with im_drawto()
  321.  * Called as \special{fp}
  322.  */
  323. static void im_flushpath()
  324. {
  325.     register int i;
  326.  
  327.     push_location();
  328.     if (pathlen <= 0) return;
  329.     set_pen_size();
  330.     ImWrt1(imP_CREATE_PATH);
  331.     ImWrt2(pathlen);
  332.     for (i=1; i<=pathlen; i++) {
  333.     ImWrt2(xx[i]);
  334.     ImWrt2(yy[i]);
  335.     }
  336.     pathlen = 0;
  337.     ImWrt1(imP_DRAW_PATH);
  338.     ImWrt1(BLACK);
  339.     do_attributes();
  340.     pop_location();
  341. }
  342.  
  343.  
  344. /* Helper routine for dashed_line() */
  345. static void connect(x0, y0, x1, y1)
  346. int x0, y0, x1, y1;
  347. {
  348.     ImWrt1(imP_CREATE_PATH);
  349.     ImWrt2(2);        /* Path length */
  350.     ImWrt2(x0);    ImWrt2(y0);/* The path */
  351.     ImWrt2(x1);    ImWrt2(y1);
  352.     ImWrt1(imP_DRAW_PATH);
  353.     ImWrt1(BLACK);
  354. }
  355.  
  356.  
  357. /* Another helper.  Draw a dot at the indicated point */
  358. static void dot_at(x, y)
  359. int x,y;
  360. {
  361.     ImWrt1(imP_CREATE_PATH);
  362.     ImWrt2(1);            /* Path length */
  363.     ImWrt2(x);    ImWrt2(y);    /* The path */
  364.     ImWrt1(imP_DRAW_PATH);
  365.     ImWrt1(BLACK);
  366. }
  367.  
  368.  
  369. /*
  370.  * Draw a dashed or dotted line between the first pair of points in the array
  371.  * Called as \special{da <inchesperdash>}    (dashed line)
  372.  *      or \special{dt <inchesperdot>}    (dotted line)
  373.  *    eg:  \special{da 0.05}
  374.  */
  375. static void dashed_line(cp, dotted)
  376. char *cp;
  377. int dotted;            /* boolean */
  378. {
  379.     int i, numdots, x0, y0, x1, y1;
  380.     double cx0, cy0, cx1, cy1;
  381.     double d, spacesize, a, b, dx, dy, pixperdash;
  382.     float inchesperdash;
  383.  
  384.     if (sscanf(cp, " %f ", &inchesperdash) != 1) return;
  385.     if (pathlen <= 1) return;
  386.     pixperdash = inchesperdash * ((double) PixPerInY);
  387.     x0 = xx[1]; x1 = xx[2];
  388.     y0 = yy[1]; y1 = yy[2];
  389.     dx = x1 - x0;
  390.     dy = y1 - y0;
  391.     push_location();
  392.     if (dotted) {
  393.     set_pen_size();    /* May want to do something thicker for dotted lines */
  394.     numdots = sqrt(dx*dx + dy*dy) / pixperdash + 0.5;
  395.     if (numdots > 0)
  396.         for (i = 0; i <= numdots; i++) {
  397.         a = (double) i / (double) numdots;
  398.         cx0 = ((double) x0) + (a*dx) + 0.5;
  399.         cy0 = ((double) y0) + (a*dy) + 0.5;
  400.         dot_at((int) cx0, (int) cy0);
  401.         }
  402.     }
  403.     else {
  404.     set_pen_size();
  405.     d = sqrt(dx*dx + dy*dy);
  406.     if (d <= 2 * pixperdash) {
  407.         connect(x0, y0, x1, y1);
  408.         pathlen = 0;
  409.         pop_location();
  410.         return;
  411.     }
  412.     numdots = d / (2 * pixperdash) + 1;
  413.     spacesize = (d - numdots * pixperdash) / (numdots - 1);
  414.     for (i=0; i<numdots-1; i++) {
  415.         a = i * (pixperdash + spacesize) / d;
  416.         b = a + pixperdash / d;
  417.         cx0 = ((double) x0) + (a*dx) + 0.5;
  418.         cy0 = ((double) y0) + (a*dy) + 0.5;
  419.         cx1 = ((double) x0) + (b*dx) + 0.5;
  420.         cy1 = ((double) y0) + (b*dy) + 0.5;
  421.         connect((int) cx0, (int) cy0, (int) cx1, (int) cy1);
  422. #ifndef UNDEF
  423.         a = b;
  424.         b = a + spacesize / d;
  425. #else
  426.         b += spacesize / d;
  427. #endif UIUC
  428.     }
  429.     cx0 = ((double) x0) + (b*dx) + 0.5;
  430.     cy0 = ((double) y0) + (b*dy) + 0.5;
  431.     connect((int) cx0, (int) cy0, x1, y1);
  432.     }
  433.     pathlen = 0;
  434.     pop_location();
  435. }
  436.  
  437.  
  438. /*
  439.  * Virtually draw to a given x,y position on the virtual page.
  440.  * X and Y are expressed in thousandths of an inch, and this
  441.  * routine converts them to pixels.
  442.  *
  443.  * Called as \special{pa <x> <y>}
  444.  *     eg:  \special{pa 0 1200}
  445.  */
  446. static void im_drawto(cp)
  447. char *cp;
  448. {
  449.     int x,y;
  450.  
  451.     if (sscanf(cp, " %d %d ", &x, &y) != 2) return;
  452.  
  453.     if (++pathlen >= MAXPOINTS)
  454.     error(1, 0, "Too many points specified");
  455.     xx[pathlen] = xconv(x);
  456.     yy[pathlen] = yconv(y);
  457. }
  458.  
  459. #ifndef    USEGRAPHICS
  460. /*
  461.  * Helper routine for im_arc().
  462.  * Convert x and y to integers, then call im_drawto() normally.
  463.  */
  464. static void im_fdraw(x, y)
  465. double x, y;
  466. {
  467.     int ix,iy;
  468.  
  469.     ix = (int) x + 0.5;
  470.     iy = (int) y + 0.5;
  471.     im_drawto(ix, iy);
  472. }
  473.  
  474.  
  475. /*
  476.  * Draw the indicated arc on the virtual page and flush it.
  477.  * The arc is always drawn counter clockwise from start_angle to end_angle on
  478.  * the virtual page.  That is, clockwise in the real world (since +y is down).
  479.  * It is assumed that start_angle has been adjusted to be in the range
  480.  *    0.0 <= start_angle < 2*PI
  481.  * and that end_angle is the smallest suitable angle >= start_angle.  Thus
  482.  * end_angle MAY be >= 2*PI.
  483.  *
  484.  * Called as \special{ar <xcenter> <ycenter> <xradius> <yradius>
  485.  *             <startangle> <endangle>}
  486.  *
  487.  * <xcenter>,<ycenter>,<xradius>,<yradius> are in 1/1000's of an inch.
  488.  * <startangle> and <endangle> are in radians.
  489.  *
  490.  *    eg:    \special{ar 240 240 30 30 0.000 6.283}
  491.  */
  492. static void im_arc(cp, invis)
  493. char *cp;
  494. int invis;
  495. {
  496.     int xc, yc, xrad, yrad;
  497.     float start_angle, end_angle;
  498.     double angle, theta, r, xcenter, ycenter, xradius, yradius;
  499.     int n;
  500.  
  501.     if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle,
  502.     &end_angle) != 6) return;
  503.     xcenter = xc;        /* Convert to floating point */
  504.     ycenter = yc;
  505.     xradius = xrad;
  506.     yradius = yrad;
  507.     r = (xradius+yradius)/2.0;
  508.     theta = sqrt(1.0 / r);
  509.     n = TWOPI / theta + 0.5;
  510.     if (n<6) n = 6;
  511.     if (n>80) n = 80;
  512.     theta = TWOPI / n;
  513.  
  514.     im_fdraw( xcenter + xradius*cos(start_angle),
  515.         ycenter + yradius*sin(start_angle) );
  516.     angle = start_angle + theta;
  517.     while (angle < end_angle) {
  518.     im_fdraw(xcenter + xradius*cos(angle),
  519.         ycenter + yradius*sin(angle) );
  520.     angle += theta;
  521.     }
  522.     im_fdraw( xcenter + xradius*cos(end_angle),
  523.         ycenter + yradius*sin(end_angle) );
  524.     if (invis)
  525.       im_invispath();
  526.     else
  527.       im_flushpath();
  528. }
  529.  
  530. #else    USEGRAPHICS
  531.  
  532. /* Same routine as above, but it uses the special graphics primitives */
  533. static void im_arc(cp, invis)
  534. char *cp;
  535. int invis;
  536. {
  537.     int xc, yc, xrad, yrad;
  538.     float start_angle, end_angle;
  539.     short alpha0, alpha1;
  540.  
  541.     if (sscanf(cp, " %d %d %d %d %f %f ", &xc, &yc, &xrad, &yrad, &start_angle,
  542.     &end_angle) != 6) return;
  543.     push_location();
  544.     set_pen_size();
  545.     ImWrt1(imP_SET_ABS_H);
  546.     ImWrt2(xconv(xc));
  547.     ImWrt1(imP_SET_ABS_V);
  548.     ImWrt2(yconv(yc));
  549.  
  550. /*
  551.  * If end_angle > TWOPI, we can't simply use it, since it will be > 16383,
  552.  * and thus an illegal angle.  Simply subtracting TWOPI will make it <
  553.  * start_angle, which will reverse the direction the arc is drawn, resulting
  554.  * in the wrong arc.  So we also exchange start_angle and end_angle.  But then
  555.  * start_angle < end_angle, so the arc goes back to its original direction!
  556.  * So we also subtract TWOPI from the original start_angle, foring end_angle
  557.  * to be negative (since 0<=start_angle<TWOPI originally), which will cause
  558.  * the Imagen to draw in a true CCW direction (opposite of normal).
  559.  */
  560.     if (end_angle >= TWOPI) {
  561.     double temp;
  562.     temp = end_angle - TWOPI;
  563.     end_angle = start_angle - TWOPI;
  564.     start_angle = temp;
  565.     }
  566.     alpha0 = RadToImpUnits(start_angle);
  567.     alpha1 = RadToImpUnits(end_angle);
  568.     if (xrad >= yrad-1 && xrad <= yrad+1) {        /* Circle or arc */
  569.     ImWrt1(CIRC_ARC);
  570.     ImWrt2(xconv((double) xrad));
  571.     ImWrt2(alpha0);
  572.     ImWrt2(alpha1);
  573.     }
  574.     else {            /* Ellipse */
  575.     ImWrt1(ELLIPSE_ARC);
  576.     ImWrt2(xconv((double) xrad));
  577.     ImWrt2(yconv((double) yrad));
  578.     ImWrt2(0);        /* alphaoff */
  579.     ImWrt2(alpha0);        /* zero start angle */
  580.     ImWrt2(alpha1);        /* two pi end angle */
  581.     }
  582.     if (!invis) {
  583.       ImWrt1(imP_DRAW_PATH);
  584.       ImWrt1(BLACK);
  585.     }
  586.     do_attributes();
  587.     pop_location();
  588. }
  589. #endif    USEGRAPHICS
  590.  
  591.  
  592. /*
  593.  * Create a spline through the points in the array.
  594.  * Called like flush path (fp) command, after points
  595.  * have been defined via pa command(s).
  596.  *
  597.  * eg:    \special{sp}
  598.  */
  599. int splinex[SPLINEPOINTS], spliney[SPLINEPOINTS], splinelen;
  600. static void flush_spline(cp)
  601. char *cp;
  602. {
  603.     int xp, yp, N;
  604.     double t1, t2, t3, w;
  605.     int i, j, steps;
  606.     float dlen;
  607.  
  608.     push_location();
  609.     set_pen_size();
  610.  
  611.     splinelen = 0;
  612.     splinex[splinelen] = xx[1];
  613.     spliney[splinelen++] = yy[1];
  614.     N = pathlen + 1;
  615.     xx[0] = xx[1];
  616.     yy[0] = yy[1];
  617.     xx[N] = xx[N-1];
  618.     yy[N] = yy[N-1];
  619.     for (i = 0; i < N-1; i++) {    /* interval */
  620.     steps = (dist(xx[i],yy[i], xx[i+1],yy[i+1]) +
  621.         dist(xx[i+1],yy[i+1], xx[i+2],yy[i+2])) / 20;
  622.     for (j = 0; j < steps; j++) {    /* points within */
  623.         w = ((double) j) / ((double) steps);
  624.         t1 = 0.5 * w * w;
  625.         w -= 0.5;
  626.         t2 = 0.75 - w * w;
  627.         w -= 0.5;
  628.         t3 = 0.5 * w * w;
  629.         xp = t1 * xx[i+2] + t2 * xx[i+1] + t3 * xx[i] + 0.5;
  630.         yp = t1 * yy[i+2] + t2 * yy[i+1] + t3 * yy[i] + 0.5;
  631.         if (splinelen >= SPLINEPOINTS)
  632.             error(1, 0, "Too many points in spline");
  633.         if (splinex[splinelen-1] != xp || spliney[splinelen-1] != yp) {
  634.             splinex[splinelen] = xp;
  635.             spliney[splinelen++] = yp;
  636.         }
  637.     }
  638.     }
  639.     if ((xx[pathlen] != splinex[splinelen-1] ||
  640.     yy[pathlen] != spliney[splinelen-1]) && splinelen < SPLINEPOINTS) {
  641.     splinex[splinelen] = xx[pathlen];
  642.     spliney[splinelen++] = yy[pathlen];
  643.     }
  644.  
  645. #define imP_SET_DRAW_PATTERN 237
  646.     if (sscanf(cp, "%f", &dlen) == 1) {
  647.     dlen *= 1000;
  648.     ImWrt1(imP_SET_DRAW_PATTERN);
  649.     ImWrt1(2);
  650.     if ( dlen > 0 ) {
  651.         /* do dashed lines */
  652.         ImWrt2(xconv(dlen));
  653.         ImWrt2(xconv(dlen));
  654.     } else {
  655.         /* do dotted lines */
  656.         ImWrt2(pensize/2 );
  657.         ImWrt2(-xconv(dlen));
  658.     }
  659.     }
  660.  
  661.     ImWrt1(imP_CREATE_PATH);
  662.     ImWrt2(splinelen);
  663.     for (i=0; i<splinelen; i++) {
  664.         ImWrt2(splinex[i]);
  665.         ImWrt2(spliney[i]);
  666.     }
  667.  
  668.     pathlen = 0;
  669.     ImWrt1(imP_DRAW_PATH);
  670.     ImWrt1(OR);
  671.     pop_location();
  672. }
  673.  
  674.  
  675. static int dist(x1, y1, x2, y2)    /* integer distance from x1,y1 to x2,y2 */
  676. {
  677.     double dx, dy;
  678.  
  679.     dx = x2 - x1;
  680.     dy = y2 - y1;
  681.     return sqrt(dx*dx + dy*dy) + 0.5;
  682. }
  683.  
  684.  
  685. /*
  686.  * Shade the interior of the next figure (path) with the predefined
  687.  * texture.  Command is:
  688.  *    \special{sh}
  689.  */
  690. static void im_shade(cp)
  691. char *cp;
  692. {
  693.     if (cp && *cp) shading = atof(cp);
  694.     else shading = 0.5;
  695. }
  696.  
  697.  
  698. /*
  699.  * Define the texture array.  Command is:
  700.  *    \special{tx 32bits 32bits ....}
  701.  */
  702. static void im_texture(pcount,bitpattern)
  703. int pcount, bitpattern[32];
  704. {
  705.     int i,j,k;
  706.     unsigned long ul_one;
  707.  
  708. #ifdef    DEBUG
  709.     if (sizeof ul_one != TWIDTH)
  710.     error(1, 0, "pointer/size mismatch");
  711. #endif
  712.     j = 0;
  713.     for (k=0; k < THEIGHT/pcount; k++) {
  714.     for (i=0; i<pcount; i++) {
  715.         ul_one = htonl((unsigned long) bitpattern[i]);
  716.         bcopy((char *) &ul_one, stexture[j++], TWIDTH);
  717.     }
  718.     }
  719.     texture_defined = FALSE;
  720. }
  721.  
  722.  
  723. /*
  724.  * This routine takes the string argument for a tx command and
  725.  * parses out the separate bitpatterns to call im_texture with.
  726.  * Written by Tinh Tang
  727.  */
  728. static void do_texture(t)
  729. char *t;
  730. {
  731.     int bitpattern[32];
  732.     int pcount = 0;
  733.  
  734.     while (isspace (*t)) t++;
  735.     while (*t) {
  736.     if (sscanf(t, "%x", &bitpattern[pcount++]) != 1) {
  737.         error(0, 0, "malformed tx command");
  738.         return;
  739.     }
  740.     while (*t && !isspace(*t)) t++;/* Skip to space */
  741.     while (*t && isspace(*t)) t++;/* Skip to nonspace */
  742.     }
  743.     if (pcount != 4 && pcount != 8 && pcount != 16 && pcount != 32) {
  744.     error(0, 0, "malformed tx command");
  745.     return;
  746.     }
  747.     im_texture(pcount, bitpattern);
  748. }
  749.  
  750.  
  751. static void do_impress(s)
  752. char *s;
  753. {
  754.     FILE *p, *popen();
  755.     int val;
  756.  
  757.     push_location();
  758.     fflush(stdout);
  759.     p = popen(UNCOMPRESS, "w");
  760.     while (*s && *s == ' ') ++s;
  761.     while (*s) {
  762.     if (sscanf(s, "%x ", &val) != 1) {
  763.         fprintf(stderr, "impossible error\n");
  764.         exit(1);
  765.     }
  766.     putc(val, p);
  767.     while (*s && *s != ' ') ++s;
  768.     while (*s && *s == ' ') ++s;
  769.     }
  770.     pclose(p);
  771.     pop_location();
  772. }
  773.  
  774.     
  775. #define    COMLEN    3        /* Length of a tpic command plus one */
  776.  
  777. void DoSpecial(k)
  778. int k;
  779. {
  780.     char *spstring, *cp, command[COMLEN];
  781.     register int len;
  782.  
  783.     spstring = malloc((unsigned) (k+1));
  784.     if (spstring == NULL) error(2, 0, "Out of memory");
  785.     len = 0;
  786.     while (k--) spstring[len++] = getchar();
  787.     spstring[len] = '\0';
  788.     cp = spstring;
  789.     while (isspace(*cp)) ++cp;
  790.     len = 0;
  791.     while (!isspace(*cp) && *cp && len < COMLEN-1) command[len++] = *cp++;
  792.     command[len] = '\0';
  793.     if (strcmp(command, "pn") == 0) im_pensize(cp);
  794.     else if (strcmp(command, "fp") == 0) im_flushpath();
  795.     else if (strcmp(command, "da") == 0) dashed_line(cp, 0);
  796.     else if (strcmp(command, "dt") == 0) dashed_line(cp, 1);
  797.     else if (strcmp(command, "pa") == 0) im_drawto(cp);
  798.     else if (strcmp(command, "ar") == 0) im_arc(cp, 0);
  799.     else if (strcmp(command, "ia") == 0) im_arc(cp, 1);
  800.     else if (strcmp(command, "sp") == 0) flush_spline(cp);
  801.     else if (strcmp(command, "sh") == 0) im_shade(cp);
  802.     else if (strcmp(command, "wh") == 0) im_shade("0");
  803.     else if (strcmp(command, "bk") == 0) im_shade("1");
  804.     else if (strcmp(command, "tx") == 0) do_texture(cp);
  805.     else if (strcmp(command, "bf") == 0) do_impress(cp);
  806.     else if (strcmp(command, "ip") == 0) im_invispath();
  807.     else if (strcmp(command, "in") == 0) do_insert(cp);
  808.     else error(0, 0, "warning: ignoring \\special");
  809.  
  810.     free(spstring);
  811. }
  812.  
  813. /***********************************************************************
  814.  *
  815.  *    This is an alternate dvistuff compatible interface to the specials.
  816.  */
  817.  
  818. void newDoSpecial(cp)
  819. char *cp;
  820. {
  821.     char command[COMLEN], *orig_cp;
  822.     register int len;
  823.  
  824.     orig_cp = cp;
  825.     while (isspace(*cp)) ++cp;
  826.     len = 0;
  827.     while (!isspace(*cp) && *cp && len < COMLEN-1) command[len++] = *cp++;
  828.     command[len] = '\0';
  829.     if (strcmp(command, "pn") == 0) im_pensize(cp);
  830.     else if (strcmp(command, "fp") == 0) im_flushpath();
  831.     else if (strcmp(command, "da") == 0) dashed_line(cp, 0);
  832.     else if (strcmp(command, "dt") == 0) dashed_line(cp, 1);
  833.     else if (strcmp(command, "pa") == 0) im_drawto(cp);
  834.     else if (strcmp(command, "ar") == 0) im_arc(cp, 0);
  835.     else if (strcmp(command, "ia") == 0) im_arc(cp, 1);
  836.     else if (strcmp(command, "sp") == 0) flush_spline(cp);
  837.     else if (strcmp(command, "sh") == 0) im_shade(cp);
  838.     else if (strcmp(command, "wh") == 0) im_shade("0");
  839.     else if (strcmp(command, "bk") == 0) im_shade("1");
  840.     else if (strcmp(command, "tx") == 0) do_texture(cp);
  841.     else if (strcmp(command, "bf") == 0) do_impress(cp);
  842.     else if (strcmp(command, "ip") == 0) im_invispath();
  843.     else if (strcmp(command, "in") == 0) do_insert(cp);
  844.     else fprintf(stderr, "[%s] special \"%s\" not implemented\n",
  845.         ProgName, orig_cp);
  846. }
  847.  
  848.  
  849. extern int DoPlots;
  850. extern int LandScape;
  851. extern int     ImHH;                   /* Imagen horizontal position */
  852. extern int     ImVV;                   /* Imagen vertical position */
  853.  
  854. do_insert(cp)
  855. char *cp;
  856. {
  857.     char *filename;
  858.     FILE * tempin;
  859.     int first;
  860.     char    *bi, *ci ;
  861.     char    inchar;
  862.     int     tempi;
  863.     int     xround,yround;
  864.  
  865.     bi = ++cp;
  866.     while ( *bi != '(' ) bi++;        /* find start of file name */
  867.     bi++;
  868.     while (isspace(*bi)) bi++;
  869.     ci = bi; 
  870.  
  871.     while ( !isspace(*ci) && *ci != ')') ci++;    /* end delimited by a ) */
  872.  
  873.     *ci = '\0';        /* terminate the string */
  874.  
  875.     /* now we have the filename to include */
  876.     filename = malloc( strlen(bi) + 1);
  877.     strcpy(filename, bi);
  878.  
  879.     if ((tempin = fopen (filename, "r")) == NULL)
  880.     {            /* open the file */
  881.     fprintf (stderr, " can't open %s \n", filename);
  882.     free(filename);
  883.     return;
  884.     }
  885.  
  886.     /* push current state */
  887.     ImWrt1 (imP_PUSH);
  888.  
  889.     /*
  890.      * The Imagen can't align raster on anything other than 32 by 32 byte
  891.      * blocks. So force the imagen onto the nearest block boundary to assure
  892.      * that vector and raster data in the plot don't come "unconnected".
  893.      * Joe Dellinger, Feb 26 1987
  894.      */
  895.     yround = 32 * (long) ((ImVV + 16) / 32);
  896.     xround = 32 * (long) ((ImHH + 16) / 32);
  897.     ImSetPosition (xround, yround);
  898.  
  899.     if ( DoPlots ) /* -P flag disables included plots */
  900.     {
  901.     /* At the moment, only insert(file) is recognized.  
  902.      * Our plots come out in landscape mode. 
  903.      * Hence the rotation and stuff.  Other
  904.      * Impress-production software may, of course, behave differently...
  905.      */
  906.  
  907.     ImWrt1 ( imP_SetHVSystem );
  908.  
  909.     if (LandScape)
  910.         ImWrt1 (0144);
  911.     else
  912.         ImWrt1 (0147);
  913.  
  914.     first = 1;
  915.  
  916.     while ((tempi = getc (tempin)) != EOF)
  917.     {
  918.         inchar = (char) tempi;
  919.         if (inchar == '@' && first)
  920.         {        /* remove document control */
  921.         while (((inchar = getc (tempin)) != EOF)
  922.             && (inchar != ')'));
  923.         tempi = getc (tempin);
  924.         }
  925.         first = 0;
  926.  
  927.         ImWrt1 (tempi);
  928.     }
  929.     }
  930.     ImWrt1 (imP_Page);
  931.     ImWrt1 (imP_POP);
  932.  
  933.     /* close up the plot file */
  934.     fclose (tempin);
  935.     free(filename);
  936.  
  937.     return 0 ;
  938. }
  939.