1 /* Copyright (C) 2009 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: zpdfops.c 10099 2009-09-28 22:07:08Z alexcher $ */
15 /* Custom operators for PDF interpreter */
16 
17 #include "ghost.h"
18 #include "oper.h"
19 #include "igstate.h"
20 #include "istack.h"
21 #include "iutil.h"
22 #include "gspath.h"
23 #include "math_.h"
24 
25 /* Construct a smooth path passing though a number of points  on the stack */
26 /* for PDF ink annotations. The program is based on a very simple method of */
27 /* smoothing polygons by Maxim Shemanarev. */
28 /* http://www.antigrain.com/research/bezier_interpolation/ */
29 /* <mark> <x0> <y0> ... <xn> <yn> .pdfinkpath - */
30 int
zpdfinkpath(i_ctx_t * i_ctx_p)31 zpdfinkpath(i_ctx_t *i_ctx_p)
32 {
33     os_ptr optr, op = osp;
34     uint count = ref_stack_counttomark(&o_stack);
35 
36     uint i, ocount;
37     int code;
38     double x0, y0, x1, y1, x2, y2, x3, y3, xc1, yc1, xc2, yc2, xc3, yc3;
39     double len1, len2, len3, k1, k2, xm1, ym1, xm2, ym2;
40     double ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y;
41     const double smooth_value = 1; /* from 0..1 range */
42 
43     if (count == 0)
44 	return_error(e_unmatchedmark);
45     if ((count & 1) == 0 || count < 3)
46 	return_error(e_rangecheck);
47 
48     ocount = count - 1;
49     optr = op - ocount + 1;
50 
51     if ((code = real_param(optr, &x1)) < 0)
52         return code;
53     if ((code = real_param(optr + 1, &y1)) < 0)
54         return code;
55     if ((code = gs_moveto(igs, x1, y1)) < 0)
56         return code;
57     if (ocount == 2)
58           goto pop;
59 
60     if ((code = real_param(optr + 2, &x2)) < 0)
61         return code;
62     if ((code = real_param(optr + 3, &y2)) < 0)
63         return code;
64     if (ocount == 4) {
65         if((code = gs_lineto(igs, x2, y2)) < 0)
66             return code;
67         goto pop;
68     }
69     x0 = 2*x1 - x2;
70     y0 = 2*y1 - y2;
71 
72     for (i = 4; i <= ocount; i += 2) {
73         if (i < ocount) {
74             if ((code = real_param(optr + i, &x3)) < 0)
75                 return code;
76             if ((code = real_param(optr + i + 1, &y3)) < 0)
77                 return code;
78         } else {
79             x3 = 2*x2 - x1;
80             y3 = 2*y2 - y1;
81         }
82 
83         xc1 = (x0 + x1) / 2.0;
84         yc1 = (y0 + y1) / 2.0;
85         xc2 = (x1 + x2) / 2.0;
86         yc2 = (y1 + y2) / 2.0;
87         xc3 = (x2 + x3) / 2.0;
88         yc3 = (y2 + y3) / 2.0;
89 
90         len1 = hypot(x1 - x0, y1 - y0);
91         len2 = hypot(x2 - x1, y2 - y1);
92         len3 = hypot(x3 - x2, y3 - y2);
93 
94         k1 = len1 / (len1 + len2);
95         k2 = len2 / (len2 + len3);
96 
97         xm1 = xc1 + (xc2 - xc1) * k1;
98         ym1 = yc1 + (yc2 - yc1) * k1;
99 
100         xm2 = xc2 + (xc3 - xc2) * k2;
101         ym2 = yc2 + (yc3 - yc2) * k2;
102 
103         ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;
104         ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1;
105 
106         ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;
107         ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
108 
109         code = gs_curveto(igs, ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, x2, y2);
110         if (code < 0)
111             return code;
112         x0 = x1, x1 = x2, x2 = x3;
113         y0 = y1, y1 = y2, y2 = y3;
114     }
115   pop:
116     ref_stack_pop(&o_stack, count);
117     return 0;
118 }
119 
120 /* ------ Initialization procedure ------ */
121 
122 const op_def zpdfops_op_defs[] =
123 {
124     {"0.pdfinkpath", zpdfinkpath},
125     op_def_end(0)
126 };
127