1/***********************************************************************
2 *                                                                     *
3 * $Id: hpgsmatrix.c 298 2006-03-05 18:18:03Z softadm $
4 *                                                                     *
5 * hpgs - HPGl Script, a hpgl/2 interpreter, which uses a Postscript   *
6 *        API for rendering a scene and thus renders to a variety of   *
7 *        devices and fileformats.                                     *
8 *                                                                     *
9 * (C) 2004-2006 ev-i Informationstechnologie GmbH  http://www.ev-i.at *
10 *                                                                     *
11 * Author: Wolfgang Glas                                               *
12 *                                                                     *
13 *  hpgs is free software; you can redistribute it and/or              *
14 * modify it under the terms of the GNU Lesser General Public          *
15 * License as published by the Free Software Foundation; either        *
16 * version 2.1 of the License, or (at your option) any later version.  *
17 *                                                                     *
18 * hpgs is distributed in the hope that it will be useful,             *
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of      *
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   *
21 * Lesser General Public License for more details.                     *
22 *                                                                     *
23 * You should have received a copy of the GNU Lesser General Public    *
24 * License along with this library; if not, write to the               *
25 * Free Software  Foundation, Inc., 59 Temple Place, Suite 330,        *
26 * Boston, MA  02111-1307  USA                                         *
27 *                                                                     *
28 ***********************************************************************
29 *                                                                     *
30 * The implementation of the public API for transformation matrices.   *
31 *                                                                     *
32 ***********************************************************************/
33
34#include<hpgs.h>
35
36/*!
37   Sets the given matrix to the identity matrix.
38 */
39void hpgs_matrix_set_identity(hpgs_matrix *m)
40{
41  m->myx = m->mxy = m->dy = m->dx = 0.0;
42  m->myy = m->mxx = 1.0;
43}
44
45/*!
46   Transforms the given point \c p with the matrix \c m.
47   The result is stored in \c res.
48   The pointers \c p and \c res may point to the same memory location.
49 */
50void hpgs_matrix_xform(hpgs_point *res,
51                       const hpgs_matrix *m, const hpgs_point *p)
52{
53  double x = m->dx + m->mxx * p->x + m->mxy * p->y;
54  double y = m->dy + m->myx * p->x + m->myy * p->y;
55  res->x = x;
56  res->y = y;
57}
58
59/*!
60   Transforms the given point \c p with the inverse of the matrix \c m.
61   The result is stored in \c res.
62   The pointers \c p and \c res may point to the same memory location.
63 */
64void hpgs_matrix_ixform(hpgs_point *res,
65                        const hpgs_point *p, const hpgs_matrix *m)
66{
67  double x0 = (p->x - m->dx);
68  double y0 = (p->y - m->dy);
69
70  double det = m->mxx * m->myy - m->mxy * m->myx;
71
72  res->x = (m->myy * x0 - m->mxy * y0)/det;
73  res->y = (m->mxx * y0 - m->myx * x0)/det;
74}
75
76/*!
77   Transforms the given bounding box \c bb with the matrix \c m.
78   The result is the enclosing bounding box of the transformed
79   rectangle of the bounding box and is stored in \c res.
80   The pointers \c bb and \c res may point to the same memory location.
81 */
82void hpgs_matrix_xform_bbox(hpgs_bbox *res,
83                            const hpgs_matrix *m, const hpgs_bbox *bb)
84{
85  hpgs_point ll = { bb->llx, bb->lly };
86  hpgs_point ur = { bb->urx, bb->ury };
87
88  hpgs_point lr = { bb->llx, bb->ury };
89  hpgs_point ul = { bb->urx, bb->lly };
90
91  hpgs_matrix_xform(&ll,m,&ll);
92  hpgs_matrix_xform(&ur,m,&ur);
93
94  hpgs_matrix_xform(&lr,m,&lr);
95  hpgs_matrix_xform(&ul,m,&ul);
96
97  res->llx = HPGS_MIN(HPGS_MIN(ll.x,ur.x),HPGS_MIN(lr.x,ul.x));
98  res->lly = HPGS_MIN(HPGS_MIN(ll.y,ur.y),HPGS_MIN(lr.y,ul.y));
99
100  res->urx = HPGS_MAX(HPGS_MAX(ll.x,ur.x),HPGS_MAX(lr.x,ul.x));
101  res->ury = HPGS_MAX(HPGS_MAX(ll.y,ur.y),HPGS_MAX(lr.y,ul.y));
102}
103
104/*!
105   Transforms the given bounding box \c bb with the the inverse of
106   the matrix \c m.
107   The result is the enclosing bounding box of the transformed
108   rectangle of the bounding box and is stored in \c res.
109   The pointers \c bb and \c res may point to the same memory location.
110 */
111void hpgs_matrix_ixform_bbox(hpgs_bbox *res,
112                             const hpgs_bbox *bb, const hpgs_matrix *m)
113{
114  hpgs_point ll = { bb->llx, bb->lly };
115  hpgs_point ur = { bb->urx, bb->ury };
116
117  hpgs_point lr = { bb->llx, bb->ury };
118  hpgs_point ul = { bb->urx, bb->lly };
119
120  hpgs_matrix_ixform(&ll,&ll,m);
121  hpgs_matrix_ixform(&ur,&ur,m);
122
123  hpgs_matrix_ixform(&lr,&lr,m);
124  hpgs_matrix_ixform(&ul,&ul,m);
125
126  res->llx = HPGS_MIN(HPGS_MIN(ll.x,ur.x),HPGS_MIN(lr.x,ul.x));
127  res->lly = HPGS_MIN(HPGS_MIN(ll.y,ur.y),HPGS_MIN(lr.y,ul.y));
128
129  res->urx = HPGS_MAX(HPGS_MAX(ll.x,ur.x),HPGS_MAX(lr.x,ul.x));
130  res->ury = HPGS_MAX(HPGS_MAX(ll.y,ur.y),HPGS_MAX(lr.y,ul.y));
131}
132
133/*!
134   Transforms the given point \c p with the matrix \c m without
135   applying the translation part of \c m. This is useful in order
136   to transform delta vectors.
137
138   The result is stored in \c res.
139   The pointers \c p and \c res may point to the same memory location.
140 */
141void hpgs_matrix_scale(hpgs_point *res,
142                       const hpgs_matrix *m, const hpgs_point *p)
143{
144  double x = m->mxx * p->x + m->mxy * p->y;
145  double y = m->myx * p->x + m->myy * p->y;
146  res->x = x;
147  res->y = y;
148}
149
150/*!
151   Transforms the given point \c p with the inverse of the matrix \c m
152   without applying the translation part of \c m. This is useful in order
153   to transform delta vectors.
154
155   The result is stored in \c res.
156   The pointers \c p and \c res may point to the same memory location.
157 */
158void hpgs_matrix_iscale(hpgs_point *res,
159                        const hpgs_point *p, const hpgs_matrix *m)
160{
161  double x0 = p->x;
162  double y0 = p->y;
163
164  double det = m->mxx * m->myy - m->mxy * m->myx;
165
166  res->x = (m->myy * x0 - m->mxy * y0)/det;
167  res->y = (m->mxx * y0 - m->myx * x0)/det;
168}
169
170/*!
171   Concatenates the given matrices \c a and \c b.
172   The result is stored in \c res.
173   Either of the pointer \c a or \b may point to the same memory location as
174   the pointer \c res.
175 */
176void hpgs_matrix_concat(hpgs_matrix *res,
177                        const hpgs_matrix *a, const hpgs_matrix *b)
178{
179  //
180  // |  1   0   0 |   |  1   0   0 |   |                1               0               0 |
181  // | dx mxx mxy | x | Dx Mxx Mxy | = | dx+Dx*mxx+Dy*mxy mxx*Mxx+mxy*Myx mxx*Mxy+mxy*Myy |
182  // | dy myx myy |   | Dy Myx Myy |   | dy+Dx*myx+Dy*myy myx*Mxx+myy*Myx myx*Mxy+myy*Myy |
183  //
184  double r0,r1,r2,r3;
185
186  r0 = a->dx+b->dx*a->mxx+b->dy*a->mxy;
187  r1 = a->dy+b->dx*a->myx+b->dy*a->myy;
188
189  res->dx = r0;
190  res->dy = r1;
191
192  r0 = a->mxx*b->mxx+a->mxy*b->myx;
193  r1 = a->mxx*b->mxy+a->mxy*b->myy;
194  r2 = a->myx*b->mxx+a->myy*b->myx;
195  r3 = a->myx*b->mxy+a->myy*b->myy;
196
197  res->mxx = r0;
198  res->mxy = r1;
199  res->myx = r2;
200  res->myy = r3;
201}
202
203/*!
204   Inverts the given matrix \c m.
205   The result is stored in \c res.
206   The pointers \c m and \c res may point to the same memory location.
207 */
208void hpgs_matrix_invert(hpgs_matrix *res, const hpgs_matrix *m)
209{
210  double det = m->mxx * m->myy - m->mxy * m->myx;
211
212  double tmp = m->mxx/det;
213  res->mxx = m->myy/det;
214  res->myy = tmp;
215
216  res->mxy = -m->mxy/det;
217  res->myx = -m->myx/det;
218
219  double x0 = -m->dx;
220  double y0 = -m->dy;
221  res->dx = x0 * res->mxx + y0 * res->mxy;
222  res->dy = x0 * res->myx + y0 * res->myy;
223}
224