386BSD 0.1 development
[unix-history] / usr / othersrc / public / ghostscript-2.4.1 / gscoord.c
CommitLineData
6c6cb4be
WJ
1/* Copyright (C) 1989, 1992 Aladdin Enterprises. All rights reserved.
2 Distributed by Free Software Foundation, Inc.
3
4This file is part of Ghostscript.
5
6Ghostscript is distributed in the hope that it will be useful, but
7WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
8to anyone for the consequences of using it or for whether it serves any
9particular purpose or works at all, unless he says so in writing. Refer
10to the Ghostscript General Public License for full details.
11
12Everyone is granted permission to copy, modify and redistribute
13Ghostscript, but only under the conditions described in the Ghostscript
14General Public License. A copy of this license is supposed to have been
15given to you along with Ghostscript so you can know your rights and
16responsibilities. It should be in a file named COPYING. Among other
17things, the copyright notice and this notice must be preserved on all
18copies. */
19
20/* gscoord.c */
21/* Coordinate system operators for Ghostscript library */
22#include "math_.h"
23#include "gx.h"
24#include "gserrors.h"
25#include "gxarith.h"
26#include "gxfixed.h"
27#include "gxmatrix.h"
28#include "gzstate.h"
29#include "gzdevice.h" /* requires gsstate */
30#include "gscoord.h" /* requires gsmatrix, gsstate */
31
32/* Choose whether to enable the new rounding code in update_ctm_fixed. */
33/* I'm pretty sure this is the right thing to do, but since this change */
34/* is being made 1 day before releasing version 2.4, I'm feeling cautious. */
35#define round_ctm_fixed 1
36
37/* Forward declarations */
38#ifdef DEBUG
39private void trace_ctm(P1(const gs_state *));
40private void trace_matrix(P1(const gs_matrix *));
41#endif
42
43/* Macro for ensuring ctm_inverse is valid */
44#ifdef DEBUG
45#define print_inverse(pgs)\
46if ( gs_debug['x'] )\
47 dprintf("[x]Inverting:\n"), trace_ctm(pgs), trace_matrix(&pgs->ctm_inverse)
48#else
49#define print_inverse(pgs) 0
50#endif
51#define ensure_inverse_valid(pgs)\
52 if ( !pgs->inverse_valid )\
53 { int code = ctm_set_inverse(pgs);\
54 if ( code < 0 ) return code;\
55 }
56
57private int
58ctm_set_inverse(gs_state *pgs)
59{ int code = gs_matrix_invert(&ctm_only(pgs), &pgs->ctm_inverse);
60 print_inverse(pgs);
61 if ( code < 0 ) return code;
62 pgs->inverse_valid = 1;
63 return 0;
64}
65
66/* Machinery for updating fixed version of ctm. */
67/*
68 * We (conditionally) adjust the floating point translation
69 * so that it exactly matches the (rounded) fixed translation.
70 * This avoids certain unpleasant rounding anomalies, such as
71 * 0 0 moveto currentpoint not returning 0 0, and () stringwidth
72 * not returning 0 0.
73 */
74#if round_ctm_fixed /* ****** NOTA BENE ****** */
75# define update_t_fixed(mat, t, t_fixed)\
76 (mat).t = fixed2float((mat).t_fixed = float2fixed((mat).t))
77#else /* !round_update_fixed */
78# define update_t_fixed(mat, t, t_fixed)\
79 (mat).t_fixed = float2fixed((mat).t)
80#endif /* (!)round_update_fixed */
81#define update_matrix_fixed(mat)\
82 update_t_fixed(mat, tx, tx_fixed),\
83 update_t_fixed(mat, ty, ty_fixed)
84#define update_ctm(pgs)\
85 update_matrix_fixed(pgs->ctm),\
86 pgs->inverse_valid = 0,\
87 pgs->char_tm_valid = 0
88
89void
90gs_update_matrix_fixed(gs_matrix_fixed *pmat)
91{ update_matrix_fixed(*pmat);
92}
93
94/* ------ Coordinate system definition ------ */
95
96int
97gs_initmatrix(gs_state *pgs)
98{ gx_device *dev = pgs->device->info;
99 (*dev->procs->get_initial_matrix)(dev, &ctm_only(pgs));
100 update_ctm(pgs);
101#ifdef DEBUG
102if ( gs_debug['x'] )
103 dprintf("[x]initmatrix:\n"), trace_ctm(pgs);
104#endif
105 return 0;
106}
107
108int
109gs_defaultmatrix(const gs_state *pgs, gs_matrix *pmat)
110{ gx_device *dev = pgs->device->info;
111 (*dev->procs->get_initial_matrix)(dev, pmat);
112 return 0;
113}
114
115int
116gs_currentmatrix(const gs_state *pgs, gs_matrix *pmat)
117{ *pmat = ctm_only(pgs);
118 return 0;
119}
120
121int
122gs_setmatrix(gs_state *pgs, const gs_matrix *pmat)
123{ ctm_only(pgs) = *pmat;
124 update_ctm(pgs);
125#ifdef DEBUG
126if ( gs_debug['x'] )
127 dprintf("[x]setmatrix:\n"), trace_ctm(pgs);
128#endif
129 return 0;
130}
131
132int
133gs_translate(gs_state *pgs, floatp dx, floatp dy)
134{ gs_point pt;
135 int code;
136 if ( (code = gs_distance_transform(dx, dy, &ctm_only(pgs), &pt)) < 0 )
137 return code;
138 pgs->ctm.tx += pt.x;
139 pgs->ctm.ty += pt.y;
140 update_ctm(pgs);
141#ifdef DEBUG
142if ( gs_debug['x'] )
143 dprintf4("[x]translate: %f %f -> %f %f\n",
144 dx, dy, pt.x, pt.y),
145 trace_ctm(pgs);
146#endif
147 return 0;
148}
149
150int
151gs_scale(gs_state *pgs, floatp sx, floatp sy)
152{ pgs->ctm.xx *= sx;
153 pgs->ctm.xy *= sx;
154 pgs->ctm.yx *= sy;
155 pgs->ctm.yy *= sy;
156 pgs->inverse_valid = 0, pgs->char_tm_valid = 0;
157#ifdef DEBUG
158if ( gs_debug['x'] )
159 dprintf2("[x]scale: %f %f\n", sx, sy), trace_ctm(pgs);
160#endif
161 return 0;
162}
163
164int
165gs_rotate(gs_state *pgs, floatp ang)
166{ int code = gs_matrix_rotate(&ctm_only(pgs), ang, &ctm_only(pgs));
167 pgs->inverse_valid = 0, pgs->char_tm_valid = 0;
168#ifdef DEBUG
169if ( gs_debug['x'] )
170 dprintf1("[x]rotate: %f\n", ang), trace_ctm(pgs);
171#endif
172 return code;
173}
174
175int
176gs_concat(gs_state *pgs, const gs_matrix *pmat)
177{ int code = gs_matrix_multiply(pmat, &ctm_only(pgs), &ctm_only(pgs));
178 update_ctm(pgs);
179#ifdef DEBUG
180if ( gs_debug['x'] )
181 dprintf("[x]concat:\n"), trace_matrix(pmat), trace_ctm(pgs);
182#endif
183 return code;
184}
185
186/* ------ Coordinate transformation ------ */
187
188int
189gs_transform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
190{ return gs_point_transform(x, y, &ctm_only(pgs), pt);
191}
192
193int
194gs_dtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
195{ return gs_distance_transform(dx, dy, &ctm_only(pgs), pt);
196}
197
198int
199gs_itransform(gs_state *pgs, floatp x, floatp y, gs_point *pt)
200{ /* If the matrix isn't skewed, we get more accurate results */
201 /* by using transform_inverse than by using the inverse matrix. */
202 if ( !is_skewed(&pgs->ctm) )
203 { return gs_point_transform_inverse(x, y, &ctm_only(pgs), pt);
204 }
205 else
206 { ensure_inverse_valid(pgs);
207 return gs_point_transform(x, y, &pgs->ctm_inverse, pt);
208 }
209}
210
211int
212gs_idtransform(gs_state *pgs, floatp dx, floatp dy, gs_point *pt)
213{ /* If the matrix isn't skewed, we get more accurate results */
214 /* by using transform_inverse than by using the inverse matrix. */
215 if ( !is_skewed(&pgs->ctm) )
216 { return gs_distance_transform_inverse(dx, dy,
217 &ctm_only(pgs), pt);
218 }
219 else
220 { ensure_inverse_valid(pgs);
221 return gs_distance_transform(dx, dy, &pgs->ctm_inverse, pt);
222 }
223}
224
225/* ------ For internal use only ------ */
226
227/* Set the translation to a fixed value, */
228/* and mark char_tm as valid. */
229/* Used by gschar.c to prepare for a BuildChar procedure. */
230int
231gs_translate_to_fixed(register gs_state *pgs, fixed px, fixed py)
232{ pgs->ctm.tx = fixed2float(pgs->ctm.tx_fixed = px);
233 pgs->ctm.ty = fixed2float(pgs->ctm.ty_fixed = py);
234 pgs->inverse_valid = 0;
235 pgs->char_tm_valid = 1;
236 return 0;
237}
238
239/* Compute the coefficients for fast fixed-point distance transformations */
240/* from a transformation matrix. */
241/* We should cache the coefficients with the ctm.... */
242int
243gx_matrix_to_fixed_coeff(const gs_matrix *pmat, register fixed_coeff *pfc,
244 int max_bits)
245{ gs_matrix ctm;
246 int scale = -10000;
247 int expt, shift;
248 ctm = *pmat;
249 pfc->skewed = 0;
250 if ( !is_fzero(ctm.xx) )
251 { (void)frexp(ctm.xx, &scale);
252 }
253 if ( !is_fzero(ctm.xy) )
254 { (void)frexp(ctm.xy, &expt);
255 if ( expt > scale ) scale = expt;
256 pfc->skewed = 1;
257 }
258 if ( !is_fzero(ctm.yx) )
259 { (void)frexp(ctm.yx, &expt);
260 if ( expt > scale ) scale = expt;
261 pfc->skewed = 1;
262 }
263 if ( !is_fzero(ctm.yy) )
264 { (void)frexp(ctm.yy, &expt);
265 if ( expt > scale ) scale = expt;
266 }
267 scale = sizeof(long) * 8 - 1 - max_bits - scale;
268 shift = scale - _fixed_shift;
269 if ( shift > 0 )
270 { pfc->shift = shift;
271 pfc->round = (fixed)1 << (shift - 1);
272 }
273 else
274 { pfc->shift = 0;
275 pfc->round = 0;
276 scale -= shift;
277 }
278 pfc->xx = (is_fzero(ctm.xx) ? 0 : (long)ldexp(ctm.xx, scale));
279 pfc->yy = (is_fzero(ctm.yy) ? 0 : (long)ldexp(ctm.yy, scale));
280 if ( pfc->skewed )
281 { pfc->xy = (is_fzero(ctm.xy) ? 0 : (long)ldexp(ctm.xy, scale));
282 pfc->yx = (is_fzero(ctm.yx) ? 0 : (long)ldexp(ctm.yx, scale));
283 }
284 else
285 pfc->xy = pfc->yx = 0;
286#ifdef DEBUG
287if ( gs_debug['x'] )
288 { dprintf7("[x]ctm: [%6g %6g %6g %6g ; %6g %6g] scale=%d\n",
289 ctm.xx, ctm.xy, ctm.yx, ctm.yy, ctm.tx, ctm.ty, scale);
290 dprintf5(" fc: [%lx %lx %lx %lx] shift=%d\n",
291 pfc->xx, pfc->xy, pfc->yx, pfc->yy,
292 pfc->shift);
293 }
294#endif
295 pfc->max_bits = max_bits;
296 return 0;
297}
298
299/* ------ Debugging printout ------ */
300
301#ifdef DEBUG
302
303/* Print a matrix */
304private void
305trace_ctm(const gs_state *pgs)
306{ const gs_matrix_fixed *pmat = &pgs->ctm;
307 trace_matrix((gs_matrix *)pmat);
308 dprintf2("\t\tt_fixed: [%6g %6g]\n",
309 fixed2float(pmat->tx_fixed), fixed2float(pmat->ty_fixed));
310}
311private void
312trace_matrix(register const gs_matrix *pmat)
313{ dprintf6("\t[%6g %6g %6g %6g %6g %6g]\n",
314 pmat->xx, pmat->xy, pmat->yx, pmat->yy, pmat->tx, pmat->ty);
315}
316
317#endif