LCOV - code coverage report
Current view: top level - preproc/pic - tex.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 0 235 0.0 %
Date: 2026-01-16 17:51:41 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Copyright (C) 1989-2024 Free Software Foundation, Inc.
       2             :      Written by James Clark (jjc@jclark.com)
       3             : 
       4             : This file is part of groff, the GNU roff typesetting system.
       5             : 
       6             : groff is free software; you can redistribute it and/or modify it under
       7             : the terms of the GNU General Public License as published by the Free
       8             : Software Foundation, either version 3 of the License, or
       9             : (at your option) any later version.
      10             : 
      11             : groff is distributed in the hope that it will be useful, but WITHOUT ANY
      12             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14             : for more details.
      15             : 
      16             : You should have received a copy of the GNU General Public License
      17             : along with this program.  If not, see <http://www.gnu.org/licenses/>. */
      18             : 
      19             : #ifdef HAVE_CONFIG_H
      20             : #include <config.h>
      21             : #endif
      22             : 
      23             : #include <assert.h>
      24             : #include <math.h> // M_PI, atan2()
      25             : #include <stdlib.h> // strtol()
      26             : #include <stdio.h> // fputs(), printf(), stdout
      27             : 
      28             : #include "pic.h"
      29             : 
      30             : #ifdef TEX_SUPPORT
      31             : 
      32             : #include "common.h"
      33             : 
      34             : class tex_output : public common_output {
      35             : public:
      36             :   tex_output();
      37             :   ~tex_output();
      38             :   void start_picture(double, const position &ll, const position &ur);
      39             :   void finish_picture();
      40             :   void text(const position &, text_piece *, int, double);
      41             :   void line(const position &, const position *, int n,
      42             :             const line_type &);
      43             :   void polygon(const position *, int n,
      44             :                const line_type &, double);
      45             :   void spline(const position &, const position *, int n,
      46             :               const line_type &);
      47             :   void arc(const position &, const position &, const position &,
      48             :            const line_type &);
      49             :   void circle(const position &, double rad, const line_type &, double);
      50             :   void ellipse(const position &, const distance &, const line_type &, double);
      51             :   void command(const char *, const char *, int);
      52             :   void set_color(char *, char *);
      53             :   void reset_color();
      54             :   char *get_last_filled();
      55             :   char *get_outline_color();
      56             :   int supports_filled_polygons();
      57             : private:
      58             :   position upper_left;
      59             :   double height;
      60             :   double width;
      61             :   double scale;
      62             :   double pen_size;
      63             : 
      64             :   void point(const position &);
      65             :   void dot(const position &, const line_type &);
      66             :   void solid_arc(const position &cent, double rad, double start_angle,
      67             :                  double end_angle, const line_type &lt);
      68             :   position transform(const position &);
      69             : protected:
      70             :   virtual void set_pen_size(double ps);
      71             : };
      72             : 
      73             : // convert inches to milliinches
      74             : 
      75           0 : inline int milliinches(double x)
      76             : {
      77           0 :   return int(x*1000.0 + .5);
      78             : }
      79             : 
      80           0 : inline position tex_output::transform(const position &pos)
      81             : {
      82           0 :   return position((pos.x - upper_left.x)/scale,
      83           0 :                   (upper_left.y - pos.y)/scale);
      84             : }
      85             : 
      86           0 : output *make_tex_output()
      87             : {
      88           0 :   return new tex_output;
      89             : }
      90             : 
      91           0 : tex_output::tex_output()
      92             : {
      93           0 : }
      94             : 
      95           0 : tex_output::~tex_output()
      96             : {
      97           0 : }
      98             : 
      99             : const int DEFAULT_PEN_SIZE = 8;
     100             : 
     101           0 : void tex_output::set_pen_size(double ps)
     102             : {
     103           0 :   if (ps < 0.0)
     104           0 :     ps = -1.0;
     105           0 :   if (ps != pen_size) {
     106           0 :     pen_size = ps;
     107           0 :     printf("    \\special{pn %d}%%\n",
     108           0 :            ps < 0.0 ? DEFAULT_PEN_SIZE : int(ps*(1000.0/72.0) + .5));
     109             :   }
     110           0 : }
     111             : 
     112           0 : void tex_output::start_picture(double sc, const position &ll,
     113             :                                const position &ur)
     114             : {
     115           0 :   upper_left.x = ll.x;
     116           0 :   upper_left.y = ur.y;
     117           0 :   scale = compute_scale(sc, ll, ur);
     118           0 :   height = (ur.y - ll.y)/scale;
     119           0 :   width = (ur.x - ll.x)/scale;
     120             :   /* The point of \vskip 0pt is to ensure that the vtop gets
     121             :      a height of 0 rather than the height of the hbox; this
     122             :      might be non-zero if text from text attributes lies outside pic's
     123             :      idea of the bounding box of the picture. */
     124             :   /* \newbox and \newdimen are defined with \outer in plain.tex and can't
     125             :      be used directly in an \if clause. */
     126           0 :   printf("\\expandafter\\ifx\\csname %s\\endcsname\\relax\n"
     127             :          "   \\csname newbox\\expandafter\\endcsname\\csname %s\\endcsname\n"
     128             :          "\\fi\n"
     129             :          "\\ifx\\graphtemp\\undefined\n"
     130             :          "  \\csname newdimen\\endcsname\\graphtemp\n"
     131             :          "\\fi\n"
     132             :          "\\expandafter\\setbox\\csname %s\\endcsname\n"
     133             :          " =\\vtop{\\vskip 0pt\\hbox{%%\n",
     134             :          graphname, graphname, graphname);
     135           0 :   pen_size = -2.0;
     136           0 : }
     137             : 
     138           0 : void tex_output::finish_picture()
     139             : {
     140           0 :   printf("    \\hbox{\\vrule depth%.3fin width0pt height 0pt}%%\n"
     141             :          "    \\kern %.3fin\n"
     142             :          "  }%%\n"
     143             :          "}%%\n",
     144             :          height, width);
     145           0 : }
     146             : 
     147           0 : void tex_output::text(const position &center, text_piece *v, int n, double)
     148             : {
     149           0 :   position c = transform(center);
     150           0 :   for (int i = 0; i < n; i++)
     151           0 :     if (v[i].text != 0 && *v[i].text != '\0') {
     152           0 :       int j = 2*i - n + 1;
     153           0 :       if (v[i].adj.v == ABOVE_ADJUST)
     154           0 :         j--;
     155           0 :       else if (v[i].adj.v == BELOW_ADJUST)
     156           0 :         j++;
     157           0 :       if (j == 0) {
     158           0 :         printf("    \\graphtemp=.5ex\n"
     159             :                "    \\advance\\graphtemp by %.3fin\n", c.y);
     160             :       }
     161             :       else {
     162           0 :         printf("    \\graphtemp=\\baselineskip\n"
     163             :                "    \\multiply\\graphtemp by %d\n"
     164             :                "    \\divide\\graphtemp by 2\n"
     165             :                "    \\advance\\graphtemp by .5ex\n"
     166             :                "    \\advance\\graphtemp by %.3fin\n",
     167             :                j, c.y);
     168             :       }
     169           0 :       printf("    \\rlap{\\kern %.3fin\\lower\\graphtemp", c.x);
     170           0 :       fputs("\\hbox to 0pt{", stdout);
     171           0 :       if (v[i].adj.h != LEFT_ADJUST)
     172           0 :         fputs("\\hss ", stdout);
     173           0 :       fputs(v[i].text, stdout);
     174           0 :       if (v[i].adj.h != RIGHT_ADJUST)
     175           0 :         fputs("\\hss", stdout);
     176           0 :       fputs("}}%\n", stdout);
     177             :     }
     178           0 : }
     179             : 
     180           0 : void tex_output::point(const position &pos)
     181             : {
     182           0 :   position p = transform(pos);
     183           0 :   printf("    \\special{pa %d %d}%%\n", milliinches(p.x), milliinches(p.y));
     184           0 : }
     185             : 
     186           0 : void tex_output::line(const position &start, const position *v, int n,
     187             :                       const line_type &lt)
     188             : {
     189           0 :   set_pen_size(lt.thickness);
     190           0 :   point(start);
     191           0 :   for (int i = 0; i < n; i++)
     192           0 :     point(v[i]);
     193           0 :   fputs("    \\special{", stdout);
     194           0 :   switch(lt.type) {
     195           0 :   case line_type::invisible:
     196           0 :     fputs("ip", stdout);
     197           0 :     break;
     198           0 :   case line_type::solid:
     199           0 :     fputs("fp", stdout);
     200           0 :     break;
     201           0 :   case line_type::dotted:
     202           0 :     printf("dt %.3f", lt.dash_width/scale);
     203           0 :     break;
     204           0 :   case line_type::dashed:
     205           0 :     printf("da %.3f", lt.dash_width/scale);
     206           0 :     break;
     207             :   }
     208           0 :   fputs("}%\n", stdout);
     209           0 : }
     210             : 
     211           0 : void tex_output::polygon(const position *v, int n,
     212             :                          const line_type &lt, double fill)
     213             : {
     214           0 :   if (fill >= 0.0) {
     215           0 :     if (fill > 1.0)
     216           0 :       fill = 1.0;
     217           0 :     printf("    \\special{sh %.3f}%%\n", fill);
     218             :   }
     219           0 :   line(v[n-1], v, n, lt);
     220           0 : }
     221             : 
     222           0 : void tex_output::spline(const position &start, const position *v, int n,
     223             :                         const line_type &lt)
     224             : {
     225           0 :   if (lt.type == line_type::invisible)
     226           0 :     return;
     227           0 :   set_pen_size(lt.thickness);
     228           0 :   point(start);
     229           0 :   for (int i = 0; i < n; i++)
     230           0 :     point(v[i]);
     231           0 :   fputs("    \\special{sp", stdout);
     232           0 :   switch(lt.type) {
     233           0 :   case line_type::solid:
     234           0 :     break;
     235           0 :   case line_type::dotted:
     236           0 :     printf(" %.3f", -lt.dash_width/scale);
     237           0 :     break;
     238           0 :   case line_type::dashed:
     239           0 :     printf(" %.3f", lt.dash_width/scale);
     240           0 :     break;
     241           0 :   case line_type::invisible:
     242           0 :     assert(0 == "unhandled case of line type");
     243             :   }
     244           0 :   fputs("}%\n", stdout);
     245             : }
     246             : 
     247           0 : void tex_output::solid_arc(const position &cent, double rad,
     248             :                            double start_angle, double end_angle,
     249             :                            const line_type &lt)
     250             : {
     251           0 :   set_pen_size(lt.thickness);
     252           0 :   position c = transform(cent);
     253           0 :   printf("    \\special{ar %d %d %d %d %f %f}%%\n",
     254             :          milliinches(c.x),
     255             :          milliinches(c.y),
     256           0 :          milliinches(rad/scale),
     257           0 :          milliinches(rad/scale),
     258             :          -end_angle,
     259             :          (-end_angle > -start_angle) ? (double)M_PI * 2 - start_angle
     260             :                                      : -start_angle);
     261           0 : }
     262             : 
     263           0 : void tex_output::arc(const position &start, const position &cent,
     264             :                      const position &end, const line_type &lt)
     265             : {
     266           0 :   switch (lt.type) {
     267           0 :   case line_type::invisible:
     268           0 :     break;
     269           0 :   case line_type::dashed:
     270           0 :     dashed_arc(start, cent, end, lt);
     271           0 :     break;
     272           0 :   case line_type::dotted:
     273           0 :     dotted_arc(start, cent, end, lt);
     274           0 :     break;
     275           0 :   case line_type::solid:
     276             :     {
     277           0 :       position c;
     278           0 :       if (!compute_arc_center(start, cent, end, &c)) {
     279           0 :         line(start, &end, 1, lt);
     280           0 :         break;
     281             :       }
     282           0 :       solid_arc(c,
     283           0 :                 hypot(cent - start),
     284           0 :                 atan2(start.y - c.y, start.x - c.x),
     285           0 :                 atan2(end.y - c.y, end.x - c.x),
     286           0 :                 lt);
     287           0 :       break;
     288             :     }
     289             :   }
     290           0 : }
     291             : 
     292           0 : void tex_output::circle(const position &cent, double rad,
     293             :                         const line_type &lt, double fill)
     294             : {
     295           0 :   if (fill >= 0.0 && lt.type != line_type::solid) {
     296           0 :     if (fill > 1.0)
     297           0 :       fill = 1.0;
     298           0 :     line_type ilt;
     299           0 :     ilt.type = line_type::invisible;
     300           0 :     ellipse(cent, position(rad*2.0, rad*2.0), ilt, fill);
     301             :   }
     302           0 :   switch (lt.type) {
     303           0 :   case line_type::dashed:
     304           0 :     dashed_circle(cent, rad, lt);
     305           0 :     break;
     306           0 :   case line_type::invisible:
     307           0 :     break;
     308           0 :   case line_type::solid:
     309           0 :     ellipse(cent, position(rad*2.0,rad*2.0), lt, fill);
     310           0 :     break;
     311           0 :   case line_type::dotted:
     312           0 :     dotted_circle(cent, rad, lt);
     313           0 :     break;
     314           0 :   default:
     315           0 :     assert(0 == "unhandled case of line type");
     316             :   }
     317           0 : }
     318             : 
     319           0 : void tex_output::ellipse(const position &cent, const distance &dim,
     320             :                          const line_type &lt, double fill)
     321             : {
     322           0 :   if (lt.type == line_type::invisible) {
     323           0 :     if (fill < 0.0)
     324           0 :       return;
     325             :   }
     326             :   else
     327           0 :     set_pen_size(lt.thickness);
     328           0 :   if (fill >= 0.0) {
     329           0 :     if (fill > 1.0)
     330           0 :       fill = 1.0;
     331           0 :     printf("    \\special{sh %.3f}%%\n", fill);
     332             :   }
     333           0 :   position c = transform(cent);
     334           0 :   switch (lt.type) {
     335           0 :   case line_type::solid:
     336             :   case line_type::invisible:
     337           0 :     printf("    \\special{%s %d %d %d %d 0 6.28319}%%\n",
     338           0 :            (lt.type == line_type::invisible ? "ia" : "ar"),
     339             :            milliinches(c.x),
     340             :            milliinches(c.y),
     341           0 :            milliinches(dim.x/(2.0*scale)),
     342           0 :            milliinches(dim.y/(2.0*scale)));
     343           0 :     break;
     344           0 :   case line_type::dashed:
     345           0 :     dashed_ellipse(cent, dim / scale, lt);
     346           0 :     break;
     347           0 :   case line_type::dotted:
     348           0 :     dotted_ellipse(cent, dim / scale, lt);
     349           0 :     break;
     350           0 :   default:
     351           0 :     assert(0 == "unhandled case of line type");
     352             :   }
     353             : }
     354             : 
     355           0 : void tex_output::command(const char *s, const char *, int)
     356             : {
     357           0 :   fputs(s, stdout);
     358           0 :   putchar('%');                 // avoid unwanted spaces
     359           0 :   putchar('\n');
     360           0 : }
     361             : 
     362           0 : int tex_output::supports_filled_polygons()
     363             : {
     364           0 :   return 1;
     365             : }
     366             : 
     367           0 : void tex_output::dot(const position &pos, const line_type &lt)
     368             : {
     369           0 :   if (zero_length_line_flag) {
     370           0 :     line_type slt = lt;
     371           0 :     slt.type = line_type::solid;
     372           0 :     line(pos, &pos, 1, slt);
     373             :   }
     374             :   else {
     375           0 :     int dot_rad = int(lt.thickness*(1000.0/(72.0*2)) + .5);
     376           0 :     if (dot_rad == 0)
     377           0 :       dot_rad = 1;
     378           0 :     position p = transform(pos);
     379           0 :     printf("    \\special{sh 1}%%\n"
     380             :            "    \\special{ia %d %d %d %d 0 6.28319}%%\n",
     381             :            milliinches(p.x), milliinches(p.y), dot_rad, dot_rad);
     382             :   }
     383           0 : }
     384             : 
     385           0 : void tex_output::set_color(char *, char *)
     386             : {
     387             :   /* not implemented yet */
     388           0 : }
     389             : 
     390           0 : void tex_output::reset_color()
     391             : {
     392             :   /* not implemented yet */
     393           0 : }
     394             : 
     395           0 : char *tex_output::get_last_filled()
     396             : {
     397             :   /* not implemented yet */
     398           0 :   return NULL;
     399             : }
     400             : 
     401           0 : char *tex_output::get_outline_color()
     402             : {
     403             :   /* not implemented yet */
     404           0 :   return NULL;
     405             : }
     406             : 
     407             : class tpic_output : public tex_output {
     408             : public:
     409             :   tpic_output();
     410             :   void command(const char *, const char *, int);
     411             : private:
     412             :   void set_pen_size(double ps);
     413             :   int default_pen_size;
     414             :   int prev_default_pen_size;
     415             : };
     416             : 
     417           0 : tpic_output::tpic_output()
     418           0 : : default_pen_size(DEFAULT_PEN_SIZE), prev_default_pen_size(DEFAULT_PEN_SIZE)
     419             : {
     420           0 : }
     421             : 
     422           0 : void tpic_output::command(const char *s, const char *filename, int lineno)
     423             : {
     424           0 :   assert(s[0] == '.');
     425           0 :   if (s[1] == 'p' && s[2] == 's' && (s[3] == '\0' || !csalpha(s[3]))) {
     426           0 :     const char *p = s + 3;
     427           0 :     while (csspace(*p))
     428           0 :       p++;
     429           0 :     if (*p == '\0') {
     430           0 :       int temp = default_pen_size;
     431           0 :       default_pen_size = prev_default_pen_size;
     432           0 :       prev_default_pen_size = temp;
     433             :     }
     434             :     else {
     435             :       char *ptr;
     436           0 :       int temp = (int)strtol(p, &ptr, 10);
     437           0 :       if (ptr == p)
     438           0 :         error_with_file_and_line(filename, lineno,
     439             :                                  "argument to '.ps' not an integer");
     440           0 :       else if (temp < 0)
     441           0 :         error_with_file_and_line(filename, lineno,
     442             :                                  "negative pen size");
     443             :       else {
     444           0 :         prev_default_pen_size = default_pen_size;
     445           0 :         default_pen_size = temp;
     446             :       }
     447             :     }
     448             :   }
     449             :   else
     450           0 :     printf("\\%s%%\n", s + 1);
     451           0 : }
     452             : 
     453           0 : void tpic_output::set_pen_size(double ps)
     454             : {
     455           0 :   if (ps < 0.0)
     456           0 :     printf("    \\special{pn %d}%%\n", default_pen_size);
     457             :   else
     458           0 :     tex_output::set_pen_size(ps);
     459           0 : }
     460             : 
     461           0 : output *make_tpic_output()
     462             : {
     463           0 :   return new tpic_output;
     464             : }
     465             : 
     466             : #endif
     467             : 
     468             : // Local Variables:
     469             : // fill-column: 72
     470             : // mode: C++
     471             : // End:
     472             : // vim: set cindent noexpandtab shiftwidth=2 textwidth=72:

Generated by: LCOV version 1.14