home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / XAP / XFIG / TRANSFIG.2 / TRANSFIG / transfig / fig2dev / dev / genlatex.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-01  |  22.8 KB  |  929 lines

  1. /*
  2.  * TransFig: Facility for Translating Fig code
  3.  * Copyright (c) 1985 Supoj Sutantavibul
  4.  * Copyright (c) 1991 Micah Beck
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and its
  7.  * documentation for any purpose is hereby granted without fee, provided that
  8.  * the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation. The authors make no representations about the suitability 
  11.  * of this software for any purpose.  It is provided "as is" without express 
  12.  * or implied warranty.
  13.  *
  14.  * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
  16.  * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  19.  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  20.  * PERFORMANCE OF THIS SOFTWARE.
  21.  *
  22.  */
  23.  
  24. /* 
  25.  *    genlatex.c : LaTeX driver for fig2dev
  26.  *
  27.  *    Author: Frank Schmuck, Cornell University 6/88
  28.  *     Converted from fig2latex 5/89 by Micah Beck
  29.  *     Color, rotated text and ISO-chars added by Herbert Bauer 11/91
  30.  *
  31.  */
  32. #if defined(hpux) || defined(SYSV)
  33. #include <sys/types.h>
  34. #endif
  35. #include <sys/file.h>
  36. #include <stdio.h>
  37. #include <math.h>
  38. #include "object.h"
  39. #include "fig2dev.h"
  40. #include "texfonts.h"
  41. #include "pi.h"
  42.  
  43. #ifndef fabs
  44. extern double fabs();
  45. #endif
  46. #ifndef sin
  47. extern double sin();
  48. #endif
  49. #ifndef cos
  50. extern double cos();
  51. #endif
  52. #ifndef acos
  53. extern double acos();
  54. #endif
  55. #ifndef atan
  56. extern double atan();
  57. #endif
  58. extern double rad2deg;
  59. extern void unpsfont();
  60.  
  61. #define rint(a) floor((a)+0.5)     /* close enough? */
  62.  
  63. /* 
  64.  *  Installation dependent constants:
  65.  *
  66.  *  THINDOT    latex command for generating a dot if line width = \thinlines
  67.  *  THICKDOT    latex command for generating a dot if line width = \thicklines
  68.  *  MIN_LEN    shortest slanted line that latex can produce; shorter lines will
  69.  *        we translated into a sequence of dots generated by \multiput.
  70.  *  THICK_LDOT    latex command for generating the dot for making short slanted
  71.  *        lines if line width = \thinlines
  72.  *  THIN_LDOT    ...  if line width = \thicklines
  73.  */
  74. #define THICKDOT    "\\SetFigFont{10}{12}{rm}."
  75. #define THINDOT        "\\SetFigFont{7}{8.4}{rm}."
  76. double    THIN_XOFF =    (0.1/72.0);
  77. double    THIN_YOFF =    (0.7/72.0);
  78. double    THICK_XOFF =    (0.4/72.0);
  79. double    THICK_YOFF =    (0.6/72.0);
  80. #define THICK_LDOT    "\\SetFigFont{7}{8.4}{rm}."
  81. #define THIN_LDOT    "\\SetFigFont{5}{6}{rm}."
  82. double    THIN_LXOFF =    (0.1/72.0);
  83. double    THIN_LYOFF =    (0.7/72.0);
  84. double    THICK_LXOFF =    (0.4/72.0);
  85. double    THICK_LYOFF =    (0.6/72.0);
  86. #define MIN_LEN        (13.0/72.0)    /* 13  points */
  87.  
  88. /*
  89.  *  other constants and macros
  90.  */
  91. #define TOP        840
  92. #define THINLINES    1
  93. #define THICKLINES    2
  94.  
  95. #define MAXCIRCLEDIA    80
  96. #define MAXCIRCLERAD    ((MAXCIRCLEDIA-0.5)/(2*72.27))
  97.  
  98. #define    SWAP(x,y)    {tmp=x; x=y; y=tmp;}
  99. #define TRANS(x,y)        (*translate_coordinates)(&x,&y)
  100. #define TRANS2(x1,y1,x2,y2)    (*translate_coordinates)(&x1,&y1); \
  101.                 (*translate_coordinates)(&x2,&y2)
  102. #define TRANSD(x,y)        (*translate_coordinates_d)(&x,&y)
  103. #ifndef MIN
  104. #define    MIN(x,y)    (((x) <= (y))? (x): (y))
  105. #endif
  106. #ifndef MAX
  107. #define    MAX(x,y)    (((x) >= (y))? (x): (y))
  108. #endif
  109. #define    ABS(x)        (((x) >= 0)? (x): -(x))
  110. #define round4(x)    ((round(10000.0*(x))/10000.0))
  111. #define round6(x)    ((round(1000000.0*(x))/1000000.0))
  112.  
  113. char        thindot [] = THINDOT;
  114. char        thickdot[] = THICKDOT;
  115. char        thin_ldot [] = THIN_LDOT;
  116. char        thick_ldot[] = THICK_LDOT;
  117.  
  118. static    int    coord_system;
  119. int        verbose = 0;
  120. double        dash_mag = 1.0;
  121. int        thick_width = 2;
  122. double        tolerance = 2.0;
  123. double        arc_tolerance = 1.0;
  124. int        (*translate_coordinates)() = NULL;
  125. int        (*translate_coordinates_d)() = NULL;
  126. double        unitlength;
  127. static int    cur_thickness = -1;
  128. double        ldot_diameter = 1.0/72.0;
  129. char        *dot_cmd = thindot;
  130. char        *ldot_cmd = thin_ldot;
  131. double        dot_xoffset;
  132. double        dot_yoffset;
  133. double        ldot_xoffset;
  134. double        ldot_yoffset;
  135.  
  136. extern char *ISOtoTeX[];
  137.  
  138. static translate1(xp, yp)
  139. int    *xp, *yp;
  140. {
  141.     *xp = *xp + 1;
  142.     *yp = *yp + 1;
  143.     }
  144.  
  145. static translate2(xp, yp)
  146. int    *xp, *yp;
  147. {
  148.     *xp = *xp + 1;
  149.     *yp = TOP - *yp -1;
  150.     }
  151.  
  152. static translate1_d(xp, yp)
  153. double    *xp, *yp;
  154. {
  155.     *xp = *xp + 1.0;
  156.     *yp = *yp + 1.0;
  157.     }
  158.  
  159. static translate2_d(xp, yp)
  160. double    *xp, *yp;
  161. {
  162.     *xp = *xp + 1.0;
  163.     *yp = (double)TOP - *yp -1.0;
  164.     }
  165.  
  166. void genlatex_option(opt, optarg)
  167. char opt, *optarg;
  168. {
  169.     int i;
  170.  
  171.     switch (opt) {
  172.     case 'a':
  173.         fprintf(stderr, "warning: latex option -a obsolete");
  174.         break;
  175.  
  176.     case 'd':
  177.         dash_mag = atof(optarg);    /* set dash magnification */
  178.         break;
  179.  
  180.  
  181.     case 'f':        /* set default text font */
  182.         for ( i = 1; i <= MAX_FONT; i++ )
  183.         if ( !strcmp(optarg, texfontnames[i]) ) break;
  184.  
  185.         if ( i > MAX_FONT)
  186.         fprintf(stderr,
  187.             "warning: non-standard font name %s\n", optarg);
  188.         
  189.         texfontnames[0] = texfontnames[1] = optarg;
  190.         break;
  191.  
  192.     case 'l':        /* set thin/thick line threshold */
  193.         thick_width = atoi(optarg);
  194.         break;
  195.  
  196.     case 's':
  197.         if (font_size <= 0 || font_size > MAXFONTSIZE) {
  198.         fprintf(stderr,
  199.             "warning: font size %d out of bounds\n", font_size);
  200.         }
  201.         break;
  202.  
  203.     case 'v':
  204.         verbose = 1;        /* verbose mode */
  205.         break;
  206.  
  207.     case 'm':
  208.     case 'L':
  209.         break;
  210.  
  211.     default:
  212.         put_msg(Err_badarg, opt, "latex");
  213.         exit(1);
  214.         break;
  215.     }
  216. }
  217.  
  218. void genlatex_start(objects)
  219. F_compound    *objects;
  220. {
  221.     int tmp;
  222.  
  223.     texfontsizes[0] = texfontsizes[1] = TEXFONTSIZE(font_size);
  224.  
  225.     coord_system = objects->nwcorner.y;
  226.      unitlength = mag/objects->nwcorner.x;
  227.  
  228.     switch (coord_system) {
  229.         case 1:
  230.         translate_coordinates = translate1;
  231.         translate_coordinates_d = translate1_d;
  232.         break;
  233.         case 2:
  234.         translate_coordinates = translate2;
  235.         translate_coordinates_d = translate2_d;
  236.         break;
  237.         default:
  238.         fprintf(stderr, "Wrong coordinate system; cannot continue\n");
  239.         return;
  240.         }
  241.  
  242.     TRANS2(llx, lly, urx, ury);
  243.     if (llx > urx) SWAP(llx, urx)
  244.     if (lly > ury) SWAP(lly, ury)
  245.  
  246.     /* LaTeX start */
  247.     fprintf(tfp, "\\setlength{\\unitlength}{%.6fin}%%\n",
  248.                         round6(unitlength));
  249.     /* define the SetFigFont macro */
  250.     define_setfigfont(tfp);
  251.     fprintf(tfp, "\\begin{picture}(%d,%d)(%d,%d)\n",
  252.                       urx-llx, ury-lly, llx, lly);
  253. }
  254.  
  255. void genlatex_end()
  256. {
  257.     /* LaTeX ending */
  258.     fprintf(tfp, "\\end{picture}\n");
  259. }
  260.  
  261. static set_linewidth(w)
  262. int    w;
  263. {
  264.     int        latex_w;
  265.  
  266.     if (w == 0) return;
  267.     /* latex only knows thin lines or thick lines */
  268.     latex_w = (w >= thick_width)? THICKLINES: THINLINES;
  269.     if (latex_w != cur_thickness) {
  270.         cur_thickness = latex_w;
  271.         if (cur_thickness == THICKLINES) {
  272.         fprintf(tfp, "\\thicklines\n");
  273.         dot_cmd = thickdot;
  274.         dot_xoffset = round4(THICK_XOFF/unitlength);
  275.         dot_yoffset = round4(THICK_YOFF/unitlength);
  276.         ldot_cmd = thick_ldot;
  277.         ldot_xoffset = round4(THICK_LXOFF/unitlength);
  278.         ldot_yoffset = round4(THICK_LYOFF/unitlength);
  279.         }
  280.         else {
  281.         fprintf(tfp, "\\thinlines\n");
  282.         dot_cmd = thin_ldot;
  283.         dot_xoffset = round4(THIN_XOFF/unitlength);
  284.         dot_yoffset = round4(THIN_YOFF/unitlength);
  285.         ldot_cmd = thin_ldot;
  286.         ldot_xoffset = round4(THIN_LXOFF/unitlength);
  287.         ldot_yoffset = round4(THIN_LYOFF/unitlength);
  288.         }
  289.         }
  290.     }
  291.  
  292. void genlatex_line(l)
  293. F_line    *l;
  294. {
  295.     F_point        *p, *q;
  296.     int        x, y, llx, lly, urx, ury, arrow;
  297.  
  298.     if (verbose) fprintf(tfp, "%%\n%% Fig POLYLINE object\n%%\n");
  299.  
  300.     set_linewidth(l->thickness);
  301.     set_color(l->color);
  302.  
  303.     p = l->points;
  304.     q = p->next;
  305.  
  306.     if (q == NULL) { /* A single point line */
  307.         x = p->x; y = p->y;
  308.         TRANS(x, y);
  309.         fprintf(tfp, "\\put(%3d,%3d){\\makebox(%.4f,%.4f){%s}}\n",
  310.           x, y, dot_xoffset, dot_yoffset, dot_cmd);
  311.         return;
  312.         }
  313.  
  314.     if (l->type == T_ARC_BOX) { /* A box with rounded corners */
  315.       fprintf(stderr, "Arc box not implemented; substituting box.\n");
  316.       l->type = T_BOX;
  317.     }
  318.  
  319.     if (l->type == T_BOX) { /* A box */
  320.         x = p->x; y = p->y;
  321.         TRANS(x, y);
  322.         llx = urx = x;
  323.         lly = ury = y;
  324.         while (q != NULL) {
  325.         x = q->x; y = q->y;
  326.         TRANS(x, y);
  327.         if (x < llx) llx = x;
  328.         if (y < lly) lly = y;
  329.         if (x > urx) urx = x;
  330.         if (y > ury) ury = y;
  331.         q = q->next;
  332.         }
  333.         put_box (llx, lly, urx, ury, l->style, l->style_val);
  334.         return;
  335.         }
  336.  
  337.     while (q != NULL) {
  338.         arrow = 0;
  339.         if (l->for_arrow  &&  q->next == NULL)
  340.         arrow = 1;
  341.         if (l->back_arrow  &&  p == l->points)
  342.         arrow = (arrow)? 2: -1;
  343.         single_line(p->x, p->y, q->x, q->y, arrow, l->style, l->style_val);
  344.         p = q;
  345.         q = q->next;
  346.         }
  347.  
  348.     if (l->area_fill && (int)l->area_fill != DEFAULT)
  349.         fprintf(stderr, "Line area fill not implemented\n");
  350.     reset_color(l->color);
  351.     }
  352.  
  353. static single_line (x1, y1, x2, y2, arrow, style, val)
  354. int    x1, y1, x2, y2, arrow, style;
  355. double    val;
  356. {
  357.     int    dx, dy, sx, sy;
  358.     double l, m, deviation;
  359.  
  360.     TRANS2(x1, y1, x2, y2);
  361.     dx = x2-x1;
  362.     dy = y2-y1;
  363.     /*** compute direction vector ***/
  364.     get_slope(dx, dy, &sx, &sy, arrow);
  365.     /*** compute line length in x-direction ***/
  366.     if (sx == 0) {
  367.         l = (double)abs(dy);
  368.     } else {
  369.         m = (double)abs(sy) / (double)abs(sx);
  370.         l = ((double)abs(dx) + m*(double)abs(dy)) / (1.0 + m*m);
  371.         deviation = fabs(l-abs(dx)) + fabs(m*l-abs(dy));
  372.         if (deviation > tolerance)
  373.         fprintf(stderr,
  374.           "Not a LaTeX slope (%d, %d), deviation %.1f pixels\n",
  375.           dx, dy, deviation);
  376.     }
  377.     l = round4(l);
  378.     /*** output letex command ***/
  379.     switch (style) {
  380.         case SOLID_LINE:
  381.         put_solidline(x1, y1, sx, sy, l, arrow);
  382.         break;
  383.         case DASH_LINE:
  384.         put_dashline(x1, y1, sx, sy, l, arrow, val);
  385.         break;
  386.         case DOTTED_LINE:
  387.         put_dotline(x1, y1, sx, sy, l, arrow, val);
  388.         break;
  389.         }
  390.     }
  391.  
  392.  
  393. /*
  394.  * draw box
  395.  */
  396. static put_box (llx, lly, urx, ury, style, val)
  397. int    llx, lly, urx, ury, style;
  398. double    val;
  399. {
  400.     int    dlen;
  401.  
  402.     switch (style) {
  403.         case SOLID_LINE:
  404.         fprintf(tfp, "\\put(%3d,%3d){\\framebox(%d,%d){}}\n",
  405.           llx, lly, urx-llx, ury-lly);
  406.         break;
  407.         case DASH_LINE:
  408.         dlen = round(val*dash_mag);
  409.         fprintf(tfp, "\\put(%3d,%3d){\\dashbox{%d}(%d,%d){}}\n",
  410.           llx, lly, dlen, urx-llx, ury-lly);
  411.         break;
  412.         case DOTTED_LINE:
  413.         put_dotline (llx, lly, 1, 0, (double)(urx-llx), 0, val);
  414.         put_dotline (llx, ury, 1, 0, (double)(urx-llx), 0, val);
  415.         put_dotline (llx, lly, 0, 1, (double)(ury-lly), 0, val);
  416.         put_dotline (urx, lly, 0, 1, (double)(ury-lly), 0, val);
  417.         break;
  418.         }
  419.     return;
  420.     }
  421.  
  422. /*
  423.  * draw a solid line given latex slope
  424.  */
  425. static put_solidline (x, y, sx, sy, l, arrow)
  426. int    x, y, sx, sy, arrow;
  427. double    l;
  428. {
  429.     double    cosine;        /* cosine of line angle */
  430.     double    dx, dy;
  431.     int    x2, y2, n;
  432.  
  433.     if (sx) {
  434.         cosine = (double)abs(sx) / sqrt((double)(sx*sx)+(double)(sy*sy));
  435.         x2 = (sx >= 0)? x + round(l): x - round(l);
  436.         y2 = y + round( ((sx>=0)? l: -l) * (double)sy / (double)sx);
  437.         }
  438.     else {
  439.         cosine = 1.0;
  440.         x2 = x;
  441.         y2 = (sy >= 0)? y + round(l): y - round(l);
  442.         }
  443.     if (sx == 0  ||  sy == 0  ||  (l/cosine)*unitlength >= MIN_LEN) {
  444.         switch (arrow) {
  445.         case 0:  /* simple line */
  446.         fprintf(tfp, "\\put(%3d,%3d){\\line(%2d,%2d)", x, y, sx,sy);
  447.         break;
  448.         case 1:  /* forward arrow */
  449.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d)", x, y, sx,sy);
  450.         break;
  451.         case -1: /* backward arrow */
  452.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d)", x2, y2, -sx,-sy);
  453.         break;
  454.         case 2:  /* double arrow */
  455.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){  0}}\n", x,y,-sx,-sy);
  456.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d)", x, y, sx, sy);
  457.         break;
  458.         }
  459.         if (l == floor(l))
  460.         fprintf(tfp, "{%3.0f}}\n", l);
  461.         else
  462.         fprintf(tfp, "{%7.3f}}\n", l);
  463.         }
  464.     else {
  465.         n = 2 * (l/cosine) / (ldot_diameter/unitlength);
  466.         fprintf(stderr, "Line too short; will do %d dots\n", n);
  467.         dx = l / (double)n;
  468.         if (sx < 0) dx = -dx;
  469.         dy = dx * (double)sy / (double)sx;
  470.         fprintf(tfp, 
  471.           "\\multiput(%3d,%3d)(%.5f,%.5f){%d}{\\makebox(%.4f,%.4f){%s}}\n",
  472.           x, y, dx, dy, n+1, ldot_xoffset, ldot_yoffset, ldot_cmd);
  473.         if (arrow == 1  ||  arrow == 2)  /* forward arrow */
  474.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x2,y2, sx,sy);
  475.         if (arrow == -1  ||  arrow == 2) /* backward arrow */
  476.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x,y, -sx,-sy);
  477.         }
  478.     }
  479.  
  480. /*
  481.  * draw a dashed line given latex slope
  482.  */
  483. static put_dashline (x, y, sx, sy, l, arrow, val)
  484. int    x, y, sx, sy, arrow;
  485. double    l;
  486. double    val;
  487. {
  488.     double    cosine;        /* cosine of line angle */
  489.     double    nd;        /* number of dashes and gaps fitting on line */
  490.     int    n;        /* nd rounded to the nearest odd integer */
  491.     double    dl;        /* actual x-length of each dash */
  492.     double    dg;        /* actual x-length of each gap */
  493.     double    dx, dy;        /* step between dashes */
  494.     int    x2, y2;
  495.  
  496.     if (sx) {
  497.         cosine = (double)abs(sx) / sqrt((double)(sx*sx)+(double)(sy*sy));
  498.         x2 = (sx >= 0)? x + round(l): x - round(l);
  499.         y2 = y + round( ((sx>=0)? l: -l) * (double)sy / (double)sx );
  500.         }
  501.     else {
  502.         cosine = 1.0;
  503.         x2 = x;
  504.         y2 = (sy >= 0)? y + round(l): y - round(l);
  505.         }
  506.     /*** compute number of dashes, length of dashes and gaps ***/
  507.     nd = l / (val*dash_mag*cosine);
  508.     n = (int) (rint((nd + 1.0)/2.0)*2 - 1);
  509.     dl = l / (double)n;
  510.     if (sx  &&  sy  &&  (dl/cosine)*unitlength < MIN_LEN) {
  511.         fprintf(stderr, "Dash too small; using larger dash\n");
  512.         dl = MIN_LEN/unitlength * cosine;
  513.         nd = l / dl;
  514.         n = (int) (rint((nd + 1.0)/2.0)*2 - 1);
  515.         }
  516.     if (2*dl >= l  ||  (sx  &&  sy  &&  (l/cosine)*unitlength < MIN_LEN)) {
  517.         fprintf(stderr, "Dashed line too short; drawing solid line\n");
  518.         put_solidline (x, y, sx, sy, l, arrow);
  519.         return;
  520.         }
  521.     dg = (l - (n/2+1)*dl) / (double)(n/2);
  522.     if (sx) {
  523.         dx = dl+dg;
  524.         if (sx < 0) dx = -dx;
  525.         dy = dx * (double)sy / (double)sx;
  526.         }
  527.     else {
  528.         dx = 0.0;
  529.         dy = dl+dg;
  530.         if (sy < 0) dy = -dy;
  531.         }
  532.     /*** draw dashed line ***/
  533.     fprintf(tfp, "\\multiput(%3d,%3d)(%.5f,%.5f){%d}{\\line(%2d,%2d){%7.3f}}\n",
  534.         x, y, dx, dy, n/2+1, sx, sy, dl);
  535.     /*** draw arrow heads ***/
  536.     if (arrow == 1  ||  arrow == 2)
  537.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x2, y2, sx, sy);
  538.     if (arrow == -1  ||  arrow == 2)
  539.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x, y, -sx, -sy);
  540.     }
  541.  
  542. /*
  543.  * draw a dotted line given latex slope
  544.  */
  545. static put_dotline (x, y, sx, sy, l, arrow, val)
  546. int    x, y, sx, sy, arrow;
  547. double    l;
  548. double    val;
  549. {
  550.     double    cosine;        /* cosine of line angle */
  551.     double    nd;        /* number of dots fitting on line */
  552.     int    n;        /* nd rounded to the nearest integer */
  553.     double    dx, dy;        /* step between dashes */
  554.     int    x2, y2;
  555.  
  556.  
  557.     cosine = (sx)? (double)abs(sx) / sqrt((double)(sx*sx)+(double)(sy*sy)): 1.0;
  558.     /*** compute step width ***/
  559.     nd = l / (3*val*cosine);
  560.     n = rint(nd);
  561.     dx = l / (double)n;
  562.     if (sx) {
  563.         dx = l / (double)n;
  564.         if (sx < 0) dx = -dx;
  565.         dy = dx * (double)sy / (double)sx;
  566.         }
  567.     else {
  568.         dx = 0.0;
  569.         dy = l / (double)n;
  570.         if (sy < 0) dy = -dy;
  571.         }
  572.     /*** draw arrow heads ***/
  573.     if (arrow == 1  ||  arrow == 2) {
  574.         /* forward arrow */
  575.         if (sx) {
  576.         x2 = (sx >= 0)? x + round(l): x - round(l);
  577.         y2 = y + round( ((sx>=0)? l: -l) * (double)sy / (double)sx );
  578.         }
  579.         else {
  580.         x2 = x;
  581.         y2 = (sy >= 0)? y + round(l): y - round(l);
  582.         }
  583.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x2, y2, sx, sy);
  584.         n--;
  585.         }
  586.     if (arrow == -1  ||  arrow == 2) {
  587.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%2d,%2d){0}}\n", x, y, -sx, -sy);
  588.         x = round(x + dx);
  589.         y = round(y + dy);
  590.         n--;
  591.         }
  592.     /*** draw dotted line ***/
  593.     fprintf(tfp, "\\multiput(%3d,%3d)(%.5f,%.5f){%d}{\\makebox(%.4f,%.4f){%s}}\n",
  594.         x, y, dx, dy, n+1, dot_xoffset, dot_yoffset, dot_cmd);
  595.     }
  596.  
  597. void genlatex_spline(s)
  598. F_spline    *s;
  599. {
  600.     fprintf(stderr, "Can't generate spline; omitting object\n");
  601.     }
  602.  
  603. void genlatex_ellipse(e)
  604. F_ellipse    *e;
  605. {
  606.     int  x, y, d, dx, dy;
  607.  
  608.     if (verbose) fprintf(tfp, "%%\n%% Fig ELLIPSE\n%%\n");
  609.  
  610.     set_linewidth(e->thickness);
  611.     switch (e->style) {
  612.         case SOLID_LINE:
  613.         break;
  614.         case DASH_LINE:
  615.         fprintf(stderr, "Dashed circles and elipses not supported\n");
  616.         break;
  617.         case DOTTED_LINE:
  618.         fprintf(stderr, "Dotted circles and elipses not supported\n");
  619.         break;
  620.         }
  621.  
  622.     x = e->center.x;
  623.     y = e->center.y;
  624.     TRANS(x, y);
  625.     if ((e->type == T_CIRCLE_BY_RAD || e->type == T_CIRCLE_BY_DIA)
  626.             && e->radiuses.x*unitlength <= MAXCIRCLERAD) {
  627.  
  628.         d = 2 * e->radiuses.x;
  629.         if (e->area_fill == BLACK_FILL)
  630.             fprintf(tfp, "\\put(%3d,%3d){\\circle*{%d}}\n", x, y, d);
  631.         else {
  632.               fprintf(tfp, "\\put(%3d,%3d){\\circle{%d}}\n", x, y, d);
  633.         if (e->area_fill && (int)e->area_fill != DEFAULT)
  634.             fprintf(stderr, "Circle area fill not implemented\n");
  635.         }
  636.  
  637.     } else {        
  638.         dx = 2 * e->radiuses.x;
  639.         dy = 2 * e->radiuses.y;
  640.         fprintf(tfp, "\\put(%3d,%3d){\\oval(%d,%d)}\n", x, y, dx, dy);
  641.         if (e->area_fill && (int)e->area_fill != DEFAULT)
  642.         fprintf(stderr, "Ellipse area fill not implemented\n");
  643.     }
  644.       }
  645.  
  646. void genlatex_text(t)
  647. F_text    *t;
  648. {
  649.     int       x, y;
  650.     char    *tpos;
  651.     unsigned char    *cp;
  652.  
  653.     if (verbose) fprintf(tfp, "%%\n%% Fig TEXT object\n%%\n");
  654.  
  655.     x = t->base_x;
  656.     y = t->base_y;
  657.     TRANS(x, y);
  658.  
  659.     switch (t->type) {
  660.  
  661.         case T_LEFT_JUSTIFIED:
  662.         case DEFAULT:
  663.             tpos = "[lb]";
  664.         break;
  665.  
  666.         case T_CENTER_JUSTIFIED:
  667.             tpos = "[b]";
  668.         break;
  669.  
  670.         case T_RIGHT_JUSTIFIED:
  671.             tpos = "[rb]";
  672.         break;
  673.  
  674.         default:
  675.         fprintf(stderr, "Text incorrectly positioned\n");
  676.         }
  677.  
  678.     /* smash is used to position text at baseline */
  679.     unpsfont(t);
  680.     fprintf(tfp, 
  681.       "\\put(%3d,%3d){\\makebox(0,0)%s{\\smash{",
  682.       x, y, tpos);
  683.  
  684. #ifdef DVIPS
  685.         if(t->angle && t->type == T_LEFT_JUSTIFIED)
  686.           fprintf(tfp, "\\special{ps:gsave currentpoint currentpoint translate\n%.1f rotate neg exch neg exch translate}", -t->angle*180/M_PI);
  687. #endif
  688.  
  689.         { int texsize;
  690.           double baselineskip;
  691.  
  692.       texsize = TEXFONTMAG(t);
  693.       baselineskip = (texsize * 1.2);
  694.  
  695.        fprintf(tfp, "\\SetFigFont{%d}{%.1f}{%s}",
  696.         texsize, baselineskip, TEXFONT(t->font));
  697.     }
  698.  
  699.     set_color(t->color);
  700.  
  701.     if (!special_text(t))
  702.  
  703.         /* this loop escapes characters "$&%#_{}" */
  704.         /* and deleted characters "~^\" */
  705.         for(cp = (unsigned char*)t->cstring; *cp; cp++) {
  706.                   if (strchr("$&%#_{}", *cp)) (void)fputc('\\', tfp);
  707.                   if (strchr("~^\\", *cp))
  708.             fprintf(stderr,
  709.                 "Bad character in text object '%c'\n" ,*cp);
  710.             else
  711.             (void)fputc(*cp, tfp);
  712.               }
  713.     else 
  714.         for(cp = (unsigned char*)t->cstring; *cp; cp++) {
  715.             if (*cp >= 0xa0)
  716.              fprintf(tfp, "%s", ISOtoTeX[(int)*cp-0xa0]);
  717.         else
  718.             fputc(*cp, tfp);
  719.         }
  720.  
  721.     reset_color(t->color);
  722.  
  723. #ifdef DVIPS
  724.         if(t->angle)
  725.     {
  726.       if (t->type == T_LEFT_JUSTIFIED)
  727.              fprintf(tfp, "\\special{ps:currentpoint grestore moveto}");
  728.       else
  729.          fprintf(stderr, "Rotated Text only for left justified text\n");
  730.     }
  731. #endif
  732.      fprintf(tfp, "}}}\n");
  733.     }
  734.  
  735. void genlatex_arc(a)
  736. F_arc    *a;
  737. /*
  738.  *  Approximates an arc by a sequence of quarter ovals.
  739.  *
  740.  *  Example:
  741.  *
  742.  *    Arc with center at (0,0) and radius 10 from +45 degree to +225 degree
  743.  *    (arc from p1 = (7.07, 7.07) to p2 = (-7.07, -7.07) counterclockwise).
  744.  *    This arc is approximated by three quarter ovals, one for each quadrant
  745.  *    through which the arc goes:
  746.  *
  747.  *     1. quarter oval from p1 to the intersection of arc and y-axis,
  748.  *        i.e., from (7.07, 7.07) to (0, 10) in quadrant 0
  749.  *
  750.  *        \put(0, 7.07){\oval(14.14, 5.86)[tr]}
  751.  *
  752.  *     2. quarter oval from intersection arc/y-axis to intersection arc/x-axis
  753.  *        i.e., from (0, 10) to (-10, 0) in quadrant 1
  754.  *
  755.  *        \put(0, 0){\oval(20,20)[tl]}
  756.  *
  757.  *     3. quarter oval from p1 to the intersection of arc and y-axis,
  758.  *        i.e., from (-10, 0) to (-7.07, -7.07) in quadrant 2
  759.  *
  760.  *        \put(-7.07, 0){\oval(5.86, 14.14)[bl]}
  761.  */
  762. {
  763.     F_pos        p1, p2, pq[4];
  764.     double        cx, cy;
  765.     double        v1x, v1y, v2x, v2y;
  766.     double        r, angle1, angle2;
  767.     int        q1, q2;
  768.     int        p1_arrow, p2_arrow;
  769.     static char    *ad1[4] = { " 0,-1", " 1, 0", " 0, 1", "-1, 0" };
  770.     static char    *ad2[4] = { "-1, 0", " 0,-1", " 1, 0", " 0, 1" };
  771.  
  772.     set_linewidth(a->thickness);
  773.     set_color(a->color);
  774.     switch (a->style) {
  775.         case SOLID_LINE:
  776.         break;
  777.         case DASH_LINE:
  778.         fprintf(stderr, "Dashed arcs not supported\n");
  779.         break;
  780.         case DOTTED_LINE:
  781.         fprintf(stderr, "Dotted arcs not supported\n");
  782.         break;
  783.         }
  784.     if (a->direction == 1) {
  785.         p1 = a->point[0];
  786.         p2 = a->point[2];
  787.         p1_arrow = (a->back_arrow != NULL);
  788.         p2_arrow = (a->for_arrow != NULL);
  789.         }
  790.     else {
  791.         p1 = a->point[2];
  792.         p2 = a->point[0];
  793.         p1_arrow = (a->for_arrow != NULL);
  794.         p2_arrow = (a->back_arrow != NULL);
  795.         }
  796.     cx = a->center.x;
  797.     cy = a->center.y;
  798.     TRANS2(p1.x, p1.y, p2.x, p2.y);
  799.     TRANSD(cx, cy);
  800.     /*** compute vectors and angles from arc center to p1, p2 ***/
  801.     v1x = (double)p1.x - cx;
  802.     v1y = (double)p1.y - cy;
  803.     v2x = (double)p2.x - cx;
  804.     v2y = (double)p2.y - cy;
  805.     angle1 = atan2(v1y, v1x) * rad2deg;
  806.     angle2 = atan2(v2y, v2x) * rad2deg;
  807.     if (angle1 < 0.0)
  808.         angle1 += 360.0; 
  809.     if (angle2 < 0.0)
  810.         angle2 += 360.0; 
  811.     /* compute arc radius */
  812.     r = sqrt(v1x*v1x+v1y*v1y);
  813.     /*** compute intersection of arc with x and y axis (origin at cx, cy) */
  814.     pq[0].x = round(cx);
  815.     pq[0].y = round(cy + r);
  816.     pq[1].x = round(cx - r);
  817.     pq[1].y = round(cy);
  818.     pq[2].x = round(cx);
  819.     pq[2].y = round(cy - r);
  820.     pq[3].x = round(cx + r);
  821.     pq[3].y = round(cy);
  822.     /*** compute in which quadrants p1 and p2 are located ***/
  823.     q1 = (int)(angle1/90.0);
  824.     q2 = (int)(angle2/90.0);
  825.     if (fabs(angle1 - 90.0*q1) > arc_tolerance 
  826.      || fabs(angle2 - 90.0*q2) > arc_tolerance)
  827.         fprintf(stderr, "Approximating arc by ovals\n");
  828.     /*** Draw arc ***/
  829.     if (p1_arrow)
  830.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%s){0}}\n", p1.x, p1.y, ad1[q1]);
  831.     while (q1 != q2) {
  832.         put_quarter(p1, pq[q1], q1);
  833.         p1 = pq[q1];
  834.         q1 = (q1 + 1) % 4;
  835.         }
  836.     put_quarter(p1, p2, q1);
  837.     if (p2_arrow)
  838.         fprintf(tfp, "\\put(%3d,%3d){\\vector(%s){0}}\n", p2.x, p2.y, ad2[q2]);
  839.  
  840.     if (a->area_fill && (int)a->area_fill != DEFAULT)
  841.         fprintf(stderr, "Arc area fill not implemented\n");
  842.     reset_color(a->color);
  843.     }
  844.  
  845. static put_quarter(p1, p2, q)
  846. F_pos    p1, p2;
  847. int    q;
  848. /*
  849.  *  Draw quarter oval from p1 to p2 in quadrant q
  850.  */
  851. {
  852.     char    *opt;
  853.     int    px, py, dx, dy;
  854.  
  855.     dx = 2*ABS(p1.x - p2.x);
  856.     dy = 2*ABS(p1.y - p2.y);
  857.     if (dx == 0  &&  dy == 0)
  858.         return;
  859.     switch (q) {
  860.         case 0:
  861.         px = MIN(p1.x, p2.x);
  862.         py = MIN(p1.y, p2.y);
  863.         opt = "tr";
  864.         break;
  865.         case 1:
  866.         px = MAX(p1.x, p2.x);
  867.         py = MIN(p1.y, p2.y);
  868.         opt = "tl";
  869.         break;
  870.         case 2:
  871.         px = MAX(p1.x, p2.x);
  872.         py = MAX(p1.y, p2.y);
  873.         opt = "bl";
  874.         break;
  875.         case 3:
  876.         px = MIN(p1.x, p2.x);
  877.         py = MAX(p1.y, p2.y);
  878.         opt = "br";
  879.         break;
  880.         }
  881.     fprintf(tfp, "\\put(%3d,%3d){\\oval(%3d,%3d)[%s]}\n", px, py, dx, dy, opt);
  882.     }
  883.  
  884. #define  MAXCOLORS 8
  885.  
  886. set_color(col)
  887. int col;
  888. {
  889.    static char *colors[] = {
  890.    "0 0 0",    /* black */
  891.    "0 0 1",    /* blue */
  892.    "0 1 0",    /* green */
  893.    "0 1 1",    /* cyan */
  894.    "1 0 0",    /* red */
  895.    "1 0 1",    /* magenta */
  896.    "1 1 0",    /* yellow */
  897.    "1 1 1",    /* white */
  898.    };
  899.    
  900. #ifdef DVIPS
  901.    if (col != -1 && col < MAXCOLORS)
  902.       fprintf(tfp, "\\special{ps: gsave %s setrgbcolor}", colors[col]);
  903. #endif
  904.    return;
  905. }
  906.  
  907. reset_color(col)
  908. int col;
  909. {
  910. #ifdef DVIPS
  911.    if (col != -1 && col < MAXCOLORS)
  912.       fprintf(tfp, "\\special{ps: grestore}");
  913. #endif
  914.    return;
  915. }
  916.  
  917.  
  918. struct driver dev_latex = {
  919.          genlatex_option,
  920.     genlatex_start,
  921.     genlatex_arc,
  922.     genlatex_ellipse,
  923.     genlatex_line,
  924.     genlatex_spline,
  925.     genlatex_text,
  926.     genlatex_end,
  927.     EXCLUDE_TEXT
  928. };
  929.