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