Code

fix by dvlierop2 for snapping bugs 1579556 and 1579587
[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/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();
313         
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;
348         
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;
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 :