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/gmessages.h>
22 #include "libnr/nr-coord.h"
23 #include "libnr/nr-values.h"
24 #include <libnr/nr-rotate.h>
25 #include <libnr/nr-scale.h>
26 #include <libnr/nr-translate.h>
28 /// NRMatrix is the obsolete form of NR::Matrix.
29 /// It consists of six NR::Coord values.
30 struct NRMatrix {
31 NR::Coord c[6];
33 NR::Coord &operator[](int i) { return c[i]; }
34 NR::Coord operator[](int i) const { return c[i]; }
35 };
37 #define nr_matrix_set_identity(m) (*(m) = NR_MATRIX_IDENTITY)
39 #define nr_matrix_test_identity(m,e) (!(m) || NR_MATRIX_DF_TEST_CLOSE(m, &NR_MATRIX_IDENTITY, e))
41 #define nr_matrix_test_equal(m0,m1,e) ((!(m0) && !(m1)) || ((m0) && (m1) && NR_MATRIX_DF_TEST_CLOSE(m0, m1, e)))
42 #define nr_matrix_test_transform_equal(m0,m1,e) ((!(m0) && !(m1)) || ((m0) && (m1) && NR_MATRIX_DF_TEST_TRANSFORM_CLOSE(m0, m1, e)))
43 #define nr_matrix_test_translate_equal(m0,m1,e) ((!(m0) && !(m1)) || ((m0) && (m1) && NR_MATRIX_DF_TEST_TRANSLATE_CLOSE(m0, m1, e)))
45 NRMatrix *nr_matrix_invert(NRMatrix *d, NRMatrix const *m);
47 /* d,m0,m1 needn't be distinct in any of these multiply routines. */
49 NRMatrix *nr_matrix_multiply(NRMatrix *d, NRMatrix const *m0, NRMatrix const *m1);
51 NRMatrix *nr_matrix_set_translate(NRMatrix *m, NR::Coord const x, NR::Coord const y);
53 NRMatrix *nr_matrix_set_scale(NRMatrix *m, NR::Coord const sx, NR::Coord const sy);
55 NRMatrix *nr_matrix_set_rotate(NRMatrix *m, NR::Coord const theta);
57 #define NR_MATRIX_DF_TRANSFORM_X(m,x,y) ((*(m))[0] * (x) + (*(m))[2] * (y) + (*(m))[4])
58 #define NR_MATRIX_DF_TRANSFORM_Y(m,x,y) ((*(m))[1] * (x) + (*(m))[3] * (y) + (*(m))[5])
60 #define NR_MATRIX_DF_EXPANSION2(m) (fabs((*(m))[0] * (*(m))[3] - (*(m))[1] * (*(m))[2]))
61 #define NR_MATRIX_DF_EXPANSION(m) (sqrt(NR_MATRIX_DF_EXPANSION2(m)))
63 namespace NR {
65 /**
66 * The Matrix class.
67 *
68 * For purposes of multiplication, points should be thought of as row vectors
69 *
70 * p = ( p[X] p[Y] 1 )
71 *
72 * to be right-multiplied by transformation matrices
73 * \verbatim
74 c[] = | c[0] c[1] 0 |
75 | c[2] c[3] 0 |
76 | c[4] c[5] 1 | \endverbatim
77 *
78 * (so the columns of the matrix correspond to the columns (elements) of the result,
79 * and the rows of the matrix correspond to columns (elements) of the "input").
80 */
81 class Matrix {
84 public:
86 /**
87 * Various forms of constructor
88 */
90 /**
91 *
92 */
93 explicit Matrix() { }
96 /**
97 *
98 */
99 Matrix(Matrix const &m) {
101 NR::Coord const *src = m._c;
102 NR::Coord *dest = _c;
104 *dest++ = *src++; //0
105 *dest++ = *src++; //1
106 *dest++ = *src++; //2
107 *dest++ = *src++; //3
108 *dest++ = *src++; //4
109 *dest = *src ; //5
111 }
116 /**
117 *
118 */
119 Matrix(NRMatrix const &m) {
121 NR::Coord const *src = m.c;
122 NR::Coord *dest = _c;
124 *dest++ = *src++; //0
125 *dest++ = *src++; //1
126 *dest++ = *src++; //2
127 *dest++ = *src++; //3
128 *dest++ = *src++; //4
129 *dest = *src ; //5
131 }
136 /**
137 *
138 */
139 Matrix(double c0, double c1,
140 double c2, double c3,
141 double c4, double c5) {
143 NR::Coord *dest = _c;
145 *dest++ = c0; //0
146 *dest++ = c1; //1
147 *dest++ = c2; //2
148 *dest++ = c3; //3
149 *dest++ = c4; //4
150 *dest = c5; //5
152 }
156 /**
157 *
158 */
159 Matrix &operator=(Matrix const &m) {
161 NR::Coord const *src = m._c;
162 NR::Coord *dest = _c;
164 *dest++ = *src++; //0
165 *dest++ = *src++; //1
166 *dest++ = *src++; //2
167 *dest++ = *src++; //3
168 *dest++ = *src++; //4
169 *dest = *src ; //5
171 return *this;
172 }
177 /**
178 *
179 */
180 explicit Matrix(scale const &sm) {
182 NR::Coord *dest = _c;
184 *dest++ = sm[X]; //0
185 *dest++ = 0.0; //1
186 *dest++ = 0.0; //2
187 *dest++ = sm[Y]; //3
188 *dest++ = 0.0; //4
189 *dest = 0.0; //5
191 }
198 /**
199 *
200 */
201 explicit Matrix(rotate const &r) {
203 NR::Coord *dest = _c;
205 *dest++ = r.vec[X]; //0
206 *dest++ = r.vec[Y]; //1
207 *dest++ = -r.vec[Y]; //2
208 *dest++ = r.vec[X]; //3
209 *dest++ = 0.0; //4
210 *dest = 0.0; //5
212 }
217 /**
218 *
219 */
220 explicit Matrix(translate const &tm) {
222 NR::Coord *dest = _c;
224 *dest++ = 1.0; //0
225 *dest++ = 0.0; //1
226 *dest++ = 0.0; //2
227 *dest++ = 1.0; //3
228 *dest++ = tm[X]; //4
229 *dest = tm[Y]; //5
230 }
234 /**
235 *
236 */
237 Matrix(NRMatrix const *nr);
240 /**
241 *
242 */
243 bool test_identity() const;
246 /**
247 *
248 */
249 bool is_translation(Coord const eps = 1e-6) const;
251 /**
252 *
253 */
254 bool is_scale(Coord const eps = 1e-6) const;
256 /**
257 *
258 */
259 bool is_rotation(Coord const eps = 1e-6) const;
262 /**
263 *
264 */
265 Matrix inverse() const;
268 /**
269 *
270 */
271 Matrix &operator*=(Matrix const &other);
274 /**
275 *
276 */
277 Matrix &operator*=(scale const &other);
281 /**
282 *
283 */
284 Matrix &operator*=(translate const &other) {
285 _c[4] += other[X];
286 _c[5] += other[Y];
287 return *this;
288 }
292 /**
293 *
294 */
295 inline Coord &operator[](int const i) {
296 return _c[i];
297 }
301 /**
302 *
303 */
304 inline Coord operator[](int const i) const {
305 return _c[i];
306 }
309 /**
310 *
311 */
312 void set_identity();
314 /**
315 *
316 */
317 Coord det() const;
320 /**
321 *
322 */
323 Coord descrim2() const;
326 /**
327 *
328 */
329 Coord descrim() const;
332 /**
333 *
334 */
335 double expansion() const;
338 /**
339 *
340 */
341 double expansionX() const;
344 /**
345 *
346 */
347 double expansionY() const;
349 // legacy
352 /**
353 *
354 */
355 Matrix &assign(Coord const *array);
358 /**
359 *
360 */
361 NRMatrix *copyto(NRMatrix* nrm) const;
364 /**
365 *
366 */
367 Coord *copyto(Coord *array) const;
371 /**
372 *
373 */
374 operator NRMatrix&() {
375 g_assert(sizeof(_c) == sizeof(NRMatrix));
376 return *reinterpret_cast<NRMatrix *>(_c);
377 }
381 /**
382 *
383 */
384 operator NRMatrix const&() const {
385 g_assert(sizeof(_c) == sizeof(NRMatrix));
386 return *reinterpret_cast<const NRMatrix *>(_c);
387 }
391 /**
392 *
393 */
394 operator NRMatrix*() {
395 g_assert(sizeof(_c) == sizeof(NRMatrix));
396 return reinterpret_cast<NRMatrix *>(_c);
397 }
400 /**
401 *
402 */
403 operator NRMatrix const*() const {
404 g_assert(sizeof(_c) == sizeof(NRMatrix));
405 return reinterpret_cast<NRMatrix const *>(_c);
406 }
409 private:
412 NR::Coord _c[6];
413 };
415 /** A function to print out the Matrix (for debugging) */
416 inline std::ostream &operator<< (std::ostream &out_file, const NR::Matrix &m) {
417 out_file << "A: " << m[0] << " C: " << m[2] << " E: " << m[4] << "\n";
418 out_file << "B: " << m[1] << " D: " << m[3] << " F: " << m[5] << "\n";
419 return out_file;
420 }
422 extern void assert_close(Matrix const &a, Matrix const &b);
424 } /* namespace NR */
432 /** \note
433 * Discussion of splitting up nr-matrix.h into lots of little files:
434 *
435 * Advantages:
436 *
437 * - Reducing amount of recompilation necessary when anything changes.
438 *
439 * - Hopefully also reducing compilation time by reducing the number of inline
440 * function definitions encountered by the compiler for a given .o file.
441 * (No timing comparisons done yet. On systems without much memory available
442 * for caching, this may be outweighed by additional I/O costs.)
443 *
444 * Disadvantages:
445 *
446 * - More #include lines necessary per file. If a compile fails due to
447 * not having all the necessary #include lines, then the developer needs
448 * to spend some time working out what #include to add.
449 */
451 #endif /* !__NR_MATRIX_H__ */
454 /*
455 Local Variables:
456 mode:c++
457 c-file-style:"stroustrup"
458 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
459 indent-tabs-mode:nil
460 fill-column:99
461 End:
462 */
463 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :