1 #ifndef __NR_MATRIX_H__
2 #define __NR_MATRIX_H__
4 /** \file
5 * Definition of NRMatrix and NR::Matrix types.
6 *
7 * \note Operator functions (e.g. Matrix * Matrix etc.) are mostly in
8 * libnr/nr-matrix-ops.h. See end of file for discussion.
9 *
10 * Main authors:
11 * Lauris Kaplinski <lauris@kaplinski.com>:
12 * Original NRMatrix definition and related macros.
13 *
14 * Nathan Hurst <njh@mail.csse.monash.edu.au>:
15 * NR::Matrix class version of the above.
16 *
17 * This code is in public domain.
18 */
20 #include <glib/gtestutils.h>
21 #include <glib/gmessages.h>
23 #include "libnr/nr-coord.h"
24 #include "libnr/nr-values.h"
25 #include <libnr/nr-rotate.h>
26 #include <libnr/nr-scale.h>
27 #include <libnr/nr-translate.h>
29 /// NRMatrix is the obsolete form of NR::Matrix.
30 /// It consists of six NR::Coord values.
31 struct NRMatrix {
32 NR::Coord c[6];
34 NR::Coord &operator[](int i) { return c[i]; }
35 NR::Coord operator[](int i) const { return c[i]; }
36 };
38 #define nr_matrix_set_identity(m) (*(m) = NR_MATRIX_IDENTITY)
40 #define nr_matrix_test_identity(m,e) (!(m) || NR_MATRIX_DF_TEST_CLOSE(m, &NR_MATRIX_IDENTITY, e))
42 #define nr_matrix_test_equal(m0,m1,e) ((!(m0) && !(m1)) || ((m0) && (m1) && NR_MATRIX_DF_TEST_CLOSE(m0, m1, e)))
43 #define nr_matrix_test_transform_equal(m0,m1,e) ((!(m0) && !(m1)) || ((m0) && (m1) && NR_MATRIX_DF_TEST_TRANSFORM_CLOSE(m0, m1, e)))
44 #define nr_matrix_test_translate_equal(m0,m1,e) ((!(m0) && !(m1)) || ((m0) && (m1) && NR_MATRIX_DF_TEST_TRANSLATE_CLOSE(m0, m1, e)))
46 NRMatrix *nr_matrix_invert(NRMatrix *d, NRMatrix const *m);
48 /* d,m0,m1 needn't be distinct in any of these multiply routines. */
50 NRMatrix *nr_matrix_multiply(NRMatrix *d, NRMatrix const *m0, NRMatrix const *m1);
52 NRMatrix *nr_matrix_set_translate(NRMatrix *m, NR::Coord const x, NR::Coord const y);
54 NRMatrix *nr_matrix_set_scale(NRMatrix *m, NR::Coord const sx, NR::Coord const sy);
56 NRMatrix *nr_matrix_set_rotate(NRMatrix *m, NR::Coord const theta);
58 #define NR_MATRIX_DF_TRANSFORM_X(m,x,y) ((*(m))[0] * (x) + (*(m))[2] * (y) + (*(m))[4])
59 #define NR_MATRIX_DF_TRANSFORM_Y(m,x,y) ((*(m))[1] * (x) + (*(m))[3] * (y) + (*(m))[5])
61 #define NR_MATRIX_DF_EXPANSION2(m) (fabs((*(m))[0] * (*(m))[3] - (*(m))[1] * (*(m))[2]))
62 #define NR_MATRIX_DF_EXPANSION(m) (sqrt(NR_MATRIX_DF_EXPANSION2(m)))
64 namespace NR {
66 /**
67 * The Matrix class.
68 *
69 * For purposes of multiplication, points should be thought of as row vectors
70 *
71 * p = ( p[X] p[Y] 1 )
72 *
73 * to be right-multiplied by transformation matrices
74 * \verbatim
75 c[] = | c[0] c[1] 0 |
76 | c[2] c[3] 0 |
77 | c[4] c[5] 1 | \endverbatim
78 *
79 * (so the columns of the matrix correspond to the columns (elements) of the result,
80 * and the rows of the matrix correspond to columns (elements) of the "input").
81 */
82 class Matrix {
85 public:
87 /**
88 * Various forms of constructor
89 */
91 /**
92 *
93 */
94 explicit Matrix() { }
97 /**
98 *
99 */
100 Matrix(Matrix const &m) {
102 NR::Coord const *src = m._c;
103 NR::Coord *dest = _c;
105 *dest++ = *src++; //0
106 *dest++ = *src++; //1
107 *dest++ = *src++; //2
108 *dest++ = *src++; //3
109 *dest++ = *src++; //4
110 *dest = *src ; //5
112 }
117 /**
118 *
119 */
120 Matrix(NRMatrix const &m) {
122 NR::Coord const *src = m.c;
123 NR::Coord *dest = _c;
125 *dest++ = *src++; //0
126 *dest++ = *src++; //1
127 *dest++ = *src++; //2
128 *dest++ = *src++; //3
129 *dest++ = *src++; //4
130 *dest = *src ; //5
132 }
137 /**
138 *
139 */
140 Matrix(double c0, double c1,
141 double c2, double c3,
142 double c4, double c5) {
144 NR::Coord *dest = _c;
146 *dest++ = c0; //0
147 *dest++ = c1; //1
148 *dest++ = c2; //2
149 *dest++ = c3; //3
150 *dest++ = c4; //4
151 *dest = c5; //5
153 }
157 /**
158 *
159 */
160 Matrix &operator=(Matrix const &m) {
162 NR::Coord const *src = m._c;
163 NR::Coord *dest = _c;
165 *dest++ = *src++; //0
166 *dest++ = *src++; //1
167 *dest++ = *src++; //2
168 *dest++ = *src++; //3
169 *dest++ = *src++; //4
170 *dest = *src ; //5
172 return *this;
173 }
178 /**
179 *
180 */
181 explicit Matrix(scale const &sm) {
183 NR::Coord *dest = _c;
185 *dest++ = sm[X]; //0
186 *dest++ = 0.0; //1
187 *dest++ = 0.0; //2
188 *dest++ = sm[Y]; //3
189 *dest++ = 0.0; //4
190 *dest = 0.0; //5
192 }
199 /**
200 *
201 */
202 explicit Matrix(rotate const &r) {
204 NR::Coord *dest = _c;
206 *dest++ = r.vec[X]; //0
207 *dest++ = r.vec[Y]; //1
208 *dest++ = -r.vec[Y]; //2
209 *dest++ = r.vec[X]; //3
210 *dest++ = 0.0; //4
211 *dest = 0.0; //5
213 }
218 /**
219 *
220 */
221 explicit Matrix(translate const &tm) {
223 NR::Coord *dest = _c;
225 *dest++ = 1.0; //0
226 *dest++ = 0.0; //1
227 *dest++ = 0.0; //2
228 *dest++ = 1.0; //3
229 *dest++ = tm[X]; //4
230 *dest = tm[Y]; //5
231 }
235 /**
236 *
237 */
238 Matrix(NRMatrix const *nr);
241 /**
242 *
243 */
244 bool test_identity() const;
247 /**
248 *
249 */
250 bool is_translation(Coord const eps = 1e-6) const;
252 /**
253 *
254 */
255 bool is_scale(Coord const eps = 1e-6) const;
257 /**
258 *
259 */
260 bool is_rotation(Coord const eps = 1e-6) const;
263 /**
264 *
265 */
266 Matrix inverse() const;
269 /**
270 *
271 */
272 Matrix &operator*=(Matrix const &other);
275 /**
276 *
277 */
278 Matrix &operator*=(scale const &other);
282 /**
283 *
284 */
285 Matrix &operator*=(translate const &other) {
286 _c[4] += other[X];
287 _c[5] += other[Y];
288 return *this;
289 }
293 /**
294 *
295 */
296 inline Coord &operator[](int const i) {
297 return _c[i];
298 }
302 /**
303 *
304 */
305 inline Coord operator[](int const i) const {
306 return _c[i];
307 }
310 /**
311 *
312 */
313 void set_identity();
315 /**
316 *
317 */
318 Coord det() const;
321 /**
322 *
323 */
324 Coord descrim2() const;
327 /**
328 *
329 */
330 Coord descrim() const;
333 /**
334 *
335 */
336 double expansion() const;
339 /**
340 *
341 */
342 double expansionX() const;
345 /**
346 *
347 */
348 double expansionY() const;
350 // legacy
353 /**
354 *
355 */
356 Matrix &assign(Coord const *array);
359 /**
360 *
361 */
362 NRMatrix *copyto(NRMatrix* nrm) const;
365 /**
366 *
367 */
368 Coord *copyto(Coord *array) const;
372 /**
373 *
374 */
375 operator NRMatrix&() {
376 g_assert(sizeof(_c) == sizeof(NRMatrix));
377 return *reinterpret_cast<NRMatrix *>(_c);
378 }
382 /**
383 *
384 */
385 operator NRMatrix const&() const {
386 g_assert(sizeof(_c) == sizeof(NRMatrix));
387 return *reinterpret_cast<const NRMatrix *>(_c);
388 }
392 /**
393 *
394 */
395 operator NRMatrix*() {
396 g_assert(sizeof(_c) == sizeof(NRMatrix));
397 return reinterpret_cast<NRMatrix *>(_c);
398 }
401 /**
402 *
403 */
404 operator NRMatrix const*() const {
405 g_assert(sizeof(_c) == sizeof(NRMatrix));
406 return reinterpret_cast<NRMatrix const *>(_c);
407 }
410 private:
413 NR::Coord _c[6];
414 };
416 /** A function to print out the Matrix (for debugging) */
417 inline std::ostream &operator<< (std::ostream &out_file, const NR::Matrix &m) {
418 out_file << "A: " << m[0] << " C: " << m[2] << " E: " << m[4] << "\n";
419 out_file << "B: " << m[1] << " D: " << m[3] << " F: " << m[5] << "\n";
420 return out_file;
421 }
423 extern void assert_close(Matrix const &a, Matrix const &b);
425 } /* namespace NR */
433 /** \note
434 * Discussion of splitting up nr-matrix.h into lots of little files:
435 *
436 * Advantages:
437 *
438 * - Reducing amount of recompilation necessary when anything changes.
439 *
440 * - Hopefully also reducing compilation time by reducing the number of inline
441 * function definitions encountered by the compiler for a given .o file.
442 * (No timing comparisons done yet. On systems without much memory available
443 * for caching, this may be outweighed by additional I/O costs.)
444 *
445 * Disadvantages:
446 *
447 * - More #include lines necessary per file. If a compile fails due to
448 * not having all the necessary #include lines, then the developer needs
449 * to spend some time working out what #include to add.
450 */
452 #endif /* !__NR_MATRIX_H__ */
455 /*
456 Local Variables:
457 mode:c++
458 c-file-style:"stroustrup"
459 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
460 indent-tabs-mode:nil
461 fill-column:99
462 End:
463 */
464 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :