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