Code

0205ab04f44438c2043229a77f2d415a0c16bf82
[inkscape.git] / src / libnr / nr-matrix.h
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();
314         
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;
349         
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;
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 :