]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/hpgl-vector.c
Merge changes from CUPS 1.5svn-r8950.
[thirdparty/cups.git] / filter / hpgl-vector.c
1 /*
2 * "$Id: hpgl-vector.c 6649 2007-07-11 21:46:42Z mike $"
3 *
4 * HP-GL/2 vector routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1993-2007 by Easy Software Products.
8 *
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
14 *
15 * This file is subject to the Apple OS-Developed Software exception.
16 *
17 * Contents:
18 *
19 * AA_arc_absolute() - Draw an arc.
20 * AR_arc_relative() - Draw an arc relative to the current pen
21 * AT_arc_absolute3() - Draw an arc using 3 points.
22 * CI_circle() - Draw a circle.
23 * PA_plot_absolute() - Plot a line using absolute coordinates.
24 * PD_pen_down() - Start drawing.
25 * PE_polygon_encoded() - Draw an encoded polyline.
26 * PR_plot_relative() - Plot a line using relative coordinates.
27 * PU_pen_up() - Stop drawing.
28 * RT_arc_relative3() - Draw an arc through 3 points relative to the
29 * decode_number() - Decode an encoded number.
30 * plot_points() - Plot the specified points.
31 */
32
33 /*
34 * Include necessary headers...
35 */
36
37 #include "hpgltops.h"
38
39
40 /*
41 * Local functions...
42 */
43
44 static double decode_number(unsigned char **, int, double);
45 static void plot_points(int, param_t *);
46
47
48 /*
49 * 'AA_arc_absolute()' - Draw an arc.
50 */
51
52 void
53 AA_arc_absolute(int num_params, /* I - Number of parameters */
54 param_t *params) /* I - Parameters */
55 {
56 float x, y, /* Transformed coordinates */
57 dx, dy; /* Distance from current pen */
58 float start, end, /* Start and end angles */
59 theta, /* Current angle */
60 dt, /* Step between points */
61 radius; /* Radius of arc */
62
63
64 if (num_params < 3)
65 return;
66
67 x = Transform[0][0] * params[0].value.number +
68 Transform[0][1] * params[1].value.number +
69 Transform[0][2];
70 y = Transform[1][0] * params[0].value.number +
71 Transform[1][1] * params[1].value.number +
72 Transform[1][2];
73
74 dx = PenPosition[0] - x;
75 dy = PenPosition[1] - y;
76
77 start = (float)(180.0 * atan2(dy, dx) / M_PI);
78 if (start < 0.0)
79 start += 360.0f;
80
81 end = start + params[2].value.number;
82 radius = (float)hypot(dx, dy);
83
84 if (PenDown)
85 {
86 if (num_params > 3 && params[3].value.number > 0.0)
87 dt = (float)fabs(params[3].value.number);
88 else
89 dt = 5.0;
90
91 if (!PolygonMode)
92 Outputf("MP\n");
93
94 PenValid = 1;
95
96 Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
97
98 if (start < end)
99 for (theta = start + dt; theta < end; theta += dt)
100 {
101 PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0));
102 PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0));
103
104 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
105 }
106 else
107 for (theta = start - dt; theta > end; theta -= dt)
108 {
109 PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0));
110 PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0));
111
112 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
113 }
114 }
115
116 PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0));
117 PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0));
118
119 if (PenDown)
120 {
121 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
122
123 if (!PolygonMode)
124 Outputf("ST\n");
125 }
126 }
127
128
129 /*
130 * 'AR_arc_relative()' - Draw an arc relative to the current pen
131 * position.
132 */
133
134 void
135 AR_arc_relative(int num_params, /* I - Number of parameters */
136 param_t *params) /* I - Parameters */
137 {
138 float x, y, /* Transformed coordinates */
139 dx, dy; /* Distance from current pen */
140 float start, end, /* Start and end angles */
141 theta, /* Current angle */
142 dt, /* Step between points */
143 radius; /* Radius of arc */
144
145
146 if (num_params < 3)
147 return;
148
149 x = Transform[0][0] * params[0].value.number +
150 Transform[0][1] * params[1].value.number +
151 PenPosition[0];
152 y = Transform[1][0] * params[0].value.number +
153 Transform[1][1] * params[1].value.number +
154 PenPosition[1];
155
156 dx = PenPosition[0] - x;
157 dy = PenPosition[1] - y;
158
159 start = (float)(180.0 * atan2(dy, dx) / M_PI);
160 if (start < 0.0)
161 start += 360.0f;
162
163 end = start + params[2].value.number;
164 radius = (float)hypot(dx, dy);
165
166 if (PenDown)
167 {
168 if (num_params > 3 && params[3].value.number > 0.0)
169 dt = (float)fabs(params[3].value.number);
170 else
171 dt = 5.0;
172
173 if (!PolygonMode)
174 Outputf("MP\n");
175
176 PenValid = 1;
177
178 Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
179
180 if (start < end)
181 for (theta = start + dt; theta < end; theta += dt)
182 {
183 PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0));
184 PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0));
185
186 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
187 }
188 else
189 for (theta = start - dt; theta > end; theta -= dt)
190 {
191 PenPosition[0] = (float)(x + radius * cos(M_PI * theta / 180.0));
192 PenPosition[1] = (float)(y + radius * sin(M_PI * theta / 180.0));
193
194 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
195 }
196 }
197
198 PenPosition[0] = (float)(x + radius * cos(M_PI * end / 180.0));
199 PenPosition[1] = (float)(y + radius * sin(M_PI * end / 180.0));
200
201 if (PenDown)
202 {
203 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
204
205 if (!PolygonMode)
206 Outputf("ST\n");
207 }
208 }
209
210
211 /*
212 * 'AT_arc_absolute3()' - Draw an arc using 3 points.
213 *
214 * Note:
215 *
216 * Currently this only draws two line segments through the
217 * specified points.
218 */
219
220 void
221 AT_arc_absolute3(int num_params, /* I - Number of parameters */
222 param_t *params) /* I - Parameters */
223 {
224 if (num_params < 4)
225 return;
226
227 if (PenDown)
228 {
229 if (!PolygonMode)
230 Outputf("MP\n");
231
232 PenValid = 1;
233
234 Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
235
236 PenPosition[0] = Transform[0][0] * params[0].value.number +
237 Transform[0][1] * params[1].value.number +
238 Transform[0][2];
239 PenPosition[1] = Transform[1][0] * params[0].value.number +
240 Transform[1][1] * params[1].value.number +
241 Transform[1][2];
242
243 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
244 }
245
246 PenPosition[0] = Transform[0][0] * params[2].value.number +
247 Transform[0][1] * params[3].value.number +
248 Transform[0][2];
249 PenPosition[1] = Transform[1][0] * params[2].value.number +
250 Transform[1][1] * params[3].value.number +
251 Transform[1][2];
252
253 if (PenDown)
254 {
255 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
256
257 if (!PolygonMode)
258 Outputf("ST\n");
259 }
260 }
261
262
263 /*
264 * 'CI_circle()' - Draw a circle.
265 */
266
267 void
268 CI_circle(int num_params, /* I - Number of parameters */
269 param_t *params) /* I - Parameters */
270 {
271 float x, y; /* Transformed coordinates */
272 float theta, /* Current angle */
273 dt, /* Step between points */
274 radius; /* Radius of circle */
275
276
277 if (num_params < 1)
278 return;
279
280 if (!PenDown)
281 return;
282
283 radius = params[0].value.number;
284
285 if (num_params > 1)
286 dt = (float)fabs(params[1].value.number);
287 else
288 dt = 5.0;
289
290 if (!PolygonMode)
291 Outputf("MP\n");
292
293 PenValid = 1;
294
295 for (theta = 0.0; theta < 360.0; theta += dt)
296 {
297 x = (float)(PenPosition[0] +
298 radius * cos(M_PI * theta / 180.0) * Transform[0][0] +
299 radius * sin(M_PI * theta / 180.0) * Transform[0][1]);
300 y = (float)(PenPosition[1] +
301 radius * cos(M_PI * theta / 180.0) * Transform[1][0] +
302 radius * sin(M_PI * theta / 180.0) * Transform[1][1]);
303
304 Outputf("%.3f %.3f %s\n", x, y, theta == 0.0 ? "MO" : "LI");
305 }
306
307 Outputf("CP\n");
308 if (!PolygonMode)
309 Outputf("ST\n");
310 }
311
312
313 /*
314 * 'PA_plot_absolute()' - Plot a line using absolute coordinates.
315 */
316
317 void
318 PA_plot_absolute(int num_params, /* I - Number of parameters */
319 param_t *params) /* I - Parameters */
320 {
321 PenMotion = 0;
322
323 if (num_params > 1)
324 plot_points(num_params, params);
325 }
326
327
328 /*
329 * 'PD_pen_down()' - Start drawing.
330 */
331
332 void
333 PD_pen_down(int num_params, /* I - Number of parameters */
334 param_t *params) /* I - Parameters */
335 {
336 PenDown = 1;
337
338 if (num_params > 1)
339 plot_points(num_params, params);
340 }
341
342
343 /*
344 * 'PE_polygon_encoded()' - Draw an encoded polyline.
345 */
346
347 void
348 PE_polyline_encoded(int num_params, /* I - Number of parameters */
349 param_t *params) /* I - Parameters */
350 {
351 unsigned char *s; /* Pointer into string */
352 int temp, /* Temporary value */
353 base_bits, /* Data bits per byte */
354 draw, /* Draw or move */
355 abscoords; /* Use absolute coordinates */
356 double tx, ty, /* Transformed coordinates */
357 x, y, /* Raw coordinates */
358 frac_bits; /* Multiplier for encoded number */
359
360
361 base_bits = 6;
362 frac_bits = 1.0;
363 draw = PenDown;
364 abscoords = 0;
365
366 if (num_params == 0)
367 return;
368
369 if (!PolygonMode)
370 {
371 Outputf("MP\n");
372 PenValid = 0;
373 }
374
375 if (!PenValid)
376 {
377 Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
378 PenValid = 1;
379 }
380
381 for (s = (unsigned char *)params[0].value.string; *s != '\0';)
382 switch (*s)
383 {
384 case '7' :
385 s ++;
386 base_bits = 5;
387
388 #ifdef DEBUG
389 fputs("DEBUG: 7-bit\n", stderr);
390 #endif /* DEBUG */
391
392 Outputf("%% PE: 7-bit\n");
393 break;
394 case ':' : /* Select pen */
395 s ++;
396 temp = (int)decode_number(&s, base_bits, 1.0) - 1;
397 if (temp < 0 || temp >= PenCount)
398 {
399 fprintf(stderr, "DEBUG: Bad pen number %d in PE\n", temp + 1);
400 return;
401 }
402
403 PenNumber = temp;
404
405 #ifdef DEBUG
406 fprintf(stderr, "DEBUG: set pen #%d\n", PenNumber + 1);
407 #endif /* DEBUG */
408
409 Outputf("%% PE: set pen #%d\n", PenNumber + 1);
410
411 if (PageDirty)
412 printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0],
413 Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2],
414 Pens[PenNumber].width * PenScaling);
415 break;
416 case '<' : /* Next coords are a move-to */
417 draw = 0;
418 s ++;
419
420 #ifdef DEBUG
421 fputs("DEBUG: moveto\n", stderr);
422 #endif /* DEBUG */
423
424 Outputf("%% PE: moveto\n");
425 break;
426 case '>' : /* Set fractional bits */
427 s ++;
428 temp = (int)decode_number(&s, base_bits, 1.0);
429 frac_bits = 1.0 / (1 << temp);
430
431 #ifdef DEBUG
432 fprintf(stderr, "DEBUG: set fractional bits %d\n", temp);
433 #endif /* DEBUG */
434
435 Outputf("%% PE: set fractional bits %d\n", temp);
436 break;
437 case '=' : /* Next coords are absolute */
438 s ++;
439 abscoords = 1;
440
441 #ifdef DEBUG
442 fputs("DEBUG: absolute\n", stderr);
443 #endif /* DEBUG */
444
445 Outputf("%% PE: absolute\n");
446 break;
447 default :
448 if (*s >= 63)
449 {
450 /*
451 * Coordinate...
452 */
453
454 x = decode_number(&s, base_bits, frac_bits);
455 y = decode_number(&s, base_bits, frac_bits);
456
457 #ifdef DEBUG
458 fprintf(stderr, "DEBUG: coords %.3f %.3f\n", x, y);
459 #endif /* DEBUG */
460
461 Outputf("%% PE: coords %.3f %.3f\n", x, y);
462
463 if (abscoords)
464 {
465 tx = Transform[0][0] * x + Transform[0][1] * y +
466 Transform[0][2];
467 ty = Transform[1][0] * x + Transform[1][1] * y +
468 Transform[1][2];
469 }
470 else if (x == 0.0 && y == 0.0)
471 {
472 draw = 1;
473 continue;
474 }
475 else
476 {
477 tx = Transform[0][0] * x + Transform[0][1] * y +
478 PenPosition[0];
479 ty = Transform[1][0] * x + Transform[1][1] * y +
480 PenPosition[1];
481 }
482
483 if (draw)
484 {
485 if (fabs(PenPosition[0] - tx) > 0.001 ||
486 fabs(PenPosition[1] - ty) > 0.001)
487 Outputf("%.3f %.3f LI\n", tx, ty);
488 }
489 else
490 Outputf("%.3f %.3f MO\n", tx, ty);
491
492 PenPosition[0] = (float)tx;
493 PenPosition[1] = (float)ty;
494
495 draw = 1;
496 abscoords = 0;
497 }
498 else
499 {
500 /*
501 * Junk - ignore...
502 */
503
504 if (*s != '\n' && *s != '\r')
505 fprintf(stderr, "WARNING: ignoring illegal PE char \'%c\'...\n", *s);
506 s ++;
507 }
508 break;
509 }
510
511 if (!PolygonMode)
512 Outputf("ST\n");
513 }
514
515
516 /*
517 * 'PR_plot_relative()' - Plot a line using relative coordinates.
518 */
519
520 void
521 PR_plot_relative(int num_params, /* I - Number of parameters */
522 param_t *params) /* I - Parameters */
523 {
524 PenMotion = 1;
525
526 if (num_params > 1)
527 plot_points(num_params, params);
528 }
529
530
531 /*
532 * 'PU_pen_up()' - Stop drawing.
533 */
534
535 void
536 PU_pen_up(int num_params, /* I - Number of parameters */
537 param_t *params) /* I - Parameters */
538 {
539 PenDown = 0;
540
541 if (num_params > 1)
542 plot_points(num_params, params);
543 }
544
545
546 /*
547 * 'RT_arc_relative3()' - Draw an arc through 3 points relative to the
548 * current pen position.
549 *
550 * Note:
551 *
552 * This currently only draws two line segments through the specified
553 * points.
554 */
555
556 void
557 RT_arc_relative3(int num_params, /* I - Number of parameters */
558 param_t *params) /* I - Parameters */
559 {
560 if (num_params < 4)
561 return;
562
563 if (PenDown)
564 {
565 if (!PolygonMode)
566 Outputf("MP\n");
567
568 PenValid = 1;
569
570 Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
571
572 PenPosition[0] = Transform[0][0] * params[0].value.number +
573 Transform[0][1] * params[1].value.number +
574 PenPosition[0];
575 PenPosition[1] = Transform[1][0] * params[0].value.number +
576 Transform[1][1] * params[1].value.number +
577 PenPosition[1];
578
579 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
580 }
581
582 PenPosition[0] = Transform[0][0] * params[2].value.number +
583 Transform[0][1] * params[3].value.number +
584 PenPosition[0];
585 PenPosition[1] = Transform[1][0] * params[2].value.number +
586 Transform[1][1] * params[3].value.number +
587 PenPosition[1];
588
589 if (PenDown)
590 {
591 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
592
593 if (!PolygonMode)
594 Outputf("ST\n");
595 }
596 }
597
598
599 /*
600 * 'decode_number()' - Decode an encoded number.
601 */
602
603 static double /* O - Value */
604 decode_number(unsigned char **s, /* IO - String to decode */
605 int base_bits, /* I - Number of data bits per byte */
606 double frac_bits) /* I - Multiplier for fractional data */
607 {
608 double temp, /* Current value */
609 shift; /* Multiplier */
610 int sign; /* Sign of result */
611
612
613 sign = 0;
614
615 if (base_bits == 5)
616 {
617 for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++)
618 if (**s >= 95 && **s < 127)
619 {
620 if (sign == 0)
621 {
622 if ((**s - 95) & 1)
623 sign = -1;
624 else
625 sign = 1;
626
627 temp += ((**s - 95) & ~1) * shift;
628 }
629 else
630 temp += (**s - 95) * shift;
631 break;
632 }
633 else if (**s < 63)
634 {
635 if (**s != '\r' && **s != '\n')
636 fprintf(stderr, "DEBUG: Bad PE character 0x%02X!\n", **s);
637
638 continue;
639 }
640 else
641 {
642 if (sign == 0)
643 {
644 if ((**s - 63) & 1)
645 sign = -1;
646 else
647 sign = 1;
648
649 temp += ((**s - 63) & ~1) * shift;
650 }
651 else
652 temp += (**s - 63) * shift;
653
654 shift *= 32.0;
655 }
656 }
657 else
658 {
659 for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++)
660 if (**s >= 191 && **s < 255)
661 {
662 if (sign == 0)
663 {
664 if ((**s - 191) & 1)
665 sign = -1;
666 else
667 sign = 1;
668
669 temp += ((**s - 191) & ~1) * shift;
670 }
671 else
672 temp += (**s - 191) * shift;
673 break;
674 }
675 else if (**s < 63)
676 {
677 if (**s != '\r' && **s != '\n')
678 fprintf(stderr, "DEBUG: Bad PE character 0x%02X!\n", **s);
679
680 continue;
681 }
682 else
683 {
684 if (sign == 0)
685 {
686 if ((**s - 63) & 1)
687 sign = -1;
688 else
689 sign = 1;
690
691 temp += ((**s - 63) & ~1) * shift;
692 }
693 else
694 temp += (**s - 63) * shift;
695
696 shift *= 64.0;
697 }
698 }
699
700 (*s) ++;
701
702 return (temp * sign);
703 }
704
705
706 /*
707 * 'plot_points()' - Plot the specified points.
708 */
709
710 static void
711 plot_points(int num_params, /* I - Number of parameters */
712 param_t *params) /* I - Parameters */
713 {
714 int i; /* Looping var */
715 float x, y; /* Transformed coordinates */
716
717
718 if (PenDown)
719 {
720 if (!PolygonMode)
721 {
722 Outputf("MP\n");
723 Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
724
725 PenValid = 1;
726 }
727 }
728
729 for (i = 0; i < num_params; i += 2)
730 {
731 if (PenMotion == 0)
732 {
733 x = Transform[0][0] * params[i + 0].value.number +
734 Transform[0][1] * params[i + 1].value.number +
735 Transform[0][2];
736 y = Transform[1][0] * params[i + 0].value.number +
737 Transform[1][1] * params[i + 1].value.number +
738 Transform[1][2];
739 }
740 else
741 {
742 x = Transform[0][0] * params[i + 0].value.number +
743 Transform[0][1] * params[i + 1].value.number +
744 PenPosition[0];
745 y = Transform[1][0] * params[i + 0].value.number +
746 Transform[1][1] * params[i + 1].value.number +
747 PenPosition[1];
748 }
749
750 if (PenDown)
751 {
752 if (PolygonMode && i == 0)
753 Outputf("%.3f %.3f MO\n", x, y);
754 else if (fabs(PenPosition[0] - x) > 0.001 ||
755 fabs(PenPosition[1] - y) > 0.001)
756 Outputf("%.3f %.3f LI\n", x, y);
757 }
758
759 PenPosition[0] = x;
760 PenPosition[1] = y;
761 }
762
763 if (PenDown)
764 {
765 if (!PolygonMode)
766 Outputf("ST\n");
767 }
768 }
769
770
771 /*
772 * End of "$Id: hpgl-vector.c 6649 2007-07-11 21:46:42Z mike $".
773 */