]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/hpgl-vector.c
Load cups into easysw/current.
[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 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 PenNumber = (int)decode_number(&s, base_bits, 1.0);
397
398 #ifdef DEBUG
399 fprintf(stderr, "DEBUG: set pen #%d\n", PenNumber);
400 #endif /* DEBUG */
401
402 Outputf("%% PE: set pen #%d\n", PenNumber);
403
404 if (PageDirty)
405 printf("%.3f %.3f %.3f %.2f SP\n", Pens[PenNumber].rgb[0],
406 Pens[PenNumber].rgb[1], Pens[PenNumber].rgb[2],
407 Pens[PenNumber].width * PenScaling);
408 break;
409 case '<' : /* Next coords are a move-to */
410 draw = 0;
411 s ++;
412
413 #ifdef DEBUG
414 fputs("DEBUG: moveto\n", stderr);
415 #endif /* DEBUG */
416
417 Outputf("%% PE: moveto\n");
418 break;
419 case '>' : /* Set fractional bits */
420 s ++;
421 temp = (int)decode_number(&s, base_bits, 1.0);
422 frac_bits = 1.0 / (1 << temp);
423
424 #ifdef DEBUG
425 fprintf(stderr, "DEBUG: set fractional bits %d\n", temp);
426 #endif /* DEBUG */
427
428 Outputf("%% PE: set fractional bits %d\n", temp);
429 break;
430 case '=' : /* Next coords are absolute */
431 s ++;
432 abscoords = 1;
433
434 #ifdef DEBUG
435 fputs("DEBUG: absolute\n", stderr);
436 #endif /* DEBUG */
437
438 Outputf("%% PE: absolute\n");
439 break;
440 default :
441 if (*s >= 63)
442 {
443 /*
444 * Coordinate...
445 */
446
447 x = decode_number(&s, base_bits, frac_bits);
448 y = decode_number(&s, base_bits, frac_bits);
449
450 #ifdef DEBUG
451 fprintf(stderr, "DEBUG: coords %.3f %.3f\n", x, y);
452 #endif /* DEBUG */
453
454 Outputf("%% PE: coords %.3f %.3f\n", x, y);
455
456 if (abscoords)
457 {
458 tx = Transform[0][0] * x + Transform[0][1] * y +
459 Transform[0][2];
460 ty = Transform[1][0] * x + Transform[1][1] * y +
461 Transform[1][2];
462 }
463 else if (x == 0.0 && y == 0.0)
464 {
465 draw = 1;
466 continue;
467 }
468 else
469 {
470 tx = Transform[0][0] * x + Transform[0][1] * y +
471 PenPosition[0];
472 ty = Transform[1][0] * x + Transform[1][1] * y +
473 PenPosition[1];
474 }
475
476 if (draw)
477 {
478 if (fabs(PenPosition[0] - tx) > 0.001 ||
479 fabs(PenPosition[1] - ty) > 0.001)
480 Outputf("%.3f %.3f LI\n", tx, ty);
481 }
482 else
483 Outputf("%.3f %.3f MO\n", tx, ty);
484
485 PenPosition[0] = (float)tx;
486 PenPosition[1] = (float)ty;
487
488 draw = 1;
489 abscoords = 0;
490 }
491 else
492 {
493 /*
494 * Junk - ignore...
495 */
496
497 if (*s != '\n' && *s != '\r')
498 fprintf(stderr, "WARNING: ignoring illegal PE char \'%c\'...\n", *s);
499 s ++;
500 }
501 break;
502 }
503
504 if (!PolygonMode)
505 Outputf("ST\n");
506 }
507
508
509 /*
510 * 'PR_plot_relative()' - Plot a line using relative coordinates.
511 */
512
513 void
514 PR_plot_relative(int num_params, /* I - Number of parameters */
515 param_t *params) /* I - Parameters */
516 {
517 PenMotion = 1;
518
519 if (num_params > 1)
520 plot_points(num_params, params);
521 }
522
523
524 /*
525 * 'PU_pen_up()' - Stop drawing.
526 */
527
528 void
529 PU_pen_up(int num_params, /* I - Number of parameters */
530 param_t *params) /* I - Parameters */
531 {
532 PenDown = 0;
533
534 if (num_params > 1)
535 plot_points(num_params, params);
536 }
537
538
539 /*
540 * 'RT_arc_relative3()' - Draw an arc through 3 points relative to the
541 * current pen position.
542 *
543 * Note:
544 *
545 * This currently only draws two line segments through the specified
546 * points.
547 */
548
549 void
550 RT_arc_relative3(int num_params, /* I - Number of parameters */
551 param_t *params) /* I - Parameters */
552 {
553 if (num_params < 4)
554 return;
555
556 if (PenDown)
557 {
558 if (!PolygonMode)
559 Outputf("MP\n");
560
561 PenValid = 1;
562
563 Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
564
565 PenPosition[0] = Transform[0][0] * params[0].value.number +
566 Transform[0][1] * params[1].value.number +
567 PenPosition[0];
568 PenPosition[1] = Transform[1][0] * params[0].value.number +
569 Transform[1][1] * params[1].value.number +
570 PenPosition[1];
571
572 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
573 }
574
575 PenPosition[0] = Transform[0][0] * params[2].value.number +
576 Transform[0][1] * params[3].value.number +
577 PenPosition[0];
578 PenPosition[1] = Transform[1][0] * params[2].value.number +
579 Transform[1][1] * params[3].value.number +
580 PenPosition[1];
581
582 if (PenDown)
583 {
584 Outputf("%.3f %.3f LI\n", PenPosition[0], PenPosition[1]);
585
586 if (!PolygonMode)
587 Outputf("ST\n");
588 }
589 }
590
591
592 /*
593 * 'decode_number()' - Decode an encoded number.
594 */
595
596 static double /* O - Value */
597 decode_number(unsigned char **s, /* IO - String to decode */
598 int base_bits, /* I - Number of data bits per byte */
599 double frac_bits) /* I - Multiplier for fractional data */
600 {
601 double temp, /* Current value */
602 shift; /* Multiplier */
603 int sign; /* Sign of result */
604
605
606 sign = 0;
607
608 if (base_bits == 5)
609 {
610 for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++)
611 if (**s >= 95 && **s < 127)
612 {
613 if (sign == 0)
614 {
615 if ((**s - 95) & 1)
616 sign = -1;
617 else
618 sign = 1;
619
620 temp += ((**s - 95) & ~1) * shift;
621 }
622 else
623 temp += (**s - 95) * shift;
624 break;
625 }
626 else if (**s < 63)
627 {
628 if (**s != '\r' && **s != '\n')
629 fprintf(stderr, "DEBUG: Bad PE character 0x%02X!\n", **s);
630
631 continue;
632 }
633 else
634 {
635 if (sign == 0)
636 {
637 if ((**s - 63) & 1)
638 sign = -1;
639 else
640 sign = 1;
641
642 temp += ((**s - 63) & ~1) * shift;
643 }
644 else
645 temp += (**s - 63) * shift;
646
647 shift *= 32.0;
648 }
649 }
650 else
651 {
652 for (temp = 0.0, shift = frac_bits * 0.5; **s != '\0'; (*s) ++)
653 if (**s >= 191 && **s < 255)
654 {
655 if (sign == 0)
656 {
657 if ((**s - 191) & 1)
658 sign = -1;
659 else
660 sign = 1;
661
662 temp += ((**s - 191) & ~1) * shift;
663 }
664 else
665 temp += (**s - 191) * shift;
666 break;
667 }
668 else if (**s < 63)
669 {
670 if (**s != '\r' && **s != '\n')
671 fprintf(stderr, "DEBUG: Bad PE character 0x%02X!\n", **s);
672
673 continue;
674 }
675 else
676 {
677 if (sign == 0)
678 {
679 if ((**s - 63) & 1)
680 sign = -1;
681 else
682 sign = 1;
683
684 temp += ((**s - 63) & ~1) * shift;
685 }
686 else
687 temp += (**s - 63) * shift;
688
689 shift *= 64.0;
690 }
691 }
692
693 (*s) ++;
694
695 return (temp * sign);
696 }
697
698
699 /*
700 * 'plot_points()' - Plot the specified points.
701 */
702
703 static void
704 plot_points(int num_params, /* I - Number of parameters */
705 param_t *params) /* I - Parameters */
706 {
707 int i; /* Looping var */
708 float x, y; /* Transformed coordinates */
709
710
711 if (PenDown)
712 {
713 if (!PolygonMode)
714 {
715 Outputf("MP\n");
716 Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]);
717
718 PenValid = 1;
719 }
720 }
721
722 for (i = 0; i < num_params; i += 2)
723 {
724 if (PenMotion == 0)
725 {
726 x = Transform[0][0] * params[i + 0].value.number +
727 Transform[0][1] * params[i + 1].value.number +
728 Transform[0][2];
729 y = Transform[1][0] * params[i + 0].value.number +
730 Transform[1][1] * params[i + 1].value.number +
731 Transform[1][2];
732 }
733 else
734 {
735 x = Transform[0][0] * params[i + 0].value.number +
736 Transform[0][1] * params[i + 1].value.number +
737 PenPosition[0];
738 y = Transform[1][0] * params[i + 0].value.number +
739 Transform[1][1] * params[i + 1].value.number +
740 PenPosition[1];
741 }
742
743 if (PenDown)
744 {
745 if (PolygonMode && i == 0)
746 Outputf("%.3f %.3f MO\n", x, y);
747 else if (fabs(PenPosition[0] - x) > 0.001 ||
748 fabs(PenPosition[1] - y) > 0.001)
749 Outputf("%.3f %.3f LI\n", x, y);
750 }
751
752 PenPosition[0] = x;
753 PenPosition[1] = y;
754 }
755
756 if (PenDown)
757 {
758 if (!PolygonMode)
759 Outputf("ST\n");
760 }
761 }
762
763
764 /*
765 * End of "$Id: hpgl-vector.c 6649 2007-07-11 21:46:42Z mike $".
766 */