1/*---------------------------------------------------------------------------*
2 |              PDFlib - A library for generating PDF on the fly             |
3 +---------------------------------------------------------------------------+
4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. |
5 +---------------------------------------------------------------------------+
6 |                                                                           |
7 |    This software is subject to the PDFlib license. It is NOT in the       |
8 |    public domain. Extended versions and commercial licenses are           |
9 |    available, please check http://www.pdflib.com.                         |
10 |                                                                           |
11 *---------------------------------------------------------------------------*/
12
13/* $Id: pc_geom.c 14574 2005-10-29 16:27:43Z bonefish $
14 *
15 * Various geometry routines
16 *
17 */
18
19#include "pc_util.h"
20#include "pc_geom.h"
21
22
23/* ---------------------- matrix functions ----------------------------- */
24
25pdc_bool
26pdc_is_identity_matrix(pdc_matrix *m)
27{
28    return (m->a == (float) 1 &&
29            m->b == (float) 0 &&
30            m->c == (float) 0 &&
31            m->d == (float) 1 &&
32            m->e == (float) 0 &&
33            m->f == (float) 0);
34}
35
36/* translation matrix */
37void
38pdc_translation_matrix(float tx, float ty, pdc_matrix *M)
39{
40    M->a = (float) 1;
41    M->b = (float) 0;
42    M->c = (float) 0;
43    M->d = (float) 1;
44    M->e = tx;
45    M->f = ty;
46}
47
48/* scale matrix */
49void
50pdc_scale_matrix(float sx, float sy, pdc_matrix *M)
51{
52    M->a = sx;
53    M->b = (float) 0;
54    M->c = (float) 0;
55    M->d = sy;
56    M->e = (float) 0;
57    M->f = (float) 0;
58}
59
60/* rotation matrix */
61void
62pdc_rotation_matrix(float alpha, pdc_matrix *M)
63{
64    double phi, c, s;
65
66    phi = (alpha * PDC_M_PI) / 180.0;
67    c = cos(phi);
68    s = sin(phi);
69
70    M->a = (float) c;
71    M->b = (float) s;
72    M->c = (float) -s;
73    M->d = (float) c;
74    M->e = (float) 0;
75    M->f = (float) 0;
76}
77
78/* skew matrix */
79void
80pdc_skew_matrix(float alpha, float beta, pdc_matrix *M)
81{
82    M->a = (float) 1;
83    M->b = (float) tan(alpha * PDC_M_PI / 180.0);
84    M->c = (float) tan(beta * PDC_M_PI / 180.0);
85    M->d = (float) 1;
86    M->e = (float) 0;
87    M->f = (float) 0;
88}
89
90/* left-multiply M to N and store the result in N */
91void
92pdc_multiply_matrix(const pdc_matrix *M, pdc_matrix *N)
93{
94    pdc_matrix result;
95
96    result.a = M->a * N->a + M->b * N->c;
97    result.b = M->a * N->b + M->b * N->d;
98    result.c = M->c * N->a + M->d * N->c;
99    result.d = M->c * N->b + M->d * N->d;
100
101    result.e = M->e * N->a + M->f * N->c + N->e;
102    result.f = M->e * N->b + M->f * N->d + N->f;
103
104    N->a = result.a;
105    N->b = result.b;
106    N->c = result.c;
107    N->d = result.d;
108    N->e = result.e;
109    N->f = result.f;
110}
111
112/* invert M and store the result in N */
113void
114pdc_invert_matrix(pdc_core *pdc, pdc_matrix *N, pdc_matrix *M)
115{
116    float det = M->a * M->d - M->b * M->c;
117
118    if (fabs(det) < (float) PDC_SMALLREAL)
119        pdc_error(pdc, PDC_E_INT_INVMATRIX,
120            pdc_errprintf(pdc, "%f %f %f %f %f %f",
121            M->a, M->b, M->c, M->d, M->e, M->f),
122            0, 0, 0);
123
124    N->a = M->d/det;
125    N->b = -M->b/det;
126    N->c = -M->c/det;
127    N->d = M->a/det;
128    N->e = -(M->e * N->a + M->f * N->c);
129    N->f = -(M->e * N->b + M->f * N->d);
130}
131
132/* transform point */
133void
134pdc_transform_point(const pdc_matrix *M, float x, float y, float *tx, float *ty)
135{
136    *tx = M->a * x + M->c * y + M->e;
137    *ty = M->b * x + M->d * y + M->f;
138}
139
140/* ---------------------- utility functions ----------------------------- */
141
142void
143pdc_place_element(pdc_fitmethod method, pdc_scalar minfscale,
144                  const pdc_box *fitbox, const pdc_vector *relpos,
145                  const pdc_vector *elemsize, pdc_box *elembox,
146                  pdc_vector *scale)
147{
148    pdc_vector refpos;
149    pdc_scalar width, height, det, fscale = 1.0;
150    pdc_bool xscaling = pdc_false;
151
152    /* reference position in fitbox */
153    width = fitbox->ur.x - fitbox->ll.x;
154    height = fitbox->ur.y - fitbox->ll.y;
155    refpos.x = fitbox->ll.x + relpos->x * width;
156    refpos.y = fitbox->ll.y + relpos->y * height;
157
158    /* first check */
159    switch (method)
160    {
161        case pdc_entire:
162        case pdc_slice:
163        case pdc_meet:
164        case pdc_tauto:
165        if (fabs(width) > PDC_FLOAT_PREC && fabs(height) > PDC_FLOAT_PREC)
166        {
167            if (method != pdc_entire)
168            {
169                det = elemsize->x * height - elemsize->y * width;
170                xscaling = (method == pdc_slice && det <= 0) ||
171                            ((method == pdc_meet || method == pdc_tauto) &&
172                             det > 0) ? pdc_true : pdc_false;
173                if (xscaling)
174                    fscale = width / elemsize->x;
175                else
176                    fscale = height / elemsize->y;
177            }
178
179            if (method == pdc_tauto)
180            {
181                if(fscale >= 1.0)
182                {
183                    method = pdc_nofit;
184                }
185                else if (fscale < minfscale)
186                {
187                    method = pdc_meet;
188                }
189            }
190        }
191        else
192        {
193            method = pdc_nofit;
194        }
195        break;
196
197        default:
198        break;
199    }
200
201    /* calculation */
202    switch (method)
203    {
204        /* entire box is covered by entire element */
205        case pdc_entire:
206        *elembox = *fitbox;
207        scale->x = width / elemsize->x;
208        scale->y = height / elemsize->y;
209        return;
210
211        /* fit into and preserve aspect ratio */
212        case pdc_slice:
213        case pdc_meet:
214        if (xscaling)
215            height = fscale * elemsize->y;
216        else
217            width = fscale * elemsize->x;
218        scale->x = fscale;
219        scale->y = fscale;
220        break;
221
222        /* fit into and doesn't preserve aspect ratio */
223        case pdc_tauto:
224        if (xscaling)
225        {
226            height = elemsize->y;
227            scale->x = fscale;
228            scale->y = 1.0;
229        }
230        else
231        {
232            width = elemsize->x;
233            scale->x = 1.0;
234            scale->y = fscale;
235        }
236        break;
237
238        /* only positioning */
239        case pdc_nofit:
240        case pdc_clip:
241        width = elemsize->x;
242        height = elemsize->y;
243        scale->x = 1.0;
244        scale->y = 1.0;
245        break;
246    }
247
248    /* placed element box */
249    elembox->ll.x = refpos.x - relpos->x * width;
250    elembox->ll.y = refpos.y - relpos->y * height;
251    elembox->ur.x = refpos.x + (1.0 - relpos->x) * width;
252    elembox->ur.y = refpos.y + (1.0 - relpos->y) * height;
253}
254
255void
256pdc_box2polyline(const pdc_box *box, pdc_vector *polyline)
257{
258    /* counter clockwise */
259    polyline[0].x = box->ll.x;
260    polyline[0].y = box->ll.y;
261    polyline[1].x = box->ur.x;
262    polyline[1].y = box->ll.y;
263    polyline[2].x = box->ur.x;
264    polyline[2].y = box->ur.y;
265    polyline[3].x = box->ll.x;
266    polyline[3].y = box->ur.y;
267    polyline[4] = polyline[0];
268}
269
270/* --------------------------- rectangles  --------------------------- */
271pdc_bool
272pdc_rect_isnull(pdc_rectangle *r)
273{
274    return
275        (r->llx == (float) 0 && r->lly == (float) 0 &&
276         r->urx == (float) 0 && r->ury == (float) 0);
277}
278
279pdc_bool
280pdc_rect_contains(pdc_rectangle *r1, pdc_rectangle *r2)
281{
282    return
283        (r1->llx <= r2->llx && r1->lly <= r2->lly &&
284         r1->urx >= r2->urx && r1->ury >= r2->ury);
285}
286
287void
288pdc_rect_copy(pdc_rectangle *r1, pdc_rectangle *r2)
289{
290    r1->llx = r2->llx;
291    r1->lly = r2->lly;
292    r1->urx = r2->urx;
293    r1->ury = r2->ury;
294}
295
296void
297pdc_rect_init(pdc_rectangle *r, float llx, float lly, float urx, float ury)
298{
299    r->llx = llx;
300    r->lly = lly;
301    r->urx = urx;
302    r->ury = ury;
303}
304
305void
306pdc_rect_transform(const pdc_matrix *M, pdc_rectangle *r1, pdc_rectangle *r2)
307{
308    float x[4], y[4];
309    int i;
310
311    pdc_transform_point(M, r1->llx, r1->lly, &x[0], &y[0]);
312    pdc_transform_point(M, r1->llx, r1->ury, &x[1], &y[1]);
313    pdc_transform_point(M, r1->urx, r1->ury, &x[2], &y[2]);
314    pdc_transform_point(M, r1->urx, r1->lly, &x[3], &y[3]);
315
316    pdc_rect_init(r2, (float) PDC_FLOAT_MAX, (float) PDC_FLOAT_MAX,
317                      (float) PDC_FLOAT_MIN, (float) PDC_FLOAT_MIN);
318
319    for (i = 0; i < 4; i++)
320    {
321        if (x[i] < r2->llx)
322            r2->llx = x[i];
323        if (y[i] < r2->lly)
324            r2->lly = y[i];
325
326        if (x[i] > r2->urx)
327            r2->urx = x[i];
328        if (y[i] > r2->ury)
329            r2->ury = y[i];
330    }
331}
332
333