1/*********************************************************************** 2 * * 3 * $Id: hpgspath.c 352 2006-10-10 20:58:26Z softadm $ 4 * * 5 * hpgs - HPGl Script, a hpgl/2 interpreter, which uses a Postscript * 6 * API for rendering a scene and thus renders to a variety of * 7 * devices and fileformats. * 8 * * 9 * (C) 2004-2006 ev-i Informationstechnologie GmbH http://www.ev-i.at * 10 * * 11 * Author: Wolfgang Glas * 12 * * 13 * hpgs is free software; you can redistribute it and/or * 14 * modify it under the terms of the GNU Lesser General Public * 15 * License as published by the Free Software Foundation; either * 16 * version 2.1 of the License, or (at your option) any later version. * 17 * * 18 * hpgs is distributed in the hope that it will be useful, * 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 21 * Lesser General Public License for more details. * 22 * * 23 * You should have received a copy of the GNU Lesser General Public * 24 * License along with this library; if not, write to the * 25 * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * 26 * Boston, MA 02111-1307 USA * 27 * * 28 *********************************************************************** 29 * * 30 * The implementation of the HPGL reader. * 31 * * 32 ***********************************************************************/ 33 34#include <hpgsreader.h> 35#include <math.h> 36#include <string.h> 37#include <ctype.h> 38 39#ifndef M_PI 40#define M_PI 3.14159265358979323846264338327950288 41#endif 42 43/* 44 Do check for an open path. 45*/ 46 47int hpgs_reader_checkpath(hpgs_reader *reader) 48{ 49 if (!reader->polygon_mode && reader->polygon_open >= 2) 50 return hpgs_reader_stroke(reader); 51 52 return 0; 53} 54 55static int push_poly_point(hpgs_reader *reader, hpgs_point *p, int flag) 56{ 57 if (flag == 0 && reader->poly_buffer_size>0 && 58 reader->poly_buffer[reader->poly_buffer_size-1].flag == 0 && 59 reader->poly_buffer[reader->poly_buffer_size-1].p.x == p->x && 60 reader->poly_buffer[reader->poly_buffer_size-1].p.y == p->y ) 61 return 0; 62 63 if (reader->poly_buffer_size >= reader->poly_buffer_alloc_size) 64 { 65 reader->poly_buffer_alloc_size *= 2; 66 reader->poly_buffer = (hpgs_reader_poly_point *) 67 realloc(reader->poly_buffer, 68 sizeof(hpgs_reader_poly_point)*reader->poly_buffer_alloc_size); 69 70 if (!reader->poly_buffer) 71 return hpgs_set_error(hpgs_i18n("out of memory in push_poly_point.")); 72 } 73 74 reader->poly_buffer[reader->poly_buffer_size].p = *p; 75 reader->poly_buffer[reader->poly_buffer_size].flag = flag; 76 ++reader->poly_buffer_size; 77 78 return 0; 79} 80 81static void add_path_point(hpgs_reader *reader, hpgs_point *p) 82{ 83 if (p->x < reader->min_path_point.x) reader->min_path_point.x = p->x; 84 if (p->y < reader->min_path_point.y) reader->min_path_point.y = p->y; 85 if (p->x > reader->max_path_point.x) reader->max_path_point.x = p->x; 86 if (p->y > reader->max_path_point.y) reader->max_path_point.y = p->y; 87} 88 89static int do_polygon(hpgs_reader *reader, hpgs_bool fill) 90{ 91 int ret = 0; 92 93 int i0 = 0; 94 95 while (i0 < reader->poly_buffer_size) 96 { 97 // find endpoint of current loop. 98 int i1 = i0; 99 100 while (i1 < reader->poly_buffer_size && reader->poly_buffer[i1].flag != 3) 101 ++i1; 102 103 if (i1 > i0+1) 104 { 105 int i=i0; 106 int open = 0; 107 hpgs_point *start=0; 108 109 // Do optimize away a polygon like (PostScript notation): 110 // p1 moveto p2 moveto p3 lineto p4 lineto p2 lineto closepath fill 111 // Such polygons are easily created if the pushed currentpoint of PM 0 112 // is followed by a closed polygon. 113 // This optimization avoids some strange graphical effects caused by the 114 // line of thickness zero produced by the final closepath. 115 if (fill && reader->poly_buffer[i+1].flag==0 && i1 > i+2 && 116 fabs(reader->poly_buffer[i+1].p.x - reader->poly_buffer[i1-1].p.x) < 1.0e-8 && 117 fabs(reader->poly_buffer[i+1].p.y - reader->poly_buffer[i1-1].p.y) < 1.0e-8 ) 118 ++i; 119 120 while (i<i1) 121 { 122 switch (reader->poly_buffer[i].flag) 123 { 124 case 0: 125 // Well, there are HPGL files in the wild, which write polygons with 126 // the pen up all the time and do a fill afterwards. 127 if (open && fill) 128 { 129 if (open == 1) 130 { 131 if (hpgs_moveto(reader->device,start)) 132 return -1; 133 open = 2; 134 } 135 136 if (hpgs_lineto(reader->device,&reader->poly_buffer[i].p)) 137 return -1; 138 } 139 else 140 { 141 start = &reader->poly_buffer[i].p; 142 open = 1; 143 } 144 145 if (i) 146 add_path_point(reader,&reader->poly_buffer[i].p); 147 else 148 { 149 reader->min_path_point = reader->poly_buffer[0].p; 150 reader->max_path_point = reader->poly_buffer[0].p; 151 } 152 break; 153 154 case 1: 155 if (open == 0) 156 return hpgs_set_error(hpgs_i18n("Missing moveto in do_polygon.")); 157 158 if (open == 1 && hpgs_moveto(reader->device,start)) 159 return -1; 160 161 if (hpgs_lineto(reader->device,&reader->poly_buffer[i].p)) 162 return -1; 163 164 add_path_point(reader,&reader->poly_buffer[i].p); 165 open = 2; 166 break; 167 case 2: 168 if (open == 0) 169 return hpgs_set_error(hpgs_i18n("Missing moveto in do_polygon.")); 170 171 if (open == 1 && hpgs_moveto(reader->device,start)) 172 return -1; 173 174 if (i+2>=reader->poly_buffer_size) 175 return hpgs_set_error(hpgs_i18n("curveto error in do_polygon.")); 176 177 if (hpgs_curveto(reader->device, 178 &reader->poly_buffer[i].p, 179 &reader->poly_buffer[i+1].p, 180 &reader->poly_buffer[i+2].p)) 181 return -1; 182 183 add_path_point(reader,&reader->poly_buffer[i].p); 184 add_path_point(reader,&reader->poly_buffer[i+1].p); 185 add_path_point(reader,&reader->poly_buffer[i+2].p); 186 i+=2; 187 open = 2; 188 break; 189 default: 190 return hpgs_set_error(hpgs_i18n("internal error in do_polygon.")); 191 } 192 ++i; 193 } 194 195 if (open >= 2) 196 { 197 if (i < reader->poly_buffer_size && 198 hpgs_closepath(reader->device)) 199 return -1; 200 ret = 1; 201 } 202 } 203 204 i0=i1+1; 205 206 } 207 208 return ret; 209} 210 211/* 212 Basic path operations. 213*/ 214int hpgs_reader_moveto(hpgs_reader *reader, hpgs_point *p) 215{ 216 reader->current_point = *p; 217 reader->cr_point = *p; 218 219 if (!reader->polygon_open) 220 { 221 reader->first_path_point = reader->current_point; 222 reader->min_path_point = reader->current_point; 223 reader->max_path_point = reader->current_point; 224 } 225 226 if (reader->polygon_mode) 227 { 228 if (push_poly_point(reader,&reader->current_point,0)) 229 return -1; 230 231 if (reader->polygon_open == 0) 232 reader->polygon_open = 1; 233 else if (reader->polygon_open == 1) 234 reader->polygon_open = 2; 235 } 236 237 return 0; 238} 239 240int hpgs_reader_lineto(hpgs_reader *reader, hpgs_point *p) 241{ 242 if (!reader->polygon_open) 243 { 244 if (reader->polygon_mode) 245 { 246 if (push_poly_point(reader,&reader->current_point,0)) 247 return -1; 248 } 249 else 250 { 251 if (hpgs_moveto(reader->device,&reader->current_point)) 252 return -1; 253 } 254 255 reader->first_path_point = reader->current_point; 256 257 reader->min_path_point = reader->current_point; 258 reader->max_path_point = reader->current_point; 259 } 260 261 if (reader->polygon_mode) 262 { 263 if (push_poly_point(reader,p,1)) 264 return -1; 265 } 266 else 267 { 268 if (hpgs_lineto(reader->device,p)) 269 return -1; 270 add_path_point(reader,p); 271 } 272 273 reader->polygon_open = 2; 274 reader->current_point = *p; 275 reader->cr_point = *p; 276 277 return 0; 278} 279 280int hpgs_reader_curveto(hpgs_reader *reader, 281 hpgs_point *p1, hpgs_point *p2, hpgs_point *p3) 282{ 283 if (!reader->polygon_open) 284 { 285 if (reader->polygon_mode) 286 { 287 if (push_poly_point(reader,&reader->current_point,0)) 288 return -1; 289 } 290 else 291 { 292 if (hpgs_moveto(reader->device,&reader->current_point)) 293 return -1; 294 } 295 296 reader->first_path_point = reader->current_point; 297 reader->min_path_point = reader->current_point; 298 reader->max_path_point = reader->current_point; 299 } 300 301 if (reader->polygon_mode) 302 { 303 if (push_poly_point(reader,p1,2) || 304 push_poly_point(reader,p2,2) || 305 push_poly_point(reader,p3,2) ) 306 return -1; 307 } 308 else 309 { 310 if (hpgs_curveto(reader->device,p1,p2,p3)) 311 return -1; 312 313 add_path_point(reader,p1); 314 add_path_point(reader,p2); 315 add_path_point(reader,p3); 316 } 317 318 reader->polygon_open = 2; 319 reader->current_point = *p3; 320 reader->cr_point = *p3; 321 322 return 0; 323} 324 325int hpgs_reader_closepath(hpgs_reader *reader) 326{ 327 if (reader->polygon_open < 2) 328 { 329 reader->polygon_open = 0; 330 return 0; 331 } 332 333 reader->current_point = reader->first_path_point; 334 reader->polygon_open = 0; 335 336 if (reader->polygon_mode) 337 return push_poly_point(reader,&reader->first_path_point,3); 338 else 339 return hpgs_closepath(reader->device); 340} 341 342int hpgs_reader_stroke(hpgs_reader *reader) 343{ 344 reader->polygon_open = 0; 345 reader->have_current_point = 0; 346 return hpgs_stroke(reader->device); 347} 348 349static int hatch(hpgs_reader *reader, double spacing, double angle, int cross, hpgs_bool winding) 350{ 351 int i; 352 double ca = cos (angle*M_PI/180.0); 353 double sa = sin (angle*M_PI/180.0); 354 hpgs_point h_min,h_max; 355 hpgs_point p,ph; 356 357 if (spacing <= 1.0) 358 spacing= hypot(reader->P2.x-reader->P1.x, 359 reader->P2.y-reader->P1.y ) * 0.01 * HP_TO_PT; 360 361 // rotate corner points to hatch coordinates and calculate min/max hatches. 362 p.x = reader->min_path_point.x-reader->anchor_point.x; 363 p.y = reader->min_path_point.y-reader->anchor_point.y; 364 365 h_max.x = h_min.x = (p.x * ca + p.y * sa)/spacing; 366 h_max.y = h_min.y = (p.y * ca - p.x * sa)/spacing; 367 368 p.x = reader->min_path_point.x-reader->anchor_point.x; 369 p.y = reader->max_path_point.y-reader->anchor_point.y; 370 371 ph.x = (p.x * ca + p.y * sa)/spacing; 372 ph.y = (p.y * ca - p.x * sa)/spacing; 373 374 if (ph.x < h_min.x) h_min.x = ph.x; 375 if (ph.y < h_min.y) h_min.y = ph.y; 376 if (ph.x > h_max.x) h_max.x = ph.x; 377 if (ph.y > h_max.y) h_max.y = ph.y; 378 379 p.x = reader->max_path_point.x-reader->anchor_point.x; 380 p.y = reader->max_path_point.y-reader->anchor_point.y; 381 382 ph.x = (p.x * ca + p.y * sa)/spacing; 383 ph.y = (p.y * ca - p.x * sa)/spacing; 384 385 if (ph.x < h_min.x) h_min.x = ph.x; 386 if (ph.y < h_min.y) h_min.y = ph.y; 387 if (ph.x > h_max.x) h_max.x = ph.x; 388 if (ph.y > h_max.y) h_max.y = ph.y; 389 390 p.x = reader->max_path_point.x-reader->anchor_point.x; 391 p.y = reader->min_path_point.y-reader->anchor_point.y; 392 393 ph.x = (p.x * ca + p.y * sa)/spacing; 394 ph.y = (p.y * ca - p.x * sa)/spacing; 395 396 if (ph.x < h_min.x) h_min.x = ph.x; 397 if (ph.y < h_min.y) h_min.y = ph.y; 398 if (ph.x > h_max.x) h_max.x = ph.x; 399 if (ph.y > h_max.y) h_max.y = ph.y; 400 401 if (hpgs_clipsave(reader->device)) return -1; 402 403 if (hpgs_clip(reader->device,winding)) return -1; 404 405 if (hpgs_newpath(reader->device)) return -1; 406 407 // go through verticaltal hatches hatches. 408 for (i = (int)ceil(h_min.y); i <= (int)floor(h_max.y); ++i) 409 { 410 ph.y = i; 411 ph.x = h_min.x; 412 413 p.x = (ph.x * ca - ph.y * sa) * spacing + reader->anchor_point.x; 414 p.y = (ph.y * ca + ph.x * sa) * spacing + reader->anchor_point.y; 415 416 if (hpgs_moveto(reader->device,&p)) return -1; 417 418 ph.x = h_max.x; 419 420 p.x = (ph.x * ca - ph.y * sa) * spacing + reader->anchor_point.x; 421 p.y = (ph.y * ca + ph.x * sa) * spacing + reader->anchor_point.y; 422 423 if (hpgs_lineto(reader->device,&p)) return -1; 424 if (hpgs_stroke(reader->device)) return -1; 425 } 426 427 if (cross) 428 // go through horizontal hatches hatches. 429 for (i = (int)ceil(h_min.x); i <= (int)floor(h_max.x); ++i) 430 { 431 ph.x = i; 432 ph.y = h_min.y; 433 434 p.x = (ph.x * ca - ph.y * sa) * spacing + reader->anchor_point.x; 435 p.y = (ph.y * ca + ph.x * sa) * spacing + reader->anchor_point.y; 436 437 if (hpgs_moveto(reader->device,&p)) return -1; 438 439 ph.y = h_max.y; 440 441 p.x = (ph.x * ca - ph.y * sa) * spacing + reader->anchor_point.x; 442 p.y = (ph.y * ca + ph.x * sa) * spacing + reader->anchor_point.y; 443 444 if (hpgs_lineto(reader->device,&p)) return -1; 445 if (hpgs_stroke(reader->device)) return -1; 446 } 447 448 if (hpgs_cliprestore(reader->device)) 449 return -1; 450 451 return hpgs_newpath(reader->device); 452} 453 454// filltype 10. 455static int shade(hpgs_reader *reader, double level, hpgs_bool winding) 456{ 457 int pen = reader->current_pen; 458 double alpha = level * 0.01; 459 460 if (alpha < 0.0) alpha = 0.0; 461 if (alpha > 1.0) alpha = 1.0; 462 463 if (alpha != 1.0) 464 { 465 hpgs_color rgb; 466 467 rgb.r = (1.0-alpha) + reader->pen_colors[pen].r*alpha; 468 rgb.g = (1.0-alpha) + reader->pen_colors[pen].g*alpha; 469 rgb.b = (1.0-alpha) + reader->pen_colors[pen].b*alpha; 470 471 if (hpgs_setrgbcolor(reader->device,&rgb)) 472 return -1; 473 } 474 475 476 if (hpgs_fill(reader->device,winding)) return -1; 477 478 if (alpha == 1.0) return 0; 479 480 return hpgs_setrgbcolor(reader->device, 481 &reader->pen_colors[pen]); 482} 483 484int hpgs_reader_fill(hpgs_reader *reader, hpgs_bool winding) 485{ 486 reader->polygon_open = 0; 487 reader->have_current_point = 0; 488 489 switch (reader->current_ft) 490 { 491 case 3: 492 return hatch(reader,reader->ft3_spacing,reader->ft3_angle,0,winding); 493 case 4: 494 return hatch(reader,reader->ft4_spacing,reader->ft4_angle,1,winding); 495 case 10: 496 return shade(reader,reader->ft10_level,winding); 497 default: 498 return hpgs_fill(reader->device,winding); 499 } 500 return 0; 501} 502 503/* 504 HPGL Command AC (AnChor Point) 505*/ 506int hpgs_reader_do_AC (hpgs_reader *reader) 507{ 508 if (reader->eoc) 509 { 510 reader->anchor_point.x = 0.0; 511 reader->anchor_point.y = 0.0; 512 return 0; 513 } 514 else 515 return hpgs_reader_read_point(reader,&reader->anchor_point,1); 516} 517 518static double sqr(double x); 519__inline__ double sqr(double x) { return x*x; } 520 521/* 522 Transform an arc from the current point through p2 to p3 to 523 center/sweep. 524 525 Return value: 0 ... arc successfully constructed. 526 1 ... points lie on a straight line. 527*/ 528 529static int arc_by_points(hpgs_reader *reader, 530 hpgs_point *p2, 531 hpgs_point *p3, 532 hpgs_point *center, 533 double *r, 534 double *sweep ) 535{ 536 hpgs_point * p1 = &reader->current_point; 537 538 double dx12 = p1->x-p2->x; 539 double dy12 = p1->y-p2->y; 540 double dx23 = p2->x-p3->x; 541 double dy23 = p2->y-p3->y; 542 double dx13 = p1->x-p3->x; 543 double dy13 = p1->y-p3->y; 544 545 double det=dy12*dx23-dy23*dx12; 546 double angle1,angle2; 547 548 // don't ask for scaling, since graphical coordinates are 549 // reasonably scaled in most situations. 550 if (fabs(det)<1.0e-8) 551 { 552 // circle detection 553 // end points coincide 554 if (hypot(dx13,dy13)<1.0e-8) 555 { 556 center->x=0.5*(p1->x+p2->x); 557 center->y=0.5*(p1->y+p2->y); 558 *sweep=360.0; 559 *r=0.5*hypot(dx12,dy12); 560 return 0; 561 } 562 563 // other points coincide or points lie on a straight line 564 center->x=0.5*(p1->x+p3->x); 565 center->y=0.5*(p1->y+p3->y); 566 *sweep=360.0; 567 *r=0.5*hypot(dx13,dy13); 568 return 1; 569 } 570 571 center->x=dy13*dy12*dy23 572 +(sqr(p1->x)-sqr(p2->x))*dy23 573 -(sqr(p2->x)-sqr(p3->x))*dy12; 574 575 center->y=dx13*dx12*dx23 576 +(sqr(p1->y)-sqr(p2->y))*dx23 577 -(sqr(p2->y)-sqr(p3->y))*dx12; 578 579 center->x /= -2.0 * det; 580 center->y /= 2.0 * det; 581 582 *r=hypot(p1->x-center->x,p1->y-center->y); 583 584 angle1 = atan2(p1->y-center->y,p1->x-center->x)*180.0/M_PI; 585 angle2 = atan2(p2->y-center->y,p2->x-center->x)*180.0/M_PI; 586 587 // det telsl us, whether the assertion 588 // angle1<angle2 or angle2<angle1 holds. 589 if (det>0) 590 { 591 // This is necessary, because atan2 breaks at M_PI. 592 if (angle2 > angle1) angle2-=360.0; 593 } 594 else 595 { 596 // This is necessary, because atan2 breaks at M_PI. 597 if (angle2 < angle1) angle2+=360.0; 598 } 599 600 *sweep = angle2-angle1; 601 602 return 0; 603} 604 605 606// draw bezier spline parts for an elliptical arc. 607static int arc_to_bezier (hpgs_reader *reader, 608 hpgs_point *center, 609 double sweep) 610{ 611 int nseg = (int)ceil(fabs(sweep)/90.0); 612 double a,seg_alpha_2,beta; 613 int i; 614 hpgs_point *p0,axis; 615 616 if (!nseg) return 0; 617 618 axis.x = reader->current_point.x - center->x; 619 axis.y = reader->current_point.y - center->y; 620 621 seg_alpha_2 = 0.5*M_PI/180.0*sweep/nseg; 622 beta = 4.0/3.0 * (1.0-cos(seg_alpha_2))/sin(seg_alpha_2); 623 624 a=0.0; 625 626 p0 = &reader->current_point; 627 628 for (i=1;i<=nseg;i++) 629 { 630 hpgs_point p1=*p0; 631 hpgs_point p2; 632 hpgs_point p3=*center; 633 634 p1.x -= sin(a)*beta*axis.x; 635 p1.y -= sin(a)*beta*axis.y; 636 637 p1.x -= cos(a)*beta*axis.y; 638 p1.y += cos(a)*beta*axis.x; 639 640 a=M_PI/180.0 * i*sweep/nseg; 641 642 p3.x += cos(a)*axis.x; 643 p3.y += cos(a)*axis.y; 644 645 p3.x -= sin(a)*axis.y; 646 p3.y += sin(a)*axis.x; 647 648 p2=p3; 649 650 p2.x += sin(a)*beta*axis.x; 651 p2.y += sin(a)*beta*axis.y; 652 653 p2.x += cos(a)*beta*axis.y; 654 p2.y -= cos(a)*beta*axis.x; 655 656 if (hpgs_reader_curveto(reader,&p1,&p2,&p3)) 657 return -1; 658 659 *p0=p3; 660 } 661 662 return 0; 663} 664 665/* 666 HPGL Command AA (Arc Absolute) 667*/ 668int hpgs_reader_do_AA (hpgs_reader *reader) 669{ 670 hpgs_point center; 671 double sweep; 672 double chord=0.0; 673 674 if (hpgs_reader_read_point(reader,¢er,1)) return -1; 675 if (hpgs_reader_read_double(reader,&sweep)) return -1; 676 if (!reader->eoc && 677 hpgs_reader_read_double(reader,&chord)) return -1; 678 679 // Be careful about the direction of the rotation for 680 // transformation matrices with neg. determinant. 681 if (reader->world_matrix.mxx * reader->world_matrix.myy - 682 reader->world_matrix.mxy * reader->world_matrix.myx < 0.0) 683 sweep=-sweep; 684 685 return arc_to_bezier(reader,¢er,sweep); 686} 687 688/* 689 HPGL Command AR (Arc Relative) 690*/ 691int hpgs_reader_do_AR (hpgs_reader *reader) 692{ 693 hpgs_point center; 694 double sweep; 695 double chord=0.0; 696 697 if (hpgs_reader_read_point(reader,¢er,-1)) return -1; 698 if (hpgs_reader_read_double(reader,&sweep)) return -1; 699 if (!reader->eoc && 700 hpgs_reader_read_double(reader,&chord)) return -1; 701 702 center.x += reader->current_point.x; 703 center.y += reader->current_point.y; 704 705 // Be careful about the direction of the rotation for 706 // transformation matrices with neg. determinant. 707 if (reader->world_matrix.mxx * reader->world_matrix.myy - 708 reader->world_matrix.mxy * reader->world_matrix.myx < 0.0) 709 sweep=-sweep; 710 711 return arc_to_bezier(reader,¢er,sweep); 712} 713 714/* 715 HPGL Command AT (Absolute Arc Three Points) 716*/ 717int hpgs_reader_do_AT (hpgs_reader *reader) 718{ 719 hpgs_point p2,p3,center; 720 double r,sweep,chord=0.0; 721 722 if (hpgs_reader_read_point(reader,&p2,1)) return -1; 723 if (hpgs_reader_read_point(reader,&p3,1)) return -1; 724 if (!reader->eoc && 725 hpgs_reader_read_double(reader,&chord)) return -1; 726 727 reader->polygon_open = 1; 728 729 if (arc_by_points(reader,&p2,&p3,¢er,&r,&sweep)) 730 return hpgs_reader_lineto(reader,&p3); 731 else 732 return arc_to_bezier(reader,¢er,sweep); 733} 734 735/* 736 HPGL Command RT (Relative arc Three points) 737*/ 738int hpgs_reader_do_RT (hpgs_reader *reader) 739{ 740 hpgs_point p2,p3,center; 741 double r,sweep,chord=0.0; 742 743 if (hpgs_reader_read_point(reader,&p2,-1)) return -1; 744 if (hpgs_reader_read_point(reader,&p3,-1)) return -1; 745 746 p2.x += reader->current_point.x; 747 p2.y += reader->current_point.y; 748 p3.x += reader->current_point.x; 749 p3.y += reader->current_point.y; 750 751 if (!reader->eoc && 752 hpgs_reader_read_double(reader,&chord)) return -1; 753 754 if (arc_by_points(reader,&p2,&p3,¢er,&r,&sweep)) 755 return hpgs_reader_lineto(reader,&p3); 756 else 757 return arc_to_bezier(reader,¢er,sweep); 758} 759 760/* 761 HPGL Command CI (CIrcle) 762*/ 763int hpgs_reader_do_CI (hpgs_reader *reader) 764{ 765 double r; 766 double chord=0.0; 767 hpgs_point p0,center = reader->current_point; 768 769 // read input point 770 if (hpgs_reader_read_double(reader,&r)) return -1; 771 if (!reader->eoc && 772 hpgs_reader_read_double(reader,&chord)) return -1; 773 774 if (reader->polygon_mode) 775 { 776 if (hpgs_reader_closepath(reader)) return -1; 777 } 778 779 // scale r with the sqrt down to the paper space. 780 r *= reader->total_scale; 781 782 p0.x = reader->current_point.x + r; 783 p0.y = reader->current_point.y; 784 reader->pen_down = 1; 785 786 if (hpgs_reader_moveto(reader,&p0)) 787 return -1; 788 789 if (arc_to_bezier(reader,¢er,360.0)) return -1; 790 791 if (reader->polygon_mode) 792 { 793 if (hpgs_reader_closepath(reader)) return -1; 794 } 795 796 return hpgs_reader_moveto(reader,¢er); 797} 798 799/* 800 HPGL Command BZ (BeZier absolute) 801*/ 802int hpgs_reader_do_BZ (hpgs_reader *reader) 803{ 804 hpgs_point p1; 805 hpgs_point p2; 806 hpgs_point p3; 807 808 while (!reader->eoc) 809 { 810 if (hpgs_reader_read_point(reader,&p1,1)) return -1; 811 if (hpgs_reader_read_point(reader,&p2,1)) return -1; 812 if (hpgs_reader_read_point(reader,&p3,1)) return -1; 813 814 if (hpgs_reader_curveto(reader,&p1,&p2,&p3)) return -1; 815 } 816 817 return 0; 818} 819 820/* 821 HPGL Command BR (Bezier Relative) 822*/ 823int hpgs_reader_do_BR (hpgs_reader *reader) 824{ 825 hpgs_point p1; 826 hpgs_point p2; 827 hpgs_point p3; 828 829 while (!reader->eoc) 830 { 831 if (hpgs_reader_read_point(reader,&p1,-1)) return -1; 832 if (hpgs_reader_read_point(reader,&p2,-1)) return -1; 833 if (hpgs_reader_read_point(reader,&p3,-1)) return -1; 834 835 p1.x += reader->current_point.x; 836 p1.y += reader->current_point.y; 837 p2.x += reader->current_point.x; 838 p2.y += reader->current_point.y; 839 p3.x += reader->current_point.x; 840 p3.y += reader->current_point.y; 841 842 if (hpgs_reader_curveto(reader,&p1,&p2,&p3)) return -1; 843 } 844 845 return 0; 846} 847 848/* 849 HPGL Command PA (Plot Absolute) 850*/ 851int hpgs_reader_do_PA (hpgs_reader *reader) 852{ 853 hpgs_point p; 854 855 if (!reader->pen_down && 856 hpgs_reader_checkpath(reader)) return -1; 857 858 while (!reader->eoc) 859 { 860 if (hpgs_reader_read_point(reader,&p,1)) return -1; 861 862 if (reader->pen_down) 863 { 864 if (hpgs_reader_lineto(reader,&p)) return -1; 865 } 866 else 867 { 868 if (hpgs_reader_moveto(reader,&p)) return -1; 869 } 870 } 871 872 reader->absolute_plotting = 1; 873 874 return 0; 875} 876 877/* 878 HPGL Command PD (Pen Down) 879*/ 880int hpgs_reader_do_PD (hpgs_reader *reader) 881{ 882 hpgs_point p; 883 884 while (!reader->eoc) 885 { 886 if (hpgs_reader_read_point(reader,&p, 887 reader->absolute_plotting ? 1 : -1)) return -1; 888 889 if (!reader->absolute_plotting) 890 { 891 p.x += reader->current_point.x; 892 p.y += reader->current_point.y; 893 } 894 895 if (hpgs_reader_lineto(reader,&p)) return -1; 896 } 897 898 reader->pen_down = 1; 899 900 return 0; 901} 902 903/* 904 HPGL Command PR (Plot Relative) 905*/ 906int hpgs_reader_do_PR (hpgs_reader *reader) 907{ 908 hpgs_point p; 909 910 if (!reader->pen_down && 911 hpgs_reader_checkpath(reader)) return -1; 912 913 while (!reader->eoc) 914 { 915 if (hpgs_reader_read_point(reader,&p,-1)) return -1; 916 917 p.x += reader->current_point.x; 918 p.y += reader->current_point.y; 919 920 if (reader->pen_down) 921 { 922 if (hpgs_reader_lineto(reader,&p)) return -1; 923 } 924 else 925 { 926 if (hpgs_reader_moveto(reader,&p)) return -1; 927 } 928 } 929 930 reader->absolute_plotting = 0; 931 932 return 0; 933} 934 935/* 936 HPGL Command PU (Pen Up) 937*/ 938int hpgs_reader_do_PU (hpgs_reader *reader) 939{ 940 hpgs_point p; 941 942 if (hpgs_reader_checkpath(reader)) return -1; 943 944 while (!reader->eoc) 945 { 946 if (hpgs_reader_read_point(reader,&p, 947 reader->absolute_plotting ? 1 : -1)) return -1; 948 949 if (!reader->absolute_plotting) 950 { 951 p.x += reader->current_point.x; 952 p.y += reader->current_point.y; 953 } 954 955 if (hpgs_reader_moveto(reader,&p)) return -1; 956 } 957 958 reader->pen_down = 0; 959 960 return 0; 961} 962 963/* 964 HPGL Command PM (Polygon Mode) 965*/ 966int hpgs_reader_do_PM (hpgs_reader *reader) 967{ 968 int mode=0; 969 970 if (!reader->eoc && 971 hpgs_reader_read_int(reader,&mode)) return -1; 972 973 switch(mode) 974 { 975 case 0: 976 if (hpgs_reader_checkpath(reader)) return -1; 977 reader->poly_buffer_size=0; 978 reader->polygon_mode=1; 979 reader->polygon_open=0; 980 // push the current point to the polygon buffer. 981 if (hpgs_reader_moveto(reader,&reader->current_point)) return -1; 982 break; 983 case 1: 984 if (hpgs_reader_closepath(reader)) return -1; 985 break; 986 case 2: 987 if (hpgs_reader_closepath(reader)) return -1; 988 reader->polygon_mode=0; 989 if (reader->poly_buffer_size > 0) 990 reader->current_point = reader->poly_buffer[0].p; 991 break; 992 default: 993 return hpgs_set_error(hpgs_i18n("PM: Illegal mode %d."),mode); 994 }; 995 996 return 0; 997} 998 999/* 1000 HPGL Command FP (Fill Polygon) 1001*/ 1002int hpgs_reader_do_FP (hpgs_reader *reader) 1003{ 1004 hpgs_bool winding = HPGS_FALSE; 1005 1006 if (!reader->eoc && 1007 hpgs_reader_read_int(reader,&winding)) return -1; 1008 1009 if (hpgs_reader_checkpath(reader)) return -1; 1010 1011 if (reader->poly_buffer_size <= 0) return 0; 1012 1013 switch (do_polygon(reader,HPGS_TRUE)) 1014 { 1015 case 0: 1016 return 0; 1017 case 1: 1018 return hpgs_reader_fill(reader,winding); 1019 default: 1020 return -1; 1021 } 1022} 1023 1024/* 1025 HPGL Command PP (Pixel Placement) 1026*/ 1027int hpgs_reader_do_PP (hpgs_reader *reader) 1028{ 1029 int dummy = 0; 1030 1031 if (!reader->eoc && 1032 hpgs_reader_read_int(reader,&dummy)) return -1; 1033 1034 if (reader->verbosity > 1) 1035 hpgs_log("PP %d: unimplemented.\n",dummy); 1036 1037 return 0; 1038} 1039 1040/* 1041 HPGL Command FT (Fill Type) 1042*/ 1043int hpgs_reader_do_FT (hpgs_reader *reader) 1044{ 1045 double option; 1046 1047 if (reader->eoc) 1048 { 1049 reader->current_ft = 1; 1050 return 0; 1051 } 1052 1053 if (hpgs_reader_read_int(reader,&reader->current_ft)) return -1; 1054 1055 if (!reader->eoc) 1056 { 1057 if (hpgs_reader_read_double(reader,&option)) return -1; 1058 1059 switch (reader->current_ft) 1060 { 1061 case 3: 1062 // spacing is measured in current units along the x axis. 1063 reader->ft3_spacing = option * hypot(reader->total_matrix.mxx,reader->total_matrix.myx); 1064 break; 1065 case 4: 1066 // spacing is measured in current units along the x axis. 1067 reader->ft4_spacing = option * hypot(reader->total_matrix.mxx,reader->total_matrix.myx); 1068 break; 1069 case 10: 1070 reader->ft10_level = option; 1071 } 1072 } 1073 1074 if (!reader->eoc) 1075 { 1076 if (hpgs_reader_read_double(reader,&option)) return -1; 1077 1078 switch (reader->current_ft) 1079 { 1080 case 3: 1081 reader->ft3_angle = option; 1082 break; 1083 case 4: 1084 reader->ft4_angle = option; 1085 } 1086 } 1087 1088 return 0; 1089} 1090 1091/* 1092 HPGL Command EA (Edge rectangle Absolute) 1093*/ 1094int hpgs_reader_do_EA (hpgs_reader *reader) 1095{ 1096 hpgs_point p,pp,cp; 1097 1098 if (hpgs_reader_read_point(reader,&p,1)) return -1; 1099 1100 if (hpgs_reader_checkpath(reader)) return -1; 1101 reader->poly_buffer_size = 0; 1102 reader->polygon_mode = 1; 1103 1104 cp = reader->current_point; 1105 1106 if (hpgs_reader_moveto(reader,&cp)) return -1; 1107 1108 pp.x = cp.x; 1109 pp.y = p.y; 1110 1111 if (hpgs_reader_lineto(reader,&pp)) return -1; 1112 if (hpgs_reader_lineto(reader,&p)) return -1; 1113 1114 pp.x = p.x; 1115 pp.y = cp.y; 1116 1117 if (hpgs_reader_lineto(reader,&pp)) return -1; 1118 if (hpgs_reader_closepath(reader)) return -1; 1119 1120 switch (do_polygon(reader,HPGS_FALSE)) 1121 { 1122 case 1: 1123 if (hpgs_reader_fill(reader,HPGS_TRUE)) 1124 return -1; 1125 1126 if (hpgs_reader_stroke(reader)) 1127 return -1; 1128 1129 case 0: 1130 reader->polygon_mode = 0; 1131 return 0; 1132 1133 default: 1134 return -1; 1135 } 1136} 1137 1138/* 1139 HPGL Command RA (fill Rectangle Absolute) 1140*/ 1141int hpgs_reader_do_RA (hpgs_reader *reader) 1142{ 1143 hpgs_point p,pp,cp; 1144 1145 if (hpgs_reader_read_point(reader,&p,1)) return -1; 1146 1147 if (hpgs_reader_checkpath(reader)) return -1; 1148 reader->poly_buffer_size = 0; 1149 reader->polygon_mode = 1; 1150 1151 cp = reader->current_point; 1152 1153 if (hpgs_reader_moveto(reader,&cp)) return -1; 1154 1155 pp.x = cp.x; 1156 pp.y = p.y; 1157 1158 if (hpgs_reader_lineto(reader,&pp)) return -1; 1159 if (hpgs_reader_lineto(reader,&p)) return -1; 1160 1161 pp.x = p.x; 1162 pp.y = cp.y; 1163 1164 if (hpgs_reader_lineto(reader,&pp)) return -1; 1165 if (hpgs_reader_closepath(reader)) return -1; 1166 1167 switch (do_polygon(reader,HPGS_TRUE)) 1168 { 1169 case 1: 1170 if (hpgs_reader_fill(reader,1)) 1171 return -1; 1172 1173 case 0: 1174 reader->polygon_mode = 0; 1175 return 0; 1176 1177 default: 1178 return -1; 1179 } 1180} 1181 1182/* 1183 HPGL Command ER (Edge rectangle Relative) 1184*/ 1185int hpgs_reader_do_ER (hpgs_reader *reader) 1186{ 1187 hpgs_point p,pp,cp; 1188 1189 if (hpgs_reader_read_point(reader,&p,-1)) return -1; 1190 1191 p.x += reader->current_point.x; 1192 p.y += reader->current_point.y; 1193 1194 if (hpgs_reader_checkpath(reader)) return -1; 1195 reader->poly_buffer_size = 0; 1196 reader->polygon_mode = 1; 1197 1198 cp = reader->current_point; 1199 1200 if (hpgs_reader_moveto(reader,&cp)) return -1; 1201 1202 pp.x = cp.x; 1203 pp.y = p.y; 1204 1205 if (hpgs_reader_lineto(reader,&pp)) return -1; 1206 if (hpgs_reader_lineto(reader,&p)) return -1; 1207 1208 pp.x = p.x; 1209 pp.y = cp.y; 1210 1211 if (hpgs_reader_lineto(reader,&pp)) return -1; 1212 if (hpgs_reader_closepath(reader)) return -1; 1213 1214 switch (do_polygon(reader,HPGS_FALSE)) 1215 { 1216 case 1: 1217 if (hpgs_reader_stroke(reader)) 1218 return -1; 1219 1220 case 0: 1221 reader->polygon_mode = 0; 1222 return 0; 1223 1224 default: 1225 return -1; 1226 } 1227} 1228 1229/* 1230 HPGL Command RR (fill Rectangle Relative) 1231*/ 1232int hpgs_reader_do_RR (hpgs_reader *reader) 1233{ 1234 hpgs_point p,pp,cp; 1235 1236 if (hpgs_reader_read_point(reader,&p,-1)) return -1; 1237 1238 p.x += reader->current_point.x; 1239 p.y += reader->current_point.y; 1240 1241 if (hpgs_reader_checkpath(reader)) return -1; 1242 reader->poly_buffer_size = 0; 1243 reader->polygon_mode = 1; 1244 1245 cp = reader->current_point; 1246 1247 if (hpgs_reader_moveto(reader,&cp)) return -1; 1248 1249 pp.x = cp.x; 1250 pp.y = p.y; 1251 1252 if (hpgs_reader_lineto(reader,&pp)) return -1; 1253 if (hpgs_reader_lineto(reader,&p)) return -1; 1254 1255 pp.x = p.x; 1256 pp.y = cp.y; 1257 1258 if (hpgs_reader_lineto(reader,&pp)) return -1; 1259 if (hpgs_reader_closepath(reader)) return -1; 1260 1261 switch (do_polygon(reader,HPGS_TRUE)) 1262 { 1263 case 1: 1264 if (hpgs_reader_fill(reader,1)) 1265 return -1; 1266 1267 case 0: 1268 reader->polygon_mode = 0; 1269 return 0; 1270 1271 default: 1272 return -1; 1273 } 1274} 1275 1276/* 1277 HPGL Command EP (Edge Polygon) 1278*/ 1279int hpgs_reader_do_EP (hpgs_reader *reader) 1280{ 1281 if (hpgs_reader_checkpath(reader)) return -1; 1282 1283 if (reader->poly_buffer_size <= 0) return 0; 1284 1285 switch (do_polygon(reader,HPGS_FALSE)) 1286 { 1287 case 1: 1288 if (hpgs_stroke(reader->device)) 1289 return -1; 1290 1291 case 0: 1292 return 0; 1293 1294 default: 1295 return -1; 1296 } 1297} 1298 1299/* 1300 HPGL Command EW (Edge Wedge) 1301*/ 1302int hpgs_reader_do_EW (hpgs_reader *reader) 1303{ 1304 double r,start,sweep,chord; 1305 hpgs_point p,center; 1306 1307 if (hpgs_reader_read_double(reader,&r)) return -1; 1308 if (hpgs_reader_read_double(reader,&start)) return -1; 1309 if (hpgs_reader_read_double(reader,&sweep)) return -1; 1310 if (!reader->eoc && 1311 hpgs_reader_read_double(reader,&chord)) return -1; 1312 1313 if (hpgs_reader_checkpath(reader)) return -1; 1314 reader->poly_buffer_size = 0; 1315 reader->polygon_mode = 1; 1316 1317 // scale r with the sqrt down to the paper space. 1318 r *= reader->total_scale; 1319 1320 center = reader->current_point; 1321 p=reader->current_point; 1322 p.x+=cos(start*M_PI/180.0)*r; 1323 p.y+=sin(start*M_PI/180.0)*r; 1324 1325 if (hpgs_reader_moveto(reader,&reader->current_point)) return -1; 1326 if (hpgs_reader_lineto(reader,&p)) return -1; 1327 1328 if (arc_to_bezier(reader,¢er,sweep)) 1329 1330 if (hpgs_reader_closepath(reader)) return -1; 1331 1332 switch (do_polygon(reader,HPGS_FALSE)) 1333 { 1334 case 1: 1335 if (hpgs_reader_stroke(reader)) 1336 return -1; 1337 1338 case 0: 1339 reader->polygon_mode = 0; 1340 return 0; 1341 1342 default: 1343 return -1; 1344 } 1345} 1346 1347/* 1348 HPGL Command WG (fill WedGe) 1349*/ 1350int hpgs_reader_do_WG (hpgs_reader *reader) 1351{ 1352 double r,start,sweep,chord; 1353 hpgs_point p,center; 1354 1355 if (hpgs_reader_read_double(reader,&r)) return -1; 1356 if (hpgs_reader_read_double(reader,&start)) return -1; 1357 if (hpgs_reader_read_double(reader,&sweep)) return -1; 1358 if (!reader->eoc && 1359 hpgs_reader_read_double(reader,&chord)) return -1; 1360 1361 if (hpgs_reader_checkpath(reader)) return -1; 1362 reader->poly_buffer_size = 0; 1363 reader->polygon_mode = 1; 1364 1365 // scale r with the sqrt down to the paper space. 1366 r *= reader->total_scale; 1367 1368 center = reader->current_point; 1369 p=reader->current_point; 1370 p.x+=cos(start*M_PI/180.0)*r; 1371 p.y+=sin(start*M_PI/180.0)*r; 1372 1373 if (hpgs_reader_moveto(reader,&reader->current_point)) return -1; 1374 if (hpgs_reader_lineto(reader,&p)) return -1; 1375 1376 if (arc_to_bezier(reader,¢er,sweep)) 1377 1378 if (hpgs_reader_closepath(reader)) return -1; 1379 1380 switch (do_polygon(reader,HPGS_TRUE)) 1381 { 1382 case 1: 1383 if (hpgs_reader_fill(reader,1)) 1384 return -1; 1385 1386 case 0: 1387 reader->polygon_mode = 0; 1388 return 0; 1389 1390 default: 1391 return -1; 1392 } 1393} 1394